summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--.github/workflows/build_cmake.yml6
-rw-r--r--CMakeLists.txt1
-rw-r--r--README.md11
-rw-r--r--cmake/QtCreatorAPI.cmake36
-rw-r--r--cmake/QtCreatorAPIInternal.cmake3
-rw-r--r--cmake/QtCreatorIDEBranding.cmake6
-rw-r--r--coin/instructions/common_environment.yaml2
-rw-r--r--doc/qtcreator/images/qtcreator-mcu-options.pngbin12741 -> 30155 bytes
-rw-r--r--doc/qtcreator/src/editors/creator-only/creator-clang-codemodel.qdoc4
-rw-r--r--doc/qtcreator/src/mcu/creator-mcu-dev.qdoc71
-rw-r--r--doc/qtcreator/src/overview/creator-acknowledgements.qdoc14
-rw-r--r--doc/qtcreator/src/projects/creator-only/creator-build-settings-qmake.qdoc13
-rw-r--r--doc/qtcreator/src/projects/creator-only/creator-projects-building.qdoc5
-rw-r--r--doc/qtcreator/src/projects/creator-only/creator-projects-qt-versions.qdoc4
-rw-r--r--doc/qtcreator/src/qtcreator-toc.qdoc1
-rw-r--r--doc/qtcreator/src/qtquick/library/qtquick-controls.qdoc310
-rw-r--r--doc/qtcreator/src/qtquick/library/qtquick-data-models.qdoc2
-rw-r--r--doc/qtcreator/src/qtquick/library/qtquick-user-interaction-methods.qdoc237
-rw-r--r--doc/qtcreator/src/qtquick/qtquick-export.qdoc3
-rw-r--r--doc/qtcreator/src/qtquick/qtquick-from-qmlproject-to-pro.qdoc24
-rw-r--r--doc/qtcreator/src/qtquick/qtquick-library.qdoc23
-rw-r--r--doc/qtcreator/src/vcs/creator-vcs-git.qdoc2
-rw-r--r--doc/qtcreatordev/src/coding-style.qdoc35
-rw-r--r--doc/qtdesignstudio/examples/doc/loginui1.qdoc7
-rw-r--r--doc/qtdesignstudio/images/ai-logo.pngbin0 -> 1084 bytes
-rw-r--r--doc/qtdesignstudio/images/blender-logo.pngbin0 -> 4585 bytes
-rw-r--r--doc/qtdesignstudio/images/figma-logo.pngbin0 -> 1378 bytes
-rw-r--r--doc/qtdesignstudio/images/maya-logo.pngbin0 -> 5485 bytes
-rw-r--r--doc/qtdesignstudio/images/ps-logo.pngbin0 -> 1112 bytes
-rw-r--r--doc/qtdesignstudio/images/qt-3ds-logo.pngbin0 -> 3915 bytes
-rw-r--r--doc/qtdesignstudio/images/sketch-logo.pngbin0 -> 1789 bytes
-rw-r--r--doc/qtdesignstudio/images/studio-custom-button.gifbin0 -> 3853 bytes
-rw-r--r--doc/qtdesignstudio/images/studio-custom-check-box.gifbin0 -> 4386 bytes
-rw-r--r--doc/qtdesignstudio/images/studio-custom-dial.gifbin0 -> 56863 bytes
-rw-r--r--doc/qtdesignstudio/images/studio-custom-slider.gifbin0 -> 39600 bytes
-rw-r--r--doc/qtdesignstudio/images/studio-custom-spinbox.gifbin0 -> 20594 bytes
-rw-r--r--doc/qtdesignstudio/images/studio-custom-switch.gifbin0 -> 3713 bytes
-rw-r--r--doc/qtdesignstudio/src/qtbridge/qtbridge-overview.qdoc76
-rw-r--r--doc/qtdesignstudio/src/qtdesignstudio-components.qdocinc27
-rw-r--r--doc/qtdesignstudio/src/qtdesignstudio-exporting-and-importing.qdoc95
-rw-r--r--doc/qtdesignstudio/src/qtdesignstudio-faq.qdoc76
-rw-r--r--doc/qtdesignstudio/src/qtdesignstudio-getting-started.qdoc46
-rw-r--r--doc/qtdesignstudio/src/qtdesignstudio-importing-designs.qdoc4
-rw-r--r--doc/qtdesignstudio/src/qtdesignstudio-projects-overview.qdoc12
-rw-r--r--doc/qtdesignstudio/src/qtdesignstudio-projects.qdoc11
-rw-r--r--doc/qtdesignstudio/src/qtdesignstudio-toc.qdoc51
-rw-r--r--doc/qtdesignstudio/src/qtdesignstudio.qdoc4
-rw-r--r--doc/qtdesignstudio/src/qtquick3d-editor/exporting-3d/exporting-3d-assets.qdoc13
-rw-r--r--doc/qtdesignstudio/src/qtquick3d-editor/exporting-3d/exporting-from-qt3ds.qdoc2
-rw-r--r--doc/qtdesignstudio/src/qtquick3d-editor/qtdesignstudio-3d-importing.qdoc4
-rw-r--r--qbs/imports/QtcLibrary.qbs2
-rw-r--r--qbs/imports/QtcPlugin.qbs2
-rw-r--r--qbs/imports/QtcProduct.qbs3
-rw-r--r--qbs/modules/qtc/qtc.qbs10
-rw-r--r--qtcreator.pri15
-rw-r--r--qtcreator.pro10
-rw-r--r--qtcreator_ide_branding.pri6
-rw-r--r--qtcreator_testvars.pri16
-rw-r--r--share/CMakeLists.txt14
-rw-r--r--share/metainfo/org.qt-project.qtcreator.appdata.xml.cmakein (renamed from share/metainfo/org.qt-project.qtcreator.appdata.xml)16
-rw-r--r--share/qtcreator/debugger/creatortypes.py16
-rw-r--r--share/qtcreator/debugger/gdbbridge.py17
-rw-r--r--share/qtcreator/debugger/lldbbridge.py48
-rw-r--r--share/qtcreator/qml/qmlpuppet/mockfiles/RotateGizmo.qml64
-rw-r--r--share/qtcreator/qml/qmlpuppet/mockfiles/RotateRing.qml7
-rw-r--r--share/qtcreator/qml/qmlpuppet/qml2puppet/editor3d/generalhelper.cpp18
-rw-r--r--share/qtcreator/qml/qmlpuppet/qml2puppet/editor3d/generalhelper.h6
-rw-r--r--share/qtcreator/qml/qmlpuppet/qml2puppet/instances/qt5informationnodeinstanceserver.cpp59
-rw-r--r--share/qtcreator/qml/qmlpuppet/qml2puppet/instances/qt5informationnodeinstanceserver.h4
-rw-r--r--share/qtcreator/qmldesigner/formatconfiguration.json24
-rw-r--r--share/qtcreator/qmldesigner/itemLibraryQmlSources/Assets.qml184
-rw-r--r--share/qtcreator/qmldesigner/itemLibraryQmlSources/ItemsView.qml6
-rw-r--r--share/qtcreator/qmldesigner/itemLibraryQmlSources/LibraryHeader.qml2
-rw-r--r--share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/HelperWidgets/ExtendedFunctionLogic.qml7
-rw-r--r--share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/HelperWidgets/Section.qml26
-rw-r--r--share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/HelperWidgets/SpinBox.qml11
-rw-r--r--share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/StudioTheme/InternalConstants.qml197
-rw-r--r--share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/StudioTheme/icons.ttfbin16516 -> 18500 bytes
-rw-r--r--share/qtcreator/styles/creator-dark.xml1
-rw-r--r--share/qtcreator/styles/intellij.xml1
-rw-r--r--share/qtcreator/styles/solarized-dark.xml1
-rw-r--r--share/qtcreator/styles/solarized-light.xml1
-rw-r--r--share/qtcreator/templates/wizards/projects/qtquickapplication/empty/wizard.json67
-rw-r--r--share/qtcreator/templates/wizards/projects/qtquickapplication/scroll/wizard.json44
-rw-r--r--share/qtcreator/templates/wizards/projects/qtquickapplication/stack/wizard.json62
-rw-r--r--share/qtcreator/templates/wizards/projects/qtquickapplication/swipe/wizard.json62
-rw-r--r--share/qtcreator/templates/wizards/projects/qtquickuiprototype/wizard.json67
-rw-r--r--share/share.pro17
-rw-r--r--src/app/app_version_header.qbs2
-rw-r--r--src/libs/3rdparty/CMakeLists.txt1
-rw-r--r--src/libs/3rdparty/cplusplus/Symbol.cpp2
-rw-r--r--src/libs/3rdparty/cplusplus/Symbol.h2
-rw-r--r--src/libs/3rdparty/minitrace/CMakeLists.txt9
-rw-r--r--src/libs/3rdparty/minitrace/private/minitrace.c484
-rw-r--r--src/libs/3rdparty/minitrace/private/minitrace.h270
-rw-r--r--src/libs/3rdparty/minitrace/trace.h (renamed from src/plugins/mesonprojectmanager/settings/general/generalsettingswidget.h)47
-rw-r--r--src/libs/3rdparty/syntax-highlighting/syntax-highlighting.qbs29
-rw-r--r--src/libs/3rdparty/yaml-cpp/yaml-cpp.qbs2
-rw-r--r--src/libs/CMakeLists.txt4
-rw-r--r--src/libs/advanceddockingsystem/dockmanager.cpp2
-rw-r--r--src/libs/advanceddockingsystem/elidinglabel.cpp8
-rw-r--r--src/libs/advanceddockingsystem/floatingdockcontainer.cpp5
-rw-r--r--src/libs/clangsupport/clangsupport_global.h1
-rw-r--r--src/libs/clangsupport/tokeninfocontainer.h1
-rw-r--r--src/libs/cplusplus/PPToken.h4
-rw-r--r--src/libs/cplusplus/cplusplus.qbs2
-rw-r--r--src/libs/cplusplus/pp-engine.cpp4
-rw-r--r--src/libs/extensionsystem/pluginmanager.cpp11
-rw-r--r--src/libs/languageserverprotocol/CMakeLists.txt2
-rw-r--r--src/libs/languageserverprotocol/client.h12
-rw-r--r--src/libs/languageserverprotocol/clientcapabilities.cpp99
-rw-r--r--src/libs/languageserverprotocol/clientcapabilities.h158
-rw-r--r--src/libs/languageserverprotocol/completion.cpp30
-rw-r--r--src/libs/languageserverprotocol/completion.h12
-rw-r--r--src/libs/languageserverprotocol/diagnostics.h3
-rw-r--r--src/libs/languageserverprotocol/icontent.h11
-rw-r--r--src/libs/languageserverprotocol/initializemessages.cpp19
-rw-r--r--src/libs/languageserverprotocol/initializemessages.h35
-rw-r--r--src/libs/languageserverprotocol/jsonkeys.h23
-rw-r--r--src/libs/languageserverprotocol/jsonobject.cpp67
-rw-r--r--src/libs/languageserverprotocol/jsonobject.h145
-rw-r--r--src/libs/languageserverprotocol/jsonrpcmessages.h26
-rw-r--r--src/libs/languageserverprotocol/languagefeatures.cpp153
-rw-r--r--src/libs/languageserverprotocol/languagefeatures.h90
-rw-r--r--src/libs/languageserverprotocol/languageserverprotocol.pro12
-rw-r--r--src/libs/languageserverprotocol/languageserverprotocol.qbs4
-rw-r--r--src/libs/languageserverprotocol/lsptypes.cpp78
-rw-r--r--src/libs/languageserverprotocol/lsptypes.h70
-rw-r--r--src/libs/languageserverprotocol/lsputils.cpp32
-rw-r--r--src/libs/languageserverprotocol/lsputils.h33
-rw-r--r--src/libs/languageserverprotocol/messages.cpp6
-rw-r--r--src/libs/languageserverprotocol/messages.h8
-rw-r--r--src/libs/languageserverprotocol/progresssupport.cpp78
-rw-r--r--src/libs/languageserverprotocol/progresssupport.h170
-rw-r--r--src/libs/languageserverprotocol/semantictokens.cpp154
-rw-r--r--src/libs/languageserverprotocol/semantictokens.h241
-rw-r--r--src/libs/languageserverprotocol/servercapabilities.cpp117
-rw-r--r--src/libs/languageserverprotocol/servercapabilities.h87
-rw-r--r--src/libs/languageserverprotocol/textsynchronization.cpp31
-rw-r--r--src/libs/languageserverprotocol/textsynchronization.h20
-rw-r--r--src/libs/languageserverprotocol/workspace.cpp21
-rw-r--r--src/libs/languageserverprotocol/workspace.h33
-rw-r--r--src/libs/modelinglib/qmt/controller/namecontroller.h1
-rw-r--r--src/libs/modelinglib/qmt/infrastructure/geometryutilities.cpp8
-rw-r--r--src/libs/modelinglib/qmt/model_widgets_ui/propertiesviewmview.cpp5
m---------src/libs/qlitehtml0
-rw-r--r--src/libs/qmljs/qmljsbind.cpp8
-rw-r--r--src/libs/qmljs/qmljscheck.cpp4
-rw-r--r--src/libs/qmljs/qmljscodeformatter.cpp43
-rw-r--r--src/libs/qmljs/qmljscodeformatter.h8
-rw-r--r--src/libs/qmljs/qmljsmodelmanagerinterface.cpp13
-rw-r--r--src/libs/qmljs/qmljsmodelmanagerinterface.h1
-rw-r--r--src/libs/qmljs/qmljsplugindumper.cpp2
-rw-r--r--src/libs/qmljs/qmljsreformatter.cpp21
-rw-r--r--src/libs/qmljs/qmljsscanner.cpp131
-rw-r--r--src/libs/qmljs/qmljsscanner.h47
-rw-r--r--src/libs/sqlite/sqlite.qbs2
-rw-r--r--src/libs/sqlite/sqlitebasestatement.cpp24
-rw-r--r--src/libs/sqlite/sqlitebasestatement.h207
-rw-r--r--src/libs/sqlite/sqlitedatabase.h3
-rw-r--r--src/libs/sqlite/sqlitereadstatement.h2
-rw-r--r--src/libs/sqlite/sqlitevalue.h19
-rw-r--r--src/libs/ssh/sftpsession.cpp4
-rw-r--r--src/libs/ssh/sftptransfer.cpp10
-rw-r--r--src/libs/ssh/sshremoteprocess.cpp2
-rw-r--r--src/libs/ssh/sshremoteprocess.h4
-rw-r--r--src/libs/tracing/qml/CategoryLabel.qml2
-rw-r--r--src/libs/tracing/qml/FlameGraphView.qml2
-rw-r--r--src/libs/tracing/qml/MainView.qml4
-rw-r--r--src/libs/tracing/qml/Overview.qml2
-rw-r--r--src/libs/tracing/qml/SelectionRange.qml2
-rw-r--r--src/libs/tracing/qml/SelectionRangeDetails.qml4
-rw-r--r--src/libs/tracing/qml/TimeMarks.qml2
-rw-r--r--src/libs/tracing/qml/TimelineContent.qml6
-rw-r--r--src/libs/tracing/timelinerenderer.cpp5
-rw-r--r--src/libs/utils/CMakeLists.txt8
-rw-r--r--src/libs/utils/algorithm.h16
-rw-r--r--src/libs/utils/archive.cpp12
-rw-r--r--src/libs/utils/archive.h5
-rw-r--r--src/libs/utils/aspects.cpp1112
-rw-r--r--src/libs/utils/aspects.h275
-rw-r--r--src/libs/utils/buildablehelperlibrary.cpp37
-rw-r--r--src/libs/utils/commandline.cpp1482
-rw-r--r--src/libs/utils/commandline.h165
-rw-r--r--src/libs/utils/consoleprocess.cpp59
-rw-r--r--src/libs/utils/environment.cpp27
-rw-r--r--src/libs/utils/environment.h7
-rw-r--r--src/libs/utils/fileutils.cpp495
-rw-r--r--src/libs/utils/fileutils.h114
-rw-r--r--src/libs/utils/futuresynchronizer.cpp (renamed from src/plugins/qmlprofiler/qmlprofileroptionspage.cpp)71
-rw-r--r--src/libs/utils/futuresynchronizer.h (renamed from src/plugins/autotest/itestsettings.h)55
-rw-r--r--src/libs/utils/icon.cpp32
-rw-r--r--src/libs/utils/icon.h11
-rw-r--r--src/libs/utils/json.cpp2
-rw-r--r--src/libs/utils/layoutbuilder.cpp429
-rw-r--r--src/libs/utils/layoutbuilder.h163
-rw-r--r--src/libs/utils/linecolumn.cpp68
-rw-r--r--src/libs/utils/linecolumn.h9
-rw-r--r--src/libs/utils/link.cpp (renamed from src/plugins/mesonprojectmanager/settings/general/generalsettingspage.cpp)44
-rw-r--r--src/libs/utils/link.h18
-rw-r--r--src/libs/utils/macroexpander.cpp10
-rw-r--r--src/libs/utils/namevaluemodel.cpp46
-rw-r--r--src/libs/utils/namevaluemodel.h1
-rw-r--r--src/libs/utils/outputformatter.cpp26
-rw-r--r--src/libs/utils/outputformatter.h5
-rw-r--r--src/libs/utils/pathchooser.cpp14
-rw-r--r--src/libs/utils/persistentsettings.cpp2
-rw-r--r--src/libs/utils/porting.h1
-rw-r--r--src/libs/utils/process_ctrlc_stub.cpp4
-rw-r--r--src/libs/utils/qtcprocess.cpp2061
-rw-r--r--src/libs/utils/qtcprocess.h221
-rw-r--r--src/libs/utils/savedaction.cpp323
-rw-r--r--src/libs/utils/savedaction.h106
-rw-r--r--src/libs/utils/shellcommand.cpp134
-rw-r--r--src/libs/utils/shellcommand.h37
-rw-r--r--src/libs/utils/synchronousprocess.cpp808
-rw-r--r--src/libs/utils/synchronousprocess.h175
-rw-r--r--src/libs/utils/textfileformat.cpp26
-rw-r--r--src/libs/utils/textfileformat.h10
-rw-r--r--src/libs/utils/utils-lib.pri13
-rw-r--r--src/libs/utils/utils.qbs10
-rw-r--r--src/libs/utils/utilsicons.cpp32
-rw-r--r--src/plugins/CMakeLists.txt1
-rw-r--r--src/plugins/android/CMakeLists.txt3
-rw-r--r--src/plugins/android/adbcommandswidget.cpp189
-rw-r--r--src/plugins/android/adbcommandswidget.ui117
-rw-r--r--src/plugins/android/android.pro7
-rw-r--r--src/plugins/android/android.qbs7
-rw-r--r--src/plugins/android/androidavdmanager.cpp279
-rw-r--r--src/plugins/android/androidavdmanager.h3
-rw-r--r--src/plugins/android/androidbuildapkstep.cpp16
-rw-r--r--src/plugins/android/androidconfigurations.cpp104
-rw-r--r--src/plugins/android/androidconfigurations.h35
-rw-r--r--src/plugins/android/androidcreatekeystorecertificate.cpp10
-rw-r--r--src/plugins/android/androiddeployqtstep.cpp16
-rw-r--r--src/plugins/android/androiddeviceinfo.cpp72
-rw-r--r--src/plugins/android/androiddeviceinfo.h66
-rw-r--r--src/plugins/android/androidmanager.cpp37
-rw-r--r--src/plugins/android/androidmanifestdocument.cpp4
-rw-r--r--src/plugins/android/androidmanifestdocument.h2
-rw-r--r--src/plugins/android/androidpackageinstallationstep.cpp4
-rw-r--r--src/plugins/android/androidplugin.h6
-rw-r--r--src/plugins/android/androidqtversion.cpp4
-rw-r--r--src/plugins/android/androidqtversion.h2
-rw-r--r--src/plugins/android/androidrunconfiguration.cpp79
-rw-r--r--src/plugins/android/androidrunconfiguration.h28
-rw-r--r--src/plugins/android/androidrunnerworker.cpp21
-rw-r--r--src/plugins/android/androidsdkmanager.cpp88
-rw-r--r--src/plugins/android/androidsettingswidget.cpp11
-rw-r--r--src/plugins/android/avdmanageroutputparser.cpp166
-rw-r--r--src/plugins/android/avdmanageroutputparser.h (renamed from src/plugins/git/settingspage.h)18
-rw-r--r--src/plugins/android/javalanguageserver.cpp10
-rw-r--r--src/plugins/android/javaparser.cpp4
-rw-r--r--src/plugins/android/javaparser.h6
-rw-r--r--src/plugins/autotest/CMakeLists.txt5
-rw-r--r--src/plugins/autotest/autotest.pro17
-rw-r--r--src/plugins/autotest/autotest.qbs1
-rw-r--r--src/plugins/autotest/autotestplugin.cpp2
-rw-r--r--src/plugins/autotest/boost/boosttestconfiguration.cpp21
-rw-r--r--src/plugins/autotest/boost/boosttestframework.cpp2
-rw-r--r--src/plugins/autotest/boost/boosttestframework.h1
-rw-r--r--src/plugins/autotest/boost/boosttestoutputreader.cpp9
-rw-r--r--src/plugins/autotest/boost/boosttestoutputreader.h8
-rw-r--r--src/plugins/autotest/boost/boosttestparser.cpp21
-rw-r--r--src/plugins/autotest/boost/boosttestparser.h2
-rw-r--r--src/plugins/autotest/boost/boosttestresult.cpp2
-rw-r--r--src/plugins/autotest/boost/boosttestresult.h4
-rw-r--r--src/plugins/autotest/boost/boosttestsettings.cpp120
-rw-r--r--src/plugins/autotest/boost/boosttestsettings.h35
-rw-r--r--src/plugins/autotest/boost/boosttestsettingspage.cpp114
-rw-r--r--src/plugins/autotest/boost/boosttestsettingspage.h42
-rw-r--r--src/plugins/autotest/boost/boosttestsettingspage.ui160
-rw-r--r--src/plugins/autotest/boost/boosttesttreeitem.cpp28
-rw-r--r--src/plugins/autotest/boost/boosttesttreeitem.h4
-rw-r--r--src/plugins/autotest/catch/catchconfiguration.cpp34
-rw-r--r--src/plugins/autotest/catch/catchframework.cpp2
-rw-r--r--src/plugins/autotest/catch/catchframework.h1
-rw-r--r--src/plugins/autotest/catch/catchoutputreader.cpp9
-rw-r--r--src/plugins/autotest/catch/catchoutputreader.h6
-rw-r--r--src/plugins/autotest/catch/catchresult.cpp2
-rw-r--r--src/plugins/autotest/catch/catchtestparser.cpp17
-rw-r--r--src/plugins/autotest/catch/catchtestparser.h2
-rw-r--r--src/plugins/autotest/catch/catchtestsettings.cpp184
-rw-r--r--src/plugins/autotest/catch/catchtestsettings.h55
-rw-r--r--src/plugins/autotest/catch/catchtestsettingspage.cpp113
-rw-r--r--src/plugins/autotest/catch/catchtestsettingspage.ui306
-rw-r--r--src/plugins/autotest/catch/catchtreeitem.cpp41
-rw-r--r--src/plugins/autotest/catch/catchtreeitem.h2
-rw-r--r--src/plugins/autotest/ctest/ctestoutputreader.cpp3
-rw-r--r--src/plugins/autotest/ctest/ctestoutputreader.h2
-rw-r--r--src/plugins/autotest/ctest/ctesttool.cpp5
-rw-r--r--src/plugins/autotest/ctest/ctesttreeitem.cpp2
-rw-r--r--src/plugins/autotest/ctest/ctesttreeitem.h2
-rw-r--r--src/plugins/autotest/gtest/gtestconfiguration.cpp16
-rw-r--r--src/plugins/autotest/gtest/gtestframework.cpp6
-rw-r--r--src/plugins/autotest/gtest/gtestframework.h1
-rw-r--r--src/plugins/autotest/gtest/gtestoutputreader.cpp14
-rw-r--r--src/plugins/autotest/gtest/gtestoutputreader.h6
-rw-r--r--src/plugins/autotest/gtest/gtestparser.cpp14
-rw-r--r--src/plugins/autotest/gtest/gtestparser.h2
-rw-r--r--src/plugins/autotest/gtest/gtestresult.cpp2
-rw-r--r--src/plugins/autotest/gtest/gtestresult.h4
-rw-r--r--src/plugins/autotest/gtest/gtestsettings.cpp164
-rw-r--r--src/plugins/autotest/gtest/gtestsettings.h44
-rw-r--r--src/plugins/autotest/gtest/gtestsettingspage.cpp123
-rw-r--r--src/plugins/autotest/gtest/gtestsettingspage.ui229
-rw-r--r--src/plugins/autotest/gtest/gtesttreeitem.cpp65
-rw-r--r--src/plugins/autotest/gtest/gtesttreeitem.h5
-rw-r--r--src/plugins/autotest/itestframework.h3
-rw-r--r--src/plugins/autotest/itestparser.cpp8
-rw-r--r--src/plugins/autotest/itestparser.h16
-rw-r--r--src/plugins/autotest/qtest/qttest_utils.cpp14
-rw-r--r--src/plugins/autotest/qtest/qttest_utils.h8
-rw-r--r--src/plugins/autotest/qtest/qttestconfiguration.cpp16
-rw-r--r--src/plugins/autotest/qtest/qttestframework.cpp2
-rw-r--r--src/plugins/autotest/qtest/qttestframework.h1
-rw-r--r--src/plugins/autotest/qtest/qttestoutputreader.cpp16
-rw-r--r--src/plugins/autotest/qtest/qttestoutputreader.h8
-rw-r--r--src/plugins/autotest/qtest/qttestparser.cpp171
-rw-r--r--src/plugins/autotest/qtest/qttestparser.h27
-rw-r--r--src/plugins/autotest/qtest/qttestresult.cpp2
-rw-r--r--src/plugins/autotest/qtest/qttestresult.h4
-rw-r--r--src/plugins/autotest/qtest/qttestsettings.cpp115
-rw-r--r--src/plugins/autotest/qtest/qttestsettings.h29
-rw-r--r--src/plugins/autotest/qtest/qttestsettingspage.cpp113
-rw-r--r--src/plugins/autotest/qtest/qttestsettingspage.ui198
-rw-r--r--src/plugins/autotest/qtest/qttesttreeitem.cpp29
-rw-r--r--src/plugins/autotest/qtest/qttesttreeitem.h2
-rw-r--r--src/plugins/autotest/quick/quicktest_utils.cpp13
-rw-r--r--src/plugins/autotest/quick/quicktest_utils.h5
-rw-r--r--src/plugins/autotest/quick/quicktestconfiguration.cpp12
-rw-r--r--src/plugins/autotest/quick/quicktestframework.cpp2
-rw-r--r--src/plugins/autotest/quick/quicktestparser.cpp32
-rw-r--r--src/plugins/autotest/quick/quicktestparser.h10
-rw-r--r--src/plugins/autotest/quick/quicktesttreeitem.cpp43
-rw-r--r--src/plugins/autotest/quick/quicktesttreeitem.h9
-rw-r--r--src/plugins/autotest/testcodeparser.cpp34
-rw-r--r--src/plugins/autotest/testcodeparser.h10
-rw-r--r--src/plugins/autotest/testconfiguration.cpp38
-rw-r--r--src/plugins/autotest/testconfiguration.h16
-rw-r--r--src/plugins/autotest/testframeworkmanager.cpp4
-rw-r--r--src/plugins/autotest/testnavigationwidget.cpp11
-rw-r--r--src/plugins/autotest/testnavigationwidget.h4
-rw-r--r--src/plugins/autotest/testoutputreader.cpp16
-rw-r--r--src/plugins/autotest/testoutputreader.h7
-rw-r--r--src/plugins/autotest/testresult.h8
-rw-r--r--src/plugins/autotest/testresultdelegate.cpp7
-rw-r--r--src/plugins/autotest/testresultmodel.cpp8
-rw-r--r--src/plugins/autotest/testresultspane.cpp8
-rw-r--r--src/plugins/autotest/testrunconfiguration.h4
-rw-r--r--src/plugins/autotest/testrunner.cpp16
-rw-r--r--src/plugins/autotest/testtreeitem.cpp67
-rw-r--r--src/plugins/autotest/testtreeitem.h37
-rw-r--r--src/plugins/autotest/testtreemodel.cpp20
-rw-r--r--src/plugins/autotest/testtreemodel.h4
-rw-r--r--src/plugins/autotoolsprojectmanager/makefileparser.cpp2
-rw-r--r--src/plugins/baremetal/debugserverprovidermanager.cpp4
-rw-r--r--src/plugins/baremetal/debugservers/gdb/openocdgdbserverprovider.cpp2
-rw-r--r--src/plugins/baremetal/iarewtoolchain.cpp52
-rw-r--r--src/plugins/baremetal/iarewtoolchain.h3
-rw-r--r--src/plugins/baremetal/keiltoolchain.cpp52
-rw-r--r--src/plugins/baremetal/keiltoolchain.h3
-rw-r--r--src/plugins/baremetal/sdcctoolchain.cpp48
-rw-r--r--src/plugins/baremetal/sdcctoolchain.h3
-rw-r--r--src/plugins/bazaar/CMakeLists.txt1
-rw-r--r--src/plugins/bazaar/bazaar.pro3
-rw-r--r--src/plugins/bazaar/bazaar.qbs3
-rw-r--r--src/plugins/bazaar/bazaarclient.cpp57
-rw-r--r--src/plugins/bazaar/bazaarplugin.cpp21
-rw-r--r--src/plugins/bazaar/bazaarsettings.cpp119
-rw-r--r--src/plugins/bazaar/bazaarsettings.h25
-rw-r--r--src/plugins/bazaar/optionspage.cpp95
-rw-r--r--src/plugins/bazaar/optionspage.ui176
-rw-r--r--src/plugins/beautifier/abstractsettings.cpp17
-rw-r--r--src/plugins/beautifier/artisticstyle/artisticstylesettings.cpp25
-rw-r--r--src/plugins/beautifier/beautifierplugin.cpp2
-rw-r--r--src/plugins/beautifier/clangformat/clangformat.cpp33
-rw-r--r--src/plugins/beautifier/clangformat/clangformat.h1
-rw-r--r--src/plugins/beautifier/clangformat/clangformatsettings.cpp7
-rw-r--r--src/plugins/beautifier/uncrustify/uncrustifysettings.cpp17
-rw-r--r--src/plugins/bineditor/bineditorplugin.cpp30
-rw-r--r--src/plugins/bineditor/bineditorwidget.cpp3
-rw-r--r--src/plugins/bookmarks/bookmarkfilter.cpp2
-rw-r--r--src/plugins/bookmarks/bookmarkmanager.cpp9
-rw-r--r--src/plugins/bookmarks/bookmarks_global.h1
-rw-r--r--src/plugins/bookmarks/bookmarksplugin.cpp21
-rw-r--r--src/plugins/clangcodemodel/CMakeLists.txt10
-rw-r--r--src/plugins/clangcodemodel/clangbackendcommunicator.cpp2
-rw-r--r--src/plugins/clangcodemodel/clangcodemodel.pro10
-rw-r--r--src/plugins/clangcodemodel/clangcodemodel.qbs8
-rw-r--r--src/plugins/clangcodemodel/clangcodemodel_dependencies.pri3
-rw-r--r--src/plugins/clangcodemodel/clangcodemodelplugin.cpp5
-rw-r--r--src/plugins/clangcodemodel/clangdclient.cpp678
-rw-r--r--src/plugins/clangcodemodel/clangdclient.h (renamed from src/plugins/qmlprofiler/tests/qmlprofilerconfigwidget_test.h)50
-rw-r--r--src/plugins/clangcodemodel/clangeditordocumentprocessor.cpp142
-rw-r--r--src/plugins/clangcodemodel/clangeditordocumentprocessor.h2
-rw-r--r--src/plugins/clangcodemodel/clangfollowsymbol.cpp26
-rw-r--r--src/plugins/clangcodemodel/clanggloballocatorfilters.cpp216
-rw-r--r--src/plugins/clangcodemodel/clanggloballocatorfilters.h (renamed from src/plugins/vcsbase/commonsettingspage.h)60
-rw-r--r--src/plugins/clangcodemodel/clanghighlightingresultreporter.cpp2
-rw-r--r--src/plugins/clangcodemodel/clangmodelmanagersupport.cpp153
-rw-r--r--src/plugins/clangcodemodel/clangmodelmanagersupport.h13
-rw-r--r--src/plugins/clangcodemodel/clangoverviewmodel.cpp2
-rw-r--r--src/plugins/clangcodemodel/clangrefactoringengine.cpp58
-rw-r--r--src/plugins/clangcodemodel/clangrefactoringengine.h21
-rw-r--r--src/plugins/clangcodemodel/clangutils.cpp198
-rw-r--r--src/plugins/clangcodemodel/clangutils.h10
-rw-r--r--src/plugins/clangcodemodel/test/clangautomationutils.cpp5
-rw-r--r--src/plugins/clangcodemodel/test/clangautomationutils.h2
-rw-r--r--src/plugins/clangcodemodel/test/clangcodecompletion_test.cpp3
-rw-r--r--src/plugins/clangcodemodel/test/clangdtests.cpp329
-rw-r--r--src/plugins/clangcodemodel/test/clangdtests.h (renamed from src/plugins/bazaar/optionspage.h)23
-rw-r--r--src/plugins/clangcodemodel/test/data/clangtestdata.qrc3
-rw-r--r--src/plugins/clangcodemodel/test/data/find-usages/defs.h28
-rw-r--r--src/plugins/clangcodemodel/test/data/find-usages/find-usages.pro4
-rw-r--r--src/plugins/clangcodemodel/test/data/find-usages/main.cpp60
-rw-r--r--src/plugins/clangformat/clangformatbaseindenter.cpp18
-rw-r--r--src/plugins/clangformat/clangformatconfigwidget.cpp9
-rw-r--r--src/plugins/clangformat/clangformatutils.cpp9
-rw-r--r--src/plugins/clangpchmanager/pchmanagerconnectionclient.cpp6
-rw-r--r--src/plugins/clangrefactoring/refactoringconnectionclient.cpp4
-rw-r--r--src/plugins/clangrefactoring/refactoringengine.cpp2
-rw-r--r--src/plugins/clangtools/clangfixitsrefactoringchanges.cpp14
-rw-r--r--src/plugins/clangtools/clangtidyclazyrunner.cpp2
-rw-r--r--src/plugins/clangtools/clangtool.cpp14
-rw-r--r--src/plugins/clangtools/clangtoolrunner.cpp34
-rw-r--r--src/plugins/clangtools/clangtoolrunner.h9
-rw-r--r--src/plugins/clangtools/clangtoolsdiagnosticview.cpp61
-rw-r--r--src/plugins/clangtools/clangtoolslogfilereader.cpp2
-rw-r--r--src/plugins/clangtools/clangtoolsplugin.cpp3
-rw-r--r--src/plugins/clangtools/clangtoolsutils.cpp18
-rw-r--r--src/plugins/clangtools/clangtoolsutils.h3
-rw-r--r--src/plugins/clangtools/diagnosticconfigswidget.cpp72
-rw-r--r--src/plugins/clangtools/diagnosticconfigswidget.h2
-rw-r--r--src/plugins/clangtools/diagnosticmark.cpp8
-rw-r--r--src/plugins/clangtools/executableinfo.cpp21
-rw-r--r--src/plugins/clangtools/virtualfilesystemoverlay.cpp2
-rw-r--r--src/plugins/classview/classviewnavigationwidgetfactory.cpp5
-rw-r--r--src/plugins/clearcase/clearcaseplugin.cpp37
-rw-r--r--src/plugins/clearcase/clearcasesync.cpp2
-rw-r--r--src/plugins/cmakeprojectmanager/CMakeLists.txt1
-rw-r--r--src/plugins/cmakeprojectmanager/builddirparameters.cpp4
-rw-r--r--src/plugins/cmakeprojectmanager/cmakebuildconfiguration.cpp136
-rw-r--r--src/plugins/cmakeprojectmanager/cmakebuildstep.cpp12
-rw-r--r--src/plugins/cmakeprojectmanager/cmakebuildsystem.cpp150
-rw-r--r--src/plugins/cmakeprojectmanager/cmakebuildsystem.h8
-rw-r--r--src/plugins/cmakeprojectmanager/cmakeeditor.cpp48
-rw-r--r--src/plugins/cmakeprojectmanager/cmakekitinformation.cpp67
-rw-r--r--src/plugins/cmakeprojectmanager/cmakekitinformation.h2
-rw-r--r--src/plugins/cmakeprojectmanager/cmakelocatorfilter.cpp2
-rw-r--r--src/plugins/cmakeprojectmanager/cmakeprocess.cpp4
-rw-r--r--src/plugins/cmakeprojectmanager/cmakeprojectimporter.cpp10
-rw-r--r--src/plugins/cmakeprojectmanager/cmakeprojectmanager.cpp6
-rw-r--r--src/plugins/cmakeprojectmanager/cmakeprojectmanager.pro5
-rw-r--r--src/plugins/cmakeprojectmanager/cmakeprojectmanager.qbs3
-rw-r--r--src/plugins/cmakeprojectmanager/cmakeprojectnodes.cpp13
-rw-r--r--src/plugins/cmakeprojectmanager/cmakeprojectplugin.cpp3
-rw-r--r--src/plugins/cmakeprojectmanager/cmakesettingspage.cpp2
-rw-r--r--src/plugins/cmakeprojectmanager/cmakespecificsettings.cpp82
-rw-r--r--src/plugins/cmakeprojectmanager/cmakespecificsettings.h45
-rw-r--r--src/plugins/cmakeprojectmanager/cmakespecificsettingspage.cpp99
-rw-r--r--src/plugins/cmakeprojectmanager/cmakespecificsettingspage.h42
-rw-r--r--src/plugins/cmakeprojectmanager/cmakespecificsettingspage.ui100
-rw-r--r--src/plugins/cmakeprojectmanager/cmaketool.cpp107
-rw-r--r--src/plugins/cmakeprojectmanager/cmaketool.h8
-rw-r--r--src/plugins/cmakeprojectmanager/cmaketoolmanager.cpp20
-rw-r--r--src/plugins/cmakeprojectmanager/cmaketoolmanager.h3
-rw-r--r--src/plugins/cmakeprojectmanager/cmaketoolsettingsaccessor.cpp39
-rw-r--r--src/plugins/cmakeprojectmanager/fileapidataextractor.cpp7
-rw-r--r--src/plugins/cmakeprojectmanager/projecttreehelper.cpp8
-rw-r--r--src/plugins/compilationdatabaseprojectmanager/compilationdatabaseprojectmanagerplugin.cpp9
-rw-r--r--src/plugins/conan/conaninstallstep.cpp2
-rw-r--r--src/plugins/conan/conanplugin.cpp2
-rw-r--r--src/plugins/conan/conansettings.cpp31
-rw-r--r--src/plugins/conan/conansettings.h16
-rw-r--r--src/plugins/coreplugin/CMakeLists.txt2
-rw-r--r--src/plugins/coreplugin/actionmanager/commandsfile.cpp2
-rw-r--r--src/plugins/coreplugin/coreplugin.cpp3
-rw-r--r--src/plugins/coreplugin/coreplugin.h2
-rw-r--r--src/plugins/coreplugin/dialogs/externaltoolconfig.cpp11
-rw-r--r--src/plugins/coreplugin/dialogs/filepropertiesdialog.cpp86
-rw-r--r--src/plugins/coreplugin/dialogs/filepropertiesdialog.h1
-rw-r--r--src/plugins/coreplugin/dialogs/filepropertiesdialog.ui64
-rw-r--r--src/plugins/coreplugin/dialogs/ioptionspage.cpp86
-rw-r--r--src/plugins/coreplugin/dialogs/ioptionspage.h10
-rw-r--r--src/plugins/coreplugin/dialogs/shortcutsettings.cpp24
-rw-r--r--src/plugins/coreplugin/documentmanager.cpp20
-rw-r--r--src/plugins/coreplugin/documentmanager.h3
-rw-r--r--src/plugins/coreplugin/editormanager/editormanager.cpp384
-rw-r--r--src/plugins/coreplugin/editormanager/editormanager.h30
-rw-r--r--src/plugins/coreplugin/editormanager/editormanager_p.h32
-rw-r--r--src/plugins/coreplugin/editormanager/editorview.cpp39
-rw-r--r--src/plugins/coreplugin/editormanager/editorview.h3
-rw-r--r--src/plugins/coreplugin/editormanager/iexternaleditor.h4
-rw-r--r--src/plugins/coreplugin/editormanager/openeditorsview.cpp2
-rw-r--r--src/plugins/coreplugin/editormanager/openeditorswindow.cpp2
-rw-r--r--src/plugins/coreplugin/editormanager/systemeditor.cpp6
-rw-r--r--src/plugins/coreplugin/editormanager/systemeditor.h2
-rw-r--r--src/plugins/coreplugin/externaltool.cpp4
-rw-r--r--src/plugins/coreplugin/externaltoolmanager.cpp4
-rw-r--r--src/plugins/coreplugin/fileutils.cpp4
-rw-r--r--src/plugins/coreplugin/find/searchresultitem.h4
-rw-r--r--src/plugins/coreplugin/find/searchresulttreeitems.cpp2
-rw-r--r--src/plugins/coreplugin/find/searchresulttreemodel.cpp56
-rw-r--r--src/plugins/coreplugin/find/searchresultwidget.cpp5
-rw-r--r--src/plugins/coreplugin/find/searchresultwidget.h1
-rw-r--r--src/plugins/coreplugin/find/searchresultwindow.cpp5
-rw-r--r--src/plugins/coreplugin/find/searchresultwindow.h1
-rw-r--r--src/plugins/coreplugin/generalsettings.cpp12
-rw-r--r--src/plugins/coreplugin/generatedfile.cpp4
-rw-r--r--src/plugins/coreplugin/icore.cpp62
-rw-r--r--src/plugins/coreplugin/icore.h14
-rw-r--r--src/plugins/coreplugin/idocument.cpp40
-rw-r--r--src/plugins/coreplugin/idocument.h9
-rw-r--r--src/plugins/coreplugin/inavigationwidgetfactory.h2
-rw-r--r--src/plugins/coreplugin/jsexpander.cpp14
-rw-r--r--src/plugins/coreplugin/locator/basefilefilter.cpp14
-rw-r--r--src/plugins/coreplugin/locator/directoryfilter.cpp3
-rw-r--r--src/plugins/coreplugin/locator/executefilter.cpp3
-rw-r--r--src/plugins/coreplugin/locator/externaltoolsfilter.cpp2
-rw-r--r--src/plugins/coreplugin/locator/filesystemfilter.cpp14
-rw-r--r--src/plugins/coreplugin/locator/ilocatorfilter.cpp20
-rw-r--r--src/plugins/coreplugin/locator/ilocatorfilter.h6
-rw-r--r--src/plugins/coreplugin/locator/javascriptfilter.cpp1
-rw-r--r--src/plugins/coreplugin/locator/locator.cpp1
-rw-r--r--src/plugins/coreplugin/locator/locatorfiltersfilter.cpp3
-rw-r--r--src/plugins/coreplugin/locator/locatorfiltersfilter.h1
-rw-r--r--src/plugins/coreplugin/locator/locatorsettingspage.cpp3
-rw-r--r--src/plugins/coreplugin/locator/locatorwidget.cpp16
-rw-r--r--src/plugins/coreplugin/locator/opendocumentsfilter.cpp8
-rw-r--r--src/plugins/coreplugin/locator/spotlightlocatorfilter.cpp36
-rw-r--r--src/plugins/coreplugin/mainwindow.cpp4
-rw-r--r--src/plugins/coreplugin/menubarfilter.cpp3
-rw-r--r--src/plugins/coreplugin/mimetypesettings.cpp11
-rw-r--r--src/plugins/coreplugin/outputwindow.cpp5
-rw-r--r--src/plugins/coreplugin/patchtool.cpp22
-rw-r--r--src/plugins/coreplugin/plugininstallwizard.cpp5
-rw-r--r--src/plugins/coreplugin/progressmanager/progressmanager.cpp3
-rw-r--r--src/plugins/coreplugin/progressmanager/progressmanager_win.cpp1
-rw-r--r--src/plugins/coreplugin/reaper.cpp32
-rw-r--r--src/plugins/coreplugin/reaper.h4
-rw-r--r--src/plugins/coreplugin/shellcommand.cpp2
-rw-r--r--src/plugins/coreplugin/shellcommand.h2
-rw-r--r--src/plugins/coreplugin/textdocument.cpp49
-rw-r--r--src/plugins/coreplugin/textdocument.h8
-rw-r--r--src/plugins/coreplugin/themechooser.cpp10
-rw-r--r--src/plugins/cpaster/CMakeLists.txt2
-rw-r--r--src/plugins/cpaster/cpaster.pro7
-rw-r--r--src/plugins/cpaster/cpaster.qbs4
-rw-r--r--src/plugins/cpaster/cpasterplugin.cpp52
-rw-r--r--src/plugins/cpaster/fileshareprotocol.cpp17
-rw-r--r--src/plugins/cpaster/fileshareprotocol.h6
-rw-r--r--src/plugins/cpaster/fileshareprotocolsettingspage.cpp117
-rw-r--r--src/plugins/cpaster/fileshareprotocolsettingspage.h53
-rw-r--r--src/plugins/cpaster/fileshareprotocolsettingswidget.ui101
-rw-r--r--src/plugins/cpaster/pasteselectdialog.cpp12
-rw-r--r--src/plugins/cpaster/pasteselectdialog.h5
-rw-r--r--src/plugins/cpaster/pasteview.cpp4
-rw-r--r--src/plugins/cpaster/pasteview.h2
-rw-r--r--src/plugins/cpaster/settings.cpp101
-rw-r--r--src/plugins/cpaster/settings.h36
-rw-r--r--src/plugins/cpaster/settingspage.cpp92
-rw-r--r--src/plugins/cpaster/settingspage.ui102
-rw-r--r--src/plugins/cppeditor/cppeditordocument.cpp4
-rw-r--r--src/plugins/cppeditor/cppeditordocument.h2
-rw-r--r--src/plugins/cppeditor/cppeditorplugin.h2
-rw-r--r--src/plugins/cppeditor/cppeditorwidget.cpp29
-rw-r--r--src/plugins/cppeditor/cppincludehierarchy.cpp17
-rw-r--r--src/plugins/cppeditor/cppquickfix_test.cpp90
-rw-r--r--src/plugins/cppeditor/cppquickfixes.cpp6
-rw-r--r--src/plugins/cppeditor/cpptypehierarchy.cpp35
-rw-r--r--src/plugins/cppeditor/cpptypehierarchy.h5
-rw-r--r--src/plugins/cppeditor/resourcepreviewhoverhandler.cpp2
-rw-r--r--src/plugins/cpptools/abstractoverviewmodel.h2
-rw-r--r--src/plugins/cpptools/builtinindexingsupport.cpp12
-rw-r--r--src/plugins/cpptools/builtinindexingsupport.h4
-rw-r--r--src/plugins/cpptools/compileroptionsbuilder.cpp2
-rw-r--r--src/plugins/cpptools/cppclassesfilter.h2
-rw-r--r--src/plugins/cpptools/cppcodemodelsettings.cpp29
-rw-r--r--src/plugins/cpptools/cppcodemodelsettings.h11
-rw-r--r--src/plugins/cpptools/cppcodemodelsettingspage.cpp23
-rw-r--r--src/plugins/cpptools/cppcodemodelsettingspage.ui34
-rw-r--r--src/plugins/cpptools/cppelementevaluator.cpp4
-rw-r--r--src/plugins/cpptools/cppfilesettingspage.cpp2
-rw-r--r--src/plugins/cpptools/cppfindreferences.cpp257
-rw-r--r--src/plugins/cpptools/cppfindreferences.h21
-rw-r--r--src/plugins/cpptools/cppfollowsymbolundercursor.cpp6
-rw-r--r--src/plugins/cpptools/cppfunctionsfilter.cpp1
-rw-r--r--src/plugins/cpptools/cppfunctionsfilter.h4
-rw-r--r--src/plugins/cpptools/cppincludesfilter.cpp4
-rw-r--r--src/plugins/cpptools/cpplocatordata.h2
-rw-r--r--src/plugins/cpptools/cpplocatorfilter.cpp5
-rw-r--r--src/plugins/cpptools/cpplocatorfilter.h5
-rw-r--r--src/plugins/cpptools/cppmodelmanager.cpp69
-rw-r--r--src/plugins/cpptools/cppmodelmanager.h11
-rw-r--r--src/plugins/cpptools/cppmodelmanager_test.cpp2
-rw-r--r--src/plugins/cpptools/cpppointerdeclarationformatter_test.cpp4
-rw-r--r--src/plugins/cpptools/cppprojectfilecategorizer.cpp5
-rw-r--r--src/plugins/cpptools/cppprojectinfogenerator.cpp45
-rw-r--r--src/plugins/cpptools/cppprojectupdater.cpp26
-rw-r--r--src/plugins/cpptools/cppprojectupdater.h8
-rw-r--r--src/plugins/cpptools/cppsourceprocessor.cpp7
-rw-r--r--src/plugins/cpptools/cpptoolstestcase.cpp2
-rw-r--r--src/plugins/cpptools/cppvirtualfunctionproposalitem.cpp6
-rw-r--r--src/plugins/cpptools/cursorineditor.h8
-rw-r--r--src/plugins/cpptools/projectpart.cpp37
-rw-r--r--src/plugins/cpptools/projectpart.h2
-rw-r--r--src/plugins/cpptools/searchsymbols.cpp1
-rw-r--r--src/plugins/cpptools/stringtable.cpp53
-rw-r--r--src/plugins/cvs/CMakeLists.txt1
-rw-r--r--src/plugins/cvs/cvs.pro4
-rw-r--r--src/plugins/cvs/cvs.qbs3
-rw-r--r--src/plugins/cvs/cvsplugin.cpp115
-rw-r--r--src/plugins/cvs/cvssettings.cpp100
-rw-r--r--src/plugins/cvs/cvssettings.h24
-rw-r--r--src/plugins/cvs/settingspage.cpp101
-rw-r--r--src/plugins/cvs/settingspage.ui144
-rw-r--r--src/plugins/debugger/CMakeLists.txt1
-rw-r--r--src/plugins/debugger/analyzer/analyzerrunconfigwidget.cpp106
-rw-r--r--src/plugins/debugger/analyzer/analyzerrunconfigwidget.h19
-rw-r--r--src/plugins/debugger/breakhandler.cpp19
-rw-r--r--src/plugins/debugger/cdb/cdb.pri3
-rw-r--r--src/plugins/debugger/cdb/cdbengine.cpp112
-rw-r--r--src/plugins/debugger/cdb/cdboptionspage.cpp137
-rw-r--r--src/plugins/debugger/cdb/cdboptionspage.h2
-rw-r--r--src/plugins/debugger/cdb/cdboptionspagewidget.ui152
-rw-r--r--src/plugins/debugger/commonoptionspage.cpp350
-rw-r--r--src/plugins/debugger/console/console.cpp65
-rw-r--r--src/plugins/debugger/console/console.h9
-rw-r--r--src/plugins/debugger/debugger.qbs1
-rw-r--r--src/plugins/debugger/debuggeractions.cpp1080
-rw-r--r--src/plugins/debugger/debuggeractions.h256
-rw-r--r--src/plugins/debugger/debuggercore.h15
-rw-r--r--src/plugins/debugger/debuggerdialogs.cpp20
-rw-r--r--src/plugins/debugger/debuggerengine.cpp66
-rw-r--r--src/plugins/debugger/debuggerinternalconstants.h2
-rw-r--r--src/plugins/debugger/debuggeritem.cpp25
-rw-r--r--src/plugins/debugger/debuggeritem.h3
-rw-r--r--src/plugins/debugger/debuggeritemmanager.cpp21
-rw-r--r--src/plugins/debugger/debuggerkitinformation.cpp30
-rw-r--r--src/plugins/debugger/debuggerplugin.cpp60
-rw-r--r--src/plugins/debugger/debuggerrunconfigurationaspect.cpp6
-rw-r--r--src/plugins/debugger/debuggerruncontrol.cpp26
-rw-r--r--src/plugins/debugger/debuggersourcepathmappingwidget.cpp178
-rw-r--r--src/plugins/debugger/debuggersourcepathmappingwidget.h60
-rw-r--r--src/plugins/debugger/debuggertooltipmanager.cpp2
-rw-r--r--src/plugins/debugger/disassembleragent.cpp4
-rw-r--r--src/plugins/debugger/gdb/gdbengine.cpp106
-rw-r--r--src/plugins/debugger/gdb/gdboptionspage.cpp373
-rw-r--r--src/plugins/debugger/lldb/lldbengine.cpp96
-rw-r--r--src/plugins/debugger/lldb/lldbengine.h3
-rw-r--r--src/plugins/debugger/logwindow.cpp13
-rw-r--r--src/plugins/debugger/moduleshandler.cpp3
-rw-r--r--src/plugins/debugger/pdb/pdbengine.cpp6
-rw-r--r--src/plugins/debugger/peripheralregisterhandler.cpp3
-rw-r--r--src/plugins/debugger/qml/qmlengine.cpp6
-rw-r--r--src/plugins/debugger/qml/qmlinspectoragent.cpp23
-rw-r--r--src/plugins/debugger/registerhandler.cpp3
-rw-r--r--src/plugins/debugger/registerpostmortemaction.cpp14
-rw-r--r--src/plugins/debugger/registerpostmortemaction.h10
-rw-r--r--src/plugins/debugger/sourcefileshandler.cpp3
-rw-r--r--src/plugins/debugger/stackhandler.cpp20
-rw-r--r--src/plugins/debugger/stackwindow.cpp2
-rw-r--r--src/plugins/debugger/terminal.cpp18
-rw-r--r--src/plugins/debugger/terminal.h4
-rw-r--r--src/plugins/debugger/threadshandler.cpp3
-rw-r--r--src/plugins/debugger/watchhandler.cpp64
-rw-r--r--src/plugins/debugger/watchwindow.cpp7
-rw-r--r--src/plugins/designer/formeditorplugin.cpp6
-rw-r--r--src/plugins/designer/formwindowfile.cpp38
-rw-r--r--src/plugins/designer/formwindowfile.h8
-rw-r--r--src/plugins/designer/qtcreatorintegration.cpp2
-rw-r--r--src/plugins/diffeditor/diffeditorconstants.h2
-rw-r--r--src/plugins/diffeditor/diffeditordocument.cpp24
-rw-r--r--src/plugins/diffeditor/diffeditordocument.h6
-rw-r--r--src/plugins/diffeditor/diffeditorplugin.cpp28
-rw-r--r--src/plugins/diffeditor/diffeditorwidgetcontroller.cpp2
-rw-r--r--src/plugins/docker/CMakeLists.txt15
-rw-r--r--src/plugins/docker/Docker.json.in19
-rw-r--r--src/plugins/docker/docker.pro19
-rw-r--r--src/plugins/docker/docker.qbs28
-rw-r--r--src/plugins/docker/docker_dependencies.pri7
-rw-r--r--src/plugins/docker/docker_global.h10
-rw-r--r--src/plugins/docker/dockerbuildstep.cpp166
-rw-r--r--src/plugins/docker/dockerbuildstep.h (renamed from src/plugins/projectexplorer/buildpropertiessettingspage.h)14
-rw-r--r--src/plugins/docker/dockerconstants.h (renamed from src/plugins/cpaster/settingspage.h)29
-rw-r--r--src/plugins/docker/dockerdevice.cpp921
-rw-r--r--src/plugins/docker/dockerdevice.h117
-rw-r--r--src/plugins/docker/dockerplugin.cpp79
-rw-r--r--src/plugins/docker/dockerplugin.h (renamed from src/plugins/mesonprojectmanager/settings/general/generalsettingspage.h)26
-rw-r--r--src/plugins/docker/dockerrunconfiguration.cpp126
-rw-r--r--src/plugins/docker/dockerrunconfiguration.h (renamed from src/plugins/cvs/settingspage.h)15
-rw-r--r--src/plugins/docker/dockersettings.cpp135
-rw-r--r--src/plugins/docker/dockersettings.h (renamed from src/plugins/qmlprofiler/qmlprofileroptionspage.h)32
-rw-r--r--src/plugins/fakevim/CMakeLists.txt1
-rw-r--r--src/plugins/fakevim/fakevim.pro3
-rw-r--r--src/plugins/fakevim/fakevim.qbs1
-rw-r--r--src/plugins/fakevim/fakevimactions.cpp209
-rw-r--r--src/plugins/fakevim/fakevimactions.h164
-rw-r--r--src/plugins/fakevim/fakevimhandler.cpp130
-rw-r--r--src/plugins/fakevim/fakevimoptions.ui443
-rw-r--r--src/plugins/fakevim/fakevimplugin.cpp304
-rw-r--r--src/plugins/genericprojectmanager/genericproject.cpp27
-rw-r--r--src/plugins/genericprojectmanager/genericproject.h1
-rw-r--r--src/plugins/git/CMakeLists.txt1
-rw-r--r--src/plugins/git/branchmodel.cpp2
-rw-r--r--src/plugins/git/branchview.cpp80
-rw-r--r--src/plugins/git/branchview.h13
-rw-r--r--src/plugins/git/changeselectiondialog.cpp4
-rw-r--r--src/plugins/git/changeselectiondialog.h4
-rw-r--r--src/plugins/git/gerrit/authenticationdialog.cpp3
-rw-r--r--src/plugins/git/gerrit/gerritmodel.cpp14
-rw-r--r--src/plugins/git/gerrit/gerritplugin.cpp15
-rw-r--r--src/plugins/git/gerrit/gerritserver.cpp36
-rw-r--r--src/plugins/git/git.pro3
-rw-r--r--src/plugins/git/git.qbs3
-rw-r--r--src/plugins/git/gitclient.cpp461
-rw-r--r--src/plugins/git/gitclient.h13
-rw-r--r--src/plugins/git/giteditor.cpp11
-rw-r--r--src/plugins/git/giteditor.h2
-rw-r--r--src/plugins/git/gitgrep.cpp20
-rw-r--r--src/plugins/git/gitplugin.cpp12
-rw-r--r--src/plugins/git/gitsettings.cpp189
-rw-r--r--src/plugins/git/gitsettings.h45
-rw-r--r--src/plugins/git/logchangedialog.cpp9
-rw-r--r--src/plugins/git/settingspage.cpp138
-rw-r--r--src/plugins/git/settingspage.ui214
-rw-r--r--src/plugins/glsleditor/glsleditorplugin.cpp2
-rw-r--r--src/plugins/help/generalsettingspage.cpp2
-rw-r--r--src/plugins/help/helpmanager.cpp3
-rw-r--r--src/plugins/help/helpplugin.cpp19
-rw-r--r--src/plugins/help/helpviewer.cpp2
-rw-r--r--src/plugins/help/localhelpmanager.cpp2
-rw-r--r--src/plugins/help/macwebkithelpviewer.mm5
-rw-r--r--src/plugins/help/searchwidget.cpp2
-rw-r--r--src/plugins/help/webenginehelpviewer.cpp4
-rw-r--r--src/plugins/imageviewer/imageview.cpp1
-rw-r--r--src/plugins/imageviewer/imageviewer.qbs5
-rw-r--r--src/plugins/imageviewer/imageviewerfile.cpp19
-rw-r--r--src/plugins/imageviewer/imageviewerfile.h6
-rw-r--r--src/plugins/incredibuild/cmakecommandbuilder.cpp2
-rw-r--r--src/plugins/ios/createsimulatordialog.cpp13
-rw-r--r--src/plugins/ios/createsimulatordialog.h6
-rw-r--r--src/plugins/ios/iosbuildstep.cpp10
-rw-r--r--src/plugins/ios/iosconfigurations.cpp23
-rw-r--r--src/plugins/ios/iosconfigurations.h4
-rw-r--r--src/plugins/ios/iosdeploystep.cpp2
-rw-r--r--src/plugins/ios/iosdsymbuildstep.cpp6
-rw-r--r--src/plugins/ios/iosprobe.cpp11
-rw-r--r--src/plugins/ios/iosrunner.cpp2
-rw-r--r--src/plugins/ios/iossettingswidget.cpp45
-rw-r--r--src/plugins/ios/iossettingswidget.h1
-rw-r--r--src/plugins/ios/iostoolhandler.cpp68
-rw-r--r--src/plugins/ios/simulatorcontrol.cpp209
-rw-r--r--src/plugins/ios/simulatorcontrol.h40
-rw-r--r--src/plugins/ios/simulatorinfomodel.cpp9
-rw-r--r--src/plugins/ios/simulatorinfomodel.h6
-rw-r--r--src/plugins/ios/simulatoroperationdialog.cpp2
-rw-r--r--src/plugins/languageclient/CMakeLists.txt1
-rw-r--r--src/plugins/languageclient/client.cpp202
-rw-r--r--src/plugins/languageclient/client.h26
-rw-r--r--src/plugins/languageclient/languageclient.pro6
-rw-r--r--src/plugins/languageclient/languageclient.qbs4
-rw-r--r--src/plugins/languageclient/languageclient_global.h1
-rw-r--r--src/plugins/languageclient/languageclientcompletionassist.cpp9
-rw-r--r--src/plugins/languageclient/languageclientformatter.cpp4
-rw-r--r--src/plugins/languageclient/languageclienthoverhandler.cpp2
-rw-r--r--src/plugins/languageclient/languageclientinterface.cpp14
-rw-r--r--src/plugins/languageclient/languageclientinterface.h8
-rw-r--r--src/plugins/languageclient/languageclientmanager.cpp22
-rw-r--r--src/plugins/languageclient/languageclientmanager.h1
-rw-r--r--src/plugins/languageclient/languageclientoutline.cpp2
-rw-r--r--src/plugins/languageclient/languageclientplugin.cpp23
-rw-r--r--src/plugins/languageclient/languageclientsettings.cpp4
-rw-r--r--src/plugins/languageclient/languageclientsettings.h4
-rw-r--r--src/plugins/languageclient/languageclientsymbolsupport.cpp73
-rw-r--r--src/plugins/languageclient/languageclientsymbolsupport.h20
-rw-r--r--src/plugins/languageclient/languageclientutils.cpp2
-rw-r--r--src/plugins/languageclient/locatorfilter.cpp38
-rw-r--r--src/plugins/languageclient/locatorfilter.h10
-rw-r--r--src/plugins/languageclient/lspinspector.cpp2
-rw-r--r--src/plugins/languageclient/progressmanager.cpp134
-rw-r--r--src/plugins/languageclient/progressmanager.h72
-rw-r--r--src/plugins/languageclient/semantichighlightsupport.cpp339
-rw-r--r--src/plugins/languageclient/semantichighlightsupport.h46
-rw-r--r--src/plugins/macros/macro.cpp2
-rw-r--r--src/plugins/macros/macrolocatorfilter.cpp2
-rw-r--r--src/plugins/macros/macromanager.cpp3
-rw-r--r--src/plugins/mcusupport/CMakeLists.txt1
-rw-r--r--src/plugins/mcusupport/McuSupport.json.in2
-rw-r--r--src/plugins/mcusupport/mcusupport.pro6
-rw-r--r--src/plugins/mcusupport/mcusupport.qbs2
-rw-r--r--src/plugins/mcusupport/mcusupportoptions.cpp490
-rw-r--r--src/plugins/mcusupport/mcusupportoptions.h58
-rw-r--r--src/plugins/mcusupport/mcusupportoptionspage.cpp62
-rw-r--r--src/plugins/mcusupport/mcusupportplugin.cpp29
-rw-r--r--src/plugins/mcusupport/mcusupportplugin.h1
-rw-r--r--src/plugins/mcusupport/mcusupportsdk.cpp186
-rw-r--r--src/plugins/mcusupport/mcusupportsdk.h2
-rw-r--r--src/plugins/mcusupport/mcusupportversiondetection.cpp151
-rw-r--r--src/plugins/mcusupport/mcusupportversiondetection.h98
-rw-r--r--src/plugins/mercurial/CMakeLists.txt1
-rw-r--r--src/plugins/mercurial/mercurial.pro4
-rw-r--r--src/plugins/mercurial/mercurial.qbs3
-rw-r--r--src/plugins/mercurial/mercurialclient.cpp79
-rw-r--r--src/plugins/mercurial/mercurialplugin.cpp23
-rw-r--r--src/plugins/mercurial/mercurialsettings.cpp82
-rw-r--r--src/plugins/mercurial/mercurialsettings.h14
-rw-r--r--src/plugins/mercurial/optionspage.cpp98
-rw-r--r--src/plugins/mercurial/optionspage.h42
-rw-r--r--src/plugins/mercurial/optionspage.ui182
-rw-r--r--src/plugins/mesonprojectmanager/CMakeLists.txt5
-rw-r--r--src/plugins/mesonprojectmanager/exewrappers/toolwrapper.h1
-rw-r--r--src/plugins/mesonprojectmanager/machinefiles/machinefilemanager.cpp3
-rw-r--r--src/plugins/mesonprojectmanager/mesonpluginconstants.h6
-rw-r--r--src/plugins/mesonprojectmanager/mesonprojectmanager.pro5
-rw-r--r--src/plugins/mesonprojectmanager/mesonprojectmanager.qbs5
-rw-r--r--src/plugins/mesonprojectmanager/mesonprojectplugin.cpp3
-rw-r--r--src/plugins/mesonprojectmanager/project/buildoptions/mesonbuildsettingswidget.cpp7
-rw-r--r--src/plugins/mesonprojectmanager/project/mesonbuildconfiguration.cpp2
-rw-r--r--src/plugins/mesonprojectmanager/project/mesonbuildsystem.cpp2
-rw-r--r--src/plugins/mesonprojectmanager/project/ninjabuildstep.cpp6
-rw-r--r--src/plugins/mesonprojectmanager/project/projecttree/mesonprojectnodes.cpp9
-rw-r--r--src/plugins/mesonprojectmanager/settings/general/generalsettingswidget.cpp55
-rw-r--r--src/plugins/mesonprojectmanager/settings/general/generalsettingswidget.ui57
-rw-r--r--src/plugins/mesonprojectmanager/settings/general/settings.cpp49
-rw-r--r--src/plugins/mesonprojectmanager/settings/general/settings.h67
-rw-r--r--src/plugins/mesonprojectmanager/settings/tools/kitaspect/toolkitaspectwidget.cpp10
-rw-r--r--src/plugins/mesonprojectmanager/settings/tools/kitaspect/toolkitaspectwidget.h15
-rw-r--r--src/plugins/mesonprojectmanager/settings/tools/toolssettingsaccessor.cpp3
-rw-r--r--src/plugins/modeleditor/editordiagramview.cpp4
-rw-r--r--src/plugins/modeleditor/modeldocument.cpp17
-rw-r--r--src/plugins/modeleditor/modeldocument.h7
-rw-r--r--src/plugins/modeleditor/modelsmanager.cpp5
-rw-r--r--src/plugins/nim/CMakeLists.txt2
-rw-r--r--src/plugins/nim/editor/nimtexteditorwidget.cpp2
-rw-r--r--src/plugins/nim/nim.pro5
-rw-r--r--src/plugins/nim/nim.qbs1
-rw-r--r--src/plugins/nim/nimconstants.h7
-rw-r--r--src/plugins/nim/nimplugin.cpp10
-rw-r--r--src/plugins/nim/project/nimblebuildstep.cpp45
-rw-r--r--src/plugins/nim/project/nimblebuildsystem.cpp16
-rw-r--r--src/plugins/nim/project/nimbletaskstep.cpp12
-rw-r--r--src/plugins/nim/project/nimcompilerbuildstep.cpp2
-rw-r--r--src/plugins/nim/project/nimtoolchainfactory.cpp4
-rw-r--r--src/plugins/nim/project/nimtoolchainfactory.h3
-rw-r--r--src/plugins/nim/settings/nimsettings.cpp84
-rw-r--r--src/plugins/nim/settings/nimsettings.h28
-rw-r--r--src/plugins/nim/settings/nimtoolssettingspage.cpp87
-rw-r--r--src/plugins/nim/settings/nimtoolssettingspage.h73
-rw-r--r--src/plugins/nim/settings/nimtoolssettingswidget.ui66
-rw-r--r--src/plugins/perforce/CMakeLists.txt1
-rw-r--r--src/plugins/perforce/perforce.pro4
-rw-r--r--src/plugins/perforce/perforce.qbs3
-rw-r--r--src/plugins/perforce/perforcechecker.cpp20
-rw-r--r--src/plugins/perforce/perforcechecker.h5
-rw-r--r--src/plugins/perforce/perforceplugin.cpp130
-rw-r--r--src/plugins/perforce/perforcesettings.cpp279
-rw-r--r--src/plugins/perforce/perforcesettings.h94
-rw-r--r--src/plugins/perforce/settingspage.cpp158
-rw-r--r--src/plugins/perforce/settingspage.ui228
-rw-r--r--src/plugins/perfprofiler/CMakeLists.txt1
-rw-r--r--src/plugins/perfprofiler/perfconfigeventsmodel.cpp18
-rw-r--r--src/plugins/perfprofiler/perfconfigwidget.cpp136
-rw-r--r--src/plugins/perfprofiler/perfconfigwidget.h15
-rw-r--r--src/plugins/perfprofiler/perfconfigwidget.ui135
-rw-r--r--src/plugins/perfprofiler/perfdatareader.cpp6
-rw-r--r--src/plugins/perfprofiler/perfprofiler.pro1
-rw-r--r--src/plugins/perfprofiler/perfprofiler.qbs1
-rw-r--r--src/plugins/perfprofiler/perfprofilerconstants.h15
-rw-r--r--src/plugins/perfprofiler/perfprofilerruncontrol.cpp4
-rw-r--r--src/plugins/perfprofiler/perfsettings.cpp155
-rw-r--r--src/plugins/perfprofiler/perfsettings.h31
-rw-r--r--src/plugins/plugins.pro3
-rw-r--r--src/plugins/plugins.qbs1
-rw-r--r--src/plugins/projectexplorer/CMakeLists.txt13
-rw-r--r--src/plugins/projectexplorer/abi.cpp20
-rw-r--r--src/plugins/projectexplorer/abstractprocessstep.cpp36
-rw-r--r--src/plugins/projectexplorer/abstractprocessstep.h6
-rw-r--r--src/plugins/projectexplorer/allprojectsfilter.cpp3
-rw-r--r--src/plugins/projectexplorer/applicationlauncher.cpp2
-rw-r--r--src/plugins/projectexplorer/buildaspects.cpp6
-rw-r--r--src/plugins/projectexplorer/buildconfiguration.cpp5
-rw-r--r--src/plugins/projectexplorer/buildpropertiessettings.cpp128
-rw-r--r--src/plugins/projectexplorer/buildpropertiessettings.h39
-rw-r--r--src/plugins/projectexplorer/buildpropertiessettingspage.cpp118
-rw-r--r--src/plugins/projectexplorer/buildstep.cpp5
-rw-r--r--src/plugins/projectexplorer/buildsteplist.cpp4
-rw-r--r--src/plugins/projectexplorer/buildsystem.cpp5
-rw-r--r--src/plugins/projectexplorer/buildsystem.h5
-rw-r--r--src/plugins/projectexplorer/clangparser.cpp39
-rw-r--r--src/plugins/projectexplorer/currentprojectfilter.cpp3
-rw-r--r--src/plugins/projectexplorer/customwizard/customwizard.cpp10
-rw-r--r--src/plugins/projectexplorer/customwizard/customwizardscriptgenerator.cpp15
-rw-r--r--src/plugins/projectexplorer/desktoprunconfiguration.cpp20
-rw-r--r--src/plugins/projectexplorer/devicesupport/desktopdevice.cpp5
-rw-r--r--src/plugins/projectexplorer/devicesupport/desktopdevice.h1
-rw-r--r--src/plugins/projectexplorer/devicesupport/desktopdeviceprocess.cpp2
-rw-r--r--src/plugins/projectexplorer/devicesupport/devicemanager.cpp104
-rw-r--r--src/plugins/projectexplorer/devicesupport/devicemanager.h1
-rw-r--r--src/plugins/projectexplorer/devicesupport/idevice.cpp94
-rw-r--r--src/plugins/projectexplorer/devicesupport/idevice.h27
-rw-r--r--src/plugins/projectexplorer/devicesupport/localprocesslist.cpp10
-rw-r--r--src/plugins/projectexplorer/environmentwidget.cpp41
-rw-r--r--src/plugins/projectexplorer/environmentwidget.h1
-rw-r--r--src/plugins/projectexplorer/extraabi.cpp2
-rw-r--r--src/plugins/projectexplorer/gccparser.cpp114
-rw-r--r--src/plugins/projectexplorer/gccparser.h1
-rw-r--r--src/plugins/projectexplorer/gcctoolchain.cpp133
-rw-r--r--src/plugins/projectexplorer/gcctoolchain.h5
-rw-r--r--src/plugins/projectexplorer/gcctoolchainfactories.h16
-rw-r--r--src/plugins/projectexplorer/jsonwizard/jsonwizard.cpp2
-rw-r--r--src/plugins/projectexplorer/jsonwizard/jsonwizard_test.cpp2
-rw-r--r--src/plugins/projectexplorer/jsonwizard/jsonwizardfactory.cpp7
-rw-r--r--src/plugins/projectexplorer/jsonwizard/jsonwizardfilegenerator.cpp2
-rw-r--r--src/plugins/projectexplorer/kit.cpp24
-rw-r--r--src/plugins/projectexplorer/kit.h7
-rw-r--r--src/plugins/projectexplorer/kitinformation.cpp328
-rw-r--r--src/plugins/projectexplorer/kitinformation.h44
-rw-r--r--src/plugins/projectexplorer/kitmanager.cpp68
-rw-r--r--src/plugins/projectexplorer/kitmanager.h27
-rw-r--r--src/plugins/projectexplorer/kitmanagerconfigwidget.cpp40
-rw-r--r--src/plugins/projectexplorer/kitmanagerconfigwidget.h1
-rw-r--r--src/plugins/projectexplorer/ldparser.cpp26
-rw-r--r--src/plugins/projectexplorer/linuxiccparser.cpp10
-rw-r--r--src/plugins/projectexplorer/localenvironmentaspect.cpp3
-rw-r--r--src/plugins/projectexplorer/makestep.cpp28
-rw-r--r--src/plugins/projectexplorer/makestep.h5
-rw-r--r--src/plugins/projectexplorer/miniprojecttargetselector.cpp34
-rw-r--r--src/plugins/projectexplorer/msvctoolchain.cpp111
-rw-r--r--src/plugins/projectexplorer/msvctoolchain.h9
-rw-r--r--src/plugins/projectexplorer/outputparser_test.cpp1
-rw-r--r--src/plugins/projectexplorer/processparameters.cpp12
-rw-r--r--src/plugins/projectexplorer/processparameters.h1
-rw-r--r--src/plugins/projectexplorer/project.cpp72
-rw-r--r--src/plugins/projectexplorer/project.h3
-rw-r--r--src/plugins/projectexplorer/projectconfiguration.cpp12
-rw-r--r--src/plugins/projectexplorer/projectconfiguration.h6
-rw-r--r--src/plugins/projectexplorer/projectexplorer.cpp180
-rw-r--r--src/plugins/projectexplorer/projectexplorer.h4
-rw-r--r--src/plugins/projectexplorer/projectexplorer.pro7
-rw-r--r--src/plugins/projectexplorer/projectexplorer.qbs14
-rw-r--r--src/plugins/projectexplorer/projectexplorer_dependencies.pri2
-rw-r--r--src/plugins/projectexplorer/projectexplorerconstants.h10
-rw-r--r--src/plugins/projectexplorer/projectnodes.cpp86
-rw-r--r--src/plugins/projectexplorer/projectnodes.h22
-rw-r--r--src/plugins/projectexplorer/projecttreewidget.cpp51
-rw-r--r--src/plugins/projectexplorer/projecttreewidget.h5
-rw-r--r--src/plugins/projectexplorer/runconfiguration.cpp22
-rw-r--r--src/plugins/projectexplorer/runconfiguration.h10
-rw-r--r--src/plugins/projectexplorer/runconfigurationaspects.cpp12
-rw-r--r--src/plugins/projectexplorer/runconfigurationaspects.h2
-rw-r--r--src/plugins/projectexplorer/runcontrol.cpp11
-rw-r--r--src/plugins/projectexplorer/session.cpp18
-rw-r--r--src/plugins/projectexplorer/showineditortaskhandler.cpp3
-rw-r--r--src/plugins/projectexplorer/target.cpp16
-rw-r--r--src/plugins/projectexplorer/target.h3
-rw-r--r--src/plugins/projectexplorer/task.cpp7
-rw-r--r--src/plugins/projectexplorer/task.h4
-rw-r--r--src/plugins/projectexplorer/taskwindow.cpp31
-rw-r--r--src/plugins/projectexplorer/testdata/generic-project/generic-project.cflags0
-rw-r--r--src/plugins/projectexplorer/testdata/generic-project/generic-project.config0
-rw-r--r--src/plugins/projectexplorer/testdata/generic-project/generic-project.creator1
-rw-r--r--src/plugins/projectexplorer/testdata/generic-project/generic-project.cxxflags0
-rw-r--r--src/plugins/projectexplorer/testdata/generic-project/generic-project.files1
-rw-r--r--src/plugins/projectexplorer/testdata/generic-project/generic-project.includes0
-rw-r--r--src/plugins/projectexplorer/testdata/generic-project/main.cpp1
-rw-r--r--src/plugins/projectexplorer/toolchain.cpp11
-rw-r--r--src/plugins/projectexplorer/toolchain.h4
-rw-r--r--src/plugins/projectexplorer/toolchainconfigwidget.cpp20
-rw-r--r--src/plugins/projectexplorer/toolchainoptionspage.cpp2
-rw-r--r--src/plugins/projectexplorer/toolchainsettingsaccessor.cpp17
-rw-r--r--src/plugins/python/pythonproject.cpp4
-rw-r--r--src/plugins/python/pythonrunconfiguration.cpp2
-rw-r--r--src/plugins/python/pythonsettings.cpp54
-rw-r--r--src/plugins/python/pythonutils.cpp42
-rw-r--r--src/plugins/qbsprojectmanager/qbsbuildstep.cpp22
-rw-r--r--src/plugins/qbsprojectmanager/qbsinstallstep.cpp3
-rw-r--r--src/plugins/qbsprojectmanager/qbskitinformation.cpp14
-rw-r--r--src/plugins/qbsprojectmanager/qbsnodes.cpp11
-rw-r--r--src/plugins/qbsprojectmanager/qbsprojectmanagerplugin.cpp19
-rw-r--r--src/plugins/qbsprojectmanager/qbsprojectmanagerplugin.h4
-rw-r--r--src/plugins/qbsprojectmanager/qbssettings.cpp2
-rw-r--r--src/plugins/qmakeprojectmanager/customwidgetwizard/plugingenerator.cpp10
-rw-r--r--src/plugins/qmakeprojectmanager/externaleditors.cpp24
-rw-r--r--src/plugins/qmakeprojectmanager/externaleditors.h6
-rw-r--r--src/plugins/qmakeprojectmanager/librarydetailscontroller.cpp2
-rw-r--r--src/plugins/qmakeprojectmanager/makefileparse.cpp12
-rw-r--r--src/plugins/qmakeprojectmanager/profileeditor.cpp6
-rw-r--r--src/plugins/qmakeprojectmanager/qmakebuildconfiguration.cpp24
-rw-r--r--src/plugins/qmakeprojectmanager/qmakebuildconfiguration.h11
-rw-r--r--src/plugins/qmakeprojectmanager/qmakekitinformation.cpp10
-rw-r--r--src/plugins/qmakeprojectmanager/qmakemakestep.cpp53
-rw-r--r--src/plugins/qmakeprojectmanager/qmakemakestep.h25
-rw-r--r--src/plugins/qmakeprojectmanager/qmakeparsernodes.cpp20
-rw-r--r--src/plugins/qmakeprojectmanager/qmakeprojectmanagerplugin.cpp23
-rw-r--r--src/plugins/qmakeprojectmanager/qmakesettings.cpp154
-rw-r--r--src/plugins/qmakeprojectmanager/qmakesettings.h29
-rw-r--r--src/plugins/qmakeprojectmanager/qmakestep.cpp70
-rw-r--r--src/plugins/qmakeprojectmanager/qmakestep.h2
-rw-r--r--src/plugins/qmakeprojectmanager/wizards/qtwizard.cpp4
-rw-r--r--src/plugins/qmldesigner/CMakeLists.txt8
-rw-r--r--src/plugins/qmldesigner/assetexporterplugin/assetexporter.cpp10
-rw-r--r--src/plugins/qmldesigner/assetexporterplugin/assetexporterview.cpp2
-rw-r--r--src/plugins/qmldesigner/assetexporterplugin/componentexporter.h2
-rw-r--r--src/plugins/qmldesigner/components/componentcore/changestyleaction.cpp4
-rw-r--r--src/plugins/qmldesigner/components/componentcore/componentcore.pri2
-rw-r--r--src/plugins/qmldesigner/components/componentcore/componentcore_constants.h6
-rw-r--r--src/plugins/qmldesigner/components/componentcore/crumblebar.cpp2
-rw-r--r--src/plugins/qmldesigner/components/componentcore/designeractionmanager.cpp26
-rw-r--r--src/plugins/qmldesigner/components/componentcore/designeractionmanagerview.cpp2
-rw-r--r--src/plugins/qmldesigner/components/componentcore/designeractionmanagerview.h2
-rw-r--r--src/plugins/qmldesigner/components/componentcore/formatoperation.cpp212
-rw-r--r--src/plugins/qmldesigner/components/componentcore/formatoperation.h (renamed from src/plugins/perforce/settingspage.h)35
-rw-r--r--src/plugins/qmldesigner/components/componentcore/modelnodeoperations.cpp2
-rw-r--r--src/plugins/qmldesigner/components/componentcore/qmldesignericonprovider.cpp18
-rw-r--r--src/plugins/qmldesigner/components/componentcore/theme.cpp6
-rw-r--r--src/plugins/qmldesigner/components/componentcore/theme.h20
-rw-r--r--src/plugins/qmldesigner/components/curveeditor/detail/graphicsview.cpp4
-rw-r--r--src/plugins/qmldesigner/components/curveeditor/detail/graphicsview.h2
-rw-r--r--src/plugins/qmldesigner/components/debugview/debugview.cpp5
-rw-r--r--src/plugins/qmldesigner/components/debugview/debugview.h2
-rw-r--r--src/plugins/qmldesigner/components/formeditor/abstractformeditortool.h3
-rw-r--r--src/plugins/qmldesigner/components/formeditor/formeditoritem.h16
-rw-r--r--src/plugins/qmldesigner/components/formeditor/formeditorscene.h4
-rw-r--r--src/plugins/qmldesigner/components/formeditor/resizecontroller.h6
-rw-r--r--src/plugins/qmldesigner/components/formeditor/rotationcontroller.h6
-rw-r--r--src/plugins/qmldesigner/components/itemlibrary/customfilesystemmodel.cpp437
-rw-r--r--src/plugins/qmldesigner/components/itemlibrary/itemlibrary.pri14
-rw-r--r--src/plugins/qmldesigner/components/itemlibrary/itemlibraryassetsdir.cpp89
-rw-r--r--src/plugins/qmldesigner/components/itemlibrary/itemlibraryassetsdir.h83
-rw-r--r--src/plugins/qmldesigner/components/itemlibrary/itemlibraryassetsdirsmodel.cpp90
-rw-r--r--src/plugins/qmldesigner/components/itemlibrary/itemlibraryassetsdirsmodel.h (renamed from src/plugins/qmldesigner/components/itemlibrary/itemlibraryresourceview.h)34
-rw-r--r--src/plugins/qmldesigner/components/itemlibrary/itemlibraryassetsfilesmodel.cpp73
-rw-r--r--src/plugins/qmldesigner/components/itemlibrary/itemlibraryassetsfilesmodel.h (renamed from src/plugins/android/adbcommandswidget.h)37
-rw-r--r--src/plugins/qmldesigner/components/itemlibrary/itemlibraryassetsiconprovider.cpp79
-rw-r--r--src/plugins/qmldesigner/components/itemlibrary/itemlibraryassetsiconprovider.h58
-rw-r--r--src/plugins/qmldesigner/components/itemlibrary/itemlibraryassetsmodel.cpp252
-rw-r--r--src/plugins/qmldesigner/components/itemlibrary/itemlibraryassetsmodel.h (renamed from src/plugins/qmldesigner/components/itemlibrary/customfilesystemmodel.h)63
-rw-r--r--src/plugins/qmldesigner/components/itemlibrary/itemlibraryresourceview.cpp204
-rw-r--r--src/plugins/qmldesigner/components/itemlibrary/itemlibraryview.cpp4
-rw-r--r--src/plugins/qmldesigner/components/itemlibrary/itemlibrarywidget.cpp165
-rw-r--r--src/plugins/qmldesigner/components/itemlibrary/itemlibrarywidget.h21
-rw-r--r--src/plugins/qmldesigner/components/navigator/navigatorview.cpp4
-rw-r--r--src/plugins/qmldesigner/components/navigator/navigatorview.h4
-rw-r--r--src/plugins/qmldesigner/components/pathtool/pathitem.h3
-rw-r--r--src/plugins/qmldesigner/components/propertyeditor/gradientpresetcustomlistmodel.cpp6
-rw-r--r--src/plugins/qmldesigner/components/propertyeditor/gradientpresetitem.cpp5
-rw-r--r--src/plugins/qmldesigner/components/propertyeditor/gradientpresetitem.h9
-rw-r--r--src/plugins/qmldesigner/components/propertyeditor/propertyeditorcontextobject.cpp31
-rw-r--r--src/plugins/qmldesigner/components/propertyeditor/propertyeditorcontextobject.h2
-rw-r--r--src/plugins/qmldesigner/components/propertyeditor/propertyeditorqmlbackend.cpp5
-rw-r--r--src/plugins/qmldesigner/components/propertyeditor/propertyeditorvalue.cpp8
-rw-r--r--src/plugins/qmldesigner/components/propertyeditor/propertyeditorview.cpp53
-rw-r--r--src/plugins/qmldesigner/components/richtexteditor/richtexteditor.cpp4
-rw-r--r--src/plugins/qmldesigner/components/stateseditor/stateseditorview.cpp6
-rw-r--r--src/plugins/qmldesigner/components/stateseditor/stateseditorview.h2
-rw-r--r--src/plugins/qmldesigner/components/stateseditor/stateseditorwidget.cpp10
-rw-r--r--src/plugins/qmldesigner/components/texteditor/texteditorwidget.cpp4
-rw-r--r--src/plugins/qmldesigner/components/timelineeditor/preseteditor.cpp6
-rw-r--r--src/plugins/qmldesigner/components/timelineeditor/timelinecontrols.cpp2
-rw-r--r--src/plugins/qmldesigner/components/timelineeditor/timelinegraphicsscene.cpp6
-rw-r--r--src/plugins/qmldesigner/components/timelineeditor/timelinepropertyitem.cpp6
-rw-r--r--src/plugins/qmldesigner/components/timelineeditor/timelineview.cpp27
-rw-r--r--src/plugins/qmldesigner/components/timelineeditor/timelinewidget.cpp11
-rw-r--r--src/plugins/qmldesigner/components/transitioneditor/transitioneditorwidget.cpp4
-rw-r--r--src/plugins/qmldesigner/designercore/filemanager/qmlrewriter.cpp77
-rw-r--r--src/plugins/qmldesigner/designercore/filemanager/qmlrewriter.h7
-rw-r--r--src/plugins/qmldesigner/designercore/include/abstractproperty.h4
-rw-r--r--src/plugins/qmldesigner/designercore/include/abstractview.h7
-rw-r--r--src/plugins/qmldesigner/designercore/include/basetexteditmodifier.h2
-rw-r--r--src/plugins/qmldesigner/designercore/include/bindingproperty.h6
-rw-r--r--src/plugins/qmldesigner/designercore/include/componenttextmodifier.h2
-rw-r--r--src/plugins/qmldesigner/designercore/include/forwardview.h9
-rw-r--r--src/plugins/qmldesigner/designercore/include/itemlibraryinfo.h2
-rw-r--r--src/plugins/qmldesigner/designercore/include/metainfo.h8
-rw-r--r--src/plugins/qmldesigner/designercore/include/model.h12
-rw-r--r--src/plugins/qmldesigner/designercore/include/modelnode.h14
-rw-r--r--src/plugins/qmldesigner/designercore/include/nodeabstractproperty.h6
-rw-r--r--src/plugins/qmldesigner/designercore/include/nodeinstance.h3
-rw-r--r--src/plugins/qmldesigner/designercore/include/nodeinstanceview.h7
-rw-r--r--src/plugins/qmldesigner/designercore/include/nodelistproperty.h187
-rw-r--r--src/plugins/qmldesigner/designercore/include/nodemetainfo.h4
-rw-r--r--src/plugins/qmldesigner/designercore/include/nodeproperty.h6
-rw-r--r--src/plugins/qmldesigner/designercore/include/plaintexteditmodifier.h19
-rw-r--r--src/plugins/qmldesigner/designercore/include/qml3dnode.h8
-rw-r--r--src/plugins/qmldesigner/designercore/include/qmlconnections.h4
-rw-r--r--src/plugins/qmldesigner/designercore/include/qmlitemnode.h3
-rw-r--r--src/plugins/qmldesigner/designercore/include/qmlobjectnode.h13
-rw-r--r--src/plugins/qmldesigner/designercore/include/qmlstate.h3
-rw-r--r--src/plugins/qmldesigner/designercore/include/qmltimeline.h2
-rw-r--r--src/plugins/qmldesigner/designercore/include/rewriterview.h5
-rw-r--r--src/plugins/qmldesigner/designercore/include/signalhandlerproperty.h6
-rw-r--r--src/plugins/qmldesigner/designercore/include/textmodifier.h6
-rw-r--r--src/plugins/qmldesigner/designercore/include/variantproperty.h6
-rw-r--r--src/plugins/qmldesigner/designercore/instances/nodeinstanceserverproxy.h4
-rw-r--r--src/plugins/qmldesigner/designercore/instances/nodeinstanceview.cpp65
-rw-r--r--src/plugins/qmldesigner/designercore/instances/puppetcreator.cpp13
-rw-r--r--src/plugins/qmldesigner/designercore/metainfo/itemlibraryinfo.cpp2
-rw-r--r--src/plugins/qmldesigner/designercore/metainfo/nodemetainfo.cpp77
-rw-r--r--src/plugins/qmldesigner/designercore/metainfo/storagecache.h335
-rw-r--r--src/plugins/qmldesigner/designercore/metainfo/storagecacheentry.h (renamed from src/plugins/autotest/gtest/gtestsettingspage.h)28
-rw-r--r--src/plugins/qmldesigner/designercore/metainfo/storagecachefwd.h (renamed from src/plugins/autotest/qtest/qttestsettingspage.h)26
-rw-r--r--src/plugins/qmldesigner/designercore/model/abstractview.cpp7
-rw-r--r--src/plugins/qmldesigner/designercore/model/basetexteditmodifier.cpp9
-rw-r--r--src/plugins/qmldesigner/designercore/model/componenttextmodifier.cpp4
-rw-r--r--src/plugins/qmldesigner/designercore/model/internalnode_p.h3
-rw-r--r--src/plugins/qmldesigner/designercore/model/internalnodeabstractproperty.h2
-rw-r--r--src/plugins/qmldesigner/designercore/model/internalnodelistproperty.cpp6
-rw-r--r--src/plugins/qmldesigner/designercore/model/internalnodelistproperty.h25
-rw-r--r--src/plugins/qmldesigner/designercore/model/model.cpp16
-rw-r--r--src/plugins/qmldesigner/designercore/model/model_p.h11
-rw-r--r--src/plugins/qmldesigner/designercore/model/modeltotextmerger.cpp15
-rw-r--r--src/plugins/qmldesigner/designercore/model/nodelistproperty.cpp96
-rw-r--r--src/plugins/qmldesigner/designercore/model/qml3dnode.cpp62
-rw-r--r--src/plugins/qmldesigner/designercore/model/qmlobjectnode.cpp16
-rw-r--r--src/plugins/qmldesigner/designercore/model/qmltextgenerator.cpp24
-rw-r--r--src/plugins/qmldesigner/designercore/model/qmltextgenerator.h13
-rw-r--r--src/plugins/qmldesigner/designercore/model/qmltimeline.cpp13
-rw-r--r--src/plugins/qmldesigner/designercore/model/rewriteactioncompressor.cpp10
-rw-r--r--src/plugins/qmldesigner/designercore/model/rewriteactioncompressor.h4
-rw-r--r--src/plugins/qmldesigner/designercore/model/rewriterview.cpp19
-rw-r--r--src/plugins/qmldesigner/designercore/model/variantproperty.cpp3
-rw-r--r--src/plugins/qmldesigner/designermcumanager.cpp14
-rw-r--r--src/plugins/qmldesigner/designersettings.cpp8
-rw-r--r--src/plugins/qmldesigner/designmodewidget.cpp3
-rw-r--r--src/plugins/qmldesigner/documentmanager.cpp2
-rw-r--r--src/plugins/qmldesigner/generateresource.cpp11
-rw-r--r--src/plugins/qmldesigner/qmldesignerplugin.cpp9
-rw-r--r--src/plugins/qmldesigner/qmldesignerplugin.qbs30
-rw-r--r--src/plugins/qmldesigner/qmldesignerunittestfiles.pri3
-rw-r--r--src/plugins/qmljseditor/qmljseditor.cpp8
-rw-r--r--src/plugins/qmljseditor/qmljseditorplugin.cpp5
-rw-r--r--src/plugins/qmljseditor/qmljsfindreferences.cpp3
-rw-r--r--src/plugins/qmljseditor/qmljsfindreferences.h3
-rw-r--r--src/plugins/qmljseditor/qmljssemantichighlighter.cpp11
-rw-r--r--src/plugins/qmljseditor/qmljssemantichighlighter.h2
-rw-r--r--src/plugins/qmljseditor/qmloutlinemodel.cpp3
-rw-r--r--src/plugins/qmljstools/qmljsbundleprovider.cpp9
-rw-r--r--src/plugins/qmljstools/qmljsmodelmanager.cpp6
-rw-r--r--src/plugins/qmljstools/qmljstools_test.cpp4
-rw-r--r--src/plugins/qmlpreview/qmlpreviewruncontrol.cpp2
-rw-r--r--src/plugins/qmlprofiler/CMakeLists.txt5
-rw-r--r--src/plugins/qmlprofiler/qmlprofiler.pro7
-rw-r--r--src/plugins/qmlprofiler/qmlprofiler.qbs5
-rw-r--r--src/plugins/qmlprofiler/qmlprofilerattachdialog.ui129
-rw-r--r--src/plugins/qmlprofiler/qmlprofilerconfigwidget.cpp64
-rw-r--r--src/plugins/qmlprofiler/qmlprofilerconfigwidget.ui71
-rw-r--r--src/plugins/qmlprofiler/qmlprofilerconstants.h4
-rw-r--r--src/plugins/qmlprofiler/qmlprofilerplugin.cpp3
-rw-r--r--src/plugins/qmlprofiler/qmlprofilerruncontrol.cpp3
-rw-r--r--src/plugins/qmlprofiler/qmlprofilersettings.cpp149
-rw-r--r--src/plugins/qmlprofiler/qmlprofilersettings.h40
-rw-r--r--src/plugins/qmlprofiler/qmlprofilertool.cpp14
-rw-r--r--src/plugins/qmlprofiler/tests/qmlprofilerconfigwidget_test.cpp96
-rw-r--r--src/plugins/qmlprofiler/tests/tests.pri2
-rw-r--r--src/plugins/qmlprojectmanager/qmlproject.cpp6
-rw-r--r--src/plugins/qmlprojectmanager/qmlprojectnodes.cpp3
-rw-r--r--src/plugins/qmlprojectmanager/qmlprojectrunconfiguration.cpp38
-rw-r--r--src/plugins/qnx/qnxanalyzesupport.cpp2
-rw-r--r--src/plugins/qnx/qnxconfiguration.cpp90
-rw-r--r--src/plugins/qnx/qnxconfiguration.h9
-rw-r--r--src/plugins/qnx/qnxconfigurationmanager.cpp2
-rw-r--r--src/plugins/qnx/qnxdebugsupport.cpp4
-rw-r--r--src/plugins/qnx/qnxdeviceprocess.cpp11
-rw-r--r--src/plugins/qnx/qnxdeviceprocesslist.cpp4
-rw-r--r--src/plugins/qnx/qnxdevicetester.cpp2
-rw-r--r--src/plugins/qnx/qnxqtversion.cpp5
-rw-r--r--src/plugins/qnx/qnxqtversion.h2
-rw-r--r--src/plugins/qnx/qnxrunconfiguration.cpp27
-rw-r--r--src/plugins/qnx/qnxrunconfiguration.h11
-rw-r--r--src/plugins/qnx/qnxtoolchain.cpp5
-rw-r--r--src/plugins/qnx/qnxtoolchain.h3
-rw-r--r--src/plugins/qnx/qnxutils.cpp53
-rw-r--r--src/plugins/qtsupport/baseqtversion.cpp217
-rw-r--r--src/plugins/qtsupport/baseqtversion.h3
-rw-r--r--src/plugins/qtsupport/exampleslistmodel.cpp2
-rw-r--r--src/plugins/qtsupport/profilereader.h4
-rw-r--r--src/plugins/qtsupport/qtbuildaspects.cpp37
-rw-r--r--src/plugins/qtsupport/qtbuildaspects.h2
-rw-r--r--src/plugins/qtsupport/qtkitinformation.cpp38
-rw-r--r--src/plugins/qtsupport/qtkitinformation.h14
-rw-r--r--src/plugins/qtsupport/qtoptionspage.cpp10
-rw-r--r--src/plugins/qtsupport/qtparser.cpp30
-rw-r--r--src/plugins/qtsupport/qtparser.h1
-rw-r--r--src/plugins/qtsupport/qtsupportconstants.h3
-rw-r--r--src/plugins/qtsupport/qtversioninfo.ui4
-rw-r--r--src/plugins/qtsupport/qtversionmanager.cpp6
-rw-r--r--src/plugins/remotelinux/genericdirectuploadservice.cpp4
-rw-r--r--src/plugins/remotelinux/makeinstallstep.cpp12
-rw-r--r--src/plugins/remotelinux/remotelinuxcustomrunconfiguration.cpp30
-rw-r--r--src/plugins/remotelinux/remotelinuxcustomrunconfiguration.h14
-rw-r--r--src/plugins/remotelinux/remotelinuxqmltoolingsupport.cpp2
-rw-r--r--src/plugins/remotelinux/remotelinuxrunconfiguration.cpp24
-rw-r--r--src/plugins/remotelinux/remotelinuxrunconfiguration.h11
-rw-r--r--src/plugins/remotelinux/remotelinuxx11forwardingaspect.cpp2
-rw-r--r--src/plugins/remotelinux/rsyncdeploystep.cpp6
-rw-r--r--src/plugins/remotelinux/sshkeydeployer.cpp2
-rw-r--r--src/plugins/resourceeditor/qrceditor/qrceditor.cpp2
-rw-r--r--src/plugins/resourceeditor/qrceditor/resourcefile.cpp4
-rw-r--r--src/plugins/resourceeditor/resourceeditorw.cpp30
-rw-r--r--src/plugins/resourceeditor/resourceeditorw.h6
-rw-r--r--src/plugins/resourceeditor/resourcenode.cpp2
-rw-r--r--src/plugins/scxmleditor/common/navigatorgraphicsview.cpp4
-rw-r--r--src/plugins/scxmleditor/plugin_interface/sceneutils.cpp4
-rw-r--r--src/plugins/scxmleditor/plugin_interface/transitionitem.cpp24
-rw-r--r--src/plugins/scxmleditor/scxmleditordocument.cpp21
-rw-r--r--src/plugins/scxmleditor/scxmleditordocument.h6
-rw-r--r--src/plugins/studiowelcome/examplecheckout.cpp4
-rw-r--r--src/plugins/studiowelcome/studiowelcomeplugin.cpp11
-rw-r--r--src/plugins/subversion/CMakeLists.txt1
-rw-r--r--src/plugins/subversion/settingspage.cpp114
-rw-r--r--src/plugins/subversion/settingspage.h42
-rw-r--r--src/plugins/subversion/settingspage.ui180
-rw-r--r--src/plugins/subversion/subversion.pro4
-rw-r--r--src/plugins/subversion/subversion.qbs3
-rw-r--r--src/plugins/subversion/subversionclient.cpp55
-rw-r--r--src/plugins/subversion/subversionclient.h2
-rw-r--r--src/plugins/subversion/subversionplugin.cpp57
-rw-r--r--src/plugins/subversion/subversionsettings.cpp123
-rw-r--r--src/plugins/subversion/subversionsettings.h25
-rw-r--r--src/plugins/texteditor/CMakeLists.txt2
-rw-r--r--src/plugins/texteditor/codeassist/assistproposalitem.cpp5
-rw-r--r--src/plugins/texteditor/codeassist/textdocumentmanipulator.cpp6
-rw-r--r--src/plugins/texteditor/codeassist/textdocumentmanipulator.h2
-rw-r--r--src/plugins/texteditor/codeassist/textdocumentmanipulatorinterface.h5
-rw-r--r--src/plugins/texteditor/codestylepool.cpp4
-rw-r--r--src/plugins/texteditor/colorscheme.cpp2
-rw-r--r--src/plugins/texteditor/fontsettings.cpp15
-rw-r--r--src/plugins/texteditor/fontsettingspage.cpp7
-rw-r--r--src/plugins/texteditor/formattexteditor.cpp23
-rw-r--r--src/plugins/texteditor/highlighter.cpp2
-rw-r--r--src/plugins/texteditor/highlightersettings.cpp15
-rw-r--r--src/plugins/texteditor/linenumberfilter.cpp1
-rw-r--r--src/plugins/texteditor/outlinefactory.cpp27
-rw-r--r--src/plugins/texteditor/outlinefactory.h4
-rw-r--r--src/plugins/texteditor/refactoringchanges.cpp16
-rw-r--r--src/plugins/texteditor/snippets/snippet.cpp375
-rw-r--r--src/plugins/texteditor/snippets/snippet.h29
-rw-r--r--src/plugins/texteditor/snippets/snippetoverlay.cpp181
-rw-r--r--src/plugins/texteditor/snippets/snippetoverlay.h78
-rw-r--r--src/plugins/texteditor/snippets/snippetparser.cpp (renamed from src/plugins/qmlprofiler/qmlprofilerconfigwidget.h)45
-rw-r--r--src/plugins/texteditor/snippets/snippetparser.h73
-rw-r--r--src/plugins/texteditor/snippets/snippetscollection.cpp10
-rw-r--r--src/plugins/texteditor/textdocument.cpp51
-rw-r--r--src/plugins/texteditor/textdocument.h14
-rw-r--r--src/plugins/texteditor/texteditor.cpp180
-rw-r--r--src/plugins/texteditor/texteditor.h8
-rw-r--r--src/plugins/texteditor/texteditor.pro8
-rw-r--r--src/plugins/texteditor/texteditor.qbs8
-rw-r--r--src/plugins/texteditor/texteditorconstants.cpp1
-rw-r--r--src/plugins/texteditor/texteditorconstants.h1
-rw-r--r--src/plugins/texteditor/texteditoroverlay.cpp124
-rw-r--r--src/plugins/texteditor/texteditoroverlay.h19
-rw-r--r--src/plugins/texteditor/texteditorsettings.cpp2
-rw-r--r--src/plugins/todo/todoplugin.cpp3
-rw-r--r--src/plugins/updateinfo/updateinfoplugin.cpp65
-rw-r--r--src/plugins/valgrind/CMakeLists.txt2
-rw-r--r--src/plugins/valgrind/callgrindengine.cpp10
-rw-r--r--src/plugins/valgrind/callgrindtool.cpp55
-rw-r--r--src/plugins/valgrind/memchecktool.cpp36
-rw-r--r--src/plugins/valgrind/suppressiondialog.cpp13
-rw-r--r--src/plugins/valgrind/valgrind.pro3
-rw-r--r--src/plugins/valgrind/valgrind.qbs2
-rw-r--r--src/plugins/valgrind/valgrindconfigwidget.cpp315
-rw-r--r--src/plugins/valgrind/valgrindconfigwidget.ui503
-rw-r--r--src/plugins/valgrind/valgrindengine.cpp8
-rw-r--r--src/plugins/valgrind/valgrindsettings.cpp808
-rw-r--r--src/plugins/valgrind/valgrindsettings.h230
-rw-r--r--src/plugins/vcsbase/CMakeLists.txt1
-rw-r--r--src/plugins/vcsbase/commonsettingspage.cpp144
-rw-r--r--src/plugins/vcsbase/commonsettingspage.ui181
-rw-r--r--src/plugins/vcsbase/commonvcssettings.cpp184
-rw-r--r--src/plugins/vcsbase/commonvcssettings.h49
-rw-r--r--src/plugins/vcsbase/nicknamedialog.cpp2
-rw-r--r--src/plugins/vcsbase/submiteditorfile.cpp22
-rw-r--r--src/plugins/vcsbase/submiteditorfile.h6
-rw-r--r--src/plugins/vcsbase/vcsbase.pro4
-rw-r--r--src/plugins/vcsbase/vcsbase.qbs3
-rw-r--r--src/plugins/vcsbase/vcsbaseclient.cpp99
-rw-r--r--src/plugins/vcsbase/vcsbaseclient.h37
-rw-r--r--src/plugins/vcsbase/vcsbaseclientsettings.cpp371
-rw-r--r--src/plugins/vcsbase/vcsbaseclientsettings.h74
-rw-r--r--src/plugins/vcsbase/vcsbasediffeditorcontroller.cpp7
-rw-r--r--src/plugins/vcsbase/vcsbasediffeditorcontroller.h10
-rw-r--r--src/plugins/vcsbase/vcsbaseeditorconfig.cpp79
-rw-r--r--src/plugins/vcsbase/vcsbaseeditorconfig.h10
-rw-r--r--src/plugins/vcsbase/vcsbaseplugin.cpp29
-rw-r--r--src/plugins/vcsbase/vcsbaseplugin.h15
-rw-r--r--src/plugins/vcsbase/vcsbasesubmiteditor.cpp64
-rw-r--r--src/plugins/vcsbase/vcsbasesubmiteditor.h9
-rw-r--r--src/plugins/vcsbase/vcscommand.cpp30
-rw-r--r--src/plugins/vcsbase/vcscommand.h12
-rw-r--r--src/plugins/vcsbase/vcsoutputwindow.cpp8
-rw-r--r--src/plugins/vcsbase/vcsplugin.cpp6
-rw-r--r--src/plugins/vcsbase/vcsplugin.h4
-rw-r--r--src/plugins/webassembly/webassemblytoolchain.cpp6
-rw-r--r--src/plugins/webassembly/webassemblytoolchain.h3
-rw-r--r--src/plugins/winrt/winrtpackagedeploymentstep.cpp4
-rw-r--r--src/qtcreatorplugin.pri2
-rw-r--r--src/shared/json/json.qbs2
-rw-r--r--src/shared/proparser/proparser.qbs2
-rw-r--r--src/shared/qtcreator_gui_pch.h4
-rw-r--r--src/shared/qtcreator_pch.h10
-rw-r--r--src/tools/clangbackend/source/clangjobs.cpp6
-rw-r--r--src/tools/clangbackend/source/clangtooltipinfocollector.cpp8
-rw-r--r--src/tools/clangbackend/source/commandlinearguments.cpp4
-rw-r--r--src/tools/clangbackend/source/cursor.cpp5
-rw-r--r--src/tools/clangbackend/source/cursor.h1
-rw-r--r--src/tools/clangbackend/source/tokeninfo.cpp8
-rw-r--r--src/tools/qml2puppet/qml2puppet.qbs6
-rw-r--r--src/tools/sdktool/CMakeLists.txt1
-rw-r--r--src/tools/sdktool/main.cpp1
-rw-r--r--src/tools/sdktool/sdktool.pro4
-rw-r--r--src/tools/sdktool/sdktool.qbs2
-rw-r--r--tests/auto/CMakeLists.txt2
-rw-r--r--tests/auto/android/CMakeLists.txt18
-rw-r--r--tests/auto/android/Test.avd/config.ini119
-rw-r--r--tests/auto/android/TestTablet.avd/config.ini119
-rw-r--r--tests/auto/android/tst_avdmanageroutputparser.cpp124
-rw-r--r--tests/auto/auto.pro1
-rw-r--r--tests/auto/auto.qbs1
-rw-r--r--tests/auto/debugger/dumpers.pro2
-rw-r--r--tests/auto/debugger/gdb.pro2
-rw-r--r--tests/auto/debugger/protocol.pro2
-rw-r--r--tests/auto/debugger/tst_dumpers.cpp27
-rw-r--r--tests/auto/languageserverprotocol/tst_languageserverprotocol.cpp123
-rw-r--r--tests/auto/qml/codemodel/check/SmurfNonRecursive.qml6
-rw-r--r--tests/auto/qml/codemodel/check/SmurfRecursive.qml5
-rw-r--r--tests/auto/qml/codemodel/check/tst_check.cpp48
-rw-r--r--tests/auto/qml/codemodel/importscheck/moduleMapping/MyControls/Oblong.qml4
-rw-r--r--tests/auto/qml/codemodel/importscheck/moduleMapping/MyControls/qmldir3
-rw-r--r--tests/auto/qml/codemodel/importscheck/moduleMapping/QtQuick/Controls/Button.qml4
-rw-r--r--tests/auto/qml/codemodel/importscheck/moduleMapping/QtQuick/Controls/qmldir3
-rw-r--r--tests/auto/qml/codemodel/importscheck/moduleMapping/importQtQuick.qml5
-rw-r--r--tests/auto/qml/codemodel/importscheck/tst_importscheck.cpp104
-rw-r--r--tests/auto/qml/qmldesigner/coretests/tst_testcore.cpp3
-rw-r--r--tests/auto/qml/qmldesigner/testview.cpp6
-rw-r--r--tests/auto/qml/qmldesigner/testview.h3
-rw-r--r--tests/auto/qml/reformatter/inline.qml8
-rw-r--r--tests/auto/qml/reformatter/jssyntax.js7
-rw-r--r--tests/auto/qml/reformatter/qmlreadonly.qml9
-rw-r--r--tests/auto/toolchaincache/CMakeLists.txt2
-rw-r--r--tests/auto/toolchaincache/toolchaincache.pro2
-rw-r--r--tests/auto/utils/CMakeLists.txt1
-rw-r--r--tests/auto/utils/fileutils/tst_fileutils.cpp276
-rw-r--r--tests/auto/utils/qtcprocess/CMakeLists.txt (renamed from tests/auto/qtcprocess/CMakeLists.txt)0
-rw-r--r--tests/auto/utils/qtcprocess/qtcprocess.pro (renamed from tests/auto/qtcprocess/qtcprocess.pro)2
-rw-r--r--tests/auto/utils/qtcprocess/qtcprocess.qbs (renamed from tests/auto/qtcprocess/qtcprocess.qbs)0
-rw-r--r--tests/auto/utils/qtcprocess/tst_qtcprocess.cpp (renamed from tests/auto/qtcprocess/tst_qtcprocess.cpp)410
-rw-r--r--tests/auto/utils/utils.pro1
-rw-r--r--tests/auto/utils/utils.qbs1
-rw-r--r--tests/manual/docker/Dockerfile21
-rwxr-xr-xtests/manual/docker/build.sh2
-rw-r--r--tests/manual/process/main.cpp10
-rw-r--r--tests/manual/process/mainwindow.cpp10
-rw-r--r--tests/manual/qml/testprojects/modulemapping/CMakeLists.txt7
-rw-r--r--tests/manual/qml/testprojects/modulemapping/MyControls/Button.qml5
-rw-r--r--tests/manual/qml/testprojects/modulemapping/MyControls/qmldir3
-rw-r--r--tests/manual/qml/testprojects/modulemapping/README.txt9
-rw-r--r--tests/manual/qml/testprojects/modulemapping/test.cc1
-rw-r--r--tests/manual/qml/testprojects/modulemapping/test.qml8
-rw-r--r--tests/manual/widgets/CMakeLists.txt1
-rw-r--r--tests/manual/widgets/common/themeselector.cpp8
-rw-r--r--tests/manual/widgets/common/themeselector.h4
-rw-r--r--tests/manual/widgets/tracing/CMakeLists.txt9
-rw-r--r--tests/manual/widgets/tracing/tracing.qbs16
-rw-r--r--tests/manual/widgets/tracing/tst_manual_widgets_tracing.cpp175
-rw-r--r--tests/manual/widgets/widgets.qbs1
-rw-r--r--tests/unit/mockup/coreplugin/icore.h15
-rw-r--r--tests/unit/mockup/qmldesigner/designercore/include/nodeinstanceview.h5
-rw-r--r--tests/unit/mockup/qmldesigner/designercore/include/rewriterview.h2
-rw-r--r--tests/unit/unittest/CMakeLists.txt2
-rw-r--r--tests/unit/unittest/abstractviewmock.h (renamed from src/plugins/autotest/catch/catchtestsettingspage.h)14
-rw-r--r--tests/unit/unittest/clangformat-test.cpp19
-rw-r--r--tests/unit/unittest/data/highlightingmarks.cpp2
-rw-r--r--tests/unit/unittest/gtest-creator-printing.cpp5
-rw-r--r--tests/unit/unittest/gtest-creator-printing.h2
-rw-r--r--tests/unit/unittest/mocksqlitestatement.h20
-rw-r--r--tests/unit/unittest/nodelistproperty-test.cpp520
-rw-r--r--tests/unit/unittest/readexporteddiagnostics-test.cpp6
-rw-r--r--tests/unit/unittest/refactoringengine-test.cpp4
-rw-r--r--tests/unit/unittest/sqlitedatabasemock.h1
-rw-r--r--tests/unit/unittest/sqlitestatement-test.cpp426
-rw-r--r--tests/unit/unittest/sqlitevalue-test.cpp4
-rw-r--r--tests/unit/unittest/storagecache-test.cpp521
-rw-r--r--tests/unit/unittest/tokenprocessor-test.cpp22
-rw-r--r--tests/unit/unittest/unittest.pro3
1388 files changed, 32491 insertions, 25648 deletions
diff --git a/.github/workflows/build_cmake.yml b/.github/workflows/build_cmake.yml
index 0fcdb68064..4e9f6f8e14 100644
--- a/.github/workflows/build_cmake.yml
+++ b/.github/workflows/build_cmake.yml
@@ -4,7 +4,7 @@ on: [push, pull_request]
env:
QT_VERSION: 5.15.2
- CLANG_VERSION: 110
+ CLANG_VERSION: 120
ELFUTILS_VERSION: 0.175
CMAKE_VERSION: 3.18.3
NINJA_VERSION: 1.10.1
@@ -35,7 +35,7 @@ jobs:
}
- {
name: "Ubuntu Latest GCC", artifact: "Linux",
- os: ubuntu-20.04,
+ os: ubuntu-latest,
cc: "gcc", cxx: "g++"
}
- {
@@ -286,7 +286,7 @@ jobs:
set(libclang "libclang-release_${clang_version}-based-windows-vs2019_32.7z")
endif()
elseif ("${{ runner.os }}" STREQUAL "Linux")
- set(libclang "libclang-release_${clang_version}-based-linux-Ubuntu20.04-gcc9.3-x86_64.7z")
+ set(libclang "libclang-release_${clang_version}-based-linux-Ubuntu18.04-gcc9.3-x86_64.7z")
elseif ("${{ runner.os }}" STREQUAL "macOS")
set(libclang "libclang-release_${clang_version}-based-mac.7z")
endif()
diff --git a/CMakeLists.txt b/CMakeLists.txt
index db494bc249..0e7aa764b2 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -27,6 +27,7 @@ qtc_handle_sccache_support()
option(WITH_TESTS "Build Tests" OFF)
add_feature_info("Build tests" ${WITH_TESTS} "")
option(WITH_DEBUG_CMAKE "Enabled CMake project debugging functionality (e.g. source file disk checking)" OFF)
+option(SHOW_BUILD_DATE "Show build date in about dialog" OFF)
# merge binary directories of sub projects into top level
set(QTC_MERGE_BINARY_DIR ON)
diff --git a/README.md b/README.md
index 8cc77302aa..6da0ba60ea 100644
--- a/README.md
+++ b/README.md
@@ -482,6 +482,17 @@ SQLite (https://www.sqlite.org) is in the Public Domain.
from Florian Loitsch which is licensed under the MIT License (see above).
Copyright © 2009 Florian Loitsch
+### Minitrace
+
+ Simple C/C++ library for producing JSON traces.
+
+ The sources can be found in:
+ * QtCreator/src/libs/3rdparty/minitrace/private
+ * https://github.com/hrydgard/minitrace
+
+ Copyright 2014 by Henrik Rydgård
+ Released under the MIT license.
+
### litehtml
The litehtml HTML/CSS rendering engine is used as a help viewer backend
diff --git a/cmake/QtCreatorAPI.cmake b/cmake/QtCreatorAPI.cmake
index 4e9e8f4c61..d2f4415ec4 100644
--- a/cmake/QtCreatorAPI.cmake
+++ b/cmake/QtCreatorAPI.cmake
@@ -13,6 +13,7 @@ set(IDE_APP_TARGET "${_IDE_APP_TARGET}") # The IDE application na
set(IDE_PLUGIN_PATH "${_IDE_PLUGIN_PATH}") # The IDE plugin path (relative to CMAKE_INSTALL_PREFIX).
set(IDE_LIBRARY_BASE_PATH "${_IDE_LIBRARY_BASE_PATH}") # The IDE library base path (relative to CMAKE_INSTALL_PREFIX).
set(IDE_LIBRARY_PATH "${_IDE_LIBRARY_PATH}") # The IDE library path (relative to CMAKE_INSTALL_PREFIX).
+set(IDE_LIBRARY_ARCHIVE_PATH "${_IDE_LIBRARY_ARCHIVE_PATH}") # The IDE library archive path (relative to CMAKE_INSTALL_PREFIX).
set(IDE_LIBEXEC_PATH "${_IDE_LIBEXEC_PATH}") # The IDE libexec path (relative to CMAKE_INSTALL_PREFIX).
set(IDE_DATA_PATH "${_IDE_DATA_PATH}") # The IDE data path (relative to CMAKE_INSTALL_PREFIX).
set(IDE_DOC_PATH "${_IDE_DOC_PATH}") # The IDE documentation path (relative to CMAKE_INSTALL_PREFIX).
@@ -249,7 +250,7 @@ function(add_qtc_library name)
INSTALL_RPATH "${_LIB_RPATH}"
RUNTIME_OUTPUT_DIRECTORY "${_output_binary_dir}/${_DESTINATION}"
LIBRARY_OUTPUT_DIRECTORY "${_output_binary_dir}/${IDE_LIBRARY_PATH}"
- ARCHIVE_OUTPUT_DIRECTORY "${_output_binary_dir}/${IDE_LIBRARY_PATH}"
+ ARCHIVE_OUTPUT_DIRECTORY "${_output_binary_dir}/${IDE_LIBRARY_ARCHIVE_PATH}"
${_arg_PROPERTIES}
)
enable_pch(${name})
@@ -289,7 +290,7 @@ function(add_qtc_library name)
DESTINATION "${IDE_LIBRARY_PATH}"
COMPONENT Devel EXCLUDE_FROM_ALL
ARCHIVE
- DESTINATION "${IDE_LIBRARY_PATH}"
+ DESTINATION "${IDE_LIBRARY_ARCHIVE_PATH}"
COMPONENT Devel EXCLUDE_FROM_ALL
OPTIONAL
)
@@ -585,9 +586,11 @@ endfunction()
function(extend_qtc_test target_name)
if (NOT (target_name IN_LIST __QTC_TESTS))
- message(FATAL_ERROR "extend_qtc_test: Unknown test target \"${name}\"")
+ message(FATAL_ERROR "extend_qtc_test: Unknown test target \"${target_name}\"")
+ endif()
+ if (TARGET ${target_name})
+ extend_qtc_target(${target_name} ${ARGN})
endif()
- extend_qtc_target(${target_name} ${ARGN})
endfunction()
function(add_qtc_executable name)
@@ -781,6 +784,12 @@ endfunction()
function(add_qtc_test name)
cmake_parse_arguments(_arg "GTEST" "TIMEOUT" "DEFINES;DEPENDS;INCLUDES;SOURCES;EXPLICIT_MOC;SKIP_AUTOMOC" ${ARGN})
+ if ($_arg_UNPARSED_ARGUMENTS)
+ message(FATAL_ERROR "add_qtc_test had unparsed arguments!")
+ endif()
+
+ update_cached_list(__QTC_TESTS "${name}")
+
foreach(dependency ${_arg_DEPENDS})
if (NOT TARGET ${dependency} AND NOT _arg_GTEST)
if (WITH_DEBUG_CMAKE)
@@ -790,12 +799,6 @@ function(add_qtc_test name)
endif()
endforeach()
- if ($_arg_UNPARSED_ARGUMENTS)
- message(FATAL_ERROR "add_qtc_test had unparsed arguments!")
- endif()
-
- update_cached_list(__QTC_TESTS "${name}")
-
set(TEST_DEFINES SRCDIR="${CMAKE_CURRENT_SOURCE_DIR}")
# relax cast requirements for tests
@@ -902,7 +905,18 @@ function(qtc_copy_to_builddir custom_target_name)
endfunction()
function(qtc_add_resources target resourceName)
- cmake_parse_arguments(rcc "" "PREFIX;LANG;BASE" "FILES;OPTIONS" ${ARGN})
+ cmake_parse_arguments(rcc "" "PREFIX;LANG;BASE" "FILES;OPTIONS;CONDITION" ${ARGN})
+ if (${_arg_UNPARSED_ARGUMENTS})
+ message(FATAL_ERROR "qtc_add_resources had unparsed arguments!")
+ endif()
+
+ if (DEFINED _arg_CONDITION AND NOT _arg_CONDITION)
+ return()
+ endif()
+
+ if(NOT TARGET ${target})
+ return()
+ endif()
string(REPLACE "/" "_" resourceName ${resourceName})
string(REPLACE "." "_" resourceName ${resourceName})
diff --git a/cmake/QtCreatorAPIInternal.cmake b/cmake/QtCreatorAPIInternal.cmake
index 45aa8246db..937ff17a9b 100644
--- a/cmake/QtCreatorAPIInternal.cmake
+++ b/cmake/QtCreatorAPIInternal.cmake
@@ -46,6 +46,7 @@ if (APPLE)
set(_IDE_DATA_PATH "${_IDE_OUTPUT_PATH}/Resources")
set(_IDE_DOC_PATH "${_IDE_OUTPUT_PATH}/Resources/doc")
set(_IDE_BIN_PATH "${_IDE_OUTPUT_PATH}/MacOS")
+ set(_IDE_LIBRARY_ARCHIVE_PATH "${_IDE_LIBRARY_PATH}")
set(_IDE_HEADER_INSTALL_PATH "${_IDE_DATA_PATH}/Headers/qtcreator")
set(_IDE_CMAKE_INSTALL_PATH "${_IDE_DATA_PATH}/lib/cmake")
@@ -60,6 +61,7 @@ elseif(WIN32)
set(_IDE_DATA_PATH "share/qtcreator")
set(_IDE_DOC_PATH "share/doc/qtcreator")
set(_IDE_BIN_PATH "bin")
+ set(_IDE_LIBRARY_ARCHIVE_PATH "${_IDE_BIN_PATH}")
set(_IDE_HEADER_INSTALL_PATH "include/qtcreator")
set(_IDE_CMAKE_INSTALL_PATH "lib/cmake")
@@ -75,6 +77,7 @@ else ()
set(_IDE_DATA_PATH "${CMAKE_INSTALL_DATAROOTDIR}/qtcreator")
set(_IDE_DOC_PATH "${CMAKE_INSTALL_DATAROOTDIR}/doc/qtcreator")
set(_IDE_BIN_PATH "${CMAKE_INSTALL_BINDIR}")
+ set(_IDE_LIBRARY_ARCHIVE_PATH "${_IDE_LIBRARY_PATH}")
set(_IDE_HEADER_INSTALL_PATH "include/qtcreator")
set(_IDE_CMAKE_INSTALL_PATH "lib/cmake")
diff --git a/cmake/QtCreatorIDEBranding.cmake b/cmake/QtCreatorIDEBranding.cmake
index c442988571..bcd788bc6f 100644
--- a/cmake/QtCreatorIDEBranding.cmake
+++ b/cmake/QtCreatorIDEBranding.cmake
@@ -1,6 +1,6 @@
-set(IDE_VERSION "4.15.1") # The IDE version.
-set(IDE_VERSION_COMPAT "4.15.0") # The IDE Compatibility version.
-set(IDE_VERSION_DISPLAY "4.15.1") # The IDE display version.
+set(IDE_VERSION "4.82.0") # The IDE version.
+set(IDE_VERSION_COMPAT "4.82.0") # The IDE Compatibility version.
+set(IDE_VERSION_DISPLAY "5.0.0-beta1") # The IDE display version.
set(IDE_COPYRIGHT_YEAR "2021") # The IDE current copyright year.
set(IDE_SETTINGSVARIANT "QtProject") # The IDE settings variation.
diff --git a/coin/instructions/common_environment.yaml b/coin/instructions/common_environment.yaml
index df8c69b387..535d69634b 100644
--- a/coin/instructions/common_environment.yaml
+++ b/coin/instructions/common_environment.yaml
@@ -13,7 +13,7 @@ instructions:
variableValue: "qt5compat qtbase qtdeclarative qtimageformats qtquick3d qtquickcontrols2 qtquicktimeline qtserialport qtshadertools qtsvg qttools qttranslations"
- type: EnvironmentVariable
variableName: LLVM_BASE_URL
- variableValue: http://master.qt.io/development_releases/prebuilt/libclang/libclang-release_110-based
+ variableValue: http://master.qt.io/development_releases/prebuilt/libclang/libclang-release_120-based
- type: Group
enable_if:
diff --git a/doc/qtcreator/images/qtcreator-mcu-options.png b/doc/qtcreator/images/qtcreator-mcu-options.png
index a5c6a4a8f1..4031311187 100644
--- a/doc/qtcreator/images/qtcreator-mcu-options.png
+++ b/doc/qtcreator/images/qtcreator-mcu-options.png
Binary files differ
diff --git a/doc/qtcreator/src/editors/creator-only/creator-clang-codemodel.qdoc b/doc/qtcreator/src/editors/creator-only/creator-clang-codemodel.qdoc
index 491c53cfd6..d190f3c97a 100644
--- a/doc/qtcreator/src/editors/creator-only/creator-clang-codemodel.qdoc
+++ b/doc/qtcreator/src/editors/creator-only/creator-clang-codemodel.qdoc
@@ -138,6 +138,10 @@
edit the value for the \uicontrol {Do not index files greater than}
check box. To index all files, deselect the check box.
+ \li To use clangd instead of the built-in code model for features such as
+ \e {Find References to Symbol}, check the \uicontrol {Use clangd} checkbox.
+ \note This is an experimental feature, which might not work reliably yet.
+
\li The \uicontrol {Diagnostic Configuration} field shows the Clang
checks to perform. Click the value of the field to open the
\uicontrol {Diagnostic Configurations} dialog, where you can
diff --git a/doc/qtcreator/src/mcu/creator-mcu-dev.qdoc b/doc/qtcreator/src/mcu/creator-mcu-dev.qdoc
index ff5b2d8c37..b6682931be 100644
--- a/doc/qtcreator/src/mcu/creator-mcu-dev.qdoc
+++ b/doc/qtcreator/src/mcu/creator-mcu-dev.qdoc
@@ -44,7 +44,7 @@
The toolchains are available for cross-compilation on Microsoft Windows,
Linux, and macOS. However, the Qt for MCU SDK is currently only available
- for Windows.
+ for Windows and Linux.
For a list of Qt for MCU reference implementations, see the
\l{Qt for MCUs - Supported Target Platforms}{Qt for MCUs} documentation.
@@ -54,7 +54,7 @@
To use \QC to develop QML applications for MCUs, you need the following:
\list
- \li Qt for MCU SDK (only available for Windows)
+ \li Qt for MCU SDK (only available for Windows and Linux)
\li \l{https://developer.arm.com/tools-and-software/open-source-software/developer-tools/gnu-toolchain/gnu-rm}
{GNU ARM Embedded Toolchain}
\endlist
@@ -120,14 +120,17 @@
\endlist
\li Select the
\uicontrol {Automatically create kits for all available targets on start}
- option to create kits automatically.
- \note You could also use \uicontrol {Create Kit} or
- \uicontrol{Remove Kit} to manually create or remove kits for the chosen
- target.
+ option to create kits automatically the next time Qt Creator is
+ started.
+ \note You could also use \uicontrol {Create Kit} to manually
+ create kits for the chosen target.
\li Select \uicontrol Apply to save the settings.
\endlist
- \note You must restart \QC if you chose to create kits automatically
- for all the available targets.
+
+ \note When updating to other versions of the Qt for MCUs SDK, \QC will
+ ask you if you want to replace the existing kits, or create new ones
+ alongside. This can also be done manually, for each individual target,
+ via \uicontrol {Update Kit} and \uicontrol {Create Kit}, respectively.
\section2 Adding MCU Devices
@@ -150,30 +153,23 @@
\li Select \uicontrol Apply to add the device.
\endlist
- \section2 Adding MCU Kits
-
- \note This optional step is not necessary if you have already
- set up the MCU SDK as outlined in \l{Specifying MCU Settings}.
+ \section2 Managing MCU Kits
- \QC automatically adds kits for all the available targets, if
- the
+ \QC automatically adds kits for all the available targets, if the
\uicontrol {Automatically create kits for all available targets on start}
- option is enabled under the \uicontrol MCU settings tab.
+ option is enabled under the \uicontrol MCU settings tab. You can also
+ create kits for individual targets manually, as outlined
+ in \l{Specifying MCU Settings}.
\image qtcreator-mcu-kit.png "MCU kits"
- To add kits, select \uicontrol Tools > \uicontrol Options > \uicontrol Kits
- > \uicontrol Add:
+ You can edit and/or remove individual kits in \uicontrol Tools >
+ \uicontrol Options > \uicontrol Kits.
- \list 1
- \li In the \uicontrol Name field, specify a name for the kit.
- \li In the \uicontrol {Device type} field, select
- \uicontrol {MCU}.
- \li In the \uicontrol Device field, select the MCU board for the kit.
- \li In the \uicontrol Compiler field, select the Arm GCC compiler for
- the kit.
- \li Select \uicontrol Apply to add the kit.
- \endlist
+ However, for adding new kits you should use the \uicontrol {Create Kit}
+ button in the {Qt for MCUs} settings tab. This method adds the paths to
+ the kit's toolkits and SDKs, and keeps them synchronized when selecting
+ \uicontrol Apply or \uicontrol OK.
\section1 Running Applications on MCUs
@@ -195,4 +191,27 @@
\li Select \uicontrol Run to specify run settings.
Usually, you can use the default settings.
\endlist
+
+ \section1 Supported Qt for MCUs SDKs
+
+ Since version 4.12.4, \QC supports version 1.3 and later of the Qt for MCUs SDK.
+ For older versions refer to the following table.
+
+ \table
+ \header
+ \li \QC version
+ \li Qt for MCUs SDK version
+ \row
+ \li 4.12.4 or later
+ \li 1.3 or later
+ \row
+ \li 4.12.2 or 4.12.3
+ \li 1.2
+ \row
+ \li 4.12.0 or 4.12.1
+ \li 1.1
+ \row
+ \li 4.11.x
+ \li 1.0
+ \endtable
*/
diff --git a/doc/qtcreator/src/overview/creator-acknowledgements.qdoc b/doc/qtcreator/src/overview/creator-acknowledgements.qdoc
index a559441a9d..28b967d8f9 100644
--- a/doc/qtcreator/src/overview/creator-acknowledgements.qdoc
+++ b/doc/qtcreator/src/overview/creator-acknowledgements.qdoc
@@ -830,6 +830,20 @@
from Florian Loitsch which is licensed under the MIT License (see above).
Copyright (C) 2009 Florian Loitsch
+ \li \b Minitrace
+
+ Simple C/C++ library for producing JSON traces.
+
+ The sources can be found in:
+ \list
+ \li \c QtCreator/src/libs/3rdparty/minitrace/private
+ \li \l https://github.com/hrydgard/minitrace
+ \endlist
+
+ Copyright 2014 by Henrik Rydg\unicode{0x00E5}rd.
+
+ \include license-mit.qdocinc
+
\li \b litehtml
The litehtml HTML/CSS rendering engine is used as a help viewer backend
diff --git a/doc/qtcreator/src/projects/creator-only/creator-build-settings-qmake.qdoc b/doc/qtcreator/src/projects/creator-only/creator-build-settings-qmake.qdoc
index eec535a688..2cf107f1ed 100644
--- a/doc/qtcreator/src/projects/creator-only/creator-build-settings-qmake.qdoc
+++ b/doc/qtcreator/src/projects/creator-only/creator-build-settings-qmake.qdoc
@@ -82,19 +82,16 @@
\section1 Compiling QML
- Since Qt 5.11, you can compile QML source code into the final binary. This
- improves the startup time of the application and eliminates the need to
- deploy QML files together with the application. For more information, see
+ You can compile QML source code into the final binary to improve the
+ startup time of the application and eliminate the need to deploy QML
+ files together with the application. For more information, see
\l{Ahead-of-Time Compilation}.
- \QC project wizard templates create Qt Quick projects that can be compiled,
+ \QC project wizard templates create Qt Quick projects that can be compiled
because they are set up to use the Qt Resource System. To compile QML code,
- select \uicontrol Enable in the \uicontrol {Qt Quick Compiler} field. To
+ select \uicontrol Enable in the \uicontrol {Use qmlcachegen} field. To
use default settings, select \uicontrol {Leave at Default}.
- \note In earlier Qt versions, this was a commercial feature. For more
- information, see \l{http://doc.qt.io/QtQuickCompiler/}{Qt Quick Compiler}.
-
\section1 qmake Build Steps
\QC builds qmake projects by running the \c make or \c nmake command from
diff --git a/doc/qtcreator/src/projects/creator-only/creator-projects-building.qdoc b/doc/qtcreator/src/projects/creator-only/creator-projects-building.qdoc
index e453b315db..b5a3b750e4 100644
--- a/doc/qtcreator/src/projects/creator-only/creator-projects-building.qdoc
+++ b/doc/qtcreator/src/projects/creator-only/creator-projects-building.qdoc
@@ -103,11 +103,10 @@
You can also use the \c cm filter in the \l {Searching with the Locator}
{locator}.
- To remove all build artifacts, select \uicontrol {Clean Project} or one
- of its variants.
+ To remove all build artifacts, select one of \uicontrol {Clean} menu commands.
To clean the build directory and then build the project, select
- \uicontrol {Rebuild Project} or one of its variants.
+ one of \uicontrol {Rebuild} menu commands.
To build and clean projects without dependencies, select the
\uicontrol {Build Without Dependencies},
diff --git a/doc/qtcreator/src/projects/creator-only/creator-projects-qt-versions.qdoc b/doc/qtcreator/src/projects/creator-only/creator-projects-qt-versions.qdoc
index 82e007c2ea..ff3bcbd36f 100644
--- a/doc/qtcreator/src/projects/creator-only/creator-projects-qt-versions.qdoc
+++ b/doc/qtcreator/src/projects/creator-only/creator-projects-qt-versions.qdoc
@@ -101,10 +101,10 @@
\li Select the Qt version to view and edit it.
- \li In the \uicontrol{Version name} field, edit the name that \QC
+ \li In the \uicontrol{Name} field, edit the name that \QC
suggests for the Qt version.
- \li In the \uicontrol{qmake location} field, you can change the qmake
+ \li In the \uicontrol{qmake path} field, you can change the qmake
location.
\li If the Qt version is for QNX, enter the path to your installed QNX SDK in the
diff --git a/doc/qtcreator/src/qtcreator-toc.qdoc b/doc/qtcreator/src/qtcreator-toc.qdoc
index e4fa3fdc18..2358c3e3d8 100644
--- a/doc/qtcreator/src/qtcreator-toc.qdoc
+++ b/doc/qtcreator/src/qtcreator-toc.qdoc
@@ -124,6 +124,7 @@
\li \l{Shapes}
\li \l{Text}
\li \l{Images}
+ \li \l{UI Controls}
\li \l{User Interaction Methods}
\li \l{Lists and Other Data Models}
\li \l{Animations}
diff --git a/doc/qtcreator/src/qtquick/library/qtquick-controls.qdoc b/doc/qtcreator/src/qtquick/library/qtquick-controls.qdoc
index 40cfee271c..31e9c028e3 100644
--- a/doc/qtcreator/src/qtquick/library/qtquick-controls.qdoc
+++ b/doc/qtcreator/src/qtquick/library/qtquick-controls.qdoc
@@ -26,15 +26,14 @@
/*!
\page quick-controls.html
\previouspage quick-images.html
- \nextpage quick-data-models.html
+ \nextpage quick-user-interaction-methods.html
- \title User Interaction Methods
+ \title UI Controls
- You can use a set of basic components to add interaction methods to UIs,
- such as performing actions by using a pointing device or the keyboard,
- or flicking the visible area of the screen horizontally or vertically.
- Further, you can use \l{Qt Quick Controls} components to inform users about
- the progress of the application or to gather input from users.
+ You can create instances of preset UI controls to inform users about
+ the progress of the application or to gather input from users. They are
+ available in \l Library > \uicontrol Components >
+ \uicontrol {Qt Quick Controls} > \uicontrol Controls.
\image qtquick-designer-qtquickcontrols-types.png "Qt Quick Controls components in Library"
@@ -46,172 +45,14 @@
\li \l {Selectors}
\li \l {Tab Bar}
\li \l {Tool Bar}
- \li \l {Summary of User Interaction Methods}
+ \li \l {Summary of UI Controls}
\endlist
- You can specify values for the properties of components in the
+ You can specify values for the properties of component instances in the
\l Properties view. Some properties are common to all components,
whereas some are common to particular types of controls. Some properties
- are only available for a particular component. The following sections
- describe the basic interaction methods, the controls, and their properties.
-
- \section1 Basic Interaction Methods
-
- Users can interact with applications by using pointing devices or the
- keyboard. If the content does not fit the visible area of the screen,
- it can be flicked horizontally or vertically.
-
- \section2 Mouse Area
-
- Signals and handlers are used to deliver mouse interactions. Specifically,
- you can use a \uicontrol {Mouse Area} component to define JavaScript
- callbacks (also called signal handlers), which accept mouse events within
- a defined area.
-
- A mouse area receives events within a defined area. One quick way to define
- this area is to \l{Setting Anchors and Margins}{anchor} the mouse area to
- its parent's area. If the parent is a \l {basic-rectangle}{Rectangle} (or
- any component that is derived from an \l {basic-item}{Item}), the mouse area
- will fill the area defined by the parent's dimensions. Alternatively, you
- can define an area smaller or larger than the parent. Several controls, such
- as \l {Button}{buttons}, contain a mouse area.
-
- A mouse area emits \l{Connecting Components to Signals}{signals} in response
- to different mouse events:
-
- \list
- \li \c canceled()
- \li \c clicked()
- \li \c doubleClicked()
- \li \c entered()
- \li \c exited()
- \li \c positionChanged()
- \li \c pressAndHold()
- \li \c pressed()
- \li \c released()
- \endlist
-
- \if defined(qtcreator)
- A more modern way of handling events from all pointing devices, including
- mouse and touchscreen, is via \l {Qt Quick Input Handlers}.
- \endif
-
- \section2 Focus Scope
-
- When a key is pressed or released, a key event is generated and delivered
- to the focused component. If no component has active focus, the key event
- is ignored. If the component with active focus accepts the key event,
- propagation stops. Otherwise the event is sent to the component's parent
- until the event is accepted, or the root component is reached and the event
- is ignored.
-
- A component has focus when the \uicontrol Focus property in the
- \uicontrol Advanced tab is set to \c true. However, for reusable
- or imported components, this is not sufficient, and you should use
- a \uicontrol {Focus Scope} component.
-
- Within each focus scope, one object may have focus enabled. If more
- than one component have it enabled, the last component to enable it
- will have the focus and the others are unset, similarly to when there
- are no focus scopes.
-
- When a focus scope receives active focus, the contained component with
- focus set (if any) also gets the active focus. If this component is
- also a focus scope, both the focus scope and the sub-focused component
- will have active focus.
-
- The \uicontrol {Focus Scope} component is not a visual component and
- therefore the properties of its children need to be exposed to the parent
- component of the focus scope. \l{Using Layouts}{Layouts} and
- \l{Using Positioners}{positioners} will use these visual and styling
- properties to create the layout.
-
- For more information, see \l {Keyboard Focus in Qt Quick}.
-
- \section2 Flickable
-
- \uicontrol Flickable places its children on a surface that can be dragged
- and flicked, causing the view onto the child components to scroll. This
- behavior forms the basis of components that are designed to show large
- numbers of child components, such as \uicontrol {List View} and
- \uicontrol {Grid View}. For more information, see \l{List and Grid Views}.
-
- In traditional user interfaces, views can be scrolled using standard
- controls, such as scroll bars and arrow buttons. In some situations, it
- is also possible to drag the view directly by pressing and holding a
- mouse button while moving the cursor. In touch-based user interfaces,
- this dragging action is often complemented with a flicking action, where
- scrolling continues after the user has stopped touching the view.
-
- The contents of a flickable component are not automatically clipped. If
- the component is not used as a full-screen component, consider selecting the
- \uicontrol Clip check box in the \uicontrol Visibility section.
-
- \image qtquick-designer-flickable-properties.png "Flickable properties"
-
- Users can interact with a flickable component if the \uicontrol Interactive
- property is set to \c true. Set it to \c false to temporarily disable
- flicking. This enables special interaction with the component's children.
- For example, you might want to freeze a flickable map while scrolling
- through a pop-up that is a child of the Flickable.
-
- The \uicontrol {Flick direction} field determines whether the view can be
- flicked horizontally or vertically. Select \uicontrol AutoFlickDirection
- to enable flicking vertically if the content height is not equal to height
- of the flickable and horizontally if the content width is not equal
- to the width of the flickable. Select \uicontrol AutoFlickIfNeeded if
- the content height or width is greater than that of the flickable.
-
- Specify the maximum velocity for flicking the view in pixels per second in
- the \uicontrol {Max. velocity} field. Specify the rate at which a flick
- will decelerate in the \uicontrol Decelerate field.
-
- The \uicontrol {Bounds movement} property determines whether the flickable
- will give a feeling that the edges of the view are soft, rather than a hard
- physical boundary. Select \uicontrol StopAtBounds for custom edge effects
- where the contents do not follow drags or flicks beyond the bounds of the
- flickable. Select \uicontrol FollowBoundsBehavior to have the contents
- follow drags or flicks beyond the bounds of the flickable depending on the
- value of the \uicontrol Behavior field.
-
- In the \uicontrol {Press delay} field, specify the time in milliseconds
- to delay delivering a press to children of a flickable. This can be useful
- when reacting to a press before a flicking action has undesirable effects.
- If the flickable is dragged or flicked before the delay times out,
- the press event will not be delivered. If the button is released
- within the timeout, both the press and release will be delivered.
-
- \note For nested flickables with press delay set, the press delay of
- outer flickables is overridden by the innermost flickable. If the drag
- exceeds the platform drag threshold, the press event will be delivered
- regardless of this property.
-
- The \uicontrol {Pixel aligned} property sets the alignment of
- \uicontrol {Content X} and \uicontrol {Content Y} to pixels (\c true)
- or subpixels (\c false). Enable it to optimize for still content or
- moving content with high constrast edges, such as one-pixel-wide lines,
- text, or vector graphics. Disable this property when optimizing for
- animation quality.
-
- If \uicontrol {Synchronous drag} is set to \c true, then when the mouse or
- touchpoint moves far enough to begin dragging the content, the content will
- jump, so that the content pixel which was under the cursor or touchpoint
- when pressed remains under that point. The default is \c false, which
- provides a smoother experience (no jump) at the cost of losing some of the
- drag distance at the beginning.
-
- The \uicontrol {Content size} field specifies the dimensions of the
- surface controlled by a flickable. Typically, set the values of the
- \uicontrol W and \uicontrol H fields to the combined size of the components
- placed in the flickable. You can set additional margins around the
- content in the \uicontrol Margins field.
-
- The \uicontrol Origin field specifies the origin of the content. It
- refers to the top-left position of the content regardless of layout
- direction. Usually, the \uicontrol X and \uicontrol Y values are set to 0.
- However, a \l{ListView}{List View} and \l {GridView}{Grid View}
- may have an arbitrary origin due to delegate size variation, or component
- insertion or removal outside the visible region.
+ are only available for a particular control. The following sections
+ describe the preset UI controls and their properties.
\section1 General Control Properties
@@ -270,9 +111,19 @@
\section2 Button
- \image qtquickcontrols2-button.gif "Button"
+ You can create an instance of \l Library > \uicontrol Components >
+ \uicontrol {Qt Quick Controls} > \uicontrol Controls > \uicontrol Button:
- \uicontrol Button can be pushed or clicked by users. Typically, buttons
+ \image qtquickcontrols2-button.gif "Qt Quick Controls - Button"
+
+ \if defined(qtdesignstudio)
+ Alternatively, you can use a wizard to create a \l{Creating Custom Controls}
+ {custom button}:
+
+ \image studio-custom-button.gif "Custom button"
+ \endif
+
+ A button can be pushed or clicked by users. Typically, buttons
are used to perform an action or to answer a question. For example, \e OK,
\e Apply, \e Cancel, \e Close, \e Yes, \e No, and \e Help.
@@ -314,9 +165,20 @@
\section2 Check Box
- \image qtquickcontrols2-checkbox.gif "Check box"
+ You can create instances of \l Library > \uicontrol Components >
+ \uicontrol {Qt Quick Controls} > \uicontrol Controls >
+ \uicontrol {Check Box}:
+
+ \image qtquickcontrols2-checkbox.gif "Check boxes"
- \uicontrol {Check Box} presents an option button that can be toggled on
+ \if defined(qtdesignstudio)
+ Alternatively, you can use a wizard to create \l{Creating Custom Controls}
+ {custom check boxes}:
+
+ \image studio-custom-check-box.gif "Custom check boxes"
+ \endif
+
+ A check box presents an option button that can be toggled on
(checked) or off (unchecked). Check boxes are typically used to select
one or more options from a set of options. For larger sets of options,
such as those in a list, consider using \uicontrol {Check Delegate} instead.
@@ -384,9 +246,19 @@
\section2 Switch
+ You can create an instance of \l Library > \uicontrol Components >
+ \uicontrol {Qt Quick Controls} > \uicontrol Controls > \uicontrol Switch:
+
\image qtquickcontrols2-switch.gif "Switch"
- \uicontrol Switch is an option button that can be dragged or toggled on
+ \if defined(qtdesignstudio)
+ Alternatively, you can use a wizard to create a \l{Creating Custom Controls}
+ {custom switch}:
+
+ \image studio-custom-switch.gif "Custom switch"
+ \endif
+
+ A switch is an option button that can be dragged or toggled on
(checked) or off (unchecked). Switches are typically used to select between
two states: \e on or \e off. For larger sets of options, such as those in a
list, consider using \uicontrol {Switch Delegate} instead.
@@ -529,9 +401,19 @@
\target slider-control
\section2 Slider and Dial
+ You can create an instance of \l Library > \uicontrol Components >
+ \uicontrol {Qt Quick Controls} > \uicontrol Controls > \uicontrol Slider:
+
\image qtquickcontrols2-slider.gif "Slider"
- \uicontrol Slider is used to select a value by sliding a handle along a
+ \if defined(qtdesignstudio)
+ Alternatively, you can use a wizard to create a \l{Creating Custom Controls}
+ {custom slider}:
+
+ \image studio-custom-slider.gif "Custom slider"
+ \endif
+
+ A slider is used to select a value by sliding a handle along a
track, whereas \uicontrol {Range Slider} is used to select a range
specified by two values, by sliding each handle along a track.
@@ -541,8 +423,18 @@
devices such as stereos or industrial equipment. It allows users to
specify a value within a range.
+ You can create an instance of \l Library > \uicontrol Components >
+ \uicontrol {Qt Quick Controls} > \uicontrol Controls > \uicontrol Dial:
+
\image qtquickcontrols2-dial-no-wrap.gif "Dial"
+ \if defined(qtdesignstudio)
+ Alternatively, you can use a wizard to create a \l{Creating Custom Controls}
+ {custom dial}:
+
+ \image studio-custom-dial.gif "Custom dial"
+ \endif
+
In the \uicontrol From and \uicontrol To fields, set the range of the
slider or dial. Set the value of the slide handle or dial in the
\uicontrol Value field. For a range slider, set the initial positions
@@ -583,9 +475,20 @@
\section2 Spin Box
+ You can create an instance of \l Library > \uicontrol Components >
+ \uicontrol {Qt Quick Controls} > \uicontrol Controls >
+ \uicontrol {Spin Box}:
+
\image qtquickcontrols2-spinbox.png "Spin Box"
- \uicontrol {Spin box} enables users to choose an integer value by clicking
+ \if defined(qtdesignstudio)
+ Alternatively, you can use a wizard to create a \l{Creating Custom Controls}
+ {custom spin box}:
+
+ \image studio-custom-spinbox.gif "Custom spin box"
+ \endif
+
+ A spin box enables users to choose an integer value by clicking
the up or down indicator buttons, or by pressing up or down on the keyboard.
Select the \uicontrol Editable check box to enable users to enter a text
value in the input field.
@@ -708,7 +611,7 @@
\section1 Styling Controls
- The UI controls can be \l {Styling Qt Quick Controls}{styled}.
+ The preset UI controls can be \l {Styling Qt Quick Controls}{styled}.
\uicontrol {Form Editor} reads the preferred style from a
configuration file (\c qtquickcontrols2.conf). To change the
style, select another style from the list on the main toolbar. This
@@ -748,135 +651,100 @@
tumbler, are provided by the \l {Qt Quick Extras} module.
\endif
- \section1 Summary of User Interaction Methods
+ \section1 Summary of UI Controls
- The following table lists the components that you can use to add interaction
- methods to UIs. The \e Location column contains the module where you can
- find the component in \l Library > \uicontrol Components. The \e MCU column
- indicates which components are supported on MCUs.
+ The following table lists preset UI controls with links to their developer
+ documentation. They are available in \l Library > \uicontrol Components >
+ \uicontrol {Qt Quick Controls} > \uicontrol Controls. The \e MCU column
+ indicates which controls are supported on MCUs.
\table
\header
\li Icon
\li Name
- \li Location
\li MCU
\li Purpose
\row
\li \inlineimage icons/busyindicator-icon16.png
\li \l [QtQuickControls]{BusyIndicator}{Busy Indicator}
- \li Qt Quick Controls
\li
\li Indicates activity while content is being loaded.
\row
\li \inlineimage icons/button-icon16.png
\li \l [QtQuickControls]{Button}
- \li Qt Quick Controls
\li \inlineimage ok
\li A push button that you can associate with an action.
\row
\li \inlineimage icons/checkbox-icon16.png
\li \l [QtQuickControls]{CheckBox}{Check Box}
- \li Qt Quick Controls
\li \inlineimage ok
\li An option button that can be toggled on (checked) or off
(unchecked).
\row
\li \inlineimage icons/checkbox-icon16.png
\li \l [QtQuickControls]{CheckDelegate}{Check Delegate}
- \li Qt Quick Controls
\li
\li An item delegate that can be toggled on (checked) or off
(unchecked).
\row
\li \inlineimage icons/combobox-icon16.png
\li \l [QtQuickControls]{ComboBox}{Combo Box}
- \li Qt Quick Controls
\li
\li A combined button and popup list that is populated by using a data
model.
\row
\li \inlineimage icons/delaybutton-icon16.png
\li \l [QtQuickControls]{DelayButton}{Delay Button}
- \li Qt Quick Controls
\li
\li An option button that is triggered when held down long enough.
\row
\li \inlineimage icons/dial-icon16.png
\li \l [QtQuickControls]{Dial}
- \li Qt Quick Controls
\li \inlineimage ok
\li A circular dial that is rotated to set a value.
\row
- \li \inlineimage flickable-icon16.png
- \li \l [QML]{Flickable}
- \li Default Components - Basic
- \li \inlineimage ok
- \li Items can be flicked horizontally or vertically.
- \row
- \li \inlineimage focusscope-icon16.png
- \li \l{FocusScope}{Focus Scope}
- \li Default Components - Basic
- \li
- \li Assists in keyboard focus handling when building reusable QML
- components.
- \row
- \li \inlineimage mouse-area-icon16.png
- \li \l [QtQuick]{MouseArea}{Mouse Area}
- \li Default Components - Basic
- \li \inlineimage ok
- \li Enables simple mouse handling.
- \row
\li \inlineimage icons/pageindicator-icon16.png
\li \l [QtQuickControls]{PageIndicator}{Page Indicator}
- \li Qt Quick Controls
\li
\li Indicates the indicate the currently active page in a container of
multiple pages.
\row
\li \inlineimage icons/progressbar-icon16.png
\li \l [QtQuickControls]{ProgressBar}{Progress Bar}
- \li Qt Quick Controls
\li \inlineimage ok
\li Indicates the progress of an operation.
\row
\li \inlineimage icons/radiobutton-icon16.png
\li \l [QtQuickControls]{RadioButton}{Radio Button}
- \li Qt Quick Controls
\li \inlineimage ok
\li An option button that can be switched on (checked) or off
(unchecked).
\row
\li \inlineimage icons/radiobutton-icon16.png
\li \l [QtQuickControls]{RadioDelegate}{Radio Delegate}
- \li Qt Quick Controls
\li
\li An item delegate that can be toggled on (checked) or off
(unchecked).
\row
\li \inlineimage icons/rangeslider-icon16.png
\li \l [QtQuickControls]{RangeSlider}{Range Slider}
- \li Qt Quick Controls
\li
\li Enables users to select a range of values by sliding two handles
along a track.
\row
\li \inlineimage icons/roundbutton-icon16.png
\li \l [QtQuickControls]{RoundButton}{Round Button}
- \li Qt Quick Controls
\li
\li A push button with rounded corners that you can associate with an
action.
\row
\li \inlineimage icons/slider-icon16.png
\li \l [QtQuickControls]{Slider}
- \li Qt Quick Controls
\li \inlineimage ok
\li Enables users to select a value by sliding a handle along a track.
\row
\li \inlineimage icons/spinbox-icon16.png
\li \l [QtQuickControls]{SpinBox}{Spin Box}
- \li Qt Quick Controls
\li
\li Enables users to specify a value by clicking the up or down buttons,
by pressing up or down on the keyboard, or by entering a value in
@@ -884,54 +752,46 @@
\row
\li \inlineimage icons/switch-icon16.png
\li \l [QtQuickControls]{Switch}
- \li Qt Quick Controls
\li \inlineimage ok
\li An option button that can be toggled on or off.
\row
\li \inlineimage icons/switch-icon16.png
\li \l [QtQuickControls]{SwitchDelegate}{Switch Delegate}
- \li Qt Quick Controls
\li
\li An item delegate with a switch indicator that can be toggled on or
off.
\row
\li \inlineimage icons/toolbar-icon16.png
\li \l [QtQuickControls] {TabBar}{Tab Bar}
- \li Qt Quick Controls
\li
\li Enables users to switch between different views or subtasks.
\row
\li \inlineimage icons/toolbutton-icon16.png
\li \l [QtQuickControls]{TabButton}{Tab Button}
- \li Qt Quick Controls
\li
\li A button that is functionally similar to \uicontrol Button, but
provides a look that is more suitable for a \uicontrol {Tab Bar}.
\row
\li \inlineimage icons/toolbar-icon16.png
\li \l [QtQuickControls]{ToolBar}{Tool Bar}
- \li Qt Quick Controls
\li
\li A container of application-wide and context sensitive actions and
controls, such as navigation buttons and search fields.
\row
\li \inlineimage icons/toolbutton-icon16.png
\li \l [QtQuickControls]{ToolButton}{Tool Button}
- \li Qt Quick Controls
\li
\li A button that is functionally similar to \uicontrol Button, but
provides a look that is more suitable for a \uicontrol {Tool Bar}.
\row
\li \inlineimage icons/toolseparator-icon16.png
\li \l [QtQuickControls]{ToolSeparator}{Tool Separator}
- \li Qt Quick Controls
\li
\li Separates a group of items from adjacent items on a
\uicontrol {Tool Bar}.
\row
\li \inlineimage icons/tumbler-icon16.png
\li \l [QtQuickControls]{Tumbler}
- \li Qt Quick Controls
\li
\li A spinnable wheel of items that can be selected.
\endtable
diff --git a/doc/qtcreator/src/qtquick/library/qtquick-data-models.qdoc b/doc/qtcreator/src/qtquick/library/qtquick-data-models.qdoc
index 894ca4ac85..8ec8aaf895 100644
--- a/doc/qtcreator/src/qtquick/library/qtquick-data-models.qdoc
+++ b/doc/qtcreator/src/qtquick/library/qtquick-data-models.qdoc
@@ -25,7 +25,7 @@
/*!
\page quick-data-models.html
- \previouspage quick-controls.html
+ \previouspage quick-user-interaction-methods.html
\if defined(qtdesignstudio)
\nextpage quick-2d-effects.html
\else
diff --git a/doc/qtcreator/src/qtquick/library/qtquick-user-interaction-methods.qdoc b/doc/qtcreator/src/qtquick/library/qtquick-user-interaction-methods.qdoc
new file mode 100644
index 0000000000..80bc3c3828
--- /dev/null
+++ b/doc/qtcreator/src/qtquick/library/qtquick-user-interaction-methods.qdoc
@@ -0,0 +1,237 @@
+/****************************************************************************
+**
+** Copyright (C) 2021 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the Qt Creator documentation.
+**
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU Free Documentation License Usage
+** Alternatively, this file may be used under the terms of the GNU Free
+** Documentation License version 1.3 as published by the Free Software
+** Foundation and appearing in the file included in the packaging of
+** this file. Please review the following information to ensure
+** the GNU Free Documentation License version 1.3 requirements
+** will be met: https://www.gnu.org/licenses/fdl-1.3.html.
+**
+****************************************************************************/
+
+/*!
+ \page quick-user-interaction-methods.html
+ \previouspage quick-controls.html
+ \nextpage quick-data-models.html
+
+ \title User Interaction Methods
+
+ You can create instances of preset basic components to add interaction
+ methods to UIs, such as performing actions by using a pointing device or
+ the keyboard, or flicking the visible area of the screen horizontally or
+ vertically. They are availabe in \l Library > \uicontrol Components >
+ \uicontrol {Default Components} > \uicontrol Basic.
+
+ In addition, you can create instances of preset \l{UI Controls} to inform
+ users about the progress of the application or to gather input from users.
+
+ The following basic components are available for user interaction:
+
+ \list
+ \li \l {Mouse Area}
+ \li \l {Focus Scope}
+ \li \l {Flickable}
+ \li \l {Summary of Basic Interaction Methods}
+ \endlist
+
+ You can specify values for the properties of component instances in the
+ \l Properties view.
+
+ \section1 Mouse Area
+
+ Signals and handlers are used to deliver mouse interactions. Specifically,
+ you can use a \uicontrol {Mouse Area} component to define JavaScript
+ callbacks (also called signal handlers), which accept mouse events within
+ a defined area.
+
+ A mouse area receives events within a defined area. One quick way to define
+ this area is to \l{Setting Anchors and Margins}{anchor} the mouse area to
+ its parent's area. If the parent is a \l {basic-rectangle}{Rectangle} (or
+ any component that is derived from an \l {basic-item}{Item}), the mouse area
+ will fill the area defined by the parent's dimensions. Alternatively, you
+ can define an area smaller or larger than the parent. Several controls, such
+ as \l {Button}{buttons}, contain a mouse area.
+
+ A mouse area emits \l{Connecting Components to Signals}{signals} in response
+ to different mouse events:
+
+ \list
+ \li \c canceled()
+ \li \c clicked()
+ \li \c doubleClicked()
+ \li \c entered()
+ \li \c exited()
+ \li \c positionChanged()
+ \li \c pressAndHold()
+ \li \c pressed()
+ \li \c released()
+ \endlist
+
+ \if defined(qtcreator)
+ A more modern way of handling events from all pointing devices, including
+ mouse and touchscreen, is via \l {Qt Quick Input Handlers}.
+ \endif
+
+ \section1 Focus Scope
+
+ When a key is pressed or released, a key event is generated and delivered
+ to the focused component. If no component has active focus, the key event
+ is ignored. If the component with active focus accepts the key event,
+ propagation stops. Otherwise the event is sent to the component's parent
+ until the event is accepted, or the root component is reached and the event
+ is ignored.
+
+ A component has focus when the \uicontrol Focus property in the
+ \uicontrol Advanced tab is set to \c true. However, for reusable
+ or imported components, this is not sufficient, and you should use
+ a \uicontrol {Focus Scope} component.
+
+ Within each focus scope, one object may have focus enabled. If more
+ than one component have it enabled, the last component to enable it
+ will have the focus and the others are unset, similarly to when there
+ are no focus scopes.
+
+ When a focus scope receives active focus, the contained component with
+ focus set (if any) also gets the active focus. If this component is
+ also a focus scope, both the focus scope and the sub-focused component
+ will have active focus.
+
+ The \uicontrol {Focus Scope} component is not a visual component and
+ therefore the properties of its children need to be exposed to the parent
+ component of the focus scope. \l{Using Layouts}{Layouts} and
+ \l{Using Positioners}{positioners} will use these visual and styling
+ properties to create the layout.
+
+ For more information, see \l {Keyboard Focus in Qt Quick}.
+
+ \section1 Flickable
+
+ \uicontrol Flickable places its children on a surface that can be dragged
+ and flicked, causing the view onto the child components to scroll. This
+ behavior forms the basis of components that are designed to show large
+ numbers of child components, such as \uicontrol {List View} and
+ \uicontrol {Grid View}. For more information, see \l{List and Grid Views}.
+
+ In traditional user interfaces, views can be scrolled using standard
+ controls, such as scroll bars and arrow buttons. In some situations, it
+ is also possible to drag the view directly by pressing and holding a
+ mouse button while moving the cursor. In touch-based user interfaces,
+ this dragging action is often complemented with a flicking action, where
+ scrolling continues after the user has stopped touching the view.
+
+ The contents of a flickable component are not automatically clipped. If
+ the component is not used as a full-screen component, consider selecting the
+ \uicontrol Clip check box in the \uicontrol Visibility section.
+
+ \image qtquick-designer-flickable-properties.png "Flickable properties"
+
+ Users can interact with a flickable component if the \uicontrol Interactive
+ property is set to \c true. Set it to \c false to temporarily disable
+ flicking. This enables special interaction with the component's children.
+ For example, you might want to freeze a flickable map while scrolling
+ through a pop-up that is a child of the Flickable.
+
+ The \uicontrol {Flick direction} field determines whether the view can be
+ flicked horizontally or vertically. Select \uicontrol AutoFlickDirection
+ to enable flicking vertically if the content height is not equal to height
+ of the flickable and horizontally if the content width is not equal
+ to the width of the flickable. Select \uicontrol AutoFlickIfNeeded if
+ the content height or width is greater than that of the flickable.
+
+ Specify the maximum velocity for flicking the view in pixels per second in
+ the \uicontrol {Max. velocity} field. Specify the rate at which a flick
+ will decelerate in the \uicontrol Decelerate field.
+
+ The \uicontrol {Bounds movement} property determines whether the flickable
+ will give a feeling that the edges of the view are soft, rather than a hard
+ physical boundary. Select \uicontrol StopAtBounds for custom edge effects
+ where the contents do not follow drags or flicks beyond the bounds of the
+ flickable. Select \uicontrol FollowBoundsBehavior to have the contents
+ follow drags or flicks beyond the bounds of the flickable depending on the
+ value of the \uicontrol Behavior field.
+
+ In the \uicontrol {Press delay} field, specify the time in milliseconds
+ to delay delivering a press to children of a flickable. This can be useful
+ when reacting to a press before a flicking action has undesirable effects.
+ If the flickable is dragged or flicked before the delay times out,
+ the press event will not be delivered. If the button is released
+ within the timeout, both the press and release will be delivered.
+
+ \note For nested flickables with press delay set, the press delay of
+ outer flickables is overridden by the innermost flickable. If the drag
+ exceeds the platform drag threshold, the press event will be delivered
+ regardless of this property.
+
+ The \uicontrol {Pixel aligned} property sets the alignment of
+ \uicontrol {Content X} and \uicontrol {Content Y} to pixels (\c true)
+ or subpixels (\c false). Enable it to optimize for still content or
+ moving content with high constrast edges, such as one-pixel-wide lines,
+ text, or vector graphics. Disable this property when optimizing for
+ animation quality.
+
+ If \uicontrol {Synchronous drag} is set to \c true, then when the mouse or
+ touchpoint moves far enough to begin dragging the content, the content will
+ jump, so that the content pixel which was under the cursor or touchpoint
+ when pressed remains under that point. The default is \c false, which
+ provides a smoother experience (no jump) at the cost of losing some of the
+ drag distance at the beginning.
+
+ The \uicontrol {Content size} field specifies the dimensions of the
+ surface controlled by a flickable. Typically, set the values of the
+ \uicontrol W and \uicontrol H fields to the combined size of the components
+ placed in the flickable. You can set additional margins around the
+ content in the \uicontrol Margins field.
+
+ The \uicontrol Origin field specifies the origin of the content. It
+ refers to the top-left position of the content regardless of layout
+ direction. Usually, the \uicontrol X and \uicontrol Y values are set to 0.
+ However, a \l{ListView}{List View} and \l {GridView}{Grid View}
+ may have an arbitrary origin due to delegate size variation, or component
+ insertion or removal outside the visible region.
+
+ \section1 Summary of Basic Interaction Methods
+
+ The following table lists the components that you can use to add basic
+ interaction methods to UIs with links to their developer documentation.
+ They are availabe in \l Library > \uicontrol Components >
+ \uicontrol {Default Components} > \uicontrol Basic. The \e MCU column
+ indicates which components are supported on MCUs.
+
+ \table
+ \header
+ \li Icon
+ \li Name
+ \li MCU
+ \li Purpose
+ \row
+ \li \inlineimage flickable-icon16.png
+ \li \l [QML]{Flickable}
+ \li \inlineimage ok
+ \li Items can be flicked horizontally or vertically.
+ \row
+ \li \inlineimage focusscope-icon16.png
+ \li \l{FocusScope}{Focus Scope}
+ \li
+ \li Assists in keyboard focus handling when building reusable
+ components.
+ \row
+ \li \inlineimage mouse-area-icon16.png
+ \li \l [QtQuick]{MouseArea}{Mouse Area}
+ \li \inlineimage ok
+ \li Enables simple mouse handling.
+ \endtable
+*/
diff --git a/doc/qtcreator/src/qtquick/qtquick-export.qdoc b/doc/qtcreator/src/qtquick/qtquick-export.qdoc
index 436847b03b..e9c305c8c4 100644
--- a/doc/qtcreator/src/qtquick/qtquick-export.qdoc
+++ b/doc/qtcreator/src/qtquick/qtquick-export.qdoc
@@ -25,10 +25,11 @@
/*!
\page creator-exporting-qml.html
- \previouspage quick-converting-ui-projects.html
\if defined(qtdesignstudio)
+ \previouspage studio-importing-3d.html
\nextpage quick-uis.html
\else
+ \previouspage quick-converting-ui-projects.html
\nextpage creator-using-qt-designer.html
\endif
diff --git a/doc/qtcreator/src/qtquick/qtquick-from-qmlproject-to-pro.qdoc b/doc/qtcreator/src/qtquick/qtquick-from-qmlproject-to-pro.qdoc
index 431d9826ab..089f9fd7ea 100644
--- a/doc/qtcreator/src/qtquick/qtquick-from-qmlproject-to-pro.qdoc
+++ b/doc/qtcreator/src/qtquick/qtquick-from-qmlproject-to-pro.qdoc
@@ -66,14 +66,18 @@
Then you can use the \l QQuickView class in the main C++ source file to
show the main QML file when the application starts.
- The \e {Qt Quick Designer Components} module is delivered with \QDS. If you
- use Qt Quick Studio Components or Effects in your project, you have to build the
- module and install it to your Qt to be able to build your project.
-
- The \l{Qt Quick Timeline} module is delivered with \QDS and with Qt 5.14,
- and later. If you use a timeline in a \QDS project that you import to \QC,
- and your Qt is older than 5.14, you must build the Qt Quick Timeline module
- and install it to your Qt to be able to build your project.
+ The \e {Qt Quick Designer Components} module is delivered with the
+ standalone \QDS installation. If you use Qt Quick Studio Components
+ or Effects from the module in a project that you want to edit in \QC,
+ you have to build the module and install it to your Qt to be able to
+ build your project.
+
+ The \l{Qt Quick Timeline} module is delivered with the standalone \QDS
+ installation package and with Qt 5.14, and later. If you install \QDS
+ using the Qt Installation Tool or use \QC, remember to also select the
+ Qt Quick Timeline module for installation. If your Qt is older than 5.14,
+ you must build the Qt Quick Timeline module and install it to your Qt to
+ be able to build your project.
\section1 Converting Projects
@@ -134,8 +138,8 @@
\section1 Adding Qt Quick Designer Components to Qt Installations
- If you use Qt Quick Studio Components or Effects in your project, you have to
- check out and install the \e {Qt Quick Designer Components} module from
+ If you use Qt Quick Studio Components or Effects in your project, you have
+ to check out and install the \e {Qt Quick Designer Components} module from
\l{https://codereview.qt-project.org/admin/repos/qt-labs/qtquickdesigner-components}
{Qt Code Review}.
diff --git a/doc/qtcreator/src/qtquick/qtquick-library.qdoc b/doc/qtcreator/src/qtquick/qtquick-library.qdoc
index c76fe8c189..5e679e6568 100644
--- a/doc/qtcreator/src/qtquick/qtquick-library.qdoc
+++ b/doc/qtcreator/src/qtquick/qtquick-library.qdoc
@@ -40,11 +40,11 @@
\image qtquick-components-tab.png "Library view Components tab"
- \uicontrol Components displays modules that have been added to your project.
- In many modules the components have been further organized into different
- categories. The modules contain visual components, such as basic shapes,
- UI controls, and 3D components, and add functionality to the project.
- All components have a type.
+ \uicontrol Library > \uicontrol Components displays modules that have been
+ added to your project. In many modules the components have been further
+ organized into different categories. The modules contain visual components,
+ such as basic shapes, UI controls, and 3D components, and add functionality
+ to the project. All components have a type.
The UI controls can be styled to have the look and feel of a particular
operating system, such as \macOS, Windows, Android, or iOS.
@@ -61,6 +61,7 @@
\li \l Shapes
\li \l Text
\li \l Images
+ \li \l {UI Controls}
\li \l {User Interaction Methods}
\li \l {Lists and Other Data Models}
\if defined(qtdesignstudio)
@@ -117,12 +118,12 @@
\image qtquick-library-context-menu.png "Context menu commands in Library"
\image qtquick-library-context-menu-hide.png "Context menu command Hide Category"
- To use the context menu commands in Library, right-click on the name of
- a module or category and select one of the following commands:
+ To use the context menu commands in \uicontrol Library, right-click the
+ name of a module or category and select one of the following commands:
\list
- \li \uicontrol {Remove Module}: removes the component module added to
- \uicontrol Library.
+ \li \uicontrol {Remove Module}: removes the module and all of its
+ components from \uicontrol Library > \uicontrol Components.
\li \uicontrol {Expand All}: expands all the modules.
\li \uicontrol {Collapse All}: collapses all the modules.
\li \uicontrol {Hide Category}: hides the category from the module.
@@ -131,4 +132,8 @@
\li \uicontrol {Show All Hidden Categories}: shows the hidden
categories in all of the modules.
\endlist
+
+ \note The context menu commands for the \uicontrol Library categories do not
+ function if you have entered something into the \uicontrol Search field.
+ Clear the \uicontrol Search field to resume using the context menu commands.
*/
diff --git a/doc/qtcreator/src/vcs/creator-vcs-git.qdoc b/doc/qtcreator/src/vcs/creator-vcs-git.qdoc
index 03f05c3ccb..acff67c588 100644
--- a/doc/qtcreator/src/vcs/creator-vcs-git.qdoc
+++ b/doc/qtcreator/src/vcs/creator-vcs-git.qdoc
@@ -172,7 +172,7 @@
\section2 Cleaning Projects
- To clean the working directory, select \uicontrol {Clean Project}.
+ To clean the working directory, select \uicontrol {Build Project} > \uicontrol {Clean}.
All files that are not under version control are displayed in
the \uicontrol {Clean Repository} dialog. Ignored files are
deselected by default. Select the files to delete and click
diff --git a/doc/qtcreatordev/src/coding-style.qdoc b/doc/qtcreatordev/src/coding-style.qdoc
index d429ea917c..6b87163baf 100644
--- a/doc/qtcreatordev/src/coding-style.qdoc
+++ b/doc/qtcreatordev/src/coding-style.qdoc
@@ -574,7 +574,7 @@
void SomeThing::bar()
{
- FileName f; // or Utils::FileName f
+ FilePath f; // or Utils::FilePath f
...
}
...
@@ -637,12 +637,39 @@
instead of backslashes (\\) even on Windows. To pass a file name from the user
to the API, convert it with QDir::fromNativeSeparators first. To present a file
name to the user, convert it back to native format with
- QDir::toNativeSeparators. Consider using Utils::FileName::fromUserInput(QString)
- and Utils::FileName::toUserOutput() for these tasks.
+ QDir::toNativeSeparators. Consider using Utils::FilePath::fromUserInput(QString)
+ and Utils::FilePath::toUserOutput() for these tasks.
- Use Utils::FileName when comparing file names, because that takes case sensitivity into account.
+ Use Utils::FilePath when comparing file names, because that takes case sensitivity into account.
Also make sure that you compare clean paths (QDir::cleanPath()).
+
+ \section2 Classes to Use and Classes Not to Use
+
+ A significant portion of Qt Creator code handles data on devices that are not
+ the same as the development machine. These may differ in aspects like path
+ separator, line endings, process launching details and so on.
+
+ However, some basic Qt classes assume that a Qt application is only
+ concerned with machines that are similar to the development machine.
+
+ These classes are therefore not appropriate to use in the part of Qt Creator that
+ is concerned with non-local code. Instead, Qt Creator's Utils library provides
+ substitutes, leading to the following rules:
+
+ \list
+ \li Use Utils::FilePath for any QString that semantically is a file or directory,
+ see also \l{Passing File Names}.
+ \li Prefer using Utils::FilePath over any use of QDir and QFileInfo.
+ \li Prefer using Utils::QtcProcess over QProcess.
+ \li If Utils::FilePath or Utils::QtcProcess functionality is not sufficient
+ for your purpose, prefer enhancing them over falling back to QString
+ or QProcess.
+ \li Avoid platform #ifdefs unless they are absolutely needed for locally
+ executed code, and even then prefer Utils::HostInfo over #ifdefs.
+ \endlist
+
+
\section2 Plugin Extension Points
A plugin extension point is an interface that is provided by one plugin
diff --git a/doc/qtdesignstudio/examples/doc/loginui1.qdoc b/doc/qtdesignstudio/examples/doc/loginui1.qdoc
index ec215093c4..e9585fda00 100644
--- a/doc/qtdesignstudio/examples/doc/loginui1.qdoc
+++ b/doc/qtdesignstudio/examples/doc/loginui1.qdoc
@@ -105,6 +105,13 @@
the UI. For the time being, it does not do anything.
\li The \e {Screen01.ui.qml} file is a custom component created by
the wizard template. For more information, see \l {UI Files}.
+
+ By default, this is the main file in the project, but you can
+ change that in the .qmlproject file. While the custom component
+ is a good starting point for new users, you don't have to use it.
+ Specifically, if you export and import designs using \QB, your main
+ file is most likely called something else. For more information,
+ see \l {Exporting from Design Tools}.
\li The \e {qtquickcontrols2.conf} file specifies the selected
\l {Styling Qt Quick Controls}{UI style} and some style-specific
arguments.
diff --git a/doc/qtdesignstudio/images/ai-logo.png b/doc/qtdesignstudio/images/ai-logo.png
new file mode 100644
index 0000000000..d42b426071
--- /dev/null
+++ b/doc/qtdesignstudio/images/ai-logo.png
Binary files differ
diff --git a/doc/qtdesignstudio/images/blender-logo.png b/doc/qtdesignstudio/images/blender-logo.png
new file mode 100644
index 0000000000..6aa1effa9c
--- /dev/null
+++ b/doc/qtdesignstudio/images/blender-logo.png
Binary files differ
diff --git a/doc/qtdesignstudio/images/figma-logo.png b/doc/qtdesignstudio/images/figma-logo.png
new file mode 100644
index 0000000000..a21a9c1b91
--- /dev/null
+++ b/doc/qtdesignstudio/images/figma-logo.png
Binary files differ
diff --git a/doc/qtdesignstudio/images/maya-logo.png b/doc/qtdesignstudio/images/maya-logo.png
new file mode 100644
index 0000000000..901246a1d9
--- /dev/null
+++ b/doc/qtdesignstudio/images/maya-logo.png
Binary files differ
diff --git a/doc/qtdesignstudio/images/ps-logo.png b/doc/qtdesignstudio/images/ps-logo.png
new file mode 100644
index 0000000000..abd5c4979d
--- /dev/null
+++ b/doc/qtdesignstudio/images/ps-logo.png
Binary files differ
diff --git a/doc/qtdesignstudio/images/qt-3ds-logo.png b/doc/qtdesignstudio/images/qt-3ds-logo.png
new file mode 100644
index 0000000000..b786b9920a
--- /dev/null
+++ b/doc/qtdesignstudio/images/qt-3ds-logo.png
Binary files differ
diff --git a/doc/qtdesignstudio/images/sketch-logo.png b/doc/qtdesignstudio/images/sketch-logo.png
new file mode 100644
index 0000000000..d27f103e77
--- /dev/null
+++ b/doc/qtdesignstudio/images/sketch-logo.png
Binary files differ
diff --git a/doc/qtdesignstudio/images/studio-custom-button.gif b/doc/qtdesignstudio/images/studio-custom-button.gif
new file mode 100644
index 0000000000..62d559da12
--- /dev/null
+++ b/doc/qtdesignstudio/images/studio-custom-button.gif
Binary files differ
diff --git a/doc/qtdesignstudio/images/studio-custom-check-box.gif b/doc/qtdesignstudio/images/studio-custom-check-box.gif
new file mode 100644
index 0000000000..59845f4109
--- /dev/null
+++ b/doc/qtdesignstudio/images/studio-custom-check-box.gif
Binary files differ
diff --git a/doc/qtdesignstudio/images/studio-custom-dial.gif b/doc/qtdesignstudio/images/studio-custom-dial.gif
new file mode 100644
index 0000000000..4c49e6953f
--- /dev/null
+++ b/doc/qtdesignstudio/images/studio-custom-dial.gif
Binary files differ
diff --git a/doc/qtdesignstudio/images/studio-custom-slider.gif b/doc/qtdesignstudio/images/studio-custom-slider.gif
new file mode 100644
index 0000000000..8e9672ec93
--- /dev/null
+++ b/doc/qtdesignstudio/images/studio-custom-slider.gif
Binary files differ
diff --git a/doc/qtdesignstudio/images/studio-custom-spinbox.gif b/doc/qtdesignstudio/images/studio-custom-spinbox.gif
new file mode 100644
index 0000000000..e93f3d5379
--- /dev/null
+++ b/doc/qtdesignstudio/images/studio-custom-spinbox.gif
Binary files differ
diff --git a/doc/qtdesignstudio/images/studio-custom-switch.gif b/doc/qtdesignstudio/images/studio-custom-switch.gif
new file mode 100644
index 0000000000..1788df14d1
--- /dev/null
+++ b/doc/qtdesignstudio/images/studio-custom-switch.gif
Binary files differ
diff --git a/doc/qtdesignstudio/src/qtbridge/qtbridge-overview.qdoc b/doc/qtdesignstudio/src/qtbridge/qtbridge-overview.qdoc
index 8bc50df787..da7748a9a8 100644
--- a/doc/qtdesignstudio/src/qtbridge/qtbridge-overview.qdoc
+++ b/doc/qtdesignstudio/src/qtbridge/qtbridge-overview.qdoc
@@ -1,6 +1,6 @@
/****************************************************************************
**
-** Copyright (C) 2020 The Qt Company Ltd.
+** Copyright (C) 2021 The Qt Company Ltd.
** Contact: https://www.qt.io/licensing/
**
** This file is part of the Qt Design Studio documentation.
@@ -30,50 +30,54 @@
\title Exporting from Design Tools
- You need to use \QB to first export 2D assets from design tools and then to
- \l{Importing Designs}{import} them into \QDS.
+ When working with 2D assets, you can use \QB to export them from design
+ tools into a metadata format that you can then \l{Importing Designs}{import}
+ into \QDS.
When working with 3D assets, you can use the export functions provided by
the 3D graphics tools to save the assets in widely-used 3D graphics formats,
and then use \QB to import them into \QDS.
- You can use the Qt Installer to install \QB if you have a commercial
- \QDS license. You can also purchase a \QB license separately from the
- \l{https://marketplace.qt.io/}{Qt Marketplace} and then install \QB using
- the Qt Installer.
-
For best results when importing assets, follow
the guidelines for creating and exporting them.
- \list
-
- \li \l{Exporting Designs from Adobe Illustrator}
-
- You can either copy-paste your assets to Adobe Photoshop as
- \e {smart objects} or export them into file formats supported
- by \QDS.
-
- \li \l{Exporting Designs from Adobe Photoshop}
-
- You can use the \QBPS export tool in Adobe Photoshop to convert
- designs into \e {.metadata} format that you can import into
- projects in \QDS.
+ \section1 2D Assets
- \li \l{Exporting Designs from Sketch}
-
- You can use the \QBSK export tool in Sketch to convert designs into
- metadata that you can import into projects in \QDS.
-
- \li \l{Exporting Designs from Figma}
-
- You can use the \QBF export tool in Figma to convert designs into
- metadata that you can import into projects in \QDS.
-
- \li \l{Exporting 3D Assets}
+ You can use the Qt Installer to install \QB if you have a commercial
+ \QDS license. You can also purchase a \QB license separately from the
+ \l{https://marketplace.qt.io/}{Qt Marketplace} and then install \QB using
+ the Qt Installer.
- You can import files you created using 3D graphics applications and
- stored in several widely-used formats, such as .blend, .dae, .fbx,
- .glb, .gltf, .obj, .uia, or .uip.
+ \table
+ \row
+ \li \inlineimage ai-logo.png
+ \li \inlineimage ps-logo.png
+ \li \inlineimage sketch-logo.png
+ \li \inlineimage figma-logo.png
+ \row
+ \li \l{Exporting Designs from Adobe Illustrator}{Adobe Illustrator}
+ \li \l{Exporting Designs from Adobe Photoshop}{Adobe Photoshop}
+ \li \l{Exporting Designs from Sketch}{Sketch}
+ \li \l{Exporting Designs from Figma}{Figma}
+ \endtable
+
+ \section1 3D Assets
+
+ You can import files you created using 3D graphics applications and
+ stored in several widely-used formats, such as .blend, .dae, .fbx,
+ .glb, .gltf, .obj, .uia, or .uip.
+
+ For an overview, see \l{Exporting 3D Assets}.
+
+ \table
+ \row
+ \li \inlineimage blender-logo.png
+ \li \inlineimage maya-logo.png
+ \li \inlineimage qt-3ds-logo.png
+ \row
+ \li \l{Exporting from Blender}{Blender}
+ \li \l{Exporting from Maya}{Maya}
+ \li \l{Exporting from Qt 3D Studio}{Qt 3D Studio}
+ \endtable
- \endlist
*/
diff --git a/doc/qtdesignstudio/src/qtdesignstudio-components.qdocinc b/doc/qtdesignstudio/src/qtdesignstudio-components.qdocinc
index 2eddd6f61e..d71417aa6b 100644
--- a/doc/qtdesignstudio/src/qtdesignstudio-components.qdocinc
+++ b/doc/qtdesignstudio/src/qtdesignstudio-components.qdocinc
@@ -30,22 +30,29 @@
You can use project wizard templates to create stylable UI controls based
on the components in the Qt Quick Controls module:
- \list
+ \table
+ \row
\li \l Button
\li \l {Check Box}
\li \l {Slider and Dial}{Dial}
+ \row
+ \li \inlineimage studio-custom-button.gif
+ \li \inlineimage studio-custom-check-box.gif
+ \li \inlineimage studio-custom-dial.gif
+ \row
\li \l {Slider and Dial}{Slider}
\li \l {Spin Box}
\li \l Switch
- \li \l [QtQuickControls2] {Pane}
- \li \l {Stack Layout}
- \li \l [QtQuickControls2] {SwipeView}{Swipe View}
- \endlist
+ \row
+ \li \inlineimage studio-custom-slider.gif
+ \li \inlineimage studio-custom-spinbox.gif
+ \li \inlineimage studio-custom-switch.gif
+ \endtable
You can edit the properties of the controls in all the preset
\l{Adding States}{states} to apply your own style to them.
- \image studio-dial.png "A stylable Dial component"
+ \image studio-dial.png "A stylable Dial component in Form Editor"
To create stylable UI controls:
@@ -68,5 +75,13 @@
and styling it, see \l{Creating a Push Button} in the \l{Log In UI - Part 1}
tutorial.
+ In addition, you can create starting points for different types of screens:
+
+ \list
+ \li \l [QtQuickControls2] {Pane}
+ \li \l {Stack Layout}
+ \li \l [QtQuickControls2] {SwipeView}{Swipe View}
+ \endlist
+
//! [creating studio components]
*/
diff --git a/doc/qtdesignstudio/src/qtdesignstudio-exporting-and-importing.qdoc b/doc/qtdesignstudio/src/qtdesignstudio-exporting-and-importing.qdoc
new file mode 100644
index 0000000000..e9b50c79a9
--- /dev/null
+++ b/doc/qtdesignstudio/src/qtdesignstudio-exporting-and-importing.qdoc
@@ -0,0 +1,95 @@
+/****************************************************************************
+**
+** Copyright (C) 2021 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the Qt Design Studio documentation.
+**
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU Free Documentation License Usage
+** Alternatively, this file may be used under the terms of the GNU Free
+** Documentation License version 1.3 as published by the Free Software
+** Foundation and appearing in the file included in the packaging of
+** this file. Please review the following information to ensure
+** the GNU Free Documentation License version 1.3 requirements
+** will be met: https://www.gnu.org/licenses/fdl-1.3.html.
+**
+****************************************************************************/
+
+/*!
+ \previouspage studio-getting-started.html
+ \page studio-exporting-and-importing.html
+ \nextpage qtbridge-overview.html
+
+ \title Exporting and Importing
+
+ Typically, you as a designer would design a UI using imaging and design
+ tools, such as Adobe Photoshop, Sketch, Figma, Blender, or Maya, and then
+ send your design to a developer for implementation. You can use the \QB
+ export tool to convert 2D assets into a metadata format supported by \QDS.
+ You can use the export functionality of 3D graphics tools to save your 3D
+ assets in a format that can be imported into \QDS.
+
+ You can import the 2D and 3D assets into \QDS for editing before you
+ submit the UI to the developer for adding the functionality to the
+ application.
+
+ If you want to make further changes to your components in the design tool,
+ you can export the UI files back into the metadata format, which you can
+ then import back into the design tool by using \QB. For example, you could
+ create components in a design tool and export them to \QDS before you start
+ making instances of them. In \QDS, you can add functionality to the
+ components, such as button states and then bring them back to the design
+ tool as assets. If you use functional \QDS components in the design tool,
+ you will find it easier to merge new iterations of the design to \QDS and
+ continue to build the components there.
+
+ The following image describes the workflow using \QBPS and \QDS:
+
+ \image studio-workflow.png
+
+ The workflow consists of the following steps:
+
+ \list 1
+ \li Export your design from a design tool into the metadata format.
+ \li \l{Creating Projects}{Create a project} in \QDS and import the
+ metadata file to it.
+ \li Edit the imported components and create more components in
+ \l {Form Editor} and \l {3D Editor}.
+ \li Animate your design in \l {Transition Editor} or \l Timeline
+ and \l {Curve Editor}.
+ \li Create interactions in \l States and \l {Connection View}.
+ \li \l{Previewing}{Preview} your design in real time, on the desktop
+ or on a mobile or an embedded device.
+ \li Optionally, export your components back into the metadata format
+ that you can import back into the design tool by using \QB. You
+ can continue to iterate your design this way until it is ready.
+ \endlist
+
+ For more information, watch a video that shows how to perform the tasks
+ above:
+
+ \youtube pEETxSxYazg
+
+ \list
+ \li \l {Exporting from Design Tools}
+
+ Export designs containing 2D and 3D assets into a metadata format
+ that you can import to projects in \QDS.
+ \li \l{Importing Designs}
+
+ Import assets that you exported from design tools to a \QDS project
+ and edit them in the \uicontrol Design mode to create a UI.
+ \li \l {Exporting Components}
+
+ Export UI files (.ui.qml) back to the metadata format and PNG assets
+ to generate native file formats in design tools using \QB.
+ \endlist
+*/
diff --git a/doc/qtdesignstudio/src/qtdesignstudio-faq.qdoc b/doc/qtdesignstudio/src/qtdesignstudio-faq.qdoc
index 0cc58cf493..401df6d837 100644
--- a/doc/qtdesignstudio/src/qtdesignstudio-faq.qdoc
+++ b/doc/qtdesignstudio/src/qtdesignstudio-faq.qdoc
@@ -30,10 +30,76 @@
\title Frequently Asked Questions
- This section contains answers to some frequently asked questions about \QDS.
- You might also find answers to your questions in the product documentation
- by searching or browsing the index in the \l{Using the Help Mode}
- {Help mode}. Many questions are also answered by the
- \l{Examples and Tutorials}{examples and video tutorials}.
+ This section contains answers to some frequently asked questions about \QDS
+ grouped by categories. You might also find answers to your questions in the
+ product documentation by searching or browsing the index in the
+ \l{Using the Help Mode}{Help mode}. Many questions are also answered by the
+ \l{Examples and Tutorials}{examples and video tutorials}. Also see
+ \l {Qt Quick Best Practices} to learn about the most efficient ways to use
+ \QDS.
+ \section1 \QB
+ \section2 How does \QBPS differ from \QBSK?
+
+ Visually, \QBPS and \QBSK, and \QBF are identical. The biggest difference
+ between \QBPS and \QBSK is that \QBSK can export .svg (vector), .png and
+ .jpeg files, while \QBPS only supports .png and .jpeg. Adobe Illustrator
+ users can port their designs into Photoshop, but they must be rasterized
+ into \e {smart objects}.
+
+ For more information, see \l {Exporting from Design Tools}.
+
+ \section2 Do I need to copy the .qml files in the resource folder after each design modification?
+ No you don't. When you add new or modified .metadata files to your project
+ from Photoshop, \QBPS, or \QBSK, select the \uicontrol {Merge QML} check
+ box in the \uicontrol {Asset Import} dialog to merge the changes into
+ existing QML files instead of overwriting them.
+
+ For more information, see \l {Importing 2D Assets}.
+
+ \section1 Using 3D Components
+ \section2 What are the 3D import formats for \QDS?
+ You can import files stored in several widely-used formats, such as .fbx,
+ .obj, .gltf, .glb, .blend, .dae, .uia, and .uip.
+
+ For more information, see \l {Importing 3D Assets}
+
+ \section2 What are the keyboard shortcuts for moving around in \uicontrol {3D Editor?}
+ \list
+ \li To pan: \key Alt + middle mouse button
+ \li To orbit (rotate): \key Alt (or \key Option on \macos) + left mouse button
+ \li To zoom: \key Alt + right mouse button
+ \endlist
+
+ For more information, see \l {3D Editor}.
+
+ \section1 Integration Between \QDS and \QC
+ \section2 Is there a way to automatically propagate name changes between \QDS and \QC?
+
+ Unfortunately we do not automate renaming files between tools at the moment.
+ If you decide to change the name of a property, alias, or signal in \QDS,
+ you need to manually change the name in \QC to maintain the connection.
+ However, you can rename symbols in all files within a project. To rename a
+ QML type in a project, select \uicontrol Tools > \uicontrol QML/JS >
+ \uicontrol {Rename Symbol Under Cursor} or press \key Ctrl+Shift+R. For more
+ information, see \l {Renaming Symbols}.
+
+ \section2 When turning your \QDS project into application in \QC, what is the best way to add .qml files?
+
+ Use the project wizard templates to create an application in \QC and copy
+ your .qml files to the project folder. Then make some changes to the project
+ configuration and source files, as instructed in
+ \l {Converting UI Projects to Applications}.
+
+ \section1 Performance
+ \section2 Will my application with 3D components run at 60 FPS?
+
+ With the ability to test the full (2D/3D) UI in \QDS on target hardware,
+ you will quickly be able to determine if a 3D object is causing performance
+ issues using the \uicontrol FPS display in \uicontrol Design mode.
+ \uicontrol FPS displays the frames-per-second (FPS) refresh rate of
+ previewed animations.
+
+ See \l {Optimizing Your 3D Scene} to learn how you can enhance the
+ performance by optimizing your scene.
*/
diff --git a/doc/qtdesignstudio/src/qtdesignstudio-getting-started.qdoc b/doc/qtdesignstudio/src/qtdesignstudio-getting-started.qdoc
index 2c8a204ea5..b1bc8b4739 100644
--- a/doc/qtdesignstudio/src/qtdesignstudio-getting-started.qdoc
+++ b/doc/qtdesignstudio/src/qtdesignstudio-getting-started.qdoc
@@ -1,6 +1,6 @@
/****************************************************************************
**
-** Copyright (C) 2020 The Qt Company Ltd.
+** Copyright (C) 2021 The Qt Company Ltd.
** Contact: https://www.qt.io/licensing/
**
** This file is part of the Qt Design Studio documentation.
@@ -26,51 +26,19 @@
/*!
\previouspage index.html
\page studio-getting-started.html
- \nextpage qtbridge-overview.html
+ \nextpage studio-exporting-and-importing.html
\title Getting Started
- Typically, you as a designer would design a UI using imaging and design
- tools, such as Adobe Photoshop, Sketch, Blender, or Maya, and then send your
- design to a developer for implementation. With the \QB export tool,
- you can convert 2D assets into \l {Qt Quick} files. You can use the export
- functionality of 3D graphics tools to save your 3D assets in a format
- supported by \QDS. You can import the 2D and 3D assets into \QDS for
- editing, before you submit the UI to the developer for adding the
- functionality to the application.
-
- The following image describes the workflow using \QBPS and \QDS:
-
- \image studio-workflow.png
-
- The workflow consists of the following steps:
-
- \list 1
- \li Export your design from a design tool.
- \li Create a project in \QDS and import your design to it.
- \li Create reusable components in the Design mode.
- \li Animate your design with the transition editor or timeline and
- easing curve editor.
- \li Create interactions using states and connections.
- \li Preview your design in real time, on the desktop or on a mobile
- or an embedded device.
- \endlist
-
- For more information, watch a video that shows how to perform the tasks
- above:
-
- \youtube pEETxSxYazg
-
- \section1 First Steps
-
- The following topics contain information that you'll need to find your
- way around \QDS:
+ The following topics contain information that you'll need to get started
+ with \QDS:
\list
- \li \l {Exporting from Design Tools}
+ \li \l {Exporting and Importing}
Describes how to export designs containing 2D and 3D assets into
- files that you can import to projects in \QDS.
+ files that you can import to projects in \QDS, how to import them,
+ and how to export them from \QDS back to the metadata format.
\li \l {User Interface}
Describes the parts and basic features of \QDS.
diff --git a/doc/qtdesignstudio/src/qtdesignstudio-importing-designs.qdoc b/doc/qtdesignstudio/src/qtdesignstudio-importing-designs.qdoc
index c8429eb3ca..26295b96c9 100644
--- a/doc/qtdesignstudio/src/qtdesignstudio-importing-designs.qdoc
+++ b/doc/qtdesignstudio/src/qtdesignstudio-importing-designs.qdoc
@@ -1,6 +1,6 @@
/****************************************************************************
**
-** Copyright (C) 2020 The Qt Company Ltd.
+** Copyright (C) 2021 The Qt Company Ltd.
** Contact: https://www.qt.io/licensing/
**
** This file is part of the Qt Bridge documentation.
@@ -24,7 +24,7 @@
****************************************************************************/
/*!
- \previouspage creator-vcs-git.html
+ \previouspage exporting-from-qt3ds.html
\page studio-importing-designs.html
\nextpage studio-importing-2d.html
diff --git a/doc/qtdesignstudio/src/qtdesignstudio-projects-overview.qdoc b/doc/qtdesignstudio/src/qtdesignstudio-projects-overview.qdoc
index 9f22e18b4c..0f738476a9 100644
--- a/doc/qtdesignstudio/src/qtdesignstudio-projects-overview.qdoc
+++ b/doc/qtdesignstudio/src/qtdesignstudio-projects-overview.qdoc
@@ -55,23 +55,11 @@
project source files and configuration files. Do not store generated
files.
- \li \l{Importing Designs}
-
- You can import assets that you exported from Adobe Photoshop to a
- \QDS project and edit them in the Design mode to create a UI.
-
\li \l {Converting UI Projects to Applications}
\QDS projects are useful for creating UIs. To use them
for application development in Qt Creator, you have to convert them
to Qt Quick Application projects that contain .pro, .cpp, and .qrc
files.
-
- \li \l {Exporting Components}
-
- You can export UI files (.ui.qml) to JSON metadata format
- and PNG assets to generate native file formats in content creation
- tools, such as Adobe Photoshop, using \QB.
-
\endlist
*/
diff --git a/doc/qtdesignstudio/src/qtdesignstudio-projects.qdoc b/doc/qtdesignstudio/src/qtdesignstudio-projects.qdoc
index eda60a979f..d283ea5d04 100644
--- a/doc/qtdesignstudio/src/qtdesignstudio-projects.qdoc
+++ b/doc/qtdesignstudio/src/qtdesignstudio-projects.qdoc
@@ -112,8 +112,15 @@
image files in the project folder belong to the project. Therefore,
you do not need to individually list all the files in the project.
\li .qml file defines the functionality and appearance of a component.
- \li .ui.qml file defines a visual component that you can edit in
- \l{Form Editor}.
+ \li \e Screen01.ui.qml defines a custom component that you can edit in
+ \l{Form Editor}. For more information, see \l {UI Files}.
+
+ By default, this is the main file in the project, but you can
+ change that in the .qmlproject file. While the custom component
+ is a good starting point for new users, you don't have to use it.
+ Specifically, if you export and import designs using \QB, your main
+ file is most likely called something else. For more information,
+ see \l {Exporting from Design Tools}.
\li qtquickcontrols2.conf file specifies the preferred style and some
style-specific arguments.
\li \e fonts folder contains font files that you have added in
diff --git a/doc/qtdesignstudio/src/qtdesignstudio-toc.qdoc b/doc/qtdesignstudio/src/qtdesignstudio-toc.qdoc
index 32896b6185..b535b88ac7 100644
--- a/doc/qtdesignstudio/src/qtdesignstudio-toc.qdoc
+++ b/doc/qtdesignstudio/src/qtdesignstudio-toc.qdoc
@@ -31,27 +31,39 @@
\list
\li \l{Getting Started}
\list
- \li \l{Exporting from Design Tools}
+ \l {Exporting and Importing}
\list
- \li \l{Exporting Designs from Adobe Illustrator}
- \li \l{Exporting Designs from Adobe Photoshop}
+ \li \l{Exporting from Design Tools}
\list
- \li \l{Setting Up Qt Bridge for Adobe Photoshop}
- \li \l{Using Qt Bridge for Adobe Photoshop}
+ \li \l{Exporting Designs from Adobe Illustrator}
+ \li \l{Exporting Designs from Adobe Photoshop}
+ \list
+ \li \l{Setting Up Qt Bridge for Adobe Photoshop}
+ \li \l{Using Qt Bridge for Adobe Photoshop}
+ \endlist
+ \li \l{Exporting Designs from Sketch}
+ \list
+ \li \l{Setting Up Qt Bridge for Sketch}
+ \li \l{Using Qt Bridge for Sketch}
+ \endlist
+ \li \l{Exporting Designs from Figma}
+ \list
+ \li \l{Setting Up Qt Bridge for Figma}
+ \li \l{Using Qt Bridge for Figma}
+ \endlist
+ \li \l{Exporting 3D Assets}
+ \list
+ \li \l{Exporting from Blender}
+ \li \l{Exporting from Maya}
+ \li \l{Exporting from Qt 3D Studio}
+ \endlist
\endlist
- \li \l{Exporting Designs from Sketch}
+ \li \l{Importing Designs}
\list
- \li \l{Setting Up Qt Bridge for Sketch}
- \li \l{Using Qt Bridge for Sketch}
+ \li \l{Importing 2D Assets}
+ \li \l{Importing 3D Assets}
\endlist
- \li \l{Exporting Designs from Figma}
- \list
- \li \l{Setting Up Qt Bridge for Figma}
- \li \l{Using Qt Bridge for Figma}
- \endlist
- \li \l{Exporting from Blender}
- \li \l{Exporting from Maya}
- \li \l{Exporting from Qt 3D Studio}
+ \li \l{Exporting Components}
\endlist
\li \l{User Interface}
\list
@@ -86,13 +98,7 @@
\list
\li \l{Creating Projects}
\li \l{Using Git}
- \li \l{Importing Designs}
- \list
- \li \l{Importing 2D Assets}
- \li \l{Importing 3D Assets}
- \endlist
\li \l{Converting UI Projects to Applications}
- \li \l{Exporting Components}
\endlist
\li \l{Creating UIs}
\list
@@ -112,6 +118,7 @@
\li \l{Shapes}
\li \l{Text}
\li \l{Images}
+ \li \l{UI Controls}
\li \l{User Interaction Methods}
\li \l{Lists and Other Data Models}
\li \l{2D Effects}
diff --git a/doc/qtdesignstudio/src/qtdesignstudio.qdoc b/doc/qtdesignstudio/src/qtdesignstudio.qdoc
index 699a33d28c..a937e8fb0a 100644
--- a/doc/qtdesignstudio/src/qtdesignstudio.qdoc
+++ b/doc/qtdesignstudio/src/qtdesignstudio.qdoc
@@ -47,7 +47,7 @@
\row
\li \b {\l{Getting Started}}
\list
- \li \l{Exporting from Design Tools}
+ \li \l{Exporting and Importing}
\li \l{User Interface}
\li \l{Design Views}
\li \l{Tutorials}
@@ -57,9 +57,7 @@
\list
\li \l{Creating Projects}
\li \l{Using Git}
- \li \l{Importing Designs}
\li \l{Converting UI Projects to Applications}
- \li \l{Exporting Components}
\endlist
\li \b {\l{Creating UIs}}
\list
diff --git a/doc/qtdesignstudio/src/qtquick3d-editor/exporting-3d/exporting-3d-assets.qdoc b/doc/qtdesignstudio/src/qtquick3d-editor/exporting-3d/exporting-3d-assets.qdoc
index 36fe041e22..b47c9d5209 100644
--- a/doc/qtdesignstudio/src/qtquick3d-editor/exporting-3d/exporting-3d-assets.qdoc
+++ b/doc/qtdesignstudio/src/qtquick3d-editor/exporting-3d/exporting-3d-assets.qdoc
@@ -1,7 +1,7 @@
/****************************************************************************
**
** Copyright (C) 1993-2009 NVIDIA Corporation.
-** Copyright (C) 2020 The Qt Company Ltd.
+** Copyright (C) 2021 The Qt Company Ltd.
** Contact: https://www.qt.io/licensing/
**
** This file is part of Qt Design Studio.
@@ -202,15 +202,4 @@
\QDS supports importing hierarchical information. Hierarchies of arbitrary
depth are supported, including grouped nodes. Hierarchical transforms are
applied as expected.
-
- \section1 Exporting from Different Tools
-
- The following sections provide additional information about exporting
- 3D assets from a particular tool:
-
- \list
- \li \l{Exporting from Blender}{Blender}
- \li \l{Exporting from Maya}{Maya}
- \li \l{Exporting from Qt 3D Studio}{Qt 3D Studio}
- \endlist
*/
diff --git a/doc/qtdesignstudio/src/qtquick3d-editor/exporting-3d/exporting-from-qt3ds.qdoc b/doc/qtdesignstudio/src/qtquick3d-editor/exporting-3d/exporting-from-qt3ds.qdoc
index 512ba02519..29ef5c5406 100644
--- a/doc/qtdesignstudio/src/qtquick3d-editor/exporting-3d/exporting-from-qt3ds.qdoc
+++ b/doc/qtdesignstudio/src/qtquick3d-editor/exporting-3d/exporting-from-qt3ds.qdoc
@@ -28,7 +28,7 @@
/*!
\page exporting-from-qt3ds.html
\previouspage exporting-from-maya.html
- \nextpage creator-quick-tour.html
+ \nextpage studio-importing-designs.html
\title Exporting from Qt 3D Studio
Use the following guidelines to achieve the best results when converting
diff --git a/doc/qtdesignstudio/src/qtquick3d-editor/qtdesignstudio-3d-importing.qdoc b/doc/qtdesignstudio/src/qtquick3d-editor/qtdesignstudio-3d-importing.qdoc
index 16abd3c503..06d8cf804a 100644
--- a/doc/qtdesignstudio/src/qtquick3d-editor/qtdesignstudio-3d-importing.qdoc
+++ b/doc/qtdesignstudio/src/qtquick3d-editor/qtdesignstudio-3d-importing.qdoc
@@ -27,10 +27,10 @@
\page studio-importing-3d.html
\if defined(qtdesignstudio)
\previouspage studio-importing-2d.html
- \nextpage quick-converting-ui-projects.html
+ \nextpage creator-exporting-qml.html
\else
\previouspage exporting-from-maya.html
- \nextpage studio-3d-editor.html
+ \nextpage studio-3d-view.html
\endif
\title Importing 3D Assets
diff --git a/qbs/imports/QtcLibrary.qbs b/qbs/imports/QtcLibrary.qbs
index 9a3721b3e0..887a79dbb5 100644
--- a/qbs/imports/QtcLibrary.qbs
+++ b/qbs/imports/QtcLibrary.qbs
@@ -34,6 +34,6 @@ QtcProduct {
Export {
Depends { name: "cpp" }
- cpp.includePaths: [product.libIncludeBase]
+ cpp.includePaths: [exportingProduct.libIncludeBase]
}
}
diff --git a/qbs/imports/QtcPlugin.qbs b/qbs/imports/QtcPlugin.qbs
index dd8e4300fe..9e5a743e12 100644
--- a/qbs/imports/QtcPlugin.qbs
+++ b/qbs/imports/QtcPlugin.qbs
@@ -56,6 +56,6 @@ QtcProduct {
Export {
Depends { name: "ExtensionSystem" }
Depends { name: "cpp" }
- cpp.includePaths: [product.pluginIncludeBase]
+ cpp.includePaths: [exportingProduct.pluginIncludeBase]
}
}
diff --git a/qbs/imports/QtcProduct.qbs b/qbs/imports/QtcProduct.qbs
index 959ce51bb6..104181657b 100644
--- a/qbs/imports/QtcProduct.qbs
+++ b/qbs/imports/QtcProduct.qbs
@@ -17,6 +17,7 @@ Product {
FileInfo.relativePath(FileInfo.joinPaths('/', qtc.ide_qbs_imports_path),
FileInfo.joinPaths('/', qtc.ide_shared_sources_path)))
property bool sanitizable: true
+ property bool usesQt6: Utilities.versionCompare(Qt.core.version, "6") >= 0
Depends { name: "cpp" }
Depends { name: "qtc" }
@@ -31,7 +32,7 @@ Product {
Depends { name: "Qt.core"; versionAtLeast: "5.14.0" }
Depends {
name: "Qt.core5compat"
- condition: Utilities.versionCompare(Qt.core.version, "6") >= 0
+ condition: usesQt6
}
// TODO: Should fall back to what came from Qt.core for Qt < 5.7, but we cannot express that
diff --git a/qbs/modules/qtc/qtc.qbs b/qbs/modules/qtc/qtc.qbs
index 864bfb910e..8a24290242 100644
--- a/qbs/modules/qtc/qtc.qbs
+++ b/qbs/modules/qtc/qtc.qbs
@@ -3,15 +3,15 @@ import qbs.Environment
import qbs.FileInfo
Module {
- property string qtcreator_display_version: '4.15.1'
+ property string qtcreator_display_version: '5.0.0-beta1'
property string ide_version_major: '4'
- property string ide_version_minor: '15'
- property string ide_version_release: '1'
+ property string ide_version_minor: '82'
+ property string ide_version_release: '0'
property string qtcreator_version: ide_version_major + '.' + ide_version_minor + '.'
+ ide_version_release
property string ide_compat_version_major: '4'
- property string ide_compat_version_minor: '15'
+ property string ide_compat_version_minor: '82'
property string ide_compat_version_release: '0'
property string qtcreator_compat_version: ide_compat_version_major + '.'
+ ide_compat_version_minor + '.' + ide_compat_version_release
@@ -68,6 +68,8 @@ Module {
property bool enableUbSanitizer: false
property bool enableThreadSanitizer: false
+ property bool preferSystemSyntaxHighlighting: true
+
property bool make_dev_package: false
// Will be replaced when creating modules from products
diff --git a/qtcreator.pri b/qtcreator.pri
index 5c586e2d76..a03d88ad31 100644
--- a/qtcreator.pri
+++ b/qtcreator.pri
@@ -4,6 +4,8 @@ QTCREATOR_PRI_INCLUDED = 1
include($$PWD/qtcreator_ide_branding.pri)
!isEmpty(IDE_BRANDING_PRI): include($$IDE_BRANDING_PRI)
+include(qtcreator_testvars.pri)
+
PRODUCT_BUNDLE_IDENTIFIER=$${PRODUCT_BUNDLE_ORGANIZATION}.$${IDE_ID}
VERSION = $$QTCREATOR_VERSION
@@ -67,17 +69,6 @@ darwin:!minQtVersion(5, 7, 0) {
QMAKE_MACOSX_DEPLOYMENT_TARGET = 10.8
}
-QTC_BUILD_TESTS = $$(QTC_BUILD_TESTS)
-!isEmpty(QTC_BUILD_TESTS):TEST = $$QTC_BUILD_TESTS
-
-!isEmpty(BUILD_TESTS):TEST = 1
-
-isEmpty(TEST):CONFIG(debug, debug|release) {
- !debug_and_release|build_pass {
- TEST = 1
- }
-}
-
isEmpty(IDE_LIBRARY_BASENAME) {
IDE_LIBRARY_BASENAME = lib
}
@@ -202,6 +193,8 @@ CONFIG += \
LIBS *= -L$$LINK_LIBRARY_PATH # Qt Creator libraries
exists($$IDE_LIBRARY_PATH): LIBS *= -L$$IDE_LIBRARY_PATH # library path from output path
+# linking against Qt Creator built with CMake
+win32: LIBS *= -L$$IDE_BUILD_TREE/bin
!isEmpty(vcproj) {
DEFINES += IDE_LIBRARY_BASENAME=\"$$IDE_LIBRARY_BASENAME\"
diff --git a/qtcreator.pro b/qtcreator.pro
index d2e9a74728..5666948919 100644
--- a/qtcreator.pro
+++ b/qtcreator.pro
@@ -98,16 +98,6 @@ else: PLATFORM = "unknown"
BASENAME = $$(INSTALL_BASENAME)
isEmpty(BASENAME): BASENAME = qt-creator-$${PLATFORM}$(INSTALL_EDITION)-$${QTCREATOR_VERSION}$(INSTALL_POSTFIX)
-linux {
- appstream.files = share/metainfo/org.qt-project.qtcreator.appdata.xml
- appstream.path = $$QTC_PREFIX/share/metainfo/
-
- desktop.files = share/applications/org.qt-project.qtcreator.desktop
- desktop.path = $$QTC_PREFIX/share/applications/
-
- INSTALLS += appstream desktop
-}
-
macx {
APPBUNDLE = "$$OUT_PWD/bin/$${IDE_APP_TARGET}.app"
BINDIST_SOURCE.release = "$$OUT_PWD/bin/$${IDE_APP_TARGET}.app"
diff --git a/qtcreator_ide_branding.pri b/qtcreator_ide_branding.pri
index 2bd6d479ba..7efd86dace 100644
--- a/qtcreator_ide_branding.pri
+++ b/qtcreator_ide_branding.pri
@@ -1,6 +1,6 @@
-QTCREATOR_VERSION = 4.15.1
-QTCREATOR_COMPAT_VERSION = 4.15.0
-QTCREATOR_DISPLAY_VERSION = 4.15.1
+QTCREATOR_VERSION = 4.82.0
+QTCREATOR_COMPAT_VERSION = 4.82.0
+QTCREATOR_DISPLAY_VERSION = 5.0.0-beta1
QTCREATOR_COPYRIGHT_YEAR = 2021
IDE_DISPLAY_NAME = Qt Creator
diff --git a/qtcreator_testvars.pri b/qtcreator_testvars.pri
new file mode 100644
index 0000000000..cf2e1c1a8c
--- /dev/null
+++ b/qtcreator_testvars.pri
@@ -0,0 +1,16 @@
+isEmpty(QTCREATOR_TESTVARS_PRI_INCLUDED) {
+
+ QTCREATOR_TESTVARS_PRI_INCLUDED = 1
+
+ QTC_BUILD_TESTS = $$(QTC_BUILD_TESTS)
+ !isEmpty(QTC_BUILD_TESTS):TEST = $$QTC_BUILD_TESTS
+
+ !isEmpty(BUILD_TESTS):TEST = 1
+
+ isEmpty(TEST):CONFIG(debug, debug|release) {
+ !debug_and_release|build_pass {
+ TEST = 1
+ }
+ }
+
+}
diff --git a/share/CMakeLists.txt b/share/CMakeLists.txt
index b1e61d596e..575c0aea8c 100644
--- a/share/CMakeLists.txt
+++ b/share/CMakeLists.txt
@@ -1,11 +1,23 @@
add_subdirectory(qtcreator)
if (NOT APPLE AND NOT WIN32)
+ set(DATE_ATTRIBUTE)
+ if(SHOW_BUILD_DATE)
+ string(TIMESTAMP timestamp "%Y-%m-%d")
+ set(DATE_ATTRIBUTE " date=\"${timestamp}\"")
+ endif()
+ configure_file(metainfo/org.qt-project.qtcreator.appdata.xml.cmakein metainfo/org.qt-project.qtcreator.appdata.xml)
+
install(
DIRECTORY
applications
- metainfo
DESTINATION
${CMAKE_INSTALL_DATAROOTDIR}
)
+ install(
+ FILES
+ ${CMAKE_CURRENT_BINARY_DIR}/metainfo/org.qt-project.qtcreator.appdata.xml
+ DESTINATION
+ ${CMAKE_INSTALL_DATAROOTDIR}/metainfo/
+ )
endif()
diff --git a/share/metainfo/org.qt-project.qtcreator.appdata.xml b/share/metainfo/org.qt-project.qtcreator.appdata.xml.cmakein
index 4706e69b22..b721029a0a 100644
--- a/share/metainfo/org.qt-project.qtcreator.appdata.xml
+++ b/share/metainfo/org.qt-project.qtcreator.appdata.xml.cmakein
@@ -26,4 +26,20 @@
<url type="homepage">https://www.qt.io/ide/</url>
<project_group>Qt</project_group>
+ <content_rating type="oars-1.1" />
+ <screenshots>
+ <screenshot>
+ <image>https://doc.qt.io/qtcreator/images/qtcreator-breakdown.png</image>
+ </screenshot>
+ <screenshot>
+ <image>https://doc.qt.io/qtcreator/images/qtcreator-qt-quick-editors.png</image>
+ </screenshot>
+ </screenshots>
+ <releases>
+ <release version="${IDE_VERSION_DISPLAY}"${DATE_ATTRIBUTE}>
+ <description>
+ <p>Qt Creator v${IDE_VERSION_DISPLAY}</p>
+ </description>
+ </release>
+ </releases>
</component>
diff --git a/share/qtcreator/debugger/creatortypes.py b/share/qtcreator/debugger/creatortypes.py
index 52a9893421..bddfbb8f4f 100644
--- a/share/qtcreator/debugger/creatortypes.py
+++ b/share/qtcreator/debugger/creatortypes.py
@@ -221,12 +221,26 @@ def qdump__CPlusPlus__Internal__Value(d, value):
def qdump__Utils__FilePath(d, value):
try:
+ # support FilePath before 4.15 as well
if not d.extractPointer(value["m_url"]): # there is no valid URL
d.putStringValue(value["m_data"])
else:
d.putItem(value["m_url"])
except:
- d.putStringValue(value) # support FileName before 4.10 as well
+ scheme, host, path = d.split("{@QString}{@QString}{@QString}", value)
+ scheme_enc = d.encodeString(scheme)
+ host_enc = d.encodeString(host)
+ path_enc = d.encodeString(path)
+ val = ""
+ slash = "2F00"
+ dot = "2E00"
+ colon = "3A00"
+ if len(scheme_enc):
+ val = scheme_enc + colon + slash + slash + host_enc
+ if not path_enc.startswith(slash):
+ val += slash + dot + slash
+ val += path_enc
+ d.putValue(val, "utf16")
d.putPlainChildren(value)
diff --git a/share/qtcreator/debugger/gdbbridge.py b/share/qtcreator/debugger/gdbbridge.py
index c2a3fa94a5..0c810556b9 100644
--- a/share/qtcreator/debugger/gdbbridge.py
+++ b/share/qtcreator/debugger/gdbbridge.py
@@ -177,12 +177,14 @@ class PlainDumper():
def importPlainDumpers(args):
if args == 'off':
+ theDumper.usePlainDumpers = False
try:
gdb.execute('disable pretty-printer .* .*')
except:
# Might occur in non-ASCII directories
DumperBase.warn('COULD NOT DISABLE PRETTY PRINTERS')
else:
+ theDumper.usePlainDumpers = True
theDumper.importPlainDumpers()
@@ -219,6 +221,9 @@ class Dumper(DumperBase):
def __init__(self):
DumperBase.__init__(self)
+ # whether to load plain dumpers for objfiles
+ self.usePlainDumpers = False
+
# These values will be kept between calls to 'fetchVariables'.
self.isGdb = True
self.typeCache = {}
@@ -1033,11 +1038,14 @@ class Dumper(DumperBase):
self.qqDumpers[name] = PlainDumper(printer)
self.qqFormats[name] = ''
+ def importPlainDumpersForObj(self, obj):
+ for printers in obj.pretty_printers + gdb.pretty_printers:
+ for printer in printers.subprinters:
+ self.importPlainDumper(printer)
+
def importPlainDumpers(self):
for obj in gdb.objfiles():
- for printers in obj.pretty_printers + gdb.pretty_printers:
- for printer in printers.subprinters:
- self.importPlainDumper(printer)
+ self.importPlainDumpersForObj(obj)
def qtNamespace(self):
# This function is replaced by handleQtCoreLoaded()
@@ -1060,6 +1068,9 @@ class Dumper(DumperBase):
self.addDebugLibs(objfile)
self.handleQtCoreLoaded(objfile)
+ if self.usePlainDumpers:
+ self.importPlainDumpersForObj(objfile)
+
def addDebugLibs(self, objfile):
# The directory where separate debug symbols are searched for
# is "/usr/lib/debug".
diff --git a/share/qtcreator/debugger/lldbbridge.py b/share/qtcreator/debugger/lldbbridge.py
index 651719dfff..7888752a23 100644
--- a/share/qtcreator/debugger/lldbbridge.py
+++ b/share/qtcreator/debugger/lldbbridge.py
@@ -1107,13 +1107,59 @@ class Dumper(DumperBase):
return
isNativeMixed = int(args.get('nativemixed', 0))
+ extraQml = int(args.get('extraqml', '0'))
limit = args.get('stacklimit', -1)
(n, isLimited) = (limit, True) if limit > 0 else (thread.GetNumFrames(), False)
self.currentCallContext = None
result = 'stack={current-thread="%d"' % thread.GetThreadID()
result += ',frames=['
- for i in range(n):
+
+ ii = 0
+ if extraQml:
+ ns = self.qtNamespace()
+ needle = self.qtNamespace() + 'QV4::ExecutionEngine'
+ pats = [
+ '{0}qt_v4StackTraceForEngine((void*)0x{1:x})',
+ '{0}qt_v4StackTrace((({0}QV4::ExecutionEngine *)0x{1:x})->currentContext())',
+ '{0}qt_v4StackTrace((({0}QV4::ExecutionEngine *)0x{1:x})->currentContext)',
+ ]
+ done = False
+ while ii < n and not done:
+ res = None
+ frame = thread.GetFrameAtIndex(ii)
+ if not frame.IsValid():
+ break
+ for variable in frame.GetVariables(True, True, False, True):
+ if not variable.GetType().IsPointerType():
+ continue
+ derefvar = variable.Dereference()
+ if derefvar.GetType().GetName() != needle:
+ continue
+ addr = derefvar.GetLoadAddress()
+ for pat in pats:
+ exp = pat.format(ns, addr)
+ val = frame.EvaluateExpression(exp)
+ err = val.GetError()
+ res = str(val)
+ if err.Fail():
+ continue
+ pos = res.find('"stack=[')
+ if pos == -1:
+ continue
+ res = res[pos + 8:-2]
+ res = res.replace('\\\"', '\"')
+ res = res.replace('func=', 'function=')
+ result += res
+ done = True
+ break
+ ii += 1
+ # if we have not found a qml stack do not omit original stack
+ if not done:
+ DumperBase.warn("Failed to fetch qml stack - you need Qt debug information")
+ ii = 0
+
+ for i in range(n - ii):
frame = thread.GetFrameAtIndex(i)
if not frame.IsValid():
isLimited = False
diff --git a/share/qtcreator/qml/qmlpuppet/mockfiles/RotateGizmo.qml b/share/qtcreator/qml/qmlpuppet/mockfiles/RotateGizmo.qml
index 6fccfbcdc7..880ced6e9c 100644
--- a/share/qtcreator/qml/qmlpuppet/mockfiles/RotateGizmo.qml
+++ b/share/qtcreator/qml/qmlpuppet/mockfiles/RotateGizmo.qml
@@ -40,16 +40,28 @@ Node {
property real currentAngle
property point currentMousePos
property alias freeDraggerArea: mouseAreaFree
+ property bool blocked: false
position: dragHelper.pivotScenePosition(targetNode)
- onTargetNodeChanged: position = dragHelper.pivotScenePosition(targetNode)
+ onTargetNodeChanged: {
+ position = dragHelper.pivotScenePosition(targetNode);
+ blocked = _generalHelper.isRotationBlocked(targetNode);
+ }
Connections {
target: rotateGizmo.targetNode
function onSceneTransformChanged()
{
- rotateGizmo.position = rotateGizmo.dragHelper.pivotScenePosition(rotateGizmo.targetNode);
+ rotateGizmo.position = dragHelper.pivotScenePosition(targetNode);
+ }
+ }
+
+ Connections {
+ target: _generalHelper
+ function onRotationBlocksChanged()
+ {
+ blocked = _generalHelper.isRotationBlocked(targetNode);
}
}
@@ -82,11 +94,12 @@ Node {
objectName: "Rotate Ring X"
eulerRotation: Qt.vector3d(0, 90, 0)
targetNode: rotateGizmo.targetNode
- color: highlightOnHover && (hovering || dragging) ? Qt.lighter(Qt.rgba(1, 0, 0, 1))
- : Qt.rgba(1, 0, 0, 1)
+ color: rotateGizmo.blocked ? Qt.rgba(0.5, 0.5, 0.5, 1)
+ : highlightOnHover && (hovering || dragging)
+ ? Qt.lighter(Qt.rgba(1, 0, 0, 1)) : Qt.rgba(1, 0, 0, 1)
priority: 40
view3D: rotateGizmo.view3D
- active: rotateGizmo.visible
+ active: rotateGizmo.visible && !rotateGizmo.blocked
dragHelper: rotateGizmo.dragHelper
onRotateCommit: rotateGizmo.rotateCommit()
@@ -100,13 +113,14 @@ Node {
objectName: "Rotate Ring Y"
eulerRotation: Qt.vector3d(90, 0, 0)
targetNode: rotateGizmo.targetNode
- color: highlightOnHover && (hovering || dragging) ? Qt.lighter(Qt.rgba(0, 0.6, 0, 1))
- : Qt.rgba(0, 0.6, 0, 1)
+ color: rotateGizmo.blocked ? Qt.rgba(0.5, 0.5, 0.5, 1)
+ : highlightOnHover && (hovering || dragging)
+ ? Qt.lighter(Qt.rgba(0, 0.6, 0, 1)) : Qt.rgba(0, 0.6, 0, 1)
// Just a smidge smaller than higher priority rings so that it doesn't obscure them
scale: Qt.vector3d(0.998, 0.998, 0.998)
priority: 30
view3D: rotateGizmo.view3D
- active: rotateGizmo.visible
+ active: rotateGizmo.visible && !rotateGizmo.blocked
dragHelper: rotateGizmo.dragHelper
onRotateCommit: rotateGizmo.rotateCommit()
@@ -120,13 +134,14 @@ Node {
objectName: "Rotate Ring Z"
eulerRotation: Qt.vector3d(0, 0, 0)
targetNode: rotateGizmo.targetNode
- color: highlightOnHover && (hovering || dragging) ? Qt.lighter(Qt.rgba(0, 0, 1, 1))
- : Qt.rgba(0, 0, 1, 1)
+ color: rotateGizmo.blocked ? Qt.rgba(0.5, 0.5, 0.5, 1)
+ : highlightOnHover && (hovering || dragging)
+ ? Qt.lighter(Qt.rgba(0, 0, 1, 1)) : Qt.rgba(0, 0, 1, 1)
// Just a smidge smaller than higher priority rings so that it doesn't obscure them
scale: Qt.vector3d(0.996, 0.996, 0.996)
priority: 20
view3D: rotateGizmo.view3D
- active: rotateGizmo.visible
+ active: rotateGizmo.visible && !rotateGizmo.blocked
dragHelper: rotateGizmo.dragHelper
onRotateCommit: rotateGizmo.rotateCommit()
@@ -154,12 +169,14 @@ Node {
objectName: "cameraRing"
rotation: rotateGizmo.view3D.camera.rotation
targetNode: rotateGizmo.targetNode
- color: highlightOnHover && (hovering || dragging) ? Qt.lighter(Qt.rgba(0.5, 0.5, 0.5, 1))
- : Qt.rgba(0.5, 0.5, 0.5, 1)
+ color: rotateGizmo.blocked ? Qt.rgba(0.5, 0.5, 0.5, 1)
+ : highlightOnHover && (hovering || dragging)
+ ? Qt.lighter(Qt.rgba(0.5, 0.5, 0.5, 1))
+ : Qt.rgba(0.5, 0.5, 0.5, 1)
scale: Qt.vector3d(1.1, 1.1, 1.1)
priority: 10
view3D: rotateGizmo.view3D
- active: rotateGizmo.visible
+ active: rotateGizmo.visible && !rotateGizmo.blocked
dragHelper: rotateGizmo.dragHelper
visible: !rotRingX.dragging && !rotRingY.dragging && !rotRingZ.dragging && !freeRotator.dragging
@@ -176,7 +193,7 @@ Node {
materials: DefaultMaterial {
id: material
diffuseColor: "black"
- opacity: mouseAreaFree.hovering ? 0.15 : 0
+ opacity: mouseAreaFree.hovering && !rotateGizmo.blocked ? 0.15 : 0
lighting: DefaultMaterial.NoLighting
}
scale: Qt.vector3d(0.15, 0.15, 0.15)
@@ -184,7 +201,6 @@ Node {
property bool dragging: false
property vector3d _pointerPosPressed
- property vector3d _targetPosOnScreen
property vector3d _startRotation
function handlePressed(screenPos)
@@ -195,14 +211,20 @@ Node {
// Need to recreate vector as we need to adjust it and we can't do that on reference of
// scenePosition, which is read-only property
var scenePos = rotateGizmo.dragHelper.pivotScenePosition(rotateGizmo.targetNode);
- _targetPosOnScreen = view3D.mapFrom3DScene(scenePos);
- _targetPosOnScreen.z = 0;
_pointerPosPressed = Qt.vector3d(screenPos.x, screenPos.y, 0);
// Recreate vector so we don't follow the changes in targetNode.rotation
_startRotation = Qt.vector3d(rotateGizmo.targetNode.eulerRotation.x,
rotateGizmo.targetNode.eulerRotation.y,
rotateGizmo.targetNode.eulerRotation.z);
+ // Ensure we never set NaN values for rotation, even if target node originally has them
+ if (isNaN(_startRotation.x))
+ _startRotation.x = 0;
+ if (isNaN(_startRotation.y))
+ _startRotation.y = 0;
+ if (isNaN(_startRotation.z))
+ _startRotation.z = 0;
+
dragging = true;
}
@@ -213,7 +235,7 @@ Node {
mouseAreaFree.applyFreeRotation(
rotateGizmo.targetNode, _startRotation, _pointerPosPressed,
- Qt.vector3d(screenPos.x, screenPos.y, 0), _targetPosOnScreen);
+ Qt.vector3d(screenPos.x, screenPos.y, 0));
rotateGizmo.rotateChange();
}
@@ -225,7 +247,7 @@ Node {
mouseAreaFree.applyFreeRotation(
rotateGizmo.targetNode, _startRotation, _pointerPosPressed,
- Qt.vector3d(screenPos.x, screenPos.y, 0), _targetPosOnScreen);
+ Qt.vector3d(screenPos.x, screenPos.y, 0));
rotateGizmo.rotateCommit();
dragging = false;
@@ -242,7 +264,7 @@ Node {
height: 100
circlePickArea: Qt.point(25, 50)
grabsMouse: rotateGizmo.targetNode
- active: rotateGizmo.visible
+ active: rotateGizmo.visible && !rotateGizmo.blocked
dragHelper: rotateGizmo.dragHelper
onPressed: freeRotator.handlePressed(screenPos)
diff --git a/share/qtcreator/qml/qmlpuppet/mockfiles/RotateRing.qml b/share/qtcreator/qml/qmlpuppet/mockfiles/RotateRing.qml
index 00494a5d91..19760b8ff9 100644
--- a/share/qtcreator/qml/qmlpuppet/mockfiles/RotateRing.qml
+++ b/share/qtcreator/qml/qmlpuppet/mockfiles/RotateRing.qml
@@ -90,6 +90,13 @@ Model {
_startRotation = Qt.vector3d(targetNode.eulerRotation.x,
targetNode.eulerRotation.y,
targetNode.eulerRotation.z);
+ // Ensure we never set NaN values for rotation, even if target node originally has them
+ if (isNaN(_startRotation.x))
+ _startRotation.x = 0;
+ if (isNaN(_startRotation.y))
+ _startRotation.y = 0;
+ if (isNaN(_startRotation.z))
+ _startRotation.z = 0;
currentAngle = 0;
currentMousePos = screenPos;
}
diff --git a/share/qtcreator/qml/qmlpuppet/qml2puppet/editor3d/generalhelper.cpp b/share/qtcreator/qml/qmlpuppet/qml2puppet/editor3d/generalhelper.cpp
index 133035de20..f65e3ccc4f 100644
--- a/share/qtcreator/qml/qmlpuppet/qml2puppet/editor3d/generalhelper.cpp
+++ b/share/qtcreator/qml/qmlpuppet/qml2puppet/editor3d/generalhelper.cpp
@@ -356,6 +356,24 @@ bool GeneralHelper::isMacOS() const
#endif
}
+void GeneralHelper::addRotationBlocks(const QSet<QQuick3DNode *> &nodes)
+{
+ m_rotationBlockedNodes.unite(nodes);
+ emit rotationBlocksChanged();
+}
+
+void GeneralHelper::removeRotationBlocks(const QSet<QQuick3DNode *> &nodes)
+{
+ for (auto node : nodes)
+ m_rotationBlockedNodes.remove(node);
+ emit rotationBlocksChanged();
+}
+
+bool GeneralHelper::isRotationBlocked(QQuick3DNode *node) const
+{
+ return m_rotationBlockedNodes.contains(node);
+}
+
bool GeneralHelper::eventFilter(QObject *obj, QEvent *event)
{
if (event->type() == QEvent::DynamicPropertyChange) {
diff --git a/share/qtcreator/qml/qmlpuppet/qml2puppet/editor3d/generalhelper.h b/share/qtcreator/qml/qmlpuppet/qml2puppet/editor3d/generalhelper.h
index 6347520e69..212411eee4 100644
--- a/share/qtcreator/qml/qmlpuppet/qml2puppet/editor3d/generalhelper.h
+++ b/share/qtcreator/qml/qmlpuppet/qml2puppet/editor3d/generalhelper.h
@@ -93,11 +93,16 @@ public:
bool isMacOS() const;
+ void addRotationBlocks(const QSet<QQuick3DNode *> &nodes);
+ void removeRotationBlocks(const QSet<QQuick3DNode *> &nodes);
+ Q_INVOKABLE bool isRotationBlocked(QQuick3DNode *node) const;
+
signals:
void overlayUpdateNeeded();
void toolStateChanged(const QString &sceneId, const QString &tool, const QVariant &toolState);
void hiddenStateChanged(QQuick3DNode *node);
void lockedStateChanged(QQuick3DNode *node);
+ void rotationBlocksChanged();
protected:
bool eventFilter(QObject *obj, QEvent *event) final;
@@ -110,6 +115,7 @@ private:
QHash<QString, QVariantMap> m_toolStates;
QHash<QString, QVariantMap> m_toolStatesPending;
QSet<QQuick3DNode *> m_gizmoTargets;
+ QSet<QQuick3DNode *> m_rotationBlockedNodes;
};
}
diff --git a/share/qtcreator/qml/qmlpuppet/qml2puppet/instances/qt5informationnodeinstanceserver.cpp b/share/qtcreator/qml/qmlpuppet/qml2puppet/instances/qt5informationnodeinstanceserver.cpp
index 1f3a662d3e..2b2ec60da8 100644
--- a/share/qtcreator/qml/qmlpuppet/qml2puppet/instances/qt5informationnodeinstanceserver.cpp
+++ b/share/qtcreator/qml/qmlpuppet/qml2puppet/instances/qt5informationnodeinstanceserver.cpp
@@ -63,6 +63,7 @@
#include "inputeventcommand.h"
#include "view3dactioncommand.h"
#include "requestmodelnodepreviewimagecommand.h"
+#include "changeauxiliarycommand.h"
#include "dummycontextobject.h"
#include "../editor3d/generalhelper.h"
@@ -288,6 +289,57 @@ void Qt5InformationNodeInstanceServer::resolveImportSupport()
#endif
}
+void Qt5InformationNodeInstanceServer::updateRotationBlocks(const QVector<PropertyValueContainer> &valueChanges)
+{
+#ifdef QUICK3D_MODULE
+ auto helper = qobject_cast<QmlDesigner::Internal::GeneralHelper *>(m_3dHelper);
+ if (helper) {
+ QSet<QQuick3DNode *> blockedNodes;
+ QSet<QQuick3DNode *> unblockedNodes;
+ const PropertyName propName = "rotBlocked@internal";
+ for (const auto &container : valueChanges) {
+ if (container.name() == propName) {
+ ServerNodeInstance instance = instanceForId(container.instanceId());
+ if (instance.isValid()) {
+ auto node = qobject_cast<QQuick3DNode *>(instance.internalObject());
+ if (node) {
+ if (container.value().toBool())
+ blockedNodes.insert(node);
+ else
+ unblockedNodes.insert(node);
+ }
+ }
+ }
+ }
+ helper->addRotationBlocks(blockedNodes);
+ helper->removeRotationBlocks(unblockedNodes);
+ }
+#else
+ Q_UNUSED(valueChanges)
+#endif
+}
+
+void Qt5InformationNodeInstanceServer::removeRotationBlocks(const QVector<qint32> &instanceIds)
+{
+#ifdef QUICK3D_MODULE
+ auto helper = qobject_cast<QmlDesigner::Internal::GeneralHelper *>(m_3dHelper);
+ if (helper) {
+ QSet<QQuick3DNode *> unblockedNodes;
+ for (const auto &id : instanceIds) {
+ ServerNodeInstance instance = instanceForId(id);
+ if (instance.isValid()) {
+ auto node = qobject_cast<QQuick3DNode *>(instance.internalObject());
+ if (node)
+ unblockedNodes.insert(node);
+ }
+ }
+ helper->removeRotationBlocks(unblockedNodes);
+ }
+#else
+ Q_UNUSED(instanceIds)
+#endif
+}
+
void Qt5InformationNodeInstanceServer::createEditView3D()
{
#ifdef QUICK3D_MODULE
@@ -1492,8 +1544,10 @@ void Qt5InformationNodeInstanceServer::createScene(const CreateSceneCommand &com
sendChildrenChangedCommand(instanceList);
nodeInstanceClient()->componentCompleted(createComponentCompletedCommand(instanceList));
- if (isQuick3DMode())
+ if (isQuick3DMode()) {
setup3DEditView(instanceList, command.edit3dToolStates);
+ updateRotationBlocks(command.auxiliaryChanges);
+ }
QObject::connect(&m_renderModelNodeImageViewTimer, &QTimer::timeout,
this, &Qt5InformationNodeInstanceServer::doRenderModelNodeImageView);
@@ -1656,6 +1710,8 @@ void Qt5InformationNodeInstanceServer::removeInstances(const RemoveInstancesComm
{
int nodeCount = m_3DSceneMap.size();
+ removeRotationBlocks(command.instanceIds());
+
Qt5NodeInstanceServer::removeInstances(command);
if (nodeCount != m_3DSceneMap.size()) {
@@ -1741,6 +1797,7 @@ void Qt5InformationNodeInstanceServer::requestModelNodePreviewImage(const Reques
void Qt5InformationNodeInstanceServer::changeAuxiliaryValues(const ChangeAuxiliaryCommand &command)
{
+ updateRotationBlocks(command.auxiliaryChanges);
Qt5NodeInstanceServer::changeAuxiliaryValues(command);
render3DEditView();
}
diff --git a/share/qtcreator/qml/qmlpuppet/qml2puppet/instances/qt5informationnodeinstanceserver.h b/share/qtcreator/qml/qmlpuppet/qml2puppet/instances/qt5informationnodeinstanceserver.h
index 55a07379b4..6e882e8728 100644
--- a/share/qtcreator/qml/qmlpuppet/qml2puppet/instances/qt5informationnodeinstanceserver.h
+++ b/share/qtcreator/qml/qmlpuppet/qml2puppet/instances/qt5informationnodeinstanceserver.h
@@ -30,6 +30,8 @@
#include "valueschangedcommand.h"
#include "changeselectioncommand.h"
#include "requestmodelnodepreviewimagecommand.h"
+#include "propertybindingcontainer.h"
+#include "propertyabstractcontainer.h"
#include <QTimer>
#include <QVariant>
@@ -132,6 +134,8 @@ private:
void updateLockedAndHiddenStates(const QSet<ServerNodeInstance> &instances);
void handleInputEvents();
void resolveImportSupport();
+ void updateRotationBlocks(const QVector<PropertyValueContainer> &valueChanges);
+ void removeRotationBlocks(const QVector<qint32> &instanceIds);
void createAuxiliaryQuickView(const QUrl &url, RenderViewData &viewData);
diff --git a/share/qtcreator/qmldesigner/formatconfiguration.json b/share/qtcreator/qmldesigner/formatconfiguration.json
new file mode 100644
index 0000000000..8526c710c7
--- /dev/null
+++ b/share/qtcreator/qmldesigner/formatconfiguration.json
@@ -0,0 +1,24 @@
+{
+ "propertylist" : [
+ {
+ "id": "textItem",
+ "subclasses": ["QtQuick.Text","QtQuick.TextInput","QtQuick.TextEdit"],
+ "properties": ["font.bold","font.italic","font.underline","color","font.capitalization","font.family","font.hintingPreference",
+ "font.kerning","font.letterSpacing","font.pixelSize","font.pointSize","font.preferShaping","font.strikeout",
+ "font.styleName","font.weight","font.wordSpacing","fontInfo.bold","fontInfo.family","fontInfo.italic","fontInfo.pixelSize",
+ "fontInfo.pointSize","fontInfo.styleName","fontInfo.weight","lineHeight","lineHeightMode","linkColor",
+ "maximumLineCount","minimumPixelSize","minimumPointSize","renderType","style","styleColor","padding","topPadding",
+ "bottomPadding","leftPadding","rightPadding"]
+ },
+ {
+ "id": "rectangleItem",
+ "subclasses": ["QtQuick.Rectangle"],
+ "properties": ["color","border.color","border.width","radius"]
+ },
+ {
+ "id":"positionerItem",
+ "subclasses": ["QtQuick.Row","QtQuick.Column","QtQuick.Grid"],
+ "properties": ["padding", "spacing", "topPadding", "bottomPadding", "leftPadding", "rightPadding"]
+ }
+ ]
+}
diff --git a/share/qtcreator/qmldesigner/itemLibraryQmlSources/Assets.qml b/share/qtcreator/qmldesigner/itemLibraryQmlSources/Assets.qml
new file mode 100644
index 0000000000..58f42cdb5d
--- /dev/null
+++ b/share/qtcreator/qmldesigner/itemLibraryQmlSources/Assets.qml
@@ -0,0 +1,184 @@
+/****************************************************************************
+**
+** Copyright (C) 2021 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of Qt Creator.
+**
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3 as published by the Free Software
+** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-3.0.html.
+**
+****************************************************************************/
+
+import QtQuick 2.15
+import QtQuick.Controls 2.15
+import QtQuick.Layouts 1.15
+import QtQuickDesignerTheme 1.0
+import HelperWidgets 2.0
+import StudioControls 1.0 as StudioControls
+import StudioTheme 1.0 as StudioTheme
+
+Item {
+ DropArea {
+ id: dropArea
+
+ property var files // list of supported dropped files
+
+ enabled: true
+ anchors.fill: parent
+
+ onEntered: {
+ files = []
+ for (var i = 0; i < drag.urls.length; ++i) {
+ var url = drag.urls[i].toString();
+ if (url.startsWith("file:///")) // remove file scheme (happens on Windows)
+ url = url.substr(8)
+ var ext = url.slice(url.lastIndexOf('.') + 1).toLowerCase()
+ if (rootView.supportedSuffixes().includes('*.' + ext))
+ files.push(url)
+ }
+
+ if (files.length === 0)
+ drag.accepted = false;
+ }
+
+ onDropped: {
+ if (files.length > 0)
+ rootView.handleFilesDrop(files)
+ }
+ }
+
+ ScrollView { // TODO: experiment using ListView instead of ScrollView + Column
+ id: assetsView
+ anchors.fill: parent
+
+ Column {
+ spacing: 2
+ Repeater {
+ model: assetsModel // context property
+ delegate: dirSection
+ }
+
+ Component {
+ id: dirSection
+
+ Section {
+ width: assetsView.width -
+ (assetsView.verticalScrollBarVisible ? assetsView.verticalThickness : 0)
+ caption: dirName
+ sectionHeight: 30
+ sectionFontSize: 15
+ contentLevel: dirDepth
+ levelShift: 20
+ leftPadding: 0
+ hideHeader: dirDepth === 0
+ showLeftBorder: true
+ expanded: dirExpanded
+ visible: dirVisible
+ expandOnClick: false
+ onToggleExpand: {
+ dirExpanded = !dirExpanded
+ }
+
+ Column {
+ spacing: 5
+ leftPadding: 15
+
+ Repeater {
+ model: dirsModel
+ delegate: dirSection
+ }
+
+ Repeater {
+ model: filesModel
+ delegate: fileSection
+ }
+ }
+ }
+ }
+
+ Component {
+ id: fileSection
+
+ Rectangle {
+ width: assetsView.width -
+ (assetsView.verticalScrollBarVisible ? assetsView.verticalThickness : 0)
+ height: img.height
+ color: mouseArea.containsMouse ? "#444444" : "transparent"
+
+ Row {
+ spacing: 5
+
+ Image {
+ id: img
+ asynchronous: true
+ width: 48
+ height: 48
+ source: "image://qmldesigner_assets/" + filePath
+ }
+
+ Text {
+ text: fileName
+ color: StudioTheme.Values.themeTextColor
+ font.pixelSize: 14
+ anchors.verticalCenter: parent.verticalCenter
+ }
+ }
+
+ readonly property string suffix: fileName.substr(-4)
+ readonly property bool isFont: suffix === ".ttf" || suffix === ".otf"
+
+ MouseArea {
+ id: mouseArea
+
+ anchors.fill: parent
+ hoverEnabled: true
+ acceptedButtons: Qt.LeftButton | Qt.RightButton
+
+ onExited: tooltipBackend.hideTooltip()
+ onCanceled: tooltipBackend.hideTooltip()
+ onPositionChanged: tooltipBackend.reposition()
+ onPressed: {
+ forceActiveFocus()
+ if (mouse.button === Qt.LeftButton)
+ rootView.startDragAsset(filePath)
+ else
+ print("TODO: impl context menu")
+ }
+
+ ToolTip {
+ visible: !isFont && mouseArea.containsMouse
+ text: filePath
+ delay: 1000
+ }
+
+ Timer {
+ interval: 1000
+ running: mouseArea.containsMouse
+ onTriggered: {
+ if (suffix === ".ttf" || suffix === ".otf") {
+ tooltipBackend.name = fileName
+ tooltipBackend.path = filePath
+ tooltipBackend.showTooltip()
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+}
diff --git a/share/qtcreator/qmldesigner/itemLibraryQmlSources/ItemsView.qml b/share/qtcreator/qmldesigner/itemLibraryQmlSources/ItemsView.qml
index f574917440..6742aceda8 100644
--- a/share/qtcreator/qmldesigner/itemLibraryQmlSources/ItemsView.qml
+++ b/share/qtcreator/qmldesigner/itemLibraryQmlSources/ItemsView.qml
@@ -225,7 +225,8 @@ ScrollView {
importToRemove = importRemovable ? importUrl : ""
currentImport = model
currentCategory = null
- moduleContextMenu.popup()
+ if (!rootView.isSearchActive())
+ moduleContextMenu.popup()
}
Column {
@@ -251,7 +252,8 @@ ScrollView {
onShowContextMenu: {
currentCategory = model
currentImport = parent.currentImportModel
- moduleContextMenu.popup()
+ if (!rootView.isSearchActive())
+ moduleContextMenu.popup()
}
Grid {
diff --git a/share/qtcreator/qmldesigner/itemLibraryQmlSources/LibraryHeader.qml b/share/qtcreator/qmldesigner/itemLibraryQmlSources/LibraryHeader.qml
index 164a103422..52570b230c 100644
--- a/share/qtcreator/qmldesigner/itemLibraryQmlSources/LibraryHeader.qml
+++ b/share/qtcreator/qmldesigner/itemLibraryQmlSources/LibraryHeader.qml
@@ -32,8 +32,6 @@ import StudioTheme 1.0 as StudioTheme
Item {
id: root
- width: 200
- height: 75
function setTab(index)
{
diff --git a/share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/HelperWidgets/ExtendedFunctionLogic.qml b/share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/HelperWidgets/ExtendedFunctionLogic.qml
index 57c39fcd68..d257ccf0cc 100644
--- a/share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/HelperWidgets/ExtendedFunctionLogic.qml
+++ b/share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/HelperWidgets/ExtendedFunctionLogic.qml
@@ -105,6 +105,13 @@ Item {
extendedFunctionButton.menuVisible = false
}
+ Connections {
+ target: modelNodeBackend
+ onSelectionChanged: {
+ menu.close()
+ }
+ }
+
StudioControls.MenuItem {
text: qsTr("Reset")
onTriggered: {
diff --git a/share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/HelperWidgets/Section.qml b/share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/HelperWidgets/Section.qml
index 09697c23ec..458c5d3150 100644
--- a/share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/HelperWidgets/Section.qml
+++ b/share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/HelperWidgets/Section.qml
@@ -38,12 +38,14 @@ Item {
property alias sectionFontSize: label.font.pixelSize
property alias showTopSeparator: topSeparator.visible
property alias showArrow: arrow.visible
+ property alias showLeftBorder: leftBorder.visible
property int leftPadding: 8
property int rightPadding: 0
property bool expanded: true
- property int level: 0
+ property int level: 0 // affects arrow and title
+ property int contentLevel: 0 // affects whole section
property int levelShift: 10
property bool hideHeader: false
property bool expandOnClick: true // if false, toggleExpand signal will be emitted instead
@@ -138,6 +140,14 @@ Item {
anchors.top: topSpacer.bottom
}
+ Rectangle {
+ id: leftBorder
+ visible: false
+ width: 1
+ height: parent.height - 15
+ color: header.color
+ }
+
Item {
id: bottomSpacer
height: addBottomPadding && row.height > 0 ? StudioTheme.Values.sectionHeadSpacerHeight : 0
@@ -160,12 +170,12 @@ Item {
]
transitions: Transition {
- id: trans
- enabled: false
- NumberAnimation {
- properties: "implicitHeight,rotation";
- duration: 120;
- easing.type: Easing.OutCubic
- }
+ id: trans
+ enabled: false
+ NumberAnimation {
+ properties: "implicitHeight,rotation";
+ duration: 120;
+ easing.type: Easing.OutCubic
}
+ }
}
diff --git a/share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/HelperWidgets/SpinBox.qml b/share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/HelperWidgets/SpinBox.qml
index 916bfc29d9..ca8f075fee 100644
--- a/share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/HelperWidgets/SpinBox.qml
+++ b/share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/HelperWidgets/SpinBox.qml
@@ -50,6 +50,17 @@ Item {
transaction.end();
}
+ Component.onCompleted: {
+ spinBox.enabled = !isBlocked(backendValue.name);
+ }
+
+ Connections {
+ target: modelNodeBackend
+ function onSelectionChanged() {
+ spinBox.enabled = !isBlocked(backendValue.name);
+ }
+ }
+
StudioControls.RealSpinBox {
id: spinBox
diff --git a/share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/StudioTheme/InternalConstants.qml b/share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/StudioTheme/InternalConstants.qml
index 19e319be32..bdbc8d95fc 100644
--- a/share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/StudioTheme/InternalConstants.qml
+++ b/share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/StudioTheme/InternalConstants.qml
@@ -48,99 +48,110 @@ QtObject {
readonly property string adsDropDown: "\u002B"
readonly property string alias: "\u002C"
readonly property string aliasAnimated: "\u002D"
- readonly property string aliasProperty: "\u002E"
- readonly property string alignBottom: "\u002F"
- readonly property string alignCenterHorizontal: "\u0030"
- readonly property string alignCenterVertical: "\u0031"
- readonly property string alignLeft: "\u0032"
- readonly property string alignRight: "\u0033"
- readonly property string alignTo: "\u0034"
- readonly property string alignTop: "\u0035"
- readonly property string anchorBaseline: "\u0036"
- readonly property string anchorBottom: "\u0037"
- readonly property string anchorFill: "\u0038"
- readonly property string anchorLeft: "\u0039"
- readonly property string anchorRight: "\u003A"
- readonly property string anchorTop: "\u003B"
- readonly property string animatedProperty: "\u003C"
- readonly property string annotationBubble: "\u003D"
- readonly property string annotationDecal: "\u003E"
- readonly property string assign: "\u003F"
- readonly property string centerHorizontal: "\u0040"
- readonly property string centerVertical: "\u0041"
- readonly property string closeCross: "\u0042"
- readonly property string curveDesigner: "\u0043"
- readonly property string curveEditor: "\u0044"
- readonly property string decisionNode: "\u0045"
- readonly property string deleteColumn: "\u0046"
- readonly property string deleteRow: "\u0047"
- readonly property string deleteTable: "\u0048"
- readonly property string detach: "\u0049"
- readonly property string distributeBottom: "\u004A"
- readonly property string distributeCenterHorizontal: "\u004B"
- readonly property string distributeCenterVertical: "\u004C"
- readonly property string distributeLeft: "\u004D"
- readonly property string distributeOriginBottomRight: "\u004E"
- readonly property string distributeOriginCenter: "\u004F"
- readonly property string distributeOriginNone: "\u0050"
- readonly property string distributeOriginTopLeft: "\u0051"
- readonly property string distributeRight: "\u0052"
- readonly property string distributeSpacingHorizontal: "\u0053"
- readonly property string distributeSpacingVertical: "\u0054"
- readonly property string distributeTop: "\u0055"
- readonly property string edit: "\u0056"
- readonly property string flowAction: "\u0057"
- readonly property string flowTransition: "\u0058"
- readonly property string fontStyleBold: "\u0059"
- readonly property string fontStyleItalic: "\u005A"
- readonly property string fontStyleStrikethrough: "\u005B"
- readonly property string fontStyleUnderline: "\u005C"
- readonly property string gridView: "\u005D"
- readonly property string idAliasOff: "\u005E"
- readonly property string idAliasOn: "\u005F"
- readonly property string keyframe: "\u0060"
- readonly property string linkTriangle: "\u0061"
- readonly property string linked: "\u0062"
- readonly property string listView: "\u0063"
- readonly property string lockOff: "\u0064"
- readonly property string lockOn: "\u0065"
- readonly property string mergeCells: "\u0066"
- readonly property string minus: "\u0067"
- readonly property string mirror: "\u0068"
- readonly property string pin: "\u0069"
- readonly property string plus: "\u006A"
- readonly property string promote: "\u006B"
- readonly property string redo: "\u006C"
- readonly property string rotationFill: "\u006D"
- readonly property string rotationOutline: "\u006E"
- readonly property string search: "\u006F"
- readonly property string splitColumns: "\u0070"
- readonly property string splitRows: "\u0071"
- readonly property string startNode: "\u0072"
- readonly property string testIcon: "\u0073"
- readonly property string textAlignBottom: "\u0074"
- readonly property string textAlignCenter: "\u0075"
- readonly property string textAlignLeft: "\u0076"
- readonly property string textAlignMiddle: "\u0077"
- readonly property string textAlignRight: "\u0078"
- readonly property string textAlignTop: "\u0079"
- readonly property string textBulletList: "\u007A"
- readonly property string textFullJustification: "\u007B"
- readonly property string textNumberedList: "\u007C"
- readonly property string tickIcon: "\u007D"
- readonly property string triState: "\u007E"
- readonly property string unLinked: "\u007F"
- readonly property string undo: "\u0080"
- readonly property string unpin: "\u0081"
- readonly property string upDownIcon: "\u0082"
- readonly property string upDownSquare2: "\u0083"
- readonly property string visibilityOff: "\u0084"
- readonly property string visibilityOn: "\u0085"
- readonly property string wildcard: "\u0086"
- readonly property string zoomAll: "\u0087"
- readonly property string zoomIn: "\u0088"
- readonly property string zoomOut: "\u0089"
- readonly property string zoomSelection: "\u008A"
+ readonly property string alignBottom: "\u002E"
+ readonly property string alignCenterHorizontal: "\u002F"
+ readonly property string alignCenterVertical: "\u0030"
+ readonly property string alignLeft: "\u0031"
+ readonly property string alignRight: "\u0032"
+ readonly property string alignTo: "\u0033"
+ readonly property string alignTop: "\u0034"
+ readonly property string anchorBaseline: "\u0035"
+ readonly property string anchorBottom: "\u0036"
+ readonly property string anchorFill: "\u0037"
+ readonly property string anchorLeft: "\u0038"
+ readonly property string anchorRight: "\u0039"
+ readonly property string anchorTop: "\u003A"
+ readonly property string animatedProperty: "\u003B"
+ readonly property string annotationBubble: "\u003C"
+ readonly property string annotationDecal: "\u003D"
+ readonly property string assign: "\u003E"
+ readonly property string bevelAll: "\u003F"
+ readonly property string bevelCorner: "\u0040"
+ readonly property string centerHorizontal: "\u0041"
+ readonly property string centerVertical: "\u0042"
+ readonly property string closeCross: "\u0043"
+ readonly property string copyStyle: "\u0044"
+ readonly property string cornerA: "\u0045"
+ readonly property string cornerB: "\u0046"
+ readonly property string cornersAll: "\u0047"
+ readonly property string curveDesigner: "\u0048"
+ readonly property string curveEditor: "\u0049"
+ readonly property string decisionNode: "\u004A"
+ readonly property string deleteColumn: "\u004B"
+ readonly property string deleteRow: "\u004C"
+ readonly property string deleteTable: "\u004D"
+ readonly property string detach: "\u004E"
+ readonly property string distributeBottom: "\u004F"
+ readonly property string distributeCenterHorizontal: "\u0050"
+ readonly property string distributeCenterVertical: "\u0051"
+ readonly property string distributeLeft: "\u0052"
+ readonly property string distributeOriginBottomRight: "\u0053"
+ readonly property string distributeOriginCenter: "\u0054"
+ readonly property string distributeOriginNone: "\u0055"
+ readonly property string distributeOriginTopLeft: "\u0056"
+ readonly property string distributeRight: "\u0057"
+ readonly property string distributeSpacingHorizontal: "\u0058"
+ readonly property string distributeSpacingVertical: "\u0059"
+ readonly property string distributeTop: "\u005A"
+ readonly property string edit: "\u005B"
+ readonly property string eyeDropper: "\u005C"
+ readonly property string flowAction: "\u005D"
+ readonly property string flowTransition: "\u005E"
+ readonly property string fontStyleBold: "\u005F"
+ readonly property string fontStyleItalic: "\u0060"
+ readonly property string fontStyleStrikethrough: "\u0061"
+ readonly property string fontStyleUnderline: "\u0062"
+ readonly property string gradient: "\u0063"
+ readonly property string gridView: "\u0064"
+ readonly property string idAliasOff: "\u0065"
+ readonly property string idAliasOn: "\u0066"
+ readonly property string keyframe: "\u0067"
+ readonly property string linkTriangle: "\u0068"
+ readonly property string linked: "\u0069"
+ readonly property string listView: "\u006A"
+ readonly property string lockOff: "\u006B"
+ readonly property string lockOn: "\u006C"
+ readonly property string mergeCells: "\u006D"
+ readonly property string minus: "\u006E"
+ readonly property string mirror: "\u006F"
+ readonly property string paddingEdge: "\u0070"
+ readonly property string paddingFrame: "\u0071"
+ readonly property string pasteStyle: "\u0072"
+ readonly property string pin: "\u0073"
+ readonly property string plus: "\u0074"
+ readonly property string promote: "\u0075"
+ readonly property string redo: "\u0076"
+ readonly property string rotationFill: "\u0077"
+ readonly property string rotationOutline: "\u0078"
+ readonly property string search: "\u0079"
+ readonly property string splitColumns: "\u007A"
+ readonly property string splitRows: "\u007B"
+ readonly property string startNode: "\u007C"
+ readonly property string testIcon: "\u007D"
+ readonly property string textAlignBottom: "\u007E"
+ readonly property string textAlignCenter: "\u007F"
+ readonly property string textAlignLeft: "\u0080"
+ readonly property string textAlignMiddle: "\u0081"
+ readonly property string textAlignRight: "\u0082"
+ readonly property string textAlignTop: "\u0083"
+ readonly property string textBulletList: "\u0084"
+ readonly property string textFullJustification: "\u0085"
+ readonly property string textNumberedList: "\u0086"
+ readonly property string tickIcon: "\u0087"
+ readonly property string transparent: "\u0088"
+ readonly property string triState: "\u0089"
+ readonly property string unLinked: "\u008A"
+ readonly property string undo: "\u008B"
+ readonly property string unpin: "\u008C"
+ readonly property string upDownIcon: "\u008D"
+ readonly property string upDownSquare2: "\u008E"
+ readonly property string visibilityOff: "\u008F"
+ readonly property string visibilityOn: "\u0090"
+ readonly property string wildcard: "\u0091"
+ readonly property string zoomAll: "\u0092"
+ readonly property string zoomIn: "\u0093"
+ readonly property string zoomOut: "\u0094"
+ readonly property string zoomSelection: "\u0095"
readonly property font iconFont: Qt.font({
"family": controlIcons.name,
diff --git a/share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/StudioTheme/icons.ttf b/share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/StudioTheme/icons.ttf
index aef8a37d56..fb3e387077 100644
--- a/share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/StudioTheme/icons.ttf
+++ b/share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/StudioTheme/icons.ttf
Binary files differ
diff --git a/share/qtcreator/styles/creator-dark.xml b/share/qtcreator/styles/creator-dark.xml
index 1ab4653423..b86483f30f 100644
--- a/share/qtcreator/styles/creator-dark.xml
+++ b/share/qtcreator/styles/creator-dark.xml
@@ -20,6 +20,7 @@
<style name="String" foreground="#d69545"/>
<style name="Type" foreground="#ff8080"/>
<style name="Local" foreground="#d6bb9a"/>
+ <style name="Parameter" foreground="#d6bb9a"/>
<style name="Global" foreground="#9aa7d6"/>
<style name="Field"/>
<style name="Static" foreground="#66a334" italic="true"/>
diff --git a/share/qtcreator/styles/intellij.xml b/share/qtcreator/styles/intellij.xml
index b4a30c3f84..ee579f0e36 100644
--- a/share/qtcreator/styles/intellij.xml
+++ b/share/qtcreator/styles/intellij.xml
@@ -13,6 +13,7 @@
<style name="PrimitiveType" foreground="#000080" bold="true"/>
<style name="Label" foreground="#800000" bold="true"/>
<style name="Local" foreground="#000000"/>
+ <style name="Parameter" foreground="#000000"/>
<style name="Number" foreground="#0000ff"/>
<style name="Operator" foreground="#000000"/>
<style name="Overloaded Operator" foreground="#000000"/>
diff --git a/share/qtcreator/styles/solarized-dark.xml b/share/qtcreator/styles/solarized-dark.xml
index 1d7b64058d..6930af67e0 100644
--- a/share/qtcreator/styles/solarized-dark.xml
+++ b/share/qtcreator/styles/solarized-dark.xml
@@ -26,6 +26,7 @@
<style name="String" foreground="#2aa198"/>
<style name="Type" foreground="#b58900"/>
<style name="Local" foreground="#839496"/>
+ <style name="Parameter" foreground="#839496"/>
<style name="Global"/>
<style name="Field" foreground="#268bd2"/>
<style name="Static" foreground="#b58900" italic="true"/>
diff --git a/share/qtcreator/styles/solarized-light.xml b/share/qtcreator/styles/solarized-light.xml
index 4344e94d64..221fc8c211 100644
--- a/share/qtcreator/styles/solarized-light.xml
+++ b/share/qtcreator/styles/solarized-light.xml
@@ -26,6 +26,7 @@
<style name="String" foreground="#2aa198"/>
<style name="Type" foreground="#b58900"/>
<style name="Local" foreground="#657b83"/>
+ <style name="Parameter" foreground="#657b83"/>
<style name="Global"/>
<style name="Field" foreground="#268bd2"/>
<style name="Static" foreground="#b58900" italic="true"/>
diff --git a/share/qtcreator/templates/wizards/projects/qtquickapplication/empty/wizard.json b/share/qtcreator/templates/wizards/projects/qtquickapplication/empty/wizard.json
index 444f22d2de..2cf267e30d 100644
--- a/share/qtcreator/templates/wizards/projects/qtquickapplication/empty/wizard.json
+++ b/share/qtcreator/templates/wizards/projects/qtquickapplication/empty/wizard.json
@@ -20,7 +20,7 @@
{ "key": "QtQuickVersion", "value": "%{JS: value('QtVersion').QtQuickVersion}" },
{ "key": "QtQuickWindowVersion", "value": "%{JS: value('QtVersion').QtQuickWindowVersion}" },
{ "key": "QtQuickVirtualKeyboardImport", "value": "%{JS: value('QtVersion').QtQuickVirtualKeyboardImport}" },
- { "key": "QtQuickFeature", "value": "QtSupport.Wizards.FeatureQtQuick.%{QtQuickVersion}" },
+ { "key": "QtQuickFeature", "value": "%{JS: (value('QtQuickVersion')=='') ? 'QtSupport.Wizards.FeatureQtQuick.6' : 'QtSupport.Wizards.FeatureQtQuick.%{QtQuickVersion}'}" },
{ "key": "UseVirtualKeyboardByDefault", "value": "%{JS: value('Plugins').indexOf('Boot2Qt') >= 0 || value('Plugins').indexOf('Boot2QtQdb') >= 0}" },
{ "key": "HasTranslation", "value": "%{JS: value('TsFileName') !== ''}" },
{ "key": "SetQPAPhysicalSize", "value": "%{UseVirtualKeyboardByDefault}" }
@@ -83,10 +83,19 @@
"persistenceKey": "QtQuick.minimumQtVersion",
"data":
{
- "index": 3,
+ "index": 1,
"items":
[
{
+ "trKey": "Qt 6",
+ "value":
+ {
+ "QtQuickVersion": "",
+ "QtQuickWindowVersion": "",
+ "QtQuickVirtualKeyboardImport": "QtQuick.VirtualKeyboard"
+ }
+ },
+ {
"trKey": "Qt 5.15",
"value":
{
@@ -121,60 +130,6 @@
"QtQuickWindowVersion": "2.12",
"QtQuickVirtualKeyboardImport": "QtQuick.VirtualKeyboard 2.4"
}
- },
- {
- "trKey": "Qt 5.11",
- "value":
- {
- "QtQuickVersion": "2.11",
- "QtQuickWindowVersion": "2.11",
- "QtQuickVirtualKeyboardImport": "QtQuick.VirtualKeyboard 2.3"
- }
- },
- {
- "trKey": "Qt 5.10",
- "value":
- {
- "QtQuickVersion": "2.10",
- "QtQuickWindowVersion": "2.10",
- "QtQuickVirtualKeyboardImport": "QtQuick.VirtualKeyboard 2.3"
- }
- },
- {
- "trKey": "Qt 5.9",
- "value":
- {
- "QtQuickVersion": "2.9",
- "QtQuickWindowVersion": "2.2",
- "QtQuickVirtualKeyboardImport": "QtQuick.VirtualKeyboard 2.2"
- }
- },
- {
- "trKey": "Qt 5.8",
- "value":
- {
- "QtQuickVersion": "2.8",
- "QtQuickWindowVersion": "2.2",
- "QtQuickVirtualKeyboardImport": "QtQuick.VirtualKeyboard 2.1"
- }
- },
- {
- "trKey": "Qt 5.7",
- "value":
- {
- "QtQuickVersion": "2.7",
- "QtQuickWindowVersion": "2.2",
- "QtQuickVirtualKeyboardImport": "QtQuick.VirtualKeyboard 2.1"
- }
- },
- {
- "trKey": "Qt 5.6",
- "value":
- {
- "QtQuickVersion": "2.6",
- "QtQuickWindowVersion": "2.2",
- "QtQuickVirtualKeyboardImport": "QtQuick.Enterprise.VirtualKeyboard 2.0"
- }
}
]
}
diff --git a/share/qtcreator/templates/wizards/projects/qtquickapplication/scroll/wizard.json b/share/qtcreator/templates/wizards/projects/qtquickapplication/scroll/wizard.json
index c7acc28ddd..6a02548958 100644
--- a/share/qtcreator/templates/wizards/projects/qtquickapplication/scroll/wizard.json
+++ b/share/qtcreator/templates/wizards/projects/qtquickapplication/scroll/wizard.json
@@ -22,7 +22,7 @@
{ "key": "QtQuickVirtualKeyboardImport", "value": "%{JS: value('QtVersion').QtQuickVirtualKeyboardImport}" },
{ "key": "QtQuickControlsStyle", "value": "%{JS: value('ControlsStyle').QtQuickControlsStyle}" },
{ "key": "QtQuickControlsStyleTheme", "value": "%{JS: value('ControlsStyle').QtQuickControlsStyleTheme}" },
- { "key": "QtQuickFeature", "value": "QtSupport.Wizards.FeatureQtQuick.%{QtQuickVersion}" },
+ { "key": "QtQuickFeature", "value": "%{JS: (value('QtQuickVersion')=='') ? 'QtSupport.Wizards.FeatureQtQuick.6' : 'QtSupport.Wizards.FeatureQtQuick.%{QtQuickVersion}'}" },
{ "key": "UseVirtualKeyboardByDefault", "value": "%{JS: value('Plugins').indexOf('Boot2Qt') >= 0 || value('Plugins').indexOf('Boot2QtQdb') >= 0}" },
{ "key": "HasTranslation", "value": "%{JS: value('TsFileName') !== ''}" },
{ "key": "SetQPAPhysicalSize", "value": "%{UseVirtualKeyboardByDefault}" }
@@ -85,10 +85,19 @@
"persistenceKey": "QtQuick.minimumQtVersion",
"data":
{
- "index": 3,
+ "index": 1,
"items":
[
{
+ "trKey": "Qt 6",
+ "value":
+ {
+ "QtQuickVersion": "",
+ "QtQuickControlsVersion": "",
+ "QtQuickVirtualKeyboardImport": "QtQuick.VirtualKeyboard"
+ }
+ },
+ {
"trKey": "Qt 5.15",
"value":
{
@@ -123,33 +132,6 @@
"QtQuickControlsVersion": "2.5",
"QtQuickVirtualKeyboardImport": "QtQuick.VirtualKeyboard 2.4"
}
- },
- {
- "trKey": "Qt 5.11",
- "value":
- {
- "QtQuickVersion": "2.11",
- "QtQuickControlsVersion": "2.4",
- "QtQuickVirtualKeyboardImport": "QtQuick.VirtualKeyboard 2.3"
- }
- },
- {
- "trKey": "Qt 5.10",
- "value":
- {
- "QtQuickVersion": "2.10",
- "QtQuickControlsVersion": "2.3",
- "QtQuickVirtualKeyboardImport": "QtQuick.VirtualKeyboard 2.3"
- }
- },
- {
- "trKey": "Qt 5.9",
- "value":
- {
- "QtQuickVersion": "2.9",
- "QtQuickControlsVersion": "2.2",
- "QtQuickVirtualKeyboardImport": "QtQuick.VirtualKeyboard 2.2"
- }
}
]
}
@@ -204,7 +186,7 @@
}
},
{
- "trKey": "Fusion (Qt 5.10+)",
+ "trKey": "Fusion",
"value":
{
"QtQuickControlsStyle": "Fusion",
@@ -212,7 +194,7 @@
}
},
{
- "trKey": "Imagine (Qt 5.10+)",
+ "trKey": "Imagine",
"value":
{
"QtQuickControlsStyle": "Imagine",
diff --git a/share/qtcreator/templates/wizards/projects/qtquickapplication/stack/wizard.json b/share/qtcreator/templates/wizards/projects/qtquickapplication/stack/wizard.json
index 572292ec75..8752c9062c 100644
--- a/share/qtcreator/templates/wizards/projects/qtquickapplication/stack/wizard.json
+++ b/share/qtcreator/templates/wizards/projects/qtquickapplication/stack/wizard.json
@@ -22,7 +22,7 @@
{ "key": "QtQuickVirtualKeyboardImport", "value": "%{JS: value('QtVersion').QtQuickVirtualKeyboardImport}" },
{ "key": "QtQuickControlsStyle", "value": "%{JS: value('ControlsStyle').QtQuickControlsStyle}" },
{ "key": "QtQuickControlsStyleTheme", "value": "%{JS: value('ControlsStyle').QtQuickControlsStyleTheme}" },
- { "key": "QtQuickFeature", "value": "QtSupport.Wizards.FeatureQtQuick.%{QtQuickVersion}" },
+ { "key": "QtQuickFeature", "value": "%{JS: (value('QtQuickVersion')=='') ? 'QtSupport.Wizards.FeatureQtQuick.6' : 'QtSupport.Wizards.FeatureQtQuick.%{QtQuickVersion}'}" },
{ "key": "UseVirtualKeyboardByDefault", "value": "%{JS: value('Plugins').indexOf('Boot2Qt') >= 0 || value('Plugins').indexOf('Boot2QtQdb') >= 0}" },
{ "key": "HasTranslation", "value": "%{JS: value('TsFileName') !== ''}" },
{ "key": "SetQPAPhysicalSize", "value": "%{UseVirtualKeyboardByDefault}" }
@@ -85,10 +85,19 @@
"persistenceKey": "QtQuick.minimumQtVersion",
"data":
{
- "index": 3,
+ "index": 1,
"items":
[
{
+ "trKey": "Qt 6",
+ "value":
+ {
+ "QtQuickVersion": "",
+ "QtQuickControlsVersion": "",
+ "QtQuickVirtualKeyboardImport": "QtQuick.VirtualKeyboard"
+ }
+ },
+ {
"trKey": "Qt 5.15",
"value":
{
@@ -124,51 +133,6 @@
"QtQuickVirtualKeyboardImport": "QtQuick.VirtualKeyboard 2.4"
}
},
- {
- "trKey": "Qt 5.11",
- "value":
- {
- "QtQuickVersion": "2.11",
- "QtQuickControlsVersion": "2.4",
- "QtQuickVirtualKeyboardImport": "QtQuick.VirtualKeyboard 2.3"
- }
- },
- {
- "trKey": "Qt 5.10",
- "value":
- {
- "QtQuickVersion": "2.10",
- "QtQuickControlsVersion": "2.3",
- "QtQuickVirtualKeyboardImport": "QtQuick.VirtualKeyboard 2.3"
- }
- },
- {
- "trKey": "Qt 5.9",
- "value":
- {
- "QtQuickVersion": "2.9",
- "QtQuickControlsVersion": "2.2",
- "QtQuickVirtualKeyboardImport": "QtQuick.VirtualKeyboard 2.2"
- }
- },
- {
- "trKey": "Qt 5.8",
- "value":
- {
- "QtQuickVersion": "2.8",
- "QtQuickControlsVersion": "2.1",
- "QtQuickVirtualKeyboardImport": "QtQuick.VirtualKeyboard 2.1"
- }
- },
- {
- "trKey": "Qt 5.7",
- "value":
- {
- "QtQuickVersion": "2.7",
- "QtQuickControlsVersion": "2.0",
- "QtQuickVirtualKeyboardImport": "QtQuick.VirtualKeyboard 2.1"
- }
- }
]
}
},
@@ -222,7 +186,7 @@
}
},
{
- "trKey": "Fusion (Qt 5.10+)",
+ "trKey": "Fusion",
"value":
{
"QtQuickControlsStyle": "Fusion",
@@ -230,7 +194,7 @@
}
},
{
- "trKey": "Imagine (Qt 5.10+)",
+ "trKey": "Imagine",
"value":
{
"QtQuickControlsStyle": "Imagine",
diff --git a/share/qtcreator/templates/wizards/projects/qtquickapplication/swipe/wizard.json b/share/qtcreator/templates/wizards/projects/qtquickapplication/swipe/wizard.json
index 4f7e8f1479..3e44affe58 100644
--- a/share/qtcreator/templates/wizards/projects/qtquickapplication/swipe/wizard.json
+++ b/share/qtcreator/templates/wizards/projects/qtquickapplication/swipe/wizard.json
@@ -22,7 +22,7 @@
{ "key": "QtQuickVirtualKeyboardImport", "value": "%{JS: value('QtVersion').QtQuickVirtualKeyboardImport}" },
{ "key": "QtQuickControlsStyle", "value": "%{JS: value('ControlsStyle').QtQuickControlsStyle}" },
{ "key": "QtQuickControlsStyleTheme", "value": "%{JS: value('ControlsStyle').QtQuickControlsStyleTheme}" },
- { "key": "QtQuickFeature", "value": "QtSupport.Wizards.FeatureQtQuick.%{QtQuickVersion}" },
+ { "key": "QtQuickFeature", "value": "%{JS: (value('QtQuickVersion')=='') ? 'QtSupport.Wizards.FeatureQtQuick.6' : 'QtSupport.Wizards.FeatureQtQuick.%{QtQuickVersion}'}" },
{ "key": "UseVirtualKeyboardByDefault", "value": "%{JS: value('Plugins').indexOf('Boot2Qt') >= 0 || value('Plugins').indexOf('Boot2QtQdb') >= 0}" },
{ "key": "HasTranslation", "value": "%{JS: value('TsFileName') !== ''}" },
{ "key": "SetQPAPhysicalSize", "value": "%{UseVirtualKeyboardByDefault}" }
@@ -85,10 +85,19 @@
"persistenceKey": "QtQuick.minimumQtVersion",
"data":
{
- "index": 3,
+ "index": 1,
"items":
[
{
+ "trKey": "Qt 6",
+ "value":
+ {
+ "QtQuickVersion": "",
+ "QtQuickControlsVersion": "",
+ "QtQuickVirtualKeyboardImport": "QtQuick.VirtualKeyboard"
+ }
+ },
+ {
"trKey": "Qt 5.15",
"value":
{
@@ -123,51 +132,6 @@
"QtQuickControlsVersion": "2.5",
"QtQuickVirtualKeyboardImport": "QtQuick.VirtualKeyboard 2.4"
}
- },
- {
- "trKey": "Qt 5.11",
- "value":
- {
- "QtQuickVersion": "2.11",
- "QtQuickControlsVersion": "2.4",
- "QtQuickVirtualKeyboardImport": "QtQuick.VirtualKeyboard 2.3"
- }
- },
- {
- "trKey": "Qt 5.10",
- "value":
- {
- "QtQuickVersion": "2.10",
- "QtQuickControlsVersion": "2.3",
- "QtQuickVirtualKeyboardImport": "QtQuick.VirtualKeyboard 2.3"
- }
- },
- {
- "trKey": "Qt 5.9",
- "value":
- {
- "QtQuickVersion": "2.9",
- "QtQuickControlsVersion": "2.2",
- "QtQuickVirtualKeyboardImport": "QtQuick.VirtualKeyboard 2.2"
- }
- },
- {
- "trKey": "Qt 5.8",
- "value":
- {
- "QtQuickVersion": "2.8",
- "QtQuickControlsVersion": "2.1",
- "QtQuickVirtualKeyboardImport": "QtQuick.VirtualKeyboard 2.1"
- }
- },
- {
- "trKey": "Qt 5.7",
- "value":
- {
- "QtQuickVersion": "2.7",
- "QtQuickControlsVersion": "2.0",
- "QtQuickVirtualKeyboardImport": "QtQuick.VirtualKeyboard 2.1"
- }
}
]
}
@@ -222,7 +186,7 @@
}
},
{
- "trKey": "Fusion (Qt 5.10+)",
+ "trKey": "Fusion",
"value":
{
"QtQuickControlsStyle": "Fusion",
@@ -230,7 +194,7 @@
}
},
{
- "trKey": "Imagine (Qt 5.10+)",
+ "trKey": "Imagine",
"value":
{
"QtQuickControlsStyle": "Imagine",
diff --git a/share/qtcreator/templates/wizards/projects/qtquickuiprototype/wizard.json b/share/qtcreator/templates/wizards/projects/qtquickuiprototype/wizard.json
index ac39bb90be..d5642f0a98 100644
--- a/share/qtcreator/templates/wizards/projects/qtquickuiprototype/wizard.json
+++ b/share/qtcreator/templates/wizards/projects/qtquickuiprototype/wizard.json
@@ -17,7 +17,7 @@
{ "key": "QtQuickVersion", "value": "%{JS: value('QtVersion').QtQuickVersion}" },
{ "key": "QtQuickWindowVersion", "value": "%{JS: value('QtVersion').QtQuickWindowVersion}" },
{ "key": "QtQuickVirtualKeyboardImport", "value": "%{JS: value('QtVersion').QtQuickVirtualKeyboardImport}" },
- { "key": "QtQuickFeature", "value": "QtSupport.Wizards.FeatureQtQuick.%{QtQuickVersion}" },
+ { "key": "QtQuickFeature", "value": "%{JS: (value('QtQuickVersion')=='') ? 'QtSupport.Wizards.FeatureQtQuick.6' : 'QtSupport.Wizards.FeatureQtQuick.%{QtQuickVersion}'}" },
{ "key": "UseVirtualKeyboardByDefault", "value": "%{JS: value('Plugins').indexOf('Boot2Qt') >= 0 || value('Plugins').indexOf('Boot2QtQdb') >= 0}" }
],
@@ -40,10 +40,19 @@
"type": "ComboBox",
"data":
{
- "index": 3,
+ "index": 1,
"items":
[
{
+ "trKey": "Qt 6",
+ "value":
+ {
+ "QtQuickVersion": "",
+ "QtQuickWindowVersion": "",
+ "QtQuickVirtualKeyboardImport": ""
+ }
+ },
+ {
"trKey": "Qt 5.15",
"value":
{
@@ -78,60 +87,6 @@
"QtQuickWindowVersion": "2.12",
"QtQuickVirtualKeyboardImport": "QtQuick.VirtualKeyboard 2.4"
}
- },
- {
- "trKey": "Qt 5.11",
- "value":
- {
- "QtQuickVersion": "2.11",
- "QtQuickWindowVersion": "2.11",
- "QtQuickVirtualKeyboardImport": "QtQuick.VirtualKeyboard 2.3"
- }
- },
- {
- "trKey": "Qt 5.10",
- "value":
- {
- "QtQuickVersion": "2.10",
- "QtQuickWindowVersion": "2.10",
- "QtQuickVirtualKeyboardImport": "QtQuick.VirtualKeyboard 2.3"
- }
- },
- {
- "trKey": "Qt 5.9",
- "value":
- {
- "QtQuickVersion": "2.9",
- "QtQuickWindowVersion": "2.2",
- "QtQuickVirtualKeyboardImport": "QtQuick.VirtualKeyboard 2.2"
- }
- },
- {
- "trKey": "Qt 5.8",
- "value":
- {
- "QtQuickVersion": "2.8",
- "QtQuickWindowVersion": "2.2",
- "QtQuickVirtualKeyboardImport": "QtQuick.VirtualKeyboard 2.1"
- }
- },
- {
- "trKey": "Qt 5.7",
- "value":
- {
- "QtQuickVersion": "2.7",
- "QtQuickWindowVersion": "2.2",
- "QtQuickVirtualKeyboardImport": "QtQuick.VirtualKeyboard 2.1"
- }
- },
- {
- "trKey": "Qt 5.6",
- "value":
- {
- "QtQuickVersion": "2.6",
- "QtQuickWindowVersion": "2.2",
- "QtQuickVirtualKeyboardImport": "QtQuick.Enterprise.VirtualKeyboard 2.0"
- }
}
]
}
diff --git a/share/share.pro b/share/share.pro
index 3fe6c8b32c..757e0ed595 100644
--- a/share/share.pro
+++ b/share/share.pro
@@ -1,6 +1,23 @@
TEMPLATE = subdirs
SUBDIRS = qtcreator/static.pro
+include(../qtcreator.pri)
+
+linux {
+ appdata = $$cat($$PWD/metainfo/org.qt-project.qtcreator.appdata.xml.cmakein, blob)
+ appdata = $$replace(appdata, \\$\\{IDE_VERSION_DISPLAY\\}, $$QTCREATOR_DISPLAY_VERSION)
+ appdata = $$replace(appdata, \\$\\{DATE_ATTRIBUTE\\}, "")
+ write_file($$OUT_PWD/metainfo/org.qt-project.qtcreator.appdata.xml, appdata)
+
+ appstream.files = $$OUT_PWD/metainfo/org.qt-project.qtcreator.appdata.xml
+ appstream.path = $$QTC_PREFIX/share/metainfo/
+
+ desktop.files = share/applications/org.qt-project.qtcreator.desktop
+ desktop.path = $$QTC_PREFIX/share/applications/
+
+ INSTALLS += appstream desktop
+}
+
defineTest(hasLupdate) {
cmd = $$eval(QT_TOOL.lupdate.binary)
isEmpty(cmd) {
diff --git a/src/app/app_version_header.qbs b/src/app/app_version_header.qbs
index 7d091bba0e..59cd014df7 100644
--- a/src/app/app_version_header.qbs
+++ b/src/app/app_version_header.qbs
@@ -68,6 +68,6 @@ Product {
Export {
Depends { name: "cpp" }
- cpp.includePaths: product.buildDirectory
+ cpp.includePaths: exportingProduct.buildDirectory
}
}
diff --git a/src/libs/3rdparty/CMakeLists.txt b/src/libs/3rdparty/CMakeLists.txt
index 7cf97ab87f..8297f25690 100644
--- a/src/libs/3rdparty/CMakeLists.txt
+++ b/src/libs/3rdparty/CMakeLists.txt
@@ -1,2 +1,3 @@
add_subdirectory(cplusplus)
add_subdirectory(syntax-highlighting)
+add_subdirectory(minitrace)
diff --git a/src/libs/3rdparty/cplusplus/Symbol.cpp b/src/libs/3rdparty/cplusplus/Symbol.cpp
index 62100474b4..05254e9d96 100644
--- a/src/libs/3rdparty/cplusplus/Symbol.cpp
+++ b/src/libs/3rdparty/cplusplus/Symbol.cpp
@@ -450,5 +450,5 @@ Utils::Link Symbol::toLink() const
if (isGenerated())
column = 0;
- return Utils::Link(filename, line, column);
+ return Utils::Link(Utils::FilePath::fromString(filename), line, column);
}
diff --git a/src/libs/3rdparty/cplusplus/Symbol.h b/src/libs/3rdparty/cplusplus/Symbol.h
index ae441b339b..3e1b525a62 100644
--- a/src/libs/3rdparty/cplusplus/Symbol.h
+++ b/src/libs/3rdparty/cplusplus/Symbol.h
@@ -22,7 +22,7 @@
#include "CPlusPlusForwardDeclarations.h"
-namespace Utils { struct Link; }
+namespace Utils { class Link; }
namespace CPlusPlus {
diff --git a/src/libs/3rdparty/minitrace/CMakeLists.txt b/src/libs/3rdparty/minitrace/CMakeLists.txt
new file mode 100644
index 0000000000..726e022cb1
--- /dev/null
+++ b/src/libs/3rdparty/minitrace/CMakeLists.txt
@@ -0,0 +1,9 @@
+
+# Enable with BUILD_LIBRARY_MINITRACE=ON
+add_qtc_library(Minitrace
+ BUILD_DEFAULT OFF
+ DEFINES MINITRACE_LIBRARY
+ PUBLIC_DEFINES MTR_ENABLED
+ SOURCES private/minitrace.c
+)
+
diff --git a/src/libs/3rdparty/minitrace/private/minitrace.c b/src/libs/3rdparty/minitrace/private/minitrace.c
new file mode 100644
index 0000000000..2877f048e8
--- /dev/null
+++ b/src/libs/3rdparty/minitrace/private/minitrace.c
@@ -0,0 +1,484 @@
+// minitrace
+// Copyright 2014 by Henrik Rydgård
+// http://www.github.com/hrydgard/minitrace
+// Released under the MIT license.
+
+// See minitrace.h for basic documentation.
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+
+#ifdef _WIN32
+#pragma warning (disable:4996)
+#define WIN32_LEAN_AND_MEAN
+#include <windows.h>
+#define __thread __declspec(thread)
+#define pthread_mutex_t CRITICAL_SECTION
+#define pthread_mutex_init(a, b) InitializeCriticalSection(a)
+#define pthread_mutex_lock(a) EnterCriticalSection(a)
+#define pthread_mutex_unlock(a) LeaveCriticalSection(a)
+#define pthread_mutex_destroy(a) DeleteCriticalSection(a)
+#else
+#include <signal.h>
+#include <pthread.h>
+#include <sys/time.h>
+#include <unistd.h>
+#endif
+
+#include "minitrace.h"
+
+#ifdef __GNUC__
+#define ATTR_NORETURN __attribute__((noreturn))
+#else
+#define ATTR_NORETURN
+#endif
+
+#define ARRAY_SIZE(x) sizeof(x)/sizeof(x[0])
+#define TRUE 1
+#define FALSE 0
+
+// Ugh, this struct is already pretty heavy.
+// Will probably need to move arguments to a second buffer to support more than one.
+typedef struct raw_event {
+ const char *name;
+ const char *cat;
+ void *id;
+ int64_t ts;
+ uint32_t pid;
+ uint32_t tid;
+ char ph;
+ mtr_arg_type arg_type;
+ const char *arg_name;
+ union {
+ const char *a_str;
+ int a_int;
+ double a_double;
+ };
+} raw_event_t;
+
+static raw_event_t *event_buffer;
+static raw_event_t *flush_buffer;
+static volatile int event_count;
+static int is_tracing = FALSE;
+static int is_flushing = FALSE;
+static int events_in_progress = 0;
+static int64_t time_offset;
+static int first_line = 1;
+static FILE *f;
+static __thread int cur_thread_id; // Thread local storage
+static int cur_process_id;
+static pthread_mutex_t mutex;
+static pthread_mutex_t event_mutex;
+
+#define STRING_POOL_SIZE 100
+static char *str_pool[100];
+
+// forward declaration
+void mtr_flush_with_state(int);
+
+// Tiny portability layer.
+// Exposes:
+// get_cur_thread_id()
+// get_cur_process_id()
+// mtr_time_s()
+// pthread basics
+#ifdef _WIN32
+static int get_cur_thread_id() {
+ return (int)GetCurrentThreadId();
+}
+static int get_cur_process_id() {
+ return (int)GetCurrentProcessId();
+}
+
+static uint64_t _frequency = 0;
+static uint64_t _starttime = 0;
+double mtr_time_s() {
+ if (_frequency == 0) {
+ QueryPerformanceFrequency((LARGE_INTEGER*)&_frequency);
+ QueryPerformanceCounter((LARGE_INTEGER*)&_starttime);
+ }
+ __int64 time;
+ QueryPerformanceCounter((LARGE_INTEGER*)&time);
+ return ((double) (time - _starttime) / (double) _frequency);
+}
+
+// Ctrl+C handling for Windows console apps
+static BOOL WINAPI CtrlHandler(DWORD fdwCtrlType) {
+ if (is_tracing && fdwCtrlType == CTRL_C_EVENT) {
+ printf("Ctrl-C detected! Flushing trace and shutting down.\n\n");
+ mtr_flush();
+ mtr_shutdown();
+ }
+ ExitProcess(1);
+}
+
+void mtr_register_sigint_handler() {
+ // For console apps:
+ SetConsoleCtrlHandler(&CtrlHandler, TRUE);
+}
+
+#else
+
+static inline int get_cur_thread_id() {
+ return (int)(intptr_t)pthread_self();
+}
+static inline int get_cur_process_id() {
+ return (int)getpid();
+}
+
+#if defined(BLACKBERRY)
+double mtr_time_s() {
+ struct timespec time;
+ clock_gettime(CLOCK_MONOTONIC, &time); // Linux must use CLOCK_MONOTONIC_RAW due to time warps
+ return time.tv_sec + time.tv_nsec / 1.0e9;
+}
+#else
+double mtr_time_s() {
+ static time_t start;
+ struct timeval tv;
+ gettimeofday(&tv, NULL);
+ if (start == 0) {
+ start = tv.tv_sec;
+ }
+ tv.tv_sec -= start;
+ return (double)tv.tv_sec + (double)tv.tv_usec / 1000000.0;
+}
+#endif // !BLACKBERRY
+
+static void termination_handler(int signum) ATTR_NORETURN;
+static void termination_handler(int signum) {
+ (void) signum;
+ if (is_tracing) {
+ printf("Ctrl-C detected! Flushing trace and shutting down.\n\n");
+ mtr_flush();
+ fwrite("\n]}\n", 1, 4, f);
+ fclose(f);
+ }
+ exit(1);
+}
+
+void mtr_register_sigint_handler() {
+#ifndef MTR_ENABLED
+ return;
+#endif
+ // Avoid altering set-to-be-ignored handlers while registering.
+ if (signal(SIGINT, &termination_handler) == SIG_IGN)
+ signal(SIGINT, SIG_IGN);
+}
+
+#endif
+
+void mtr_init_from_stream(void *stream) {
+#ifndef MTR_ENABLED
+ return;
+#endif
+ event_buffer = (raw_event_t *)malloc(INTERNAL_MINITRACE_BUFFER_SIZE * sizeof(raw_event_t));
+ flush_buffer = (raw_event_t *)malloc(INTERNAL_MINITRACE_BUFFER_SIZE * sizeof(raw_event_t));
+ is_tracing = 1;
+ event_count = 0;
+ f = (FILE *)stream;
+ const char *header = "{\"traceEvents\":[\n";
+ fwrite(header, 1, strlen(header), f);
+ time_offset = (uint64_t)(mtr_time_s() * 1000000);
+ first_line = 1;
+ pthread_mutex_init(&mutex, 0);
+ pthread_mutex_init(&event_mutex, 0);
+}
+
+void mtr_init(const char *json_file) {
+#ifndef MTR_ENABLED
+ return;
+#endif
+ mtr_init_from_stream(fopen(json_file, "wb"));
+}
+
+void mtr_shutdown() {
+ int i;
+#ifndef MTR_ENABLED
+ return;
+#endif
+ pthread_mutex_lock(&mutex);
+ is_tracing = FALSE;
+ pthread_mutex_unlock(&mutex);
+ mtr_flush_with_state(TRUE);
+
+ fwrite("\n]}\n", 1, 4, f);
+ fclose(f);
+ pthread_mutex_destroy(&mutex);
+ pthread_mutex_destroy(&event_mutex);
+ f = 0;
+ free(event_buffer);
+ event_buffer = 0;
+ for (i = 0; i < STRING_POOL_SIZE; i++) {
+ if (str_pool[i]) {
+ free(str_pool[i]);
+ str_pool[i] = 0;
+ }
+ }
+}
+
+const char *mtr_pool_string(const char *str) {
+ int i;
+ for (i = 0; i < STRING_POOL_SIZE; i++) {
+ if (!str_pool[i]) {
+ str_pool[i] = (char*)malloc(strlen(str) + 1);
+ strcpy(str_pool[i], str);
+ return str_pool[i];
+ } else {
+ if (!strcmp(str, str_pool[i]))
+ return str_pool[i];
+ }
+ }
+ return "string pool full";
+}
+
+void mtr_start() {
+#ifndef MTR_ENABLED
+ return;
+#endif
+ pthread_mutex_lock(&mutex);
+ is_tracing = TRUE;
+ pthread_mutex_unlock(&mutex);
+}
+
+void mtr_stop() {
+#ifndef MTR_ENABLED
+ return;
+#endif
+ pthread_mutex_lock(&mutex);
+ is_tracing = FALSE;
+ pthread_mutex_unlock(&mutex);
+}
+
+// TODO: fwrite more than one line at a time.
+// Flushing is thread safe and process async
+// using double-buffering mechanism.
+// Aware: only one flushing process may be
+// running at any point of time
+void mtr_flush_with_state(int is_last) {
+#ifndef MTR_ENABLED
+ return;
+#endif
+ int i = 0;
+ char linebuf[1024];
+ char arg_buf[1024];
+ char id_buf[256];
+ int event_count_copy = 0;
+ int events_in_progress_copy = 1;
+ raw_event_t *event_buffer_tmp = NULL;
+
+ // small critical section to swap buffers
+ // - no any new events can be spawn while
+ // swapping since they tied to the same mutex
+ // - checks for any flushing in process
+ pthread_mutex_lock(&mutex);
+ // if not flushing already
+ if (is_flushing) {
+ pthread_mutex_unlock(&mutex);
+ return;
+ }
+ is_flushing = TRUE;
+ event_count_copy = event_count;
+ event_buffer_tmp = flush_buffer;
+ flush_buffer = event_buffer;
+ event_buffer = event_buffer_tmp;
+ event_count = 0;
+ // waiting for any unfinished events before swap
+ while (events_in_progress_copy != 0) {
+ pthread_mutex_lock(&event_mutex);
+ events_in_progress_copy = events_in_progress;
+ pthread_mutex_unlock(&event_mutex);
+ }
+ pthread_mutex_unlock(&mutex);
+
+ for (i = 0; i < event_count_copy; i++) {
+ raw_event_t *raw = &flush_buffer[i];
+ int len;
+ switch (raw->arg_type) {
+ case MTR_ARG_TYPE_INT:
+ snprintf(arg_buf, ARRAY_SIZE(arg_buf), "\"%s\":%i", raw->arg_name, raw->a_int);
+ break;
+ case MTR_ARG_TYPE_STRING_CONST:
+ snprintf(arg_buf, ARRAY_SIZE(arg_buf), "\"%s\":\"%s\"", raw->arg_name, raw->a_str);
+ break;
+ case MTR_ARG_TYPE_STRING_COPY:
+ if (strlen(raw->a_str) > 700) {
+ snprintf(arg_buf, ARRAY_SIZE(arg_buf), "\"%s\":\"%.*s\"", raw->arg_name, 700, raw->a_str);
+ } else {
+ snprintf(arg_buf, ARRAY_SIZE(arg_buf), "\"%s\":\"%s\"", raw->arg_name, raw->a_str);
+ }
+ break;
+ case MTR_ARG_TYPE_NONE:
+ arg_buf[0] = '\0';
+ break;
+ }
+ if (raw->id) {
+ switch (raw->ph) {
+ case 'S':
+ case 'T':
+ case 'F':
+ // TODO: Support full 64-bit pointers
+ snprintf(id_buf, ARRAY_SIZE(id_buf), ",\"id\":\"0x%08x\"", (uint32_t)(uintptr_t)raw->id);
+ break;
+ case 'X':
+ snprintf(id_buf, ARRAY_SIZE(id_buf), ",\"dur\":%i", (int)raw->a_double);
+ break;
+ }
+ } else {
+ id_buf[0] = 0;
+ }
+ const char *cat = raw->cat;
+#ifdef _WIN32
+ // On Windows, we often end up with backslashes in category.
+ char temp[256];
+ {
+ int len = (int)strlen(cat);
+ int i;
+ if (len > 255) len = 255;
+ for (i = 0; i < len; i++) {
+ temp[i] = cat[i] == '\\' ? '/' : cat[i];
+ }
+ temp[len] = 0;
+ cat = temp;
+ }
+#endif
+
+ len = snprintf(linebuf, ARRAY_SIZE(linebuf), "%s{\"cat\":\"%s\",\"pid\":%i,\"tid\":%i,\"ts\":%" PRId64 ",\"ph\":\"%c\",\"name\":\"%s\",\"args\":{%s}%s}",
+ first_line ? "" : ",\n",
+ cat, raw->pid, raw->tid, raw->ts - time_offset, raw->ph, raw->name, arg_buf, id_buf);
+ fwrite(linebuf, 1, len, f);
+ first_line = 0;
+
+ if (raw->arg_type == MTR_ARG_TYPE_STRING_COPY) {
+ free((void*)raw->a_str);
+ }
+ #ifdef MTR_COPY_EVENT_CATEGORY_AND_NAME
+ free(raw->name);
+ free(raw->cat);
+ #endif
+ }
+
+ pthread_mutex_lock(&mutex);
+ is_flushing = is_last;
+ pthread_mutex_unlock(&mutex);
+}
+
+void mtr_flush() {
+ mtr_flush_with_state(FALSE);
+}
+
+void internal_mtr_raw_event(const char *category, const char *name, char ph, void *id) {
+#ifndef MTR_ENABLED
+ return;
+#endif
+ pthread_mutex_lock(&mutex);
+ if (!is_tracing || event_count >= INTERNAL_MINITRACE_BUFFER_SIZE) {
+ pthread_mutex_unlock(&mutex);
+ return;
+ }
+ raw_event_t *ev = &event_buffer[event_count];
+ ++event_count;
+ pthread_mutex_lock(&event_mutex);
+ ++events_in_progress;
+ pthread_mutex_unlock(&event_mutex);
+ pthread_mutex_unlock(&mutex);
+
+ double ts = mtr_time_s();
+ if (!cur_thread_id) {
+ cur_thread_id = get_cur_thread_id();
+ }
+ if (!cur_process_id) {
+ cur_process_id = get_cur_process_id();
+ }
+
+#ifdef MTR_COPY_EVENT_CATEGORY_AND_NAME
+ const size_t category_len = strlen(category);
+ ev->cat = malloc(category_len + 1);
+ strcpy(ev->cat, category);
+
+ const size_t name_len = strlen(name);
+ ev->name = malloc(name_len + 1);
+ strcpy(ev->name, name);
+
+#else
+ ev->cat = category;
+ ev->name = name;
+#endif
+
+ ev->id = id;
+ ev->ph = ph;
+ if (ev->ph == 'X') {
+ double x;
+ memcpy(&x, id, sizeof(double));
+ ev->ts = (int64_t)(x * 1000000);
+ ev->a_double = (ts - x) * 1000000;
+ } else {
+ ev->ts = (int64_t)(ts * 1000000);
+ }
+ ev->tid = cur_thread_id;
+ ev->pid = cur_process_id;
+ ev->arg_type = MTR_ARG_TYPE_NONE;
+
+ pthread_mutex_lock(&event_mutex);
+ --events_in_progress;
+ pthread_mutex_unlock(&event_mutex);
+}
+
+void internal_mtr_raw_event_arg(const char *category, const char *name, char ph, void *id, mtr_arg_type arg_type, const char *arg_name, void *arg_value) {
+#ifndef MTR_ENABLED
+ return;
+#endif
+ pthread_mutex_lock(&mutex);
+ if (!is_tracing || event_count >= INTERNAL_MINITRACE_BUFFER_SIZE) {
+ pthread_mutex_unlock(&mutex);
+ return;
+ }
+ raw_event_t *ev = &event_buffer[event_count];
+ ++event_count;
+ pthread_mutex_lock(&event_mutex);
+ ++events_in_progress;
+ pthread_mutex_unlock(&event_mutex);
+ pthread_mutex_unlock(&mutex);
+
+ if (!cur_thread_id) {
+ cur_thread_id = get_cur_thread_id();
+ }
+ if (!cur_process_id) {
+ cur_process_id = get_cur_process_id();
+ }
+ double ts = mtr_time_s();
+
+#ifdef MTR_COPY_EVENT_CATEGORY_AND_NAME
+ const size_t category_len = strlen(category);
+ ev->cat = malloc(category_len + 1);
+ strcpy(ev->cat, category);
+
+ const size_t name_len = strlen(name);
+ ev->name = malloc(name_len + 1);
+ strcpy(ev->name, name);
+
+#else
+ ev->cat = category;
+ ev->name = name;
+#endif
+
+ ev->id = id;
+ ev->ts = (int64_t)(ts * 1000000);
+ ev->ph = ph;
+ ev->tid = cur_thread_id;
+ ev->pid = cur_process_id;
+ ev->arg_type = arg_type;
+ ev->arg_name = arg_name;
+ switch (arg_type) {
+ case MTR_ARG_TYPE_INT: ev->a_int = (int)(uintptr_t)arg_value; break;
+ case MTR_ARG_TYPE_STRING_CONST: ev->a_str = (const char*)arg_value; break;
+ case MTR_ARG_TYPE_STRING_COPY: ev->a_str = strdup((const char*)arg_value); break;
+ case MTR_ARG_TYPE_NONE: break;
+ }
+
+ pthread_mutex_lock(&event_mutex);
+ --events_in_progress;
+ pthread_mutex_unlock(&event_mutex);
+}
+
diff --git a/src/libs/3rdparty/minitrace/private/minitrace.h b/src/libs/3rdparty/minitrace/private/minitrace.h
new file mode 100644
index 0000000000..2047eedb78
--- /dev/null
+++ b/src/libs/3rdparty/minitrace/private/minitrace.h
@@ -0,0 +1,270 @@
+// Minitrace
+//
+// Copyright 2014 by Henrik Rydgård
+// http://www.github.com/hrydgard/minitrace
+// Released under the MIT license.
+//
+// Ultra-light dependency free library for performance tracing C/C++ applications.
+// Produces traces compatible with Google Chrome's trace viewer.
+// Simply open "about:tracing" in Chrome and load the produced JSON.
+//
+// This contains far less template magic than the original libraries from Chrome
+// because this is meant to be usable from C.
+//
+// See README.md for a tutorial.
+//
+// The trace format is documented here:
+// https://docs.google.com/document/d/1CvAClvFfyA5R-PhYUmn5OOQtYMH4h6I0nSsKchNAySU/edit
+// More:
+// http://www.altdevblogaday.com/2012/08/21/using-chrometracing-to-view-your-inline-profiling-data/
+
+#ifndef MINITRACE_H
+#define MINITRACE_H
+
+#include <inttypes.h>
+
+// If MTR_ENABLED is not defined, Minitrace does nothing and has near zero overhead.
+// Preferably, set this flag in your build system. If you can't just uncomment this line.
+// #define MTR_ENABLED
+
+// By default, will collect up to 1000000 events, then you must flush.
+// It's recommended that you simply call mtr_flush on a background thread
+// occasionally. It's safe...ish.
+#define INTERNAL_MINITRACE_BUFFER_SIZE 1000000
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+// Initializes Minitrace. Must be called very early during startup of your executable,
+// before any MTR_ statements.
+void mtr_init(const char *json_file);
+// Same as above, but allows passing in a custom stream (FILE *), as returned by
+// fopen(). It should be opened for writing, preferably in binary mode to avoid
+// processing of line endings (i.e. the "wb" mode).
+void mtr_init_from_stream(void *stream);
+
+// Shuts down minitrace cleanly, flushing the trace buffer.
+void mtr_shutdown(void);
+
+// Lets you enable and disable Minitrace at runtime.
+// May cause strange discontinuities in the output.
+// Minitrace is enabled on startup by default.
+void mtr_start(void);
+void mtr_stop(void);
+
+// Flushes the collected data to disk, clearing the buffer for new data.
+void mtr_flush(void);
+
+// Returns the current time in seconds. Used internally by Minitrace. No caching.
+double mtr_time_s(void);
+
+// Registers a handler that will flush the trace on Ctrl+C.
+// Works on Linux and MacOSX, and in Win32 console applications.
+void mtr_register_sigint_handler(void);
+
+// Utility function that should rarely be used.
+// If str is semi dynamic, store it permanently in a small pool so we don't need to malloc it.
+// The pool fills up fast though and performance isn't great.
+// Returns a fixed string if the pool is full.
+const char *mtr_pool_string(const char *str);
+
+// Commented-out types will be supported in the future.
+typedef enum {
+ MTR_ARG_TYPE_NONE = 0,
+ MTR_ARG_TYPE_INT = 1, // I
+ // MTR_ARG_TYPE_FLOAT = 2, // TODO
+ // MTR_ARG_TYPE_DOUBLE = 3, // TODO
+ MTR_ARG_TYPE_STRING_CONST = 8, // C
+ MTR_ARG_TYPE_STRING_COPY = 9,
+ // MTR_ARG_TYPE_JSON_COPY = 10,
+} mtr_arg_type;
+
+// TODO: Add support for more than one argument (metadata) per event
+// Having more costs speed and memory.
+#define MTR_MAX_ARGS 1
+
+// Only use the macros to call these.
+void internal_mtr_raw_event(const char *category, const char *name, char ph, void *id);
+void internal_mtr_raw_event_arg(const char *category, const char *name, char ph, void *id, mtr_arg_type arg_type, const char *arg_name, void *arg_value);
+
+#ifdef MTR_ENABLED
+
+// c - category. Can be filtered by in trace viewer (or at least that's the intention).
+// A good use is to pass __FILE__, there are macros further below that will do it for you.
+// n - name. Pass __FUNCTION__ in most cases, unless you are marking up parts of one.
+
+// Scopes. In C++, use MTR_SCOPE. In C, always match them within the same scope.
+#define MTR_BEGIN(c, n) internal_mtr_raw_event(c, n, 'B', 0)
+#define MTR_END(c, n) internal_mtr_raw_event(c, n, 'E', 0)
+#define MTR_SCOPE(c, n) MTRScopedTrace ____mtr_scope(c, n)
+#define MTR_SCOPE_LIMIT(c, n, l) MTRScopedTraceLimit ____mtr_scope(c, n, l)
+
+// Async events. Can span threads. ID identifies which events to connect in the view.
+#define MTR_START(c, n, id) internal_mtr_raw_event(c, n, 'S', (void *)(id))
+#define MTR_STEP(c, n, id, step) internal_mtr_raw_event_arg(c, n, 'T', (void *)(id), MTR_ARG_TYPE_STRING_CONST, "step", (void *)(step))
+#define MTR_FINISH(c, n, id) internal_mtr_raw_event(c, n, 'F', (void *)(id))
+
+// Flow events. Like async events, but displayed in a more fancy way in the viewer.
+#define MTR_FLOW_START(c, n, id) internal_mtr_raw_event(c, n, 's', (void *)(id))
+#define MTR_FLOW_STEP(c, n, id, step) internal_mtr_raw_event_arg(c, n, 't', (void *)(id), MTR_ARG_TYPE_STRING_CONST, "step", (void *)(step))
+#define MTR_FLOW_FINISH(c, n, id) internal_mtr_raw_event(c, n, 'f', (void *)(id))
+
+// The same macros, but with a single named argument which shows up as metadata in the viewer.
+// _I for int.
+// _C is for a const string arg.
+// _S will copy the string, freeing on flush (expensive but sometimes necessary).
+// but required if the string was generated dynamically.
+
+// Note that it's fine to match BEGIN_S with END and BEGIN with END_S, etc.
+#define MTR_BEGIN_C(c, n, aname, astrval) internal_mtr_raw_event_arg(c, n, 'B', 0, MTR_ARG_TYPE_STRING_CONST, aname, (void *)(astrval))
+#define MTR_END_C(c, n, aname, astrval) internal_mtr_raw_event_arg(c, n, 'E', 0, MTR_ARG_TYPE_STRING_CONST, aname, (void *)(astrval))
+#define MTR_SCOPE_C(c, n, aname, astrval) MTRScopedTraceArg ____mtr_scope(c, n, MTR_ARG_TYPE_STRING_CONST, aname, (void *)(astrval))
+
+#define MTR_BEGIN_S(c, n, aname, astrval) internal_mtr_raw_event_arg(c, n, 'B', 0, MTR_ARG_TYPE_STRING_COPY, aname, (void *)(astrval))
+#define MTR_END_S(c, n, aname, astrval) internal_mtr_raw_event_arg(c, n, 'E', 0, MTR_ARG_TYPE_STRING_COPY, aname, (void *)(astrval))
+#define MTR_SCOPE_S(c, n, aname, astrval) MTRScopedTraceArg ____mtr_scope(c, n, MTR_ARG_TYPE_STRING_COPY, aname, (void *)(astrval))
+
+#define MTR_BEGIN_I(c, n, aname, aintval) internal_mtr_raw_event_arg(c, n, 'B', 0, MTR_ARG_TYPE_INT, aname, (void*)(intptr_t)(aintval))
+#define MTR_END_I(c, n, aname, aintval) internal_mtr_raw_event_arg(c, n, 'E', 0, MTR_ARG_TYPE_INT, aname, (void*)(intptr_t)(aintval))
+#define MTR_SCOPE_I(c, n, aname, aintval) MTRScopedTraceArg ____mtr_scope(c, n, MTR_ARG_TYPE_INT, aname, (void*)(intptr_t)(aintval))
+
+// Instant events. For things with no duration.
+#define MTR_INSTANT(c, n) internal_mtr_raw_event(c, n, 'I', 0)
+#define MTR_INSTANT_C(c, n, aname, astrval) internal_mtr_raw_event_arg(c, n, 'I', 0, MTR_ARG_TYPE_STRING_CONST, aname, (void *)(astrval))
+#define MTR_INSTANT_I(c, n, aname, aintval) internal_mtr_raw_event_arg(c, n, 'I', 0, MTR_ARG_TYPE_INT, aname, (void *)(aintval))
+
+// Counters (can't do multi-value counters yet)
+#define MTR_COUNTER(c, n, val) internal_mtr_raw_event_arg(c, n, 'C', 0, MTR_ARG_TYPE_INT, n, (void *)(intptr_t)(val))
+
+// Metadata. Call at the start preferably. Must be const strings.
+
+#define MTR_META_PROCESS_NAME(n) internal_mtr_raw_event_arg("", "process_name", 'M', 0, MTR_ARG_TYPE_STRING_COPY, "name", (void *)(n))
+#define MTR_META_THREAD_NAME(n) internal_mtr_raw_event_arg("", "thread_name", 'M', 0, MTR_ARG_TYPE_STRING_COPY, "name", (void *)(n))
+#define MTR_META_THREAD_SORT_INDEX(i) internal_mtr_raw_event_arg("", "thread_sort_index", 'M', 0, MTR_ARG_TYPE_INT, "sort_index", (void *)(i))
+
+#else
+
+#define MTR_BEGIN(c, n)
+#define MTR_END(c, n)
+#define MTR_SCOPE(c, n)
+#define MTR_START(c, n, id)
+#define MTR_STEP(c, n, id, step)
+#define MTR_FINISH(c, n, id)
+#define MTR_FLOW_START(c, n, id)
+#define MTR_FLOW_STEP(c, n, id, step)
+#define MTR_FLOW_FINISH(c, n, id)
+#define MTR_INSTANT(c, n)
+
+#define MTR_BEGIN_C(c, n, aname, astrval)
+#define MTR_END_C(c, n, aname, astrval)
+#define MTR_SCOPE_C(c, n, aname, astrval)
+
+#define MTR_BEGIN_S(c, n, aname, astrval)
+#define MTR_END_S(c, n, aname, astrval)
+#define MTR_SCOPE_S(c, n, aname, astrval)
+
+#define MTR_BEGIN_I(c, n, aname, aintval)
+#define MTR_END_I(c, n, aname, aintval)
+#define MTR_SCOPE_I(c, n, aname, aintval)
+
+#define MTR_INSTANT(c, n)
+#define MTR_INSTANT_C(c, n, aname, astrval)
+#define MTR_INSTANT_I(c, n, aname, aintval)
+
+// Counters (can't do multi-value counters yet)
+#define MTR_COUNTER(c, n, val)
+
+// Metadata. Call at the start preferably. Must be const strings.
+
+#define MTR_META_PROCESS_NAME(n)
+
+#define MTR_META_THREAD_NAME(n)
+#define MTR_META_THREAD_SORT_INDEX(i)
+
+#endif
+
+// Shortcuts for simple function timing with automatic categories and names.
+
+#define MTR_BEGIN_FUNC() MTR_BEGIN(__FILE__, __FUNCTION__)
+#define MTR_END_FUNC() MTR_END(__FILE__, __FUNCTION__)
+#define MTR_SCOPE_FUNC() MTR_SCOPE(__FILE__, __FUNCTION__)
+#define MTR_INSTANT_FUNC() MTR_INSTANT(__FILE__, __FUNCTION__)
+#define MTR_SCOPE_FUNC_LIMIT_S(l) MTRScopedTraceLimit ____mtr_scope(__FILE__, __FUNCTION__, l)
+#define MTR_SCOPE_FUNC_LIMIT_MS(l) MTRScopedTraceLimit ____mtr_scope(__FILE__, __FUNCTION__, (double)l * 0.000001)
+
+// Same, but with a single argument of the usual types.
+#define MTR_BEGIN_FUNC_S(aname, arg) MTR_BEGIN_S(__FILE__, __FUNCTION__, aname, arg)
+#define MTR_END_FUNC_S(aname, arg) MTR_END_S(__FILE__, __FUNCTION__, aname, arg)
+#define MTR_SCOPE_FUNC_S(aname, arg) MTR_SCOPE_S(__FILE__, __FUNCTION__, aname, arg)
+
+#define MTR_BEGIN_FUNC_C(aname, arg) MTR_BEGIN_C(__FILE__, __FUNCTION__, aname, arg)
+#define MTR_END_FUNC_C(aname, arg) MTR_END_C(__FILE__, __FUNCTION__, aname, arg)
+#define MTR_SCOPE_FUNC_C(aname, arg) MTR_SCOPE_C(__FILE__, __FUNCTION__, aname, arg)
+
+#define MTR_BEGIN_FUNC_I(aname, arg) MTR_BEGIN_I(__FILE__, __FUNCTION__, aname, arg)
+#define MTR_END_FUNC_I(aname, arg) MTR_END_I(__FILE__, __FUNCTION__, aname, arg)
+#define MTR_SCOPE_FUNC_I(aname, arg) MTR_SCOPE_I(__FILE__, __FUNCTION__, aname, arg)
+
+#ifdef __cplusplus
+}
+
+#ifdef MTR_ENABLED
+// These are optimized to use X events (combined B and E). Much easier to do in C++ than in C.
+class MTRScopedTrace {
+public:
+ MTRScopedTrace(const char *category, const char *name)
+ : category_(category), name_(name) {
+ start_time_ = mtr_time_s();
+ }
+ ~MTRScopedTrace() {
+ internal_mtr_raw_event(category_, name_, 'X', &start_time_);
+ }
+
+private:
+ const char *category_;
+ const char *name_;
+ double start_time_;
+};
+
+// Only outputs a block if execution time exceeded the limit.
+// TODO: This will effectively call mtr_time_s twice at the end, which is bad.
+class MTRScopedTraceLimit {
+public:
+ MTRScopedTraceLimit(const char *category, const char *name, double limit_s)
+ : category_(category), name_(name), limit_(limit_s) {
+ start_time_ = mtr_time_s();
+ }
+ ~MTRScopedTraceLimit() {
+ double end_time = mtr_time_s();
+ if (end_time - start_time_ >= limit_) {
+ internal_mtr_raw_event(category_, name_, 'X', &start_time_);
+ }
+ }
+
+private:
+ const char *category_;
+ const char *name_;
+ double start_time_;
+ double limit_;
+};
+
+class MTRScopedTraceArg {
+public:
+ MTRScopedTraceArg(const char *category, const char *name, mtr_arg_type arg_type, const char *arg_name, void *arg_value)
+ : category_(category), name_(name) {
+ internal_mtr_raw_event_arg(category, name, 'B', 0, arg_type, arg_name, arg_value);
+ }
+ ~MTRScopedTraceArg() {
+ internal_mtr_raw_event(category_, name_, 'E', 0);
+ }
+
+private:
+ const char *category_;
+ const char *name_;
+};
+#endif
+
+#endif
+
+#endif
diff --git a/src/plugins/mesonprojectmanager/settings/general/generalsettingswidget.h b/src/libs/3rdparty/minitrace/trace.h
index 04cc8adb69..1de9ae95df 100644
--- a/src/plugins/mesonprojectmanager/settings/general/generalsettingswidget.h
+++ b/src/libs/3rdparty/minitrace/trace.h
@@ -1,6 +1,6 @@
/****************************************************************************
**
-** Copyright (C) 2020 Alexis Jeandet.
+** Copyright (C) 2021 The Qt Company Ltd.
** Contact: https://www.qt.io/licensing/
**
** This file is part of Qt Creator.
@@ -25,29 +25,38 @@
#pragma once
-#include <coreplugin/dialogs/ioptionspage.h>
+#include "private/minitrace.h"
-#include <QCoreApplication>
-#include <QTabWidget>
-#include <QWidget>
+#ifdef MTR_ENABLED
-namespace MesonProjectManager {
-namespace Internal {
+#define MINITRACE_INITIALIZE(FILENAME, PROCESSNAME, THREADNAME) \
+ Minitrace::initialize(FILENAME, PROCESSNAME, THREADNAME)
-namespace Ui { class GeneralSettingsWidget; }
+#define MINITRACE_SHUTDOWN() Minitrace::shutdown()
-class GeneralSettingsWidget final : public Core::IOptionsPageWidget
+#else
+
+#define MINITRACE_INITIALIZE(FILENAME, PROCESSNAME, THREADNAME)
+
+#define MINITRACE_SHUTDOWN()
+
+#endif
+
+
+namespace Minitrace
{
- Q_DECLARE_TR_FUNCTIONS(MesonProjectManager::Internal::GeneralSettingsWidget)
- void apply() final;
-public:
- explicit GeneralSettingsWidget();
- ~GeneralSettingsWidget();
+inline void initialize(const char* fileName, const char* processName, const char* threadName)
+{
+ mtr_init(fileName);
+ MTR_META_PROCESS_NAME(processName);
+ MTR_META_THREAD_NAME(threadName);
+}
-private:
- Ui::GeneralSettingsWidget *ui;
-};
+inline void shutdown()
+{
+ mtr_flush();
+ mtr_shutdown();
+}
-} // namespace Internal
-} // namespace MesonProjectManager
+}
diff --git a/src/libs/3rdparty/syntax-highlighting/syntax-highlighting.qbs b/src/libs/3rdparty/syntax-highlighting/syntax-highlighting.qbs
index f932c1c4c3..e3c7682e3f 100644
--- a/src/libs/3rdparty/syntax-highlighting/syntax-highlighting.qbs
+++ b/src/libs/3rdparty/syntax-highlighting/syntax-highlighting.qbs
@@ -4,9 +4,27 @@ import qbs.FileInfo
import qbs.Environment
Project {
- QtcLibrary {
+ Product {
name: "KSyntaxHighlighting"
+ Export {
+ Depends { name: "qtc" }
+ Depends {
+ name: "Qt.KSyntaxHighlighting"
+ condition: qtc.preferSystemSyntaxHighlighting
+ required: false
+ }
+ Depends {
+ name: "KSyntaxHighlighting_bundled"
+ required: !qtc.preferSystemSyntaxHighlighting
+ }
+ }
+ }
+
+ QtcLibrary {
+ name: "KSyntaxHighlighting_bundled"
+ condition: !qtc.preferSystemSyntaxHighlighting || !Qt.KSyntaxHighlighting.present
+
cpp.defines: base.concat("KSYNTAXHIGHLIGHTING_LIBRARY")
cpp.includePaths: [
product.sourceDirectory + "/src/lib/",
@@ -16,6 +34,11 @@ Project {
Depends { name: "Qt.gui" }
Depends { name: "Qt.network" }
+ Depends {
+ name: "Qt.KSyntaxHighlighting"
+ condition: qtc.preferSystemSyntaxHighlighting
+ required: false
+ }
Group {
name: "lib"
@@ -55,8 +78,8 @@ Project {
Export {
Depends { name: "cpp" }
cpp.includePaths: [
- product.sourceDirectory + "/src/lib/",
- product.sourceDirectory + "/autogenerated/src/lib/",
+ exportingProduct.sourceDirectory + "/src/lib/",
+ exportingProduct.sourceDirectory + "/autogenerated/src/lib/",
]
}
}
diff --git a/src/libs/3rdparty/yaml-cpp/yaml-cpp.qbs b/src/libs/3rdparty/yaml-cpp/yaml-cpp.qbs
index 9a2d3f96a0..ca39a4864f 100644
--- a/src/libs/3rdparty/yaml-cpp/yaml-cpp.qbs
+++ b/src/libs/3rdparty/yaml-cpp/yaml-cpp.qbs
@@ -98,7 +98,7 @@ Project {
Export {
Depends { name: "cpp" }
- cpp.includePaths: [product.sourceDirectory + "/include/"]
+ cpp.includePaths: [exportingProduct.sourceDirectory + "/include/"]
cpp.defines: base.concat(["YAML_CPP_DLL"])
}
}
diff --git a/src/libs/CMakeLists.txt b/src/libs/CMakeLists.txt
index 7907d8272a..9abc90d155 100644
--- a/src/libs/CMakeLists.txt
+++ b/src/libs/CMakeLists.txt
@@ -25,10 +25,12 @@ if(EXISTS ${CMAKE_CURRENT_SOURCE_DIR}/qlitehtml/src/CMakeLists.txt)
if(BUILD_LIBRARY_QLITEHTML)
set(QLITEHTML_BIN_PATH ${IDE_BIN_PATH})
set(QLITEHTML_LIBRARY_PATH ${IDE_LIBRARY_PATH})
+ set(QLITEHTML_LIBRARY_ARCHIVE_PATH ${IDE_LIBRARY_ARCHIVE_PATH})
set(QLITEHTML_EXPORT QtCreator)
set(QLITEHTML_DEVEL_COMPONENT Devel)
set(QLITEHTML_DEVEL_EXCLUDE_FROM_ALL ON)
set(QLITEHTML_HEADER_PATH "${IDE_HEADER_INSTALL_PATH}/src/lib/qlitehtml")
+ set(QT_VERSION_MAJOR ${Qt5_VERSION_MAJOR})
add_subdirectory(qlitehtml/src)
endif()
if(TARGET qlitehtml)
@@ -42,7 +44,7 @@ if(EXISTS ${CMAKE_CURRENT_SOURCE_DIR}/qlitehtml/src/CMakeLists.txt)
INSTALL_RPATH "${_LIB_RPATH}"
RUNTIME_OUTPUT_DIRECTORY "${_output_binary_dir}/${IDE_BIN_PATH}"
LIBRARY_OUTPUT_DIRECTORY "${_output_binary_dir}/${IDE_LIBRARY_PATH}"
- ARCHIVE_OUTPUT_DIRECTORY "${_output_binary_dir}/${IDE_LIBRARY_PATH}"
+ ARCHIVE_OUTPUT_DIRECTORY "${_output_binary_dir}/${IDE_LIBRARY_ARCHIVE_PATH}"
)
endif()
endif()
diff --git a/src/libs/advanceddockingsystem/dockmanager.cpp b/src/libs/advanceddockingsystem/dockmanager.cpp
index 7ae018b912..bbb4a3b615 100644
--- a/src/libs/advanceddockingsystem/dockmanager.cpp
+++ b/src/libs/advanceddockingsystem/dockmanager.cpp
@@ -961,7 +961,7 @@ namespace ADS
QDir tmp;
tmp.mkpath(fileName.toFileInfo().path());
- Utils::FileSaver fileSaver(fileName.toString(), QIODevice::Text);
+ Utils::FileSaver fileSaver(fileName, QIODevice::Text);
if (!fileSaver.hasError())
fileSaver.write(data);
diff --git a/src/libs/advanceddockingsystem/elidinglabel.cpp b/src/libs/advanceddockingsystem/elidinglabel.cpp
index 47ada90461..f5c02502f7 100644
--- a/src/libs/advanceddockingsystem/elidinglabel.cpp
+++ b/src/libs/advanceddockingsystem/elidinglabel.cpp
@@ -151,11 +151,7 @@ namespace ADS {
return QLabel::minimumSizeHint();
const QFontMetrics &fm = fontMetrics();
-#if (QT_VERSION >= QT_VERSION_CHECK(5, 11, 0))
QSize size(fm.horizontalAdvance(d->m_text.left(2) + "…"), fm.height());
-#else
- QSize size(fm.width(d->m_text.left(2) + "…"), fm.height());
-#endif
return size;
}
@@ -165,11 +161,7 @@ namespace ADS {
return QLabel::sizeHint();
const QFontMetrics &fm = fontMetrics();
-#if (QT_VERSION >= QT_VERSION_CHECK(5, 11, 0))
QSize size(fm.horizontalAdvance(d->m_text), QLabel::sizeHint().height());
-#else
- QSize size(fm.width(d->m_text), QLabel::sizeHint().height());
-#endif
return size;
}
diff --git a/src/libs/advanceddockingsystem/floatingdockcontainer.cpp b/src/libs/advanceddockingsystem/floatingdockcontainer.cpp
index d0b8766c7b..59575ab20a 100644
--- a/src/libs/advanceddockingsystem/floatingdockcontainer.cpp
+++ b/src/libs/advanceddockingsystem/floatingdockcontainer.cpp
@@ -878,13 +878,8 @@ bool FloatingDockContainer::event(QEvent *event)
// is clicked.
// It is really great to work around the whole NonClientMouseArea
// bugs
-#if (QT_VERSION >= QT_VERSION_CHECK(5, 12, 2))
if (event->type() == QEvent::NonClientAreaMouseButtonPress
/*&& QGuiApplication::mouseButtons().testFlag(Qt::LeftButton)*/)
-#else
- if (event->type() == QEvent::NonClientAreaMouseButtonPress
- && QGuiApplication::mouseButtons().testFlag(Qt::LeftButton))
-#endif
{
qCInfo(adsLog) << Q_FUNC_INFO << "QEvent::NonClientAreaMouseButtonPress"
<< event->type();
diff --git a/src/libs/clangsupport/clangsupport_global.h b/src/libs/clangsupport/clangsupport_global.h
index 281dd05806..b482c10327 100644
--- a/src/libs/clangsupport/clangsupport_global.h
+++ b/src/libs/clangsupport/clangsupport_global.h
@@ -78,6 +78,7 @@ enum class HighlightingType : quint8
Type,
PrimitiveType,
LocalVariable,
+ Parameter,
Field,
GlobalVariable,
Enumeration,
diff --git a/src/libs/clangsupport/tokeninfocontainer.h b/src/libs/clangsupport/tokeninfocontainer.h
index c819268fb9..dc2f8ba252 100644
--- a/src/libs/clangsupport/tokeninfocontainer.h
+++ b/src/libs/clangsupport/tokeninfocontainer.h
@@ -138,6 +138,7 @@ public:
return extraInfo.declaration
&& types.mainHighlightingType != HighlightingType::LocalVariable
+ && types.mainHighlightingType != HighlightingType::Parameter
&& (types.mixinHighlightingTypes.contains(HighlightingType::Operator)
== extraInfo.token.startsWith("operator"));
}
diff --git a/src/libs/cplusplus/PPToken.h b/src/libs/cplusplus/PPToken.h
index af31dec861..a2d0f2af53 100644
--- a/src/libs/cplusplus/PPToken.h
+++ b/src/libs/cplusplus/PPToken.h
@@ -109,6 +109,10 @@ public:
: m_src(src)
{}
+ PPToken(QByteArray &&src)
+ : m_src(std::move(src))
+ {}
+
void setSource(const QByteArray &src)
{ m_src = src; }
diff --git a/src/libs/cplusplus/cplusplus.qbs b/src/libs/cplusplus/cplusplus.qbs
index f5a9f6b947..80c6174ba2 100644
--- a/src/libs/cplusplus/cplusplus.qbs
+++ b/src/libs/cplusplus/cplusplus.qbs
@@ -126,7 +126,7 @@ Project {
Export {
cpp.includePaths: [
- product.sourceDirectory + "/../3rdparty"
+ exportingProduct.sourceDirectory + "/../3rdparty"
]
}
}
diff --git a/src/libs/cplusplus/pp-engine.cpp b/src/libs/cplusplus/pp-engine.cpp
index 913a6a3c9b..b3cfe6bd15 100644
--- a/src/libs/cplusplus/pp-engine.cpp
+++ b/src/libs/cplusplus/pp-engine.cpp
@@ -1219,12 +1219,12 @@ bool Preprocessor::handleFunctionLikeMacro(const Macro *macro,
// No formal macro parameter for this identifier in the body.
bodyTk.f.generated = true;
bodyTk.lineno = baseLine;
- expanded.push_back(bodyTk);
+ expanded.push_back(std::move(bodyTk));
}
} else if (bodyTk.isNot(T_POUND) && bodyTk.isNot(T_POUND_POUND)) {
bodyTk.f.generated = true;
bodyTk.lineno = baseLine;
- expanded.push_back(bodyTk);
+ expanded.push_back(std::move(bodyTk));
}
if (i > 1 && body[int(i) - 1].is(T_POUND_POUND)) {
diff --git a/src/libs/extensionsystem/pluginmanager.cpp b/src/libs/extensionsystem/pluginmanager.cpp
index ab83ed210b..2efc73e97e 100644
--- a/src/libs/extensionsystem/pluginmanager.cpp
+++ b/src/libs/extensionsystem/pluginmanager.cpp
@@ -55,8 +55,8 @@
#include <utils/hostosinfo.h>
#include <utils/mimetypes/mimedatabase.h>
#include <utils/qtcassert.h>
+#include <utils/qtcprocess.h>
#include <utils/qtcsettings.h>
-#include <utils/synchronousprocess.h>
#ifdef WITH_TESTS
#include <utils/hostosinfo.h>
@@ -418,10 +418,11 @@ QString PluginManager::systemInformation()
QString result;
CommandLine qtDiag(HostOsInfo::withExecutableSuffix(
QLibraryInfo::location(QLibraryInfo::BinariesPath) + "/qtdiag"));
- SynchronousProcess qtdiagProc;
- const SynchronousProcessResponse response = qtdiagProc.runBlocking(qtDiag);
- if (response.result == SynchronousProcessResponse::Finished)
- result += response.allOutput() + "\n";
+ SynchronousProcess qtDiagProc;
+ qtDiagProc.setCommand(qtDiag);
+ qtDiagProc.runBlocking();
+ if (qtDiagProc.result() == QtcProcess::Finished)
+ result += qtDiagProc.allOutput() + "\n";
result += "Plugin information:\n\n";
auto longestSpec = std::max_element(d->pluginSpecs.cbegin(), d->pluginSpecs.cend(),
[](const PluginSpec *left, const PluginSpec *right) {
diff --git a/src/libs/languageserverprotocol/CMakeLists.txt b/src/libs/languageserverprotocol/CMakeLists.txt
index 9ad446817f..55415e2db7 100644
--- a/src/libs/languageserverprotocol/CMakeLists.txt
+++ b/src/libs/languageserverprotocol/CMakeLists.txt
@@ -16,6 +16,8 @@ add_qtc_library(LanguageServerProtocol
lsptypes.cpp lsptypes.h
lsputils.cpp lsputils.h
messages.cpp messages.h
+ progresssupport.cpp progresssupport.h
+ semantictokens.cpp semantictokens.h
servercapabilities.cpp servercapabilities.h
shutdownmessages.cpp shutdownmessages.h
textsynchronization.cpp textsynchronization.h
diff --git a/src/libs/languageserverprotocol/client.h b/src/libs/languageserverprotocol/client.h
index 4c04c2a90e..67e5b75554 100644
--- a/src/libs/languageserverprotocol/client.h
+++ b/src/libs/languageserverprotocol/client.h
@@ -50,8 +50,7 @@ public:
void setRegisterOptions(const QJsonValue &registerOptions)
{ insert(registerOptionsKey, registerOptions); }
- bool isValid(ErrorHierarchy *error) const override
- { return check<QString>(error, idKey) && check<QString>(error, methodKey); }
+ bool isValid() const override { return contains(idKey) && contains(methodKey); }
};
class RegistrationParams : public JsonObject
@@ -66,8 +65,7 @@ public:
void setRegistrations(const QList<Registration> &registrations)
{ insertArray(registrationsKey, registrations); }
- bool isValid(ErrorHierarchy *error) const override
- { return checkArray<Registration>(error, registrationsKey); }
+ bool isValid() const override { return contains(registrationsKey); }
};
class LANGUAGESERVERPROTOCOL_EXPORT RegisterCapabilityRequest : public Request<
@@ -90,8 +88,7 @@ public:
QString method() const { return typedValue<QString>(methodKey); }
void setMethod(const QString &method) { insert(methodKey, method); }
- bool isValid(ErrorHierarchy *error) const override
- { return check<QString>(error, idKey) && check<QString>(error, methodKey); }
+ bool isValid() const override { return contains(idKey) && contains(methodKey); }
};
class UnregistrationParams : public JsonObject
@@ -104,8 +101,7 @@ public:
void setUnregistrations(const QList<Unregistration> &unregistrations)
{ insertArray(unregistrationsKey, unregistrations); }
- bool isValid(ErrorHierarchy *error) const override
- { return checkArray<Unregistration>(error, unregistrationsKey); }
+ bool isValid() const override { return contains(unregistrationsKey); }
};
class LANGUAGESERVERPROTOCOL_EXPORT UnregisterCapabilityRequest : public Request<
diff --git a/src/libs/languageserverprotocol/clientcapabilities.cpp b/src/libs/languageserverprotocol/clientcapabilities.cpp
index 4ee6d74166..c3665462f8 100644
--- a/src/libs/languageserverprotocol/clientcapabilities.cpp
+++ b/src/libs/languageserverprotocol/clientcapabilities.cpp
@@ -42,96 +42,63 @@ void SymbolCapabilities::SymbolKindCapabilities::setValueSet(const QList<SymbolK
insert(valueSetKey, enumArrayToJsonArray<SymbolKind>(valueSet));
}
-bool ClientCapabilities::isValid(ErrorHierarchy *error) const
-{
- return checkOptional<WorkspaceClientCapabilities>(error, workspaceKey)
- && checkOptional<TextDocumentClientCapabilities>(error, textDocumentKey);
-}
-
WorkspaceClientCapabilities::WorkspaceClientCapabilities()
{
setWorkspaceFolders(true);
}
-bool WorkspaceClientCapabilities::isValid(ErrorHierarchy *error) const
-{
- return checkOptional<bool>(error,applyEditKey)
- && checkOptional<WorkspaceEditCapabilities>(error,workspaceEditKey)
- && checkOptional<DynamicRegistrationCapabilities>(error,didChangeConfigurationKey)
- && checkOptional<DynamicRegistrationCapabilities>(error,didChangeWatchedFilesKey)
- && checkOptional<SymbolCapabilities>(error,symbolKey)
- && checkOptional<DynamicRegistrationCapabilities>(error,executeCommandKey)
- && checkOptional<bool>(error,workspaceFoldersKey)
- && checkOptional<bool>(error,configurationKey);
-}
-
-bool TextDocumentClientCapabilities::SynchronizationCapabilities::isValid(ErrorHierarchy *error) const
-{
- return DynamicRegistrationCapabilities::isValid(error)
- && checkOptional<bool>(error, willSaveKey)
- && checkOptional<bool>(error, willSaveWaitUntilKey)
- && checkOptional<bool>(error, didSaveKey);
-}
-
-bool TextDocumentClientCapabilities::isValid(ErrorHierarchy *error) const
+Utils::optional<Utils::variant<bool, QJsonObject>> SemanticTokensClientCapabilities::Requests::range()
+ const
{
- return checkOptional<SynchronizationCapabilities>(error, synchronizationKey)
- && checkOptional<CompletionCapabilities>(error, completionKey)
- && checkOptional<HoverCapabilities>(error, hoverKey)
- && checkOptional<SignatureHelpCapabilities>(error, signatureHelpKey)
- && checkOptional<DynamicRegistrationCapabilities>(error, referencesKey)
- && checkOptional<DynamicRegistrationCapabilities>(error, documentHighlightKey)
- && checkOptional<SymbolCapabilities>(error, documentSymbolKey)
- && checkOptional<DynamicRegistrationCapabilities>(error, formattingKey)
- && checkOptional<DynamicRegistrationCapabilities>(error, rangeFormattingKey)
- && checkOptional<DynamicRegistrationCapabilities>(error, onTypeFormattingKey)
- && checkOptional<DynamicRegistrationCapabilities>(error, definitionKey)
- && checkOptional<DynamicRegistrationCapabilities>(error, typeDefinitionKey)
- && checkOptional<DynamicRegistrationCapabilities>(error, implementationKey)
- && checkOptional<CodeActionCapabilities>(error, codeActionKey)
- && checkOptional<DynamicRegistrationCapabilities>(error, codeLensKey)
- && checkOptional<DynamicRegistrationCapabilities>(error, documentLinkKey)
- && checkOptional<DynamicRegistrationCapabilities>(error, colorProviderKey)
- && checkOptional<RenameClientCapabilities>(error, renameKey)
- && checkOptional<SemanticHighlightingCapabilities>(error, semanticHighlightingCapabilitiesKey);
+ using RetType = Utils::variant<bool, QJsonObject>;
+ const QJsonValue &rangeOptions = value(rangeKey);
+ if (rangeOptions.isBool())
+ return RetType(rangeOptions.toBool());
+ if (rangeOptions.isObject())
+ return RetType(rangeOptions.toObject());
+ return Utils::nullopt;
}
-bool SymbolCapabilities::isValid(ErrorHierarchy *error) const
+void SemanticTokensClientCapabilities::Requests::setRange(
+ const Utils::variant<bool, QJsonObject> &range)
{
- return DynamicRegistrationCapabilities::isValid(error)
- && checkOptional<SymbolKindCapabilities>(error, symbolKindKey);
+ insertVariant<bool, QJsonObject>(rangeKey, range);
}
-bool TextDocumentClientCapabilities::CompletionCapabilities::isValid(ErrorHierarchy *error) const
+Utils::optional<Utils::variant<bool, FullSemanticTokenOptions>>
+SemanticTokensClientCapabilities::Requests::full() const
{
- return DynamicRegistrationCapabilities::isValid(error)
- && checkOptional<CompletionItemCapbilities>(error, completionItemKey)
- && checkOptional<CompletionItemKindCapabilities>(error, completionItemKindKey)
- && checkOptional<bool>(error, contextSupportKey);
+ using RetType = Utils::variant<bool, FullSemanticTokenOptions>;
+ const QJsonValue &fullOptions = value(fullKey);
+ if (fullOptions.isBool())
+ return RetType(fullOptions.toBool());
+ if (fullOptions.isObject())
+ return RetType(FullSemanticTokenOptions(fullOptions.toObject()));
+ return Utils::nullopt;
}
-bool TextDocumentClientCapabilities::HoverCapabilities::isValid(ErrorHierarchy *error) const
+void SemanticTokensClientCapabilities::Requests::setFull(
+ const Utils::variant<bool, FullSemanticTokenOptions> &full)
{
- return DynamicRegistrationCapabilities::isValid(error)
- && checkOptionalArray<int>(error, contentFormatKey);
+ insertVariant<bool, FullSemanticTokenOptions>(fullKey, full);
}
-bool TextDocumentClientCapabilities::SignatureHelpCapabilities::isValid(ErrorHierarchy *error) const
+Utils::optional<SemanticTokensClientCapabilities> TextDocumentClientCapabilities::semanticTokens()
+ const
{
- return DynamicRegistrationCapabilities::isValid(error)
- && checkOptional<SignatureHelpCapabilities>(error, signatureInformationKey);
+ return optionalValue<SemanticTokensClientCapabilities>(semanticTokensKey);
}
-bool TextDocumentClientCapabilities::CodeActionCapabilities::isValid(ErrorHierarchy *errorHierarchy) const
+void TextDocumentClientCapabilities::setSemanticTokens(
+ const SemanticTokensClientCapabilities &semanticTokens)
{
- return DynamicRegistrationCapabilities::isValid(errorHierarchy)
- && checkOptional<CodeActionLiteralSupport>(errorHierarchy, codeActionLiteralSupportKey);
+ insert(semanticTokensKey, semanticTokens);
}
-bool TextDocumentClientCapabilities::RenameClientCapabilities::isValid(ErrorHierarchy *error) const
+bool SemanticTokensClientCapabilities::isValid() const
{
- return DynamicRegistrationCapabilities::isValid(error)
- && checkOptional<bool>(error, prepareSupportKey);
+ return contains(requestsKey) && contains(tokenTypesKey) && contains(tokenModifiersKey)
+ && contains(formatsKey);
}
} // namespace LanguageServerProtocol
diff --git a/src/libs/languageserverprotocol/clientcapabilities.h b/src/libs/languageserverprotocol/clientcapabilities.h
index 14490ae6ad..f2b12fea68 100644
--- a/src/libs/languageserverprotocol/clientcapabilities.h
+++ b/src/libs/languageserverprotocol/clientcapabilities.h
@@ -27,6 +27,7 @@
#include "jsonkeys.h"
#include "lsptypes.h"
+#include "semantictokens.h"
namespace LanguageServerProtocol {
@@ -38,9 +39,84 @@ public:
Utils::optional<bool> dynamicRegistration() const { return optionalValue<bool>(dynamicRegistrationKey); }
void setDynamicRegistration(bool dynamicRegistration) { insert(dynamicRegistrationKey, dynamicRegistration); }
void clearDynamicRegistration() { remove(dynamicRegistrationKey); }
+};
- bool isValid(ErrorHierarchy *error) const override
- { return checkOptional<bool>(error, dynamicRegistrationKey); }
+class LANGUAGESERVERPROTOCOL_EXPORT FullSemanticTokenOptions : public JsonObject
+{
+public:
+ using JsonObject::JsonObject;
+
+ /**
+ * The client will send the `textDocument/semanticTokens/full/delta`
+ * request if the server provides a corresponding handler.
+ */
+ Utils::optional<bool> delta() const { return optionalValue<bool>(deltaKey); }
+ void setDelta(bool delta) { insert(deltaKey, delta); }
+ void clearDelta() { remove(deltaKey); }
+};
+
+class LANGUAGESERVERPROTOCOL_EXPORT SemanticTokensClientCapabilities : public DynamicRegistrationCapabilities
+{
+public:
+ using DynamicRegistrationCapabilities::DynamicRegistrationCapabilities;
+ class LANGUAGESERVERPROTOCOL_EXPORT Requests : public JsonObject
+ {
+ /**
+ * Which requests the client supports and might send to the server
+ * depending on the server's capability. Please note that clients might not
+ * show semantic tokens or degrade some of the user experience if a range
+ * or full request is advertised by the client but not provided by the
+ * server. If for example the client capability `requests.full` and
+ * `request.range` are both set to true but the server only provides a
+ * range provider the client might not render a minimap correctly or might
+ * even decide to not show any semantic tokens at all.
+ */
+ public:
+ using JsonObject::JsonObject;
+
+ /**
+ * The client will send the `textDocument/semanticTokens/range` request
+ * if the server provides a corresponding handler.
+ */
+ Utils::optional<Utils::variant<bool, QJsonObject>> range() const;
+ void setRange(const Utils::variant<bool, QJsonObject> &range);
+ void clearRange() { remove(rangeKey); }
+
+ /**
+ * The client will send the `textDocument/semanticTokens/full` request
+ * if the server provides a corresponding handler.
+ */
+ Utils::optional<Utils::variant<bool, FullSemanticTokenOptions>> full() const;
+ void setFull(const Utils::variant<bool, FullSemanticTokenOptions> &full);
+ void clearFull() { remove(fullKey); }
+ };
+
+ Requests requests() const { return typedValue<Requests>(requestsKey); }
+ void setRequests(const Requests &requests) { insert(requestsKey, requests); }
+
+ /// The token types that the client supports.
+ QList<QString> tokenTypes() const { return array<QString>(tokenTypesKey); }
+ void setTokenTypes(const QList<QString> &value) { insertArray(tokenTypesKey, value); }
+
+ /// The token modifiers that the client supports.
+ QList<QString> tokenModifiers() const { return array<QString>(tokenModifiersKey); }
+ void setTokenModifiers(const QList<QString> &value) { insertArray(tokenModifiersKey, value); }
+
+ /// The formats the clients supports.
+ QList<QString> formats() const { return array<QString>(formatsKey); }
+ void setFormats(const QList<QString> &value) { insertArray(formatsKey, value); }
+
+ /// Whether the client supports tokens that can overlap each other.
+ Utils::optional<bool> overlappingTokenSupport() const { return optionalValue<bool>(overlappingTokenSupportKey); }
+ void setOverlappingTokenSupport(bool overlappingTokenSupport) { insert(overlappingTokenSupportKey, overlappingTokenSupport); }
+ void clearOverlappingTokenSupport() { remove(overlappingTokenSupportKey); }
+
+ /// Whether the client supports tokens that can span multiple lines.
+ Utils::optional<bool> multiLineTokenSupport() const { return optionalValue<bool>(multiLineTokenSupportKey); }
+ void setMultiLineTokenSupport(bool multiLineTokenSupport) { insert(multiLineTokenSupportKey, multiLineTokenSupport); }
+ void clearMultiLineTokenSupport() { remove(multiLineTokenSupportKey); }
+
+ bool isValid() const override;
};
class LANGUAGESERVERPROTOCOL_EXPORT SymbolCapabilities : public DynamicRegistrationCapabilities
@@ -66,9 +142,6 @@ public:
Utils::optional<QList<SymbolKind>> valueSet() const;
void setValueSet(const QList<SymbolKind> &valueSet);
void clearValueSet() { remove(valueSetKey); }
-
- bool isValid(ErrorHierarchy *error) const override
- { return checkOptionalArray<int>(error, valueSetKey); }
};
// Specific capabilities for the `SymbolKind` in the `workspace/symbol` request.
@@ -76,8 +149,6 @@ public:
{ return optionalValue<SymbolKindCapabilities>(symbolKindKey); }
void setSymbolKind(const SymbolKindCapabilities &symbolKind) { insert(symbolKindKey, symbolKind); }
void clearSymbolKind() { remove(symbolKindKey); }
-
- bool isValid(ErrorHierarchy *error) const override;
};
class LANGUAGESERVERPROTOCOL_EXPORT TextDocumentClientCapabilities : public JsonObject
@@ -110,8 +181,6 @@ public:
Utils::optional<bool> didSave() const { return optionalValue<bool>(didSaveKey); }
void setDidSave(bool didSave) { insert(didSaveKey, didSave); }
void clearDidSave() { remove(didSaveKey); }
-
- bool isValid(ErrorHierarchy *error) const override;
};
Utils::optional<SynchronizationCapabilities> synchronization() const
@@ -129,8 +198,7 @@ public:
void setSemanticHighlighting(bool semanticHighlighting)
{ insert(semanticHighlightingKey, semanticHighlighting); }
- bool isValid(ErrorHierarchy *error) const override
- { return check<bool>(error, semanticHighlightingKey); }
+ bool isValid() const override { return contains(semanticHighlightingKey); }
};
Utils::optional<SemanticHighlightingCapabilities> semanticHighlightingCapabilities() const
@@ -178,13 +246,6 @@ public:
Utils::optional<QList<MarkupKind>> documentationFormat() const;
void setDocumentationFormat(const QList<MarkupKind> &documentationFormat);
void clearDocumentationFormat() { remove(documentationFormatKey); }
-
- bool isValid(ErrorHierarchy *error) const override
- {
- return checkOptional<bool>(error, snippetSupportKey)
- && checkOptional<bool>(error, commitCharacterSupportKey)
- && checkOptionalArray<int>(error, documentationFormatKey);
- }
};
// The client supports the following `CompletionItem` specific capabilities.
@@ -212,9 +273,6 @@ public:
Utils::optional<QList<CompletionItemKind::Kind>> valueSet() const;
void setValueSet(const QList<CompletionItemKind::Kind> &valueSet);
void clearValueSet() { remove(valueSetKey); }
-
- bool isValid(ErrorHierarchy *error) const override
- { return checkOptionalArray<int>(error, valueSetKey); }
};
Utils::optional<CompletionItemKindCapabilities> completionItemKind() const
@@ -230,8 +288,6 @@ public:
Utils::optional<bool> contextSupport() const { return optionalValue<bool>(contextSupportKey); }
void setContextSupport(bool contextSupport) { insert(contextSupportKey, contextSupport); }
void clearContextSupport() { remove(contextSupportKey); }
-
- bool isValid(ErrorHierarchy *error) const override;
};
// Capabilities specific to the `textDocument/completion`
@@ -252,8 +308,6 @@ public:
Utils::optional<QList<MarkupKind>> contentFormat() const;
void setContentFormat(const QList<MarkupKind> &contentFormat);
void clearContentFormat() { remove(contentFormatKey); }
-
- bool isValid(ErrorHierarchy *error) const override;
};
Utils::optional<HoverCapabilities> hover() const { return optionalValue<HoverCapabilities>(hoverKey); }
@@ -276,9 +330,6 @@ public:
Utils::optional<QList<MarkupKind>> documentationFormat() const;
void setDocumentationFormat(const QList<MarkupKind> &documentationFormat);
void clearDocumentationFormat() { remove(documentationFormatKey); }
-
- bool isValid(ErrorHierarchy *error) const override
- { return checkOptionalArray<int>(error, documentationFormatKey); }
};
// The client supports the following `SignatureInformation` specific properties.
@@ -287,8 +338,6 @@ public:
void setSignatureInformation(const SignatureInformationCapabilities &signatureInformation)
{ insert(signatureInformationKey, signatureInformation); }
void clearSignatureInformation() { remove(signatureInformationKey); }
-
- bool isValid(ErrorHierarchy *error) const override;
};
// Capabilities specific to the `textDocument/signatureHelp`
@@ -390,8 +439,7 @@ public:
void setValueSet(const QList<QString> &valueSet)
{ insertArray(valueSetKey, valueSet); }
- bool isValid(ErrorHierarchy *errorHierarchy) const override
- { return checkArray<QString>(errorHierarchy, valueSetKey); }
+ bool isValid() const override { return contains(valueSetKey); }
};
CodeActionKind codeActionKind() const
@@ -399,8 +447,7 @@ public:
void setCodeActionKind(const CodeActionKind &codeActionKind)
{ insert(codeActionKindKey, codeActionKind); }
- bool isValid(ErrorHierarchy *errorHierarchy) const override
- { return check<CodeActionKind>(errorHierarchy, codeActionKindKey); }
+ bool isValid() const override { return contains(codeActionKindKey); }
};
Utils::optional<CodeActionLiteralSupport> codeActionLiteralSupport() const
@@ -408,8 +455,6 @@ public:
void setCodeActionLiteralSupport(const CodeActionLiteralSupport &codeActionLiteralSupport)
{ insert(codeActionLiteralSupportKey, codeActionLiteralSupport); }
void clearCodeActionLiteralSupport() { remove(codeActionLiteralSupportKey); }
-
- bool isValid(ErrorHierarchy *errorHierarchy) const override;
};
// Whether code action supports dynamic registration.
@@ -458,8 +503,6 @@ public:
Utils::optional<bool> prepareSupport() const { return optionalValue<bool>(prepareSupportKey); }
void setPrepareSupport(bool prepareSupport) { insert(prepareSupportKey, prepareSupport); }
void clearPrepareSupport() { remove(prepareSupportKey); }
-
- bool isValid(ErrorHierarchy *error) const override;
};
// Whether rename supports dynamic registration.
@@ -469,7 +512,9 @@ public:
{ insert(renameKey, rename); }
void clearRename() { remove(renameKey); }
- bool isValid(ErrorHierarchy *error) const override;
+ Utils::optional<SemanticTokensClientCapabilities> semanticTokens() const;
+ void setSemanticTokens(const SemanticTokensClientCapabilities &semanticTokens);
+ void clearSemanticTokens() { remove(semanticTokensKey); }
};
class LANGUAGESERVERPROTOCOL_EXPORT WorkspaceClientCapabilities : public JsonObject
@@ -497,9 +542,6 @@ public:
void setDocumentChanges(bool documentChanges)
{ insert(documentChangesKey, documentChanges); }
void clearDocumentChanges() { remove(documentChangesKey); }
-
- bool isValid(ErrorHierarchy *error) const override
- { return checkOptional<bool>(error, documentChangesKey); }
};
// Capabilities specific to `WorkspaceEdit`s
@@ -547,8 +589,27 @@ public:
Utils::optional<bool> configuration() const { return optionalValue<bool>(configurationKey); }
void setConfiguration(bool configuration) { insert(configurationKey, configuration); }
void clearConfiguration() { remove(configurationKey); }
+};
- bool isValid(ErrorHierarchy *error) const override;
+class WindowClientClientCapabilities : public JsonObject
+{
+public:
+ using JsonObject::JsonObject;
+
+ /**
+ * Whether client supports handling progress notifications.
+ * If set, servers are allowed to report in `workDoneProgress` property
+ * in the request specific server capabilities.
+ *
+ */
+ Utils::optional<bool> workDoneProgress() const
+ { return optionalValue<bool>(workDoneProgressKey); }
+ void setWorkDoneProgress(bool workDoneProgress)
+ { insert(workDoneProgressKey, workDoneProgress); }
+ void clearWorkDoneProgress() { remove(workDoneProgressKey); }
+
+private:
+ constexpr static const char workDoneProgressKey[] = "workDoneProgress";
};
class LANGUAGESERVERPROTOCOL_EXPORT ClientCapabilities : public JsonObject
@@ -570,12 +631,17 @@ public:
{ insert(textDocumentKey, textDocument); }
void clearTextDocument() { remove(textDocumentKey); }
+ // Window specific client capabilities.
+ Utils::optional<WindowClientClientCapabilities> window() const
+ { return optionalValue<WindowClientClientCapabilities>(windowKey); }
+ void setWindow(const WindowClientClientCapabilities &window)
+ { insert(windowKey, window); }
+ void clearWindow() { remove(windowKey); }
+
// Experimental client capabilities.
QJsonValue experimental() const { return value(experimentalKey); }
void setExperimental(const QJsonValue &experimental) { insert(experimentalKey, experimental); }
void clearExperimental() { remove(experimentalKey); }
-
- bool isValid(ErrorHierarchy *error) const override;
};
-}
+} // namespace LanguageServerProtocol
diff --git a/src/libs/languageserverprotocol/completion.cpp b/src/libs/languageserverprotocol/completion.cpp
index faeb237718..f4e1295d75 100644
--- a/src/libs/languageserverprotocol/completion.cpp
+++ b/src/libs/languageserverprotocol/completion.cpp
@@ -50,40 +50,12 @@ Utils::optional<CompletionItem::InsertTextFormat> CompletionItem::insertTextForm
: Utils::nullopt;
}
-bool CompletionItem::isValid(ErrorHierarchy *error) const
-{
- return check<QString>(error, labelKey)
- && checkOptional<int>(error, kindKey)
- && checkOptional<QString>(error, detailKey)
- && checkOptional<QString>(error, documentationKey)
- && checkOptional<QString>(error, sortTextKey)
- && checkOptional<QString>(error, filterTextKey)
- && checkOptional<QString>(error, insertTextKey)
- && checkOptional<int>(error, insertTextFormatKey)
- && checkOptional<TextEdit>(error, textEditKey)
- && checkOptionalArray<TextEdit>(error, additionalTextEditsKey)
- && checkOptionalArray<QString>(error, commitCharactersKey)
- && checkOptional<Command>(error, commandKey)
- && checkOptional<QJsonValue>(error, dataKey);
-}
+
CompletionItemResolveRequest::CompletionItemResolveRequest(const CompletionItem &params)
: Request(methodName, params)
{ }
-bool CompletionList::isValid(ErrorHierarchy *error) const
-{
- return check<bool>(error, isIncompleteKey)
- && checkOptionalArray<CompletionItem>(error, itemsKey);
-
-}
-
-bool CompletionParams::isValid(ErrorHierarchy *error) const
-{
- return TextDocumentPositionParams::isValid(error)
- && checkOptional<CompletionContext>(error, contextKey);
-}
-
CompletionResult::CompletionResult(const QJsonValue &value)
{
if (value.isNull()) {
diff --git a/src/libs/languageserverprotocol/completion.h b/src/libs/languageserverprotocol/completion.h
index 013136b58a..ab5e43ac22 100644
--- a/src/libs/languageserverprotocol/completion.h
+++ b/src/libs/languageserverprotocol/completion.h
@@ -71,11 +71,7 @@ public:
{ insert(triggerCharacterKey, triggerCharacter); }
void clearTriggerCharacter() { remove(triggerCharacterKey); }
- bool isValid(ErrorHierarchy *error) const override
- {
- return check<int>(error, triggerKindKey)
- && checkOptional<QString>(error, triggerCharacterKey);
- }
+ bool isValid() const override { return contains(triggerKindKey); }
};
/**
@@ -87,8 +83,6 @@ public:
void setContext(const CompletionContext &context)
{ insert(contextKey, context); }
void clearContext() { remove(contextKey); }
-
- bool isValid(ErrorHierarchy *error) const override;
};
class LANGUAGESERVERPROTOCOL_EXPORT CompletionItem : public JsonObject
@@ -220,7 +214,7 @@ public:
void setData(const QJsonValue &data) { insert(dataKey, data); }
void clearData() { remove(dataKey); }
- bool isValid(ErrorHierarchy *error) const override;
+ bool isValid() const override { return contains(labelKey); }
};
class LANGUAGESERVERPROTOCOL_EXPORT CompletionList : public JsonObject
@@ -240,7 +234,7 @@ public:
void setItems(const QList<CompletionItem> &items) { insertArray(itemsKey, items); }
void clearItems() { remove(itemsKey); }
- bool isValid(ErrorHierarchy *error) const override;
+ bool isValid() const override { return contains(isIncompleteKey); }
};
/// The result of a completion is CompletionItem[] | CompletionList | null
diff --git a/src/libs/languageserverprotocol/diagnostics.h b/src/libs/languageserverprotocol/diagnostics.h
index c7b6d7fefb..03b6a22421 100644
--- a/src/libs/languageserverprotocol/diagnostics.h
+++ b/src/libs/languageserverprotocol/diagnostics.h
@@ -46,8 +46,7 @@ public:
void setVersion(int version) { insert(versionKey, version); }
void clearVersion() { remove(versionKey); }
- bool isValid(ErrorHierarchy *error) const override
- { return checkArray<Diagnostic>(error, diagnosticsKey); }
+ bool isValid() const override { return contains(diagnosticsKey); }
};
class LANGUAGESERVERPROTOCOL_EXPORT PublishDiagnosticsNotification : public Notification<PublishDiagnosticsParams>
diff --git a/src/libs/languageserverprotocol/icontent.h b/src/libs/languageserverprotocol/icontent.h
index fb1b3b05fc..a6ecb40714 100644
--- a/src/libs/languageserverprotocol/icontent.h
+++ b/src/libs/languageserverprotocol/icontent.h
@@ -60,7 +60,7 @@ public:
*this = MessageId(value.toString());
}
- QJsonValue toJson() const
+ operator QJsonValue() const
{
QTC_CHECK(Utils::holds_alternative<int>(*this) || Utils::holds_alternative<QString>(*this));
if (auto id = Utils::get_if<int>(this))
@@ -70,14 +70,7 @@ public:
return QJsonValue();
}
- bool isValid(ErrorHierarchy *error = nullptr) const
- {
- if (Utils::holds_alternative<int>(*this) || Utils::holds_alternative<QString>(*this))
- return true;
- if (error)
- error->setError("Expected int or string as MessageId");
- return false;
- }
+ bool isValid() const { return true; }
QString toString() const
{
diff --git a/src/libs/languageserverprotocol/initializemessages.cpp b/src/libs/languageserverprotocol/initializemessages.cpp
index 1f46469438..ab09cf1120 100644
--- a/src/libs/languageserverprotocol/initializemessages.cpp
+++ b/src/libs/languageserverprotocol/initializemessages.cpp
@@ -132,6 +132,14 @@ InitializeParams::InitializeParams()
setTrace(s_trace);
}
+Utils::optional<QJsonObject> InitializeParams::initializationOptions() const
+{
+ const QJsonValue &optionsValue = value(initializationOptionsKey);
+ if (optionsValue.isObject())
+ return optionsValue.toObject();
+ return Utils::nullopt;
+}
+
Utils::optional<Trace> InitializeParams::trace() const
{
const QJsonValue &traceValue = value(traceKey);
@@ -140,17 +148,6 @@ Utils::optional<Trace> InitializeParams::trace() const
return Utils::make_optional(Trace(traceValue.toString()));
}
-bool InitializeParams::isValid(ErrorHierarchy *error) const
-{
- return checkVariant<int, std::nullptr_t>(error, processIdKey)
- && checkOptional<QString, std::nullptr_t>(error, rootPathKey)
- && checkOptional<QString, std::nullptr_t>(error, rootUriKey)
- && check<ClientCapabilities>(error, capabilitiesKey)
- && checkOptional<int>(error, traceKey)
- && (checkOptional<std::nullptr_t>(error, workspaceFoldersKey)
- || checkOptionalArray<WorkSpaceFolder>(error, workspaceFoldersKey));
-}
-
InitializeRequest::InitializeRequest(const InitializeParams &params)
: Request(methodName, params)
{ }
diff --git a/src/libs/languageserverprotocol/initializemessages.h b/src/libs/languageserverprotocol/initializemessages.h
index 5d88267b38..b8a4bf7da4 100644
--- a/src/libs/languageserverprotocol/initializemessages.h
+++ b/src/libs/languageserverprotocol/initializemessages.h
@@ -91,8 +91,7 @@ public:
{ insert(rootUriKey, uri); }
// User provided initialization options.
- Utils::optional<QJsonObject> initializationOptions() const
- { return optionalValue<QJsonObject>(initializationOptionsKey); }
+ Utils::optional<QJsonObject> initializationOptions() const;
void setInitializationOptions(const QJsonObject &options)
{ insert(initializationOptionsKey, options); }
void clearInitializationOptions() { remove(initializationOptionsKey); }
@@ -121,7 +120,8 @@ public:
{ insert(workspaceFoldersKey, folders.toJson()); }
void clearWorkSpaceFolders() { remove(workspaceFoldersKey); }
- bool isValid(ErrorHierarchy *error) const override;
+ bool isValid() const override
+ { return contains(processIdKey) && contains(rootUriKey) && contains(capabilitiesKey); }
};
using InitializedParams = JsonObject;
@@ -136,19 +136,31 @@ public:
bool parametersAreValid(QString * /*errorMessage*/) const final { return true; }
};
+class LANGUAGESERVERPROTOCOL_EXPORT ServerInfo : public JsonObject
+{
+public:
+ using JsonObject::JsonObject;
+
+ QString name() const { return typedValue<QString>(nameKey); }
+ Utils::optional<QString> version() const { return optionalValue<QString>(versionKey); }
+
+ bool isValid() const override { return contains(nameKey); }
+};
+
class LANGUAGESERVERPROTOCOL_EXPORT InitializeResult : public JsonObject
{
public:
using JsonObject::JsonObject;
- Utils::optional<ServerCapabilities> capabilities() const
- { return optionalValue<ServerCapabilities>(capabilitiesKey); }
+ ServerCapabilities capabilities() const
+ { return typedValue<ServerCapabilities>(capabilitiesKey); }
void setCapabilities(const ServerCapabilities &capabilities)
{ insert(capabilitiesKey, capabilities); }
- void clearCapabilities() { remove(capabilitiesKey); }
- bool isValid(ErrorHierarchy *error) const override
- { return checkOptional<ServerCapabilities>(error, capabilitiesKey); }
+ Utils::optional<ServerInfo> serverInfo() const
+ { return optionalValue<ServerInfo>(serverInfoKey); }
+
+ bool isValid() const override { return contains(capabilitiesKey); }
};
class LANGUAGESERVERPROTOCOL_EXPORT InitializeError : public JsonObject
@@ -162,11 +174,10 @@ public:
* (2) user selects retry or cancel
* (3) if user selected retry the initialize method is sent again.
*/
- Utils::optional<bool> retry() const { return optionalValue<bool>(retryKey); }
- void setRetry(bool retry) { insert(retryKey, retry); }
- void clearRetry() { remove(retryKey); }
+ bool retry() const { return typedValue<bool>(retryKey); }
+ void setRetry(const bool &retry) { insert(retryKey, retry); }
- bool isValid(ErrorHierarchy *error) const override { return checkOptional<bool>(error, retryKey); }
+ bool isValid() const override { return contains(retryKey); }
};
class LANGUAGESERVERPROTOCOL_EXPORT InitializeRequest : public Request<
diff --git a/src/libs/languageserverprotocol/jsonkeys.h b/src/libs/languageserverprotocol/jsonkeys.h
index 98b0f488d9..44978e4fc8 100644
--- a/src/libs/languageserverprotocol/jsonkeys.h
+++ b/src/libs/languageserverprotocol/jsonkeys.h
@@ -37,6 +37,7 @@ constexpr char appliedKey[] = "applied";
constexpr char applyEditKey[] = "applyEdit";
constexpr char argumentsKey[] = "arguments";
constexpr char blueKey[] = "blue";
+constexpr char cancellableKey[] = "cancellable";
constexpr char capabilitiesKey[] = "capabilities";
constexpr char chKey[] = "ch";
constexpr char changeKey[] = "change";
@@ -69,15 +70,17 @@ constexpr char contentChangesKey[] = "contentChanges";
constexpr char contentCharsetName[] = "charset";
constexpr char contentFormatKey[] = "contentFormat";
constexpr char contentKey[] = "value";
-constexpr char contentsKey[] = "contents";
constexpr char contentLengthFieldName[] = "Content-Length";
constexpr char contentTypeFieldName[] = "Content-Type";
+constexpr char contentsKey[] = "contents";
constexpr char contextKey[] = "context";
constexpr char contextSupportKey[] = "contextSupport";
constexpr char dataKey[] = "data";
constexpr char defaultCharset[] = "utf-8";
constexpr char definitionKey[] = "definition";
constexpr char definitionProviderKey[] = "definitionProvider";
+constexpr char deleteCountKey[] = "deleteCount";
+constexpr char deltaKey[] = "delta";
constexpr char deprecatedKey[] = "deprecated";
constexpr char detailKey[] = "detail";
constexpr char diagnosticsKey[] = "diagnostics";
@@ -107,7 +110,9 @@ constexpr char executeCommandProviderKey[] = "executeCommandProvider";
constexpr char experimentalKey[] = "experimental";
constexpr char filterTextKey[] = "filterText";
constexpr char firstTriggerCharacterKey[] = "firstTriggerCharacter";
+constexpr char formatsKey[] = "formats";
constexpr char formattingKey[] = "formatting";
+constexpr char fullKey[] = "full";
constexpr char greenKey[] = "green";
constexpr char headerFieldSeparator[] = ": ";
constexpr char headerSeparator[] = "\r\n";
@@ -130,12 +135,14 @@ constexpr char kindKey[] = "kind";
constexpr char labelKey[] = "label";
constexpr char languageIdKey[] = "languageId";
constexpr char languageKey[] = "language";
+constexpr char legendKey[] = "legend";
constexpr char lineKey[] = "line";
constexpr char linesKey[] = "lines";
constexpr char locationKey[] = "location";
constexpr char messageKey[] = "message";
constexpr char methodKey[] = "method";
constexpr char moreTriggerCharacterKey[] = "moreTriggerCharacter";
+constexpr char multiLineTokenSupportKey[] = "multiLineTokenSupport";
constexpr char nameKey[] = "name";
constexpr char newNameKey[] = "newName";
constexpr char newTextKey[] = "newText";
@@ -143,12 +150,15 @@ constexpr char onTypeFormattingKey[] = "onTypeFormatting";
constexpr char onlyKey[] = "only";
constexpr char openCloseKey[] = "openClose";
constexpr char optionsKey[] = "options";
+constexpr char overlappingTokenSupportKey[] = "overlappingTokenSupport";
constexpr char parametersKey[] = "params";
constexpr char patternKey[] = "pattern";
+constexpr char percentageKey[] = "percentage";
constexpr char placeHolderKey[] = "placeHolder";
constexpr char positionKey[] = "position";
constexpr char prepareProviderKey[] = "prepareProvider";
constexpr char prepareSupportKey[] = "prepareSupport";
+constexpr char previousResultIdKey[] = "previousResultId";
constexpr char processIdKey[] = "processId";
constexpr char queryKey[] = "query";
constexpr char rangeFormattingKey[] = "rangeFormatting";
@@ -163,7 +173,9 @@ constexpr char registrationsKey[] = "registrations";
constexpr char removedKey[] = "removed";
constexpr char renameKey[] = "rename";
constexpr char renameProviderKey[] = "renameProvider";
+constexpr char requestsKey[] = "requests";
constexpr char resolveProviderKey[] = "resolveProvider";
+constexpr char resultIdKey[] = "resultId";
constexpr char resultKey[] = "result";
constexpr char retryKey[] = "retry";
constexpr char rootPathKey[] = "rootPath";
@@ -174,8 +186,11 @@ constexpr char scopeUriKey[] = "scopeUri";
constexpr char scopesKey[] = "scopes";
constexpr char sectionKey[] = "section";
constexpr char selectionRangeKey[] = "selectionRange";
-constexpr char semanticHighlightingKey[] = "semanticHighlighting";
constexpr char semanticHighlightingCapabilitiesKey[] = "semanticHighlightingCapabilities";
+constexpr char semanticHighlightingKey[] = "semanticHighlighting";
+constexpr char semanticTokensKey[] = "semanticTokens";
+constexpr char semanticTokensProviderKey[] = "semanticTokensProvider";
+constexpr char serverInfoKey[] = "serverInfo";
constexpr char settingsKey[] = "settings";
constexpr char severityKey[] = "severity";
constexpr char signatureHelpKey[] = "signatureHelp";
@@ -198,6 +213,9 @@ constexpr char textDocumentSyncKey[] = "textDocumentSync";
constexpr char textEditKey[] = "textEdit";
constexpr char textKey[] = "text";
constexpr char titleKey[] = "title";
+constexpr char tokenKey[] = "token";
+constexpr char tokenModifiersKey[] = "tokenModifiers";
+constexpr char tokenTypesKey[] = "tokenTypes";
constexpr char tokensKey[] = "tokens";
constexpr char traceKey[] = "trace";
constexpr char triggerCharacterKey[] = "triggerCharacter";
@@ -215,6 +233,7 @@ constexpr char valueSetKey[] = "valueSet";
constexpr char versionKey[] = "version";
constexpr char willSaveKey[] = "willSave";
constexpr char willSaveWaitUntilKey[] = "willSaveWaitUntil";
+constexpr char windowKey[] = "window";
constexpr char workDoneProgressKey[] = "workDoneProgress";
constexpr char workspaceEditKey[] = "workspaceEdit";
constexpr char workspaceFoldersKey[] = "workspaceFolders";
diff --git a/src/libs/languageserverprotocol/jsonobject.cpp b/src/libs/languageserverprotocol/jsonobject.cpp
index 7bdf3f8688..75edb76de3 100644
--- a/src/libs/languageserverprotocol/jsonobject.cpp
+++ b/src/libs/languageserverprotocol/jsonobject.cpp
@@ -29,34 +29,6 @@
namespace LanguageServerProtocol {
-template <>
-bool JsonObject::checkVal<QString>(ErrorHierarchy *errorHierarchy, const QJsonValue &val)
-{ return checkType(val.type(), QJsonValue::String, errorHierarchy); }
-
-template <>
-bool JsonObject::checkVal<int>(ErrorHierarchy *errorHierarchy, const QJsonValue &val)
-{ return checkType(val.type(), QJsonValue::Double, errorHierarchy); }
-
-template <>
-bool JsonObject::checkVal<double>(ErrorHierarchy *errorHierarchy, const QJsonValue &val)
-{ return checkType(val.type(), QJsonValue::Double, errorHierarchy); }
-
-template <>
-bool JsonObject::checkVal<bool>(ErrorHierarchy *errorHierarchy, const QJsonValue &val)
-{ return checkType(val.type(), QJsonValue::Bool, errorHierarchy); }
-
-template <>
-bool JsonObject::checkVal<std::nullptr_t>(ErrorHierarchy *errorHierarchy, const QJsonValue &val)
-{ return checkType(val.type(), QJsonValue::Null, errorHierarchy); }
-
-template<>
-bool JsonObject::checkVal<QJsonArray>(ErrorHierarchy *errorHierarchy, const QJsonValue &val)
-{ return checkType(val.type(), QJsonValue::Array, errorHierarchy); }
-
-template<>
-bool JsonObject::checkVal<QJsonValue>(ErrorHierarchy * /*errorHierarchy*/, const QJsonValue &/*val*/)
-{ return true; }
-
JsonObject &JsonObject::operator=(const JsonObject &other) = default;
JsonObject &JsonObject::operator=(JsonObject &&other)
@@ -75,43 +47,4 @@ QJsonObject::iterator JsonObject::insert(const QString &key, const QJsonValue &v
return m_jsonObject.insert(key, value);
}
-bool JsonObject::checkKey(ErrorHierarchy *errorHierarchy, const QString &key,
- const std::function<bool (const QJsonValue &)> &predicate) const
-{
- const bool valid = predicate(m_jsonObject.value(key));
- if (!valid && errorHierarchy)
- errorHierarchy->prependMember(key);
- return valid;
-}
-
-QString JsonObject::valueTypeString(QJsonValue::Type type)
-{
- switch (type) {
- case QJsonValue::Null: return QString("Null");
- case QJsonValue::Bool: return QString("Bool");
- case QJsonValue::Double: return QString("Double");
- case QJsonValue::String: return QString("String");
- case QJsonValue::Array: return QString("Array");
- case QJsonValue::Object: return QString("Object");
- case QJsonValue::Undefined: return QString("Undefined");
- }
- return QString();
-}
-
-QString JsonObject::errorString(QJsonValue::Type expected, QJsonValue::Type actual)
-{
- return tr("Expected type %1 but value contained %2")
- .arg(valueTypeString(expected), valueTypeString(actual));
-}
-
-bool JsonObject::checkType(QJsonValue::Type type,
- QJsonValue::Type expectedType,
- ErrorHierarchy *errorHierarchy)
-{
- const bool ret = type == expectedType;
- if (!ret && errorHierarchy)
- errorHierarchy->setError(errorString(expectedType, type));
- return ret;
-}
-
} // namespace LanguageServerProtocol
diff --git a/src/libs/languageserverprotocol/jsonobject.h b/src/libs/languageserverprotocol/jsonobject.h
index 2df8d9dbfb..3b32ed81f5 100644
--- a/src/libs/languageserverprotocol/jsonobject.h
+++ b/src/libs/languageserverprotocol/jsonobject.h
@@ -61,7 +61,7 @@ public:
operator const QJsonObject&() const { return m_jsonObject; }
- virtual bool isValid(ErrorHierarchy * /*errorHierarchy*/) const { return true; }
+ virtual bool isValid() const { return true; }
iterator end() { return m_jsonObject.end(); }
const_iterator end() const { return m_jsonObject.end(); }
@@ -105,31 +105,6 @@ protected:
template<typename>
void insertArray(const QString &key, const QList<JsonObject> &array);
- // value checking
- bool checkKey(ErrorHierarchy *errorHierarchy, const QString &key,
- const std::function<bool(const QJsonValue &val)> &predicate) const;
- static QString valueTypeString(QJsonValue::Type type);
- static QString errorString(QJsonValue::Type expected, QJsonValue::Type type2);
- static bool checkType(QJsonValue::Type type,
- QJsonValue::Type expectedType,
- ErrorHierarchy *errorHierarchy);
- template <typename T>
- static bool checkVal(ErrorHierarchy *errorHierarchy, const QJsonValue &val);
- template <typename T>
- bool check(ErrorHierarchy *errorHierarchy, const QString &key) const;
- template <typename T1, typename T2, typename... Args>
- bool checkVariant(ErrorHierarchy *errorHierarchy, const QString &key) const;
- template <typename T>
- bool checkVariant(ErrorHierarchy *errorHierarchy, const QString &key) const;
- template <typename T>
- bool checkArray(ErrorHierarchy *errorHierarchy, const QString &key) const;
- template <typename T1, typename T2, typename... Args>
- bool checkOptional(ErrorHierarchy *errorHierarchy, const QString &key) const;
- template <typename T>
- bool checkOptional(ErrorHierarchy *errorHierarchy, const QString &key) const;
- template <typename T>
- bool checkOptionalArray(ErrorHierarchy *errorHierarchy, const QString &key) const;
-
private:
QJsonObject m_jsonObject;
};
@@ -223,122 +198,4 @@ void JsonObject::insertArray(const QString &key, const QList<JsonObject> &array)
insert(key, jsonArray);
}
-template <typename T>
-bool JsonObject::checkVal(ErrorHierarchy *errorHierarchy, const QJsonValue &val)
-{
- return checkType(val.type(), QJsonValue::Object, errorHierarchy)
- && T(val).isValid(errorHierarchy);
-}
-
-template <typename T>
-bool JsonObject::check(ErrorHierarchy *errorHierarchy, const QString &key) const
-{
- return checkKey(errorHierarchy, key, [errorHierarchy](const QJsonValue &val) {
- return checkVal<T>(errorHierarchy, val);
- });
-}
-
-template <typename T1, typename T2, typename... Args>
-bool JsonObject::checkVariant(ErrorHierarchy *errorHierarchy, const QString &key) const
-{
- if (checkVariant<T1>(errorHierarchy, key))
- return true;
-
- if (checkVariant<T2, Args...>(errorHierarchy, key)) {
- if (errorHierarchy)
- errorHierarchy->clear();
- return true;
- }
- errorHierarchy->setError(
- QCoreApplication::translate("LanguageServerProtocol::JsonObject",
- "None of the following variants could be correctly parsed:"));
- return false;
-}
-
-template <typename T>
-bool JsonObject::checkVariant(ErrorHierarchy *errorHierarchy, const QString &key) const
-{
- if (!errorHierarchy)
- return check<T>(nullptr, key);
- ErrorHierarchy subError;
- if (check<T>(&subError, key))
- return true;
- errorHierarchy->addVariantHierachy(subError);
- return false;
-}
-
-template <typename T>
-bool JsonObject::checkArray(ErrorHierarchy *errorHierarchy, const QString &key) const
-{
- return checkKey(errorHierarchy, key, [errorHierarchy](const QJsonValue &val){
- return val.isArray() && Utils::allOf(val.toArray(), [&errorHierarchy](const QJsonValue &value){
- return checkVal<T>(errorHierarchy, value);
- });
- });
-}
-
-template <typename T1, typename T2, typename... Args>
-bool JsonObject::checkOptional(ErrorHierarchy *errorHierarchy, const QString &key) const
-{
- if (!contains(key))
- return true;
-
- if (checkVariant<T1>(errorHierarchy, key))
- return true;
-
- if (checkVariant<T2, Args...>(errorHierarchy, key)) {
- if (errorHierarchy)
- errorHierarchy->clear();
- return true;
- }
- errorHierarchy->setError(
- QCoreApplication::translate("LanguageServerProtocol::JsonObject",
- "None of the following variants could be correctly parsed:"));
- return false;
-}
-
-template <typename T>
-bool JsonObject::checkOptional(ErrorHierarchy *errorHierarchy, const QString &key) const
-{
- if (contains(key))
- return check<T>(errorHierarchy, key);
- return true;
-}
-
-template <typename T>
-bool JsonObject::checkOptionalArray(ErrorHierarchy *errorHierarchy, const QString &key) const
-{
- if (contains(key))
- return checkArray<T>(errorHierarchy, key);
- return true;
-}
-
-template <>
-LANGUAGESERVERPROTOCOL_EXPORT bool JsonObject::checkVal<QString>(ErrorHierarchy *errorHierarchy,
- const QJsonValue &val);
-
-template <>
-LANGUAGESERVERPROTOCOL_EXPORT bool JsonObject::checkVal<int>(ErrorHierarchy *errorHierarchy,
- const QJsonValue &val);
-
-template <>
-LANGUAGESERVERPROTOCOL_EXPORT bool JsonObject::checkVal<double>(ErrorHierarchy *errorHierarchy,
- const QJsonValue &val);
-
-template <>
-LANGUAGESERVERPROTOCOL_EXPORT bool JsonObject::checkVal<bool>(ErrorHierarchy *errorHierarchy,
- const QJsonValue &val);
-
-template <>
-LANGUAGESERVERPROTOCOL_EXPORT bool JsonObject::checkVal<std::nullptr_t>(ErrorHierarchy *errorHierarchy,
- const QJsonValue &val);
-
-template<>
-LANGUAGESERVERPROTOCOL_EXPORT bool JsonObject::checkVal<QJsonArray>(ErrorHierarchy *errorHierarchy,
- const QJsonValue &val);
-
-template<>
-LANGUAGESERVERPROTOCOL_EXPORT bool JsonObject::checkVal<QJsonValue>(ErrorHierarchy *errorHierarchy,
- const QJsonValue &val);
-
} // namespace LanguageServerProtocol
diff --git a/src/libs/languageserverprotocol/jsonrpcmessages.h b/src/libs/languageserverprotocol/jsonrpcmessages.h
index d0d3189e00..f0247e3c56 100644
--- a/src/libs/languageserverprotocol/jsonrpcmessages.h
+++ b/src/libs/languageserverprotocol/jsonrpcmessages.h
@@ -121,7 +121,7 @@ public:
virtual bool parametersAreValid(QString *errorMessage) const
{
if (auto parameter = params())
- return parameter.value().isValid(nullptr);
+ return parameter.value().isValid();
if (errorMessage)
*errorMessage = QCoreApplication::translate("LanguageServerProtocol::Notification",
"No parameters in \"%1\".").arg(method());
@@ -179,12 +179,7 @@ public:
void setData(const Error &data) { insert(dataKey, data); }
void clearData() { remove(dataKey); }
- bool isValid(ErrorHierarchy *error) const override
- {
- return check<int>(error, codeKey)
- && check<QString>(error, messageKey)
- && checkOptional<Error>(error, dataKey);
- }
+ bool isValid() const override { return contains(codeKey) && contains(messageKey); }
QString toString() const { return errorCodesToString(code()) + ": " + message(); }
@@ -237,7 +232,7 @@ public:
MessageId id() const
{ return MessageId(m_jsonObject.value(idKey)); }
void setId(MessageId id)
- { this->m_jsonObject.insert(idKey, id.toJson()); }
+ { this->m_jsonObject.insert(idKey, id); }
Utils::optional<Result> result() const
{
@@ -277,7 +272,7 @@ public:
MessageId id() const
{ return MessageId(JsonRpcMessage::m_jsonObject.value(idKey)); }
void setId(const MessageId &id)
- { JsonRpcMessage::m_jsonObject.insert(idKey, id.toJson()); }
+ { JsonRpcMessage::m_jsonObject.insert(idKey, id); }
using Response = LanguageServerProtocol::Response<Result, ErrorDataType>;
using ResponseCallback = std::function<void(Response)>;
@@ -328,17 +323,10 @@ public:
CancelParameter() = default;
using JsonObject::JsonObject;
- MessageId id() const { return MessageId(value(idKey)); }
- void setId(const MessageId &id) { insert(idKey, id.toJson()); }
+ MessageId id() const { return typedValue<MessageId>(idKey); }
+ void setId(const MessageId &id) { insert(idKey, id); }
- bool isValid(ErrorHierarchy *error) const override
- {
- if (MessageId(value(idKey)).isValid(error))
- return true;
- if (error)
- error->prependMember(idKey);
- return false;
- }
+ bool isValid() const override { return contains(idKey); }
};
class LANGUAGESERVERPROTOCOL_EXPORT CancelRequest : public Notification<CancelParameter>
diff --git a/src/libs/languageserverprotocol/languagefeatures.cpp b/src/libs/languageserverprotocol/languagefeatures.cpp
index de175b7e7e..0d32fbcae0 100644
--- a/src/libs/languageserverprotocol/languagefeatures.cpp
+++ b/src/libs/languageserverprotocol/languagefeatures.cpp
@@ -80,11 +80,6 @@ Utils::optional<MarkupOrString> ParameterInformation::documentation() const
return MarkupOrString(documentation);
}
-bool SignatureHelp::isValid(ErrorHierarchy *error) const
-{
- return checkArray<SignatureInformation>(error, signaturesKey);
-}
-
GotoDefinitionRequest::GotoDefinitionRequest(const TextDocumentPositionParams &params)
: Request(methodName, params)
{ }
@@ -119,18 +114,6 @@ void CodeActionParams::CodeActionContext::setOnly(const QList<CodeActionKind> &o
insertArray(onlyKey, only);
}
-bool CodeActionParams::CodeActionContext::isValid(ErrorHierarchy *error) const
-{
- return checkArray<Diagnostic>(error, diagnosticsKey);
-}
-
-bool CodeActionParams::isValid(ErrorHierarchy *error) const
-{
- return check<TextDocumentIdentifier>(error, textDocumentKey)
- && check<Range>(error, rangeKey)
- && check<CodeActionContext>(error, contextKey);
-}
-
CodeActionRequest::CodeActionRequest(const CodeActionParams &params)
: Request(methodName, params)
{ }
@@ -155,21 +138,6 @@ DocumentColorRequest::DocumentColorRequest(const DocumentColorParams &params)
: Request(methodName, params)
{ }
-bool Color::isValid(ErrorHierarchy *error) const
-{
- return check<int>(error, redKey)
- && check<int>(error, greenKey)
- && check<int>(error, blueKey)
- && check<int>(error, alphaKey);
-}
-
-bool ColorPresentationParams::isValid(ErrorHierarchy *error) const
-{
- return check<TextDocumentIdentifier>(error, textDocumentKey)
- && check<Color>(error, colorInfoKey)
- && check<Range>(error, rangeKey);
-}
-
ColorPresentationRequest::ColorPresentationRequest(const ColorPresentationParams &params)
: Request(methodName, params)
{ }
@@ -202,43 +170,19 @@ void FormattingOptions::setProperty(const QString &key, const DocumentFormatting
insert(key, *val);
}
-bool FormattingOptions::isValid(ErrorHierarchy *error) const
-{
- return Utils::allOf(keys(), [this, &error](auto key){
- return (key == tabSizeKey && this->check<int>(error, key))
- || (key == insertSpaceKey && this->check<bool>(error, key))
- || this->check<DocumentFormattingProperty>(error, key);
- });
-}
-
-bool DocumentFormattingParams::isValid(ErrorHierarchy *error) const
-{
- return check<TextDocumentIdentifier>(error, textDocumentKey)
- && check<FormattingOptions>(error, optionsKey);
-}
-
DocumentFormattingRequest::DocumentFormattingRequest(const DocumentFormattingParams &params)
: Request(methodName, params)
{ }
-bool DocumentRangeFormattingParams::isValid(ErrorHierarchy *error) const
-{
- return check<TextDocumentIdentifier>(error, textDocumentKey)
- && check<Range>(error, rangeKey)
- && check<FormattingOptions>(error, optionsKey);
-}
-
DocumentRangeFormattingRequest::DocumentRangeFormattingRequest(
const DocumentRangeFormattingParams &params)
: Request(methodName, params)
{ }
-bool DocumentOnTypeFormattingParams::isValid(ErrorHierarchy *error) const
+bool DocumentOnTypeFormattingParams::isValid() const
{
- return check<TextDocumentIdentifier>(error, textDocumentKey)
- && check<Position>(error, positionKey)
- && check<QString>(error, chKey)
- && check<FormattingOptions>(error, optionsKey);
+ return contains(textDocumentKey) && contains(positionKey) && contains(chKey)
+ && contains(optionsKey);
}
DocumentOnTypeFormattingRequest::DocumentOnTypeFormattingRequest(
@@ -250,11 +194,9 @@ PrepareRenameRequest::PrepareRenameRequest(const TextDocumentPositionParams &par
: Request(methodName, params)
{ }
-bool RenameParams::isValid(ErrorHierarchy *error) const
+bool RenameParams::isValid() const
{
- return check<TextDocumentIdentifier>(error, textDocumentKey)
- && check<Position>(error, positionKey)
- && check<QString>(error, newNameKey);
+ return contains(textDocumentKey) && contains(positionKey) && contains(newNameKey);
}
RenameRequest::RenameRequest(const RenameParams &params)
@@ -269,6 +211,11 @@ Utils::optional<DocumentUri> DocumentLink::target() const
: Utils::nullopt;
}
+Utils::optional<QJsonValue> DocumentLink::data() const
+{
+ return contains(dataKey) ? Utils::make_optional(value(dataKey)) : Utils::nullopt;
+}
+
TextDocumentParams::TextDocumentParams()
: TextDocumentParams(TextDocumentIdentifier())
{ }
@@ -340,13 +287,17 @@ DocumentHighlightsResult::DocumentHighlightsResult(const QJsonValue &value)
MarkedString::MarkedString(const QJsonValue &value)
{
- if (value.isObject()) {
- MarkedLanguageString string(value.toObject());
- if (string.isValid(nullptr))
- emplace<MarkedLanguageString>(string);
- } else if (value.isString()) {
+ if (value.isObject())
+ emplace<MarkedLanguageString>(MarkedLanguageString(value.toObject()));
+ else
emplace<QString>(value.toString());
- }
+}
+
+bool MarkedString::isValid() const
+{
+ if (auto markedLanguageString = Utils::get_if<MarkedLanguageString>(this))
+ return markedLanguageString->isValid();
+ return true;
}
LanguageServerProtocol::MarkedString::operator QJsonValue() const
@@ -365,7 +316,7 @@ HoverContent::HoverContent(const QJsonValue &value)
} else if (value.isObject()) {
const QJsonObject &object = value.toObject();
MarkedLanguageString markedLanguageString(object);
- if (markedLanguageString.isValid(nullptr))
+ if (markedLanguageString.isValid())
emplace<MarkedString>(markedLanguageString);
else
emplace<MarkupContent>(MarkupContent(object));
@@ -374,20 +325,11 @@ HoverContent::HoverContent(const QJsonValue &value)
}
}
-bool HoverContent::isValid(ErrorHierarchy *errorHierarchy) const
+bool HoverContent::isValid() const
{
- if (Utils::holds_alternative<MarkedString>(*this)
- || Utils::holds_alternative<MarkupContent>(*this)
- || Utils::holds_alternative<QList<MarkedString>>(*this)) {
- return true;
- }
- if (errorHierarchy) {
- errorHierarchy->setError(
- QCoreApplication::translate("LanguageServerProtocol::HoverContent",
- "HoverContent should be either MarkedString, "
- "MarkupContent, or QList<MarkedString>."));
- }
- return false;
+ if (Utils::holds_alternative<MarkedString>(*this))
+ return Utils::get<MarkedString>(*this).isValid();
+ return true;
}
DocumentFormattingProperty::DocumentFormattingProperty(const QJsonValue &value)
@@ -400,21 +342,6 @@ DocumentFormattingProperty::DocumentFormattingProperty(const QJsonValue &value)
*this = value.toString();
}
-bool DocumentFormattingProperty::isValid(ErrorHierarchy *error) const
-{
- if (Utils::holds_alternative<bool>(*this)
- || Utils::holds_alternative<double>(*this)
- || Utils::holds_alternative<QString>(*this)) {
- return true;
- }
- if (error) {
- error->setError(QCoreApplication::translate(
- "LanguageServerProtocol::MarkedString",
- "DocumentFormattingProperty should be either bool, double, or QString."));
- }
- return false;
-}
-
SignatureHelpRequest::SignatureHelpRequest(const TextDocumentPositionParams &params)
: Request(methodName, params)
{ }
@@ -427,7 +354,7 @@ CodeActionResult::CodeActionResult(const QJsonValue &val)
ResultArray result;
for (const QJsonValue &val : array) {
Command command(val);
- if (command.isValid(nullptr))
+ if (command.isValid())
result << command;
else
result << CodeAction(val);
@@ -438,15 +365,6 @@ CodeActionResult::CodeActionResult(const QJsonValue &val)
emplace<std::nullptr_t>(nullptr);
}
-bool CodeAction::isValid(ErrorHierarchy *error) const
-{
- return check<QString>(error, titleKey)
- && checkOptional<CodeActionKind>(error, codeActionKindKey)
- && checkOptionalArray<Diagnostic>(error, diagnosticsKey)
- && checkOptional<WorkspaceEdit>(error, editKey)
- && checkOptional<Command>(error, commandKey);
-}
-
Utils::optional<QList<SemanticHighlightToken>> SemanticHighlightingInformation::tokens() const
{
QList<SemanticHighlightToken> resultTokens;
@@ -501,19 +419,7 @@ SemanticHighlightingParams::textDocument() const
{
VersionedTextDocumentIdentifier textDocument = fromJsonValue<VersionedTextDocumentIdentifier>(
value(textDocumentKey));
- ErrorHierarchy error;
- if (!textDocument.isValid(&error)) {
- return TextDocumentIdentifier(textDocument);
- } else {
- return textDocument;
- }
-}
-
-bool SemanticHighlightingParams::isValid(ErrorHierarchy *error) const
-{
- return checkVariant<VersionedTextDocumentIdentifier, TextDocumentIdentifier>(error,
- textDocumentKey)
- && checkArray<SemanticHighlightingInformation>(error, linesKey);
+ return textDocument.isValid() ? textDocument : TextDocumentIdentifier(textDocument);
}
PrepareRenameResult::PrepareRenameResult()
@@ -551,4 +457,9 @@ SemanticHighlightNotification::SemanticHighlightNotification(const SemanticHighl
: Notification(methodName, params)
{}
+Utils::optional<QJsonValue> CodeLens::data() const
+{
+ return contains(dataKey) ? Utils::make_optional(value(dataKey)) : Utils::nullopt;
+}
+
} // namespace LanguageServerProtocol
diff --git a/src/libs/languageserverprotocol/languagefeatures.h b/src/libs/languageserverprotocol/languagefeatures.h
index c1818b34f2..fc8df0bc71 100644
--- a/src/libs/languageserverprotocol/languagefeatures.h
+++ b/src/libs/languageserverprotocol/languagefeatures.h
@@ -54,8 +54,7 @@ public:
QString value() const { return typedValue<QString>(valueKey); }
void setValue(const QString &value) { insert(valueKey, value); }
- bool isValid(ErrorHierarchy *error) const override
- { return check<QString>(error, languageKey) && check<QString>(error, valueKey); }
+ bool isValid() const override { return contains(languageKey) && contains(valueKey); }
};
class LANGUAGESERVERPROTOCOL_EXPORT MarkedString
@@ -71,6 +70,7 @@ public:
{}
explicit MarkedString(const QJsonValue &value);
+ bool isValid() const;
operator QJsonValue() const;
};
@@ -83,7 +83,7 @@ public:
explicit HoverContent(const QList<MarkedString> &other) : variant(other) {}
explicit HoverContent(const MarkupContent &other) : variant(other) {}
explicit HoverContent(const QJsonValue &value);
- bool isValid(ErrorHierarchy *errorHierarchy) const;
+ bool isValid() const;
};
class LANGUAGESERVERPROTOCOL_EXPORT Hover : public JsonObject
@@ -98,8 +98,7 @@ public:
void setRange(const Range &range) { insert(rangeKey, range); }
void clearRange() { remove(rangeKey); }
- bool isValid(ErrorHierarchy *error) const override
- { return check<HoverContent>(error, contentsKey) && checkOptional<Range>(error, rangeKey); }
+ bool isValid() const override { return contains(contentsKey); }
};
class LANGUAGESERVERPROTOCOL_EXPORT HoverRequest
@@ -128,11 +127,7 @@ public:
{ insert(documentationKey, documentation.toJson()); }
void clearDocumentation() { remove(documentationKey); }
- bool isValid(ErrorHierarchy *error) const override
- {
- return check<QString>(error, labelKey)
- && checkOptional<MarkupOrString>(error, documentationKey);
- }
+ bool isValid() const override { return contains(labelKey); }
};
/**
@@ -194,7 +189,7 @@ public:
void setActiveParameter(int activeParameter) { insert(activeParameterKey, activeParameter); }
void clearActiveParameter() { remove(activeParameterKey); }
- bool isValid(ErrorHierarchy *error) const override;
+ bool isValid() const override { return contains(signaturesKey); }
};
class LANGUAGESERVERPROTOCOL_EXPORT SignatureHelpRequest
@@ -258,17 +253,14 @@ public:
void setIncludeDeclaration(bool includeDeclaration)
{ insert(includeDeclarationKey, includeDeclaration); }
- bool isValid(ErrorHierarchy *error) const override
- { return check<bool>(error, includeDeclarationKey); }
+ bool isValid() const override { return contains(includeDeclarationKey); }
};
ReferenceContext context() const { return typedValue<ReferenceContext>(contextKey); }
void setContext(const ReferenceContext &context) { insert(contextKey, context); }
- bool isValid(ErrorHierarchy *error) const override
- {
- return TextDocumentPositionParams::isValid(error)
- && check<ReferenceContext>(error, contextKey); }
+ bool isValid() const override
+ { return TextDocumentPositionParams::isValid() && contains(contextKey); }
};
class LANGUAGESERVERPROTOCOL_EXPORT FindReferencesRequest : public Request<
@@ -298,8 +290,7 @@ public:
void setKind(int kind) { insert(kindKey, kind); }
void clearKind() { remove(kindKey); }
- bool isValid(ErrorHierarchy *error) const override
- { return check<Range>(error, rangeKey) && checkOptional<int>(error, kindKey); }
+ bool isValid() const override { return contains(rangeKey); }
};
class LANGUAGESERVERPROTOCOL_EXPORT DocumentHighlightsResult
@@ -333,8 +324,7 @@ public:
void setTextDocument(const TextDocumentIdentifier &textDocument)
{ insert(textDocumentKey, textDocument); }
- bool isValid(ErrorHierarchy *error) const override
- { return check<TextDocumentIdentifier>(error, textDocumentKey); }
+ bool isValid() const override { return contains(textDocumentKey); }
};
using DocumentSymbolParams = TextDocumentParams;
@@ -417,7 +407,7 @@ public:
void setOnly(const QList<CodeActionKind> &only);
void clearOnly() { remove(onlyKey); }
- bool isValid(ErrorHierarchy *error) const override;
+ bool isValid() const override { return contains(diagnosticsKey); }
};
TextDocumentIdentifier textDocument() const
@@ -431,7 +421,8 @@ public:
CodeActionContext context() const { return typedValue<CodeActionContext>(contextKey); }
void setContext(const CodeActionContext &context) { insert(contextKey, context); }
- bool isValid(ErrorHierarchy *error) const override;
+ bool isValid() const override
+ { return contains(textDocumentKey) && contains(rangeKey) && contains(contextKey); }
};
class LANGUAGESERVERPROTOCOL_EXPORT CodeAction : public JsonObject
@@ -460,7 +451,7 @@ public:
void setCommand(const Command &command) { insert(commandKey, command); }
void clearCommand() { remove(commandKey); }
- bool isValid(ErrorHierarchy *) const override;
+ bool isValid() const override { return contains(titleKey); }
};
class LANGUAGESERVERPROTOCOL_EXPORT CodeActionResult
@@ -494,12 +485,11 @@ public:
void setCommand(const Command &command) { insert(commandKey, command); }
void clearCommand() { remove(commandKey); }
- Utils::optional<QJsonValue> data() const { return optionalValue<QJsonValue>(dataKey); }
+ Utils::optional<QJsonValue> data() const;
void setData(const QJsonValue &data) { insert(dataKey, data); }
void clearData() { remove(dataKey); }
- bool isValid(ErrorHierarchy *error) const override
- { return check<Range>(error, rangeKey) && checkOptional<Command>(error, commandKey); }
+ bool isValid() const override { return contains(rangeKey); }
};
class LANGUAGESERVERPROTOCOL_EXPORT CodeLensRequest : public Request<
@@ -532,12 +522,11 @@ public:
void setTarget(const DocumentUri &target) { insert(targetKey, target.toString()); }
void clearTarget() { remove(targetKey); }
- Utils::optional<QJsonValue> data() const { return optionalValue<QJsonValue>(dataKey); }
+ Utils::optional<QJsonValue> data() const;
void setData(const QJsonValue &data) { insert(dataKey, data); }
void clearData() { remove(dataKey); }
- bool isValid(ErrorHierarchy *error) const override
- { return check<Range>(error, rangeKey) && checkOptional<QString>(error, targetKey); }
+ bool isValid() const override { return contains(rangeKey); }
};
using DocumentLinkParams = TextDocumentParams;
@@ -579,7 +568,8 @@ public:
double alpha() const { return typedValue<double>(alphaKey); }
void setAlpha(double alpha) { insert(alphaKey, alpha); }
- bool isValid(ErrorHierarchy *error) const override;
+ bool isValid() const override
+ { return contains(redKey) && contains(greenKey) && contains(blueKey) && contains(alphaKey); }
};
class LANGUAGESERVERPROTOCOL_EXPORT ColorInformation : public JsonObject
@@ -593,8 +583,7 @@ public:
Color color() const { return typedValue<Color>(colorKey); }
void setColor(const Color &color) { insert(colorKey, color); }
- bool isValid(ErrorHierarchy *error) const override
- { return check<Range>(error, rangeKey) && check<Color>(error, colorKey); }
+ bool isValid() const override { return contains(rangeKey) && contains(colorKey); }
};
class LANGUAGESERVERPROTOCOL_EXPORT DocumentColorRequest : public Request<
@@ -622,7 +611,8 @@ public:
Range range() const { return typedValue<Range>(rangeKey); }
void setRange(const Range &range) { insert(rangeKey, range); }
- bool isValid(ErrorHierarchy *error) const override;
+ bool isValid() const override
+ { return contains(textDocumentKey) && contains(colorInfoKey) && contains(rangeKey); }
};
class LANGUAGESERVERPROTOCOL_EXPORT ColorPresentation : public JsonObject
@@ -643,12 +633,7 @@ public:
{ insertArray(additionalTextEditsKey, additionalTextEdits); }
void clearAdditionalTextEdits() { remove(additionalTextEditsKey); }
- bool isValid(ErrorHierarchy *error) const override
- {
- return check<QString>(error, labelKey)
- && checkOptional<TextEdit>(error, textEditKey)
- && checkOptionalArray<TextEdit>(error, additionalTextEditsKey);
- }
+ bool isValid() const override { return contains(labelKey); }
};
class LANGUAGESERVERPROTOCOL_EXPORT ColorPresentationRequest : public Request<
@@ -670,8 +655,6 @@ public:
using variant::variant;
using variant::operator=;
-
- bool isValid(ErrorHierarchy *error) const;
};
class LANGUAGESERVERPROTOCOL_EXPORT FormattingOptions : public JsonObject
@@ -707,7 +690,7 @@ public:
void setProperty(const QString &key, const DocumentFormattingProperty &property);
void removeProperty(const QString &key) { remove(key); }
- bool isValid(ErrorHierarchy *error) const override;
+ bool isValid() const override { return contains(insertSpaceKey) && contains(tabSizeKey); }
};
class LANGUAGESERVERPROTOCOL_EXPORT DocumentFormattingParams : public JsonObject
@@ -723,7 +706,7 @@ public:
FormattingOptions options() const { return typedValue<FormattingOptions>(optionsKey); }
void setOptions(const FormattingOptions &options) { insert(optionsKey, options); }
- bool isValid(ErrorHierarchy *error) const override;
+ bool isValid() const override { return contains(textDocumentKey) && contains(optionsKey); }
};
class LANGUAGESERVERPROTOCOL_EXPORT DocumentFormattingRequest : public Request<
@@ -751,7 +734,8 @@ public:
FormattingOptions options() const { return typedValue<FormattingOptions>(optionsKey); }
void setOptions(const FormattingOptions &options) { insert(optionsKey, options); }
- bool isValid(ErrorHierarchy *error) const override;
+ bool isValid() const override
+ { return contains(textDocumentKey) && contains(rangeKey) && contains(optionsKey); }
};
class LANGUAGESERVERPROTOCOL_EXPORT DocumentRangeFormattingRequest : public Request<
@@ -782,7 +766,7 @@ public:
FormattingOptions options() const { return typedValue<FormattingOptions>(optionsKey); }
void setOptions(const FormattingOptions &options) { insert(optionsKey, options); }
- bool isValid(ErrorHierarchy *error) const override;
+ bool isValid() const override;
};
class LANGUAGESERVERPROTOCOL_EXPORT DocumentOnTypeFormattingRequest : public Request<
@@ -805,10 +789,7 @@ public:
QString placeHolder() const { return typedValue<QString>(placeHolderKey); }
void setPlaceHolder(const QString &placeHolder) { insert(placeHolderKey, placeHolder); }
- bool isValid(ErrorHierarchy *error) const override
- {
- return check<Range>(error, rangeKey) && checkOptional<QString>(error, placeHolderKey);
- }
+ bool isValid() const override { return contains(rangeKey); }
};
class LANGUAGESERVERPROTOCOL_EXPORT PrepareRenameResult
@@ -821,7 +802,7 @@ public:
explicit PrepareRenameResult(const Range &val);
explicit PrepareRenameResult(const QJsonValue &val);
- bool isValid(ErrorHierarchy *error) const;
+ bool isValid() const;
};
class LANGUAGESERVERPROTOCOL_EXPORT PrepareRenameRequest
@@ -849,7 +830,7 @@ public:
QString newName() const { return typedValue<QString>(newNameKey); }
void setNewName(const QString &newName) { insert(newNameKey, newName); }
- bool isValid(ErrorHierarchy *error) const override;
+ bool isValid() const override;
};
class LANGUAGESERVERPROTOCOL_EXPORT RenameRequest : public Request<
@@ -887,8 +868,7 @@ public:
void setTokens(const QList<SemanticHighlightToken> &tokens);
void clearTokens() { remove(tokensKey); }
- bool isValid(ErrorHierarchy *error) const override
- { return check<int>(error, lineKey) && checkOptional<QString>(error, tokensKey); }
+ bool isValid() const override { return contains(lineKey); }
};
class LANGUAGESERVERPROTOCOL_EXPORT SemanticHighlightingParams : public JsonObject
@@ -907,7 +887,7 @@ public:
void setLines(const QList<SemanticHighlightingInformation> &lines)
{ insertArray(linesKey, lines); }
- bool isValid(ErrorHierarchy *error) const override;
+ bool isValid() const override { return contains(textDocumentKey) && contains(linesKey); }
};
class LANGUAGESERVERPROTOCOL_EXPORT SemanticHighlightNotification
diff --git a/src/libs/languageserverprotocol/languageserverprotocol.pro b/src/libs/languageserverprotocol/languageserverprotocol.pro
index d9460cbf02..33651a9280 100644
--- a/src/libs/languageserverprotocol/languageserverprotocol.pro
+++ b/src/libs/languageserverprotocol/languageserverprotocol.pro
@@ -17,15 +17,19 @@ HEADERS += \
lsptypes.h \
lsputils.h \
messages.h \
+ progresssupport.h \
+ semantictokens.h \
servercapabilities.h \
shutdownmessages.h \
textsynchronization.h \
- workspace.h
+ workspace.h \
SOURCES += \
basemessage.cpp \
+ client.cpp \
clientcapabilities.cpp \
completion.cpp \
+ diagnostics.cpp \
initializemessages.cpp \
jsonobject.cpp \
jsonrpcmessages.cpp \
@@ -33,9 +37,9 @@ SOURCES += \
lsptypes.cpp \
lsputils.cpp \
messages.cpp \
+ progresssupport.cpp \
+ semantictokens.cpp \
servercapabilities.cpp \
+ shutdownmessages.cpp \
textsynchronization.cpp \
workspace.cpp \
- client.cpp \
- shutdownmessages.cpp \
- diagnostics.cpp
diff --git a/src/libs/languageserverprotocol/languageserverprotocol.qbs b/src/libs/languageserverprotocol/languageserverprotocol.qbs
index bca58fbd04..97e5b5d1c7 100644
--- a/src/libs/languageserverprotocol/languageserverprotocol.qbs
+++ b/src/libs/languageserverprotocol/languageserverprotocol.qbs
@@ -35,6 +35,10 @@ Project {
"lsputils.h",
"messages.cpp",
"messages.h",
+ "progresssupport.cpp",
+ "progresssupport.h",
+ "semantictokens.cpp",
+ "semantictokens.h",
"servercapabilities.cpp",
"servercapabilities.h",
"shutdownmessages.cpp",
diff --git a/src/libs/languageserverprotocol/lsptypes.cpp b/src/libs/languageserverprotocol/lsptypes.cpp
index ddf2cc2ee3..bae7f157f1 100644
--- a/src/libs/languageserverprotocol/lsptypes.cpp
+++ b/src/libs/languageserverprotocol/lsptypes.cpp
@@ -65,15 +65,6 @@ void Diagnostic::setCode(const Diagnostic::Code &code)
insertVariant<int, QString>(codeKey, code);
}
-bool Diagnostic::isValid(ErrorHierarchy *error) const
-{
- return check<Range>(error, rangeKey)
- && checkOptional<int>(error, severityKey)
- && (checkOptional<int>(error, codeKey) || checkOptional<QString>(error, codeKey))
- && checkOptional<QString>(error, sourceKey)
- && check<QString>(error, messageKey);
-}
-
Utils::optional<WorkspaceEdit::Changes> WorkspaceEdit::changes() const
{
auto it = find(changesKey);
@@ -123,23 +114,11 @@ MarkupOrString::MarkupOrString(const QJsonValue &val)
emplace<QString>(val.toString());
} else {
MarkupContent markupContent(val.toObject());
- if (markupContent.isValid(nullptr))
+ if (markupContent.isValid())
emplace<MarkupContent>(MarkupContent(val.toObject()));
}
}
-bool MarkupOrString::isValid(ErrorHierarchy *error) const
-{
- if (Utils::holds_alternative<MarkupContent>(*this) || Utils::holds_alternative<QString>(*this))
- return true;
- if (error) {
- error->setError(
- QCoreApplication::translate("LanguageServerProtocoll::MarkupOrString",
- "Expected a string or MarkupContent in MarkupOrString."));
- }
- return false;
-}
-
QJsonValue MarkupOrString::toJson() const
{
if (Utils::holds_alternative<QString>(*this))
@@ -149,28 +128,6 @@ QJsonValue MarkupOrString::toJson() const
return {};
}
-bool SymbolInformation::isValid(ErrorHierarchy *error) const
-{
- return check<QString>(error, nameKey)
- && check<int>(error, kindKey)
- && check<Location>(error, locationKey)
- && checkOptional<QString>(error, containerNameKey);
-}
-
-bool TextDocumentEdit::isValid(ErrorHierarchy *error) const
-{
- return check<VersionedTextDocumentIdentifier>(error, textDocumentKey)
- && checkArray<TextEdit>(error, editsKey);
-}
-
-bool TextDocumentItem::isValid(ErrorHierarchy *error) const
-{
- return check<QString>(error, uriKey)
- && check<QString>(error, languageIdKey)
- && check<int>(error, versionKey)
- && check<QString>(error, textKey);
-}
-
static QHash<Utils::MimeType, QString> mimeTypeLanguageIdMap()
{
static QHash<Utils::MimeType, QString> hash;
@@ -281,6 +238,11 @@ QMap<QString, QString> languageIds()
return languages;
}
+bool TextDocumentItem::isValid() const
+{
+ return contains(uriKey) && contains(languageIdKey) && contains(versionKey) && contains(textKey);
+}
+
QString TextDocumentItem::mimeTypeToLanguageId(const Utils::MimeType &mimeType)
{
return mimeTypeLanguageIdMap().value(mimeType);
@@ -304,12 +266,6 @@ TextDocumentPositionParams::TextDocumentPositionParams(
setPosition(position);
}
-bool TextDocumentPositionParams::isValid(ErrorHierarchy *error) const
-{
- return check<TextDocumentIdentifier>(error, textDocumentKey)
- && check<Position>(error, positionKey);
-}
-
Position::Position(int line, int character)
{
setLine(line);
@@ -356,6 +312,15 @@ Range::Range(const QTextCursor &cursor)
setEnd(Position(line - 1, character - 1));
}
+bool Range::contains(const Range &other) const
+{
+ if (start() > other.start())
+ return false;
+ if (end() < other.end())
+ return false;
+ return true;
+}
+
bool Range::overlaps(const Range &range) const
{
return contains(range.start()) || contains(range.end());
@@ -388,16 +353,9 @@ bool DocumentFilter::applies(const Utils::FilePath &fileName, const Utils::MimeT
return !contains(schemeKey) && !contains(languageKey) && !contains(patternKey);
}
-bool DocumentFilter::isValid(ErrorHierarchy *error) const
-{
- return Utils::allOf(QStringList{languageKey, schemeKey, patternKey}, [this, &error](auto key){
- return this->checkOptional<QString>(error, key);
- });
-}
-
Utils::Link Location::toLink() const
{
- if (!isValid(nullptr))
+ if (!isValid())
return Utils::Link();
// Ensure %xx like %20 are really decoded using fromPercentEncoding
@@ -408,7 +366,9 @@ Utils::Link Location::toLink() const
// fromPercentEncoding convert %xx encoding to raw values and then interpret
// the result as utf-8, so toUtf8() must be used here.
file = QUrl::fromPercentEncoding(file.toUtf8());
- return Utils::Link(file, range().start().line() + 1, range().start().character());
+ return Utils::Link(Utils::FilePath::fromString(file),
+ range().start().line() + 1,
+ range().start().character());
}
DocumentUri::DocumentUri(const QString &other)
diff --git a/src/libs/languageserverprotocol/lsptypes.h b/src/libs/languageserverprotocol/lsptypes.h
index d6de79b430..1c6820a4aa 100644
--- a/src/libs/languageserverprotocol/lsptypes.h
+++ b/src/libs/languageserverprotocol/lsptypes.h
@@ -83,17 +83,27 @@ public:
int character() const { return typedValue<int>(characterKey); }
void setCharacter(int character) { insert(characterKey, character); }
- bool isValid(ErrorHierarchy *error) const override
- { return check<int>(error, lineKey) && check<int>(error, characterKey); }
+ bool isValid() const override
+ { return contains(lineKey) && contains(characterKey); }
int toPositionInDocument(QTextDocument *doc) const;
QTextCursor toTextCursor(QTextDocument *doc) const;
};
-static bool operator<=(const Position &first, const Position &second)
+inline bool operator<(const Position &first, const Position &second)
{
return first.line() < second.line()
- || (first.line() == second.line() && first.character() <= second.character());
+ || (first.line() == second.line() && first.character() < second.character());
+}
+
+inline bool operator>(const Position &first, const Position &second)
+{
+ return second < first;
+}
+
+inline bool operator<=(const Position &first, const Position &second)
+{
+ return !(first > second);
}
class LANGUAGESERVERPROTOCOL_EXPORT Range : public JsonObject
@@ -113,10 +123,11 @@ public:
void setEnd(const Position &end) { insert(endKey, end); }
bool contains(const Position &pos) const { return start() <= pos && pos <= end(); }
+ bool contains(const Range &other) const;
bool overlaps(const Range &range) const;
- bool isValid(ErrorHierarchy *error) const override
- { return check<Position>(error, startKey) && check<Position>(error, endKey); }
+ bool isValid() const override
+ { return JsonObject::contains(startKey) && JsonObject::contains(endKey); }
};
class LANGUAGESERVERPROTOCOL_EXPORT Location : public JsonObject
@@ -133,8 +144,7 @@ public:
Utils::Link toLink() const;
- bool isValid(ErrorHierarchy *error) const override
- { return check<QString>(error, uriKey) && check<Range>(error, rangeKey); }
+ bool isValid() const override { return contains(uriKey) && contains(rangeKey); }
};
enum class DiagnosticSeverity
@@ -180,7 +190,7 @@ public:
{ return typedValue<QString>(messageKey); }
void setMessage(const QString &message) { insert(messageKey, message); }
- bool isValid(ErrorHierarchy *error) const override;
+ bool isValid() const override { return contains(rangeKey) && contains(messageKey); }
};
class LANGUAGESERVERPROTOCOL_EXPORT Command : public JsonObject
@@ -203,10 +213,7 @@ public:
void setArguments(const QJsonArray &arguments) { insert(argumentsKey, arguments); }
void clearArguments() { remove(argumentsKey); }
- bool isValid(ErrorHierarchy *error) const override
- { return check<QString>(error, titleKey)
- && check<QString>(error, commandKey)
- && checkOptional<QJsonArray>(error, argumentsKey); }
+ bool isValid() const override { return contains(titleKey) && contains(commandKey); }
};
class LANGUAGESERVERPROTOCOL_EXPORT TextEdit : public JsonObject
@@ -225,8 +232,8 @@ public:
Utils::Text::Replacement toReplacement(QTextDocument *document) const;
- bool isValid(ErrorHierarchy *error) const override
- { return check<Range>(error, rangeKey) && check<QString>(error, newTextKey); }
+ bool isValid() const override
+ { return contains(rangeKey) && contains(newTextKey); }
};
class LANGUAGESERVERPROTOCOL_EXPORT TextDocumentIdentifier : public JsonObject
@@ -240,7 +247,7 @@ public:
DocumentUri uri() const { return DocumentUri::fromProtocol(typedValue<QString>(uriKey)); }
void setUri(const DocumentUri &uri) { insert(uriKey, uri); }
- bool isValid(ErrorHierarchy *error) const override { return check<QString>(error, uriKey); }
+ bool isValid() const override { return contains(uriKey); }
};
class LANGUAGESERVERPROTOCOL_EXPORT VersionedTextDocumentIdentifier : public TextDocumentIdentifier
@@ -258,10 +265,9 @@ public:
LanguageClientValue<int> version() const { return clientValue<int>(versionKey); }
void setVersion(LanguageClientValue<int> version) { insert(versionKey, version); }
- bool isValid(ErrorHierarchy *error) const override
+ bool isValid() const override
{
- return TextDocumentIdentifier::isValid(error)
- && checkVariant<int, std::nullptr_t>(error, versionKey);
+ return TextDocumentIdentifier::isValid() && contains(versionKey);
}
};
@@ -280,7 +286,7 @@ public:
QList<TextEdit> edits() const { return array<TextEdit>(editsKey); }
void setEdits(const QList<TextEdit> edits) { insertArray(editsKey, edits); }
- bool isValid(ErrorHierarchy *error) const override;
+ bool isValid() const override { return contains(textDocumentKey) && contains(editsKey); }
};
class LANGUAGESERVERPROTOCOL_EXPORT WorkspaceEdit : public JsonObject
@@ -306,9 +312,6 @@ public:
{ return optionalArray<TextDocumentEdit>(documentChangesKey); }
void setDocumentChanges(const QList<TextDocumentEdit> &changes)
{ insertArray(documentChangesKey, changes); }
-
- bool isValid(ErrorHierarchy *error) const override
- { return checkOptionalArray<TextDocumentEdit>(error, documentChangesKey); }
};
LANGUAGESERVERPROTOCOL_EXPORT QMap<QString, QString> languageIds();
@@ -334,7 +337,7 @@ public:
QString text() const { return typedValue<QString>(textKey); }
void setText(const QString &text) { insert(textKey, text); }
- bool isValid(ErrorHierarchy *error) const override;
+ bool isValid() const override;
static QString mimeTypeToLanguageId(const Utils::MimeType &mimeType);
static QString mimeTypeToLanguageId(const QString &mimeTypeName);
@@ -356,7 +359,7 @@ public:
Position position() const { return typedValue<Position>(positionKey); }
void setPosition(const Position &position) { insert(positionKey, position); }
- bool isValid(ErrorHierarchy *error) const override;
+ bool isValid() const override { return contains(textDocumentKey) && contains(positionKey); }
};
class LANGUAGESERVERPROTOCOL_EXPORT DocumentFilter : public JsonObject
@@ -381,8 +384,6 @@ public:
bool applies(const Utils::FilePath &fileName,
const Utils::MimeType &mimeType = Utils::MimeType()) const;
-
- bool isValid(ErrorHierarchy *error) const override;
};
class LANGUAGESERVERPROTOCOL_EXPORT MarkupKind
@@ -400,7 +401,7 @@ public:
bool operator==(const Value &value) const { return m_value == value; }
- bool isValid(void *) const { return true; }
+ bool isValid() const { return true; }
private:
Value m_value = plaintext;
};
@@ -420,8 +421,8 @@ public:
QString content() const { return typedValue<QString>(contentKey); }
void setContent(const QString &content) { insert(contentKey, content); }
- bool isValid(ErrorHierarchy *error) const override
- { return check<MarkupKind>(error, kindKey) && check<QString>(error, contentKey); }
+ bool isValid() const override
+ { return contains(kindKey) && contains(contentKey); }
};
class LANGUAGESERVERPROTOCOL_EXPORT MarkupOrString : public Utils::variant<QString, MarkupContent>
@@ -433,7 +434,7 @@ public:
explicit MarkupOrString(const MarkupContent &val);
MarkupOrString(const QJsonValue &val);
- bool isValid(ErrorHierarchy *error) const;
+ bool isValid() const { return true; }
QJsonValue toJson() const;
};
@@ -453,8 +454,8 @@ public:
QString name() const { return typedValue<QString>(nameKey); }
void setName(const QString &name) { insert(nameKey, name); }
- bool isValid(ErrorHierarchy *error) const override
- { return check<QString>(error, uriKey) && check<QString>(error, nameKey); }
+ bool isValid() const override
+ { return contains(uriKey) && contains(nameKey); }
};
class LANGUAGESERVERPROTOCOL_EXPORT SymbolInformation : public JsonObject
@@ -480,7 +481,8 @@ public:
void setContainerName(const QString &containerName) { insert(containerNameKey, containerName); }
void clearContainerName() { remove(containerNameKey); }
- bool isValid(ErrorHierarchy *error) const override;
+ bool isValid() const override
+ { return contains(nameKey) && contains(kindKey) && contains(locationKey); }
};
class LANGUAGESERVERPROTOCOL_EXPORT DocumentSymbol : public JsonObject
diff --git a/src/libs/languageserverprotocol/lsputils.cpp b/src/libs/languageserverprotocol/lsputils.cpp
index ecb78129cc..fdac50c3d1 100644
--- a/src/libs/languageserverprotocol/lsputils.cpp
+++ b/src/libs/languageserverprotocol/lsputils.cpp
@@ -75,34 +75,18 @@ QJsonArray fromJsonValue<QJsonArray>(const QJsonValue &value)
return value.toArray();
}
-void ErrorHierarchy::clear()
-{
- m_hierarchy.clear();
- m_children.clear();
- m_error.clear();
-}
-
-bool ErrorHierarchy::isEmpty() const
-{
- return m_hierarchy.isEmpty() && m_children.isEmpty() && m_error.isEmpty();
-}
-
-QString ErrorHierarchy::toString() const
+template<>
+QJsonObject fromJsonValue<QJsonObject>(const QJsonValue &value)
{
- if (m_error.isEmpty() && m_hierarchy.isEmpty())
- return {};
- QString error = m_hierarchy.join(" > ") + ": " + m_error;
- if (!m_children.isEmpty()) {
- error.append("\n\t");
- error.append(Utils::transform(m_children, &ErrorHierarchy::toString).join("\n\t"));
- }
- return error;
+ if (conversionLog().isDebugEnabled() && !value.isObject())
+ qCDebug(conversionLog) << "Expected Object in json value but got: " << value;
+ return value.toObject();
}
-bool ErrorHierarchy::operator==(const ErrorHierarchy &other) const
+template<>
+QJsonValue fromJsonValue<QJsonValue>(const QJsonValue &value)
{
- return m_hierarchy == other.m_hierarchy && m_children == other.m_children
- && m_error == other.m_error;
+ return value;
}
} // namespace LanguageServerProtocol
diff --git a/src/libs/languageserverprotocol/lsputils.h b/src/libs/languageserverprotocol/lsputils.h
index 677325448b..08d5e1e3ec 100644
--- a/src/libs/languageserverprotocol/lsputils.h
+++ b/src/libs/languageserverprotocol/lsputils.h
@@ -46,7 +46,10 @@ T fromJsonValue(const QJsonValue &value)
{
if (conversionLog().isDebugEnabled() && !value.isObject())
qCDebug(conversionLog) << "Expected Object in json value but got: " << value;
- return T(value.toObject());
+ T result(value.toObject());
+ if (conversionLog().isDebugEnabled() && !result.isValid())
+ qCDebug(conversionLog) << typeid(result).name() << " is not valid: " << result;
+ return result;
}
template<>
@@ -62,8 +65,14 @@ template<>
LANGUAGESERVERPROTOCOL_EXPORT bool fromJsonValue<bool>(const QJsonValue &value);
template<>
+LANGUAGESERVERPROTOCOL_EXPORT QJsonObject fromJsonValue<QJsonObject>(const QJsonValue &value);
+
+template<>
LANGUAGESERVERPROTOCOL_EXPORT QJsonArray fromJsonValue<QJsonArray>(const QJsonValue &value);
+template<>
+LANGUAGESERVERPROTOCOL_EXPORT QJsonValue fromJsonValue<QJsonValue>(const QJsonValue &value);
+
template <typename T>
class LanguageClientArray : public Utils::variant<QList<T>, std::nullptr_t>
{
@@ -165,24 +174,4 @@ QList<T> jsonArrayToList(const QJsonArray &array)
return list;
}
-class LANGUAGESERVERPROTOCOL_EXPORT ErrorHierarchy
-{
-public:
- ErrorHierarchy() = default;
-
- void setError(const QString &error) { m_error = error; }
- void prependMember(const QString &member) { m_hierarchy.prepend(member); }
- void addVariantHierachy(const ErrorHierarchy &subError) { m_children.append(subError); }
- void clear();
-
- bool isEmpty() const;
- QString toString() const;
-
- bool operator==(const ErrorHierarchy &other) const;
-private:
- QStringList m_hierarchy;
- QList<ErrorHierarchy> m_children;
- QString m_error;
-};
-
-} // namespace LanguageClient
+} // namespace LanguageServerProtocol
diff --git a/src/libs/languageserverprotocol/messages.cpp b/src/libs/languageserverprotocol/messages.cpp
index 44a699ca25..2f658e3afe 100644
--- a/src/libs/languageserverprotocol/messages.cpp
+++ b/src/libs/languageserverprotocol/messages.cpp
@@ -50,12 +50,6 @@ TelemetryNotification::TelemetryNotification(const JsonObject &params)
: Notification(methodName, params)
{ }
-bool ShowMessageRequestParams::isValid(ErrorHierarchy *error) const
-{
- return ShowMessageParams::isValid(error)
- && checkOptionalArray<MessageActionItem>(error, actionsKey);
-}
-
static QString messageTypeName(int messageType)
{
switch (messageType) {
diff --git a/src/libs/languageserverprotocol/messages.h b/src/libs/languageserverprotocol/messages.h
index 6a9580e3e5..840f380ce0 100644
--- a/src/libs/languageserverprotocol/messages.h
+++ b/src/libs/languageserverprotocol/messages.h
@@ -49,8 +49,8 @@ public:
QString toString() const;
- bool isValid(ErrorHierarchy *error) const override
- { return check<int>(error, typeKey) && check<QString>(error, messageKey); }
+ bool isValid() const override
+ { return contains(typeKey) && contains(messageKey); }
};
class LANGUAGESERVERPROTOCOL_EXPORT ShowMessageNotification : public Notification<ShowMessageParams>
@@ -70,7 +70,7 @@ public:
QString title() const { return typedValue<QString>(titleKey); }
void setTitle(QString title) { insert(titleKey, title); }
- bool isValid(ErrorHierarchy *error) const override { return check<QString>(error, titleKey); }
+ bool isValid() const override { return contains(titleKey); }
};
class LANGUAGESERVERPROTOCOL_EXPORT ShowMessageRequestParams : public ShowMessageParams
@@ -82,8 +82,6 @@ public:
{ return optionalArray<MessageActionItem>(actionsKey); }
void setActions(const QList<MessageActionItem> &actions) { insertArray(actionsKey, actions); }
void clearActions() { remove(actionsKey); }
-
- bool isValid(ErrorHierarchy *error) const override;
};
class LANGUAGESERVERPROTOCOL_EXPORT ShowMessageRequest : public Request<
diff --git a/src/libs/languageserverprotocol/progresssupport.cpp b/src/libs/languageserverprotocol/progresssupport.cpp
new file mode 100644
index 0000000000..479a48489a
--- /dev/null
+++ b/src/libs/languageserverprotocol/progresssupport.cpp
@@ -0,0 +1,78 @@
+/****************************************************************************
+**
+** Copyright (C) 2021 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of Qt Creator.
+**
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3 as published by the Free Software
+** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-3.0.html.
+**
+****************************************************************************/
+
+#include "progresssupport.h"
+
+#include <utils/qtcassert.h>
+
+#include <QUuid>
+
+namespace LanguageServerProtocol {
+
+ProgressToken::ProgressToken(const QJsonValue &value)
+{
+ if (!QTC_GUARD(value.isDouble() || value.isString()))
+ emplace<QString>(QUuid::createUuid().toString());
+ else if (value.isDouble())
+ emplace<int>(value.toInt());
+ else
+ emplace<QString>(value.toString());
+}
+
+ProgressToken::operator QJsonValue() const
+{
+ if (Utils::holds_alternative<QString>(*this))
+ return QJsonValue(Utils::get<QString>(*this));
+ return QJsonValue(Utils::get<int>(*this));
+}
+
+ProgressParams::ProgressType ProgressParams::value() const
+{
+ QJsonObject paramsValue = JsonObject::value(valueKey).toObject();
+ if (paramsValue[kindKey] == "begin")
+ return ProgressParams::ProgressType(WorkDoneProgressBegin(paramsValue));
+ if (paramsValue[kindKey] == "report")
+ return ProgressParams::ProgressType(WorkDoneProgressReport(paramsValue));
+ return ProgressParams::ProgressType(WorkDoneProgressEnd(paramsValue));
+}
+
+void ProgressParams::setValue(const ProgressParams::ProgressType &value)
+{
+ insertVariant<WorkDoneProgressBegin, WorkDoneProgressReport, WorkDoneProgressEnd>(valueKey, value);
+}
+
+ProgressNotification::ProgressNotification(const ProgressParams &params)
+ : Notification(methodName, params)
+{
+
+}
+
+WorkDoneProgressCreateRequest::WorkDoneProgressCreateRequest(const WorkDoneProgressCreateParams &params)
+ : Request(methodName, params)
+{
+
+}
+
+} // namespace LanguageServerProtocol
diff --git a/src/libs/languageserverprotocol/progresssupport.h b/src/libs/languageserverprotocol/progresssupport.h
new file mode 100644
index 0000000000..0c2be91cda
--- /dev/null
+++ b/src/libs/languageserverprotocol/progresssupport.h
@@ -0,0 +1,170 @@
+/****************************************************************************
+**
+** Copyright (C) 2021 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of Qt Creator.
+**
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3 as published by the Free Software
+** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-3.0.html.
+**
+****************************************************************************/
+
+#pragma once
+
+#include "jsonrpcmessages.h"
+
+#include <utils/variant.h>
+
+#include <QJsonValue>
+
+namespace LanguageServerProtocol {
+
+class LANGUAGESERVERPROTOCOL_EXPORT ProgressToken : public Utils::variant<int, QString>
+{
+public:
+ using variant::variant;
+ explicit ProgressToken(const QJsonValue &value);
+
+ bool isValid() { return true; }
+ operator QJsonValue() const;
+};
+
+class LANGUAGESERVERPROTOCOL_EXPORT WorkDoneProgressReport : public JsonObject
+{
+public:
+ using JsonObject::JsonObject;
+
+ /**
+ * Controls if a cancel button should be shown to allow the user to cancel the
+ * long running operation.
+ * Clients that don't support cancellation can ignore the setting.
+ */
+ Utils::optional<bool> cancellable() const { return optionalValue<bool>(cancellableKey); }
+ void setCancellable(bool cancellable) { insert(cancellableKey, cancellable); }
+ void clearCancellable() { remove(cancellableKey); }
+
+ /**
+ * Optional, more detailed associated progress message. Contains
+ * complementary information to the `title`.
+ *
+ * Examples: "3/25 files", "project/src/module2", "node_modules/some_dep".
+ * If unset, the previous progress message (if any) is still valid.
+ */
+ Utils::optional<QString> message() const { return optionalValue<QString>(messageKey); }
+ void setMessage(const QString &message) { insert(messageKey, message); }
+ void clearMessage() { remove(messageKey); }
+
+ /**
+ * Optional progress percentage to display (value 100 is considered 100%).
+ * If not provided infinite progress is assumed and clients are allowed
+ * to ignore the `percentage` value in subsequent in report notifications.
+ *
+ * The value should be steadily rising. Clients are free to ignore values
+ * that are not following this rule.
+ */
+ Utils::optional<int> percentage() const { return optionalValue<int>(percentageKey); }
+ void setPercentage(int percentage) { insert(percentageKey, percentage); }
+ void clearPercentage() { remove(percentageKey); }
+};
+
+class LANGUAGESERVERPROTOCOL_EXPORT WorkDoneProgressBegin : public WorkDoneProgressReport
+{
+public:
+ using WorkDoneProgressReport::WorkDoneProgressReport;
+
+ /**
+ * Mandatory title of the progress operation. Used to briefly inform about
+ * the kind of operation being performed.
+ *
+ * Examples: "Indexing" or "Linking dependencies".
+ */
+
+ QString title() const { return typedValue<QString>(titleKey); }
+ void setTitle(const QString &title) { insert(titleKey, title); }
+};
+
+class LANGUAGESERVERPROTOCOL_EXPORT WorkDoneProgressEnd : public JsonObject
+{
+public:
+ using JsonObject::JsonObject;
+
+ /**
+ * Optional, a final message indicating to for example indicate the outcome
+ * of the operation.
+ */
+ Utils::optional<QString> message() const { return optionalValue<QString>(messageKey); }
+ void setMessage(const QString &message) { insert(messageKey, message); }
+ void clearMessage() { remove(messageKey); }
+};
+
+class LANGUAGESERVERPROTOCOL_EXPORT ProgressParams : public JsonObject
+{
+public:
+ using JsonObject::JsonObject;
+
+ ProgressToken token() const { return ProgressToken(JsonObject::value(tokenKey)); }
+ void setToken(const ProgressToken &token) { insert(tokenKey, token); }
+
+ using ProgressType
+ = Utils::variant<WorkDoneProgressBegin, WorkDoneProgressReport, WorkDoneProgressEnd>;
+ ProgressType value() const;
+ void setValue(const ProgressType &value);
+
+ bool isValid() const override { return contains(tokenKey) && contains(valueKey); }
+};
+
+class LANGUAGESERVERPROTOCOL_EXPORT ProgressNotification : public Notification<ProgressParams>
+{
+public:
+ ProgressNotification(const ProgressParams &params);
+ using Notification::Notification;
+ constexpr static const char methodName[] = "$/progress";
+};
+
+class LANGUAGESERVERPROTOCOL_EXPORT ProgressTokenParams : public JsonObject
+{
+public:
+ using JsonObject::JsonObject;
+
+ // The token to be used to report progress.
+ ProgressToken token() const { return typedValue<ProgressToken>(tokenKey); }
+ void setToken(const ProgressToken &token) { insert(tokenKey, token); }
+};
+
+using WorkDoneProgressCreateParams = ProgressTokenParams;
+
+class LANGUAGESERVERPROTOCOL_EXPORT WorkDoneProgressCreateRequest
+ : public Request<std::nullptr_t, std::nullptr_t, WorkDoneProgressCreateParams>
+{
+public:
+ WorkDoneProgressCreateRequest(const WorkDoneProgressCreateParams &params);
+ using Request::Request;
+ constexpr static const char methodName[] = "window/workDoneProgress/create";
+};
+
+using WorkDoneProgressCancelParams = ProgressTokenParams;
+
+class LANGUAGESERVERPROTOCOL_EXPORT WorkDoneProgressCancelRequest
+ : public Request<std::nullptr_t, std::nullptr_t, WorkDoneProgressCancelParams>
+{
+public:
+ using Request::Request;
+ constexpr static const char methodName[] = "window/workDoneProgress/cancel";
+};
+
+
+} // namespace LanguageServerProtocol
diff --git a/src/libs/languageserverprotocol/semantictokens.cpp b/src/libs/languageserverprotocol/semantictokens.cpp
new file mode 100644
index 0000000000..fc8233b170
--- /dev/null
+++ b/src/libs/languageserverprotocol/semantictokens.cpp
@@ -0,0 +1,154 @@
+/****************************************************************************
+**
+** Copyright (C) 2021 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of Qt Creator.
+**
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3 as published by the Free Software
+** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-3.0.html.
+**
+****************************************************************************/
+
+#include "semantictokens.h"
+
+namespace LanguageServerProtocol {
+
+bool SemanticTokensLegend::isValid() const
+{
+ return contains(tokenTypesKey) && contains(tokenModifiersKey);
+}
+
+QMap<QString, int> SemanticTokens::defaultTokenTypesMap()
+{
+ QMap<QString, int> map;
+ map.insert("namespace", namespaceToken);
+ map.insert("type", typeToken);
+ map.insert("class", classToken);
+ map.insert("enum", enumToken);
+ map.insert("interface", interfaceToken);
+ map.insert("struct", structToken);
+ map.insert("typeParameter", typeParameterToken);
+ map.insert("parameter", parameterToken);
+ map.insert("variable", variableToken);
+ map.insert("property", propertyToken);
+ map.insert("enumMember", enumMemberToken);
+ map.insert("event", eventToken);
+ map.insert("function", functionToken);
+ map.insert("method", methodToken);
+ map.insert("macro", macroToken);
+ map.insert("keyword", keywordToken);
+ map.insert("modifier", modifierToken);
+ map.insert("comment", commentToken);
+ map.insert("string", stringToken);
+ map.insert("number", numberToken);
+ map.insert("regexp", regexpToken);
+ map.insert("operator", operatorToken);
+ return map;
+}
+
+QMap<QString, int> SemanticTokens::defaultTokenModifiersMap()
+{
+ QMap<QString, int> map;
+ map.insert("declaration", declarationModifier);
+ map.insert("definition", definitionModifier);
+ map.insert("readonly", readonlyModifier);
+ map.insert("static", staticModifier);
+ map.insert("deprecated", deprecatedModifier);
+ map.insert("abstract", abstractModifier);
+ map.insert("async", asyncModifier);
+ map.insert("modification", modificationModifier);
+ map.insert("documentation", documentationModifier);
+ map.insert("defaultLibrary", defaultLibraryModifier);
+ return map;
+}
+
+static int convertModifiers(int modifiersData, const QList<int> &tokenModifiers)
+{
+ int result = 0;
+ for (int i = 0; i < tokenModifiers.size() && modifiersData > 0; ++i) {
+ if (modifiersData & 0x1)
+ result |= tokenModifiers[i];
+ modifiersData = modifiersData >> 1;
+ }
+ return result;
+}
+
+QList<SemanticToken> SemanticTokens::toTokens(const QList<int> &tokenTypes,
+ const QList<int> &tokenModifiers) const
+{
+ const QList<int> &data = this->data();
+ if (data.size() % 5 != 0)
+ return {};
+ QList<SemanticToken> tokens;
+ tokens.reserve(int(data.size() / 5));
+ auto end = data.end();
+ for (auto it = data.begin(); it != end; it += 5) {
+ SemanticToken token;
+ token.deltaLine = *(it);
+ token.deltaStart = *(it + 1);
+ token.length = *(it + 2);
+ token.tokenType = tokenTypes.value(*(it + 3), -1);
+ token.tokenModifiers = convertModifiers(*(it + 4), tokenModifiers);
+ tokens << token;
+ }
+ return tokens;
+}
+
+bool SemanticTokensRangeParams::isValid() const
+{
+ return SemanticTokensParams::isValid() && contains(rangeKey);
+}
+
+SemanticTokensFullRequest::SemanticTokensFullRequest(const SemanticTokensParams &params)
+ : Request(methodName, params)
+{}
+
+SemanticTokensRangeRequest::SemanticTokensRangeRequest(const SemanticTokensRangeParams &params)
+ : Request(methodName, params)
+{}
+
+SemanticTokensResult::SemanticTokensResult(const QJsonValue &value)
+{
+ if (value.isObject())
+ emplace<SemanticTokens>(SemanticTokens(value.toObject()));
+ else
+ emplace<std::nullptr_t>(nullptr);
+}
+
+SemanticTokensFullDeltaRequest::SemanticTokensFullDeltaRequest(const SemanticTokensDeltaParams &params)
+ : Request(methodName, params)
+{}
+
+bool SemanticTokensDeltaParams::isValid() const
+{
+ return SemanticTokensParams::isValid() && contains(previousResultIdKey);
+}
+
+SemanticTokensDeltaResult::SemanticTokensDeltaResult(const QJsonValue &value)
+{
+ if (value.isObject()) {
+ QJsonObject object = value.toObject();
+ if (object.contains(editsKey))
+ emplace<SemanticTokensDelta>(object);
+ else
+ emplace<SemanticTokens>(object);
+ } else {
+ emplace<std::nullptr_t>(nullptr);
+ }
+}
+
+} // namespace LanguageServerProtocol
diff --git a/src/libs/languageserverprotocol/semantictokens.h b/src/libs/languageserverprotocol/semantictokens.h
new file mode 100644
index 0000000000..8d23e31154
--- /dev/null
+++ b/src/libs/languageserverprotocol/semantictokens.h
@@ -0,0 +1,241 @@
+/****************************************************************************
+**
+** Copyright (C) 2021 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of Qt Creator.
+**
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3 as published by the Free Software
+** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-3.0.html.
+**
+****************************************************************************/
+
+#pragma once
+
+#include "jsonkeys.h"
+#include "jsonobject.h"
+#include "jsonrpcmessages.h"
+#include "languageserverprotocol_global.h"
+#include "lsptypes.h"
+
+namespace LanguageServerProtocol {
+
+struct LANGUAGESERVERPROTOCOL_EXPORT SemanticToken
+{
+ int deltaLine = 0;
+ int deltaStart = 0;
+ int length = 0;
+ int tokenType = 0;
+ int tokenModifiers = 0;
+};
+
+class LANGUAGESERVERPROTOCOL_EXPORT SemanticTokensLegend : public JsonObject
+{
+public:
+ using JsonObject::JsonObject;
+
+ // The token types a server uses.
+ QList<QString> tokenTypes() const { return array<QString>(tokenTypesKey); }
+ void setTokenTypes(const QList<QString> &tokenTypes) { insertArray(tokenTypesKey, tokenTypes); }
+
+ // The token modifiers a server uses.
+ QList<QString> tokenModifiers() const { return array<QString>(tokenModifiersKey); }
+ void setTokenModifiers(const QList<QString> &value) { insertArray(tokenModifiersKey, value); }
+
+ bool isValid() const override;
+};
+
+enum SemanticTokenTypes {
+ namespaceToken,
+ typeToken,
+ classToken,
+ enumToken,
+ interfaceToken,
+ structToken,
+ typeParameterToken,
+ parameterToken,
+ variableToken,
+ propertyToken,
+ enumMemberToken,
+ eventToken,
+ functionToken,
+ methodToken,
+ macroToken,
+ keywordToken,
+ modifierToken,
+ commentToken,
+ stringToken,
+ numberToken,
+ regexpToken,
+ operatorToken
+};
+
+enum SemanticTokenModifiers {
+ declarationModifier = 0x1,
+ definitionModifier = 0x2,
+ readonlyModifier = 0x4,
+ staticModifier = 0x8,
+ deprecatedModifier = 0x10,
+ abstractModifier = 0x20,
+ asyncModifier = 0x40,
+ modificationModifier = 0x80,
+ documentationModifier = 0x100,
+ defaultLibraryModifier = 0x200
+};
+
+class LANGUAGESERVERPROTOCOL_EXPORT SemanticTokensParams : public JsonObject
+{
+public:
+ using JsonObject::JsonObject;
+
+ TextDocumentIdentifier textDocument() const
+ { return typedValue<TextDocumentIdentifier>(textDocumentKey); }
+ void setTextDocument(const TextDocumentIdentifier &textDocument)
+ { insert(textDocumentKey, textDocument); }
+
+ bool isValid() const override { return contains(textDocumentKey); }
+};
+
+class LANGUAGESERVERPROTOCOL_EXPORT SemanticTokensDeltaParams : public SemanticTokensParams
+{
+public:
+ using SemanticTokensParams::SemanticTokensParams;
+
+ QString previousResultId() const { return typedValue<QString>(previousResultIdKey); }
+ void setPreviousResultId(const QString &previousResultId)
+ {
+ insert(previousResultIdKey, previousResultId);
+ }
+
+ bool isValid() const override;
+};
+
+class LANGUAGESERVERPROTOCOL_EXPORT SemanticTokensRangeParams : public SemanticTokensParams
+{
+public:
+ using SemanticTokensParams::SemanticTokensParams;
+
+ Range range() const { return typedValue<Range>(rangeKey); }
+ void setRange(const Range &range) { insert(rangeKey, range); }
+
+ bool isValid() const override;
+};
+
+class LANGUAGESERVERPROTOCOL_EXPORT SemanticTokens : public JsonObject
+{
+public:
+ using JsonObject::JsonObject;
+
+ /**
+ * An optional result id. If provided and clients support delta updating
+ * the client will include the result id in the next semantic token request.
+ * A server can then instead of computing all semantic tokens again simply
+ * send a delta.
+ */
+ Utils::optional<QString> resultId() const { return optionalValue<QString>(resultIdKey); }
+ void setResultId(const QString &resultId) { insert(resultIdKey, resultId); }
+ void clearResultId() { remove(resultIdKey); }
+
+ /// The actual tokens.
+ QList<int> data() const { return array<int>(dataKey); }
+ void setData(const QList<int> &value) { insertArray(dataKey, value); }
+
+ bool isValid() const override { return contains(dataKey); }
+
+ QList<SemanticToken> toTokens(const QList<int> &tokenTypes,
+ const QList<int> &tokenModifiers) const;
+ static QMap<QString, int> defaultTokenTypesMap();
+ static QMap<QString, int> defaultTokenModifiersMap();
+};
+
+class LANGUAGESERVERPROTOCOL_EXPORT SemanticTokensResult
+ : public Utils::variant<SemanticTokens, std::nullptr_t>
+{
+public:
+ using variant::variant;
+ explicit SemanticTokensResult(const QJsonValue &value);
+};
+
+class LANGUAGESERVERPROTOCOL_EXPORT SemanticTokensFullRequest
+ : public Request<SemanticTokensResult, std::nullptr_t, SemanticTokensParams>
+{
+public:
+ explicit SemanticTokensFullRequest(const SemanticTokensParams &params);
+ using Request::Request;
+ constexpr static const char methodName[] = "textDocument/semanticTokens/full";
+};
+
+class SemanticTokensEdit : public JsonObject
+{
+public:
+ using JsonObject::JsonObject;
+
+ int start() const { return typedValue<int>(startKey); }
+ void setStart(int start) { insert(startKey, start); }
+
+ int deleteCount() const { return typedValue<int>(deleteCountKey); }
+ void setDeleteCount(int deleteCount) { insert(deleteCountKey, deleteCount); }
+
+ Utils::optional<QList<int>> data() const { return optionalArray<int>(dataKey); }
+ void setData(const QList<int> &value) { insertArray(dataKey, value); }
+ void clearData() { remove(dataKey); }
+
+ int dataSize() const { return contains(dataKey) ? value(dataKey).toArray().size() : 0; }
+
+ bool isValid() const override { return contains(dataKey) && contains(deleteCountKey); }
+};
+
+class SemanticTokensDelta : public JsonObject
+{
+public:
+ using JsonObject::JsonObject;
+
+ QString resultId() const { return typedValue<QString>(resultIdKey); }
+ void setResultId(const QString &resultId) { insert(resultIdKey, resultId); }
+
+ QList<SemanticTokensEdit> edits() const { return array<SemanticTokensEdit>(editsKey); }
+ void setEdits(const QList<SemanticTokensEdit> &edits) { insertArray(editsKey, edits); }
+
+ bool isValid() const override { return contains(resultIdKey) && contains(editsKey); }
+};
+
+class LANGUAGESERVERPROTOCOL_EXPORT SemanticTokensDeltaResult
+ : public Utils::variant<SemanticTokens, SemanticTokensDelta, std::nullptr_t>
+{
+public:
+ using variant::variant;
+ explicit SemanticTokensDeltaResult(const QJsonValue &value);
+};
+
+class LANGUAGESERVERPROTOCOL_EXPORT SemanticTokensFullDeltaRequest
+ : public Request<SemanticTokensDeltaResult, std::nullptr_t, SemanticTokensDeltaParams>
+{
+public:
+ explicit SemanticTokensFullDeltaRequest(const SemanticTokensDeltaParams &params);
+ using Request::Request;
+ constexpr static const char methodName[] = "textDocument/semanticTokens/full/delta";
+};
+
+class LANGUAGESERVERPROTOCOL_EXPORT SemanticTokensRangeRequest
+ : public Request<SemanticTokensResult, std::nullptr_t, SemanticTokensRangeParams>
+{
+public:
+ explicit SemanticTokensRangeRequest(const SemanticTokensRangeParams &params);
+ using Request::Request;
+ constexpr static const char methodName[] = "textDocument/semanticTokens/range";
+};
+
+} // namespace LanguageServerProtocol
diff --git a/src/libs/languageserverprotocol/servercapabilities.cpp b/src/libs/languageserverprotocol/servercapabilities.cpp
index 9c3d076f3c..ba8a6836ac 100644
--- a/src/libs/languageserverprotocol/servercapabilities.cpp
+++ b/src/libs/languageserverprotocol/servercapabilities.cpp
@@ -165,6 +165,17 @@ void ServerCapabilities::setDocumentSymbolProvider(
documentSymbolProvider);
}
+Utils::optional<SemanticTokensOptions> ServerCapabilities::semanticTokensProvider() const
+{
+ return optionalValue<SemanticTokensOptions>(semanticTokensProviderKey);
+}
+
+void ServerCapabilities::setSemanticTokensProvider(
+ const SemanticTokensOptions &semanticTokensProvider)
+{
+ insert(semanticTokensProviderKey, semanticTokensProvider);
+}
+
Utils::optional<Utils::variant<bool, WorkDoneProgressOptions>>
ServerCapabilities::workspaceSymbolProvider() const
{
@@ -191,7 +202,7 @@ Utils::optional<Utils::variant<bool, CodeActionOptions>> ServerCapabilities::cod
return Utils::make_optional(Utils::variant<bool, CodeActionOptions>(provider.toBool()));
if (provider.isObject()) {
CodeActionOptions options(provider);
- if (options.isValid(nullptr))
+ if (options.isValid())
return Utils::make_optional(Utils::variant<bool, CodeActionOptions>(options));
}
return Utils::nullopt;
@@ -267,31 +278,6 @@ void ServerCapabilities::setColorProvider(Utils::variant<bool, JsonObject> color
insertVariant<bool, JsonObject>(renameProviderKey, colorProvider);
}
-bool ServerCapabilities::isValid(ErrorHierarchy *error) const
-{
- return checkOptional<TextDocumentSyncOptions, int>(error, textDocumentSyncKey)
- && checkOptional<bool>(error, hoverProviderKey)
- && checkOptional<CompletionOptions>(error, completionProviderKey)
- && checkOptional<SignatureHelpOptions>(error, signatureHelpProviderKey)
- && checkOptional<bool>(error, definitionProviderKey)
- && checkOptional<bool, RegistrationOptions>(error, typeDefinitionProviderKey)
- && checkOptional<bool, RegistrationOptions>(error, implementationProviderKey)
- && checkOptional<bool>(error, referencesProviderKey)
- && checkOptional<bool>(error, documentHighlightProviderKey)
- && checkOptional<bool>(error, documentSymbolProviderKey)
- && checkOptional<bool>(error, workspaceSymbolProviderKey)
- && checkOptional<bool, CodeActionOptions>(error, codeActionProviderKey)
- && checkOptional<CodeLensOptions>(error, codeLensProviderKey)
- && checkOptional<bool>(error, documentFormattingProviderKey)
- && checkOptional<bool>(error, documentRangeFormattingProviderKey)
- && checkOptional<bool, RenameOptions>(error, renameProviderKey)
- && checkOptional<DocumentLinkOptions>(error, documentLinkProviderKey)
- && checkOptional<bool, JsonObject>(error, colorProviderKey)
- && checkOptional<ExecuteCommandOptions>(error, executeCommandProviderKey)
- && checkOptional<WorkspaceServerCapabilities>(error, workspaceKey)
- && checkOptional<SemanticHighlightingServerCapabilities>(error, semanticHighlightingKey);
-}
-
Utils::optional<Utils::variant<QString, bool> >
ServerCapabilities::WorkspaceServerCapabilities::WorkspaceFoldersCapabilities::changeNotifications() const
{
@@ -309,12 +295,6 @@ void ServerCapabilities::WorkspaceServerCapabilities::WorkspaceFoldersCapabiliti
insertVariant<QString, bool>(changeNotificationsKey, changeNotifications);
}
-bool ServerCapabilities::WorkspaceServerCapabilities::WorkspaceFoldersCapabilities::isValid(ErrorHierarchy *error) const
-{
- return checkOptional<bool>(error, supportedKey)
- && checkOptional<QString, bool>(error, changeNotificationsKey);
-}
-
bool TextDocumentRegistrationOptions::filterApplies(const Utils::FilePath &fileName,
const Utils::MimeType &mimeType) const
{
@@ -326,15 +306,6 @@ bool TextDocumentRegistrationOptions::filterApplies(const Utils::FilePath &fileN
});
}
-bool TextDocumentSyncOptions::isValid(ErrorHierarchy *error) const
-{
- return checkOptional<bool>(error, openCloseKey)
- && checkOptional<int>(error, changeKey)
- && checkOptional<bool>(error, willSaveKey)
- && checkOptional<bool>(error, willSaveWaitUntilKey)
- && checkOptional<SaveOptions>(error, saveKey);
-}
-
Utils::optional<QList<QList<QString>>> ServerCapabilities::SemanticHighlightingServerCapabilities::scopes() const
{
QList<QList<QString>> scopes;
@@ -367,7 +338,7 @@ void ServerCapabilities::SemanticHighlightingServerCapabilities::setScopes(
insert(scopesKey, jsonScopes);
}
-bool ServerCapabilities::SemanticHighlightingServerCapabilities::isValid(ErrorHierarchy *) const
+bool ServerCapabilities::SemanticHighlightingServerCapabilities::isValid() const
{
return contains(scopesKey) && value(scopesKey).isArray()
&& Utils::allOf(value(scopesKey).toArray(), [](const QJsonValue &array) {
@@ -379,34 +350,66 @@ bool ServerCapabilities::SemanticHighlightingServerCapabilities::isValid(ErrorHi
});
}
-bool ServerCapabilities::ExecuteCommandOptions::isValid(ErrorHierarchy *error) const
+bool ServerCapabilities::ExecuteCommandOptions::isValid() const
{
- return WorkDoneProgressOptions::isValid(error) && checkArray<QString>(error, commandsKey);
+ return WorkDoneProgressOptions::isValid() && contains(commandsKey);
}
-bool ServerCapabilities::CompletionOptions::isValid(ErrorHierarchy *error) const
+bool CodeActionOptions::isValid() const
{
- return WorkDoneProgressOptions::isValid(error)
- && checkOptionalArray<QString>(error, triggerCharactersKey)
- && checkOptional<bool>(error, resolveProviderKey);
+ return WorkDoneProgressOptions::isValid() && contains(codeActionKindsKey);
}
-bool ServerCapabilities::SignatureHelpOptions::isValid(ErrorHierarchy *error) const
+Utils::optional<Utils::variant<bool, QJsonObject>> SemanticTokensOptions::range() const
{
- return WorkDoneProgressOptions::isValid(error)
- && checkOptionalArray<QString>(error, triggerCharactersKey);
+ using RetType = Utils::variant<bool, QJsonObject>;
+ const QJsonValue &rangeOptions = value(rangeKey);
+ if (rangeOptions.isBool())
+ return RetType(rangeOptions.toBool());
+ if (rangeOptions.isObject())
+ return RetType(rangeOptions.toObject());
+ return Utils::nullopt;
}
-bool CodeActionOptions::isValid(ErrorHierarchy *error) const
+void SemanticTokensOptions::setRange(const Utils::variant<bool, QJsonObject> &range)
{
- return WorkDoneProgressOptions::isValid(error)
- && checkArray<QString>(error, codeActionKindsKey);
+ insertVariant<bool, QJsonObject>(rangeKey, range);
}
-bool ServerCapabilities::RenameOptions::isValid(ErrorHierarchy *error) const
+Utils::optional<Utils::variant<bool, SemanticTokensOptions::FullSemanticTokenOptions>>
+SemanticTokensOptions::full() const
{
- return WorkDoneProgressOptions::isValid(error)
- && checkOptional<bool>(error, prepareProviderKey);
+ using RetType = Utils::variant<bool, SemanticTokensOptions::FullSemanticTokenOptions>;
+ const QJsonValue &fullOptions = value(fullKey);
+ if (fullOptions.isBool())
+ return RetType(fullOptions.toBool());
+ if (fullOptions.isObject())
+ return RetType(FullSemanticTokenOptions(fullOptions.toObject()));
+ return Utils::nullopt;
+}
+
+void SemanticTokensOptions::setFull(
+ const Utils::variant<bool, SemanticTokensOptions::FullSemanticTokenOptions> &full)
+{
+ insertVariant<bool, FullSemanticTokenOptions>(fullKey, full);
+}
+
+SemanticRequestTypes SemanticTokensOptions::supportedRequests() const
+{
+ SemanticRequestTypes result;
+ QJsonValue rangeValue = value(rangeKey);
+ if (rangeValue.isObject() || rangeValue.toBool())
+ result |= SemanticRequestType::Range;
+ QJsonValue fullValue = value(fullKey);
+ if (fullValue.isObject()) {
+ SemanticTokensOptions::FullSemanticTokenOptions options(fullValue.toObject());
+ if (options.delta().value_or(false))
+ result |= SemanticRequestType::FullDelta;
+ result |= SemanticRequestType::Full;
+ } else if (fullValue.toBool()) {
+ result |= SemanticRequestType::Full;
+ }
+ return result;
}
} // namespace LanguageServerProtocol
diff --git a/src/libs/languageserverprotocol/servercapabilities.h b/src/libs/languageserverprotocol/servercapabilities.h
index f575017ad9..e1c847ccaa 100644
--- a/src/libs/languageserverprotocol/servercapabilities.h
+++ b/src/libs/languageserverprotocol/servercapabilities.h
@@ -26,6 +26,7 @@
#pragma once
#include "lsptypes.h"
+#include "semantictokens.h"
namespace LanguageServerProtocol {
@@ -37,9 +38,6 @@ public:
Utils::optional<bool> workDoneProgress() const { return optionalValue<bool>(workDoneProgressKey); }
void setWorkDoneProgress(bool workDoneProgress) { insert(workDoneProgressKey, workDoneProgress); }
void clearWorkDoneProgress() { remove(workDoneProgressKey); }
-
- bool isValid(ErrorHierarchy *error) const override
- { return checkOptional<bool>(error, workDoneProgressKey); }
};
class LANGUAGESERVERPROTOCOL_EXPORT ResolveProviderOption : public JsonObject
@@ -50,9 +48,6 @@ public:
Utils::optional<bool> resolveProvider() const { return optionalValue<bool>(resolveProviderKey); }
void setResolveProvider(bool resolveProvider) { insert(resolveProviderKey, resolveProvider); }
void clearResolveProvider() { remove(resolveProviderKey); }
-
- bool isValid(ErrorHierarchy *error) const override
- { return checkOptional<bool>(error, resolveProviderKey); }
};
class LANGUAGESERVERPROTOCOL_EXPORT TextDocumentRegistrationOptions : public JsonObject
@@ -68,8 +63,7 @@ public:
bool filterApplies(const Utils::FilePath &fileName,
const Utils::MimeType &mimeType = Utils::MimeType()) const;
- bool isValid(ErrorHierarchy *error) const override
- { return checkArray<DocumentFilter>(error, documentSelectorKey); }
+ bool isValid() const override { return contains(documentSelectorKey); }
};
class LANGUAGESERVERPROTOCOL_EXPORT SaveOptions : public JsonObject
@@ -81,9 +75,6 @@ public:
Utils::optional<bool> includeText() const { return optionalValue<bool>(includeTextKey); }
void setIncludeText(bool includeText) { insert(includeTextKey, includeText); }
void clearIncludeText() { remove(includeTextKey); }
-
- bool isValid(ErrorHierarchy *error) const override
- { return checkOptional<bool>(error, includeTextKey); }
};
class LANGUAGESERVERPROTOCOL_EXPORT TextDocumentSyncOptions : public JsonObject
@@ -118,8 +109,6 @@ public:
Utils::optional<SaveOptions> save() const { return optionalValue<SaveOptions>(saveKey); }
void setSave(const SaveOptions &save) { insert(saveKey, save); }
void clearSave() { remove(saveKey); }
-
- bool isValid(ErrorHierarchy *error) const override;
};
enum class TextDocumentSyncKind
@@ -142,7 +131,50 @@ public:
void setCodeActionKinds(const QList<QString> &codeActionKinds)
{ insertArray(codeActionKindsKey, codeActionKinds); }
- bool isValid(ErrorHierarchy *error) const override;
+ bool isValid() const override;
+};
+
+enum class SemanticRequestType {
+ None = 0x0,
+ Full = 0x1,
+ FullDelta = 0x2,
+ Range = 0x4
+};
+Q_DECLARE_FLAGS(SemanticRequestTypes, SemanticRequestType)
+
+class LANGUAGESERVERPROTOCOL_EXPORT SemanticTokensOptions : public WorkDoneProgressOptions
+{
+public:
+ using WorkDoneProgressOptions::WorkDoneProgressOptions;
+
+ /// The legend used by the server
+ SemanticTokensLegend legend() const { return typedValue<SemanticTokensLegend>(legendKey); }
+ void setLegend(const SemanticTokensLegend &legend) { insert(legendKey, legend); }
+
+ /// Server supports providing semantic tokens for a specific range of a document.
+ Utils::optional<Utils::variant<bool, QJsonObject>> range() const;
+ void setRange(const Utils::variant<bool, QJsonObject> &range);
+ void clearRange() { remove(rangeKey); }
+
+ class FullSemanticTokenOptions : public JsonObject
+ {
+ public:
+ using JsonObject::JsonObject;
+
+ /// The server supports deltas for full documents.
+ Utils::optional<bool> delta() const { return optionalValue<bool>(deltaKey); }
+ void setDelta(bool delta) { insert(deltaKey, delta); }
+ void clearDelta() { remove(deltaKey); }
+ };
+
+ /// Server supports providing semantic tokens for a full document.
+ Utils::optional<Utils::variant<bool, FullSemanticTokenOptions>> full() const;
+ void setFull(const Utils::variant<bool, FullSemanticTokenOptions> &full);
+ void clearFull() { remove(fullKey); }
+
+ bool isValid() const override { return contains(legendKey); }
+
+ SemanticRequestTypes supportedRequests() const;
};
class LANGUAGESERVERPROTOCOL_EXPORT ServerCapabilities : public JsonObject
@@ -167,8 +199,6 @@ public:
Utils::optional<bool> resolveProvider() const { return optionalValue<bool>(resolveProviderKey); }
void setResolveProvider(bool resolveProvider) { insert(resolveProviderKey, resolveProvider); }
void clearResolveProvider() { remove(resolveProviderKey); }
-
- bool isValid(ErrorHierarchy *error) const override;
};
class LANGUAGESERVERPROTOCOL_EXPORT SignatureHelpOptions : public WorkDoneProgressOptions
@@ -182,8 +212,6 @@ public:
void setTriggerCharacters(const QList<QString> &triggerCharacters)
{ insertArray(triggerCharactersKey, triggerCharacters); }
void clearTriggerCharacters() { remove(triggerCharactersKey); }
-
- bool isValid(ErrorHierarchy *error) const override;
};
using CodeLensOptions = ResolveProviderOption;
@@ -205,11 +233,7 @@ public:
{ insertArray(moreTriggerCharacterKey, moreTriggerCharacter); }
void clearMoreTriggerCharacter() { remove(moreTriggerCharacterKey); }
- bool isValid(ErrorHierarchy *error) const override
- {
- return check<QString>(error, firstTriggerCharacterKey)
- && checkOptionalArray<QString>(error, moreTriggerCharacterKey);
- }
+ bool isValid() const override { return contains(firstTriggerCharacterKey); }
};
using DocumentLinkOptions = ResolveProviderOption;
@@ -222,7 +246,7 @@ public:
QList<QString> commands() const { return array<QString>(commandsKey); }
void setCommands(const QList<QString> &commands) { insertArray(commandsKey, commands); }
- bool isValid(ErrorHierarchy *error) const override;
+ bool isValid() const override;
};
using ColorProviderOptions = JsonObject;
@@ -247,7 +271,7 @@ public:
Utils::optional<QList<QList<QString>>> scopes() const;
void setScopes(const QList<QList<QString>> &scopes);
- bool isValid(ErrorHierarchy *) const override;
+ bool isValid() const override;
};
// Defines how text documents are synced. Is either a detailed structure defining each
@@ -304,8 +328,7 @@ public:
void setId(const QString &id) { insert(idKey, id); }
void clearId() { remove(idKey); }
- bool isValid(ErrorHierarchy *error) const override
- { return checkArray<DocumentFilter>(error, documentSelectorKey) && checkOptional<bool>(error, idKey); }
+ bool isValid() const override { return contains(documentSelectorKey); }
};
// The server provides Goto Type Definition support.
@@ -334,6 +357,10 @@ public:
void setDocumentSymbolProvider(Utils::variant<bool, WorkDoneProgressOptions> documentSymbolProvider);
void clearDocumentSymbolProvider() { remove(documentSymbolProviderKey); }
+ Utils::optional<SemanticTokensOptions> semanticTokensProvider() const;
+ void setSemanticTokensProvider(const SemanticTokensOptions &semanticTokensProvider);
+ void clearSemanticTokensProvider() { remove(semanticTokensProviderKey); }
+
// The server provides workspace symbol support.
Utils::optional<Utils::variant<bool, WorkDoneProgressOptions>> workspaceSymbolProvider() const;
void setWorkspaceSymbolProvider(Utils::variant<bool, WorkDoneProgressOptions> workspaceSymbolProvider);
@@ -374,8 +401,6 @@ public:
Utils::optional<bool> prepareProvider() const { return optionalValue<bool>(prepareProviderKey); }
void setPrepareProvider(bool prepareProvider) { insert(prepareProviderKey, prepareProvider); }
void clearPrepareProvider() { remove(prepareProviderKey); }
-
- bool isValid(ErrorHierarchy * error) const override;
};
// The server provides rename support.
@@ -420,8 +445,6 @@ public:
Utils::optional<Utils::variant<QString, bool>> changeNotifications() const;
void setChangeNotifications(Utils::variant<QString, bool> changeNotifications);
void clearChangeNotifications() { remove(changeNotificationsKey); }
-
- bool isValid(ErrorHierarchy *error) const override;
};
Utils::optional<WorkspaceFoldersCapabilities> workspaceFolders() const
@@ -446,8 +469,6 @@ public:
void setSemanticHighlighting(const SemanticHighlightingServerCapabilities &semanticHighlighting)
{ insert(semanticHighlightingKey, semanticHighlighting); }
void clearSemanticHighlighting() { remove(semanticHighlightingKey); }
-
- bool isValid(ErrorHierarchy *error) const override;
};
} // namespace LanguageClient
diff --git a/src/libs/languageserverprotocol/textsynchronization.cpp b/src/libs/languageserverprotocol/textsynchronization.cpp
index ec8ec0963f..f18548f820 100644
--- a/src/libs/languageserverprotocol/textsynchronization.cpp
+++ b/src/libs/languageserverprotocol/textsynchronization.cpp
@@ -74,12 +74,6 @@ DidChangeTextDocumentParams::DidChangeTextDocumentParams(
setContentChanges({TextDocumentContentChangeEvent(text)});
}
-bool DidChangeTextDocumentParams::isValid(ErrorHierarchy *error) const
-{
- return check<VersionedTextDocumentIdentifier>(error, textDocumentKey)
- && checkArray<TextDocumentContentChangeEvent>(error, contentChangesKey);
-}
-
DidOpenTextDocumentParams::DidOpenTextDocumentParams(const TextDocumentItem &document)
{
setTextDocument(document);
@@ -96,24 +90,11 @@ DidChangeTextDocumentParams::TextDocumentContentChangeEvent::TextDocumentContent
setText(text);
}
-bool DidChangeTextDocumentParams::TextDocumentContentChangeEvent::isValid(ErrorHierarchy *error) const
-{
- return checkOptional<Range>(error, rangeKey)
- && checkOptional<int>(error, rangeLengthKey)
- && check<QString>(error, textKey);
-}
-
DidSaveTextDocumentParams::DidSaveTextDocumentParams(const TextDocumentIdentifier &document)
{
setTextDocument(document);
}
-bool DidSaveTextDocumentParams::isValid(ErrorHierarchy *error) const
-{
- return check<TextDocumentIdentifier>(error, textDocumentKey)
- && checkOptional<QString>(error, textKey);
-}
-
WillSaveTextDocumentParams::WillSaveTextDocumentParams(
const TextDocumentIdentifier &document,
const WillSaveTextDocumentParams::TextDocumentSaveReason &reason)
@@ -122,16 +103,4 @@ WillSaveTextDocumentParams::WillSaveTextDocumentParams(
setReason(reason);
}
-bool WillSaveTextDocumentParams::isValid(ErrorHierarchy *error) const
-{
- return check<TextDocumentIdentifier>(error, textDocumentKey)
- && check<int>(error, reasonKey);
-}
-
-bool TextDocumentSaveRegistrationOptions::isValid(ErrorHierarchy *error) const
-{
- return TextDocumentRegistrationOptions::isValid(error)
- && checkOptional<bool>(error, includeTextKey);
-}
-
} // namespace LanguageServerProtocol
diff --git a/src/libs/languageserverprotocol/textsynchronization.h b/src/libs/languageserverprotocol/textsynchronization.h
index 72746ad07d..3cf03b787a 100644
--- a/src/libs/languageserverprotocol/textsynchronization.h
+++ b/src/libs/languageserverprotocol/textsynchronization.h
@@ -40,11 +40,9 @@ public:
TextDocumentItem textDocument() const { return typedValue<TextDocumentItem>(textDocumentKey); }
void setTextDocument(TextDocumentItem textDocument) { insert(textDocumentKey, textDocument); }
- bool isValid(ErrorHierarchy *error) const override
- { return check<TextDocumentItem>(error, textDocumentKey); }
+ bool isValid() const override { return contains(textDocumentKey); }
};
-
class LANGUAGESERVERPROTOCOL_EXPORT DidOpenTextDocumentNotification : public Notification<
DidOpenTextDocumentParams>
{
@@ -66,7 +64,7 @@ public:
void setSyncKind(TextDocumentSyncKind syncKind)
{ insert(syncKindKey, static_cast<int>(syncKind)); }
- bool isValid(ErrorHierarchy *error) const override { return check<int>(error, syncKindKey); }
+ bool isValid() const override { return contains(syncKindKey); }
};
class LANGUAGESERVERPROTOCOL_EXPORT DidChangeTextDocumentParams : public JsonObject
@@ -107,7 +105,7 @@ public:
QString text() const { return typedValue<QString>(textKey); }
void setText(const QString &text) { insert(textKey, text); }
- bool isValid(ErrorHierarchy *error) const override;
+ bool isValid() const override { return contains(textKey); }
};
QList<TextDocumentContentChangeEvent> contentChanges() const
@@ -115,7 +113,8 @@ public:
void setContentChanges(const QList<TextDocumentContentChangeEvent> &contentChanges)
{ insertArray(contentChangesKey, contentChanges); }
- bool isValid(ErrorHierarchy *error) const override;
+ bool isValid() const override
+ { return contains(textDocumentKey) && contains(contentChangesKey); }
};
class LANGUAGESERVERPROTOCOL_EXPORT DidChangeTextDocumentNotification : public Notification<
@@ -151,7 +150,7 @@ public:
{ return static_cast<TextDocumentSaveReason>(typedValue<int>(reasonKey)); }
void setReason(TextDocumentSaveReason reason) { insert(reasonKey, static_cast<int>(reason)); }
- bool isValid(ErrorHierarchy *error) const override;
+ bool isValid() const override { return contains(textDocumentKey) && contains(reasonKey); }
};
class LANGUAGESERVERPROTOCOL_EXPORT WillSaveTextDocumentNotification : public Notification<
@@ -181,8 +180,6 @@ public:
Utils::optional<bool> includeText() const { return optionalValue<bool>(includeTextKey); }
void setIncludeText(bool includeText) { insert(includeTextKey, includeText); }
void clearIncludeText() { remove(includeTextKey); }
-
- bool isValid(ErrorHierarchy *error) const override;
};
class LANGUAGESERVERPROTOCOL_EXPORT DidSaveTextDocumentParams : public JsonObject
@@ -201,7 +198,7 @@ public:
void setText(const QString &text) { insert(textKey, text); }
void clearText() { remove(textKey); }
- bool isValid(ErrorHierarchy *error) const override;
+ bool isValid() const override { return contains(textDocumentKey); }
};
class LANGUAGESERVERPROTOCOL_EXPORT DidSaveTextDocumentNotification : public Notification<
@@ -225,8 +222,7 @@ public:
void setTextDocument(const TextDocumentIdentifier &textDocument)
{ insert(textDocumentKey, textDocument); }
- bool isValid(ErrorHierarchy *error) const override
- { return check<TextDocumentIdentifier>(error, textDocumentKey); }
+ bool isValid() const override { return contains(textDocumentKey); }
};
class LANGUAGESERVERPROTOCOL_EXPORT DidCloseTextDocumentNotification : public Notification<
diff --git a/src/libs/languageserverprotocol/workspace.cpp b/src/libs/languageserverprotocol/workspace.cpp
index 2f9e800548..8b82a70dde 100644
--- a/src/libs/languageserverprotocol/workspace.cpp
+++ b/src/libs/languageserverprotocol/workspace.cpp
@@ -72,27 +72,6 @@ WorkspaceFoldersChangeEvent::WorkspaceFoldersChangeEvent()
insert(removedKey, QJsonArray());
}
-bool WorkspaceFoldersChangeEvent::isValid(ErrorHierarchy *error) const
-{
- return checkArray<WorkSpaceFolder>(error, addedKey)
- && checkArray<WorkSpaceFolder>(error, removedKey);
-}
-
-bool ConfigurationParams::ConfigurationItem::isValid(ErrorHierarchy *error) const
-{
- return checkOptional<QString>(error, scopeUriKey)
- && checkOptional<QString>(error, sectionKey);
-}
-
-bool DidChangeConfigurationParams::isValid(ErrorHierarchy *error) const
-{
- if (contains(settingsKey))
- return true;
- if (error)
- error->prependMember(settingsKey);
- return false;
-}
-
DidChangeWatchedFilesNotification::DidChangeWatchedFilesNotification(
const DidChangeWatchedFilesParams &params)
: Notification(methodName, params)
diff --git a/src/libs/languageserverprotocol/workspace.h b/src/libs/languageserverprotocol/workspace.h
index a93d6c893a..3b0b247b88 100644
--- a/src/libs/languageserverprotocol/workspace.h
+++ b/src/libs/languageserverprotocol/workspace.h
@@ -61,7 +61,7 @@ public:
QList<WorkSpaceFolder> removed() const { return array<WorkSpaceFolder>(removedKey); }
void setRemoved(const QList<WorkSpaceFolder> &removed) { insertArray(removedKey, removed); }
- bool isValid(ErrorHierarchy *error) const override;
+ bool isValid() const override { return contains(addedKey) && contains(removedKey); }
};
class LANGUAGESERVERPROTOCOL_EXPORT DidChangeWorkspaceFoldersParams : public JsonObject
@@ -73,8 +73,7 @@ public:
{ return typedValue<WorkspaceFoldersChangeEvent>(eventKey); }
void setEvent(const WorkspaceFoldersChangeEvent &event) { insert(eventKey, event); }
- bool isValid(ErrorHierarchy *error) const override
- { return check<WorkspaceFoldersChangeEvent>(error, eventKey); }
+ bool isValid() const override { return contains(eventKey); }
};
class LANGUAGESERVERPROTOCOL_EXPORT DidChangeWorkspaceFoldersNotification : public Notification<
@@ -91,10 +90,10 @@ class LANGUAGESERVERPROTOCOL_EXPORT DidChangeConfigurationParams : public JsonOb
public:
using JsonObject::JsonObject;
- QJsonValue settings() const { return typedValue<QJsonValue>(settingsKey); }
+ QJsonValue settings() const { return value(settingsKey); }
void setSettings(QJsonValue settings) { insert(settingsKey, settings); }
- bool isValid(ErrorHierarchy *error) const override;
+ bool isValid() const override { return contains(settingsKey); }
};
class LANGUAGESERVERPROTOCOL_EXPORT DidChangeConfigurationNotification : public Notification<
@@ -123,14 +122,13 @@ public:
void setSection(const QString &section) { insert(sectionKey, section); }
void clearSection() { remove(sectionKey); }
- bool isValid(ErrorHierarchy *error) const override;
+ bool isValid() const override { return contains(scopeUriKey); }
};
QList<ConfigurationItem> items() const { return array<ConfigurationItem>(itemsKey); }
void setItems(const QList<ConfigurationItem> &items) { insertArray(itemsKey, items); }
- bool isValid(ErrorHierarchy *error) const override
- { return checkArray<ConfigurationItem>(error, itemsKey); }
+ bool isValid() const override { return contains(itemsKey); }
};
class LANGUAGESERVERPROTOCOL_EXPORT ConfigurationRequest : public Request<
@@ -164,15 +162,13 @@ public:
Deleted = 3
};
- bool isValid(ErrorHierarchy *error) const override
- { return check<QString>(error, uriKey) && check<int>(error, typeKey); }
+ bool isValid() const override { return contains(uriKey) && contains(typeKey); }
};
QList<FileEvent> changes() const { return array<FileEvent>(changesKey); }
void setChanges(const QList<FileEvent> &changes) { insertArray(changesKey, changes); }
- bool isValid(ErrorHierarchy *error) const override
- { return checkArray<FileEvent>(error, changesKey); }
+ bool isValid() const override { return contains(changesKey); }
};
class LANGUAGESERVERPROTOCOL_EXPORT DidChangeWatchedFilesNotification : public Notification<
@@ -192,7 +188,7 @@ public:
QString query() const { return typedValue<QString>(queryKey); }
void setQuery(const QString &query) { insert(queryKey, query); }
- bool isValid(ErrorHierarchy *error) const override { return check<QString>(error, queryKey); }
+ bool isValid() const override { return contains(queryKey); }
};
class LANGUAGESERVERPROTOCOL_EXPORT WorkspaceSymbolRequest : public Request<
@@ -219,11 +215,7 @@ public:
void setArguments(const QJsonArray &arguments) { insert(argumentsKey, arguments); }
void clearArguments() { remove(argumentsKey); }
- bool isValid(ErrorHierarchy *error) const override
- {
- return check<QString>(error, commandKey)
- && checkOptionalArray<QJsonValue>(error, argumentsKey);
- }
+ bool isValid() const override { return contains(commandKey); }
};
class LANGUAGESERVERPROTOCOL_EXPORT ExecuteCommandRequest : public Request<
@@ -247,8 +239,7 @@ public:
WorkspaceEdit edit() const { return typedValue<WorkspaceEdit>(editKey); }
void setEdit(const WorkspaceEdit &edit) { insert(editKey, edit); }
- bool isValid(ErrorHierarchy *error) const override
- { return check<WorkspaceEdit>(error, editKey) && checkOptional<QString>(error, labelKey); }
+ bool isValid() const override { return contains(editKey); }
};
class LANGUAGESERVERPROTOCOL_EXPORT ApplyWorkspaceEditResponse : public JsonObject
@@ -259,7 +250,7 @@ public:
bool applied() const { return typedValue<bool>(appliedKey); }
void setApplied(bool applied) { insert(appliedKey, applied); }
- bool isValid(ErrorHierarchy *error) const override { return check<bool>(error, appliedKey); }
+ bool isValid() const override { return contains(appliedKey); }
};
class LANGUAGESERVERPROTOCOL_EXPORT ApplyWorkspaceEditRequest : public Request<
diff --git a/src/libs/modelinglib/qmt/controller/namecontroller.h b/src/libs/modelinglib/qmt/controller/namecontroller.h
index 50ed023d20..45a10b1567 100644
--- a/src/libs/modelinglib/qmt/controller/namecontroller.h
+++ b/src/libs/modelinglib/qmt/controller/namecontroller.h
@@ -44,6 +44,7 @@ private:
public:
static QString convertFileNameToElementName(const QString &fileName);
static QString convertElementNameToBaseFileName(const QString &elementName);
+ // TODO use Utils::FilePath instead
static QString calcRelativePath(const QString &absoluteFileName, const QString &anchorPath);
static QString calcElementNameSearchId(const QString &elementName);
static QStringList buildElementsPath(const QString &filePath, bool ignoreLastFilePathPart);
diff --git a/src/libs/modelinglib/qmt/infrastructure/geometryutilities.cpp b/src/libs/modelinglib/qmt/infrastructure/geometryutilities.cpp
index 91886cf49e..711b71a457 100644
--- a/src/libs/modelinglib/qmt/infrastructure/geometryutilities.cpp
+++ b/src/libs/modelinglib/qmt/infrastructure/geometryutilities.cpp
@@ -64,11 +64,7 @@ bool GeometryUtilities::intersect(const QPolygonF &polygon, const QLineF &line,
for (int i = 0; i <= polygon.size() - 2; ++i) {
QLineF polygonLine(polygon.at(i), polygon.at(i+1));
QPointF point;
-#if QT_VERSION < QT_VERSION_CHECK(5, 14, 0)
- QLineF::IntersectType intersectionType = polygonLine.intersect(line, &point);
-#else
QLineF::IntersectType intersectionType = polygonLine.intersects(line, &point);
-#endif
if (intersectionType == QLineF::BoundedIntersection) {
qreal dist = QLineF(point, nearestPoint <= 0 ? line.p1() : line.p2()).length();
if (!found || dist < mindist) {
@@ -102,11 +98,7 @@ bool GeometryUtilities::intersect(const QList<QPolygonF> &polygons, const QLineF
for (int i = 0; i <= polygon.size() - 2; ++i) {
const QLineF polygonLine(polygon.at(i), polygon.at(i + 1));
QPointF point;
-#if QT_VERSION < QT_VERSION_CHECK(5, 14, 0)
- QLineF::IntersectType intersectionType = polygonLine.intersect(line, &point);
-#else
QLineF::IntersectType intersectionType = polygonLine.intersects(line, &point);
-#endif
if (intersectionType == QLineF::BoundedIntersection) {
qreal dist = QLineF(point, nearestPoint <= 0 ? line.p1() : line.p2()).length();
if (!found || dist < mindist) {
diff --git a/src/libs/modelinglib/qmt/model_widgets_ui/propertiesviewmview.cpp b/src/libs/modelinglib/qmt/model_widgets_ui/propertiesviewmview.cpp
index fbb0f2520d..199422cb31 100644
--- a/src/libs/modelinglib/qmt/model_widgets_ui/propertiesviewmview.cpp
+++ b/src/libs/modelinglib/qmt/model_widgets_ui/propertiesviewmview.cpp
@@ -352,13 +352,8 @@ void PropertiesView::MView::visitMElement(const MElement *element)
m_stereotypeComboBox->addItems(m_propertiesView->stereotypeController()->knownStereotypes(m_stereotypeElement));
connect(m_stereotypeComboBox->lineEdit(), &QLineEdit::textEdited,
this, &PropertiesView::MView::onStereotypesChanged);
-#if QT_VERSION < QT_VERSION_CHECK(5, 14, 0)
- connect(m_stereotypeComboBox, QOverload<const QString &>::of(&QComboBox::activated),
- this, &PropertiesView::MView::onStereotypesChanged);
-#else
connect(m_stereotypeComboBox, &QComboBox::textActivated,
this, &PropertiesView::MView::onStereotypesChanged);
-#endif
}
if (!m_stereotypeComboBox->hasFocus()) {
QList<QString> stereotypeList;
diff --git a/src/libs/qlitehtml b/src/libs/qlitehtml
-Subproject a94f0b57a879fa6b626f8ca3e796af2e6b80285
+Subproject 44e15759b7400901bfdc6b69ffb1256c82cc169
diff --git a/src/libs/qmljs/qmljsbind.cpp b/src/libs/qmljs/qmljsbind.cpp
index d24b95319a..9838a7dfc9 100644
--- a/src/libs/qmljs/qmljsbind.cpp
+++ b/src/libs/qmljs/qmljsbind.cpp
@@ -221,19 +221,21 @@ bool Bind::visit(UiImport *ast)
if (ast->version)
version = ComponentVersion(ast->version->majorVersion, ast->version->minorVersion);
- if (ast->importUri) {
+ if (auto importUri = ast->importUri) {
QVersionNumber qtVersion;
+ QString uri = toString(importUri);
if (ModelManagerInterface *model = ModelManagerInterface::instance()) {
ModelManagerInterface::ProjectInfo pInfo = model->projectInfoForPath(_doc->fileName());
qtVersion = QVersionNumber::fromString(pInfo.qtVersionString);
+ uri = pInfo.moduleMappings.value(uri, uri);
}
if (!version.isValid() && (!qtVersion.isNull() && qtVersion.majorVersion() < 6)) {
_diagnosticMessages->append(
errorMessage(ast, tr("package import requires a version number")));
}
const QString importId = ast->importId.toString();
- ImportInfo import = ImportInfo::moduleImport(toString(ast->importUri), version,
- importId, ast);
+
+ ImportInfo import = ImportInfo::moduleImport(uri, version, importId, ast);
if (_doc->language() == Dialect::Qml) {
const QString importStr = import.name() + importId;
if (ModelManagerInterface::instance()) {
diff --git a/src/libs/qmljs/qmljscheck.cpp b/src/libs/qmljs/qmljscheck.cpp
index 42287c4740..8e364fa6be 100644
--- a/src/libs/qmljs/qmljscheck.cpp
+++ b/src/libs/qmljs/qmljscheck.cpp
@@ -939,13 +939,13 @@ void Check::visitQmlObject(Node *ast, UiQualifiedId *typeId,
if (checkTypeForDesignerSupport(typeId))
addMessage(WarnUnsupportedTypeInVisualDesigner, typeErrorLocation, typeName);
- if (QFileInfo(_doc->fileName()).baseName() == getRightMostIdentifier(typeId)->name.toString())
+ if (typeId->next == nullptr && QFileInfo(_doc->fileName()).baseName() == typeName)
addMessage(ErrTypeIsInstantiatedRecursively, typeErrorLocation, typeName);
if (checkTypeForQmlUiSupport(typeId))
addMessage(ErrUnsupportedTypeInQmlUi, typeErrorLocation, typeName);
- if (m_typeStack.count() > 1 && getRightMostIdentifier(typeId)->name.toString() == "State") {
+ if (m_typeStack.count() > 1 && typeName == "State") {
addMessage(WarnStatesOnlyInRootItemForVisualDesigner, typeErrorLocation);
addMessage(ErrStatesOnlyInRootItemInQmlUi, typeErrorLocation);
}
diff --git a/src/libs/qmljs/qmljscodeformatter.cpp b/src/libs/qmljs/qmljscodeformatter.cpp
index 63932e9ecd..ac08030542 100644
--- a/src/libs/qmljs/qmljscodeformatter.cpp
+++ b/src/libs/qmljs/qmljscodeformatter.cpp
@@ -163,6 +163,8 @@ void CodeFormatter::recalculateStateAfter(const QTextBlock &block)
case Import:
case Signal:
case Property:
+ case Required:
+ case Readonly:
case Identifier: enter(expression_or_objectdefinition); break;
// error recovery
@@ -175,8 +177,10 @@ void CodeFormatter::recalculateStateAfter(const QTextBlock &block)
case objectdefinition_open:
switch (kind) {
case RightBrace: leave(true); break;
- case Default: enter(default_property_start); break;
+ case Default:
+ case Readonly: enter(property_modifiers); break;
case Property: enter(property_start); break;
+ case Required: enter(required_property); break;
case Function: enter(function_start); break;
case Signal: enter(signal_start); break;
case Enum: enter(enum_start); break;
@@ -187,12 +191,14 @@ void CodeFormatter::recalculateStateAfter(const QTextBlock &block)
case Identifier: enter(binding_or_objectdefinition); break;
} break;
- case default_property_start:
- if (kind != Property)
- leave(true);
- else
- turnInto(property_start);
- break;
+ case property_modifiers:
+ switch (kind) {
+ case Property: turnInto(property_start); break;
+ case Default:
+ case Readonly: break;
+ case Required: turnInto(required_property); break;
+ default: leave(true); break;
+ } break;
case property_start:
switch (kind) {
@@ -203,6 +209,21 @@ void CodeFormatter::recalculateStateAfter(const QTextBlock &block)
default: leave(true); continue;
} break;
+ case required_property:
+ switch (kind) {
+ case Property: turnInto(property_start); break;
+ case Default:
+ case Readonly: turnInto(property_modifiers); break;
+ case Identifier: leave(true); break;
+ default: leave(true); continue;
+ } break;
+
+ case component_start:
+ switch (kind) {
+ case Identifier: turnInto(StateType::component_name); break;
+ default: leave(true); continue;
+ } break;
+
case property_name:
turnInto(property_maybe_initializer);
break;
@@ -788,6 +809,8 @@ bool CodeFormatter::tryStatement()
case As:
case List:
case Property:
+ case Required:
+ case Readonly:
case Function:
case Number:
case String:
@@ -938,6 +961,12 @@ CodeFormatter::TokenKind CodeFormatter::extendedTokenKind(const QmlJS::Token &to
return Signal;
if (text == QLatin1String("property"))
return Property;
+ if (text == QLatin1String("readonly"))
+ return Readonly;
+ if (text == QLatin1String("component"))
+ return Component;
+ if (text == QLatin1String("required"))
+ return Required;
if (text == QLatin1String("on"))
return On;
if (text == QLatin1String("list"))
diff --git a/src/libs/qmljs/qmljscodeformatter.h b/src/libs/qmljs/qmljscodeformatter.h
index c91b36ba27..947e7a0f4e 100644
--- a/src/libs/qmljs/qmljscodeformatter.h
+++ b/src/libs/qmljs/qmljscodeformatter.h
@@ -104,10 +104,13 @@ public: // must be public to make Q_GADGET introspection work
import_as,
property_start, // after 'property'
- default_property_start, // after 'default'
+ property_modifiers, // after 'default' or readonly
+ required_property, // after required
property_list_open, // after 'list' as a type
property_name, // after the type
property_maybe_initializer, // after the identifier
+ component_start, // after component
+ component_name, // after component Name
enum_start, // after 'enum'
@@ -237,6 +240,9 @@ protected:
As,
List,
Property,
+ Required,
+ Component,
+ Readonly,
Question,
PlusPlus,
diff --git a/src/libs/qmljs/qmljsmodelmanagerinterface.cpp b/src/libs/qmljs/qmljsmodelmanagerinterface.cpp
index bb4dde444e..86e1e7046e 100644
--- a/src/libs/qmljs/qmljsmodelmanagerinterface.cpp
+++ b/src/libs/qmljs/qmljsmodelmanagerinterface.cpp
@@ -615,6 +615,9 @@ ModelManagerInterface::ProjectInfo ModelManagerInterface::projectInfoForPath(
res.applicationDirectories.append(pInfo.applicationDirectories);
for (const auto &importPath : pInfo.importPaths)
res.importPaths.maybeInsert(importPath);
+ auto end = pInfo.moduleMappings.cend();
+ for (auto it = pInfo.moduleMappings.cbegin(); it != end; ++it)
+ res.moduleMappings.insert(it.key(), it.value());
}
res.applicationDirectories = Utils::filteredUnique(res.applicationDirectories);
return res;
@@ -641,6 +644,10 @@ QList<ModelManagerInterface::ProjectInfo> ModelManagerInterface::allProjectInfos
if (!info.project.isNull())
infos.append(info);
}
+ if (infos.isEmpty()) {
+ QMutexLocker locker(&m_mutex);
+ return { m_defaultProjectInfo };
+ }
std::sort(infos.begin(), infos.end(), &pInfoLessThanImports);
return infos;
}
@@ -1200,6 +1207,10 @@ void ModelManagerInterface::updateImportPaths()
allImportPaths.maybeInsert(Utils::FilePath::fromString(pathAtt), Dialect::QmlQtQuick2);
}
+ for (const auto &importPath : defaultProjectInfo().importPaths) {
+ allImportPaths.maybeInsert(importPath);
+ }
+
for (const QString &path : qAsConst(m_defaultImportPaths))
allImportPaths.maybeInsert(Utils::FilePath::fromString(path), Dialect::Qml);
allImportPaths.compact();
@@ -1432,6 +1443,8 @@ ViewerContext ModelManagerInterface::getVContext(const ViewerContext &vCtx,
info.qtQmlPath = defaultInfo.qtQmlPath;
info.qtVersionString = defaultInfo.qtVersionString;
}
+ if (info.qtQmlPath.isEmpty() && info.importPaths.size() == 0)
+ info.importPaths = defaultInfo.importPaths;
info.applicationDirectories = Utils::filteredUnique(info.applicationDirectories
+ defaultInfo.applicationDirectories);
switch (res.flags) {
diff --git a/src/libs/qmljs/qmljsmodelmanagerinterface.h b/src/libs/qmljs/qmljsmodelmanagerinterface.h
index 2dc00c3ed8..f614225546 100644
--- a/src/libs/qmljs/qmljsmodelmanagerinterface.h
+++ b/src/libs/qmljs/qmljsmodelmanagerinterface.h
@@ -72,6 +72,7 @@ public:
QStringList allResourceFiles;
QHash<QString, QString> resourceFileContents;
QStringList applicationDirectories;
+ QHash<QString, QString> moduleMappings; // E.g.: QtQuick.Controls -> MyProject.MyControls
// whether trying to run qmldump makes sense
bool tryQmlDump = false;
diff --git a/src/libs/qmljs/qmljsplugindumper.cpp b/src/libs/qmljs/qmljsplugindumper.cpp
index 730743f890..a98f7550d6 100644
--- a/src/libs/qmljs/qmljsplugindumper.cpp
+++ b/src/libs/qmljs/qmljsplugindumper.cpp
@@ -370,7 +370,7 @@ QFuture<PluginDumper::QmlTypeDescription> PluginDumper::loadQmlTypeDescription(c
for (const QString &p: paths) {
Utils::FileReader reader;
- if (!reader.fetch(p, QFile::Text)) {
+ if (!reader.fetch(Utils::FilePath::fromString(p), QFile::Text)) {
result.errors += reader.errorString();
continue;
}
diff --git a/src/libs/qmljs/qmljsreformatter.cpp b/src/libs/qmljs/qmljsreformatter.cpp
index 60e32288c9..c83ee11a35 100644
--- a/src/libs/qmljs/qmljsreformatter.cpp
+++ b/src/libs/qmljs/qmljsreformatter.cpp
@@ -598,6 +598,15 @@ protected:
return false;
}
+ bool visit(UiInlineComponent *ast) override
+ {
+ out(ast->componentToken);
+ out(" ");
+ out(ast->name.toString());
+ out(": ");
+ return true;
+ }
+
bool visit(UiObjectDefinition *ast) override
{
accept(ast->qualifiedTypeNameId);
@@ -669,6 +678,14 @@ protected:
return false;
}
+ bool visit(UiRequired *ast) override
+ {
+ out(ast->requiredToken);
+ out(" ");
+ out(ast->name.toString());
+ return true;
+ }
+
bool visit(UiObjectBinding *ast) override
{
if (ast->hasOnToken) {
@@ -1006,7 +1023,7 @@ protected:
}
out(ast->identifierToken);
if (ast->initializer) {
- if (ast->isVariableDeclaration())
+ if (ast->isVariableDeclaration() || ast->type == PatternElement::Binding)
out(" = ");
accept(ast->initializer);
}
@@ -1377,7 +1394,7 @@ protected:
bool visit(FormalParameterList *ast) override
{
for (FormalParameterList *it = ast; it; it = it->next) {
- out(it->element->bindingIdentifier.toString()); // TODO
+ accept(it->element);
if (it->next)
out(", ");
}
diff --git a/src/libs/qmljs/qmljsscanner.cpp b/src/libs/qmljs/qmljsscanner.cpp
index 32fa532ebc..35c616b3bc 100644
--- a/src/libs/qmljs/qmljsscanner.cpp
+++ b/src/libs/qmljs/qmljsscanner.cpp
@@ -25,6 +25,8 @@
#include <qmljs/qmljsscanner.h>
+#include <QDebug>
+
#include <algorithm>
using namespace QmlJS;
@@ -183,6 +185,22 @@ static inline void setRegexpMayFollow(int *state, bool on)
*state = (on ? Scanner::RegexpMayFollow : 0) | (*state & ~Scanner::RegexpMayFollow);
}
+static inline int templateExpressionDepth(int state)
+{
+ if ((state & Scanner::TemplateExpressionOpenBracesMask) == 0)
+ return 0;
+ if ((state & (Scanner::TemplateExpressionOpenBracesMask3 | Scanner::TemplateExpressionOpenBracesMask4)) == 0) {
+ if ((state & Scanner::TemplateExpressionOpenBracesMask2) == 0)
+ return 1;
+ else
+ return 2;
+ }
+ if ((state & Scanner::TemplateExpressionOpenBracesMask4) == 0)
+ return 3;
+ else
+ return 4;
+}
+
QList<Token> Scanner::operator()(const QString &text, int startState)
{
_state = startState;
@@ -190,6 +208,45 @@ QList<Token> Scanner::operator()(const QString &text, int startState)
int index = 0;
+ auto scanTemplateString = [&index, &text, &tokens, this](int startShift = 0){
+ const QChar quote = QLatin1Char('`');
+ const int start = index + startShift;
+ while (index < text.length()) {
+ const QChar ch = text.at(index);
+
+ if (ch == quote)
+ break;
+ else if (ch == QLatin1Char('$') && index + 1 < text.length() && text.at(index + 1) == QLatin1Char('{')) {
+ tokens.append(Token(start, index - start, Token::String));
+ tokens.append(Token(index, 2, Token::Delimiter));
+ index += 2;
+ setRegexpMayFollow(&_state, true);
+ setMultiLineState(&_state, Normal);
+ int depth = templateExpressionDepth(_state);
+ if (depth == 4) {
+ qWarning() << "QQmljs::Dom::Scanner reached maximum nesting of template expressions (4), parsing will fail";
+ } else {
+ _state |= 1 << (4 + depth * 7);
+ }
+ return;
+ } else if (ch == QLatin1Char('\\') && index + 1 < text.length())
+ index += 2;
+ else
+ ++index;
+ }
+
+ if (index < text.length()) {
+ setMultiLineState(&_state, Normal);
+ ++index;
+ // good one
+ } else {
+ setMultiLineState(&_state, MultiLineStringBQuote);
+ }
+
+ tokens.append(Token(start, index - start, Token::String));
+ setRegexpMayFollow(&_state, false);
+ };
+
if (multiLineState(_state) == MultiLineComment) {
int start = -1;
while (index < text.length()) {
@@ -233,8 +290,14 @@ QList<Token> Scanner::operator()(const QString &text, int startState)
if (start < index)
tokens.append(Token(start, index - start, Token::String));
setRegexpMayFollow(&_state, false);
+ } else if (multiLineState(_state) == MultiLineStringBQuote) {
+ scanTemplateString();
}
+ auto braceCounterOffset = [](int templateDepth) {
+ return FlagsBits + (templateDepth - 1) * BraceCounterBits;
+ };
+
while (index < text.length()) {
const QChar ch = text.at(index);
@@ -273,6 +336,9 @@ QList<Token> Scanner::operator()(const QString &text, int startState)
tokens.append(Token(index, end - index, Token::RegExp));
index = end;
setRegexpMayFollow(&_state, false);
+ } else if (la == QLatin1Char('=')) {
+ tokens.append(Token(index, 2, Token::Delimiter));
+ index += 2;
} else {
tokens.append(Token(index++, 1, Token::Delimiter));
setRegexpMayFollow(&_state, true);
@@ -280,7 +346,6 @@ QList<Token> Scanner::operator()(const QString &text, int startState)
break;
case '\'':
- case '`':
case '"': {
const QChar quote = ch;
const int start = index;
@@ -310,6 +375,11 @@ QList<Token> Scanner::operator()(const QString &text, int startState)
setRegexpMayFollow(&_state, false);
} break;
+ case '`': {
+ ++index;
+ scanTemplateString(-1);
+ } break;
+
case '.':
if (la.isDigit()) {
const int start = index;
@@ -343,15 +413,38 @@ QList<Token> Scanner::operator()(const QString &text, int startState)
setRegexpMayFollow(&_state, false);
break;
- case '{':
+ case '{':{
tokens.append(Token(index++, 1, Token::LeftBrace));
setRegexpMayFollow(&_state, true);
- break;
+ int depth = templateExpressionDepth(_state);
+ if (depth > 0) {
+ int shift = braceCounterOffset(depth);
+ int mask = Scanner::TemplateExpressionOpenBracesMask0 << shift;
+ if ((_state & mask) == mask) {
+ qWarning() << "QQmljs::Dom::Scanner reached maximum open braces of template expressions (127), parsing will fail";
+ } else {
+ _state = (_state & ~mask) | (((Scanner::TemplateExpressionOpenBracesMask0 & (_state >> shift)) + 1) << shift);
+ }
+ }
+ } break;
- case '}':
- tokens.append(Token(index++, 1, Token::RightBrace));
+ case '}': {
setRegexpMayFollow(&_state, false);
- break;
+ int depth = templateExpressionDepth(_state);
+ if (depth > 0) {
+ int shift = braceCounterOffset(depth);
+ int s = _state;
+ int nBraces = Scanner::TemplateExpressionOpenBracesMask0 & (s >> shift);
+ int mask = Scanner::TemplateExpressionOpenBracesMask0 << shift;
+ _state = (s & ~mask) | ((nBraces - 1) << shift);
+ if (nBraces == 1) {
+ tokens.append(Token(index++, 1, Token::Delimiter));
+ scanTemplateString();
+ break;
+ }
+ }
+ tokens.append(Token(index++, 1, Token::RightBrace));
+ } break;
case ';':
tokens.append(Token(index++, 1, Token::Semicolon));
@@ -370,6 +463,32 @@ QList<Token> Scanner::operator()(const QString &text, int startState)
case '+':
case '-':
+ case '<':
+ if (la == ch || la == QLatin1Char('=')) {
+ tokens.append(Token(index, 2, Token::Delimiter));
+ index += 2;
+ } else {
+ tokens.append(Token(index++, 1, Token::Delimiter));
+ }
+ setRegexpMayFollow(&_state, true);
+ break;
+
+ case '>':
+ if (la == ch && index + 2 < text.length() && text.at(index + 2) == ch) {
+ tokens.append(Token(index, 2, Token::Delimiter));
+ index += 3;
+ } else if (la == ch || la == QLatin1Char('=')) {
+ tokens.append(Token(index, 2, Token::Delimiter));
+ index += 2;
+ } else {
+ tokens.append(Token(index++, 1, Token::Delimiter));
+ }
+ setRegexpMayFollow(&_state, true);
+ break;
+
+ case '|':
+ case '=':
+ case '&':
if (la == ch) {
tokens.append(Token(index, 2, Token::Delimiter));
index += 2;
diff --git a/src/libs/qmljs/qmljsscanner.h b/src/libs/qmljs/qmljsscanner.h
index 0cd8c69d7d..523616de3e 100644
--- a/src/libs/qmljs/qmljsscanner.h
+++ b/src/libs/qmljs/qmljsscanner.h
@@ -62,23 +62,60 @@ public:
inline bool is(int k) const { return k == kind; }
inline bool isNot(int k) const { return k != kind; }
+ static int compare(const Token &t1, const Token &t2) {
+ if (int c = t1.offset - t2.offset)
+ return c;
+ if (int c = t1.length - t2.length)
+ return c;
+ return int(t1.kind) - int(t2.kind);
+ }
+
public:
- int offset;
- int length;
- Kind kind;
+ int offset = 0;
+ int length = 0;
+ Kind kind = EndOfFile;
};
+inline int operator == (const Token &t1, const Token &t2) {
+ return Token::compare(t1, t2) == 0;
+}
+inline int operator != (const Token &t1, const Token &t2) {
+ return Token::compare(t1, t2) != 0;
+}
+
class QMLJS_EXPORT Scanner
{
public:
enum {
+ FlagsBits = 4,
+ BraceCounterBits = 7
+ };
+ enum {
Normal = 0,
MultiLineComment = 1,
MultiLineStringDQuote = 2,
MultiLineStringSQuote = 3,
- MultiLineMask = 3,
+ MultiLineStringBQuote = 4,
+ MultiLineMask = 7,
+
+ RegexpMayFollow = 8, // flag that may be combined with the above
- RegexpMayFollow = 4 // flag that may be combined with the above
+ // templates can be nested, which means that the scanner/lexer cannot
+ // be a simple state machine anymore, but should have a stack to store
+ // the state (the number of open braces in the current template
+ // string).
+ // The lexer stare is currently stored in an int, so we abuse that and
+ // store a the number of open braces (maximum 0x7f = 127) for at most 5
+ // nested templates in the int after the flags for the multiline
+ // comments and strings.
+ TemplateExpression = 0x1 << 4,
+ TemplateExpressionOpenBracesMask0 = 0x7F,
+ TemplateExpressionOpenBracesMask1 = 0x7F << 4,
+ TemplateExpressionOpenBracesMask2 = 0x7F << 11,
+ TemplateExpressionOpenBracesMask3 = 0x7F << 18,
+ TemplateExpressionOpenBracesMask4 = 0x7F << 25,
+ TemplateExpressionOpenBracesMask = TemplateExpressionOpenBracesMask1 | TemplateExpressionOpenBracesMask2
+ | TemplateExpressionOpenBracesMask3 | TemplateExpressionOpenBracesMask4
};
Scanner();
diff --git a/src/libs/sqlite/sqlite.qbs b/src/libs/sqlite/sqlite.qbs
index f5f0e182ab..f0c5879000 100644
--- a/src/libs/sqlite/sqlite.qbs
+++ b/src/libs/sqlite/sqlite.qbs
@@ -8,6 +8,6 @@ QtcLibrary {
Export {
Depends { name: "cpp" }
- cpp.includePaths: product.exportedIncludeDir
+ cpp.includePaths: exportingProduct.exportedIncludeDir
}
}
diff --git a/src/libs/sqlite/sqlitebasestatement.cpp b/src/libs/sqlite/sqlitebasestatement.cpp
index 72a040fa04..28ebbb8d2e 100644
--- a/src/libs/sqlite/sqlitebasestatement.cpp
+++ b/src/libs/sqlite/sqlitebasestatement.cpp
@@ -277,6 +277,30 @@ void BaseStatement::bind(int index, const Value &value)
case ValueType::String:
bind(index, value.toStringView());
break;
+ case ValueType::Blob:
+ bind(index, value.toBlobView());
+ break;
+ case ValueType::Null:
+ bind(index, NullValue{});
+ break;
+ }
+}
+
+void BaseStatement::bind(int index, ValueView value)
+{
+ switch (value.type()) {
+ case ValueType::Integer:
+ bind(index, value.toInteger());
+ break;
+ case ValueType::Float:
+ bind(index, value.toFloat());
+ break;
+ case ValueType::String:
+ bind(index, value.toStringView());
+ break;
+ case ValueType::Blob:
+ bind(index, value.toBlobView());
+ break;
case ValueType::Null:
bind(index, NullValue{});
break;
diff --git a/src/libs/sqlite/sqlitebasestatement.h b/src/libs/sqlite/sqlitebasestatement.h
index c96fb3fade..8baf1a3b23 100644
--- a/src/libs/sqlite/sqlitebasestatement.h
+++ b/src/libs/sqlite/sqlitebasestatement.h
@@ -29,6 +29,7 @@
#include "sqliteblob.h"
#include "sqliteexception.h"
+#include "sqlitetransaction.h"
#include "sqlitevalue.h"
#include <utils/smallstringvector.h>
@@ -37,6 +38,7 @@
#include <utils/span.h>
#include <cstdint>
+#include <exception>
#include <functional>
#include <memory>
#include <tuple>
@@ -91,6 +93,7 @@ public:
void bind(int index, Utils::span<const char *> values);
void bind(int index, Utils::SmallStringView value);
void bind(int index, const Value &value);
+ void bind(int index, ValueView value);
void bind(int index, BlobView blobView);
void bind(int index, uint value) { bind(index, static_cast<long long>(value)); }
@@ -162,13 +165,14 @@ extern template SQLITE_EXPORT Utils::PathString BaseStatement::fetchValue<Utils:
template<typename BaseStatement, int ResultCount>
class StatementImplementation : public BaseStatement
{
+ struct Resetter;
public:
using BaseStatement::BaseStatement;
void execute()
{
- Resetter resetter{*this};
+ Resetter resetter{this};
BaseStatement::next();
resetter.reset();
}
@@ -185,7 +189,7 @@ public:
template<typename... ValueType>
void write(const ValueType&... values)
{
- Resetter resetter{*this};
+ Resetter resetter{this};
bindValues(values...);
BaseStatement::next();
resetter.reset();
@@ -194,7 +198,7 @@ public:
template<typename ResultType>
std::vector<ResultType> values(std::size_t reserveSize)
{
- Resetter resetter{*this};
+ Resetter resetter{this};
std::vector<ResultType> resultValues;
resultValues.reserve(std::max(reserveSize, m_maximumResultCount));
@@ -211,7 +215,7 @@ public:
template<typename ResultType, typename... QueryTypes>
auto values(std::size_t reserveSize, const QueryTypes &...queryValues)
{
- Resetter resetter{*this};
+ Resetter resetter{this};
std::vector<ResultType> resultValues;
resultValues.reserve(std::max(reserveSize, m_maximumResultCount));
@@ -230,13 +234,13 @@ public:
template<typename ResultType, typename... QueryTypes>
auto value(const QueryTypes &...queryValues)
{
- Resetter resetter{*this};
+ Resetter resetter{this};
Utils::optional<ResultType> resultValue;
bindValues(queryValues...);
if (BaseStatement::next())
- resultValue = assignValue<Utils::optional<ResultType>>();
+ resultValue = createOptionalValue<Utils::optional<ResultType>>();
resetter.reset();
@@ -258,7 +262,7 @@ public:
template<typename Callable, typename... QueryTypes>
void readCallback(Callable &&callable, const QueryTypes &...queryValues)
{
- Resetter resetter{*this};
+ Resetter resetter{this};
bindValues(queryValues...);
@@ -272,10 +276,10 @@ public:
resetter.reset();
}
- template<int ResultTypeCount = 1, typename Container, typename... QueryTypes>
+ template<typename Container, typename... QueryTypes>
void readTo(Container &container, const QueryTypes &...queryValues)
{
- Resetter resetter{*this};
+ Resetter resetter{this};
bindValues(queryValues...);
@@ -285,39 +289,187 @@ public:
resetter.reset();
}
+ template<typename ResultType, typename... QueryTypes>
+ auto range(const QueryTypes &...queryValues)
+ {
+ return SqliteResultRange<ResultType>{*this, queryValues...};
+ }
+
+ template<typename ResultType, typename... QueryTypes>
+ auto rangeWithTransaction(const QueryTypes &...queryValues)
+ {
+ return SqliteResultRangeWithTransaction<ResultType>{*this, queryValues...};
+ }
+
+ template<typename ResultType>
+ class BaseSqliteResultRange
+ {
+ public:
+ class SqliteResultIteratator
+ {
+ public:
+ using iterator_category = std::input_iterator_tag;
+ using difference_type = int;
+ using value_type = ResultType;
+ using pointer = ResultType *;
+ using reference = ResultType &;
+
+ SqliteResultIteratator(StatementImplementation &statement)
+ : m_statement{statement}
+ , m_hasNext{m_statement.next()}
+ {}
+
+ SqliteResultIteratator(StatementImplementation &statement, bool hasNext)
+ : m_statement{statement}
+ , m_hasNext{hasNext}
+ {}
+
+ SqliteResultIteratator &operator++()
+ {
+ m_hasNext = m_statement.next();
+ return *this;
+ }
+
+ void operator++(int) { m_hasNext = m_statement.next(); }
+
+ friend bool operator==(const SqliteResultIteratator &first,
+ const SqliteResultIteratator &second)
+ {
+ return first.m_hasNext == second.m_hasNext;
+ }
+
+ friend bool operator!=(const SqliteResultIteratator &first,
+ const SqliteResultIteratator &second)
+ {
+ return !(first == second);
+ }
+
+ value_type operator*() const { return m_statement.createValue<ResultType>(); }
+
+ private:
+ StatementImplementation &m_statement;
+ bool m_hasNext = false;
+ };
+
+ using value_type = ResultType;
+ using iterator = SqliteResultIteratator;
+ using const_iterator = iterator;
+
+ template<typename... QueryTypes>
+ BaseSqliteResultRange(StatementImplementation &statement, const QueryTypes &...queryValues)
+ : m_statement{statement}
+ {
+ statement.bindValues(queryValues...);
+ }
+
+ BaseSqliteResultRange(BaseSqliteResultRange &) = delete;
+ BaseSqliteResultRange &operator=(BaseSqliteResultRange &) = delete;
+
+ BaseSqliteResultRange(BaseSqliteResultRange &&other)
+ : m_statement{std::move(other.resetter)}
+ {}
+ BaseSqliteResultRange &operator=(BaseSqliteResultRange &&) = delete;
+
+ iterator begin() & { return iterator{m_statement}; }
+ iterator end() & { return iterator{m_statement, false}; }
+
+ const_iterator begin() const & { return iterator{m_statement}; }
+ const_iterator end() const & { return iterator{m_statement, false}; }
+
+ private:
+ StatementImplementation &m_statement;
+ };
+
+ template<typename ResultType>
+ class SqliteResultRange : public BaseSqliteResultRange<ResultType>
+ {
+ public:
+ template<typename... QueryTypes>
+ SqliteResultRange(StatementImplementation &statement, const QueryTypes &...queryValues)
+ : BaseSqliteResultRange<ResultType>{statement}
+ , resetter{&statement}
+
+ {
+ statement.bindValues(queryValues...);
+ }
+
+ ~SqliteResultRange()
+ {
+ if (!std::uncaught_exceptions())
+ resetter.reset();
+ }
+
+ private:
+ Resetter resetter;
+ };
+
+ template<typename ResultType>
+ class SqliteResultRangeWithTransaction : public BaseSqliteResultRange<ResultType>
+ {
+ public:
+ template<typename... QueryTypes>
+ SqliteResultRangeWithTransaction(StatementImplementation &statement,
+ const QueryTypes &...queryValues)
+ : BaseSqliteResultRange<ResultType>{statement}
+ , m_transaction{statement.database()}
+ , resetter{&statement}
+ {
+ statement.bindValues(queryValues...);
+ }
+
+ ~SqliteResultRangeWithTransaction()
+ {
+ if (!std::uncaught_exceptions()) {
+ resetter.reset();
+ m_transaction.commit();
+ }
+ }
+
+ private:
+ DeferredTransaction m_transaction;
+ Resetter resetter;
+ };
+
protected:
~StatementImplementation() = default;
private:
struct Resetter
{
- Resetter(StatementImplementation &statement)
+ Resetter(StatementImplementation *statement)
: statement(statement)
{}
+ Resetter(Resetter &) = delete;
+ Resetter &operator=(Resetter &) = delete;
+
+ Resetter(Resetter &&other)
+ : statement{std::exchange(other.statement, nullptr)}
+ {}
+
void reset()
{
try {
- statement.reset();
+ if (statement)
+ statement->reset();
} catch (...) {
- shouldReset = false;
+ statement = nullptr;
throw;
}
- shouldReset = false;
+ statement = nullptr;
}
~Resetter() noexcept
{
try {
- if (shouldReset)
- statement.reset();
+ if (statement)
+ statement->reset();
} catch (...) {
}
}
- StatementImplementation &statement;
- bool shouldReset = true;
+ StatementImplementation *statement;
};
struct ValueGetter
@@ -351,17 +503,28 @@ private:
emplaceBackValues(container, std::make_integer_sequence<int, ResultCount>{});
}
- template <typename ResultOptionalType,
- int... ColumnIndices>
- ResultOptionalType assignValue(std::integer_sequence<int, ColumnIndices...>)
+ template<typename ResultOptionalType, int... ColumnIndices>
+ ResultOptionalType createOptionalValue(std::integer_sequence<int, ColumnIndices...>)
{
return ResultOptionalType(Utils::in_place, ValueGetter(*this, ColumnIndices)...);
}
template<typename ResultOptionalType>
- ResultOptionalType assignValue()
+ ResultOptionalType createOptionalValue()
+ {
+ return createOptionalValue<ResultOptionalType>(std::make_integer_sequence<int, ResultCount>{});
+ }
+
+ template<typename ResultType, int... ColumnIndices>
+ ResultType createValue(std::integer_sequence<int, ColumnIndices...>)
+ {
+ return ResultType{ValueGetter(*this, ColumnIndices)...};
+ }
+
+ template<typename ResultType>
+ ResultType createValue()
{
- return assignValue<ResultOptionalType>(std::make_integer_sequence<int, ResultCount>{});
+ return createValue<ResultType>(std::make_integer_sequence<int, ResultCount>{});
}
template<typename Callable, int... ColumnIndices>
diff --git a/src/libs/sqlite/sqlitedatabase.h b/src/libs/sqlite/sqlitedatabase.h
index 077e2723e0..7268600124 100644
--- a/src/libs/sqlite/sqlitedatabase.h
+++ b/src/libs/sqlite/sqlitedatabase.h
@@ -28,9 +28,12 @@
#include "sqlitedatabasebackend.h"
#include "sqlitedatabaseinterface.h"
#include "sqliteglobal.h"
+#include "sqlitereadstatement.h"
+#include "sqlitereadwritestatement.h"
#include "sqlitesessionchangeset.h"
#include "sqlitetable.h"
#include "sqlitetransaction.h"
+#include "sqlitewritestatement.h"
#include <utils/smallstring.h>
diff --git a/src/libs/sqlite/sqlitereadstatement.h b/src/libs/sqlite/sqlitereadstatement.h
index eb9c4e5cc5..281a7a3fa6 100644
--- a/src/libs/sqlite/sqlitereadstatement.h
+++ b/src/libs/sqlite/sqlitereadstatement.h
@@ -42,6 +42,8 @@ public:
Base::checkColumnCount(ResultCount);
}
+ using Base::range;
+ using Base::rangeWithTransaction;
using Base::readCallback;
using Base::readTo;
using Base::toValue;
diff --git a/src/libs/sqlite/sqlitevalue.h b/src/libs/sqlite/sqlitevalue.h
index 220d8d1e06..2ad97d7613 100644
--- a/src/libs/sqlite/sqlitevalue.h
+++ b/src/libs/sqlite/sqlitevalue.h
@@ -44,11 +44,11 @@ class NullValue
friend bool operator==(NullValue, NullValue) { return false; }
};
-template<typename StringType>
+template<typename StringType, typename BlobType>
class ValueBase
{
public:
- using VariantType = Utils::variant<NullValue, long long, double, StringType, Blob>;
+ using VariantType = Utils::variant<NullValue, long long, double, StringType, BlobType>;
ValueBase() = default;
@@ -115,9 +115,12 @@ public:
BlobView toBlobView() const
{
- const Blob &blob = Utils::get<int(ValueType::Blob)>(value);
-
- return {blob.bytes};
+ const BlobType &blob = Utils::get<int(ValueType::Blob)>(value);
+ if constexpr (std::is_same_v<BlobType, Blob>) {
+ return {blob.bytes};
+ } else {
+ return blob;
+ }
}
explicit operator QVariant() const
{
@@ -245,7 +248,7 @@ public:
VariantType value;
};
-class ValueView : public ValueBase<Utils::SmallStringView>
+class ValueView : public ValueBase<Utils::SmallStringView, BlobView>
{
public:
explicit ValueView(ValueBase &&base)
@@ -259,9 +262,9 @@ public:
}
};
-class Value : public ValueBase<Utils::SmallString>
+class Value : public ValueBase<Utils::SmallString, Blob>
{
- using Base = ValueBase<Utils::SmallString>;
+ using Base = ValueBase<Utils::SmallString, Blob>;
public:
using Base::Base;
diff --git a/src/libs/ssh/sftpsession.cpp b/src/libs/ssh/sftpsession.cpp
index 528475ed2b..80762a643e 100644
--- a/src/libs/ssh/sftpsession.cpp
+++ b/src/libs/ssh/sftpsession.cpp
@@ -30,8 +30,8 @@
#include "sshsettings.h"
#include <utils/fileutils.h>
+#include <utils/commandline.h>
#include <utils/qtcassert.h>
-#include <utils/qtcprocess.h>
#include <QByteArrayList>
#include <QFileInfo>
@@ -102,7 +102,7 @@ struct SftpSession::SftpSessionPrivate
// The second newline forces the prompt to appear after the command has finished.
sftpProc.write(commandString(activeCommand.type) + ' '
- + QtcProcess::Arguments::createUnixArgs(activeCommand.paths)
+ + ProcessArgs::createUnixArgs(activeCommand.paths)
.toString().toLocal8Bit() + "\n\n");
}
};
diff --git a/src/libs/ssh/sftptransfer.cpp b/src/libs/ssh/sftptransfer.cpp
index 155d796564..c7561e611a 100644
--- a/src/libs/ssh/sftptransfer.cpp
+++ b/src/libs/ssh/sftptransfer.cpp
@@ -36,7 +36,7 @@
#include <QTimer>
#include <utils/algorithm.h>
-#include <utils/qtcprocess.h>
+#include <utils/commandline.h>
using namespace Utils;
@@ -151,7 +151,7 @@ void SftpTransfer::doStart()
for (const QString &dir : d->dirsToCreate()) {
switch (d->transferType) {
case Internal::FileTransferType::Upload:
- batchFile.write("-mkdir " + QtcProcess::quoteArgUnix(dir).toLocal8Bit() + '\n');
+ batchFile.write("-mkdir " + ProcessArgs::quoteArgUnix(dir).toLocal8Bit() + '\n');
break;
case Internal::FileTransferType::Download:
if (!QDir::root().mkpath(dir)) {
@@ -169,14 +169,14 @@ void SftpTransfer::doStart()
QFileInfo fi(f.sourceFile);
if (fi.isSymLink()) {
link = true;
- batchFile.write("-rm " + QtcProcess::quoteArgUnix(f.targetFile).toLocal8Bit()
+ batchFile.write("-rm " + ProcessArgs::quoteArgUnix(f.targetFile).toLocal8Bit()
+ '\n');
sourceFileOrLinkTarget = fi.dir().relativeFilePath(fi.symLinkTarget()); // see QTBUG-5817.
}
}
batchFile.write(d->transferCommand(link) + ' '
- + QtcProcess::quoteArgUnix(sourceFileOrLinkTarget).toLocal8Bit() + ' '
- + QtcProcess::quoteArgUnix(f.targetFile).toLocal8Bit() + '\n');
+ + ProcessArgs::quoteArgUnix(sourceFileOrLinkTarget).toLocal8Bit() + ' '
+ + ProcessArgs::quoteArgUnix(f.targetFile).toLocal8Bit() + '\n');
}
d->sftpProc.setStandardInputFile(batchFile.fileName());
d->sftpProc.start(sftpBinary.toString(), d->connectionArgs);
diff --git a/src/libs/ssh/sshremoteprocess.cpp b/src/libs/ssh/sshremoteprocess.cpp
index 3d1ef6a81e..fdfe76e9b2 100644
--- a/src/libs/ssh/sshremoteprocess.cpp
+++ b/src/libs/ssh/sshremoteprocess.cpp
@@ -28,7 +28,7 @@
#include "sshlogging_p.h"
#include "sshsettings.h"
-#include <utils/fileutils.h>
+#include <utils/commandline.h>
#include <utils/qtcassert.h>
#include <QDir>
diff --git a/src/libs/ssh/sshremoteprocess.h b/src/libs/ssh/sshremoteprocess.h
index d1d62d76fa..16793d1c01 100644
--- a/src/libs/ssh/sshremoteprocess.h
+++ b/src/libs/ssh/sshremoteprocess.h
@@ -28,7 +28,9 @@
#include "ssh_global.h"
#include "sshprocess.h"
-#include <utils/fileutils.h>
+namespace Utils {
+class CommandLine;
+}
namespace QSsh {
class SshConnection;
diff --git a/src/libs/tracing/qml/CategoryLabel.qml b/src/libs/tracing/qml/CategoryLabel.qml
index 171c92400e..c47e843f23 100644
--- a/src/libs/tracing/qml/CategoryLabel.qml
+++ b/src/libs/tracing/qml/CategoryLabel.qml
@@ -148,7 +148,7 @@ Item {
property int currentNote: -1
Connections {
target: notesModel
- onChanged: {
+ function onChanged(typeId, modelId, timelineIndex) {
// This will only be called if notesModel != null.
if (modelId === -1 || modelId === model.modelId) {
var notes = notesModel.byTimelineModel(model.modelId);
diff --git a/src/libs/tracing/qml/FlameGraphView.qml b/src/libs/tracing/qml/FlameGraphView.qml
index f98bcb3134..a27f3da8d6 100644
--- a/src/libs/tracing/qml/FlameGraphView.qml
+++ b/src/libs/tracing/qml/FlameGraphView.qml
@@ -307,7 +307,7 @@ ScrollView {
Connections {
target: root.model
- onModelReset: {
+ function onModelReset() {
tooltip.hoveredNode = null;
tooltip.selectedNode = null;
}
diff --git a/src/libs/tracing/qml/MainView.qml b/src/libs/tracing/qml/MainView.qml
index f544721f9a..4e28ea9b26 100644
--- a/src/libs/tracing/qml/MainView.qml
+++ b/src/libs/tracing/qml/MainView.qml
@@ -51,12 +51,12 @@ Rectangle {
// ***** connections with external objects
Connections {
target: zoomControl
- onRangeChanged: {
+ function onRangeChanged() {
zoomSliderToolBar.updateZoomLevel();
content.scroll();
selectionRange.update();
}
- onWindowChanged: {
+ function onWindowChanged() {
content.scroll();
}
}
diff --git a/src/libs/tracing/qml/Overview.qml b/src/libs/tracing/qml/Overview.qml
index e560285802..f24bd03dae 100644
--- a/src/libs/tracing/qml/Overview.qml
+++ b/src/libs/tracing/qml/Overview.qml
@@ -70,7 +70,7 @@ Rectangle {
Connections {
target: zoomer
- onRangeChanged: updateRangeMover()
+ function onRangeChanged() { updateRangeMover(); }
}
TimeDisplay {
diff --git a/src/libs/tracing/qml/SelectionRange.qml b/src/libs/tracing/qml/SelectionRange.qml
index 9f111b75c4..3f10ac3414 100644
--- a/src/libs/tracing/qml/SelectionRange.qml
+++ b/src/libs/tracing/qml/SelectionRange.qml
@@ -68,7 +68,7 @@ RangeMover {
Connections {
target: zoomer
- onWindowChanged: updateRange()
+ function onWindowChanged() { updateRange(); }
}
function setPos(pos) {
diff --git a/src/libs/tracing/qml/SelectionRangeDetails.qml b/src/libs/tracing/qml/SelectionRangeDetails.qml
index 288ac7693c..e5b9c41106 100644
--- a/src/libs/tracing/qml/SelectionRangeDetails.qml
+++ b/src/libs/tracing/qml/SelectionRangeDetails.qml
@@ -48,8 +48,8 @@ Item {
// keep inside view
Connections {
target: selectionRangeDetails.parent
- onWidthChanged: fitInView();
- onHeightChanged: fitInView();
+ function onWidthChanged() { fitInView(); }
+ function onHeightChanged() { fitInView(); }
}
function fitInView() {
diff --git a/src/libs/tracing/qml/TimeMarks.qml b/src/libs/tracing/qml/TimeMarks.qml
index a3622b06d2..a0f93e6ead 100644
--- a/src/libs/tracing/qml/TimeMarks.qml
+++ b/src/libs/tracing/qml/TimeMarks.qml
@@ -70,7 +70,7 @@ Item {
Connections {
target: model
- onExpandedRowHeightChanged: {
+ function onExpandedRowHeightChanged(row, height) {
if (model && model.expanded && row >= 0)
rowRepeater.itemAt(row).height = height;
}
diff --git a/src/libs/tracing/qml/TimelineContent.qml b/src/libs/tracing/qml/TimelineContent.qml
index 5eb667822f..188ee28136 100644
--- a/src/libs/tracing/qml/TimelineContent.qml
+++ b/src/libs/tracing/qml/TimelineContent.qml
@@ -135,8 +135,8 @@ Flickable {
Connections {
target: timelineView
- onClearChildren: renderer.clearData()
- onSelect: {
+ function onClearChildren() { renderer.clearData(); }
+ function onSelect(modelIndex, eventIndex) {
if (modelIndex === index || modelIndex === -1) {
renderer.selectedItem = eventIndex;
if (eventIndex !== -1)
@@ -167,7 +167,7 @@ Flickable {
Connections {
target: model
- onDetailsChanged: {
+ function onDetailsChanged() {
if (selectedItem != -1) {
flick.propagateSelection(-1, -1);
flick.propagateSelection(index, selectedItem);
diff --git a/src/libs/tracing/timelinerenderer.cpp b/src/libs/tracing/timelinerenderer.cpp
index 2abd234e01..195e08edc9 100644
--- a/src/libs/tracing/timelinerenderer.cpp
+++ b/src/libs/tracing/timelinerenderer.cpp
@@ -209,13 +209,8 @@ void TimelineRenderer::wheelEvent(QWheelEvent *event)
int degrees = (event->angleDelta().x() + event->angleDelta().y()) / 8;
const qint64 circle = 360;
-#if QT_VERSION < QT_VERSION_CHECK(5, 14, 0)
- qint64 mouseTime = event->pos().x() * zoom->windowDuration() / width() +
- zoom->windowStart();
-#else
qint64 mouseTime = event->position().toPoint().x() * zoom->windowDuration() / width() +
zoom->windowStart();
-#endif
qint64 beforeMouse = (mouseTime - zoom->rangeStart()) * (circle - degrees) / circle;
qint64 afterMouse = (zoom->rangeEnd() - mouseTime) * (circle - degrees) / circle;
diff --git a/src/libs/utils/CMakeLists.txt b/src/libs/utils/CMakeLists.txt
index c76e367abc..e78809ff85 100644
--- a/src/libs/utils/CMakeLists.txt
+++ b/src/libs/utils/CMakeLists.txt
@@ -24,6 +24,7 @@ add_qtc_library(Utils
checkablemessagebox.cpp checkablemessagebox.h
classnamevalidatinglineedit.cpp classnamevalidatinglineedit.h
codegeneration.cpp codegeneration.h
+ commandline.cpp commandline.h
completinglineedit.cpp completinglineedit.h
completingtextedit.cpp completingtextedit.h
consoleprocess.cpp consoleprocess.h
@@ -58,6 +59,7 @@ add_qtc_library(Utils
fixedsizeclicklabel.cpp fixedsizeclicklabel.h
flowlayout.cpp flowlayout.h
functiontraits.h
+ futuresynchronizer.cpp futuresynchronizer.h
fuzzymatcher.cpp fuzzymatcher.h
genericconstants.h
globalfilechangeblocker.cpp globalfilechangeblocker.h
@@ -75,8 +77,8 @@ add_qtc_library(Utils
json.cpp json.h
jsontreeitem.cpp jsontreeitem.h
layoutbuilder.cpp layoutbuilder.h
- linecolumn.h
- link.h
+ linecolumn.cpp linecolumn.h
+ link.cpp link.h
listmodel.h
listutils.h
macroexpander.cpp macroexpander.h
@@ -128,7 +130,6 @@ add_qtc_library(Utils
reloadpromptutils.cpp reloadpromptutils.h
removefiledialog.cpp removefiledialog.h removefiledialog.ui
runextensions.cpp runextensions.h
- savedaction.cpp savedaction.h
savefile.cpp savefile.h
scopedswap.h
set_algorithm.h
@@ -152,7 +153,6 @@ add_qtc_library(Utils
stringutils.cpp stringutils.h
styledbar.cpp styledbar.h
stylehelper.cpp stylehelper.h
- synchronousprocess.cpp synchronousprocess.h
templateengine.cpp templateengine.h
temporarydirectory.cpp temporarydirectory.h
temporaryfile.cpp temporaryfile.h
diff --git a/src/libs/utils/algorithm.h b/src/libs/utils/algorithm.h
index 772c6b1c91..62bcace8ef 100644
--- a/src/libs/utils/algorithm.h
+++ b/src/libs/utils/algorithm.h
@@ -1283,37 +1283,21 @@ OutputIterator set_union(InputIterator1 first1,
template <class T>
QSet<T> toSet(const QList<T> &list)
{
-#if (QT_VERSION < QT_VERSION_CHECK(5, 14, 0))
- return list.toSet();
-#else
return QSet<T>(list.begin(), list.end());
-#endif
}
#if QT_VERSION < QT_VERSION_CHECK(6, 0, 0)
template<class T>
QSet<T> toSet(const QVector<T> &vec)
{
-#if (QT_VERSION < QT_VERSION_CHECK(5, 14, 0))
- QSet<T> result;
- for (const T &p : vec) {
- result.insert(p);
- }
- return result;
-#else
return QSet<T>(vec.begin(), vec.end());
-#endif
}
#endif
template<class T>
QList<T> toList(const QSet<T> &set)
{
-#if (QT_VERSION < QT_VERSION_CHECK(5, 14, 0))
- return set.toList();
-#else
return QList<T>(set.begin(), set.end());
-#endif
}
template <class Key, class T>
diff --git a/src/libs/utils/archive.cpp b/src/libs/utils/archive.cpp
index 9f61eb28ab..de111dec83 100644
--- a/src/libs/utils/archive.cpp
+++ b/src/libs/utils/archive.cpp
@@ -30,7 +30,7 @@
#include "environment.h"
#include "mimetypes/mimedatabase.h"
#include "qtcassert.h"
-#include "synchronousprocess.h"
+#include "qtcprocess.h"
#include <QDir>
#include <QPushButton>
@@ -208,7 +208,7 @@ Archive *Archive::unarchive(const FilePath &src, const FilePath &dest)
const QString workingDirectory = dest.toFileInfo().absoluteFilePath();
QDir(workingDirectory).mkpath(".");
- archive->m_process = new QProcess;
+ archive->m_process = new QtcProcess;
archive->m_process->setProcessChannelMode(QProcess::MergedChannels);
QObject::connect(
archive->m_process,
@@ -265,15 +265,15 @@ Archive *Archive::unarchive(const FilePath &src, const FilePath &dest)
archive->m_process->setArguments(tool->arguments);
#endif
archive->m_process->setWorkingDirectory(workingDirectory);
- archive->m_process->start(QProcess::ReadOnly);
+ archive->m_process->setOpenMode(QProcess::ReadOnly);
+ archive->m_process->start();
return archive;
}
void Archive::cancel()
{
- if (!m_process)
- return;
- SynchronousProcess::stopProcess(*m_process);
+ if (m_process)
+ m_process->stopProcess();
}
} // namespace Utils
diff --git a/src/libs/utils/archive.h b/src/libs/utils/archive.h
index 324a473ba3..217191073a 100644
--- a/src/libs/utils/archive.h
+++ b/src/libs/utils/archive.h
@@ -30,10 +30,11 @@
#include "fileutils.h"
#include <QObject>
-#include <QProcess>
namespace Utils {
+class QtcProcess;
+
class QTCREATOR_UTILS_EXPORT Archive : public QObject
{
Q_OBJECT
@@ -51,7 +52,7 @@ signals:
private:
Archive() = default;
- QProcess *m_process = nullptr;
+ QtcProcess *m_process = nullptr;
};
} // namespace Utils
diff --git a/src/libs/utils/aspects.cpp b/src/libs/utils/aspects.cpp
index ef0f7b1866..3207497f4a 100644
--- a/src/libs/utils/aspects.cpp
+++ b/src/libs/utils/aspects.cpp
@@ -31,18 +31,24 @@
#include "pathchooser.h"
#include "qtcassert.h"
#include "qtcprocess.h"
+#include "qtcsettings.h"
#include "utilsicons.h"
#include "variablechooser.h"
+#include <QAction>
#include <QButtonGroup>
#include <QCheckBox>
#include <QComboBox>
+#include <QDebug>
#include <QFormLayout>
+#include <QGroupBox>
#include <QLabel>
#include <QLineEdit>
#include <QListWidget>
#include <QPointer>
+#include <QPushButton>
#include <QRadioButton>
+#include <QSettings>
#include <QSpinBox>
#include <QTextEdit>
#include <QToolButton>
@@ -56,17 +62,24 @@ public:
Utils::Id m_id;
QVariant m_value;
QVariant m_defaultValue;
+ std::function<QVariant(const QVariant &)> m_toSettings;
+ std::function<QVariant(const QVariant &)> m_fromSettings;
QString m_displayName;
QString m_settingsKey; // Name of data in settings.
QString m_tooltip;
QString m_labelText;
QPixmap m_labelPixmap;
+ QIcon m_icon;
QPointer<QLabel> m_label; // Owned by configuration widget
+ QPointer<QAction> m_action; // Owned by us.
bool m_visible = true;
bool m_enabled = true;
bool m_readOnly = true;
+ bool m_autoApply = true;
+ int m_spanX = 1;
+ int m_spanY = 1;
BaseAspect::ConfigWidgetCreator m_configWidgetCreator;
QList<QPointer<QWidget>> m_subWidgets;
};
@@ -102,7 +115,10 @@ BaseAspect::BaseAspect()
/*!
Destructs a BaseAspect.
*/
-BaseAspect::~BaseAspect() = default;
+BaseAspect::~BaseAspect()
+{
+ delete d->m_action;
+}
Id BaseAspect::id() const
{
@@ -126,8 +142,10 @@ QVariant BaseAspect::value() const
*/
void BaseAspect::setValue(const QVariant &value)
{
- if (setValueQuietly(value))
+ if (setValueQuietly(value)) {
emit changed();
+ emitChangedValue();
+ }
}
/*!
@@ -149,13 +167,18 @@ QVariant BaseAspect::defaultValue() const
}
/*!
- Sets a default value for this aspect.
+ Sets a default value and the current value for this aspect.
+
+ \note The current value will be set silently to the same value.
+ It is reasonable to only set default values in the setup phase
+ of the aspect.
Default values will not be stored in settings.
*/
void BaseAspect::setDefaultValue(const QVariant &value)
{
d->m_defaultValue = value;
+ d->m_value = value;
}
void BaseAspect::setDisplayName(const QString &displayName)
@@ -178,13 +201,19 @@ void BaseAspect::setVisible(bool visible)
d->m_visible = visible;
for (QWidget *w : qAsConst(d->m_subWidgets)) {
QTC_ASSERT(w, continue);
- w->setVisible(visible);
+ // This may happen during layout building. Explicit setting visibility here
+ // may create a show a toplevel widget for a moment until it is parented
+ // to some non-shown widget.
+ if (visible && w->parentWidget())
+ w->setVisible(visible);
}
}
void BaseAspect::setupLabel()
{
QTC_ASSERT(!d->m_label, delete d->m_label);
+ if (d->m_labelText.isEmpty() && d->m_labelPixmap.isNull())
+ return;
d->m_label = new QLabel(d->m_labelText);
d->m_label->setTextInteractionFlags(Qt::TextSelectableByMouse);
if (!d->m_labelPixmap.isNull())
@@ -192,6 +221,20 @@ void BaseAspect::setupLabel()
registerSubWidget(d->m_label);
}
+void BaseAspect::addLabeledItem(LayoutBuilder &builder, QWidget *widget)
+{
+ setupLabel();
+ if (QLabel *l = label()) {
+ l->setBuddy(widget);
+ builder.addItem(l);
+ LayoutBuilder::LayoutItem item(widget);
+ item.span = std::max(d->m_spanX - 1, 1);
+ builder.addItem(item);
+ } else {
+ builder.addItem(LayoutBuilder::LayoutItem(widget));
+ }
+}
+
/*!
Sets \a labelText as text for the separate label in the visual
representation of this aspect.
@@ -214,6 +257,13 @@ void BaseAspect::setLabelPixmap(const QPixmap &labelPixmap)
d->m_label->setPixmap(labelPixmap);
}
+void BaseAspect::setIcon(const QIcon &icon)
+{
+ d->m_icon = icon;
+ if (d->m_action)
+ d->m_action->setIcon(icon);
+}
+
/*!
Returns the current text for the separate label in the visual
representation of this aspect.
@@ -245,6 +295,11 @@ void BaseAspect::setToolTip(const QString &tooltip)
}
}
+bool BaseAspect::isEnabled() const
+{
+ return d->m_enabled;
+}
+
void BaseAspect::setEnabled(bool enabled)
{
d->m_enabled = enabled;
@@ -254,6 +309,22 @@ void BaseAspect::setEnabled(bool enabled)
}
}
+/*!
+ Makes the enabled state of this aspect depend on the checked state of \a checker.
+*/
+void BaseAspect::setEnabler(BoolAspect *checker)
+{
+ QTC_ASSERT(checker, return);
+ setEnabled(checker->value());
+ connect(checker, &BoolAspect::volatileValueChanged, this, &BaseAspect::setEnabled);
+ connect(checker, &BoolAspect::valueChanged, this, &BaseAspect::setEnabled);
+}
+
+bool BaseAspect::isReadOnly() const
+{
+ return d->m_readOnly;
+}
+
void BaseAspect::setReadOnly(bool readOnly)
{
d->m_readOnly = readOnly;
@@ -266,6 +337,30 @@ void BaseAspect::setReadOnly(bool readOnly)
}
}
+void BaseAspect::setSpan(int x, int y)
+{
+ d->m_spanX = x;
+ d->m_spanY = y;
+}
+
+bool BaseAspect::isAutoApply() const
+{
+ return d->m_autoApply;
+}
+
+/*!
+ Sets auto-apply mode. When auto-apply mode is on, user interaction to this
+ aspect's widget will not modify the \c value of the aspect until \c apply()
+ is called programmatically.
+
+ \sa setSettingsKey()
+*/
+
+void BaseAspect::setAutoApply(bool on)
+{
+ d->m_autoApply = on;
+}
+
/*!
\internal
*/
@@ -304,7 +399,17 @@ void BaseAspect::setSettingsKey(const QString &group, const QString &key)
d->m_settingsKey = group + "/" + key;
}
-QString BaseAspect::displayName() const { return d->m_displayName; }
+/*!
+ Returns the string that should be used when this action appears in menus
+ or other places that are typically used with Book style capitalization.
+
+ If no display name is set, the label text will be used as fallback.
+*/
+
+QString BaseAspect::displayName() const
+{
+ return d->m_displayName.isEmpty() ? d->m_labelText : d->m_displayName;
+}
/*!
\internal
@@ -314,6 +419,15 @@ QWidget *BaseAspect::createConfigWidget() const
return d->m_configWidgetCreator ? d->m_configWidgetCreator() : nullptr;
}
+QAction *BaseAspect::action()
+{
+ if (!d->m_action) {
+ d->m_action = new QAction(labelText());
+ d->m_action->setIcon(d->m_icon);
+ }
+ return d->m_action;
+}
+
/*!
Adds the visual representation of this aspect to a layout using
a layout builder.
@@ -322,10 +436,72 @@ void BaseAspect::addToLayout(LayoutBuilder &)
{
}
+/*!
+ Updates this aspect's value from user-initiated changes in the widget.
+
+ This has only an effect if \c isAutoApply is false.
+*/
+void BaseAspect::apply()
+{
+ QTC_CHECK(!d->m_autoApply);
+ if (isDirty())
+ setValue(volatileValue());
+}
+
+/*!
+ Discard user changes in the widget and restore widget contents from
+ aspect's value.
+
+ This has only an effect if \c isAutoApply is false.
+*/
+void BaseAspect::cancel()
+{
+ QTC_CHECK(!d->m_autoApply);
+ if (!d->m_subWidgets.isEmpty())
+ setVolatileValue(d->m_value);
+}
+
+void BaseAspect::finish()
+{
+ // No qDeleteAll() possible as long as the connect in registerSubWidget() exist.
+ while (d->m_subWidgets.size())
+ delete d->m_subWidgets.takeLast();
+}
+
+bool BaseAspect::hasAction() const
+{
+ return d->m_action != nullptr;
+}
+
+bool BaseAspect::isDirty() const
+{
+ QTC_CHECK(!isAutoApply());
+ // Aspects that were never shown cannot contain unsaved user changes.
+ if (d->m_subWidgets.isEmpty())
+ return false;
+ return volatileValue() != d->m_value;
+}
+
+QVariant BaseAspect::volatileValue() const
+{
+ QTC_CHECK(!isAutoApply());
+ return {};
+}
+
+void BaseAspect::setVolatileValue(const QVariant &val)
+{
+ Q_UNUSED(val);
+}
+
void BaseAspect::registerSubWidget(QWidget *widget)
{
d->m_subWidgets.append(widget);
+ // FIXME: This interferes with qDeleteAll() in finish() and destructor,
+ // it would not be needed when all users actually deleted their subwidgets,
+ // e.g. the SettingsPage::finish() base implementation, but this still
+ // leaves the cases where no such base functionality is available, e.g.
+ // in the run/build config aspects.
connect(widget, &QObject::destroyed, this, [this, widget] {
d->m_subWidgets.removeAll(widget);
});
@@ -340,11 +516,10 @@ void BaseAspect::registerSubWidget(QWidget *widget)
}
void BaseAspect::saveToMap(QVariantMap &data, const QVariant &value,
- const QVariant &defaultValue, const QString &keyExtension) const
+ const QVariant &defaultValue, const QString &key)
{
- if (settingsKey().isEmpty())
+ if (key.isEmpty())
return;
- const QString key = settingsKey() + keyExtension;
if (value == defaultValue)
data.remove(key);
else
@@ -356,7 +531,8 @@ void BaseAspect::saveToMap(QVariantMap &data, const QVariant &value,
*/
void BaseAspect::fromMap(const QVariantMap &map)
{
- setValue(map.value(settingsKey(), defaultValue()));
+ const QVariant val = map.value(settingsKey(), toSettingsValue(defaultValue()));
+ setValue(fromSettingsValue(val));
}
/*!
@@ -364,66 +540,52 @@ void BaseAspect::fromMap(const QVariantMap &map)
*/
void BaseAspect::toMap(QVariantMap &map) const
{
- saveToMap(map, d->m_value, d->m_defaultValue);
+ saveToMap(map, toSettingsValue(d->m_value), toSettingsValue(d->m_defaultValue), settingsKey());
}
-/*!
- \internal
-*/
-void BaseAspect::acquaintSiblings(const BaseAspects &)
-{}
-
-// BaseAspects
-
-/*!
- \class BaseAspects
- \inmodule QtCreator
-
- \brief This class represent a collection of one or more aspects.
-
- A BaseAspects object assumes ownership on its aspects.
-*/
+void BaseAspect::readSettings(const QSettings *settings)
+{
+ if (settingsKey().isEmpty())
+ return;
+ const QVariant &val = settings->value(settingsKey());
+ setValue(val.isValid() ? fromSettingsValue(val) : defaultValue());
+}
-/*!
- Constructs a BaseAspects object.
-*/
-BaseAspects::BaseAspects() = default;
+void BaseAspect::writeSettings(QSettings *settings) const
+{
+ if (settingsKey().isEmpty())
+ return;
+ QtcSettings::setValueWithDefault(settings,
+ settingsKey(),
+ toSettingsValue(value()),
+ toSettingsValue(defaultValue()));
+}
-/*!
- Destructs a BaseAspects object.
-*/
-BaseAspects::~BaseAspects()
+void BaseAspect::setFromSettingsTransformation(const SavedValueTransformation &transform)
{
- qDeleteAll(m_aspects);
+ d->m_fromSettings = transform;
}
-/*!
- Retrieves a BaseAspect with a given \a id, or nullptr if no such aspect is contained.
+void BaseAspect::setToSettingsTransformation(const SavedValueTransformation &transform)
+{
+ d->m_toSettings = transform;
+}
- \sa BaseAspect.
-*/
-BaseAspect *BaseAspects::aspect(Utils::Id id) const
+QVariant BaseAspect::toSettingsValue(const QVariant &val) const
{
- return Utils::findOrDefault(m_aspects, Utils::equal(&BaseAspect::id, id));
+ return d->m_toSettings ? d->m_toSettings(val) : val;
}
-/*!
- \internal
-*/
-void BaseAspects::fromMap(const QVariantMap &map) const
+QVariant BaseAspect::fromSettingsValue(const QVariant &val) const
{
- for (BaseAspect *aspect : m_aspects)
- aspect->fromMap(map);
+ return d->m_fromSettings ? d->m_fromSettings(val) : val;
}
/*!
\internal
*/
-void BaseAspects::toMap(QVariantMap &map) const
-{
- for (BaseAspect *aspect : m_aspects)
- aspect->toMap(map);
-}
+void BaseAspect::acquaintSiblings(const AspectContainer &)
+{}
namespace Internal {
@@ -432,15 +594,17 @@ class BoolAspectPrivate
public:
BoolAspect::LabelPlacement m_labelPlacement = BoolAspect::LabelPlacement::AtCheckBox;
QPointer<QCheckBox> m_checkBox; // Owned by configuration widget
+ QPointer<QGroupBox> m_groupBox; // For BoolAspects handling GroupBox check boxes
};
class SelectionAspectPrivate
{
public:
+ ~SelectionAspectPrivate() { delete m_buttonGroup; }
+
SelectionAspect::DisplayStyle m_displayStyle
= SelectionAspect::DisplayStyle::RadioButtons;
- struct Option { QString displayName; QString tooltip; };
- QVector<Option> m_options;
+ QVector<SelectionAspect::Option> m_options;
// These are all owned by the configuration widget.
QList<QPointer<QRadioButton>> m_buttons;
@@ -490,40 +654,50 @@ public:
std::function<void()> m_openTerminal;
bool m_undoRedoEnabled = true;
+ bool m_acceptRichText = false;
bool m_showToolTipOnLabel = false;
bool m_fileDialogOnly = false;
+ bool m_useResetButton = false;
- template<class Widget> void updateWidgetFromCheckStatus(Widget *w)
+ template<class Widget> void updateWidgetFromCheckStatus(StringAspect *aspect, Widget *w)
{
const bool enabled = !m_checker || m_checker->value();
if (m_uncheckedSemantics == StringAspect::UncheckedSemantics::Disabled)
- w->setEnabled(enabled);
+ w->setEnabled(enabled && aspect->isEnabled());
else
- w->setReadOnly(!enabled);
+ w->setReadOnly(!enabled || aspect->isReadOnly());
}
};
class IntegerAspectPrivate
{
public:
- QVariant m_minimumValue;
- QVariant m_maximumValue;
+ Utils::optional<qint64> m_minimumValue;
+ Utils::optional<qint64> m_maximumValue;
int m_displayIntegerBase = 10;
qint64 m_displayScaleFactor = 1;
QString m_prefix;
QString m_suffix;
+ QString m_specialValueText;
+ int m_singleStep = 1;
QPointer<QSpinBox> m_spinBox; // Owned by configuration widget
};
-class StringListAspectPrivate
+class DoubleAspectPrivate
{
public:
+ Utils::optional<double> m_minimumValue;
+ Utils::optional<double> m_maximumValue;
+ QString m_prefix;
+ QString m_suffix;
+ QString m_specialValueText;
+ double m_singleStep = 1;
+ QPointer<QDoubleSpinBox> m_spinBox; // Owned by configuration widget
};
-class AspectContainerPrivate
+class StringListAspectPrivate
{
public:
- QList<BaseAspect *> m_items;
};
class TextDisplayPrivate
@@ -586,7 +760,10 @@ public:
StringAspect::StringAspect()
: d(new Internal::StringAspectPrivate)
-{}
+{
+ setDefaultValue(QString());
+ setSpan(2, 1); // Default: Label + something
+}
/*!
\internal
@@ -631,9 +808,15 @@ void StringAspect::setValue(const QString &val)
if (BaseAspect::setValueQuietly(QVariant(processedValue))) {
update();
emit changed();
+ emit valueChanged(processedValue);
}
}
+void StringAspect::setDefaultValue(const QString &val)
+{
+ BaseAspect::setDefaultValue(val);
+}
+
/*!
\reimp
*/
@@ -650,7 +833,7 @@ void StringAspect::fromMap(const QVariantMap &map)
*/
void StringAspect::toMap(QVariantMap &map) const
{
- saveToMap(map, value(), QString());
+ saveToMap(map, value(), defaultValue(), settingsKey());
if (d->m_checker)
d->m_checker->toMap(map);
}
@@ -679,6 +862,11 @@ void StringAspect::setFilePath(const FilePath &value)
setValue(value.toUserOutput());
}
+PathChooser *StringAspect::pathChooser() const
+{
+ return d->m_pathChooserDisplay.data();
+}
+
/*!
\internal
*/
@@ -798,11 +986,28 @@ void StringAspect::setUndoRedoEnabled(bool undoRedoEnabled)
d->m_textEditDisplay->setUndoRedoEnabled(undoRedoEnabled);
}
+void StringAspect::setAcceptRichText(bool acceptRichText)
+{
+ d->m_acceptRichText = acceptRichText;
+ if (d->m_textEditDisplay)
+ d->m_textEditDisplay->setAcceptRichText(acceptRichText);
+}
+
void StringAspect::setMacroExpanderProvider(const MacroExpanderProvider &expanderProvider)
{
d->m_expanderProvider = expanderProvider;
}
+void StringAspect::setUseGlobalMacroExpander()
+{
+ d->m_expanderProvider = &globalMacroExpander;
+}
+
+void StringAspect::setUseResetButton()
+{
+ d->m_useResetButton = true;
+}
+
void StringAspect::setValidationFunction(const FancyLineEdit::ValidationFunction &validator)
{
d->m_validator = validator;
@@ -837,17 +1042,16 @@ void StringAspect::addToLayout(LayoutBuilder &builder)
builder.finishRow();
}
- setupLabel();
- builder.addItem(label());
-
- const auto useMacroExpander = [this, &builder](QWidget *w) {
+ const auto useMacroExpander = [this](QWidget *w) {
if (!d->m_expanderProvider)
return;
- const auto chooser = new VariableChooser(builder.layout()->parentWidget());
+ const auto chooser = new VariableChooser(w);
chooser->addSupportedWidget(w);
chooser->addMacroExpanderProvider(d->m_expanderProvider);
};
+ const QString displayedString = d->m_displayFilter ? d->m_displayFilter(value()) : value();
+
switch (d->m_displayStyle) {
case PathChooserDisplay:
d->m_pathChooserDisplay = createSubWidget<PathChooser>();
@@ -856,12 +1060,16 @@ void StringAspect::addToLayout(LayoutBuilder &builder)
d->m_pathChooserDisplay->setHistoryCompleter(d->m_historyCompleterKey);
d->m_pathChooserDisplay->setEnvironment(d->m_environment);
d->m_pathChooserDisplay->setBaseDirectory(d->m_baseFileName);
- useMacroExpander(d->m_pathChooserDisplay->lineEdit());
- connect(d->m_pathChooserDisplay, &PathChooser::pathChanged,
- this, &StringAspect::setValue);
- builder.addItem(d->m_pathChooserDisplay.data());
d->m_pathChooserDisplay->setFileDialogOnly(d->m_fileDialogOnly);
d->m_pathChooserDisplay->setOpenTerminalHandler(d->m_openTerminal);
+ d->m_pathChooserDisplay->setFilePath(FilePath::fromString(displayedString));
+ d->updateWidgetFromCheckStatus(this, d->m_pathChooserDisplay.data());
+ addLabeledItem(builder, d->m_pathChooserDisplay);
+ useMacroExpander(d->m_pathChooserDisplay->lineEdit());
+ if (isAutoApply()) {
+ connect(d->m_pathChooserDisplay, &PathChooser::pathChanged, this, [this] {
+ setValue(d->m_pathChooserDisplay->path()); });
+ }
break;
case LineEditDisplay:
d->m_lineEditDisplay = createSubWidget<FancyLineEdit>();
@@ -870,28 +1078,48 @@ void StringAspect::addToLayout(LayoutBuilder &builder)
d->m_lineEditDisplay->setHistoryCompleter(d->m_historyCompleterKey);
if (d->m_validator)
d->m_lineEditDisplay->setValidationFunction(d->m_validator);
+ d->m_lineEditDisplay->setTextKeepingActiveCursor(displayedString);
+ d->updateWidgetFromCheckStatus(this, d->m_lineEditDisplay.data());
+ addLabeledItem(builder, d->m_lineEditDisplay);
useMacroExpander(d->m_lineEditDisplay);
- connect(d->m_lineEditDisplay, &FancyLineEdit::textEdited,
- this, &StringAspect::setValue);
- builder.addItem(d->m_lineEditDisplay.data());
+ if (isAutoApply()) {
+ connect(d->m_lineEditDisplay, &FancyLineEdit::textEdited,
+ this, &StringAspect::setValue);
+ }
+ if (d->m_useResetButton) {
+ auto resetButton = createSubWidget<QPushButton>(tr("Reset"));
+ resetButton->setEnabled(d->m_lineEditDisplay->text() != defaultValue());
+ connect(resetButton, &QPushButton::clicked, this, [this] {
+ d->m_lineEditDisplay->setText(defaultValue().toString());
+ });
+ connect(d->m_lineEditDisplay, &QLineEdit::textChanged, this, [this, resetButton] {
+ resetButton->setEnabled(d->m_lineEditDisplay->text() != defaultValue());
+ });
+ builder.addItem(resetButton);
+ }
break;
case TextEditDisplay:
d->m_textEditDisplay = createSubWidget<QTextEdit>();
d->m_textEditDisplay->setPlaceholderText(d->m_placeHolderText);
d->m_textEditDisplay->setUndoRedoEnabled(d->m_undoRedoEnabled);
- d->m_textEditDisplay->setAcceptRichText(false);
+ d->m_textEditDisplay->setAcceptRichText(d->m_acceptRichText);
d->m_textEditDisplay->setTextInteractionFlags(Qt::TextEditorInteraction);
+ d->m_textEditDisplay->setText(displayedString);
+ d->updateWidgetFromCheckStatus(this, d->m_textEditDisplay.data());
+ addLabeledItem(builder, d->m_textEditDisplay);
useMacroExpander(d->m_textEditDisplay);
- connect(d->m_textEditDisplay, &QTextEdit::textChanged, this, [this] {
- const QString value = d->m_textEditDisplay->document()->toPlainText();
- setValue(value);
- });
- builder.addItem(d->m_textEditDisplay.data());
+ if (isAutoApply()) {
+ connect(d->m_textEditDisplay, &QTextEdit::textChanged, this, [this] {
+ setValue(d->m_textEditDisplay->document()->toPlainText());
+ });
+ }
break;
case LabelDisplay:
d->m_labelDisplay = createSubWidget<QLabel>();
d->m_labelDisplay->setTextInteractionFlags(Qt::TextSelectableByMouse);
- builder.addItem(d->m_labelDisplay.data());
+ d->m_labelDisplay->setText(displayedString);
+ d->m_labelDisplay->setToolTip(d->m_showToolTipOnLabel ? displayedString : toolTip());
+ addLabeledItem(builder, d->m_labelDisplay);
break;
}
@@ -899,8 +1127,50 @@ void StringAspect::addToLayout(LayoutBuilder &builder)
if (d->m_checker && d->m_checkBoxPlacement == CheckBoxPlacement::Right)
d->m_checker->addToLayout(builder);
+}
- update();
+QVariant StringAspect::volatileValue() const
+{
+ QTC_CHECK(!isAutoApply());
+ switch (d->m_displayStyle) {
+ case PathChooserDisplay:
+ QTC_ASSERT(d->m_pathChooserDisplay, return {});
+ return d->m_pathChooserDisplay->path();
+ case LineEditDisplay:
+ QTC_ASSERT(d->m_lineEditDisplay, return {});
+ return d->m_lineEditDisplay->text();
+ case TextEditDisplay:
+ QTC_ASSERT(d->m_textEditDisplay, return {});
+ return d->m_textEditDisplay->document()->toPlainText();
+ case LabelDisplay:
+ break;
+ }
+ return {};
+}
+
+void StringAspect::setVolatileValue(const QVariant &val)
+{
+ switch (d->m_displayStyle) {
+ case PathChooserDisplay:
+ if (d->m_pathChooserDisplay)
+ d->m_pathChooserDisplay->setPath(val.toString());
+ break;
+ case LineEditDisplay:
+ if (d->m_lineEditDisplay)
+ d->m_lineEditDisplay->setText(val.toString());
+ break;
+ case TextEditDisplay:
+ if (d->m_textEditDisplay)
+ d->m_textEditDisplay->document()->setPlainText(val.toString());
+ break;
+ case LabelDisplay:
+ break;
+ }
+}
+
+void StringAspect::emitChangedValue()
+{
+ emit valueChanged(value());
}
void StringAspect::update()
@@ -909,19 +1179,19 @@ void StringAspect::update()
if (d->m_pathChooserDisplay) {
d->m_pathChooserDisplay->setFilePath(FilePath::fromString(displayedString));
- d->updateWidgetFromCheckStatus(d->m_pathChooserDisplay.data());
+ d->updateWidgetFromCheckStatus(this, d->m_pathChooserDisplay.data());
}
if (d->m_lineEditDisplay) {
d->m_lineEditDisplay->setTextKeepingActiveCursor(displayedString);
- d->updateWidgetFromCheckStatus(d->m_lineEditDisplay.data());
+ d->updateWidgetFromCheckStatus(this, d->m_lineEditDisplay.data());
}
if (d->m_textEditDisplay) {
const QString old = d->m_textEditDisplay->document()->toPlainText();
if (displayedString != old)
d->m_textEditDisplay->setText(displayedString);
- d->updateWidgetFromCheckStatus(d->m_textEditDisplay.data());
+ d->updateWidgetFromCheckStatus(this, d->m_textEditDisplay.data());
}
if (d->m_labelDisplay) {
@@ -975,9 +1245,9 @@ void StringAspect::makeCheckable(CheckBoxPlacement checkBoxPlacement,
BoolAspect::BoolAspect(const QString &settingsKey)
: d(new Internal::BoolAspectPrivate)
{
- setValue(false);
setDefaultValue(false);
setSettingsKey(settingsKey);
+ setSpan(2, 1);
}
/*!
@@ -995,23 +1265,73 @@ void BoolAspect::addToLayout(LayoutBuilder &builder)
switch (d->m_labelPlacement) {
case LabelPlacement::AtCheckBoxWithoutDummyLabel:
d->m_checkBox->setText(labelText());
+ builder.addItem(d->m_checkBox.data());
break;
- case LabelPlacement::AtCheckBox:
+ case LabelPlacement::AtCheckBox: {
d->m_checkBox->setText(labelText());
- builder.addItem(createSubWidget<QLabel>());
+ LayoutBuilder::LayoutType type = builder.layoutType();
+ if (type == LayoutBuilder::FormLayout)
+ builder.addItem(createSubWidget<QLabel>());
+ builder.addItem(d->m_checkBox.data());
break;
+ }
case LabelPlacement::InExtraLabel:
- setupLabel();
- builder.addItem(label());
+ addLabeledItem(builder, d->m_checkBox);
break;
}
d->m_checkBox->setChecked(value());
- builder.addItem(d->m_checkBox.data());
- connect(d->m_checkBox.data(), &QAbstractButton::clicked, this, [this] {
- setValue(d->m_checkBox->isChecked());
+ if (isAutoApply()) {
+ connect(d->m_checkBox.data(), &QAbstractButton::clicked,
+ this, [this](bool val) { setValue(val); });
+ }
+ connect(d->m_checkBox.data(), &QAbstractButton::clicked,
+ this, &BoolAspect::volatileValueChanged);
+}
+
+QAction *BoolAspect::action()
+{
+ if (hasAction())
+ return BaseAspect::action();
+ auto act = BaseAspect::action(); // Creates it.
+ act->setCheckable(true);
+ act->setChecked(value());
+ connect(act, &QAction::triggered, this, [this](bool newValue) {
+ // The check would be nice to have in simple conditions, but if we
+ // have an action that's used both on a settings page and as action
+ // in a menu like "Use FakeVim", isAutoApply() is false, and yet this
+ // here can trigger.
+ //QTC_CHECK(isAutoApply());
+ setValue(newValue);
});
+ return act;
}
+QVariant BoolAspect::volatileValue() const
+{
+ QTC_CHECK(!isAutoApply());
+ if (d->m_checkBox)
+ return d->m_checkBox->isChecked();
+ if (d->m_groupBox)
+ return d->m_groupBox->isChecked();
+ QTC_CHECK(false);
+ return {};
+}
+
+void BoolAspect::setVolatileValue(const QVariant &val)
+{
+ QTC_CHECK(!isAutoApply());
+ if (d->m_checkBox)
+ d->m_checkBox->setChecked(val.toBool());
+ else if (d->m_groupBox)
+ d->m_groupBox->setChecked(val.toBool());
+}
+
+void BoolAspect::emitChangedValue()
+{
+ emit valueChanged(value());
+}
+
+
/*!
\reimp
*/
@@ -1026,16 +1346,40 @@ void BoolAspect::setValue(bool value)
if (BaseAspect::setValueQuietly(value)) {
if (d->m_checkBox)
d->m_checkBox->setChecked(value);
+ //qDebug() << "SetValue: Changing" << labelText() << " to " << value;
emit changed();
+ //QTC_CHECK(!labelText().isEmpty());
+ emit valueChanged(value);
+ //qDebug() << "SetValue: Changed" << labelText() << " to " << value;
+ if (hasAction()) {
+ //qDebug() << "SetValue: Triggering " << labelText() << "with" << value;
+ emit action()->triggered(value);
+ }
}
}
+void BoolAspect::setDefaultValue(bool val)
+{
+ BaseAspect::setDefaultValue(val);
+}
+
void BoolAspect::setLabel(const QString &labelText, LabelPlacement labelPlacement)
{
BaseAspect::setLabelText(labelText);
d->m_labelPlacement = labelPlacement;
}
+void BoolAspect::setLabelPlacement(BoolAspect::LabelPlacement labelPlacement)
+{
+ d->m_labelPlacement = labelPlacement;
+}
+
+void BoolAspect::setHandlesGroup(QGroupBox *box)
+{
+ registerSubWidget(box);
+ d->m_groupBox = box;
+}
+
/*!
\class Utils::SelectionAspect
\inmodule QtCreator
@@ -1049,7 +1393,9 @@ void BoolAspect::setLabel(const QString &labelText, LabelPlacement labelPlacemen
SelectionAspect::SelectionAspect()
: d(new Internal::SelectionAspectPrivate)
-{}
+{
+ setSpan(2, 1);
+}
/*!
\reimp
@@ -1070,40 +1416,77 @@ void SelectionAspect::addToLayout(LayoutBuilder &builder)
d->m_buttonGroup = new QButtonGroup();
d->m_buttonGroup->setExclusive(true);
for (int i = 0, n = d->m_options.size(); i < n; ++i) {
- const Internal::SelectionAspectPrivate::Option &option = d->m_options.at(i);
- auto button = new QRadioButton(option.displayName);
+ const Option &option = d->m_options.at(i);
+ auto button = createSubWidget<QRadioButton>(option.displayName);
button->setChecked(i == value());
+ button->setEnabled(option.enabled);
button->setToolTip(option.tooltip);
builder.addItems({{}, button});
d->m_buttons.append(button);
- d->m_buttonGroup->addButton(button);
- connect(button, &QAbstractButton::clicked, this, [this, i] {
- setValue(i);
- });
+ d->m_buttonGroup->addButton(button, i);
+ if (isAutoApply()) {
+ connect(button, &QAbstractButton::clicked, this, [this, i] {
+ setValue(i);
+ });
+ }
}
break;
case DisplayStyle::ComboBox:
- setupLabel();
setLabelText(displayName());
d->m_comboBox = createSubWidget<QComboBox>();
for (int i = 0, n = d->m_options.size(); i < n; ++i)
d->m_comboBox->addItem(d->m_options.at(i).displayName);
- connect(d->m_comboBox.data(), QOverload<int>::of(&QComboBox::activated),
- this, &SelectionAspect::setValue);
+ if (isAutoApply()) {
+ connect(d->m_comboBox.data(), QOverload<int>::of(&QComboBox::activated),
+ this, &SelectionAspect::setValue);
+ }
+ connect(d->m_comboBox.data(), QOverload<int>::of(&QComboBox::currentIndexChanged),
+ this, &SelectionAspect::volatileValueChanged);
d->m_comboBox->setCurrentIndex(value());
- builder.addItems({label(), d->m_comboBox.data()});
+ addLabeledItem(builder, d->m_comboBox);
+ break;
+ }
+}
+
+QVariant SelectionAspect::volatileValue() const
+{
+ QTC_CHECK(!isAutoApply());
+ switch (d->m_displayStyle) {
+ case DisplayStyle::RadioButtons:
+ QTC_ASSERT(d->m_buttonGroup, return {});
+ return d->m_buttonGroup->checkedId();
+ case DisplayStyle::ComboBox:
+ QTC_ASSERT(d->m_comboBox, return {});
+ return d->m_comboBox->currentIndex();
+ }
+ return {};
+}
+
+void SelectionAspect::setVolatileValue(const QVariant &val)
+{
+ QTC_CHECK(!isAutoApply());
+ switch (d->m_displayStyle) {
+ case DisplayStyle::RadioButtons: {
+ if (d->m_buttonGroup) {
+ QAbstractButton *button = d->m_buttonGroup->button(val.toInt());
+ QTC_ASSERT(button, return);
+ button->setChecked(true);
+ }
+ break;
+ }
+ case DisplayStyle::ComboBox:
+ if (d->m_comboBox)
+ d->m_comboBox->setCurrentIndex(val.toInt());
break;
}
}
-void SelectionAspect::setVisibleDynamic(bool visible)
+void SelectionAspect::finish()
{
- if (QLabel *l = label())
- l->setVisible(visible);
- if (d->m_comboBox)
- d->m_comboBox->setVisible(visible);
- for (QRadioButton * const button : qAsConst(d->m_buttons))
- button->setVisible(visible);
+ delete d->m_buttonGroup;
+ d->m_buttonGroup = nullptr;
+ BaseAspect::finish();
+ d->m_buttons.clear();
}
void SelectionAspect::setDisplayStyle(SelectionAspect::DisplayStyle style)
@@ -1127,14 +1510,72 @@ void SelectionAspect::setValue(int value)
}
}
+void SelectionAspect::setStringValue(const QString &val)
+{
+ const int index = indexForDisplay(val);
+ QTC_ASSERT(index >= 0, return);
+ setValue(index);
+}
+
+void SelectionAspect::setDefaultValue(int val)
+{
+ BaseAspect::setDefaultValue(val);
+}
+
+// Note: This needs to be set after all options are added.
+void SelectionAspect::setDefaultValue(const QString &val)
+{
+ BaseAspect::setDefaultValue(indexForDisplay(val));
+}
+
QString SelectionAspect::stringValue() const
{
return d->m_options.at(value()).displayName;
}
+QVariant SelectionAspect::itemValue() const
+{
+ return d->m_options.at(value()).itemData;
+}
+
void SelectionAspect::addOption(const QString &displayName, const QString &toolTip)
{
- d->m_options.append({displayName, toolTip});
+ d->m_options.append(Option(displayName, toolTip, {}));
+}
+
+void SelectionAspect::addOption(const Option &option)
+{
+ d->m_options.append(option);
+}
+
+int SelectionAspect::indexForDisplay(const QString &displayName) const
+{
+ for (int i = 0, n = d->m_options.size(); i < n; ++i) {
+ if (d->m_options.at(i).displayName == displayName)
+ return i;
+ }
+ return -1;
+}
+
+QString SelectionAspect::displayForIndex(int index) const
+{
+ QTC_ASSERT(index >= 0 && index < d->m_options.size(), return {});
+ return d->m_options.at(index).displayName;
+}
+
+int SelectionAspect::indexForItemValue(const QVariant &value) const
+{
+ for (int i = 0, n = d->m_options.size(); i < n; ++i) {
+ if (d->m_options.at(i).itemData == value)
+ return i;
+ }
+ return -1;
+}
+
+QVariant SelectionAspect::itemValueForIndex(int index) const
+{
+ QTC_ASSERT(index >= 0 && index < d->m_options.size(), return {});
+ return d->m_options.at(index).itemData;
}
/*!
@@ -1151,8 +1592,8 @@ void SelectionAspect::addOption(const QString &displayName, const QString &toolT
MultiSelectionAspect::MultiSelectionAspect()
: d(new Internal::MultiSelectionAspectPrivate(this))
{
- setValue(QStringList());
setDefaultValue(QStringList());
+ setSpan(2, 1);
}
/*!
@@ -1171,7 +1612,6 @@ void MultiSelectionAspect::addToLayout(LayoutBuilder &builder)
switch (d->m_displayStyle) {
case DisplayStyle::ListView:
- setupLabel();
d->m_listView = createSubWidget<QListWidget>();
for (const QString &val : qAsConst(d->m_allValues)) {
auto item = new QListWidgetItem(val, d->m_listView);
@@ -1183,7 +1623,7 @@ void MultiSelectionAspect::addToLayout(LayoutBuilder &builder)
if (d->setValueSelectedHelper(item->text(), item->checkState() & Qt::Checked))
emit changed();
});
- builder.addItems({label(), d->m_listView.data()});
+ addLabeledItem(builder, d->m_listView);
}
}
@@ -1213,14 +1653,6 @@ void MultiSelectionAspect::setAllValues(const QStringList &val)
d->m_allValues = val;
}
-void MultiSelectionAspect::setVisibleDynamic(bool visible)
-{
- if (QLabel *l = label())
- l->setVisible(visible);
- if (d->m_listView)
- d->m_listView->setVisible(visible);
-}
-
void MultiSelectionAspect::setDisplayStyle(MultiSelectionAspect::DisplayStyle style)
{
d->m_displayStyle = style;
@@ -1268,6 +1700,7 @@ IntegerAspect::IntegerAspect()
: d(new Internal::IntegerAspectPrivate)
{
setDefaultValue(qint64(0));
+ setSpan(2, 1);
}
/*!
@@ -1280,23 +1713,37 @@ IntegerAspect::~IntegerAspect() = default;
*/
void IntegerAspect::addToLayout(LayoutBuilder &builder)
{
- setupLabel();
-
QTC_CHECK(!d->m_spinBox);
d->m_spinBox = createSubWidget<QSpinBox>();
- d->m_spinBox->setValue(int(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(int(d->m_minimumValue.toLongLong() / d->m_displayScaleFactor),
- int(d->m_maximumValue.toLongLong() / d->m_displayScaleFactor));
-
- builder.addItems({label(), d->m_spinBox.data()});
- connect(d->m_spinBox.data(), QOverload<int>::of(&QSpinBox::valueChanged),
- this, [this](int value) {
- setValue(value * d->m_displayScaleFactor);
- });
+ d->m_spinBox->setSingleStep(d->m_singleStep);
+ d->m_spinBox->setSpecialValueText(d->m_specialValueText);
+ if (d->m_maximumValue && d->m_maximumValue)
+ d->m_spinBox->setRange(int(d->m_minimumValue.value() / d->m_displayScaleFactor),
+ int(d->m_maximumValue.value() / d->m_displayScaleFactor));
+ d->m_spinBox->setValue(int(value() / d->m_displayScaleFactor)); // Must happen after setRange()
+ addLabeledItem(builder, d->m_spinBox);
+
+ if (isAutoApply()) {
+ connect(d->m_spinBox.data(), QOverload<int>::of(&QSpinBox::valueChanged),
+ this, [this] { setValue(d->m_spinBox->value()); });
+ }
+}
+
+QVariant IntegerAspect::volatileValue() const
+{
+ QTC_CHECK(!isAutoApply());
+ QTC_ASSERT(d->m_spinBox, return {});
+ return d->m_spinBox->value() * d->m_displayScaleFactor;
+}
+
+void IntegerAspect::setVolatileValue(const QVariant &val)
+{
+ QTC_CHECK(!isAutoApply());
+ if (d->m_spinBox)
+ d->m_spinBox->setValue(int(val.toLongLong() / d->m_displayScaleFactor));
}
qint64 IntegerAspect::value() const
@@ -1306,11 +1753,7 @@ qint64 IntegerAspect::value() const
void IntegerAspect::setValue(qint64 value)
{
- if (setValueQuietly(value)) {
- if (d->m_spinBox)
- d->m_spinBox->setValue(int(value / d->m_displayScaleFactor));
- emit changed();
- }
+ BaseAspect::setValue(value);
}
void IntegerAspect::setRange(qint64 min, qint64 max)
@@ -1349,6 +1792,121 @@ void IntegerAspect::setDefaultValue(qint64 defaultValue)
BaseAspect::setDefaultValue(defaultValue);
}
+void IntegerAspect::setSpecialValueText(const QString &specialText)
+{
+ d->m_specialValueText = specialText;
+}
+
+void IntegerAspect::setSingleStep(qint64 step)
+{
+ d->m_singleStep = step;
+}
+
+
+/*!
+ \class Utils::DoubleAspect
+ \inmodule QtCreator
+
+ \brief An double aspect is a numerical property of some object, together with
+ a description of its behavior for common operations like visualizing or
+ persisting.
+
+ The double aspect is displayed using a \c QDoubleSpinBox.
+
+ The visual representation often contains a label in front
+ the display of the spin box.
+*/
+
+DoubleAspect::DoubleAspect()
+ : d(new Internal::DoubleAspectPrivate)
+{
+ setDefaultValue(double(0));
+ setSpan(2, 1);
+}
+
+/*!
+ \reimp
+*/
+DoubleAspect::~DoubleAspect() = default;
+
+/*!
+ \reimp
+*/
+void DoubleAspect::addToLayout(LayoutBuilder &builder)
+{
+ QTC_CHECK(!d->m_spinBox);
+ d->m_spinBox = createSubWidget<QDoubleSpinBox>();
+ d->m_spinBox->setPrefix(d->m_prefix);
+ d->m_spinBox->setSuffix(d->m_suffix);
+ d->m_spinBox->setSingleStep(d->m_singleStep);
+ d->m_spinBox->setSpecialValueText(d->m_specialValueText);
+ if (d->m_maximumValue && d->m_maximumValue)
+ d->m_spinBox->setRange(d->m_minimumValue.value(), d->m_maximumValue.value());
+ d->m_spinBox->setValue(value()); // Must happen after setRange()!
+ addLabeledItem(builder, d->m_spinBox);
+
+ if (isAutoApply()) {
+ connect(d->m_spinBox.data(), QOverload<double>::of(&QDoubleSpinBox::valueChanged),
+ this, [this] { setValue(d->m_spinBox->value()); });
+ }
+}
+
+QVariant DoubleAspect::volatileValue() const
+{
+ QTC_CHECK(!isAutoApply());
+ QTC_ASSERT(d->m_spinBox, return {});
+ return d->m_spinBox->value();
+}
+
+void DoubleAspect::setVolatileValue(const QVariant &val)
+{
+ QTC_CHECK(!isAutoApply());
+ if (d->m_spinBox)
+ d->m_spinBox->setValue(val.toDouble());
+}
+
+double DoubleAspect::value() const
+{
+ return BaseAspect::value().toDouble();
+}
+
+void DoubleAspect::setValue(double value)
+{
+ BaseAspect::setValue(value);
+}
+
+void DoubleAspect::setRange(double min, double max)
+{
+ d->m_minimumValue = min;
+ d->m_maximumValue = max;
+}
+
+void DoubleAspect::setPrefix(const QString &prefix)
+{
+ d->m_prefix = prefix;
+}
+
+void DoubleAspect::setSuffix(const QString &suffix)
+{
+ d->m_suffix = suffix;
+}
+
+void DoubleAspect::setDefaultValue(double defaultValue)
+{
+ BaseAspect::setDefaultValue(defaultValue);
+}
+
+void DoubleAspect::setSpecialValueText(const QString &specialText)
+{
+ d->m_specialValueText = specialText;
+}
+
+void DoubleAspect::setSingleStep(double step)
+{
+ d->m_singleStep = step;
+}
+
+
/*!
\class Utils::BaseTristateAspect
\inmodule QtCreator
@@ -1363,7 +1921,6 @@ TriStateAspect::TriStateAspect(const QString onString, const QString &offString,
const QString &defaultString)
{
setDisplayStyle(DisplayStyle::ComboBox);
- setValue(TriState::Default);
setDefaultValue(TriState::Default);
addOption(onString);
addOption(offString);
@@ -1435,6 +1992,88 @@ void StringListAspect::setValue(const QStringList &value)
BaseAspect::setValue(value);
}
+void StringListAspect::appendValue(const QString &s, bool allowDuplicates)
+{
+ QStringList val = value();
+ if (allowDuplicates || !val.contains(s))
+ val.append(s);
+ setValue(val);
+}
+
+void StringListAspect::removeValue(const QString &s)
+{
+ QStringList val = value();
+ val.removeAll(s);
+ setValue(val);
+}
+
+void StringListAspect::appendValues(const QStringList &values, bool allowDuplicates)
+{
+ QStringList val = value();
+ for (const QString &s : values) {
+ if (allowDuplicates || !val.contains(s))
+ val.append(s);
+ }
+ setValue(val);
+}
+
+void StringListAspect::removeValues(const QStringList &values)
+{
+ QStringList val = value();
+ for (const QString &s : values)
+ val.removeAll(s);
+ setValue(val);
+}
+
+/*!
+ \class Utils::IntegerListAspect
+ \inmodule QtCreator
+
+ \brief A string list aspect represents a property of some object
+ that is a list of strings.
+*/
+
+IntegersAspect::IntegersAspect()
+{
+ setDefaultValue({});
+}
+
+/*!
+ \reimp
+*/
+IntegersAspect::~IntegersAspect() = default;
+
+/*!
+ \reimp
+*/
+void IntegersAspect::addToLayout(LayoutBuilder &builder)
+{
+ Q_UNUSED(builder)
+ // TODO - when needed.
+}
+
+void IntegersAspect::emitChangedValue()
+{
+ emit valueChanged(value());
+}
+
+QList<int> IntegersAspect::value() const
+{
+ return Utils::transform(BaseAspect::value().toList(),
+ [](QVariant v) { return v.toInt(); });
+}
+
+void IntegersAspect::setValue(const QList<int> &value)
+{
+ BaseAspect::setValue(Utils::transform(value, &QVariant::fromValue<int>));
+}
+
+void IntegersAspect::setDefaultValue(const QList<int> &value)
+{
+ BaseAspect::setDefaultValue(Utils::transform(value, &QVariant::fromValue<int>));
+}
+
+
/*!
\class Utils::TextDisplay
@@ -1471,9 +2110,12 @@ void TextDisplay::addToLayout(LayoutBuilder &builder)
d->m_label->setTextInteractionFlags(Qt::TextSelectableByMouse);
d->m_label->setElideMode(Qt::ElideNone);
d->m_label->setWordWrap(true);
+ // Do not use m_label->setVisible(isVisible()) unconditionally, it does not
+ // have a QWidget parent yet when used in a LayoutBuilder.
+ if (!isVisible())
+ d->m_label->setVisible(false);
}
builder.addItem(d->m_label.data());
- d->m_label->setVisible(isVisible());
}
/*!
@@ -1487,59 +2129,207 @@ void TextDisplay::setIconType(InfoLabel::InfoType t)
d->m_label->setType(t);
}
+void TextDisplay::setText(const QString &message)
+{
+ d->m_message = message;
+}
+
/*!
\class Utils::AspectContainer
\inmodule QtCreator
\brief The AspectContainer class wraps one or more aspects while providing
the interface of a single aspect.
+
+ Sub-aspects ownership can be declared using \a setOwnsSubAspects.
*/
-AspectContainer::AspectContainer()
- : d(new Internal::AspectContainerPrivate)
+namespace Internal {
+
+class AspectContainerPrivate
+{
+public:
+ QList<BaseAspect *> m_items; // Not owned
+ bool m_autoApply = true;
+ bool m_ownsSubAspects = false;
+ QStringList m_settingsGroup;
+};
+
+} // Internal
+
+AspectContainer::AspectContainer(QObject *parent)
+ : QObject(parent), d(new Internal::AspectContainerPrivate)
{}
/*!
\reimp
*/
-AspectContainer::~AspectContainer() = default;
+AspectContainer::~AspectContainer()
+{
+ if (d->m_ownsSubAspects)
+ qDeleteAll(d->m_items);
+}
/*!
\internal
*/
-void AspectContainer::addAspectHelper(BaseAspect *aspect)
+void AspectContainer::registerAspect(BaseAspect *aspect)
{
+ aspect->setAutoApply(d->m_autoApply);
d->m_items.append(aspect);
- connect(aspect, &BaseAspect::changed, this, &BaseAspect::changed);
}
-/*!
- Adds all visible sub-aspects to \a builder.
-*/
-void AspectContainer::addToLayout(LayoutBuilder &builder)
+void AspectContainer::registerAspects(const AspectContainer &aspects)
{
- for (BaseAspect *aspect : qAsConst(d->m_items)) {
- if (aspect->isVisible())
- aspect->addToLayout(builder);
- }
+ for (BaseAspect *aspect : qAsConst(aspects.d->m_items))
+ registerAspect(aspect);
}
/*!
- \reimp
+ Retrieves a BaseAspect with a given \a id, or nullptr if no such aspect is contained.
+
+ \sa BaseAspect.
*/
+BaseAspect *AspectContainer::aspect(Id id) const
+{
+ return Utils::findOrDefault(d->m_items, Utils::equal(&BaseAspect::id, id));
+}
+
+AspectContainer::const_iterator AspectContainer::begin() const
+{
+ return d->m_items.begin();
+}
+
+AspectContainer::const_iterator AspectContainer::end() const
+{
+ return d->m_items.end();
+}
+
+const QList<BaseAspect *> &AspectContainer::aspects() const
+{
+ return d->m_items;
+}
+
void AspectContainer::fromMap(const QVariantMap &map)
{
for (BaseAspect *aspect : qAsConst(d->m_items))
aspect->fromMap(map);
+
+ emit fromMapFinished();
+
}
-/*!
- \reimp
-*/
void AspectContainer::toMap(QVariantMap &map) const
{
for (BaseAspect *aspect : qAsConst(d->m_items))
aspect->toMap(map);
}
+void AspectContainer::readSettings(QSettings *settings)
+{
+ for (const QString &group : d->m_settingsGroup)
+ settings->beginGroup(group);
+
+ for (BaseAspect *aspect : qAsConst(d->m_items))
+ aspect->readSettings(settings);
+
+ for (int i = 0; i != d->m_settingsGroup.size(); ++i)
+ settings->endGroup();
+}
+
+void AspectContainer::writeSettings(QSettings *settings) const
+{
+ for (const QString &group : d->m_settingsGroup)
+ settings->beginGroup(group);
+
+ for (BaseAspect *aspect : qAsConst(d->m_items))
+ aspect->writeSettings(settings);
+
+ for (int i = 0; i != d->m_settingsGroup.size(); ++i)
+ settings->endGroup();
+}
+
+void AspectContainer::setSettingsGroup(const QString &groupKey)
+{
+ d->m_settingsGroup = QStringList{groupKey};
+}
+
+void AspectContainer::setSettingsGroups(const QString &groupKey, const QString &subGroupKey)
+{
+ d->m_settingsGroup = QStringList{groupKey, subGroupKey};
+}
+
+void AspectContainer::apply()
+{
+ for (BaseAspect *aspect : qAsConst(d->m_items))
+ aspect->apply();
+
+ emit applied();
+}
+
+void AspectContainer::cancel()
+{
+ for (BaseAspect *aspect : qAsConst(d->m_items))
+ aspect->cancel();
+}
+
+void AspectContainer::finish()
+{
+ for (BaseAspect *aspect : qAsConst(d->m_items))
+ aspect->finish();
+}
+
+void AspectContainer::reset()
+{
+ for (BaseAspect *aspect : qAsConst(d->m_items))
+ aspect->setValueQuietly(aspect->defaultValue());
+}
+
+void AspectContainer::setAutoApply(bool on)
+{
+ d->m_autoApply = on;
+ for (BaseAspect *aspect : qAsConst(d->m_items))
+ aspect->setAutoApply(on);
+}
+
+void AspectContainer::setOwnsSubAspects(bool on)
+{
+ d->m_ownsSubAspects = on;
+}
+
+bool AspectContainer::isDirty() const
+{
+ for (BaseAspect *aspect : qAsConst(d->m_items)) {
+ if (aspect->isDirty())
+ return true;
+ }
+ return false;
+}
+
+bool AspectContainer::equals(const AspectContainer &other) const
+{
+ // FIXME: Expensive, but should not really be needed in a fully aspectified world.
+ QVariantMap thisMap, thatMap;
+ toMap(thisMap);
+ other.toMap(thatMap);
+ return thisMap == thatMap;
+}
+
+void AspectContainer::copyFrom(const AspectContainer &other)
+{
+ QVariantMap map;
+ other.toMap(map);
+ fromMap(map);
+}
+
+void AspectContainer::forEachAspect(const std::function<void(BaseAspect *)> &run) const
+{
+ for (BaseAspect *aspect : qAsConst(d->m_items)) {
+ if (auto container = dynamic_cast<AspectContainer *>(aspect))
+ container->forEachAspect(run);
+ else
+ run(aspect);
+ }
+}
+
} // namespace Utils
diff --git a/src/libs/utils/aspects.h b/src/libs/utils/aspects.h
index 0b076340e0..799aadaac2 100644
--- a/src/libs/utils/aspects.h
+++ b/src/libs/utils/aspects.h
@@ -35,15 +35,23 @@
#include <functional>
#include <memory>
+QT_BEGIN_NAMESPACE
+class QAction;
+class QGroupBox;
+class QSettings;
+QT_END_NAMESPACE
+
namespace Utils {
-class BaseAspects;
+class AspectContainer;
+class BoolAspect;
class LayoutBuilder;
namespace Internal {
class AspectContainerPrivate;
class BaseAspectPrivate;
class BoolAspectPrivate;
+class DoubleAspectPrivate;
class IntegerAspectPrivate;
class MultiSelectionAspectPrivate;
class SelectionAspectPrivate;
@@ -83,31 +91,62 @@ public:
bool isVisible() const;
void setVisible(bool visible);
+ bool isAutoApply() const;
+ void setAutoApply(bool on);
+
+ bool isEnabled() const;
void setEnabled(bool enabled);
+ void setEnabler(BoolAspect *checker);
+ bool isReadOnly() const;
void setReadOnly(bool enabled);
+ void setSpan(int x, int y = 1);
+
QString labelText() const;
void setLabelText(const QString &labelText);
void setLabelPixmap(const QPixmap &labelPixmap);
+ void setIcon(const QIcon &labelIcon);
using ConfigWidgetCreator = std::function<QWidget *()>;
void setConfigWidgetCreator(const ConfigWidgetCreator &configWidgetCreator);
QWidget *createConfigWidget() const;
+ virtual QAction *action();
+
virtual void fromMap(const QVariantMap &map);
virtual void toMap(QVariantMap &map) const;
virtual void toActiveMap(QVariantMap &map) const { toMap(map); }
- virtual void acquaintSiblings(const BaseAspects &);
+ virtual void acquaintSiblings(const AspectContainer &);
virtual void addToLayout(LayoutBuilder &builder);
+ virtual QVariant volatileValue() const;
+ virtual void setVolatileValue(const QVariant &val);
+ virtual void emitChangedValue() {}
+
+ virtual void readSettings(const QSettings *settings);
+ virtual void writeSettings(QSettings *settings) const;
+
+ using SavedValueTransformation = std::function<QVariant(const QVariant &)>;
+ void setFromSettingsTransformation(const SavedValueTransformation &transform);
+ void setToSettingsTransformation(const SavedValueTransformation &transform);
+ QVariant toSettingsValue(const QVariant &val) const;
+ QVariant fromSettingsValue(const QVariant &val) const;
+
+ virtual void apply();
+ virtual void cancel();
+ virtual void finish();
+ bool isDirty() const;
+ bool hasAction() const;
+
signals:
void changed();
protected:
QLabel *label() const;
void setupLabel();
+ void addLabeledItem(LayoutBuilder &builder, QWidget *widget);
template <class Widget, typename ...Args>
Widget *createSubWidget(Args && ...args) {
@@ -117,61 +156,13 @@ protected:
}
void registerSubWidget(QWidget *widget);
- virtual void setVisibleDynamic(bool visible) { Q_UNUSED(visible) } // TODO: Better name? Merge with setVisible() somehow?
- void saveToMap(QVariantMap &data, const QVariant &value,
- const QVariant &defaultValue, const QString &keyExtension = {}) const;
+ static void saveToMap(QVariantMap &data, const QVariant &value,
+ const QVariant &defaultValue, const QString &key);
private:
std::unique_ptr<Internal::BaseAspectPrivate> d;
};
-class QTCREATOR_UTILS_EXPORT BaseAspects
-{
- BaseAspects(const BaseAspects &) = delete;
- BaseAspects &operator=(const BaseAspects &) = delete;
-
-public:
- using const_iterator = QList<BaseAspect *>::const_iterator;
- using value_type = QList<BaseAspect *>::value_type;
-
- BaseAspects();
- ~BaseAspects();
-
- template <class Aspect, typename ...Args>
- Aspect *addAspect(Args && ...args)
- {
- auto aspect = new Aspect(args...);
- m_aspects.append(aspect);
- return aspect;
- }
-
- BaseAspect *aspect(Utils::Id id) const;
-
- template <typename T> T *aspect() const
- {
- for (BaseAspect *aspect : m_aspects)
- if (T *result = qobject_cast<T *>(aspect))
- return result;
- return nullptr;
- }
-
- template <typename T> T *aspect(Utils::Id id) const
- {
- return qobject_cast<T*>(aspect(id));
- }
-
- void fromMap(const QVariantMap &map) const;
- void toMap(QVariantMap &map) const;
-
- const_iterator begin() const { return m_aspects.begin(); }
- const_iterator end() const { return m_aspects.end(); }
-
- void append(BaseAspect *const &aspect) { m_aspects.append(aspect); }
-
-private:
- QList<BaseAspect *> m_aspects;
-};
-
class QTCREATOR_UTILS_EXPORT BoolAspect : public BaseAspect
{
Q_OBJECT
@@ -182,12 +173,25 @@ public:
void addToLayout(LayoutBuilder &builder) override;
+ QAction *action() override;
+
+ QVariant volatileValue() const override;
+ void setVolatileValue(const QVariant &val) override;
+ void emitChangedValue() override;
+
bool value() const;
void setValue(bool val);
+ void setDefaultValue(bool val);
enum class LabelPlacement { AtCheckBox, AtCheckBoxWithoutDummyLabel, InExtraLabel };
void setLabel(const QString &labelText,
LabelPlacement labelPlacement = LabelPlacement::InExtraLabel);
+ void setLabelPlacement(LabelPlacement labelPlacement);
+ void setHandlesGroup(QGroupBox *box);
+
+signals:
+ void valueChanged(bool newValue);
+ void volatileValueChanged(bool newValue);
private:
std::unique_ptr<Internal::BoolAspectPrivate> d;
@@ -202,19 +206,43 @@ public:
~SelectionAspect() override;
void addToLayout(LayoutBuilder &builder) override;
+ QVariant volatileValue() const override;
+ void setVolatileValue(const QVariant &val) override;
+ void finish() override;
int value() const;
void setValue(int val);
+ void setStringValue(const QString &val);
+ void setDefaultValue(int val);
+ void setDefaultValue(const QString &val);
QString stringValue() const;
+ QVariant itemValue() const;
enum class DisplayStyle { RadioButtons, ComboBox };
void setDisplayStyle(DisplayStyle style);
+ class Option
+ {
+ public:
+ Option(const QString &displayName, const QString &toolTip, const QVariant &itemData)
+ : displayName(displayName), tooltip(toolTip), itemData(itemData)
+ {}
+ QString displayName;
+ QString tooltip;
+ QVariant itemData;
+ bool enabled = true;
+ };
+
void addOption(const QString &displayName, const QString &toolTip = {});
+ void addOption(const Option &option);
+ int indexForDisplay(const QString &displayName) const;
+ QString displayForIndex(int index) const;
+ int indexForItemValue(const QVariant &value) const;
+ QVariant itemValueForIndex(int index) const;
-protected:
- void setVisibleDynamic(bool visible) override;
+signals:
+ void volatileValueChanged(int newValue);
private:
std::unique_ptr<Internal::SelectionAspectPrivate> d;
@@ -239,9 +267,6 @@ public:
QStringList allValues() const;
void setAllValues(const QStringList &val);
-protected:
- void setVisibleDynamic(bool visible) override;
-
private:
std::unique_ptr<Internal::MultiSelectionAspectPrivate> d;
};
@@ -256,11 +281,16 @@ public:
void addToLayout(LayoutBuilder &builder) override;
+ QVariant volatileValue() const override;
+ void setVolatileValue(const QVariant &val) override;
+ void emitChangedValue() override;
+
// Hook between UI and StringAspect:
using ValueAcceptor = std::function<Utils::optional<QString>(const QString &, const QString &)>;
void setValueAcceptor(ValueAcceptor &&acceptor);
QString value() const;
void setValue(const QString &val);
+ void setDefaultValue(const QString &val);
void setShowToolTipOnLabel(bool show);
@@ -272,7 +302,10 @@ public:
void setEnvironment(const Utils::Environment &env);
void setBaseFileName(const Utils::FilePath &baseFileName);
void setUndoRedoEnabled(bool readOnly);
+ void setAcceptRichText(bool acceptRichText);
void setMacroExpanderProvider(const Utils::MacroExpanderProvider &expanderProvider);
+ void setUseGlobalMacroExpander();
+ void setUseResetButton();
void setValidationFunction(const Utils::FancyLineEdit::ValidationFunction &validator);
void setOpenTerminalHandler(const std::function<void()> &openTerminal);
@@ -300,8 +333,11 @@ public:
Utils::FilePath filePath() const;
void setFilePath(const Utils::FilePath &value);
+ PathChooser *pathChooser() const; // Avoid to use.
+
signals:
void checkedChanged();
+ void valueChanged(const QString &newValue);
protected:
void update();
@@ -319,8 +355,12 @@ public:
void addToLayout(LayoutBuilder &builder) override;
+ QVariant volatileValue() const override;
+ void setVolatileValue(const QVariant &val) override;
+
qint64 value() const;
void setValue(qint64 val);
+ void setDefaultValue(qint64 defaultValue);
void setRange(qint64 min, qint64 max);
void setLabel(const QString &label); // FIXME: Use setLabelText
@@ -328,12 +368,40 @@ public:
void setSuffix(const QString &suffix);
void setDisplayIntegerBase(int base);
void setDisplayScaleFactor(qint64 factor);
- void setDefaultValue(qint64 defaultValue);
+ void setSpecialValueText(const QString &specialText);
+ void setSingleStep(qint64 step);
private:
std::unique_ptr<Internal::IntegerAspectPrivate> d;
};
+class QTCREATOR_UTILS_EXPORT DoubleAspect : public BaseAspect
+{
+ Q_OBJECT
+
+public:
+ DoubleAspect();
+ ~DoubleAspect() override;
+
+ void addToLayout(LayoutBuilder &builder) override;
+
+ QVariant volatileValue() const override;
+ void setVolatileValue(const QVariant &val) override;
+
+ double value() const;
+ void setValue(double val);
+ void setDefaultValue(double defaultValue);
+
+ void setRange(double min, double max);
+ void setPrefix(const QString &prefix);
+ void setSuffix(const QString &suffix);
+ void setSpecialValueText(const QString &specialText);
+ void setSingleStep(double step);
+
+private:
+ std::unique_ptr<Internal::DoubleAspectPrivate> d;
+};
+
class QTCREATOR_UTILS_EXPORT TriState
{
enum Value { EnabledValue, DisabledValue, DefaultValue };
@@ -383,10 +451,34 @@ public:
QStringList value() const;
void setValue(const QStringList &val);
+ void appendValue(const QString &value, bool allowDuplicates = true);
+ void removeValue(const QString &value);
+ void appendValues(const QStringList &values, bool allowDuplicates = true);
+ void removeValues(const QStringList &values);
+
private:
std::unique_ptr<Internal::StringListAspectPrivate> d;
};
+class QTCREATOR_UTILS_EXPORT IntegersAspect : public BaseAspect
+{
+ Q_OBJECT
+
+public:
+ IntegersAspect();
+ ~IntegersAspect() override;
+
+ void addToLayout(LayoutBuilder &builder) override;
+ void emitChangedValue() override;
+
+ QList<int> value() const;
+ void setValue(const QList<int> &value);
+ void setDefaultValue(const QList<int> &value);
+
+signals:
+ void valueChanged(const QList<int> &values);
+};
+
class QTCREATOR_UTILS_EXPORT TextDisplay : public BaseAspect
{
Q_OBJECT
@@ -399,35 +491,84 @@ public:
void addToLayout(LayoutBuilder &builder) override;
void setIconType(Utils::InfoLabel::InfoType t);
+ void setText(const QString &message);
private:
std::unique_ptr<Internal::TextDisplayPrivate> d;
};
-class QTCREATOR_UTILS_EXPORT AspectContainer : public BaseAspect
+class QTCREATOR_UTILS_EXPORT AspectContainer : public QObject
{
Q_OBJECT
public:
- AspectContainer();
- ~AspectContainer() override;
+ AspectContainer(QObject *parent = nullptr);
+ ~AspectContainer();
+
+ AspectContainer(const AspectContainer &) = delete;
+ AspectContainer &operator=(const AspectContainer &) = delete;
+
+ void registerAspect(BaseAspect *aspect);
+ void registerAspects(const AspectContainer &aspects);
template <class Aspect, typename ...Args>
Aspect *addAspect(Args && ...args)
{
auto aspect = new Aspect(args...);
- addAspectHelper(aspect);
+ registerAspect(aspect);
return aspect;
}
- void addToLayout(LayoutBuilder &builder) override;
+ void fromMap(const QVariantMap &map);
+ void toMap(QVariantMap &map) const;
- void fromMap(const QVariantMap &map) override;
- void toMap(QVariantMap &map) const override;
+ void readSettings(QSettings *settings);
+ void writeSettings(QSettings *settings) const;
-private:
- void addAspectHelper(BaseAspect *aspect);
+ void setSettingsGroup(const QString &groupKey);
+ void setSettingsGroups(const QString &groupKey, const QString &subGroupKey);
+
+ void apply();
+ void cancel();
+ void finish();
+
+ void reset();
+ bool equals(const AspectContainer &other) const;
+ void copyFrom(const AspectContainer &other);
+ void setAutoApply(bool on);
+ void setOwnsSubAspects(bool on);
+ bool isDirty() const;
+
+ template <typename T> T *aspect() const
+ {
+ for (BaseAspect *aspect : aspects())
+ if (T *result = qobject_cast<T *>(aspect))
+ return result;
+ return nullptr;
+ }
+
+ BaseAspect *aspect(Utils::Id id) const;
+ template <typename T> T *aspect(Utils::Id id) const
+ {
+ return qobject_cast<T*>(aspect(id));
+ }
+
+ void forEachAspect(const std::function<void(BaseAspect *)> &run) const;
+
+ const QList<BaseAspect *> &aspects() const;
+
+ using const_iterator = QList<BaseAspect *>::const_iterator;
+ using value_type = QList<BaseAspect *>::value_type;
+
+ const_iterator begin() const;
+ const_iterator end() const;
+
+signals:
+ void applied();
+ void fromMapFinished();
+
+private:
std::unique_ptr<Internal::AspectContainerPrivate> d;
};
diff --git a/src/libs/utils/buildablehelperlibrary.cpp b/src/libs/utils/buildablehelperlibrary.cpp
index fdebca957e..ae288f22e9 100644
--- a/src/libs/utils/buildablehelperlibrary.cpp
+++ b/src/libs/utils/buildablehelperlibrary.cpp
@@ -25,7 +25,7 @@
#include "buildablehelperlibrary.h"
#include "hostosinfo.h"
-#include "synchronousprocess.h"
+#include "qtcprocess.h"
#include <QDateTime>
#include <QDebug>
@@ -46,10 +46,11 @@ QString BuildableHelperLibrary::qtChooserToQmakePath(const QString &path)
const QString toolDir = QLatin1String("QTTOOLDIR=\"");
SynchronousProcess proc;
proc.setTimeoutS(1);
- SynchronousProcessResponse response = proc.runBlocking({path, {"-print-env"}});
- if (response.result != SynchronousProcessResponse::Finished)
+ proc.setCommand({path, {"-print-env"}});
+ proc.runBlocking();
+ if (proc.result() != QtcProcess::Finished)
return QString();
- const QString output = response.stdOut();
+ const QString output = proc.stdOut();
int pos = output.indexOf(toolDir);
if (pos == -1)
return QString();
@@ -130,13 +131,14 @@ QString BuildableHelperLibrary::qtVersionForQMake(const QString &qmakePath)
SynchronousProcess qmake;
qmake.setTimeoutS(5);
- SynchronousProcessResponse response = qmake.runBlocking({qmakePath, {"--version"}});
- if (response.result != SynchronousProcessResponse::Finished) {
- qWarning() << response.exitMessage(qmakePath, 5);
+ qmake.setCommand({qmakePath, {"--version"}});
+ qmake.runBlocking();
+ if (qmake.result() != QtcProcess::Finished) {
+ qWarning() << qmake.exitMessage();
return QString();
}
- const QString output = response.allOutput();
+ const QString output = qmake.allOutput();
static const QRegularExpression regexp("(QMake version:?)[\\s]*([\\d.]*)",
QRegularExpression::CaseInsensitiveOption);
const QRegularExpressionMatch match = regexp.match(output);
@@ -225,14 +227,12 @@ bool BuildableHelperLibrary::copyFiles(const QString &sourcePath,
}
// Helper: Run a build process with merged stdout/stderr
-static inline bool runBuildProcessI(QProcess &proc,
- const FilePath &binary,
- const QStringList &args,
+static inline bool runBuildProcessI(QtcProcess &proc,
int timeoutS,
bool ignoreNonNullExitCode,
QString *output, QString *errorMessage)
{
- proc.start(binary.toString(), args);
+ proc.start();
if (!proc.waitForStarted()) {
*errorMessage = QCoreApplication::translate("ProjectExplorer::BuildableHelperLibrary",
"Cannot start process: %1").
@@ -242,11 +242,11 @@ static inline bool runBuildProcessI(QProcess &proc,
// Read stdout/err and check for timeouts
QByteArray stdOut;
QByteArray stdErr;
- if (!SynchronousProcess::readDataFromProcess(proc, timeoutS, &stdOut, &stdErr, false)) {
+ if (!proc.readDataFromProcess(timeoutS, &stdOut, &stdErr, false)) {
*errorMessage = QCoreApplication::translate("ProjectExplorer::BuildableHelperLibrary",
"Timeout after %1 s.").
arg(timeoutS);
- SynchronousProcess::stopProcess(proc);
+ proc.stopProcess();
return false;
}
if (proc.exitStatus() != QProcess::NormalExit) {
@@ -266,14 +266,15 @@ static inline bool runBuildProcessI(QProcess &proc,
}
// Run a build process with merged stdout/stderr and qWarn about errors.
-static bool runBuildProcess(QProcess &proc,
+static bool runBuildProcess(QtcProcess &proc,
const FilePath &binary,
const QStringList &args,
int timeoutS,
bool ignoreNonNullExitCode,
QString *output, QString *errorMessage)
{
- const bool rc = runBuildProcessI(proc, binary, args, timeoutS, ignoreNonNullExitCode, output, errorMessage);
+ proc.setCommand({binary, args});
+ const bool rc = runBuildProcessI(proc, timeoutS, ignoreNonNullExitCode, output, errorMessage);
if (!rc) {
// Fail - reformat error.
QString cmd = binary.toString();
@@ -296,8 +297,8 @@ bool BuildableHelperLibrary::buildHelper(const BuildHelperArguments &arguments,
{
const QChar newline = QLatin1Char('\n');
// Setup process
- QProcess proc;
- proc.setEnvironment(arguments.environment.toStringList());
+ QtcProcess proc;
+ proc.setEnvironment(arguments.environment);
proc.setWorkingDirectory(arguments.directory);
proc.setProcessChannelMode(QProcess::MergedChannels);
diff --git a/src/libs/utils/commandline.cpp b/src/libs/utils/commandline.cpp
new file mode 100644
index 0000000000..3ae7984275
--- /dev/null
+++ b/src/libs/utils/commandline.cpp
@@ -0,0 +1,1482 @@
+/****************************************************************************
+**
+** 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 "commandline.h"
+
+#include "environment.h"
+#include "qtcassert.h"
+#include "stringutils.h"
+
+#include <QDir>
+#include <QRegularExpression>
+#include <QStack>
+
+
+// The main state of the Unix shell parser
+enum MxQuoting { MxBasic, MxSingleQuote, MxDoubleQuote, MxParen, MxSubst, MxGroup, MxMath };
+
+struct MxState
+{
+ MxQuoting current;
+ // Bizarrely enough, double quoting has an impact on the behavior of some
+ // complex expressions within the quoted string.
+ bool dquote;
+};
+QT_BEGIN_NAMESPACE
+Q_DECLARE_TYPEINFO(MxState, Q_PRIMITIVE_TYPE);
+QT_END_NAMESPACE
+
+// Pushed state for the case where a $(()) expansion turns out bogus
+struct MxSave
+{
+ QString str;
+ int pos, varPos;
+};
+QT_BEGIN_NAMESPACE
+Q_DECLARE_TYPEINFO(MxSave, Q_MOVABLE_TYPE);
+QT_END_NAMESPACE
+
+namespace Utils {
+
+/*!
+ \class Utils::ProcessArgs
+
+ \brief The ProcessArgs class provides functionality for dealing with
+ shell-quoted process arguments.
+*/
+
+inline static bool isMetaCharWin(ushort c)
+{
+ static const uchar iqm[] = {
+ 0x00, 0x00, 0x00, 0x00, 0x40, 0x03, 0x00, 0x50,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10
+ }; // &()<>|
+
+ return (c < sizeof(iqm) * 8) && (iqm[c / 8] & (1 << (c & 7)));
+}
+
+static void envExpandWin(QString &args, const Environment *env, const QString *pwd)
+{
+ static const QString cdName = QLatin1String("CD");
+ int off = 0;
+ next:
+ for (int prev = -1, that;
+ (that = args.indexOf(QLatin1Char('%'), off)) >= 0;
+ prev = that, off = that + 1) {
+ if (prev >= 0) {
+ const QString var = args.mid(prev + 1, that - prev - 1).toUpper();
+ const QString val = (var == cdName && pwd && !pwd->isEmpty())
+ ? QDir::toNativeSeparators(*pwd) : env->expandedValueForKey(var);
+ if (!val.isEmpty()) { // Empty values are impossible, so this is an existence check
+ args.replace(prev, that - prev + 1, val);
+ off = prev + val.length();
+ goto next;
+ }
+ }
+ }
+}
+
+static ProcessArgs prepareArgsWin(const QString &_args, ProcessArgs::SplitError *err,
+ const Environment *env, const QString *pwd)
+{
+ QString args(_args);
+
+ if (env) {
+ envExpandWin(args, env, pwd);
+ } else {
+ if (args.indexOf(QLatin1Char('%')) >= 0) {
+ if (err)
+ *err = ProcessArgs::FoundMeta;
+ return ProcessArgs::createWindowsArgs(QString());
+ }
+ }
+
+ if (!args.isEmpty() && args.unicode()[0].unicode() == '@')
+ args.remove(0, 1);
+
+ for (int p = 0; p < args.length(); p++) {
+ ushort c = args.unicode()[p].unicode();
+ if (c == '^') {
+ args.remove(p, 1);
+ } else if (c == '"') {
+ do {
+ if (++p == args.length())
+ break; // For cmd, this is no error.
+ } while (args.unicode()[p].unicode() != '"');
+ } else if (isMetaCharWin(c)) {
+ if (err)
+ *err = ProcessArgs::FoundMeta;
+ return ProcessArgs::createWindowsArgs(QString());
+ }
+ }
+
+ if (err)
+ *err = ProcessArgs::SplitOk;
+ return ProcessArgs::createWindowsArgs(args);
+}
+
+inline static bool isWhiteSpaceWin(ushort c)
+{
+ return c == ' ' || c == '\t';
+}
+
+static QStringList doSplitArgsWin(const QString &args, ProcessArgs::SplitError *err)
+{
+ QStringList ret;
+
+ if (err)
+ *err = ProcessArgs::SplitOk;
+
+ int p = 0;
+ const int length = args.length();
+ forever {
+ forever {
+ if (p == length)
+ return ret;
+ if (!isWhiteSpaceWin(args.unicode()[p].unicode()))
+ break;
+ ++p;
+ }
+
+ QString arg;
+ bool inquote = false;
+ forever {
+ bool copy = true; // copy this char
+ int bslashes = 0; // number of preceding backslashes to insert
+ while (p < length && args.unicode()[p] == QLatin1Char('\\')) {
+ ++p;
+ ++bslashes;
+ }
+ if (p < length && args.unicode()[p] == QLatin1Char('"')) {
+ if (!(bslashes & 1)) {
+ // Even number of backslashes, so the quote is not escaped.
+ if (inquote) {
+ if (p + 1 < length && args.unicode()[p + 1] == QLatin1Char('"')) {
+ // This is not documented on MSDN.
+ // Two consecutive quotes make a literal quote. Brain damage:
+ // this still closes the quoting, so a 3rd quote is required,
+ // which makes the runtime's quoting run out of sync with the
+ // shell's one unless the 2nd quote is escaped.
+ ++p;
+ } else {
+ // Closing quote
+ copy = false;
+ }
+ inquote = false;
+ } else {
+ // Opening quote
+ copy = false;
+ inquote = true;
+ }
+ }
+ bslashes >>= 1;
+ }
+
+ while (--bslashes >= 0)
+ arg.append(QLatin1Char('\\'));
+
+ if (p == length || (!inquote && isWhiteSpaceWin(args.unicode()[p].unicode()))) {
+ ret.append(arg);
+ if (inquote) {
+ if (err)
+ *err = ProcessArgs::BadQuoting;
+ return QStringList();
+ }
+ break;
+ }
+
+ if (copy)
+ arg.append(args.unicode()[p]);
+ ++p;
+ }
+ }
+ //not reached
+}
+
+/*!
+ Splits \a _args according to system shell word splitting and quoting rules.
+
+ \section1 Unix
+
+ The behavior is based on the POSIX shell and bash:
+ \list
+ \li Whitespace splits tokens.
+ \li The backslash quotes the following character.
+ \li A string enclosed in single quotes is not split. No shell meta
+ characters are interpreted.
+ \li A string enclosed in double quotes is not split. Within the string,
+ the backslash quotes shell meta characters - if it is followed
+ by a "meaningless" character, the backslash is output verbatim.
+ \endlist
+ If \a abortOnMeta is \c false, only the splitting and quoting rules apply,
+ while other meta characters (substitutions, redirections, etc.) are ignored.
+ If \a abortOnMeta is \c true, encounters of unhandled meta characters are
+ treated as errors.
+
+ If \a err is not NULL, stores a status code at the pointer target. For more
+ information, see \l SplitError.
+
+ If \env is not NULL, performs variable substitution with the
+ given environment.
+
+ Returns a list of unquoted words or an empty list if an error occurred.
+
+ \section1 Windows
+
+ The behavior is defined by the Microsoft C runtime:
+ \list
+ \li Whitespace splits tokens.
+ \li A string enclosed in double quotes is not split.
+ \list
+ \li 3N double quotes within a quoted string yield N literal quotes.
+ This is not documented on MSDN.
+ \endlist
+ \li Backslashes have special semantics if they are followed by a double quote:
+ \list
+ \li 2N backslashes + double quote => N backslashes and begin/end quoting
+ \li 2N+1 backslashes + double quote => N backslashes + literal quote
+ \endlist
+ \endlist
+ Qt and many other implementations comply with this standard, but many do not.
+
+ If \a abortOnMeta is \c true, cmd shell semantics are applied before
+ proceeding with word splitting:
+ \list
+ \li Cmd ignores \e all special chars between double quotes.
+ Note that the quotes are \e not removed at this stage - the
+ tokenization rules described above still apply.
+ \li The \c circumflex is the escape char for everything including itself.
+ \endlist
+ As the quoting levels are independent from each other and have different
+ semantics, you need a command line like \c{"foo "\^"" bar"} to get
+ \c{foo " bar}.
+ */
+
+
+static QStringList splitArgsWin(const QString &_args, bool abortOnMeta,
+ ProcessArgs::SplitError *err,
+ const Environment *env, const QString *pwd)
+{
+ if (abortOnMeta) {
+ ProcessArgs::SplitError perr;
+ if (!err)
+ err = &perr;
+ QString args = prepareArgsWin(_args, &perr, env, pwd).toWindowsArgs();
+ if (*err != ProcessArgs::SplitOk)
+ return QStringList();
+ return doSplitArgsWin(args, err);
+ } else {
+ QString args = _args;
+ if (env)
+ envExpandWin(args, env, pwd);
+ return doSplitArgsWin(args, err);
+ }
+}
+
+
+static bool isMetaUnix(QChar cUnicode)
+{
+ static const uchar iqm[] = {
+ 0x00, 0x00, 0x00, 0x00, 0xdc, 0x07, 0x00, 0xd8,
+ 0x00, 0x00, 0x00, 0x38, 0x01, 0x00, 0x00, 0x38
+ }; // \'"$`<>|;&(){}*?#[]
+
+ uint c = cUnicode.unicode();
+
+ return (c < sizeof(iqm) * 8) && (iqm[c / 8] & (1 << (c & 7)));
+}
+
+static QStringList splitArgsUnix(const QString &args, bool abortOnMeta,
+ ProcessArgs::SplitError *err,
+ const Environment *env, const QString *pwd)
+{
+ static const QString pwdName = QLatin1String("PWD");
+ QStringList ret;
+
+ for (int pos = 0; ; ) {
+ QChar c;
+ do {
+ if (pos >= args.length())
+ goto okret;
+ c = args.unicode()[pos++];
+ } while (c.isSpace());
+ QString cret;
+ bool hadWord = false;
+ if (c == QLatin1Char('~')) {
+ if (pos >= args.length()
+ || args.unicode()[pos].isSpace() || args.unicode()[pos] == QLatin1Char('/')) {
+ cret = QDir::homePath();
+ hadWord = true;
+ goto getc;
+ } else if (abortOnMeta) {
+ goto metaerr;
+ }
+ }
+ do {
+ if (c == QLatin1Char('\'')) {
+ int spos = pos;
+ do {
+ if (pos >= args.length())
+ goto quoteerr;
+ c = args.unicode()[pos++];
+ } while (c != QLatin1Char('\''));
+ cret += args.mid(spos, pos - spos - 1);
+ hadWord = true;
+ } else if (c == QLatin1Char('"')) {
+ for (;;) {
+ if (pos >= args.length())
+ goto quoteerr;
+ c = args.unicode()[pos++];
+ nextq:
+ if (c == QLatin1Char('"'))
+ break;
+ if (c == QLatin1Char('\\')) {
+ if (pos >= args.length())
+ goto quoteerr;
+ c = args.unicode()[pos++];
+ if (c != QLatin1Char('"') &&
+ c != QLatin1Char('\\') &&
+ !(abortOnMeta &&
+ (c == QLatin1Char('$') ||
+ c == QLatin1Char('`'))))
+ cret += QLatin1Char('\\');
+ } else if (c == QLatin1Char('$') && env) {
+ if (pos >= args.length())
+ goto quoteerr;
+ c = args.unicode()[pos++];
+ bool braced = false;
+ if (c == QLatin1Char('{')) {
+ if (pos >= args.length())
+ goto quoteerr;
+ c = args.unicode()[pos++];
+ braced = true;
+ }
+ QString var;
+ while (c.isLetterOrNumber() || c == QLatin1Char('_')) {
+ var += c;
+ if (pos >= args.length())
+ goto quoteerr;
+ c = args.unicode()[pos++];
+ }
+ if (var == pwdName && pwd && !pwd->isEmpty()) {
+ cret += *pwd;
+ } else {
+ Environment::const_iterator vit = env->constFind(var);
+ if (vit == env->constEnd()) {
+ if (abortOnMeta)
+ goto metaerr; // Assume this is a shell builtin
+ } else {
+ cret += env->expandedValueForKey(env->key(vit));
+ }
+ }
+ if (!braced)
+ goto nextq;
+ if (c != QLatin1Char('}')) {
+ if (abortOnMeta)
+ goto metaerr; // Assume this is a complex expansion
+ goto quoteerr; // Otherwise it's just garbage
+ }
+ continue;
+ } else if (abortOnMeta &&
+ (c == QLatin1Char('$') ||
+ c == QLatin1Char('`'))) {
+ goto metaerr;
+ }
+ cret += c;
+ }
+ hadWord = true;
+ } else if (c == QLatin1Char('$') && env) {
+ if (pos >= args.length())
+ goto quoteerr; // Bash just takes it verbatim, but whatever
+ c = args.unicode()[pos++];
+ bool braced = false;
+ if (c == QLatin1Char('{')) {
+ if (pos >= args.length())
+ goto quoteerr;
+ c = args.unicode()[pos++];
+ braced = true;
+ }
+ QString var;
+ while (c.isLetterOrNumber() || c == QLatin1Char('_')) {
+ var += c;
+ if (pos >= args.length()) {
+ if (braced)
+ goto quoteerr;
+ c = QLatin1Char(' ');
+ break;
+ }
+ c = args.unicode()[pos++];
+ }
+ QString val;
+ if (var == pwdName && pwd && !pwd->isEmpty()) {
+ val = *pwd;
+ } else {
+ Environment::const_iterator vit = env->constFind(var);
+ if (vit == env->constEnd()) {
+ if (abortOnMeta)
+ goto metaerr; // Assume this is a shell builtin
+ } else {
+ val = env->expandedValueForKey(env->key(vit));
+ }
+ }
+ for (int i = 0; i < val.length(); i++) {
+ const QChar cc = val.unicode()[i];
+ if (cc.unicode() == 9 || cc.unicode() == 10 || cc.unicode() == 32) {
+ if (hadWord) {
+ ret += cret;
+ cret.clear();
+ hadWord = false;
+ }
+ } else {
+ cret += cc;
+ hadWord = true;
+ }
+ }
+ if (!braced)
+ goto nextc;
+ if (c != QLatin1Char('}')) {
+ if (abortOnMeta)
+ goto metaerr; // Assume this is a complex expansion
+ goto quoteerr; // Otherwise it's just garbage
+ }
+ } else {
+ if (c == QLatin1Char('\\')) {
+ if (pos >= args.length())
+ goto quoteerr;
+ c = args.unicode()[pos++];
+ } else if (abortOnMeta && isMetaUnix(c)) {
+ goto metaerr;
+ }
+ cret += c;
+ hadWord = true;
+ }
+ getc:
+ if (pos >= args.length())
+ break;
+ c = args.unicode()[pos++];
+ nextc: ;
+ } while (!c.isSpace());
+ if (hadWord)
+ ret += cret;
+ }
+
+ okret:
+ if (err)
+ *err = ProcessArgs::SplitOk;
+ return ret;
+
+ quoteerr:
+ if (err)
+ *err = ProcessArgs::BadQuoting;
+ return QStringList();
+
+ metaerr:
+ if (err)
+ *err = ProcessArgs::FoundMeta;
+ return QStringList();
+}
+
+inline static bool isSpecialCharUnix(ushort c)
+{
+ // Chars that should be quoted (TM). This includes:
+ static const uchar iqm[] = {
+ 0xff, 0xff, 0xff, 0xff, 0xdf, 0x07, 0x00, 0xd8,
+ 0x00, 0x00, 0x00, 0x38, 0x01, 0x00, 0x00, 0x78
+ }; // 0-32 \'"$`<>|;&(){}*?#!~[]
+
+ return (c < sizeof(iqm) * 8) && (iqm[c / 8] & (1 << (c & 7)));
+}
+
+inline static bool hasSpecialCharsUnix(const QString &arg)
+{
+ for (int x = arg.length() - 1; x >= 0; --x)
+ if (isSpecialCharUnix(arg.unicode()[x].unicode()))
+ return true;
+ return false;
+}
+
+QStringList ProcessArgs::splitArgs(const QString &args, OsType osType,
+ bool abortOnMeta, ProcessArgs::SplitError *err,
+ const Environment *env, const QString *pwd)
+{
+ if (osType == OsTypeWindows)
+ return splitArgsWin(args, abortOnMeta, err, env, pwd);
+ else
+ return splitArgsUnix(args, abortOnMeta, err, env, pwd);
+}
+
+QString ProcessArgs::quoteArgUnix(const QString &arg)
+{
+ if (arg.isEmpty())
+ return QString::fromLatin1("''");
+
+ QString ret(arg);
+ if (hasSpecialCharsUnix(ret)) {
+ ret.replace(QLatin1Char('\''), QLatin1String("'\\''"));
+ ret.prepend(QLatin1Char('\''));
+ ret.append(QLatin1Char('\''));
+ }
+ return ret;
+}
+
+static bool isSpecialCharWin(ushort c)
+{
+ // Chars that should be quoted (TM). This includes:
+ // - control chars & space
+ // - the shell meta chars "&()<>^|
+ // - the potential separators ,;=
+ static const uchar iqm[] = {
+ 0xff, 0xff, 0xff, 0xff, 0x45, 0x13, 0x00, 0x78,
+ 0x00, 0x00, 0x00, 0x40, 0x00, 0x00, 0x00, 0x10
+ };
+
+ return (c < sizeof(iqm) * 8) && (iqm[c / 8] & (1 << (c & 7)));
+}
+
+static bool hasSpecialCharsWin(const QString &arg)
+{
+ for (int x = arg.length() - 1; x >= 0; --x)
+ if (isSpecialCharWin(arg.unicode()[x].unicode()))
+ return true;
+ return false;
+}
+
+static QString quoteArgWin(const QString &arg)
+{
+ if (arg.isEmpty())
+ return QString::fromLatin1("\"\"");
+
+ QString ret(arg);
+ if (hasSpecialCharsWin(ret)) {
+ // Quotes are escaped and their preceding backslashes are doubled.
+ // It's impossible to escape anything inside a quoted string on cmd
+ // level, so the outer quoting must be "suspended".
+ ret.replace(QRegularExpression(QLatin1String("(\\\\*)\"")), QLatin1String("\"\\1\\1\\^\"\""));
+ // The argument must not end with a \ since this would be interpreted
+ // as escaping the quote -- rather put the \ behind the quote: e.g.
+ // rather use "foo"\ than "foo\"
+ int i = ret.length();
+ while (i > 0 && ret.at(i - 1) == QLatin1Char('\\'))
+ --i;
+ ret.insert(i, QLatin1Char('"'));
+ ret.prepend(QLatin1Char('"'));
+ }
+ // FIXME: Without this, quoting is not foolproof. But it needs support in the process setup, etc.
+ //ret.replace('%', QLatin1String("%PERCENT_SIGN%"));
+ return ret;
+}
+
+ProcessArgs ProcessArgs::prepareArgs(const QString &cmd, SplitError *err, OsType osType,
+ const Environment *env, const QString *pwd, bool abortOnMeta)
+{
+ if (osType == OsTypeWindows)
+ return prepareArgsWin(cmd, err, env, pwd);
+ else
+ return createUnixArgs(splitArgs(cmd, osType, abortOnMeta, err, env, pwd));
+}
+
+QString ProcessArgs::quoteArg(const QString &arg, OsType osType)
+{
+ if (osType == OsTypeWindows)
+ return quoteArgWin(arg);
+ else
+ return quoteArgUnix(arg);
+}
+
+void ProcessArgs::addArg(QString *args, const QString &arg, OsType osType)
+{
+ if (!args->isEmpty())
+ *args += QLatin1Char(' ');
+ *args += quoteArg(arg, osType);
+}
+
+QString ProcessArgs::joinArgs(const QStringList &args, OsType osType)
+{
+ QString ret;
+ for (const QString &arg : args)
+ addArg(&ret, arg, osType);
+ return ret;
+}
+
+void ProcessArgs::addArgs(QString *args, const QString &inArgs)
+{
+ if (!inArgs.isEmpty()) {
+ if (!args->isEmpty())
+ *args += QLatin1Char(' ');
+ *args += inArgs;
+ }
+}
+
+void ProcessArgs::addArgs(QString *args, const QStringList &inArgs)
+{
+ for (const QString &arg : inArgs)
+ addArg(args, arg);
+}
+
+bool ProcessArgs::prepareCommand(const QString &command, const QString &arguments,
+ QString *outCmd, ProcessArgs *outArgs, OsType osType,
+ const Environment *env, const QString *pwd)
+{
+ ProcessArgs::SplitError err;
+ *outArgs = ProcessArgs::prepareArgs(arguments, &err, osType, env, pwd);
+ if (err == ProcessArgs::SplitOk) {
+ *outCmd = command;
+ } else {
+ if (osType == OsTypeWindows) {
+ *outCmd = QString::fromLatin1(qgetenv("COMSPEC"));
+ *outArgs = ProcessArgs::createWindowsArgs(QLatin1String("/v:off /s /c \"")
+ + quoteArg(QDir::toNativeSeparators(command)) + QLatin1Char(' ') + arguments
+ + QLatin1Char('"'));
+ } else {
+ if (err != ProcessArgs::FoundMeta)
+ return false;
+#if QT_VERSION >= QT_VERSION_CHECK(5, 10, 0)
+ *outCmd = qEnvironmentVariable("SHELL", "/bin/sh");
+#else
+ // for sdktool
+ *outCmd = qEnvironmentVariableIsSet("SHELL") ? QString::fromLocal8Bit(qgetenv("SHELL"))
+ : QString("/bin/sh");
+#endif
+ *outArgs = ProcessArgs::createUnixArgs(
+ QStringList({"-c", (quoteArg(command) + ' ' + arguments)}));
+ }
+ }
+ return true;
+}
+
+// This function assumes that the resulting string will be quoted.
+// That's irrelevant if it does not contain quotes itself.
+static int quoteArgInternalWin(QString &ret, int bslashes)
+{
+ // Quotes are escaped and their preceding backslashes are doubled.
+ // It's impossible to escape anything inside a quoted string on cmd
+ // level, so the outer quoting must be "suspended".
+ const QChar bs(QLatin1Char('\\')), dq(QLatin1Char('"'));
+ for (int p = 0; p < ret.length(); p++) {
+ if (ret.at(p) == bs) {
+ bslashes++;
+ } else {
+ if (ret.at(p) == dq) {
+ if (bslashes) {
+ ret.insert(p, QString(bslashes, bs));
+ p += bslashes;
+ }
+ ret.insert(p, QLatin1String("\"\\^\""));
+ p += 4;
+ }
+ bslashes = 0;
+ }
+ }
+ return bslashes;
+}
+
+
+// TODO: This documentation is relevant for end-users. Where to put it?
+/**
+ * Perform safe macro expansion (substitution) on a string for use
+ * in shell commands.
+ *
+ * \section Unix notes
+ *
+ * Explicitly supported shell constructs:
+ * \\ '' "" {} () $(()) ${} $() ``
+ *
+ * Implicitly supported shell constructs:
+ * (())
+ *
+ * Unsupported shell constructs that will cause problems:
+ * \list
+ * \li Shortened \c{case $v in pat)} syntax. Use \c{case $v in (pat)} instead.
+ * \li Bash-style \c{$""} and \c{$''} string quoting syntax.
+ * \endlist
+ *
+ * The rest of the shell (incl. bash) syntax is simply ignored,
+ * as it is not expected to cause problems.
+ *
+ * Security considerations:
+ * \list
+ * \li Backslash-escaping an expando is treated as a quoting error
+ * \li Do not put expandos into double quoted substitutions:
+ * \badcode
+ * "${VAR:-%{macro}}"
+ * \endcode
+ * \li Do not put expandos into command line arguments which are nested
+ * shell commands:
+ * \badcode
+ * sh -c 'foo \%{file}'
+ * \endcode
+ * \goodcode
+ * file=\%{file} sh -c 'foo "$file"'
+ * \endcode
+ * \endlist
+ *
+ * \section Windows notes
+ *
+ * All quoting syntax supported by splitArgs() is supported here as well.
+ * Additionally, command grouping via parentheses is recognized - note
+ * however, that the parser is much stricter about unquoted parentheses
+ * than cmd itself.
+ * The rest of the cmd syntax is simply ignored, as it is not expected
+ * to cause problems.
+ *
+ * Security considerations:
+ * \list
+ * \li Circumflex-escaping an expando is treated as a quoting error
+ * \li Closing double quotes right before expandos and opening double quotes
+ * right after expandos are treated as quoting errors
+ * \li Do not put expandos into nested commands:
+ * \badcode
+ * for /f "usebackq" \%v in (`foo \%{file}`) do \@echo \%v
+ * \endcode
+ * \li A macro's value must not contain anything which may be interpreted
+ * as an environment variable expansion. A solution is replacing any
+ * percent signs with a fixed string like \c{\%PERCENT_SIGN\%} and
+ * injecting \c{PERCENT_SIGN=\%} into the shell's environment.
+ * \li Enabling delayed environment variable expansion (cmd /v:on) should have
+ * no security implications, but may still wreak havoc due to the
+ * need for doubling circumflexes if any exclamation marks are present,
+ * and the need to circumflex-escape the exclamation marks themselves.
+ * \endlist
+ *
+ * \param cmd pointer to the string in which macros are expanded in-place
+ * \param mx pointer to a macro expander instance
+ * \return false if the string could not be parsed and therefore no safe
+ * substitution was possible
+ */
+bool ProcessArgs::expandMacros(QString *cmd, AbstractMacroExpander *mx, OsType osType)
+{
+ QString str = *cmd;
+ if (str.isEmpty())
+ return true;
+
+ QString rsts;
+ int varLen;
+ int varPos = 0;
+ if (!(varLen = mx->findMacro(str, &varPos, &rsts)))
+ return true;
+
+ int pos = 0;
+
+ if (osType == OsTypeWindows) {
+ enum { // cmd.exe parsing state
+ ShellBasic, // initial state
+ ShellQuoted, // double-quoted state => *no* other meta chars are interpreted
+ ShellEscaped // circumflex-escaped state => next char is not interpreted
+ } shellState = ShellBasic;
+ enum { // CommandLineToArgv() parsing state and some more
+ CrtBasic, // initial state
+ CrtNeedWord, // after empty expando; insert empty argument if whitespace follows
+ CrtInWord, // in non-whitespace
+ CrtClosed, // previous char closed the double-quoting
+ CrtHadQuote, // closed double-quoting after an expando
+ // The remaining two need to be numerically higher
+ CrtQuoted, // double-quoted state => spaces don't split tokens
+ CrtNeedQuote // expando opened quote; close if no expando follows
+ } crtState = CrtBasic;
+ int bslashes = 0; // previous chars were manual backslashes
+ int rbslashes = 0; // trailing backslashes in replacement
+
+ forever {
+ if (pos == varPos) {
+ if (shellState == ShellEscaped)
+ return false; // Circumflex'd quoted expando would be Bad (TM).
+ if ((shellState == ShellQuoted) != (crtState == CrtQuoted))
+ return false; // CRT quoting out of sync with shell quoting. Ahoy to Redmond.
+ rbslashes += bslashes;
+ bslashes = 0;
+ if (crtState < CrtQuoted) {
+ if (rsts.isEmpty()) {
+ if (crtState == CrtBasic) {
+ // Outside any quoting and the string is empty, so put
+ // a pair of quotes. Delaying that is just pedantry.
+ crtState = CrtNeedWord;
+ }
+ } else {
+ if (hasSpecialCharsWin(rsts)) {
+ if (crtState == CrtClosed) {
+ // Quoted expando right after closing quote. Can't do that.
+ return false;
+ }
+ int tbslashes = quoteArgInternalWin(rsts, 0);
+ rsts.prepend(QLatin1Char('"'));
+ if (rbslashes)
+ rsts.prepend(QString(rbslashes, QLatin1Char('\\')));
+ crtState = CrtNeedQuote;
+ rbslashes = tbslashes;
+ } else {
+ crtState = CrtInWord; // We know that this string contains no spaces.
+ // We know that this string contains no quotes,
+ // so the function won't make a mess.
+ rbslashes = quoteArgInternalWin(rsts, rbslashes);
+ }
+ }
+ } else {
+ rbslashes = quoteArgInternalWin(rsts, rbslashes);
+ }
+ str.replace(pos, varLen, rsts);
+ pos += rsts.length();
+ varPos = pos;
+ if (!(varLen = mx->findMacro(str, &varPos, &rsts))) {
+ // Don't leave immediately, as we may be in CrtNeedWord state which could
+ // be still resolved, or we may have inserted trailing backslashes.
+ varPos = INT_MAX;
+ }
+ continue;
+ }
+ if (crtState == CrtNeedQuote) {
+ if (rbslashes) {
+ str.insert(pos, QString(rbslashes, QLatin1Char('\\')));
+ pos += rbslashes;
+ varPos += rbslashes;
+ rbslashes = 0;
+ }
+ str.insert(pos, QLatin1Char('"'));
+ pos++;
+ varPos++;
+ crtState = CrtHadQuote;
+ }
+ ushort cc = str.unicode()[pos].unicode();
+ if (shellState == ShellBasic && cc == '^') {
+ shellState = ShellEscaped;
+ } else {
+ if (!cc || cc == ' ' || cc == '\t') {
+ if (crtState < CrtQuoted) {
+ if (crtState == CrtNeedWord) {
+ str.insert(pos, QLatin1String("\"\""));
+ pos += 2;
+ varPos += 2;
+ }
+ crtState = CrtBasic;
+ }
+ if (!cc)
+ break;
+ bslashes = 0;
+ rbslashes = 0;
+ } else {
+ if (cc == '\\') {
+ bslashes++;
+ if (crtState < CrtQuoted)
+ crtState = CrtInWord;
+ } else {
+ if (cc == '"') {
+ if (shellState != ShellEscaped)
+ shellState = (shellState == ShellQuoted) ? ShellBasic : ShellQuoted;
+ if (rbslashes) {
+ // Offset -1: skip possible circumflex. We have at least
+ // one backslash, so a fixed offset is ok.
+ str.insert(pos - 1, QString(rbslashes, QLatin1Char('\\')));
+ pos += rbslashes;
+ varPos += rbslashes;
+ }
+ if (!(bslashes & 1)) {
+ // Even number of backslashes, so the quote is not escaped.
+ switch (crtState) {
+ case CrtQuoted:
+ // Closing quote
+ crtState = CrtClosed;
+ break;
+ case CrtClosed:
+ // Two consecutive quotes make a literal quote - and
+ // still close quoting. See QtcProcess::quoteArg().
+ crtState = CrtInWord;
+ break;
+ case CrtHadQuote:
+ // Opening quote right after quoted expando. Can't do that.
+ return false;
+ default:
+ // Opening quote
+ crtState = CrtQuoted;
+ break;
+ }
+ } else if (crtState < CrtQuoted) {
+ crtState = CrtInWord;
+ }
+ } else if (crtState < CrtQuoted) {
+ crtState = CrtInWord;
+ }
+ bslashes = 0;
+ rbslashes = 0;
+ }
+ }
+ if (varPos == INT_MAX && !rbslashes)
+ break;
+ if (shellState == ShellEscaped)
+ shellState = ShellBasic;
+ }
+ pos++;
+ }
+ } else {
+ // !Windows
+ MxState state = {MxBasic, false};
+ QStack<MxState> sstack;
+ QStack<MxSave> ostack;
+
+ while (pos < str.length()) {
+ if (pos == varPos) {
+ // Our expansion rules trigger in any context
+ if (state.dquote) {
+ // We are within a double-quoted string. Escape relevant meta characters.
+ rsts.replace(QRegularExpression(QLatin1String("([$`\"\\\\])")), QLatin1String("\\\\1"));
+ } else if (state.current == MxSingleQuote) {
+ // We are within a single-quoted string. "Suspend" single-quoting and put a
+ // single escaped quote for each single quote inside the string.
+ rsts.replace(QLatin1Char('\''), QLatin1String("'\\''"));
+ } else if (rsts.isEmpty() || hasSpecialCharsUnix(rsts)) {
+ // String contains "quote-worthy" characters. Use single quoting - but
+ // that choice is arbitrary.
+ rsts.replace(QLatin1Char('\''), QLatin1String("'\\''"));
+ rsts.prepend(QLatin1Char('\''));
+ rsts.append(QLatin1Char('\''));
+ } // Else just use the string verbatim.
+ str.replace(pos, varLen, rsts);
+ pos += rsts.length();
+ varPos = pos;
+ if (!(varLen = mx->findMacro(str, &varPos, &rsts)))
+ break;
+ continue;
+ }
+ ushort cc = str.unicode()[pos].unicode();
+ if (state.current == MxSingleQuote) {
+ // Single quoted context - only the single quote has any special meaning.
+ if (cc == '\'')
+ state = sstack.pop();
+ } else if (cc == '\\') {
+ // In any other context, the backslash starts an escape.
+ pos += 2;
+ if (varPos < pos)
+ return false; // Backslash'd quoted expando would be Bad (TM).
+ continue;
+ } else if (cc == '$') {
+ cc = str.unicode()[++pos].unicode();
+ if (cc == '(') {
+ sstack.push(state);
+ if (str.unicode()[pos + 1].unicode() == '(') {
+ // $(( starts a math expression. This may also be a $( ( in fact,
+ // so we push the current string and offset on a stack so we can retry.
+ MxSave sav = {str, pos + 2, varPos};
+ ostack.push(sav);
+ state.current = MxMath;
+ pos += 2;
+ continue;
+ } else {
+ // $( starts a command substitution. This actually "opens a new context"
+ // which overrides surrounding double quoting.
+ state.current = MxParen;
+ state.dquote = false;
+ }
+ } else if (cc == '{') {
+ // ${ starts a "braced" variable substitution.
+ sstack.push(state);
+ state.current = MxSubst;
+ } // Else assume that a "bare" variable substitution has started
+ } else if (cc == '`') {
+ // Backticks are evil, as every shell interprets escapes within them differently,
+ // which is a danger for the quoting of our own expansions.
+ // So we just apply *our* rules (which match bash) and transform it into a POSIX
+ // command substitution which has clear semantics.
+ str.replace(pos, 1, QLatin1String("$( " )); // add space -> avoid creating $((
+ varPos += 2;
+ int pos2 = pos += 3;
+ forever {
+ if (pos2 >= str.length())
+ return false; // Syntax error - unterminated backtick expression.
+ cc = str.unicode()[pos2].unicode();
+ if (cc == '`')
+ break;
+ if (cc == '\\') {
+ cc = str.unicode()[++pos2].unicode();
+ if (cc == '$' || cc == '`' || cc == '\\' ||
+ (cc == '"' && state.dquote))
+ {
+ str.remove(pos2 - 1, 1);
+ if (varPos >= pos2)
+ varPos--;
+ continue;
+ }
+ }
+ pos2++;
+ }
+ str[pos2] = QLatin1Char(')');
+ sstack.push(state);
+ state.current = MxParen;
+ state.dquote = false;
+ continue;
+ } else if (state.current == MxDoubleQuote) {
+ // (Truly) double quoted context - only remaining special char is the closing quote.
+ if (cc == '"')
+ state = sstack.pop();
+ } else if (cc == '\'') {
+ // Start single quote if we are not in "inherited" double quoted context.
+ if (!state.dquote) {
+ sstack.push(state);
+ state.current = MxSingleQuote;
+ }
+ } else if (cc == '"') {
+ // Same for double quoting.
+ if (!state.dquote) {
+ sstack.push(state);
+ state.current = MxDoubleQuote;
+ state.dquote = true;
+ }
+ } else if (state.current == MxSubst) {
+ // "Braced" substitution context - only remaining special char is the closing brace.
+ if (cc == '}')
+ state = sstack.pop();
+ } else if (cc == ')') {
+ if (state.current == MxMath) {
+ if (str.unicode()[pos + 1].unicode() == ')') {
+ state = sstack.pop();
+ pos += 2;
+ } else {
+ // False hit: the $(( was a $( ( in fact.
+ // ash does not care (and will complain), but bash actually parses it.
+ varPos = ostack.top().varPos;
+ pos = ostack.top().pos;
+ str = ostack.top().str;
+ ostack.pop();
+ state.current = MxParen;
+ state.dquote = false;
+ sstack.push(state);
+ }
+ continue;
+ } else if (state.current == MxParen) {
+ state = sstack.pop();
+ } else {
+ break; // Syntax error - excess closing parenthesis.
+ }
+ } else if (cc == '}') {
+ if (state.current == MxGroup)
+ state = sstack.pop();
+ else
+ break; // Syntax error - excess closing brace.
+ } else if (cc == '(') {
+ // Context-saving command grouping.
+ sstack.push(state);
+ state.current = MxParen;
+ } else if (cc == '{') {
+ // Plain command grouping.
+ sstack.push(state);
+ state.current = MxGroup;
+ }
+ pos++;
+ }
+ // FIXME? May complain if (!sstack.empty()), but we don't really care anyway.
+ }
+
+ *cmd = str;
+ return true;
+}
+
+QString ProcessArgs::expandMacros(const QString &str, AbstractMacroExpander *mx, OsType osType)
+{
+ QString ret = str;
+ expandMacros(&ret, mx, osType);
+ return ret;
+}
+
+bool ProcessArgs::ArgIterator::next()
+{
+ // We delay the setting of m_prev so we can still delete the last argument
+ // after we find that there are no more arguments. It's a bit of a hack ...
+ int prev = m_pos;
+
+ m_simple = true;
+ m_value.clear();
+
+ if (m_osType == OsTypeWindows) {
+ enum { // cmd.exe parsing state
+ ShellBasic, // initial state
+ ShellQuoted, // double-quoted state => *no* other meta chars are interpreted
+ ShellEscaped // circumflex-escaped state => next char is not interpreted
+ } shellState = ShellBasic;
+ enum { // CommandLineToArgv() parsing state and some more
+ CrtBasic, // initial state
+ CrtInWord, // in non-whitespace
+ CrtClosed, // previous char closed the double-quoting
+ CrtQuoted // double-quoted state => spaces don't split tokens
+ } crtState = CrtBasic;
+ enum { NoVar, NewVar, FullVar } varState = NoVar; // inside a potential env variable expansion
+ int bslashes = 0; // number of preceding backslashes
+
+ for (;; m_pos++) {
+ ushort cc = m_pos < m_str->length() ? m_str->unicode()[m_pos].unicode() : 0;
+ if (shellState == ShellBasic && cc == '^') {
+ varState = NoVar;
+ shellState = ShellEscaped;
+ } else if ((shellState == ShellBasic && isMetaCharWin(cc)) || !cc) { // A "bit" simplistic ...
+ // We ignore crtQuote state here. Whatever ...
+ doReturn:
+ if (m_simple)
+ while (--bslashes >= 0)
+ m_value += QLatin1Char('\\');
+ else
+ m_value.clear();
+ if (crtState != CrtBasic) {
+ m_prev = prev;
+ return true;
+ }
+ return false;
+ } else {
+ if (crtState != CrtQuoted && (cc == ' ' || cc == '\t')) {
+ if (crtState != CrtBasic) {
+ // We'll lose shellQuote state here. Whatever ...
+ goto doReturn;
+ }
+ } else {
+ if (cc == '\\') {
+ bslashes++;
+ if (crtState != CrtQuoted)
+ crtState = CrtInWord;
+ varState = NoVar;
+ } else {
+ if (cc == '"') {
+ varState = NoVar;
+ if (shellState != ShellEscaped)
+ shellState = (shellState == ShellQuoted) ? ShellBasic : ShellQuoted;
+ int obslashes = bslashes;
+ bslashes >>= 1;
+ if (!(obslashes & 1)) {
+ // Even number of backslashes, so the quote is not escaped.
+ switch (crtState) {
+ case CrtQuoted:
+ // Closing quote
+ crtState = CrtClosed;
+ continue;
+ case CrtClosed:
+ // Two consecutive quotes make a literal quote - and
+ // still close quoting. See quoteArg().
+ crtState = CrtInWord;
+ break;
+ default:
+ // Opening quote
+ crtState = CrtQuoted;
+ continue;
+ }
+ } else if (crtState != CrtQuoted) {
+ crtState = CrtInWord;
+ }
+ } else {
+ if (cc == '%') {
+ if (varState == FullVar) {
+ m_simple = false;
+ varState = NoVar;
+ } else {
+ varState = NewVar;
+ }
+ } else if (varState != NoVar) {
+ // This check doesn't really reflect cmd reality, but it is an
+ // approximation of what would be sane.
+ varState = (cc == '_' || cc == '-' || cc == '.'
+ || QChar(cc).isLetterOrNumber()) ? FullVar : NoVar;
+
+ }
+ if (crtState != CrtQuoted)
+ crtState = CrtInWord;
+ }
+ for (; bslashes > 0; bslashes--)
+ m_value += QLatin1Char('\\');
+ m_value += QChar(cc);
+ }
+ }
+ if (shellState == ShellEscaped)
+ shellState = ShellBasic;
+ }
+ }
+ } else {
+ MxState state = {MxBasic, false};
+ QStack<MxState> sstack;
+ QStack<int> ostack;
+ bool hadWord = false;
+
+ for (; m_pos < m_str->length(); m_pos++) {
+ ushort cc = m_str->unicode()[m_pos].unicode();
+ if (state.current == MxSingleQuote) {
+ if (cc == '\'') {
+ state = sstack.pop();
+ continue;
+ }
+ } else if (cc == '\\') {
+ if (++m_pos >= m_str->length())
+ break;
+ cc = m_str->unicode()[m_pos].unicode();
+ if (state.dquote && cc != '"' && cc != '\\' && cc != '$' && cc != '`')
+ m_value += QLatin1Char('\\');
+ } else if (cc == '$') {
+ if (++m_pos >= m_str->length())
+ break;
+ cc = m_str->unicode()[m_pos].unicode();
+ if (cc == '(') {
+ sstack.push(state);
+ if (++m_pos >= m_str->length())
+ break;
+ if (m_str->unicode()[m_pos].unicode() == '(') {
+ ostack.push(m_pos);
+ state.current = MxMath;
+ } else {
+ state.dquote = false;
+ state.current = MxParen;
+ // m_pos too far by one now - whatever.
+ }
+ } else if (cc == '{') {
+ sstack.push(state);
+ state.current = MxSubst;
+ } else {
+ // m_pos too far by one now - whatever.
+ }
+ m_simple = false;
+ hadWord = true;
+ continue;
+ } else if (cc == '`') {
+ forever {
+ if (++m_pos >= m_str->length()) {
+ m_simple = false;
+ m_prev = prev;
+ return true;
+ }
+ cc = m_str->unicode()[m_pos].unicode();
+ if (cc == '`')
+ break;
+ if (cc == '\\')
+ m_pos++; // m_pos may be too far by one now - whatever.
+ }
+ m_simple = false;
+ hadWord = true;
+ continue;
+ } else if (state.current == MxDoubleQuote) {
+ if (cc == '"') {
+ state = sstack.pop();
+ continue;
+ }
+ } else if (cc == '\'') {
+ if (!state.dquote) {
+ sstack.push(state);
+ state.current = MxSingleQuote;
+ hadWord = true;
+ continue;
+ }
+ } else if (cc == '"') {
+ if (!state.dquote) {
+ sstack.push(state);
+ state.dquote = true;
+ state.current = MxDoubleQuote;
+ hadWord = true;
+ continue;
+ }
+ } else if (state.current == MxSubst) {
+ if (cc == '}')
+ state = sstack.pop();
+ continue; // Not simple anyway
+ } else if (cc == ')') {
+ if (state.current == MxMath) {
+ if (++m_pos >= m_str->length())
+ break;
+ if (m_str->unicode()[m_pos].unicode() == ')') {
+ ostack.pop();
+ state = sstack.pop();
+ } else {
+ // false hit: the $(( was a $( ( in fact.
+ // ash does not care, but bash does.
+ m_pos = ostack.pop();
+ state.current = MxParen;
+ state.dquote = false;
+ sstack.push(state);
+ }
+ continue;
+ } else if (state.current == MxParen) {
+ state = sstack.pop();
+ continue;
+ } else {
+ break;
+ }
+#if 0 // MxGroup is impossible, see below.
+ } else if (cc == '}') {
+ if (state.current == MxGroup) {
+ state = sstack.pop();
+ continue;
+ }
+#endif
+ } else if (cc == '(') {
+ sstack.push(state);
+ state.current = MxParen;
+ m_simple = false;
+ hadWord = true;
+ continue;
+#if 0 // Should match only at the beginning of a command, which we never have currently.
+ } else if (cc == '{') {
+ sstack.push(state);
+ state.current = MxGroup;
+ m_simple = false;
+ hadWord = true;
+ continue;
+#endif
+ } else if (cc == '<' || cc == '>' || cc == '&' || cc == '|' || cc == ';') {
+ if (sstack.isEmpty())
+ break;
+ } else if (cc == ' ' || cc == '\t') {
+ if (!hadWord)
+ continue;
+ if (sstack.isEmpty())
+ break;
+ }
+ m_value += QChar(cc);
+ hadWord = true;
+ }
+ // TODO: Possibly complain here if (!sstack.empty())
+ if (!m_simple)
+ m_value.clear();
+ if (hadWord) {
+ m_prev = prev;
+ return true;
+ }
+ return false;
+ }
+}
+
+void ProcessArgs::ArgIterator::deleteArg()
+{
+ if (!m_prev)
+ while (m_pos < m_str->length() && m_str->at(m_pos).isSpace())
+ m_pos++;
+ m_str->remove(m_prev, m_pos - m_prev);
+ m_pos = m_prev;
+}
+
+void ProcessArgs::ArgIterator::appendArg(const QString &str)
+{
+ const QString qstr = quoteArg(str);
+ if (!m_pos)
+ m_str->insert(0, qstr + QLatin1Char(' '));
+ else
+ m_str->insert(m_pos, QLatin1Char(' ') + qstr);
+ m_pos += qstr.length() + 1;
+}
+
+ProcessArgs ProcessArgs::createWindowsArgs(const QString &args)
+{
+ ProcessArgs result;
+ result.m_windowsArgs = args;
+ result.m_isWindows = true;
+ return result;
+}
+
+ProcessArgs ProcessArgs::createUnixArgs(const QStringList &args)
+{
+ ProcessArgs result;
+ result.m_unixArgs = args;
+ result.m_isWindows = false;
+ return result;
+}
+
+QString ProcessArgs::toWindowsArgs() const
+{
+ QTC_CHECK(m_isWindows);
+ return m_windowsArgs;
+}
+
+QStringList ProcessArgs::toUnixArgs() const
+{
+ QTC_CHECK(!m_isWindows);
+ return m_unixArgs;
+}
+
+QString ProcessArgs::toString() const
+{
+ if (m_isWindows)
+ return m_windowsArgs;
+ else
+ return ProcessArgs::joinArgs(m_unixArgs, OsTypeLinux);
+}
+
+/*!
+ \class Utils::CommandLine
+
+ \brief The CommandLine class represents a command line of a QProcess or
+ similar utility.
+ */
+
+CommandLine::CommandLine() = default;
+
+CommandLine::CommandLine(const QString &executable)
+ : m_executable(FilePath::fromString(executable))
+{}
+
+CommandLine::CommandLine(const FilePath &executable)
+ : m_executable(executable)
+{}
+
+CommandLine::CommandLine(const QString &exe, const QStringList &args)
+ : CommandLine(FilePath::fromString(exe), args)
+{}
+
+CommandLine::CommandLine(const FilePath &exe, const QStringList &args)
+ : m_executable(exe)
+{
+ addArgs(args);
+}
+
+CommandLine::CommandLine(const FilePath &exe, const QString &args, RawType)
+ : m_executable(exe)
+{
+ addArgs(args, Raw);
+}
+
+void CommandLine::addArg(const QString &arg, OsType osType)
+{
+ ProcessArgs::addArg(&m_arguments, arg, osType);
+}
+
+void CommandLine::addArgs(const QStringList &inArgs, OsType osType)
+{
+ for (const QString &arg : inArgs)
+ addArg(arg, osType);
+}
+
+// Adds cmd's executable and arguments one by one to this commandline.
+// Useful for 'sudo', 'nice', etc
+void CommandLine::addArgs(const CommandLine &cmd, OsType osType)
+{
+ addArg(cmd.executable().toString());
+ addArgs(cmd.splitArguments(osType));
+}
+
+void CommandLine::addArgs(const QString &inArgs, RawType)
+{
+ ProcessArgs::addArgs(&m_arguments, inArgs);
+}
+
+QString CommandLine::toUserOutput() const
+{
+ QString res = m_executable.toUserOutput();
+ if (!m_arguments.isEmpty())
+ res += ' ' + m_arguments;
+ return res;
+}
+
+QStringList CommandLine::splitArguments(OsType osType) const
+{
+ return ProcessArgs::splitArgs(m_arguments, osType);
+}
+
+} // namespace Utils
diff --git a/src/libs/utils/commandline.h b/src/libs/utils/commandline.h
new file mode 100644
index 0000000000..473c267720
--- /dev/null
+++ b/src/libs/utils/commandline.h
@@ -0,0 +1,165 @@
+/****************************************************************************
+**
+** Copyright (C) 2016 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of Qt Creator.
+**
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3 as published by the Free Software
+** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-3.0.html.
+**
+****************************************************************************/
+
+#pragma once
+
+#include "utils_global.h"
+
+#include "fileutils.h"
+#include "hostosinfo.h"
+
+#include <QStringList>
+
+namespace Utils {
+
+class AbstractMacroExpander;
+class Environment;
+
+class QTCREATOR_UTILS_EXPORT ProcessArgs
+{
+public:
+ static ProcessArgs createWindowsArgs(const QString &args);
+ static ProcessArgs createUnixArgs(const QStringList &args);
+
+ QString toWindowsArgs() const;
+ QStringList toUnixArgs() const;
+ QString toString() const;
+
+ enum SplitError {
+ SplitOk = 0, //! All went just fine
+ BadQuoting, //! Command contains quoting errors
+ FoundMeta //! Command contains complex shell constructs
+ };
+
+ //! Quote a single argument for usage in a unix shell command
+ static QString quoteArgUnix(const QString &arg);
+ //! Quote a single argument for usage in a shell command
+ static QString quoteArg(const QString &arg, OsType osType = HostOsInfo::hostOs());
+ //! Quote a single argument and append it to a shell command
+ static void addArg(QString *args, const QString &arg, OsType osType = HostOsInfo::hostOs());
+ //! Join an argument list into a shell command
+ static QString joinArgs(const QStringList &args, OsType osType = HostOsInfo::hostOs());
+ //! Prepare argument of a shell command for feeding into QProcess
+ static ProcessArgs prepareArgs(const QString &cmd, SplitError *err,
+ OsType osType = HostOsInfo::hostOs(),
+ const Environment *env = nullptr, const QString *pwd = nullptr,
+ bool abortOnMeta = true);
+ //! Prepare a shell command for feeding into QProcess
+ static bool prepareCommand(const QString &command, const QString &arguments,
+ QString *outCmd, ProcessArgs *outArgs, OsType osType = HostOsInfo::hostOs(),
+ const Environment *env = nullptr, const QString *pwd = nullptr);
+ //! Quote and append each argument to a shell command
+ static void addArgs(QString *args, const QStringList &inArgs);
+ //! Append already quoted arguments to a shell command
+ static void addArgs(QString *args, const QString &inArgs);
+ //! Split a shell command into separate arguments.
+ static QStringList splitArgs(const QString &cmd, OsType osType = HostOsInfo::hostOs(),
+ bool abortOnMeta = false, SplitError *err = nullptr,
+ const Environment *env = nullptr, const QString *pwd = nullptr);
+ //! Safely replace the expandos in a shell command
+ static bool expandMacros(QString *cmd, AbstractMacroExpander *mx,
+ OsType osType = HostOsInfo::hostOs());
+ static QString expandMacros(const QString &str, AbstractMacroExpander *mx,
+ OsType osType = HostOsInfo::hostOs());
+
+ /*! Iterate over arguments from a command line.
+ * Assumes that the name of the actual command is *not* part of the line.
+ * Terminates after the first command if the command line is complex.
+ */
+ class QTCREATOR_UTILS_EXPORT ArgIterator {
+ public:
+ ArgIterator(QString *str, OsType osType = HostOsInfo::hostOs())
+ : m_str(str), m_osType(osType)
+ {}
+ //! Get the next argument. Returns false on encountering end of first command.
+ bool next();
+ //! True iff the argument is a plain string, possibly after unquoting.
+ bool isSimple() const { return m_simple; }
+ //! Return the string value of the current argument if it is simple, otherwise empty.
+ QString value() const { return m_value; }
+ //! Delete the last argument fetched via next() from the command line.
+ void deleteArg();
+ //! Insert argument into the command line after the last one fetched via next().
+ //! This may be used before the first call to next() to insert at the front.
+ void appendArg(const QString &str);
+ private:
+ QString *m_str, m_value;
+ int m_pos = 0;
+ int m_prev = -1;
+ bool m_simple;
+ OsType m_osType;
+ };
+
+ class QTCREATOR_UTILS_EXPORT ConstArgIterator {
+ public:
+ ConstArgIterator(const QString &str, OsType osType = HostOsInfo::hostOs())
+ : m_str(str), m_ait(&m_str, osType)
+ {}
+ bool next() { return m_ait.next(); }
+ bool isSimple() const { return m_ait.isSimple(); }
+ QString value() const { return m_ait.value(); }
+ private:
+ QString m_str;
+ ArgIterator m_ait;
+ };
+
+private:
+ QString m_windowsArgs;
+ QStringList m_unixArgs;
+ bool m_isWindows;
+};
+
+class QTCREATOR_UTILS_EXPORT CommandLine
+{
+public:
+ enum RawType { Raw };
+
+ CommandLine();
+ explicit CommandLine(const QString &executable);
+ explicit CommandLine(const FilePath &executable);
+ CommandLine(const QString &exe, const QStringList &args);
+ CommandLine(const FilePath &exe, const QStringList &args);
+ CommandLine(const FilePath &exe, const QString &unparsedArgs, RawType);
+
+ void addArg(const QString &arg, OsType osType = HostOsInfo::hostOs());
+ void addArgs(const QStringList &inArgs, OsType osType = HostOsInfo::hostOs());
+ void addArgs(const CommandLine &cmd, OsType osType = HostOsInfo::hostOs());
+
+ void addArgs(const QString &inArgs, RawType);
+
+ QString toUserOutput() const;
+
+ FilePath executable() const { return m_executable; }
+ QString arguments() const { return m_arguments; }
+ QStringList splitArguments(OsType osType = HostOsInfo::hostOs()) const;
+
+private:
+ FilePath m_executable;
+ QString m_arguments;
+};
+
+} // namespace Utils
+
+Q_DECLARE_METATYPE(Utils::CommandLine)
diff --git a/src/libs/utils/consoleprocess.cpp b/src/libs/utils/consoleprocess.cpp
index 18f6a73e6d..19f5f3a79f 100644
--- a/src/libs/utils/consoleprocess.cpp
+++ b/src/libs/utils/consoleprocess.cpp
@@ -28,6 +28,7 @@
#include <utils/algorithm.h>
#include <utils/environment.h>
#include <utils/hostosinfo.h>
+#include <utils/commandline.h>
#include <utils/qtcassert.h>
#include <utils/qtcprocess.h>
#include <utils/winutils.h>
@@ -232,11 +233,11 @@ TerminalCommand ConsoleProcess::terminalEmulator(const QSettings *settings)
const QString value = settings->value("General/TerminalEmulator").toString().trimmed();
if (!value.isEmpty()) {
// split off command and options
- const QStringList splitCommand = QtcProcess::splitArgs(value);
+ const QStringList splitCommand = ProcessArgs::splitArgs(value);
if (QTC_GUARD(!splitCommand.isEmpty())) {
const QString command = splitCommand.first();
const QStringList quotedArgs = Utils::transform(splitCommand.mid(1),
- &QtcProcess::quoteArgUnix);
+ &ProcessArgs::quoteArgUnix);
const QString options = quotedArgs.join(' ');
return {command, "", options};
}
@@ -358,7 +359,7 @@ bool ConsoleProcess::startTerminalEmulator(QSettings *settings, const QString &w
const TerminalCommand term = terminalEmulator(settings);
QProcess process;
process.setProgram(term.command);
- process.setArguments(QtcProcess::splitArgs(term.openArgs));
+ process.setArguments(ProcessArgs::splitArgs(term.openArgs));
process.setProcessEnvironment(env.toProcessEnvironment());
process.setWorkingDirectory(workingDir);
@@ -394,11 +395,11 @@ bool ConsoleProcess::start()
pcmd = d->m_commandLine.executable().toString();
pargs = d->m_commandLine.arguments();
} else {
- QtcProcess::Arguments outArgs;
- QtcProcess::prepareCommand(d->m_commandLine.executable().toString(),
- d->m_commandLine.arguments(),
- &pcmd, &outArgs, OsTypeWindows,
- &d->m_environment, &d->m_workingDir);
+ ProcessArgs outArgs;
+ ProcessArgs::prepareCommand(d->m_commandLine.executable().toString(),
+ d->m_commandLine.arguments(),
+ &pcmd, &outArgs, OsTypeWindows,
+ &d->m_environment, &d->m_workingDir);
pargs = outArgs.toWindowsArgs();
}
@@ -452,7 +453,7 @@ bool ConsoleProcess::start()
return false;
}
d->m_tempFile->flush();
-}
+ }
STARTUPINFO si;
ZeroMemory(&si, sizeof(si));
@@ -497,19 +498,19 @@ bool ConsoleProcess::start()
#else
- QtcProcess::SplitError perr;
- QtcProcess::Arguments pargs = QtcProcess::prepareArgs(d->m_commandLine.arguments(),
- &perr,
- HostOsInfo::hostOs(),
- &d->m_environment,
- &d->m_workingDir,
- d->m_abortOnMetaChars);
+ ProcessArgs::SplitError perr;
+ ProcessArgs pargs = ProcessArgs::prepareArgs(d->m_commandLine.arguments(),
+ &perr,
+ HostOsInfo::hostOs(),
+ &d->m_environment,
+ &d->m_workingDir,
+ d->m_abortOnMetaChars);
QString pcmd;
- if (perr == QtcProcess::SplitOk) {
+ if (perr == ProcessArgs::SplitOk) {
pcmd = d->m_commandLine.executable().toString();
} else {
- if (perr != QtcProcess::FoundMeta) {
+ if (perr != ProcessArgs::FoundMeta) {
emitError(QProcess::FailedToStart, tr("Quoting error in command."));
return false;
}
@@ -520,20 +521,20 @@ bool ConsoleProcess::start()
return false;
}
pcmd = qEnvironmentVariable("SHELL", "/bin/sh");
- pargs = QtcProcess::Arguments::createUnixArgs(
- {"-c", (QtcProcess::quoteArg(d->m_commandLine.executable().toString())
+ pargs = ProcessArgs::createUnixArgs(
+ {"-c", (ProcessArgs::quoteArg(d->m_commandLine.executable().toString())
+ ' ' + d->m_commandLine.arguments())});
}
- QtcProcess::SplitError qerr;
+ ProcessArgs::SplitError qerr;
const TerminalCommand terminal = terminalEmulator(d->m_settings);
- const QtcProcess::Arguments terminalArgs = QtcProcess::prepareArgs(terminal.executeArgs,
- &qerr,
- HostOsInfo::hostOs(),
- &d->m_environment,
- &d->m_workingDir);
- if (qerr != QtcProcess::SplitOk) {
- emitError(QProcess::FailedToStart, qerr == QtcProcess::BadQuoting
+ const ProcessArgs terminalArgs = ProcessArgs::prepareArgs(terminal.executeArgs,
+ &qerr,
+ HostOsInfo::hostOs(),
+ &d->m_environment,
+ &d->m_workingDir);
+ if (qerr != ProcessArgs::SplitOk) {
+ emitError(QProcess::FailedToStart, qerr == ProcessArgs::BadQuoting
? tr("Quoting error in terminal command.")
: tr("Terminal command may not be a shell command."));
return false;
@@ -589,7 +590,7 @@ bool ConsoleProcess::start()
<< pargs.toUnixArgs();
if (terminal.needsQuotes)
- allArgs = QStringList { QtcProcess::joinArgs(allArgs) };
+ allArgs = QStringList { ProcessArgs::joinArgs(allArgs) };
d->m_process.setEnvironment(env);
d->m_process.start(terminal.command, allArgs);
diff --git a/src/libs/utils/environment.cpp b/src/libs/utils/environment.cpp
index b10bc71caf..e02a407dbc 100644
--- a/src/libs/utils/environment.cpp
+++ b/src/libs/utils/environment.cpp
@@ -130,31 +130,10 @@ Environment Environment::systemEnvironment()
return *staticSystemEnvironment();
}
-const char lcMessages[] = "LC_MESSAGES";
-const char language[] = "LANGUAGE";
-const char englishLocale[] = "en_US.utf8";
-const char languageEnglishLocales[] = "en_US:en";
-
-void Environment::setupEnglishOutput(Environment *environment)
-{
- QTC_ASSERT(environment, return);
- environment->set(lcMessages, englishLocale);
- environment->set(language, languageEnglishLocales);
-}
-
-void Environment::setupEnglishOutput(QProcessEnvironment *environment)
-{
- QTC_ASSERT(environment, return);
- environment->insert(lcMessages, englishLocale);
- environment->insert(language, languageEnglishLocales);
-}
-
-void Environment::setupEnglishOutput(QStringList *environment)
+void Environment::setupEnglishOutput()
{
- QTC_ASSERT(environment, return);
- Environment env(*environment);
- setupEnglishOutput(&env);
- *environment = env.toStringList();
+ set("LC_MESSAGES", "en_US.utf8");
+ set("LANGUAGE", "en_US:en");
}
FilePath Environment::searchInDirectory(const QStringList &execs, const FilePath &directory,
diff --git a/src/libs/utils/environment.h b/src/libs/utils/environment.h
index cd7d803ee2..75e7aeb4aa 100644
--- a/src/libs/utils/environment.h
+++ b/src/libs/utils/environment.h
@@ -31,12 +31,10 @@
#include "namevalueitem.h"
#include "optional.h"
-#include <QMap>
#include <QStringList>
#include <functional>
-QT_FORWARD_DECLARE_CLASS(QDebug)
QT_FORWARD_DECLARE_CLASS(QProcessEnvironment)
namespace Utils {
@@ -47,9 +45,6 @@ public:
using NameValueDictionary::NameValueDictionary;
static Environment systemEnvironment();
- static void setupEnglishOutput(Environment *environment);
- static void setupEnglishOutput(QProcessEnvironment *environment);
- static void setupEnglishOutput(QStringList *environment);
QProcessEnvironment toProcessEnvironment() const;
@@ -62,6 +57,8 @@ public:
void prependOrSetLibrarySearchPath(const QString &value);
void prependOrSetLibrarySearchPaths(const QStringList &values);
+ void setupEnglishOutput();
+
using PathFilter = std::function<bool(const FilePath &)>;
FilePath searchInPath(const QString &executable,
const FilePaths &additionalDirs = FilePaths(),
diff --git a/src/libs/utils/fileutils.cpp b/src/libs/utils/fileutils.cpp
index 7a67cfb4d5..92b848f25f 100644
--- a/src/libs/utils/fileutils.cpp
+++ b/src/libs/utils/fileutils.cpp
@@ -27,8 +27,8 @@
#include "savefile.h"
#include "algorithm.h"
+#include "commandline.h"
#include "qtcassert.h"
-#include "qtcprocess.h"
#include <QDataStream>
#include <QDateTime>
@@ -44,6 +44,9 @@
#endif
#ifdef Q_OS_WIN
+#ifdef QTCREATOR_PCH_H
+#define CALLBACK WINAPI
+#endif
#include <qt_windows.h>
#include <shlobj.h>
#endif
@@ -55,82 +58,14 @@
QT_BEGIN_NAMESPACE
QDebug operator<<(QDebug dbg, const Utils::FilePath &c)
{
- return dbg << c.toString();
+ return dbg << c.toUserOutput();
}
QT_END_NAMESPACE
namespace Utils {
-/*! \class Utils::CommandLine
-
- \brief The CommandLine class represents a command line of a QProcess
- or similar utility.
-
-*/
-
-CommandLine::CommandLine() = default;
-
-CommandLine::CommandLine(const QString &executable)
- : m_executable(FilePath::fromString(executable))
-{}
-
-CommandLine::CommandLine(const FilePath &executable)
- : m_executable(executable)
-{}
-
-CommandLine::CommandLine(const QString &exe, const QStringList &args)
- : CommandLine(FilePath::fromString(exe), args)
-{}
-
-CommandLine::CommandLine(const FilePath &exe, const QStringList &args)
- : m_executable(exe)
-{
- addArgs(args);
-}
-
-CommandLine::CommandLine(const FilePath &exe, const QString &args, RawType)
- : m_executable(exe)
-{
- addArgs(args, Raw);
-}
-
-void CommandLine::addArg(const QString &arg, OsType osType)
-{
- QtcProcess::addArg(&m_arguments, arg, osType);
-}
-
-void CommandLine::addArgs(const QStringList &inArgs, OsType osType)
-{
- for (const QString &arg : inArgs)
- addArg(arg, osType);
-}
-
-// Adds cmd's executable and arguments one by one to this commandline.
-// Useful for 'sudo', 'nice', etc
-void CommandLine::addArgs(const CommandLine &cmd, OsType osType)
-{
- addArg(cmd.executable().toString());
- addArgs(cmd.splitArguments(osType));
-}
-
-void CommandLine::addArgs(const QString &inArgs, RawType)
-{
- QtcProcess::addArgs(&m_arguments, inArgs);
-}
-
-QString CommandLine::toUserOutput() const
-{
- QString res = m_executable.toUserOutput();
- if (!m_arguments.isEmpty())
- res += ' ' + m_arguments;
- return res;
-}
-
-QStringList CommandLine::splitArguments(OsType osType) const
-{
- return QtcProcess::splitArgs(m_arguments, osType);
-}
+static DeviceFileHooks s_deviceHooks;
/*! \class Utils::FileUtils
@@ -277,6 +212,18 @@ bool FilePath::isNewerThan(const QDateTime &timeStamp) const
return false;
}
+Qt::CaseSensitivity FilePath::caseSensitivity() const
+{
+ if (m_scheme.isEmpty())
+ return HostOsInfo::fileNameCaseSensitivity();
+
+ // FIXME: This could or possibly should the target device's file name case sensitivity
+ // into account by diverting to IDevice. However, as this is expensive and we are
+ // in time-critical path here, we go with "good enough" for now:
+ // The first approximation is "Anything unusual is not case sensitive"
+ return Qt::CaseSensitive;
+}
+
/*!
Recursively resolves symlinks if \a filePath is a symlink.
To resolve symlinks anywhere in the path, see canonicalPath.
@@ -318,6 +265,18 @@ FilePath FilePath::operator/(const QString &str) const
return pathAppended(str);
}
+void FilePath::clear()
+{
+ m_data.clear();
+ m_host.clear();
+ m_scheme.clear();
+}
+
+bool FilePath::isEmpty() const
+{
+ return m_data.isEmpty();
+}
+
/*!
Like QDir::toNativeSeparators(), but use prefix '~' instead of $HOME on unix systems when an
absolute path is given.
@@ -421,6 +380,13 @@ FilePath FilePath::resolvePath(const QString &fileName) const
return FilePath::fromString(QDir::cleanPath(toString() + QLatin1Char('/') + fileName));
}
+FilePath FilePath::resolveSymlinkTarget() const
+{
+ // FIXME: implement
+ QTC_CHECK(false);
+ return *this;
+}
+
FilePath FileUtils::commonPath(const FilePath &oldCommonPath, const FilePath &filePath)
{
FilePath newCommonPath = oldCommonPath;
@@ -499,35 +465,41 @@ QByteArray FileUtils::fileId(const FilePath &fileName)
QByteArray FileReader::fetchQrc(const QString &fileName)
{
- QTC_ASSERT(fileName.startsWith(QLatin1Char(':')), return QByteArray());
+ QTC_ASSERT(fileName.startsWith(':'), return QByteArray());
QFile file(fileName);
bool ok = file.open(QIODevice::ReadOnly);
QTC_ASSERT(ok, qWarning() << fileName << "not there!"; return QByteArray());
return file.readAll();
}
-bool FileReader::fetch(const QString &fileName, QIODevice::OpenMode mode)
+bool FileReader::fetch(const FilePath &filePath, QIODevice::OpenMode mode)
{
QTC_ASSERT(!(mode & ~(QIODevice::ReadOnly | QIODevice::Text)), return false);
- QFile file(fileName);
+ if (filePath.needsDevice()) {
+ // TODO: add error handling to FilePath::fileContents
+ m_data = filePath.fileContents();
+ return true;
+ }
+
+ QFile file(filePath.toString());
if (!file.open(QIODevice::ReadOnly | mode)) {
m_errorString = tr("Cannot open %1 for reading: %2").arg(
- QDir::toNativeSeparators(fileName), file.errorString());
+ filePath.toUserOutput(), file.errorString());
return false;
}
m_data = file.readAll();
if (file.error() != QFile::NoError) {
m_errorString = tr("Cannot read %1: %2").arg(
- QDir::toNativeSeparators(fileName), file.errorString());
+ filePath.toUserOutput(), file.errorString());
return false;
}
return true;
}
-bool FileReader::fetch(const QString &fileName, QIODevice::OpenMode mode, QString *errorString)
+bool FileReader::fetch(const FilePath &filePath, QIODevice::OpenMode mode, QString *errorString)
{
- if (fetch(fileName, mode))
+ if (fetch(filePath, mode))
return true;
if (errorString)
*errorString = m_errorString;
@@ -535,9 +507,9 @@ bool FileReader::fetch(const QString &fileName, QIODevice::OpenMode mode, QStrin
}
#ifdef QT_GUI_LIB
-bool FileReader::fetch(const QString &fileName, QIODevice::OpenMode mode, QWidget *parent)
+bool FileReader::fetch(const FilePath &filePath, QIODevice::OpenMode mode, QWidget *parent)
{
- if (fetch(fileName, mode))
+ if (fetch(filePath, mode))
return true;
if (parent)
QMessageBox::critical(parent, tr("File Error"), m_errorString);
@@ -594,11 +566,10 @@ bool FileSaverBase::setResult(bool ok)
{
if (!ok && !m_hasError) {
if (!m_file->errorString().isEmpty()) {
- m_errorString = tr("Cannot write file %1: %2").arg(
- QDir::toNativeSeparators(m_fileName), m_file->errorString());
+ m_errorString = tr("Cannot write file %1: %2")
+ .arg(m_filePath.toUserOutput(), m_file->errorString());
} else {
- m_errorString = tr("Cannot write file %1. Disk full?").arg(
- QDir::toNativeSeparators(m_fileName));
+ m_errorString = tr("Cannot write file %1. Disk full?").arg(m_filePath.toUserOutput());
}
m_hasError = true;
}
@@ -622,9 +593,9 @@ bool FileSaverBase::setResult(QXmlStreamWriter *stream)
}
-FileSaver::FileSaver(const QString &filename, QIODevice::OpenMode mode)
+FileSaver::FileSaver(const FilePath &filePath, QIODevice::OpenMode mode)
{
- m_fileName = filename;
+ m_filePath = filePath;
// Workaround an assert in Qt -- and provide a useful error message, too:
if (HostOsInfo::isWindowsHost()) {
// Taken from: https://msdn.microsoft.com/en-us/library/windows/desktop/aa365247(v=vs.85).aspx
@@ -632,26 +603,25 @@ FileSaver::FileSaver(const QString &filename, QIODevice::OpenMode mode)
= {"CON", "PRN", "AUX", "NUL",
"COM1", "COM2", "COM3", "COM4", "COM5", "COM6", "COM7", "COM8", "COM9",
"LPT1", "LPT2", "LPT3", "LPT4", "LPT5", "LPT6", "LPT7", "LPT8", "LPT9"};
- const QString fn = QFileInfo(filename).baseName().toUpper();
- for (const QString &rn : reservedNames) {
- if (fn == rn) {
- m_errorString = tr("%1: Is a reserved filename on Windows. Cannot save.").arg(filename);
- m_hasError = true;
- return;
- }
+ const QString fn = filePath.toFileInfo().baseName().toUpper();
+ if (reservedNames.contains(fn)) {
+ m_errorString = tr("%1: Is a reserved filename on Windows. Cannot save.")
+ .arg(filePath.toString());
+ m_hasError = true;
+ return;
}
}
if (mode & (QIODevice::ReadOnly | QIODevice::Append)) {
- m_file.reset(new QFile{filename});
+ m_file.reset(new QFile{filePath.toString()});
m_isSafe = false;
} else {
- m_file.reset(new SaveFile{filename});
+ m_file.reset(new SaveFile{filePath.toString()});
m_isSafe = true;
}
if (!m_file->open(QIODevice::WriteOnly | mode)) {
- QString err = QFile::exists(filename) ?
+ QString err = filePath.exists() ?
tr("Cannot overwrite file %1: %2") : tr("Cannot create file %1: %2");
- m_errorString = err.arg(QDir::toNativeSeparators(filename), m_file->errorString());
+ m_errorString = err.arg(filePath.toUserOutput(), m_file->errorString());
m_hasError = true;
}
}
@@ -685,14 +655,14 @@ TempFileSaver::TempFileSaver(const QString &templ)
tempFile->errorString());
m_hasError = true;
}
- m_fileName = tempFile->fileName();
+ m_filePath = FilePath::fromString(tempFile->fileName());
}
TempFileSaver::~TempFileSaver()
{
m_file.reset();
if (m_autoRemove)
- QFile::remove(m_fileName);
+ QFile::remove(m_filePath.toString());
}
/*! \class Utils::FilePath
@@ -721,29 +691,43 @@ QFileInfo FilePath::toFileInfo() const
FilePath FilePath::fromUrl(const QUrl &url)
{
FilePath fn;
- fn.m_url = url;
+ fn.m_scheme = url.scheme();
+ fn.m_host = url.host();
fn.m_data = url.path();
return fn;
}
/// \returns a QString for passing on to QString based APIs
-const QString &FilePath::toString() const
+QString FilePath::toString() const
{
- return m_data;
+ if (m_scheme.isEmpty())
+ return m_data;
+ if (m_data.startsWith('/'))
+ return m_scheme + "://" + m_host + m_data;
+ return m_scheme + "://" + m_host + "/./" + m_data;
}
QUrl FilePath::toUrl() const
{
- return m_url;
+ QUrl url;
+ url.setScheme(m_scheme);
+ url.setHost(m_host);
+ url.setPath(m_data);
+ return url;
+}
+
+void FilePath::setDeviceFileHooks(const DeviceFileHooks &hooks)
+{
+ s_deviceHooks = hooks;
}
/// \returns a QString to display to the user
/// Converts the separators to the native format
QString FilePath::toUserOutput() const
{
- if (m_url.isEmpty())
- return QDir::toNativeSeparators(toString());
- return m_url.toString();
+ if (m_scheme.isEmpty())
+ return QDir::toNativeSeparators(m_data);
+ return toString();
}
QString FilePath::fileName() const
@@ -777,20 +761,123 @@ QString FilePath::fileNameWithPathComponents(int pathComponents) const
return m_data;
}
+void FilePath::setScheme(const QString &scheme)
+{
+ QTC_CHECK(!scheme.contains('/'));
+ m_scheme = scheme;
+}
+
+void FilePath::setHost(const QString &host)
+{
+ QTC_CHECK(!host.contains('/'));
+ m_host = host;
+}
+
+
/// \returns a bool indicating whether a file with this
/// FilePath exists.
bool FilePath::exists() const
{
+ QTC_ASSERT(!needsDevice(), return false);
return !isEmpty() && QFileInfo::exists(m_data);
}
+
+
/// \returns a bool indicating whether a path is writable.
-bool FilePath::isWritablePath() const
+bool FilePath::isWritableDir() const
{
+ if (needsDevice()) {
+ QTC_ASSERT(s_deviceHooks.isWritableDir, return false);
+ return s_deviceHooks.isReadableFile(*this);
+ }
const QFileInfo fi{m_data};
return exists() && fi.isDir() && fi.isWritable();
}
+bool FilePath::isExecutableFile() const
+{
+ if (needsDevice()) {
+ QTC_ASSERT(s_deviceHooks.isExecutableFile, return false);
+ return s_deviceHooks.isExecutableFile(*this);
+ }
+ const QFileInfo fi{m_data};
+ return fi.exists() && fi.isExecutable() && !fi.isDir();
+}
+
+bool FilePath::isReadableFile() const
+{
+ if (needsDevice()) {
+ QTC_ASSERT(s_deviceHooks.isReadableFile, return false);
+ return s_deviceHooks.isReadableFile(*this);
+ }
+ const QFileInfo fi{m_data};
+ return fi.exists() && fi.isReadable() && !fi.isDir();
+}
+
+bool FilePath::isReadableDir() const
+{
+ if (needsDevice()) {
+ QTC_ASSERT(s_deviceHooks.isReadableDir, return false);
+ return s_deviceHooks.isReadableDir(*this);
+ }
+ const QFileInfo fi{m_data};
+ return fi.exists() && fi.isReadable() && fi.isDir();
+}
+
+bool FilePath::createDir() const
+{
+ if (needsDevice()) {
+ QTC_ASSERT(s_deviceHooks.createDir, return false);
+ return s_deviceHooks.createDir(*this);
+ }
+ QDir dir(m_data);
+ return dir.mkpath(dir.absolutePath());
+}
+
+QList<FilePath> FilePath::dirEntries(const QStringList &nameFilters, QDir::Filters filters) const
+{
+ if (needsDevice()) {
+ QTC_ASSERT(s_deviceHooks.dirEntries, return {});
+ return s_deviceHooks.dirEntries(*this, nameFilters, filters);
+ }
+
+ const QFileInfoList entryInfoList = QDir(toString()).entryInfoList(nameFilters, filters);
+ return Utils::transform(entryInfoList, &FilePath::fromFileInfo);
+}
+
+QList<FilePath> FilePath::dirEntries(QDir::Filters filters) const
+{
+ return dirEntries({}, filters);
+}
+
+QByteArray FilePath::fileContents(int maxSize) const
+{
+ if (needsDevice()) {
+ QTC_ASSERT(s_deviceHooks.fileContents, return {});
+ return s_deviceHooks.fileContents(*this, maxSize);
+ }
+
+ const QString path = toString();
+ QFile f(path);
+ if (!f.exists())
+ return {};
+
+ if (!f.open(QFile::ReadOnly))
+ return {};
+
+ if (maxSize != -1)
+ return f.read(maxSize);
+
+ return f.readAll();
+}
+
+bool FilePath::needsDevice() const
+{
+ return !m_scheme.isEmpty();
+}
+
+
/// Find the parent directory of a given directory.
/// Returns an empty FilePath if the current directory is already
@@ -821,12 +908,47 @@ FilePath FilePath::absolutePath() const
return result;
}
+FilePath FilePath::absoluteFilePath() const
+{
+ FilePath result = *this;
+ result.m_data = QFileInfo(m_data).absoluteFilePath();
+ return result;
+}
+
+/// Constructs an absolute FilePath from this path which
+/// is interpreted as being relative to \a anchor.
+FilePath FilePath::absoluteFromRelativePath(const FilePath &anchor) const
+{
+ QDir anchorDir = QFileInfo(anchor.m_data).absoluteDir();
+ QString absoluteFilePath = QFileInfo(anchorDir, m_data).canonicalFilePath();
+ return FilePath::fromString(absoluteFilePath);
+}
+
/// Constructs a FilePath from \a filename
/// \a filename is not checked for validity.
FilePath FilePath::fromString(const QString &filename)
{
FilePath fn;
- fn.m_data = filename;
+ if (filename.startsWith('/')) {
+ fn.m_data = filename; // fast track: absolute local paths
+ } else {
+ int pos1 = filename.indexOf("://");
+ if (pos1 >= 0) {
+ fn.m_scheme = filename.left(pos1);
+ pos1 += 3;
+ int pos2 = filename.indexOf('/', pos1);
+ if (pos2 == -1) {
+ fn.m_data = filename.mid(pos1);
+ } else {
+ fn.m_host = filename.mid(pos1, pos2 - pos1);
+ fn.m_data = filename.mid(pos2);
+ }
+ if (fn.m_data.startsWith("/./"))
+ fn.m_data = fn.m_data.mid(3);
+ } else {
+ fn.m_data = filename; // treat everything else as local, too.
+ }
+ }
return fn;
}
@@ -876,16 +998,19 @@ FilePath FilePath::fromVariant(const QVariant &variant)
QVariant FilePath::toVariant() const
{
- if (!m_url.isEmpty())
- return m_url;
- return m_data;
+ return toString();
+}
+
+QDir FilePath::toDir() const
+{
+ return QDir(m_data);
}
bool FilePath::operator==(const FilePath &other) const
{
- if (!m_url.isEmpty())
- return m_url == other.m_url;
- return QString::compare(m_data, other.m_data, HostOsInfo::fileNameCaseSensitivity()) == 0;
+ return QString::compare(m_data, other.m_data, caseSensitivity()) == 0
+ && m_host == other.m_host
+ && m_scheme == other.m_scheme;
}
bool FilePath::operator!=(const FilePath &other) const
@@ -895,9 +1020,12 @@ bool FilePath::operator!=(const FilePath &other) const
bool FilePath::operator<(const FilePath &other) const
{
- if (!m_url.isEmpty())
- return m_url < other.m_url;
- return QString::compare(m_data, other.m_data, HostOsInfo::fileNameCaseSensitivity()) < 0;
+ const int cmp = QString::compare(m_data, other.m_data, caseSensitivity());
+ if (cmp != 0)
+ return cmp < 0;
+ if (m_host != other.m_host)
+ return m_host < other.m_host;
+ return m_scheme < other.m_scheme;
}
bool FilePath::operator<=(const FilePath &other) const
@@ -917,7 +1045,9 @@ bool FilePath::operator>=(const FilePath &other) const
FilePath FilePath::operator+(const QString &s) const
{
- return FilePath::fromString(m_data + s);
+ FilePath res = *this;
+ res.m_data += s;
+ return res;
}
/// \returns whether FilePath is a child of \a s
@@ -925,7 +1055,7 @@ bool FilePath::isChildOf(const FilePath &s) const
{
if (s.isEmpty())
return false;
- if (!m_data.startsWith(s.m_data, HostOsInfo::fileNameCaseSensitivity()))
+ if (!m_data.startsWith(s.m_data, caseSensitivity()))
return false;
if (m_data.size() <= s.m_data.size())
return false;
@@ -945,18 +1075,18 @@ bool FilePath::isChildOf(const QDir &dir) const
/// \returns whether FilePath startsWith \a s
bool FilePath::startsWith(const QString &s) const
{
- return m_data.startsWith(s, HostOsInfo::fileNameCaseSensitivity());
+ return m_data.startsWith(s, caseSensitivity());
}
/// \returns whether FilePath endsWith \a s
bool FilePath::endsWith(const QString &s) const
{
- return m_data.endsWith(s, HostOsInfo::fileNameCaseSensitivity());
+ return m_data.endsWith(s, caseSensitivity());
}
bool FilePath::isDir() const
{
- QTC_CHECK(m_url.isEmpty()); // FIXME: Not implemented yet.
+ QTC_CHECK(m_scheme.isEmpty()); // FIXME: Not implemented yet.
return QFileInfo(m_data).isDir();
}
@@ -965,9 +1095,119 @@ bool FilePath::isDir() const
/// That is, this never returns a path starting with "../"
FilePath FilePath::relativeChildPath(const FilePath &parent) const
{
- if (!isChildOf(parent))
- return FilePath();
- return FilePath::fromString(m_data.mid(parent.m_data.size() + 1, -1));
+ FilePath res;
+ if (isChildOf(parent))
+ res.m_data = m_data.mid(parent.m_data.size() + 1, -1);
+ return res;
+}
+
+/// \returns the relativePath of FilePath to given \a anchor.
+/// Both, FilePath and anchor may be files or directories.
+/// Example usage:
+///
+/// \code
+/// FilePath filePath("/foo/b/ar/file.txt");
+/// FilePath relativePath = filePath.relativePath("/foo/c");
+/// qDebug() << relativePath
+/// \endcode
+///
+/// The debug output will be "../b/ar/file.txt".
+///
+FilePath FilePath::relativePath(const FilePath &anchor) const
+{
+ const QFileInfo fileInfo(m_data);
+ QString absolutePath;
+ QString filename;
+ if (fileInfo.isFile()) {
+ absolutePath = fileInfo.absolutePath();
+ filename = fileInfo.fileName();
+ } else if (fileInfo.isDir()) {
+ absolutePath = fileInfo.absoluteFilePath();
+ } else {
+ return {};
+ }
+ const QFileInfo anchorInfo(anchor.m_data);
+ QString absoluteAnchorPath;
+ if (anchorInfo.isFile())
+ absoluteAnchorPath = anchorInfo.absolutePath();
+ else if (anchorInfo.isDir())
+ absoluteAnchorPath = anchorInfo.absoluteFilePath();
+ else
+ return {};
+ QString relativeFilePath = calcRelativePath(absolutePath, absoluteAnchorPath);
+ if (!filename.isEmpty()) {
+ if (!relativeFilePath.isEmpty())
+ relativeFilePath += '/';
+ relativeFilePath += filename;
+ }
+ return FilePath::fromString(relativeFilePath);
+}
+
+/// \returns the relativePath of \a absolutePath to given \a absoluteAnchorPath.
+/// Both paths must be an absolute path to a directory. Example usage:
+///
+/// \code
+/// qDebug() << FilePath::calcRelativePath("/foo/b/ar", "/foo/c");
+/// \endcode
+///
+/// The debug output will be "../b/ar".
+///
+/// \see FilePath::relativePath
+///
+QString FilePath::calcRelativePath(const QString &absolutePath, const QString &absoluteAnchorPath)
+{
+ if (absolutePath.isEmpty() || absoluteAnchorPath.isEmpty())
+ return QString();
+ // TODO using split() instead of parsing the strings by char index is slow
+ // and needs more memory (but the easiest implementation for now)
+ const QStringList splits1 = absolutePath.split('/');
+ const QStringList splits2 = absoluteAnchorPath.split('/');
+ int i = 0;
+ while (i < splits1.count() && i < splits2.count() && splits1.at(i) == splits2.at(i))
+ ++i;
+ QString relativePath;
+ int j = i;
+ bool addslash = false;
+ while (j < splits2.count()) {
+ if (!splits2.at(j).isEmpty()) {
+ if (addslash)
+ relativePath += '/';
+ relativePath += "..";
+ addslash = true;
+ }
+ ++j;
+ }
+ while (i < splits1.count()) {
+ if (!splits1.at(i).isEmpty()) {
+ if (addslash)
+ relativePath += '/';
+ relativePath += splits1.at(i);
+ addslash = true;
+ }
+ ++i;
+ }
+ return relativePath;
+}
+
+/*!
+ Returns a path corresponding to the current object on the
+ same device as \a deviceTemplate.
+
+ Example usage:
+ \code
+ localDir = FilePath::fromString("/tmp/workingdir");
+ executable = FilePath::fromUrl("docker://123/bin/ls")
+ realDir = localDir.onDevice(executable)
+ assert(realDir == FilePath::fromUrl("docker://123/tmp/workingdir"))
+ \endcode
+*/
+FilePath FilePath::onDevice(const FilePath &deviceTemplate) const
+{
+ FilePath res;
+ res.m_data = m_data;
+ res.m_host = deviceTemplate.m_host;
+ res.m_scheme = deviceTemplate.m_scheme;
+ return res;
}
FilePath FilePath::pathAppended(const QString &str) const
@@ -975,7 +1215,7 @@ FilePath FilePath::pathAppended(const QString &str) const
FilePath fn = *this;
if (str.isEmpty())
return fn;
- if (!isEmpty() && !m_data.endsWith(QLatin1Char('/')))
+ if (!fn.m_data.isEmpty() && !fn.m_data.endsWith(QLatin1Char('/')))
fn.m_data.append('/');
fn.m_data.append(str);
return fn;
@@ -1071,12 +1311,13 @@ void withNtfsPermissions(const std::function<void()> &task)
qt_ntfs_permission_lookup--;
}
#endif
+
} // namespace Utils
std::hash<Utils::FilePath>::result_type
std::hash<Utils::FilePath>::operator()(const std::hash<Utils::FilePath>::argument_type &fn) const
{
- if (Utils::HostOsInfo::fileNameCaseSensitivity() == Qt::CaseInsensitive)
+ if (fn.caseSensitivity() == Qt::CaseInsensitive)
return hash<string>()(fn.toString().toUpper().toStdString());
return hash<string>()(fn.toString().toStdString());
}
diff --git a/src/libs/utils/fileutils.h b/src/libs/utils/fileutils.h
index 73800d2df9..67b40c4eff 100644
--- a/src/libs/utils/fileutils.h
+++ b/src/libs/utils/fileutils.h
@@ -61,8 +61,23 @@ extern Q_CORE_EXPORT int qt_ntfs_permission_lookup;
QT_END_NAMESPACE
+// tst_fileutils becomes a friend of Utils::FilePath for testing private method
+class tst_fileutils;
+
namespace Utils {
+class DeviceFileHooks
+{
+public:
+ std::function<bool(const FilePath &)> isExecutableFile;
+ std::function<bool(const FilePath &)> isReadableFile;
+ std::function<bool(const FilePath &)> isReadableDir;
+ std::function<bool(const FilePath &)> isWritableDir;
+ std::function<bool(const FilePath &)> createDir;
+ std::function<QList<FilePath>(const FilePath &, const QStringList &, QDir::Filters)> dirEntries;
+ std::function<QByteArray(const FilePath &, int)> fileContents;
+};
+
class QTCREATOR_UTILS_EXPORT FilePath
{
public:
@@ -75,20 +90,45 @@ public:
static FilePath fromUtf8(const char *filepath, int filepathSize = -1);
static FilePath fromVariant(const QVariant &variant);
- const QString &toString() const;
+ QString toString() const;
+ FilePath onDevice(const FilePath &deviceTemplate) const;
+
QFileInfo toFileInfo() const;
QVariant toVariant() const;
+ QDir toDir() const;
QString toUserOutput() const;
QString shortNativePath() const;
QString fileName() const;
QString fileNameWithPathComponents(int pathComponents) const;
+
+ QString scheme() const { return m_scheme; }
+ void setScheme(const QString &scheme);
+
+ QString host() const { return m_host; }
+ void setHost(const QString &host);
+
+ QString path() const { return m_data; }
+ void setPath(const QString &path) { m_data = path; }
+
+ bool needsDevice() const;
bool exists() const;
- bool isWritablePath() const;
+
+ bool isWritablePath() const { return isWritableDir(); } // Remove.
+ bool isWritableDir() const;
+ bool isExecutableFile() const;
+ bool isReadableFile() const;
+ bool isReadableDir() const;
+ bool createDir() const;
+ QList<FilePath> dirEntries(const QStringList &nameFilters, QDir::Filters filters) const;
+ QList<FilePath> dirEntries(QDir::Filters filters) const;
+ QByteArray fileContents(int maxSize = -1) const;
FilePath parentDir() const;
FilePath absolutePath() const;
+ FilePath absoluteFilePath() const;
+ FilePath absoluteFromRelativePath(const FilePath &anchor) const;
bool operator==(const FilePath &other) const;
bool operator!=(const FilePath &other) const;
@@ -106,63 +146,44 @@ public:
bool isDir() const;
bool isNewerThan(const QDateTime &timeStamp) const;
+ Qt::CaseSensitivity caseSensitivity() const;
+
FilePath relativeChildPath(const FilePath &parent) const;
+ FilePath relativePath(const FilePath &anchor) const;
FilePath pathAppended(const QString &str) const;
FilePath stringAppended(const QString &str) const;
FilePath resolvePath(const QString &fileName) const;
+ FilePath resolveSymlinkTarget() const;
FilePath canonicalPath() const;
FilePath operator/(const QString &str) const;
- void clear() { m_data.clear(); }
- bool isEmpty() const { return m_data.isEmpty(); }
+ void clear();
+ bool isEmpty() const;
uint hash(uint seed) const;
- // NOTE: FilePath operations on FilePath created from URL currenly
- // do not work except for .toVariant() and .toUrl().
+ // NOTE: Most FilePath operations on FilePath created from URL currently
+ // do not work. Among the working are .toVariant() and .toUrl().
static FilePath fromUrl(const QUrl &url);
QUrl toUrl() const;
+ static void setDeviceFileHooks(const DeviceFileHooks &hooks);
+
private:
+ friend class ::tst_fileutils;
+ static QString calcRelativePath(const QString &absolutePath, const QString &absoluteAnchorPath);
+
+ QString m_scheme;
+ QString m_host;
QString m_data;
- QUrl m_url;
};
QTCREATOR_UTILS_EXPORT QTextStream &operator<<(QTextStream &s, const FilePath &fn);
using FilePaths = QList<FilePath>;
-class QTCREATOR_UTILS_EXPORT CommandLine
-{
-public:
- enum RawType { Raw };
-
- CommandLine();
- explicit CommandLine(const QString &executable);
- explicit CommandLine(const FilePath &executable);
- CommandLine(const QString &exe, const QStringList &args);
- CommandLine(const FilePath &exe, const QStringList &args);
- CommandLine(const FilePath &exe, const QString &unparsedArgs, RawType);
-
- void addArg(const QString &arg, OsType osType = HostOsInfo::hostOs());
- void addArgs(const QStringList &inArgs, OsType osType = HostOsInfo::hostOs());
- void addArgs(const CommandLine &cmd, OsType osType = HostOsInfo::hostOs());
-
- void addArgs(const QString &inArgs, RawType);
-
- QString toUserOutput() const;
-
- FilePath executable() const { return m_executable; }
- QString arguments() const { return m_arguments; }
- QStringList splitArguments(OsType osType = HostOsInfo::hostOs()) const;
-
-private:
- FilePath m_executable;
- QString m_arguments;
-};
-
class QTCREATOR_UTILS_EXPORT FileUtils {
public:
#ifdef QT_GUI_LIB
@@ -272,14 +293,14 @@ class QTCREATOR_UTILS_EXPORT FileReader
Q_DECLARE_TR_FUNCTIONS(Utils::FileUtils) // sic!
public:
static QByteArray fetchQrc(const QString &fileName); // Only for internal resources
- bool fetch(const QString &fileName, QIODevice::OpenMode mode = QIODevice::NotOpen); // QIODevice::ReadOnly is implicit
- bool fetch(const QString &fileName, QIODevice::OpenMode mode, QString *errorString);
- bool fetch(const QString &fileName, QString *errorString)
- { return fetch(fileName, QIODevice::NotOpen, errorString); }
+ bool fetch(const FilePath &filePath, QIODevice::OpenMode mode = QIODevice::NotOpen); // QIODevice::ReadOnly is implicit
+ bool fetch(const FilePath &filePath, QIODevice::OpenMode mode, QString *errorString);
+ bool fetch(const FilePath &filePath, QString *errorString)
+ { return fetch(filePath, QIODevice::NotOpen, errorString); }
#ifdef QT_GUI_LIB
- bool fetch(const QString &fileName, QIODevice::OpenMode mode, QWidget *parent);
- bool fetch(const QString &fileName, QWidget *parent)
- { return fetch(fileName, QIODevice::NotOpen, parent); }
+ bool fetch(const FilePath &filePath, QIODevice::OpenMode mode, QWidget *parent);
+ bool fetch(const FilePath &filePath, QWidget *parent)
+ { return fetch(filePath, QIODevice::NotOpen, parent); }
#endif // QT_GUI_LIB
const QByteArray &data() const { return m_data; }
const QString &errorString() const { return m_errorString; }
@@ -295,7 +316,7 @@ public:
FileSaverBase();
virtual ~FileSaverBase();
- QString fileName() const { return m_fileName; }
+ FilePath filePath() const { return m_filePath; }
bool hasError() const { return m_hasError; }
QString errorString() const { return m_errorString; }
virtual bool finalize();
@@ -315,7 +336,7 @@ public:
protected:
std::unique_ptr<QFile> m_file;
- QString m_fileName;
+ FilePath m_filePath;
QString m_errorString;
bool m_hasError = false;
@@ -328,7 +349,7 @@ class QTCREATOR_UTILS_EXPORT FileSaver : public FileSaverBase
Q_DECLARE_TR_FUNCTIONS(Utils::FileUtils) // sic!
public:
// QIODevice::WriteOnly is implicit
- explicit FileSaver(const QString &filename, QIODevice::OpenMode mode = QIODevice::NotOpen);
+ explicit FileSaver(const FilePath &filePath, QIODevice::OpenMode mode = QIODevice::NotOpen);
bool finalize() override;
using FileSaverBase::finalize;
@@ -364,4 +385,3 @@ template<> struct QTCREATOR_UTILS_EXPORT hash<Utils::FilePath>
} // namespace std
Q_DECLARE_METATYPE(Utils::FilePath)
-Q_DECLARE_METATYPE(Utils::CommandLine)
diff --git a/src/plugins/qmlprofiler/qmlprofileroptionspage.cpp b/src/libs/utils/futuresynchronizer.cpp
index 4d1f478a6c..6e0f953af5 100644
--- a/src/plugins/qmlprofiler/qmlprofileroptionspage.cpp
+++ b/src/libs/utils/futuresynchronizer.cpp
@@ -1,6 +1,6 @@
/****************************************************************************
**
-** Copyright (C) 2016 The Qt Company Ltd.
+** Copyright (C) 2021 The Qt Company Ltd.
** Contact: https://www.qt.io/licensing/
**
** This file is part of Qt Creator.
@@ -23,42 +23,63 @@
**
****************************************************************************/
-#include "qmlprofileroptionspage.h"
-#include "qmlprofilerconfigwidget.h"
-#include "qmlprofilerplugin.h"
-#include "qmlprofilerconstants.h"
+#include "futuresynchronizer.h"
-#include <debugger/analyzer/analyzericons.h>
+/*! \class Utils::FutureSynchronizer
-namespace QmlProfiler {
-namespace Internal {
+ \brief The FutureSynchronizer is an enhanced version of QFutureSynchronizer.
+*/
-QmlProfilerOptionsPage::QmlProfilerOptionsPage()
+namespace Utils {
+
+FutureSynchronizer::~FutureSynchronizer()
+{
+ waitForFinished();
+}
+
+bool FutureSynchronizer::isEmpty() const
+{
+ return m_futures.isEmpty();
+}
+
+void FutureSynchronizer::waitForFinished()
+{
+ if (m_cancelOnWait)
+ cancelAllFutures();
+ for (QFuture<void> &future : m_futures)
+ future.waitForFinished();
+ clearFutures();
+}
+
+void FutureSynchronizer::cancelAllFutures()
+{
+ for (QFuture<void> &future : m_futures)
+ future.cancel();
+}
+
+void FutureSynchronizer::clearFutures()
{
- setId(Constants::SETTINGS);
- setDisplayName(QmlProfilerConfigWidget::tr("QML Profiler"));
- setCategory("T.Analyzer");
- setDisplayCategory(QmlProfilerConfigWidget::tr("Analyzer"));
- setCategoryIconPath(Analyzer::Icons::SETTINGSCATEGORY_ANALYZER);
+ m_futures.clear();
}
-QWidget *QmlProfilerOptionsPage::widget()
+void FutureSynchronizer::setCancelOnWait(bool enabled)
{
- // We cannot parent the widget to the options page as it expects a QWidget as parent
- if (!m_widget)
- m_widget = new QmlProfilerConfigWidget(QmlProfilerPlugin::globalSettings());
- return m_widget;
+ m_cancelOnWait = enabled;
}
-void QmlProfilerOptionsPage::apply()
+bool FutureSynchronizer::isCancelOnWait() const
{
- QmlProfilerPlugin::globalSettings()->writeGlobalSettings();
+ return m_cancelOnWait;
}
-void QmlProfilerOptionsPage::finish()
+void FutureSynchronizer::flushFinishedFutures()
{
- delete m_widget;
+ QList<QFuture<void>> newFutures;
+ for (const QFuture<void> &future : qAsConst(m_futures)) {
+ if (!future.isFinished())
+ newFutures.append(future);
+ }
+ m_futures = newFutures;
}
-} // Internal
-} // QmlProfiler
+} // namespace Utils
diff --git a/src/plugins/autotest/itestsettings.h b/src/libs/utils/futuresynchronizer.h
index 7e868b53b6..00f49043a7 100644
--- a/src/plugins/autotest/itestsettings.h
+++ b/src/libs/utils/futuresynchronizer.h
@@ -1,6 +1,6 @@
/****************************************************************************
**
-** Copyright (C) 2016 The Qt Company Ltd.
+** Copyright (C) 2021 The Qt Company Ltd.
** Contact: https://www.qt.io/licensing/
**
** This file is part of Qt Creator.
@@ -25,41 +25,42 @@
#pragma once
-#include "autotestconstants.h"
+#include "utils_global.h"
+#include <QtGlobal>
-#include <QSettings>
+#include <QFuture>
+#include <QList>
-namespace Autotest {
+namespace Utils {
-class ITestSettings
+class QTCREATOR_UTILS_EXPORT FutureSynchronizer final
{
public:
- ITestSettings() {}
- virtual ~ITestSettings() {}
+ FutureSynchronizer() = default;
+ ~FutureSynchronizer();
- virtual QString name() const = 0;
-
- void toSettings(QSettings *s) const
+ template <typename T>
+ void addFuture(const QFuture<T> &future)
{
- s->beginGroup(Constants::SETTINGSGROUP);
- s->beginGroup(name());
- toTestSettings(s);
- s->endGroup();
- s->endGroup();
+ m_futures.append(QFuture<void>(future));
+ flushFinishedFutures();
}
- void fromSettings(QSettings *s)
- {
- s->beginGroup(Constants::SETTINGSGROUP);
- s->beginGroup(name());
- fromTestSettings(s);
- s->endGroup();
- s->endGroup();
- }
+ bool isEmpty() const;
+
+ void waitForFinished();
+ void cancelAllFutures();
+ void clearFutures();
+
+ void setCancelOnWait(bool enabled);
+ bool isCancelOnWait() const; // TODO: The original contained cancelOnWait, what suggests action, not a getter
+
+ void flushFinishedFutures();
+
+private:
-protected:
- virtual void toTestSettings(QSettings *s) const = 0;
- virtual void fromTestSettings(const QSettings *s) = 0;
+ QList<QFuture<void>> m_futures;
+ bool m_cancelOnWait = false; // TODO: True default makes more sense...
};
-} // namespace Autotest
+} // namespace Utils
diff --git a/src/libs/utils/icon.cpp b/src/libs/utils/icon.cpp
index 63a5e6ac3f..f0b42e2f93 100644
--- a/src/libs/utils/icon.cpp
+++ b/src/libs/utils/icon.cpp
@@ -63,10 +63,12 @@ static MasksAndColors masksAndColors(const Icon &icon, int dpr)
{
MasksAndColors result;
for (const IconMaskAndColor &i: icon) {
- const QString &fileName = i.first;
+ const QString &fileName = i.first.toString();
const QColor color = creatorTheme()->color(i.second);
- const QString dprFileName = StyleHelper::availableImageResolutions(i.first).contains(dpr) ?
- StyleHelper::imageFileWithResolution(fileName, dpr) : fileName;
+ const QString dprFileName = StyleHelper::availableImageResolutions(i.first.toString())
+ .contains(dpr)
+ ? StyleHelper::imageFileWithResolution(fileName, dpr)
+ : fileName;
QPixmap pixmap;
if (!pixmap.load(dprFileName)) {
pixmap = QPixmap(1, 1);
@@ -161,18 +163,30 @@ Icon::Icon(std::initializer_list<IconMaskAndColor> args, Icon::IconStyleOptions
{
}
-Icon::Icon(const QString &imageFileName)
- : m_style(None)
+Icon::Icon(std::initializer_list<IconStringMaskAndColor> args, Icon::IconStyleOptions style)
+ : m_style(style)
+{
+ reserve(args.size());
+ for (const IconStringMaskAndColor &i : args)
+ append({FilePath::fromString(i.first), i.second});
+}
+
+Icon::Icon(const FilePath &imageFileName)
{
append({imageFileName, Theme::Color(-1)});
}
+Icon::Icon(const QString &imageFileName)
+ : Icon(FilePath::fromString(imageFileName))
+{
+}
+
QIcon Icon::icon() const
{
if (isEmpty()) {
return QIcon();
} else if (m_style == None) {
- return QIcon(constFirst().first);
+ return QIcon(constFirst().first.toString());
} else {
QIcon result;
const int maxDpr = qRound(qApp->devicePixelRatio());
@@ -193,7 +207,7 @@ QPixmap Icon::pixmap(QIcon::Mode iconMode) const
if (isEmpty()) {
return QPixmap();
} else if (m_style == None) {
- return QPixmap(StyleHelper::dpiSpecificImageFile(constFirst().first));
+ return QPixmap(StyleHelper::dpiSpecificImageFile(constFirst().first.toString()));
} else {
const MasksAndColors masks =
masksAndColors(*this, qRound(qApp->devicePixelRatio()));
@@ -204,9 +218,9 @@ QPixmap Icon::pixmap(QIcon::Mode iconMode) const
}
}
-QString Icon::imageFileName() const
+FilePath Icon::imageFilePath() const
{
- QTC_ASSERT(length() == 1, return QString());
+ QTC_ASSERT(length() == 1, return {});
return first().first;
}
diff --git a/src/libs/utils/icon.h b/src/libs/utils/icon.h
index 67c39ac4ee..a0ae7fd3e3 100644
--- a/src/libs/utils/icon.h
+++ b/src/libs/utils/icon.h
@@ -25,8 +25,9 @@
#pragma once
-#include "utils_global.h"
+#include "fileutils.h"
#include "theme/theme.h"
+#include "utils_global.h"
#include <QIcon>
#include <QPair>
@@ -38,7 +39,8 @@ QT_FORWARD_DECLARE_CLASS(QString)
namespace Utils {
-using IconMaskAndColor = QPair<QString, Theme::Color>;
+using IconMaskAndColor = QPair<FilePath, Theme::Color>;
+using IconStringMaskAndColor = QPair<QString, Theme::Color>;
// Returns a recolored icon with shadow and custom disabled state for a
// series of grayscalemask|Theme::Color mask pairs
@@ -59,7 +61,10 @@ public:
Icon();
Icon(std::initializer_list<IconMaskAndColor> args, IconStyleOptions style = ToolBarStyle);
+ Icon(std::initializer_list<IconStringMaskAndColor> args, IconStyleOptions style = ToolBarStyle);
+ Icon(const FilePath &imageFileName);
Icon(const QString &imageFileName);
+
Icon(const Icon &other) = default;
QIcon icon() const;
@@ -68,7 +73,7 @@ public:
// Try to avoid it. it is just there for special API cases in Qt Creator
// where icons are still defined as filename.
- QString imageFileName() const;
+ FilePath imageFilePath() const;
// Returns either the classic or a themed icon depending on
// the current Theme::FlatModeIcons flag.
diff --git a/src/libs/utils/json.cpp b/src/libs/utils/json.cpp
index ff2b5a5948..2d8a8ae75f 100644
--- a/src/libs/utils/json.cpp
+++ b/src/libs/utils/json.cpp
@@ -734,7 +734,7 @@ JsonSchema *JsonSchemaManager::schemaByName(const QString &baseName) const
JsonSchema *JsonSchemaManager::parseSchema(const QString &schemaFileName) const
{
FileReader reader;
- if (reader.fetch(schemaFileName, QIODevice::Text)) {
+ if (reader.fetch(FilePath::fromString(schemaFileName), QIODevice::Text)) {
const QString &contents = QString::fromUtf8(reader.data());
JsonValue *json = JsonValue::create(contents, &m_pool);
if (json && json->kind() == JsonValue::Object)
diff --git a/src/libs/utils/layoutbuilder.cpp b/src/libs/utils/layoutbuilder.cpp
index 2edb07c343..6c76808177 100644
--- a/src/libs/utils/layoutbuilder.cpp
+++ b/src/libs/utils/layoutbuilder.cpp
@@ -31,6 +31,7 @@
#include <QFormLayout>
#include <QGridLayout>
+#include <QGroupBox>
#include <QStyle>
#include <QWidget>
@@ -43,8 +44,10 @@ namespace Utils {
The LayoutType enum describes the type of \c QLayout a layout builder
operates on.
- \value FormLayout
- \value GridLayout
+ \value Form
+ \value Grid
+ \value HBox
+ \value VBox
*/
/*!
@@ -67,19 +70,17 @@ LayoutBuilder::LayoutItem::LayoutItem()
/*!
- Constructs a layout item proxy for \a layout, spanning the number
- of cells specified by \a span in the target layout, with alignment \a align.
+ Constructs a layout item proxy for \a layout.
*/
-LayoutBuilder::LayoutItem::LayoutItem(QLayout *layout, int span, Alignment align)
- : layout(layout), span(span), align(align)
+LayoutBuilder::LayoutItem::LayoutItem(QLayout *layout)
+ : layout(layout)
{}
/*!
- Constructs a layout item proxy for \a widget, spanning the number
- of cell specified by \a span in the target layout, with alignment \a align.
+ Constructs a layout item proxy for \a widget.
*/
-LayoutBuilder::LayoutItem::LayoutItem(QWidget *widget, int span, Alignment align)
- : widget(widget), span(span), align(align)
+LayoutBuilder::LayoutItem::LayoutItem(QWidget *widget)
+ : widget(widget)
{}
/*!
@@ -90,6 +91,10 @@ LayoutBuilder::LayoutItem::LayoutItem(QWidget *widget, int span, Alignment align
\sa BaseAspect::addToLayout()
*/
+LayoutBuilder::LayoutItem::LayoutItem(BaseAspect &aspect)
+ : aspect(&aspect)
+{}
+
LayoutBuilder::LayoutItem::LayoutItem(BaseAspect *aspect)
: aspect(aspect)
{}
@@ -97,7 +102,168 @@ LayoutBuilder::LayoutItem::LayoutItem(BaseAspect *aspect)
/*!
Constructs a layout item containing some static \a text.
*/
-LayoutBuilder::LayoutItem::LayoutItem(const QString &text) : text(text) {}
+LayoutBuilder::LayoutItem::LayoutItem(const QString &text)
+ : text(text)
+{}
+
+static QLayout *createLayoutFromType(LayoutBuilder::LayoutType layoutType)
+{
+ switch (layoutType) {
+ case LayoutBuilder::FormLayout: {
+ auto formLayout = new QFormLayout;
+ formLayout->setFieldGrowthPolicy(QFormLayout::ExpandingFieldsGrow);
+ return formLayout;
+ }
+ case LayoutBuilder::GridLayout: {
+ auto gridLayout = new QGridLayout;
+ return gridLayout;
+ }
+ case LayoutBuilder::HBoxLayout: {
+ auto hboxLayout = new QHBoxLayout;
+ return hboxLayout;
+ }
+ case LayoutBuilder::VBoxLayout: {
+ auto vboxLayout = new QVBoxLayout;
+ return vboxLayout;
+ }
+ }
+ QTC_CHECK(false);
+ return nullptr;
+}
+
+static void setMargins(bool on, QLayout *layout)
+{
+ const int d = on ? 9 : 0;
+ layout->setContentsMargins(d, d, d, d);
+}
+
+static void flushPendingFormItems(QFormLayout *formLayout,
+ LayoutBuilder::LayoutItems &pendingFormItems)
+{
+ QTC_ASSERT(formLayout, return);
+
+ if (pendingFormItems.empty())
+ return;
+
+ // If there are more than two items, we cram the last ones in one hbox.
+ if (pendingFormItems.size() > 2) {
+ auto hbox = new QHBoxLayout;
+ setMargins(false, hbox);
+ for (int i = 1; i < pendingFormItems.size(); ++i) {
+ if (QWidget *w = pendingFormItems.at(i).widget)
+ hbox->addWidget(w);
+ else if (QLayout *l = pendingFormItems.at(i).layout)
+ hbox->addLayout(l);
+ else
+ QTC_CHECK(false);
+ }
+ while (pendingFormItems.size() >= 2)
+ pendingFormItems.pop_back();
+ pendingFormItems.append(LayoutBuilder::LayoutItem(hbox));
+ }
+
+ if (pendingFormItems.size() == 1) { // One one item given, so this spans both columns.
+ if (auto layout = pendingFormItems.at(0).layout)
+ formLayout->addRow(layout);
+ else if (auto widget = pendingFormItems.at(0).widget)
+ formLayout->addRow(widget);
+ } else if (pendingFormItems.size() == 2) { // Normal case, both columns used.
+ if (auto label = pendingFormItems.at(0).widget) {
+ if (auto layout = pendingFormItems.at(1).layout)
+ formLayout->addRow(label, layout);
+ else if (auto widget = pendingFormItems.at(1).widget)
+ formLayout->addRow(label, widget);
+ } else {
+ if (auto layout = pendingFormItems.at(1).layout)
+ formLayout->addRow(pendingFormItems.at(0).text, layout);
+ else if (auto widget = pendingFormItems.at(1).widget)
+ formLayout->addRow(pendingFormItems.at(0).text, widget);
+ }
+ } else {
+ QTC_CHECK(false);
+ }
+
+ pendingFormItems.clear();
+}
+
+static void doLayoutHelper(QLayout *layout,
+ const LayoutBuilder::LayoutItems &items,
+ int currentGridRow = 0)
+{
+ int currentGridColumn = 0;
+ LayoutBuilder::LayoutItems pendingFormItems;
+
+ auto formLayout = qobject_cast<QFormLayout *>(layout);
+ auto gridLayout = qobject_cast<QGridLayout *>(layout);
+ auto boxLayout = qobject_cast<QBoxLayout *>(layout);
+
+ for (const LayoutBuilder::LayoutItem &item : items) {
+ if (item.specialType == LayoutBuilder::SpecialType::Break) {
+ if (formLayout)
+ flushPendingFormItems(formLayout, pendingFormItems);
+ else if (gridLayout) {
+ if (currentGridColumn != 0) {
+ ++currentGridRow;
+ currentGridColumn = 0;
+ }
+ }
+ continue;
+ }
+
+ QWidget *widget = item.widget;
+
+ if (gridLayout) {
+ Qt::Alignment align;
+ if (item.align == LayoutBuilder::AlignmentType::AlignAsFormLabel)
+ align = Qt::Alignment(widget->style()->styleHint(QStyle::SH_FormLayoutLabelAlignment));
+ if (widget)
+ gridLayout->addWidget(widget, currentGridRow, currentGridColumn, 1, item.span, align);
+ else if (item.layout)
+ gridLayout->addLayout(item.layout, currentGridRow, currentGridColumn, 1, item.span, align);
+ currentGridColumn += item.span;
+ } else if (boxLayout) {
+ if (widget) {
+ boxLayout->addWidget(widget);
+ } else if (item.layout) {
+ boxLayout->addLayout(item.layout);
+ } else if (item.specialType == LayoutBuilder::SpecialType::Stretch) {
+ boxLayout->addStretch(item.specialValue.toInt());
+ } else if (item.specialType == LayoutBuilder::SpecialType::Space) {
+ boxLayout->addSpacing(item.specialValue.toInt());
+ }
+ } else {
+ pendingFormItems.append(item);
+ }
+ }
+
+ if (formLayout)
+ flushPendingFormItems(formLayout, pendingFormItems);
+}
+
+
+/*!
+ Constructs a layout item from the contents of another LayoutBuilder
+ */
+LayoutBuilder::LayoutItem::LayoutItem(const LayoutBuilder &builder)
+{
+ layout = createLayoutFromType(builder.m_layoutType);
+ doLayoutHelper(layout, builder.m_items);
+ setMargins(builder.m_withMargins, layout);
+}
+
+/*!
+ \class Utils::LayoutBuilder::Space
+ \inmodule QtCreator
+
+ \brief The LayoutBuilder::Space class represents some empty space in a layout.
+ */
+
+/*!
+ \class Utils::LayoutBuilder::Stretch
+ \inmodule QtCreator
+
+ \brief The LayoutBuilder::Stretch class represents some stretch in a layout.
+ */
/*!
\class Utils::LayoutBuilder
@@ -113,50 +279,20 @@ LayoutBuilder::LayoutItem::LayoutItem(const QString &text) : text(text) {}
\sa addItem(), addItems(), addRow(), finishRow()
*/
-
-/*!
- Constructs a new layout builder with the specified \a layoutType.
-
- The constructed layout will be attached to the provided \c QWidget \a parent.
- */
-LayoutBuilder::LayoutBuilder(QWidget *parent, LayoutType layoutType)
+LayoutBuilder::LayoutBuilder(LayoutType layoutType, const LayoutItems &items)
+ : m_layoutType(layoutType)
{
- if (layoutType == FormLayout) {
- m_formLayout = new QFormLayout(parent);
- m_formLayout->setContentsMargins(0, 0, 0, 0);
- m_formLayout->setFieldGrowthPolicy(QFormLayout::ExpandingFieldsGrow);
- } else {
- m_gridLayout = new QGridLayout(parent);
- m_gridLayout->setContentsMargins(0, 0, 0, 0);
- }
+ m_items.reserve(items.size() * 2);
+ for (const LayoutItem &item : items)
+ addItem(item);
}
-/*!
- Constructs a new layout builder to extend an existing \a layout.
-
- This constructor can be used to continue the work of previous layout building.
- The type of the underlying layout and previous contents will be retained,
- new items will be added below existing ones.
- */
-LayoutBuilder::LayoutBuilder(QLayout *layout)
-{
- if (auto fl = qobject_cast<QFormLayout *>(layout)) {
- m_formLayout = fl;
- } else if (auto grid = qobject_cast<QGridLayout *>(layout)) {
- m_gridLayout = grid;
- m_currentGridRow = grid->rowCount();
- m_currentGridColumn = 0;
- }
-}
+LayoutBuilder::LayoutBuilder() = default;
/*!
Destructs a layout builder.
*/
-LayoutBuilder::~LayoutBuilder()
-{
- if (m_formLayout)
- flushPendingFormItems();
-}
+LayoutBuilder::~LayoutBuilder() = default;
/*!
Instructs a layout builder to finish the current row.
@@ -164,14 +300,7 @@ LayoutBuilder::~LayoutBuilder()
*/
LayoutBuilder &LayoutBuilder::finishRow()
{
- if (m_formLayout)
- flushPendingFormItems();
- if (m_gridLayout) {
- if (m_currentGridColumn != 0) {
- ++m_currentGridRow;
- m_currentGridColumn = 0;
- }
- }
+ addItem(Break());
return *this;
}
@@ -192,106 +321,146 @@ LayoutBuilder &LayoutBuilder::addRow(const LayoutItem &item)
\sa finishRow(), addItem(), addItems()
*/
-LayoutBuilder &LayoutBuilder::addRow(const QList<LayoutBuilder::LayoutItem> &items)
+LayoutBuilder &LayoutBuilder::addRow(const LayoutItems &items)
{
return finishRow().addItems(items);
}
/*!
- \internal
+ Adds the layout item \a item to the current row.
*/
-void LayoutBuilder::flushPendingFormItems()
+LayoutBuilder &LayoutBuilder::addItem(const LayoutItem &item)
{
- QTC_ASSERT(m_formLayout, return);
-
- if (m_pendingFormItems.isEmpty())
- return;
-
- // If there are more than two items, we cram the last ones in one hbox.
- if (m_pendingFormItems.size() > 2) {
- auto hbox = new QHBoxLayout;
- hbox->setContentsMargins(0, 0, 0, 0);
- for (int i = 1; i < m_pendingFormItems.size(); ++i) {
- if (QWidget *w = m_pendingFormItems.at(i).widget)
- hbox->addWidget(w);
- else if (QLayout *l = m_pendingFormItems.at(i).layout)
- hbox->addItem(l);
- else
- QTC_CHECK(false);
- }
- while (m_pendingFormItems.size() >= 2)
- m_pendingFormItems.takeLast();
- m_pendingFormItems.append(LayoutItem(hbox));
- }
-
- if (m_pendingFormItems.size() == 1) { // One one item given, so this spans both columns.
- if (auto layout = m_pendingFormItems.at(0).layout)
- m_formLayout->addRow(layout);
- else if (auto widget = m_pendingFormItems.at(0).widget)
- m_formLayout->addRow(widget);
- } else if (m_pendingFormItems.size() == 2) { // Normal case, both columns used.
- if (auto label = m_pendingFormItems.at(0).widget) {
- if (auto layout = m_pendingFormItems.at(1).layout)
- m_formLayout->addRow(label, layout);
- else if (auto widget = m_pendingFormItems.at(1).widget)
- m_formLayout->addRow(label, widget);
- } else {
- if (auto layout = m_pendingFormItems.at(1).layout)
- m_formLayout->addRow(m_pendingFormItems.at(0).text, layout);
- else if (auto widget = m_pendingFormItems.at(1).widget)
- m_formLayout->addRow(m_pendingFormItems.at(0).text, widget);
- }
+ if (item.aspect) {
+ item.aspect->addToLayout(*this);
+ if (m_layoutType == FormLayout || m_layoutType == VBoxLayout)
+ finishRow();
} else {
- QTC_CHECK(false);
+ m_items.push_back(item);
}
+ return *this;
+}
- m_pendingFormItems.clear();
+void LayoutBuilder::doLayout(QWidget *parent)
+{
+ QLayout *layout = createLayoutFromType(m_layoutType);
+ parent->setLayout(layout);
+
+ doLayoutHelper(layout, m_items);
+ setMargins(m_withMargins, layout);
}
/*!
- Returns the layout this layout builder operates on.
+ Adds the layout item \a items to the current row.
*/
-QLayout *LayoutBuilder::layout() const
+LayoutBuilder &LayoutBuilder::addItems(const LayoutItems &items)
{
- if (m_formLayout)
- return m_formLayout;
- return m_gridLayout;
+ for (const LayoutItem &item : items)
+ addItem(item);
+ return *this;
}
/*!
- Adds the layout item \a item to the current row.
+ Attach the constructed layout to the provided \c QWidget \a parent.
+
+ This operation can only be performed once per LayoutBuilder instance.
*/
-LayoutBuilder &LayoutBuilder::addItem(const LayoutItem &item)
+void LayoutBuilder::attachTo(QWidget *w, bool withMargins)
{
- if (item.widget && !item.widget->parent())
- item.widget->setParent(layout()->parentWidget());
+ m_withMargins = withMargins;
+ doLayout(w);
+}
- if (item.aspect) {
- item.aspect->addToLayout(*this);
- } else {
- if (m_gridLayout) {
- if (auto widget = item.widget) {
- Qt::Alignment align;
- if (item.align == AlignAsFormLabel)
- align = Qt::Alignment(widget->style()->styleHint(QStyle::SH_FormLayoutLabelAlignment));
- m_gridLayout->addWidget(widget, m_currentGridRow, m_currentGridColumn, 1, item.span, align);
- }
- m_currentGridColumn += item.span;
- } else {
- m_pendingFormItems.append(item);
- }
- }
- return *this;
+QWidget *LayoutBuilder::emerge(bool withMargins)
+{
+ m_withMargins = withMargins;
+ auto w = new QWidget;
+ doLayout(w);
+ return w;
}
/*!
- Adds the layout item \a items to the current row.
+ Constructs a layout extender to extend an existing \a layout.
+
+ This constructor can be used to continue the work of previous layout building.
+ The type of the underlying layout and previous contents will be retained,
+ new items will be added below existing ones.
*/
-LayoutBuilder &LayoutBuilder::addItems(const QList<LayoutBuilder::LayoutItem> &items)
+
+LayoutExtender::LayoutExtender(QLayout *layout)
+ : m_layout(layout)
+{}
+
+LayoutExtender::~LayoutExtender()
{
- for (const LayoutItem &item : items)
- addItem(item);
- return *this;
+ QTC_ASSERT(m_layout, return);
+ int currentGridRow = 0;
+ if (auto gridLayout = qobject_cast<QGridLayout *>(m_layout))
+ currentGridRow = gridLayout->rowCount();
+ doLayoutHelper(m_layout, m_items, currentGridRow);
+}
+
+// Special items
+
+LayoutBuilder::Break::Break()
+{
+ specialType = SpecialType::Break;
+}
+
+LayoutBuilder::Stretch::Stretch(int stretch)
+{
+ specialType = SpecialType::Stretch;
+ specialValue = stretch;
+}
+
+LayoutBuilder::Space::Space(int space)
+{
+ specialType = SpecialType::Space;
+ specialValue = space;
+}
+
+LayoutBuilder::Title::Title(const QString &title, BoolAspect *check)
+{
+ specialType = SpecialType::Title;
+ specialValue = title;
+ aspect = check;
+}
+
+LayoutBuilder::Span::Span(int span_, const LayoutItem &item)
+{
+ LayoutBuilder::LayoutItem::operator=(item);
+ span = span_;
+}
+
+LayoutBuilder::AlignAsFormLabel::AlignAsFormLabel(const LayoutItem &item)
+{
+ LayoutBuilder::LayoutItem::operator=(item);
+ align = AlignmentType::AlignAsFormLabel;
+}
+
+namespace Layouting {
+
+Group::Group(std::initializer_list<LayoutItem> items)
+{
+ auto box = new QGroupBox;
+ Column builder;
+ bool innerMargins = true;
+ for (const LayoutItem &item : items) {
+ if (item.specialType == LayoutBuilder::SpecialType::Title) {
+ box->setTitle(item.specialValue.toString());
+ box->setObjectName(item.specialValue.toString());
+ if (auto check = qobject_cast<BoolAspect *>(item.aspect)) {
+ box->setCheckable(true);
+ box->setChecked(check->value());
+ check->setHandlesGroup(box);
+ }
+ } else {
+ builder.addItem(item);
+ }
+ }
+ builder.attachTo(box, innerMargins);
+ widget = box;
}
+} // Layouting
} // Utils
diff --git a/src/libs/utils/layoutbuilder.h b/src/libs/utils/layoutbuilder.h
index 1a2ad1f5e5..a258690416 100644
--- a/src/libs/utils/layoutbuilder.h
+++ b/src/libs/utils/layoutbuilder.h
@@ -29,10 +29,9 @@
#include <QList>
#include <QString>
+#include <QVariant>
QT_BEGIN_NAMESPACE
-class QFormLayout;
-class QGridLayout;
class QLayout;
class QWidget;
QT_END_NAMESPACE
@@ -40,52 +39,174 @@ QT_END_NAMESPACE
namespace Utils {
class BaseAspect;
+class BoolAspect;
class QTCREATOR_UTILS_EXPORT LayoutBuilder
{
public:
- enum LayoutType { GridLayout, FormLayout };
- enum Alignment { DefaultAlignment, AlignAsFormLabel };
+ enum LayoutType {
+ HBoxLayout,
+ VBoxLayout,
+ FormLayout,
+ GridLayout,
+ };
- explicit LayoutBuilder(QWidget *parent, LayoutType layoutType = FormLayout);
- explicit LayoutBuilder(QLayout *layout); // Adds to existing layout.
+ enum class AlignmentType {
+ DefaultAlignment,
+ AlignAsFormLabel,
+ };
- ~LayoutBuilder();
+ enum class SpecialType {
+ NotSpecial,
+ Space,
+ Stretch,
+ Break,
+ Title,
+ };
class QTCREATOR_UTILS_EXPORT LayoutItem
{
public:
LayoutItem();
- LayoutItem(QLayout *layout, int span = 1, Alignment align = {});
- LayoutItem(QWidget *widget, int span = 1, Alignment align = {});
- LayoutItem(BaseAspect *aspect);
+ LayoutItem(QLayout *layout);
+ LayoutItem(QWidget *widget);
+ LayoutItem(BaseAspect *aspect); // Remove
+ LayoutItem(BaseAspect &aspect);
LayoutItem(const QString &text);
+ LayoutItem(const LayoutBuilder &builder);
QLayout *layout = nullptr;
QWidget *widget = nullptr;
BaseAspect *aspect = nullptr;
- QString text;
+
+ QString text; // FIXME: Use specialValue for that
int span = 1;
- Alignment align;
+ AlignmentType align = AlignmentType::DefaultAlignment;
+ SpecialType specialType = SpecialType::NotSpecial;
+ QVariant specialValue;
};
+ using LayoutItems = QList<LayoutItem>;
+
+ explicit LayoutBuilder(LayoutType layoutType, const LayoutItems &items = {});
+
+ LayoutBuilder(const LayoutBuilder &) = delete;
+ LayoutBuilder(LayoutBuilder &&) = default;
+ LayoutBuilder &operator=(const LayoutBuilder &) = delete;
+ LayoutBuilder &operator=(LayoutBuilder &&) = default;
+
+ ~LayoutBuilder();
+
LayoutBuilder &addItem(const LayoutItem &item);
- LayoutBuilder &addItems(const QList<LayoutItem> &items);
+ LayoutBuilder &addItems(const LayoutItems &items);
LayoutBuilder &finishRow();
LayoutBuilder &addRow(const LayoutItem &item);
- LayoutBuilder &addRow(const QList<LayoutItem> &items);
+ LayoutBuilder &addRow(const LayoutItems &items);
+
+ LayoutType layoutType() const { return m_layoutType; }
+
+ void attachTo(QWidget *w, bool withMargins = true);
+ QWidget *emerge(bool withMargins = true);
+
+ class QTCREATOR_UTILS_EXPORT Space : public LayoutItem
+ {
+ public:
+ explicit Space(int space);
+ };
- QLayout *layout() const;
+ class QTCREATOR_UTILS_EXPORT Span : public LayoutItem
+ {
+ public:
+ Span(int span, const LayoutItem &item);
+ };
+
+ class QTCREATOR_UTILS_EXPORT AlignAsFormLabel : public LayoutItem
+ {
+ public:
+ AlignAsFormLabel(const LayoutItem &item);
+ };
+
+ class QTCREATOR_UTILS_EXPORT Stretch : public LayoutItem
+ {
+ public:
+ explicit Stretch(int stretch = 1);
+ };
+
+ class QTCREATOR_UTILS_EXPORT Break : public LayoutItem
+ {
+ public:
+ Break();
+ };
+
+ class QTCREATOR_UTILS_EXPORT Title : public LayoutItem
+ {
+ public:
+ explicit Title(const QString &title, BoolAspect *check = nullptr);
+ };
+
+protected:
+ explicit LayoutBuilder(); // Adds to existing layout.
+
+ void doLayout(QWidget *parent);
+
+ LayoutItems m_items;
+ LayoutType m_layoutType;
+ bool m_withMargins = false;
+};
+
+class QTCREATOR_UTILS_EXPORT LayoutExtender : public LayoutBuilder
+{
+public:
+ explicit LayoutExtender(QLayout *layout);
+ ~LayoutExtender();
private:
- void flushPendingFormItems();
+ QLayout *m_layout = nullptr;
+};
+
+namespace Layouting {
- QFormLayout *m_formLayout = nullptr;
- QGridLayout *m_gridLayout = nullptr;
- QList<LayoutItem> m_pendingFormItems;
- int m_currentGridRow = 0;
- int m_currentGridColumn = 0;
+class QTCREATOR_UTILS_EXPORT Group : public LayoutBuilder::LayoutItem
+{
+public:
+ Group(std::initializer_list<LayoutBuilder::LayoutItem> items);
};
+class QTCREATOR_UTILS_EXPORT Column : public LayoutBuilder
+{
+public:
+ Column() : LayoutBuilder(VBoxLayout) {}
+ Column(std::initializer_list<LayoutItem> items) : LayoutBuilder(VBoxLayout, items) {}
+};
+
+class QTCREATOR_UTILS_EXPORT Row : public LayoutBuilder
+{
+public:
+ Row() : LayoutBuilder(HBoxLayout) {}
+ Row(std::initializer_list<LayoutItem> items) : LayoutBuilder(HBoxLayout, items) {}
+};
+
+class QTCREATOR_UTILS_EXPORT Grid : public LayoutBuilder
+{
+public:
+ Grid() : LayoutBuilder(GridLayout) {}
+ Grid(std::initializer_list<LayoutItem> items) : LayoutBuilder(GridLayout, items) {}
+};
+
+class QTCREATOR_UTILS_EXPORT Form : public LayoutBuilder
+{
+public:
+ Form() : LayoutBuilder(FormLayout) {}
+ Form(std::initializer_list<LayoutItem> items) : LayoutBuilder(FormLayout, items) {}
+};
+
+using Stretch = LayoutBuilder::Stretch;
+using Space = LayoutBuilder::Space;
+using Span = LayoutBuilder::Span;
+using AlignAsFormLabel = LayoutBuilder::AlignAsFormLabel;
+using Break = LayoutBuilder::Break;
+using Title = LayoutBuilder::Title;
+
+}
} // namespace Utils
diff --git a/src/libs/utils/linecolumn.cpp b/src/libs/utils/linecolumn.cpp
new file mode 100644
index 0000000000..de094d9d8f
--- /dev/null
+++ b/src/libs/utils/linecolumn.cpp
@@ -0,0 +1,68 @@
+/****************************************************************************
+**
+** Copyright (C) 2021 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of Qt Creator.
+**
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3 as published by the Free Software
+** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-3.0.html.
+**
+****************************************************************************/
+
+#include "linecolumn.h"
+
+#include <QRegularExpression>
+
+namespace Utils {
+
+/*!
+ Returns the line and column of a \a fileName and sets the \a postfixPos if
+ it can find a positional postfix.
+
+ The following patterns are supported: \c {filepath.txt:19},
+ \c{filepath.txt:19:12}, \c {filepath.txt+19},
+ \c {filepath.txt+19+12}, and \c {filepath.txt(19)}.
+*/
+
+LineColumn LineColumn::extractFromFileName(const QString &fileName, int &postfixPos)
+{
+ static const auto regexp = QRegularExpression("[:+](\\d+)?([:+](\\d+)?)?$");
+ // (10) MSVC-style
+ static const auto vsRegexp = QRegularExpression("[(]((\\d+)[)]?)?$");
+ const QRegularExpressionMatch match = regexp.match(fileName);
+ QString filePath = fileName;
+ LineColumn lineColumn;
+ if (match.hasMatch()) {
+ postfixPos = match.capturedStart(0);
+ filePath = fileName.left(match.capturedStart(0));
+ lineColumn.line = 0; // for the case that there's only a : at the end
+ if (match.lastCapturedIndex() > 0) {
+ lineColumn.line = match.captured(1).toInt();
+ if (match.lastCapturedIndex() > 2) // index 2 includes the + or : for the column number
+ lineColumn.column = match.captured(3).toInt() - 1; //column is 0 based, despite line being 1 based
+ }
+ } else {
+ const QRegularExpressionMatch vsMatch = vsRegexp.match(fileName);
+ postfixPos = match.capturedStart(0);
+ filePath = fileName.left(vsMatch.capturedStart(0));
+ if (vsMatch.lastCapturedIndex() > 1) // index 1 includes closing )
+ lineColumn.line = vsMatch.captured(2).toInt();
+ }
+ return lineColumn;
+}
+
+} // namespace Utils
diff --git a/src/libs/utils/linecolumn.h b/src/libs/utils/linecolumn.h
index 1be72c281d..f592a6d89a 100644
--- a/src/libs/utils/linecolumn.h
+++ b/src/libs/utils/linecolumn.h
@@ -25,22 +25,25 @@
#pragma once
+#include "utils_global.h"
+
#include "optional.h"
#include <QMetaType>
namespace Utils {
-class LineColumn
+class QTCREATOR_UTILS_EXPORT LineColumn
{
public:
constexpr LineColumn() = default;
constexpr
LineColumn(int line, int column)
: line(line),
- column(column)
+ column(column)
{}
+
bool isValid() const
{
return line >= 0 && column >= 0;
@@ -56,6 +59,8 @@ public:
return !(first == second);
}
+ static LineColumn extractFromFileName(const QString &fileName, int &postfixPos);
+
public:
int line = -1;
int column = -1;
diff --git a/src/plugins/mesonprojectmanager/settings/general/generalsettingspage.cpp b/src/libs/utils/link.cpp
index 0b415cf97f..92526909b4 100644
--- a/src/plugins/mesonprojectmanager/settings/general/generalsettingspage.cpp
+++ b/src/libs/utils/link.cpp
@@ -1,6 +1,6 @@
/****************************************************************************
**
-** Copyright (C) 2020 Alexis Jeandet.
+** Copyright (C) 2021 The Qt Company Ltd.
** Contact: https://www.qt.io/licensing/
**
** This file is part of Qt Creator.
@@ -23,30 +23,32 @@
**
****************************************************************************/
-#include "generalsettingspage.h"
+#include "link.h"
-#include "generalsettingswidget.h"
-#include "mesonpluginconstants.h"
-#include "settings.h"
+#include "linecolumn.h"
-namespace MesonProjectManager {
-namespace Internal {
+namespace Utils {
-GeneralSettingsPage::GeneralSettingsPage()
-{
- setId(Constants::SettingsPage::GENERAL_ID);
- setDisplayName(tr("General"));
- setDisplayCategory("Meson");
- setCategory(Constants::SettingsPage::CATEGORY);
- setCategoryIconPath(Constants::Icons::MESON_BW);
- setWidgetCreator([]() { return new GeneralSettingsWidget; });
- Settings::loadAll();
-}
+/*!
+ Returns the Link to \a fileName.
+ If \a canContainLineNumber is true the line number, and column number components
+ are extracted from \a fileName and the found \a postfix is set.
-void GeneralSettingsPage::saveAll()
+ The following patterns are supported: \c {filepath.txt:19},
+ \c{filepath.txt:19:12}, \c {filepath.txt+19},
+ \c {filepath.txt+19+12}, and \c {filepath.txt(19)}.
+*/
+Link Link::fromString(const QString &fileName, bool canContainLineNumber, QString *postfix)
{
- Settings::saveAll();
+ if (!canContainLineNumber)
+ return {Utils::FilePath::fromString(fileName)};
+ int postfixPos = -1;
+ const LineColumn lineColumn = LineColumn::extractFromFileName(fileName, postfixPos);
+ if (postfix && postfixPos >= 0)
+ *postfix = fileName.mid(postfixPos);
+ return {Utils::FilePath::fromString(fileName.left(postfixPos - 1)),
+ lineColumn.line,
+ lineColumn.column};
}
-} // namespace Internal
-} // namespace MesonProjectManager
+} // namespace Utils
diff --git a/src/libs/utils/link.h b/src/libs/utils/link.h
index caf58a0251..08d603ccfd 100644
--- a/src/libs/utils/link.h
+++ b/src/libs/utils/link.h
@@ -25,23 +25,31 @@
#pragma once
+#include <utils/fileutils.h>
+
#include <QString>
#include <qmetatype.h>
#include <functional>
+
namespace Utils {
-struct Link
+class QTCREATOR_UTILS_EXPORT Link
{
- Link(const QString &fileName = QString(), int line = 0, int column = 0)
- : targetFileName(fileName)
+public:
+ Link(const Utils::FilePath &filePath = Utils::FilePath(), int line = 0, int column = 0)
+ : targetFilePath(filePath)
, targetLine(line)
, targetColumn(column)
{}
+ static Link fromString(const QString &fileName,
+ bool canContainLineNumber = false,
+ QString *postfix = nullptr);
+
bool hasValidTarget() const
- { return !targetFileName.isEmpty(); }
+ { return !targetFilePath.isEmpty(); }
bool hasValidLinkText() const
{ return linkTextStart != linkTextEnd; }
@@ -52,7 +60,7 @@ struct Link
int linkTextStart = -1;
int linkTextEnd = -1;
- QString targetFileName;
+ Utils::FilePath targetFilePath;
int targetLine;
int targetColumn;
};
diff --git a/src/libs/utils/macroexpander.cpp b/src/libs/utils/macroexpander.cpp
index 958fe656b8..ddf74bff31 100644
--- a/src/libs/utils/macroexpander.cpp
+++ b/src/libs/utils/macroexpander.cpp
@@ -26,8 +26,9 @@
#include "macroexpander.h"
#include "algorithm.h"
+#include "fileutils.h"
+#include "commandline.h"
#include "qtcassert.h"
-#include "qtcprocess.h"
#include "stringutils.h"
#include <QCoreApplication>
@@ -292,6 +293,11 @@ QString MacroExpander::expand(const QString &stringWithVariables) const
FilePath MacroExpander::expand(const FilePath &fileNameWithVariables) const
{
+ if (fileNameWithVariables.needsDevice()) {
+ QUrl url = fileNameWithVariables.toUrl();
+ url.setPath(expand(url.path()));
+ return FilePath::fromUrl(url);
+ }
return FilePath::fromString(expand(fileNameWithVariables.toString()));
}
@@ -322,7 +328,7 @@ QVariant MacroExpander::expandVariant(const QVariant &v) const
QString MacroExpander::expandProcessArgs(const QString &argsWithVariables) const
{
- return QtcProcess::expandMacros(argsWithVariables, d);
+ return ProcessArgs::expandMacros(argsWithVariables, d);
}
static QByteArray fullPrefix(const QByteArray &prefix)
diff --git a/src/libs/utils/namevaluemodel.cpp b/src/libs/utils/namevaluemodel.cpp
index 0283bd9ba7..697a6b5811 100644
--- a/src/libs/utils/namevaluemodel.cpp
+++ b/src/libs/utils/namevaluemodel.cpp
@@ -167,10 +167,16 @@ QVariant NameValueModel::data(const QModelIndex &index, int role) const
}
QString value = d->m_resultNameValueDictionary.value(resultIterator);
if (role == Qt::ToolTipRole && value.length() > 80) {
- // Use html to enable text wrapping
- value = value.toHtmlEscaped();
- value.prepend(QLatin1String("<html><body>"));
- value.append(QLatin1String("</body></html>"));
+ if (currentEntryIsPathList(index)) {
+ // For path lists, display one entry per line without separator
+ const QChar sep = Utils::HostOsInfo::pathListSeparator();
+ value = value.replace(sep, '\n');
+ } else {
+ // Use html to enable text wrapping
+ value = value.toHtmlEscaped();
+ value.prepend(QLatin1String("<html><body>"));
+ value.append(QLatin1String("</body></html>"));
+ }
}
return value;
}
@@ -437,4 +443,36 @@ void NameValueModel::setUserChanges(const NameValueItems &items)
emit userChangesChanged();
}
+bool NameValueModel::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 = 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;
+ if (varName == "PKG_CONFIG_DIR")
+ return true;
+ if (Utils::HostOsInfo::isWindowsHost()
+ && QStringList{"INCLUDE", "LIB", "LIBPATH"}.contains(varName)) {
+ 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 = data(valueIndex).toString()
+ .split(Utils::HostOsInfo::pathListSeparator(), Qt::SkipEmptyParts);
+ if (entries.length() < 2)
+ return false;
+ return Utils::anyOf(entries, [](const QString &d) { return QFileInfo(d).isDir(); });
+}
+
} // namespace Utils
diff --git a/src/libs/utils/namevaluemodel.h b/src/libs/utils/namevaluemodel.h
index ede319a013..6e6ddfc177 100644
--- a/src/libs/utils/namevaluemodel.h
+++ b/src/libs/utils/namevaluemodel.h
@@ -70,6 +70,7 @@ public:
void setBaseNameValueDictionary(const NameValueDictionary &dictionary);
NameValueItems userChanges() const;
void setUserChanges(const NameValueItems &items);
+ bool currentEntryIsPathList(const QModelIndex &current) const;
signals:
void userChangesChanged();
diff --git a/src/libs/utils/outputformatter.cpp b/src/libs/utils/outputformatter.cpp
index 93111240fa..f0012314c2 100644
--- a/src/libs/utils/outputformatter.cpp
+++ b/src/libs/utils/outputformatter.cpp
@@ -28,8 +28,9 @@
#include "algorithm.h"
#include "ansiescapecodehandler.h"
#include "fileinprojectfinder.h"
+#include "link.h"
#include "qtcassert.h"
-#include "synchronousprocess.h"
+#include "qtcprocess.h"
#include "theme/theme.h"
#include <QDir>
@@ -72,15 +73,14 @@ bool OutputLineParser::isLinkTarget(const QString &target)
return target.startsWith(*linkPrefix());
}
-void OutputLineParser::parseLinkTarget(const QString &target, FilePath &filePath, int &line,
- int &column)
+Link OutputLineParser::parseLinkTarget(const QString &target)
{
const QStringList parts = target.mid(linkPrefix()->length()).split(*linkSep());
if (parts.isEmpty())
- return;
- filePath = FilePath::fromString(parts.first());
- line = parts.length() > 1 ? parts.at(1).toInt() : 0;
- column = parts.length() > 2 ? parts.at(2).toInt() : 0;
+ return {};
+ return Link(FilePath::fromString(parts.first()),
+ parts.length() > 1 ? parts.at(1).toInt() : 0,
+ parts.length() > 2 ? parts.at(2).toInt() : 0);
}
// The redirection mechanism is needed for broken build tools (e.g. xcodebuild) that get invoked
@@ -528,12 +528,10 @@ bool OutputFormatter::handleFileLink(const QString &href)
{
if (!OutputLineParser::isLinkTarget(href))
return false;
- FilePath filePath;
- int line;
- int column;
- OutputLineParser::parseLinkTarget(href, filePath, line, column);
- QTC_ASSERT(!filePath.isEmpty(), return false);
- emit openInEditorRequested(filePath, line, column);
+
+ Link link = OutputLineParser::parseLinkTarget(href);
+ QTC_ASSERT(!link.targetFilePath.isEmpty(), return false);
+ emit openInEditorRequested(link);
return true;
}
@@ -631,7 +629,7 @@ void OutputFormatter::appendMessage(const QString &text, OutputFormat format)
d->prependCarriageReturn = false;
out.prepend('\r');
}
- out = SynchronousProcess::normalizeNewlines(out);
+ out = QtcProcess::normalizeNewlines(out);
if (out.endsWith('\r')) {
d->prependCarriageReturn = true;
out.chop(1);
diff --git a/src/libs/utils/outputformatter.h b/src/libs/utils/outputformatter.h
index 10ec2049f4..76fbc273fa 100644
--- a/src/libs/utils/outputformatter.h
+++ b/src/libs/utils/outputformatter.h
@@ -44,6 +44,7 @@ QT_END_NAMESPACE
namespace Utils {
class FileInProjectFinder;
class FormattedText;
+class Link;
class QTCREATOR_UTILS_EXPORT OutputLineParser : public QObject
{
@@ -72,7 +73,7 @@ public:
};
static bool isLinkTarget(const QString &target);
- static void parseLinkTarget(const QString &target, FilePath &filePath, int &line, int &column);
+ static Utils::Link parseLinkTarget(const QString &target);
void addSearchDir(const Utils::FilePath &dir);
void dropSearchDir(const Utils::FilePath &dir);
@@ -172,7 +173,7 @@ private:
static QTextCharFormat linkFormat(const QTextCharFormat &inputFormat, const QString &href);
signals:
- void openInEditorRequested(const FilePath &filePath, int line, int column);
+ void openInEditorRequested(const Utils::Link &link);
private:
void doAppendMessage(const QString &text, OutputFormat format);
diff --git a/src/libs/utils/pathchooser.cpp b/src/libs/utils/pathchooser.cpp
index 3ee14ab466..c87a64097f 100644
--- a/src/libs/utils/pathchooser.cpp
+++ b/src/libs/utils/pathchooser.cpp
@@ -26,11 +26,10 @@
#include "pathchooser.h"
#include "environment.h"
-#include "qtcassert.h"
-#include "macroexpander.h"
-
-#include "synchronousprocess.h"
#include "hostosinfo.h"
+#include "macroexpander.h"
+#include "qtcassert.h"
+#include "qtcprocess.h"
#include "theme/theme.h"
#include <QDebug>
@@ -152,10 +151,11 @@ QString BinaryVersionToolTipEventFilter::toolVersion(const CommandLine &cmd)
return QString();
SynchronousProcess proc;
proc.setTimeoutS(1);
- SynchronousProcessResponse response = proc.runBlocking(cmd);
- if (response.result != SynchronousProcessResponse::Finished)
+ proc.setCommand(cmd);
+ proc.runBlocking();
+ if (proc.result() != QtcProcess::Finished)
return QString();
- return response.allOutput();
+ return proc.allOutput();
}
// Extends BinaryVersionToolTipEventFilter to prepend the existing pathchooser
diff --git a/src/libs/utils/persistentsettings.cpp b/src/libs/utils/persistentsettings.cpp
index 6b5946ecf8..eda01977de 100644
--- a/src/libs/utils/persistentsettings.cpp
+++ b/src/libs/utils/persistentsettings.cpp
@@ -465,7 +465,7 @@ bool PersistentSettingsWriter::write(const QVariantMap &data, QString *errorStri
{
QDir tmp;
tmp.mkpath(m_fileName.toFileInfo().path());
- FileSaver saver(m_fileName.toString(), QIODevice::Text);
+ FileSaver saver(m_fileName, QIODevice::Text);
if (!saver.hasError()) {
const Context ctx;
QXmlStreamWriter w(saver.file());
diff --git a/src/libs/utils/porting.h b/src/libs/utils/porting.h
index 1b5fa07be8..f8d945a0c4 100644
--- a/src/libs/utils/porting.h
+++ b/src/libs/utils/porting.h
@@ -35,6 +35,7 @@
namespace Utils {
#if QT_VERSION < QT_VERSION_CHECK(5, 14, 0)
+// Keep the support code for lower Qt versions for sdktool
constexpr QString::SplitBehavior SkipEmptyParts = QString::SkipEmptyParts;
#else
constexpr Qt::SplitBehaviorFlags SkipEmptyParts = Qt::SkipEmptyParts;
diff --git a/src/libs/utils/process_ctrlc_stub.cpp b/src/libs/utils/process_ctrlc_stub.cpp
index 951c135265..1c37adec3c 100644
--- a/src/libs/utils/process_ctrlc_stub.cpp
+++ b/src/libs/utils/process_ctrlc_stub.cpp
@@ -46,6 +46,10 @@
#include <cstdlib>
#include <cstdio>
+#ifdef QTCREATOR_PCH_H
+#define CALLBACK WINAPI
+#endif
+
const wchar_t szTitle[] = L"qtcctrlcstub";
const wchar_t szWindowClass[] = L"wcqtcctrlcstub";
const wchar_t szNice[] = L"-nice ";
diff --git a/src/libs/utils/qtcprocess.cpp b/src/libs/utils/qtcprocess.cpp
index 331a882a32..713232a434 100644
--- a/src/libs/utils/qtcprocess.cpp
+++ b/src/libs/utils/qtcprocess.cpp
@@ -24,18 +24,35 @@
****************************************************************************/
#include "qtcprocess.h"
-#include "stringutils.h"
-#include <utils/qtcassert.h>
-#include <utils/hostosinfo.h>
+#include "stringutils.h"
+#include "executeondestruction.h"
+#include "hostosinfo.h"
+#include "commandline.h"
+#include "qtcassert.h"
-#include <QDir>
-#include <QDebug>
#include <QCoreApplication>
-#include <QRegularExpression>
-#include <QStack>
+#include <QDebug>
+#include <QDir>
+#include <QLoggingCategory>
+#include <QTextCodec>
+#include <QThread>
+#include <QTimer>
+
+#ifdef QT_GUI_LIB
+// qmlpuppet does not use that.
+#include <QApplication>
+#include <QMessageBox>
+#endif
+
+#include <algorithm>
+#include <limits.h>
+#include <memory>
#ifdef Q_OS_WIN
+#ifdef QTCREATOR_PCH_H
+#define CALLBACK WINAPI
+#endif
#include <qt_windows.h>
#else
#include <errno.h>
@@ -44,650 +61,151 @@
#endif
-// The main state of the Unix shell parser
-enum MxQuoting { MxBasic, MxSingleQuote, MxDoubleQuote, MxParen, MxSubst, MxGroup, MxMath };
-
-struct MxState
-{
- MxQuoting current;
- // Bizarrely enough, double quoting has an impact on the behavior of some
- // complex expressions within the quoted string.
- bool dquote;
-};
-QT_BEGIN_NAMESPACE
-Q_DECLARE_TYPEINFO(MxState, Q_PRIMITIVE_TYPE);
-QT_END_NAMESPACE
-
-// Pushed state for the case where a $(()) expansion turns out bogus
-struct MxSave
-{
- QString str;
- int pos, varPos;
-};
-QT_BEGIN_NAMESPACE
-Q_DECLARE_TYPEINFO(MxSave, Q_MOVABLE_TYPE);
-QT_END_NAMESPACE
+using namespace Utils::Internal;
namespace Utils {
+namespace Internal {
-/*!
- \class Utils::QtcProcess
-
- \brief The QtcProcess class provides functionality for dealing with
- shell-quoted process arguments.
-*/
-
-inline static bool isMetaCharWin(ushort c)
-{
- static const uchar iqm[] = {
- 0x00, 0x00, 0x00, 0x00, 0x40, 0x03, 0x00, 0x50,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10
- }; // &()<>|
-
- return (c < sizeof(iqm) * 8) && (iqm[c / 8] & (1 << (c & 7)));
-}
-
-static void envExpandWin(QString &args, const Environment *env, const QString *pwd)
-{
- static const QString cdName = QLatin1String("CD");
- int off = 0;
- next:
- for (int prev = -1, that;
- (that = args.indexOf(QLatin1Char('%'), off)) >= 0;
- prev = that, off = that + 1) {
- if (prev >= 0) {
- const QString var = args.mid(prev + 1, that - prev - 1).toUpper();
- const QString val = (var == cdName && pwd && !pwd->isEmpty())
- ? QDir::toNativeSeparators(*pwd) : env->expandedValueForKey(var);
- if (!val.isEmpty()) { // Empty values are impossible, so this is an existence check
- args.replace(prev, that - prev + 1, val);
- off = prev + val.length();
- goto next;
- }
- }
- }
-}
-
-static QtcProcess::Arguments prepareArgsWin(const QString &_args, QtcProcess::SplitError *err,
- const Environment *env, const QString *pwd)
-{
- QString args(_args);
+enum { debug = 0 };
+enum { syncDebug = 0 };
- if (env) {
- envExpandWin(args, env, pwd);
- } else {
- if (args.indexOf(QLatin1Char('%')) >= 0) {
- if (err)
- *err = QtcProcess::FoundMeta;
- return QtcProcess::Arguments::createWindowsArgs(QString());
- }
- }
+enum { defaultMaxHangTimerCount = 10 };
- if (!args.isEmpty() && args.unicode()[0].unicode() == '@')
- args.remove(0, 1);
-
- for (int p = 0; p < args.length(); p++) {
- ushort c = args.unicode()[p].unicode();
- if (c == '^') {
- args.remove(p, 1);
- } else if (c == '"') {
- do {
- if (++p == args.length())
- break; // For cmd, this is no error.
- } while (args.unicode()[p].unicode() != '"');
- } else if (isMetaCharWin(c)) {
- if (err)
- *err = QtcProcess::FoundMeta;
- return QtcProcess::Arguments::createWindowsArgs(QString());
- }
- }
+static Q_LOGGING_CATEGORY(processLog, "qtc.utils.synchronousprocess", QtWarningMsg);
- if (err)
- *err = QtcProcess::SplitOk;
- return QtcProcess::Arguments::createWindowsArgs(args);
-}
+static DeviceProcessHooks s_deviceHooks;
-inline static bool isWhiteSpaceWin(ushort c)
+// Data for one channel buffer (stderr/stdout)
+class ChannelBuffer
{
- return c == ' ' || c == '\t';
-}
+public:
+ void clearForRun();
-static QStringList doSplitArgsWin(const QString &args, QtcProcess::SplitError *err)
-{
- QStringList ret;
-
- if (err)
- *err = QtcProcess::SplitOk;
-
- int p = 0;
- const int length = args.length();
- forever {
- forever {
- if (p == length)
- return ret;
- if (!isWhiteSpaceWin(args.unicode()[p].unicode()))
- break;
- ++p;
- }
+ QString linesRead();
+ void append(const QByteArray &text, bool emitSignals);
- QString arg;
- bool inquote = false;
- forever {
- bool copy = true; // copy this char
- int bslashes = 0; // number of preceding backslashes to insert
- while (p < length && args.unicode()[p] == QLatin1Char('\\')) {
- ++p;
- ++bslashes;
- }
- if (p < length && args.unicode()[p] == QLatin1Char('"')) {
- if (!(bslashes & 1)) {
- // Even number of backslashes, so the quote is not escaped.
- if (inquote) {
- if (p + 1 < length && args.unicode()[p + 1] == QLatin1Char('"')) {
- // This is not documented on MSDN.
- // Two consecutive quotes make a literal quote. Brain damage:
- // this still closes the quoting, so a 3rd quote is required,
- // which makes the runtime's quoting run out of sync with the
- // shell's one unless the 2nd quote is escaped.
- ++p;
- } else {
- // Closing quote
- copy = false;
- }
- inquote = false;
- } else {
- // Opening quote
- copy = false;
- inquote = true;
- }
- }
- bslashes >>= 1;
- }
-
- while (--bslashes >= 0)
- arg.append(QLatin1Char('\\'));
-
- if (p == length || (!inquote && isWhiteSpaceWin(args.unicode()[p].unicode()))) {
- ret.append(arg);
- if (inquote) {
- if (err)
- *err = QtcProcess::BadQuoting;
- return QStringList();
- }
- break;
- }
-
- if (copy)
- arg.append(args.unicode()[p]);
- ++p;
- }
- }
- //not reached
-}
-
-/*!
- Splits \a _args according to system shell word splitting and quoting rules.
-
- \section1 Unix
-
- The behavior is based on the POSIX shell and bash:
- \list
- \li Whitespace splits tokens.
- \li The backslash quotes the following character.
- \li A string enclosed in single quotes is not split. No shell meta
- characters are interpreted.
- \li A string enclosed in double quotes is not split. Within the string,
- the backslash quotes shell meta characters - if it is followed
- by a "meaningless" character, the backslash is output verbatim.
- \endlist
- If \a abortOnMeta is \c false, only the splitting and quoting rules apply,
- while other meta characters (substitutions, redirections, etc.) are ignored.
- If \a abortOnMeta is \c true, encounters of unhandled meta characters are
- treated as errors.
-
- If \a err is not NULL, stores a status code at the pointer target. For more
- information, see \l SplitError.
-
- If \env is not NULL, performs variable substitution with the
- given environment.
-
- Returns a list of unquoted words or an empty list if an error occurred.
-
- \section1 Windows
-
- The behavior is defined by the Microsoft C runtime:
- \list
- \li Whitespace splits tokens.
- \li A string enclosed in double quotes is not split.
- \list
- \li 3N double quotes within a quoted string yield N literal quotes.
- This is not documented on MSDN.
- \endlist
- \li Backslashes have special semantics if they are followed by a double quote:
- \list
- \li 2N backslashes + double quote => N backslashes and begin/end quoting
- \li 2N+1 backslashes + double quote => N backslashes + literal quote
- \endlist
- \endlist
- Qt and many other implementations comply with this standard, but many do not.
-
- If \a abortOnMeta is \c true, cmd shell semantics are applied before
- proceeding with word splitting:
- \list
- \li Cmd ignores \e all special chars between double quotes.
- Note that the quotes are \e not removed at this stage - the
- tokenization rules described above still apply.
- \li The \c circumflex is the escape char for everything including itself.
- \endlist
- As the quoting levels are independent from each other and have different
- semantics, you need a command line like \c{"foo "\^"" bar"} to get
- \c{foo " bar}.
- */
-
-
-static QStringList splitArgsWin(const QString &_args, bool abortOnMeta,
- QtcProcess::SplitError *err,
- const Environment *env, const QString *pwd)
-{
- if (abortOnMeta) {
- QtcProcess::SplitError perr;
- if (!err)
- err = &perr;
- QString args = prepareArgsWin(_args, &perr, env, pwd).toWindowsArgs();
- if (*err != QtcProcess::SplitOk)
- return QStringList();
- return doSplitArgsWin(args, err);
- } else {
- QString args = _args;
- if (env)
- envExpandWin(args, env, pwd);
- return doSplitArgsWin(args, err);
- }
-}
-
-
-static bool isMetaUnix(QChar cUnicode)
-{
- static const uchar iqm[] = {
- 0x00, 0x00, 0x00, 0x00, 0xdc, 0x07, 0x00, 0xd8,
- 0x00, 0x00, 0x00, 0x38, 0x01, 0x00, 0x00, 0x38
- }; // \'"$`<>|;&(){}*?#[]
-
- uint c = cUnicode.unicode();
-
- return (c < sizeof(iqm) * 8) && (iqm[c / 8] & (1 << (c & 7)));
-}
-
-static QStringList splitArgsUnix(const QString &args, bool abortOnMeta,
- QtcProcess::SplitError *err,
- const Environment *env, const QString *pwd)
-{
- static const QString pwdName = QLatin1String("PWD");
- QStringList ret;
-
- for (int pos = 0; ; ) {
- QChar c;
- do {
- if (pos >= args.length())
- goto okret;
- c = args.unicode()[pos++];
- } while (c.isSpace());
- QString cret;
- bool hadWord = false;
- if (c == QLatin1Char('~')) {
- if (pos >= args.length()
- || args.unicode()[pos].isSpace() || args.unicode()[pos] == QLatin1Char('/')) {
- cret = QDir::homePath();
- hadWord = true;
- goto getc;
- } else if (abortOnMeta) {
- goto metaerr;
- }
- }
- do {
- if (c == QLatin1Char('\'')) {
- int spos = pos;
- do {
- if (pos >= args.length())
- goto quoteerr;
- c = args.unicode()[pos++];
- } while (c != QLatin1Char('\''));
- cret += args.mid(spos, pos - spos - 1);
- hadWord = true;
- } else if (c == QLatin1Char('"')) {
- for (;;) {
- if (pos >= args.length())
- goto quoteerr;
- c = args.unicode()[pos++];
- nextq:
- if (c == QLatin1Char('"'))
- break;
- if (c == QLatin1Char('\\')) {
- if (pos >= args.length())
- goto quoteerr;
- c = args.unicode()[pos++];
- if (c != QLatin1Char('"') &&
- c != QLatin1Char('\\') &&
- !(abortOnMeta &&
- (c == QLatin1Char('$') ||
- c == QLatin1Char('`'))))
- cret += QLatin1Char('\\');
- } else if (c == QLatin1Char('$') && env) {
- if (pos >= args.length())
- goto quoteerr;
- c = args.unicode()[pos++];
- bool braced = false;
- if (c == QLatin1Char('{')) {
- if (pos >= args.length())
- goto quoteerr;
- c = args.unicode()[pos++];
- braced = true;
- }
- QString var;
- while (c.isLetterOrNumber() || c == QLatin1Char('_')) {
- var += c;
- if (pos >= args.length())
- goto quoteerr;
- c = args.unicode()[pos++];
- }
- if (var == pwdName && pwd && !pwd->isEmpty()) {
- cret += *pwd;
- } else {
- Environment::const_iterator vit = env->constFind(var);
- if (vit == env->constEnd()) {
- if (abortOnMeta)
- goto metaerr; // Assume this is a shell builtin
- } else {
- cret += env->expandedValueForKey(env->key(vit));
- }
- }
- if (!braced)
- goto nextq;
- if (c != QLatin1Char('}')) {
- if (abortOnMeta)
- goto metaerr; // Assume this is a complex expansion
- goto quoteerr; // Otherwise it's just garbage
- }
- continue;
- } else if (abortOnMeta &&
- (c == QLatin1Char('$') ||
- c == QLatin1Char('`'))) {
- goto metaerr;
- }
- cret += c;
- }
- hadWord = true;
- } else if (c == QLatin1Char('$') && env) {
- if (pos >= args.length())
- goto quoteerr; // Bash just takes it verbatim, but whatever
- c = args.unicode()[pos++];
- bool braced = false;
- if (c == QLatin1Char('{')) {
- if (pos >= args.length())
- goto quoteerr;
- c = args.unicode()[pos++];
- braced = true;
- }
- QString var;
- while (c.isLetterOrNumber() || c == QLatin1Char('_')) {
- var += c;
- if (pos >= args.length()) {
- if (braced)
- goto quoteerr;
- c = QLatin1Char(' ');
- break;
- }
- c = args.unicode()[pos++];
- }
- QString val;
- if (var == pwdName && pwd && !pwd->isEmpty()) {
- val = *pwd;
- } else {
- Environment::const_iterator vit = env->constFind(var);
- if (vit == env->constEnd()) {
- if (abortOnMeta)
- goto metaerr; // Assume this is a shell builtin
- } else {
- val = env->expandedValueForKey(env->key(vit));
- }
- }
- for (int i = 0; i < val.length(); i++) {
- const QChar cc = val.unicode()[i];
- if (cc.unicode() == 9 || cc.unicode() == 10 || cc.unicode() == 32) {
- if (hadWord) {
- ret += cret;
- cret.clear();
- hadWord = false;
- }
- } else {
- cret += cc;
- hadWord = true;
- }
- }
- if (!braced)
- goto nextc;
- if (c != QLatin1Char('}')) {
- if (abortOnMeta)
- goto metaerr; // Assume this is a complex expansion
- goto quoteerr; // Otherwise it's just garbage
- }
- } else {
- if (c == QLatin1Char('\\')) {
- if (pos >= args.length())
- goto quoteerr;
- c = args.unicode()[pos++];
- } else if (abortOnMeta && isMetaUnix(c)) {
- goto metaerr;
- }
- cret += c;
- hadWord = true;
- }
- getc:
- if (pos >= args.length())
- break;
- c = args.unicode()[pos++];
- nextc: ;
- } while (!c.isSpace());
- if (hadWord)
- ret += cret;
- }
-
- okret:
- if (err)
- *err = QtcProcess::SplitOk;
- return ret;
-
- quoteerr:
- if (err)
- *err = QtcProcess::BadQuoting;
- return QStringList();
-
- metaerr:
- if (err)
- *err = QtcProcess::FoundMeta;
- return QStringList();
-}
-
-inline static bool isSpecialCharUnix(ushort c)
-{
- // Chars that should be quoted (TM). This includes:
- static const uchar iqm[] = {
- 0xff, 0xff, 0xff, 0xff, 0xdf, 0x07, 0x00, 0xd8,
- 0x00, 0x00, 0x00, 0x38, 0x01, 0x00, 0x00, 0x78
- }; // 0-32 \'"$`<>|;&(){}*?#!~[]
-
- return (c < sizeof(iqm) * 8) && (iqm[c / 8] & (1 << (c & 7)));
-}
-
-inline static bool hasSpecialCharsUnix(const QString &arg)
-{
- for (int x = arg.length() - 1; x >= 0; --x)
- if (isSpecialCharUnix(arg.unicode()[x].unicode()))
- return true;
- return false;
-}
+ QByteArray rawData;
+ QString incompleteLineBuffer; // lines not yet signaled
+ QTextCodec *codec = nullptr; // Not owner
+ std::unique_ptr<QTextCodec::ConverterState> codecState;
+ int rawDataPos = 0;
+ std::function<void(const QString &lines)> outputCallback;
+};
-QStringList QtcProcess::splitArgs(const QString &args, OsType osType,
- bool abortOnMeta, QtcProcess::SplitError *err,
- const Environment *env, const QString *pwd)
-{
- if (osType == OsTypeWindows)
- return splitArgsWin(args, abortOnMeta, err, env, pwd);
- else
- return splitArgsUnix(args, abortOnMeta, err, env, pwd);
-}
+class QtcProcessPrivate : public QObject
+{
+public:
+ explicit QtcProcessPrivate(QtcProcess *parent) : q(parent) {}
+
+ void setupChildProcess_impl();
+
+ CommandLine m_commandLine;
+ Environment m_environment;
+ QByteArray m_writeData;
+ bool m_haveEnv = false;
+ bool m_useCtrlCStub = false;
+ bool m_lowPriority = false;
+ bool m_disableUnixTerminal = false;
+
+ QProcess::OpenMode m_openMode = QProcess::ReadWrite;
+
+ // SynchronousProcess left overs:
+ void slotTimeout();
+ void slotFinished(int exitCode, QProcess::ExitStatus e);
+ void slotError(QProcess::ProcessError);
+ void clearForRun();
+
+ QtcProcess::Result interpretExitCode(int exitCode);
+
+ QtcProcess *q;
+ QTextCodec *m_codec = QTextCodec::codecForLocale();
+ QTimer m_timer;
+ QEventLoop m_eventLoop;
+ QtcProcess::Result m_result = QtcProcess::StartFailed;
+ int m_exitCode = -1;
+ FilePath m_binary;
+ ChannelBuffer m_stdOut;
+ ChannelBuffer m_stdErr;
+ ExitCodeInterpreter m_exitCodeInterpreter;
+
+ int m_hangTimerCount = 0;
+ int m_maxHangTimerCount = defaultMaxHangTimerCount;
+ bool m_startFailure = false;
+ bool m_timeOutMessageBoxEnabled = false;
+ bool m_waitingForUser = false;
+ bool m_isSynchronousProcess = false;
+ bool m_processUserEvents = false;
+};
-QString QtcProcess::quoteArgUnix(const QString &arg)
+void QtcProcessPrivate::clearForRun()
{
- if (arg.isEmpty())
- return QString::fromLatin1("''");
-
- QString ret(arg);
- if (hasSpecialCharsUnix(ret)) {
- ret.replace(QLatin1Char('\''), QLatin1String("'\\''"));
- ret.prepend(QLatin1Char('\''));
- ret.append(QLatin1Char('\''));
- }
- return ret;
+ m_hangTimerCount = 0;
+ m_stdOut.clearForRun();
+ m_stdOut.codec = m_codec;
+ m_stdErr.clearForRun();
+ m_stdErr.codec = m_codec;
+ m_result = QtcProcess::StartFailed;
+ m_exitCode = -1;
+ m_startFailure = false;
+ m_binary = {};
}
-static bool isSpecialCharWin(ushort c)
+QtcProcess::Result QtcProcessPrivate::interpretExitCode(int exitCode)
{
- // Chars that should be quoted (TM). This includes:
- // - control chars & space
- // - the shell meta chars "&()<>^|
- // - the potential separators ,;=
- static const uchar iqm[] = {
- 0xff, 0xff, 0xff, 0xff, 0x45, 0x13, 0x00, 0x78,
- 0x00, 0x00, 0x00, 0x40, 0x00, 0x00, 0x00, 0x10
- };
+ if (m_exitCodeInterpreter)
+ return m_exitCodeInterpreter(exitCode);
- return (c < sizeof(iqm) * 8) && (iqm[c / 8] & (1 << (c & 7)));
+ // default:
+ return exitCode ? QtcProcess::FinishedError : QtcProcess::Finished;
}
-static bool hasSpecialCharsWin(const QString &arg)
-{
- for (int x = arg.length() - 1; x >= 0; --x)
- if (isSpecialCharWin(arg.unicode()[x].unicode()))
- return true;
- return false;
-}
+} // Internal
-static QString quoteArgWin(const QString &arg)
-{
- if (arg.isEmpty())
- return QString::fromLatin1("\"\"");
-
- QString ret(arg);
- if (hasSpecialCharsWin(ret)) {
- // Quotes are escaped and their preceding backslashes are doubled.
- // It's impossible to escape anything inside a quoted string on cmd
- // level, so the outer quoting must be "suspended".
- ret.replace(QRegularExpression(QLatin1String("(\\\\*)\"")), QLatin1String("\"\\1\\1\\^\"\""));
- // The argument must not end with a \ since this would be interpreted
- // as escaping the quote -- rather put the \ behind the quote: e.g.
- // rather use "foo"\ than "foo\"
- int i = ret.length();
- while (i > 0 && ret.at(i - 1) == QLatin1Char('\\'))
- --i;
- ret.insert(i, QLatin1Char('"'));
- ret.prepend(QLatin1Char('"'));
- }
- // FIXME: Without this, quoting is not foolproof. But it needs support in the process setup, etc.
- //ret.replace('%', QLatin1String("%PERCENT_SIGN%"));
- return ret;
-}
+/*!
+ \class Utils::QtcProcess
-QtcProcess::Arguments QtcProcess::prepareArgs(const QString &cmd, SplitError *err, OsType osType,
- const Environment *env, const QString *pwd, bool abortOnMeta)
-{
- if (osType == OsTypeWindows)
- return prepareArgsWin(cmd, err, env, pwd);
- else
- return Arguments::createUnixArgs(splitArgs(cmd, osType, abortOnMeta, err, env, pwd));
-}
+ \brief The QtcProcess class provides functionality for with processes.
+ \sa Utils::ProcessArgs
+*/
-QString QtcProcess::quoteArg(const QString &arg, OsType osType)
+QtcProcess::QtcProcess(QObject *parent)
+ : QProcess(parent), d(new QtcProcessPrivate(this))
{
- if (osType == OsTypeWindows)
- return quoteArgWin(arg);
- else
- return quoteArgUnix(arg);
-}
+ static int qProcessExitStatusMeta = qRegisterMetaType<QProcess::ExitStatus>();
+ static int qProcessProcessErrorMeta = qRegisterMetaType<QProcess::ProcessError>();
+ Q_UNUSED(qProcessExitStatusMeta)
+ Q_UNUSED(qProcessProcessErrorMeta)
-void QtcProcess::addArg(QString *args, const QString &arg, OsType osType)
-{
- if (!args->isEmpty())
- *args += QLatin1Char(' ');
- *args += quoteArg(arg, osType);
+#if QT_VERSION >= QT_VERSION_CHECK(6, 0, 0) && defined(Q_OS_UNIX)
+ setChildProcessModifier([this] { d->setupChildProcess_impl(); });
+#endif
}
-QString QtcProcess::joinArgs(const QStringList &args, OsType osType)
+QtcProcess::~QtcProcess()
{
- QString ret;
- for (const QString &arg : args)
- addArg(&ret, arg, osType);
- return ret;
+ delete d;
}
-void QtcProcess::addArgs(QString *args, const QString &inArgs)
+void QtcProcess::setEnvironment(const Environment &env)
{
- if (!inArgs.isEmpty()) {
- if (!args->isEmpty())
- *args += QLatin1Char(' ');
- *args += inArgs;
- }
+ d->m_environment = env;
+ d->m_haveEnv = true;
}
-void QtcProcess::addArgs(QString *args, const QStringList &inArgs)
+const Environment &QtcProcess::environment() const
{
- for (const QString &arg : inArgs)
- addArg(args, arg);
+ return d->m_environment;
}
-bool QtcProcess::prepareCommand(const QString &command, const QString &arguments,
- QString *outCmd, Arguments *outArgs, OsType osType,
- const Environment *env, const QString *pwd)
+void QtcProcess::setCommand(const CommandLine &cmdLine)
{
- QtcProcess::SplitError err;
- *outArgs = QtcProcess::prepareArgs(arguments, &err, osType, env, pwd);
- if (err == QtcProcess::SplitOk) {
- *outCmd = command;
- } else {
- if (osType == OsTypeWindows) {
- *outCmd = QString::fromLatin1(qgetenv("COMSPEC"));
- *outArgs = Arguments::createWindowsArgs(QLatin1String("/v:off /s /c \"")
- + quoteArg(QDir::toNativeSeparators(command)) + QLatin1Char(' ') + arguments
- + QLatin1Char('"'));
- } else {
- if (err != QtcProcess::FoundMeta)
- return false;
-#if QT_VERSION >= QT_VERSION_CHECK(5, 10, 0)
- *outCmd = qEnvironmentVariable("SHELL", "/bin/sh");
-#else
- // for sdktool
- *outCmd = qEnvironmentVariableIsSet("SHELL") ? QString::fromLocal8Bit(qgetenv("SHELL"))
- : QString("/bin/sh");
-#endif
- *outArgs = Arguments::createUnixArgs(
- QStringList({"-c", (quoteArg(command) + ' ' + arguments)}));
- }
- }
- return true;
+ d->m_commandLine = cmdLine;
}
-QtcProcess::QtcProcess(QObject *parent)
- : QProcess(parent)
+const CommandLine &QtcProcess::commandLine() const
{
- static int qProcessExitStatusMeta = qRegisterMetaType<QProcess::ExitStatus>();
- static int qProcessProcessErrorMeta = qRegisterMetaType<QProcess::ProcessError>();
- Q_UNUSED(qProcessExitStatusMeta)
- Q_UNUSED(qProcessProcessErrorMeta)
-
-#if QT_VERSION >= QT_VERSION_CHECK(6, 0, 0) && defined(Q_OS_UNIX)
- setChildProcessModifier([this] { setupChildProcess_impl(); });
-#endif
+ return d->m_commandLine;
}
void QtcProcess::setUseCtrlCStub(bool enabled)
@@ -696,7 +214,7 @@ void QtcProcess::setUseCtrlCStub(bool enabled)
// Qt Creator otherwise, because they share the same Windows console.
// See QTCREATORBUG-11995 for details.
#ifndef QT_DEBUG
- m_useCtrlCStub = enabled;
+ d->m_useCtrlCStub = enabled;
#else
Q_UNUSED(enabled)
#endif
@@ -704,13 +222,21 @@ void QtcProcess::setUseCtrlCStub(bool enabled)
void QtcProcess::start()
{
+ QTC_CHECK(d->m_writeData.isEmpty()); // FIXME: Use it.
+
+ if (d->m_commandLine.executable().needsDevice()) {
+ QTC_ASSERT(s_deviceHooks.startProcessHook, return);
+ s_deviceHooks.startProcessHook(*this);
+ return;
+ }
+
Environment env;
const OsType osType = HostOsInfo::hostOs();
- if (m_haveEnv) {
- if (m_environment.size() == 0)
+ if (d->m_haveEnv) {
+ if (d->m_environment.size() == 0)
qWarning("QtcProcess::start: Empty environment set when running '%s'.",
- qPrintable(m_commandLine.executable().toString()));
- env = m_environment;
+ qPrintable(d->m_commandLine.executable().toString()));
+ env = d->m_environment;
QProcess::setProcessEnvironment(env.toProcessEnvironment());
} else {
@@ -719,32 +245,32 @@ void QtcProcess::start()
const QString &workDir = workingDirectory();
QString command;
- QtcProcess::Arguments arguments;
- bool success = prepareCommand(m_commandLine.executable().toString(),
- m_commandLine.arguments(),
- &command, &arguments, osType, &env, &workDir);
+ ProcessArgs arguments;
+ bool success = ProcessArgs::prepareCommand(d->m_commandLine.executable().toString(),
+ d->m_commandLine.arguments(),
+ &command, &arguments, osType, &env, &workDir);
if (osType == OsTypeWindows) {
QString args;
- if (m_useCtrlCStub) {
- if (m_lowPriority)
- addArg(&args, "-nice");
- addArg(&args, QDir::toNativeSeparators(command));
+ if (d->m_useCtrlCStub) {
+ if (d->m_lowPriority)
+ ProcessArgs::addArg(&args, "-nice");
+ ProcessArgs::addArg(&args, QDir::toNativeSeparators(command));
command = QCoreApplication::applicationDirPath()
+ QLatin1String("/qtcreator_ctrlc_stub.exe");
- } else if (m_lowPriority) {
+ } else if (d->m_lowPriority) {
#ifdef Q_OS_WIN
setCreateProcessArgumentsModifier([](CreateProcessArguments *args) {
args->flags |= BELOW_NORMAL_PRIORITY_CLASS;
});
#endif
}
- QtcProcess::addArgs(&args, arguments.toWindowsArgs());
+ ProcessArgs::addArgs(&args, arguments.toWindowsArgs());
#ifdef Q_OS_WIN
setNativeArguments(args);
#endif
// Note: Arguments set with setNativeArgs will be appended to the ones
// passed with start() below.
- QProcess::start(command, QStringList());
+ QProcess::start(command, QStringList(), d->m_openMode);
} else {
if (!success) {
setErrorString(tr("Error in command line."));
@@ -753,7 +279,7 @@ void QtcProcess::start()
emit errorOccurred(QProcess::UnknownError);
return;
}
- QProcess::start(command, arguments.toUnixArgs());
+ QProcess::start(command, arguments.toUnixArgs(), d->m_openMode);
}
}
@@ -785,7 +311,7 @@ BOOL CALLBACK sendInterruptMessageToAllWindowsOfProcess_enumWnd(HWND hwnd, LPARA
void QtcProcess::terminate()
{
#ifdef Q_OS_WIN
- if (m_useCtrlCStub)
+ if (d->m_useCtrlCStub)
EnumWindows(sendShutDownMessageToAllWindowsOfProcess_enumWnd, processId());
else
#endif
@@ -795,449 +321,34 @@ void QtcProcess::terminate()
void QtcProcess::interrupt()
{
#ifdef Q_OS_WIN
- QTC_ASSERT(m_useCtrlCStub, return);
+ QTC_ASSERT(d->m_useCtrlCStub, return);
EnumWindows(sendInterruptMessageToAllWindowsOfProcess_enumWnd, processId());
#endif
}
-// This function assumes that the resulting string will be quoted.
-// That's irrelevant if it does not contain quotes itself.
-static int quoteArgInternalWin(QString &ret, int bslashes)
+void QtcProcess::setLowPriority()
{
- // Quotes are escaped and their preceding backslashes are doubled.
- // It's impossible to escape anything inside a quoted string on cmd
- // level, so the outer quoting must be "suspended".
- const QChar bs(QLatin1Char('\\')), dq(QLatin1Char('"'));
- for (int p = 0; p < ret.length(); p++) {
- if (ret.at(p) == bs) {
- bslashes++;
- } else {
- if (ret.at(p) == dq) {
- if (bslashes) {
- ret.insert(p, QString(bslashes, bs));
- p += bslashes;
- }
- ret.insert(p, QLatin1String("\"\\^\""));
- p += 4;
- }
- bslashes = 0;
- }
- }
- return bslashes;
+ d->m_lowPriority = true;
}
-
-// TODO: This documentation is relevant for end-users. Where to put it?
-/**
- * Perform safe macro expansion (substitution) on a string for use
- * in shell commands.
- *
- * \section Unix notes
- *
- * Explicitly supported shell constructs:
- * \\ '' "" {} () $(()) ${} $() ``
- *
- * Implicitly supported shell constructs:
- * (())
- *
- * Unsupported shell constructs that will cause problems:
- * \list
- * \li Shortened \c{case $v in pat)} syntax. Use \c{case $v in (pat)} instead.
- * \li Bash-style \c{$""} and \c{$''} string quoting syntax.
- * \endlist
- *
- * The rest of the shell (incl. bash) syntax is simply ignored,
- * as it is not expected to cause problems.
- *
- * Security considerations:
- * \list
- * \li Backslash-escaping an expando is treated as a quoting error
- * \li Do not put expandos into double quoted substitutions:
- * \badcode
- * "${VAR:-%{macro}}"
- * \endcode
- * \li Do not put expandos into command line arguments which are nested
- * shell commands:
- * \badcode
- * sh -c 'foo \%{file}'
- * \endcode
- * \goodcode
- * file=\%{file} sh -c 'foo "$file"'
- * \endcode
- * \endlist
- *
- * \section Windows notes
- *
- * All quoting syntax supported by splitArgs() is supported here as well.
- * Additionally, command grouping via parentheses is recognized - note
- * however, that the parser is much stricter about unquoted parentheses
- * than cmd itself.
- * The rest of the cmd syntax is simply ignored, as it is not expected
- * to cause problems.
- *
- * Security considerations:
- * \list
- * \li Circumflex-escaping an expando is treated as a quoting error
- * \li Closing double quotes right before expandos and opening double quotes
- * right after expandos are treated as quoting errors
- * \li Do not put expandos into nested commands:
- * \badcode
- * for /f "usebackq" \%v in (`foo \%{file}`) do \@echo \%v
- * \endcode
- * \li A macro's value must not contain anything which may be interpreted
- * as an environment variable expansion. A solution is replacing any
- * percent signs with a fixed string like \c{\%PERCENT_SIGN\%} and
- * injecting \c{PERCENT_SIGN=\%} into the shell's environment.
- * \li Enabling delayed environment variable expansion (cmd /v:on) should have
- * no security implications, but may still wreak havoc due to the
- * need for doubling circumflexes if any exclamation marks are present,
- * and the need to circumflex-escape the exclamation marks themselves.
- * \endlist
- *
- * \param cmd pointer to the string in which macros are expanded in-place
- * \param mx pointer to a macro expander instance
- * \return false if the string could not be parsed and therefore no safe
- * substitution was possible
- */
-bool QtcProcess::expandMacros(QString *cmd, AbstractMacroExpander *mx, OsType osType)
+void QtcProcess::setDisableUnixTerminal()
{
- QString str = *cmd;
- if (str.isEmpty())
- return true;
-
- QString rsts;
- int varLen;
- int varPos = 0;
- if (!(varLen = mx->findMacro(str, &varPos, &rsts)))
- return true;
-
- int pos = 0;
-
- if (osType == OsTypeWindows) {
- enum { // cmd.exe parsing state
- ShellBasic, // initial state
- ShellQuoted, // double-quoted state => *no* other meta chars are interpreted
- ShellEscaped // circumflex-escaped state => next char is not interpreted
- } shellState = ShellBasic;
- enum { // CommandLineToArgv() parsing state and some more
- CrtBasic, // initial state
- CrtNeedWord, // after empty expando; insert empty argument if whitespace follows
- CrtInWord, // in non-whitespace
- CrtClosed, // previous char closed the double-quoting
- CrtHadQuote, // closed double-quoting after an expando
- // The remaining two need to be numerically higher
- CrtQuoted, // double-quoted state => spaces don't split tokens
- CrtNeedQuote // expando opened quote; close if no expando follows
- } crtState = CrtBasic;
- int bslashes = 0; // previous chars were manual backslashes
- int rbslashes = 0; // trailing backslashes in replacement
-
- forever {
- if (pos == varPos) {
- if (shellState == ShellEscaped)
- return false; // Circumflex'd quoted expando would be Bad (TM).
- if ((shellState == ShellQuoted) != (crtState == CrtQuoted))
- return false; // CRT quoting out of sync with shell quoting. Ahoy to Redmond.
- rbslashes += bslashes;
- bslashes = 0;
- if (crtState < CrtQuoted) {
- if (rsts.isEmpty()) {
- if (crtState == CrtBasic) {
- // Outside any quoting and the string is empty, so put
- // a pair of quotes. Delaying that is just pedantry.
- crtState = CrtNeedWord;
- }
- } else {
- if (hasSpecialCharsWin(rsts)) {
- if (crtState == CrtClosed) {
- // Quoted expando right after closing quote. Can't do that.
- return false;
- }
- int tbslashes = quoteArgInternalWin(rsts, 0);
- rsts.prepend(QLatin1Char('"'));
- if (rbslashes)
- rsts.prepend(QString(rbslashes, QLatin1Char('\\')));
- crtState = CrtNeedQuote;
- rbslashes = tbslashes;
- } else {
- crtState = CrtInWord; // We know that this string contains no spaces.
- // We know that this string contains no quotes,
- // so the function won't make a mess.
- rbslashes = quoteArgInternalWin(rsts, rbslashes);
- }
- }
- } else {
- rbslashes = quoteArgInternalWin(rsts, rbslashes);
- }
- str.replace(pos, varLen, rsts);
- pos += rsts.length();
- varPos = pos;
- if (!(varLen = mx->findMacro(str, &varPos, &rsts))) {
- // Don't leave immediately, as we may be in CrtNeedWord state which could
- // be still resolved, or we may have inserted trailing backslashes.
- varPos = INT_MAX;
- }
- continue;
- }
- if (crtState == CrtNeedQuote) {
- if (rbslashes) {
- str.insert(pos, QString(rbslashes, QLatin1Char('\\')));
- pos += rbslashes;
- varPos += rbslashes;
- rbslashes = 0;
- }
- str.insert(pos, QLatin1Char('"'));
- pos++;
- varPos++;
- crtState = CrtHadQuote;
- }
- ushort cc = str.unicode()[pos].unicode();
- if (shellState == ShellBasic && cc == '^') {
- shellState = ShellEscaped;
- } else {
- if (!cc || cc == ' ' || cc == '\t') {
- if (crtState < CrtQuoted) {
- if (crtState == CrtNeedWord) {
- str.insert(pos, QLatin1String("\"\""));
- pos += 2;
- varPos += 2;
- }
- crtState = CrtBasic;
- }
- if (!cc)
- break;
- bslashes = 0;
- rbslashes = 0;
- } else {
- if (cc == '\\') {
- bslashes++;
- if (crtState < CrtQuoted)
- crtState = CrtInWord;
- } else {
- if (cc == '"') {
- if (shellState != ShellEscaped)
- shellState = (shellState == ShellQuoted) ? ShellBasic : ShellQuoted;
- if (rbslashes) {
- // Offset -1: skip possible circumflex. We have at least
- // one backslash, so a fixed offset is ok.
- str.insert(pos - 1, QString(rbslashes, QLatin1Char('\\')));
- pos += rbslashes;
- varPos += rbslashes;
- }
- if (!(bslashes & 1)) {
- // Even number of backslashes, so the quote is not escaped.
- switch (crtState) {
- case CrtQuoted:
- // Closing quote
- crtState = CrtClosed;
- break;
- case CrtClosed:
- // Two consecutive quotes make a literal quote - and
- // still close quoting. See QtcProcess::quoteArg().
- crtState = CrtInWord;
- break;
- case CrtHadQuote:
- // Opening quote right after quoted expando. Can't do that.
- return false;
- default:
- // Opening quote
- crtState = CrtQuoted;
- break;
- }
- } else if (crtState < CrtQuoted) {
- crtState = CrtInWord;
- }
- } else if (crtState < CrtQuoted) {
- crtState = CrtInWord;
- }
- bslashes = 0;
- rbslashes = 0;
- }
- }
- if (varPos == INT_MAX && !rbslashes)
- break;
- if (shellState == ShellEscaped)
- shellState = ShellBasic;
- }
- pos++;
- }
- } else {
- // !Windows
- MxState state = {MxBasic, false};
- QStack<MxState> sstack;
- QStack<MxSave> ostack;
-
- while (pos < str.length()) {
- if (pos == varPos) {
- // Our expansion rules trigger in any context
- if (state.dquote) {
- // We are within a double-quoted string. Escape relevant meta characters.
- rsts.replace(QRegularExpression(QLatin1String("([$`\"\\\\])")), QLatin1String("\\\\1"));
- } else if (state.current == MxSingleQuote) {
- // We are within a single-quoted string. "Suspend" single-quoting and put a
- // single escaped quote for each single quote inside the string.
- rsts.replace(QLatin1Char('\''), QLatin1String("'\\''"));
- } else if (rsts.isEmpty() || hasSpecialCharsUnix(rsts)) {
- // String contains "quote-worthy" characters. Use single quoting - but
- // that choice is arbitrary.
- rsts.replace(QLatin1Char('\''), QLatin1String("'\\''"));
- rsts.prepend(QLatin1Char('\''));
- rsts.append(QLatin1Char('\''));
- } // Else just use the string verbatim.
- str.replace(pos, varLen, rsts);
- pos += rsts.length();
- varPos = pos;
- if (!(varLen = mx->findMacro(str, &varPos, &rsts)))
- break;
- continue;
- }
- ushort cc = str.unicode()[pos].unicode();
- if (state.current == MxSingleQuote) {
- // Single quoted context - only the single quote has any special meaning.
- if (cc == '\'')
- state = sstack.pop();
- } else if (cc == '\\') {
- // In any other context, the backslash starts an escape.
- pos += 2;
- if (varPos < pos)
- return false; // Backslash'd quoted expando would be Bad (TM).
- continue;
- } else if (cc == '$') {
- cc = str.unicode()[++pos].unicode();
- if (cc == '(') {
- sstack.push(state);
- if (str.unicode()[pos + 1].unicode() == '(') {
- // $(( starts a math expression. This may also be a $( ( in fact,
- // so we push the current string and offset on a stack so we can retry.
- MxSave sav = {str, pos + 2, varPos};
- ostack.push(sav);
- state.current = MxMath;
- pos += 2;
- continue;
- } else {
- // $( starts a command substitution. This actually "opens a new context"
- // which overrides surrounding double quoting.
- state.current = MxParen;
- state.dquote = false;
- }
- } else if (cc == '{') {
- // ${ starts a "braced" variable substitution.
- sstack.push(state);
- state.current = MxSubst;
- } // Else assume that a "bare" variable substitution has started
- } else if (cc == '`') {
- // Backticks are evil, as every shell interprets escapes within them differently,
- // which is a danger for the quoting of our own expansions.
- // So we just apply *our* rules (which match bash) and transform it into a POSIX
- // command substitution which has clear semantics.
- str.replace(pos, 1, QLatin1String("$( " )); // add space -> avoid creating $((
- varPos += 2;
- int pos2 = pos += 3;
- forever {
- if (pos2 >= str.length())
- return false; // Syntax error - unterminated backtick expression.
- cc = str.unicode()[pos2].unicode();
- if (cc == '`')
- break;
- if (cc == '\\') {
- cc = str.unicode()[++pos2].unicode();
- if (cc == '$' || cc == '`' || cc == '\\' ||
- (cc == '"' && state.dquote))
- {
- str.remove(pos2 - 1, 1);
- if (varPos >= pos2)
- varPos--;
- continue;
- }
- }
- pos2++;
- }
- str[pos2] = QLatin1Char(')');
- sstack.push(state);
- state.current = MxParen;
- state.dquote = false;
- continue;
- } else if (state.current == MxDoubleQuote) {
- // (Truly) double quoted context - only remaining special char is the closing quote.
- if (cc == '"')
- state = sstack.pop();
- } else if (cc == '\'') {
- // Start single quote if we are not in "inherited" double quoted context.
- if (!state.dquote) {
- sstack.push(state);
- state.current = MxSingleQuote;
- }
- } else if (cc == '"') {
- // Same for double quoting.
- if (!state.dquote) {
- sstack.push(state);
- state.current = MxDoubleQuote;
- state.dquote = true;
- }
- } else if (state.current == MxSubst) {
- // "Braced" substitution context - only remaining special char is the closing brace.
- if (cc == '}')
- state = sstack.pop();
- } else if (cc == ')') {
- if (state.current == MxMath) {
- if (str.unicode()[pos + 1].unicode() == ')') {
- state = sstack.pop();
- pos += 2;
- } else {
- // False hit: the $(( was a $( ( in fact.
- // ash does not care (and will complain), but bash actually parses it.
- varPos = ostack.top().varPos;
- pos = ostack.top().pos;
- str = ostack.top().str;
- ostack.pop();
- state.current = MxParen;
- state.dquote = false;
- sstack.push(state);
- }
- continue;
- } else if (state.current == MxParen) {
- state = sstack.pop();
- } else {
- break; // Syntax error - excess closing parenthesis.
- }
- } else if (cc == '}') {
- if (state.current == MxGroup)
- state = sstack.pop();
- else
- break; // Syntax error - excess closing brace.
- } else if (cc == '(') {
- // Context-saving command grouping.
- sstack.push(state);
- state.current = MxParen;
- } else if (cc == '{') {
- // Plain command grouping.
- sstack.push(state);
- state.current = MxGroup;
- }
- pos++;
- }
- // FIXME? May complain if (!sstack.empty()), but we don't really care anyway.
- }
-
- *cmd = str;
- return true;
+ d->m_disableUnixTerminal = true;
}
-QString QtcProcess::expandMacros(const QString &str, AbstractMacroExpander *mx, OsType osType)
+void QtcProcess::setRemoteProcessHooks(const DeviceProcessHooks &hooks)
{
- QString ret = str;
- expandMacros(&ret, mx, osType);
- return ret;
+ s_deviceHooks = hooks;
}
#if QT_VERSION < QT_VERSION_CHECK(6, 0, 0)
void QtcProcess::setupChildProcess()
{
- setupChildProcess_impl();
+ d->setupChildProcess_impl();
}
#endif
-void QtcProcess::setupChildProcess_impl()
+void QtcProcessPrivate::setupChildProcess_impl()
{
#if defined Q_OS_UNIX
// nice value range is -20 to +19 where -20 is highest, 0 default and +19 is lowest
@@ -1246,320 +357,598 @@ void QtcProcess::setupChildProcess_impl()
if (::nice(5) == -1 && errno != 0)
perror("Failed to set nice value");
}
+
+ // Disable terminal by becoming a session leader.
+ if (m_disableUnixTerminal)
+ setsid();
#endif
}
-bool QtcProcess::ArgIterator::next()
+void QtcProcess::setOpenMode(OpenMode mode)
{
- // We delay the setting of m_prev so we can still delete the last argument
- // after we find that there are no more arguments. It's a bit of a hack ...
- int prev = m_pos;
-
- m_simple = true;
- m_value.clear();
-
- if (m_osType == OsTypeWindows) {
- enum { // cmd.exe parsing state
- ShellBasic, // initial state
- ShellQuoted, // double-quoted state => *no* other meta chars are interpreted
- ShellEscaped // circumflex-escaped state => next char is not interpreted
- } shellState = ShellBasic;
- enum { // CommandLineToArgv() parsing state and some more
- CrtBasic, // initial state
- CrtInWord, // in non-whitespace
- CrtClosed, // previous char closed the double-quoting
- CrtQuoted // double-quoted state => spaces don't split tokens
- } crtState = CrtBasic;
- enum { NoVar, NewVar, FullVar } varState = NoVar; // inside a potential env variable expansion
- int bslashes = 0; // number of preceding backslashes
-
- for (;; m_pos++) {
- ushort cc = m_pos < m_str->length() ? m_str->unicode()[m_pos].unicode() : 0;
- if (shellState == ShellBasic && cc == '^') {
- varState = NoVar;
- shellState = ShellEscaped;
- } else if ((shellState == ShellBasic && isMetaCharWin(cc)) || !cc) { // A "bit" simplistic ...
- // We ignore crtQuote state here. Whatever ...
- doReturn:
- if (m_simple)
- while (--bslashes >= 0)
- m_value += QLatin1Char('\\');
- else
- m_value.clear();
- if (crtState != CrtBasic) {
- m_prev = prev;
- return true;
- }
- return false;
- } else {
- if (crtState != CrtQuoted && (cc == ' ' || cc == '\t')) {
- if (crtState != CrtBasic) {
- // We'll lose shellQuote state here. Whatever ...
- goto doReturn;
- }
- } else {
- if (cc == '\\') {
- bslashes++;
- if (crtState != CrtQuoted)
- crtState = CrtInWord;
- varState = NoVar;
- } else {
- if (cc == '"') {
- varState = NoVar;
- if (shellState != ShellEscaped)
- shellState = (shellState == ShellQuoted) ? ShellBasic : ShellQuoted;
- int obslashes = bslashes;
- bslashes >>= 1;
- if (!(obslashes & 1)) {
- // Even number of backslashes, so the quote is not escaped.
- switch (crtState) {
- case CrtQuoted:
- // Closing quote
- crtState = CrtClosed;
- continue;
- case CrtClosed:
- // Two consecutive quotes make a literal quote - and
- // still close quoting. See quoteArg().
- crtState = CrtInWord;
- break;
- default:
- // Opening quote
- crtState = CrtQuoted;
- continue;
- }
- } else if (crtState != CrtQuoted) {
- crtState = CrtInWord;
- }
- } else {
- if (cc == '%') {
- if (varState == FullVar) {
- m_simple = false;
- varState = NoVar;
- } else {
- varState = NewVar;
- }
- } else if (varState != NoVar) {
- // This check doesn't really reflect cmd reality, but it is an
- // approximation of what would be sane.
- varState = (cc == '_' || cc == '-' || cc == '.'
- || QChar(cc).isLetterOrNumber()) ? FullVar : NoVar;
-
- }
- if (crtState != CrtQuoted)
- crtState = CrtInWord;
- }
- for (; bslashes > 0; bslashes--)
- m_value += QLatin1Char('\\');
- m_value += QChar(cc);
- }
- }
- if (shellState == ShellEscaped)
- shellState = ShellBasic;
- }
- }
- } else {
- MxState state = {MxBasic, false};
- QStack<MxState> sstack;
- QStack<int> ostack;
- bool hadWord = false;
-
- for (; m_pos < m_str->length(); m_pos++) {
- ushort cc = m_str->unicode()[m_pos].unicode();
- if (state.current == MxSingleQuote) {
- if (cc == '\'') {
- state = sstack.pop();
- continue;
- }
- } else if (cc == '\\') {
- if (++m_pos >= m_str->length())
- break;
- cc = m_str->unicode()[m_pos].unicode();
- if (state.dquote && cc != '"' && cc != '\\' && cc != '$' && cc != '`')
- m_value += QLatin1Char('\\');
- } else if (cc == '$') {
- if (++m_pos >= m_str->length())
- break;
- cc = m_str->unicode()[m_pos].unicode();
- if (cc == '(') {
- sstack.push(state);
- if (++m_pos >= m_str->length())
- break;
- if (m_str->unicode()[m_pos].unicode() == '(') {
- ostack.push(m_pos);
- state.current = MxMath;
- } else {
- state.dquote = false;
- state.current = MxParen;
- // m_pos too far by one now - whatever.
- }
- } else if (cc == '{') {
- sstack.push(state);
- state.current = MxSubst;
- } else {
- // m_pos too far by one now - whatever.
- }
- m_simple = false;
- hadWord = true;
- continue;
- } else if (cc == '`') {
- forever {
- if (++m_pos >= m_str->length()) {
- m_simple = false;
- m_prev = prev;
- return true;
- }
- cc = m_str->unicode()[m_pos].unicode();
- if (cc == '`')
- break;
- if (cc == '\\')
- m_pos++; // m_pos may be too far by one now - whatever.
- }
- m_simple = false;
- hadWord = true;
- continue;
- } else if (state.current == MxDoubleQuote) {
- if (cc == '"') {
- state = sstack.pop();
- continue;
- }
- } else if (cc == '\'') {
- if (!state.dquote) {
- sstack.push(state);
- state.current = MxSingleQuote;
- hadWord = true;
- continue;
- }
- } else if (cc == '"') {
- if (!state.dquote) {
- sstack.push(state);
- state.dquote = true;
- state.current = MxDoubleQuote;
- hadWord = true;
- continue;
- }
- } else if (state.current == MxSubst) {
- if (cc == '}')
- state = sstack.pop();
- continue; // Not simple anyway
- } else if (cc == ')') {
- if (state.current == MxMath) {
- if (++m_pos >= m_str->length())
- break;
- if (m_str->unicode()[m_pos].unicode() == ')') {
- ostack.pop();
- state = sstack.pop();
- } else {
- // false hit: the $(( was a $( ( in fact.
- // ash does not care, but bash does.
- m_pos = ostack.pop();
- state.current = MxParen;
- state.dquote = false;
- sstack.push(state);
- }
- continue;
- } else if (state.current == MxParen) {
- state = sstack.pop();
- continue;
- } else {
- break;
- }
-#if 0 // MxGroup is impossible, see below.
- } else if (cc == '}') {
- if (state.current == MxGroup) {
- state = sstack.pop();
- continue;
- }
-#endif
- } else if (cc == '(') {
- sstack.push(state);
- state.current = MxParen;
- m_simple = false;
- hadWord = true;
- continue;
-#if 0 // Should match only at the beginning of a command, which we never have currently.
- } else if (cc == '{') {
- sstack.push(state);
- state.current = MxGroup;
- m_simple = false;
- hadWord = true;
- continue;
+ d->m_openMode = mode;
+}
+
+bool QtcProcess::stopProcess()
+{
+ if (state() == QProcess::NotRunning)
+ return true;
+ terminate();
+ if (waitForFinished(300))
+ return true;
+ kill();
+ return waitForFinished(300);
+}
+
+static bool askToKill(const QString &command)
+{
+#ifdef QT_GUI_LIB
+ if (QThread::currentThread() != QCoreApplication::instance()->thread())
+ return true;
+ const QString title = QtcProcess::tr("Process not Responding");
+ QString msg = command.isEmpty() ?
+ QtcProcess::tr("The process is not responding.") :
+ QtcProcess::tr("The process \"%1\" is not responding.").arg(command);
+ msg += ' ';
+ msg += QtcProcess::tr("Would you like to terminate it?");
+ // Restore the cursor that is set to wait while running.
+ const bool hasOverrideCursor = QApplication::overrideCursor() != nullptr;
+ if (hasOverrideCursor)
+ QApplication::restoreOverrideCursor();
+ QMessageBox::StandardButton answer = QMessageBox::question(nullptr, title, msg, QMessageBox::Yes|QMessageBox::No);
+ if (hasOverrideCursor)
+ QApplication::setOverrideCursor(Qt::WaitCursor);
+ return answer == QMessageBox::Yes;
+#else
+ Q_UNUSED(command)
+ return true;
#endif
- } else if (cc == '<' || cc == '>' || cc == '&' || cc == '|' || cc == ';') {
- if (sstack.isEmpty())
- break;
- } else if (cc == ' ' || cc == '\t') {
- if (!hadWord)
- continue;
- if (sstack.isEmpty())
- break;
+}
+
+// Helper for running a process synchronously in the foreground with timeout
+// detection similar SynchronousProcess' handling (taking effect after no more output
+// occurs on stderr/stdout as opposed to waitForFinished()). Returns false if a timeout
+// occurs. Checking of the process' exit state/code still has to be done.
+
+bool QtcProcess::readDataFromProcess(int timeoutS,
+ QByteArray *stdOut,
+ QByteArray *stdErr,
+ bool showTimeOutMessageBox)
+{
+ enum { syncDebug = 0 };
+ if (syncDebug)
+ qDebug() << ">readDataFromProcess" << timeoutS;
+ if (state() != QProcess::Running) {
+ qWarning("readDataFromProcess: Process in non-running state passed in.");
+ return false;
+ }
+
+ QTC_ASSERT(readChannel() == QProcess::StandardOutput, return false);
+
+ // Keep the process running until it has no longer has data
+ bool finished = false;
+ bool hasData = false;
+ do {
+ finished = waitForFinished(timeoutS > 0 ? timeoutS * 1000 : -1)
+ || state() == QProcess::NotRunning;
+ // First check 'stdout'
+ if (bytesAvailable()) { // applies to readChannel() only
+ hasData = true;
+ const QByteArray newStdOut = readAllStandardOutput();
+ if (stdOut)
+ stdOut->append(newStdOut);
+ }
+ // Check 'stderr' separately. This is a special handling
+ // for 'git pull' and the like which prints its progress on stderr.
+ const QByteArray newStdErr = readAllStandardError();
+ if (!newStdErr.isEmpty()) {
+ hasData = true;
+ if (stdErr)
+ stdErr->append(newStdErr);
+ }
+ // Prompt user, pretend we have data if says 'No'.
+ const bool hang = !hasData && !finished;
+ hasData = hang && showTimeOutMessageBox && !askToKill(program());
+ } while (hasData && !finished);
+ if (syncDebug)
+ qDebug() << "<readDataFromProcess" << finished;
+ return finished;
+}
+
+QString QtcProcess::normalizeNewlines(const QString &text)
+{
+ QString res = text;
+ const auto newEnd = std::unique(res.begin(), res.end(), [](const QChar &c1, const QChar &c2) {
+ return c1 == '\r' && c2 == '\r'; // QTCREATORBUG-24556
+ });
+ res.chop(std::distance(newEnd, res.end()));
+ res.replace("\r\n", "\n");
+ return res;
+}
+
+QtcProcess::Result QtcProcess::result() const
+{
+ return d->m_result;
+}
+
+void QtcProcess::setResult(Result result)
+{
+ d->m_result = result;
+}
+
+int QtcProcess::exitCode() const
+{
+ return d->m_isSynchronousProcess ? d->m_exitCode : QProcess::exitCode(); // FIXME: Unify.
+}
+
+
+// Path utilities
+
+// Locate a binary in a directory, applying all kinds of
+// extensions the operating system supports.
+static QString checkBinary(const QDir &dir, const QString &binary)
+{
+ // naive UNIX approach
+ const QFileInfo info(dir.filePath(binary));
+ if (info.isFile() && info.isExecutable())
+ return info.absoluteFilePath();
+
+ // Does the OS have some weird extension concept or does the
+ // binary have a 3 letter extension?
+ if (HostOsInfo::isAnyUnixHost() && !HostOsInfo::isMacHost())
+ return QString();
+ const int dotIndex = binary.lastIndexOf(QLatin1Char('.'));
+ if (dotIndex != -1 && dotIndex == binary.size() - 4)
+ return QString();
+
+ switch (HostOsInfo::hostOs()) {
+ case OsTypeLinux:
+ case OsTypeOtherUnix:
+ case OsTypeOther:
+ break;
+ case OsTypeWindows: {
+ static const char *windowsExtensions[] = {".cmd", ".bat", ".exe", ".com"};
+ // Check the Windows extensions using the order
+ const int windowsExtensionCount = sizeof(windowsExtensions)/sizeof(const char*);
+ for (int e = 0; e < windowsExtensionCount; e ++) {
+ const QFileInfo windowsBinary(dir.filePath(binary + QLatin1String(windowsExtensions[e])));
+ if (windowsBinary.isFile() && windowsBinary.isExecutable())
+ return windowsBinary.absoluteFilePath();
}
- m_value += QChar(cc);
- hadWord = true;
}
- // TODO: Possibly complain here if (!sstack.empty())
- if (!m_simple)
- m_value.clear();
- if (hadWord) {
- m_prev = prev;
- return true;
+ break;
+ case OsTypeMac: {
+ // Check for Mac app folders
+ const QFileInfo appFolder(dir.filePath(binary + QLatin1String(".app")));
+ if (appFolder.isDir()) {
+ QString macBinaryPath = appFolder.absoluteFilePath();
+ macBinaryPath += QLatin1String("/Contents/MacOS/");
+ macBinaryPath += binary;
+ const QFileInfo macBinary(macBinaryPath);
+ if (macBinary.isFile() && macBinary.isExecutable())
+ return macBinary.absoluteFilePath();
+ }
}
- return false;
+ break;
}
+ return QString();
}
-void QtcProcess::ArgIterator::deleteArg()
+QString QtcProcess::locateBinary(const QString &path, const QString &binary)
{
- if (!m_prev)
- while (m_pos < m_str->length() && m_str->at(m_pos).isSpace())
- m_pos++;
- m_str->remove(m_prev, m_pos - m_prev);
- m_pos = m_prev;
+ // Absolute file?
+ const QFileInfo absInfo(binary);
+ if (absInfo.isAbsolute())
+ return checkBinary(absInfo.dir(), absInfo.fileName());
+
+ // Windows finds binaries in the current directory
+ if (HostOsInfo::isWindowsHost()) {
+ const QString currentDirBinary = checkBinary(QDir::current(), binary);
+ if (!currentDirBinary.isEmpty())
+ return currentDirBinary;
+ }
+
+ const QStringList paths = path.split(HostOsInfo::pathListSeparator());
+ if (paths.empty())
+ return QString();
+ const QStringList::const_iterator cend = paths.constEnd();
+ for (QStringList::const_iterator it = paths.constBegin(); it != cend; ++it) {
+ const QDir dir(*it);
+ const QString rc = checkBinary(dir, binary);
+ if (!rc.isEmpty())
+ return rc;
+ }
+ return QString();
}
-void QtcProcess::ArgIterator::appendArg(const QString &str)
+Environment QtcProcess::systemEnvironmentForBinary(const FilePath &filePath)
{
- const QString qstr = quoteArg(str);
- if (!m_pos)
- m_str->insert(0, qstr + QLatin1Char(' '));
- else
- m_str->insert(m_pos, QLatin1Char(' ') + qstr);
- m_pos += qstr.length() + 1;
+ if (filePath.needsDevice()) {
+ QTC_ASSERT(s_deviceHooks.systemEnvironmentForBinary, return {});
+ return s_deviceHooks.systemEnvironmentForBinary(filePath);
+ }
+
+ return Environment::systemEnvironment();
+}
+
+QString QtcProcess::locateBinary(const QString &binary)
+{
+ const QByteArray path = qgetenv("PATH");
+ return locateBinary(QString::fromLocal8Bit(path), binary);
+}
+
+
+/*!
+ \class Utils::SynchronousProcess
+
+ \brief The SynchronousProcess class runs a synchronous process in its own
+ event loop that blocks only user input events. Thus, it allows for the GUI to
+ repaint and append output to log windows.
+
+ The callbacks set with setStdOutCallBack(), setStdErrCallback() are called
+ with complete lines based on the '\\n' marker.
+ They would typically be used for log windows.
+
+ There is a timeout handling that takes effect after the last data have been
+ read from stdout/stdin (as opposed to waitForFinished(), which measures time
+ since it was invoked). It is thus also suitable for slow processes that
+ continuously output data (like version system operations).
+
+ The property timeOutMessageBoxEnabled influences whether a message box is
+ shown asking the user if they want to kill the process on timeout (default: false).
+
+ There are also static utility functions for dealing with fully synchronous
+ processes, like reading the output with correct timeout handling.
+
+ Caution: This class should NOT be used if there is a chance that the process
+ triggers opening dialog boxes (for example, by file watchers triggering),
+ as this will cause event loop problems.
+*/
+
+QString QtcProcess::exitMessage()
+{
+ const QString fullCmd = commandLine().toUserOutput();
+ switch (result()) {
+ case Finished:
+ return QtcProcess::tr("The command \"%1\" finished successfully.").arg(fullCmd);
+ case FinishedError:
+ return QtcProcess::tr("The command \"%1\" terminated with exit code %2.")
+ .arg(fullCmd).arg(exitCode());
+ case TerminatedAbnormally:
+ return QtcProcess::tr("The command \"%1\" terminated abnormally.").arg(fullCmd);
+ case StartFailed:
+ return QtcProcess::tr("The command \"%1\" could not be started.").arg(fullCmd);
+ case Hang:
+ return QtcProcess::tr("The command \"%1\" did not respond within the timeout limit (%2 s).")
+ .arg(fullCmd).arg(d->m_hangTimerCount);
+ }
+ return QString();
}
-QtcProcess::Arguments QtcProcess::Arguments::createWindowsArgs(const QString &args)
+QByteArray QtcProcess::allRawOutput() const
{
- Arguments result;
- result.m_windowsArgs = args;
- result.m_isWindows = true;
- return result;
+ if (!d->m_stdOut.rawData.isEmpty() && !d->m_stdErr.rawData.isEmpty()) {
+ QByteArray result = d->m_stdOut.rawData;
+ if (!result.endsWith('\n'))
+ result += '\n';
+ result += d->m_stdErr.rawData;
+ return result;
+ }
+ return !d->m_stdOut.rawData.isEmpty() ? d->m_stdOut.rawData : d->m_stdErr.rawData;
}
-QtcProcess::Arguments QtcProcess::Arguments::createUnixArgs(const QStringList &args)
+QString QtcProcess::allOutput() const
{
- Arguments result;
- result.m_unixArgs = args;
- result.m_isWindows = false;
- return result;
+ const QString out = stdOut();
+ const QString err = stdErr();
+
+ if (!out.isEmpty() && !err.isEmpty()) {
+ QString result = out;
+ if (!result.endsWith('\n'))
+ result += '\n';
+ result += err;
+ return result;
+ }
+ return !out.isEmpty() ? out : err;
}
-QString QtcProcess::Arguments::toWindowsArgs() const
+QString QtcProcess::stdOut() const
{
- QTC_CHECK(m_isWindows);
- return m_windowsArgs;
+ return normalizeNewlines(d->m_codec->toUnicode(d->m_stdOut.rawData));
}
-QStringList QtcProcess::Arguments::toUnixArgs() const
+QString QtcProcess::stdErr() const
{
- QTC_CHECK(!m_isWindows);
- return m_unixArgs;
+ return normalizeNewlines(d->m_codec->toUnicode(d->m_stdErr.rawData));
}
-QString QtcProcess::Arguments::toString() const
+QByteArray QtcProcess::rawStdOut() const
{
- if (m_isWindows)
- return m_windowsArgs;
+ return d->m_stdOut.rawData;
+}
+
+QByteArray QtcProcess::rawStdErr() const
+{
+ return d->m_stdErr.rawData;
+}
+
+QTCREATOR_UTILS_EXPORT QDebug operator<<(QDebug str, const QtcProcess &r)
+{
+ QDebug nsp = str.nospace();
+ nsp << "QtcProcess: result="
+ << r.d->m_result << " ex=" << r.exitCode() << '\n'
+ << r.d->m_stdOut.rawData.size() << " bytes stdout, stderr=" << r.d->m_stdErr.rawData << '\n';
+ return str;
+}
+
+void ChannelBuffer::clearForRun()
+{
+ rawDataPos = 0;
+ rawData.clear();
+ codecState.reset(new QTextCodec::ConverterState);
+ incompleteLineBuffer.clear();
+}
+
+/* Check for complete lines read from the device and return them, moving the
+ * buffer position. */
+QString ChannelBuffer::linesRead()
+{
+ // Convert and append the new input to the buffer of incomplete lines
+ const char *start = rawData.constData() + rawDataPos;
+ const int len = rawData.size() - rawDataPos;
+ incompleteLineBuffer.append(codec->toUnicode(start, len, codecState.get()));
+ rawDataPos = rawData.size();
+
+ // Any completed lines in the incompleteLineBuffer?
+ const int lastLineIndex = qMax(incompleteLineBuffer.lastIndexOf('\n'),
+ incompleteLineBuffer.lastIndexOf('\r'));
+ if (lastLineIndex == -1)
+ return QString();
+
+ // Get completed lines and remove them from the incompleteLinesBuffer:
+ const QString lines = QtcProcess::normalizeNewlines(incompleteLineBuffer.left(lastLineIndex + 1));
+ incompleteLineBuffer = incompleteLineBuffer.mid(lastLineIndex + 1);
+
+ return lines;
+}
+
+void ChannelBuffer::append(const QByteArray &text, bool emitSignals)
+{
+ if (text.isEmpty())
+ return;
+ rawData += text;
+ if (!emitSignals)
+ return;
+
+ // Buffered. Emit complete lines?
+ if (outputCallback) {
+ const QString lines = linesRead();
+ if (!lines.isEmpty())
+ outputCallback(lines);
+ }
+}
+
+
+// ----------- SynchronousProcess
+SynchronousProcess::SynchronousProcess()
+{
+ d->m_isSynchronousProcess = true; // Only for QTC_ASSERTs above.
+
+ d->m_timer.setInterval(1000);
+ connect(&d->m_timer, &QTimer::timeout, d, &QtcProcessPrivate::slotTimeout);
+ connect(this, QOverload<int, QProcess::ExitStatus>::of(&QProcess::finished),
+ d, &QtcProcessPrivate::slotFinished);
+ connect(this, &QProcess::errorOccurred, d, &QtcProcessPrivate::slotError);
+ connect(this, &QProcess::readyReadStandardOutput, d, [this] {
+ d->m_hangTimerCount = 0;
+ d->m_stdOut.append(readAllStandardOutput(), true);
+ });
+ connect(this, &QProcess::readyReadStandardError, d, [this] {
+ d->m_hangTimerCount = 0;
+ d->m_stdErr.append(readAllStandardError(), true);
+ });
+}
+
+SynchronousProcess::~SynchronousProcess()
+{
+ disconnect(&d->m_timer, nullptr, this, nullptr);
+ disconnect(this, nullptr, this, nullptr);
+}
+
+void SynchronousProcess::setProcessUserEventWhileRunning()
+{
+ d->m_processUserEvents = true;
+}
+
+void QtcProcess::setTimeoutS(int timeoutS)
+{
+ QTC_CHECK(d->m_isSynchronousProcess);
+ if (timeoutS > 0)
+ d->m_maxHangTimerCount = qMax(2, timeoutS);
else
- return QtcProcess::joinArgs(m_unixArgs, OsTypeLinux);
+ d->m_maxHangTimerCount = INT_MAX / 1000;
+}
+
+void QtcProcess::setCodec(QTextCodec *c)
+{
+ QTC_ASSERT(c, return);
+ d->m_codec = c;
+}
+
+void QtcProcess::setTimeOutMessageBoxEnabled(bool v)
+{
+ QTC_CHECK(d->m_isSynchronousProcess);
+ d->m_timeOutMessageBoxEnabled = v;
+}
+
+void QtcProcess::setExitCodeInterpreter(const ExitCodeInterpreter &interpreter)
+{
+ d->m_exitCodeInterpreter = interpreter;
+}
+
+void QtcProcess::setWriteData(const QByteArray &writeData)
+{
+ QTC_CHECK(d->m_isSynchronousProcess);
+ d->m_writeData = writeData;
+}
+
+#ifdef QT_GUI_LIB
+static bool isGuiThread()
+{
+ return QThread::currentThread() == QCoreApplication::instance()->thread();
+}
+#endif
+
+void SynchronousProcess::runBlocking()
+{
+ QTC_CHECK(d->m_isSynchronousProcess);
+ // FIXME: Implement properly
+ if (d->m_commandLine.executable().needsDevice()) {
+
+ // writeData ?
+ QtcProcess::start();
+
+ waitForFinished();
+
+ d->m_result = QtcProcess::Finished;
+ d->m_exitCode = exitCode();
+ d->m_stdOut.rawData += readAllStandardOutput();
+ d->m_stdErr.rawData += readAllStandardError();
+ return;
+ };
+
+ qCDebug(processLog).noquote() << "Starting blocking:" << d->m_commandLine.toUserOutput()
+ << " process user events: " << d->m_processUserEvents;
+ ExecuteOnDestruction logResult([this] { qCDebug(processLog) << *this; });
+
+ d->clearForRun();
+
+ d->m_binary = d->m_commandLine.executable();
+
+ if (d->m_processUserEvents) {
+ if (!d->m_writeData.isEmpty()) {
+ connect(this, &QProcess::started, this, [this] {
+ write(d->m_writeData);
+ closeWriteChannel();
+ });
+ }
+ setOpenMode(d->m_writeData.isEmpty() ? QIODevice::ReadOnly : QIODevice::ReadWrite);
+ QtcProcess::start();
+
+ // On Windows, start failure is triggered immediately if the
+ // executable cannot be found in the path. Do not start the
+ // event loop in that case.
+ if (!d->m_startFailure) {
+ d->m_timer.start();
+#ifdef QT_GUI_LIB
+ if (isGuiThread())
+ QApplication::setOverrideCursor(Qt::WaitCursor);
+#endif
+ d->m_eventLoop.exec(QEventLoop::ExcludeUserInputEvents);
+ d->m_stdOut.append(readAllStandardOutput(), false);
+ d->m_stdErr.append(readAllStandardError(), false);
+
+ d->m_timer.stop();
+#ifdef QT_GUI_LIB
+ if (isGuiThread())
+ QApplication::restoreOverrideCursor();
+#endif
+ }
+ } else {
+ setOpenMode(QIODevice::ReadOnly);
+ QtcProcess::start();
+ if (!waitForStarted(d->m_maxHangTimerCount * 1000)) {
+ d->m_result = QtcProcess::StartFailed;
+ return;
+ }
+ closeWriteChannel();
+ if (!waitForFinished(d->m_maxHangTimerCount * 1000)) {
+ d->m_result = QtcProcess::Hang;
+ terminate();
+ if (!waitForFinished(1000)) {
+ kill();
+ waitForFinished(1000);
+ }
+ }
+
+ if (state() != QProcess::NotRunning)
+ return;
+
+ d->m_exitCode = exitCode();
+ if (d->m_result == QtcProcess::StartFailed) {
+ if (exitStatus() != QProcess::NormalExit)
+ d->m_result = QtcProcess::TerminatedAbnormally;
+ else
+ d->m_result = d->interpretExitCode(d->m_exitCode);
+ }
+ d->m_stdOut.append(readAllStandardOutput(), false);
+ d->m_stdErr.append(readAllStandardError(), false);
+ }
+}
+
+void QtcProcess::setStdOutCallback(const std::function<void (const QString &)> &callback)
+{
+ QTC_CHECK(d->m_isSynchronousProcess);
+ d->m_stdOut.outputCallback = callback;
+}
+
+void QtcProcess::setStdErrCallback(const std::function<void (const QString &)> &callback)
+{
+ QTC_CHECK(d->m_isSynchronousProcess);
+ d->m_stdErr.outputCallback = callback;
+}
+
+void QtcProcessPrivate::slotTimeout()
+{
+ if (!m_waitingForUser && (++m_hangTimerCount > m_maxHangTimerCount)) {
+ if (debug)
+ qDebug() << Q_FUNC_INFO << "HANG detected, killing";
+ m_waitingForUser = true;
+ const bool terminate = !m_timeOutMessageBoxEnabled || askToKill(m_binary.toString());
+ m_waitingForUser = false;
+ if (terminate) {
+ q->stopProcess();
+ m_result = QtcProcess::Hang;
+ } else {
+ m_hangTimerCount = 0;
+ }
+ } else {
+ if (debug)
+ qDebug() << Q_FUNC_INFO << m_hangTimerCount;
+ }
+}
+
+void QtcProcessPrivate::slotFinished(int exitCode, QProcess::ExitStatus e)
+{
+ if (debug)
+ qDebug() << Q_FUNC_INFO << exitCode << e;
+ m_hangTimerCount = 0;
+
+ switch (e) {
+ case QProcess::NormalExit:
+ m_result = interpretExitCode(exitCode);
+ m_exitCode = exitCode;
+ break;
+ case QProcess::CrashExit:
+ // Was hang detected before and killed?
+ if (m_result != QtcProcess::Hang)
+ m_result = QtcProcess::TerminatedAbnormally;
+ m_exitCode = -1;
+ break;
+ }
+ m_eventLoop.quit();
+}
+
+void QtcProcessPrivate::slotError(QProcess::ProcessError e)
+{
+ m_hangTimerCount = 0;
+ if (debug)
+ qDebug() << Q_FUNC_INFO << e;
+ // Was hang detected before and killed?
+ if (m_result != QtcProcess::Hang)
+ m_result = QtcProcess::StartFailed;
+ m_startFailure = true;
+ m_eventLoop.quit();
}
} // namespace Utils
diff --git a/src/libs/utils/qtcprocess.h b/src/libs/utils/qtcprocess.h
index 4b2590ca64..365306867d 100644
--- a/src/libs/utils/qtcprocess.h
+++ b/src/libs/utils/qtcprocess.h
@@ -25,12 +25,32 @@
#pragma once
+#include "utils_global.h"
+
#include "environment.h"
+#include "commandline.h"
#include <QProcess>
+#include <QTextCodec>
+
+#include <functional>
+
+QT_FORWARD_DECLARE_CLASS(QDebug)
namespace Utils {
-class AbstractMacroExpander;
+
+class CommandLine;
+class Environment;
+class QtcProcess;
+
+namespace Internal { class QtcProcessPrivate; }
+
+class DeviceProcessHooks
+{
+public:
+ std::function<void(QtcProcess &)> startProcessHook;
+ std::function<Environment(const FilePath &)> systemEnvironmentForBinary;
+};
class QTCREATOR_UTILS_EXPORT QtcProcess : public QProcess
{
@@ -38,121 +58,114 @@ class QTCREATOR_UTILS_EXPORT QtcProcess : public QProcess
public:
QtcProcess(QObject *parent = nullptr);
+ ~QtcProcess();
+
+ enum Result {
+ // Finished with return code 0
+ Finished,
+ // Finished with return code != 0
+ FinishedError,
+ // Process terminated abnormally (kill)
+ TerminatedAbnormally,
+ // Executable could not be started
+ StartFailed,
+ // Hang, no output after time out
+ Hang };
+
+ void setEnvironment(const Environment &env);
+ const Environment &environment() const;
+
+ void setCommand(const CommandLine &cmdLine);
+ const CommandLine &commandLine() const;
- void setEnvironment(const Environment &env) { m_environment = env; m_haveEnv = true; }
- void setCommand(const CommandLine &cmdLine) { m_commandLine = cmdLine; }
void setUseCtrlCStub(bool enabled);
+ void setLowPriority();
+ void setDisableUnixTerminal();
+
void start();
void terminate();
void interrupt();
- void setLowPriority() { m_lowPriority = true; }
-
- class QTCREATOR_UTILS_EXPORT Arguments
- {
- public:
- static Arguments createWindowsArgs(const QString &args);
- static Arguments createUnixArgs(const QStringList &args);
-
- QString toWindowsArgs() const;
- QStringList toUnixArgs() const;
- QString toString() const;
-
- private:
- QString m_windowsArgs;
- QStringList m_unixArgs;
- bool m_isWindows;
- };
-
- enum SplitError {
- SplitOk = 0, //! All went just fine
- BadQuoting, //! Command contains quoting errors
- FoundMeta //! Command contains complex shell constructs
- };
-
- //! Quote a single argument for usage in a unix shell command
- static QString quoteArgUnix(const QString &arg);
- //! Quote a single argument for usage in a shell command
- static QString quoteArg(const QString &arg, OsType osType = HostOsInfo::hostOs());
- //! Quote a single argument and append it to a shell command
- static void addArg(QString *args, const QString &arg, OsType osType = HostOsInfo::hostOs());
- //! Join an argument list into a shell command
- static QString joinArgs(const QStringList &args, OsType osType = HostOsInfo::hostOs());
- //! Prepare argument of a shell command for feeding into QProcess
- static Arguments prepareArgs(const QString &cmd, SplitError *err,
- OsType osType = HostOsInfo::hostOs(),
- const Environment *env = nullptr, const QString *pwd = nullptr,
- bool abortOnMeta = true);
- //! Prepare a shell command for feeding into QProcess
- static bool prepareCommand(const QString &command, const QString &arguments,
- QString *outCmd, Arguments *outArgs, OsType osType = HostOsInfo::hostOs(),
- const Environment *env = nullptr, const QString *pwd = nullptr);
- //! Quote and append each argument to a shell command
- static void addArgs(QString *args, const QStringList &inArgs);
- //! Append already quoted arguments to a shell command
- static void addArgs(QString *args, const QString &inArgs);
- //! Split a shell command into separate arguments. ArgIterator is usually a better choice.
- static QStringList splitArgs(const QString &cmd, OsType osType = HostOsInfo::hostOs(),
- bool abortOnMeta = false, SplitError *err = nullptr,
- const Environment *env = nullptr, const QString *pwd = nullptr);
- //! Safely replace the expandos in a shell command
- static bool expandMacros(QString *cmd, AbstractMacroExpander *mx,
- OsType osType = HostOsInfo::hostOs());
- static QString expandMacros(const QString &str, AbstractMacroExpander *mx,
- OsType osType = HostOsInfo::hostOs());
-
- /*! Iterate over arguments from a command line.
- * Assumes that the name of the actual command is *not* part of the line.
- * Terminates after the first command if the command line is complex.
- */
- class QTCREATOR_UTILS_EXPORT ArgIterator {
- public:
- ArgIterator(QString *str, OsType osType = HostOsInfo::hostOs())
- : m_str(str), m_osType(osType)
- {}
- //! Get the next argument. Returns false on encountering end of first command.
- bool next();
- //! True iff the argument is a plain string, possibly after unquoting.
- bool isSimple() const { return m_simple; }
- //! Return the string value of the current argument if it is simple, otherwise empty.
- QString value() const { return m_value; }
- //! Delete the last argument fetched via next() from the command line.
- void deleteArg();
- //! Insert argument into the command line after the last one fetched via next().
- //! This may be used before the first call to next() to insert at the front.
- void appendArg(const QString &str);
- private:
- QString *m_str, m_value;
- int m_pos = 0;
- int m_prev = -1;
- bool m_simple;
- OsType m_osType;
- };
-
- class QTCREATOR_UTILS_EXPORT ConstArgIterator {
- public:
- ConstArgIterator(const QString &str, OsType osType = HostOsInfo::hostOs())
- : m_str(str), m_ait(&m_str, osType)
- {}
- bool next() { return m_ait.next(); }
- bool isSimple() const { return m_ait.isSimple(); }
- QString value() const { return m_ait.value(); }
- private:
- QString m_str;
- ArgIterator m_ait;
- };
+
+ /* Timeout for hanging processes (triggers after no more output
+ * occurs on stderr/stdout). */
+ void setTimeoutS(int timeoutS);
+
+ void setCodec(QTextCodec *c);
+ void setTimeOutMessageBoxEnabled(bool);
+ void setExitCodeInterpreter(const std::function<QtcProcess::Result(int)> &interpreter);
+
+ // FIXME: This is currently only used in run(), not in start()
+ void setWriteData(const QByteArray &writeData);
+
+ void setStdOutCallback(const std::function<void(const QString &)> &callback);
+ void setStdErrCallback(const std::function<void(const QString &)> &callback);
+
+ static void setRemoteProcessHooks(const DeviceProcessHooks &hooks);
+
+ void setOpenMode(OpenMode mode);
+
+ bool stopProcess();
+ bool readDataFromProcess(int timeoutS, QByteArray *stdOut, QByteArray *stdErr,
+ bool showTimeOutMessageBox);
+
+ static QString normalizeNewlines(const QString &text);
+
+ Result result() const;
+ void setResult(Result result);
+
+ QByteArray allRawOutput() const;
+ QString allOutput() const;
+
+ QString stdOut() const;
+ QString stdErr() const;
+
+ QByteArray rawStdOut() const;
+ QByteArray rawStdErr() const;
+
+ int exitCode() const;
+
+ QString exitMessage();
+
+ // Helpers to find binaries. Do not use it for other path variables
+ // and file types.
+ static QString locateBinary(const QString &binary);
+ static QString locateBinary(const QString &path, const QString &binary);
+
+ static Environment systemEnvironmentForBinary(const FilePath &filePath);
private:
#if QT_VERSION < QT_VERSION_CHECK(6, 0, 0)
void setupChildProcess() override;
#endif
+ friend class SynchronousProcess;
+ friend QTCREATOR_UTILS_EXPORT QDebug operator<<(QDebug str, const QtcProcess &r);
+
+ Internal::QtcProcessPrivate *d = nullptr;
+
+ void setProcessEnvironment(const QProcessEnvironment &environment) = delete;
+ QProcessEnvironment processEnvironment() const = delete;
+};
+
+using ExitCodeInterpreter = std::function<QtcProcess::Result(int /*exitCode*/)>;
+
+QTCREATOR_UTILS_EXPORT QDebug operator<<(QDebug str, const QtcProcess &);
+
+class QTCREATOR_UTILS_EXPORT SynchronousProcess : public QtcProcess
+{
+ Q_OBJECT
+public:
+ SynchronousProcess();
+ ~SynchronousProcess() override;
+
+ // Force the use of 'runBlocking' for now.
+ void start() = delete;
- void setupChildProcess_impl();
+ // This starts a nested event loop when running the command.
+ void setProcessUserEventWhileRunning(); // Avoid.
- CommandLine m_commandLine;
- Environment m_environment;
- bool m_haveEnv = false;
- bool m_useCtrlCStub = false;
- bool m_lowPriority = false;
+ // Starts the command and waits for finish. User input processing depends
+ // on whether setProcessUserEventWhileRunning was called.
+ void runBlocking();
};
} // namespace Utils
diff --git a/src/libs/utils/savedaction.cpp b/src/libs/utils/savedaction.cpp
deleted file mode 100644
index 062a12b923..0000000000
--- a/src/libs/utils/savedaction.cpp
+++ /dev/null
@@ -1,323 +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 <utils/savedaction.h>
-
-#include "pathchooser.h"
-#include "pathlisteditor.h"
-#include "qtcassert.h"
-#include "qtcsettings.h"
-
-#include <QActionGroup>
-#include <QCheckBox>
-#include <QDebug>
-#include <QGroupBox>
-#include <QLineEdit>
-#include <QSettings>
-#include <QSpinBox>
-#include <QTextEdit>
-
-namespace Utils {
-
-//////////////////////////////////////////////////////////////////////////
-//
-// SavedAction
-//
-//////////////////////////////////////////////////////////////////////////
-
-/*!
- \class Utils::SavedAction
-
- \brief The SavedAction class is a helper class for actions with persistent
- state.
-*/
-
-SavedAction::SavedAction(QObject *parent)
-{
- setParent(parent);
- connect(&m_action, &QAction::triggered, this, &SavedAction::actionTriggered);
-}
-
-
-/*!
- Returns the current value of the object.
-
- \sa setValue()
-*/
-QVariant SavedAction::value() const
-{
- return m_value;
-}
-
-
-/*!
- Sets the current value of the object. If the value changed and
- \a doemit is true, the \c valueChanged() signal will be emitted.
-
- \sa value()
-*/
-void SavedAction::setValue(const QVariant &value, bool doemit)
-{
- if (value == m_value)
- return;
- m_value = value;
- if (m_action.isCheckable())
- m_action.setChecked(m_value.toBool());
- if (doemit)
- emit valueChanged(m_value);
-}
-
-
-/*!
- Returns the default value to be used when the item does not exist yet
- in the settings.
-
- \sa setDefaultValue()
-*/
-QVariant SavedAction::defaultValue() const
-{
- return m_defaultValue;
-}
-
-
-/*!
- Sets the default value to be used when the item does not exist yet
- in the settings.
-
- \sa defaultValue()
-*/
-void SavedAction::setDefaultValue(const QVariant &value)
-{
- m_defaultValue = value;
-}
-
-
-QString SavedAction::toString() const
-{
- return QLatin1String("value: ") + m_value.toString()
- + QLatin1String(" defaultvalue: ") + m_defaultValue.toString()
- + QLatin1String(" settingskey: ") + settingsKey();
-}
-
-/*
- Uses \c settingsGroup() and \c settingsKey() to restore the
- item from \a settings,
-
- \sa settingsKey(), settingsGroup(), writeSettings()
-*/
-void SavedAction::readSettings(const QSettings *settings)
-{
- if (settingsKey().isEmpty())
- return;
- QVariant var = settings->value(settingsKey(), m_defaultValue);
- // work around old ini files containing @Invalid() entries
- if (m_action.isCheckable() && !var.isValid())
- var = false;
- setValue(var);
-}
-
-/*
- Uses \c settingsGroup() and \c settingsKey() to write the
- item to \a settings,
-
- \sa settingsKey(), settingsGroup(), readSettings()
-*/
-void SavedAction::writeSettings(QSettings *settings)
-{
- if (settingsKey().isEmpty())
- return;
- QtcSettings::setValueWithDefault(settings, settingsKey(), m_value, m_defaultValue);
-}
-
-/*
- A \c SavedAction can be connected to a widget, typically a
- checkbox, radiobutton, or a lineedit in some configuration dialog.
-
- The widget will retrieve its contents from the SavedAction's
- value, and - depending on the \a ApplyMode - either write
- changes back immediately, or when \s SavedAction::apply()
- is called explicitly.
-
- \sa apply(), disconnectWidget()
-*/
-void SavedAction::connectWidget(QWidget *widget, ApplyMode applyMode)
-{
- QTC_ASSERT(!m_widget,
- qDebug() << "ALREADY CONNECTED: " << widget << m_widget << toString(); return);
- m_widget = widget;
-
- if (auto button = qobject_cast<QCheckBox *>(widget)) {
- if (!m_dialogText.isEmpty())
- button->setText(m_dialogText);
- button->setChecked(m_value.toBool());
- if (applyMode == ImmediateApply) {
- connect(button, &QCheckBox::clicked,
- this, [this, button] { setValue(button->isChecked()); });
- }
- } else if (auto spinBox = qobject_cast<QSpinBox *>(widget)) {
- spinBox->setValue(m_value.toInt());
- if (applyMode == ImmediateApply) {
- connect(spinBox, QOverload<int>::of(&QSpinBox::valueChanged),
- this, [this, spinBox]() { setValue(spinBox->value()); });
- }
- } else if (auto lineEdit = qobject_cast<QLineEdit *>(widget)) {
- lineEdit->setText(m_value.toString());
- if (applyMode == ImmediateApply) {
- connect(lineEdit, &QLineEdit::editingFinished,
- this, [this, lineEdit] { setValue(lineEdit->text()); });
- }
-
- } else if (auto pathChooser = qobject_cast<PathChooser *>(widget)) {
- pathChooser->setPath(m_value.toString());
- if (applyMode == ImmediateApply) {
- auto finished = [this, pathChooser] { setValue(pathChooser->path()); };
- connect(pathChooser, &PathChooser::editingFinished, this, finished);
- connect(pathChooser, &PathChooser::browsingFinished, this, finished);
- }
- } else if (auto groupBox = qobject_cast<QGroupBox *>(widget)) {
- if (!groupBox->isCheckable())
- qDebug() << "connectWidget to non-checkable group box" << widget << toString();
- groupBox->setChecked(m_value.toBool());
- if (applyMode == ImmediateApply) {
- connect(groupBox, &QGroupBox::toggled,
- this, [this, groupBox] { setValue(QVariant(groupBox->isChecked())); });
- }
- } else if (auto textEdit = qobject_cast<QTextEdit *>(widget)) {
- textEdit->setPlainText(m_value.toString());
- if (applyMode == ImmediateApply) {
- connect(textEdit, &QTextEdit::textChanged,
- this, [this, textEdit] { setValue(textEdit->toPlainText()); });
- }
- } else if (auto editor = qobject_cast<PathListEditor *>(widget)) {
- editor->setPathList(m_value.toStringList());
- } else {
- qDebug() << "Cannot connect widget " << widget << toString();
- }
-
- // Copy tooltip, but only if there's nothing explcitly set on the widget yet.
- if (widget->toolTip().isEmpty())
- widget->setToolTip(m_action.toolTip());
-}
-
-/*
- Disconnects the \c SavedAction from a widget.
-
- \sa apply(), connectWidget()
-*/
-void SavedAction::disconnectWidget()
-{
- m_widget = nullptr;
-}
-
-void SavedAction::apply(QSettings *s)
-{
- if (auto button = qobject_cast<QCheckBox *>(m_widget))
- setValue(button->isChecked());
- else if (auto lineEdit = qobject_cast<QLineEdit *>(m_widget))
- setValue(lineEdit->text());
- else if (auto spinBox = qobject_cast<QSpinBox *>(m_widget))
- setValue(spinBox->value());
- else if (auto pathChooser = qobject_cast<PathChooser *>(m_widget))
- setValue(pathChooser->path());
- else if (auto groupBox = qobject_cast<QGroupBox *>(m_widget))
- setValue(groupBox->isChecked());
- else if (auto textEdit = qobject_cast<QTextEdit *>(m_widget))
- setValue(textEdit->toPlainText());
- else if (auto editor = qobject_cast<PathListEditor *>(m_widget))
- setValue(editor->pathList());
- if (s)
- writeSettings(s);
-}
-
-/*
- Default text to be used in labels if this SavedAction is
- used in a settings dialog.
-
- This typically is similar to the text this SavedAction shows
- when used in menus, but differs in capitalization.
-
-
- \sa text()
-*/
-QString SavedAction::dialogText() const
-{
- return m_dialogText;
-}
-
-void SavedAction::setDialogText(const QString &dialogText)
-{
- m_dialogText = dialogText;
-}
-
-void SavedAction::actionTriggered(bool)
-{
- if (m_action.isCheckable())
- setValue(m_action.isChecked());
- if (m_action.actionGroup() && m_action.actionGroup()->isExclusive()) {
- // FIXME: should be taken care of more directly
- const QList<QAction *> actions = m_action.actionGroup()->actions();
- for (QAction *act : actions)
- if (auto dact = qobject_cast<SavedAction *>(act))
- dact->setValue(bool(act == &m_action));
- }
-}
-
-QAction *SavedAction::action()
-{
- return &m_action;
-}
-
-void SavedAction::trigger(const QVariant &data)
-{
- m_action.setData(data);
- m_action.trigger();
-}
-
-//////////////////////////////////////////////////////////////////////////
-//
-// SavedActionSet
-//
-//////////////////////////////////////////////////////////////////////////
-
-void SavedActionSet::insert(SavedAction *action, QWidget *widget)
-{
- m_list.append(action);
- if (widget)
- action->connectWidget(widget);
-}
-
-void SavedActionSet::apply(QSettings *settings)
-{
- for (SavedAction *action : qAsConst(m_list))
- action->apply(settings);
-}
-
-void SavedActionSet::finish()
-{
- for (SavedAction *action : qAsConst(m_list))
- action->disconnectWidget();
-}
-
-} // namespace Utils
diff --git a/src/libs/utils/savedaction.h b/src/libs/utils/savedaction.h
deleted file mode 100644
index a6188ab509..0000000000
--- a/src/libs/utils/savedaction.h
+++ /dev/null
@@ -1,106 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of Qt Creator.
-**
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 3 as published by the Free Software
-** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-3.0.html.
-**
-****************************************************************************/
-
-#pragma once
-
-#include "utils_global.h"
-
-#include "aspects.h"
-
-#include <QAction>
-
-QT_BEGIN_NAMESPACE
-class QSettings;
-QT_END_NAMESPACE
-
-namespace Utils {
-
-enum ApplyMode { ImmediateApply, DeferedApply };
-
-class QTCREATOR_UTILS_EXPORT SavedAction : public BaseAspect
-{
- Q_OBJECT
-
-public:
- SavedAction(QObject *parent = nullptr);
-
- QVariant value() const;
- void setValue(const QVariant &value, bool doemit = true);
-
- QVariant defaultValue() const;
- void setDefaultValue(const QVariant &value);
-
- void trigger(const QVariant &data);
-
- virtual void readSettings(const QSettings *settings);
- virtual void writeSettings(QSettings *settings);
-
- void connectWidget(QWidget *widget, ApplyMode applyMode = DeferedApply);
- void disconnectWidget();
- void apply(QSettings *settings);
-
- QString toString() const;
-
- QString dialogText() const;
- void setDialogText(const QString &dialogText);
-
- QAction *action();
-
- void setText(const QString &text) { m_action.setText(text); }
- void setToolTip(const QString &toolTip) { m_action.setToolTip(toolTip); }
- void setCheckable(bool checkable) { m_action.setCheckable(checkable); }
- void setChecked(bool checked) { m_action.setChecked(checked); }
- void setEnabled(bool enabled) { m_action.setEnabled(enabled); }
- void setIcon(const QIcon &icon) { m_action.setIcon(icon); }
-
-signals:
- void valueChanged(const QVariant &newValue);
-
-private:
- void actionTriggered(bool);
-
- QVariant m_value;
- QVariant m_defaultValue;
- QString m_dialogText;
- QWidget *m_widget = nullptr;
- QAction m_action;
-};
-
-class QTCREATOR_UTILS_EXPORT SavedActionSet
-{
-public:
- SavedActionSet() = default;
- ~SavedActionSet() = default;
-
- void insert(SavedAction *action, QWidget *widget);
- void apply(QSettings *settings);
- void finish();
- void clear() { m_list.clear(); }
-
-private:
- QList<SavedAction *> m_list;
-};
-
-} // namespace Utils
diff --git a/src/libs/utils/shellcommand.cpp b/src/libs/utils/shellcommand.cpp
index 6742858aa0..0da6738bfe 100644
--- a/src/libs/utils/shellcommand.cpp
+++ b/src/libs/utils/shellcommand.cpp
@@ -25,6 +25,7 @@
#include "shellcommand.h"
+#include "environment.h"
#include "fileutils.h"
#include "qtcassert.h"
#include "runextensions.h"
@@ -77,14 +78,17 @@ public:
int timeoutS;
};
- ShellCommandPrivate(const QString &defaultWorkingDirectory,
- const QProcessEnvironment &environment);
- ~ShellCommandPrivate();
+ ShellCommandPrivate(const QString &defaultWorkingDirectory, const Environment &environment)
+ : m_defaultWorkingDirectory(defaultWorkingDirectory),
+ m_environment(environment)
+ {}
+
+ ~ShellCommandPrivate() { delete m_progressParser; }
std::function<OutputProxy *()> m_proxyFactory = []() { return new OutputProxy; };
QString m_displayName;
const QString m_defaultWorkingDirectory;
- const QProcessEnvironment m_environment;
+ const Environment m_environment;
QVariant m_cookie;
QTextCodec *m_codec = nullptr;
ProgressParser *m_progressParser = nullptr;
@@ -99,19 +103,9 @@ public:
bool m_progressiveOutput = false;
bool m_hadOutput = false;
bool m_aborted = false;
+ bool m_disableUnixTerminal = false;
};
-ShellCommandPrivate::ShellCommandPrivate(const QString &defaultWorkingDirectory,
- const QProcessEnvironment &environment) :
- m_defaultWorkingDirectory(defaultWorkingDirectory),
- m_environment(environment)
-{ }
-
-ShellCommandPrivate::~ShellCommandPrivate()
-{
- delete m_progressParser;
-}
-
ShellCommandPrivate::Job::Job(const QString &wd, const CommandLine &command,
int t, const ExitCodeInterpreter &interpreter) :
workingDirectory(wd),
@@ -127,7 +121,7 @@ ShellCommandPrivate::Job::Job(const QString &wd, const CommandLine &command,
} // namespace Internal
ShellCommand::ShellCommand(const QString &workingDirectory,
- const QProcessEnvironment &environment) :
+ const Environment &environment) :
d(new Internal::ShellCommandPrivate(workingDirectory, environment))
{
connect(&d->m_watcher, &QFutureWatcher<void>::canceled, this, &ShellCommand::cancel);
@@ -168,7 +162,7 @@ const QString &ShellCommand::defaultWorkingDirectory() const
return d->m_defaultWorkingDirectory;
}
-const QProcessEnvironment ShellCommand::processEnvironment() const
+const Environment ShellCommand::processEnvironment() const
{
return d->m_environment;
}
@@ -231,11 +225,6 @@ void ShellCommand::cancel()
emit terminate();
}
-unsigned ShellCommand::processFlags() const
-{
- return 0;
-}
-
void ShellCommand::addTask(QFuture<void> &future)
{
Q_UNUSED(future)
@@ -284,13 +273,14 @@ void ShellCommand::run(QFutureInterface<void> &future)
d->m_lastExecSuccess = true;
for (int j = 0; j < count; j++) {
const Internal::ShellCommandPrivate::Job &job = d->m_jobs.at(j);
- SynchronousProcessResponse resp
- = runCommand(job.command, job.timeoutS, job.workingDirectory,
- job.exitCodeInterpreter);
- stdOut += resp.stdOut();
- stdErr += resp.stdErr();
- d->m_lastExecExitCode = resp.exitCode;
- d->m_lastExecSuccess = resp.result == SynchronousProcessResponse::Finished;
+ SynchronousProcess proc;
+ proc.setExitCodeInterpreter(job.exitCodeInterpreter);
+ proc.setTimeoutS(job.timeoutS);
+ runCommand(proc, job.command, job.workingDirectory);
+ stdOut += proc.stdOut();
+ stdErr += proc.stdErr();
+ d->m_lastExecExitCode = proc.exitCode();
+ d->m_lastExecSuccess = proc.result() == QtcProcess::Finished;
if (!d->m_lastExecSuccess)
break;
}
@@ -317,17 +307,15 @@ void ShellCommand::run(QFutureInterface<void> &future)
this->deleteLater();
}
-SynchronousProcessResponse ShellCommand::runCommand(const CommandLine &command, int timeoutS,
- const QString &workingDirectory,
- const ExitCodeInterpreter &interpreter)
+void ShellCommand::runCommand(SynchronousProcess &proc,
+ const CommandLine &command,
+ const QString &workingDirectory)
{
- SynchronousProcessResponse response;
-
const QString dir = workDirectory(workingDirectory);
if (command.executable().isEmpty()) {
- response.result = SynchronousProcessResponse::StartFailed;
- return response;
+ proc.setResult(QtcProcess::StartFailed);
+ return;
}
QSharedPointer<OutputProxy> proxy(d->m_proxyFactory());
@@ -335,55 +323,50 @@ SynchronousProcessResponse ShellCommand::runCommand(const CommandLine &command,
if (!(d->m_flags & SuppressCommandLogging))
emit proxy->appendCommand(dir, command);
+ proc.setCommand(command);
if ((d->m_flags & FullySynchronously)
|| (!(d->m_flags & NoFullySync)
&& QThread::currentThread() == QCoreApplication::instance()->thread())) {
- response = runFullySynchronous(command, proxy, timeoutS, dir, interpreter);
+ runFullySynchronous(proc, proxy, dir);
} else {
- response = runSynchronous(command, proxy, timeoutS, dir, interpreter);
+ runSynchronous(proc, proxy, dir);
}
if (!d->m_aborted) {
// Success/Fail message in appropriate window?
- if (response.result == SynchronousProcessResponse::Finished) {
+ if (proc.result() == QtcProcess::Finished) {
if (d->m_flags & ShowSuccessMessage)
- emit proxy->appendMessage(response.exitMessage(command.executable().toUserOutput(), timeoutS));
+ emit proxy->appendMessage(proc.exitMessage());
} else if (!(d->m_flags & SuppressFailMessage)) {
- emit proxy->appendError(response.exitMessage(command.executable().toUserOutput(), timeoutS));
+ emit proxy->appendError(proc.exitMessage());
}
}
-
- return response;
}
-SynchronousProcessResponse ShellCommand::runFullySynchronous(const CommandLine &cmd,
- QSharedPointer<OutputProxy> proxy,
- int timeoutS,
- const QString &workingDirectory,
- const ExitCodeInterpreter &interpreter)
+void ShellCommand::runFullySynchronous(SynchronousProcess &process,
+ QSharedPointer<OutputProxy> proxy,
+ const QString &workingDirectory)
{
// Set up process
- SynchronousProcess process;
- process.setFlags(processFlags());
+ if (d->m_disableUnixTerminal)
+ process.setDisableUnixTerminal();
const QString dir = workDirectory(workingDirectory);
if (!dir.isEmpty())
process.setWorkingDirectory(dir);
- process.setProcessEnvironment(processEnvironment());
+ process.setEnvironment(processEnvironment());
if (d->m_flags & MergeOutputChannels)
process.setProcessChannelMode(QProcess::MergedChannels);
if (d->m_codec)
process.setCodec(d->m_codec);
- process.setTimeoutS(timeoutS);
- process.setExitCodeInterpreter(interpreter);
- SynchronousProcessResponse resp = process.runBlocking(cmd);
+ process.runBlocking();
if (!d->m_aborted) {
- const QString stdErr = resp.stdErr();
+ const QString stdErr = process.stdErr();
if (!stdErr.isEmpty() && !(d->m_flags & SuppressStdErr))
emit proxy->append(stdErr);
- const QString stdOut = resp.stdOut();
+ const QString stdOut = process.stdOut();
if (!stdOut.isEmpty() && d->m_flags & ShowStdOut) {
if (d->m_flags & SilentOutput)
emit proxy->appendSilently(stdOut);
@@ -391,35 +374,26 @@ SynchronousProcessResponse ShellCommand::runFullySynchronous(const CommandLine &
emit proxy->append(stdOut);
}
}
-
- return resp;
}
-SynchronousProcessResponse ShellCommand::runSynchronous(const CommandLine &cmd,
- QSharedPointer<OutputProxy> proxy,
- int timeoutS,
- const QString &workingDirectory,
- const ExitCodeInterpreter &interpreter)
+void ShellCommand::runSynchronous(SynchronousProcess &process,
+ QSharedPointer<OutputProxy> proxy,
+ const QString &workingDirectory)
{
- SynchronousProcess process;
- process.setExitCodeInterpreter(interpreter);
- connect(this, &ShellCommand::terminate, &process, &SynchronousProcess::terminate);
- process.setProcessEnvironment(processEnvironment());
- process.setTimeoutS(timeoutS);
+ connect(this, &ShellCommand::terminate, &process, &SynchronousProcess::stopProcess);
+ process.setEnvironment(processEnvironment());
if (d->m_codec)
process.setCodec(d->m_codec);
- process.setFlags(processFlags());
+ if (d->m_disableUnixTerminal)
+ process.setDisableUnixTerminal();
const QString dir = workDirectory(workingDirectory);
if (!dir.isEmpty())
process.setWorkingDirectory(dir);
- process.setProcessEnvironment(processEnvironment());
// connect stderr to the output window if desired
if (d->m_flags & MergeOutputChannels) {
process.setProcessChannelMode(QProcess::MergedChannels);
} else if (d->m_progressiveOutput || !(d->m_flags & SuppressStdErr)) {
- process.setStdErrBufferedSignalsEnabled(true);
- connect(&process, &SynchronousProcess::stdErrBuffered,
- this, [this, proxy](const QString &text) {
+ process.setStdErrCallback([this, proxy](const QString &text) {
if (d->m_progressParser)
d->m_progressParser->parseProgress(text);
if (!(d->m_flags & SuppressStdErr))
@@ -431,9 +405,7 @@ SynchronousProcessResponse ShellCommand::runSynchronous(const CommandLine &cmd,
// connect stdout to the output window if desired
if (d->m_progressParser || d->m_progressiveOutput || (d->m_flags & ShowStdOut)) {
- process.setStdOutBufferedSignalsEnabled(true);
- connect(&process, &SynchronousProcess::stdOutBuffered,
- this, [this, proxy](const QString &text) {
+ process.setStdOutCallback([this, proxy](const QString &text) {
if (d->m_progressParser)
d->m_progressParser->parseProgress(text);
if (d->m_flags & ShowStdOut)
@@ -449,10 +421,9 @@ SynchronousProcessResponse ShellCommand::runSynchronous(const CommandLine &cmd,
if (d->m_codec)
process.setCodec(d->m_codec);
- process.setTimeoutS(timeoutS);
- process.setExitCodeInterpreter(interpreter);
- return process.run(cmd);
+ process.setProcessUserEventWhileRunning();
+ process.runBlocking();
}
const QVariant &ShellCommand::cookie() const
@@ -497,6 +468,11 @@ void ShellCommand::setOutputProxyFactory(const std::function<OutputProxy *()> &f
d->m_proxyFactory = factory;
}
+void ShellCommand::setDisableUnixTerminal()
+{
+ d->m_disableUnixTerminal = true;
+}
+
ProgressParser::ProgressParser() :
m_futureMutex(new QMutex)
{ }
diff --git a/src/libs/utils/shellcommand.h b/src/libs/utils/shellcommand.h
index df89abad6e..5c606cb656 100644
--- a/src/libs/utils/shellcommand.h
+++ b/src/libs/utils/shellcommand.h
@@ -27,16 +27,13 @@
#include "utils_global.h"
-#include "synchronousprocess.h"
-
-#include <QObject>
+#include "qtcprocess.h"
#include <functional>
QT_BEGIN_NAMESPACE
class QMutex;
class QVariant;
-class QProcessEnvironment;
template <typename T>
class QFutureInterface;
template <typename T>
@@ -45,7 +42,6 @@ QT_END_NAMESPACE
namespace Utils {
-class CommandLine;
namespace Internal { class ShellCommandPrivate; }
class QTCREATOR_UTILS_EXPORT ProgressParser
@@ -104,7 +100,7 @@ public:
};
- ShellCommand(const QString &workingDirectory, const QProcessEnvironment &environment);
+ ShellCommand(const QString &workingDirectory, const Environment &environment);
~ShellCommand() override;
QString displayName() const;
@@ -112,17 +108,17 @@ public:
void addJob(const CommandLine &command,
const QString &workingDirectory = QString(),
- const ExitCodeInterpreter &interpreter = defaultExitCodeInterpreter);
+ const ExitCodeInterpreter &interpreter = {});
void addJob(const CommandLine &command, int timeoutS,
const QString &workingDirectory = QString(),
- const ExitCodeInterpreter &interpreter = defaultExitCodeInterpreter);
+ const ExitCodeInterpreter &interpreter = {});
void execute(); // Execute tasks asynchronously!
void abort();
bool lastExecutionSuccess() const;
int lastExecutionExitCode() const;
const QString &defaultWorkingDirectory() const;
- virtual const QProcessEnvironment processEnvironment() const;
+ virtual const Environment processEnvironment() const;
int defaultTimeoutS() const;
void setDefaultTimeoutS(int timeout);
@@ -141,14 +137,14 @@ public:
void setProgressiveOutput(bool progressive);
void setOutputProxyFactory(const std::function<OutputProxy *()> &factory);
+ void setDisableUnixTerminal();
// This is called once per job in a thread.
// When called from the UI thread it will execute fully synchronously, so no signals will
// be triggered!
- virtual SynchronousProcessResponse runCommand(const CommandLine &command,
- int timeoutS,
- const QString &workingDirectory = QString(),
- const ExitCodeInterpreter &interpreter = defaultExitCodeInterpreter);
+ virtual void runCommand(Utils::SynchronousProcess &process,
+ const CommandLine &command,
+ const QString &workingDirectory = QString());
void cancel();
@@ -162,7 +158,6 @@ signals:
void terminate(); // Internal
protected:
- virtual unsigned processFlags() const;
virtual void addTask(QFuture<void> &future);
int timeoutS() const;
QString workDirectory(const QString &wd) const;
@@ -171,15 +166,13 @@ private:
void run(QFutureInterface<void> &future);
// Run without a event loop in fully blocking mode. No signals will be delivered.
- SynchronousProcessResponse runFullySynchronous(const CommandLine &cmd,
- QSharedPointer<OutputProxy> proxy,
- int timeoutS, const QString &workingDirectory,
- const ExitCodeInterpreter &interpreter = defaultExitCodeInterpreter);
+ void runFullySynchronous(SynchronousProcess &proc,
+ QSharedPointer<OutputProxy> proxy,
+ const QString &workingDirectory);
// Run with an event loop. Signals will be delivered.
- SynchronousProcessResponse runSynchronous(const CommandLine &cmd,
- QSharedPointer<OutputProxy> proxy,
- int timeoutS, const QString &workingDirectory,
- const ExitCodeInterpreter &interpreter = defaultExitCodeInterpreter);
+ void runSynchronous(SynchronousProcess &proc,
+ QSharedPointer<OutputProxy> proxy,
+ const QString &workingDirectory);
class Internal::ShellCommandPrivate *const d;
};
diff --git a/src/libs/utils/synchronousprocess.cpp b/src/libs/utils/synchronousprocess.cpp
deleted file mode 100644
index fa6cf77556..0000000000
--- a/src/libs/utils/synchronousprocess.cpp
+++ /dev/null
@@ -1,808 +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 "synchronousprocess.h"
-#include "executeondestruction.h"
-#include "hostosinfo.h"
-#include "qtcassert.h"
-#include "qtcprocess.h"
-
-#include <QDebug>
-#include <QDir>
-#include <QLoggingCategory>
-#include <QMessageBox>
-#include <QTextCodec>
-#include <QThread>
-#include <QTimer>
-
-#include <QApplication>
-
-#include <algorithm>
-#include <limits.h>
-#include <memory>
-
-#ifdef Q_OS_UNIX
-# include <unistd.h>
-#endif
-
-/*!
- \class Utils::SynchronousProcess
-
- \brief The SynchronousProcess class runs a synchronous process in its own
- event loop that blocks only user input events. Thus, it allows for the GUI to
- repaint and append output to log windows.
-
- The stdOut(), stdErr() signals are emitted unbuffered as the process
- writes them.
-
- The stdOutBuffered(), stdErrBuffered() signals are emitted with complete
- lines based on the '\\n' marker if they are enabled using
- stdOutBufferedSignalsEnabled()/setStdErrBufferedSignalsEnabled().
- They would typically be used for log windows.
-
- There is a timeout handling that takes effect after the last data have been
- read from stdout/stdin (as opposed to waitForFinished(), which measures time
- since it was invoked). It is thus also suitable for slow processes that continously
- output data (like version system operations).
-
- The property timeOutMessageBoxEnabled influences whether a message box is
- shown asking the user if they want to kill the process on timeout (default: false).
-
- There are also static utility functions for dealing with fully synchronous
- processes, like reading the output with correct timeout handling.
-
- Caution: This class should NOT be used if there is a chance that the process
- triggers opening dialog boxes (for example, by file watchers triggering),
- as this will cause event loop problems.
-*/
-
-enum { debug = 0 };
-enum { syncDebug = 0 };
-
-enum { defaultMaxHangTimerCount = 10 };
-
-namespace Utils {
-
-static Q_LOGGING_CATEGORY(processLog, "qtc.utils.synchronousprocess", QtWarningMsg);
-
-// A special QProcess derivative allowing for terminal control.
-class TerminalControllingProcess : public QProcess {
-public:
- TerminalControllingProcess();
-
- unsigned flags() const { return m_flags; }
- void setFlags(unsigned tc) { m_flags = tc; }
-
-protected:
-#if QT_VERSION < QT_VERSION_CHECK(6, 0, 0)
- void setupChildProcess() override;
-#endif
-
-private:
- void setupChildProcess_impl();
-
- unsigned m_flags = 0;
-};
-
-TerminalControllingProcess::TerminalControllingProcess()
-{
-#if QT_VERSION >= QT_VERSION_CHECK(6, 0, 0) && defined(Q_OS_UNIX)
- setChildProcessModifier([this] { setupChildProcess_impl(); });
-#endif
-}
-
-#if QT_VERSION < QT_VERSION_CHECK(6, 0, 0)
-void TerminalControllingProcess::setupChildProcess()
-{
- setupChildProcess_impl();
-}
-#endif
-
-void TerminalControllingProcess::setupChildProcess_impl()
-{
-#ifdef Q_OS_UNIX
- // Disable terminal by becoming a session leader.
- if (m_flags & SynchronousProcess::UnixTerminalDisabled)
- setsid();
-#endif
-}
-
-// ----------- SynchronousProcessResponse
-void SynchronousProcessResponse::clear()
-{
- result = StartFailed;
- exitCode = -1;
- rawStdOut.clear();
- rawStdErr.clear();
-}
-
-QString SynchronousProcessResponse::exitMessage(const QString &binary, int timeoutS) const
-{
- switch (result) {
- case Finished:
- return SynchronousProcess::tr("The command \"%1\" finished successfully.").arg(QDir::toNativeSeparators(binary));
- case FinishedError:
- return SynchronousProcess::tr("The command \"%1\" terminated with exit code %2.").arg(QDir::toNativeSeparators(binary)).arg(exitCode);
- case TerminatedAbnormally:
- return SynchronousProcess::tr("The command \"%1\" terminated abnormally.").arg(QDir::toNativeSeparators(binary));
- case StartFailed:
- return SynchronousProcess::tr("The command \"%1\" could not be started.").arg(QDir::toNativeSeparators(binary));
- case Hang:
- return SynchronousProcess::tr("The command \"%1\" did not respond within the timeout limit (%2 s).")
- .arg(QDir::toNativeSeparators(binary)).arg(timeoutS);
- }
- return QString();
-}
-
-QByteArray SynchronousProcessResponse::allRawOutput() const
-{
- if (!rawStdOut.isEmpty() && !rawStdErr.isEmpty()) {
- QByteArray result = rawStdOut;
- if (!result.endsWith('\n'))
- result += '\n';
- result += rawStdErr;
- return result;
- }
- return !rawStdOut.isEmpty() ? rawStdOut : rawStdErr;
-}
-
-QString SynchronousProcessResponse::allOutput() const
-{
- const QString out = stdOut();
- const QString err = stdErr();
-
- if (!out.isEmpty() && !err.isEmpty()) {
- QString result = out;
- if (!result.endsWith('\n'))
- result += '\n';
- result += err;
- return result;
- }
- return !out.isEmpty() ? out : err;
-}
-
-QString SynchronousProcessResponse::stdOut() const
-{
- return SynchronousProcess::normalizeNewlines(codec->toUnicode(rawStdOut));
-}
-
-QString SynchronousProcessResponse::stdErr() const
-{
- return SynchronousProcess::normalizeNewlines(codec->toUnicode(rawStdErr));
-}
-
-QTCREATOR_UTILS_EXPORT QDebug operator<<(QDebug str, const SynchronousProcessResponse& r)
-{
- QDebug nsp = str.nospace();
- nsp << "SynchronousProcessResponse: result=" << r.result << " ex=" << r.exitCode << '\n'
- << r.rawStdOut.size() << " bytes stdout, stderr=" << r.rawStdErr << '\n';
- return str;
-}
-
-SynchronousProcessResponse::Result defaultExitCodeInterpreter(int code)
-{
- return code ? SynchronousProcessResponse::FinishedError
- : SynchronousProcessResponse::Finished;
-}
-
-// Data for one channel buffer (stderr/stdout)
-class ChannelBuffer : public QObject
-{
- Q_OBJECT
-
-public:
- void clearForRun();
-
- QString linesRead();
- void append(const QByteArray &text, bool emitSignals);
-
- QByteArray rawData;
- QString incompleteLineBuffer; // lines not yet signaled
- QTextCodec *codec = nullptr; // Not owner
- std::unique_ptr<QTextCodec::ConverterState> codecState;
- int rawDataPos = 0;
- bool bufferedSignalsEnabled = false;
- bool firstBuffer = true;
-
-signals:
- void outputBuffered(const QString &text, bool firstTime);
-};
-
-void ChannelBuffer::clearForRun()
-{
- firstBuffer = true;
- rawDataPos = 0;
- rawData.clear();
- codecState.reset(new QTextCodec::ConverterState);
- incompleteLineBuffer.clear();
-}
-
-/* Check for complete lines read from the device and return them, moving the
- * buffer position. */
-QString ChannelBuffer::linesRead()
-{
- // Convert and append the new input to the buffer of incomplete lines
- const char *start = rawData.constData() + rawDataPos;
- const int len = rawData.size() - rawDataPos;
- incompleteLineBuffer.append(codec->toUnicode(start, len, codecState.get()));
- rawDataPos = rawData.size();
-
- // Any completed lines in the incompleteLineBuffer?
- const int lastLineIndex = qMax(incompleteLineBuffer.lastIndexOf('\n'),
- incompleteLineBuffer.lastIndexOf('\r'));
- if (lastLineIndex == -1)
- return QString();
-
- // Get completed lines and remove them from the incompleteLinesBuffer:
- const QString lines = SynchronousProcess::normalizeNewlines(incompleteLineBuffer.left(lastLineIndex + 1));
- incompleteLineBuffer = incompleteLineBuffer.mid(lastLineIndex + 1);
-
- return lines;
-}
-
-void ChannelBuffer::append(const QByteArray &text, bool emitSignals)
-{
- if (text.isEmpty())
- return;
- rawData += text;
- if (!emitSignals)
- return;
-
- // Buffered. Emit complete lines?
- if (bufferedSignalsEnabled) {
- const QString lines = linesRead();
- if (!lines.isEmpty()) {
- emit outputBuffered(lines, firstBuffer);
- firstBuffer = false;
- }
- }
-}
-
-// ----------- SynchronousProcessPrivate
-class SynchronousProcessPrivate {
-public:
- void clearForRun();
-
- QTextCodec *m_codec = QTextCodec::codecForLocale();
- TerminalControllingProcess m_process;
- QTimer m_timer;
- QEventLoop m_eventLoop;
- SynchronousProcessResponse m_result;
- FilePath m_binary;
- ChannelBuffer m_stdOut;
- ChannelBuffer m_stdErr;
- ExitCodeInterpreter m_exitCodeInterpreter = defaultExitCodeInterpreter;
-
- int m_hangTimerCount = 0;
- int m_maxHangTimerCount = defaultMaxHangTimerCount;
- bool m_startFailure = false;
- bool m_timeOutMessageBoxEnabled = false;
- bool m_waitingForUser = false;
-};
-
-void SynchronousProcessPrivate::clearForRun()
-{
- m_hangTimerCount = 0;
- m_stdOut.clearForRun();
- m_stdOut.codec = m_codec;
- m_stdErr.clearForRun();
- m_stdErr.codec = m_codec;
- m_result.clear();
- m_result.codec = m_codec;
- m_startFailure = false;
- m_binary = {};
-}
-
-// ----------- SynchronousProcess
-SynchronousProcess::SynchronousProcess() :
- d(new SynchronousProcessPrivate)
-{
- d->m_timer.setInterval(1000);
- connect(&d->m_timer, &QTimer::timeout, this, &SynchronousProcess::slotTimeout);
- connect(&d->m_process, QOverload<int, QProcess::ExitStatus>::of(&QProcess::finished),
- this, &SynchronousProcess::finished);
- connect(&d->m_process, &QProcess::errorOccurred, this, &SynchronousProcess::error);
- connect(&d->m_process, &QProcess::readyReadStandardOutput,
- this, [this]() {
- d->m_hangTimerCount = 0;
- processStdOut(true);
- });
- connect(&d->m_process, &QProcess::readyReadStandardError,
- this, [this]() {
- d->m_hangTimerCount = 0;
- processStdErr(true);
- });
- connect(&d->m_stdOut, &ChannelBuffer::outputBuffered, this, &SynchronousProcess::stdOutBuffered);
- connect(&d->m_stdErr, &ChannelBuffer::outputBuffered, this, &SynchronousProcess::stdErrBuffered);
-}
-
-SynchronousProcess::~SynchronousProcess()
-{
- disconnect(&d->m_timer, nullptr, this, nullptr);
- disconnect(&d->m_process, nullptr, this, nullptr);
- delete d;
-}
-
-void SynchronousProcess::setTimeoutS(int timeoutS)
-{
- if (timeoutS > 0)
- d->m_maxHangTimerCount = qMax(2, timeoutS);
- else
- d->m_maxHangTimerCount = INT_MAX / 1000;
-}
-
-int SynchronousProcess::timeoutS() const
-{
- return d->m_maxHangTimerCount == (INT_MAX / 1000) ? -1 : d->m_maxHangTimerCount;
-}
-
-void SynchronousProcess::setCodec(QTextCodec *c)
-{
- QTC_ASSERT(c, return);
- d->m_codec = c;
-}
-
-QTextCodec *SynchronousProcess::codec() const
-{
- return d->m_codec;
-}
-
-bool SynchronousProcess::stdOutBufferedSignalsEnabled() const
-{
- return d->m_stdOut.bufferedSignalsEnabled;
-}
-
-void SynchronousProcess::setStdOutBufferedSignalsEnabled(bool v)
-{
- d->m_stdOut.bufferedSignalsEnabled = v;
-}
-
-bool SynchronousProcess::stdErrBufferedSignalsEnabled() const
-{
- return d->m_stdErr.bufferedSignalsEnabled;
-}
-
-void SynchronousProcess::setStdErrBufferedSignalsEnabled(bool v)
-{
- d->m_stdErr.bufferedSignalsEnabled = v;
-}
-
-QStringList SynchronousProcess::environment() const
-{
- return d->m_process.environment();
-}
-
-bool SynchronousProcess::timeOutMessageBoxEnabled() const
-{
- return d->m_timeOutMessageBoxEnabled;
-}
-
-void SynchronousProcess::setTimeOutMessageBoxEnabled(bool v)
-{
- d->m_timeOutMessageBoxEnabled = v;
-}
-
-void SynchronousProcess::setEnvironment(const QStringList &e)
-{
- d->m_process.setEnvironment(e);
-}
-
-void SynchronousProcess::setProcessEnvironment(const QProcessEnvironment &environment)
-{
- d->m_process.setProcessEnvironment(environment);
-}
-
-QProcessEnvironment SynchronousProcess::processEnvironment() const
-{
- return d->m_process.processEnvironment();
-}
-
-unsigned SynchronousProcess::flags() const
-{
- return d->m_process.flags();
-}
-
-void SynchronousProcess::setFlags(unsigned tc)
-{
- d->m_process.setFlags(tc);
-}
-
-void SynchronousProcess::setExitCodeInterpreter(const ExitCodeInterpreter &interpreter)
-{
- QTC_ASSERT(interpreter, return);
- d->m_exitCodeInterpreter = interpreter;
-}
-
-ExitCodeInterpreter SynchronousProcess::exitCodeInterpreter() const
-{
- return d->m_exitCodeInterpreter;
-}
-
-void SynchronousProcess::setWorkingDirectory(const QString &workingDirectory)
-{
- d->m_process.setWorkingDirectory(workingDirectory);
-}
-
-QString SynchronousProcess::workingDirectory() const
-{
- return d->m_process.workingDirectory();
-}
-
-QProcess::ProcessChannelMode SynchronousProcess::processChannelMode () const
-{
- return d->m_process.processChannelMode();
-}
-
-void SynchronousProcess::setProcessChannelMode(QProcess::ProcessChannelMode m)
-{
- d->m_process.setProcessChannelMode(m);
-}
-
-static bool isGuiThread()
-{
- return QThread::currentThread() == QCoreApplication::instance()->thread();
-}
-
-SynchronousProcessResponse SynchronousProcess::run(const CommandLine &cmd,
- const QByteArray &writeData)
-{
- qCDebug(processLog).noquote() << "Starting:" << cmd.toUserOutput();
- ExecuteOnDestruction logResult([this] {
- qCDebug(processLog) << d->m_result;
- });
-
- d->clearForRun();
-
- d->m_binary = cmd.executable();
- // using QProcess::start() and passing program, args and OpenMode results in a different
- // quoting of arguments than using QProcess::setArguments() beforehand and calling start()
- // only with the OpenMode
- d->m_process.setProgram(cmd.executable().toString());
- d->m_process.setArguments(cmd.splitArguments());
- if (!writeData.isEmpty()) {
- connect(&d->m_process, &QProcess::started, this, [this, writeData] {
- d->m_process.write(writeData);
- d->m_process.closeWriteChannel();
- });
- }
- d->m_process.start(writeData.isEmpty() ? QIODevice::ReadOnly : QIODevice::ReadWrite);
-
- // On Windows, start failure is triggered immediately if the
- // executable cannot be found in the path. Do not start the
- // event loop in that case.
- if (!d->m_startFailure) {
- d->m_timer.start();
- if (isGuiThread())
- QApplication::setOverrideCursor(Qt::WaitCursor);
- d->m_eventLoop.exec(QEventLoop::ExcludeUserInputEvents);
- processStdOut(false);
- processStdErr(false);
-
- d->m_result.rawStdOut = d->m_stdOut.rawData;
- d->m_result.rawStdErr = d->m_stdErr.rawData;
-
- d->m_timer.stop();
- if (isGuiThread())
- QApplication::restoreOverrideCursor();
- }
-
- return d->m_result;
-}
-
-SynchronousProcessResponse SynchronousProcess::runBlocking(const CommandLine &cmd)
-{
- qCDebug(processLog).noquote() << "Starting blocking:" << cmd.toUserOutput();
- ExecuteOnDestruction logResult([this] {
- qCDebug(processLog) << d->m_result;
- });
-
- d->clearForRun();
-
- d->m_binary = cmd.executable();
- d->m_process.start(cmd.executable().toString(), cmd.splitArguments(), QIODevice::ReadOnly);
- if (!d->m_process.waitForStarted(d->m_maxHangTimerCount * 1000)) {
- d->m_result.result = SynchronousProcessResponse::StartFailed;
- return d->m_result;
- }
- d->m_process.closeWriteChannel();
- if (!d->m_process.waitForFinished(d->m_maxHangTimerCount * 1000)) {
- d->m_result.result = SynchronousProcessResponse::Hang;
- d->m_process.terminate();
- if (!d->m_process.waitForFinished(1000)) {
- d->m_process.kill();
- d->m_process.waitForFinished(1000);
- }
- }
-
- if (d->m_process.state() != QProcess::NotRunning)
- return d->m_result;
-
- d->m_result.exitCode = d->m_process.exitCode();
- if (d->m_result.result == SynchronousProcessResponse::StartFailed) {
- if (d->m_process.exitStatus() != QProcess::NormalExit)
- d->m_result.result = SynchronousProcessResponse::TerminatedAbnormally;
- else
- d->m_result.result = (exitCodeInterpreter())(d->m_result.exitCode);
- }
- processStdOut(false);
- processStdErr(false);
-
- d->m_result.rawStdOut = d->m_stdOut.rawData;
- d->m_result.rawStdErr = d->m_stdErr.rawData;
-
- return d->m_result;
-}
-
-bool SynchronousProcess::terminate()
-{
- return stopProcess(d->m_process);
-}
-
-static inline bool askToKill(const QString &binary = QString())
-{
- if (!isGuiThread())
- return true;
- const QString title = SynchronousProcess::tr("Process not Responding");
- QString msg = binary.isEmpty() ?
- SynchronousProcess::tr("The process is not responding.") :
- SynchronousProcess::tr("The process \"%1\" is not responding.").arg(QDir::toNativeSeparators(binary));
- msg += QLatin1Char(' ');
- msg += SynchronousProcess::tr("Would you like to terminate it?");
- // Restore the cursor that is set to wait while running.
- const bool hasOverrideCursor = QApplication::overrideCursor() != nullptr;
- if (hasOverrideCursor)
- QApplication::restoreOverrideCursor();
- QMessageBox::StandardButton answer = QMessageBox::question(nullptr, title, msg, QMessageBox::Yes|QMessageBox::No);
- if (hasOverrideCursor)
- QApplication::setOverrideCursor(Qt::WaitCursor);
- return answer == QMessageBox::Yes;
-}
-
-void SynchronousProcess::slotTimeout()
-{
- if (!d->m_waitingForUser && (++d->m_hangTimerCount > d->m_maxHangTimerCount)) {
- if (debug)
- qDebug() << Q_FUNC_INFO << "HANG detected, killing";
- d->m_waitingForUser = true;
- const bool terminate = !d->m_timeOutMessageBoxEnabled || askToKill(d->m_binary.toString());
- d->m_waitingForUser = false;
- if (terminate) {
- SynchronousProcess::stopProcess(d->m_process);
- d->m_result.result = SynchronousProcessResponse::Hang;
- } else {
- d->m_hangTimerCount = 0;
- }
- } else {
- if (debug)
- qDebug() << Q_FUNC_INFO << d->m_hangTimerCount;
- }
-}
-
-void SynchronousProcess::finished(int exitCode, QProcess::ExitStatus e)
-{
- if (debug)
- qDebug() << Q_FUNC_INFO << exitCode << e;
- d->m_hangTimerCount = 0;
-
- switch (e) {
- case QProcess::NormalExit:
- d->m_result.result = d->m_exitCodeInterpreter(exitCode);
- d->m_result.exitCode = exitCode;
- break;
- case QProcess::CrashExit:
- // Was hang detected before and killed?
- if (d->m_result.result != SynchronousProcessResponse::Hang)
- d->m_result.result = SynchronousProcessResponse::TerminatedAbnormally;
- d->m_result.exitCode = -1;
- break;
- }
- d->m_eventLoop.quit();
-}
-
-void SynchronousProcess::error(QProcess::ProcessError e)
-{
- d->m_hangTimerCount = 0;
- if (debug)
- qDebug() << Q_FUNC_INFO << e;
- // Was hang detected before and killed?
- if (d->m_result.result != SynchronousProcessResponse::Hang)
- d->m_result.result = SynchronousProcessResponse::StartFailed;
- d->m_startFailure = true;
- d->m_eventLoop.quit();
-}
-
-void SynchronousProcess::processStdOut(bool emitSignals)
-{
- // Handle binary data
- d->m_stdOut.append(d->m_process.readAllStandardOutput(), emitSignals);
-}
-
-void SynchronousProcess::processStdErr(bool emitSignals)
-{
- // Handle binary data
- d->m_stdErr.append(d->m_process.readAllStandardError(), emitSignals);
-}
-
-QSharedPointer<QProcess> SynchronousProcess::createProcess(unsigned flags)
-{
- auto process = new TerminalControllingProcess;
- process->setFlags(flags);
- return QSharedPointer<QProcess>(process);
-}
-
-// Static utilities: Keep running as long as it gets data.
-bool SynchronousProcess::readDataFromProcess(QProcess &p, int timeoutS,
- QByteArray *stdOut, QByteArray *stdErr,
- bool showTimeOutMessageBox)
-{
- if (syncDebug)
- qDebug() << ">readDataFromProcess" << timeoutS;
- if (p.state() != QProcess::Running) {
- qWarning("readDataFromProcess: Process in non-running state passed in.");
- return false;
- }
-
- QTC_ASSERT(p.readChannel() == QProcess::StandardOutput, return false);
-
- // Keep the process running until it has no longer has data
- bool finished = false;
- bool hasData = false;
- do {
- finished = p.waitForFinished(timeoutS > 0 ? timeoutS * 1000 : -1)
- || p.state() == QProcess::NotRunning;
- // First check 'stdout'
- if (p.bytesAvailable()) { // applies to readChannel() only
- hasData = true;
- const QByteArray newStdOut = p.readAllStandardOutput();
- if (stdOut)
- stdOut->append(newStdOut);
- }
- // Check 'stderr' separately. This is a special handling
- // for 'git pull' and the like which prints its progress on stderr.
- const QByteArray newStdErr = p.readAllStandardError();
- if (!newStdErr.isEmpty()) {
- hasData = true;
- if (stdErr)
- stdErr->append(newStdErr);
- }
- // Prompt user, pretend we have data if says 'No'.
- const bool hang = !hasData && !finished;
- hasData = hang && showTimeOutMessageBox && !askToKill(p.program());
- } while (hasData && !finished);
- if (syncDebug)
- qDebug() << "<readDataFromProcess" << finished;
- return finished;
-}
-
-bool SynchronousProcess::stopProcess(QProcess &p)
-{
- if (p.state() == QProcess::NotRunning)
- return true;
- p.terminate();
- if (p.waitForFinished(300))
- return true;
- p.kill();
- return p.waitForFinished(300);
-}
-
-// Path utilities
-
-// Locate a binary in a directory, applying all kinds of
-// extensions the operating system supports.
-static QString checkBinary(const QDir &dir, const QString &binary)
-{
- // naive UNIX approach
- const QFileInfo info(dir.filePath(binary));
- if (info.isFile() && info.isExecutable())
- return info.absoluteFilePath();
-
- // Does the OS have some weird extension concept or does the
- // binary have a 3 letter extension?
- if (HostOsInfo::isAnyUnixHost() && !HostOsInfo::isMacHost())
- return QString();
- const int dotIndex = binary.lastIndexOf(QLatin1Char('.'));
- if (dotIndex != -1 && dotIndex == binary.size() - 4)
- return QString();
-
- switch (HostOsInfo::hostOs()) {
- case OsTypeLinux:
- case OsTypeOtherUnix:
- case OsTypeOther:
- break;
- case OsTypeWindows: {
- static const char *windowsExtensions[] = {".cmd", ".bat", ".exe", ".com"};
- // Check the Windows extensions using the order
- const int windowsExtensionCount = sizeof(windowsExtensions)/sizeof(const char*);
- for (int e = 0; e < windowsExtensionCount; e ++) {
- const QFileInfo windowsBinary(dir.filePath(binary + QLatin1String(windowsExtensions[e])));
- if (windowsBinary.isFile() && windowsBinary.isExecutable())
- return windowsBinary.absoluteFilePath();
- }
- }
- break;
- case OsTypeMac: {
- // Check for Mac app folders
- const QFileInfo appFolder(dir.filePath(binary + QLatin1String(".app")));
- if (appFolder.isDir()) {
- QString macBinaryPath = appFolder.absoluteFilePath();
- macBinaryPath += QLatin1String("/Contents/MacOS/");
- macBinaryPath += binary;
- const QFileInfo macBinary(macBinaryPath);
- if (macBinary.isFile() && macBinary.isExecutable())
- return macBinary.absoluteFilePath();
- }
- }
- break;
- }
- return QString();
-}
-
-QString SynchronousProcess::locateBinary(const QString &path, const QString &binary)
-{
- // Absolute file?
- const QFileInfo absInfo(binary);
- if (absInfo.isAbsolute())
- return checkBinary(absInfo.dir(), absInfo.fileName());
-
- // Windows finds binaries in the current directory
- if (HostOsInfo::isWindowsHost()) {
- const QString currentDirBinary = checkBinary(QDir::current(), binary);
- if (!currentDirBinary.isEmpty())
- return currentDirBinary;
- }
-
- const QStringList paths = path.split(HostOsInfo::pathListSeparator());
- if (paths.empty())
- return QString();
- const QStringList::const_iterator cend = paths.constEnd();
- for (QStringList::const_iterator it = paths.constBegin(); it != cend; ++it) {
- const QDir dir(*it);
- const QString rc = checkBinary(dir, binary);
- if (!rc.isEmpty())
- return rc;
- }
- return QString();
-}
-
-QString SynchronousProcess::normalizeNewlines(const QString &text)
-{
- QString res = text;
- const auto newEnd = std::unique(res.begin(), res.end(), [](const QChar &c1, const QChar &c2) {
- return c1 == '\r' && c2 == '\r'; // QTCREATORBUG-24556
- });
- res.chop(std::distance(newEnd, res.end()));
- res.replace("\r\n", "\n");
- return res;
-}
-
-QString SynchronousProcess::locateBinary(const QString &binary)
-{
- const QByteArray path = qgetenv("PATH");
- return locateBinary(QString::fromLocal8Bit(path), binary);
-}
-
-} // namespace Utils
-
-#include "synchronousprocess.moc"
diff --git a/src/libs/utils/synchronousprocess.h b/src/libs/utils/synchronousprocess.h
deleted file mode 100644
index 071e20e007..0000000000
--- a/src/libs/utils/synchronousprocess.h
+++ /dev/null
@@ -1,175 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of Qt Creator.
-**
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 3 as published by the Free Software
-** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-3.0.html.
-**
-****************************************************************************/
-
-#pragma once
-
-#include "utils_global.h"
-
-#include <QProcess>
-#include <QSharedPointer>
-#include <QTextCodec>
-
-#include <functional>
-
-QT_FORWARD_DECLARE_CLASS(QDebug)
-
-namespace Utils {
-
-class SynchronousProcessPrivate;
-class CommandLine;
-
-/* Result of SynchronousProcess execution */
-class QTCREATOR_UTILS_EXPORT SynchronousProcessResponse
-{
-public:
- enum Result {
- // Finished with return code 0
- Finished,
- // Finished with return code != 0
- FinishedError,
- // Process terminated abnormally (kill)
- TerminatedAbnormally,
- // Executable could not be started
- StartFailed,
- // Hang, no output after time out
- Hang };
-
- void clear();
-
- // Helper to format an exit message.
- QString exitMessage(const QString &binary, int timeoutS) const;
-
- QByteArray allRawOutput() const;
- QString allOutput() const;
-
- QString stdOut() const;
- QString stdErr() const;
-
- Result result = StartFailed;
- int exitCode = -1;
-
- QByteArray rawStdOut;
- QByteArray rawStdErr;
- QTextCodec *codec = QTextCodec::codecForLocale();
-};
-
-QTCREATOR_UTILS_EXPORT QDebug operator<<(QDebug str, const SynchronousProcessResponse &);
-
-using ExitCodeInterpreter = std::function<SynchronousProcessResponse::Result(int /*exitCode*/)>;
-QTCREATOR_UTILS_EXPORT SynchronousProcessResponse::Result defaultExitCodeInterpreter(int code);
-
-class QTCREATOR_UTILS_EXPORT SynchronousProcess : public QObject
-{
- Q_OBJECT
-public:
- enum Flags {
- // Unix: Do not give the child process a terminal for input prompting.
- UnixTerminalDisabled = 0x1
- };
-
- SynchronousProcess();
- ~SynchronousProcess() override;
-
- /* Timeout for hanging processes (triggers after no more output
- * occurs on stderr/stdout). */
- void setTimeoutS(int timeoutS);
- int timeoutS() const;
-
- void setCodec(QTextCodec *c);
- QTextCodec *codec() const;
-
- QProcess::ProcessChannelMode processChannelMode () const;
- void setProcessChannelMode(QProcess::ProcessChannelMode m);
-
- bool stdOutBufferedSignalsEnabled() const;
- void setStdOutBufferedSignalsEnabled(bool);
-
- bool stdErrBufferedSignalsEnabled() const;
- void setStdErrBufferedSignalsEnabled(bool);
-
- bool timeOutMessageBoxEnabled() const;
- void setTimeOutMessageBoxEnabled(bool);
-
- QStringList environment() const;
- void setEnvironment(const QStringList &);
-
- void setProcessEnvironment(const QProcessEnvironment &environment);
- QProcessEnvironment processEnvironment() const;
-
- void setWorkingDirectory(const QString &workingDirectory);
- QString workingDirectory() const;
-
- unsigned flags() const;
- void setFlags(unsigned);
-
- void setExitCodeInterpreter(const ExitCodeInterpreter &interpreter);
- ExitCodeInterpreter exitCodeInterpreter() const;
-
- // Starts a nested event loop and runs the command
- SynchronousProcessResponse run(const CommandLine &cmd, const QByteArray &writeData = {});
- // Starts the command blocking the UI fully
- SynchronousProcessResponse runBlocking(const CommandLine &cmd);
-
- // Create a (derived) processes with flags applied.
- static QSharedPointer<QProcess> createProcess(unsigned flags);
-
- // Static helper for running a process synchronously in the foreground with timeout
- // detection similar SynchronousProcess' handling (taking effect after no more output
- // occurs on stderr/stdout as opposed to waitForFinished()). Returns false if a timeout
- // occurs. Checking of the process' exit state/code still has to be done.
- static bool readDataFromProcess(QProcess &p,
- int timeoutS,
- QByteArray *rawStdOut = nullptr,
- QByteArray *rawStdErr = nullptr,
- bool timeOutMessageBox = false);
- // Stop a process by first calling terminate() (allowing for signal handling) and
- // then kill().
- static bool stopProcess(QProcess &p);
-
- // Helpers to find binaries. Do not use it for other path variables
- // and file types.
- static QString locateBinary(const QString &binary);
- static QString locateBinary(const QString &path, const QString &binary);
-
- static QString normalizeNewlines(const QString &text);
-
-signals:
- void stdOutBuffered(const QString &lines, bool firstTime);
- void stdErrBuffered(const QString &lines, bool firstTime);
-
-public slots:
- bool terminate();
-
-private:
- void slotTimeout();
- void finished(int exitCode, QProcess::ExitStatus e);
- void error(QProcess::ProcessError);
- void processStdOut(bool emitSignals);
- void processStdErr(bool emitSignals);
-
- SynchronousProcessPrivate *d;
-};
-
-} // namespace Utils
diff --git a/src/libs/utils/textfileformat.cpp b/src/libs/utils/textfileformat.cpp
index 6f11734624..c06bf5dc38 100644
--- a/src/libs/utils/textfileformat.cpp
+++ b/src/libs/utils/textfileformat.cpp
@@ -198,7 +198,7 @@ bool TextFileFormat::decode(const QByteArray &data, QStringList *target) const
// Read text file contents to string or stringlist.
template <class Target>
-TextFileFormat::ReadResult readTextFile(const QString &fileName, const QTextCodec *defaultCodec,
+TextFileFormat::ReadResult readTextFile(const FilePath &filePath, const QTextCodec *defaultCodec,
Target *target, TextFileFormat *format, QString *errorString,
QByteArray *decodingErrorSampleIn = nullptr)
{
@@ -208,7 +208,7 @@ TextFileFormat::ReadResult readTextFile(const QString &fileName, const QTextCode
QByteArray data;
try {
FileReader reader;
- if (!reader.fetch(fileName, errorString))
+ if (!reader.fetch(filePath, errorString))
return TextFileFormat::ReadIOError;
data = reader.data();
} catch (const std::bad_alloc &) {
@@ -236,15 +236,15 @@ TextFileFormat::ReadResult readTextFile(const QString &fileName, const QTextCode
*/
TextFileFormat::ReadResult
- TextFileFormat::readFile(const QString &fileName, const QTextCodec *defaultCodec,
+ TextFileFormat::readFile(const FilePath &filePath, const QTextCodec *defaultCodec,
QStringList *plainTextList, TextFileFormat *format, QString *errorString,
QByteArray *decodingErrorSample /* = 0 */)
{
const TextFileFormat::ReadResult result =
- readTextFile(fileName, defaultCodec,
+ readTextFile(filePath, defaultCodec,
plainTextList, format, errorString, decodingErrorSample);
if (debug)
- qDebug().nospace() << Q_FUNC_INFO << fileName << ' ' << *format
+ qDebug().nospace() << Q_FUNC_INFO << filePath << ' ' << *format
<< " returns " << result << '/' << plainTextList->size() << " chunks";
return result;
}
@@ -254,27 +254,27 @@ TextFileFormat::ReadResult
*/
TextFileFormat::ReadResult
- TextFileFormat::readFile(const QString &fileName, const QTextCodec *defaultCodec,
+ TextFileFormat::readFile(const FilePath &filePath, const QTextCodec *defaultCodec,
QString *plainText, TextFileFormat *format, QString *errorString,
QByteArray *decodingErrorSample /* = 0 */)
{
const TextFileFormat::ReadResult result =
- readTextFile(fileName, defaultCodec,
+ readTextFile(filePath, defaultCodec,
plainText, format, errorString, decodingErrorSample);
if (debug)
- qDebug().nospace() << Q_FUNC_INFO << fileName << ' ' << *format
+ qDebug().nospace() << Q_FUNC_INFO << filePath << ' ' << *format
<< " returns " << result << '/' << plainText->size() << " characters";
return result;
}
-TextFileFormat::ReadResult TextFileFormat::readFileUTF8(const QString &fileName,
+TextFileFormat::ReadResult TextFileFormat::readFileUTF8(const FilePath &filePath,
const QTextCodec *defaultCodec,
QByteArray *plainText, QString *errorString)
{
QByteArray data;
try {
FileReader reader;
- if (!reader.fetch(fileName, errorString))
+ if (!reader.fetch(filePath, errorString))
return TextFileFormat::ReadIOError;
data = reader.data();
} catch (const std::bad_alloc &) {
@@ -302,7 +302,7 @@ TextFileFormat::ReadResult TextFileFormat::readFileUTF8(const QString &fileName,
Writes out a text file.
*/
-bool TextFileFormat::writeFile(const QString &fileName, QString plainText, QString *errorString) const
+bool TextFileFormat::writeFile(const FilePath &filePath, QString plainText, QString *errorString) const
{
QTC_ASSERT(codec, return false);
@@ -313,7 +313,7 @@ bool TextFileFormat::writeFile(const QString &fileName, QString plainText, QStri
if (lineTerminationMode == CRLFLineTerminator)
plainText.replace(QLatin1Char('\n'), QLatin1String("\r\n"));
- FileSaver saver(fileName, fileMode);
+ FileSaver saver(filePath, fileMode);
if (!saver.hasError()) {
if (hasUtf8Bom && codec->name() == "UTF-8")
saver.write("\xef\xbb\xbf", 3);
@@ -321,7 +321,7 @@ bool TextFileFormat::writeFile(const QString &fileName, QString plainText, QStri
}
const bool ok = saver.finalize(errorString);
if (debug)
- qDebug().nospace() << Q_FUNC_INFO << fileName << ' ' << *this << ' ' << plainText.size()
+ qDebug().nospace() << Q_FUNC_INFO << filePath << ' ' << *this << ' ' << plainText.size()
<< " bytes, returns " << ok;
return ok;
}
diff --git a/src/libs/utils/textfileformat.h b/src/libs/utils/textfileformat.h
index f95d1e7913..27c4ea169a 100644
--- a/src/libs/utils/textfileformat.h
+++ b/src/libs/utils/textfileformat.h
@@ -36,6 +36,8 @@ QT_END_NAMESPACE
namespace Utils {
+class FilePath;
+
class QTCREATOR_UTILS_EXPORT TextFileFormat {
public:
enum LineTerminationMode
@@ -65,16 +67,16 @@ public:
bool decode(const QByteArray &data, QString *target) const;
bool decode(const QByteArray &data, QStringList *target) const;
- static ReadResult readFile(const QString &fileName, const QTextCodec *defaultCodec,
+ static ReadResult readFile(const FilePath &filePath, const QTextCodec *defaultCodec,
QStringList *plainText, TextFileFormat *format, QString *errorString,
QByteArray *decodingErrorSample = nullptr);
- static ReadResult readFile(const QString &fileName, const QTextCodec *defaultCodec,
+ static ReadResult readFile(const FilePath &filePath, const QTextCodec *defaultCodec,
QString *plainText, TextFileFormat *format, QString *errorString,
QByteArray *decodingErrorSample = nullptr);
- static ReadResult readFileUTF8(const QString &fileName, const QTextCodec *defaultCodec,
+ static ReadResult readFileUTF8(const FilePath &filePath, const QTextCodec *defaultCodec,
QByteArray *plainText, QString *errorString);
- bool writeFile(const QString &fileName, QString plainText, QString *errorString) const;
+ bool writeFile(const FilePath &filePath, QString plainText, QString *errorString) const;
static QByteArray decodingErrorSample(const QByteArray &data);
diff --git a/src/libs/utils/utils-lib.pri b/src/libs/utils/utils-lib.pri
index cd9edbbbdb..872675f306 100644
--- a/src/libs/utils/utils-lib.pri
+++ b/src/libs/utils/utils-lib.pri
@@ -34,6 +34,7 @@ SOURCES += \
$$PWD/namevalueitem.cpp \
$$PWD/namevaluemodel.cpp \
$$PWD/namevaluesdialog.cpp \
+ $$PWD/commandline.cpp \
$$PWD/qrcparser.cpp \
$$PWD/qtcprocess.cpp \
$$PWD/reloadpromptutils.cpp \
@@ -60,8 +61,6 @@ SOURCES += \
$$PWD/classnamevalidatinglineedit.cpp \
$$PWD/fancylineedit.cpp \
$$PWD/qtcolorbutton.cpp \
- $$PWD/savedaction.cpp \
- $$PWD/synchronousprocess.cpp \
$$PWD/savefile.cpp \
$$PWD/fileutils.cpp \
$$PWD/textfileformat.cpp \
@@ -142,7 +141,10 @@ SOURCES += \
$$PWD/aspects.cpp \
$$PWD/layoutbuilder.cpp \
$$PWD/variablechooser.cpp \
- $$PWD/qtcsettings.cpp
+ $$PWD/futuresynchronizer.cpp \
+ $$PWD/qtcsettings.cpp \
+ $$PWD/link.cpp \
+ $$PWD/linecolumn.cpp \
HEADERS += \
$$PWD/environmentfwd.h \
@@ -157,7 +159,7 @@ HEADERS += \
$$PWD/namevalueitem.h \
$$PWD/namevaluemodel.h \
$$PWD/namevaluesdialog.h \
- $$PWD/pointeralgorithm.h \
+ $$PWD/commandline.h \
$$PWD/qrcparser.h \
$$PWD/qtcprocess.h \
$$PWD/span.h \
@@ -188,9 +190,7 @@ HEADERS += \
$$PWD/classnamevalidatinglineedit.h \
$$PWD/fancylineedit.h \
$$PWD/qtcolorbutton.h \
- $$PWD/savedaction.h \
$$PWD/consoleprocess.h \
- $$PWD/synchronousprocess.h \
$$PWD/savefile.h \
$$PWD/fileutils.h \
$$PWD/textfileformat.h \
@@ -301,6 +301,7 @@ HEADERS += \
$$PWD/layoutbuilder.h \
$$PWD/variablechooser.h \
$$PWD/set_algorithm.h \
+ $$PWD/futuresynchronizer.h \
$$PWD/qtcsettings.h
FORMS += $$PWD/filewizardpage.ui \
diff --git a/src/libs/utils/utils.qbs b/src/libs/utils/utils.qbs
index 7c2ff56e06..d921160208 100644
--- a/src/libs/utils/utils.qbs
+++ b/src/libs/utils/utils.qbs
@@ -64,6 +64,8 @@ Project {
"classnamevalidatinglineedit.h",
"codegeneration.cpp",
"codegeneration.h",
+ "commandline.cpp",
+ "commandline.h",
"completinglineedit.cpp",
"completinglineedit.h",
"completingtextedit.cpp",
@@ -127,6 +129,8 @@ Project {
"flowlayout.cpp",
"flowlayout.h",
"functiontraits.h",
+ "futuresynchronizer.cpp",
+ "futuresynchronizer.h",
"fuzzymatcher.cpp",
"fuzzymatcher.h",
"globalfilechangeblocker.cpp",
@@ -157,7 +161,9 @@ Project {
"jsontreeitem.h",
"layoutbuilder.cpp",
"layoutbuilder.h",
+ "linecolumn.cpp",
"linecolumn.h",
+ "link.cpp",
"link.h",
"listmodel.h",
"listutils.h",
@@ -232,8 +238,6 @@ Project {
"removefiledialog.ui",
"runextensions.cpp",
"runextensions.h",
- "savedaction.cpp",
- "savedaction.h",
"savefile.cpp",
"savefile.h",
"scopedswap.h",
@@ -265,8 +269,6 @@ Project {
"styledbar.h",
"stylehelper.cpp",
"stylehelper.h",
- "synchronousprocess.cpp",
- "synchronousprocess.h",
"templateengine.cpp",
"templateengine.h",
"temporarydirectory.cpp",
diff --git a/src/libs/utils/utilsicons.cpp b/src/libs/utils/utilsicons.cpp
index 88c7ed225a..6450891cc6 100644
--- a/src/libs/utils/utilsicons.cpp
+++ b/src/libs/utils/utilsicons.cpp
@@ -300,37 +300,37 @@ const Icon MACOS_TOUCHBAR_CLEAR(
QIcon CodeModelIcon::iconForType(CodeModelIcon::Type type)
{
- static const IconMaskAndColor classRelationIcon {
+ static const IconStringMaskAndColor classRelationIcon {
QLatin1String(":/codemodel/images/classrelation.png"), Theme::IconsCodeModelOverlayForegroundColor};
- static const IconMaskAndColor classRelationBackgroundIcon {
+ static const IconStringMaskAndColor classRelationBackgroundIcon {
QLatin1String(":/codemodel/images/classrelationbackground.png"), Theme::IconsCodeModelOverlayBackgroundColor};
- static const IconMaskAndColor classMemberFunctionIcon {
+ static const IconStringMaskAndColor classMemberFunctionIcon {
QLatin1String(":/codemodel/images/classmemberfunction.png"), Theme::IconsCodeModelFunctionColor};
- static const IconMaskAndColor classMemberVariableIcon {
+ static const IconStringMaskAndColor classMemberVariableIcon {
QLatin1String(":/codemodel/images/classmembervariable.png"), Theme::IconsCodeModelVariableColor};
- static const IconMaskAndColor functionIcon {
+ static const IconStringMaskAndColor functionIcon {
QLatin1String(":/codemodel/images/member.png"), Theme::IconsCodeModelFunctionColor};
- static const IconMaskAndColor variableIcon {
+ static const IconStringMaskAndColor variableIcon {
QLatin1String(":/codemodel/images/member.png"), Theme::IconsCodeModelVariableColor};
- static const IconMaskAndColor signalIcon {
+ static const IconStringMaskAndColor signalIcon {
QLatin1String(":/codemodel/images/signal.png"), Theme::IconsCodeModelFunctionColor};
- static const IconMaskAndColor slotIcon {
+ static const IconStringMaskAndColor slotIcon {
QLatin1String(":/codemodel/images/slot.png"), Theme::IconsCodeModelFunctionColor};
- static const IconMaskAndColor propertyIcon {
+ static const IconStringMaskAndColor propertyIcon {
QLatin1String(":/codemodel/images/property.png"), Theme::IconsCodeModelOverlayForegroundColor};
- static const IconMaskAndColor propertyBackgroundIcon {
+ static const IconStringMaskAndColor propertyBackgroundIcon {
QLatin1String(":/codemodel/images/propertybackground.png"), Theme::IconsCodeModelOverlayBackgroundColor};
- static const IconMaskAndColor protectedIcon {
+ static const IconStringMaskAndColor protectedIcon {
QLatin1String(":/codemodel/images/protected.png"), Theme::IconsCodeModelOverlayForegroundColor};
- static const IconMaskAndColor protectedBackgroundIcon {
+ static const IconStringMaskAndColor protectedBackgroundIcon {
QLatin1String(":/codemodel/images/protectedbackground.png"), Theme::IconsCodeModelOverlayBackgroundColor};
- static const IconMaskAndColor privateIcon {
+ static const IconStringMaskAndColor privateIcon {
QLatin1String(":/codemodel/images/private.png"), Theme::IconsCodeModelOverlayForegroundColor};
- static const IconMaskAndColor privateBackgroundIcon {
+ static const IconStringMaskAndColor privateBackgroundIcon {
QLatin1String(":/codemodel/images/privatebackground.png"), Theme::IconsCodeModelOverlayBackgroundColor};
- static const IconMaskAndColor staticIcon {
+ static const IconStringMaskAndColor staticIcon {
QLatin1String(":/codemodel/images/static.png"), Theme::IconsCodeModelOverlayForegroundColor};
- static const IconMaskAndColor staticBackgroundIcon {
+ static const IconStringMaskAndColor staticBackgroundIcon {
QLatin1String(":/codemodel/images/staticbackground.png"), Theme::IconsCodeModelOverlayBackgroundColor};
switch (type) {
diff --git a/src/plugins/CMakeLists.txt b/src/plugins/CMakeLists.txt
index 871f999b43..ba8fa0a3e1 100644
--- a/src/plugins/CMakeLists.txt
+++ b/src/plugins/CMakeLists.txt
@@ -46,6 +46,7 @@ add_subdirectory(clangrefactoring)
add_subdirectory(clearcase)
add_subdirectory(cvs)
add_subdirectory(designer)
+add_subdirectory(docker)
add_subdirectory(fakevim)
add_subdirectory(genericprojectmanager)
add_subdirectory(git)
diff --git a/src/plugins/android/CMakeLists.txt b/src/plugins/android/CMakeLists.txt
index d2f57f253e..bd63886f9a 100644
--- a/src/plugins/android/CMakeLists.txt
+++ b/src/plugins/android/CMakeLists.txt
@@ -2,7 +2,6 @@ add_qtc_plugin(Android
DEPENDS QtcSsh QmlDebug Qt5::Xml LanguageServerProtocol
PLUGIN_DEPENDS Core Debugger ProjectExplorer QtSupport LanguageClient
SOURCES
- adbcommandswidget.cpp adbcommandswidget.h adbcommandswidget.ui
addnewavddialog.ui
android.qrc
android_global.h
@@ -15,6 +14,7 @@ add_qtc_plugin(Android
androiddeployqtstep.cpp androiddeployqtstep.h
androiddevice.cpp androiddevice.h
androiddevicedialog.cpp androiddevicedialog.h androiddevicedialog.ui
+ androiddeviceinfo.cpp androiddeviceinfo.h
androiderrormessage.cpp androiderrormessage.h
androidextralibrarylistmodel.cpp androidextralibrarylistmodel.h
androidglobal.h
@@ -44,6 +44,7 @@ add_qtc_plugin(Android
androidsignaloperation.cpp androidsignaloperation.h
androidtoolchain.cpp androidtoolchain.h
avddialog.cpp avddialog.h
+ avdmanageroutputparser.cpp avdmanageroutputparser.h
certificatesmodel.cpp certificatesmodel.h
createandroidmanifestwizard.cpp createandroidmanifestwizard.h
javaeditor.cpp javaeditor.h
diff --git a/src/plugins/android/adbcommandswidget.cpp b/src/plugins/android/adbcommandswidget.cpp
deleted file mode 100644
index 4fe5c76d8c..0000000000
--- a/src/plugins/android/adbcommandswidget.cpp
+++ /dev/null
@@ -1,189 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2017 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 "adbcommandswidget.h"
-#include "ui_adbcommandswidget.h"
-
-#include <utils/utilsicons.h>
-
-#include <QGroupBox>
-#include <QItemSelectionModel>
-#include <QShortcut>
-#include <QStringListModel>
-
-#include <functional>
-
-namespace Android {
-namespace Internal {
-
-using namespace std::placeholders;
-
-const char defaultCommand[] = "echo \"shell command\"";
-
-static void swapData(QStringListModel *model, const QModelIndex &srcIndex,
- const QModelIndex &destIndex)
-{
- if (model) {
- QVariant data = model->data(destIndex, Qt::EditRole); // QTBUG-55078
- model->setData(destIndex, model->data(srcIndex, Qt::EditRole));
- model->setData(srcIndex, data);
- }
-}
-
-class AdbCommandsWidgetPrivate
-{
-public:
- AdbCommandsWidgetPrivate(AdbCommandsWidget *parent);
- ~AdbCommandsWidgetPrivate();
-
-private:
- void addString(const QString &str);
- void onAddButton();
- void onMoveUpButton();
- void onMoveDownButton();
- void onRemove();
- void onCurrentIndexChanged(const QModelIndex &newIndex, const QModelIndex &prevIndex);
-
- AdbCommandsWidget *q;
- Ui::AdbCommandsWidget *m_ui = nullptr;
- QStringListModel *m_stringModel = nullptr;
- friend class AdbCommandsWidget;
-};
-
-AdbCommandsWidget::AdbCommandsWidget()
- : d(new AdbCommandsWidgetPrivate(this))
-{
-}
-
-AdbCommandsWidget::~AdbCommandsWidget() = default;
-
-QStringList AdbCommandsWidget::commandsList() const
-{
- return d->m_stringModel->stringList();
-}
-
-void AdbCommandsWidget::setTitleText(const QString &title)
-{
- setTitle(title);
-}
-
-void AdbCommandsWidget::setCommandList(const QStringList &commands)
-{
- d->m_stringModel->setStringList(commands);
-}
-
-AdbCommandsWidgetPrivate::AdbCommandsWidgetPrivate(AdbCommandsWidget *q):
- q(q),
- m_ui(new Ui::AdbCommandsWidget),
- m_stringModel(new QStringListModel)
-{
- m_ui->setupUi(q);
- m_ui->addButton->setIcon(Utils::Icons::PLUS.icon());
- m_ui->removeButton->setIcon(Utils::Icons::MINUS.icon());
- m_ui->moveUpButton->setIcon(Utils::Icons::ARROW_UP.icon());
- m_ui->moveDownButton->setIcon(Utils::Icons::ARROW_DOWN.icon());
-
- auto deleteShortcut = new QShortcut(QKeySequence(QKeySequence::Delete), m_ui->commandsView);
- deleteShortcut->setContext(Qt::WidgetShortcut);
- QObject::connect(deleteShortcut, &QShortcut::activated,
- std::bind(&AdbCommandsWidgetPrivate::onRemove, this));
-
- QObject::connect(m_ui->addButton, &QToolButton::clicked,
- std::bind(&AdbCommandsWidgetPrivate::onAddButton, this));
- QObject::connect(m_ui->removeButton, &QToolButton::clicked,
- std::bind(&AdbCommandsWidgetPrivate::onRemove, this));
- QObject::connect(m_ui->moveUpButton, &QToolButton::clicked,
- std::bind(&AdbCommandsWidgetPrivate::onMoveUpButton, this));
- QObject::connect(m_ui->moveDownButton, &QToolButton::clicked,
- std::bind(&AdbCommandsWidgetPrivate::onMoveDownButton, this));
-
- m_ui->commandsView->setModel(m_stringModel);
- QObject::connect(m_stringModel, &QStringListModel::dataChanged,
- q, &AdbCommandsWidget::commandsChanged);
- QObject::connect(m_stringModel, &QStringListModel::rowsRemoved,
- q, &AdbCommandsWidget::commandsChanged);
- QObject::connect(m_ui->commandsView->selectionModel(), &QItemSelectionModel::currentChanged,
- std::bind(&AdbCommandsWidgetPrivate::onCurrentIndexChanged, this, _1, _2));
-}
-
-AdbCommandsWidgetPrivate::~AdbCommandsWidgetPrivate()
-{
- delete m_ui;
- delete m_stringModel;
-}
-
-void AdbCommandsWidgetPrivate::addString(const QString &str)
-{
- if (!str.isEmpty()) {
- m_stringModel->insertRows(m_stringModel->rowCount(), 1);
- const QModelIndex lastItemIndex = m_stringModel->index(m_stringModel->rowCount() - 1);
- m_stringModel->setData(lastItemIndex, str);
- }
-}
-
-void AdbCommandsWidgetPrivate::onAddButton()
-{
- addString(defaultCommand);
- const QModelIndex index = m_stringModel->index(m_stringModel->rowCount() - 1);
- m_ui->commandsView->setCurrentIndex(index);
- m_ui->commandsView->edit(index);
-}
-
-void AdbCommandsWidgetPrivate::onMoveUpButton()
-{
- QModelIndex index = m_ui->commandsView->currentIndex();
- if (index.row() > 0) {
- const QModelIndex newIndex = m_stringModel->index(index.row() - 1, 0);
- swapData(m_stringModel, index, newIndex);
- m_ui->commandsView->setCurrentIndex(newIndex);
- }
-}
-
-void AdbCommandsWidgetPrivate::onMoveDownButton()
-{
- QModelIndex index = m_ui->commandsView->currentIndex();
- if (index.row() < m_stringModel->rowCount() - 1) {
- const QModelIndex newIndex = m_stringModel->index(index.row() + 1, 0);
- swapData(m_stringModel, index, newIndex);
- m_ui->commandsView->setCurrentIndex(newIndex);
- }
-}
-
-void AdbCommandsWidgetPrivate::onRemove()
-{
- const QModelIndex &index = m_ui->commandsView->currentIndex();
- if (index.isValid())
- m_stringModel->removeRow(index.row());
-}
-
-void AdbCommandsWidgetPrivate::onCurrentIndexChanged(const QModelIndex &newIndex, const QModelIndex &prevIndex)
-{
- Q_UNUSED(prevIndex)
- m_ui->moveUpButton->setEnabled(newIndex.row() != 0);
- m_ui->moveDownButton->setEnabled(newIndex.row() < m_stringModel->rowCount() - 1);
- m_ui->removeButton->setEnabled(newIndex.isValid());
-}
-
-} // Internal
-} // Android
diff --git a/src/plugins/android/adbcommandswidget.ui b/src/plugins/android/adbcommandswidget.ui
deleted file mode 100644
index 3aff5e4fea..0000000000
--- a/src/plugins/android/adbcommandswidget.ui
+++ /dev/null
@@ -1,117 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<ui version="4.0">
- <class>AdbCommandsWidget</class>
- <widget class="QGroupBox" name="AdbCommandsWidget">
- <property name="geometry">
- <rect>
- <x>0</x>
- <y>0</y>
- <width>682</width>
- <height>391</height>
- </rect>
- </property>
- <property name="windowTitle">
- <string>Widget</string>
- </property>
- <property name="title">
- <string/>
- </property>
- <layout class="QGridLayout" name="gridLayout">
- <item row="2" column="1">
- <spacer name="verticalSpacer">
- <property name="orientation">
- <enum>Qt::Vertical</enum>
- </property>
- <property name="sizeHint" stdset="0">
- <size>
- <width>20</width>
- <height>40</height>
- </size>
- </property>
- </spacer>
- </item>
- <item row="0" column="0" rowspan="6">
- <widget class="QListView" name="commandsView">
- <property name="sizePolicy">
- <sizepolicy hsizetype="Expanding" vsizetype="Expanding">
- <horstretch>0</horstretch>
- <verstretch>0</verstretch>
- </sizepolicy>
- </property>
- <property name="defaultDropAction">
- <enum>Qt::MoveAction</enum>
- </property>
- <property name="movement">
- <enum>QListView::Snap</enum>
- </property>
- </widget>
- </item>
- <item row="3" column="1">
- <widget class="QToolButton" name="moveUpButton">
- <property name="enabled">
- <bool>false</bool>
- </property>
- <property name="text">
- <string/>
- </property>
- <property name="arrowType">
- <enum>Qt::NoArrow</enum>
- </property>
- </widget>
- </item>
- <item row="5" column="1">
- <spacer name="verticalSpacer_2">
- <property name="orientation">
- <enum>Qt::Vertical</enum>
- </property>
- <property name="sizeHint" stdset="0">
- <size>
- <width>20</width>
- <height>40</height>
- </size>
- </property>
- </spacer>
- </item>
- <item row="0" column="1">
- <widget class="QToolButton" name="addButton">
- <property name="text">
- <string/>
- </property>
- </widget>
- </item>
- <item row="4" column="1">
- <widget class="QToolButton" name="moveDownButton">
- <property name="enabled">
- <bool>false</bool>
- </property>
- <property name="text">
- <string/>
- </property>
- <property name="arrowType">
- <enum>Qt::NoArrow</enum>
- </property>
- </widget>
- </item>
- <item row="1" column="1">
- <widget class="QToolButton" name="removeButton">
- <property name="enabled">
- <bool>false</bool>
- </property>
- <property name="text">
- <string/>
- </property>
- </widget>
- </item>
- </layout>
- </widget>
- <layoutdefault spacing="6" margin="11"/>
- <tabstops>
- <tabstop>commandsView</tabstop>
- <tabstop>addButton</tabstop>
- <tabstop>removeButton</tabstop>
- <tabstop>moveUpButton</tabstop>
- <tabstop>moveDownButton</tabstop>
- </tabstops>
- <resources/>
- <connections/>
-</ui>
diff --git a/src/plugins/android/android.pro b/src/plugins/android/android.pro
index 701194791c..7bdd5539c9 100644
--- a/src/plugins/android/android.pro
+++ b/src/plugins/android/android.pro
@@ -27,6 +27,7 @@ HEADERS += \
javaparser.h \
androidplugin.h \
androiddevice.h \
+ androiddeviceinfo.h \
androidqmltoolingsupport.h \
androidmanifesteditorfactory.h \
androidmanifesteditor.h \
@@ -40,11 +41,11 @@ HEADERS += \
javaeditor.h \
javaindenter.h \
avddialog.h \
+ avdmanageroutputparser.h \
android_global.h \
androidbuildapkstep.h \
androidsdkmanager.h \
androidavdmanager.h \
- adbcommandswidget.h \
androidsdkpackage.h \
androidsdkmodel.h \
androidsdkmanagerwidget.h \
@@ -75,6 +76,7 @@ SOURCES += \
javaparser.cpp \
androidplugin.cpp \
androiddevice.cpp \
+ androiddeviceinfo.cpp \
androidqmltoolingsupport.cpp \
androidmanifesteditorfactory.cpp \
androidmanifesteditor.cpp \
@@ -88,10 +90,10 @@ SOURCES += \
javaeditor.cpp \
javaindenter.cpp \
avddialog.cpp \
+ avdmanageroutputparser.cpp \
androidbuildapkstep.cpp \
androidsdkmanager.cpp \
androidavdmanager.cpp \
- adbcommandswidget.cpp \
androidsdkpackage.cpp \
androidsdkmodel.cpp \
androidsdkmanagerwidget.cpp \
@@ -108,7 +110,6 @@ FORMS += \
addnewavddialog.ui \
androidcreatekeystorecertificate.ui \
androiddevicedialog.ui \
- adbcommandswidget.ui \
androidsdkmanagerwidget.ui
RESOURCES = android.qrc
diff --git a/src/plugins/android/android.qbs b/src/plugins/android/android.qbs
index 777be666f4..7dbe73b1d9 100644
--- a/src/plugins/android/android.qbs
+++ b/src/plugins/android/android.qbs
@@ -20,9 +20,6 @@ Project {
files: [
"android_global.h",
"android.qrc",
- "adbcommandswidget.cpp",
- "adbcommandswidget.h",
- "adbcommandswidget.ui",
"addnewavddialog.ui",
"androidavdmanager.cpp",
"androidavdmanager.h",
@@ -43,6 +40,8 @@ Project {
"androiddevicedialog.ui",
"androiddevice.cpp",
"androiddevice.h",
+ "androiddeviceinfo.cpp",
+ "androiddeviceinfo.h",
"androiderrormessage.h",
"androiderrormessage.cpp",
"androidextralibrarylistmodel.cpp",
@@ -103,6 +102,8 @@ Project {
"androidtoolchain.h",
"avddialog.cpp",
"avddialog.h",
+ "avdmanageroutputparser.cpp",
+ "avdmanageroutputparser.h",
"certificatesmodel.cpp",
"certificatesmodel.h",
"createandroidmanifestwizard.h",
diff --git a/src/plugins/android/androidavdmanager.cpp b/src/plugins/android/androidavdmanager.cpp
index 7fb12a49d6..9d6d8116f2 100644
--- a/src/plugins/android/androidavdmanager.cpp
+++ b/src/plugins/android/androidavdmanager.cpp
@@ -22,14 +22,19 @@
** be met: https://www.gnu.org/licenses/gpl-3.0.html.
**
****************************************************************************/
+
#include "androidavdmanager.h"
+#include "avdmanageroutputparser.h"
+
#include <coreplugin/icore.h>
+
#include <projectexplorer/projectexplorerconstants.h>
+
#include <utils/algorithm.h>
#include <utils/qtcassert.h>
+#include <utils/qtcprocess.h>
#include <utils/runextensions.h>
-#include <utils/synchronousprocess.h>
#include <QApplication>
#include <QFileInfo>
@@ -51,17 +56,6 @@ namespace Internal {
using namespace std;
-// Avd list keys to parse avd
-const char avdInfoNameKey[] = "Name:";
-const char avdInfoPathKey[] = "Path:";
-const char avdInfoAbiKey[] = "abi.type";
-const char avdInfoTargetKey[] = "target";
-const char avdInfoErrorKey[] = "Error:";
-const char avdInfoSdcardKey[] = "Sdcard";
-const char avdInfoTargetTypeKey[] = "Target";
-const char avdInfoDeviceKey[] = "Device";
-const char avdInfoSkinKey[] = "Skin";
-
const int avdCreateTimeoutMs = 30000;
/*!
@@ -73,28 +67,14 @@ bool AndroidAvdManager::avdManagerCommand(const AndroidConfig &config, const QSt
{
CommandLine cmd(config.avdManagerToolPath(), args);
Utils::SynchronousProcess proc;
- auto env = AndroidConfigurations::toolsEnvironment(config).toStringList();
+ Environment env = AndroidConfigurations::toolsEnvironment(config);
proc.setEnvironment(env);
qCDebug(avdManagerLog) << "Running AVD Manager command:" << cmd.toUserOutput();
- SynchronousProcessResponse response = proc.runBlocking(cmd);
- if (response.result == Utils::SynchronousProcessResponse::Finished) {
+ proc.setCommand(cmd);
+ proc.runBlocking();
+ if (proc.result() == Utils::QtcProcess::Finished) {
if (output)
- *output = response.allOutput();
- return true;
- }
- return false;
-}
-
-/*!
- Parses the \a line for a [spaces]key[spaces]value[spaces] pattern and returns
- \c true if the key is found, \c false otherwise. The value is copied into \a value.
- */
-static bool valueForKey(QString key, const QString &line, QString *value = nullptr)
-{
- auto trimmedInput = line.trimmed();
- if (trimmedInput.startsWith(key)) {
- if (value)
- *value = trimmedInput.section(key, 1, 1).trimmed();
+ *output = proc.allOutput();
return true;
}
return false;
@@ -203,25 +183,8 @@ static void avdProcessFinished(int exitCode, QProcess *p)
p->deleteLater();
}
-/*!
- \class AvdManagerOutputParser
- \brief The AvdManagerOutputParser class is a helper class to parse the output of the avdmanager
- commands.
- */
-class AvdManagerOutputParser
-{
-public:
- AndroidDeviceInfoList listVirtualDevices(const AndroidConfig &config);
- AndroidDeviceInfoList parseAvdList(const QString &output);
-
-private:
- bool parseAvd(const QStringList &deviceInfo, AndroidDeviceInfo *avd);
-};
-
-
-AndroidAvdManager::AndroidAvdManager(const AndroidConfig &config):
- m_config(config),
- m_parser(new AvdManagerOutputParser)
+AndroidAvdManager::AndroidAvdManager(const AndroidConfig &config)
+ : m_config(config)
{
}
@@ -237,15 +200,76 @@ bool AndroidAvdManager::removeAvd(const QString &name) const
{
const CommandLine command(m_config.avdManagerToolPath(), {"delete", "avd", "-n", name});
qCDebug(avdManagerLog) << "Running command (removeAvd):" << command.toUserOutput();
- Utils::SynchronousProcess proc;
+ SynchronousProcess proc;
proc.setTimeoutS(5);
- const Utils::SynchronousProcessResponse response = proc.runBlocking(command);
- return response.result == Utils::SynchronousProcessResponse::Finished && response.exitCode == 0;
+ proc.setCommand(command);
+ proc.runBlocking();
+ return proc.result() == QtcProcess::Finished && proc.exitCode() == 0;
+}
+
+static void avdConfigEditManufacturerTag(const QString &avdPathStr, bool recoverMode = false)
+{
+ const Utils::FilePath avdPath = Utils::FilePath::fromString(avdPathStr);
+ if (avdPath.exists()) {
+ const QString configFilePath = avdPath.pathAppended("config.ini").toString();
+ QFile configFile(configFilePath);
+ if (configFile.open(QIODevice::ReadWrite | QIODevice::Text)) {
+ QString newContent;
+ QTextStream textStream(&configFile);
+ while (!textStream.atEnd()) {
+ QString line = textStream.readLine();
+ if (!line.contains("hw.device.manufacturer"))
+ newContent.append(line + "\n");
+ else if (recoverMode)
+ newContent.append(line.replace("#", "") + "\n");
+ else
+ newContent.append("#" + line + "\n");
+ }
+ configFile.resize(0);
+ textStream << newContent;
+ configFile.close();
+ }
+ }
+}
+
+static AndroidDeviceInfoList listVirtualDevices(const AndroidConfig &config)
+{
+ QString output;
+ AndroidDeviceInfoList avdList;
+ /*
+ Currenly avdmanager tool fails to parse some AVDs because the correct
+ device definitions at devices.xml does not have some of the newest devices.
+ Particularly, failing because of tag "hw.device.manufacturer", thus removing
+ it would make paring successful. However, it has to be returned afterwards,
+ otherwise, Android Studio would give an error during parsing also. So this fix
+ aim to keep support for Qt Creator and Android Studio.
+ */
+ QStringList allAvdErrorPaths;
+ QStringList avdErrorPaths;
+
+ do {
+ if (!AndroidAvdManager::avdManagerCommand(config, {"list", "avd"}, &output)) {
+ qCDebug(avdManagerLog)
+ << "Avd list command failed" << output << config.sdkToolsVersion();
+ return {};
+ }
+
+ avdErrorPaths.clear();
+ avdList = parseAvdList(output, &avdErrorPaths);
+ allAvdErrorPaths << avdErrorPaths;
+ for (const QString &avdPathStr : qAsConst(avdErrorPaths))
+ avdConfigEditManufacturerTag(avdPathStr); // comment out manufacturer tag
+ } while (!avdErrorPaths.isEmpty()); // try again
+
+ for (const QString &avdPathStr : qAsConst(allAvdErrorPaths))
+ avdConfigEditManufacturerTag(avdPathStr, true); // re-add manufacturer tag
+
+ return avdList;
}
QFuture<AndroidDeviceInfoList> AndroidAvdManager::avdList() const
{
- return Utils::runAsync(&AvdManagerOutputParser::listVirtualDevices, m_parser.get(), m_config);
+ return Utils::runAsync(listVirtualDevices, m_config);
}
QString AndroidAvdManager::startAvd(const QString &name) const
@@ -328,10 +352,11 @@ bool AndroidAvdManager::isAvdBooted(const QString &device) const
qCDebug(avdManagerLog) << "Running command (isAvdBooted):" << command.toUserOutput();
SynchronousProcess adbProc;
adbProc.setTimeoutS(10);
- const SynchronousProcessResponse response = adbProc.runBlocking(command);
- if (response.result != Utils::SynchronousProcessResponse::Finished)
+ adbProc.setCommand(command);
+ adbProc.runBlocking();
+ if (adbProc.result() != QtcProcess::Finished)
return false;
- QString value = response.allOutput().trimmed();
+ QString value = adbProc.allOutput().trimmed();
return value == "stopped";
}
@@ -353,147 +378,7 @@ bool AndroidAvdManager::waitForBooted(const QString &serialNumber,
return false;
}
-/* Currenly avdmanager tool fails to parse some AVDs because the correct
- * device definitions at devices.xml does not have some of the newest devices.
- * Particularly, failing because of tag "hw.device.manufacturer", thus removing
- * it would make paring successful. However, it has to be returned afterwards,
- * otherwise, Android Studio would give an error during parsing also. So this fix
- * aim to keep support for Qt Creator and Android Studio.
- */
-static const QString avdManufacturerError = "no longer exists as a device";
static QStringList avdErrorPaths;
-static void AvdConfigEditManufacturerTag(const QString &avdPathStr, bool recoverMode = false)
-{
- const Utils::FilePath avdPath = Utils::FilePath::fromString(avdPathStr);
- if (avdPath.exists()) {
- const QString configFilePath = avdPath.pathAppended("config.ini").toString();
- QFile configFile(configFilePath);
- if (configFile.open(QIODevice::ReadWrite | QIODevice::Text)) {
- QString newContent;
- QTextStream textStream(&configFile);
- while (!textStream.atEnd()) {
- QString line = textStream.readLine();
- if (!line.contains("hw.device.manufacturer"))
- newContent.append(line + "\n");
- else if (recoverMode)
- newContent.append(line.replace("#", "") + "\n");
- else
- newContent.append("#" + line + "\n");
- }
- configFile.resize(0);
- textStream << newContent;
- configFile.close();
- }
- }
-}
-
-AndroidDeviceInfoList AvdManagerOutputParser::listVirtualDevices(const AndroidConfig &config)
-{
- QString output;
- AndroidDeviceInfoList avdList;
-
- do {
- if (!AndroidAvdManager::avdManagerCommand(config, {"list", "avd"}, &output)) {
- qCDebug(avdManagerLog)
- << "Avd list command failed" << output << config.sdkToolsVersion();
- return {};
- }
-
- avdList = parseAvdList(output);
- } while (output.contains(avdManufacturerError));
-
- for (const QString &avdPathStr : qAsConst(avdErrorPaths))
- AvdConfigEditManufacturerTag(avdPathStr, true);
-
- return avdList;
-}
-
-AndroidDeviceInfoList AvdManagerOutputParser::parseAvdList(const QString &output)
-{
- AndroidDeviceInfoList avdList;
- QStringList avdInfo;
- auto parseAvdInfo = [&avdInfo, &avdList, this] () {
- AndroidDeviceInfo avd;
- if (!avdInfo.filter(avdManufacturerError).isEmpty()) {
- for (const QString &line : avdInfo) {
- QString value;
- if (valueForKey(avdInfoPathKey, line, &value)) {
- avdErrorPaths.append(value);
- AvdConfigEditManufacturerTag(value);
- }
- }
- } else if (parseAvd(avdInfo, &avd)) {
- // armeabi-v7a devices can also run armeabi code
- if (avd.cpuAbi.contains(ProjectExplorer::Constants::ANDROID_ABI_ARMEABI_V7A))
- avd.cpuAbi << ProjectExplorer::Constants::ANDROID_ABI_ARMEABI;
- avd.state = AndroidDeviceInfo::OkState;
- avd.type = AndroidDeviceInfo::Emulator;
- avdList << avd;
- } else {
- qCDebug(avdManagerLog) << "Avd Parsing: Parsing failed: " << avdInfo;
- }
- avdInfo.clear();
- };
-
- for (const QString &line : output.split('\n')) {
- if (line.startsWith("---------") || line.isEmpty())
- parseAvdInfo();
- else
- avdInfo << line;
- }
-
- Utils::sort(avdList);
-
- return avdList;
-}
-
-bool AvdManagerOutputParser::parseAvd(const QStringList &deviceInfo, AndroidDeviceInfo *avd)
-{
- QTC_ASSERT(avd, return false);
- for (const QString &line : deviceInfo) {
- QString value;
- if (valueForKey(avdInfoErrorKey, line)) {
- qCDebug(avdManagerLog) << "Avd Parsing: Skip avd device. Error key found:" << line;
- return false;
- } else if (valueForKey(avdInfoNameKey, line, &value)) {
- avd->avdname = value;
- } else if (valueForKey(avdInfoPathKey, line, &value)) {
- const Utils::FilePath avdPath = Utils::FilePath::fromString(value);
- if (avdPath.exists())
- {
- // Get ABI.
- const Utils::FilePath configFile = avdPath.pathAppended("config.ini");
- QSettings config(configFile.toString(), QSettings::IniFormat);
- value = config.value(avdInfoAbiKey).toString();
- if (!value.isEmpty())
- avd->cpuAbi << value;
- else
- qCDebug(avdManagerLog) << "Avd Parsing: Cannot find ABI:" << configFile;
-
- // Get Target
- const QString avdInfoFileName = avd->avdname + ".ini";
- const Utils::FilePath
- avdInfoFile = avdPath.parentDir().pathAppended(avdInfoFileName);
- QSettings avdInfo(avdInfoFile.toString(), QSettings::IniFormat);
- value = avdInfo.value(avdInfoTargetKey).toString();
- if (!value.isEmpty())
- avd->sdk = value.section('-', -1).toInt();
- else
- qCDebug(avdManagerLog) << "Avd Parsing: Cannot find sdk API:" << avdInfoFile.toString();
- }
- } else if (valueForKey(avdInfoDeviceKey, line, &value)) {
- avd->avdDevice = value.remove(0, 2);
- } else if (valueForKey(avdInfoTargetTypeKey, line, &value)) {
- avd->avdTarget = value.remove(0, 2);
- } else if (valueForKey(avdInfoSkinKey, line, &value)) {
- avd->avdSkin = value.remove(0, 2);
- } else if (valueForKey(avdInfoSdcardKey, line, &value)) {
- avd->avdSdcardSize = value.remove(0, 2);
- }
- }
- return true;
-}
-
} // namespace Internal
} // namespace Android
diff --git a/src/plugins/android/androidavdmanager.h b/src/plugins/android/androidavdmanager.h
index 667301a58d..c33064c2f1 100644
--- a/src/plugins/android/androidavdmanager.h
+++ b/src/plugins/android/androidavdmanager.h
@@ -32,8 +32,6 @@
namespace Android {
namespace Internal {
-class AvdManagerOutputParser;
-
class AndroidAvdManager
{
Q_DECLARE_TR_FUNCTIONS(Android::Internal::AndroidAvdManager)
@@ -62,7 +60,6 @@ private:
private:
const AndroidConfig &m_config;
- std::unique_ptr<AvdManagerOutputParser> m_parser;
};
} // namespace Internal
diff --git a/src/plugins/android/androidbuildapkstep.cpp b/src/plugins/android/androidbuildapkstep.cpp
index c9c0ab3f80..8dcc9d62e3 100644
--- a/src/plugins/android/androidbuildapkstep.cpp
+++ b/src/plugins/android/androidbuildapkstep.cpp
@@ -59,7 +59,6 @@
#include <utils/infolabel.h>
#include <utils/pathchooser.h>
#include <utils/qtcprocess.h>
-#include <utils/synchronousprocess.h>
#include <QCheckBox>
#include <QComboBox>
@@ -639,8 +638,8 @@ bool AndroidBuildApkStep::init()
void AndroidBuildApkStep::setupOutputFormatter(OutputFormatter *formatter)
{
const auto parser = new JavaParser;
- parser->setProjectFileList(Utils::transform(project()->files(ProjectExplorer::Project::AllFiles),
- &Utils::FilePath::toString));
+ parser->setProjectFileList(project()->files(Project::AllFiles));
+
const QString buildKey = target()->activeBuildKey();
const ProjectNode *node = project()->findNodeForBuildKey(buildKey);
QString sourceDirName;
@@ -1008,14 +1007,15 @@ QAbstractItemModel *AndroidBuildApkStep::keystoreCertificates()
const QStringList params = {"-list", "-v", "-keystore", m_keystorePath.toUserOutput(),
"-storepass", m_keystorePasswd, "-J-Duser.language=en"};
- Utils::SynchronousProcess keytoolProc;
+ SynchronousProcess keytoolProc;
keytoolProc.setTimeoutS(30);
- const SynchronousProcessResponse response
- = keytoolProc.run({AndroidConfigurations::currentConfig().keytoolPath(), params});
- if (response.result > Utils::SynchronousProcessResponse::FinishedError)
+ keytoolProc.setCommand({AndroidConfigurations::currentConfig().keytoolPath(), params});
+ keytoolProc.setProcessUserEventWhileRunning();
+ keytoolProc.runBlocking();
+ if (keytoolProc.result() > QtcProcess::FinishedError)
QMessageBox::critical(nullptr, tr("Error"), tr("Failed to run keytool."));
else
- model = new CertificatesModel(response.stdOut(), this);
+ model = new CertificatesModel(keytoolProc.stdOut(), this);
return model;
}
diff --git a/src/plugins/android/androidconfigurations.cpp b/src/plugins/android/androidconfigurations.cpp
index 34593bb340..65d8031463 100644
--- a/src/plugins/android/androidconfigurations.cpp
+++ b/src/plugins/android/androidconfigurations.cpp
@@ -57,9 +57,9 @@
#include <utils/hostosinfo.h>
#include <utils/persistentsettings.h>
#include <utils/qtcassert.h>
+#include <utils/qtcprocess.h>
#include <utils/runextensions.h>
#include <utils/stringutils.h>
-#include <utils/synchronousprocess.h>
#include <QApplication>
#include <QDirIterator>
@@ -91,7 +91,7 @@ static Q_LOGGING_CATEGORY(avdConfigLog, "qtc.android.androidconfig", QtWarningMs
namespace Android {
using namespace Internal;
-const char JsonFilePath[] = "/android/sdk_definitions.json";
+const char JsonFilePath[] = "android/sdk_definitions.json";
const char SdkToolsUrlKey[] = "sdk_tools_url";
const char CommonKey[] = "common";
const char SdkEssentialPkgsKey[] = "sdk_essential_packages";
@@ -142,7 +142,7 @@ namespace {
static QString sdkSettingsFileName()
{
- return Core::ICore::installerResourcePath() + "/android.xml";
+ return Core::ICore::installerResourcePath("android.xml").toString();
}
static bool is32BitUserSpace()
@@ -159,10 +159,11 @@ namespace {
SynchronousProcess proc;
proc.setProcessChannelMode(QProcess::MergedChannels);
proc.setTimeoutS(30);
- SynchronousProcessResponse response = proc.runBlocking({executable, {shell}});
- if (response.result != SynchronousProcessResponse::Finished)
+ proc.setCommand({executable, {shell}});
+ proc.runBlocking();
+ if (proc.result() != QtcProcess::Finished)
return true;
- return !response.allOutput().contains("x86-64");
+ return !proc.allOutput().contains("x86-64");
}
}
return false;
@@ -270,21 +271,22 @@ void AndroidConfig::save(QSettings &settings) const
void AndroidConfig::parseDependenciesJson()
{
- QString sdkConfigUserFile(Core::ICore::userResourcePath() + JsonFilePath);
- QString sdkConfigFile(Core::ICore::resourcePath() + JsonFilePath);
+ const FilePath sdkConfigUserFile = Core::ICore::userResourcePath(JsonFilePath);
+ const FilePath sdkConfigFile = Core::ICore::resourcePath(JsonFilePath);
- if (!QFile::exists(sdkConfigUserFile)) {
- QDir(QFileInfo(sdkConfigUserFile).absolutePath()).mkpath(".");
- QFile::copy(sdkConfigFile, sdkConfigUserFile);
+ if (!sdkConfigUserFile.exists()) {
+ QDir(sdkConfigUserFile.toFileInfo().absolutePath()).mkpath(".");
+ QFile::copy(sdkConfigFile.toString(), sdkConfigUserFile.toString());
}
- if (QFileInfo(sdkConfigFile).lastModified() > QFileInfo(sdkConfigUserFile).lastModified()) {
- QFile::remove(sdkConfigUserFile + ".old");
- QFile::rename(sdkConfigUserFile, sdkConfigUserFile + ".old");
- QFile::copy(sdkConfigFile, sdkConfigUserFile);
+ if (sdkConfigFile.toFileInfo().lastModified() > sdkConfigUserFile.toFileInfo().lastModified()) {
+ const QString oldUserFile = (sdkConfigUserFile + ".old").toString();
+ QFile::remove(oldUserFile);
+ QFile::rename(sdkConfigUserFile.toString(), oldUserFile);
+ QFile::copy(sdkConfigFile.toString(), sdkConfigUserFile.toString());
}
- QFile jsonFile(sdkConfigUserFile);
+ QFile jsonFile(sdkConfigUserFile.toString());
if (!jsonFile.open(QIODevice::ReadOnly)) {
qCDebug(avdConfigLog, "Couldn't open JSON config file %s.", qPrintable(jsonFile.fileName()));
return;
@@ -560,14 +562,15 @@ QVector<AndroidDeviceInfo> AndroidConfig::connectedDevices(const FilePath &adbTo
SynchronousProcess adbProc;
adbProc.setTimeoutS(30);
CommandLine cmd{adbToolPath, {"devices"}};
- SynchronousProcessResponse response = adbProc.runBlocking(cmd);
- if (response.result != SynchronousProcessResponse::Finished) {
+ adbProc.setCommand(cmd);
+ adbProc.runBlocking();
+ if (adbProc.result() != QtcProcess::Finished) {
if (error)
*error = QApplication::translate("AndroidConfiguration", "Could not run: %1")
.arg(cmd.toUserOutput());
return devices;
}
- QStringList adbDevs = response.allOutput().split('\n', Qt::SkipEmptyParts);
+ QStringList adbDevs = adbProc.allOutput().split('\n', Qt::SkipEmptyParts);
if (adbDevs.empty())
return devices;
@@ -628,11 +631,12 @@ QString AndroidConfig::getDeviceProperty(const FilePath &adbToolPath, const QStr
SynchronousProcess adbProc;
adbProc.setTimeoutS(10);
- SynchronousProcessResponse response = adbProc.runBlocking(cmd);
- if (response.result != SynchronousProcessResponse::Finished)
+ adbProc.setCommand(cmd);
+ adbProc.runBlocking();
+ if (adbProc.result() != QtcProcess::Finished)
return QString();
- return response.allOutput();
+ return adbProc.allOutput();
}
int AndroidConfig::getSDKVersion(const FilePath &adbToolPath, const QString &device)
@@ -725,11 +729,12 @@ QStringList AndroidConfig::getAbis(const FilePath &adbToolPath, const QString &d
arguments << "shell" << "getprop" << "ro.product.cpu.abilist";
SynchronousProcess adbProc;
adbProc.setTimeoutS(10);
- SynchronousProcessResponse response = adbProc.runBlocking({adbToolPath, arguments});
- if (response.result != SynchronousProcessResponse::Finished)
+ adbProc.setCommand({adbToolPath, arguments});
+ adbProc.runBlocking();
+ if (adbProc.result() != QtcProcess::Finished)
return result;
- QString output = response.allOutput().trimmed();
+ QString output = adbProc.allOutput().trimmed();
if (!output.isEmpty()) {
QStringList result = output.split(QLatin1Char(','));
if (!result.isEmpty())
@@ -747,11 +752,12 @@ QStringList AndroidConfig::getAbis(const FilePath &adbToolPath, const QString &d
SynchronousProcess abiProc;
abiProc.setTimeoutS(10);
- SynchronousProcessResponse abiResponse = abiProc.runBlocking({adbToolPath, arguments});
- if (abiResponse.result != SynchronousProcessResponse::Finished)
+ abiProc.setCommand({adbToolPath, arguments});
+ abiProc.runBlocking();
+ if (abiProc.result() != QtcProcess::Finished)
return result;
- QString abi = abiResponse.allOutput().trimmed();
+ QString abi = abiProc.allOutput().trimmed();
if (abi.isEmpty())
break;
result << abi;
@@ -855,7 +861,7 @@ QVersionNumber AndroidConfig::ndkVersion(const FilePath &ndkPath) const
const FilePath ndkReleaseTxtPath = ndkPath.pathAppended("RELEASE.TXT");
Utils::FileReader reader;
QString errorString;
- if (reader.fetch(ndkReleaseTxtPath.toString(), &errorString)) {
+ if (reader.fetch(ndkReleaseTxtPath, &errorString)) {
// RELEASE.TXT contains the ndk version in either of the following formats:
// r6a
// r10e (64 bit)
@@ -1376,40 +1382,15 @@ bool AndroidConfigurations::force32bitEmulator()
return m_instance->m_force32bit;
}
-QProcessEnvironment AndroidConfigurations::toolsEnvironment(const AndroidConfig &config)
+Environment AndroidConfigurations::toolsEnvironment(const AndroidConfig &config)
{
Environment env = Environment::systemEnvironment();
- Utils::FilePath jdkLocation = config.openJDKLocation();
+ FilePath jdkLocation = config.openJDKLocation();
if (!jdkLocation.isEmpty()) {
env.set("JAVA_HOME", jdkLocation.toUserOutput());
env.prependOrSetPath(jdkLocation.pathAppended("bin").toUserOutput());
}
- return env.toProcessEnvironment();
-}
-
-/**
- * Workaround for '????????????' serial numbers
- * @return ("-d") for buggy devices, ("-s", <serial no>) for normal
- */
-QStringList AndroidDeviceInfo::adbSelector(const QString &serialNumber)
-{
- if (serialNumber.startsWith(QLatin1String("????")))
- return QStringList("-d");
- return QStringList({"-s", serialNumber});
-}
-
-bool AndroidDeviceInfo::operator<(const AndroidDeviceInfo &other) const
-{
- if (serialNumber.contains("????") != other.serialNumber.contains("????"))
- return !serialNumber.contains("????");
- if (type != other.type)
- return type == AndroidDeviceInfo::Hardware;
- if (sdk != other.sdk)
- return sdk < other.sdk;
- if (avdname != other.avdname)
- return avdname < other.avdname;
-
- return serialNumber < other.serialNumber;
+ return env;
}
const AndroidConfig &AndroidConfigurations::currentConfig()
@@ -1560,13 +1541,4 @@ void AndroidConfigurations::updateAndroidDevice()
AndroidConfigurations *AndroidConfigurations::m_instance = nullptr;
-QDebug &operator<<(QDebug &stream, const AndroidDeviceInfo &device)
-{
- stream << "Type:"<< (device.type == AndroidDeviceInfo::Emulator ? "Emulator" : "Device")
- << ", ABI:" << device.cpuAbi << ", Serial:" << device.serialNumber
- << ", Name:" << device.avdname << ", API:" << device.sdk
- << ", Authorised:" << !device.unauthorized;
- return stream;
-}
-
} // namespace Android
diff --git a/src/plugins/android/androidconfigurations.h b/src/plugins/android/androidconfigurations.h
index 3791acd8c8..dc9d3fd6be 100644
--- a/src/plugins/android/androidconfigurations.h
+++ b/src/plugins/android/androidconfigurations.h
@@ -26,14 +26,14 @@
#pragma once
#include "android_global.h"
-#include "androidsdkpackage.h"
+#include "androiddeviceinfo.h"
#include "androidsdkmanager.h"
+#include "androidsdkpackage.h"
#include <projectexplorer/toolchain.h>
#include <qtsupport/qtversionmanager.h>
#include <QObject>
-#include <QProcessEnvironment>
#include <QString>
#include <QStringList>
#include <QVector>
@@ -59,31 +59,6 @@ class AndroidSdkManager;
class AndroidPluginPrivate;
}
-class AndroidDeviceInfo
-{
-public:
- QString serialNumber;
- QString avdname;
- QStringList cpuAbi;
- QString avdTarget;
- QString avdDevice;
- QString avdSkin;
- QString avdSdcardSize;
-
- int sdk = -1;
- enum State { OkState, UnAuthorizedState, OfflineState };
- State state = OfflineState;
- bool unauthorized = false;
- enum AndroidDeviceType { Hardware, Emulator };
- AndroidDeviceType type = Emulator;
-
- static QStringList adbSelector(const QString &serialNumber);
-
- bool isValid() const { return !serialNumber.isEmpty() || !avdname.isEmpty(); }
- bool operator<(const AndroidDeviceInfo &other) const;
-};
-using AndroidDeviceInfoList = QList<AndroidDeviceInfo>;
-
class CreateAvdInfo
{
public:
@@ -248,7 +223,7 @@ public:
static void removeOldToolChains();
static void updateAutomaticKitList();
static bool force32bitEmulator();
- static QProcessEnvironment toolsEnvironment(const AndroidConfig &config);
+ static Utils::Environment toolsEnvironment(const AndroidConfig &config);
signals:
void aboutToUpdate();
@@ -270,8 +245,4 @@ private:
bool m_force32bit;
};
-QDebug &operator<<(QDebug &stream, const AndroidDeviceInfo &device);
-
} // namespace Android
-
-Q_DECLARE_METATYPE(Android::AndroidDeviceInfo)
diff --git a/src/plugins/android/androidcreatekeystorecertificate.cpp b/src/plugins/android/androidcreatekeystorecertificate.cpp
index 2417abf5a5..9549f5157f 100644
--- a/src/plugins/android/androidcreatekeystorecertificate.cpp
+++ b/src/plugins/android/androidcreatekeystorecertificate.cpp
@@ -27,7 +27,7 @@
#include "androidconfigurations.h"
#include "ui_androidcreatekeystorecertificate.h"
-#include <utils/synchronousprocess.h>
+#include <utils/qtcprocess.h>
#include <QFileDialog>
#include <QRegularExpression>
@@ -198,11 +198,13 @@ void AndroidCreateKeystoreCertificate::buttonBoxAccepted()
SynchronousProcess genKeyCertProc;
genKeyCertProc.setTimeoutS(15);
- SynchronousProcessResponse response = genKeyCertProc.run(command);
+ genKeyCertProc.setCommand(command);
+ genKeyCertProc.setProcessUserEventWhileRunning();
+ genKeyCertProc.runBlocking();
- if (response.result != Utils::SynchronousProcessResponse::Finished || response.exitCode != 0) {
+ if (genKeyCertProc.result() != QtcProcess::Finished || genKeyCertProc.exitCode() != 0) {
QMessageBox::critical(this, tr("Error"),
- response.exitMessage(command.executable().toString(), 15) + '\n' + response.allOutput());
+ genKeyCertProc.exitMessage() + '\n' + genKeyCertProc.allOutput());
return;
}
accept();
diff --git a/src/plugins/android/androiddeployqtstep.cpp b/src/plugins/android/androiddeployqtstep.cpp
index ab31f2ad83..99203853ad 100644
--- a/src/plugins/android/androiddeployqtstep.cpp
+++ b/src/plugins/android/androiddeployqtstep.cpp
@@ -55,7 +55,6 @@
#include <utils/layoutbuilder.h>
#include <utils/qtcassert.h>
#include <utils/qtcprocess.h>
-#include <utils/synchronousprocess.h>
#include <QCheckBox>
#include <QFileDialog>
@@ -482,9 +481,12 @@ void AndroidDeployQtStep::runCommand(const CommandLine &command)
buildProc.setTimeoutS(2 * 60);
emit addOutput(tr("Package deploy: Running command \"%1\".").arg(command.toUserOutput()),
OutputFormat::NormalMessage);
- SynchronousProcessResponse response = buildProc.run(command);
- if (response.result != SynchronousProcessResponse::Finished || response.exitCode != 0) {
- const QString error = response.exitMessage(command.executable().toString(), 2 * 60);
+
+ buildProc.setCommand(command);
+ buildProc.setProcessUserEventWhileRunning();
+ buildProc.runBlocking();
+ if (buildProc.result() != QtcProcess::Finished || buildProc.exitCode() != 0) {
+ const QString error = buildProc.exitMessage();
emit addOutput(error, OutputFormat::ErrorMessage);
TaskHub::addTask(DeploymentTask(Task::Error, error));
}
@@ -494,9 +496,6 @@ QWidget *AndroidDeployQtStep::createConfigWidget()
{
auto widget = new QWidget;
- setDisplayName(QString("<b>%1</b>").arg(displayName()));
- setSummaryText(displayName());
-
auto resetDefaultDevices = new QPushButton(widget);
resetDefaultDevices->setText(tr("Reset Default Deployment Devices"));
@@ -517,10 +516,11 @@ QWidget *AndroidDeployQtStep::createConfigWidget()
AndroidManager::installQASIPackage(target(), packagePath);
});
- LayoutBuilder builder(widget);
+ Layouting::Form builder;
builder.addRow(m_uninstallPreviousPackage);
builder.addRow(resetDefaultDevices);
builder.addRow(installCustomApkButton);
+ builder.attachTo(widget);
return widget;
}
diff --git a/src/plugins/android/androiddeviceinfo.cpp b/src/plugins/android/androiddeviceinfo.cpp
new file mode 100644
index 0000000000..817f64a362
--- /dev/null
+++ b/src/plugins/android/androiddeviceinfo.cpp
@@ -0,0 +1,72 @@
+/****************************************************************************
+**
+** Copyright (C) 2021 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of Qt Creator.
+**
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3 as published by the Free Software
+** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-3.0.html.
+**
+****************************************************************************/
+
+#include "androiddeviceinfo.h"
+
+namespace Android {
+
+/**
+ * Workaround for '????????????' serial numbers
+ * @return ("-d") for buggy devices, ("-s", <serial no>) for normal
+ */
+QStringList AndroidDeviceInfo::adbSelector(const QString &serialNumber)
+{
+ if (serialNumber.startsWith(QLatin1String("????")))
+ return QStringList("-d");
+ return QStringList({"-s", serialNumber});
+}
+
+bool AndroidDeviceInfo::operator<(const AndroidDeviceInfo &other) const
+{
+ if (serialNumber.contains("????") != other.serialNumber.contains("????"))
+ return !serialNumber.contains("????");
+ if (type != other.type)
+ return type == AndroidDeviceInfo::Hardware;
+ if (sdk != other.sdk)
+ return sdk < other.sdk;
+ if (avdname != other.avdname)
+ return avdname < other.avdname;
+
+ return serialNumber < other.serialNumber;
+}
+
+bool AndroidDeviceInfo::operator==(const AndroidDeviceInfo &other) const
+{
+ return serialNumber == other.serialNumber && avdname == other.avdname && cpuAbi == other.cpuAbi
+ && avdTarget == other.avdTarget && avdDevice == other.avdDevice
+ && avdSkin == other.avdSkin && avdSdcardSize == other.avdSdcardSize && sdk == other.sdk
+ && state == other.state && unauthorized == other.unauthorized && type == other.type;
+}
+
+QDebug &operator<<(QDebug &stream, const AndroidDeviceInfo &device)
+{
+ stream << "Type:" << (device.type == AndroidDeviceInfo::Emulator ? "Emulator" : "Device")
+ << ", ABI:" << device.cpuAbi << ", Serial:" << device.serialNumber
+ << ", Name:" << device.avdname << ", API:" << device.sdk
+ << ", Authorised:" << !device.unauthorized;
+ return stream;
+}
+
+} // namespace Android
diff --git a/src/plugins/android/androiddeviceinfo.h b/src/plugins/android/androiddeviceinfo.h
new file mode 100644
index 0000000000..9c8e6c30ea
--- /dev/null
+++ b/src/plugins/android/androiddeviceinfo.h
@@ -0,0 +1,66 @@
+/****************************************************************************
+**
+** Copyright (C) 2021 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of Qt Creator.
+**
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3 as published by the Free Software
+** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-3.0.html.
+**
+****************************************************************************/
+
+#pragma once
+
+#include <QDebug>
+#include <QMetaType>
+#include <QString>
+#include <QStringList>
+
+namespace Android {
+
+class AndroidDeviceInfo
+{
+public:
+ QString serialNumber;
+ QString avdname;
+ QStringList cpuAbi;
+ QString avdTarget;
+ QString avdDevice;
+ QString avdSkin;
+ QString avdSdcardSize;
+
+ int sdk = -1;
+ enum State { OkState, UnAuthorizedState, OfflineState };
+ State state = OfflineState;
+ bool unauthorized = false;
+ enum AndroidDeviceType { Hardware, Emulator };
+ AndroidDeviceType type = Emulator;
+
+ static QStringList adbSelector(const QString &serialNumber);
+
+ bool isValid() const { return !serialNumber.isEmpty() || !avdname.isEmpty(); }
+ bool operator<(const AndroidDeviceInfo &other) const;
+ bool operator==(const AndroidDeviceInfo &other) const; // should be = default with C++20
+ bool operator!=(const AndroidDeviceInfo &other) const { return !(*this == other); }
+};
+using AndroidDeviceInfoList = QList<AndroidDeviceInfo>;
+
+QDebug &operator<<(QDebug &stream, const AndroidDeviceInfo &device);
+
+} // namespace Android
+
+Q_DECLARE_METATYPE(Android::AndroidDeviceInfo)
diff --git a/src/plugins/android/androidmanager.cpp b/src/plugins/android/androidmanager.cpp
index f77bfa6d1e..cf50cee401 100644
--- a/src/plugins/android/androidmanager.cpp
+++ b/src/plugins/android/androidmanager.cpp
@@ -53,8 +53,8 @@
#include <utils/algorithm.h>
#include <utils/qtcassert.h>
+#include <utils/qtcprocess.h>
#include <utils/stringutils.h>
-#include <utils/synchronousprocess.h>
#include <QApplication>
#include <QDir>
@@ -538,8 +538,10 @@ bool AndroidManager::checkKeystorePassword(const QString &keystorePath, const QS
{"-list", "-keystore", keystorePath, "--storepass", keystorePasswd});
SynchronousProcess proc;
proc.setTimeoutS(10);
- SynchronousProcessResponse response = proc.run(cmd);
- return (response.result == SynchronousProcessResponse::Finished && response.exitCode == 0);
+ proc.setCommand(cmd);
+ proc.setProcessUserEventWhileRunning();
+ proc.runBlocking();
+ return proc.result() == QtcProcess::Finished && proc.exitCode() == 0;
}
bool AndroidManager::checkCertificatePassword(const QString &keystorePath, const QString &keystorePasswd, const QString &alias, const QString &certificatePasswd)
@@ -554,9 +556,10 @@ bool AndroidManager::checkCertificatePassword(const QString &keystorePath, const
SynchronousProcess proc;
proc.setTimeoutS(10);
- SynchronousProcessResponse response
- = proc.run({AndroidConfigurations::currentConfig().keytoolPath(), arguments});
- return response.result == SynchronousProcessResponse::Finished && response.exitCode == 0;
+ proc.setCommand({AndroidConfigurations::currentConfig().keytoolPath(), arguments});
+ proc.setProcessUserEventWhileRunning();
+ proc.runBlocking();
+ return proc.result() == QtcProcess::Finished && proc.exitCode() == 0;
}
bool AndroidManager::checkCertificateExists(const QString &keystorePath,
@@ -568,9 +571,10 @@ bool AndroidManager::checkCertificateExists(const QString &keystorePath,
SynchronousProcess proc;
proc.setTimeoutS(10);
- SynchronousProcessResponse response
- = proc.run({AndroidConfigurations::currentConfig().keytoolPath(), arguments});
- return response.result == SynchronousProcessResponse::Finished && response.exitCode == 0;
+ proc.setCommand({AndroidConfigurations::currentConfig().keytoolPath(), arguments});
+ proc.setProcessUserEventWhileRunning();
+ proc.runBlocking();
+ return proc.result() == QtcProcess::Finished && proc.exitCode() == 0;
}
using GradleProperties = QMap<QByteArray, QByteArray>;
@@ -723,16 +727,19 @@ SdkToolResult AndroidManager::runCommand(const CommandLine &command,
Android::SdkToolResult cmdResult;
SynchronousProcess cmdProc;
cmdProc.setTimeoutS(timeoutS);
+ cmdProc.setWriteData(writeData);
qCDebug(androidManagerLog) << "Running command (sync):" << command.toUserOutput();
- SynchronousProcessResponse response = cmdProc.run(command, writeData);
- cmdResult.m_stdOut = response.stdOut().trimmed();
- cmdResult.m_stdErr = response.stdErr().trimmed();
- cmdResult.m_success = response.result == SynchronousProcessResponse::Finished;
+ cmdProc.setCommand(command);
+ cmdProc.setProcessUserEventWhileRunning();
+ cmdProc.runBlocking();
+ cmdResult.m_stdOut = cmdProc.stdOut().trimmed();
+ cmdResult.m_stdErr = cmdProc.stdErr().trimmed();
+ cmdResult.m_success = cmdProc.result() == QtcProcess::Finished;
qCDebug(androidManagerLog) << "Command finshed (sync):" << command.toUserOutput()
<< "Success:" << cmdResult.m_success
- << "Output:" << response.allRawOutput();
+ << "Output:" << cmdProc.allRawOutput();
if (!cmdResult.success())
- cmdResult.m_exitMessage = response.exitMessage(command.executable().toString(), timeoutS);
+ cmdResult.m_exitMessage = cmdProc.exitMessage();
return cmdResult;
}
diff --git a/src/plugins/android/androidmanifestdocument.cpp b/src/plugins/android/androidmanifestdocument.cpp
index e3473a891b..6bb879de0f 100644
--- a/src/plugins/android/androidmanifestdocument.cpp
+++ b/src/plugins/android/androidmanifestdocument.cpp
@@ -47,10 +47,10 @@ AndroidManifestDocument::AndroidManifestDocument(AndroidManifestEditorWidget *ed
this, &Core::IDocument::changed);
}
-bool AndroidManifestDocument::save(QString *errorString, const QString &fileName, bool autoSave)
+bool AndroidManifestDocument::save(QString *errorString, const Utils::FilePath &filePath, bool autoSave)
{
m_editorWidget->preSave();
- bool result = TextDocument::save(errorString, fileName, autoSave);
+ bool result = TextDocument::save(errorString, filePath, autoSave);
m_editorWidget->postSave();
return result;
}
diff --git a/src/plugins/android/androidmanifestdocument.h b/src/plugins/android/androidmanifestdocument.h
index 169047f051..ce22c8b37f 100644
--- a/src/plugins/android/androidmanifestdocument.h
+++ b/src/plugins/android/androidmanifestdocument.h
@@ -36,7 +36,7 @@ class AndroidManifestDocument : public TextEditor::TextDocument
{
public:
explicit AndroidManifestDocument(AndroidManifestEditorWidget *editorWidget);
- bool save(QString *errorString, const QString &fileName = QString(),
+ bool save(QString *errorString, const Utils::FilePath &filePath,
bool autoSave = false) override;
bool isModified() const override;
diff --git a/src/plugins/android/androidpackageinstallationstep.cpp b/src/plugins/android/androidpackageinstallationstep.cpp
index 024aa1785d..bd4fdc104f 100644
--- a/src/plugins/android/androidpackageinstallationstep.cpp
+++ b/src/plugins/android/androidpackageinstallationstep.cpp
@@ -96,8 +96,8 @@ bool AndroidPackageInstallationStep::init()
QTC_ASSERT(tc, return false);
QString dirPath = nativeAndroidBuildPath();
- const QString innerQuoted = QtcProcess::quoteArg(dirPath);
- const QString outerQuoted = QtcProcess::quoteArg("INSTALL_ROOT=" + innerQuoted);
+ const QString innerQuoted = ProcessArgs::quoteArg(dirPath);
+ const QString outerQuoted = ProcessArgs::quoteArg("INSTALL_ROOT=" + innerQuoted);
CommandLine cmd{tc->makeCommand(buildEnvironment())};
cmd.addArgs(outerQuoted + " install", CommandLine::Raw);
diff --git a/src/plugins/android/androidplugin.h b/src/plugins/android/androidplugin.h
index 45db6ed237..d90449c392 100644
--- a/src/plugins/android/androidplugin.h
+++ b/src/plugins/android/androidplugin.h
@@ -43,6 +43,12 @@ class AndroidPlugin final : public ExtensionSystem::IPlugin
void askUserAboutAndroidSetup();
class AndroidPluginPrivate *d = nullptr;
+
+#ifdef WITH_TESTS
+private slots:
+ void testAndroidSdkManagerProgressParser_data();
+ void testAndroidSdkManagerProgressParser();
+#endif // WITH_TESTS
};
} // namespace Internal
diff --git a/src/plugins/android/androidqtversion.cpp b/src/plugins/android/androidqtversion.cpp
index 952580462d..94872e34c8 100644
--- a/src/plugins/android/androidqtversion.cpp
+++ b/src/plugins/android/androidqtversion.cpp
@@ -145,12 +145,10 @@ void AndroidQtVersion::addToEnvironment(const Kit *k, Utils::Environment &env) c
config.bestNdkPlatformMatch(qMax(minimumNDK(), AndroidManager::minimumSDK(k)), this));
}
-Utils::Environment AndroidQtVersion::qmakeRunEnvironment() const
+void AndroidQtVersion::setupQmakeRunEnvironment(Utils::Environment &env) const
{
- Utils::Environment env = Utils::Environment::systemEnvironment();
env.set(QLatin1String("ANDROID_NDK_ROOT"),
AndroidConfigurations::currentConfig().ndkLocation(this).toUserOutput());
- return env;
}
QString AndroidQtVersion::description() const
diff --git a/src/plugins/android/androidqtversion.h b/src/plugins/android/androidqtversion.h
index bb5c5ff7a5..61ce496753 100644
--- a/src/plugins/android/androidqtversion.h
+++ b/src/plugins/android/androidqtversion.h
@@ -47,7 +47,7 @@ public:
ProjectExplorer::Abis detectQtAbis() const override;
void addToEnvironment(const ProjectExplorer::Kit *k, Utils::Environment &env) const override;
- Utils::Environment qmakeRunEnvironment() const override;
+ void setupQmakeRunEnvironment(Utils::Environment &env) const override;
QSet<Utils::Id> availableFeatures() const override;
QSet<Utils::Id> targetDeviceTypes() const override;
diff --git a/src/plugins/android/androidrunconfiguration.cpp b/src/plugins/android/androidrunconfiguration.cpp
index 58b2e2813b..5b834fa673 100644
--- a/src/plugins/android/androidrunconfiguration.cpp
+++ b/src/plugins/android/androidrunconfiguration.cpp
@@ -29,82 +29,45 @@
#include "androidglobal.h"
#include "androidtoolchain.h"
#include "androidmanager.h"
-#include "adbcommandswidget.h"
#include <app/app_version.h>
#include <projectexplorer/buildsystem.h>
#include <projectexplorer/kitinformation.h>
#include <projectexplorer/project.h>
+#include <projectexplorer/runconfigurationaspects.h>
#include <projectexplorer/target.h>
#include <qtsupport/qtkitinformation.h>
#include <utils/detailswidget.h>
-#include <utils/layoutbuilder.h>
#include <utils/qtcassert.h>
#include <utils/qtcprocess.h>
#include <utils/utilsicons.h>
-#include <QLabel>
-#include <QLineEdit>
-#include <QSpacerItem>
-#include <QWidget>
-
-using namespace Android::Internal;
using namespace ProjectExplorer;
using namespace Utils;
namespace Android {
-BaseStringListAspect::BaseStringListAspect(const QString &settingsKey, Utils::Id id)
-{
- setSettingsKey(settingsKey);
- setId(id);
-}
-
-BaseStringListAspect::~BaseStringListAspect() = default;
-
-void BaseStringListAspect::addToLayout(LayoutBuilder &builder)
-{
- QTC_CHECK(!m_widget);
- m_widget = new AdbCommandsWidget;
- m_widget->setCommandList(m_value);
- m_widget->setTitleText(m_label);
- builder.addItem(m_widget.data());
- connect(m_widget.data(), &AdbCommandsWidget::commandsChanged, this, [this] {
- m_value = m_widget->commandsList();
- emit changed();
- });
-}
-
-void BaseStringListAspect::fromMap(const QVariantMap &map)
-{
- m_value = map.value(settingsKey()).toStringList();
-}
-
-void BaseStringListAspect::toMap(QVariantMap &data) const
+class BaseStringListAspect final : public Utils::StringAspect
{
- saveToMap(data, m_value, QStringList());
-}
-
-QStringList BaseStringListAspect::value() const
-{
- return m_value;
-}
-
-void BaseStringListAspect::setValue(const QStringList &value)
-{
- m_value = value;
- if (m_widget)
- m_widget->setCommandList(m_value);
-}
-
-void BaseStringListAspect::setLabel(const QString &label)
-{
- m_label = label;
-}
-
+public:
+ explicit BaseStringListAspect() = default;
+ ~BaseStringListAspect() final = default;
+
+ void fromMap(const QVariantMap &map) final
+ {
+ // Pre Qt Creator 5.0 hack: Reads QStringList as QString
+ setValue(map.value(settingsKey()).toStringList().join('\n'));
+ }
+
+ void toMap(QVariantMap &map) const final
+ {
+ // Pre Qt Creator 5.0 hack: Writes QString as QStringList
+ map.insert(settingsKey(), value().split('\n'));
+ }
+};
AndroidRunConfiguration::AndroidRunConfiguration(Target *target, Utils::Id id)
: RunConfiguration(target, id)
@@ -139,14 +102,16 @@ AndroidRunConfiguration::AndroidRunConfiguration(Target *target, Utils::Id id)
.arg(Core::Constants::IDE_DISPLAY_NAME));
auto preStartShellCmdAspect = addAspect<BaseStringListAspect>();
+ preStartShellCmdAspect->setDisplayStyle(StringAspect::TextEditDisplay);
preStartShellCmdAspect->setId(Constants::ANDROID_PRESTARTSHELLCMDLIST);
preStartShellCmdAspect->setSettingsKey("Android.PreStartShellCmdListKey");
- preStartShellCmdAspect->setLabel(tr("Shell commands to run on Android device before application launch."));
+ preStartShellCmdAspect->setLabelText(tr("Pre-launch on-device shell commands:"));
auto postStartShellCmdAspect = addAspect<BaseStringListAspect>();
+ postStartShellCmdAspect->setDisplayStyle(StringAspect::TextEditDisplay);
postStartShellCmdAspect->setId(Constants::ANDROID_POSTFINISHSHELLCMDLIST);
postStartShellCmdAspect->setSettingsKey("Android.PostStartShellCmdListKey");
- postStartShellCmdAspect->setLabel(tr("Shell commands to run on Android device after application quits."));
+ postStartShellCmdAspect->setLabelText(tr("Post-quit on-device shell commands:"));
setUpdater([this, target] {
const BuildTargetInfo bti = buildTargetInfo();
diff --git a/src/plugins/android/androidrunconfiguration.h b/src/plugins/android/androidrunconfiguration.h
index ebc833b75d..57894330f8 100644
--- a/src/plugins/android/androidrunconfiguration.h
+++ b/src/plugins/android/androidrunconfiguration.h
@@ -27,38 +27,10 @@
#include "android_global.h"
-#include "adbcommandswidget.h"
-
#include <projectexplorer/runconfiguration.h>
-#include <projectexplorer/runconfigurationaspects.h>
namespace Android {
-class BaseStringListAspect : public Utils::BaseAspect
-{
- Q_OBJECT
-
-public:
- explicit BaseStringListAspect(const QString &settingsKey = QString(),
- Utils::Id id = Utils::Id());
- ~BaseStringListAspect() override;
-
- void addToLayout(Utils::LayoutBuilder &builder) override;
-
- QStringList value() const;
- void setValue(const QStringList &val);
-
- void setLabel(const QString &label);
-
- void fromMap(const QVariantMap &map) override;
- void toMap(QVariantMap &map) const override;
-
-private:
- QStringList m_value;
- QString m_label;
- QPointer<Android::Internal::AdbCommandsWidget> m_widget; // Owned by RunConfigWidget
-};
-
class ANDROID_EXPORT AndroidRunConfiguration : public ProjectExplorer::RunConfiguration
{
Q_OBJECT
diff --git a/src/plugins/android/androidrunnerworker.cpp b/src/plugins/android/androidrunnerworker.cpp
index b07e621059..14cebeb425 100644
--- a/src/plugins/android/androidrunnerworker.cpp
+++ b/src/plugins/android/androidrunnerworker.cpp
@@ -47,7 +47,6 @@
#include <utils/qtcprocess.h>
#include <utils/runextensions.h>
#include <utils/stringutils.h>
-#include <utils/synchronousprocess.h>
#include <utils/temporaryfile.h>
#include <utils/url.h>
@@ -138,7 +137,10 @@ static void findProcessPID(QFutureInterface<qint64> &fi, QStringList selector,
chrono::high_resolution_clock::time_point start = chrono::high_resolution_clock::now();
do {
QThread::msleep(200);
- const auto out = SynchronousProcess().runBlocking({adbPath, args}).allRawOutput();
+ SynchronousProcess proc;
+ proc.setCommand({adbPath, args});
+ proc.runBlocking();
+ const QByteArray out = proc.allRawOutput();
if (preNougat) {
processPID = extractPID(out, packageName);
} else {
@@ -292,19 +294,24 @@ AndroidRunnerWorker::AndroidRunnerWorker(RunWorker *runner, const QString &packa
}
if (auto aspect = runControl->aspect(Constants::ANDROID_AMSTARTARGS)) {
- const QString startArgs = static_cast<StringAspect *>(aspect)->value();
- m_amStartExtraArgs = QtcProcess::splitArgs(startArgs, OsTypeOtherUnix);
+ QTC_CHECK(aspect->value().type() == QVariant::String);
+ const QString startArgs = aspect->value().toString();
+ m_amStartExtraArgs = ProcessArgs::splitArgs(startArgs, OsTypeOtherUnix);
}
if (auto aspect = runControl->aspect(Constants::ANDROID_PRESTARTSHELLCMDLIST)) {
- for (const QString &shellCmd : static_cast<BaseStringListAspect *>(aspect)->value())
+ QTC_CHECK(aspect->value().type() == QVariant::String);
+ const QStringList commands = aspect->value().toString().split('\n', Qt::SkipEmptyParts);
+ for (const QString &shellCmd : commands)
m_beforeStartAdbCommands.append(QString("shell %1").arg(shellCmd));
}
for (const QString &shellCmd : runner->recordedData(Constants::ANDROID_PRESTARTSHELLCMDLIST).toStringList())
m_beforeStartAdbCommands.append(QString("shell %1").arg(shellCmd));
if (auto aspect = runControl->aspect(Constants::ANDROID_POSTFINISHSHELLCMDLIST)) {
- for (const QString &shellCmd : static_cast<BaseStringListAspect *>(aspect)->value())
+ QTC_CHECK(aspect->value().type() == QVariant::String);
+ const QStringList commands = aspect->value().toString().split('\n', Qt::SkipEmptyParts);
+ for (const QString &shellCmd : commands)
m_afterFinishAdbCommands.append(QString("shell %1").arg(shellCmd));
}
for (const QString &shellCmd : runner->recordedData(Constants::ANDROID_POSTFINISHSHELLCMDLIST).toStringList())
@@ -629,7 +636,7 @@ void AndroidRunnerWorker::asyncStartHelper()
if (!m_extraAppParams.isEmpty()) {
QStringList appArgs =
- Utils::QtcProcess::splitArgs(m_extraAppParams, Utils::OsType::OsTypeLinux);
+ Utils::ProcessArgs::splitArgs(m_extraAppParams, Utils::OsType::OsTypeLinux);
qCDebug(androidRunWorkerLog) << "Using application arguments: " << appArgs;
args << "-e" << "extraappparams"
<< QString::fromLatin1(appArgs.join(' ').toUtf8().toBase64());
diff --git a/src/plugins/android/androidsdkmanager.cpp b/src/plugins/android/androidsdkmanager.cpp
index c0001e7a39..ae0dd0dd5c 100644
--- a/src/plugins/android/androidsdkmanager.cpp
+++ b/src/plugins/android/androidsdkmanager.cpp
@@ -34,7 +34,6 @@
#include <utils/qtcprocess.h>
#include <utils/runextensions.h>
#include <utils/stringutils.h>
-#include <utils/synchronousprocess.h>
#include <QFutureWatcher>
#include <QLoggingCategory>
@@ -42,6 +41,11 @@
#include <QRegularExpression>
#include <QSettings>
+#ifdef WITH_TESTS
+# include <QTest>
+# include "androidplugin.h"
+#endif // WITH_TESTS
+
namespace {
static Q_LOGGING_CATEGORY(sdkManagerLog, "qtc.android.sdkManager", QtWarningMsg)
}
@@ -147,13 +151,15 @@ static bool sdkManagerCommand(const AndroidConfig &config, const QStringList &ar
<< CommandLine(config.sdkManagerToolPath(), newArgs)
.toUserOutput();
SynchronousProcess proc;
- proc.setProcessEnvironment(AndroidConfigurations::toolsEnvironment(config));
+ proc.setEnvironment(AndroidConfigurations::toolsEnvironment(config));
proc.setTimeoutS(timeout);
proc.setTimeOutMessageBoxEnabled(true);
- SynchronousProcessResponse response = proc.run({config.sdkManagerToolPath(), newArgs});
+ proc.setCommand({config.sdkManagerToolPath(), newArgs});
+ proc.setProcessUserEventWhileRunning();
+ proc.runBlocking();
if (output)
- *output = response.allOutput();
- return response.result == SynchronousProcessResponse::Finished;
+ *output = proc.allOutput();
+ return proc.result() == QtcProcess::Finished;
}
/*!
@@ -173,35 +179,34 @@ static void sdkManagerCommand(const AndroidConfig &config, const QStringList &ar
<< CommandLine(config.sdkManagerToolPath(), newArgs).toUserOutput();
int offset = fi.progressValue();
SynchronousProcess proc;
- proc.setProcessEnvironment(AndroidConfigurations::toolsEnvironment(config));
+ proc.setEnvironment(AndroidConfigurations::toolsEnvironment(config));
bool assertionFound = false;
- proc.setStdErrBufferedSignalsEnabled(true);
- proc.setStdOutBufferedSignalsEnabled(true);
proc.setTimeoutS(timeout);
- QObject::connect(&proc, &SynchronousProcess::stdOutBuffered,
- [offset, progressQuota, &proc, &assertionFound, &fi](const QString &out) {
+ proc.setStdOutCallback([offset, progressQuota, &proc, &assertionFound, &fi](const QString &out) {
int progressPercent = parseProgress(out, assertionFound);
if (assertionFound)
- proc.terminate();
+ proc.stopProcess();
if (progressPercent != -1)
fi.setProgressValue(offset + qRound((progressPercent / 100.0) * progressQuota));
});
- QObject::connect(&proc, &SynchronousProcess::stdErrBuffered, [&output](const QString &err) {
+ proc.setStdErrCallback([&output](const QString &err) {
output.stdError = err;
});
if (interruptible) {
QObject::connect(&sdkManager, &AndroidSdkManager::cancelActiveOperations,
- &proc, &SynchronousProcess::terminate);
+ &proc, &SynchronousProcess::stopProcess);
}
- SynchronousProcessResponse response = proc.run({config.sdkManagerToolPath(), newArgs});
+ proc.setCommand({config.sdkManagerToolPath(), newArgs});
+ proc.setProcessUserEventWhileRunning();
+ proc.runBlocking();
if (assertionFound) {
output.success = false;
- output.stdOutput = response.stdOut();
+ output.stdOutput = proc.stdOut();
output.stdError = QCoreApplication::translate("Android::Internal::AndroidSdkManager",
"The operation requires user interaction. "
"Use the \"sdkmanager\" command-line tool.");
} else {
- output.success = response.result == SynchronousProcessResponse::Finished;
+ output.success = proc.result() == QtcProcess::Finished;
}
}
@@ -1032,7 +1037,7 @@ void AndroidSdkManagerPrivate::getPendingLicense(SdkCmdFutureInterface &fi)
AndroidSdkManager::OperationOutput result;
result.type = AndroidSdkManager::LicenseWorkflow;
QtcProcess licenseCommand;
- licenseCommand.setProcessEnvironment(AndroidConfigurations::toolsEnvironment(m_config));
+ licenseCommand.setEnvironment(AndroidConfigurations::toolsEnvironment(m_config));
bool reviewingLicenses = false;
licenseCommand.setCommand(CommandLine(m_config.sdkManagerToolPath(), {"--licenses", sdkRootArg(m_config)}));
if (Utils::HostOsInfo::isWindowsHost())
@@ -1158,5 +1163,54 @@ void AndroidSdkManagerPrivate::clearPackages()
m_allPackages.clear();
}
+#ifdef WITH_TESTS
+void AndroidPlugin::testAndroidSdkManagerProgressParser_data()
+{
+ QTest::addColumn<QString>("output");
+ QTest::addColumn<int>("progress");
+ QTest::addColumn<bool>("foundAssertion");
+
+ // Output of "sdkmanager --licenses", Android SDK Tools version 4.0
+ QTest::newRow("Loading local repository")
+ << "Loading local repository... \r"
+ << -1
+ << false;
+
+ QTest::newRow("Fetch progress (single line)")
+ << "[============= ] 34% Fetch remote repository... \r"
+ << 34
+ << false;
+
+ QTest::newRow("Fetch progress (multi line)")
+ << "[============================= ] 73% Fetch remote repository... \r"
+ "[============================= ] 75% Fetch remote repository... \r"
+ << 75
+ << false;
+
+ QTest::newRow("Some SDK package licenses not accepted")
+ << "7 of 7 SDK package licenses not accepted.\n"
+ << -1
+ << false;
+
+ QTest::newRow("Unaccepted licenses assertion")
+ << "\nReview licenses that have not been accepted (y/N)? "
+ << -1
+ << true;
+}
+
+void AndroidPlugin::testAndroidSdkManagerProgressParser()
+{
+ QFETCH(QString, output);
+ QFETCH(int, progress);
+ QFETCH(bool, foundAssertion);
+
+ bool actualFoundAssertion = false;
+ const int actualProgress = parseProgress(output, actualFoundAssertion);
+
+ QCOMPARE(progress, actualProgress);
+ QCOMPARE(foundAssertion, actualFoundAssertion);
+}
+#endif // WITH_TESTS
+
} // namespace Internal
} // namespace Android
diff --git a/src/plugins/android/androidsettingswidget.cpp b/src/plugins/android/androidsettingswidget.cpp
index 51b837af0f..4e57b1868b 100644
--- a/src/plugins/android/androidsettingswidget.cpp
+++ b/src/plugins/android/androidsettingswidget.cpp
@@ -45,7 +45,6 @@
#include <utils/pathchooser.h>
#include <utils/qtcassert.h>
#include <utils/qtcprocess.h>
-#include <utils/synchronousprocess.h>
#include <utils/utilsicons.h>
#include <QDesktopServices>
@@ -595,7 +594,7 @@ void AndroidSettingsWidget::validateOpenSsl()
void AndroidSettingsWidget::onSdkPathChanged()
{
- auto sdkPath = FilePath::fromUserInput(m_ui.SDKLocationPathChooser->rawPath());
+ const FilePath sdkPath = m_ui.SDKLocationPathChooser->filePath();
m_androidConfig.setSdkLocation(sdkPath);
FilePath currentOpenSslPath = m_androidConfig.openSslLocation();
if (currentOpenSslPath.isEmpty() || !currentOpenSslPath.exists())
@@ -607,7 +606,7 @@ void AndroidSettingsWidget::onSdkPathChanged()
void AndroidSettingsWidget::validateSdk()
{
- auto sdkPath = FilePath::fromUserInput(m_ui.SDKLocationPathChooser->rawPath());
+ const FilePath sdkPath = m_ui.SDKLocationPathChooser->filePath();
m_androidConfig.setSdkLocation(sdkPath);
m_androidSummary->setPointValid(SdkPathExistsRow, m_androidConfig.sdkLocation().exists());
@@ -826,7 +825,7 @@ void AndroidSettingsWidget::editEmulatorArgsAVD()
if (dialog.exec() != QDialog::Accepted)
return;
- m_androidConfig.setEmulatorArgs(QtcProcess::splitArgs(dialog.textValue()));
+ m_androidConfig.setEmulatorArgs(ProcessArgs::splitArgs(dialog.textValue()));
}
void AndroidSettingsWidget::createKitToggled()
@@ -866,12 +865,12 @@ void AndroidSettingsWidget::downloadSdk()
}
const QString message = tr("Download and install Android SDK Tools to: %1?")
- .arg(QDir::toNativeSeparators(m_ui.SDKLocationPathChooser->rawPath()));
+ .arg(m_ui.SDKLocationPathChooser->filePath().toUserOutput());
auto userInput = QMessageBox::information(this, AndroidSdkDownloader::dialogTitle(),
message, QMessageBox::Yes | QMessageBox::No);
if (userInput == QMessageBox::Yes) {
if (m_javaSummary->allRowsOk()) {
- auto javaPath = FilePath::fromUserInput(m_ui.OpenJDKLocationPathChooser->rawPath());
+ auto javaPath = m_ui.OpenJDKLocationPathChooser->filePath();
m_sdkDownloader.downloadAndExtractSdk(javaPath.toString(),
m_ui.SDKLocationPathChooser->filePath().toString());
}
diff --git a/src/plugins/android/avdmanageroutputparser.cpp b/src/plugins/android/avdmanageroutputparser.cpp
new file mode 100644
index 0000000000..69edfbe896
--- /dev/null
+++ b/src/plugins/android/avdmanageroutputparser.cpp
@@ -0,0 +1,166 @@
+/****************************************************************************
+**
+** Copyright (C) 2021 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of Qt Creator.
+**
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3 as published by the Free Software
+** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-3.0.html.
+**
+****************************************************************************/
+
+#include "avdmanageroutputparser.h"
+
+#include <projectexplorer/projectexplorerconstants.h>
+#include <utils/algorithm.h>
+#include <utils/fileutils.h>
+#include <utils/optional.h>
+#include <utils/qtcassert.h>
+#include <utils/variant.h>
+
+#include <QLoggingCategory>
+#include <QSettings>
+
+namespace {
+Q_LOGGING_CATEGORY(avdOutputParserLog, "qtc.android.avdOutputParser", QtWarningMsg)
+}
+
+// Avd list keys to parse avd
+const char avdInfoNameKey[] = "Name:";
+const char avdInfoPathKey[] = "Path:";
+const char avdInfoAbiKey[] = "abi.type";
+const char avdInfoTargetKey[] = "target";
+const char avdInfoErrorKey[] = "Error:";
+const char avdInfoSdcardKey[] = "Sdcard";
+const char avdInfoTargetTypeKey[] = "Target";
+const char avdInfoDeviceKey[] = "Device";
+const char avdInfoSkinKey[] = "Skin";
+
+namespace Android {
+namespace Internal {
+
+/*!
+ Parses the \a line for a [spaces]key[spaces]value[spaces] pattern and returns
+ \c true if the key is found, \c false otherwise. The value is copied into \a value.
+ */
+static bool valueForKey(QString key, const QString &line, QString *value = nullptr)
+{
+ auto trimmedInput = line.trimmed();
+ if (trimmedInput.startsWith(key)) {
+ if (value)
+ *value = trimmedInput.section(key, 1, 1).trimmed();
+ return true;
+ }
+ return false;
+}
+
+static Utils::optional<AndroidDeviceInfo> parseAvd(const QStringList &deviceInfo)
+{
+ AndroidDeviceInfo avd;
+ for (const QString &line : deviceInfo) {
+ QString value;
+ if (valueForKey(avdInfoErrorKey, line)) {
+ qCDebug(avdOutputParserLog) << "Avd Parsing: Skip avd device. Error key found:" << line;
+ return {};
+ } else if (valueForKey(avdInfoNameKey, line, &value)) {
+ avd.avdname = value;
+ } else if (valueForKey(avdInfoPathKey, line, &value)) {
+ const Utils::FilePath avdPath = Utils::FilePath::fromString(value);
+ if (avdPath.exists()) {
+ // Get ABI.
+ const Utils::FilePath configFile = avdPath.pathAppended("config.ini");
+ QSettings config(configFile.toString(), QSettings::IniFormat);
+ value = config.value(avdInfoAbiKey).toString();
+ if (!value.isEmpty())
+ avd.cpuAbi << value;
+ else
+ qCDebug(avdOutputParserLog) << "Avd Parsing: Cannot find ABI:" << configFile;
+
+ // Get Target
+ const QString avdInfoFileName = avd.avdname + ".ini";
+ const Utils::FilePath avdInfoFile = avdPath.parentDir().pathAppended(
+ avdInfoFileName);
+ QSettings avdInfo(avdInfoFile.toString(), QSettings::IniFormat);
+ value = avdInfo.value(avdInfoTargetKey).toString();
+ if (!value.isEmpty())
+ avd.sdk = value.section('-', -1).toInt();
+ else
+ qCDebug(avdOutputParserLog)
+ << "Avd Parsing: Cannot find sdk API:" << avdInfoFile.toString();
+ }
+ } else if (valueForKey(avdInfoDeviceKey, line, &value)) {
+ avd.avdDevice = value.remove(0, 2);
+ } else if (valueForKey(avdInfoTargetTypeKey, line, &value)) {
+ avd.avdTarget = value.remove(0, 2);
+ } else if (valueForKey(avdInfoSkinKey, line, &value)) {
+ avd.avdSkin = value.remove(0, 2);
+ } else if (valueForKey(avdInfoSdcardKey, line, &value)) {
+ avd.avdSdcardSize = value.remove(0, 2);
+ }
+ }
+ if (avd != AndroidDeviceInfo())
+ return avd;
+ return {};
+}
+
+AndroidDeviceInfoList parseAvdList(const QString &output, QStringList *avdErrorPaths)
+{
+ QTC_CHECK(avdErrorPaths);
+ AndroidDeviceInfoList avdList;
+ QStringList avdInfo;
+ using ErrorPath = QString;
+ using AvdResult = Utils::variant<std::monostate, AndroidDeviceInfo, ErrorPath>;
+ const auto parseAvdInfo = [](const QStringList &avdInfo) {
+ if (!avdInfo.filter(avdManufacturerError).isEmpty()) {
+ for (const QString &line : avdInfo) {
+ QString value;
+ if (valueForKey(avdInfoPathKey, line, &value))
+ return AvdResult(value); // error path
+ }
+ } else if (Utils::optional<AndroidDeviceInfo> avd = parseAvd(avdInfo)) {
+ // armeabi-v7a devices can also run armeabi code
+ if (avd->cpuAbi.contains(ProjectExplorer::Constants::ANDROID_ABI_ARMEABI_V7A))
+ avd->cpuAbi << ProjectExplorer::Constants::ANDROID_ABI_ARMEABI;
+ avd->state = AndroidDeviceInfo::OkState;
+ avd->type = AndroidDeviceInfo::Emulator;
+ return AvdResult(*avd);
+ } else {
+ qCDebug(avdOutputParserLog) << "Avd Parsing: Parsing failed: " << avdInfo;
+ }
+ return AvdResult();
+ };
+
+ for (const QString &line : output.split('\n')) {
+ if (line.startsWith("---------") || line.isEmpty()) {
+ const AvdResult result = parseAvdInfo(avdInfo);
+ if (auto info = Utils::get_if<AndroidDeviceInfo>(&result))
+ avdList << *info;
+ else if (auto errorPath = Utils::get_if<ErrorPath>(&result))
+ *avdErrorPaths << *errorPath;
+ avdInfo.clear();
+ } else {
+ avdInfo << line;
+ }
+ }
+
+ Utils::sort(avdList);
+
+ return avdList;
+}
+
+} // namespace Internal
+} // namespace Android
diff --git a/src/plugins/git/settingspage.h b/src/plugins/android/avdmanageroutputparser.h
index cc6dfba083..e5a50beae3 100644
--- a/src/plugins/git/settingspage.h
+++ b/src/plugins/android/avdmanageroutputparser.h
@@ -1,6 +1,6 @@
/****************************************************************************
**
-** Copyright (C) 2016 The Qt Company Ltd.
+** Copyright (C) 2021 The Qt Company Ltd.
** Contact: https://www.qt.io/licensing/
**
** This file is part of Qt Creator.
@@ -23,20 +23,14 @@
**
****************************************************************************/
-#pragma once
+#include "androiddeviceinfo.h"
-#include <coreplugin/dialogs/ioptionspage.h>
-
-namespace Git {
+namespace Android {
namespace Internal {
-class GitSettings;
+const char avdManufacturerError[] = "no longer exists as a device";
-class GitSettingsPage final : public Core::IOptionsPage
-{
-public:
- GitSettingsPage(GitSettings *settings, const std::function<void()> &onChange);
-};
+AndroidDeviceInfoList parseAvdList(const QString &output, QStringList *avdErrorPaths);
} // namespace Internal
-} // namespace Git
+} // namespace Android
diff --git a/src/plugins/android/javalanguageserver.cpp b/src/plugins/android/javalanguageserver.cpp
index 42ee452906..a3031e716a 100644
--- a/src/plugins/android/javalanguageserver.cpp
+++ b/src/plugins/android/javalanguageserver.cpp
@@ -192,10 +192,10 @@ private:
LanguageClient::BaseClientInterface *JLSSettings::createInterface() const
{
auto interface = new JLSInterface();
- interface->setExecutable(m_executable);
- QString arguments = this->arguments();
- arguments += QString(" -data \"%1\"").arg(interface->workspaceDir());
- interface->setArguments(arguments);
+ CommandLine cmd{m_executable};
+ cmd.addArgs(arguments(), CommandLine::Raw);
+ cmd.addArgs({"-data", interface->workspaceDir()});
+ interface->setCommandLine(cmd);
return interface;
}
@@ -221,7 +221,7 @@ void JLSClient::executeCommand(const LanguageServerProtocol::Command &command)
if (!argument.isObject())
continue;
LanguageServerProtocol::WorkspaceEdit edit(argument.toObject());
- if (edit.isValid(nullptr))
+ if (edit.isValid())
LanguageClient::applyWorkspaceEdit(edit);
}
} else {
diff --git a/src/plugins/android/javaparser.cpp b/src/plugins/android/javaparser.cpp
index 04b1b729ad..063ffb32f9 100644
--- a/src/plugins/android/javaparser.cpp
+++ b/src/plugins/android/javaparser.cpp
@@ -36,7 +36,7 @@ JavaParser::JavaParser() :
m_javaRegExp(QLatin1String("^(.*\\[javac\\]\\s)(.*\\.java):(\\d+):(.*)$"))
{ }
-void JavaParser::setProjectFileList(const QStringList &fileList)
+void JavaParser::setProjectFileList(const Utils::FilePaths &fileList)
{
m_fileList = fileList;
}
@@ -71,7 +71,7 @@ Utils::OutputLineParser::Result JavaParser::handleLine(const QString &line,
if (file.toFileInfo().isRelative()) {
for (int i = 0; i < m_fileList.size(); i++)
if (m_fileList[i].endsWith(file.toString())) {
- file = Utils::FilePath::fromString(m_fileList[i]);
+ file = m_fileList[i];
break;
}
}
diff --git a/src/plugins/android/javaparser.h b/src/plugins/android/javaparser.h
index 839f51626b..ea8c0ec158 100644
--- a/src/plugins/android/javaparser.h
+++ b/src/plugins/android/javaparser.h
@@ -39,16 +39,16 @@ class JavaParser : public ProjectExplorer::OutputTaskParser
public:
JavaParser();
- void setProjectFileList(const QStringList &fileList);
+ void setProjectFileList(const Utils::FilePaths &fileList);
void setBuildDirectory(const Utils::FilePath &buildDirectory);
void setSourceDirectory(const Utils::FilePath &sourceDirectory);
private:
Result handleLine(const QString &line, Utils::OutputFormat type) override;
- QRegularExpression m_javaRegExp;
- QStringList m_fileList;
+ const QRegularExpression m_javaRegExp;
+ Utils::FilePaths m_fileList;
Utils::FilePath m_sourceDirectory;
Utils::FilePath m_buildDirectory;
};
diff --git a/src/plugins/autotest/CMakeLists.txt b/src/plugins/autotest/CMakeLists.txt
index 275544653d..7b1438ab01 100644
--- a/src/plugins/autotest/CMakeLists.txt
+++ b/src/plugins/autotest/CMakeLists.txt
@@ -16,7 +16,6 @@ add_qtc_plugin(AutoTest
boost/boosttestparser.cpp boost/boosttestparser.h
boost/boosttestresult.cpp boost/boosttestresult.h
boost/boosttestsettings.cpp boost/boosttestsettings.h
- boost/boosttestsettingspage.cpp boost/boosttestsettingspage.h boost/boosttestsettingspage.ui
boost/boosttesttreeitem.cpp boost/boosttesttreeitem.h
catch/catchcodeparser.cpp catch/catchcodeparser.h
catch/catchconfiguration.cpp catch/catchconfiguration.h
@@ -24,7 +23,6 @@ add_qtc_plugin(AutoTest
catch/catchoutputreader.cpp catch/catchresult.h catch/catchresult.cpp catch/catchtestparser.h
catch/catchtestparser.cpp catch/catchtreeitem.h catch/catchtreeitem.cpp
catch/catchtestsettings.cpp catch/catchtestsettings.h
- catch/catchtestsettingspage.cpp catch/catchtestsettingspage.h catch/catchtestsettingspage.ui
ctest/ctestconfiguration.cpp ctest/ctestconfiguration.h
ctest/ctestoutputreader.cpp ctest/ctestoutputreader.h
ctest/ctesttool.cpp ctest/ctesttool.h
@@ -37,13 +35,11 @@ add_qtc_plugin(AutoTest
gtest/gtestparser.cpp gtest/gtestparser.h
gtest/gtestresult.cpp gtest/gtestresult.h
gtest/gtestsettings.cpp gtest/gtestsettings.h
- gtest/gtestsettingspage.cpp gtest/gtestsettingspage.h gtest/gtestsettingspage.ui
gtest/gtesttreeitem.cpp gtest/gtesttreeitem.h
gtest/gtestvisitors.cpp gtest/gtestvisitors.h
itemdatacache.h
itestframework.cpp itestframework.h
itestparser.cpp itestparser.h
- itestsettings.h
projectsettingswidget.cpp projectsettingswidget.h
qtest/qttest_utils.cpp qtest/qttest_utils.h
qtest/qttestconfiguration.cpp qtest/qttestconfiguration.h
@@ -53,7 +49,6 @@ add_qtc_plugin(AutoTest
qtest/qttestparser.cpp qtest/qttestparser.h
qtest/qttestresult.cpp qtest/qttestresult.h
qtest/qttestsettings.cpp qtest/qttestsettings.h
- qtest/qttestsettingspage.cpp qtest/qttestsettingspage.h qtest/qttestsettingspage.ui
qtest/qttesttreeitem.cpp qtest/qttesttreeitem.h
qtest/qttestvisitors.cpp qtest/qttestvisitors.h
quick/quicktest_utils.cpp quick/quicktest_utils.h
diff --git a/src/plugins/autotest/autotest.pro b/src/plugins/autotest/autotest.pro
index 3ca8ca2d42..6bfd57bbe1 100644
--- a/src/plugins/autotest/autotest.pro
+++ b/src/plugins/autotest/autotest.pro
@@ -39,7 +39,6 @@ SOURCES += \
catch/catchresult.cpp \
catch/catchtestparser.cpp \
catch/catchtestsettings.cpp \
- catch/catchtestsettingspage.cpp \
catch/catchtreeitem.cpp \
gtest/gtestconfiguration.cpp \
gtest/gtestparser.cpp \
@@ -49,7 +48,6 @@ SOURCES += \
gtest/gtestvisitors.cpp \
gtest/gtestframework.cpp \
gtest/gtestsettings.cpp \
- gtest/gtestsettingspage.cpp \
gtest/gtest_utils.cpp \
qtest/qttesttreeitem.cpp \
qtest/qttestvisitors.cpp \
@@ -59,7 +57,6 @@ SOURCES += \
qtest/qttestparser.cpp \
qtest/qttestframework.cpp \
qtest/qttestsettings.cpp \
- qtest/qttestsettingspage.cpp \
qtest/qttest_utils.cpp \
quick/quicktestconfiguration.cpp \
quick/quicktestparser.cpp \
@@ -74,8 +71,7 @@ SOURCES += \
boost/boosttestconfiguration.cpp \
boost/boosttestoutputreader.cpp \
boost/boosttestresult.cpp \
- boost/boosttestsettings.cpp \
- boost/boosttestsettingspage.cpp
+ boost/boosttestsettings.cpp
HEADERS += \
autotest_global.h \
@@ -89,7 +85,6 @@ HEADERS += \
itemdatacache.h \
itestframework.h \
itestparser.h \
- itestsettings.h \
projectsettingswidget.h \
testcodeparser.h \
testconfiguration.h \
@@ -117,7 +112,6 @@ HEADERS += \
catch/catchresult.h \
catch/catchtestparser.h \
catch/catchtestsettings.h \
- catch/catchtestsettingspage.h \
catch/catchtreeitem.h \
gtest/gtestconfiguration.h \
gtest/gtestparser.h \
@@ -128,7 +122,6 @@ HEADERS += \
gtest/gtestvisitors.h \
gtest/gtestframework.h \
gtest/gtestsettings.h \
- gtest/gtestsettingspage.h \
gtest/gtestconstants.h \
qtest/qttesttreeitem.h \
qtest/qttest_utils.h \
@@ -139,7 +132,6 @@ HEADERS += \
qtest/qttestparser.h \
qtest/qttestframework.h \
qtest/qttestsettings.h \
- qtest/qttestsettingspage.h \
qtest/qttestconstants.h \
quick/quicktestconfiguration.h \
quick/quicktestparser.h \
@@ -155,18 +147,13 @@ HEADERS += \
boost/boosttestconfiguration.h \
boost/boosttestoutputreader.h \
boost/boosttestresult.h \
- boost/boosttestsettingspage.h \
boost/boosttestsettings.h
RESOURCES += \
autotest.qrc
FORMS += \
- testsettingspage.ui \
- boost/boosttestsettingspage.ui \
- catch/catchtestsettingspage.ui \
- qtest/qttestsettingspage.ui \
- gtest/gtestsettingspage.ui
+ testsettingspage.ui
equals(TEST, 1) {
HEADERS += autotestunittests.h
diff --git a/src/plugins/autotest/autotest.qbs b/src/plugins/autotest/autotest.qbs
index 08adf7c215..cd9d0a5508 100644
--- a/src/plugins/autotest/autotest.qbs
+++ b/src/plugins/autotest/autotest.qbs
@@ -79,7 +79,6 @@ QtcPlugin {
"itestparser.h",
"itestframework.cpp",
"itestframework.h",
- "itestsettings.h",
"testframeworkmanager.cpp",
"testframeworkmanager.h",
"testrunconfiguration.h"
diff --git a/src/plugins/autotest/autotestplugin.cpp b/src/plugins/autotest/autotestplugin.cpp
index 7cd1259f25..47c53628ca 100644
--- a/src/plugins/autotest/autotestplugin.cpp
+++ b/src/plugins/autotest/autotestplugin.cpp
@@ -375,7 +375,7 @@ void AutotestPluginPrivate::onRunUnderCursorTriggered(TestRunMode mode)
// check whether we have been triggered on a test function definition
const int line = currentEditor->currentLine();
- const QString &filePath = currentEditor->textDocument()->filePath().toString();
+ const Utils::FilePath &filePath = currentEditor->textDocument()->filePath();
const QList<ITestTreeItem *> filteredItems = Utils::filtered(testsItems, [&](ITestTreeItem *it){
return it->line() == line && it->filePath() == filePath;
});
diff --git a/src/plugins/autotest/boost/boosttestconfiguration.cpp b/src/plugins/autotest/boost/boosttestconfiguration.cpp
index c559c2c6bd..eef1bb5890 100644
--- a/src/plugins/autotest/boost/boosttestconfiguration.cpp
+++ b/src/plugins/autotest/boost/boosttestconfiguration.cpp
@@ -40,9 +40,10 @@ namespace Internal {
TestOutputReader *BoostTestConfiguration::outputReader(const QFutureInterface<TestResultPtr> &fi,
QProcess *app) const
{
- auto settings = dynamic_cast<BoostTestSettings *>(framework()->testSettings());
+ auto settings = static_cast<BoostTestSettings *>(framework()->testSettings());
return new BoostTestOutputReader(fi, app, buildDirectory(), projectFile(),
- settings->logLevel, settings->reportLevel);
+ LogLevel(settings->logLevel.value()),
+ ReportLevel(settings->reportLevel.value()));
}
enum class InterferingType { Options, EnvironmentVariables };
@@ -107,19 +108,19 @@ static QStringList filterInterfering(const QStringList &provided, QStringList *o
QStringList BoostTestConfiguration::argumentsForTestRunner(QStringList *omitted) const
{
- auto boostSettings = dynamic_cast<BoostTestSettings *>(framework()->testSettings());
+ auto boostSettings = static_cast<BoostTestSettings *>(framework()->testSettings());
QStringList arguments;
- arguments << "-l" << BoostTestSettings::logLevelToOption(boostSettings->logLevel);
- arguments << "-r" << BoostTestSettings::reportLevelToOption(boostSettings->reportLevel);
+ arguments << "-l" << BoostTestSettings::logLevelToOption(LogLevel(boostSettings->logLevel.value()));
+ arguments << "-r" << BoostTestSettings::reportLevelToOption(ReportLevel(boostSettings->reportLevel.value()));
- if (boostSettings->randomize)
- arguments << QString("--random=").append(QString::number(boostSettings->seed));
+ if (boostSettings->randomize.value())
+ arguments << QString("--random=").append(QString::number(boostSettings->seed.value()));
- if (boostSettings->systemErrors)
+ if (boostSettings->systemErrors.value())
arguments << "-s";
- if (boostSettings->fpExceptions)
+ if (boostSettings->fpExceptions.value())
arguments << "--detect_fp_exceptions";
- if (!boostSettings->memLeaks)
+ if (!boostSettings->memLeaks.value())
arguments << "--detect_memory_leaks=0";
// TODO improve the test case gathering and arguments building to avoid too long command lines
diff --git a/src/plugins/autotest/boost/boosttestframework.cpp b/src/plugins/autotest/boost/boosttestframework.cpp
index 6f8ac0192f..74a7880c98 100644
--- a/src/plugins/autotest/boost/boosttestframework.cpp
+++ b/src/plugins/autotest/boost/boosttestframework.cpp
@@ -43,7 +43,7 @@ ITestTreeItem *BoostTestFramework::createRootNode()
this,
QCoreApplication::translate("BoostTestFramework",
BoostTest::Constants::FRAMEWORK_SETTINGS_CATEGORY),
- QString(), ITestTreeItem::Root);
+ Utils::FilePath(), ITestTreeItem::Root);
}
const char *BoostTestFramework::name() const
diff --git a/src/plugins/autotest/boost/boosttestframework.h b/src/plugins/autotest/boost/boosttestframework.h
index f91e06e6f8..2ca7b60869 100644
--- a/src/plugins/autotest/boost/boosttestframework.h
+++ b/src/plugins/autotest/boost/boosttestframework.h
@@ -28,7 +28,6 @@
#include "../itestframework.h"
#include "boosttestsettings.h"
-#include "boosttestsettingspage.h"
namespace Autotest {
namespace Internal {
diff --git a/src/plugins/autotest/boost/boosttestoutputreader.cpp b/src/plugins/autotest/boost/boosttestoutputreader.cpp
index 7338c6a660..5036a683ff 100644
--- a/src/plugins/autotest/boost/boosttestoutputreader.cpp
+++ b/src/plugins/autotest/boost/boosttestoutputreader.cpp
@@ -40,15 +40,10 @@ namespace Internal {
static Q_LOGGING_CATEGORY(orLog, "qtc.autotest.boost.outputreader", QtWarningMsg)
-static QString constructSourceFilePath(const QString &path, const QString &filePath)
-{
- return QFileInfo(path, filePath).canonicalFilePath();
-}
-
BoostTestOutputReader::BoostTestOutputReader(const QFutureInterface<TestResultPtr> &futureInterface,
QProcess *testApplication,
- const QString &buildDirectory,
- const QString &projectFile,
+ const Utils::FilePath &buildDirectory,
+ const Utils::FilePath &projectFile,
LogLevel log, ReportLevel report)
: TestOutputReader(futureInterface, testApplication, buildDirectory)
, m_projectFile(projectFile)
diff --git a/src/plugins/autotest/boost/boosttestoutputreader.h b/src/plugins/autotest/boost/boosttestoutputreader.h
index 4d109ecd45..56527fa627 100644
--- a/src/plugins/autotest/boost/boosttestoutputreader.h
+++ b/src/plugins/autotest/boost/boosttestoutputreader.h
@@ -39,8 +39,8 @@ class BoostTestOutputReader : public TestOutputReader
Q_OBJECT
public:
BoostTestOutputReader(const QFutureInterface<TestResultPtr> &futureInterface,
- QProcess *testApplication, const QString &buildDirectory,
- const QString &projectFile, LogLevel log, ReportLevel report);
+ QProcess *testApplication, const Utils::FilePath &buildDirectory,
+ const Utils::FilePath &projectFile, LogLevel log, ReportLevel report);
protected:
void processOutputLine(const QByteArray &outputLine) override;
void processStdError(const QByteArray &outputLine) override;
@@ -51,12 +51,12 @@ private:
void sendCompleteInformation();
void handleMessageMatch(const QRegularExpressionMatch &match);
void reportNoOutputFinish(const QString &description, ResultType type);
- QString m_projectFile;
+ Utils::FilePath m_projectFile;
QString m_currentModule;
QString m_currentSuite;
QString m_currentTest;
QString m_description;
- QString m_fileName;
+ Utils::FilePath m_fileName;
ResultType m_result = ResultType::Invalid;
int m_lineNumber = 0;
int m_testCaseCount = -1;
diff --git a/src/plugins/autotest/boost/boosttestparser.cpp b/src/plugins/autotest/boost/boosttestparser.cpp
index 6b01a5477e..53a1443430 100644
--- a/src/plugins/autotest/boost/boosttestparser.cpp
+++ b/src/plugins/autotest/boost/boosttestparser.cpp
@@ -98,8 +98,9 @@ static bool hasBoostTestMacros(const CPlusPlus::Document::Ptr &doc)
return false;
}
-static BoostTestParseResult *createParseResult(const QString &name, const QString &filePath,
- const QString &projectFile, ITestFramework *framework,
+static BoostTestParseResult *createParseResult(const QString &name, const Utils::FilePath &filePath,
+ const Utils::FilePath &projectFile,
+ ITestFramework *framework,
TestTreeItem::Type type, const BoostTestInfo &info)
{
BoostTestParseResult *partialSuite = new BoostTestParseResult(framework);
@@ -116,21 +117,19 @@ static BoostTestParseResult *createParseResult(const QString &name, const QStrin
}
bool BoostTestParser::processDocument(QFutureInterface<TestParseResultPtr> futureInterface,
- const QString &fileName)
+ const Utils::FilePath &fileName)
{
CPlusPlus::Document::Ptr doc = document(fileName);
if (doc.isNull() || !includesBoostTest(doc, m_cppSnapshot) || !hasBoostTestMacros(doc))
return false;
const CppTools::CppModelManager *modelManager = CppTools::CppModelManager::instance();
- const QString &filePath = doc->fileName();
-
- const QList<CppTools::ProjectPart::Ptr> projectParts = modelManager->projectPart(filePath);
+ const QList<CppTools::ProjectPart::Ptr> projectParts = modelManager->projectPart(fileName);
if (projectParts.isEmpty()) // happens if shutting down while parsing
return false;
const CppTools::ProjectPart::Ptr projectPart = projectParts.first();
- const auto projectFile = projectPart->projectFile;
- const QByteArray &fileContent = getFileContent(filePath);
+ const auto projectFile = Utils::FilePath::fromString(projectPart->projectFile);
+ const QByteArray &fileContent = getFileContent(fileName);
BoostCodeParser codeParser(fileContent, projectPart->languageFeatures, doc, m_cppSnapshot);
const BoostTestCodeLocationList foundTests = codeParser.findTests();
@@ -141,7 +140,7 @@ bool BoostTestParser::processDocument(QFutureInterface<TestParseResultPtr> futur
BoostTestInfoList suitesStates = locationAndType.m_suitesState;
BoostTestInfo firstSuite = suitesStates.first();
QStringList suites = firstSuite.fullName.split('/');
- BoostTestParseResult *topLevelSuite = createParseResult(suites.first(), filePath,
+ BoostTestParseResult *topLevelSuite = createParseResult(suites.first(), fileName,
projectFile, framework(),
TestTreeItem::TestSuite,
firstSuite);
@@ -150,7 +149,7 @@ bool BoostTestParser::processDocument(QFutureInterface<TestParseResultPtr> futur
while (!suitesStates.isEmpty()) {
firstSuite = suitesStates.first();
suites = firstSuite.fullName.split('/');
- BoostTestParseResult *suiteResult = createParseResult(suites.last(), filePath,
+ BoostTestParseResult *suiteResult = createParseResult(suites.last(), fileName,
projectFile, framework(),
TestTreeItem::TestSuite,
firstSuite);
@@ -163,7 +162,7 @@ bool BoostTestParser::processDocument(QFutureInterface<TestParseResultPtr> futur
BoostTestInfo tmpInfo{
locationAndType.m_suitesState.last().fullName + "::" + locationAndType.m_name,
locationAndType.m_state, locationAndType.m_line};
- BoostTestParseResult *funcResult = createParseResult(locationAndType.m_name, filePath,
+ BoostTestParseResult *funcResult = createParseResult(locationAndType.m_name, fileName,
projectFile, framework(),
locationAndType.m_type,
tmpInfo);
diff --git a/src/plugins/autotest/boost/boosttestparser.h b/src/plugins/autotest/boost/boosttestparser.h
index bba9640ef2..795a7e4c78 100644
--- a/src/plugins/autotest/boost/boosttestparser.h
+++ b/src/plugins/autotest/boost/boosttestparser.h
@@ -45,7 +45,7 @@ class BoostTestParser : public CppParser
public:
explicit BoostTestParser(ITestFramework *framework) : CppParser(framework) {}
bool processDocument(QFutureInterface<TestParseResultPtr> futureInterface,
- const QString &fileName) override;
+ const Utils::FilePath &fileName) override;
};
} // namespace Internal
diff --git a/src/plugins/autotest/boost/boosttestresult.cpp b/src/plugins/autotest/boost/boosttestresult.cpp
index 7d88787446..9cfab7d289 100644
--- a/src/plugins/autotest/boost/boosttestresult.cpp
+++ b/src/plugins/autotest/boost/boosttestresult.cpp
@@ -36,7 +36,7 @@
namespace Autotest {
namespace Internal {
-BoostTestResult::BoostTestResult(const QString &id, const QString &projectFile, const QString &name)
+BoostTestResult::BoostTestResult(const QString &id, const Utils::FilePath &projectFile, const QString &name)
: TestResult(id, name), m_projectFile(projectFile)
{
}
diff --git a/src/plugins/autotest/boost/boosttestresult.h b/src/plugins/autotest/boost/boosttestresult.h
index 842afc241c..99c25c5dfa 100644
--- a/src/plugins/autotest/boost/boosttestresult.h
+++ b/src/plugins/autotest/boost/boosttestresult.h
@@ -35,7 +35,7 @@ class BoostTestTreeItem;
class BoostTestResult : public TestResult
{
public:
- BoostTestResult(const QString &id, const QString &projectFile, const QString &name);
+ BoostTestResult(const QString &id, const Utils::FilePath &projectFile, const QString &name);
const QString outputString(bool selected) const override;
bool isDirectParentOf(const TestResult *other, bool *needsIntermediate) const override;
@@ -45,7 +45,7 @@ public:
private:
bool matches(const BoostTestTreeItem *item) const;
- QString m_projectFile;
+ Utils::FilePath m_projectFile;
QString m_testSuite;
QString m_testCase;
};
diff --git a/src/plugins/autotest/boost/boosttestsettings.cpp b/src/plugins/autotest/boost/boosttestsettings.cpp
index 333ae57891..a32899d022 100644
--- a/src/plugins/autotest/boost/boosttestsettings.cpp
+++ b/src/plugins/autotest/boost/boosttestsettings.cpp
@@ -25,43 +25,107 @@
#include "boosttestsettings.h"
+#include "boosttestconstants.h"
+
+#include "../autotestconstants.h"
+
+#include <utils/layoutbuilder.h>
+
+using namespace Utils;
+
namespace Autotest {
namespace Internal {
-static const char logLevelKey[] = "LogLevel";
-static const char reportLevelKey[] = "ReportLevel";
-static const char seedKey[] = "Seed";
-static const char randomizeKey[] = "Randomize";
-static const char systemErrorsKey[] = "SystemErrors";
-static const char fpExceptionsKey[] = "FPExceptions";
-static const char memLeaksKey[] = "MemoryLeaks";
-
-QString BoostTestSettings::name() const
+BoostTestSettings::BoostTestSettings()
{
- return QString("BoostTest");
-}
+ setSettingsGroups("Autotest", "BoostTest");
+ setAutoApply(false);
-void BoostTestSettings::fromTestSettings(const QSettings *s)
+ registerAspect(&logLevel);
+ logLevel.setSettingsKey("LogLevel");
+ logLevel.setDisplayStyle(SelectionAspect::DisplayStyle::ComboBox);
+ logLevel.addOption("All");
+ logLevel.addOption("Success");
+ logLevel.addOption("Test Suite");
+ logLevel.addOption("Unit Scope");
+ logLevel.addOption("Message");
+ logLevel.addOption("Warning");
+ logLevel.addOption("Error");
+ logLevel.addOption("C++ Exception");
+ logLevel.addOption("System Error");
+ logLevel.addOption("Fatal Error");
+ logLevel.addOption("Nothing");
+ logLevel.setDefaultValue(int(LogLevel::Warning));
+ logLevel.setLabelText(tr("Log format:"));
-{
- logLevel = LogLevel((s->value(logLevelKey, int(LogLevel::All)).toInt()));
- reportLevel = ReportLevel((s->value(reportLevelKey, int(ReportLevel::Confirm)).toInt()));
- systemErrors = s->value(systemErrorsKey, false).toBool();
- fpExceptions = s->value(fpExceptionsKey, false).toBool();
- memLeaks = s->value(memLeaksKey, true).toBool();
- randomize = s->value(randomizeKey, false).toBool();
- seed = s->value(seedKey, 0).toInt();
+ registerAspect(&reportLevel);
+ reportLevel.setSettingsKey("ReportLevel");
+ reportLevel.setDisplayStyle(SelectionAspect::DisplayStyle::ComboBox);
+ reportLevel.addOption("Confirm");
+ reportLevel.addOption("Short");
+ reportLevel.addOption("Detailed");
+ reportLevel.addOption("No");
+ reportLevel.setDefaultValue(int(ReportLevel::Confirm));
+ reportLevel.setLabelText(tr("Report level:"));
+
+ registerAspect(&seed);
+ seed.setSettingsKey("Seed");
+ seed.setEnabled(false);
+ seed.setLabelText(tr("Seed:"));
+ seed.setToolTip(tr("A seed of 0 means no randomization. A value of 1 uses the current "
+ "time, any other value is used as random seed generator."));
+ seed.setEnabler(&randomize);
+
+ registerAspect(&randomize);
+ randomize.setSettingsKey("Randomize");
+ randomize.setLabelPlacement(BoolAspect::LabelPlacement::AtCheckBoxWithoutDummyLabel);
+ randomize.setLabelText(tr("Randomize"));
+ randomize.setToolTip(tr("Randomize execution order."));
+
+ registerAspect(&systemErrors);
+ systemErrors.setSettingsKey("SystemErrors");
+ systemErrors.setLabelPlacement(BoolAspect::LabelPlacement::AtCheckBoxWithoutDummyLabel);
+ systemErrors.setLabelText(tr("Catch system errors"));
+ systemErrors.setToolTip(tr("Catch or ignore system errors."));
+
+ registerAspect(&fpExceptions);
+ fpExceptions.setSettingsKey("FPExceptions");
+ fpExceptions.setLabelPlacement(BoolAspect::LabelPlacement::AtCheckBoxWithoutDummyLabel);
+ fpExceptions.setLabelText(tr("Floating point exceptions"));
+ fpExceptions.setToolTip(tr("Enable floating point exception traps."));
+
+ registerAspect(&memLeaks);
+ memLeaks.setSettingsKey("MemoryLeaks");
+ memLeaks.setLabelPlacement(BoolAspect::LabelPlacement::AtCheckBoxWithoutDummyLabel);
+ memLeaks.setDefaultValue(true);
+ memLeaks.setLabelText(tr("Detect memory leaks"));
+ memLeaks.setToolTip(tr("Enable memory leak detection."));
}
-void BoostTestSettings::toTestSettings(QSettings *s) const
+BoostTestSettingsPage::BoostTestSettingsPage(BoostTestSettings *settings, Utils::Id settingsId)
{
- s->setValue(logLevelKey, int(logLevel));
- s->setValue(reportLevelKey, int(reportLevel));
- s->setValue(systemErrorsKey, systemErrors);
- s->setValue(fpExceptionsKey, fpExceptions);
- s->setValue(memLeaksKey, memLeaks);
- s->setValue(randomizeKey, randomize);
- s->setValue(seedKey, seed);
+ setId(settingsId);
+ setCategory(Constants::AUTOTEST_SETTINGS_CATEGORY);
+ setDisplayName(QCoreApplication::translate("BoostTestFramework",
+ BoostTest::Constants::FRAMEWORK_SETTINGS_CATEGORY));
+ setSettings(settings);
+
+ setLayouter([settings](QWidget *widget) {
+ BoostTestSettings &s = *settings;
+ using namespace Layouting;
+ const Break nl;
+
+ Grid grid {
+ s.logLevel, nl,
+ s.reportLevel, nl,
+ s.randomize, Row { s.seed }, nl,
+ s.systemErrors, nl,
+ s.fpExceptions, nl,
+ s.memLeaks,
+ };
+
+ Column { Row { Column { grid, Stretch() }, Stretch() } }.attachTo(widget);
+ });
}
QString BoostTestSettings::logLevelToOption(const LogLevel logLevel)
diff --git a/src/plugins/autotest/boost/boosttestsettings.h b/src/plugins/autotest/boost/boosttestsettings.h
index 081f8acc89..15f55483a2 100644
--- a/src/plugins/autotest/boost/boosttestsettings.h
+++ b/src/plugins/autotest/boost/boosttestsettings.h
@@ -25,7 +25,9 @@
#pragma once
-#include "../itestsettings.h"
+#include <coreplugin/dialogs/ioptionspage.h>
+
+#include <utils/aspects.h>
namespace Autotest {
namespace Internal {
@@ -53,25 +55,30 @@ enum class ReportLevel
No
};
-class BoostTestSettings : public ITestSettings
+class BoostTestSettings : public Utils::AspectContainer
{
+ Q_DECLARE_TR_FUNCTIONS(Autotest::Internal::BoostTestSettings)
+
public:
- BoostTestSettings() = default;
- QString name() const override;
+ BoostTestSettings();
+
static QString logLevelToOption(const LogLevel logLevel);
static QString reportLevelToOption(const ReportLevel reportLevel);
- LogLevel logLevel = LogLevel::Warning;
- ReportLevel reportLevel = ReportLevel::Confirm;
- int seed = 0;
- bool randomize = false;
- bool systemErrors = false;
- bool fpExceptions = false;
- bool memLeaks = true;
+ Utils::SelectionAspect logLevel;
+ Utils::SelectionAspect reportLevel;
+ Utils::IntegerAspect seed;
+ Utils::BoolAspect randomize;
+ Utils::BoolAspect systemErrors;
+ Utils::BoolAspect fpExceptions;
+ Utils::BoolAspect memLeaks;
+};
-protected:
- void fromTestSettings(const QSettings *s) override;
- void toTestSettings(QSettings *s) const override;
+
+class BoostTestSettingsPage final : public Core::IOptionsPage
+{
+public:
+ BoostTestSettingsPage(BoostTestSettings *settings, Utils::Id settingsId);
};
} // namespace Internal
diff --git a/src/plugins/autotest/boost/boosttestsettingspage.cpp b/src/plugins/autotest/boost/boosttestsettingspage.cpp
deleted file mode 100644
index 955d50683d..0000000000
--- a/src/plugins/autotest/boost/boosttestsettingspage.cpp
+++ /dev/null
@@ -1,114 +0,0 @@
-/****************************************************************************
-**
-** 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 "boosttestsettingspage.h"
-#include "boosttestconstants.h"
-#include "boosttestsettings.h"
-#include "../testframeworkmanager.h"
-#include "ui_boosttestsettingspage.h"
-
-#include <coreplugin/icore.h>
-
-namespace Autotest {
-namespace Internal {
-
-class BoostTestSettingsWidget : public Core::IOptionsPageWidget
-{
- Q_DECLARE_TR_FUNCTIONS(Autotest::Internal::BoostTestSettingsWidget)
-
-public:
- explicit BoostTestSettingsWidget(BoostTestSettings *settings);
-
- void apply() final;
-
- void setSettings(const BoostTestSettings &settings);
- BoostTestSettings settings() const;
-
-private:
- void fillComboBoxes();
- Ui::BoostSettingsPage m_ui;
- BoostTestSettings *m_settings;
-};
-
-BoostTestSettingsWidget::BoostTestSettingsWidget(BoostTestSettings *settings)
- : m_settings(settings)
-{
- m_ui.setupUi(this);
- fillComboBoxes();
- connect(m_ui.randomizeCB, &QCheckBox::toggled, m_ui.seedSB, &QSpinBox::setEnabled);
-
- m_ui.logFormatCB->setCurrentIndex(int(m_settings->logLevel));
- m_ui.reportLevelCB->setCurrentIndex(int(m_settings->reportLevel));
- m_ui.randomizeCB->setChecked(m_settings->randomize);
- m_ui.seedSB->setValue(m_settings->seed);
- m_ui.systemErrorCB->setChecked(m_settings->systemErrors);
- m_ui.fpExceptions->setChecked(m_settings->fpExceptions);
- m_ui.memoryLeakCB->setChecked(m_settings->memLeaks);
-}
-
-void BoostTestSettingsWidget::apply()
-{
- m_settings->logLevel = LogLevel(m_ui.logFormatCB->currentData().toInt());
- m_settings->reportLevel = ReportLevel(m_ui.reportLevelCB->currentData().toInt());
- m_settings->randomize = m_ui.randomizeCB->isChecked();
- m_settings->seed = m_ui.seedSB->value();
- m_settings->systemErrors = m_ui.systemErrorCB->isChecked();
- m_settings->fpExceptions = m_ui.fpExceptions->isChecked();
- m_settings->memLeaks = m_ui.memoryLeakCB->isChecked();
-
- m_settings->toSettings(Core::ICore::settings());
-}
-
-void BoostTestSettingsWidget::fillComboBoxes()
-{
- m_ui.logFormatCB->addItem("All", QVariant::fromValue(LogLevel::All));
- m_ui.logFormatCB->addItem("Success", QVariant::fromValue(LogLevel::Success));
- m_ui.logFormatCB->addItem("Test Suite", QVariant::fromValue(LogLevel::TestSuite));
- m_ui.logFormatCB->addItem("Unit Scope", QVariant::fromValue(LogLevel::UnitScope));
- m_ui.logFormatCB->addItem("Message", QVariant::fromValue(LogLevel::Message));
- m_ui.logFormatCB->addItem("Warning", QVariant::fromValue(LogLevel::Warning));
- m_ui.logFormatCB->addItem("Error", QVariant::fromValue(LogLevel::Error));
- m_ui.logFormatCB->addItem("C++ Exception", QVariant::fromValue(LogLevel::CppException));
- m_ui.logFormatCB->addItem("System Error", QVariant::fromValue(LogLevel::SystemError));
- m_ui.logFormatCB->addItem("Fatal Error", QVariant::fromValue(LogLevel::FatalError));
- m_ui.logFormatCB->addItem("Nothing", QVariant::fromValue(LogLevel::Nothing));
-
- m_ui.reportLevelCB->addItem("Confirm", QVariant::fromValue(ReportLevel::Confirm));
- m_ui.reportLevelCB->addItem("Short", QVariant::fromValue(ReportLevel::Short));
- m_ui.reportLevelCB->addItem("Detailed", QVariant::fromValue(ReportLevel::Detailed));
- m_ui.reportLevelCB->addItem("No", QVariant::fromValue(ReportLevel::No));
-}
-
-BoostTestSettingsPage::BoostTestSettingsPage(BoostTestSettings *settings, Utils::Id settingsId)
-{
- setId(settingsId);
- setCategory(Constants::AUTOTEST_SETTINGS_CATEGORY);
- setDisplayName(QCoreApplication::translate("BoostTestFramework",
- BoostTest::Constants::FRAMEWORK_SETTINGS_CATEGORY));
- setWidgetCreator([settings] { return new BoostTestSettingsWidget(settings); });
-}
-
-} // Internal
-} // Autotest
diff --git a/src/plugins/autotest/boost/boosttestsettingspage.h b/src/plugins/autotest/boost/boosttestsettingspage.h
deleted file mode 100644
index 92601652d5..0000000000
--- a/src/plugins/autotest/boost/boosttestsettingspage.h
+++ /dev/null
@@ -1,42 +0,0 @@
-/****************************************************************************
-**
-** 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 <coreplugin/dialogs/ioptionspage.h>
-
-namespace Autotest {
-namespace Internal {
-
-class BoostTestSettings;
-
-class BoostTestSettingsPage final : public Core::IOptionsPage
-{
-public:
- BoostTestSettingsPage(BoostTestSettings *settings, Utils::Id settingsId);
-};
-
-} // Internal
-} // Autotest
diff --git a/src/plugins/autotest/boost/boosttestsettingspage.ui b/src/plugins/autotest/boost/boosttestsettingspage.ui
deleted file mode 100644
index 22ddef51f6..0000000000
--- a/src/plugins/autotest/boost/boosttestsettingspage.ui
+++ /dev/null
@@ -1,160 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<ui version="4.0">
- <class>BoostSettingsPage</class>
- <widget class="QWidget" name="BoostSettingsPage">
- <property name="geometry">
- <rect>
- <x>0</x>
- <y>0</y>
- <width>309</width>
- <height>284</height>
- </rect>
- </property>
- <layout class="QVBoxLayout" name="verticalLayout_2">
- <item>
- <layout class="QHBoxLayout" name="horizontalLayout_4">
- <item>
- <layout class="QVBoxLayout" name="verticalLayout">
- <item>
- <layout class="QHBoxLayout" name="horizontalLayout">
- <item>
- <widget class="QLabel" name="label">
- <property name="text">
- <string>Log format:</string>
- </property>
- </widget>
- </item>
- <item>
- <widget class="QComboBox" name="logFormatCB"/>
- </item>
- </layout>
- </item>
- <item>
- <layout class="QHBoxLayout" name="horizontalLayout_2">
- <item>
- <widget class="QLabel" name="label_2">
- <property name="text">
- <string>Report level:</string>
- </property>
- </widget>
- </item>
- <item>
- <widget class="QComboBox" name="reportLevelCB"/>
- </item>
- </layout>
- </item>
- <item>
- <layout class="QHBoxLayout" name="horizontalLayout_3">
- <item>
- <widget class="QCheckBox" name="randomizeCB">
- <property name="toolTip">
- <string>Randomize execution order.</string>
- </property>
- <property name="text">
- <string>Randomize</string>
- </property>
- </widget>
- </item>
- <item>
- <spacer name="horizontalSpacer_2">
- <property name="orientation">
- <enum>Qt::Horizontal</enum>
- </property>
- <property name="sizeHint" stdset="0">
- <size>
- <width>40</width>
- <height>20</height>
- </size>
- </property>
- </spacer>
- </item>
- <item>
- <widget class="QLabel" name="label_3">
- <property name="text">
- <string>Seed:</string>
- </property>
- </widget>
- </item>
- <item>
- <widget class="QSpinBox" name="seedSB">
- <property name="enabled">
- <bool>false</bool>
- </property>
- <property name="toolTip">
- <string>A seed of 0 means no randomization. A value of 1 uses the current time any other value is used as random seed generator.</string>
- </property>
- <property name="maximum">
- <number>65535</number>
- </property>
- </widget>
- </item>
- </layout>
- </item>
- <item>
- <widget class="QCheckBox" name="systemErrorCB">
- <property name="toolTip">
- <string>Catch or ignore system errors.</string>
- </property>
- <property name="text">
- <string>Catch system errors</string>
- </property>
- </widget>
- </item>
- <item>
- <widget class="QCheckBox" name="fpExceptions">
- <property name="toolTip">
- <string>Enable floating point exception traps.</string>
- </property>
- <property name="text">
- <string>Floating point exceptions</string>
- </property>
- </widget>
- </item>
- <item>
- <widget class="QCheckBox" name="memoryLeakCB">
- <property name="toolTip">
- <string>Enable memory leak detection.</string>
- </property>
- <property name="text">
- <string>Detect memory leaks</string>
- </property>
- <property name="checked">
- <bool>true</bool>
- </property>
- </widget>
- </item>
- </layout>
- </item>
- <item>
- <spacer name="horizontalSpacer">
- <property name="orientation">
- <enum>Qt::Horizontal</enum>
- </property>
- <property name="sizeHint" stdset="0">
- <size>
- <width>40</width>
- <height>20</height>
- </size>
- </property>
- </spacer>
- </item>
- </layout>
- </item>
- <item>
- <spacer name="verticalSpacer">
- <property name="orientation">
- <enum>Qt::Vertical</enum>
- </property>
- <property name="sizeHint" stdset="0">
- <size>
- <width>20</width>
- <height>84</height>
- </size>
- </property>
- </spacer>
- </item>
- </layout>
- </widget>
- <resources/>
- <connections/>
-</ui>
diff --git a/src/plugins/autotest/boost/boosttesttreeitem.cpp b/src/plugins/autotest/boost/boosttesttreeitem.cpp
index 928bd24420..74e9740973 100644
--- a/src/plugins/autotest/boost/boosttesttreeitem.cpp
+++ b/src/plugins/autotest/boost/boosttesttreeitem.cpp
@@ -30,6 +30,7 @@
#include "boosttestparser.h"
#include "../testframeworkmanager.h"
+#include <cpptools/cppmodelmanager.h>
#include <projectexplorer/session.h>
#include <utils/qtcassert.h>
@@ -76,11 +77,9 @@ TestTreeItem *BoostTestTreeItem::find(const TestParseResult *result)
switch (type()) {
case Root:
if (result->framework->grouping()) {
- const QFileInfo fileInfo(bResult->fileName);
- const QFileInfo base(fileInfo.absolutePath());
for (int row = 0; row < childCount(); ++row) {
BoostTestTreeItem *group = static_cast<BoostTestTreeItem *>(childAt(row));
- if (group->filePath() != base.absoluteFilePath())
+ if (group->filePath() != bResult->fileName.absoluteFilePath())
continue;
if (auto groupChild = group->findChildByNameStateAndFile(
bResult->name, bResult->state, bResult->proFile)) {
@@ -145,9 +144,8 @@ bool BoostTestTreeItem::modify(const TestParseResult *result)
TestTreeItem *BoostTestTreeItem::createParentGroupNode() const
{
- const QFileInfo fileInfo(filePath());
- const QFileInfo base(fileInfo.absolutePath());
- return new BoostTestTreeItem(framework(), base.baseName(), fileInfo.absolutePath(), TestTreeItem::GroupNode);
+ const QFileInfo base = filePath().absolutePath().toFileInfo();
+ return new BoostTestTreeItem(framework(), base.baseName(), filePath().absolutePath(), TestTreeItem::GroupNode);
}
QString BoostTestTreeItem::prependWithParentsSuitePaths(const QString &testName) const
@@ -187,7 +185,7 @@ QList<ITestConfiguration *> BoostTestTreeItem::getAllTestConfigurations() const
};
// we only need the unique project files (and number of test cases for the progress indicator)
- QHash<QString, BoostTestCases> testsPerProjectfile;
+ QHash<Utils::FilePath, BoostTestCases> testsPerProjectfile;
forAllChildItems([&testsPerProjectfile](TestTreeItem *item){
if (item->type() != TestSuite)
return;
@@ -197,8 +195,10 @@ QList<ITestConfiguration *> BoostTestTreeItem::getAllTestConfigurations() const
++funcChildren;
});
if (funcChildren) {
+ const auto cppMM = CppTools::CppModelManager::instance();
+ QTC_ASSERT(cppMM, return);
testsPerProjectfile[item->proFile()].testCases += funcChildren;
- testsPerProjectfile[item->proFile()].internalTargets.unite(item->internalTargets());
+ testsPerProjectfile[item->proFile()].internalTargets.unite(cppMM->internalTargets(item->filePath()));
}
});
@@ -228,7 +228,7 @@ QList<ITestConfiguration *> BoostTestTreeItem::getTestConfigurations(
QSet<QString> internalTargets;
};
- QHash<QString, BoostTestCases> testCasesForProjectFile;
+ QHash<Utils::FilePath, BoostTestCases> testCasesForProjectFile;
forAllChildren([&testCasesForProjectFile, &predicate](TreeItem *it){
auto item = static_cast<BoostTestTreeItem *>(it);
if (item->type() != TestCase)
@@ -236,6 +236,8 @@ QList<ITestConfiguration *> BoostTestTreeItem::getTestConfigurations(
if (!item->enabled()) // ignore child tests known to be disabled when using run selected
return;
if (predicate(item)) {
+ const auto cppMM = CppTools::CppModelManager::instance();
+ QTC_ASSERT(cppMM, return);
QString tcName = item->name();
if (item->state().testFlag(BoostTestTreeItem::Templated))
tcName.append("<*");
@@ -244,7 +246,7 @@ QList<ITestConfiguration *> BoostTestTreeItem::getTestConfigurations(
tcName = handleSpecialFunctionNames(tcName);
testCasesForProjectFile[item->proFile()].testCases.append(
item->prependWithParentsSuitePaths(tcName));
- testCasesForProjectFile[item->proFile()].internalTargets.unite(item->internalTargets());
+ testCasesForProjectFile[item->proFile()].internalTargets.unite(cppMM->internalTargets(item->filePath()));
}
});
@@ -280,6 +282,8 @@ ITestConfiguration *BoostTestTreeItem::testConfiguration() const
{
ProjectExplorer::Project *project = ProjectExplorer::SessionManager::startupProject();
QTC_ASSERT(project, return nullptr);
+ const auto cppMM = CppTools::CppModelManager::instance();
+ QTC_ASSERT(cppMM, return nullptr);
const Type itemType = type();
if (itemType == TestSuite || itemType == TestCase) {
@@ -313,7 +317,7 @@ ITestConfiguration *BoostTestTreeItem::testConfiguration() const
config->setProjectFile(proFile());
config->setProject(project);
config->setTestCases(testCases);
- config->setInternalTargets(internalTargets());
+ config->setInternalTargets(cppMM->internalTargets(filePath()));
return config;
}
return nullptr;
@@ -364,7 +368,7 @@ bool BoostTestTreeItem::enabled() const
TestTreeItem *BoostTestTreeItem::findChildByNameStateAndFile(const QString &name,
BoostTestTreeItem::TestStates state,
- const QString &proFile) const
+ const Utils::FilePath &proFile) const
{
return static_cast<TestTreeItem *>(
findAnyChild([name, state, proFile](const Utils::TreeItem *other){
diff --git a/src/plugins/autotest/boost/boosttesttreeitem.h b/src/plugins/autotest/boost/boosttesttreeitem.h
index 5bcdf5cf19..96b6315151 100644
--- a/src/plugins/autotest/boost/boosttesttreeitem.h
+++ b/src/plugins/autotest/boost/boosttesttreeitem.h
@@ -50,7 +50,7 @@ public:
explicit BoostTestTreeItem(ITestFramework *framework,
const QString &name = QString(),
- const QString &filePath = QString(),
+ const Utils::FilePath &filePath = Utils::FilePath(),
Type type = Root)
: TestTreeItem(framework, name, filePath, type)
{}
@@ -82,7 +82,7 @@ private:
bool enabled() const;
TestTreeItem *findChildByNameStateAndFile(const QString &name,
BoostTestTreeItem::TestStates state,
- const QString &proFile) const;
+ const Utils::FilePath &proFile) const;
QString prependWithParentsSuitePaths(const QString &testName) const;
QList<ITestConfiguration *> getTestConfigurations(
std::function<bool(BoostTestTreeItem *)> predicate) const;
diff --git a/src/plugins/autotest/catch/catchconfiguration.cpp b/src/plugins/autotest/catch/catchconfiguration.cpp
index 4fb235e035..3d01b58bd0 100644
--- a/src/plugins/autotest/catch/catchconfiguration.cpp
+++ b/src/plugins/autotest/catch/catchconfiguration.cpp
@@ -105,32 +105,32 @@ QStringList CatchConfiguration::argumentsForTestRunner(QStringList *omitted) con
' ', Qt::SkipEmptyParts), omitted);
}
- auto settings = dynamic_cast<CatchTestSettings *>(framework()->testSettings());
+ auto settings = static_cast<CatchTestSettings *>(framework()->testSettings());
if (!settings)
return arguments;
- if (settings->abortAfterChecked)
- arguments << "-x" << QString::number(settings->abortAfter);
- if (settings->samplesChecked)
- arguments << "--benchmark-samples" << QString::number(settings->benchmarkSamples);
- if (settings->resamplesChecked)
- arguments << "--benchmark-resamples" << QString::number(settings->benchmarkResamples);
- if (settings->warmupChecked)
- arguments << "--benchmark-warmup-time" << QString::number(settings->benchmarkWarmupTime);
- if (settings->confidenceIntervalChecked)
- arguments << "--benchmark-confidence-interval" << QString::number(settings->confidenceInterval);
- if (settings->noAnalysis)
+ if (settings->abortAfterChecked.value())
+ arguments << "-x" << QString::number(settings->abortAfter.value());
+ if (settings->samplesChecked.value())
+ arguments << "--benchmark-samples" << QString::number(settings->benchmarkSamples.value());
+ if (settings->resamplesChecked.value())
+ arguments << "--benchmark-resamples" << QString::number(settings->benchmarkResamples.value());
+ if (settings->warmupChecked.value())
+ arguments << "--benchmark-warmup-time" << QString::number(settings->benchmarkWarmupTime.value());
+ if (settings->confidenceIntervalChecked.value())
+ arguments << "--benchmark-confidence-interval" << QString::number(settings->confidenceInterval.value());
+ if (settings->noAnalysis.value())
arguments << "--benchmark-no-analysis";
- if (settings->showSuccess)
+ if (settings->showSuccess.value())
arguments << "-s";
- if (settings->noThrow)
+ if (settings->noThrow.value())
arguments << "-e";
- if (settings->visibleWhitespace)
+ if (settings->visibleWhitespace.value())
arguments << "-i";
- if (settings->warnOnEmpty)
+ if (settings->warnOnEmpty.value())
arguments << "-w" << "NoAssertions";
- if (isDebugRunMode() && settings->breakOnFailure)
+ if (isDebugRunMode() && settings->breakOnFailure.value())
arguments << "-b";
return arguments;
}
diff --git a/src/plugins/autotest/catch/catchframework.cpp b/src/plugins/autotest/catch/catchframework.cpp
index 3a8b71c4c2..754703bf71 100644
--- a/src/plugins/autotest/catch/catchframework.cpp
+++ b/src/plugins/autotest/catch/catchframework.cpp
@@ -49,7 +49,7 @@ ITestTreeItem *CatchFramework::createRootNode()
{
return new CatchTreeItem(this,
QCoreApplication::translate("CatchFramework", "Catch Test"),
- QString(), ITestTreeItem::Root);
+ Utils::FilePath(), ITestTreeItem::Root);
}
} // namespace Internal
diff --git a/src/plugins/autotest/catch/catchframework.h b/src/plugins/autotest/catch/catchframework.h
index 0b143472ea..c49e79c929 100644
--- a/src/plugins/autotest/catch/catchframework.h
+++ b/src/plugins/autotest/catch/catchframework.h
@@ -27,7 +27,6 @@
#include "../itestframework.h"
#include "catchtestsettings.h"
-#include "catchtestsettingspage.h"
namespace Autotest {
namespace Internal {
diff --git a/src/plugins/autotest/catch/catchoutputreader.cpp b/src/plugins/autotest/catch/catchoutputreader.cpp
index 4a46c7722c..f7ae4d3bc8 100644
--- a/src/plugins/autotest/catch/catchoutputreader.cpp
+++ b/src/plugins/autotest/catch/catchoutputreader.cpp
@@ -49,8 +49,8 @@ namespace CatchXml {
}
CatchOutputReader::CatchOutputReader(const QFutureInterface<TestResultPtr> &futureInterface,
- QProcess *testApplication, const QString &buildDirectory,
- const QString &projectFile)
+ QProcess *testApplication, const Utils::FilePath &buildDirectory,
+ const Utils::FilePath &projectFile)
: TestOutputReader (futureInterface, testApplication, buildDirectory)
, m_projectFile(projectFile)
{
@@ -174,11 +174,8 @@ TestResultPtr CatchOutputReader::createDefaultResult() const
result->setDescription(m_testCaseInfo.last().name);
result->setLine(m_testCaseInfo.last().line);
const QString givenPath = m_testCaseInfo.last().filename;
- const Utils::FilePath filePath = Utils::FilePath::fromFileInfo(QFileInfo(givenPath));
if (!givenPath.isEmpty()) {
- result->setFileName(QDir::isAbsolutePath(givenPath)
- ? filePath.toString()
- : QFileInfo(m_buildDir + '/' + givenPath).canonicalFilePath());
+ result->setFileName(constructSourceFilePath(m_buildDir, givenPath));
}
} else {
result = new CatchResult(id(), QString());
diff --git a/src/plugins/autotest/catch/catchoutputreader.h b/src/plugins/autotest/catch/catchoutputreader.h
index 86f016478b..7015830961 100644
--- a/src/plugins/autotest/catch/catchoutputreader.h
+++ b/src/plugins/autotest/catch/catchoutputreader.h
@@ -39,8 +39,8 @@ class CatchOutputReader : public TestOutputReader
public:
CatchOutputReader(const QFutureInterface<TestResultPtr> &futureInterface,
- QProcess *testApplication, const QString &buildDirectory,
- const QString &projectFile);
+ QProcess *testApplication, const Utils::FilePath &buildDirectory,
+ const Utils::FilePath &projectFile);
protected:
void processOutputLine(const QByteArray &outputLineWithNewLine) override;
@@ -74,7 +74,7 @@ private:
QStack<TestOutputNode> m_testCaseInfo;
int m_sectionDepth = 0;
- QString m_projectFile;
+ Utils::FilePath m_projectFile;
QString m_currentTagName;
QString m_currentExpression;
QXmlStreamReader m_xmlReader;
diff --git a/src/plugins/autotest/catch/catchresult.cpp b/src/plugins/autotest/catch/catchresult.cpp
index 36641f9d01..8e7f2cdb7e 100644
--- a/src/plugins/autotest/catch/catchresult.cpp
+++ b/src/plugins/autotest/catch/catchresult.cpp
@@ -73,7 +73,7 @@ const ITestTreeItem *CatchResult::findTestTreeItem() const
return nullptr;
const QString tcName = name();
- const QString tcFilePath = fileName();
+ const Utils::FilePath tcFilePath = fileName();
return rootNode->findAnyChild([&tcName, &tcFilePath](const Utils::TreeItem *item) {
const auto treeItem = static_cast<const CatchTreeItem *>(item);
if (!treeItem || treeItem->filePath() != tcFilePath)
diff --git a/src/plugins/autotest/catch/catchtestparser.cpp b/src/plugins/autotest/catch/catchtestparser.cpp
index a01de57a75..a95e1f2905 100644
--- a/src/plugins/autotest/catch/catchtestparser.cpp
+++ b/src/plugins/autotest/catch/catchtestparser.cpp
@@ -105,7 +105,8 @@ static bool hasCatchNames(const CPlusPlus::Document::Ptr &document)
return false;
}
-bool CatchTestParser::processDocument(QFutureInterface<TestParseResultPtr> futureInterface, const QString &fileName)
+bool CatchTestParser::processDocument(QFutureInterface<TestParseResultPtr> futureInterface,
+ const Utils::FilePath &fileName)
{
CPlusPlus::Document::Ptr doc = document(fileName);
if (doc.isNull() || !includesCatchHeader(doc, m_cppSnapshot) || !hasCatchNames(doc))
@@ -113,28 +114,28 @@ bool CatchTestParser::processDocument(QFutureInterface<TestParseResultPtr> futur
const CppTools::CppModelManager *modelManager = CppTools::CppModelManager::instance();
const QString &filePath = doc->fileName();
- const QByteArray &fileContent = getFileContent(filePath);
+ const QByteArray &fileContent = getFileContent(fileName);
- const QList<CppTools::ProjectPart::Ptr> projectParts = modelManager->projectPart(filePath);
+ const QList<CppTools::ProjectPart::Ptr> projectParts = modelManager->projectPart(fileName);
if (projectParts.isEmpty()) // happens if shutting down while parsing
return false;
- QString proFile;
+ Utils::FilePath proFile;
const CppTools::ProjectPart::Ptr projectPart = projectParts.first();
- proFile = projectPart->projectFile;
+ proFile = Utils::FilePath::fromString(projectPart->projectFile);
CatchCodeParser codeParser(fileContent, projectPart->languageFeatures);
const CatchTestCodeLocationList foundTests = codeParser.findTests();
CatchParseResult *parseResult = new CatchParseResult(framework());
parseResult->itemType = TestTreeItem::TestSuite;
- parseResult->fileName = filePath;
+ parseResult->fileName = fileName;
parseResult->name = filePath;
parseResult->displayName = filePath;
- parseResult->proFile = projectParts.first()->projectFile;
+ parseResult->proFile = proFile;
for (const CatchTestCodeLocationAndType & testLocation : foundTests) {
CatchParseResult *testCase = new CatchParseResult(framework());
- testCase->fileName = filePath;
+ testCase->fileName = fileName;
testCase->name = testLocation.m_name;
testCase->proFile = proFile;
testCase->itemType = testLocation.m_type;
diff --git a/src/plugins/autotest/catch/catchtestparser.h b/src/plugins/autotest/catch/catchtestparser.h
index 4c558aa637..3191072f05 100644
--- a/src/plugins/autotest/catch/catchtestparser.h
+++ b/src/plugins/autotest/catch/catchtestparser.h
@@ -45,7 +45,7 @@ public:
CatchTestParser(ITestFramework *framework)
: CppParser(framework) {}
bool processDocument(QFutureInterface<TestParseResultPtr> futureInterface,
- const QString &fileName) override;
+ const Utils::FilePath &fileName) override;
};
} // namespace Internal
diff --git a/src/plugins/autotest/catch/catchtestsettings.cpp b/src/plugins/autotest/catch/catchtestsettings.cpp
index d7eabb9aff..358ff85fd4 100644
--- a/src/plugins/autotest/catch/catchtestsettings.cpp
+++ b/src/plugins/autotest/catch/catchtestsettings.cpp
@@ -25,69 +25,143 @@
#include "catchtestsettings.h"
+#include "../autotestconstants.h"
+
+#include <coreplugin/icore.h>
+
+#include <utils/layoutbuilder.h>
+
+using namespace Utils;
+
namespace Autotest {
namespace Internal {
-static const char abortAfterKey[] = "AbortAfter";
-static const char abortAfterCheckedKey[] = "AbortChecked";
-static const char benchmarkSamplesKey[] = "BenchSamples";
-static const char samplesCheckedKey[] = "SamplesChecked";
-static const char benchmarkResamplesKey[] = "BenchResamples";
-static const char resamplesCheckedKey[] = "ResamplesChecked";
-static const char benchmarConfidenceIntervalKey[] = "BenchConfInt";
-static const char confIntCheckedKey[] = "ConfIntChecked";
-static const char benchmarWarmupTimeKey[] = "BenchWarmup";
-static const char warmupCheckedKey[] = "WarmupChecked";
-static const char noAnalysisKey[] = "NoAnalysis";
-static const char showSuccessKey[] = "ShowSuccess";
-static const char breakOnFailureKey[] = "BreakOnFailure";
-static const char noThrowKey[] = "NoThrow";
-static const char visibleWhitespaceKey[] = "VisibleWS";
-static const char warnOnEmptyKey[] = "WarnEmpty";
-
-QString CatchTestSettings::name() const
+CatchTestSettings::CatchTestSettings()
{
- return QString("Catch2");
-}
+ setSettingsGroups("Autotest", "Catch2");
+ setAutoApply(false);
-void CatchTestSettings::toTestSettings(QSettings *s) const
-{
- s->setValue(abortAfterCheckedKey, abortAfterChecked);
- s->setValue(abortAfterKey, abortAfter);
- s->setValue(samplesCheckedKey, samplesChecked);
- s->setValue(benchmarkSamplesKey, benchmarkSamples);
- s->setValue(resamplesCheckedKey, resamplesChecked);
- s->setValue(benchmarkResamplesKey, benchmarkResamples);
- s->setValue(confIntCheckedKey, confidenceIntervalChecked);
- s->setValue(benchmarConfidenceIntervalKey, confidenceInterval);
- s->setValue(warmupCheckedKey, warmupChecked);
- s->setValue(benchmarWarmupTimeKey, benchmarkWarmupTime);
- s->setValue(noAnalysisKey, noAnalysis);
- s->setValue(showSuccessKey, showSuccess);
- s->setValue(breakOnFailureKey, breakOnFailure);
- s->setValue(noThrowKey, noThrow);
- s->setValue(visibleWhitespaceKey, visibleWhitespace);
- s->setValue(warnOnEmptyKey, warnOnEmpty);
+ registerAspect(&abortAfter);
+ abortAfter.setSettingsKey("AbortAfter");
+ abortAfter.setRange(1, 9999);
+ abortAfter.setEnabler(&abortAfterChecked);
+
+ registerAspect(&benchmarkSamples);
+ benchmarkSamples.setSettingsKey("BenchSamples");
+ benchmarkSamples.setRange(1, 999999);
+ benchmarkSamples.setDefaultValue(100);
+ benchmarkSamples.setEnabler(&samplesChecked);
+
+ registerAspect(&benchmarkResamples);
+ benchmarkResamples.setSettingsKey("BenchResamples");
+ benchmarkResamples.setRange(1, 9999999);
+ benchmarkResamples.setDefaultValue(100000);
+ benchmarkResamples.setToolTip(tr("Number of resamples for bootstrapping."));
+ benchmarkResamples.setEnabler(&resamplesChecked);
+
+ registerAspect(&confidenceInterval);
+ confidenceInterval.setSettingsKey("BenchConfInt");
+ confidenceInterval.setRange(0., 1.);
+ confidenceInterval.setSingleStep(0.05);
+ confidenceInterval.setDefaultValue(0.95);
+ confidenceInterval.setEnabler(&confidenceIntervalChecked);
+
+ registerAspect(&benchmarkWarmupTime);
+ benchmarkWarmupTime.setSettingsKey("BenchWarmup");
+ benchmarkWarmupTime.setSuffix(tr(" ms"));
+ benchmarkWarmupTime.setRange(0, 10000);
+ benchmarkWarmupTime.setEnabler(&warmupChecked);
+
+ registerAspect(&abortAfterChecked);
+ abortAfterChecked.setSettingsKey("AbortChecked");
+ abortAfterChecked.setLabelText(tr("Abort after"));
+ abortAfterChecked.setToolTip(tr("Aborts after the specified number of failures."));
+
+ registerAspect(&samplesChecked);
+ samplesChecked.setSettingsKey("SamplesChecked");
+ samplesChecked.setLabelText(tr("Benchmark samples"));
+ samplesChecked.setToolTip(tr("Number of samples to collect while running benchmarks."));
+
+ registerAspect(&resamplesChecked);
+ resamplesChecked.setSettingsKey("ResamplesChecked");
+ resamplesChecked.setLabelText(tr("Benchmark resamples"));
+ resamplesChecked.setToolTip(tr("Number of resamples used for statistical bootstrapping."));
+
+ registerAspect(&confidenceIntervalChecked);
+ confidenceIntervalChecked.setSettingsKey("ConfIntChecked");
+ confidenceIntervalChecked.setToolTip(tr("Confidence interval used for statistical bootstrapping."));
+ confidenceIntervalChecked.setLabelText(tr("Benchmark confidence interval"));
+
+ registerAspect(&warmupChecked);
+ warmupChecked.setSettingsKey("WarmupChecked");
+ warmupChecked.setLabelText(tr("Benchmark warmup time"));
+ warmupChecked.setToolTip(tr("Warmup time for each test."));
+
+ registerAspect(&noAnalysis);
+ noAnalysis.setSettingsKey("NoAnalysis");
+ noAnalysis.setLabelText(tr("Disable analysis"));
+ noAnalysis.setToolTip(tr("Disables statistical analysis and bootstrapping."));
+
+ registerAspect(&showSuccess);
+ showSuccess.setSettingsKey("ShowSuccess");
+ showSuccess.setLabelText(tr("Show success"));
+ showSuccess.setToolTip(tr("Show success for tests."));
+
+ registerAspect(&breakOnFailure);
+ breakOnFailure.setSettingsKey("BreakOnFailure");
+ breakOnFailure.setDefaultValue(true);
+ breakOnFailure.setLabelText(tr("Break on failure while debugging"));
+ breakOnFailure.setToolTip(tr("Turns failures into debugger breakpoints."));
+
+ registerAspect(&noThrow);
+ noThrow.setSettingsKey("NoThrow");
+ noThrow.setLabelText(tr("Skip throwing assertions"));
+ noThrow.setToolTip(tr("Skips all assertions that test for thrown exceptions."));
+
+ registerAspect(&visibleWhitespace);
+ visibleWhitespace.setSettingsKey("VisibleWS");
+ visibleWhitespace.setLabelText(tr("Visualize whitespace"));
+ visibleWhitespace.setToolTip(tr("Makes whitespace visible."));
+
+ registerAspect(&warnOnEmpty);
+ warnOnEmpty.setSettingsKey("WarnEmpty");
+ warnOnEmpty.setLabelText(tr("Warn on empty tests"));
+ warnOnEmpty.setToolTip(tr("Warns if a test section does not check any assertion."));
+
+ forEachAspect([](BaseAspect *aspect) {
+ // FIXME: Make the positioning part of the LayoutBuilder later
+ if (auto boolAspect = dynamic_cast<BoolAspect *>(aspect))
+ boolAspect->setLabelPlacement(BoolAspect::LabelPlacement::AtCheckBoxWithoutDummyLabel);
+ });
}
-void CatchTestSettings::fromTestSettings(const QSettings *s)
+CatchTestSettingsPage::CatchTestSettingsPage(CatchTestSettings *settings, Utils::Id settingsId)
{
- abortAfterChecked = s->value(abortAfterCheckedKey, false).toBool();
- abortAfter = s->value(abortAfterKey, 0).toInt();
- samplesChecked = s->value(samplesCheckedKey, false).toBool();
- benchmarkSamples = s->value(benchmarkSamplesKey, 100).toInt();
- resamplesChecked = s->value(resamplesCheckedKey, false).toBool();
- benchmarkResamples = s->value(benchmarkResamplesKey, 100000).toInt();
- confidenceIntervalChecked = s->value(confIntCheckedKey, false).toBool();
- confidenceInterval = s->value(benchmarConfidenceIntervalKey, 0.95).toDouble();
- warmupChecked = s->value(warmupCheckedKey, false).toBool();
- benchmarkWarmupTime = s->value(benchmarWarmupTimeKey, 0).toInt();
- noAnalysis = s->value(noAnalysisKey, false).toBool();
- showSuccess = s->value(showSuccessKey, false).toBool();
- breakOnFailure = s->value(breakOnFailureKey, true).toBool();
- noThrow = s->value(noThrowKey, false).toBool();
- visibleWhitespace = s->value(visibleWhitespaceKey, false).toBool();
- warnOnEmpty = s->value(warnOnEmptyKey, false).toBool();
+ setId(settingsId);
+ setCategory(Constants::AUTOTEST_SETTINGS_CATEGORY);
+ setDisplayName(QCoreApplication::translate("CatchTestFramework", "Catch Test"));
+ setSettings(settings);
+
+ setLayouter([settings](QWidget *widget) {
+ CatchTestSettings &s = *settings;
+ using namespace Layouting;
+ const Break nl;
+
+ Grid col {
+ s.showSuccess, nl,
+ s.breakOnFailure, nl,
+ s.noThrow, nl,
+ s.visibleWhitespace, nl,
+ s.abortAfterChecked, s.abortAfter, nl,
+ s.samplesChecked, s.benchmarkSamples, nl,
+ s.resamplesChecked, s.benchmarkResamples, nl,
+ s.confidenceIntervalChecked, s.confidenceInterval, nl,
+ s.warmupChecked, s.benchmarkWarmupTime, nl,
+ s.noAnalysis
+ };
+
+ Column { Row { col, Stretch() }, Stretch() }.attachTo(widget);
+ });
}
} // namespace Internal
diff --git a/src/plugins/autotest/catch/catchtestsettings.h b/src/plugins/autotest/catch/catchtestsettings.h
index 0706611cd0..79498edd7a 100644
--- a/src/plugins/autotest/catch/catchtestsettings.h
+++ b/src/plugins/autotest/catch/catchtestsettings.h
@@ -25,37 +25,42 @@
#pragma once
-#include "../itestsettings.h"
+#include <coreplugin/dialogs/ioptionspage.h>
+
+#include <utils/aspects.h>
namespace Autotest {
namespace Internal {
-class CatchTestSettings : public ITestSettings
+class CatchTestSettings : public Utils::AspectContainer
+{
+ Q_DECLARE_TR_FUNCTIONS(Autotest::Internal::CatchTestSettings)
+
+public:
+ CatchTestSettings();
+
+ Utils::IntegerAspect abortAfter;
+ Utils::IntegerAspect benchmarkSamples;
+ Utils::IntegerAspect benchmarkResamples;
+ Utils::DoubleAspect confidenceInterval;
+ Utils::IntegerAspect benchmarkWarmupTime;
+ Utils::BoolAspect abortAfterChecked;
+ Utils::BoolAspect samplesChecked;
+ Utils::BoolAspect resamplesChecked;
+ Utils::BoolAspect confidenceIntervalChecked;
+ Utils::BoolAspect warmupChecked;
+ Utils::BoolAspect noAnalysis;
+ Utils::BoolAspect showSuccess;
+ Utils::BoolAspect breakOnFailure;
+ Utils::BoolAspect noThrow;
+ Utils::BoolAspect visibleWhitespace;
+ Utils::BoolAspect warnOnEmpty;
+};
+
+class CatchTestSettingsPage : public Core::IOptionsPage
{
public:
- CatchTestSettings() = default;
- QString name() const override;
-
- int abortAfter = 0;
- int benchmarkSamples = 0;
- int benchmarkResamples = 0;
- double confidenceInterval = 0;
- int benchmarkWarmupTime = 0;
- bool abortAfterChecked = false;
- bool samplesChecked = false;
- bool resamplesChecked = false;
- bool confidenceIntervalChecked = false;
- bool warmupChecked = false;
- bool noAnalysis = false;
- bool showSuccess = false;
- bool breakOnFailure = true;
- bool noThrow = false;
- bool visibleWhitespace = false;
- bool warnOnEmpty = false;
-
-protected:
- void toTestSettings(QSettings *s) const override;
- void fromTestSettings(const QSettings *s) override;
+ CatchTestSettingsPage(CatchTestSettings *settings, Utils::Id settingsId);
};
} // namespace Internal
diff --git a/src/plugins/autotest/catch/catchtestsettingspage.cpp b/src/plugins/autotest/catch/catchtestsettingspage.cpp
deleted file mode 100644
index 0bb597b8b0..0000000000
--- a/src/plugins/autotest/catch/catchtestsettingspage.cpp
+++ /dev/null
@@ -1,113 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2020 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of Qt Creator.
-**
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 3 as published by the Free Software
-** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-3.0.html.
-**
-****************************************************************************/
-
-#include "catchtestsettingspage.h"
-#include "catchtestsettings.h"
-#include "ui_catchtestsettingspage.h"
-#include "../autotestconstants.h"
-
-#include <coreplugin/icore.h>
-
-namespace Autotest {
-namespace Internal {
-
-class CatchTestSettingsWidget final : public Core::IOptionsPageWidget
-{
- Q_DECLARE_TR_FUNCTIONS(Autotest::Internal::CatchTestSettingsWidget)
-public:
- explicit CatchTestSettingsWidget(CatchTestSettings *settings);
- void apply() override;
-private:
- Ui::CatchTestSettingsPage m_ui;
- CatchTestSettings *m_settings;
-};
-
-CatchTestSettingsWidget::CatchTestSettingsWidget(CatchTestSettings *settings)
- : m_settings(settings)
-{
- m_ui.setupUi(this);
-
- m_ui.abortSB->setEnabled(m_settings->abortAfterChecked);
- m_ui.samplesSB->setEnabled(m_settings->samplesChecked),
- m_ui.resamplesSB->setEnabled(m_settings->resamplesChecked);
- m_ui.confIntSB->setEnabled(m_settings->confidenceIntervalChecked);
- m_ui.warmupSB->setEnabled(m_settings->warmupChecked);
-
- connect(m_ui.abortCB, &QCheckBox::toggled, m_ui.abortSB, &QSpinBox::setEnabled);
- connect(m_ui.samplesCB, &QCheckBox::toggled, m_ui.samplesSB, &QSpinBox::setEnabled);
- connect(m_ui.resamplesCB, &QCheckBox::toggled, m_ui.resamplesSB, &QSpinBox::setEnabled);
- connect(m_ui.confIntCB, &QCheckBox::toggled, m_ui.confIntSB, &QDoubleSpinBox::setEnabled);
- connect(m_ui.warmupCB, &QCheckBox::toggled, m_ui.warmupSB, &QSpinBox::setEnabled);
-
- m_ui.showSuccessCB->setChecked(m_settings->showSuccess);
- m_ui.breakOnFailCB->setChecked(m_settings->breakOnFailure);
- m_ui.noThrowCB->setChecked(m_settings->noThrow);
- m_ui.visibleWhiteCB->setChecked(m_settings->visibleWhitespace);
- m_ui.warnOnEmpty->setChecked(m_settings->warnOnEmpty);
- m_ui.noAnalysisCB->setChecked(m_settings->noAnalysis);
- m_ui.abortCB->setChecked(m_settings->abortAfterChecked);
- m_ui.abortSB->setValue(m_settings->abortAfter);
- m_ui.samplesCB->setChecked(m_settings->samplesChecked);
- m_ui.samplesSB->setValue(m_settings->benchmarkSamples);
- m_ui.resamplesCB->setChecked(m_settings->resamplesChecked);
- m_ui.resamplesSB->setValue(m_settings->benchmarkResamples);
- m_ui.confIntCB->setChecked(m_settings->confidenceIntervalChecked);
- m_ui.confIntSB->setValue(m_settings->confidenceInterval);
- m_ui.warmupCB->setChecked(m_settings->warmupChecked);
- m_ui.warmupSB->setValue(m_settings->benchmarkWarmupTime);
-}
-
-void CatchTestSettingsWidget::apply()
-{
- m_settings->showSuccess = m_ui.showSuccessCB->isChecked();
- m_settings->breakOnFailure = m_ui.breakOnFailCB->isChecked();
- m_settings->noThrow = m_ui.noThrowCB->isChecked();
- m_settings->visibleWhitespace = m_ui.visibleWhiteCB->isChecked();
- m_settings->warnOnEmpty = m_ui.warnOnEmpty->isChecked();
- m_settings->noAnalysis = m_ui.noAnalysisCB->isChecked();
- m_settings->abortAfterChecked = m_ui.abortCB->isChecked();
- m_settings->abortAfter = m_ui.abortSB->value();
- m_settings->samplesChecked = m_ui.samplesCB->isChecked();
- m_settings->benchmarkSamples = m_ui.samplesSB->value();
- m_settings->resamplesChecked = m_ui.resamplesCB->isChecked();
- m_settings->benchmarkResamples = m_ui.resamplesSB->value();
- m_settings->confidenceIntervalChecked = m_ui.confIntCB->isChecked();
- m_settings->confidenceInterval = m_ui.confIntSB->value();
- m_settings->warmupChecked = m_ui.warmupCB->isChecked();
- m_settings->benchmarkWarmupTime = m_ui.warmupSB->value();
-
- m_settings->toSettings(Core::ICore::settings());
-}
-
-CatchTestSettingsPage::CatchTestSettingsPage(CatchTestSettings *settings, Utils::Id settingsId)
-{
- setId(settingsId);
- setCategory(Constants::AUTOTEST_SETTINGS_CATEGORY);
- setDisplayName(QCoreApplication::translate("CatchTestFramework", "Catch Test"));
- setWidgetCreator([settings] { return new CatchTestSettingsWidget(settings); });
-}
-
-} // namespace Internal
-} // namespace Autotest
diff --git a/src/plugins/autotest/catch/catchtestsettingspage.ui b/src/plugins/autotest/catch/catchtestsettingspage.ui
deleted file mode 100644
index aaa3ea26dd..0000000000
--- a/src/plugins/autotest/catch/catchtestsettingspage.ui
+++ /dev/null
@@ -1,306 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<ui version="4.0">
- <class>CatchTestSettingsPage</class>
- <widget class="QWidget" name="CatchTestSettingsPage">
- <property name="geometry">
- <rect>
- <x>0</x>
- <y>0</y>
- <width>314</width>
- <height>323</height>
- </rect>
- </property>
- <layout class="QVBoxLayout" name="verticalLayout_2">
- <item>
- <layout class="QHBoxLayout" name="horizontalLayout_2">
- <item>
- <layout class="QVBoxLayout" name="verticalLayout">
- <item>
- <widget class="QCheckBox" name="showSuccessCB">
- <property name="toolTip">
- <string>Show success for tests.</string>
- </property>
- <property name="text">
- <string>Show success</string>
- </property>
- </widget>
- </item>
- <item>
- <widget class="QCheckBox" name="breakOnFailCB">
- <property name="toolTip">
- <string>Turns failures into debugger breakpoints.</string>
- </property>
- <property name="text">
- <string>Break on failure while debugging</string>
- </property>
- <property name="checked">
- <bool>true</bool>
- </property>
- </widget>
- </item>
- <item>
- <widget class="QCheckBox" name="noThrowCB">
- <property name="toolTip">
- <string>Skips all assertions that test for thrown exceptions.</string>
- </property>
- <property name="text">
- <string>Skip throwing assertions</string>
- </property>
- </widget>
- </item>
- <item>
- <widget class="QCheckBox" name="visibleWhiteCB">
- <property name="toolTip">
- <string>Makes whitespace visible.</string>
- </property>
- <property name="text">
- <string>Visualize whitespace</string>
- </property>
- </widget>
- </item>
- <item>
- <widget class="QCheckBox" name="warnOnEmpty">
- <property name="toolTip">
- <string>Warns if a test section does not check any assertion.</string>
- </property>
- <property name="text">
- <string>Warn on empty tests</string>
- </property>
- </widget>
- </item>
- <item>
- <layout class="QHBoxLayout" name="abortHL">
- <item>
- <widget class="QCheckBox" name="abortCB">
- <property name="toolTip">
- <string>Aborts after the specified number of failures.</string>
- </property>
- <property name="text">
- <string>Abort after</string>
- </property>
- </widget>
- </item>
- <item>
- <spacer name="horizontalSpacer">
- <property name="orientation">
- <enum>Qt::Horizontal</enum>
- </property>
- <property name="sizeHint" stdset="0">
- <size>
- <width>40</width>
- <height>20</height>
- </size>
- </property>
- </spacer>
- </item>
- <item>
- <widget class="QSpinBox" name="abortSB">
- <property name="minimum">
- <number>1</number>
- </property>
- <property name="maximum">
- <number>9999</number>
- </property>
- </widget>
- </item>
- </layout>
- </item>
- <item>
- <layout class="QHBoxLayout" name="samplesHL">
- <item>
- <widget class="QCheckBox" name="samplesCB">
- <property name="toolTip">
- <string>Number of samples to collect while running benchmarks.</string>
- </property>
- <property name="text">
- <string>Benchmark samples</string>
- </property>
- </widget>
- </item>
- <item>
- <spacer name="horizontalSpacer_2">
- <property name="orientation">
- <enum>Qt::Horizontal</enum>
- </property>
- <property name="sizeHint" stdset="0">
- <size>
- <width>40</width>
- <height>20</height>
- </size>
- </property>
- </spacer>
- </item>
- <item>
- <widget class="QSpinBox" name="samplesSB">
- <property name="maximum">
- <number>999999</number>
- </property>
- <property name="value">
- <number>100</number>
- </property>
- </widget>
- </item>
- </layout>
- </item>
- <item>
- <layout class="QHBoxLayout" name="resamplesHL">
- <item>
- <widget class="QCheckBox" name="resamplesCB">
- <property name="toolTip">
- <string>Number of resamples used for statistical bootstrapping.</string>
- </property>
- <property name="text">
- <string>Benchmark resamples</string>
- </property>
- </widget>
- </item>
- <item>
- <spacer name="horizontalSpacer_3">
- <property name="orientation">
- <enum>Qt::Horizontal</enum>
- </property>
- <property name="sizeHint" stdset="0">
- <size>
- <width>40</width>
- <height>20</height>
- </size>
- </property>
- </spacer>
- </item>
- <item>
- <widget class="QSpinBox" name="resamplesSB">
- <property name="toolTip">
- <string>Number of resamples for bootstrapping.</string>
- </property>
- <property name="maximum">
- <number>9999999</number>
- </property>
- <property name="value">
- <number>100000</number>
- </property>
- </widget>
- </item>
- </layout>
- </item>
- <item>
- <layout class="QHBoxLayout" name="confIntHL">
- <item>
- <widget class="QCheckBox" name="confIntCB">
- <property name="toolTip">
- <string>Confidence interval used for statistical bootstrapping.</string>
- </property>
- <property name="text">
- <string>Benchmark confidence interval</string>
- </property>
- </widget>
- </item>
- <item>
- <spacer name="horizontalSpacer_4">
- <property name="orientation">
- <enum>Qt::Horizontal</enum>
- </property>
- <property name="sizeHint" stdset="0">
- <size>
- <width>40</width>
- <height>20</height>
- </size>
- </property>
- </spacer>
- </item>
- <item>
- <widget class="QDoubleSpinBox" name="confIntSB">
- <property name="maximum">
- <double>1.000000000000000</double>
- </property>
- <property name="singleStep">
- <double>0.050000000000000</double>
- </property>
- <property name="value">
- <double>0.950000000000000</double>
- </property>
- </widget>
- </item>
- </layout>
- </item>
- <item>
- <layout class="QHBoxLayout" name="warmupHL">
- <item>
- <widget class="QCheckBox" name="warmupCB">
- <property name="toolTip">
- <string>Warmup time for each test.</string>
- </property>
- <property name="text">
- <string>Benchmark warmup time</string>
- </property>
- </widget>
- </item>
- <item>
- <spacer name="horizontalSpacer_5">
- <property name="orientation">
- <enum>Qt::Horizontal</enum>
- </property>
- <property name="sizeHint" stdset="0">
- <size>
- <width>40</width>
- <height>20</height>
- </size>
- </property>
- </spacer>
- </item>
- <item>
- <widget class="QSpinBox" name="warmupSB">
- <property name="suffix">
- <string> ms</string>
- </property>
- <property name="maximum">
- <number>10000</number>
- </property>
- </widget>
- </item>
- </layout>
- </item>
- <item>
- <widget class="QCheckBox" name="noAnalysisCB">
- <property name="toolTip">
- <string>Disables statistical analysis and bootstrapping.</string>
- </property>
- <property name="text">
- <string>Disable analysis</string>
- </property>
- </widget>
- </item>
- </layout>
- </item>
- <item>
- <spacer name="horizontalSpacer_6">
- <property name="orientation">
- <enum>Qt::Horizontal</enum>
- </property>
- <property name="sizeHint" stdset="0">
- <size>
- <width>20</width>
- <height>20</height>
- </size>
- </property>
- </spacer>
- </item>
- </layout>
- </item>
- <item>
- <spacer name="verticalSpacer">
- <property name="orientation">
- <enum>Qt::Vertical</enum>
- </property>
- <property name="sizeHint" stdset="0">
- <size>
- <width>20</width>
- <height>20</height>
- </size>
- </property>
- </spacer>
- </item>
- </layout>
- </widget>
- <resources/>
- <connections/>
-</ui>
diff --git a/src/plugins/autotest/catch/catchtreeitem.cpp b/src/plugins/autotest/catch/catchtreeitem.cpp
index e0fbb145a9..96ee881653 100644
--- a/src/plugins/autotest/catch/catchtreeitem.cpp
+++ b/src/plugins/autotest/catch/catchtreeitem.cpp
@@ -27,6 +27,7 @@
#include "catchconfiguration.h"
#include "catchframework.h"
+#include <cpptools/cppmodelmanager.h>
#include <projectexplorer/project.h>
#include <projectexplorer/session.h>
#include <utils/qtcassert.h>
@@ -48,7 +49,7 @@ static QString nonRootDisplayName(const CatchTreeItem *it)
return it->name();
TestTreeItem *parent = it->parentItem();
int baseDirSize = (parent->type() == TestTreeItem::GroupNode)
- ? parent->filePath().size() : project->projectDirectory().toString().size();
+ ? parent->filePath().toString().size() : project->projectDirectory().toString().size();
return it->name().mid(baseDirSize + 1);
}
@@ -87,7 +88,7 @@ TestTreeItem *CatchTreeItem::find(const TestParseResult *result)
switch (type()) {
case Root:
if (result->framework->grouping()) {
- const QString path = QFileInfo(result->fileName).absolutePath();
+ const Utils::FilePath path = result->fileName.absolutePath();
for (int row = 0; row < childCount(); ++row) {
TestTreeItem *group = childItem(row);
if (group->filePath() != path)
@@ -138,9 +139,8 @@ bool CatchTreeItem::modify(const TestParseResult *result)
TestTreeItem *CatchTreeItem::createParentGroupNode() const
{
- const QFileInfo fileInfo(filePath());
- const QFileInfo base(fileInfo.absolutePath());
- return new CatchTreeItem(framework(), base.baseName(), fileInfo.absolutePath(), TestTreeItem::GroupNode);
+ const QFileInfo base(filePath().toFileInfo().absolutePath());
+ return new CatchTreeItem(framework(), base.baseName(), filePath(), TestTreeItem::GroupNode);
}
bool CatchTreeItem::canProvideTestConfiguration() const
@@ -157,6 +157,8 @@ ITestConfiguration *CatchTreeItem::testConfiguration() const
{
ProjectExplorer::Project *project = ProjectExplorer::SessionManager::startupProject();
QTC_ASSERT(project, return nullptr);
+ const auto cppMM = CppTools::CppModelManager::instance();
+ QTC_ASSERT(cppMM, return nullptr);
if (type() != TestCase)
return nullptr;
@@ -167,7 +169,7 @@ ITestConfiguration *CatchTreeItem::testConfiguration() const
config->setProjectFile(proFile());
config->setProject(project);
config->setTestCases(QStringList(testCasesString()));
- config->setInternalTargets(internalTargets());
+ config->setInternalTargets(cppMM->internalTargets(filePath()));
return config;
}
@@ -186,10 +188,12 @@ struct CatchTestCases
};
static void collectTestInfo(const TestTreeItem *item,
- QHash<QString, CatchTestCases> &testCasesForProfile,
+ QHash<Utils::FilePath, CatchTestCases> &testCasesForProfile,
bool ignoreCheckState)
{
QTC_ASSERT(item, return);
+ const auto cppMM = CppTools::CppModelManager::instance();
+ QTC_ASSERT(cppMM, return);
const int childCount = item->childCount();
if (item->type() == TestTreeItem::GroupNode) {
item->forFirstLevelChildItems([&testCasesForProfile, ignoreCheckState](TestTreeItem *it) {
@@ -201,20 +205,20 @@ static void collectTestInfo(const TestTreeItem *item,
QTC_ASSERT(childCount != 0, return);
QTC_ASSERT(item->type() == TestTreeItem::TestSuite, return);
if (ignoreCheckState || item->checked() == Qt::Checked) {
- const QString &projectFile = item->childItem(0)->proFile();
+ const Utils::FilePath &projectFile = item->childItem(0)->proFile();
item->forAllChildItems([&testCasesForProfile, &projectFile](TestTreeItem *it) {
CatchTreeItem *current = static_cast<CatchTreeItem *>(it);
testCasesForProfile[projectFile].names.append(current->testCasesString());
});
- testCasesForProfile[projectFile].internalTargets.unite(item->internalTargets());
+ testCasesForProfile[projectFile].internalTargets.unite(cppMM->internalTargets(item->filePath()));
} else if (item->checked() == Qt::PartiallyChecked) {
- item->forFirstLevelChildItems([&testCasesForProfile](TestTreeItem *child) {
+ item->forFirstLevelChildItems([&testCasesForProfile, cppMM](TestTreeItem *child) {
QTC_ASSERT(child->type() == TestTreeItem::TestCase, return);
if (child->checked() == Qt::Checked) {
CatchTreeItem *current = static_cast<CatchTreeItem *>(child);
testCasesForProfile[child->proFile()].names.append(current->testCasesString());
testCasesForProfile[child->proFile()].internalTargets.unite(
- child->internalTargets());
+ cppMM->internalTargets(child->filePath()));
}
});
@@ -222,7 +226,7 @@ static void collectTestInfo(const TestTreeItem *item,
}
static void collectFailedTestInfo(const CatchTreeItem *item,
- QHash<QString, CatchTestCases> &testCasesForProfile)
+ QHash<Utils::FilePath, CatchTestCases> &testCasesForProfile)
{
QTC_ASSERT(item, return);
QTC_ASSERT(item->type() == TestTreeItem::Root, return);
@@ -230,11 +234,13 @@ static void collectFailedTestInfo(const CatchTreeItem *item,
item->forAllChildItems([&testCasesForProfile](TestTreeItem *it) {
QTC_ASSERT(it, return);
QTC_ASSERT(it->parentItem(), return);
+ const auto cppMM = CppTools::CppModelManager::instance();
+ QTC_ASSERT(cppMM, return);
if (it->type() == TestTreeItem::TestCase && it->data(0, FailedRole).toBool()) {
CatchTreeItem *current = static_cast<CatchTreeItem *>(it);
testCasesForProfile[it->proFile()].names.append(current->testCasesString());
testCasesForProfile[it->proFile()].internalTargets.unite(
- it->internalTargets());
+ cppMM->internalTargets(it->filePath()));
}
});
}
@@ -256,7 +262,7 @@ QList<ITestConfiguration *> CatchTreeItem::getFailedTestConfigurations() const
if (!project || type() != Root)
return result;
- QHash<QString, CatchTestCases> testCasesForProFile;
+ QHash<Utils::FilePath, CatchTestCases> testCasesForProFile;
collectFailedTestInfo(this, testCasesForProFile);
for (auto it = testCasesForProFile.begin(), end = testCasesForProFile.end(); it != end; ++it) {
@@ -276,6 +282,9 @@ QList<ITestConfiguration *> CatchTreeItem::getFailedTestConfigurations() const
QList<ITestConfiguration *> CatchTreeItem::getTestConfigurationsForFile(const Utils::FilePath &fileName) const
{
QList<ITestConfiguration *> result;
+ const auto cppMM = CppTools::CppModelManager::instance();
+ QTC_ASSERT(cppMM, return result);
+
ProjectExplorer::Project *project = ProjectExplorer::SessionManager::startupProject();
if (!project || type() != Root)
return result;
@@ -300,7 +309,7 @@ QList<ITestConfiguration *> CatchTreeItem::getTestConfigurationsForFile(const Ut
testConfig->setTestCases(testCases);
testConfig->setProjectFile(item->proFile());
testConfig->setProject(ProjectExplorer::SessionManager::startupProject());
- testConfig->setInternalTargets(item->internalTargets());
+ testConfig->setInternalTargets(cppMM->internalTargets(item->filePath()));
result << testConfig;
}
@@ -324,7 +333,7 @@ QList<ITestConfiguration *> CatchTreeItem::getTestConfigurations(bool ignoreChec
if (!project || type() != Root)
return result;
- QHash<QString, CatchTestCases> testCasesForProfile;
+ QHash<Utils::FilePath, CatchTestCases> testCasesForProfile;
for (int row = 0, end = childCount(); row < end; ++row)
collectTestInfo(childItem(row), testCasesForProfile, ignoreCheckState);
diff --git a/src/plugins/autotest/catch/catchtreeitem.h b/src/plugins/autotest/catch/catchtreeitem.h
index 72256cdb13..c79e9aa640 100644
--- a/src/plugins/autotest/catch/catchtreeitem.h
+++ b/src/plugins/autotest/catch/catchtreeitem.h
@@ -42,7 +42,7 @@ public:
Q_DECLARE_FLAGS(TestStates, TestState)
explicit CatchTreeItem(ITestFramework *testFramework, const QString &name = QString(),
- const QString &filePath = QString(), Type type = Root)
+ const Utils::FilePath &filePath = Utils::FilePath(), Type type = Root)
: TestTreeItem(testFramework, name, filePath, type) {}
void setStates(CatchTreeItem::TestStates state) { m_state = state; }
diff --git a/src/plugins/autotest/ctest/ctestoutputreader.cpp b/src/plugins/autotest/ctest/ctestoutputreader.cpp
index 8722e2d9a6..be20942da5 100644
--- a/src/plugins/autotest/ctest/ctestoutputreader.cpp
+++ b/src/plugins/autotest/ctest/ctestoutputreader.cpp
@@ -71,7 +71,8 @@ private:
};
CTestOutputReader::CTestOutputReader(const QFutureInterface<TestResultPtr> &futureInterface,
- QProcess *testApplication, const QString &buildDirectory)
+ QProcess *testApplication,
+ const Utils::FilePath &buildDirectory)
: TestOutputReader(futureInterface, testApplication, buildDirectory)
{
}
diff --git a/src/plugins/autotest/ctest/ctestoutputreader.h b/src/plugins/autotest/ctest/ctestoutputreader.h
index da93a71183..b5baaaf96c 100644
--- a/src/plugins/autotest/ctest/ctestoutputreader.h
+++ b/src/plugins/autotest/ctest/ctestoutputreader.h
@@ -36,7 +36,7 @@ class CTestOutputReader final : public Autotest::TestOutputReader
Q_DECLARE_TR_FUNCTIONS(Autotest::Internal::CTestOutputReader)
public:
CTestOutputReader(const QFutureInterface<TestResultPtr> &futureInterface,
- QProcess *testApplication, const QString &buildDirectory);
+ QProcess *testApplication, const Utils::FilePath &buildDirectory);
protected:
void processOutputLine(const QByteArray &outputLineWithNewLine) final;
diff --git a/src/plugins/autotest/ctest/ctesttool.cpp b/src/plugins/autotest/ctest/ctesttool.cpp
index c4388f1dac..4db818581e 100644
--- a/src/plugins/autotest/ctest/ctesttool.cpp
+++ b/src/plugins/autotest/ctest/ctesttool.cpp
@@ -40,8 +40,7 @@ Utils::Id CTestTool::buildSystemId() const
ITestTreeItem *CTestTool::createItemFromTestCaseInfo(const ProjectExplorer::TestCaseInfo &tci)
{
- CTestTreeItem *item = new CTestTreeItem(this, tci.name, tci.path.toString(),
- TestTreeItem::TestCase);
+ CTestTreeItem *item = new CTestTreeItem(this, tci.name, tci.path, TestTreeItem::TestCase);
item->setLine(tci.line);
return item;
}
@@ -55,7 +54,7 @@ ITestTreeItem *CTestTool::createRootNode()
{
return new CTestTreeItem(this,
QCoreApplication::translate("CTestTool", "CTest"),
- QString(), ITestTreeItem::Root);
+ Utils::FilePath(), ITestTreeItem::Root);
}
} // namespace Internal
diff --git a/src/plugins/autotest/ctest/ctesttreeitem.cpp b/src/plugins/autotest/ctest/ctesttreeitem.cpp
index d2ebdcc709..085ecb6500 100644
--- a/src/plugins/autotest/ctest/ctesttreeitem.cpp
+++ b/src/plugins/autotest/ctest/ctesttreeitem.cpp
@@ -43,7 +43,7 @@ namespace Autotest {
namespace Internal {
CTestTreeItem::CTestTreeItem(ITestBase *testBase, const QString &name,
- const QString &filepath, Type type)
+ const Utils::FilePath &filepath, Type type)
: ITestTreeItem(testBase, name, filepath, type)
{
}
diff --git a/src/plugins/autotest/ctest/ctesttreeitem.h b/src/plugins/autotest/ctest/ctesttreeitem.h
index f63dabaa8e..424872e7cd 100644
--- a/src/plugins/autotest/ctest/ctesttreeitem.h
+++ b/src/plugins/autotest/ctest/ctesttreeitem.h
@@ -33,7 +33,7 @@ namespace Internal {
class CTestTreeItem final : public Autotest::ITestTreeItem
{
public:
- CTestTreeItem(ITestBase *testBase, const QString &name, const QString &filepath, Type type);
+ CTestTreeItem(ITestBase *testBase, const QString &name, const Utils::FilePath &filepath, Type type);
QList<ITestConfiguration *> getAllTestConfigurations() const final;
QList<ITestConfiguration *> getSelectedTestConfigurations() const final;
diff --git a/src/plugins/autotest/gtest/gtestconfiguration.cpp b/src/plugins/autotest/gtest/gtestconfiguration.cpp
index b4fdde3f9b..4556aceb0d 100644
--- a/src/plugins/autotest/gtest/gtestconfiguration.cpp
+++ b/src/plugins/autotest/gtest/gtestconfiguration.cpp
@@ -84,21 +84,21 @@ QStringList GTestConfiguration::argumentsForTestRunner(QStringList *omitted) con
if (!testSets.isEmpty())
arguments << "--gtest_filter=" + testSets.join(':');
- auto gSettings = dynamic_cast<GTestSettings *>(framework()->testSettings());
+ auto gSettings = static_cast<GTestSettings *>(framework()->testSettings());
if (!gSettings)
return arguments;
- if (gSettings->runDisabled)
+ if (gSettings->runDisabled.value())
arguments << "--gtest_also_run_disabled_tests";
- if (gSettings->repeat)
- arguments << QString("--gtest_repeat=%1").arg(gSettings->iterations);
- if (gSettings->shuffle)
- arguments << "--gtest_shuffle" << QString("--gtest_random_seed=%1").arg(gSettings->seed);
- if (gSettings->throwOnFailure)
+ if (gSettings->repeat.value())
+ arguments << QString("--gtest_repeat=%1").arg(gSettings->iterations.value());
+ if (gSettings->shuffle.value())
+ arguments << "--gtest_shuffle" << QString("--gtest_random_seed=%1").arg(gSettings->seed.value());
+ if (gSettings->throwOnFailure.value())
arguments << "--gtest_throw_on_failure";
if (isDebugRunMode()) {
- if (gSettings->breakOnFailure)
+ if (gSettings->breakOnFailure.value())
arguments << "--gtest_break_on_failure";
}
return arguments;
diff --git a/src/plugins/autotest/gtest/gtestframework.cpp b/src/plugins/autotest/gtest/gtestframework.cpp
index 9480ee5732..b093417324 100644
--- a/src/plugins/autotest/gtest/gtestframework.cpp
+++ b/src/plugins/autotest/gtest/gtestframework.cpp
@@ -50,7 +50,7 @@ ITestTreeItem *GTestFramework::createRootNode()
this,
QCoreApplication::translate("GTestFramework",
GTest::Constants::FRAMEWORK_SETTINGS_CATEGORY),
- QString(), ITestTreeItem::Root);
+ Utils::FilePath(), ITestTreeItem::Root);
}
const char *GTestFramework::name() const
@@ -65,7 +65,7 @@ unsigned GTestFramework::priority() const
QString GTestFramework::currentGTestFilter()
{
- return g_settings->gtestFilter;
+ return g_settings->gtestFilter.value();
}
QString GTestFramework::groupingToolTip() const
@@ -77,7 +77,7 @@ QString GTestFramework::groupingToolTip() const
GTest::Constants::GroupMode GTestFramework::groupMode()
{
- return g_settings->groupMode;
+ return GTest::Constants::GroupMode(g_settings->groupMode.itemValue().toInt());
}
} // namespace Internal
diff --git a/src/plugins/autotest/gtest/gtestframework.h b/src/plugins/autotest/gtest/gtestframework.h
index 1bdfd68241..c7504d28e3 100644
--- a/src/plugins/autotest/gtest/gtestframework.h
+++ b/src/plugins/autotest/gtest/gtestframework.h
@@ -28,7 +28,6 @@
#include "../itestframework.h"
#include "gtestconstants.h"
#include "gtestsettings.h"
-#include "gtestsettingspage.h"
namespace Autotest {
namespace Internal {
diff --git a/src/plugins/autotest/gtest/gtestoutputreader.cpp b/src/plugins/autotest/gtest/gtestoutputreader.cpp
index 77c0e825e8..4bc93690bc 100644
--- a/src/plugins/autotest/gtest/gtestoutputreader.cpp
+++ b/src/plugins/autotest/gtest/gtestoutputreader.cpp
@@ -36,14 +36,10 @@
namespace Autotest {
namespace Internal {
-static QString constructSourceFilePath(const QString &path, const QString &filePath)
-{
- return QFileInfo(path, filePath).canonicalFilePath();
-}
-
GTestOutputReader::GTestOutputReader(const QFutureInterface<TestResultPtr> &futureInterface,
- QProcess *testApplication, const QString &buildDirectory,
- const QString &projectFile)
+ QProcess *testApplication,
+ const Utils::FilePath &buildDirectory,
+ const Utils::FilePath &projectFile)
: TestOutputReader(futureInterface, testApplication, buildDirectory)
, m_projectFile(projectFile)
{
@@ -181,7 +177,7 @@ void GTestOutputReader::processOutputLine(const QByteArray &outputLine)
TestResultPtr testResult = createDefaultResult();
testResult->setResult(type);
testResult->setLine(match.captured(3).toInt());
- const QString file = constructSourceFilePath(m_buildDir, match.captured(2));
+ const Utils::FilePath file = constructSourceFilePath(m_buildDir, match.captured(2));
if (!file.isEmpty())
testResult->setFileName(file);
testResult->setDescription(match.captured(4));
@@ -246,7 +242,7 @@ void GTestOutputReader::handleDescriptionAndReportResult(TestResultPtr testResul
testResult = createDefaultResult();
testResult->setResult(ResultType::MessageLocation);
testResult->setLine(innerMatch.captured(2).toInt());
- QString file = constructSourceFilePath(m_buildDir, innerMatch.captured(1));
+ const Utils::FilePath file = constructSourceFilePath(m_buildDir, innerMatch.captured(1));
if (!file.isEmpty())
testResult->setFileName(file);
resultDescription << output;
diff --git a/src/plugins/autotest/gtest/gtestoutputreader.h b/src/plugins/autotest/gtest/gtestoutputreader.h
index 9bed450971..05688a4fa2 100644
--- a/src/plugins/autotest/gtest/gtestoutputreader.h
+++ b/src/plugins/autotest/gtest/gtestoutputreader.h
@@ -38,8 +38,8 @@ class GTestOutputReader : public TestOutputReader
public:
GTestOutputReader(const QFutureInterface<TestResultPtr> &futureInterface,
- QProcess *testApplication, const QString &buildDirectory,
- const QString &projectFile);
+ QProcess *testApplication, const Utils::FilePath &buildDirectory,
+ const Utils::FilePath &projectFile);
protected:
void processOutputLine(const QByteArray &outputLine) override;
void processStdError(const QByteArray &outputLine) override;
@@ -50,7 +50,7 @@ private:
void setCurrentTestSuite(const QString &testSuite);
void handleDescriptionAndReportResult(TestResultPtr testResult);
- QString m_projectFile;
+ Utils::FilePath m_projectFile;
QString m_currentTestSuite;
QString m_currentTestCase;
QString m_description;
diff --git a/src/plugins/autotest/gtest/gtestparser.cpp b/src/plugins/autotest/gtest/gtestparser.cpp
index e59251a877..4975bc66da 100644
--- a/src/plugins/autotest/gtest/gtestparser.cpp
+++ b/src/plugins/autotest/gtest/gtestparser.cpp
@@ -88,7 +88,7 @@ static bool hasGTestNames(const CPlusPlus::Document::Ptr &document)
}
bool GTestParser::processDocument(QFutureInterface<TestParseResultPtr> futureInterface,
- const QString &fileName)
+ const Utils::FilePath &fileName)
{
CPlusPlus::Document::Ptr doc = document(fileName);
if (doc.isNull() || !includesGTest(doc, m_cppSnapshot) || !hasGTestNames(doc))
@@ -96,18 +96,18 @@ bool GTestParser::processDocument(QFutureInterface<TestParseResultPtr> futureInt
const CppTools::CppModelManager *modelManager = CppTools::CppModelManager::instance();
const QString &filePath = doc->fileName();
- const QByteArray &fileContent = getFileContent(filePath);
- CPlusPlus::Document::Ptr document = m_cppSnapshot.preprocessedDocument(fileContent, filePath);
+ const QByteArray &fileContent = getFileContent(fileName);
+ CPlusPlus::Document::Ptr document = m_cppSnapshot.preprocessedDocument(fileContent, fileName);
document->check();
CPlusPlus::AST *ast = document->translationUnit()->ast();
GTestVisitor visitor(document);
visitor.accept(ast);
const QMap<GTestCaseSpec, GTestCodeLocationList> result = visitor.gtestFunctions();
- QString proFile;
+ Utils::FilePath proFile;
const QList<CppTools::ProjectPart::Ptr> &ppList = modelManager->projectPart(filePath);
if (!ppList.isEmpty())
- proFile = ppList.first()->projectFile;
+ proFile = Utils::FilePath::fromString(ppList.first()->projectFile);
else
return false; // happens if shutting down while parsing
@@ -115,7 +115,7 @@ bool GTestParser::processDocument(QFutureInterface<TestParseResultPtr> futureInt
const GTestCaseSpec &testSpec = it.key();
GTestParseResult *parseResult = new GTestParseResult(framework());
parseResult->itemType = TestTreeItem::TestSuite;
- parseResult->fileName = filePath;
+ parseResult->fileName = fileName;
parseResult->name = testSpec.testCaseName;
parseResult->parameterized = testSpec.parameterized;
parseResult->typed = testSpec.typed;
@@ -125,7 +125,7 @@ bool GTestParser::processDocument(QFutureInterface<TestParseResultPtr> futureInt
for (const GTestCodeLocationAndType &location : it.value()) {
GTestParseResult *testSet = new GTestParseResult(framework());
testSet->name = location.m_name;
- testSet->fileName = filePath;
+ testSet->fileName = fileName;
testSet->line = location.m_line;
testSet->column = location.m_column;
testSet->disabled = location.m_state & GTestTreeItem::Disabled;
diff --git a/src/plugins/autotest/gtest/gtestparser.h b/src/plugins/autotest/gtest/gtestparser.h
index 781c9fe902..6f8f87603f 100644
--- a/src/plugins/autotest/gtest/gtestparser.h
+++ b/src/plugins/autotest/gtest/gtestparser.h
@@ -45,7 +45,7 @@ class GTestParser : public CppParser
public:
explicit GTestParser(ITestFramework *framework) : CppParser(framework) {}
bool processDocument(QFutureInterface<TestParseResultPtr> futureInterface,
- const QString &fileName) override;
+ const Utils::FilePath &fileName) override;
};
} // namespace Internal
diff --git a/src/plugins/autotest/gtest/gtestresult.cpp b/src/plugins/autotest/gtest/gtestresult.cpp
index 10a81f48db..fb3527425c 100644
--- a/src/plugins/autotest/gtest/gtestresult.cpp
+++ b/src/plugins/autotest/gtest/gtestresult.cpp
@@ -36,7 +36,7 @@
namespace Autotest {
namespace Internal {
-GTestResult::GTestResult(const QString &id, const QString &projectFile,
+GTestResult::GTestResult(const QString &id, const Utils::FilePath &projectFile,
const QString &name)
: TestResult(id, name), m_projectFile(projectFile)
{
diff --git a/src/plugins/autotest/gtest/gtestresult.h b/src/plugins/autotest/gtest/gtestresult.h
index 6fc1728629..a662134b7b 100644
--- a/src/plugins/autotest/gtest/gtestresult.h
+++ b/src/plugins/autotest/gtest/gtestresult.h
@@ -36,7 +36,7 @@ namespace Internal {
class GTestResult : public TestResult
{
public:
- GTestResult(const QString &id, const QString &projectFile, const QString &name);
+ GTestResult(const QString &id, const Utils::FilePath &projectFile, const QString &name);
const QString outputString(bool selected) const override;
void setTestCaseName(const QString &testSetName) { m_testCaseName = testSetName; }
@@ -53,7 +53,7 @@ private:
bool matchesTestSuite(const TestTreeItem *treeItem) const;
QString m_testCaseName;
- QString m_projectFile;
+ Utils::FilePath m_projectFile;
int m_iteration = 1;
};
diff --git a/src/plugins/autotest/gtest/gtestsettings.cpp b/src/plugins/autotest/gtest/gtestsettings.cpp
index c0cbba9729..e6eabe35a1 100644
--- a/src/plugins/autotest/gtest/gtestsettings.cpp
+++ b/src/plugins/autotest/gtest/gtestsettings.cpp
@@ -24,55 +24,141 @@
****************************************************************************/
#include "gtestsettings.h"
+
#include "gtest_utils.h"
+#include "gtestconstants.h"
+#include "../autotestconstants.h"
+#include "../testframeworkmanager.h"
+#include "../testtreemodel.h"
+
+#include <utils/layoutbuilder.h>
+
+using namespace Utils;
namespace Autotest {
namespace Internal {
-static const char breakOnFailureKey[] = "BreakOnFailure";
-static const char iterationsKey[] = "Iterations";
-static const char repeatKey[] = "Repeat";
-static const char runDisabledKey[] = "RunDisabled";
-static const char seedKey[] = "Seed";
-static const char shuffleKey[] = "Shuffle";
-static const char throwOnFailureKey[] = "ThrowOnFailure";
-static const char groupModeKey[] = "GroupMode";
-static const char gtestFilterKey[] = "GTestFilter";
-
-QString GTestSettings::name() const
+GTestSettings::GTestSettings()
{
- return QString("GTest");
-}
+ setSettingsGroups("Autotest", "GTest");
+ setAutoApply(false);
-void GTestSettings::fromTestSettings(const QSettings *s)
-{
- runDisabled = s->value(runDisabledKey, false).toBool();
- repeat = s->value(repeatKey, false).toBool();
- shuffle = s->value(shuffleKey, false).toBool();
- iterations = s->value(iterationsKey, 1).toInt();
- seed = s->value(seedKey, 0).toInt();
- breakOnFailure = s->value(breakOnFailureKey, true).toBool();
- throwOnFailure = s->value(throwOnFailureKey, false).toBool();
- // avoid problems if user messes around with the settings file
- bool ok = false;
- const int tmp = s->value(groupModeKey, GTest::Constants::Directory).toInt(&ok);
- groupMode = ok ? static_cast<GTest::Constants::GroupMode>(tmp) : GTest::Constants::Directory;
- gtestFilter = s->value(gtestFilterKey, GTest::Constants::DEFAULT_FILTER).toString();
- if (!GTestUtils::isValidGTestFilter(gtestFilter))
- gtestFilter = GTest::Constants::DEFAULT_FILTER;
+ registerAspect(&iterations);
+ iterations.setSettingsKey("Iterations");
+ iterations.setDefaultValue(1);
+ iterations.setEnabled(false);
+ iterations.setLabelText(tr("Iterations:"));
+ iterations.setEnabler(&repeat);
+
+ registerAspect(&seed);
+ seed.setSettingsKey("Seed");
+ seed.setSpecialValueText(QString());
+ seed.setEnabled(false);
+ seed.setLabelText(tr("Seed:"));
+ seed.setToolTip(tr("A seed of 0 generates a seed based on the current timestamp."));
+ seed.setEnabler(&shuffle);
+
+ registerAspect(&runDisabled);
+ runDisabled.setSettingsKey("RunDisabled");
+ runDisabled.setLabelText(tr("Run disabled tests"));
+ runDisabled.setToolTip(tr("Executes disabled tests when performing a test run."));
+
+ registerAspect(&shuffle);
+ shuffle.setSettingsKey("Shuffle");
+ shuffle.setLabelText(tr("Shuffle tests"));
+ shuffle.setToolTip(tr("Shuffles tests automatically on every iteration by the given seed."));
+
+ registerAspect(&repeat);
+ repeat.setSettingsKey("Repeat");
+ repeat.setLabelText(tr("Repeat tests"));
+ repeat.setToolTip(tr("Repeats a test run (you might be required to increase the timeout to avoid canceling the tests)."));
+
+ registerAspect(&throwOnFailure);
+ throwOnFailure.setSettingsKey("ThrowOnFailure");
+ throwOnFailure.setLabelText(tr("Throw on failure"));
+ throwOnFailure.setToolTip(tr("Turns assertion failures into C++ exceptions."));
+
+ registerAspect(&breakOnFailure);
+ breakOnFailure.setSettingsKey("BreakOnFailure");
+ breakOnFailure.setDefaultValue(true);
+ breakOnFailure.setLabelText(tr("Break on failure while debugging"));
+ breakOnFailure.setToolTip(tr("Turns failures into debugger breakpoints."));
+
+ registerAspect(&groupMode);
+ groupMode.setSettingsKey("GroupMode");
+ groupMode.setDisplayStyle(SelectionAspect::DisplayStyle::ComboBox);
+ groupMode.setFromSettingsTransformation([this](const QVariant &savedValue) -> QVariant {
+ // avoid problems if user messes around with the settings file
+ bool ok = false;
+ const int tmp = savedValue.toInt(&ok);
+ return ok ? groupMode.indexForItemValue(tmp) : GTest::Constants::Directory;
+ });
+ groupMode.setToSettingsTransformation([this](const QVariant &value) {
+ return groupMode.itemValueForIndex(value.toInt());
+ });
+ groupMode.addOption({tr("Directory"), {}, GTest::Constants::Directory});
+ groupMode.addOption({tr("GTest Filter"), {}, GTest::Constants::GTestFilter});
+ groupMode.setDefaultValue(GTest::Constants::Directory);
+ groupMode.setLabelText(tr("Group mode:"));
+ groupMode.setToolTip(tr("Select on what grouping the tests should be based."));
+
+ registerAspect(&gtestFilter);
+ gtestFilter.setSettingsKey("GTestFilter");
+ gtestFilter.setDisplayStyle(StringAspect::LineEditDisplay);
+ gtestFilter.setDefaultValue(GTest::Constants::DEFAULT_FILTER);
+ gtestFilter.setFromSettingsTransformation([](const QVariant &savedValue) -> QVariant {
+ // avoid problems if user messes around with the settings file
+ const QString tmp = savedValue.toString();
+ if (GTestUtils::isValidGTestFilter(tmp))
+ return tmp;
+ return GTest::Constants::DEFAULT_FILTER;
+ });
+ gtestFilter.setEnabled(false);
+ gtestFilter.setLabelText(tr("Active filter:"));
+ gtestFilter.setToolTip(tr("Set the GTest filter to be used for grouping.\n"
+ "See Google Test documentation for further information on GTest filters."));
+
+ gtestFilter.setValidationFunction([](FancyLineEdit *edit, QString * /*error*/) {
+ return edit && GTestUtils::isValidGTestFilter(edit->text());
+ });
+
+ QObject::connect(&groupMode, &SelectionAspect::volatileValueChanged,
+ &gtestFilter, [this](int val) {
+ gtestFilter.setEnabled(groupMode.itemValueForIndex(val) == GTest::Constants::GTestFilter);
+ });
}
-void GTestSettings::toTestSettings(QSettings *s) const
+GTestSettingsPage::GTestSettingsPage(GTestSettings *settings, Utils::Id settingsId)
{
- s->setValue(runDisabledKey, runDisabled);
- s->setValue(repeatKey, repeat);
- s->setValue(shuffleKey, shuffle);
- s->setValue(iterationsKey, iterations);
- s->setValue(seedKey, seed);
- s->setValue(breakOnFailureKey, breakOnFailure);
- s->setValue(throwOnFailureKey, throwOnFailure);
- s->setValue(groupModeKey, groupMode);
- s->setValue(gtestFilterKey, gtestFilter);
+ setId(settingsId);
+ setCategory(Constants::AUTOTEST_SETTINGS_CATEGORY);
+ setDisplayName(QCoreApplication::translate("GTestFramework",
+ GTest::Constants::FRAMEWORK_SETTINGS_CATEGORY));
+ setSettings(settings);
+ QObject::connect(settings, &AspectContainer::applied, this, [] {
+ Id id = Id(Constants::FRAMEWORK_PREFIX).withSuffix(GTest::Constants::FRAMEWORK_NAME);
+ TestTreeModel::instance()->rebuild({id});
+ });
+
+ setLayouter([settings](QWidget *widget) {
+ GTestSettings &s = *settings;
+ using namespace Layouting;
+ const Break nl;
+
+ Grid grid {
+ s.runDisabled, nl,
+ s.breakOnFailure, nl,
+ s.repeat, s.iterations, nl,
+ s.shuffle, s.seed
+ };
+
+ Form form {
+ s.groupMode,
+ s.gtestFilter
+ };
+
+ Column { Row { Column { grid, form, Stretch() }, Stretch() } }.attachTo(widget);
+ });
}
} // namespace Internal
diff --git a/src/plugins/autotest/gtest/gtestsettings.h b/src/plugins/autotest/gtest/gtestsettings.h
index e8b75d6331..ea9a7621f3 100644
--- a/src/plugins/autotest/gtest/gtestsettings.h
+++ b/src/plugins/autotest/gtest/gtestsettings.h
@@ -25,31 +25,39 @@
#pragma once
-#include "../itestsettings.h"
#include "gtestconstants.h"
+#include <coreplugin/dialogs/ioptionspage.h>
+
+#include <utils/aspects.h>
+
namespace Autotest {
namespace Internal {
-class GTestSettings : public ITestSettings
+class GTestSettings : public Utils::AspectContainer
{
+ Q_DECLARE_TR_FUNCTIONS(Autotest::Internal::GTestSettings)
+
+public:
+ GTestSettings();
+
+ Utils::IntegerAspect iterations;
+ Utils::IntegerAspect seed;
+ Utils::BoolAspect runDisabled;
+ Utils::BoolAspect shuffle;
+ Utils::BoolAspect repeat;
+ Utils::BoolAspect throwOnFailure;
+ Utils::BoolAspect breakOnFailure;
+ Utils::SelectionAspect groupMode;
+ Utils::StringAspect gtestFilter;
+};
+
+class GTestSettingsPage final : public Core::IOptionsPage
+{
+ Q_DECLARE_TR_FUNCTIONS(Autotest::Internal::GTestSettings)
+
public:
- GTestSettings() {}
- QString name() const override;
-
- int iterations = 1;
- int seed = 0;
- bool runDisabled = false;
- bool shuffle = false;
- bool repeat = false;
- bool throwOnFailure = false;
- bool breakOnFailure = true;
- GTest::Constants::GroupMode groupMode = GTest::Constants::Directory;
- QString gtestFilter{GTest::Constants::DEFAULT_FILTER};
-
-protected:
- void fromTestSettings(const QSettings *s) override;
- void toTestSettings(QSettings *s) const override;
+ GTestSettingsPage(GTestSettings *settings, Utils::Id settingsId);
};
} // namespace Internal
diff --git a/src/plugins/autotest/gtest/gtestsettingspage.cpp b/src/plugins/autotest/gtest/gtestsettingspage.cpp
deleted file mode 100644
index 3bd28433ad..0000000000
--- a/src/plugins/autotest/gtest/gtestsettingspage.cpp
+++ /dev/null
@@ -1,123 +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 "gtestconstants.h"
-#include "gtestsettingspage.h"
-#include "gtestsettings.h"
-#include "gtest_utils.h"
-#include "../autotestconstants.h"
-#include "../testframeworkmanager.h"
-#include "../testtreemodel.h"
-
-#include "ui_gtestsettingspage.h"
-#include <coreplugin/icore.h>
-
-namespace Autotest {
-namespace Internal {
-
-static bool validateFilter(Utils::FancyLineEdit *edit, QString * /*error*/)
-{
- return edit && GTestUtils::isValidGTestFilter(edit->text());
-}
-
-class GTestSettingsWidget final : public Core::IOptionsPageWidget
-{
- Q_DECLARE_TR_FUNCTIONS(Autotest::Internal::GTestSettingsWidget)
-
-public:
- explicit GTestSettingsWidget(GTestSettings *settings);
-
-private:
- void apply() final;
-
- Ui::GTestSettingsPage m_ui;
- QString m_currentGTestFilter;
- GTestSettings *m_settings;
-};
-
-GTestSettingsWidget::GTestSettingsWidget(GTestSettings *settings)
- : m_settings(settings)
-{
- m_ui.setupUi(this);
- m_ui.filterLineEdit->setValidationFunction(&validateFilter);
- m_ui.filterLineEdit->setEnabled(m_ui.groupModeCombo->currentIndex() == 1);
-
- connect(m_ui.groupModeCombo, &QComboBox::currentTextChanged,
- this, [this] () {
- m_ui.filterLineEdit->setEnabled(m_ui.groupModeCombo->currentIndex() == 1);
- });
- connect(m_ui.repeatGTestsCB, &QCheckBox::toggled, m_ui.repetitionSpin, &QSpinBox::setEnabled);
- connect(m_ui.shuffleGTestsCB, &QCheckBox::toggled, m_ui.seedSpin, &QSpinBox::setEnabled);
-
- m_ui.runDisabledGTestsCB->setChecked(m_settings->runDisabled);
- m_ui.repeatGTestsCB->setChecked(m_settings->repeat);
- m_ui.shuffleGTestsCB->setChecked(m_settings->shuffle);
- m_ui.repetitionSpin->setValue(m_settings->iterations);
- m_ui.seedSpin->setValue(m_settings->seed);
- m_ui.breakOnFailureCB->setChecked(m_settings->breakOnFailure);
- m_ui.throwOnFailureCB->setChecked(m_settings->throwOnFailure);
- m_ui.groupModeCombo->setCurrentIndex(m_settings->groupMode - 1); // there's None for internal use
- m_ui.filterLineEdit->setText(m_settings->gtestFilter);
- m_currentGTestFilter = m_settings->gtestFilter; // store it temporarily (if edit is invalid)
-}
-
-void GTestSettingsWidget::apply()
-{
- GTest::Constants::GroupMode oldGroupMode = m_settings->groupMode;
- const QString oldFilter = m_settings->gtestFilter;
-
- m_settings->runDisabled = m_ui.runDisabledGTestsCB->isChecked();
- m_settings->repeat = m_ui.repeatGTestsCB->isChecked();
- m_settings->shuffle = m_ui.shuffleGTestsCB->isChecked();
- m_settings->iterations = m_ui.repetitionSpin->value();
- m_settings->seed = m_ui.seedSpin->value();
- m_settings->breakOnFailure = m_ui.breakOnFailureCB->isChecked();
- m_settings->throwOnFailure = m_ui.throwOnFailureCB->isChecked();
- m_settings->groupMode = static_cast<GTest::Constants::GroupMode>(
- m_ui.groupModeCombo->currentIndex() + 1);
- if (m_ui.filterLineEdit->isValid())
- m_settings->gtestFilter = m_ui.filterLineEdit->text();
- else
- m_settings->gtestFilter = m_currentGTestFilter;
-
- m_settings->toSettings(Core::ICore::settings());
- if (m_settings->groupMode == oldGroupMode && oldFilter == m_settings->gtestFilter)
- return;
-
- auto id = Utils::Id(Constants::FRAMEWORK_PREFIX).withSuffix(GTest::Constants::FRAMEWORK_NAME);
- TestTreeModel::instance()->rebuild({id});
-}
-
-GTestSettingsPage::GTestSettingsPage(GTestSettings *settings, Utils::Id settingsId)
-{
- setId(settingsId);
- setCategory(Constants::AUTOTEST_SETTINGS_CATEGORY);
- setDisplayName(QCoreApplication::translate("GTestFramework",
- GTest::Constants::FRAMEWORK_SETTINGS_CATEGORY));
- setWidgetCreator([settings] { return new GTestSettingsWidget(settings); });
-}
-
-} // namespace Internal
-} // namespace Autotest
diff --git a/src/plugins/autotest/gtest/gtestsettingspage.ui b/src/plugins/autotest/gtest/gtestsettingspage.ui
deleted file mode 100644
index e0a13196df..0000000000
--- a/src/plugins/autotest/gtest/gtestsettingspage.ui
+++ /dev/null
@@ -1,229 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<ui version="4.0">
- <class>Autotest::Internal::GTestSettingsPage</class>
- <widget class="QWidget" name="Autotest::Internal::GTestSettingsPage">
- <property name="geometry">
- <rect>
- <x>0</x>
- <y>0</y>
- <width>449</width>
- <height>232</height>
- </rect>
- </property>
- <property name="windowTitle">
- <string/>
- </property>
- <layout class="QHBoxLayout" name="horizontalLayout">
- <item>
- <layout class="QVBoxLayout" name="verticalLayout">
- <item>
- <layout class="QGridLayout" name="gridLayout">
- <item row="1" column="0">
- <widget class="QCheckBox" name="breakOnFailureCB">
- <property name="toolTip">
- <string>Turns failures into debugger breakpoints.</string>
- </property>
- <property name="text">
- <string>Break on failure while debugging</string>
- </property>
- <property name="checked">
- <bool>true</bool>
- </property>
- </widget>
- </item>
- <item row="0" column="0">
- <widget class="QCheckBox" name="runDisabledGTestsCB">
- <property name="toolTip">
- <string>Executes disabled tests when performing a test run.</string>
- </property>
- <property name="text">
- <string>Run disabled tests</string>
- </property>
- </widget>
- </item>
- <item row="4" column="0">
- <widget class="QCheckBox" name="throwOnFailureCB">
- <property name="toolTip">
- <string>Turns assertion failures into C++ exceptions.</string>
- </property>
- <property name="text">
- <string>Throw on failure</string>
- </property>
- </widget>
- </item>
- <item row="2" column="1">
- <widget class="QLabel" name="label">
- <property name="sizePolicy">
- <sizepolicy hsizetype="Minimum" vsizetype="Fixed">
- <horstretch>0</horstretch>
- <verstretch>0</verstretch>
- </sizepolicy>
- </property>
- <property name="text">
- <string>Iterations:</string>
- </property>
- </widget>
- </item>
- <item row="3" column="0">
- <widget class="QCheckBox" name="shuffleGTestsCB">
- <property name="toolTip">
- <string>Shuffles tests automatically on every iteration by the given seed.</string>
- </property>
- <property name="text">
- <string>Shuffle tests</string>
- </property>
- </widget>
- </item>
- <item row="2" column="0">
- <widget class="QCheckBox" name="repeatGTestsCB">
- <property name="toolTip">
- <string>Repeats a test run (you might be required to increase the timeout to avoid canceling the tests).</string>
- </property>
- <property name="text">
- <string>Repeat tests</string>
- </property>
- </widget>
- </item>
- <item row="2" column="2">
- <widget class="QSpinBox" name="repetitionSpin">
- <property name="enabled">
- <bool>false</bool>
- </property>
- <property name="minimum">
- <number>1</number>
- </property>
- <property name="maximum">
- <number>9999</number>
- </property>
- </widget>
- </item>
- <item row="3" column="1">
- <widget class="QLabel" name="label_2">
- <property name="sizePolicy">
- <sizepolicy hsizetype="Minimum" vsizetype="Fixed">
- <horstretch>0</horstretch>
- <verstretch>0</verstretch>
- </sizepolicy>
- </property>
- <property name="text">
- <string>Seed:</string>
- </property>
- </widget>
- </item>
- <item row="3" column="2">
- <widget class="QSpinBox" name="seedSpin">
- <property name="enabled">
- <bool>false</bool>
- </property>
- <property name="toolTip">
- <string>A seed of 0 generates a seed based on the current timestamp.</string>
- </property>
- <property name="specialValueText">
- <string/>
- </property>
- <property name="maximum">
- <number>99999</number>
- </property>
- </widget>
- </item>
- </layout>
- </item>
- <item>
- <layout class="QGridLayout" name="gridLayout_2">
- <item row="0" column="0">
- <widget class="QLabel" name="label_3">
- <property name="text">
- <string>Group mode:</string>
- </property>
- </widget>
- </item>
- <item row="1" column="0">
- <widget class="QLabel" name="label_4">
- <property name="text">
- <string>Active filter:</string>
- </property>
- </widget>
- </item>
- <item row="0" column="2">
- <widget class="QComboBox" name="groupModeCombo">
- <property name="toolTip">
- <string>Select on what grouping the tests should be based.</string>
- </property>
- <item>
- <property name="text">
- <string>Directory</string>
- </property>
- </item>
- <item>
- <property name="text">
- <string>GTest Filter</string>
- </property>
- </item>
- </widget>
- </item>
- <item row="1" column="2">
- <widget class="Utils::FancyLineEdit" name="filterLineEdit">
- <property name="toolTip">
- <string>Set the GTest filter to be used for grouping.
-See Google Test documentation for further information on GTest filters.</string>
- </property>
- </widget>
- </item>
- <item row="1" column="1">
- <spacer name="horizontalSpacer_2">
- <property name="orientation">
- <enum>Qt::Horizontal</enum>
- </property>
- <property name="sizeType">
- <enum>QSizePolicy::Fixed</enum>
- </property>
- <property name="sizeHint" stdset="0">
- <size>
- <width>60</width>
- <height>20</height>
- </size>
- </property>
- </spacer>
- </item>
- </layout>
- </item>
- <item>
- <spacer name="verticalSpacer">
- <property name="orientation">
- <enum>Qt::Vertical</enum>
- </property>
- <property name="sizeHint" stdset="0">
- <size>
- <width>20</width>
- <height>40</height>
- </size>
- </property>
- </spacer>
- </item>
- </layout>
- </item>
- <item>
- <spacer name="horizontalSpacer">
- <property name="orientation">
- <enum>Qt::Horizontal</enum>
- </property>
- <property name="sizeHint" stdset="0">
- <size>
- <width>40</width>
- <height>20</height>
- </size>
- </property>
- </spacer>
- </item>
- </layout>
- </widget>
- <customwidgets>
- <customwidget>
- <class>Utils::FancyLineEdit</class>
- <extends>QLineEdit</extends>
- <header location="global">utils/fancylineedit.h</header>
- </customwidget>
- </customwidgets>
- <resources/>
- <connections/>
-</ui>
diff --git a/src/plugins/autotest/gtest/gtesttreeitem.cpp b/src/plugins/autotest/gtest/gtesttreeitem.cpp
index df593b1159..2d2012e35d 100644
--- a/src/plugins/autotest/gtest/gtesttreeitem.cpp
+++ b/src/plugins/autotest/gtest/gtesttreeitem.cpp
@@ -116,6 +116,8 @@ static bool matchesFilter(const QString &filter, const QString &fullTestName)
return positive.isEmpty();
}
+QSet<QString> internalTargets(const TestTreeItem &item);
+
QVariant GTestTreeItem::data(int column, int role) const
{
switch (role) {
@@ -137,7 +139,7 @@ QVariant GTestTreeItem::data(int column, int role) const
case Qt::ToolTipRole:
if (type() == GroupNode
&& GTestFramework::groupMode() == GTest::Constants::GTestFilter) {
- const auto tpl = QString("<p>%1</p><p>%2</p>").arg(filePath());
+ const auto tpl = QString("<p>%1</p><p>%2</p>").arg(filePath().toString());
return tpl.arg(QCoreApplication::translate(
"GTestTreeItem", "Change GTest filter in use inside the settings."));
}
@@ -195,7 +197,7 @@ ITestConfiguration *GTestTreeItem::testConfiguration() const
return nullptr;
}
if (config)
- config->setInternalTargets(internalTargets());
+ config->setInternalTargets(internalTargets(*this));
return config;
}
@@ -215,7 +217,7 @@ struct GTestCases
};
static void collectTestInfo(const GTestTreeItem *item,
- QHash<QString, GTestCases> &testCasesForProFile,
+ QHash<Utils::FilePath, GTestCases> &testCasesForProFile,
bool ignoreCheckState)
{
QTC_ASSERT(item, return);
@@ -230,11 +232,11 @@ static void collectTestInfo(const GTestTreeItem *item,
QTC_ASSERT(childCount != 0, return);
QTC_ASSERT(item->type() == TestTreeItem::TestSuite, return);
if (ignoreCheckState || item->checked() == Qt::Checked) {
- const QString &projectFile = item->childItem(0)->proFile();
+ const Utils::FilePath &projectFile = item->childItem(0)->proFile();
testCasesForProFile[projectFile].filters.append(
gtestFilter(item->state()).arg(item->name()).arg('*'));
testCasesForProFile[projectFile].testSetCount += childCount - 1;
- testCasesForProFile[projectFile].internalTargets.unite(item->internalTargets());
+ testCasesForProFile[projectFile].internalTargets.unite(internalTargets(*item));
} else if (item->checked() == Qt::PartiallyChecked) {
item->forFirstLevelChildItems([&testCasesForProFile, item](TestTreeItem *child){
QTC_ASSERT(child->type() == TestTreeItem::TestCase, return);
@@ -242,14 +244,14 @@ static void collectTestInfo(const GTestTreeItem *item,
testCasesForProFile[child->proFile()].filters.append(
gtestFilter(item->state()).arg(item->name()).arg(child->name()));
testCasesForProFile[child->proFile()].internalTargets.unite(
- child->internalTargets());
+ internalTargets(*child));
}
});
}
}
static void collectFailedTestInfo(const GTestTreeItem *item,
- QHash<QString, GTestCases> &testCasesForProfile)
+ QHash<Utils::FilePath, GTestCases> &testCasesForProfile)
{
QTC_ASSERT(item, return);
QTC_ASSERT(item->type() == TestTreeItem::Root, return);
@@ -262,7 +264,7 @@ static void collectFailedTestInfo(const GTestTreeItem *item,
testCasesForProfile[it->proFile()].filters.append(
gtestFilter(parent->state()).arg(parent->name()).arg(it->name()));
testCasesForProfile[it->proFile()].internalTargets.unite(
- it->internalTargets());
+ internalTargets(*it));
}
});
}
@@ -274,7 +276,7 @@ QList<ITestConfiguration *> GTestTreeItem::getTestConfigurations(bool ignoreChec
if (!project || type() != Root)
return result;
- QHash<QString, GTestCases> testCasesForProFile;
+ QHash<Utils::FilePath, GTestCases> testCasesForProFile;
for (int row = 0, count = childCount(); row < count; ++row) {
auto child = static_cast<const GTestTreeItem *>(childAt(row));
collectTestInfo(child, testCasesForProFile, ignoreCheckState);
@@ -313,7 +315,7 @@ QList<ITestConfiguration *> GTestTreeItem::getFailedTestConfigurations() const
if (!project || type() != Root)
return result;
- QHash<QString, GTestCases> testCasesForProFile;
+ QHash<Utils::FilePath, GTestCases> testCasesForProFile;
collectFailedTestInfo(this, testCasesForProFile);
for (auto it = testCasesForProFile.begin(), end = testCasesForProFile.end(); it != end; ++it) {
@@ -338,17 +340,16 @@ QList<ITestConfiguration *> GTestTreeItem::getTestConfigurationsForFile(const Ut
if (!project || type() != Root)
return result;
- QHash<QString, GTestCases> testCases;
- const QString &file = fileName.toString();
- forAllChildItems([&testCases, &file](TestTreeItem *node) {
- if (node->type() == Type::TestCase && node->filePath() == file) {
+ QHash<Utils::FilePath, GTestCases> testCases;
+ forAllChildItems([&testCases, &fileName](TestTreeItem *node) {
+ if (node->type() == Type::TestCase && node->filePath() == fileName) {
QTC_ASSERT(node->parentItem(), return);
const GTestTreeItem *testCase = static_cast<GTestTreeItem *>(node->parentItem());
QTC_ASSERT(testCase->type() == Type::TestSuite, return);
GTestCases &cases = testCases[testCase->proFile()];
cases.filters.append(
gtestFilter(testCase->state()).arg(testCase->name(), node->name()));
- cases.internalTargets.unite(node->internalTargets());
+ cases.internalTargets.unite(internalTargets(*node));
}
});
for (auto it = testCases.begin(), end = testCases.end(); it != end; ++it) {
@@ -379,8 +380,7 @@ TestTreeItem *GTestTreeItem::find(const TestParseResult *result)
case Root:
if (result->framework->grouping()) {
if (GTestFramework::groupMode() == GTest::Constants::Directory) {
- const QFileInfo fileInfo(parseResult->fileName);
- const QFileInfo base(fileInfo.absolutePath());
+ const Utils::FilePath base = parseResult->fileName.absolutePath();
for (int row = 0; row < childCount(); ++row) {
GTestTreeItem *group = static_cast<GTestTreeItem *>(childAt(row));
if (group->filePath() != base.absoluteFilePath())
@@ -464,9 +464,9 @@ bool GTestTreeItem::modify(const TestParseResult *result)
TestTreeItem *GTestTreeItem::createParentGroupNode() const
{
if (GTestFramework::groupMode() == GTest::Constants::Directory) {
- const QFileInfo fileInfo(filePath());
- const QFileInfo base(fileInfo.absolutePath());
- return new GTestTreeItem(framework(), base.baseName(), fileInfo.absolutePath(), TestTreeItem::GroupNode);
+ const QFileInfo base = filePath().absolutePath().toFileInfo();
+ return new GTestTreeItem(framework(), base.baseName(), filePath().absolutePath(),
+ TestTreeItem::GroupNode);
} else { // GTestFilter
QTC_ASSERT(childCount(), return nullptr); // paranoia
const TestTreeItem *firstChild = childItem(0);
@@ -474,7 +474,10 @@ TestTreeItem *GTestTreeItem::createParentGroupNode() const
const QString fullTestName = name() + '.' + firstChild->name();
const QString groupNodeName =
matchesFilter(activeFilter, fullTestName) ? matchingString() : notMatchingString();
- auto groupNode = new GTestTreeItem(framework(), groupNodeName, activeFilter, TestTreeItem::GroupNode);
+ // FIXME activeFilter is not a FilePath
+ auto groupNode = new GTestTreeItem(framework(), groupNodeName,
+ Utils::FilePath::fromString(activeFilter),
+ TestTreeItem::GroupNode);
if (groupNodeName == notMatchingString())
groupNode->setData(0, Qt::Unchecked, Qt::CheckStateRole);
return groupNode;
@@ -495,7 +498,7 @@ bool GTestTreeItem::modifyTestSetContent(const GTestParseResult *result)
TestTreeItem *GTestTreeItem::findChildByNameStateAndFile(const QString &name,
GTestTreeItem::TestStates state,
- const QString &proFile) const
+ const Utils::FilePath &proFile) const
{
return findFirstLevelChildItem([name, state, proFile](const TestTreeItem *other) {
const GTestTreeItem *gtestItem = static_cast<const GTestTreeItem *>(other);
@@ -517,23 +520,24 @@ QString GTestTreeItem::nameSuffix() const
return suffix;
}
-QSet<QString> GTestTreeItem::internalTargets() const
+QSet<QString> internalTargets(const TestTreeItem &item)
{
QSet<QString> result;
const auto cppMM = CppTools::CppModelManager::instance();
const auto projectInfo = cppMM->projectInfo(ProjectExplorer::SessionManager::startupProject());
- const QString file = filePath();
+ const Utils::FilePath filePath = item.filePath();
+ const QString file = filePath.toString();
const QVector<CppTools::ProjectPart::Ptr> projectParts = projectInfo.projectParts();
if (projectParts.isEmpty())
- return TestTreeItem::dependingInternalTargets(cppMM, file);
+ return cppMM->dependingInternalTargets(item.filePath());
for (const CppTools::ProjectPart::Ptr &projectPart : projectParts) {
- if (projectPart->projectFile == proFile()
+ if (Utils::FilePath::fromString(projectPart->projectFile) == item.proFile()
&& Utils::anyOf(projectPart->files, [&file] (const CppTools::ProjectFile &pf) {
return pf.path == file;
})) {
result.insert(projectPart->buildSystemTarget);
if (projectPart->buildTargetType != ProjectExplorer::BuildTargetType::Executable)
- result.unite(TestTreeItem::dependingInternalTargets(cppMM, file));
+ result.unite(cppMM->dependingInternalTargets(filePath));
}
}
return result;
@@ -546,7 +550,7 @@ bool GTestTreeItem::isGroupNodeFor(const TestTreeItem *other) const
return false;
if (GTestFramework::groupMode() == GTest::Constants::Directory) {
- return QFileInfo(other->filePath()).absolutePath() == filePath();
+ return other->filePath().absolutePath() == filePath();
} else { // GTestFilter
QString fullName;
if (other->type() == TestSuite) {
@@ -561,9 +565,10 @@ bool GTestTreeItem::isGroupNodeFor(const TestTreeItem *other) const
} else {
QTC_ASSERT(false, return false);
}
- if (GTestFramework::currentGTestFilter() != filePath()) // filter has changed in settings
+ // FIXME gtest filter is no FilePath
+ if (GTestFramework::currentGTestFilter() != filePath().toString()) // filter has changed in settings
return false;
- bool matches = matchesFilter(filePath(), fullName);
+ bool matches = matchesFilter(filePath().toString(), fullName);
return (matches && name() == matchingString())
|| (!matches && name() == notMatchingString());
}
diff --git a/src/plugins/autotest/gtest/gtesttreeitem.h b/src/plugins/autotest/gtest/gtesttreeitem.h
index dd6741cca8..62133063ed 100644
--- a/src/plugins/autotest/gtest/gtesttreeitem.h
+++ b/src/plugins/autotest/gtest/gtesttreeitem.h
@@ -48,7 +48,7 @@ public:
explicit GTestTreeItem(ITestFramework *testFramework,
const QString &name = QString(),
- const QString &filePath = QString(),
+ const Utils::FilePath &filePath = Utils::FilePath(),
Type type = Root)
: TestTreeItem(testFramework, name, filePath, type), m_state(Enabled)
{}
@@ -73,9 +73,8 @@ public:
TestStates state() const { return m_state; }
TestTreeItem *findChildByNameStateAndFile(const QString &name,
GTestTreeItem::TestStates state,
- const QString &proFile) const;
+ const Utils::FilePath &proFile) const;
QString nameSuffix() const;
- QSet<QString> internalTargets() const override;
bool isGroupNodeFor(const TestTreeItem *other) const override;
bool isGroupable() const override;
TestTreeItem *applyFilters() override;
diff --git a/src/plugins/autotest/itestframework.h b/src/plugins/autotest/itestframework.h
index 6e36ecfe3c..6b30c70dd0 100644
--- a/src/plugins/autotest/itestframework.h
+++ b/src/plugins/autotest/itestframework.h
@@ -28,12 +28,13 @@
#include <utils/id.h>
namespace ProjectExplorer { struct TestCaseInfo; }
+namespace Utils { class AspectContainer; }
namespace Autotest {
class ITestFramework;
class ITestParser;
-class ITestSettings;
+using ITestSettings = Utils::AspectContainer;
class ITestTool;
class ITestTreeItem;
class TestTreeItem;
diff --git a/src/plugins/autotest/itestparser.cpp b/src/plugins/autotest/itestparser.cpp
index 51ab6f6b3b..740f029e4c 100644
--- a/src/plugins/autotest/itestparser.cpp
+++ b/src/plugins/autotest/itestparser.cpp
@@ -36,7 +36,7 @@ CppParser::CppParser(ITestFramework *framework)
{
}
-void CppParser::init(const QStringList &filesToParse, bool fullParse)
+void CppParser::init(const Utils::FilePaths &filesToParse, bool fullParse)
{
Q_UNUSED(filesToParse)
Q_UNUSED(fullParse)
@@ -44,7 +44,7 @@ void CppParser::init(const QStringList &filesToParse, bool fullParse)
m_workingCopy = CppTools::CppModelManager::instance()->workingCopy();
}
-bool CppParser::selectedForBuilding(const QString &fileName)
+bool CppParser::selectedForBuilding(const Utils::FilePath &fileName)
{
QList<CppTools::ProjectPart::Ptr> projParts =
CppTools::CppModelManager::instance()->projectPart(fileName);
@@ -52,7 +52,7 @@ bool CppParser::selectedForBuilding(const QString &fileName)
return !projParts.isEmpty() && projParts.at(0)->selectedForBuilding;
}
-QByteArray CppParser::getFileContent(const QString &filePath) const
+QByteArray CppParser::getFileContent(const Utils::FilePath &filePath) const
{
QByteArray fileContent;
if (m_workingCopy.contains(filePath)) {
@@ -75,7 +75,7 @@ void CppParser::release()
m_workingCopy = CppTools::WorkingCopy();
}
-CPlusPlus::Document::Ptr CppParser::document(const QString &fileName)
+CPlusPlus::Document::Ptr CppParser::document(const Utils::FilePath &fileName)
{
return selectedForBuilding(fileName) ? m_cppSnapshot.document(fileName) : nullptr;
}
diff --git a/src/plugins/autotest/itestparser.h b/src/plugins/autotest/itestparser.h
index 0639797fa1..e089c030d4 100644
--- a/src/plugins/autotest/itestparser.h
+++ b/src/plugins/autotest/itestparser.h
@@ -49,8 +49,8 @@ public:
ITestFramework *framework;
TestTreeItem::Type itemType = TestTreeItem::Root;
QString displayName;
- QString fileName;
- QString proFile;
+ Utils::FilePath fileName;
+ Utils::FilePath proFile;
QString name;
int line = 0;
int column = 0;
@@ -63,9 +63,9 @@ class ITestParser
public:
explicit ITestParser(ITestFramework *framework) : m_framework(framework) {}
virtual ~ITestParser() { }
- virtual void init(const QStringList &filesToParse, bool fullParse) = 0;
+ virtual void init(const Utils::FilePaths &filesToParse, bool fullParse) = 0;
virtual bool processDocument(QFutureInterface<TestParseResultPtr> futureInterface,
- const QString &fileName) = 0;
+ const Utils::FilePath &fileName) = 0;
virtual void release() = 0;
ITestFramework *framework() const { return m_framework; }
@@ -78,12 +78,12 @@ class CppParser : public ITestParser
{
public:
explicit CppParser(ITestFramework *framework);
- void init(const QStringList &filesToParse, bool fullParse) override;
- static bool selectedForBuilding(const QString &fileName);
- QByteArray getFileContent(const QString &filePath) const;
+ void init(const Utils::FilePaths &filesToParse, bool fullParse) override;
+ static bool selectedForBuilding(const Utils::FilePath &fileName);
+ QByteArray getFileContent(const Utils::FilePath &filePath) const;
void release() override;
- CPlusPlus::Document::Ptr document(const QString &fileName);
+ CPlusPlus::Document::Ptr document(const Utils::FilePath &fileName);
protected:
CPlusPlus::Snapshot m_cppSnapshot;
diff --git a/src/plugins/autotest/qtest/qttest_utils.cpp b/src/plugins/autotest/qtest/qttest_utils.cpp
index ce98f959d2..7d5e0d96aa 100644
--- a/src/plugins/autotest/qtest/qttest_utils.cpp
+++ b/src/plugins/autotest/qtest/qttest_utils.cpp
@@ -47,9 +47,10 @@ bool isQTestMacro(const QByteArray &macro)
return valid.contains(macro);
}
-QHash<QString, QString> testCaseNamesForFiles(ITestFramework *framework, const QStringList &files)
+QHash<Utils::FilePath, QString> testCaseNamesForFiles(ITestFramework *framework,
+ const Utils::FilePaths &files)
{
- QHash<QString, QString> result;
+ QHash<Utils::FilePath, QString> result;
TestTreeItem *rootNode = framework->rootNode();
QTC_ASSERT(rootNode, return result);
@@ -64,17 +65,18 @@ QHash<QString, QString> testCaseNamesForFiles(ITestFramework *framework, const Q
return result;
}
-QMultiHash<QString, QString> alternativeFiles(ITestFramework *framework, const QStringList &files)
+QMultiHash<Utils::FilePath, Utils::FilePath> alternativeFiles(ITestFramework *framework,
+ const Utils::FilePaths &files)
{
- QMultiHash<QString, QString> result;
+ QMultiHash<Utils::FilePath, Utils::FilePath> result;
TestTreeItem *rootNode = framework->rootNode();
QTC_ASSERT(rootNode, return result);
rootNode->forFirstLevelChildren([&result, &files](ITestTreeItem *child) {
- const QString &baseFilePath = child->filePath();
+ const Utils::FilePath &baseFilePath = child->filePath();
for (int childRow = 0, count = child->childCount(); childRow < count; ++childRow) {
auto grandChild = static_cast<const QtTestTreeItem *>(child->childAt(childRow));
- const QString &filePath = grandChild->filePath();
+ const Utils::FilePath &filePath = grandChild->filePath();
if (grandChild->inherited() && baseFilePath != filePath && files.contains(filePath)) {
if (!result.contains(filePath, baseFilePath))
result.insert(filePath, baseFilePath);
diff --git a/src/plugins/autotest/qtest/qttest_utils.h b/src/plugins/autotest/qtest/qttest_utils.h
index b1156ff7ee..22a127899d 100644
--- a/src/plugins/autotest/qtest/qttest_utils.h
+++ b/src/plugins/autotest/qtest/qttest_utils.h
@@ -25,6 +25,8 @@
#pragma once
+#include <utils/fileutils.h>
+
#include <QHash>
namespace Utils { class Environment; }
@@ -37,8 +39,10 @@ namespace Internal {
namespace QTestUtils {
bool isQTestMacro(const QByteArray &macro);
-QHash<QString, QString> testCaseNamesForFiles(ITestFramework *framework, const QStringList &files);
-QMultiHash<QString, QString> alternativeFiles(ITestFramework *framework, const QStringList &files);
+QHash<Utils::FilePath, QString> testCaseNamesForFiles(ITestFramework *framework,
+ const Utils::FilePaths &files);
+QMultiHash<Utils::FilePath, Utils::FilePath> alternativeFiles(ITestFramework *framework,
+ const Utils::FilePaths &files);
QStringList filterInterfering(const QStringList &provided, QStringList *omitted, bool isQuickTest);
Utils::Environment prepareBasicEnvironment(const Utils::Environment &env);
diff --git a/src/plugins/autotest/qtest/qttestconfiguration.cpp b/src/plugins/autotest/qtest/qttestconfiguration.cpp
index b02daed554..edc58a9090 100644
--- a/src/plugins/autotest/qtest/qttestconfiguration.cpp
+++ b/src/plugins/autotest/qtest/qttestconfiguration.cpp
@@ -40,8 +40,8 @@ namespace Internal {
TestOutputReader *QtTestConfiguration::outputReader(const QFutureInterface<TestResultPtr> &fi,
QProcess *app) const
{
- auto qtSettings = dynamic_cast<QtTestSettings *>(framework()->testSettings());
- const QtTestOutputReader::OutputMode mode = qtSettings && qtSettings->useXMLOutput
+ auto qtSettings = static_cast<QtTestSettings *>(framework()->testSettings());
+ const QtTestOutputReader::OutputMode mode = qtSettings && qtSettings->useXMLOutput.value()
? QtTestOutputReader::XML
: QtTestOutputReader::PlainText;
return new QtTestOutputReader(fi, app, buildDirectory(), projectFile(), mode, TestType::QtTest);
@@ -55,25 +55,25 @@ QStringList QtTestConfiguration::argumentsForTestRunner(QStringList *omitted) co
runnable().commandLineArguments.split(' ', Qt::SkipEmptyParts),
omitted, false));
}
- auto qtSettings = dynamic_cast<QtTestSettings *>(framework()->testSettings());
+ auto qtSettings = static_cast<QtTestSettings *>(framework()->testSettings());
if (!qtSettings)
return arguments;
- if (qtSettings->useXMLOutput)
+ if (qtSettings->useXMLOutput.value())
arguments << "-xml";
if (!testCases().isEmpty())
arguments << testCases();
- const QString &metricsOption = QtTestSettings::metricsTypeToOption(qtSettings->metrics);
+ const QString &metricsOption = QtTestSettings::metricsTypeToOption(MetricsType(qtSettings->metrics.value()));
if (!metricsOption.isEmpty())
arguments << metricsOption;
- if (qtSettings->verboseBench)
+ if (qtSettings->verboseBench.value())
arguments << "-vb";
- if (qtSettings->logSignalsSlots)
+ if (qtSettings->logSignalsSlots.value())
arguments << "-vs";
- if (isDebugRunMode() && qtSettings->noCrashHandler)
+ if (isDebugRunMode() && qtSettings->noCrashHandler.value())
arguments << "-nocrashhandler";
return arguments;
diff --git a/src/plugins/autotest/qtest/qttestframework.cpp b/src/plugins/autotest/qtest/qttestframework.cpp
index fcf2445ebd..23646e43d9 100644
--- a/src/plugins/autotest/qtest/qttestframework.cpp
+++ b/src/plugins/autotest/qtest/qttestframework.cpp
@@ -42,7 +42,7 @@ ITestTreeItem *QtTestFramework::createRootNode()
this,
QCoreApplication::translate("QtTestFramework",
QtTest::Constants::FRAMEWORK_SETTINGS_CATEGORY),
- QString(), ITestTreeItem::Root);
+ Utils::FilePath(), ITestTreeItem::Root);
}
const char *QtTestFramework::name() const
diff --git a/src/plugins/autotest/qtest/qttestframework.h b/src/plugins/autotest/qtest/qttestframework.h
index 1f66deb09a..d75e07044b 100644
--- a/src/plugins/autotest/qtest/qttestframework.h
+++ b/src/plugins/autotest/qtest/qttestframework.h
@@ -28,7 +28,6 @@
#include "../itestframework.h"
#include "qttestsettings.h"
-#include "qttestsettingspage.h"
namespace Autotest {
namespace Internal {
diff --git a/src/plugins/autotest/qtest/qttestoutputreader.cpp b/src/plugins/autotest/qtest/qttestoutputreader.cpp
index 843a1dd2ad..a15a0fc1d4 100644
--- a/src/plugins/autotest/qtest/qttestoutputreader.cpp
+++ b/src/plugins/autotest/qtest/qttestoutputreader.cpp
@@ -125,14 +125,11 @@ static QString constructBenchmarkInformation(const QString &metric, double value
.arg(iterations);
}
-static QString constructSourceFilePath(const QString &path, const QString &filePath)
-{
- return QFileInfo(path, filePath).canonicalFilePath();
-}
-
QtTestOutputReader::QtTestOutputReader(const QFutureInterface<TestResultPtr> &futureInterface,
- QProcess *testApplication, const QString &buildDirectory,
- const QString &projectFile, OutputMode mode, TestType type)
+ QProcess *testApplication,
+ const Utils::FilePath &buildDirectory,
+ const Utils::FilePath &projectFile,
+ OutputMode mode, TestType type)
: TestOutputReader(futureInterface, testApplication, buildDirectory)
, m_projectFile(projectFile)
, m_mode(mode)
@@ -237,9 +234,8 @@ void QtTestOutputReader::processXMLOutput(const QByteArray &outputLine)
const QXmlStreamAttributes &attributes = m_xmlReader.attributes();
m_result = TestResult::resultFromString(
attributes.value(QStringLiteral("type")).toString());
- m_file = decode(attributes.value(QStringLiteral("file")).toString());
- if (!m_file.isEmpty())
- m_file = constructSourceFilePath(m_buildDir, m_file);
+ const QString file = decode(attributes.value(QStringLiteral("file")).toString());
+ m_file = constructSourceFilePath(m_buildDir, file);
m_lineNumber = attributes.value(QStringLiteral("line")).toInt();
} else if (currentTag == QStringLiteral("BenchmarkResult")) {
const QXmlStreamAttributes &attributes = m_xmlReader.attributes();
diff --git a/src/plugins/autotest/qtest/qttestoutputreader.h b/src/plugins/autotest/qtest/qttestoutputreader.h
index 8d03726b12..eff84dd464 100644
--- a/src/plugins/autotest/qtest/qttestoutputreader.h
+++ b/src/plugins/autotest/qtest/qttestoutputreader.h
@@ -48,8 +48,8 @@ public:
};
QtTestOutputReader(const QFutureInterface<TestResultPtr> &futureInterface,
- QProcess *testApplication, const QString &buildDirectory,
- const QString &projectFile, OutputMode mode, TestType type);
+ QProcess *testApplication, const Utils::FilePath &buildDirectory,
+ const Utils::FilePath &projectFile, OutputMode mode, TestType type);
protected:
void processOutputLine(const QByteArray &outputLine) override;
TestResultPtr createDefaultResult() const override;
@@ -78,14 +78,14 @@ private:
};
CDATAMode m_cdataMode = None;
- QString m_projectFile;
+ Utils::FilePath m_projectFile;
QString m_className;
QString m_testCase;
QString m_formerTestCase;
QString m_dataTag;
ResultType m_result = ResultType::Invalid;
QString m_description;
- QString m_file;
+ Utils::FilePath m_file;
int m_lineNumber = 0;
QString m_duration;
QXmlStreamReader m_xmlReader;
diff --git a/src/plugins/autotest/qtest/qttestparser.cpp b/src/plugins/autotest/qtest/qttestparser.cpp
index 29e861a927..d1c27723fc 100644
--- a/src/plugins/autotest/qtest/qttestparser.cpp
+++ b/src/plugins/autotest/qtest/qttestparser.cpp
@@ -81,7 +81,7 @@ static bool includesQtTest(const CPlusPlus::Document::Ptr &doc, const CPlusPlus:
return false;
}
-static bool qtTestLibDefined(const QString &fileName)
+static bool qtTestLibDefined(const Utils::FilePath &fileName)
{
const QList<CppTools::ProjectPart::Ptr> parts =
CppTools::CppModelManager::instance()->projectPart(fileName);
@@ -93,10 +93,11 @@ static bool qtTestLibDefined(const QString &fileName)
return false;
}
-QString QtTestParser::testClass(const CppTools::CppModelManager *modelManager, const QString &fileName) const
+QString QtTestParser::testClass(const CppTools::CppModelManager *modelManager,
+ const Utils::FilePath &fileName) const
{
const QByteArray &fileContent = getFileContent(fileName);
- CPlusPlus::Document::Ptr document = modelManager->document(fileName);
+ CPlusPlus::Document::Ptr document = modelManager->document(fileName.toString());
if (document.isNull())
return QString();
@@ -124,7 +125,7 @@ QString QtTestParser::testClass(const CppTools::CppModelManager *modelManager, c
static CPlusPlus::Document::Ptr declaringDocument(CPlusPlus::Document::Ptr doc,
const CPlusPlus::Snapshot &snapshot,
const QString &testCaseName,
- const QStringList &alternativeFiles = {},
+ const Utils::FilePaths &alternativeFiles = {},
int *line = nullptr,
int *column = nullptr)
{
@@ -136,7 +137,7 @@ static CPlusPlus::Document::Ptr declaringDocument(CPlusPlus::Document::Ptr doc,
doc->globalNamespace());
// fallback for inherited functions
if (lookupItems.size() == 0 && !alternativeFiles.isEmpty()) {
- for (const QString &alternativeFile : alternativeFiles) {
+ for (const Utils::FilePath &alternativeFile : alternativeFiles) {
if (snapshot.contains(alternativeFile)) {
CPlusPlus::Document::Ptr document = snapshot.document(alternativeFile);
CPlusPlus::TypeOfExpression typeOfExpr; // we need a new one with no bindings
@@ -181,7 +182,7 @@ static QSet<QString> filesWithDataFunctionDefinitions(
QHash<QString, QtTestCodeLocationList> QtTestParser::checkForDataTags(const QString &fileName) const
{
- const QByteArray fileContent = getFileContent(fileName);
+ const QByteArray fileContent = getFileContent(Utils::FilePath::fromString(fileName));
CPlusPlus::Document::Ptr document = m_cppSnapshot.preprocessedDocument(fileContent, fileName);
document->check();
CPlusPlus::AST *ast = document->translationUnit()->ast();
@@ -278,7 +279,7 @@ static bool isQObject(const CPlusPlus::Document::Ptr &declaringDoc)
}
bool QtTestParser::processDocument(QFutureInterface<TestParseResultPtr> futureInterface,
- const QString &fileName)
+ const Utils::FilePath &fileName)
{
CPlusPlus::Document::Ptr doc = document(fileName);
if (doc.isNull())
@@ -293,84 +294,106 @@ bool QtTestParser::processDocument(QFutureInterface<TestParseResultPtr> futureIn
if (testCaseName.isEmpty())
testCaseName = oldTestCaseName;
if (!testCaseName.isEmpty()) {
- int line = 0;
- int column = 0;
- const QStringList &alternativeFiles = m_alternativeFiles.values(fileName);
- CPlusPlus::Document::Ptr declaringDoc = declaringDocument(doc, m_cppSnapshot, testCaseName,
- alternativeFiles, &line, &column);
- if (declaringDoc.isNull())
- return false;
-
- TestVisitor visitor(testCaseName, m_cppSnapshot);
- visitor.accept(declaringDoc->globalNamespace());
- if (!visitor.resultValid())
- return false;
+ TestCaseData data;
+ Utils::optional<bool> earlyReturn = fillTestCaseData(testCaseName, doc, data);
+ if (earlyReturn.has_value())
+ return earlyReturn.value();
- QMap<QString, QtTestCodeLocationAndType> testFunctions = visitor.privateSlots();
- // gather appropriate information of base classes as well and merge into already found
- // functions - but only as far as QtTest can handle this appropriate
- fetchAndMergeBaseTestFunctions(
- visitor.baseClasses(), testFunctions, declaringDoc, m_cppSnapshot);
-
- // handle tests that are not runnable without more information (plugin unit test of QC)
- if (testFunctions.isEmpty() && testCaseName == "QObject" && isQObject(declaringDoc))
- return true; // we did not handle it, but we do not expect any test defined there either
-
- const QSet<QString> &files = filesWithDataFunctionDefinitions(testFunctions);
-
- QHash<QString, QtTestCodeLocationList> dataTags;
- for (const QString &file : files)
- Utils::addToHash(&dataTags, checkForDataTags(file));
-
- QtTestParseResult *parseResult = new QtTestParseResult(framework());
- parseResult->itemType = TestTreeItem::TestCase;
- parseResult->fileName = declaringDoc->fileName();
- parseResult->name = testCaseName;
- parseResult->displayName = testCaseName;
- parseResult->line = line;
- parseResult->column = column;
QList<CppTools::ProjectPart::Ptr> projectParts = modelManager->projectPart(fileName);
if (projectParts.isEmpty()) // happens if shutting down while parsing
return false;
- parseResult->proFile = projectParts.first()->projectFile;
- QMap<QString, QtTestCodeLocationAndType>::ConstIterator it = testFunctions.begin();
- const QMap<QString, QtTestCodeLocationAndType>::ConstIterator end = testFunctions.end();
- for ( ; it != end; ++it) {
- const QtTestCodeLocationAndType &location = it.value();
- QString functionName = it.key();
- functionName = functionName.mid(functionName.lastIndexOf(':') + 1);
- QtTestParseResult *func = new QtTestParseResult(framework());
- func->itemType = location.m_type;
- func->name = testCaseName + "::" + functionName;
- func->displayName = functionName;
- func->fileName = location.m_name;
- func->line = location.m_line;
- func->column = location.m_column;
- func->setInherited(location.m_inherited);
-
- const QtTestCodeLocationList &tagLocations = tagLocationsFor(func, dataTags);
- for (const QtTestCodeLocationAndType &tag : tagLocations) {
- QtTestParseResult *dataTag = new QtTestParseResult(framework());
- dataTag->itemType = tag.m_type;
- dataTag->name = tag.m_name;
- dataTag->displayName = tag.m_name;
- dataTag->fileName = testFunctions.value(it.key() + "_data").m_name;
- dataTag->line = tag.m_line;
- dataTag->column = tag.m_column;
- dataTag->setInherited(tag.m_inherited);
-
- func->children.append(dataTag);
- }
- parseResult->children.append(func);
- }
+ QtTestParseResult *parseResult
+ = createParseResult(testCaseName, data, projectParts.first()->projectFile);
futureInterface.reportResult(TestParseResultPtr(parseResult));
return true;
}
return false;
}
-void QtTestParser::init(const QStringList &filesToParse, bool fullParse)
+Utils::optional<bool> QtTestParser::fillTestCaseData(
+ const QString &testCaseName, const CPlusPlus::Document::Ptr &doc,
+ TestCaseData &data) const
+{
+ const Utils::FilePath filePath = Utils::FilePath::fromString(doc->fileName());
+ const Utils::FilePaths &alternativeFiles = m_alternativeFiles.values(filePath);
+ CPlusPlus::Document::Ptr declaringDoc = declaringDocument(doc, m_cppSnapshot, testCaseName,
+ alternativeFiles,
+ &(data.line), &(data.column));
+ if (declaringDoc.isNull())
+ return false;
+
+ TestVisitor visitor(testCaseName, m_cppSnapshot);
+ visitor.accept(declaringDoc->globalNamespace());
+ if (!visitor.resultValid())
+ return false;
+
+ data.testFunctions = visitor.privateSlots();
+ // gather appropriate information of base classes as well and merge into already found
+ // functions - but only as far as QtTest can handle this appropriate
+ fetchAndMergeBaseTestFunctions(
+ visitor.baseClasses(), data.testFunctions, declaringDoc, m_cppSnapshot);
+
+ // handle tests that are not runnable without more information (plugin unit test of QC)
+ if (data.testFunctions.isEmpty() && testCaseName == "QObject" && isQObject(declaringDoc))
+ return true; // we did not handle it, but we do not expect any test defined there either
+
+ const QSet<QString> &files = filesWithDataFunctionDefinitions(data.testFunctions);
+
+ for (const QString &file : files)
+ Utils::addToHash(&(data.dataTags), checkForDataTags(file));
+
+ data.fileName = Utils::FilePath::fromString(declaringDoc->fileName());
+ data.valid = true;
+ return Utils::optional<bool>();
+}
+
+QtTestParseResult *QtTestParser::createParseResult(
+ const QString &testCaseName, const TestCaseData &data, const QString &projectFile) const
+{
+ QtTestParseResult *parseResult = new QtTestParseResult(framework());
+ parseResult->itemType = TestTreeItem::TestCase;
+ parseResult->fileName = data.fileName;
+ parseResult->name = testCaseName;
+ parseResult->displayName = testCaseName;
+ parseResult->line = data.line;
+ parseResult->column = data.column;
+ parseResult->proFile = Utils::FilePath::fromString(projectFile);
+ QMap<QString, QtTestCodeLocationAndType>::ConstIterator it = data.testFunctions.begin();
+ const QMap<QString, QtTestCodeLocationAndType>::ConstIterator end = data.testFunctions.end();
+ for ( ; it != end; ++it) {
+ const QtTestCodeLocationAndType &location = it.value();
+ QString functionName = it.key();
+ functionName = functionName.mid(functionName.lastIndexOf(':') + 1);
+ QtTestParseResult *func = new QtTestParseResult(framework());
+ func->itemType = location.m_type;
+ func->name = testCaseName + "::" + functionName;
+ func->displayName = functionName;
+ func->fileName = Utils::FilePath::fromString(location.m_name);
+ func->line = location.m_line;
+ func->column = location.m_column;
+ func->setInherited(location.m_inherited);
+
+ const QtTestCodeLocationList &tagLocations = tagLocationsFor(func, data.dataTags);
+ for (const QtTestCodeLocationAndType &tag : tagLocations) {
+ QtTestParseResult *dataTag = new QtTestParseResult(framework());
+ dataTag->itemType = tag.m_type;
+ dataTag->name = tag.m_name;
+ dataTag->displayName = tag.m_name;
+ dataTag->fileName = Utils::FilePath::fromString(
+ data.testFunctions.value(it.key() + "_data").m_name);
+ dataTag->line = tag.m_line;
+ dataTag->column = tag.m_column;
+ dataTag->setInherited(tag.m_inherited);
+
+ func->children.append(dataTag);
+ }
+ parseResult->children.append(func);
+ }
+ return parseResult;
+}
+
+void QtTestParser::init(const Utils::FilePaths &filesToParse, bool fullParse)
{
if (!fullParse) { // in a full parse cached information might lead to wrong results
m_testCaseNames = QTestUtils::testCaseNamesForFiles(framework(), filesToParse);
diff --git a/src/plugins/autotest/qtest/qttestparser.h b/src/plugins/autotest/qtest/qttestparser.h
index 56d355e624..861bf2dfa9 100644
--- a/src/plugins/autotest/qtest/qttestparser.h
+++ b/src/plugins/autotest/qtest/qttestparser.h
@@ -29,6 +29,8 @@
#include "qttesttreeitem.h"
+#include <utils/optional.h>
+
namespace CppTools { class CppModelManager; }
namespace Autotest {
@@ -50,16 +52,31 @@ class QtTestParser : public CppParser
public:
explicit QtTestParser(ITestFramework *framework) : CppParser(framework) {}
- void init(const QStringList &filesToParse, bool fullParse) override;
+ void init(const Utils::FilePaths &filesToParse, bool fullParse) override;
void release() override;
bool processDocument(QFutureInterface<TestParseResultPtr> futureInterface,
- const QString &fileName) override;
+ const Utils::FilePath &fileName) override;
private:
- QString testClass(const CppTools::CppModelManager *modelManager, const QString &fileName) const;
+ QString testClass(const CppTools::CppModelManager *modelManager,
+ const Utils::FilePath &fileName) const;
QHash<QString, QtTestCodeLocationList> checkForDataTags(const QString &fileName) const;
- QHash<QString, QString> m_testCaseNames;
- QMultiHash<QString, QString> m_alternativeFiles;
+ struct TestCaseData {
+ Utils::FilePath fileName;
+ int line = 0;
+ int column = 0;
+ QMap<QString, QtTestCodeLocationAndType> testFunctions;
+ QHash<QString, QtTestCodeLocationList> dataTags;
+ bool valid = false;
+ };
+
+ Utils::optional<bool> fillTestCaseData(const QString &testCaseName,
+ const CPlusPlus::Document::Ptr &doc,
+ TestCaseData &data) const;
+ QtTestParseResult *createParseResult(const QString &testCaseName, const TestCaseData &data,
+ const QString &projectFile) const;
+ QHash<Utils::FilePath, QString> m_testCaseNames;
+ QMultiHash<Utils::FilePath, Utils::FilePath> m_alternativeFiles;
};
} // namespace Internal
diff --git a/src/plugins/autotest/qtest/qttestresult.cpp b/src/plugins/autotest/qtest/qttestresult.cpp
index e1b9edc22f..aa16f60196 100644
--- a/src/plugins/autotest/qtest/qttestresult.cpp
+++ b/src/plugins/autotest/qtest/qttestresult.cpp
@@ -34,7 +34,7 @@
namespace Autotest {
namespace Internal {
-QtTestResult::QtTestResult(const QString &id, const QString &projectFile, TestType type,
+QtTestResult::QtTestResult(const QString &id, const Utils::FilePath &projectFile, TestType type,
const QString &className)
: TestResult(id, className), m_projectFile(projectFile), m_type(type)
{
diff --git a/src/plugins/autotest/qtest/qttestresult.h b/src/plugins/autotest/qtest/qttestresult.h
index e2c1ae2e67..949ec63817 100644
--- a/src/plugins/autotest/qtest/qttestresult.h
+++ b/src/plugins/autotest/qtest/qttestresult.h
@@ -37,7 +37,7 @@ namespace Internal {
class QtTestResult : public TestResult
{
public:
- QtTestResult(const QString &id, const QString &projectFile, TestType type,
+ QtTestResult(const QString &id, const Utils::FilePath &projectFile, TestType type,
const QString &className);
const QString outputString(bool selected) const override;
@@ -59,7 +59,7 @@ private:
QString m_function;
QString m_dataTag;
- QString m_projectFile;
+ Utils::FilePath m_projectFile;
TestType m_type;
};
diff --git a/src/plugins/autotest/qtest/qttestsettings.cpp b/src/plugins/autotest/qtest/qttestsettings.cpp
index 2e953661ea..f98cdc4357 100644
--- a/src/plugins/autotest/qtest/qttestsettings.cpp
+++ b/src/plugins/autotest/qtest/qttestsettings.cpp
@@ -25,54 +25,60 @@
#include "qttestsettings.h"
+#include "../autotestconstants.h"
+#include "qttestconstants.h"
+
+#include <utils/layoutbuilder.h>
+
+using namespace Utils;
+
namespace Autotest {
namespace Internal {
-static const char metricsKey[] = "Metrics";
-static const char noCrashhandlerKey[] = "NoCrashhandlerOnDebug";
-static const char useXMLOutputKey[] = "UseXMLOutput";
-static const char verboseBenchKey[] = "VerboseBench";
-static const char logSignalsSlotsKey[] = "LogSignalsSlots";
-
-static MetricsType intToMetrics(int value)
+QtTestSettings::QtTestSettings()
{
- switch (value) {
- case Walltime:
- return Walltime;
- case TickCounter:
- return TickCounter;
- case EventCounter:
- return EventCounter;
- case CallGrind:
- return CallGrind;
- case Perf:
- return Perf;
- default:
- return Walltime;
- }
-}
+ setSettingsGroups("Autotest", "QtTest");
+ setAutoApply(false);
-QString QtTestSettings::name() const
-{
- return QString("QtTest");
-}
+ registerAspect(&metrics);
+ metrics.setSettingsKey("Metrics");
+ metrics.setDefaultValue(Walltime);
+ metrics.addOption(tr("Walltime"), tr("Uses walltime metrics for executing benchmarks (default)."));
+ metrics.addOption(tr("Tick counter"), tr("Uses tick counter when executing benchmarks."));
+ metrics.addOption(tr("Event counter"), tr("Uses event counter when executing benchmarks."));
+ metrics.addOption({
+ tr("Callgrind"),
+ tr("Uses Valgrind Callgrind when executing benchmarks (it must be installed)."),
+ HostOsInfo::isAnyUnixHost() // valgrind available on UNIX
+ });
+ metrics.addOption({
+ tr("Perf"),
+ tr("Uses Perf when executing benchmarks (it must be installed)."),
+ HostOsInfo::isLinuxHost() // according to docs perf Linux only
+ });
-void QtTestSettings::fromTestSettings(const QSettings *s)
-{
- metrics = intToMetrics(s->value(metricsKey, Walltime).toInt());
- noCrashHandler = s->value(noCrashhandlerKey, true).toBool();
- useXMLOutput = s->value(useXMLOutputKey, true).toBool();
- verboseBench = s->value(verboseBenchKey, false).toBool();
- logSignalsSlots = s->value(logSignalsSlotsKey, false).toBool();
-}
+ registerAspect(&noCrashHandler);
+ noCrashHandler.setSettingsKey("NoCrashhandlerOnDebug");
+ noCrashHandler.setDefaultValue(true);
+ noCrashHandler.setLabelText(tr("Disable crash handler while debugging"));
+ noCrashHandler.setToolTip(tr("Enables interrupting tests on assertions."));
-void QtTestSettings::toTestSettings(QSettings *s) const
-{
- s->setValue(metricsKey, metrics);
- s->setValue(noCrashhandlerKey, noCrashHandler);
- s->setValue(useXMLOutputKey, useXMLOutput);
- s->setValue(verboseBenchKey, verboseBench);
- s->setValue(logSignalsSlotsKey, logSignalsSlots);
+ registerAspect(&useXMLOutput);
+ useXMLOutput.setSettingsKey("UseXMLOutput");
+ useXMLOutput.setDefaultValue(true);
+ useXMLOutput.setLabelText(tr("Use XML output"));
+ useXMLOutput.setToolTip(tr("XML output is recommended, because it avoids parsing issues, "
+ "while plain text is more human readable.\n\n"
+ "Warning: Plain text misses some information, such as duration."));
+
+ registerAspect(&verboseBench);
+ verboseBench.setSettingsKey("VerboseBench");
+ verboseBench.setLabelText(tr("Verbose benchmarks"));
+
+ registerAspect(&logSignalsSlots);
+ logSignalsSlots.setSettingsKey("LogSignalsSlots");
+ logSignalsSlots.setLabelText(tr("Log signals and slots"));
+ logSignalsSlots.setToolTip(tr("Log every signal emission and resulting slot invocations."));
}
QString QtTestSettings::metricsTypeToOption(const MetricsType type)
@@ -92,5 +98,32 @@ QString QtTestSettings::metricsTypeToOption(const MetricsType type)
return QString();
}
+QtTestSettingsPage::QtTestSettingsPage(QtTestSettings *settings, Id settingsId)
+{
+ setId(settingsId);
+ setCategory(Constants::AUTOTEST_SETTINGS_CATEGORY);
+ setDisplayName(QCoreApplication::translate("QtTestFramework",
+ QtTest::Constants::FRAMEWORK_SETTINGS_CATEGORY));
+ setSettings(settings);
+
+ setLayouter([settings](QWidget *widget) {
+ QtTestSettings &s = *settings;
+ using namespace Layouting;
+
+ Column col {
+ s.noCrashHandler,
+ s.useXMLOutput,
+ s.verboseBench,
+ s.logSignalsSlots,
+ Group {
+ Title(QtTestSettings::tr("Benchmark Metrics")),
+ s.metrics
+ },
+ };
+
+ Column { Row { col, Stretch() }, Stretch() }.attachTo(widget);
+ });
+}
+
} // namespace Internal
} // namespace Autotest
diff --git a/src/plugins/autotest/qtest/qttestsettings.h b/src/plugins/autotest/qtest/qttestsettings.h
index cedd821d39..bc89059152 100644
--- a/src/plugins/autotest/qtest/qttestsettings.h
+++ b/src/plugins/autotest/qtest/qttestsettings.h
@@ -25,7 +25,9 @@
#pragma once
-#include "../itestsettings.h"
+#include <coreplugin/dialogs/ioptionspage.h>
+
+#include <utils/aspects.h>
namespace Autotest {
namespace Internal {
@@ -39,22 +41,25 @@ enum MetricsType
Perf
};
-class QtTestSettings : public ITestSettings
+class QtTestSettings : public Utils::AspectContainer
{
+ Q_DECLARE_TR_FUNCTIONS(Autotest::Internal::QtTestSettings)
public:
- QtTestSettings() {}
- QString name() const override;
+ QtTestSettings();
+
static QString metricsTypeToOption(const MetricsType type);
- MetricsType metrics = Walltime;
- bool noCrashHandler = true;
- bool useXMLOutput = true;
- bool verboseBench = false;
- bool logSignalsSlots = false;
+ Utils::SelectionAspect metrics;
+ Utils::BoolAspect noCrashHandler;
+ Utils::BoolAspect useXMLOutput;
+ Utils::BoolAspect verboseBench;
+ Utils::BoolAspect logSignalsSlots;
+};
-protected:
- void fromTestSettings(const QSettings *s) override;
- void toTestSettings(QSettings *s) const override;
+class QtTestSettingsPage final : public Core::IOptionsPage
+{
+public:
+ QtTestSettingsPage(QtTestSettings *settings, Utils::Id settingsId);
};
} // namespace Internal
diff --git a/src/plugins/autotest/qtest/qttestsettingspage.cpp b/src/plugins/autotest/qtest/qttestsettingspage.cpp
deleted file mode 100644
index bed1930baa..0000000000
--- a/src/plugins/autotest/qtest/qttestsettingspage.cpp
+++ /dev/null
@@ -1,113 +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 "../autotestconstants.h"
-#include "qttestconstants.h"
-#include "qttestsettingspage.h"
-#include "qttestsettings.h"
-#include "ui_qttestsettingspage.h"
-
-#include <coreplugin/icore.h>
-
-#include <utils/hostosinfo.h>
-
-namespace Autotest {
-namespace Internal {
-
-class QtTestSettingsWidget final : public Core::IOptionsPageWidget
-{
- Q_DECLARE_TR_FUNCTIONS(Autotest::Internal::QtTestSettingsWidget)
-
-public:
- explicit QtTestSettingsWidget(QtTestSettings *settings);
-
- void apply() final;
-
-private:
- Ui::QtTestSettingsPage m_ui;
- QtTestSettings *m_settings;
-};
-
-QtTestSettingsWidget::QtTestSettingsWidget(QtTestSettings *settings)
- : m_settings(settings)
-{
- m_ui.setupUi(this);
- m_ui.callgrindRB->setEnabled(Utils::HostOsInfo::isAnyUnixHost()); // valgrind available on UNIX
- m_ui.perfRB->setEnabled(Utils::HostOsInfo::isLinuxHost()); // according to docs perf Linux only
-
- m_ui.disableCrashhandlerCB->setChecked(m_settings->noCrashHandler);
- m_ui.useXMLOutputCB->setChecked(m_settings->useXMLOutput);
- m_ui.verboseBenchmarksCB->setChecked(m_settings->verboseBench);
- m_ui.logSignalsAndSlotsCB->setChecked(m_settings->logSignalsSlots);
- switch (m_settings->metrics) {
- case MetricsType::Walltime:
- m_ui.walltimeRB->setChecked(true);
- break;
- case MetricsType::TickCounter:
- m_ui.tickcounterRB->setChecked(true);
- break;
- case MetricsType::EventCounter:
- m_ui.eventCounterRB->setChecked(true);
- break;
- case MetricsType::CallGrind:
- m_ui.callgrindRB->setChecked(true);
- break;
- case MetricsType::Perf:
- m_ui.perfRB->setChecked(true);
- break;
- }
-}
-
-void QtTestSettingsWidget::apply()
-{
- m_settings->noCrashHandler = m_ui.disableCrashhandlerCB->isChecked();
- m_settings->useXMLOutput = m_ui.useXMLOutputCB->isChecked();
- m_settings->verboseBench = m_ui.verboseBenchmarksCB->isChecked();
- m_settings->logSignalsSlots = m_ui.logSignalsAndSlotsCB->isChecked();
- if (m_ui.walltimeRB->isChecked())
- m_settings->metrics = MetricsType::Walltime;
- else if (m_ui.tickcounterRB->isChecked())
- m_settings->metrics = MetricsType::TickCounter;
- else if (m_ui.eventCounterRB->isChecked())
- m_settings->metrics = MetricsType::EventCounter;
- else if (m_ui.callgrindRB->isChecked())
- m_settings->metrics = MetricsType::CallGrind;
- else if (m_ui.perfRB->isChecked())
- m_settings->metrics = MetricsType::Perf;
-
- m_settings->toSettings(Core::ICore::settings());
-}
-
-QtTestSettingsPage::QtTestSettingsPage(QtTestSettings *settings, Utils::Id settingsId)
-{
- setId(settingsId);
- setCategory(Constants::AUTOTEST_SETTINGS_CATEGORY);
- setDisplayName(QCoreApplication::translate("QtTestFramework",
- QtTest::Constants::FRAMEWORK_SETTINGS_CATEGORY));
- setWidgetCreator([settings] { return new QtTestSettingsWidget(settings); });
-}
-
-} // namespace Internal
-} // namespace Autotest
diff --git a/src/plugins/autotest/qtest/qttestsettingspage.ui b/src/plugins/autotest/qtest/qttestsettingspage.ui
deleted file mode 100644
index eedb1a8e57..0000000000
--- a/src/plugins/autotest/qtest/qttestsettingspage.ui
+++ /dev/null
@@ -1,198 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<ui version="4.0">
- <class>Autotest::Internal::QtTestSettingsPage</class>
- <widget class="QWidget" name="Autotest::Internal::QtTestSettingsPage">
- <property name="geometry">
- <rect>
- <x>0</x>
- <y>0</y>
- <width>327</width>
- <height>266</height>
- </rect>
- </property>
- <property name="windowTitle">
- <string/>
- </property>
- <layout class="QVBoxLayout" name="verticalLayout">
- <item>
- <layout class="QHBoxLayout" name="horizontalLayout">
- <item>
- <layout class="QVBoxLayout" name="verticalLayout_2">
- <item>
- <widget class="QCheckBox" name="disableCrashhandlerCB">
- <property name="toolTip">
- <string>Enables interrupting tests on assertions.</string>
- </property>
- <property name="text">
- <string>Disable crash handler while debugging</string>
- </property>
- <property name="checked">
- <bool>true</bool>
- </property>
- </widget>
- </item>
- <item>
- <widget class="QCheckBox" name="useXMLOutputCB">
- <property name="toolTip">
- <string>XML output is recommended, because it avoids parsing issues, while plain text is more human readable.
-
-Warning: Plain text misses some information, such as duration.</string>
- </property>
- <property name="text">
- <string>Use XML output</string>
- </property>
- <property name="checked">
- <bool>true</bool>
- </property>
- </widget>
- </item>
- <item>
- <widget class="QCheckBox" name="verboseBenchmarksCB">
- <property name="text">
- <string>Verbose benchmarks</string>
- </property>
- </widget>
- </item>
- <item>
- <widget class="QCheckBox" name="logSignalsAndSlotsCB">
- <property name="toolTip">
- <string>Log every signal emission and resulting slot invocations.</string>
- </property>
- <property name="text">
- <string>Log signals and slots</string>
- </property>
- </widget>
- </item>
- <item>
- <widget class="QGroupBox" name="groupBox">
- <property name="title">
- <string>Benchmark Metrics</string>
- </property>
- <layout class="QVBoxLayout" name="verticalLayout_3">
- <item>
- <widget class="QRadioButton" name="walltimeRB">
- <property name="sizePolicy">
- <sizepolicy hsizetype="Minimum" vsizetype="Minimum">
- <horstretch>0</horstretch>
- <verstretch>0</verstretch>
- </sizepolicy>
- </property>
- <property name="toolTip">
- <string>Uses walltime metrics for executing benchmarks (default).</string>
- </property>
- <property name="text">
- <string>Walltime</string>
- </property>
- <property name="checked">
- <bool>true</bool>
- </property>
- </widget>
- </item>
- <item>
- <widget class="QRadioButton" name="tickcounterRB">
- <property name="sizePolicy">
- <sizepolicy hsizetype="Minimum" vsizetype="Minimum">
- <horstretch>0</horstretch>
- <verstretch>0</verstretch>
- </sizepolicy>
- </property>
- <property name="toolTip">
- <string>Uses tick counter when executing benchmarks.</string>
- </property>
- <property name="text">
- <string>Tick counter</string>
- </property>
- </widget>
- </item>
- <item>
- <widget class="QRadioButton" name="eventCounterRB">
- <property name="sizePolicy">
- <sizepolicy hsizetype="Minimum" vsizetype="Minimum">
- <horstretch>0</horstretch>
- <verstretch>0</verstretch>
- </sizepolicy>
- </property>
- <property name="toolTip">
- <string>Uses event counter when executing benchmarks.</string>
- </property>
- <property name="text">
- <string>Event counter</string>
- </property>
- </widget>
- </item>
- <item>
- <widget class="QRadioButton" name="callgrindRB">
- <property name="enabled">
- <bool>false</bool>
- </property>
- <property name="sizePolicy">
- <sizepolicy hsizetype="Minimum" vsizetype="Minimum">
- <horstretch>0</horstretch>
- <verstretch>0</verstretch>
- </sizepolicy>
- </property>
- <property name="toolTip">
- <string>Uses Valgrind Callgrind when executing benchmarks (it must be installed).</string>
- </property>
- <property name="text">
- <string>Callgrind</string>
- </property>
- </widget>
- </item>
- <item>
- <widget class="QRadioButton" name="perfRB">
- <property name="enabled">
- <bool>false</bool>
- </property>
- <property name="sizePolicy">
- <sizepolicy hsizetype="Minimum" vsizetype="Minimum">
- <horstretch>0</horstretch>
- <verstretch>0</verstretch>
- </sizepolicy>
- </property>
- <property name="toolTip">
- <string>Uses Perf when executing benchmarks (it must be installed).</string>
- </property>
- <property name="text">
- <string>Perf</string>
- </property>
- </widget>
- </item>
- </layout>
- </widget>
- </item>
- </layout>
- </item>
- <item>
- <spacer name="horizontalSpacer">
- <property name="orientation">
- <enum>Qt::Horizontal</enum>
- </property>
- <property name="sizeHint" stdset="0">
- <size>
- <width>40</width>
- <height>20</height>
- </size>
- </property>
- </spacer>
- </item>
- </layout>
- </item>
- <item>
- <spacer name="verticalSpacer">
- <property name="orientation">
- <enum>Qt::Vertical</enum>
- </property>
- <property name="sizeHint" stdset="0">
- <size>
- <width>20</width>
- <height>40</height>
- </size>
- </property>
- </spacer>
- </item>
- </layout>
- </widget>
- <resources/>
- <connections/>
-</ui>
diff --git a/src/plugins/autotest/qtest/qttesttreeitem.cpp b/src/plugins/autotest/qtest/qttesttreeitem.cpp
index 909ee82d07..98cde79ee1 100644
--- a/src/plugins/autotest/qtest/qttesttreeitem.cpp
+++ b/src/plugins/autotest/qtest/qttesttreeitem.cpp
@@ -28,6 +28,7 @@
#include "qttestparser.h"
#include "qttestframework.h"
+#include <cpptools/cppmodelmanager.h>
#include <projectexplorer/session.h>
#include <utils/qtcassert.h>
@@ -35,7 +36,7 @@ namespace Autotest {
namespace Internal {
QtTestTreeItem::QtTestTreeItem(ITestFramework *testFramework, const QString &name,
- const QString &filePath, TestTreeItem::Type type)
+ const Utils::FilePath &filePath, TestTreeItem::Type type)
: TestTreeItem(testFramework, name, filePath, type)
{
if (type == TestDataTag)
@@ -111,6 +112,8 @@ ITestConfiguration *QtTestTreeItem::testConfiguration() const
{
ProjectExplorer::Project *project = ProjectExplorer::SessionManager::startupProject();
QTC_ASSERT(project, return nullptr);
+ const auto cppMM = CppTools::CppModelManager::instance();
+ QTC_ASSERT(cppMM, return nullptr);
QtTestConfiguration *config = nullptr;
switch (type()) {
@@ -144,13 +147,15 @@ ITestConfiguration *QtTestTreeItem::testConfiguration() const
return nullptr;
}
if (config)
- config->setInternalTargets(internalTargets());
+ config->setInternalTargets(cppMM->internalTargets(filePath()));
return config;
}
static void fillTestConfigurationsFromCheckState(const TestTreeItem *item,
QList<ITestConfiguration *> &testConfigurations)
{
+ const auto cppMM = CppTools::CppModelManager::instance();
+ QTC_ASSERT(cppMM, return);
QTC_ASSERT(item, return);
if (item->type() == TestTreeItem::GroupNode) {
for (int row = 0, count = item->childCount(); row < count; ++row)
@@ -185,13 +190,15 @@ static void fillTestConfigurationsFromCheckState(const TestTreeItem *item,
testConfig->setTestCases(testCases);
testConfig->setProjectFile(item->proFile());
testConfig->setProject(ProjectExplorer::SessionManager::startupProject());
- testConfig->setInternalTargets(item->internalTargets());
+ testConfig->setInternalTargets(cppMM->internalTargets(item->filePath()));
testConfigurations << testConfig;
}
}
static void collectFailedTestInfo(TestTreeItem *item, QList<ITestConfiguration *> &testConfigs)
{
+ const auto cppMM = CppTools::CppModelManager::instance();
+ QTC_ASSERT(cppMM, return);
QTC_ASSERT(item, return);
if (item->type() == TestTreeItem::GroupNode) {
for (int row = 0, count = item->childCount(); row < count; ++row)
@@ -217,7 +224,7 @@ static void collectFailedTestInfo(TestTreeItem *item, QList<ITestConfiguration *
testConfig->setTestCases(testCases);
testConfig->setProjectFile(item->proFile());
testConfig->setProject(ProjectExplorer::SessionManager::startupProject());
- testConfig->setInternalTargets(item->internalTargets());
+ testConfig->setInternalTargets(cppMM->internalTargets(item->filePath()));
testConfigs << testConfig;
}
@@ -284,9 +291,8 @@ QList<ITestConfiguration *> QtTestTreeItem::getTestConfigurationsForFile(const U
return result;
QHash<TestTreeItem *, QStringList> testFunctions;
- const QString &file = fileName.toString();
- forAllChildItems([&testFunctions, &file](TestTreeItem *node) {
- if (node->type() == Type::TestFunction && node->filePath() == file) {
+ forAllChildItems([&testFunctions, &fileName](TestTreeItem *node) {
+ if (node->type() == Type::TestFunction && node->filePath() == fileName) {
QTC_ASSERT(node->parentItem(), return);
TestTreeItem *testCase = node->parentItem();
QTC_ASSERT(testCase->type() == Type::TestCase, return);
@@ -311,7 +317,7 @@ TestTreeItem *QtTestTreeItem::find(const TestParseResult *result)
switch (type()) {
case Root:
if (result->framework->grouping()) {
- const QString path = QFileInfo(result->fileName).absolutePath();
+ const Utils::FilePath path = result->fileName.absolutePath();
for (int row = 0; row < childCount(); ++row) {
TestTreeItem *group = childItem(row);
if (group->filePath() != path)
@@ -350,7 +356,7 @@ TestTreeItem *QtTestTreeItem::findChild(const TestTreeItem *other)
if (otherType != TestFunction && otherType != TestDataFunction && otherType != TestSpecialFunction)
return nullptr;
auto qtOther = static_cast<const QtTestTreeItem *>(other);
- return findChildByNameAndInheritance(other->filePath(), qtOther->inherited());
+ return findChildByNameAndInheritance(other->name(), qtOther->inherited());
}
case TestFunction:
case TestDataFunction:
@@ -381,9 +387,8 @@ bool QtTestTreeItem::modify(const TestParseResult *result)
TestTreeItem *QtTestTreeItem::createParentGroupNode() const
{
- const QFileInfo fileInfo(filePath());
- const QFileInfo base(fileInfo.absolutePath());
- return new QtTestTreeItem(framework(), base.baseName(), fileInfo.absolutePath(), TestTreeItem::GroupNode);
+ const QFileInfo base = filePath().absolutePath().toFileInfo();
+ return new QtTestTreeItem(framework(), base.baseName(), filePath().absolutePath(), TestTreeItem::GroupNode);
}
bool QtTestTreeItem::isGroupable() const
diff --git a/src/plugins/autotest/qtest/qttesttreeitem.h b/src/plugins/autotest/qtest/qttesttreeitem.h
index d3583c4a92..087e1d79b8 100644
--- a/src/plugins/autotest/qtest/qttesttreeitem.h
+++ b/src/plugins/autotest/qtest/qttesttreeitem.h
@@ -34,7 +34,7 @@ class QtTestTreeItem : public TestTreeItem
{
public:
explicit QtTestTreeItem(ITestFramework *framework, const QString &name = QString(),
- const QString &filePath = QString(), Type type = Root);
+ const Utils::FilePath &filePath = Utils::FilePath(), Type type = Root);
TestTreeItem *copyWithoutChildren() override;
QVariant data(int column, int role) const override;
diff --git a/src/plugins/autotest/quick/quicktest_utils.cpp b/src/plugins/autotest/quick/quicktest_utils.cpp
index ef7dc81f37..c25009a1ff 100644
--- a/src/plugins/autotest/quick/quicktest_utils.cpp
+++ b/src/plugins/autotest/quick/quicktest_utils.cpp
@@ -43,9 +43,10 @@ bool isQuickTestMacro(const QByteArray &macro)
return valid.contains(macro);
}
-QHash<QString, QString> proFilesForQmlFiles(ITestFramework *framework, const QStringList &files)
+QHash<Utils::FilePath, Utils::FilePath> proFilesForQmlFiles(ITestFramework *framework,
+ const Utils::FilePaths &files)
{
- QHash<QString, QString> result;
+ QHash<Utils::FilePath, Utils::FilePath> result;
TestTreeItem *rootNode = framework->rootNode();
QTC_ASSERT(rootNode, return result);
@@ -53,16 +54,16 @@ QHash<QString, QString> proFilesForQmlFiles(ITestFramework *framework, const QSt
return result;
rootNode->forFirstLevelChildItems([&result, &files](TestTreeItem *child) {
- const QString &file = child->filePath();
+ const Utils::FilePath &file = child->filePath();
if (!file.isEmpty() && files.contains(file)) {
- const QString &proFile = child->proFile();
+ const Utils::FilePath &proFile = child->proFile();
if (!proFile.isEmpty())
result.insert(file, proFile);
}
child->forFirstLevelChildItems([&result, &files](TestTreeItem *grandChild) {
- const QString &file = grandChild->filePath();
+ const Utils::FilePath &file = grandChild->filePath();
if (!file.isEmpty() && files.contains(file)) {
- const QString &proFile = grandChild->proFile();
+ const Utils::FilePath &proFile = grandChild->proFile();
if (!proFile.isEmpty())
result.insert(file, proFile);
}
diff --git a/src/plugins/autotest/quick/quicktest_utils.h b/src/plugins/autotest/quick/quicktest_utils.h
index 3fc919ce67..51f52f38ba 100644
--- a/src/plugins/autotest/quick/quicktest_utils.h
+++ b/src/plugins/autotest/quick/quicktest_utils.h
@@ -25,6 +25,8 @@
#pragma once
+#include <utils/fileutils.h>
+
#include <QHash>
namespace Autotest {
@@ -35,7 +37,8 @@ namespace Internal {
namespace QuickTestUtils {
bool isQuickTestMacro(const QByteArray &macro);
-QHash<QString, QString> proFilesForQmlFiles(ITestFramework *framework, const QStringList &files);
+QHash<Utils::FilePath, Utils::FilePath> proFilesForQmlFiles(ITestFramework *framework,
+ const Utils::FilePaths &files);
} // namespace QuickTestUtils
} // namespace Internal
diff --git a/src/plugins/autotest/quick/quicktestconfiguration.cpp b/src/plugins/autotest/quick/quicktestconfiguration.cpp
index 2d8e01484f..aa2bdc18ac 100644
--- a/src/plugins/autotest/quick/quicktestconfiguration.cpp
+++ b/src/plugins/autotest/quick/quicktestconfiguration.cpp
@@ -46,8 +46,8 @@ QuickTestConfiguration::QuickTestConfiguration(ITestFramework *framework)
TestOutputReader *QuickTestConfiguration::outputReader(const QFutureInterface<TestResultPtr> &fi,
QProcess *app) const
{
- auto qtSettings = dynamic_cast<QtTestSettings *>(framework()->testSettings());
- const QtTestOutputReader::OutputMode mode = qtSettings && qtSettings->useXMLOutput
+ auto qtSettings = static_cast<QtTestSettings *>(framework()->testSettings());
+ const QtTestOutputReader::OutputMode mode = qtSettings && qtSettings->useXMLOutput.value()
? QtTestOutputReader::XML
: QtTestOutputReader::PlainText;
return new QtTestOutputReader(fi, app, buildDirectory(), projectFile(),
@@ -63,20 +63,20 @@ QStringList QuickTestConfiguration::argumentsForTestRunner(QStringList *omitted)
omitted, true));
}
- auto qtSettings = dynamic_cast<QtTestSettings *>(framework()->testSettings());
+ auto qtSettings = static_cast<QtTestSettings *>(framework()->testSettings());
if (!qtSettings)
return arguments;
- if (qtSettings->useXMLOutput)
+ if (qtSettings->useXMLOutput.value())
arguments << "-xml";
if (!testCases().isEmpty())
arguments << testCases();
- const QString &metricsOption = QtTestSettings::metricsTypeToOption(qtSettings->metrics);
+ const QString &metricsOption = QtTestSettings::metricsTypeToOption(MetricsType(qtSettings->metrics.value()));
if (!metricsOption.isEmpty())
arguments << metricsOption;
if (isDebugRunMode()) {
- if (qtSettings->noCrashHandler)
+ if (qtSettings->noCrashHandler.value())
arguments << "-nocrashhandler";
}
return arguments;
diff --git a/src/plugins/autotest/quick/quicktestframework.cpp b/src/plugins/autotest/quick/quicktestframework.cpp
index 39763bc07a..e4fecb1daf 100644
--- a/src/plugins/autotest/quick/quicktestframework.cpp
+++ b/src/plugins/autotest/quick/quicktestframework.cpp
@@ -42,7 +42,7 @@ ITestParser *QuickTestFramework::createTestParser()
ITestTreeItem *QuickTestFramework::createRootNode()
{
return new QuickTestTreeItem(this, QCoreApplication::translate("QuickTestFramework", "Quick Test"),
- QString(), ITestTreeItem::Root);
+ Utils::FilePath(), ITestTreeItem::Root);
}
const char *QuickTestFramework::name() const
diff --git a/src/plugins/autotest/quick/quicktestparser.cpp b/src/plugins/autotest/quick/quicktestparser.cpp
index c08d0da3cf..fdd045bb31 100644
--- a/src/plugins/autotest/quick/quicktestparser.cpp
+++ b/src/plugins/autotest/quick/quicktestparser.cpp
@@ -91,7 +91,7 @@ static bool includesQtQuickTest(const CPlusPlus::Document::Ptr &doc,
}
static QString quickTestSrcDir(const CppTools::CppModelManager *cppMM,
- const QString &fileName)
+ const Utils::FilePath &fileName)
{
const QList<CppTools::ProjectPart::Ptr> parts = cppMM->projectPart(fileName);
if (parts.size() > 0) {
@@ -122,14 +122,14 @@ QString QuickTestParser::quickTestName(const CPlusPlus::Document::Ptr &doc) cons
const QByteArray name = macro.macro().name();
if (QuickTestUtils::isQuickTestMacro(name)) {
CPlusPlus::Document::Block arg = macro.arguments().at(0);
- return QLatin1String(getFileContent(doc->fileName())
+ return QLatin1String(getFileContent(Utils::FilePath::fromString(doc->fileName()))
.mid(int(arg.bytesBegin()), int(arg.bytesEnd() - arg.bytesBegin())));
}
}
// check for using quick_test_main() directly
const QString fileName = doc->fileName();
- const QByteArray &fileContent = getFileContent(fileName);
+ const QByteArray &fileContent = getFileContent(Utils::FilePath::fromString(fileName));
CPlusPlus::Document::Ptr document = m_cppSnapshot.preprocessedDocument(fileContent, fileName);
if (document.isNull())
return QString();
@@ -182,7 +182,7 @@ QList<Document::Ptr> QuickTestParser::scanDirectoryForQuickTestQmlFiles(const QS
static bool checkQmlDocumentForQuickTestCode(QFutureInterface<TestParseResultPtr> futureInterface,
const Document::Ptr &qmlJSDoc,
ITestFramework *framework,
- const QString &proFile = QString())
+ const Utils::FilePath &proFile = Utils::FilePath())
{
if (qmlJSDoc.isNull())
return false;
@@ -203,7 +203,7 @@ static bool checkQmlDocumentForQuickTestCode(QFutureInterface<TestParseResultPtr
parseResult->proFile = proFile;
parseResult->itemType = TestTreeItem::TestCase;
if (!testCaseName.isEmpty()) {
- parseResult->fileName = testCase.m_locationAndType.m_name;
+ parseResult->fileName = Utils::FilePath::fromString(testCase.m_locationAndType.m_name);
parseResult->name = testCaseName;
parseResult->line = testCase.m_locationAndType.m_line;
parseResult->column = testCase.m_locationAndType.m_column;
@@ -214,7 +214,7 @@ static bool checkQmlDocumentForQuickTestCode(QFutureInterface<TestParseResultPtr
funcResult->name = function.m_functionName;
funcResult->displayName = function.m_functionName;
funcResult->itemType = function.m_locationAndType.m_type;
- funcResult->fileName = function.m_locationAndType.m_name;
+ funcResult->fileName = Utils::FilePath::fromString(function.m_locationAndType.m_name);
funcResult->line = function.m_locationAndType.m_line;
funcResult->column = function.m_locationAndType.m_column;
funcResult->proFile = proFile;
@@ -235,11 +235,11 @@ bool QuickTestParser::handleQtQuickTest(QFutureInterface<TestParseResultPtr> fut
if (quickTestName(document).isEmpty())
return false;
- const QString cppFileName = document->fileName();
- QList<CppTools::ProjectPart::Ptr> ppList = modelManager->projectPart(cppFileName);
+ QList<CppTools::ProjectPart::Ptr> ppList = modelManager->projectPart(document->fileName());
if (ppList.isEmpty()) // happens if shutting down while parsing
return false;
- const QString &proFile = ppList.at(0)->projectFile;
+ const Utils::FilePath cppFileName = Utils::FilePath::fromString(document->fileName());
+ const Utils::FilePath proFile = Utils::FilePath::fromString(ppList.at(0)->projectFile);
m_mainCppFiles.insert(cppFileName, proFile);
const QString srcDir = quickTestSrcDir(modelManager, cppFileName);
if (srcDir.isEmpty())
@@ -315,14 +315,14 @@ QuickTestParser::QuickTestParser(ITestFramework *framework)
this, &QuickTestParser::handleDirectoryChanged);
}
-void QuickTestParser::init(const QStringList &filesToParse, bool fullParse)
+void QuickTestParser::init(const Utils::FilePaths &filesToParse, bool fullParse)
{
m_qmlSnapshot = QmlJSTools::Internal::ModelManager::instance()->snapshot();
if (!fullParse) {
// in a full parse we get the correct entry points by the respective main
m_proFilesForQmlFiles = QuickTestUtils::proFilesForQmlFiles(framework(), filesToParse);
// get rid of cached main cpp files that are going to get processed anyhow
- for (const QString &file : filesToParse) {
+ for (const Utils::FilePath &file : filesToParse) {
if (m_mainCppFiles.contains(file)) {
m_mainCppFiles.remove(file);
if (m_mainCppFiles.isEmpty())
@@ -344,13 +344,13 @@ void QuickTestParser::release()
}
bool QuickTestParser::processDocument(QFutureInterface<TestParseResultPtr> futureInterface,
- const QString &fileName)
+ const Utils::FilePath &fileName)
{
if (fileName.endsWith(".qml")) {
- const QString &proFile = m_proFilesForQmlFiles.value(fileName);
+ const Utils::FilePath &proFile = m_proFilesForQmlFiles.value(fileName);
if (proFile.isEmpty())
return false;
- Document::Ptr qmlJSDoc = m_qmlSnapshot.document(fileName);
+ Document::Ptr qmlJSDoc = m_qmlSnapshot.document(fileName.toString());
return checkQmlDocumentForQuickTestCode(futureInterface, qmlJSDoc, framework(), proFile);
}
if (!m_cppSnapshot.contains(fileName) || !selectedForBuilding(fileName))
@@ -361,9 +361,9 @@ bool QuickTestParser::processDocument(QFutureInterface<TestParseResultPtr> futur
return handleQtQuickTest(futureInterface, document, framework());
}
-QString QuickTestParser::projectFileForMainCppFile(const QString &fileName) const
+Utils::FilePath QuickTestParser::projectFileForMainCppFile(const Utils::FilePath &fileName) const
{
- return m_mainCppFiles.contains(fileName) ? m_mainCppFiles.value(fileName) : QString();
+ return m_mainCppFiles.contains(fileName) ? m_mainCppFiles.value(fileName) : Utils::FilePath();
}
} // namespace Internal
diff --git a/src/plugins/autotest/quick/quicktestparser.h b/src/plugins/autotest/quick/quicktestparser.h
index 51dde56fe6..440e54a73e 100644
--- a/src/plugins/autotest/quick/quicktestparser.h
+++ b/src/plugins/autotest/quick/quicktestparser.h
@@ -46,11 +46,11 @@ class QuickTestParser : public QObject, public CppParser
Q_OBJECT
public:
explicit QuickTestParser(ITestFramework *framework);
- void init(const QStringList &filesToParse, bool fullParse) override;
+ void init(const Utils::FilePaths &filesToParse, bool fullParse) override;
void release() override;
bool processDocument(QFutureInterface<TestParseResultPtr> futureInterface,
- const QString &fileName) override;
- QString projectFileForMainCppFile(const QString &fileName) const;
+ const Utils::FilePath &fileName) override;
+ Utils::FilePath projectFileForMainCppFile(const Utils::FilePath &fileName) const;
private:
bool handleQtQuickTest(QFutureInterface<TestParseResultPtr> futureInterface,
CPlusPlus::Document::Ptr document, ITestFramework *framework);
@@ -59,10 +59,10 @@ private:
QString quickTestName(const CPlusPlus::Document::Ptr &doc) const;
QList<QmlJS::Document::Ptr> scanDirectoryForQuickTestQmlFiles(const QString &srcDir);
QmlJS::Snapshot m_qmlSnapshot;
- QHash<QString, QString> m_proFilesForQmlFiles;
+ QHash<Utils::FilePath, Utils::FilePath> m_proFilesForQmlFiles;
QFileSystemWatcher m_directoryWatcher;
QMap<QString, QMap<QString, QDateTime> > m_watchedFiles;
- QMap<QString, QString> m_mainCppFiles;
+ QMap<Utils::FilePath, Utils::FilePath> m_mainCppFiles;
};
} // namespace Internal
diff --git a/src/plugins/autotest/quick/quicktesttreeitem.cpp b/src/plugins/autotest/quick/quicktesttreeitem.cpp
index d93df66759..ad42099720 100644
--- a/src/plugins/autotest/quick/quicktesttreeitem.cpp
+++ b/src/plugins/autotest/quick/quicktesttreeitem.cpp
@@ -36,6 +36,8 @@
namespace Autotest {
namespace Internal {
+QSet<QString> internalTargets(const Utils::FilePath &proFile);
+
TestTreeItem *QuickTestTreeItem::copyWithoutChildren()
{
QuickTestTreeItem *copied = new QuickTestTreeItem(framework());
@@ -156,7 +158,7 @@ ITestConfiguration *QuickTestTreeItem::testConfiguration() const
return nullptr;
}
if (config)
- config->setInternalTargets(internalTargets());
+ config->setInternalTargets(internalTargets(proFile()));
return config;
}
@@ -168,7 +170,7 @@ static QList<ITestConfiguration *> testConfigurationsFor(
if (!project || rootNode->type() != TestTreeItem::Root)
return {};
- QHash<QString, QuickTestConfiguration *> configurationForProFiles;
+ QHash<Utils::FilePath, QuickTestConfiguration *> configurationForProFiles;
rootNode->forSelectedChildren([&predicate, &configurationForProFiles](Utils::TreeItem *it) {
auto treeItem = static_cast<TestTreeItem *>(it);
if (treeItem->type() == TestTreeItem::Root || treeItem->type() == TestTreeItem::GroupNode)
@@ -189,7 +191,7 @@ static QList<ITestConfiguration *> testConfigurationsFor(
auto tc = new QuickTestConfiguration(treeItem->framework());
tc->setProjectFile(treeItem->proFile());
tc->setProject(ProjectExplorer::SessionManager::startupProject());
- tc->setInternalTargets(treeItem->internalTargets());
+ tc->setInternalTargets(internalTargets(treeItem->proFile()));
it = configurationForProFiles.insert(treeItem->proFile(), tc);
}
it.value()->setTestCases(it.value()->testCases() + functions);
@@ -216,7 +218,7 @@ struct Tests {
static void addTestsForItem(Tests &tests, const TestTreeItem *item)
{
tests.testCount += item->childCount();
- tests.internalTargets = item->internalTargets();
+ tests.internalTargets = internalTargets(item->proFile());
}
QList<ITestConfiguration *> QuickTestTreeItem::getAllTestConfigurations() const
@@ -227,14 +229,14 @@ QList<ITestConfiguration *> QuickTestTreeItem::getAllTestConfigurations() const
if (!project || type() != Root)
return result;
- QHash<QString, Tests> testsForProfile;
+ QHash<Utils::FilePath, Tests> testsForProfile;
forFirstLevelChildItems([&testsForProfile](TestTreeItem *child) {
// unnamed Quick Tests must be handled separately
if (child->name().isEmpty()) {
child->forFirstLevelChildItems([&testsForProfile](TestTreeItem *grandChild) {
- const QString &proFile = grandChild->proFile();
+ const Utils::FilePath &proFile = grandChild->proFile();
++(testsForProfile[proFile].testCount);
- testsForProfile[proFile].internalTargets = grandChild->internalTargets();
+ testsForProfile[proFile].internalTargets = internalTargets(grandChild->proFile());
});
return;
}
@@ -276,9 +278,8 @@ QList<ITestConfiguration *> QuickTestTreeItem::getFailedTestConfigurations() con
QList<ITestConfiguration *> QuickTestTreeItem::getTestConfigurationsForFile(
const Utils::FilePath &fileName) const
{
- const QString &file = fileName.toString();
- return testConfigurationsFor(this, [&file](TestTreeItem *it) {
- return it->filePath() == file;
+ return testConfigurationsFor(this, [&fileName](TestTreeItem *it) {
+ return it->filePath() == fileName;
});
}
@@ -291,7 +292,7 @@ TestTreeItem *QuickTestTreeItem::find(const TestParseResult *result)
if (result->name.isEmpty())
return unnamedQuickTests();
if (result->framework->grouping()) {
- const QString path = QFileInfo(result->fileName).absolutePath();
+ const Utils::FilePath path = result->fileName.absolutePath();
TestTreeItem *group = findFirstLevelChildItem([path](TestTreeItem *group) {
return group->filePath() == path;
});
@@ -374,9 +375,8 @@ bool QuickTestTreeItem::removeOnSweepIfEmpty() const
TestTreeItem *QuickTestTreeItem::createParentGroupNode() const
{
- const QFileInfo fileInfo(filePath());
- const QFileInfo base(fileInfo.absolutePath());
- return new QuickTestTreeItem(framework(), base.baseName(), fileInfo.absolutePath(), TestTreeItem::GroupNode);
+ const QFileInfo base = filePath().absolutePath().toFileInfo();
+ return new QuickTestTreeItem(framework(), base.baseName(), filePath().absolutePath(), TestTreeItem::GroupNode);
}
bool QuickTestTreeItem::isGroupable() const
@@ -384,7 +384,7 @@ bool QuickTestTreeItem::isGroupable() const
return type() == TestCase && !name().isEmpty() && !filePath().isEmpty();
}
-QSet<QString> QuickTestTreeItem::internalTargets() const
+QSet<QString> internalTargets(const Utils::FilePath &proFile)
{
QSet<QString> result;
const auto cppMM = CppTools::CppModelManager::instance();
@@ -392,17 +392,17 @@ QSet<QString> QuickTestTreeItem::internalTargets() const
for (const CppTools::ProjectPart::Ptr &projectPart : projectInfo.projectParts()) {
if (projectPart->buildTargetType != ProjectExplorer::BuildTargetType::Executable)
continue;
- if (projectPart->projectFile == proFile())
+ if (projectPart->projectFile == proFile.toString())
result.insert(projectPart->buildSystemTarget);
}
return result;
}
-void QuickTestTreeItem::markForRemovalRecursively(const QString &filePath)
+void QuickTestTreeItem::markForRemovalRecursively(const Utils::FilePath &filePath)
{
TestTreeItem::markForRemovalRecursively(filePath);
- auto parser = dynamic_cast<QuickTestParser *>(framework()->testParser());
- const QString proFile = parser->projectFileForMainCppFile(filePath);
+ auto parser = static_cast<QuickTestParser *>(framework()->testParser());
+ const Utils::FilePath proFile = parser->projectFileForMainCppFile(filePath);
if (!proFile.isEmpty()) {
TestTreeItem *root = framework()->rootNode();
root->forAllChildItems([proFile](TestTreeItem *it) {
@@ -412,7 +412,7 @@ void QuickTestTreeItem::markForRemovalRecursively(const QString &filePath)
}
}
-TestTreeItem *QuickTestTreeItem::findChildByFileNameAndType(const QString &filePath,
+TestTreeItem *QuickTestTreeItem::findChildByFileNameAndType(const Utils::FilePath &filePath,
const QString &name,
TestTreeItem::Type tType)
@@ -423,7 +423,8 @@ TestTreeItem *QuickTestTreeItem::findChildByFileNameAndType(const QString &fileP
}
TestTreeItem *QuickTestTreeItem::findChildByNameFileAndLine(const QString &name,
- const QString &filePath, int line)
+ const Utils::FilePath &filePath,
+ int line)
{
return findFirstLevelChildItem([name, filePath, line](const TestTreeItem *other) {
return other->filePath() == filePath && other->line() == line && other->name() == name;
diff --git a/src/plugins/autotest/quick/quicktesttreeitem.h b/src/plugins/autotest/quick/quicktesttreeitem.h
index a599c6ceab..f9977b1bec 100644
--- a/src/plugins/autotest/quick/quicktesttreeitem.h
+++ b/src/plugins/autotest/quick/quicktesttreeitem.h
@@ -35,7 +35,7 @@ class QuickTestTreeItem : public TestTreeItem
public:
explicit QuickTestTreeItem(ITestFramework *testFramework,
const QString &name = QString(),
- const QString &filePath = QString(),
+ const Utils::FilePath &filePath = Utils::FilePath(),
Type type = Root)
: TestTreeItem(testFramework, name, filePath, type)
{}
@@ -59,12 +59,11 @@ public:
bool removeOnSweepIfEmpty() const override;
TestTreeItem *createParentGroupNode() const override;
bool isGroupable() const override;
- QSet<QString> internalTargets() const override;
- void markForRemovalRecursively(const QString &filePath) override;
+ void markForRemovalRecursively(const Utils::FilePath &filePath) override;
private:
- TestTreeItem *findChildByFileNameAndType(const QString &filePath, const QString &name,
+ TestTreeItem *findChildByFileNameAndType(const Utils::FilePath &filePath, const QString &name,
Type tType);
- TestTreeItem *findChildByNameFileAndLine(const QString &name, const QString &filePath,
+ TestTreeItem *findChildByNameFileAndLine(const QString &name, const Utils::FilePath &filePath,
int line);
TestTreeItem *unnamedQuickTests() const;
};
diff --git a/src/plugins/autotest/testcodeparser.cpp b/src/plugins/autotest/testcodeparser.cpp
index c2afe3846d..f2fc52778d 100644
--- a/src/plugins/autotest/testcodeparser.cpp
+++ b/src/plugins/autotest/testcodeparser.cpp
@@ -163,12 +163,12 @@ void TestCodeParser::updateTestTree(const QSet<ITestParser *> &parsers)
Utils::sort(sortedParsers, [](const ITestParser *lhs, const ITestParser *rhs) {
return lhs->framework()->priority() < rhs->framework()->priority();
});
- scanForTests(QStringList(), sortedParsers);
+ scanForTests(Utils::FilePaths(), sortedParsers);
}
/****** threaded parsing stuff *******/
-void TestCodeParser::onDocumentUpdated(const QString &fileName, bool isQmlFile)
+void TestCodeParser::onDocumentUpdated(const Utils::FilePath &fileName, bool isQmlFile)
{
if (m_codeModelParsing || m_fullUpdatePostponed)
return;
@@ -177,22 +177,22 @@ void TestCodeParser::onDocumentUpdated(const QString &fileName, bool isQmlFile)
if (!project)
return;
// Quick tests: qml files aren't necessarily listed inside project files
- if (!isQmlFile && !project->isKnownFile(Utils::FilePath::fromString(fileName)))
+ if (!isQmlFile && !project->isKnownFile(fileName))
return;
- scanForTests(QStringList(fileName));
+ scanForTests(Utils::FilePaths{fileName});
}
void TestCodeParser::onCppDocumentUpdated(const CPlusPlus::Document::Ptr &document)
{
- onDocumentUpdated(document->fileName());
+ onDocumentUpdated(Utils::FilePath::fromString(document->fileName()));
}
void TestCodeParser::onQmlDocumentUpdated(const QmlJS::Document::Ptr &document)
{
const QString fileName = document->fileName();
if (!fileName.endsWith(".qbs"))
- onDocumentUpdated(fileName, true);
+ onDocumentUpdated(Utils::FilePath::fromString(fileName), true);
}
void TestCodeParser::onStartupProjectChanged(Project *project)
@@ -227,7 +227,7 @@ void TestCodeParser::aboutToShutdown()
}
}
-bool TestCodeParser::postponed(const QStringList &fileList)
+bool TestCodeParser::postponed(const Utils::FilePaths &fileList)
{
switch (m_parserState) {
case Idle:
@@ -270,7 +270,7 @@ bool TestCodeParser::postponed(const QStringList &fileList)
if (m_fullUpdatePostponed)
return true;
// partial parse triggered, postpone or add current files to already postponed partial
- for (const QString &file : fileList)
+ for (const Utils::FilePath &file : fileList)
m_postponedFiles.insert(file);
m_partialUpdatePostponed = true;
}
@@ -283,7 +283,7 @@ bool TestCodeParser::postponed(const QStringList &fileList)
static void parseFileForTests(const QList<ITestParser *> &parsers,
QFutureInterface<TestParseResultPtr> &futureInterface,
- const QString &fileName)
+ const Utils::FilePath &fileName)
{
for (ITestParser *parser : parsers) {
if (futureInterface.isCanceled())
@@ -293,7 +293,8 @@ static void parseFileForTests(const QList<ITestParser *> &parsers,
}
}
-void TestCodeParser::scanForTests(const QStringList &fileList, const QList<ITestParser *> &parsers)
+void TestCodeParser::scanForTests(const Utils::FilePaths &fileList,
+ const QList<ITestParser *> &parsers)
{
if (m_parserState == Shutdown || m_testCodeParsers.isEmpty())
return;
@@ -308,9 +309,9 @@ void TestCodeParser::scanForTests(const QStringList &fileList, const QList<ITest
Project *project = SessionManager::startupProject();
if (!project)
return;
- QStringList list;
+ Utils::FilePaths list;
if (isFullParse) {
- list = Utils::transform(project->files(Project::SourceFiles), &Utils::FilePath::toString);
+ list = project->files(Project::SourceFiles);
if (list.isEmpty()) {
// at least project file should be there, but might happen if parsing current project
// takes too long, especially when opening sessions holding multiple projects
@@ -330,7 +331,7 @@ void TestCodeParser::scanForTests(const QStringList &fileList, const QList<ITest
TestTreeModel::instance()->updateCheckStateCache();
if (isFullParse) {
// remove qml files as they will be found automatically by the referencing cpp file
- list = Utils::filtered(list, [] (const QString &fn) {
+ list = Utils::filtered(list, [] (const Utils::FilePath &fn) {
return !fn.endsWith(".qml");
});
if (!parsers.isEmpty()) {
@@ -342,12 +343,11 @@ void TestCodeParser::scanForTests(const QStringList &fileList, const QList<ITest
}
} else if (!parsers.isEmpty()) {
for (ITestParser *parser: parsers) {
- for (const QString &filePath : qAsConst(list)) {
+ for (const Utils::FilePath &filePath : qAsConst(list))
parser->framework()->rootNode()->markForRemovalRecursively(filePath);
- }
}
} else {
- for (const QString &filePath : qAsConst(list))
+ for (const Utils::FilePath &filePath : qAsConst(list))
emit requestRemoval(filePath);
}
@@ -360,7 +360,7 @@ void TestCodeParser::scanForTests(const QStringList &fileList, const QList<ITest
parser->init(list, isFullParse);
QFuture<TestParseResultPtr> future = Utils::map(list,
- [codeParsers](QFutureInterface<TestParseResultPtr> &fi, const QString &file) {
+ [codeParsers](QFutureInterface<TestParseResultPtr> &fi, const Utils::FilePath &file) {
parseFileForTests(codeParsers, fi, file);
},
Utils::MapReduceOption::Unordered,
diff --git a/src/plugins/autotest/testcodeparser.h b/src/plugins/autotest/testcodeparser.h
index c426c274da..85e6f505fe 100644
--- a/src/plugins/autotest/testcodeparser.h
+++ b/src/plugins/autotest/testcodeparser.h
@@ -74,7 +74,7 @@ signals:
void parsingStarted();
void parsingFinished();
void parsingFailed();
- void requestRemoval(const QString &filePath);
+ void requestRemoval(const Utils::FilePath &filePath);
void requestRemoveAllFrameworkItems();
public:
@@ -87,12 +87,12 @@ public:
void aboutToShutdown();
private:
- bool postponed(const QStringList &fileList);
- void scanForTests(const QStringList &fileList = QStringList(),
+ bool postponed(const Utils::FilePaths &fileList);
+ void scanForTests(const Utils::FilePaths &fileList = Utils::FilePaths(),
const QList<ITestParser *> &parsers = {});
// qml files must be handled slightly different
- void onDocumentUpdated(const QString &fileName, bool isQmlFile = false);
+ void onDocumentUpdated(const Utils::FilePath &fileName, bool isQmlFile = false);
void onTaskStarted(Utils::Id type);
void onAllTasksFinished(Utils::Id type);
void onFinished();
@@ -110,7 +110,7 @@ private:
bool m_dirty = false;
bool m_singleShotScheduled = false;
bool m_reparseTimerTimedOut = false;
- QSet<QString> m_postponedFiles;
+ QSet<Utils::FilePath> m_postponedFiles;
State m_parserState = Idle;
QFutureWatcher<TestParseResultPtr> m_futureWatcher;
QList<ITestParser *> m_testCodeParsers; // ptrs are still owned by TestFrameworkManager
diff --git a/src/plugins/autotest/testconfiguration.cpp b/src/plugins/autotest/testconfiguration.cpp
index 4e032e8a6e..e15fe3ac57 100644
--- a/src/plugins/autotest/testconfiguration.cpp
+++ b/src/plugins/autotest/testconfiguration.cpp
@@ -62,16 +62,16 @@ void ITestConfiguration::setWorkingDirectory(const QString &workingDirectory)
m_runnable.workingDirectory = workingDirectory;
}
-QString ITestConfiguration::workingDirectory() const
+Utils::FilePath ITestConfiguration::workingDirectory() const
{
if (!m_runnable.workingDirectory.isEmpty()) {
const QFileInfo info(m_runnable.workingDirectory);
if (info.isDir()) // ensure wanted working dir does exist
- return info.absoluteFilePath();
+ return Utils::FilePath::fromString(info.absoluteFilePath());
}
- const QString executable = executableFilePath();
- return executable.isEmpty() ? executable : QFileInfo(executable).absolutePath();
+ const Utils::FilePath executable = executableFilePath();
+ return executable.isEmpty() ? executable : executable.absolutePath();
}
bool ITestConfiguration::hasExecutable() const
@@ -79,15 +79,15 @@ bool ITestConfiguration::hasExecutable() const
return !m_runnable.executable.isEmpty();
}
-QString ITestConfiguration::executableFilePath() const
+Utils::FilePath ITestConfiguration::executableFilePath() const
{
if (!hasExecutable())
- return QString();
+ return {};
QFileInfo commandFileInfo = m_runnable.executable.toFileInfo();
- if (commandFileInfo.isExecutable() && commandFileInfo.path() != ".") {
- return commandFileInfo.absoluteFilePath();
- } else if (commandFileInfo.path() == "."){
+ if (m_runnable.executable.isExecutableFile() && m_runnable.executable.path() != ".") {
+ return m_runnable.executable.absoluteFilePath();
+ } else if (m_runnable.executable.path() == "."){
QString fullCommandFileName = m_runnable.executable.toString();
// TODO: check if we can use searchInPath() from Utils::Environment
const QStringList &pathList = m_runnable.environment.toProcessEnvironment().value("PATH")
@@ -96,10 +96,10 @@ QString ITestConfiguration::executableFilePath() const
for (const QString &path : pathList) {
QString filePath(path + QDir::separator() + fullCommandFileName);
if (QFileInfo(filePath).isExecutable())
- return commandFileInfo.absoluteFilePath();
+ return m_runnable.executable.absoluteFilePath();
}
}
- return QString();
+ return {};
}
Environment ITestConfiguration::filteredEnvironment(const Environment &original) const
@@ -158,12 +158,12 @@ void TestConfiguration::completeTestInformation(ProjectExplorer::RunConfiguratio
if (!targetInfo.targetFilePath.isEmpty())
m_runnable.executable = ensureExeEnding(targetInfo.targetFilePath);
- QString buildBase;
+ Utils::FilePath buildBase;
if (auto buildConfig = target->activeBuildConfiguration()) {
- buildBase = buildConfig->buildDirectory().toString();
+ buildBase = buildConfig->buildDirectory();
const QString projBase = startupProject->projectDirectory().toString();
if (m_projectFile.startsWith(projBase))
- m_buildDir = QFileInfo(buildBase + m_projectFile.mid(projBase.length())).absolutePath();
+ m_buildDir = (buildBase / m_projectFile.toString().mid(projBase.length())).absolutePath();
}
if (runMode == TestRunMode::Debug || runMode == TestRunMode::DebugWithoutDeploy)
m_runConfig = new Internal::TestRunConfiguration(rc->target(), this);
@@ -225,12 +225,12 @@ void TestConfiguration::completeTestInformation(TestRunMode runMode)
if (localExecutable.isEmpty())
return;
- QString buildBase;
+ Utils::FilePath buildBase;
if (auto buildConfig = target->activeBuildConfiguration()) {
- buildBase = buildConfig->buildDirectory().toString();
+ buildBase = buildConfig->buildDirectory();
const QString projBase = startupProject->projectDirectory().toString();
if (m_projectFile.startsWith(projBase))
- m_buildDir = QFileInfo(buildBase + m_projectFile.mid(projBase.length())).absolutePath();
+ m_buildDir = (buildBase / m_projectFile.toString().mid(projBase.length())).absolutePath();
}
// deployment information should get taken into account, but it pretty much seems as if
@@ -323,12 +323,12 @@ void TestConfiguration::setExecutableFile(const QString &executableFile)
m_runnable.executable = Utils::FilePath::fromString(executableFile);
}
-void TestConfiguration::setProjectFile(const QString &projectFile)
+void TestConfiguration::setProjectFile(const Utils::FilePath &projectFile)
{
m_projectFile = projectFile;
}
-void TestConfiguration::setBuildDirectory(const QString &buildDirectory)
+void TestConfiguration::setBuildDirectory(const FilePath &buildDirectory)
{
m_buildDir = buildDirectory;
}
diff --git a/src/plugins/autotest/testconfiguration.h b/src/plugins/autotest/testconfiguration.h
index a065c045f9..2d6c36544d 100644
--- a/src/plugins/autotest/testconfiguration.h
+++ b/src/plugins/autotest/testconfiguration.h
@@ -61,9 +61,9 @@ public:
void setEnvironment(const Utils::Environment &env) { m_runnable.environment = env; }
Utils::Environment environment() const { return m_runnable.environment; }
void setWorkingDirectory(const QString &workingDirectory);
- QString workingDirectory() const;
+ Utils::FilePath workingDirectory() const;
bool hasExecutable() const;
- QString executableFilePath() const;
+ Utils::FilePath executableFilePath() const;
virtual TestOutputReader *outputReader(const QFutureInterface<TestResultPtr> &fi,
QProcess *app) const = 0;
@@ -99,16 +99,16 @@ public:
void setTestCases(const QStringList &testCases);
void setExecutableFile(const QString &executableFile);
- void setProjectFile(const QString &projectFile);
- void setBuildDirectory(const QString &buildDirectory);
+ void setProjectFile(const Utils::FilePath &projectFile);
+ void setBuildDirectory(const Utils::FilePath &buildDirectory);
void setInternalTarget(const QString &target);
void setInternalTargets(const QSet<QString> &targets);
void setOriginalRunConfiguration(ProjectExplorer::RunConfiguration *runConfig);
ITestFramework *framework() const;
QStringList testCases() const { return m_testCases; }
- QString buildDirectory() const { return m_buildDir; }
- QString projectFile() const { return m_projectFile; }
+ Utils::FilePath buildDirectory() const { return m_buildDir; }
+ Utils::FilePath projectFile() const { return m_projectFile; }
QSet<QString> internalTargets() const { return m_buildTargets; }
ProjectExplorer::RunConfiguration *originalRunConfiguration() const { return m_origRunConfig; }
Internal::TestRunConfiguration *runConfiguration() const { return m_runConfig; }
@@ -120,8 +120,8 @@ public:
private:
QStringList m_testCases;
- QString m_projectFile;
- QString m_buildDir;
+ Utils::FilePath m_projectFile;
+ Utils::FilePath m_buildDir;
QString m_deducedFrom;
bool m_deducedConfiguration = false;
Internal::TestRunConfiguration *m_runConfig = nullptr;
diff --git a/src/plugins/autotest/testframeworkmanager.cpp b/src/plugins/autotest/testframeworkmanager.cpp
index d6edee794c..b7ec3dc022 100644
--- a/src/plugins/autotest/testframeworkmanager.cpp
+++ b/src/plugins/autotest/testframeworkmanager.cpp
@@ -27,9 +27,9 @@
#include "autotestconstants.h"
#include "autotestplugin.h"
-#include "itestsettings.h"
#include "testsettings.h"
+#include <utils/aspects.h>
#include <utils/algorithm.h>
#include <utils/qtcassert.h>
@@ -123,7 +123,7 @@ void TestFrameworkManager::synchronizeSettings(QSettings *s)
Internal::AutotestPlugin::settings()->fromSettings(s);
for (ITestFramework *framework : qAsConst(m_registeredFrameworks)) {
if (ITestSettings *fSettings = framework->testSettings())
- fSettings->fromSettings(s);
+ fSettings->readSettings(s);
}
}
diff --git a/src/plugins/autotest/testnavigationwidget.cpp b/src/plugins/autotest/testnavigationwidget.cpp
index 32505ddaf0..7a8e757662 100644
--- a/src/plugins/autotest/testnavigationwidget.cpp
+++ b/src/plugins/autotest/testnavigationwidget.cpp
@@ -266,10 +266,8 @@ void TestNavigationWidget::updateExpandedStateCache()
void TestNavigationWidget::onItemActivated(const QModelIndex &index)
{
const Utils::Link link = index.data(LinkRole).value<Utils::Link>();
- if (link.hasValidTarget()) {
- Core::EditorManager::openEditorAt(link.targetFileName, link.targetLine,
- link.targetColumn);
- }
+ if (link.hasValidTarget())
+ Core::EditorManager::openEditorAt(link);
}
void TestNavigationWidget::onSortClicked()
@@ -357,10 +355,7 @@ TestNavigationWidgetFactory::TestNavigationWidgetFactory()
Core::NavigationView TestNavigationWidgetFactory::createWidget()
{
TestNavigationWidget *treeViewWidget = new TestNavigationWidget;
- Core::NavigationView view;
- view.widget = treeViewWidget;
- view.dockToolBarWidgets = treeViewWidget->createToolButtons();
- return view;
+ return {treeViewWidget, treeViewWidget->createToolButtons()};
}
} // namespace Internal
diff --git a/src/plugins/autotest/testnavigationwidget.h b/src/plugins/autotest/testnavigationwidget.h
index f2fb9caae3..73c45a4509 100644
--- a/src/plugins/autotest/testnavigationwidget.h
+++ b/src/plugins/autotest/testnavigationwidget.h
@@ -38,10 +38,6 @@ class QTimer;
class QToolButton;
QT_END_NAMESPACE
-namespace Core {
-class IContext;
-}
-
namespace Utils {
class ProgressIndicator;
}
diff --git a/src/plugins/autotest/testoutputreader.cpp b/src/plugins/autotest/testoutputreader.cpp
index dcbb61a0c2..403f086de5 100644
--- a/src/plugins/autotest/testoutputreader.cpp
+++ b/src/plugins/autotest/testoutputreader.cpp
@@ -38,8 +38,16 @@
namespace Autotest {
+Utils::FilePath TestOutputReader::constructSourceFilePath(const Utils::FilePath &path,
+ const QString &filePath)
+{
+ if (!filePath.isEmpty() && filePath.at(0) != '.')
+ return Utils::FilePath::fromFileInfo(QFileInfo(filePath));
+ return (path / filePath).canonicalPath();
+}
+
TestOutputReader::TestOutputReader(const QFutureInterface<TestResultPtr> &futureInterface,
- QProcess *testApplication, const QString &buildDirectory)
+ QProcess *testApplication, const Utils::FilePath &buildDirectory)
: m_futureInterface(futureInterface)
, m_testApplication(testApplication)
, m_buildDir(buildDirectory)
@@ -167,9 +175,11 @@ void TestOutputReader::checkForSanitizerOutput(const QByteArray &line)
m_sanitizerLines.append("Sanitizer Issue");
m_sanitizerLines.append(lineStr);
if (m_sanitizerOutputMode == SanitizerOutputMode::Ubsan) {
- const QString path = QFileInfo(m_buildDir, match.captured(1)).canonicalFilePath();
+ const Utils::FilePath path = constructSourceFilePath(m_buildDir, match.captured(1));
// path may be empty if not existing - so, provide at least what we have
- m_sanitizerResult->setFileName(path.isEmpty() ? match.captured(1) : path);
+ m_sanitizerResult->setFileName(path.isEmpty()
+ ? Utils::FilePath::fromString(match.captured(1))
+ : path);
m_sanitizerResult->setLine(match.captured(2).toInt());
}
}
diff --git a/src/plugins/autotest/testoutputreader.h b/src/plugins/autotest/testoutputreader.h
index d4dd5c4698..b3d7cc3476 100644
--- a/src/plugins/autotest/testoutputreader.h
+++ b/src/plugins/autotest/testoutputreader.h
@@ -39,7 +39,7 @@ class TestOutputReader : public QObject
Q_OBJECT
public:
TestOutputReader(const QFutureInterface<TestResultPtr> &futureInterface,
- QProcess *testApplication, const QString &buildDirectory);
+ QProcess *testApplication, const Utils::FilePath &buildDirectory);
virtual ~TestOutputReader();
void processStdOutput(const QByteArray &outputLine);
virtual void processStdError(const QByteArray &outputLine);
@@ -56,6 +56,9 @@ public:
signals:
void newOutputLineAvailable(const QByteArray &outputLine, OutputChannel channel);
protected:
+ static Utils::FilePath constructSourceFilePath(const Utils::FilePath &base,
+ const QString &file);
+
QString removeCommandlineColors(const QString &original);
virtual void processOutputLine(const QByteArray &outputLine) = 0;
virtual TestResultPtr createDefaultResult() const = 0;
@@ -65,7 +68,7 @@ protected:
void reportResult(const TestResultPtr &result);
QFutureInterface<TestResultPtr> m_futureInterface;
QProcess *m_testApplication; // not owned
- QString m_buildDir;
+ Utils::FilePath m_buildDir;
QString m_id;
QHash<ResultType, int> m_summary;
int m_disabled = -1;
diff --git a/src/plugins/autotest/testresult.h b/src/plugins/autotest/testresult.h
index af8ba7e450..e1081fe952 100644
--- a/src/plugins/autotest/testresult.h
+++ b/src/plugins/autotest/testresult.h
@@ -27,6 +27,8 @@
#include "autotestconstants.h"
+#include <utils/fileutils.h>
+
#include <QColor>
#include <QMetaType>
#include <QSharedPointer>
@@ -92,11 +94,11 @@ public:
QString name() const { return m_name; }
ResultType result() const { return m_result; }
QString description() const { return m_description; }
- QString fileName() const { return m_file; }
+ Utils::FilePath fileName() const { return m_file; }
int line() const { return m_line; }
void setDescription(const QString &description) { m_description = description; }
- void setFileName(const QString &fileName) { m_file = fileName; }
+ void setFileName(const Utils::FilePath &fileName) { m_file = fileName; }
void setLine(int line) { m_line = line; }
void setResult(ResultType type) { m_result = type; }
@@ -113,7 +115,7 @@ private:
QString m_name;
ResultType m_result = ResultType::Invalid; // the real result..
QString m_description;
- QString m_file;
+ Utils::FilePath m_file;
int m_line = 0;
};
diff --git a/src/plugins/autotest/testresultdelegate.cpp b/src/plugins/autotest/testresultdelegate.cpp
index a439c58a5c..f0e7ec111c 100644
--- a/src/plugins/autotest/testresultdelegate.cpp
+++ b/src/plugins/autotest/testresultdelegate.cpp
@@ -117,15 +117,10 @@ void TestResultDelegate::paint(QPainter *painter, const QStyleOptionViewItem &op
fm.elidedText(output.left(2000), Qt::ElideRight, positions.textAreaWidth()));
}
- QString file = testResult->fileName();
- const int pos = file.lastIndexOf('/');
- if (pos != -1)
- file = file.mid(pos + 1);
-
+ const QString file = testResult->fileName().fileName();
painter->setClipRect(positions.fileArea());
painter->drawText(positions.fileAreaLeft(), positions.top() + fm.ascent(), file);
-
if (testResult->line()) {
QString line = QString::number(testResult->line());
painter->setClipRect(positions.lineArea());
diff --git a/src/plugins/autotest/testresultmodel.cpp b/src/plugins/autotest/testresultmodel.cpp
index bc93a3ad65..c4060f4d42 100644
--- a/src/plugins/autotest/testresultmodel.cpp
+++ b/src/plugins/autotest/testresultmodel.cpp
@@ -299,7 +299,7 @@ void TestResultModel::addTestResult(const TestResultPtr &testResult, bool autoEx
}
TestResultItem *parentItem = findParentItemFor(newItem, root);
- addFileName(testResult->fileName()); // ensure we calculate the results pane correctly
+ addFileName(testResult->fileName().fileName()); // ensure we calculate the results pane correctly
if (parentItem) {
parentItem->appendChild(newItem);
if (autoExpand) {
@@ -362,16 +362,14 @@ void TestResultModel::recalculateMaxWidthOfFileName(const QFont &font)
const QFontMetrics fm(font);
m_maxWidthOfFileName = 0;
for (const QString &fileName : qAsConst(m_fileNames)) {
- int pos = fileName.lastIndexOf('/');
- m_maxWidthOfFileName = qMax(m_maxWidthOfFileName, fm.horizontalAdvance(fileName.mid(pos + 1)));
+ m_maxWidthOfFileName = qMax(m_maxWidthOfFileName, fm.horizontalAdvance(fileName));
}
}
void TestResultModel::addFileName(const QString &fileName)
{
const QFontMetrics fm(m_measurementFont);
- int pos = fileName.lastIndexOf('/');
- m_maxWidthOfFileName = qMax(m_maxWidthOfFileName, fm.horizontalAdvance(fileName.mid(pos + 1)));
+ m_maxWidthOfFileName = qMax(m_maxWidthOfFileName, fm.horizontalAdvance(fileName));
m_fileNames.insert(fileName);
}
diff --git a/src/plugins/autotest/testresultspane.cpp b/src/plugins/autotest/testresultspane.cpp
index b4d133d958..b1600eb29e 100644
--- a/src/plugins/autotest/testresultspane.cpp
+++ b/src/plugins/autotest/testresultspane.cpp
@@ -76,6 +76,7 @@ ResultsTreeView::ResultsTreeView(QWidget *parent)
: Utils::TreeView(parent)
{
setAttribute(Qt::WA_MacShowFocusRect, false);
+ setFrameStyle(NoFrame);
}
void ResultsTreeView::keyPressEvent(QKeyEvent *event)
@@ -473,7 +474,7 @@ void TestResultsPane::onItemActivated(const QModelIndex &index)
const TestResult *testResult = m_filterModel->testResult(index);
if (testResult && !testResult->fileName().isEmpty())
- EditorManager::openEditorAt(testResult->fileName(), testResult->line(), 0);
+ EditorManager::openEditorAt(Utils::Link{testResult->fileName(), testResult->line(), 0});
}
void TestResultsPane::onRunAllTriggered()
@@ -692,7 +693,7 @@ void TestResultsPane::onSaveWholeTriggered()
if (fileName.isEmpty())
return;
- Utils::FileSaver saver(fileName, QIODevice::Text);
+ Utils::FileSaver saver(Utils::FilePath::fromString(fileName), QIODevice::Text);
if (!saver.write(getWholeOutput().toUtf8()) || !saver.finalize()) {
QMessageBox::critical(ICore::dialogParent(), tr("Error"),
tr("Failed to write \"%1\".\n\n%2").arg(fileName)
@@ -750,8 +751,7 @@ void TestResultsPane::createMarks(const QModelIndex &parent)
bool isLocationItem = result->result() == ResultType::MessageLocation;
if (interested.contains(result->result())
|| (isLocationItem && interested.contains(parentType))) {
- const Utils::FilePath fileName = Utils::FilePath::fromString(result->fileName());
- TestEditorMark *mark = new TestEditorMark(index, fileName, result->line());
+ TestEditorMark *mark = new TestEditorMark(index, result->fileName(), result->line());
mark->setIcon(index.data(Qt::DecorationRole).value<QIcon>());
mark->setColor(Utils::Theme::OutputPanes_TestFailTextColor);
mark->setPriority(TextEditor::TextMark::NormalPriority);
diff --git a/src/plugins/autotest/testrunconfiguration.h b/src/plugins/autotest/testrunconfiguration.h
index 7e88eb6ce8..2e8748edea 100644
--- a/src/plugins/autotest/testrunconfiguration.h
+++ b/src/plugins/autotest/testrunconfiguration.h
@@ -65,9 +65,9 @@ public:
{
ProjectExplorer::Runnable r;
QTC_ASSERT(m_testConfig, return r);
- r.executable = Utils::FilePath::fromString(m_testConfig->executableFilePath());
+ r.executable = m_testConfig->executableFilePath();
r.commandLineArguments = m_testConfig->argumentsForTestRunner().join(' ');
- r.workingDirectory = m_testConfig->workingDirectory();
+ r.workingDirectory = m_testConfig->workingDirectory().toString();
r.environment = m_testConfig->environment();
r.device = ProjectExplorer::DeviceManager::instance()->defaultDevice(
ProjectExplorer::Constants::DESKTOP_DEVICE_TYPE);
diff --git a/src/plugins/autotest/testrunner.cpp b/src/plugins/autotest/testrunner.cpp
index c807f6b863..a0b00f7d37 100644
--- a/src/plugins/autotest/testrunner.cpp
+++ b/src/plugins/autotest/testrunner.cpp
@@ -176,13 +176,13 @@ static QString constructOmittedVariablesDetailsString(const Utils::EnvironmentIt
bool TestRunner::currentConfigValid()
{
- QString commandFilePath;
+ Utils::FilePath commandFilePath;
if (m_currentConfig->testBase()->type() == ITestBase::Framework) {
TestConfiguration *current = static_cast<TestConfiguration *>(m_currentConfig);
commandFilePath = current->executableFilePath();
} else {
TestToolConfiguration *current = static_cast<TestToolConfiguration *>(m_currentConfig);
- commandFilePath = current->commandLine().executable().toString();
+ commandFilePath = current->commandLine().executable();
}
if (commandFilePath.isEmpty()) {
reportResult(ResultType::MessageFatal,
@@ -208,7 +208,7 @@ void TestRunner::setUpProcess()
m_currentProcess->setReadChannel(QProcess::StandardOutput);
if (m_currentConfig->testBase()->type() == ITestBase::Framework) {
TestConfiguration *current = static_cast<TestConfiguration *>(m_currentConfig);
- m_currentProcess->setProgram(current->executableFilePath());
+ m_currentProcess->setProgram(current->executableFilePath().toString());
} else {
TestToolConfiguration *current = static_cast<TestToolConfiguration *>(m_currentConfig);
m_currentProcess->setProgram(current->commandLine().executable().toString());
@@ -231,7 +231,7 @@ void TestRunner::setUpProcessEnv()
m_currentProcess->setArguments(current->commandLine().splitArguments());
}
- m_currentProcess->setWorkingDirectory(m_currentConfig->workingDirectory());
+ m_currentProcess->setWorkingDirectory(m_currentConfig->workingDirectory().toString());
const Utils::Environment &original = m_currentConfig->environment();
Utils::Environment environment = m_currentConfig->filteredEnvironment(original);
const Utils::EnvironmentItems removedVariables = Utils::filtered(
@@ -625,10 +625,10 @@ void TestRunner::debugTests()
return;
}
- const QString &commandFilePath = config->executableFilePath();
+ const Utils::FilePath &commandFilePath = config->executableFilePath();
if (commandFilePath.isEmpty()) {
reportResult(ResultType::MessageFatal, tr("Could not find command \"%1\". (%2)")
- .arg(config->executableFilePath(), config->displayName()));
+ .arg(config->executableFilePath().toString(), config->displayName()));
onFinished();
return;
}
@@ -638,10 +638,10 @@ void TestRunner::debugTests()
QStringList omitted;
Runnable inferior = config->runnable();
- inferior.executable = FilePath::fromString(commandFilePath);
+ inferior.executable = commandFilePath;
const QStringList args = config->argumentsForTestRunner(&omitted);
- inferior.commandLineArguments = Utils::QtcProcess::joinArgs(args);
+ inferior.commandLineArguments = Utils::ProcessArgs::joinArgs(args);
if (!omitted.isEmpty()) {
const QString &details = constructOmittedDetailsString(omitted);
reportResult(ResultType::MessageWarn, details.arg(config->displayName()));
diff --git a/src/plugins/autotest/testtreeitem.cpp b/src/plugins/autotest/testtreeitem.cpp
index a5a40a8922..1b68a192c7 100644
--- a/src/plugins/autotest/testtreeitem.cpp
+++ b/src/plugins/autotest/testtreeitem.cpp
@@ -30,9 +30,6 @@
#include "itestparser.h"
#include "testconfiguration.h"
-#include <cplusplus/Icons.h>
-#include <cpptools/cppmodelmanager.h>
-#include <cpptools/cpptoolsreuse.h>
#include <texteditor/texteditor.h>
#include <utils/utilsicons.h>
@@ -57,7 +54,7 @@ static QIcon testTreeIcon(TestTreeItem::Type type)
}
ITestTreeItem::ITestTreeItem(ITestBase *testBase, const QString &name,
- const QString &filePath, Type type)
+ const Utils::FilePath &filePath, Type type)
: m_testBase(testBase)
, m_name(name)
, m_filePath(filePath)
@@ -73,7 +70,7 @@ QVariant ITestTreeItem::data(int /*column*/, int role) const
else
return m_name;
case Qt::ToolTipRole:
- return m_filePath;
+ return m_filePath.toString();
case Qt::DecorationRole:
return testTreeIcon(m_type);
case Qt::CheckStateRole:
@@ -140,12 +137,12 @@ bool ITestTreeItem::lessThan(const ITestTreeItem *other, ITestTreeItem::SortMode
const Utils::Link &leftLink = data(0, LinkRole).value<Utils::Link>();
const Utils::Link &rightLink = other->data(0, LinkRole).value<Utils::Link>();
- if (leftLink.targetFileName == rightLink.targetFileName) {
+ if (leftLink.targetFilePath == rightLink.targetFilePath) {
return leftLink.targetLine == rightLink.targetLine
? leftLink.targetColumn > rightLink.targetColumn
: leftLink.targetLine > rightLink.targetLine;
}
- return leftLink.targetFileName > rightLink.targetFileName;
+ return leftLink.targetFilePath > rightLink.targetFilePath;
}
}
return true;
@@ -165,7 +162,7 @@ ITestConfiguration *ITestTreeItem::asConfiguration(TestRunMode mode) const
/****************************** TestTreeItem ********************************************/
TestTreeItem::TestTreeItem(ITestFramework *testFramework, const QString &name,
- const QString &filePath, Type type)
+ const Utils::FilePath &filePath, Type type)
: ITestTreeItem(testFramework, name, filePath, type)
{
switch (type) {
@@ -188,7 +185,8 @@ QVariant TestTreeItem::data(int column, int role) const
if (type() == GroupNode)
return QVariant();
QVariant itemLink;
- itemLink.setValue(Utils::Link(filePath(), line(), int(m_column)));
+ itemLink.setValue(
+ Utils::Link(filePath(), line(), int(m_column)));
return itemLink;
}
return ITestTreeItem::data(column, role);
@@ -242,7 +240,7 @@ void TestTreeItem::markForRemovalRecursively(bool mark)
childItem(row)->markForRemovalRecursively(mark);
}
-void TestTreeItem::markForRemovalRecursively(const QString &filepath)
+void TestTreeItem::markForRemovalRecursively(const Utils::FilePath &filepath)
{
bool mark = filePath() == filepath;
forFirstLevelChildItems([&mark, &filepath](TestTreeItem *child) {
@@ -269,20 +267,20 @@ TestTreeItem *TestTreeItem::findChildByName(const QString &name)
});
}
-TestTreeItem *TestTreeItem::findChildByFile(const QString &filePath)
+TestTreeItem *TestTreeItem::findChildByFile(const Utils::FilePath &filePath)
{
return findFirstLevelChildItem([filePath](const TestTreeItem *other) {
return other->filePath() == filePath;
});
}
-TestTreeItem *TestTreeItem::findChildByFileAndType(const QString &filePath, Type tType)
+TestTreeItem *TestTreeItem::findChildByFileAndType(const Utils::FilePath &filePath, Type tType)
{
return findFirstLevelChildItem([filePath, tType](const TestTreeItem *other) {
return other->type() == tType && other->filePath() == filePath;
});}
-TestTreeItem *TestTreeItem::findChildByNameAndFile(const QString &name, const QString &filePath)
+TestTreeItem *TestTreeItem::findChildByNameAndFile(const QString &name, const Utils::FilePath &filePath)
{
return findFirstLevelChildItem([name, filePath](const TestTreeItem *other) {
return other->filePath() == filePath && other->name() == name;
@@ -312,7 +310,7 @@ bool TestTreeItem::isGroupNodeFor(const TestTreeItem *other) const
return false;
// for now there's only the possibility to have 'Folder' nodes
- return QFileInfo(other->filePath()).absolutePath() == filePath();
+ return other->filePath().absolutePath() == filePath();
}
bool TestTreeItem::isGroupable() const
@@ -320,22 +318,6 @@ bool TestTreeItem::isGroupable() const
return true;
}
-QSet<QString> TestTreeItem::internalTargets() const
-{
- auto cppMM = CppTools::CppModelManager::instance();
- const QList<CppTools::ProjectPart::Ptr> projectParts = cppMM->projectPart(filePath());
- // if we have no project parts it's most likely a header with declarations only and CMake based
- if (projectParts.isEmpty())
- return TestTreeItem::dependingInternalTargets(cppMM, filePath());
- QSet<QString> targets;
- for (const CppTools::ProjectPart::Ptr &part : projectParts) {
- targets.insert(part->buildSystemTarget);
- if (part->buildTargetType != ProjectExplorer::BuildTargetType::Executable)
- targets.unite(TestTreeItem::dependingInternalTargets(cppMM, filePath()));
- }
- return targets;
-}
-
void TestTreeItem::forAllChildItems(const std::function<void(TestTreeItem *)> &pred) const
{
for (int row = 0, end = childCount(); row < end; ++row) {
@@ -378,7 +360,7 @@ void TestTreeItem::copyBasicDataFrom(const TestTreeItem *other)
m_status = other->m_status;
}
-inline bool TestTreeItem::modifyFilePath(const QString &filepath)
+inline bool TestTreeItem::modifyFilePath(const Utils::FilePath &filepath)
{
if (filePath() != filepath) {
setFilePath(filepath);
@@ -401,27 +383,4 @@ ITestFramework *TestTreeItem::framework() const
return static_cast<ITestFramework *>(testBase());
}
-/*
- * try to find build system target that depends on the given file - if the file is no header
- * try to find the corresponding header and use this instead to find the respective target
- */
-QSet<QString> TestTreeItem::dependingInternalTargets(CppTools::CppModelManager *cppMM,
- const QString &file)
-{
- QSet<QString> result;
- QTC_ASSERT(cppMM, return result);
- const CPlusPlus::Snapshot snapshot = cppMM->snapshot();
- QTC_ASSERT(snapshot.contains(file), return result);
- bool wasHeader;
- const QString correspondingFile
- = CppTools::correspondingHeaderOrSource(file, &wasHeader, CppTools::CacheUsage::ReadOnly);
- const Utils::FilePaths dependingFiles = snapshot.filesDependingOn(
- wasHeader ? file : correspondingFile);
- for (const Utils::FilePath &fn : dependingFiles) {
- for (const CppTools::ProjectPart::Ptr &part : cppMM->projectPart(fn))
- result.insert(part->buildSystemTarget);
- }
- return result;
-}
-
} // namespace Autotest
diff --git a/src/plugins/autotest/testtreeitem.h b/src/plugins/autotest/testtreeitem.h
index 21237146a6..43b41ca160 100644
--- a/src/plugins/autotest/testtreeitem.h
+++ b/src/plugins/autotest/testtreeitem.h
@@ -25,6 +25,7 @@
#pragma once
+#include <utils/fileutils.h>
#include <utils/treemodel.h>
#include <QList>
@@ -42,9 +43,6 @@ namespace {
};
}
-namespace CppTools { class CppModelManager; }
-namespace Utils { class FilePath; }
-
namespace Autotest {
class ITestBase;
@@ -76,7 +74,7 @@ public:
explicit ITestTreeItem(ITestBase *testBase,
const QString &name = QString(),
- const QString &filePath = QString(),
+ const Utils::FilePath &filePath = Utils::FilePath(),
Type type = Root);
virtual QVariant data(int column, int role) const override;
@@ -94,15 +92,15 @@ public:
const QString name() const { return m_name; }
void setName(const QString &name) { m_name = name; }
- const QString filePath() const { return m_filePath; }
- void setFilePath(const QString &filePath) { m_filePath = filePath; }
+ const Utils::FilePath filePath() const { return m_filePath; }
+ void setFilePath(const Utils::FilePath &filePath) { m_filePath = filePath; }
Type type() const { return m_type; }
int line() const { return m_line; }
void setLine(int line) { m_line = line;}
ITestBase *testBase() const { return m_testBase; }
virtual bool lessThan(const ITestTreeItem *other, SortMode mode) const;
- QString cacheName() const { return m_filePath + ':' + m_name; }
+ QString cacheName() const { return m_filePath.toString() + ':' + m_name; }
protected:
void setType(Type type) { m_type = type; }
@@ -111,7 +109,7 @@ protected:
private:
ITestBase *m_testBase = nullptr; // not owned
QString m_name;
- QString m_filePath;
+ Utils::FilePath m_filePath;
Type m_type;
int m_line = 0;
bool m_failed = false;
@@ -122,7 +120,7 @@ class TestTreeItem : public ITestTreeItem
public:
explicit TestTreeItem(ITestFramework *testFramework,
const QString &name = QString(),
- const QString &filePath = QString(),
+ const Utils::FilePath &filePath = Utils::FilePath(),
Type type = Root);
virtual TestTreeItem *copyWithoutChildren() = 0;
@@ -135,11 +133,11 @@ public:
ITestFramework *framework() const;
void setColumn(int column) { m_column = column; }
int column() const { return m_column; }
- QString proFile() const { return m_proFile; }
- void setProFile(const QString &proFile) { m_proFile = proFile; }
+ Utils::FilePath proFile() const { return m_proFile; }
+ void setProFile(const Utils::FilePath &proFile) { m_proFile = proFile; }
void markForRemoval(bool mark);
void markForRemovalRecursively(bool mark);
- virtual void markForRemovalRecursively(const QString &filepath);
+ virtual void markForRemovalRecursively(const Utils::FilePath &filepath);
virtual bool removeOnSweepIfEmpty() const { return type() == GroupNode; }
bool markedForRemoval() const { return m_status == MarkedForRemoval; }
bool newlyAdded() const { return m_status == NewlyAdded; }
@@ -147,9 +145,9 @@ public:
TestTreeItem *parentItem() const;
TestTreeItem *findChildByName(const QString &name);
- TestTreeItem *findChildByFile(const QString &filePath);
- TestTreeItem *findChildByFileAndType(const QString &filePath, Type type);
- TestTreeItem *findChildByNameAndFile(const QString &name, const QString &filePath);
+ TestTreeItem *findChildByFile(const Utils::FilePath &filePath);
+ TestTreeItem *findChildByFileAndType(const Utils::FilePath &filePath, Type type);
+ TestTreeItem *findChildByNameAndFile(const QString &name, const Utils::FilePath &filePath);
virtual ITestConfiguration *debugConfiguration() const { return nullptr; }
virtual bool canProvideDebugConfiguration() const { return false; }
@@ -166,7 +164,6 @@ public:
virtual TestTreeItem *applyFilters() { return nullptr; }
// decide whether an item should still be added to the treemodel
virtual bool shouldBeAddedAfterFiltering() const { return true; }
- virtual QSet<QString> internalTargets() const;
void forAllChildItems(const std::function<void(TestTreeItem *)> &pred) const;
void forFirstLevelChildItems(const std::function<void(TestTreeItem *)> &pred) const;
@@ -174,11 +171,9 @@ public:
protected:
void copyBasicDataFrom(const TestTreeItem *other);
typedef std::function<bool(const TestTreeItem *)> CompareFunction;
- static QSet<QString> dependingInternalTargets(CppTools::CppModelManager *cppMM,
- const QString &file);
private:
- bool modifyFilePath(const QString &filepath);
+ bool modifyFilePath(const Utils::FilePath &filepath);
bool modifyName(const QString &name);
enum Status
@@ -189,7 +184,7 @@ private:
};
int m_column = 0;
- QString m_proFile;
+ Utils::FilePath m_proFile;
Status m_status = NewlyAdded;
friend class TestTreeModel; // grant access to (protected) findChildBy()
@@ -198,7 +193,7 @@ private:
class TestCodeLocationAndType
{
public:
- QString m_name; // tag name for m_type == TestDataTag, file name for other values
+ QString m_name; // tag name for m_type == TestDataTag, file name for other values // FIXME
int m_line = 0;
int m_column = 0;
TestTreeItem::Type m_type = TestTreeItem::Root;
diff --git a/src/plugins/autotest/testtreemodel.cpp b/src/plugins/autotest/testtreemodel.cpp
index 4719818d5d..da6da812d6 100644
--- a/src/plugins/autotest/testtreemodel.cpp
+++ b/src/plugins/autotest/testtreemodel.cpp
@@ -115,7 +115,11 @@ void TestTreeModel::setupParsingConnections()
connect(cppMM, &CppTools::CppModelManager::documentUpdated,
m_parser, &TestCodeParser::onCppDocumentUpdated, Qt::QueuedConnection);
connect(cppMM, &CppTools::CppModelManager::aboutToRemoveFiles,
- this, &TestTreeModel::removeFiles, Qt::QueuedConnection);
+ this, [this](const QStringList &files) {
+ const Utils::FilePaths filesToRemove
+ = Utils::transform(files, &Utils::FilePath::fromString);
+ removeFiles(filesToRemove);
+ }, Qt::QueuedConnection);
connect(cppMM, &CppTools::CppModelManager::projectPartsUpdated,
m_parser, &TestCodeParser::onProjectPartsUpdated);
@@ -123,7 +127,11 @@ void TestTreeModel::setupParsingConnections()
connect(qmlJsMM, &QmlJS::ModelManagerInterface::documentUpdated,
m_parser, &TestCodeParser::onQmlDocumentUpdated, Qt::QueuedConnection);
connect(qmlJsMM, &QmlJS::ModelManagerInterface::aboutToRemoveFiles,
- this, &TestTreeModel::removeFiles, Qt::QueuedConnection);
+ this, [this](const QStringList files) {
+ const Utils::FilePaths filesToRemove
+ = Utils::transform(files, &Utils::FilePath::fromString);
+ removeFiles(filesToRemove);
+ }, Qt::QueuedConnection);
connectionsInitialized = true;
}
@@ -481,9 +489,9 @@ void TestTreeModel::clearFailedMarks()
m_failedStateCache.clear();
}
-void TestTreeModel::removeFiles(const QStringList &files)
+void TestTreeModel::removeFiles(const Utils::FilePaths &files)
{
- for (const QString &file : files)
+ for (const Utils::FilePath &file : files)
markForRemoval(file);
sweep();
}
@@ -497,7 +505,7 @@ void TestTreeModel::markAllFrameworkItemsForRemoval()
}
}
-void TestTreeModel::markForRemoval(const QString &filePath)
+void TestTreeModel::markForRemoval(const Utils::FilePath &filePath)
{
if (filePath.isEmpty())
return;
@@ -865,7 +873,7 @@ QMap<QString, int> TestTreeModel::boostTestSuitesAndTests() const
if (TestTreeItem *rootNode = boostTestRootNode()) {
rootNode->forFirstLevelChildItems([&result](TestTreeItem *child) {
- result.insert(child->name() + '|' + child->proFile(), child->childCount());
+ result.insert(child->name() + '|' + child->proFile().toString(), child->childCount());
});
}
return result;
diff --git a/src/plugins/autotest/testtreemodel.h b/src/plugins/autotest/testtreemodel.h
index 4f84487482..ab9dcd5156 100644
--- a/src/plugins/autotest/testtreemodel.h
+++ b/src/plugins/autotest/testtreemodel.h
@@ -88,7 +88,7 @@ public:
#endif
void markAllFrameworkItemsForRemoval();
- void markForRemoval(const QString &filePath);
+ void markForRemoval(const Utils::FilePath &filePath);
void sweep();
signals:
@@ -105,7 +105,7 @@ private:
void handleParseResult(const TestParseResult *result, TestTreeItem *rootNode);
void removeAllTestItems();
void removeAllTestToolItems();
- void removeFiles(const QStringList &files);
+ void removeFiles(const Utils::FilePaths &files);
bool sweepChildren(TestTreeItem *item);
void insertItemInParent(TestTreeItem *item, TestTreeItem *root, bool groupingEnabled);
void revalidateCheckState(ITestTreeItem *item);
diff --git a/src/plugins/autotoolsprojectmanager/makefileparser.cpp b/src/plugins/autotoolsprojectmanager/makefileparser.cpp
index 0e056dda9c..bdf5f59b23 100644
--- a/src/plugins/autotoolsprojectmanager/makefileparser.cpp
+++ b/src/plugins/autotoolsprojectmanager/makefileparser.cpp
@@ -441,7 +441,7 @@ QStringList MakefileParser::parseTermsAfterAssign(const QString &line)
if (assignPos <= 0 || assignPos >= line.size())
return QStringList();
- const QStringList parts = Utils::QtcProcess::splitArgs(line.mid(assignPos));
+ const QStringList parts = Utils::ProcessArgs::splitArgs(line.mid(assignPos));
QStringList result;
for (int i = 0; i < parts.count(); ++i) {
const QString cur = parts.at(i);
diff --git a/src/plugins/baremetal/debugserverprovidermanager.cpp b/src/plugins/baremetal/debugserverprovidermanager.cpp
index 6ab84c0208..55f4551eef 100644
--- a/src/plugins/baremetal/debugserverprovidermanager.cpp
+++ b/src/plugins/baremetal/debugserverprovidermanager.cpp
@@ -54,14 +54,14 @@ namespace Internal {
const char dataKeyC[] = "DebugServerProvider.";
const char countKeyC[] = "DebugServerProvider.Count";
const char fileVersionKeyC[] = "Version";
-const char fileNameKeyC[] = "/debugserverproviders.xml";
+const char fileNameKeyC[] = "debugserverproviders.xml";
static DebugServerProviderManager *m_instance = nullptr;
// DebugServerProviderManager
DebugServerProviderManager::DebugServerProviderManager()
- : m_configFile(Utils::FilePath::fromString(Core::ICore::userResourcePath() + fileNameKeyC))
+ : m_configFile(Core::ICore::userResourcePath(fileNameKeyC))
, m_factories({new GenericGdbServerProviderFactory,
new JLinkGdbServerProviderFactory,
new OpenOcdGdbServerProviderFactory,
diff --git a/src/plugins/baremetal/debugservers/gdb/openocdgdbserverprovider.cpp b/src/plugins/baremetal/debugservers/gdb/openocdgdbserverprovider.cpp
index 0e32338af7..7ac79e4aa7 100644
--- a/src/plugins/baremetal/debugservers/gdb/openocdgdbserverprovider.cpp
+++ b/src/plugins/baremetal/debugservers/gdb/openocdgdbserverprovider.cpp
@@ -86,7 +86,7 @@ QString OpenOcdGdbServerProvider::channelString() const
// otherwise running will be stuck.
CommandLine cmd = command();
QStringList args = {"|", cmd.executable().toString()};
- for (const QString &a : QtcProcess::splitArgs(cmd.arguments())) {
+ for (const QString &a : ProcessArgs::splitArgs(cmd.arguments())) {
if (a.startsWith('\"') && a.endsWith('\"'))
args << a;
else
diff --git a/src/plugins/baremetal/iarewtoolchain.cpp b/src/plugins/baremetal/iarewtoolchain.cpp
index c666365ab3..38b5b0ed31 100644
--- a/src/plugins/baremetal/iarewtoolchain.cpp
+++ b/src/plugins/baremetal/iarewtoolchain.cpp
@@ -38,7 +38,6 @@
#include <utils/pathchooser.h>
#include <utils/qtcassert.h>
#include <utils/qtcprocess.h>
-#include <utils/synchronousprocess.h>
#include <QDebug>
#include <QDir>
@@ -87,7 +86,7 @@ static QString cppLanguageOption(const FilePath &compiler)
}
static Macros dumpPredefinedMacros(const FilePath &compiler, const QStringList &extraArgs,
- const Utils::Id languageId, const QStringList &env)
+ const Id languageId, const Environment &env)
{
if (compiler.isEmpty() || !compiler.toFileInfo().isExecutable())
return {};
@@ -112,10 +111,10 @@ static Macros dumpPredefinedMacros(const FilePath &compiler, const QStringList &
cmd.addArg("--predef_macros");
cmd.addArg(outpath);
- const SynchronousProcessResponse response = cpp.runBlocking(cmd);
- if (response.result != SynchronousProcessResponse::Finished
- || response.exitCode != 0) {
- qWarning() << response.exitMessage(cmd.toUserOutput(), 10);
+ cpp.setCommand(cmd);
+ cpp.runBlocking();
+ if (cpp.result() != QtcProcess::Finished || cpp.exitCode() != 0) {
+ qWarning() << cpp.exitMessage();
return {};
}
@@ -128,8 +127,8 @@ static Macros dumpPredefinedMacros(const FilePath &compiler, const QStringList &
return Macro::toMacros(output);
}
-static HeaderPaths dumpHeaderPaths(const FilePath &compiler, const Utils::Id languageId,
- const QStringList &env)
+static HeaderPaths dumpHeaderPaths(const FilePath &compiler, const Id languageId,
+ const Environment &env)
{
if (!compiler.exists())
return {};
@@ -147,22 +146,21 @@ static HeaderPaths dumpHeaderPaths(const FilePath &compiler, const Utils::Id lan
return {};
fakeIn.close();
- SynchronousProcess cpp;
- cpp.setEnvironment(env);
- cpp.setTimeoutS(10);
-
CommandLine cmd(compiler, {fakeIn.fileName()});
if (languageId == ProjectExplorer::Constants::CXX_LANGUAGE_ID)
cmd.addArg(cppLanguageOption(compiler));
cmd.addArg("--preinclude");
cmd.addArg(".");
- // Note: Response should retutn an error, just don't check on errors.
- const SynchronousProcessResponse response = cpp.runBlocking(cmd);
+ SynchronousProcess cpp;
+ cpp.setEnvironment(env);
+ cpp.setTimeoutS(10);
+ cpp.setCommand(cmd);
+ cpp.runBlocking();
HeaderPaths headerPaths;
- const QByteArray output = response.allOutput().toUtf8();
+ const QByteArray output = cpp.allOutput().toUtf8();
for (auto pos = 0; pos < output.size(); ++pos) {
const int searchIndex = output.indexOf("searched:", pos);
if (searchIndex == -1)
@@ -310,7 +308,7 @@ ToolChain::MacroInspectionRunner IarToolChain::createMacroInspectionRunner() con
(const QStringList &flags) {
Q_UNUSED(flags)
- Macros macros = dumpPredefinedMacros(compiler, extraArgs, languageId, env.toStringList());
+ Macros macros = dumpPredefinedMacros(compiler, extraArgs, languageId, env);
macros.append({"__intrinsic", "", MacroType::Define});
macros.append({"__nounwind", "", MacroType::Define});
macros.append({"__noreturn", "", MacroType::Define});
@@ -354,7 +352,7 @@ ToolChain::BuiltInHeaderPathsRunner IarToolChain::createBuiltInHeaderPathsRunner
Q_UNUSED(flags)
Q_UNUSED(fileName)
- const HeaderPaths paths = dumpHeaderPaths(compiler, languageId, env.toStringList());
+ const HeaderPaths paths = dumpHeaderPaths(compiler, languageId, env);
headerPaths->insert({}, paths);
return paths;
@@ -435,8 +433,10 @@ IarToolChainFactory::IarToolChainFactory()
setUserCreatable(true);
}
-QList<ToolChain *> IarToolChainFactory::autoDetect(const QList<ToolChain *> &alreadyKnown)
+QList<ToolChain *> IarToolChainFactory::autoDetect(const QList<ToolChain *> &alreadyKnown,
+ const IDevice::Ptr &device)
{
+ Q_UNUSED(device);
Candidates candidates;
#ifdef Q_OS_WIN
@@ -537,8 +537,7 @@ QList<ToolChain *> IarToolChainFactory::autoDetectToolchain(
const Candidate &candidate, Utils::Id languageId) const
{
const auto env = Environment::systemEnvironment();
- const Macros macros = dumpPredefinedMacros(candidate.compilerPath, {}, languageId,
- env.toStringList());
+ const Macros macros = dumpPredefinedMacros(candidate.compilerPath, {}, languageId, env);
if (macros.isEmpty())
return {};
const Abi abi = guessAbi(macros);
@@ -567,7 +566,7 @@ IarToolChainConfigWidget::IarToolChainConfigWidget(IarToolChain *tc) :
m_compilerCommand->setHistoryCompleter("PE.IAREW.Command.History");
m_mainLayout->addRow(tr("&Compiler path:"), m_compilerCommand);
m_platformCodeGenFlagsLineEdit = new QLineEdit(this);
- m_platformCodeGenFlagsLineEdit->setText(QtcProcess::joinArgs(tc->extraCodeModelFlags()));
+ m_platformCodeGenFlagsLineEdit->setText(ProcessArgs::joinArgs(tc->extraCodeModelFlags()));
m_mainLayout->addRow(tr("Platform codegen flags:"), m_platformCodeGenFlagsLineEdit);
m_mainLayout->addRow(tr("&ABI:"), m_abiWidget);
@@ -609,7 +608,7 @@ bool IarToolChainConfigWidget::isDirtyImpl() const
{
const auto tc = static_cast<IarToolChain *>(toolChain());
return m_compilerCommand->filePath() != tc->compilerCommand()
- || m_platformCodeGenFlagsLineEdit->text() != QtcProcess::joinArgs(tc->extraCodeModelFlags())
+ || m_platformCodeGenFlagsLineEdit->text() != ProcessArgs::joinArgs(tc->extraCodeModelFlags())
|| m_abiWidget->currentAbi() != tc->targetAbi()
;
}
@@ -626,7 +625,7 @@ void IarToolChainConfigWidget::setFromToolchain()
const QSignalBlocker blocker(this);
const auto tc = static_cast<IarToolChain *>(toolChain());
m_compilerCommand->setFilePath(tc->compilerCommand());
- m_platformCodeGenFlagsLineEdit->setText(QtcProcess::joinArgs(tc->extraCodeModelFlags()));
+ m_platformCodeGenFlagsLineEdit->setText(ProcessArgs::joinArgs(tc->extraCodeModelFlags()));
m_abiWidget->setAbis({}, tc->targetAbi());
const bool haveCompiler = compilerExists(m_compilerCommand->filePath());
m_abiWidget->setEnabled(haveCompiler && !tc->isAutoDetected());
@@ -639,9 +638,8 @@ void IarToolChainConfigWidget::handleCompilerCommandChange()
if (haveCompiler) {
const auto env = Environment::systemEnvironment();
const QStringList extraArgs = splitString(m_platformCodeGenFlagsLineEdit->text());
- const auto languageId = toolChain()->language();
- m_macros = dumpPredefinedMacros(compilerPath, extraArgs, languageId,
- env.toStringList());
+ const Id languageId = toolChain()->language();
+ m_macros = dumpPredefinedMacros(compilerPath, extraArgs, languageId, env);
const Abi guessed = guessAbi(m_macros);
m_abiWidget->setAbis({}, guessed);
}
@@ -653,7 +651,7 @@ void IarToolChainConfigWidget::handleCompilerCommandChange()
void IarToolChainConfigWidget::handlePlatformCodeGenFlagsChange()
{
const QString str1 = m_platformCodeGenFlagsLineEdit->text();
- const QString str2 = QtcProcess::joinArgs(splitString(str1));
+ const QString str2 = ProcessArgs::joinArgs(splitString(str1));
if (str1 != str2)
m_platformCodeGenFlagsLineEdit->setText(str2);
else
diff --git a/src/plugins/baremetal/iarewtoolchain.h b/src/plugins/baremetal/iarewtoolchain.h
index fb42da3c73..0d4d73f3ee 100644
--- a/src/plugins/baremetal/iarewtoolchain.h
+++ b/src/plugins/baremetal/iarewtoolchain.h
@@ -91,7 +91,8 @@ public:
IarToolChainFactory();
QList<ProjectExplorer::ToolChain *> autoDetect(
- const QList<ProjectExplorer::ToolChain *> &alreadyKnown) final;
+ const QList<ProjectExplorer::ToolChain *> &alreadyKnown,
+ const ProjectExplorer::IDevice::Ptr &device) final;
private:
QList<ProjectExplorer::ToolChain *> autoDetectToolchains(const Candidates &candidates,
diff --git a/src/plugins/baremetal/keiltoolchain.cpp b/src/plugins/baremetal/keiltoolchain.cpp
index b2e58dc6ca..120b0aee2b 100644
--- a/src/plugins/baremetal/keiltoolchain.cpp
+++ b/src/plugins/baremetal/keiltoolchain.cpp
@@ -38,7 +38,6 @@
#include <utils/pathchooser.h>
#include <utils/qtcassert.h>
#include <utils/qtcprocess.h>
-#include <utils/synchronousprocess.h>
#include <QDebug>
#include <QDir>
@@ -83,7 +82,7 @@ static Abi::Architecture guessArchitecture(const FilePath &compilerPath)
return Abi::Architecture::UnknownArchitecture;
}
-static Macros dumpMcsPredefinedMacros(const FilePath &compiler, const QStringList &env)
+static Macros dumpMcsPredefinedMacros(const FilePath &compiler, const Environment &env)
{
// Note: The KEIL C51 or C251 compiler does not support the predefined
// macros dumping. So, we do it with the following trick, where we try
@@ -139,10 +138,10 @@ static Macros dumpMcsPredefinedMacros(const FilePath &compiler, const QStringLis
SynchronousProcess cpp;
cpp.setEnvironment(env);
cpp.setTimeoutS(10);
+ cpp.setCommand({compiler, {fakeIn.fileName()}});
- const CommandLine cmd(compiler, {fakeIn.fileName()});
- const SynchronousProcessResponse response = cpp.runBlocking(cmd);
- QString output = response.allOutput();
+ cpp.runBlocking();
+ QString output = cpp.allOutput();
Macros macros;
QTextStream stream(&output);
QString line;
@@ -156,7 +155,7 @@ static Macros dumpMcsPredefinedMacros(const FilePath &compiler, const QStringLis
return macros;
}
-static Macros dumpC166PredefinedMacros(const FilePath &compiler, const QStringList &env)
+static Macros dumpC166PredefinedMacros(const FilePath &compiler, const Environment &env)
{
// Note: The KEIL C166 compiler does not support the predefined
// macros dumping. Also, it does not support the '#pragma' and
@@ -269,14 +268,14 @@ static Macros dumpC166PredefinedMacros(const FilePath &compiler, const QStringLi
}
};
- const CommandLine cmd(compiler, {fakeIn.fileName()});
- const SynchronousProcessResponse response = cpp.runBlocking(cmd);
- const QString output = response.allOutput();
+ cpp.setCommand({compiler, {fakeIn.fileName()}});
+ cpp.runBlocking();
+ const QString output = cpp.allOutput();
extractMacros(output);
return macros;
}
-static Macros dumpArmPredefinedMacros(const FilePath &compiler, const QStringList &extraArgs, const QStringList &env)
+static Macros dumpArmPredefinedMacros(const FilePath &compiler, const QStringList &extraArgs, const Environment &env)
{
SynchronousProcess cpp;
cpp.setEnvironment(env);
@@ -285,16 +284,15 @@ static Macros dumpArmPredefinedMacros(const FilePath &compiler, const QStringLis
QStringList args = extraArgs;
args.push_back("-E");
args.push_back("--list-macros");
- const CommandLine cmd(compiler, args);
+ cpp.setCommand({compiler, args});
- const SynchronousProcessResponse response = cpp.runBlocking(cmd);
- if (response.result != SynchronousProcessResponse::Finished
- || response.exitCode != 0) {
- qWarning() << response.exitMessage(compiler.toString(), 10);
+ cpp.runBlocking();
+ if (cpp.result() != QtcProcess::Finished || cpp.exitCode() != 0) {
+ qWarning() << cpp.exitMessage();
return {};
}
- const QByteArray output = response.allOutput().toUtf8();
+ const QByteArray output = cpp.allOutput().toUtf8();
return Macro::toMacros(output);
}
@@ -314,7 +312,7 @@ static bool isArmArchitecture(Abi::Architecture arch)
return arch == Abi::Architecture::ArmArchitecture;
}
-static Macros dumpPredefinedMacros(const FilePath &compiler, const QStringList &args, const QStringList &env)
+static Macros dumpPredefinedMacros(const FilePath &compiler, const QStringList &args, const Environment &env)
{
if (compiler.isEmpty() || !compiler.toFileInfo().isExecutable())
return {};
@@ -449,7 +447,7 @@ ToolChain::MacroInspectionRunner KeilToolChain::createMacroInspectionRunner() co
return [env, compiler, extraArgs, macroCache, lang](const QStringList &flags) {
Q_UNUSED(flags)
- const Macros macros = dumpPredefinedMacros(compiler, extraArgs, env.toStringList());
+ const Macros macros = dumpPredefinedMacros(compiler, extraArgs, env);
const auto report = MacroInspectionReport{macros, languageVersion(lang, macros)};
macroCache->insert({}, report);
@@ -605,8 +603,10 @@ static QString extractVersion(const QString &toolsFile, const QString &section)
return {};
}
-QList<ToolChain *> KeilToolChainFactory::autoDetect(const QList<ToolChain *> &alreadyKnown)
+QList<ToolChain *> KeilToolChainFactory::autoDetect(const QList<ToolChain *> &alreadyKnown,
+ const IDevice::Ptr &device)
{
+ Q_UNUSED(device)
#ifdef Q_OS_WIN64
static const char kRegistryNode[] = "HKEY_LOCAL_MACHINE\\SOFTWARE\\WOW6432Node\\Microsoft\\" \
"Windows\\CurrentVersion\\Uninstall\\Keil µVision4";
@@ -690,7 +690,7 @@ QList<ToolChain *> KeilToolChainFactory::autoDetectToolchain(
QStringList extraArgs;
addDefaultCpuArgs(candidate.compilerPath, extraArgs);
- const Macros macros = dumpPredefinedMacros(candidate.compilerPath, extraArgs, env.toStringList());
+ const Macros macros = dumpPredefinedMacros(candidate.compilerPath, extraArgs, env);
if (macros.isEmpty())
return {};
@@ -726,7 +726,7 @@ KeilToolChainConfigWidget::KeilToolChainConfigWidget(KeilToolChain *tc) :
m_compilerCommand->setHistoryCompleter("PE.KEIL.Command.History");
m_mainLayout->addRow(tr("&Compiler path:"), m_compilerCommand);
m_platformCodeGenFlagsLineEdit = new QLineEdit(this);
- m_platformCodeGenFlagsLineEdit->setText(QtcProcess::joinArgs(tc->extraCodeModelFlags()));
+ m_platformCodeGenFlagsLineEdit->setText(ProcessArgs::joinArgs(tc->extraCodeModelFlags()));
m_mainLayout->addRow(tr("Platform codegen flags:"), m_platformCodeGenFlagsLineEdit);
m_mainLayout->addRow(tr("&ABI:"), m_abiWidget);
@@ -768,7 +768,7 @@ bool KeilToolChainConfigWidget::isDirtyImpl() const
{
const auto tc = static_cast<KeilToolChain *>(toolChain());
return m_compilerCommand->filePath() != tc->compilerCommand()
- || m_platformCodeGenFlagsLineEdit->text() != QtcProcess::joinArgs(tc->extraCodeModelFlags())
+ || m_platformCodeGenFlagsLineEdit->text() != ProcessArgs::joinArgs(tc->extraCodeModelFlags())
|| m_abiWidget->currentAbi() != tc->targetAbi()
;
}
@@ -785,7 +785,7 @@ void KeilToolChainConfigWidget::setFromToolChain()
const QSignalBlocker blocker(this);
const auto tc = static_cast<KeilToolChain *>(toolChain());
m_compilerCommand->setFilePath(tc->compilerCommand());
- m_platformCodeGenFlagsLineEdit->setText(QtcProcess::joinArgs(tc->extraCodeModelFlags()));
+ m_platformCodeGenFlagsLineEdit->setText(ProcessArgs::joinArgs(tc->extraCodeModelFlags()));
m_abiWidget->setAbis({}, tc->targetAbi());
const bool haveCompiler = compilerExists(m_compilerCommand->filePath());
m_abiWidget->setEnabled(haveCompiler && !tc->isAutoDetected());
@@ -801,8 +801,8 @@ void KeilToolChainConfigWidget::handleCompilerCommandChange()
QStringList newExtraArgs = prevExtraArgs;
addDefaultCpuArgs(compilerPath, newExtraArgs);
if (prevExtraArgs != newExtraArgs)
- m_platformCodeGenFlagsLineEdit->setText(QtcProcess::joinArgs(newExtraArgs));
- m_macros = dumpPredefinedMacros(compilerPath, newExtraArgs, env.toStringList());
+ m_platformCodeGenFlagsLineEdit->setText(ProcessArgs::joinArgs(newExtraArgs));
+ m_macros = dumpPredefinedMacros(compilerPath, newExtraArgs, env);
const Abi guessed = guessAbi(m_macros);
m_abiWidget->setAbis({}, guessed);
}
@@ -814,7 +814,7 @@ void KeilToolChainConfigWidget::handleCompilerCommandChange()
void KeilToolChainConfigWidget::handlePlatformCodeGenFlagsChange()
{
const QString str1 = m_platformCodeGenFlagsLineEdit->text();
- const QString str2 = QtcProcess::joinArgs(splitString(str1));
+ const QString str2 = ProcessArgs::joinArgs(splitString(str1));
if (str1 != str2)
m_platformCodeGenFlagsLineEdit->setText(str2);
else
diff --git a/src/plugins/baremetal/keiltoolchain.h b/src/plugins/baremetal/keiltoolchain.h
index 3dd620266d..a4a3eb2011 100644
--- a/src/plugins/baremetal/keiltoolchain.h
+++ b/src/plugins/baremetal/keiltoolchain.h
@@ -92,7 +92,8 @@ public:
KeilToolChainFactory();
QList<ProjectExplorer::ToolChain *> autoDetect(
- const QList<ProjectExplorer::ToolChain *> &alreadyKnown) final;
+ const QList<ProjectExplorer::ToolChain *> &alreadyKnown,
+ const ProjectExplorer::IDevice::Ptr &device) final;
private:
QList<ProjectExplorer::ToolChain *> autoDetectToolchains(const Candidates &candidates,
diff --git a/src/plugins/baremetal/sdcctoolchain.cpp b/src/plugins/baremetal/sdcctoolchain.cpp
index 5e2d22b3b0..9c6bc61526 100644
--- a/src/plugins/baremetal/sdcctoolchain.cpp
+++ b/src/plugins/baremetal/sdcctoolchain.cpp
@@ -37,7 +37,7 @@
#include <utils/environment.h>
#include <utils/pathchooser.h>
#include <utils/qtcassert.h>
-#include <utils/synchronousprocess.h>
+#include <utils/qtcprocess.h>
#include <QDebug>
#include <QDir>
@@ -76,7 +76,7 @@ static QString compilerTargetFlag(const Abi &abi)
}
}
-static Macros dumpPredefinedMacros(const FilePath &compiler, const QStringList &env,
+static Macros dumpPredefinedMacros(const FilePath &compiler, const Environment &env,
const Abi &abi)
{
if (compiler.isEmpty() || !compiler.toFileInfo().isExecutable())
@@ -90,21 +90,19 @@ static Macros dumpPredefinedMacros(const FilePath &compiler, const QStringList &
SynchronousProcess cpp;
cpp.setEnvironment(env);
cpp.setTimeoutS(10);
+ cpp.setCommand({compiler, {compilerTargetFlag(abi), "-dM", "-E", fakeIn.fileName()}});
- const CommandLine cmd(compiler, {compilerTargetFlag(abi), "-dM", "-E", fakeIn.fileName()});
-
- const SynchronousProcessResponse response = cpp.runBlocking(cmd);
- if (response.result != SynchronousProcessResponse::Finished
- || response.exitCode != 0) {
- qWarning() << response.exitMessage(compiler.toString(), 10);
+ cpp.runBlocking();
+ if (cpp.result() != QtcProcess::Finished || cpp.exitCode() != 0) {
+ qWarning() << cpp.exitMessage();
return {};
}
- const QByteArray output = response.allOutput().toUtf8();
+ const QByteArray output = cpp.allOutput().toUtf8();
return Macro::toMacros(output);
}
-static HeaderPaths dumpHeaderPaths(const FilePath &compiler, const QStringList &env,
+static HeaderPaths dumpHeaderPaths(const FilePath &compiler, const Environment &env,
const Abi &abi)
{
if (!compiler.exists())
@@ -113,17 +111,15 @@ static HeaderPaths dumpHeaderPaths(const FilePath &compiler, const QStringList &
SynchronousProcess cpp;
cpp.setEnvironment(env);
cpp.setTimeoutS(10);
+ cpp.setCommand({compiler, {compilerTargetFlag(abi), "--print-search-dirs"}});
- const CommandLine cmd(compiler, {compilerTargetFlag(abi), "--print-search-dirs"});
-
- const SynchronousProcessResponse response = cpp.runBlocking(cmd);
- if (response.result != SynchronousProcessResponse::Finished
- || response.exitCode != 0) {
- qWarning() << response.exitMessage(compiler.toString(), 10);
+ cpp.runBlocking();
+ if (cpp.result() != QtcProcess::Finished || cpp.exitCode() != 0) {
+ qWarning() << cpp.exitMessage();
return {};
}
- QString output = response.allOutput();
+ QString output = cpp.allOutput();
HeaderPaths headerPaths;
QTextStream in(&output);
QString line;
@@ -234,8 +230,7 @@ ToolChain::MacroInspectionRunner SdccToolChain::createMacroInspectionRunner() co
(const QStringList &flags) {
Q_UNUSED(flags)
- const Macros macros = dumpPredefinedMacros(compiler, env.toStringList(),
- abi);
+ const Macros macros = dumpPredefinedMacros(compiler, env, abi);
const auto report = MacroInspectionReport{macros, languageVersion(lang, macros)};
macrosCache->insert({}, report);
@@ -264,7 +259,7 @@ ToolChain::BuiltInHeaderPathsRunner SdccToolChain::createBuiltInHeaderPathsRunne
const Abi abi = targetAbi();
return [env, compiler, abi](const QStringList &, const QString &, const QString &) {
- return dumpHeaderPaths(compiler, env.toStringList(), abi);
+ return dumpHeaderPaths(compiler, env, abi);
};
}
@@ -313,8 +308,10 @@ SdccToolChainFactory::SdccToolChainFactory()
setUserCreatable(true);
}
-QList<ToolChain *> SdccToolChainFactory::autoDetect(const QList<ToolChain *> &alreadyKnown)
+QList<ToolChain *> SdccToolChainFactory::autoDetect(const QList<ToolChain *> &alreadyKnown,
+ const IDevice::Ptr &device)
{
+ Q_UNUSED(device)
Candidates candidates;
if (Utils::HostOsInfo::isWindowsHost()) {
@@ -359,8 +356,8 @@ QList<ToolChain *> SdccToolChainFactory::autoDetect(const QList<ToolChain *> &al
const FilePath fn = compilerPathFromEnvironment("sdcc");
if (fn.exists()) {
- const auto env = Environment::systemEnvironment();
- const auto macros = dumpPredefinedMacros(fn, env.toStringList(), {});
+ const Environment env = Environment::systemEnvironment();
+ const Macros macros = dumpPredefinedMacros(fn, env, {});
const QString version = guessVersion(macros);
const Candidate candidate = {fn, version};
if (!candidates.contains(candidate))
@@ -411,8 +408,7 @@ QList<ToolChain *> SdccToolChainFactory::autoDetectToolchain(
// Probe each ABI from the table, because the SDCC compiler
// can be compiled with or without the specified architecture.
for (const auto &knownAbi : knownAbis) {
- const Macros macros = dumpPredefinedMacros(candidate.compilerPath,
- env.toStringList(), knownAbi);
+ const Macros macros = dumpPredefinedMacros(candidate.compilerPath, env, knownAbi);
if (macros.isEmpty())
continue;
const Abi abi = guessAbi(macros);
@@ -509,7 +505,7 @@ void SdccToolChainConfigWidget::handleCompilerCommandChange()
const bool haveCompiler = compilerExists(compilerPath);
if (haveCompiler) {
const auto env = Environment::systemEnvironment();
- m_macros = dumpPredefinedMacros(compilerPath, env.toStringList(), {});
+ m_macros = dumpPredefinedMacros(compilerPath, env, {});
const Abi guessed = guessAbi(m_macros);
m_abiWidget->setAbis({}, guessed);
}
diff --git a/src/plugins/baremetal/sdcctoolchain.h b/src/plugins/baremetal/sdcctoolchain.h
index da9039c827..261ec2545f 100644
--- a/src/plugins/baremetal/sdcctoolchain.h
+++ b/src/plugins/baremetal/sdcctoolchain.h
@@ -83,7 +83,8 @@ public:
SdccToolChainFactory();
QList<ProjectExplorer::ToolChain *> autoDetect(
- const QList<ProjectExplorer::ToolChain *> &alreadyKnown) final;
+ const QList<ProjectExplorer::ToolChain *> &alreadyKnown,
+ const ProjectExplorer::IDevice::Ptr &device) final;
private:
QList<ProjectExplorer::ToolChain *> autoDetectToolchains(const Candidates &candidates,
diff --git a/src/plugins/bazaar/CMakeLists.txt b/src/plugins/bazaar/CMakeLists.txt
index 6c40d344c3..ac4bcd4ffe 100644
--- a/src/plugins/bazaar/CMakeLists.txt
+++ b/src/plugins/bazaar/CMakeLists.txt
@@ -11,7 +11,6 @@ add_qtc_plugin(Bazaar
branchinfo.cpp branchinfo.h
commiteditor.cpp commiteditor.h
constants.h
- optionspage.cpp optionspage.h optionspage.ui
pullorpushdialog.cpp pullorpushdialog.h pullorpushdialog.ui
revertdialog.ui
uncommitdialog.ui
diff --git a/src/plugins/bazaar/bazaar.pro b/src/plugins/bazaar/bazaar.pro
index 6718ab3323..e71f1f8b85 100644
--- a/src/plugins/bazaar/bazaar.pro
+++ b/src/plugins/bazaar/bazaar.pro
@@ -2,7 +2,6 @@ include(../../qtcreatorplugin.pri)
SOURCES += \
bazaarclient.cpp \
bazaarplugin.cpp \
- optionspage.cpp \
bazaarsettings.cpp \
commiteditor.cpp \
bazaarcommitwidget.cpp \
@@ -15,7 +14,6 @@ HEADERS += \
bazaarclient.h \
constants.h \
bazaarplugin.h \
- optionspage.h \
bazaarsettings.h \
commiteditor.h \
bazaarcommitwidget.h \
@@ -25,7 +23,6 @@ HEADERS += \
branchinfo.h
FORMS += \
- optionspage.ui \
revertdialog.ui \
bazaarcommitpanel.ui \
pullorpushdialog.ui \
diff --git a/src/plugins/bazaar/bazaar.qbs b/src/plugins/bazaar/bazaar.qbs
index 2e5f9f0ea5..b7413b2e7c 100644
--- a/src/plugins/bazaar/bazaar.qbs
+++ b/src/plugins/bazaar/bazaar.qbs
@@ -29,9 +29,6 @@ QtcPlugin {
"commiteditor.cpp",
"commiteditor.h",
"constants.h",
- "optionspage.cpp",
- "optionspage.h",
- "optionspage.ui",
"pullorpushdialog.cpp",
"pullorpushdialog.h",
"pullorpushdialog.ui",
diff --git a/src/plugins/bazaar/bazaarclient.cpp b/src/plugins/bazaar/bazaarclient.cpp
index 84ff8c7d7d..04e86c37ae 100644
--- a/src/plugins/bazaar/bazaarclient.cpp
+++ b/src/plugins/bazaar/bazaarclient.cpp
@@ -49,13 +49,13 @@ class BazaarDiffConfig : public VcsBaseEditorConfig
{
Q_OBJECT
public:
- BazaarDiffConfig(VcsBaseClientSettings &settings, QToolBar *toolBar) :
+ BazaarDiffConfig(BazaarSettings &settings, QToolBar *toolBar) :
VcsBaseEditorConfig(toolBar)
{
- mapSetting(addToggleButton(QLatin1String("-w"), tr("Ignore Whitespace")),
- settings.boolPointer(BazaarSettings::diffIgnoreWhiteSpaceKey));
- mapSetting(addToggleButton(QLatin1String("-B"), tr("Ignore Blank Lines")),
- settings.boolPointer(BazaarSettings::diffIgnoreBlankLinesKey));
+ mapSetting(addToggleButton("-w", tr("Ignore Whitespace")),
+ &settings.diffIgnoreWhiteSpace);
+ mapSetting(addToggleButton("-B", tr("Ignore Blank Lines")),
+ &settings.diffIgnoreBlankLines);
}
QStringList arguments() const override
@@ -64,8 +64,7 @@ public:
// Bazaar wants "--diff-options=-w -B.."
const QStringList formatArguments = VcsBaseEditorConfig::arguments();
if (!formatArguments.isEmpty()) {
- const QString a = QLatin1String("--diff-options=")
- + formatArguments.join(QString(QLatin1Char(' ')));
+ const QString a = "--diff-options=" + formatArguments.join(' ');
args.append(a);
}
return args;
@@ -76,27 +75,27 @@ class BazaarLogConfig : public VcsBaseEditorConfig
{
Q_OBJECT
public:
- BazaarLogConfig(VcsBaseClientSettings &settings, QToolBar *toolBar) :
+ BazaarLogConfig(BazaarSettings &settings, QToolBar *toolBar) :
VcsBaseEditorConfig(toolBar)
{
- mapSetting(addToggleButton(QLatin1String("--verbose"), tr("Verbose"),
+ mapSetting(addToggleButton("--verbose", tr("Verbose"),
tr("Show files changed in each revision.")),
- settings.boolPointer(BazaarSettings::logVerboseKey));
- mapSetting(addToggleButton(QLatin1String("--forward"), tr("Forward"),
+ &settings.logVerbose);
+ mapSetting(addToggleButton("--forward", tr("Forward"),
tr("Show from oldest to newest.")),
- settings.boolPointer(BazaarSettings::logForwardKey));
- mapSetting(addToggleButton(QLatin1String("--include-merges"), tr("Include Merges"),
+ &settings.logForward);
+ mapSetting(addToggleButton("--include-merges", tr("Include Merges"),
tr("Show merged revisions.")),
- settings.boolPointer(BazaarSettings::logIncludeMergesKey));
+ &settings.logIncludeMerges);
const QList<ChoiceItem> logChoices = {
- ChoiceItem(tr("Detailed"), QLatin1String("long")),
- ChoiceItem(tr("Moderately Short"), QLatin1String("short")),
- ChoiceItem(tr("One Line"), QLatin1String("line")),
- ChoiceItem(tr("GNU Change Log"), QLatin1String("gnu-changelog"))
+ {tr("Detailed"), "long"},
+ {tr("Moderately Short"), "short"},
+ {tr("One Line"), "line"},
+ {tr("GNU Change Log"), "gnu-changelog"}
};
mapSetting(addChoices(tr("Format"), { "--log-format=%1" }, logChoices),
- settings.stringPointer(BazaarSettings::logFormatKey));
+ &settings.logFormat);
}
};
@@ -151,9 +150,10 @@ bool BazaarClient::synchronousUncommit(const QString &workingDir,
<< revisionSpec(revision)
<< extraOptions;
- const SynchronousProcessResponse result = vcsFullySynchronousExec(workingDir, args);
- VcsOutputWindow::append(result.stdOut());
- return result.result == SynchronousProcessResponse::Finished;
+ SynchronousProcess proc;
+ vcsFullySynchronousExec(proc, workingDir, args);
+ VcsOutputWindow::append(proc.stdOut());
+ return proc.result() == QtcProcess::Finished;
}
void BazaarClient::commit(const QString &repositoryRoot, const QStringList &files,
@@ -191,10 +191,11 @@ bool BazaarClient::managesFile(const QString &workingDirectory, const QString &f
QStringList args(QLatin1String("status"));
args << fileName;
- const SynchronousProcessResponse result = vcsFullySynchronousExec(workingDirectory, args);
- if (result.result != SynchronousProcessResponse::Finished)
+ SynchronousProcess proc;
+ vcsFullySynchronousExec(proc, workingDirectory, args);
+ if (proc.result() != QtcProcess::Finished)
return false;
- return result.rawStdOut.startsWith("unknown");
+ return proc.rawStdOut().startsWith("unknown");
}
void BazaarClient::view(const QString &source, const QString &id, const QStringList &extraOptions)
@@ -232,11 +233,11 @@ ExitCodeInterpreter BazaarClient::exitCodeInterpreter(VcsCommandTag cmd) const
{
if (cmd == DiffCommand) {
return [](int code) {
- return (code < 0 || code > 2) ? SynchronousProcessResponse::FinishedError
- : SynchronousProcessResponse::Finished;
+ return (code < 0 || code > 2) ? QtcProcess::FinishedError
+ : QtcProcess::Finished;
};
}
- return Utils::defaultExitCodeInterpreter;
+ return {};
}
QStringList BazaarClient::revisionSpec(const QString &revision) const
diff --git a/src/plugins/bazaar/bazaarplugin.cpp b/src/plugins/bazaar/bazaarplugin.cpp
index 9d1f7724fa..449fb85d78 100644
--- a/src/plugins/bazaar/bazaarplugin.cpp
+++ b/src/plugins/bazaar/bazaarplugin.cpp
@@ -31,7 +31,6 @@
#include "bazaarsettings.h"
#include "commiteditor.h"
#include "constants.h"
-#include "optionspage.h"
#include "pullorpushdialog.h"
#include "ui_revertdialog.h"
@@ -206,8 +205,7 @@ public:
// Variables
BazaarSettings m_settings;
BazaarClient m_client{&m_settings};
-
- OptionsPage m_optionsPage{[this] { configurationChanged(); }, &m_settings};
+ BazaarSettingsPage m_settingPage{&m_settings};
VcsSubmitEditorFactory m_submitEditorFactory {
submitEditorParameters,
@@ -320,6 +318,7 @@ BazaarPluginPrivate::BazaarPluginPrivate()
const QString prefix = QLatin1String("bzr");
m_commandLocator = new CommandLocator("Bazaar", prefix, prefix, this);
+ m_commandLocator->setDescription(tr("Triggers a Bazaar version control operation."));
// Create menu item for Bazaar
m_bazaarContainer = ActionManager::createMenu("Bazaar.BazaarMenu");
@@ -337,6 +336,8 @@ BazaarPluginPrivate::BazaarPluginPrivate()
ActionContainer *toolsMenu = ActionManager::actionContainer(Core::Constants::M_TOOLS);
toolsMenu->addMenu(m_bazaarContainer);
m_menuAction = m_bazaarContainer->menu()->menuAction();
+
+ connect(&m_settings, &AspectContainer::applied, this, &IVersionControl::configurationChanged);
}
void BazaarPluginPrivate::createFileActions(const Context &context)
@@ -490,7 +491,7 @@ void BazaarPluginPrivate::logRepository()
const VcsBasePluginState state = currentState();
QTC_ASSERT(state.hasTopLevel(), return);
QStringList extraOptions;
- extraOptions += QLatin1String("--limit=") + QString::number(m_settings.intValue(BazaarSettings::logCountKey));
+ extraOptions += "--limit=" + QString::number(m_settings.logCount.value());
m_client.log(state.topLevel(), QStringList(), extraOptions);
}
@@ -653,7 +654,7 @@ void BazaarPluginPrivate::showCommitWidget(const QList<VcsBaseClient::StatusItem
return;
}
- IEditor *editor = EditorManager::openEditor(saver.fileName(), COMMIT_ID);
+ IEditor *editor = EditorManager::openEditor(saver.filePath().toString(), COMMIT_ID);
if (!editor) {
VcsOutputWindow::appendError(tr("Unable to create an editor for the commit."));
return;
@@ -677,8 +678,8 @@ void BazaarPluginPrivate::showCommitWidget(const QList<VcsBaseClient::StatusItem
const BranchInfo branch = m_client.synchronousBranchQuery(m_submitRepository);
commitEditor->setFields(m_submitRepository, branch,
- m_settings.stringValue(BazaarSettings::userNameKey),
- m_settings.stringValue(BazaarSettings::userEmailKey), status);
+ m_settings.userName.value(),
+ m_settings.userEmail.value(), status);
}
void BazaarPluginPrivate::diffFromEditorSelected(const QStringList &files)
@@ -865,7 +866,7 @@ bool BazaarPluginPrivate::managesFile(const QString &workingDirectory, const QSt
bool BazaarPluginPrivate::isConfigured() const
{
- const Utils::FilePath binary = m_settings.binaryPath();
+ const FilePath binary = m_settings.binaryPath.filePath();
if (binary.isEmpty())
return false;
QFileInfo fi = binary.toFileInfo();
@@ -938,8 +939,8 @@ Core::ShellCommand *BazaarPluginPrivate::createInitialCheckoutCommand(const QStr
args << m_client.vcsCommandString(BazaarClient::CloneCommand)
<< extraArgs << url << localName;
- QProcessEnvironment env = m_client.processEnvironment();
- env.insert(QLatin1String("BZR_PROGRESS_BAR"), QLatin1String("text"));
+ Environment env = m_client.processEnvironment();
+ env.set("BZR_PROGRESS_BAR", "text");
auto command = new VcsBase::VcsCommand(baseDirectory.toString(), env);
command->addJob({m_client.vcsBinary(), args}, -1);
return command;
diff --git a/src/plugins/bazaar/bazaarsettings.cpp b/src/plugins/bazaar/bazaarsettings.cpp
index cb7d9762a4..d39d5758ec 100644
--- a/src/plugins/bazaar/bazaarsettings.cpp
+++ b/src/plugins/bazaar/bazaarsettings.cpp
@@ -24,36 +24,113 @@
****************************************************************************/
#include "bazaarsettings.h"
+
+#include "bazaarclient.h"
#include "constants.h"
+#include <coreplugin/icore.h>
+
+#include <utils/layoutbuilder.h>
+
+#include <vcsbase/vcsbaseconstants.h>
+
+using namespace Utils;
+
namespace Bazaar {
namespace Internal {
-const QLatin1String BazaarSettings::diffIgnoreWhiteSpaceKey("diffIgnoreWhiteSpace");
-const QLatin1String BazaarSettings::diffIgnoreBlankLinesKey("diffIgnoreBlankLines");
-const QLatin1String BazaarSettings::logVerboseKey("logVerbose");
-const QLatin1String BazaarSettings::logForwardKey("logForward");
-const QLatin1String BazaarSettings::logIncludeMergesKey("logIncludeMerges");
-const QLatin1String BazaarSettings::logFormatKey("logFormat");
-
BazaarSettings::BazaarSettings()
{
- setSettingsGroup(QLatin1String(Constants::BAZAAR));
- // Override default binary path
- declareKey(binaryPathKey, QLatin1String(Constants::BAZAARDEFAULT));
- declareKey(diffIgnoreWhiteSpaceKey, false);
- declareKey(diffIgnoreBlankLinesKey, false);
- declareKey(logVerboseKey, false);
- declareKey(logForwardKey, false);
- declareKey(logIncludeMergesKey, false);
- declareKey(logFormatKey, QLatin1String("long"));
+ setSettingsGroup(Constants::BAZAAR);
+ setAutoApply(false);
+
+ registerAspect(&binaryPath);
+ binaryPath.setDisplayStyle(StringAspect::PathChooserDisplay);
+ binaryPath.setExpectedKind(PathChooser::ExistingCommand);
+ binaryPath.setDefaultValue(Constants::BAZAARDEFAULT);
+ binaryPath.setDisplayName(tr("Bazaar Command"));
+ binaryPath.setHistoryCompleter("Bazaar.Command.History");
+ binaryPath.setLabelText(tr("Command:"));
+
+ registerAspect(&diffIgnoreWhiteSpace);
+ diffIgnoreWhiteSpace.setSettingsKey("diffIgnoreWhiteSpace");
+
+ registerAspect(&diffIgnoreBlankLines);
+ diffIgnoreBlankLines.setSettingsKey("diffIgnoreBlankLines");
+
+ registerAspect(&logVerbose);
+ logVerbose.setSettingsKey("logVerbose");
+
+ registerAspect(&logFormat);
+ logForward.setSettingsKey("logForward");
+
+ registerAspect(&logIncludeMerges);
+ logIncludeMerges.setSettingsKey("logIncludeMerges");
+
+ registerAspect(&logFormat);
+ logFormat.setDisplayStyle(StringAspect::LineEditDisplay);
+ logFormat.setSettingsKey("logFormat");
+ logFormat.setDefaultValue("long");
+
+ registerAspect(&userName);
+ userName.setDisplayStyle(StringAspect::LineEditDisplay);
+ userName.setLabelText(tr("Default username:"));
+ userName.setToolTip(tr("Username to use by default on commit."));
+
+ registerAspect(&userEmail);
+ userEmail.setDisplayStyle(StringAspect::LineEditDisplay);
+ userEmail.setLabelText(tr("Default email:"));
+ userEmail.setToolTip(tr("Email to use by default on commit."));
+
+ registerAspect(&logCount);
+ logCount.setLabelText(tr("Log count:"));
+ logCount.setToolTip(tr("The number of recent commit logs to show. Choose 0 to see all entries."));
+
+ registerAspect(&logCount);
+ timeout.setLabelText(tr("Timeout:"));
+ timeout.setSuffix(tr("s"));
}
-bool BazaarSettings::sameUserId(const BazaarSettings &other) const
+// BazaarSettingsPage
+
+BazaarSettingsPage::BazaarSettingsPage(BazaarSettings *settings)
{
- return stringValue(userNameKey) == other.stringValue(userNameKey)
- && stringValue(userEmailKey) == other.stringValue(userEmailKey);
+ setId(VcsBase::Constants::VCS_ID_BAZAAR);
+ setDisplayName(BazaarSettings::tr("Bazaar"));
+ setCategory(VcsBase::Constants::VCS_SETTINGS_CATEGORY);
+ setSettings(settings);
+
+ setLayouter([settings](QWidget *widget) {
+ BazaarSettings &s = *settings;
+ using namespace Layouting;
+
+ Column {
+ Group {
+ Title(BazaarSettings::tr("Configuration")),
+ Row { s.binaryPath }
+ },
+
+ Group {
+ Title(BazaarSettings::tr("User")),
+ Form {
+ s.userName,
+ s.userEmail
+ }
+ },
+
+ Group {
+ Title(BazaarSettings::tr("Miscellaneous")),
+ Row {
+ s.logCount,
+ s.timeout,
+ Stretch()
+ }
+ },
+ Stretch()
+
+ }.attachTo(widget);
+ });
}
-} // namespace Internal
-} // namespace Bazaar
+} // Internal
+} // Bazaar
diff --git a/src/plugins/bazaar/bazaarsettings.h b/src/plugins/bazaar/bazaarsettings.h
index 2bc1adc022..5810325d60 100644
--- a/src/plugins/bazaar/bazaarsettings.h
+++ b/src/plugins/bazaar/bazaarsettings.h
@@ -25,23 +25,30 @@
#pragma once
+#include <coreplugin/dialogs/ioptionspage.h>
+
#include <vcsbase/vcsbaseclientsettings.h>
namespace Bazaar {
namespace Internal {
-class BazaarSettings : public VcsBase::VcsBaseClientSettings
+class BazaarSettings final : public VcsBase::VcsBaseSettings
{
public:
- static const QLatin1String diffIgnoreWhiteSpaceKey;
- static const QLatin1String diffIgnoreBlankLinesKey;
- static const QLatin1String logVerboseKey;
- static const QLatin1String logForwardKey;
- static const QLatin1String logIncludeMergesKey;
- static const QLatin1String logFormatKey;
-
BazaarSettings();
- bool sameUserId(const BazaarSettings &other) const;
+
+ Utils::BoolAspect diffIgnoreWhiteSpace;
+ Utils::BoolAspect diffIgnoreBlankLines;
+ Utils::BoolAspect logVerbose;
+ Utils::BoolAspect logForward;
+ Utils::BoolAspect logIncludeMerges;
+ Utils::StringAspect logFormat;
+};
+
+class BazaarSettingsPage final : public Core::IOptionsPage
+{
+public:
+ explicit BazaarSettingsPage(BazaarSettings *settings);
};
} // namespace Internal
diff --git a/src/plugins/bazaar/optionspage.cpp b/src/plugins/bazaar/optionspage.cpp
deleted file mode 100644
index b6b41296fc..0000000000
--- a/src/plugins/bazaar/optionspage.cpp
+++ /dev/null
@@ -1,95 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 Hugues Delorme
-** 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 "optionspage.h"
-#include "bazaarclient.h"
-#include "bazaarsettings.h"
-#include "bazaarplugin.h"
-#include "ui_optionspage.h"
-
-#include <coreplugin/icore.h>
-#include <vcsbase/vcsbaseconstants.h>
-
-using namespace VcsBase;
-
-namespace Bazaar {
-namespace Internal {
-
-class OptionsPageWidget final : public Core::IOptionsPageWidget
-{
- Q_DECLARE_TR_FUNCTIONS(Bazaar::Internal::OptionsPageWidget)
-
-public:
- OptionsPageWidget(const std::function<void()> &onApply, BazaarSettings *settings);
-
- void apply() final;
-
-private:
- Ui::OptionsPage m_ui;
- const std::function<void()> m_onApply;
- BazaarSettings *m_settings;
-};
-
-void OptionsPageWidget::apply()
-{
- BazaarSettings s = *m_settings;
- s.setValue(BazaarSettings::binaryPathKey, m_ui.commandChooser->rawPath());
- s.setValue(BazaarSettings::userNameKey, m_ui.defaultUsernameLineEdit->text().trimmed());
- s.setValue(BazaarSettings::userEmailKey, m_ui.defaultEmailLineEdit->text().trimmed());
- s.setValue(BazaarSettings::logCountKey, m_ui.logEntriesCount->value());
- s.setValue(BazaarSettings::timeoutKey, m_ui.timeout->value());
-
- if (*m_settings == s)
- return;
-
- *m_settings = s;
- m_onApply();
-}
-
-OptionsPageWidget::OptionsPageWidget(const std::function<void(void)> &onApply, BazaarSettings *settings)
- : m_onApply(onApply), m_settings(settings)
-{
- m_ui.setupUi(this);
- m_ui.commandChooser->setExpectedKind(Utils::PathChooser::ExistingCommand);
- m_ui.commandChooser->setPromptDialogTitle(tr("Bazaar Command"));
- m_ui.commandChooser->setHistoryCompleter(QLatin1String("Bazaar.Command.History"));
-
- m_ui.commandChooser->setPath(m_settings->stringValue(BazaarSettings::binaryPathKey));
- m_ui.defaultUsernameLineEdit->setText(m_settings->stringValue(BazaarSettings::userNameKey));
- m_ui.defaultEmailLineEdit->setText(m_settings->stringValue(BazaarSettings::userEmailKey));
- m_ui.logEntriesCount->setValue(m_settings->intValue(BazaarSettings::logCountKey));
- m_ui.timeout->setValue(m_settings->intValue(BazaarSettings::timeoutKey));
-}
-
-OptionsPage::OptionsPage(const std::function<void(void)> &onApply, BazaarSettings *settings)
-{
- setId(VcsBase::Constants::VCS_ID_BAZAAR);
- setDisplayName(OptionsPageWidget::tr("Bazaar"));
- setWidgetCreator([onApply, settings] { return new OptionsPageWidget(onApply, settings); });
- setCategory(Constants::VCS_SETTINGS_CATEGORY);
-}
-
-} // Internal
-} // Bazaar
diff --git a/src/plugins/bazaar/optionspage.ui b/src/plugins/bazaar/optionspage.ui
deleted file mode 100644
index 419ce3e94d..0000000000
--- a/src/plugins/bazaar/optionspage.ui
+++ /dev/null
@@ -1,176 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<ui version="4.0">
- <class>Bazaar::Internal::OptionsPage</class>
- <widget class="QWidget" name="Bazaar::Internal::OptionsPage">
- <property name="geometry">
- <rect>
- <x>0</x>
- <y>0</y>
- <width>649</width>
- <height>268</height>
- </rect>
- </property>
- <property name="windowTitle">
- <string/>
- </property>
- <layout class="QVBoxLayout" name="verticalLayout">
- <item>
- <widget class="QGroupBox" name="configGroupBox">
- <property name="title">
- <string>Configuration</string>
- </property>
- <layout class="QFormLayout" name="formLayout_3">
- <property name="fieldGrowthPolicy">
- <enum>QFormLayout::ExpandingFieldsGrow</enum>
- </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="commandChooser" native="true"/>
- </item>
- </layout>
- </widget>
- </item>
- <item>
- <widget class="QGroupBox" name="userGroupBox">
- <property name="title">
- <string>User</string>
- </property>
- <layout class="QFormLayout" name="formLayout">
- <property name="fieldGrowthPolicy">
- <enum>QFormLayout::ExpandingFieldsGrow</enum>
- </property>
- <item row="0" column="0">
- <widget class="QLabel" name="defaultUsernameLabel">
- <property name="toolTip">
- <string>Username to use by default on commit.</string>
- </property>
- <property name="text">
- <string>Default username:</string>
- </property>
- </widget>
- </item>
- <item row="0" column="1">
- <widget class="QLineEdit" name="defaultUsernameLineEdit">
- <property name="toolTip">
- <string>Username to use by default on commit.</string>
- </property>
- </widget>
- </item>
- <item row="1" column="0">
- <widget class="QLabel" name="defaultEmailLabel">
- <property name="toolTip">
- <string>Email to use by default on commit.</string>
- </property>
- <property name="text">
- <string>Default email:</string>
- </property>
- </widget>
- </item>
- <item row="1" column="1">
- <widget class="QLineEdit" name="defaultEmailLineEdit">
- <property name="toolTip">
- <string>Email to use by default on commit.</string>
- </property>
- </widget>
- </item>
- </layout>
- </widget>
- </item>
- <item>
- <widget class="QGroupBox" name="miscGroupBox">
- <property name="title">
- <string>Miscellaneous</string>
- </property>
- <layout class="QGridLayout" name="gridLayout">
- <item row="0" column="0">
- <widget class="QLabel" name="showLogEntriesLabel">
- <property name="text">
- <string>Log count:</string>
- </property>
- </widget>
- </item>
- <item row="0" column="1">
- <widget class="QSpinBox" name="logEntriesCount">
- <property name="toolTip">
- <string>The number of recent commit logs to show. Choose 0 to see all entries.</string>
- </property>
- <property name="maximum">
- <number>1000</number>
- </property>
- <property name="value">
- <number>1000</number>
- </property>
- </widget>
- </item>
- <item row="0" column="2">
- <widget class="QLabel" name="timeoutSecondsLabel">
- <property name="text">
- <string>Timeout:</string>
- </property>
- </widget>
- </item>
- <item row="0" column="3">
- <widget class="QSpinBox" name="timeout">
- <property name="suffix">
- <string>s</string>
- </property>
- <property name="maximum">
- <number>360</number>
- </property>
- <property name="value">
- <number>30</number>
- </property>
- </widget>
- </item>
- <item row="0" column="4">
- <spacer name="horizontalSpacer">
- <property name="orientation">
- <enum>Qt::Horizontal</enum>
- </property>
- <property name="sizeHint" stdset="0">
- <size>
- <width>213</width>
- <height>20</height>
- </size>
- </property>
- </spacer>
- </item>
- </layout>
- </widget>
- </item>
- <item>
- <spacer name="verticalSpacer">
- <property name="orientation">
- <enum>Qt::Vertical</enum>
- </property>
- <property name="sizeHint" stdset="0">
- <size>
- <width>20</width>
- <height>40</height>
- </size>
- </property>
- </spacer>
- </item>
- </layout>
- </widget>
- <customwidgets>
- <customwidget>
- <class>Utils::PathChooser</class>
- <extends>QWidget</extends>
- <header location="global">utils/pathchooser.h</header>
- <container>1</container>
- <slots>
- <signal>editingFinished()</signal>
- <signal>browsingFinished()</signal>
- </slots>
- </customwidget>
- </customwidgets>
- <resources/>
- <connections/>
-</ui>
diff --git a/src/plugins/beautifier/abstractsettings.cpp b/src/plugins/beautifier/abstractsettings.cpp
index 73df51d06c..e1524ac1d9 100644
--- a/src/plugins/beautifier/abstractsettings.cpp
+++ b/src/plugins/beautifier/abstractsettings.cpp
@@ -47,11 +47,12 @@ const char COMMAND[] = "command";
const char SUPPORTED_MIME[] = "supportedMime";
}
-AbstractSettings::AbstractSettings(const QString &name, const QString &ending) :
- m_ending(ending),
- m_styleDir(Core::ICore::userResourcePath() + '/' + Beautifier::Constants::SETTINGS_DIRNAME
- + '/' + name),
- m_name(name)
+AbstractSettings::AbstractSettings(const QString &name, const QString &ending)
+ : m_ending(ending)
+ , m_styleDir(Core::ICore::userResourcePath(Beautifier::Constants::SETTINGS_DIRNAME)
+ .pathAppended(name)
+ .toString())
+ , m_name(name)
{
}
@@ -245,16 +246,16 @@ void AbstractSettings::save()
continue;
}
- Utils::FileSaver saver(fi.absoluteFilePath());
+ Utils::FileSaver saver(Utils::FilePath::fromUserInput(fi.absoluteFilePath()));
if (saver.hasError()) {
BeautifierPlugin::showError(tr("Cannot open file \"%1\": %2.")
- .arg(saver.fileName())
+ .arg(saver.filePath().toUserOutput())
.arg(saver.errorString()));
} else {
saver.write(iStyles.value().toLocal8Bit());
if (!saver.finalize()) {
BeautifierPlugin::showError(tr("Cannot save file \"%1\": %2.")
- .arg(saver.fileName())
+ .arg(saver.filePath().toUserOutput())
.arg(saver.errorString()));
}
}
diff --git a/src/plugins/beautifier/artisticstyle/artisticstylesettings.cpp b/src/plugins/beautifier/artisticstyle/artisticstylesettings.cpp
index d908eba363..4954975cd4 100644
--- a/src/plugins/beautifier/artisticstyle/artisticstylesettings.cpp
+++ b/src/plugins/beautifier/artisticstyle/artisticstylesettings.cpp
@@ -33,7 +33,7 @@
#include <utils/runextensions.h>
#include <utils/stringutils.h>
-#include <utils/synchronousprocess.h>
+#include <utils/qtcprocess.h>
#include <QDateTime>
#include <QFile>
@@ -84,15 +84,16 @@ static int parseVersion(const QString &text)
static int updateVersionHelper(const Utils::FilePath &command)
{
Utils::SynchronousProcess process;
- Utils::SynchronousProcessResponse response = process.runBlocking({command, {"--version"}});
- if (response.result != Utils::SynchronousProcessResponse::Finished)
+ process.setCommand({command, {"--version"}});
+ process.runBlocking();
+ if (process.result() != Utils::QtcProcess::Finished)
return 0;
// Astyle prints the version on stdout or stderr, depending on platform
- const int version = parseVersion(response.stdOut().trimmed());
+ const int version = parseVersion(process.stdOut().trimmed());
if (version != 0)
return version;
- return parseVersion(response.stdErr().trimmed());
+ return parseVersion(process.stdErr().trimmed());
}
void ArtisticStyleSettings::updateVersion()
@@ -171,17 +172,19 @@ void ArtisticStyleSettings::setCustomStyle(const QString &customStyle)
QString ArtisticStyleSettings::documentationFilePath() const
{
- return Core::ICore::userResourcePath() + '/' + Beautifier::Constants::SETTINGS_DIRNAME + '/'
- + Beautifier::Constants::DOCUMENTATION_DIRNAME + '/'
- + SETTINGS_NAME + ".xml";
+ return (Core::ICore::userResourcePath(Beautifier::Constants::SETTINGS_DIRNAME)
+ / Beautifier::Constants::DOCUMENTATION_DIRNAME / SETTINGS_NAME
+ + ".xml")
+ .toString();
}
void ArtisticStyleSettings::createDocumentationFile() const
{
Utils::SynchronousProcess process;
process.setTimeoutS(2);
- Utils::SynchronousProcessResponse response = process.runBlocking({command(), {"-h"}});
- if (response.result != Utils::SynchronousProcessResponse::Finished)
+ process.setCommand({command(), {"-h"}});
+ process.runBlocking();
+ if (process.result() != Utils::QtcProcess::Finished)
return;
QFile file(documentationFilePath());
@@ -199,7 +202,7 @@ void ArtisticStyleSettings::createDocumentationFile() const
stream.writeStartElement(Constants::DOCUMENTATION_XMLROOT);
// astyle writes its output to 'error'...
- const QStringList lines = response.stdErr().split(QLatin1Char('\n'));
+ const QStringList lines = process.stdErr().split(QLatin1Char('\n'));
QStringList keys;
QStringList docu;
for (QString line : lines) {
diff --git a/src/plugins/beautifier/beautifierplugin.cpp b/src/plugins/beautifier/beautifierplugin.cpp
index f67495396c..534de41ce0 100644
--- a/src/plugins/beautifier/beautifierplugin.cpp
+++ b/src/plugins/beautifier/beautifierplugin.cpp
@@ -53,8 +53,8 @@
#include <utils/fileutils.h>
#include <utils/mimetypes/mimedatabase.h>
#include <utils/qtcassert.h>
+#include <utils/qtcprocess.h>
#include <utils/runextensions.h>
-#include <utils/synchronousprocess.h>
#include <utils/temporarydirectory.h>
#include <utils/textutils.h>
diff --git a/src/plugins/beautifier/clangformat/clangformat.cpp b/src/plugins/beautifier/clangformat/clangformat.cpp
index f7a289945f..8f8d1b8fde 100644
--- a/src/plugins/beautifier/clangformat/clangformat.cpp
+++ b/src/plugins/beautifier/clangformat/clangformat.cpp
@@ -41,6 +41,7 @@
#include <coreplugin/editormanager/ieditor.h>
#include <coreplugin/idocument.h>
#include <texteditor/formattexteditor.h>
+#include <texteditor/textdocument.h>
#include <texteditor/texteditor.h>
#include <utils/algorithm.h>
#include <utils/fileutils.h>
@@ -48,6 +49,7 @@
#include <QAction>
#include <QMenu>
#include <QTextBlock>
+#include <QTextCodec>
using namespace TextEditor;
@@ -106,6 +108,25 @@ void ClangFormat::formatFile()
formatCurrentFile(command());
}
+void ClangFormat::formatAtPosition(const int pos, const int length)
+{
+ const TextEditorWidget *widget = TextEditorWidget::currentTextEditorWidget();
+ if (!widget)
+ return;
+
+ const QTextCodec *codec = widget->textDocument()->codec();
+ if (!codec) {
+ formatCurrentFile(command(pos, length));
+ return;
+ }
+
+ const QString &text = widget->textAt(0, pos + length);
+ const QStringView buffer(text);
+ const int encodedOffset = codec->fromUnicode(buffer.left(pos)).size();
+ const int encodedLength = codec->fromUnicode(buffer.mid(pos, length)).size();
+ formatCurrentFile(command(encodedOffset, encodedLength));
+}
+
void ClangFormat::formatAtCursor()
{
const TextEditorWidget *widget = TextEditorWidget::currentTextEditorWidget();
@@ -113,18 +134,16 @@ void ClangFormat::formatAtCursor()
return;
const QTextCursor tc = widget->textCursor();
+
if (tc.hasSelection()) {
- const int offset = tc.selectionStart();
- const int length = tc.selectionEnd() - offset;
- formatCurrentFile(command(offset, length));
+ const int selectionStart = tc.selectionStart();
+ formatAtPosition(selectionStart, tc.selectionEnd() - selectionStart);
} else {
// Pretend that the current line was selected.
// Note that clang-format will extend the range to the next bigger
// syntactic construct if needed.
const QTextBlock block = tc.block();
- const int offset = block.position();
- const int length = block.length();
- formatCurrentFile(command(offset, length));
+ formatAtPosition(block.position(), block.length());
}
}
@@ -185,7 +204,7 @@ void ClangFormat::disableFormattingSelectedText()
// The indentation of these markers might be undesired, so reformat.
// This is not optimal because two undo steps will be needed to remove the markers.
const int reformatTextLength = insertCursor.position() - selectionStartBlock.position();
- formatCurrentFile(command(selectionStartBlock.position(), reformatTextLength));
+ formatAtPosition(selectionStartBlock.position(), reformatTextLength);
}
Command ClangFormat::command() const
diff --git a/src/plugins/beautifier/clangformat/clangformat.h b/src/plugins/beautifier/clangformat/clangformat.h
index 24ce566861..2189398d5a 100644
--- a/src/plugins/beautifier/clangformat/clangformat.h
+++ b/src/plugins/beautifier/clangformat/clangformat.h
@@ -47,6 +47,7 @@ public:
private:
void formatFile();
+ void formatAtPosition(const int pos, const int length);
void formatAtCursor();
void formatLines();
void disableFormattingSelectedText();
diff --git a/src/plugins/beautifier/clangformat/clangformatsettings.cpp b/src/plugins/beautifier/clangformat/clangformatsettings.cpp
index d2b5416715..30e09619cf 100644
--- a/src/plugins/beautifier/clangformat/clangformatsettings.cpp
+++ b/src/plugins/beautifier/clangformat/clangformatsettings.cpp
@@ -56,9 +56,10 @@ ClangFormatSettings::ClangFormatSettings() :
QString ClangFormatSettings::documentationFilePath() const
{
- return Core::ICore::userResourcePath() + '/' + Beautifier::Constants::SETTINGS_DIRNAME + '/'
- + Beautifier::Constants::DOCUMENTATION_DIRNAME + '/'
- + SETTINGS_NAME + ".xml";
+ return (Core::ICore::userResourcePath() / Beautifier::Constants::SETTINGS_DIRNAME
+ / Beautifier::Constants::DOCUMENTATION_DIRNAME / SETTINGS_NAME
+ + ".xml")
+ .toString();
}
void ClangFormatSettings::createDocumentationFile() const
diff --git a/src/plugins/beautifier/uncrustify/uncrustifysettings.cpp b/src/plugins/beautifier/uncrustify/uncrustifysettings.cpp
index 6f94d5e49f..61008fa8ea 100644
--- a/src/plugins/beautifier/uncrustify/uncrustifysettings.cpp
+++ b/src/plugins/beautifier/uncrustify/uncrustifysettings.cpp
@@ -31,7 +31,7 @@
#include <coreplugin/icore.h>
-#include <utils/synchronousprocess.h>
+#include <utils/qtcprocess.h>
#include <QDateTime>
#include <QFile>
@@ -140,18 +140,19 @@ void UncrustifySettings::setFormatEntireFileFallback(bool formatEntireFileFallba
QString UncrustifySettings::documentationFilePath() const
{
- return Core::ICore::userResourcePath() + '/' + Beautifier::Constants::SETTINGS_DIRNAME + '/'
- + Beautifier::Constants::DOCUMENTATION_DIRNAME + '/'
- + SETTINGS_NAME + ".xml";
+ return (Core::ICore::userResourcePath() / Beautifier::Constants::SETTINGS_DIRNAME
+ / Beautifier::Constants::DOCUMENTATION_DIRNAME / SETTINGS_NAME
+ + ".xml")
+ .toString();
}
void UncrustifySettings::createDocumentationFile() const
{
Utils::SynchronousProcess process;
process.setTimeoutS(2);
- Utils::SynchronousProcessResponse response
- = process.runBlocking({command(), {"--show-config"}});
- if (response.result != Utils::SynchronousProcessResponse::Finished)
+ process.setCommand({command(), {"--show-config"}});
+ process.runBlocking();
+ if (process.result() != Utils::QtcProcess::Finished)
return;
QFile file(documentationFilePath());
@@ -168,7 +169,7 @@ void UncrustifySettings::createDocumentationFile() const
stream.writeComment("Created " + QDateTime::currentDateTime().toString(Qt::ISODate));
stream.writeStartElement(Constants::DOCUMENTATION_XMLROOT);
- const QStringList lines = response.allOutput().split(QLatin1Char('\n'));
+ const QStringList lines = process.allOutput().split(QLatin1Char('\n'));
const int totalLines = lines.count();
for (int i = 0; i < totalLines; ++i) {
const QString &line = lines.at(i);
diff --git a/src/plugins/bineditor/bineditorplugin.cpp b/src/plugins/bineditor/bineditorplugin.cpp
index ae766e5be0..9781161a5b 100644
--- a/src/plugins/bineditor/bineditorplugin.cpp
+++ b/src/plugins/bineditor/bineditorplugin.cpp
@@ -230,28 +230,27 @@ public:
return type == TypeRemoved ? BehaviorSilent : IDocument::reloadBehavior(state, type);
}
- bool save(QString *errorString, const QString &fn, bool autoSave) override
+ bool save(QString *errorString, const Utils::FilePath &filePath, bool autoSave) override
{
QTC_ASSERT(!autoSave, return true); // bineditor does not support autosave - it would be a bit expensive
- const FilePath fileNameToUse = fn.isEmpty() ? filePath() : FilePath::fromString(fn);
- if (m_widget->save(errorString, filePath().toString(), fileNameToUse.toString())) {
+ const FilePath &fileNameToUse = filePath.isEmpty() ? this->filePath() : filePath;
+ if (m_widget->save(errorString, this->filePath().toString(), fileNameToUse.toString())) {
setFilePath(fileNameToUse);
return true;
- } else {
- return false;
}
+ return false;
}
- OpenResult open(QString *errorString, const QString &fileName,
- const QString &realFileName) override
+ OpenResult open(QString *errorString, const Utils::FilePath &filePath,
+ const Utils::FilePath &realFilePath) override
{
- QTC_CHECK(fileName == realFileName); // The bineditor can do no autosaving
- return openImpl(errorString, fileName);
+ QTC_CHECK(filePath == realFilePath); // The bineditor can do no autosaving
+ return openImpl(errorString, filePath);
}
- OpenResult openImpl(QString *errorString, const QString &fileName, quint64 offset = 0)
+ OpenResult openImpl(QString *errorString, const Utils::FilePath &filePath, quint64 offset = 0)
{
- QFile file(fileName);
+ QFile file(filePath.toString());
if (file.open(QIODevice::ReadOnly)) {
file.close();
quint64 size = static_cast<quint64>(file.size());
@@ -274,12 +273,11 @@ public:
}
if (offset >= size)
return OpenResult::CannotHandle;
- setFilePath(FilePath::fromString(fileName));
+ setFilePath(filePath);
m_widget->setSizes(offset, file.size());
return OpenResult::Success;
}
- QString errStr = tr("Cannot open %1: %2").arg(
- QDir::toNativeSeparators(fileName), file.errorString());
+ QString errStr = tr("Cannot open %1: %2").arg(filePath.toUserOutput(), file.errorString());
if (errorString)
*errorString = errStr;
else
@@ -312,7 +310,7 @@ public:
void provideNewRange(quint64 offset)
{
if (filePath().exists())
- openImpl(nullptr, filePath().toString(), offset);
+ openImpl(nullptr, filePath(), offset);
}
public:
@@ -332,7 +330,7 @@ public:
emit aboutToReload();
int cPos = m_widget->cursorPosition();
m_widget->clear();
- const bool success = (openImpl(errorString, filePath().toString()) == OpenResult::Success);
+ const bool success = (openImpl(errorString, filePath()) == OpenResult::Success);
m_widget->setCursorPosition(cPos);
emit reloadFinished(success);
return success;
diff --git a/src/plugins/bineditor/bineditorwidget.cpp b/src/plugins/bineditor/bineditorwidget.cpp
index fafbcaa51b..73b822c5c4 100644
--- a/src/plugins/bineditor/bineditorwidget.cpp
+++ b/src/plugins/bineditor/bineditorwidget.cpp
@@ -419,7 +419,8 @@ bool BinEditorWidget::save(QString *errorString, const QString &oldFileName, con
if (!QFile::rename(tmpName, newFileName))
return false;
}
- Utils::FileSaver saver(newFileName, QIODevice::ReadWrite); // QtBug: WriteOnly truncates.
+ Utils::FileSaver saver(Utils::FilePath::fromString(newFileName),
+ QIODevice::ReadWrite); // QtBug: WriteOnly truncates.
if (!saver.hasError()) {
QFile *output = saver.file();
const qint64 size = output->size();
diff --git a/src/plugins/bookmarks/bookmarkfilter.cpp b/src/plugins/bookmarks/bookmarkfilter.cpp
index c62cf7edc8..28173ffe5d 100644
--- a/src/plugins/bookmarks/bookmarkfilter.cpp
+++ b/src/plugins/bookmarks/bookmarkfilter.cpp
@@ -39,6 +39,8 @@ BookmarkFilter::BookmarkFilter(BookmarkManager *manager)
{
setId("Bookmarks");
setDisplayName(tr("Bookmarks"));
+ setDescription(tr("Matches all bookmarks. Filter by file name, by the text on the line of the "
+ "bookmark, or by the bookmark's note text."));
setPriority(Medium);
setDefaultShortcutString("b");
}
diff --git a/src/plugins/bookmarks/bookmarkmanager.cpp b/src/plugins/bookmarks/bookmarkmanager.cpp
index 01f76026f8..bb346b6507 100644
--- a/src/plugins/bookmarks/bookmarkmanager.cpp
+++ b/src/plugins/bookmarks/bookmarkmanager.cpp
@@ -489,9 +489,10 @@ Bookmark *BookmarkManager::bookmarkForIndex(const QModelIndex &index) const
bool BookmarkManager::gotoBookmark(const Bookmark *bookmark) const
{
- if (IEditor *editor = EditorManager::openEditorAt(bookmark->fileName().toString(),
- bookmark->lineNumber()))
+ if (IEditor *editor = EditorManager::openEditorAt(
+ Utils::Link(bookmark->fileName(), bookmark->lineNumber()))) {
return editor->currentLine() == bookmark->lineNumber();
+ }
return false;
}
@@ -812,9 +813,7 @@ BookmarkViewFactory::BookmarkViewFactory(BookmarkManager *bm)
NavigationView BookmarkViewFactory::createWidget()
{
auto view = new BookmarkView(m_manager);
- auto navview = NavigationView(view);
- navview.dockToolBarWidgets = view->createToolBarWidgets();
- return navview;
+ return {view, view->createToolBarWidgets()};
}
} // namespace Internal
diff --git a/src/plugins/bookmarks/bookmarks_global.h b/src/plugins/bookmarks/bookmarks_global.h
index 6f22b7eb09..bdc02f8a63 100644
--- a/src/plugins/bookmarks/bookmarks_global.h
+++ b/src/plugins/bookmarks/bookmarks_global.h
@@ -29,6 +29,7 @@ namespace Bookmarks {
namespace Constants {
const char BOOKMARKS_TOGGLE_ACTION[] = "Bookmarks.Toggle";
+const char BOOKMARKS_EDIT_ACTION[] = "Bookmarks.Edit";
const char BOOKMARKS_MOVEUP_ACTION[] = "Bookmarks.MoveUp";
const char BOOKMARKS_MOVEDOWN_ACTION[] = "Bookmarks.MoveDown";
const char BOOKMARKS_EDITNOTE_ACTION[] = "Bookmarks.EditNote";
diff --git a/src/plugins/bookmarks/bookmarksplugin.cpp b/src/plugins/bookmarks/bookmarksplugin.cpp
index 4ac250d0a8..db0bd49beb 100644
--- a/src/plugins/bookmarks/bookmarksplugin.cpp
+++ b/src/plugins/bookmarks/bookmarksplugin.cpp
@@ -72,6 +72,7 @@ public:
BookmarkViewFactory m_bookmarkViewFactory;
QAction m_toggleAction{BookmarksPlugin::tr("Toggle Bookmark"), nullptr};
+ QAction m_editAction{BookmarksPlugin::tr("Edit Bookmark"), nullptr};
QAction m_prevAction{BookmarksPlugin::tr("Previous Bookmark"), nullptr};
QAction m_nextAction{BookmarksPlugin::tr("Next Bookmark"), nullptr};
QAction m_docPrevAction{BookmarksPlugin::tr("Previous Bookmark in Document"), nullptr};
@@ -113,6 +114,14 @@ BookmarksPluginPrivate::BookmarksPluginPrivate()
: BookmarksPlugin::tr("Ctrl+M")));
cmd->setTouchBarIcon(Utils::Icons::MACOS_TOUCHBAR_BOOKMARK.icon());
mbm->addAction(cmd);
+
+ cmd = ActionManager::registerAction(&m_editAction,
+ BOOKMARKS_EDIT_ACTION,
+ editorManagerContext);
+ cmd->setDefaultKeySequence(QKeySequence(useMacShortcuts ? BookmarksPlugin::tr("Meta+Shift+M")
+ : BookmarksPlugin::tr("Ctrl+Shift+M")));
+ mbm->addAction(cmd);
+
touchBar->addAction(cmd, Core::Constants::G_TOUCHBAR_EDITOR);
mbm->addSeparator();
@@ -151,6 +160,17 @@ BookmarksPluginPrivate::BookmarksPluginPrivate()
m_bookmarkManager.toggleBookmark(editor->document()->filePath(), editor->currentLine());
});
+ connect(&m_editAction, &QAction::triggered, this, [this] {
+ BaseTextEditor *editor = BaseTextEditor::currentTextEditor();
+ if (editor && !editor->document()->isTemporary()) {
+ const FilePath filePath = editor->document()->filePath();
+ const int line = editor->currentLine();
+ if (!m_bookmarkManager.hasBookmarkInPosition(filePath, line))
+ m_bookmarkManager.toggleBookmark(filePath, line);
+ m_bookmarkManager.editByFileAndLine(filePath, line);
+ }
+ });
+
connect(&m_prevAction, &QAction::triggered, &m_bookmarkManager, &BookmarkManager::prev);
connect(&m_nextAction, &QAction::triggered, &m_bookmarkManager, &BookmarkManager::next);
connect(&m_docPrevAction, &QAction::triggered,
@@ -183,6 +203,7 @@ void BookmarksPluginPrivate::updateActions(bool enableToggle, int state)
const bool hasdocbm = state == BookmarkManager::HasBookmarksInDocument;
m_toggleAction.setEnabled(enableToggle);
+ m_editAction.setEnabled(enableToggle);
m_prevAction.setEnabled(hasbm);
m_nextAction.setEnabled(hasbm);
m_docPrevAction.setEnabled(hasdocbm);
diff --git a/src/plugins/clangcodemodel/CMakeLists.txt b/src/plugins/clangcodemodel/CMakeLists.txt
index ac90081b3a..4176bfd1e9 100644
--- a/src/plugins/clangcodemodel/CMakeLists.txt
+++ b/src/plugins/clangcodemodel/CMakeLists.txt
@@ -1,7 +1,12 @@
+set(TEST_LINK_DEPENDS)
+if(WITH_TESTS)
+ set(TEST_LINK_DEPENDS QtSupport)
+endif()
+
add_qtc_plugin(ClangCodeModel
CONDITION TARGET libclang
DEPENDS ClangSupport CPlusPlus
- PLUGIN_DEPENDS Core CppTools TextEditor
+ PLUGIN_DEPENDS Core CppTools LanguageClient ${TEST_LINK_DEPENDS} TextEditor
PLUGIN_TEST_DEPENDS CppEditor QmakeProjectManager
SOURCES
clangactivationsequencecontextprocessor.cpp clangactivationsequencecontextprocessor.h
@@ -19,6 +24,7 @@ add_qtc_plugin(ClangCodeModel
clangcompletionchunkstotextconverter.cpp clangcompletionchunkstotextconverter.h
clangcompletioncontextanalyzer.cpp clangcompletioncontextanalyzer.h
clangconstants.h
+ clangdclient.cpp clangdclient.h
clangcurrentdocumentfilter.cpp clangcurrentdocumentfilter.h
clangdiagnosticfilter.cpp clangdiagnosticfilter.h
clangdiagnosticmanager.cpp clangdiagnosticmanager.h
@@ -29,6 +35,7 @@ add_qtc_plugin(ClangCodeModel
clangfixitoperationsextractor.cpp clangfixitoperationsextractor.h
clangfollowsymbol.cpp clangfollowsymbol.h
clangfunctionhintmodel.cpp clangfunctionhintmodel.h
+ clanggloballocatorfilters.cpp clanggloballocatorfilters.h
clanghighlightingresultreporter.cpp clanghighlightingresultreporter.h
clanghoverhandler.cpp clanghoverhandler.h
clangisdiagnosticrelatedtolocation.h
@@ -50,5 +57,6 @@ extend_qtc_plugin(ClangCodeModel
test/clangautomationutils.cpp test/clangautomationutils.h
test/clangbatchfileprocessor.cpp test/clangbatchfileprocessor.h
test/clangcodecompletion_test.cpp test/clangcodecompletion_test.h
+ test/clangdtests.cpp test/clangdtests.h
test/data/clangtestdata.qrc
)
diff --git a/src/plugins/clangcodemodel/clangbackendcommunicator.cpp b/src/plugins/clangcodemodel/clangbackendcommunicator.cpp
index 569645bd2d..510d1d8d41 100644
--- a/src/plugins/clangcodemodel/clangbackendcommunicator.cpp
+++ b/src/plugins/clangcodemodel/clangbackendcommunicator.cpp
@@ -64,7 +64,7 @@ enum { backEndStartTimeOutInMs = 10000 };
static QString backendProcessPath()
{
- return Core::ICore::libexecPath() + "/clangbackend" + QTC_HOST_EXE_SUFFIX;
+ return Core::ICore::libexecPath("clangbackend" QTC_HOST_EXE_SUFFIX).toString();
}
namespace ClangCodeModel {
diff --git a/src/plugins/clangcodemodel/clangcodemodel.pro b/src/plugins/clangcodemodel/clangcodemodel.pro
index aba8a8ee7f..f6d7b79071 100644
--- a/src/plugins/clangcodemodel/clangcodemodel.pro
+++ b/src/plugins/clangcodemodel/clangcodemodel.pro
@@ -40,7 +40,9 @@ SOURCES += \
clangtextmark.cpp \
clanguiheaderondiskmanager.cpp \
clangutils.cpp \
- clangoverviewmodel.cpp
+ clangoverviewmodel.cpp \
+ clangdclient.cpp \
+ clanggloballocatorfilters.cpp
HEADERS += \
clangactivationsequencecontextprocessor.h \
@@ -79,7 +81,9 @@ HEADERS += \
clangtextmark.h \
clanguiheaderondiskmanager.h \
clangutils.h \
- clangoverviewmodel.h
+ clangoverviewmodel.h \
+ clangdclient.h \
+ clanggloballocatorfilters.h
FORMS += clangprojectsettingswidget.ui
@@ -92,11 +96,13 @@ equals(TEST, 1) {
test/clangautomationutils.h \
test/clangbatchfileprocessor.h \
test/clangcodecompletion_test.h \
+ test/clangdtests.h
SOURCES += \
test/clangautomationutils.cpp \
test/clangbatchfileprocessor.cpp \
test/clangcodecompletion_test.cpp \
+ test/clangdtests.cpp
RESOURCES += test/data/clangtestdata.qrc
OTHER_FILES += $$files(test/data/*)
diff --git a/src/plugins/clangcodemodel/clangcodemodel.qbs b/src/plugins/clangcodemodel/clangcodemodel.qbs
index dc9d9fb757..d16c11f732 100644
--- a/src/plugins/clangcodemodel/clangcodemodel.qbs
+++ b/src/plugins/clangcodemodel/clangcodemodel.qbs
@@ -8,9 +8,11 @@ QtcPlugin {
Depends { name: "Core" }
Depends { name: "CppTools" }
Depends { name: "ProjectExplorer" }
+ Depends { name: "QtSupport"; condition: qtc.testsEnabled }
Depends { name: "TextEditor" }
Depends { name: "Utils" }
Depends { name: "ClangSupport" }
+ Depends { name: "LanguageClient" }
Depends { name: "libclang"; required: false }
Depends { name: "clang_defines" }
@@ -54,6 +56,8 @@ QtcPlugin {
"clangconstants.h",
"clangcurrentdocumentfilter.cpp",
"clangcurrentdocumentfilter.h",
+ "clangdclient.cpp",
+ "clangdclient.h",
"clangdiagnosticfilter.cpp",
"clangdiagnosticfilter.h",
"clangdiagnosticmanager.cpp",
@@ -72,6 +76,8 @@ QtcPlugin {
"clangfollowsymbol.h",
"clangfunctionhintmodel.cpp",
"clangfunctionhintmodel.h",
+ "clanggloballocatorfilters.cpp",
+ "clanggloballocatorfilters.h",
"clanghighlightingresultreporter.cpp",
"clanghighlightingresultreporter.h",
"clanghoverhandler.cpp",
@@ -109,6 +115,8 @@ QtcPlugin {
"clangbatchfileprocessor.h",
"clangcodecompletion_test.cpp",
"clangcodecompletion_test.h",
+ "clangdtests.cpp",
+ "clangdtests.h",
"data/clangtestdata.qrc",
]
}
diff --git a/src/plugins/clangcodemodel/clangcodemodel_dependencies.pri b/src/plugins/clangcodemodel/clangcodemodel_dependencies.pri
index 9b44838b01..f32eaa4c4f 100644
--- a/src/plugins/clangcodemodel/clangcodemodel_dependencies.pri
+++ b/src/plugins/clangcodemodel/clangcodemodel_dependencies.pri
@@ -5,7 +5,10 @@ QTC_LIB_DEPENDS += \
QTC_PLUGIN_DEPENDS += \
coreplugin \
cpptools \
+ languageclient \
texteditor
QTC_TEST_DEPENDS += \
cppeditor \
qmakeprojectmanager
+
+equals(TEST, 1): QTC_PLUGIN_DEPENDS += qtsupport
diff --git a/src/plugins/clangcodemodel/clangcodemodelplugin.cpp b/src/plugins/clangcodemodel/clangcodemodelplugin.cpp
index 7393eb590d..126b3e9b5b 100644
--- a/src/plugins/clangcodemodel/clangcodemodelplugin.cpp
+++ b/src/plugins/clangcodemodel/clangcodemodelplugin.cpp
@@ -32,6 +32,7 @@
#ifdef WITH_TESTS
# include "test/clangbatchfileprocessor.h"
# include "test/clangcodecompletion_test.h"
+# include "test/clangdtests.h"
#endif
#include <coreplugin/actionmanager/actioncontainer.h>
@@ -77,7 +78,8 @@ void ClangCodeModelPlugin::generateCompilationDB()
QFuture<GenerateCompilationDbResult> task
= QtConcurrent::run(&Internal::generateCompilationDB,
- CppModelManager::instance()->projectInfo(target->project()));
+ CppModelManager::instance()->projectInfo(target->project()),
+ CompilationDbPurpose::Project);
Core::ProgressManager::addTask(task, tr("Generating Compilation DB"), "generate compilation db");
m_generatorWatcher.setFuture(task);
}
@@ -203,6 +205,7 @@ QVector<QObject *> ClangCodeModelPlugin::createTestObjects() const
{
return {
new Tests::ClangCodeCompletionTest,
+ new Tests::ClangdTests,
};
}
#endif
diff --git a/src/plugins/clangcodemodel/clangdclient.cpp b/src/plugins/clangcodemodel/clangdclient.cpp
new file mode 100644
index 0000000000..0f477fd811
--- /dev/null
+++ b/src/plugins/clangcodemodel/clangdclient.cpp
@@ -0,0 +1,678 @@
+/****************************************************************************
+**
+** Copyright (C) 2021 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of Qt Creator.
+**
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3 as published by the Free Software
+** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-3.0.html.
+**
+****************************************************************************/
+
+#include "clangdclient.h"
+
+#include <coreplugin/find/searchresultitem.h>
+#include <coreplugin/find/searchresultwindow.h>
+#include <cplusplus/FindUsages.h>
+#include <cpptools/cppcodemodelsettings.h>
+#include <cpptools/cppfindreferences.h>
+#include <cpptools/cpptoolsreuse.h>
+#include <languageclient/languageclientinterface.h>
+#include <projectexplorer/projecttree.h>
+#include <projectexplorer/session.h>
+#include <texteditor/basefilefind.h>
+#include <utils/algorithm.h>
+
+#include <QCheckBox>
+#include <QFile>
+#include <QHash>
+#include <QPointer>
+#include <QRegularExpression>
+
+using namespace CPlusPlus;
+using namespace Core;
+using namespace LanguageClient;
+using namespace LanguageServerProtocol;
+using namespace ProjectExplorer;
+
+namespace ClangCodeModel {
+namespace Internal {
+
+static Q_LOGGING_CATEGORY(clangdLog, "qtc.clangcodemodel.clangd", QtWarningMsg);
+static QString indexingToken() { return "backgroundIndexProgress"; }
+
+class AstParams : public JsonObject
+{
+public:
+ AstParams() {}
+ AstParams(const TextDocumentIdentifier &document, const Range &range);
+ using JsonObject::JsonObject;
+
+ // The open file to inspect.
+ TextDocumentIdentifier textDocument() const
+ { return typedValue<TextDocumentIdentifier>(textDocumentKey); }
+ void setTextDocument(const TextDocumentIdentifier &id) { insert(textDocumentKey, id); }
+
+ // The region of the source code whose AST is fetched. The highest-level node that entirely
+ // contains the range is returned.
+ Utils::optional<Range> range() const { return optionalValue<Range>(rangeKey); }
+ void setRange(const Range &range) { insert(rangeKey, range); }
+
+ bool isValid() const override { return contains(textDocumentKey); }
+};
+
+class AstNode : public JsonObject
+{
+public:
+ using JsonObject::JsonObject;
+
+ static constexpr char roleKey[] = "role";
+ static constexpr char arcanaKey[] = "arcana";
+
+ // The general kind of node, such as “expression”. Corresponds to clang’s base AST node type,
+ // such as Expr. The most common are “expression”, “statement”, “type” and “declaration”.
+ QString role() const { return typedValue<QString>(roleKey); }
+
+ // The specific kind of node, such as “BinaryOperator”. Corresponds to clang’s concrete
+ // node class, with Expr etc suffix dropped.
+ QString kind() const { return typedValue<QString>(kindKey); }
+
+ // Brief additional details, such as ‘||’. Information present here depends on the node kind.
+ Utils::optional<QString> detail() const { return optionalValue<QString>(detailKey); }
+
+ // One line dump of information, similar to that printed by clang -Xclang -ast-dump.
+ // Only available for certain types of nodes.
+ Utils::optional<QString> arcana() const { return optionalValue<QString>(arcanaKey); }
+
+ // The part of the code that produced this node. Missing for implicit nodes, nodes produced
+ // by macro expansion, etc.
+ Range range() const { return typedValue<Range>(rangeKey); }
+
+ // Descendants describing the internal structure. The tree of nodes is similar to that printed
+ // by clang -Xclang -ast-dump, or that traversed by clang::RecursiveASTVisitor.
+ Utils::optional<QList<AstNode>> children() const { return optionalArray<AstNode>(childrenKey); }
+
+ bool hasRange() const { return contains(rangeKey); }
+
+ bool arcanaContains(const QString &s) const
+ {
+ const Utils::optional<QString> arcanaString = arcana();
+ return arcanaString && arcanaString->contains(s);
+ }
+
+ bool detailIs(const QString &s) const
+ {
+ return detail() && detail().value() == s;
+ }
+
+ QString type() const
+ {
+ const Utils::optional<QString> arcanaString = arcana();
+ if (!arcanaString)
+ return {};
+ const int quote1Offset = arcanaString->indexOf('\'');
+ if (quote1Offset == -1)
+ return {};
+ const int quote2Offset = arcanaString->indexOf('\'', quote1Offset + 1);
+ if (quote2Offset == -1)
+ return {};
+ return arcanaString->mid(quote1Offset + 1, quote2Offset - quote1Offset - 1);
+ }
+
+ // Returns true <=> the type is "recursively const".
+ // E.g. returns true for "const int &", "const int *" and "const int * const *",
+ // and false for "int &" and "const int **".
+ // For non-pointer types such as "int", we check whether they are uses as lvalues
+ // or rvalues.
+ bool hasConstType() const
+ {
+ QString theType = type();
+ if (theType.endsWith("const"))
+ theType.chop(5);
+ const int ptrRefCount = theType.count('*') + theType.count('&');
+ const int constCount = theType.count("const");
+ if (ptrRefCount == 0)
+ return constCount > 0 || detailIs("LValueToRValue");
+ return ptrRefCount <= constCount;
+ }
+
+ bool childContainsRange(int index, const Range &range) const
+ {
+ const Utils::optional<QList<AstNode>> childList = children();
+ return childList && childList->size() > index
+ && childList->at(index).range().contains(range);
+ }
+
+ QString operatorString() const
+ {
+ if (kind() == "BinaryOperator")
+ return detail().value_or(QString());
+ QTC_ASSERT(kind() == "CXXOperatorCall", return {});
+ const Utils::optional<QString> arcanaString = arcana();
+ if (!arcanaString)
+ return {};
+ const int closingQuoteOffset = arcanaString->lastIndexOf('\'');
+ if (closingQuoteOffset <= 0)
+ return {};
+ const int openingQuoteOffset = arcanaString->lastIndexOf('\'', closingQuoteOffset - 1);
+ if (openingQuoteOffset == -1)
+ return {};
+ return arcanaString->mid(openingQuoteOffset + 1, closingQuoteOffset
+ - openingQuoteOffset - 1);
+ }
+
+ bool isValid() const override
+ {
+ return contains(roleKey) && contains(kindKey);
+ }
+};
+
+static QList<AstNode> getAstPath(const AstNode &root, const Range &range)
+{
+ QList<AstNode> path;
+ QList<AstNode> queue{root};
+ bool isRoot = true;
+ while (!queue.isEmpty()) {
+ AstNode curNode = queue.takeFirst();
+ if (!isRoot && !curNode.hasRange())
+ continue;
+ if (curNode.range() == range)
+ return path << curNode;
+ if (isRoot || curNode.range().contains(range)) {
+ path << curNode;
+ const auto children = curNode.children();
+ if (!children)
+ break;
+ queue = children.value();
+ }
+ isRoot = false;
+ }
+ return path;
+}
+
+static Usage::Type getUsageType(const QList<AstNode> &path)
+{
+ bool potentialWrite = false;
+ const bool symbolIsDataType = path.last().role() == "type" && path.last().kind() == "Record";
+ for (auto pathIt = path.rbegin(); pathIt != path.rend(); ++pathIt) {
+ if (pathIt->arcanaContains("non_odr_use_unevaluated"))
+ return Usage::Type::Other;
+ if (pathIt->kind() == "CXXDelete")
+ return Usage::Type::Write;
+ if (pathIt->kind() == "CXXNew")
+ return Usage::Type::Other;
+ if (pathIt->kind() == "Switch" || pathIt->kind() == "If")
+ return Usage::Type::Read;
+ if (pathIt->kind() == "Call" || pathIt->kind() == "CXXMemberCall")
+ return potentialWrite ? Usage::Type::WritableRef : Usage::Type::Read;
+ if ((pathIt->kind() == "DeclRef" || pathIt->kind() == "Member")
+ && pathIt->arcanaContains("lvalue")) {
+ potentialWrite = true;
+ }
+ if (pathIt->role() == "declaration") {
+ if (symbolIsDataType)
+ return Usage::Type::Other;
+ if (pathIt->arcanaContains("cinit")) {
+ if (pathIt == path.rbegin())
+ return Usage::Type::Initialization;
+ if (pathIt->childContainsRange(0, path.last().range()))
+ return Usage::Type::Initialization;
+ if (!pathIt->hasConstType())
+ return Usage::Type::WritableRef;
+ return Usage::Type::Read;
+ }
+ return Usage::Type::Declaration;
+ }
+ if (pathIt->kind() == "MemberInitializer")
+ return pathIt == path.rbegin() ? Usage::Type::Write : Usage::Type::Read;
+ if (pathIt->kind() == "UnaryOperator"
+ && (pathIt->detailIs("++") || pathIt->detailIs("--"))) {
+ return Usage::Type::Write;
+ }
+
+ // LLVM uses BinaryOperator only for built-in types; for classes, CXXOperatorCall
+ // is used. The latter has an additional node at index 0, so the left-hand side
+ // of an assignment is at index 1.
+ const bool isBinaryOp = pathIt->kind() == "BinaryOperator";
+ const bool isOpCall = pathIt->kind() == "CXXOperatorCall";
+ if (isBinaryOp || isOpCall) {
+ if (isOpCall && symbolIsDataType) // Constructor invocation.
+ return Usage::Type::Other;
+
+ const QString op = pathIt->operatorString();
+ if (op.endsWith("=") && op != "==") { // Assignment.
+ const int lhsIndex = isBinaryOp ? 0 : 1;
+ if (pathIt->childContainsRange(lhsIndex, path.last().range()))
+ return Usage::Type::Write;
+ return potentialWrite ? Usage::Type::WritableRef : Usage::Type::Read;
+ }
+ return Usage::Type::Read;
+ }
+
+ if (pathIt->kind() == "ImplicitCast") {
+ if (pathIt->detailIs("FunctionToPointerDecay"))
+ return Usage::Type::Other;
+ if (pathIt->hasConstType())
+ return Usage::Type::Read;
+ potentialWrite = true;
+ continue;
+ }
+ }
+
+ return Usage::Type::Other;
+}
+
+class AstRequest : public Request<AstNode, std::nullptr_t, AstParams>
+{
+public:
+ using Request::Request;
+ explicit AstRequest(const AstParams &params) : Request("textDocument/ast", params) {}
+};
+
+static BaseClientInterface *clientInterface(const Utils::FilePath &jsonDbDir)
+{
+ Utils::CommandLine cmd{CppTools::codeModelSettings()->clangdFilePath(),
+ {"--background-index", "--limit-results=0"}};
+ if (!jsonDbDir.isEmpty())
+ cmd.addArg("--compile-commands-dir=" + jsonDbDir.toString());
+ if (clangdLog().isDebugEnabled())
+ cmd.addArgs({"--log=verbose", "--pretty"});
+ const auto interface = new StdIOClientInterface;
+ interface->setCommandLine(cmd);
+ return interface;
+}
+
+class ReferencesFileData {
+public:
+ QList<QPair<Range, QString>> rangesAndLineText;
+ QString fileContent;
+ AstNode ast;
+};
+class ReplacementData {
+public:
+ QString oldSymbolName;
+ QString newSymbolName;
+ QSet<Utils::FilePath> fileRenameCandidates;
+};
+class ReferencesData {
+public:
+ QMap<DocumentUri, ReferencesFileData> fileData;
+ QList<MessageId> pendingAstRequests;
+ QPointer<SearchResult> search;
+ Utils::optional<ReplacementData> replacementData;
+ quint64 key;
+ bool canceled = false;
+};
+
+class ClangdClient::Private
+{
+public:
+ Private(ClangdClient *q) : q(q) {}
+
+ void handleFindUsagesResult(quint64 key, const QList<Location> &locations);
+ static void handleRenameRequest(const SearchResult *search,
+ const ReplacementData &replacementData,
+ const QString &newSymbolName,
+ const QList<Core::SearchResultItem> &checkedItems,
+ bool preserveCase);
+ void addSearchResultsForFile(ReferencesData &refData, const Utils::FilePath &file,
+ const ReferencesFileData &fileData);
+ void reportAllSearchResultsAndFinish(ReferencesData &data);
+ void finishSearch(const ReferencesData &refData, bool canceled);
+
+ ClangdClient * const q;
+ QHash<quint64, ReferencesData> runningFindUsages;
+ Utils::optional<QVersionNumber> versionNumber;
+ quint64 nextFindUsagesKey = 0;
+ bool isFullyIndexed = false;
+ bool isTesting = false;
+};
+
+ClangdClient::ClangdClient(Project *project, const Utils::FilePath &jsonDbDir)
+ : Client(clientInterface(jsonDbDir)), d(new Private(this))
+{
+ setName(tr("clangd"));
+ LanguageFilter langFilter;
+ langFilter.mimeTypes = QStringList{"text/x-chdr", "text/x-c++hdr", "text/x-c++src",
+ "text/x-objc++src", "text/x-objcsrc"};
+ setSupportedLanguage(langFilter);
+ LanguageServerProtocol::ClientCapabilities caps = Client::defaultClientCapabilities();
+ caps.clearExperimental();
+ caps.clearTextDocument();
+ setClientCapabilities(caps);
+ setLocatorsEnabled(false);
+ setProgressTitleForToken(indexingToken(), tr("Parsing C/C++ Files (clangd)"));
+ setCurrentProject(project);
+ connect(this, &Client::workDone, this, [this](const ProgressToken &token) {
+ const QString * const val = Utils::get_if<QString>(&token);
+ if (val && *val == indexingToken()) {
+ d->isFullyIndexed = true;
+ emit indexingFinished();
+ }
+ });
+
+ connect(this, &Client::initialized, this, [this] {
+ // If we get this signal while there are pending searches, it means that
+ // the client was re-initialized, i.e. clangd crashed.
+
+ // Report all search results found so far.
+ for (quint64 key : d->runningFindUsages.keys())
+ d->reportAllSearchResultsAndFinish(d->runningFindUsages[key]);
+ QTC_CHECK(d->runningFindUsages.isEmpty());
+ });
+
+ start();
+}
+
+ClangdClient::~ClangdClient()
+{
+ delete d;
+}
+
+bool ClangdClient::isFullyIndexed() const { return d->isFullyIndexed; }
+
+void ClangdClient::openExtraFile(const Utils::FilePath &filePath, const QString &content)
+{
+ QFile cxxFile(filePath.toString());
+ if (content.isEmpty() && !cxxFile.open(QIODevice::ReadOnly))
+ return;
+ TextDocumentItem item;
+ item.setLanguageId("cpp");
+ item.setUri(DocumentUri::fromFilePath(filePath));
+ item.setText(!content.isEmpty() ? content : QString::fromUtf8(cxxFile.readAll()));
+ item.setVersion(0);
+ sendContent(DidOpenTextDocumentNotification(DidOpenTextDocumentParams(item)));
+}
+
+void ClangdClient::closeExtraFile(const Utils::FilePath &filePath)
+{
+ sendContent(DidCloseTextDocumentNotification(DidCloseTextDocumentParams(
+ TextDocumentIdentifier{DocumentUri::fromFilePath(filePath)})));
+}
+
+void ClangdClient::findUsages(TextEditor::TextDocument *document, const QTextCursor &cursor,
+ const Utils::optional<QString> &replacement)
+{
+ QTextCursor termCursor(cursor);
+ termCursor.select(QTextCursor::WordUnderCursor);
+ const QString searchTerm = termCursor.selectedText(); // TODO: This will be wrong for e.g. operators. Use a Symbol info request to get the real symbol string.
+ if (searchTerm.isEmpty())
+ return;
+
+ ReferencesData refData;
+ refData.key = d->nextFindUsagesKey++;
+ if (replacement) {
+ ReplacementData replacementData;
+ replacementData.oldSymbolName = searchTerm;
+ replacementData.newSymbolName = *replacement;
+ if (replacementData.newSymbolName.isEmpty())
+ replacementData.newSymbolName = replacementData.oldSymbolName;
+ refData.replacementData = replacementData;
+ }
+ refData.search = SearchResultWindow::instance()->startNewSearch(
+ tr("C++ Usages:"),
+ {},
+ searchTerm,
+ replacement ? SearchResultWindow::SearchAndReplace : SearchResultWindow::SearchOnly,
+ SearchResultWindow::PreserveCaseDisabled,
+ "CppEditor");
+ refData.search->setFilter(new CppTools::CppSearchResultFilter);
+ if (refData.replacementData) {
+ refData.search->setTextToReplace(refData.replacementData->newSymbolName);
+ const auto renameFilesCheckBox = new QCheckBox;
+ renameFilesCheckBox->setVisible(false);
+ refData.search->setAdditionalReplaceWidget(renameFilesCheckBox);
+ const auto renameHandler =
+ [search = refData.search](const QString &newSymbolName,
+ const QList<SearchResultItem> &checkedItems,
+ bool preserveCase) {
+ const auto replacementData = search->userData().value<ReplacementData>();
+ Private::handleRenameRequest(search, replacementData, newSymbolName, checkedItems,
+ preserveCase);
+ };
+ connect(refData.search, &SearchResult::replaceButtonClicked, renameHandler);
+ }
+ connect(refData.search, &SearchResult::activated, [](const SearchResultItem& item) {
+ Core::EditorManager::openEditorAtSearchResult(item);
+ });
+ SearchResultWindow::instance()->popup(IOutputPane::ModeSwitch | IOutputPane::WithFocus);
+ d->runningFindUsages.insert(refData.key, refData);
+
+ const Utils::optional<MessageId> requestId = symbolSupport().findUsages(
+ document, cursor, [this, key = refData.key](const QList<Location> &locations) {
+ d->handleFindUsagesResult(key, locations);
+ });
+
+ if (!requestId) {
+ d->finishSearch(refData, false);
+ return;
+ }
+ connect(refData.search, &SearchResult::cancelled, this, [this, requestId, key = refData.key] {
+ const auto refData = d->runningFindUsages.find(key);
+ if (refData == d->runningFindUsages.end())
+ return;
+ cancelRequest(*requestId);
+ refData->canceled = true;
+ refData->search->disconnect(this);
+ d->finishSearch(*refData, true);
+ });
+}
+
+void ClangdClient::enableTesting() { d->isTesting = true; }
+
+QVersionNumber ClangdClient::versionNumber() const
+{
+ if (d->versionNumber)
+ return d->versionNumber.value();
+
+ const QRegularExpression versionPattern("^clangd version (\\d+)\\.(\\d+)\\.(\\d+).*$");
+ QTC_CHECK(versionPattern.isValid());
+ const QRegularExpressionMatch match = versionPattern.match(serverVersion());
+ if (match.isValid()) {
+ d->versionNumber.emplace({match.captured(1).toInt(), match.captured(2).toInt(),
+ match.captured(3).toInt()});
+ } else {
+ qCWarning(clangdLog) << "Failed to parse clangd server string" << serverVersion();
+ d->versionNumber.emplace({0});
+ }
+ return d->versionNumber.value();
+}
+
+void ClangdClient::Private::handleFindUsagesResult(quint64 key, const QList<Location> &locations)
+{
+ const auto refData = runningFindUsages.find(key);
+ if (refData == runningFindUsages.end())
+ return;
+ if (!refData->search || refData->canceled) {
+ finishSearch(*refData, true);
+ return;
+ }
+ refData->search->disconnect(q);
+
+ qCDebug(clangdLog) << "found" << locations.size() << "locations";
+ if (locations.isEmpty()) {
+ finishSearch(*refData, false);
+ return;
+ }
+
+ QObject::connect(refData->search, &SearchResult::cancelled, q, [this, key] {
+ const auto refData = runningFindUsages.find(key);
+ if (refData == runningFindUsages.end())
+ return;
+ refData->canceled = true;
+ refData->search->disconnect(q);
+ for (const MessageId &id : qAsConst(refData->pendingAstRequests))
+ q->cancelRequest(id);
+ refData->pendingAstRequests.clear();
+ finishSearch(*refData, true);
+ });
+
+ for (const Location &loc : locations) // TODO: Can contain duplicates. Rather fix in clang than work around it here.
+ refData->fileData[loc.uri()].rangesAndLineText << qMakePair(loc.range(), QString()); // TODO: Can we assume that locations for the same file are grouped?
+ for (auto it = refData->fileData.begin(); it != refData->fileData.end(); ++it) {
+ const QStringList lines = SymbolSupport::getFileContents(it.key().toFilePath());
+ it->fileContent = lines.join('\n');
+ for (auto &rangeWithText : it.value().rangesAndLineText) {
+ const int lineNo = rangeWithText.first.start().line();
+ if (lineNo >= 0 && lineNo < lines.size())
+ rangeWithText.second = lines.at(lineNo);
+ }
+ }
+
+ qCDebug(clangdLog) << "document count is" << refData->fileData.size();
+ if (refData->replacementData || q->versionNumber() < QVersionNumber(13)
+ || refData->fileData.size() > 15) { // TODO: If we need to keep this, make it configurable.
+ qCDebug(clangdLog) << "skipping AST retrieval";
+ reportAllSearchResultsAndFinish(*refData);
+ return;
+ }
+
+ for (auto it = refData->fileData.begin(); it != refData->fileData.end(); ++it) {
+ const bool extraOpen = !q->documentForFilePath(it.key().toFilePath());
+ if (extraOpen)
+ q->openExtraFile(it.key().toFilePath(), it->fileContent);
+ it->fileContent.clear();
+
+ AstParams params;
+ params.setTextDocument(TextDocumentIdentifier(it.key()));
+ AstRequest request(params);
+ request.setResponseCallback([this, key, loc = it.key(), request]
+ (AstRequest::Response response) {
+ qCDebug(clangdLog) << "AST response for" << loc.toFilePath();
+ const auto refData = runningFindUsages.find(key);
+ if (refData == runningFindUsages.end())
+ return;
+ if (!refData->search || refData->canceled)
+ return;
+ ReferencesFileData &data = refData->fileData[loc];
+ const auto result = response.result();
+ if (result)
+ data.ast = *result;
+ refData->pendingAstRequests.removeOne(request.id());
+ qCDebug(clangdLog) << refData->pendingAstRequests.size()
+ << "AST requests still pending";
+ addSearchResultsForFile(*refData, loc.toFilePath(), data);
+ refData->fileData.remove(loc);
+ if (refData->pendingAstRequests.isEmpty()) {
+ qDebug(clangdLog) << "retrieved all ASTs";
+ finishSearch(*refData, false);
+ }
+ });
+ qCDebug(clangdLog) << "requesting AST for" << it.key().toFilePath();
+ refData->pendingAstRequests << request.id();
+ q->sendContent(request);
+
+ if (extraOpen)
+ q->closeExtraFile(it.key().toFilePath());
+ }
+}
+
+void ClangdClient::Private::handleRenameRequest(const SearchResult *search,
+ const ReplacementData &replacementData,
+ const QString &newSymbolName,
+ const QList<SearchResultItem> &checkedItems,
+ bool preserveCase)
+{
+ const QStringList fileNames = TextEditor::BaseFileFind::replaceAll(newSymbolName, checkedItems,
+ preserveCase);
+ if (!fileNames.isEmpty())
+ SearchResultWindow::instance()->hide();
+
+ const auto renameFilesCheckBox = qobject_cast<QCheckBox *>(search->additionalReplaceWidget());
+ QTC_ASSERT(renameFilesCheckBox, return);
+ if (!renameFilesCheckBox->isChecked())
+ return;
+
+ QVector<Node *> fileNodes;
+ for (const Utils::FilePath &file : replacementData.fileRenameCandidates) {
+ Node * const node = ProjectTree::nodeForFile(file);
+ if (node)
+ fileNodes << node;
+ }
+ if (!fileNodes.isEmpty())
+ CppTools::renameFilesForSymbol(replacementData.oldSymbolName, newSymbolName, fileNodes);
+}
+
+void ClangdClient::Private::addSearchResultsForFile(ReferencesData &refData,
+ const Utils::FilePath &file,
+ const ReferencesFileData &fileData)
+{
+ QList<SearchResultItem> items;
+ qCDebug(clangdLog) << file << "has valid AST:" << fileData.ast.isValid();
+ for (const auto &rangeWithText : fileData.rangesAndLineText) {
+ const Range &range = rangeWithText.first;
+ const Usage::Type usageType = fileData.ast.isValid()
+ ? getUsageType(getAstPath(fileData.ast, qAsConst(range)))
+ : Usage::Type::Other;
+ SearchResultItem item;
+ item.setUserData(int(usageType));
+ item.setStyle(CppTools::colorStyleForUsageType(usageType));
+ item.setFilePath(file);
+ item.setMainRange(SymbolSupport::convertRange(range));
+ item.setUseTextEditorFont(true);
+ item.setLineText(rangeWithText.second);
+ if (refData.search->supportsReplace()) {
+ const bool fileInSession = SessionManager::projectForFile(file);
+ item.setSelectForReplacement(fileInSession);
+ if (fileInSession && file.toFileInfo().baseName().compare(
+ refData.replacementData->oldSymbolName,
+ Qt::CaseInsensitive) == 0) {
+ refData.replacementData->fileRenameCandidates << file; // TODO: We want to do this only for types. Use SymbolInformation once we have it.
+ }
+ }
+ items << item;
+ }
+ if (isTesting)
+ emit q->foundReferences(items);
+ else
+ refData.search->addResults(items, SearchResult::AddOrdered);
+}
+
+void ClangdClient::Private::reportAllSearchResultsAndFinish(ReferencesData &refData)
+{
+ for (auto it = refData.fileData.begin(); it != refData.fileData.end(); ++it)
+ addSearchResultsForFile(refData, it.key().toFilePath(), it.value());
+ finishSearch(refData, refData.canceled);
+}
+
+void ClangdClient::Private::finishSearch(const ReferencesData &refData, bool canceled)
+{
+ if (isTesting) {
+ emit q->findUsagesDone();
+ } else if (refData.search) {
+ refData.search->finishSearch(canceled);
+ refData.search->disconnect(q);
+ if (refData.replacementData) {
+ const auto renameCheckBox = qobject_cast<QCheckBox *>(
+ refData.search->additionalReplaceWidget());
+ QTC_CHECK(renameCheckBox);
+ const QSet<Utils::FilePath> files = refData.replacementData->fileRenameCandidates;
+ renameCheckBox->setText(tr("Re&name %n files", nullptr, files.size()));
+ const QStringList filesForUser = Utils::transform<QStringList>(files,
+ [](const Utils::FilePath &fp) { return fp.toUserOutput(); });
+ renameCheckBox->setToolTip(tr("Files:\n%1").arg(filesForUser.join('\n')));
+ renameCheckBox->setVisible(true);
+ refData.search->setUserData(QVariant::fromValue(*refData.replacementData));
+ }
+ }
+ runningFindUsages.remove(refData.key);
+}
+
+} // namespace Internal
+} // namespace ClangCodeModel
+
+Q_DECLARE_METATYPE(ClangCodeModel::Internal::ReplacementData)
diff --git a/src/plugins/qmlprofiler/tests/qmlprofilerconfigwidget_test.h b/src/plugins/clangcodemodel/clangdclient.h
index d669d1c899..c2f61c1ba9 100644
--- a/src/plugins/qmlprofiler/tests/qmlprofilerconfigwidget_test.h
+++ b/src/plugins/clangcodemodel/clangdclient.h
@@ -1,6 +1,6 @@
/****************************************************************************
**
-** Copyright (C) 2016 The Qt Company Ltd.
+** Copyright (C) 2021 The Qt Company Ltd.
** Contact: https://www.qt.io/licensing/
**
** This file is part of Qt Creator.
@@ -22,34 +22,48 @@
** be met: https://www.gnu.org/licenses/gpl-3.0.html.
**
****************************************************************************/
+
#pragma once
-#include <qmlprofiler/qmlprofilerconfigwidget.h>
-#include <QObject>
-#include <QCheckBox>
-#include <QSpinBox>
+#include <languageclient/client.h>
+#include <utils/optional.h>
+
+#include <QVersionNumber>
-namespace QmlProfiler {
+namespace Core { class SearchResultItem; }
+namespace ProjectExplorer { class Project; }
+namespace TextEditor { class TextDocument; }
+
+namespace ClangCodeModel {
namespace Internal {
-class QmlProfilerConfigWidgetTest : public QObject
+class ClangdClient : public LanguageClient::Client
{
Q_OBJECT
public:
- explicit QmlProfilerConfigWidgetTest(QObject *parent = nullptr);
+ ClangdClient(ProjectExplorer::Project *project, const Utils::FilePath &jsonDbDir);
+ ~ClangdClient() override;
-private slots:
- void testUpdateFromSettings();
- void testChangeWidget();
+ bool isFullyIndexed() const;
+ QVersionNumber versionNumber() const;
-private:
- QmlProfilerSettings settings;
- QmlProfilerConfigWidget widget;
+ void openExtraFile(const Utils::FilePath &filePath, const QString &content = {});
+ void closeExtraFile(const Utils::FilePath &filePath);
- QCheckBox *flushEnabled;
- QSpinBox *flushInterval;
- QCheckBox *aggregateTraces;
+ void findUsages(TextEditor::TextDocument *document, const QTextCursor &cursor,
+ const Utils::optional<QString> &replacement);
+
+ void enableTesting();
+
+signals:
+ void indexingFinished();
+ void foundReferences(const QList<Core::SearchResultItem> &items);
+ void findUsagesDone();
+
+private:
+ class Private;
+ Private * const d;
};
} // namespace Internal
-} // namespace QmlProfiler
+} // namespace ClangCodeModel
diff --git a/src/plugins/clangcodemodel/clangeditordocumentprocessor.cpp b/src/plugins/clangcodemodel/clangeditordocumentprocessor.cpp
index 7fa8b9302e..58eae03422 100644
--- a/src/plugins/clangcodemodel/clangeditordocumentprocessor.cpp
+++ b/src/plugins/clangcodemodel/clangeditordocumentprocessor.cpp
@@ -31,7 +31,6 @@
#include "clangfixitoperationsextractor.h"
#include "clangmodelmanagersupport.h"
#include "clanghighlightingresultreporter.h"
-#include "clangprojectsettings.h"
#include "clangutils.h"
#include <diagnosticcontainer.h>
@@ -66,12 +65,6 @@
namespace ClangCodeModel {
namespace Internal {
-static ClangProjectSettings &getProjectSettings(ProjectExplorer::Project *project)
-{
- QTC_CHECK(project);
- return ClangModelManagerSupport::instance()->projectSettings(project);
-}
-
ClangEditorDocumentProcessor::ClangEditorDocumentProcessor(
BackendCommunicator &communicator,
TextEditor::TextDocument *document)
@@ -98,15 +91,14 @@ ClangEditorDocumentProcessor::ClangEditorDocumentProcessor(
this, &ClangEditorDocumentProcessor::cppDocumentUpdated);
connect(&m_builtinProcessor, &CppTools::BuiltinEditorDocumentProcessor::semanticInfoUpdated,
this, &ClangEditorDocumentProcessor::semanticInfoUpdated);
+
+ m_parserSynchronizer.setCancelOnWait(true);
}
ClangEditorDocumentProcessor::~ClangEditorDocumentProcessor()
{
m_updateBackendDocumentTimer.stop();
- m_parserWatcher.cancel();
- m_parserWatcher.waitForFinished();
-
if (m_projectPart)
closeBackendDocument();
}
@@ -127,6 +119,7 @@ void ClangEditorDocumentProcessor::runImpl(
this, &ClangEditorDocumentProcessor::onParserFinished);
const QFuture<void> future = ::Utils::runAsync(&runParser, parser(), updateParams);
m_parserWatcher.setFuture(future);
+ m_parserSynchronizer.addFuture(future);
// Run builtin processor
m_builtinProcessor.runImpl(updateParams);
@@ -439,123 +432,6 @@ void ClangEditorDocumentProcessor::onParserFinished()
updateBackendProjectPartAndDocument();
}
-namespace {
-// TODO: Can we marry this with CompilerOptionsBuilder?
-class FileOptionsBuilder
-{
-public:
- FileOptionsBuilder(const QString &filePath, CppTools::ProjectPart &projectPart)
- : m_filePath(filePath)
- , m_projectPart(projectPart)
- , m_builder(projectPart)
- {
- // Determine the driver mode from toolchain and flags.
- m_builder.evaluateCompilerFlags();
- m_isClMode = m_builder.isClStyle();
-
- addLanguageOptions();
- addGlobalDiagnosticOptions(); // Before addDiagnosticOptions() so users still can overwrite.
- addDiagnosticOptions();
- addGlobalOptions();
- addPrecompiledHeaderOptions();
- }
-
- const QStringList &options() const { return m_options; }
- const ::Utils::Id &diagnosticConfigId() const { return m_diagnosticConfigId; }
- CppTools::UseBuildSystemWarnings useBuildSystemWarnings() const
- {
- return m_useBuildSystemWarnings;
- }
-
-private:
- void addLanguageOptions()
- {
- // Determine file kind with respect to ambiguous headers.
- CppTools::ProjectFile::Kind fileKind = CppTools::ProjectFile::classify(m_filePath);
- if (fileKind == CppTools::ProjectFile::AmbiguousHeader) {
- fileKind = m_projectPart.languageVersion <= ::Utils::LanguageVersion::LatestC
- ? CppTools::ProjectFile::CHeader
- : CppTools::ProjectFile::CXXHeader;
- }
-
- m_builder.reset();
- m_builder.updateFileLanguage(fileKind);
-
- m_options.append(m_builder.options());
- }
-
- void addDiagnosticOptions()
- {
- if (m_projectPart.project) {
- ClangProjectSettings &projectSettings = getProjectSettings(m_projectPart.project);
- if (!projectSettings.useGlobalConfig()) {
- const ::Utils::Id warningConfigId = projectSettings.warningConfigId();
- const CppTools::ClangDiagnosticConfigsModel configsModel
- = CppTools::diagnosticConfigsModel();
- if (configsModel.hasConfigWithId(warningConfigId)) {
- addDiagnosticOptionsForConfig(configsModel.configWithId(warningConfigId));
- return;
- }
- }
- }
-
- addDiagnosticOptionsForConfig(CppTools::codeModelSettings()->clangDiagnosticConfig());
- }
-
- void addDiagnosticOptionsForConfig(const CppTools::ClangDiagnosticConfig &diagnosticConfig)
- {
- m_diagnosticConfigId = diagnosticConfig.id();
- m_useBuildSystemWarnings = diagnosticConfig.useBuildSystemWarnings()
- ? CppTools::UseBuildSystemWarnings::Yes
- : CppTools::UseBuildSystemWarnings::No;
-
- const QStringList options = m_isClMode
- ? CppTools::clangArgsForCl(diagnosticConfig.clangOptions())
- : diagnosticConfig.clangOptions();
- m_options.append(options);
- }
-
- void addGlobalDiagnosticOptions()
- {
- m_options += CppTools::ClangDiagnosticConfigsModel::globalDiagnosticOptions();
- }
-
- void addGlobalOptions()
- {
- if (!m_projectPart.project)
- m_options.append(ClangProjectSettings::globalCommandLineOptions());
- else
- m_options.append(getProjectSettings(m_projectPart.project).commandLineOptions());
- }
-
- void addPrecompiledHeaderOptions()
- {
- using namespace CppTools;
-
- if (getPchUsage() == UsePrecompiledHeaders::No)
- return;
-
- if (m_projectPart.precompiledHeaders.contains(m_filePath))
- return;
-
- m_builder.reset();
- m_builder.addPrecompiledHeaderOptions(UsePrecompiledHeaders::Yes);
-
- m_options.append(m_builder.options());
- }
-
-private:
- const QString &m_filePath;
- const CppTools::ProjectPart &m_projectPart;
-
- ::Utils::Id m_diagnosticConfigId;
- CppTools::UseBuildSystemWarnings m_useBuildSystemWarnings = CppTools::UseBuildSystemWarnings::No;
- CppTools::CompilerOptionsBuilder m_builder;
- bool m_isClMode = false;
- QStringList m_options;
-};
-} // namespace
-
void ClangEditorDocumentProcessor::updateBackendDocument(CppTools::ProjectPart &projectPart)
{
// On registration we send the document content immediately as an unsaved
@@ -572,17 +448,11 @@ void ClangEditorDocumentProcessor::updateBackendDocument(CppTools::ProjectPart &
return;
}
- const FileOptionsBuilder fileOptions(filePath(), projectPart);
- m_diagnosticConfigId = fileOptions.diagnosticConfigId();
-
- const QStringList projectPartOptions = createClangOptions(
- projectPart, fileOptions.useBuildSystemWarnings(),
- CppTools::ProjectFile::Unsupported); // No language option as FileOptionsBuilder adds it.
-
- const QStringList compilationArguments = projectPartOptions + fileOptions.options();
+ const auto clangOptions = createClangOptions(projectPart, filePath());
+ m_diagnosticConfigId = clangOptions.first;
m_communicator.documentsOpened(
- {fileContainerWithOptionsAndDocumentContent(compilationArguments, projectPart.headerPaths)});
+ {fileContainerWithOptionsAndDocumentContent(clangOptions.second, projectPart.headerPaths)});
setLastSentDocumentRevision(filePath(), revision());
}
diff --git a/src/plugins/clangcodemodel/clangeditordocumentprocessor.h b/src/plugins/clangcodemodel/clangeditordocumentprocessor.h
index 91d98601aa..90890c4710 100644
--- a/src/plugins/clangcodemodel/clangeditordocumentprocessor.h
+++ b/src/plugins/clangcodemodel/clangeditordocumentprocessor.h
@@ -31,6 +31,7 @@
#include <cpptools/builtineditordocumentprocessor.h>
#include <cpptools/semantichighlighter.h>
+#include <utils/futuresynchronizer.h>
#include <utils/id.h>
#include <QFutureWatcher>
@@ -145,6 +146,7 @@ private:
QVector<ClangBackEnd::TokenInfoContainer> m_tokenInfos;
CppTools::SemanticHighlighter m_semanticHighlighter;
CppTools::BuiltinEditorDocumentProcessor m_builtinProcessor;
+ Utils::FutureSynchronizer m_parserSynchronizer;
};
} // namespace Internal
diff --git a/src/plugins/clangcodemodel/clangfollowsymbol.cpp b/src/plugins/clangcodemodel/clangfollowsymbol.cpp
index a6d856b201..07c4b84cb4 100644
--- a/src/plugins/clangcodemodel/clangfollowsymbol.cpp
+++ b/src/plugins/clangcodemodel/clangfollowsymbol.cpp
@@ -23,9 +23,12 @@
**
****************************************************************************/
-#include "clangeditordocumentprocessor.h"
#include "clangfollowsymbol.h"
+#include "clangdclient.h"
+#include "clangeditordocumentprocessor.h"
+#include "clangmodelmanagersupport.h"
+
#include <coreplugin/editormanager/editormanager.h>
#include <cpptools/cppmodelmanager.h>
#include <cpptools/cppfollowsymbolundercursor.h>
@@ -114,7 +117,7 @@ static Utils::Link linkAtCursor(const QTextCursor &cursor,
if (mark.extraInfo.includeDirectivePath && !isValidIncludePathToken(mark))
return Link();
- Link token(filePath, mark.line, mark.column);
+ Link token(Utils::FilePath::fromString(filePath), mark.line, mark.column);
token.linkTextStart = getMarkPos(cursor, mark);
token.linkTextEnd = token.linkTextStart + mark.length;
@@ -152,8 +155,9 @@ static ::Utils::ProcessLinkCallback extendedCallback(::Utils::ProcessLinkCallbac
// If globalFollowSymbol finds nothing follow to the declaration.
return [original_callback = std::move(callback), result](const ::Utils::Link &link) {
if (link.linkTextStart < 0 && result.isResultOnlyForFallBack) {
- return original_callback(::Utils::Link(result.fileName, result.startLine,
- result.startColumn - 1));
+ return original_callback(::Utils::Link(::Utils::FilePath::fromString(result.fileName),
+ result.startLine,
+ result.startColumn - 1));
}
return original_callback(link);
};
@@ -173,6 +177,16 @@ void ClangFollowSymbol::findLink(const CppTools::CursorInEditor &data,
CppTools::SymbolFinder *symbolFinder,
bool inNextSplit)
{
+ ClangdClient * const client
+ = ClangModelManagerSupport::instance()->clientForFile(data.filePath());
+ if (client && client->isFullyIndexed()) {
+ QTC_ASSERT(client->documentOpen(data.textDocument()),
+ client->openDocument(data.textDocument()));
+ client->symbolSupport().findLinkAt(data.textDocument(), data.cursor(),
+ std::move(processLinkCallback), resolveTarget);
+ return;
+ }
+
int line = 0;
int column = 0;
QTextCursor cursor = Utils::Text::wordStartCursor(data.cursor());
@@ -230,7 +244,9 @@ void ClangFollowSymbol::findLink(const CppTools::CursorInEditor &data,
symbolFinder,
inNextSplit);
} else {
- callback(Link(result.fileName, result.startLine, result.startColumn - 1));
+ callback(Link(Utils::FilePath::fromString(result.fileName),
+ result.startLine,
+ result.startColumn - 1));
}
});
diff --git a/src/plugins/clangcodemodel/clanggloballocatorfilters.cpp b/src/plugins/clangcodemodel/clanggloballocatorfilters.cpp
new file mode 100644
index 0000000000..cee2f8718b
--- /dev/null
+++ b/src/plugins/clangcodemodel/clanggloballocatorfilters.cpp
@@ -0,0 +1,216 @@
+/****************************************************************************
+**
+** Copyright (C) 2021 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of Qt Creator.
+**
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3 as published by the Free Software
+** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-3.0.html.
+**
+****************************************************************************/
+
+#include "clanggloballocatorfilters.h"
+
+#include "clangdclient.h"
+#include "clangmodelmanagersupport.h"
+
+#include <cpptools/cppclassesfilter.h>
+#include <cpptools/cppfunctionsfilter.h>
+#include <cpptools/cppmodelmanager.h>
+#include <cpptools/cpptoolsconstants.h>
+#include <cpptools/indexitem.h>
+#include <languageclient/locatorfilter.h>
+#include <projectexplorer/session.h>
+#include <utils/link.h>
+
+#include <set>
+#include <tuple>
+
+namespace ClangCodeModel {
+namespace Internal {
+
+class CppLocatorFilter : public CppTools::CppLocatorFilter
+{
+public:
+ CppLocatorFilter()
+ : CppTools::CppLocatorFilter(CppTools::CppModelManager::instance()->locatorData())
+ {
+ setId({});
+ setDisplayName({});
+ setDefaultShortcutString({});
+ setEnabled(false);
+ }
+};
+
+class LspWorkspaceFilter : public LanguageClient::WorkspaceLocatorFilter
+{
+public:
+ LspWorkspaceFilter()
+ {
+ setId({});
+ setDisplayName({});
+ setDefaultShortcutString({});
+ setEnabled(false);
+ }
+};
+
+
+class CppClassesFilter : public CppTools::CppClassesFilter
+{
+public:
+ CppClassesFilter()
+ : CppTools::CppClassesFilter(CppTools::CppModelManager::instance()->locatorData())
+ {
+ setId({});
+ setDisplayName({});
+ setDefaultShortcutString({});
+ setEnabled(false);
+ }
+};
+
+class LspClassesFilter : public LanguageClient::WorkspaceClassLocatorFilter
+{
+public:
+ LspClassesFilter() {
+ setId({});
+ setDisplayName({});
+ setDefaultShortcutString({});
+ setEnabled(false);
+ }
+};
+
+class CppFunctionsFilter : public CppTools::CppFunctionsFilter
+{
+public:
+ CppFunctionsFilter()
+ : CppTools::CppFunctionsFilter(CppTools::CppModelManager::instance()->locatorData())
+ {
+ setId({});
+ setDisplayName({});
+ setDefaultShortcutString({});
+ setEnabled(false);
+ }
+};
+
+class LspFunctionsFilter : public LanguageClient::WorkspaceMethodLocatorFilter
+{
+public:
+ LspFunctionsFilter()
+ {
+ setId({});
+ setDisplayName({});
+ setDefaultShortcutString({});
+ setEnabled(false);
+ }
+};
+
+
+ClangGlobalSymbolFilter::ClangGlobalSymbolFilter()
+ : ClangGlobalSymbolFilter(new CppLocatorFilter, new LspWorkspaceFilter)
+{
+}
+
+ClangGlobalSymbolFilter::ClangGlobalSymbolFilter(ILocatorFilter *cppFilter,
+ ILocatorFilter *lspFilter)
+ : m_cppFilter(cppFilter), m_lspFilter(lspFilter)
+{
+ setId(CppTools::Constants::LOCATOR_FILTER_ID);
+ setDisplayName(CppTools::Constants::LOCATOR_FILTER_DISPLAY_NAME);
+ setDefaultShortcutString(":");
+ setDefaultIncludedByDefault(false);
+}
+
+ClangGlobalSymbolFilter::~ClangGlobalSymbolFilter()
+{
+ delete m_cppFilter;
+ delete m_lspFilter;
+}
+
+void ClangGlobalSymbolFilter::prepareSearch(const QString &entry)
+{
+ m_cppFilter->prepareSearch(entry);
+ QVector<LanguageClient::Client *> clients;
+ for (ProjectExplorer::Project * const project : ProjectExplorer::SessionManager::projects()) {
+ LanguageClient::Client * const client
+ = ClangModelManagerSupport::instance()->clientForProject(project);
+ if (client)
+ clients << client;
+ }
+ if (!clients.isEmpty()) {
+ static_cast<LanguageClient::WorkspaceLocatorFilter *>(m_lspFilter)
+ ->prepareSearch(entry, clients);
+ }
+}
+
+QList<Core::LocatorFilterEntry> ClangGlobalSymbolFilter::matchesFor(
+ QFutureInterface<Core::LocatorFilterEntry> &future, const QString &entry)
+{
+ QList<Core::LocatorFilterEntry> matches = m_cppFilter->matchesFor(future, entry);
+ const QList<Core::LocatorFilterEntry> lspMatches = m_lspFilter->matchesFor(future, entry);
+ if (!lspMatches.isEmpty()) {
+ std::set<std::tuple<Utils::FilePath, int, int>> locations;
+ for (const auto &entry : qAsConst(matches)) {
+ const CppTools::IndexItem::Ptr item
+ = qvariant_cast<CppTools::IndexItem::Ptr>(entry.internalData);
+ locations.insert(std::make_tuple(Utils::FilePath::fromString(item->fileName()),
+ item->line(),
+ item->column()));
+ }
+ for (const auto &entry : lspMatches) {
+ if (!entry.internalData.canConvert<Utils::Link>())
+ continue;
+ const auto link = qvariant_cast<Utils::Link>(entry.internalData);
+ if (locations.find(std::make_tuple(link.targetFilePath, link.targetLine,
+ link.targetColumn)) == locations.cend()) {
+ matches << entry; // TODO: Insert sorted?
+ }
+ }
+ }
+
+ return matches;
+}
+
+void ClangGlobalSymbolFilter::accept(Core::LocatorFilterEntry selection, QString *newText,
+ int *selectionStart, int *selectionLength) const
+{
+ if (qvariant_cast<CppTools::IndexItem::Ptr>(selection.internalData))
+ m_cppFilter->accept(selection, newText, selectionStart, selectionLength);
+ else
+ m_lspFilter->accept(selection, newText, selectionStart, selectionLength);
+}
+
+
+ClangClassesFilter::ClangClassesFilter()
+ : ClangGlobalSymbolFilter(new CppClassesFilter, new LspClassesFilter)
+{
+ setId(CppTools::Constants::CLASSES_FILTER_ID);
+ setDisplayName(CppTools::Constants::CLASSES_FILTER_DISPLAY_NAME);
+ setDefaultShortcutString("c");
+ setDefaultIncludedByDefault(false);
+}
+
+ClangFunctionsFilter::ClangFunctionsFilter()
+ : ClangGlobalSymbolFilter(new CppFunctionsFilter, new LspFunctionsFilter)
+{
+ setId(CppTools::Constants::FUNCTIONS_FILTER_ID);
+ setDisplayName(CppTools::Constants::FUNCTIONS_FILTER_DISPLAY_NAME);
+ setDefaultShortcutString("m");
+ setDefaultIncludedByDefault(false);
+}
+
+} // namespace Internal
+} // namespace ClangCodeModel
diff --git a/src/plugins/vcsbase/commonsettingspage.h b/src/plugins/clangcodemodel/clanggloballocatorfilters.h
index 8e4ca319a0..e01ac4b356 100644
--- a/src/plugins/vcsbase/commonsettingspage.h
+++ b/src/plugins/clangcodemodel/clanggloballocatorfilters.h
@@ -1,6 +1,6 @@
/****************************************************************************
**
-** Copyright (C) 2016 The Qt Company Ltd.
+** Copyright (C) 2021 The Qt Company Ltd.
** Contact: https://www.qt.io/licensing/
**
** This file is part of Qt Creator.
@@ -25,54 +25,40 @@
#pragma once
-#include "commonvcssettings.h"
+#include <coreplugin/locator/ilocatorfilter.h>
-#include <coreplugin/dialogs/ioptionspage.h>
-
-#include <QPointer>
-
-namespace VcsBase {
+namespace ClangCodeModel {
namespace Internal {
-namespace Ui { class CommonSettingsPage; }
-
-class CommonSettingsWidget : public QWidget
+class ClangGlobalSymbolFilter : public Core::ILocatorFilter
{
- Q_OBJECT
-
public:
- explicit CommonSettingsWidget(QWidget *parent = nullptr);
- ~CommonSettingsWidget() override;
-
- CommonVcsSettings settings() const;
- void setSettings(const CommonVcsSettings &s);
+ ClangGlobalSymbolFilter();
+ ClangGlobalSymbolFilter(Core::ILocatorFilter *cppFilter, Core::ILocatorFilter *lspFilter);
+ ~ClangGlobalSymbolFilter() override;
private:
- void updatePath();
-
- Ui::CommonSettingsPage *m_ui;
+ void prepareSearch(const QString &entry) override;
+ QList<Core::LocatorFilterEntry> matchesFor(QFutureInterface<Core::LocatorFilterEntry> &future,
+ const QString &entry) override;
+ void accept(Core::LocatorFilterEntry selection, QString *newText,
+ int *selectionStart, int *selectionLength) const override;
+
+ Core::ILocatorFilter * const m_cppFilter;
+ Core::ILocatorFilter * const m_lspFilter;
};
-class CommonOptionsPage final : public Core::IOptionsPage
+class ClangClassesFilter : public ClangGlobalSymbolFilter
{
- Q_OBJECT
-
public:
- explicit CommonOptionsPage();
-
- QWidget *widget() override;
- void apply() override;
- void finish() override;
-
- CommonVcsSettings settings() const { return m_settings; }
-
-signals:
- void settingsChanged(const VcsBase::Internal::CommonVcsSettings &s);
+ ClangClassesFilter();
+};
-private:
- QPointer<CommonSettingsWidget> m_widget;
- CommonVcsSettings m_settings;
+class ClangFunctionsFilter : public ClangGlobalSymbolFilter
+{
+public:
+ ClangFunctionsFilter();
};
} // namespace Internal
-} // namespace VcsBase
+} // namespace ClangCodeModel
diff --git a/src/plugins/clangcodemodel/clanghighlightingresultreporter.cpp b/src/plugins/clangcodemodel/clanghighlightingresultreporter.cpp
index 451a6465d0..d5e16c6f49 100644
--- a/src/plugins/clangcodemodel/clanghighlightingresultreporter.cpp
+++ b/src/plugins/clangcodemodel/clanghighlightingresultreporter.cpp
@@ -50,6 +50,8 @@ TextEditor::TextStyle toTextStyle(ClangBackEnd::HighlightingType type)
return TextEditor::C_PRIMITIVE_TYPE;
case HighlightingType::LocalVariable:
return TextEditor::C_LOCAL;
+ case HighlightingType::Parameter:
+ return TextEditor::C_PARAMETER;
case HighlightingType::Field:
case HighlightingType::QtProperty:
return TextEditor::C_FIELD;
diff --git a/src/plugins/clangcodemodel/clangmodelmanagersupport.cpp b/src/plugins/clangcodemodel/clangmodelmanagersupport.cpp
index 8b22f6f145..d2fb17d64d 100644
--- a/src/plugins/clangcodemodel/clangmodelmanagersupport.cpp
+++ b/src/plugins/clangcodemodel/clangmodelmanagersupport.cpp
@@ -26,6 +26,7 @@
#include "clangmodelmanagersupport.h"
#include "clangconstants.h"
+#include "clangdclient.h"
#include "clangeditordocumentprocessor.h"
#include "clangutils.h"
#include "clangfollowsymbol.h"
@@ -33,9 +34,13 @@
#include "clangprojectsettings.h"
#include "clangrefactoringengine.h"
#include "clangcurrentdocumentfilter.h"
+#include "clanggloballocatorfilters.h"
#include "clangoverviewmodel.h"
+#include <coreplugin/editormanager/documentmodel.h>
#include <coreplugin/editormanager/editormanager.h>
+#include <coreplugin/icore.h>
+#include <coreplugin/messagemanager.h>
#include <cpptools/cppcodemodelsettings.h>
#include <cpptools/cppfollowsymbolundercursor.h>
@@ -44,14 +49,20 @@
#include <cpptools/editordocumenthandle.h>
#include <cpptools/projectinfo.h>
+#include <languageclient/languageclientmanager.h>
+
#include <texteditor/quickfix.h>
+#include <projectexplorer/buildconfiguration.h>
#include <projectexplorer/project.h>
+#include <projectexplorer/projectnodes.h>
#include <projectexplorer/session.h>
+#include <projectexplorer/target.h>
#include <clangsupport/filecontainer.h>
#include <utils/algorithm.h>
#include <utils/qtcassert.h>
+#include <utils/runextensions.h>
#include <QApplication>
#include <QMenu>
@@ -60,6 +71,7 @@
using namespace ClangCodeModel;
using namespace ClangCodeModel::Internal;
+using namespace LanguageClient;
static ClangModelManagerSupport *m_instance = nullptr;
@@ -79,6 +91,9 @@ ClangModelManagerSupport::ClangModelManagerSupport()
CppTools::CppModelManager::instance()->setCurrentDocumentFilter(
std::make_unique<ClangCurrentDocumentFilter>());
+ cppModelManager()->setLocatorFilter(std::make_unique<ClangGlobalSymbolFilter>());
+ cppModelManager()->setClassesFilter(std::make_unique<ClangClassesFilter>());
+ cppModelManager()->setFunctionsFilter(std::make_unique<ClangFunctionsFilter>());
Core::EditorManager *editorManager = Core::EditorManager::instance();
connect(editorManager, &Core::EditorManager::editorOpened,
@@ -104,14 +119,21 @@ ClangModelManagerSupport::ClangModelManagerSupport()
connect(sessionManager, &ProjectExplorer::SessionManager::aboutToRemoveProject,
this, &ClangModelManagerSupport::onAboutToRemoveProject);
+ CppTools::CppCodeModelSettings::setDefaultClangdPath(Utils::FilePath::fromString(
+ Core::ICore::clangdExecutable(CLANG_BINDIR)));
CppTools::CppCodeModelSettings *settings = CppTools::codeModelSettings();
connect(settings, &CppTools::CppCodeModelSettings::clangDiagnosticConfigsInvalidated,
this, &ClangModelManagerSupport::onDiagnosticConfigsInvalidated);
+
+ // TODO: Enable this once we do document-level stuff with clangd (highlighting etc)
+ // createClient(nullptr, {});
+ m_generatorSynchronizer.setCancelOnWait(true);
}
ClangModelManagerSupport::~ClangModelManagerSupport()
{
QTC_CHECK(m_projectSettings.isEmpty());
+ m_generatorSynchronizer.waitForFinished();
m_instance = nullptr;
}
@@ -220,6 +242,130 @@ void ClangModelManagerSupport::connectToWidgetsMarkContextMenuRequested(QWidget
}
}
+void ClangModelManagerSupport::updateLanguageClient(ProjectExplorer::Project *project,
+ const CppTools::ProjectInfo &projectInfo)
+{
+ if (!CppTools::codeModelSettings()->useClangd())
+ return;
+ const auto getJsonDbDir = [project] {
+ if (const ProjectExplorer::Target * const target = project->activeTarget()) {
+ if (const ProjectExplorer::BuildConfiguration * const bc
+ = target->activeBuildConfiguration()) {
+ return bc->buildDirectory();
+ }
+ }
+ return Utils::FilePath();
+ };
+
+ const Utils::FilePath jsonDbDir = getJsonDbDir();
+ if (jsonDbDir.isEmpty())
+ return;
+ const auto generatorWatcher = new QFutureWatcher<GenerateCompilationDbResult>;
+ connect(generatorWatcher, &QFutureWatcher<GenerateCompilationDbResult>::finished,
+ [this, project, projectInfo, getJsonDbDir, jsonDbDir, generatorWatcher] {
+ generatorWatcher->deleteLater();
+ if (!CppTools::codeModelSettings()->useClangd())
+ return;
+ if (!ProjectExplorer::SessionManager::hasProject(project))
+ return;
+ if (cppModelManager()->projectInfo(project) != projectInfo)
+ return;
+ if (getJsonDbDir() != jsonDbDir)
+ return;
+ const GenerateCompilationDbResult result = generatorWatcher->result();
+ if (!result.error.isEmpty()) {
+ Core::MessageManager::writeDisrupting(
+ tr("Cannot use clangd: Failed to generate compilation database:\n%1")
+ .arg(result.error));
+ return;
+ }
+ if (Client * const oldClient = clientForProject(project))
+ LanguageClientManager::shutdownClient(oldClient);
+ ClangdClient * const client = createClient(project, jsonDbDir);
+ connect(client, &Client::initialized, this, [client, project, projectInfo, jsonDbDir] {
+ using namespace ProjectExplorer;
+ if (!CppTools::codeModelSettings()->useClangd())
+ return;
+ if (!SessionManager::hasProject(project))
+ return;
+ if (cppModelManager()->projectInfo(project) != projectInfo)
+ return;
+
+ // Acquaint the client with all open C++ documents for this project.
+ bool hasDocuments = false;
+ for (const Core::DocumentModel::Entry * const entry : Core::DocumentModel::entries()) {
+ const auto textDocument = qobject_cast<TextEditor::TextDocument *>(entry->document);
+ if (!textDocument)
+ continue;
+ const bool isCppDocument = Utils::contains(
+ Core::DocumentModel::editorsForDocument(textDocument),
+ [](Core::IEditor *editor) {
+ return CppTools::CppModelManager::isCppEditor(editor);
+ });
+ if (!isCppDocument)
+ continue;
+ if (!project->isKnownFile(entry->fileName()))
+ continue;
+ client->openDocument(textDocument);
+ hasDocuments = true;
+ }
+
+ if (hasDocuments)
+ return;
+
+ // clangd oddity: Background indexing only starts after opening a random file.
+ // TODO: changes to the compilation db do not seem to trigger re-indexing.
+ // How to force it?
+ ProjectNode * const rootNode = project->rootProjectNode();
+ if (!rootNode)
+ return;
+ const Node * const cxxNode = rootNode->findNode([](Node *n) {
+ const FileNode * const fileNode = n->asFileNode();
+ return fileNode && (fileNode->fileType() == FileType::Source
+ || fileNode->fileType() == FileType::Header)
+ && fileNode->filePath().exists();
+ });
+ if (!cxxNode)
+ return;
+
+ client->openExtraFile(cxxNode->filePath());
+ client->closeExtraFile(cxxNode->filePath());
+ });
+
+ });
+ auto future = Utils::runAsync(&Internal::generateCompilationDB, projectInfo,
+ CompilationDbPurpose::CodeModel);
+ generatorWatcher->setFuture(future);
+ m_generatorSynchronizer.addFuture(future);
+}
+
+ClangdClient *ClangModelManagerSupport::clientForProject(
+ const ProjectExplorer::Project *project)
+{
+ const QList<Client *> clients = Utils::filtered(
+ LanguageClientManager::clientsForProject(project),
+ [](const LanguageClient::Client *c) {
+ return qobject_cast<const ClangdClient *>(c)
+ && c->state() != Client::ShutdownRequested
+ && c->state() != Client::Shutdown;
+ });
+ QTC_CHECK(clients.size() <= 1);
+ return clients.empty() ? nullptr : qobject_cast<ClangdClient *>(clients.first());
+}
+
+ClangdClient *ClangModelManagerSupport::clientForFile(const Utils::FilePath &file)
+{
+ return clientForProject(ProjectExplorer::SessionManager::projectForFile(file));
+}
+
+ClangdClient *ClangModelManagerSupport::createClient(ProjectExplorer::Project *project,
+ const Utils::FilePath &jsonDbDir)
+{
+ const auto client = new ClangdClient(project, jsonDbDir);
+ emit createdClient(client);
+ return client;
+}
+
void ClangModelManagerSupport::onEditorOpened(Core::IEditor *editor)
{
QTC_ASSERT(editor, return);
@@ -232,6 +378,11 @@ void ClangModelManagerSupport::onEditorOpened(Core::IEditor *editor)
connectToWidgetsMarkContextMenuRequested(editor->widget());
// TODO: Ensure that not fully loaded documents are updated?
+
+ ProjectExplorer::Project * const project
+ = ProjectExplorer::SessionManager::projectForFile(document->filePath());
+ if (Client * const client = clientForProject(project))
+ client->openDocument(textDocument);
}
}
@@ -420,6 +571,8 @@ void ClangModelManagerSupport::onProjectPartsUpdated(ProjectExplorer::Project *p
const CppTools::ProjectInfo projectInfo = cppModelManager()->projectInfo(project);
QTC_ASSERT(projectInfo.isValid(), return);
+ updateLanguageClient(project, projectInfo);
+
QStringList projectPartIds;
for (const CppTools::ProjectPart::Ptr &projectPart : projectInfo.projectParts())
projectPartIds.append(projectPart->id());
diff --git a/src/plugins/clangcodemodel/clangmodelmanagersupport.h b/src/plugins/clangcodemodel/clangmodelmanagersupport.h
index 40348f850c..1c7724b5d5 100644
--- a/src/plugins/clangcodemodel/clangmodelmanagersupport.h
+++ b/src/plugins/clangcodemodel/clangmodelmanagersupport.h
@@ -30,6 +30,7 @@
#include <cpptools/cppmodelmanagersupport.h>
+#include <utils/futuresynchronizer.h>
#include <utils/id.h>
#include <QObject>
@@ -50,6 +51,7 @@ class RefactoringEngineInterface;
namespace ClangCodeModel {
namespace Internal {
+class ClangdClient;
class ClangProjectSettings;
class ClangModelManagerSupport:
@@ -77,8 +79,14 @@ public:
ClangProjectSettings &projectSettings(ProjectExplorer::Project *project) const;
+ ClangdClient *clientForProject(const ProjectExplorer::Project *project);
+ ClangdClient *clientForFile(const Utils::FilePath &file);
+
static ClangModelManagerSupport *instance();
+signals:
+ void createdClient(ClangdClient *client);
+
private:
void onEditorOpened(Core::IEditor *editor);
void onEditorClosed(const QList<Core::IEditor *> &editors);
@@ -118,6 +126,10 @@ private:
void connectToTextDocumentContentsChangedForUnsavedFile(TextEditor::TextDocument *textDocument);
void connectToWidgetsMarkContextMenuRequested(QWidget *editorWidget);
+ void updateLanguageClient(ProjectExplorer::Project *project,
+ const CppTools::ProjectInfo &projectInfo);
+ ClangdClient *createClient(ProjectExplorer::Project *project, const Utils::FilePath &jsonDbDir);
+
private:
UiHeaderOnDiskManager m_uiHeaderOnDiskManager;
BackendCommunicator m_communicator;
@@ -127,6 +139,7 @@ private:
std::unique_ptr<CppTools::RefactoringEngineInterface> m_refactoringEngine;
QHash<ProjectExplorer::Project *, ClangProjectSettings *> m_projectSettings;
+ Utils::FutureSynchronizer m_generatorSynchronizer;
};
class ClangModelManagerSupportProvider : public CppTools::ModelManagerSupportProvider
diff --git a/src/plugins/clangcodemodel/clangoverviewmodel.cpp b/src/plugins/clangcodemodel/clangoverviewmodel.cpp
index 88c5aa9d9f..48ba29924b 100644
--- a/src/plugins/clangcodemodel/clangoverviewmodel.cpp
+++ b/src/plugins/clangcodemodel/clangoverviewmodel.cpp
@@ -226,7 +226,7 @@ Link OverviewModel::linkFromIndex(const QModelIndex &sourceIndex) const
auto item = static_cast<TokenTreeItem *>(itemForIndex(sourceIndex));
if (!item)
return {};
- return Link(m_filePath, item->token.line, item->token.column - 1);
+ return Link(FilePath::fromString(m_filePath), item->token.line, item->token.column - 1);
}
LineColumn OverviewModel::lineColumnFromIndex(const QModelIndex &sourceIndex) const
diff --git a/src/plugins/clangcodemodel/clangrefactoringengine.cpp b/src/plugins/clangcodemodel/clangrefactoringengine.cpp
index ed9af84d66..f42cf79a61 100644
--- a/src/plugins/clangcodemodel/clangrefactoringengine.cpp
+++ b/src/plugins/clangcodemodel/clangrefactoringengine.cpp
@@ -26,6 +26,11 @@
#include "clangrefactoringengine.h"
#include "clangeditordocumentprocessor.h"
+#include "clangdclient.h"
+#include "clangmodelmanagersupport.h"
+
+#include <cpptools/cppmodelmanager.h>
+#include <languageclient/languageclientsymbolsupport.h>
#include <utils/textutils.h>
#include <utils/qtcassert.h>
@@ -80,5 +85,58 @@ void RefactoringEngine::startLocalRenaming(const CppTools::CursorInEditor &data,
m_watcher->setFuture(cursorFuture);
}
+void RefactoringEngine::globalRename(const CppTools::CursorInEditor &cursor,
+ CppTools::UsagesCallback &&callback,
+ const QString &replacement)
+{
+ ClangdClient * const client
+ = ClangModelManagerSupport::instance()->clientForFile(cursor.filePath());
+ if (!client || !client->isFullyIndexed()) {
+ CppTools::CppModelManager::builtinRefactoringEngine()
+ ->globalRename(cursor, std::move(callback), replacement);
+ return;
+ }
+ QTC_ASSERT(client->documentOpen(cursor.textDocument()),
+ client->openDocument(cursor.textDocument()));
+ client->findUsages(cursor.textDocument(), cursor.cursor(), replacement);
+}
+
+void RefactoringEngine::findUsages(const CppTools::CursorInEditor &cursor,
+ CppTools::UsagesCallback &&callback) const
+{
+ ClangdClient * const client
+ = ClangModelManagerSupport::instance()->clientForFile(cursor.filePath());
+ if (!client || !client->isFullyIndexed()) {
+ CppTools::CppModelManager::builtinRefactoringEngine()
+ ->findUsages(cursor, std::move(callback));
+ return;
+ }
+ QTC_ASSERT(client->documentOpen(cursor.textDocument()),
+ client->openDocument(cursor.textDocument()));
+ client->findUsages(cursor.textDocument(), cursor.cursor(), {});
+}
+
+void RefactoringEngine::globalFollowSymbol(
+ const CppTools::CursorInEditor &cursor,
+ Utils::ProcessLinkCallback &&callback,
+ const CPlusPlus::Snapshot &snapshot,
+ const CPlusPlus::Document::Ptr &doc,
+ CppTools::SymbolFinder *symbolFinder,
+ bool inNextSplit) const
+{
+ ClangdClient * const client
+ = ClangModelManagerSupport::instance()->clientForFile(cursor.filePath());
+ if (!client || !client->isFullyIndexed()) {
+ CppTools::CppModelManager::builtinRefactoringEngine()
+ ->globalFollowSymbol(cursor, std::move(callback), snapshot, doc, symbolFinder,
+ inNextSplit);
+ return;
+ }
+ QTC_ASSERT(client->documentOpen(cursor.textDocument()),
+ client->openDocument(cursor.textDocument()));
+ client->symbolSupport().findLinkAt(cursor.textDocument(), cursor.cursor(), std::move(callback),
+ true);
+}
+
} // namespace Internal
} // namespace ClangCodeModel
diff --git a/src/plugins/clangcodemodel/clangrefactoringengine.h b/src/plugins/clangcodemodel/clangrefactoringengine.h
index 297c8ff238..c4e728b022 100644
--- a/src/plugins/clangcodemodel/clangrefactoringengine.h
+++ b/src/plugins/clangcodemodel/clangrefactoringengine.h
@@ -44,17 +44,16 @@ public:
void startLocalRenaming(const CppTools::CursorInEditor &data,
CppTools::ProjectPart *projectPart,
RenameCallback &&renameSymbolsCallback) override;
- void globalRename(const CppTools::CursorInEditor &, CppTools::UsagesCallback &&,
- const QString &) override {}
- void findUsages(const CppTools::CursorInEditor &, CppTools::UsagesCallback &&) const override {}
- void globalFollowSymbol(const CppTools::CursorInEditor &,
- ::Utils::ProcessLinkCallback &&,
- const CPlusPlus::Snapshot &,
- const CPlusPlus::Document::Ptr &,
- CppTools::SymbolFinder *,
- bool) const override
- {
- }
+ void globalRename(const CppTools::CursorInEditor &cursor, CppTools::UsagesCallback &&callback,
+ const QString &replacement) override;
+ void findUsages(const CppTools::CursorInEditor &cursor,
+ CppTools::UsagesCallback &&callback) const override;
+ void globalFollowSymbol(const CppTools::CursorInEditor &cursor,
+ ::Utils::ProcessLinkCallback &&callback,
+ const CPlusPlus::Snapshot &snapshot,
+ const CPlusPlus::Document::Ptr &doc,
+ CppTools::SymbolFinder *symbolFinder,
+ bool inNextSplit) const override;
private:
using FutureCursorWatcher = QFutureWatcher<CppTools::CursorInfo>;
diff --git a/src/plugins/clangcodemodel/clangutils.cpp b/src/plugins/clangcodemodel/clangutils.cpp
index f46b455197..95b9364e0c 100644
--- a/src/plugins/clangcodemodel/clangutils.cpp
+++ b/src/plugins/clangcodemodel/clangutils.cpp
@@ -27,6 +27,7 @@
#include "clangeditordocumentprocessor.h"
#include "clangmodelmanagersupport.h"
+#include "clangprojectsettings.h"
#include <clangsupport/tokeninfocontainer.h>
@@ -104,14 +105,6 @@ private:
}
};
-QStringList createClangOptions(const ProjectPart &projectPart,
- UseBuildSystemWarnings useBuildSystemWarnings,
- ProjectFile::Kind fileKind)
-{
- return LibClangOptionsBuilder(projectPart, useBuildSystemWarnings)
- .build(fileKind, UsePrecompiledHeaders::No);
-}
-
ProjectPart::Ptr projectPartForFile(const QString &filePath)
{
if (const auto parser = CppTools::BaseEditorDocumentParser::get(filePath))
@@ -354,34 +347,45 @@ static QStringList projectPartArguments(const ProjectPart &projectPart)
static QJsonObject createFileObject(const FilePath &buildDir,
const QStringList &arguments,
const ProjectPart &projectPart,
- const ProjectFile &projFile)
+ const ProjectFile &projFile,
+ CompilationDbPurpose purpose)
{
QJsonObject fileObject;
fileObject["file"] = projFile.path;
- QJsonArray args = QJsonArray::fromStringList(arguments);
-
- const ProjectFile::Kind kind = ProjectFile::classify(projFile.path);
- if (projectPart.toolchainType == ProjectExplorer::Constants::MSVC_TOOLCHAIN_TYPEID
- || projectPart.toolchainType == ProjectExplorer::Constants::CLANG_CL_TOOLCHAIN_TYPEID) {
- if (ProjectFile::isC(kind))
- args.append("/TC");
- else if (ProjectFile::isCxx(kind))
- args.append("/TP");
+ QJsonArray args;
+
+ if (purpose == CompilationDbPurpose::Project) {
+ args = QJsonArray::fromStringList(arguments);
+
+ const ProjectFile::Kind kind = ProjectFile::classify(projFile.path);
+ if (projectPart.toolchainType == ProjectExplorer::Constants::MSVC_TOOLCHAIN_TYPEID
+ || projectPart.toolchainType == ProjectExplorer::Constants::CLANG_CL_TOOLCHAIN_TYPEID) {
+ if (ProjectFile::isC(kind))
+ args.append("/TC");
+ else if (ProjectFile::isCxx(kind))
+ args.append("/TP");
+ } else {
+ QStringList langOption
+ = createLanguageOptionGcc(kind,
+ projectPart.languageExtensions
+ & LanguageExtension::ObjectiveC);
+ for (const QString &langOptionPart : langOption)
+ args.append(langOptionPart);
+ }
} else {
- QStringList langOption
- = createLanguageOptionGcc(kind,
- projectPart.languageExtensions
- & LanguageExtension::ObjectiveC);
- for (const QString &langOptionPart : langOption)
- args.append(langOptionPart);
+ // TODO: Do we really need to re-calculate the project part options per source file?
+ args = QJsonArray::fromStringList(createClangOptions(projectPart, projFile.path).second);
+ args.prepend("clang"); // TODO: clang-cl for MSVC targets? Does it matter at all what we put here?
}
+
args.append(QDir::toNativeSeparators(projFile.path));
fileObject["arguments"] = args;
fileObject["directory"] = buildDir.toString();
return fileObject;
}
-GenerateCompilationDbResult generateCompilationDB(CppTools::ProjectInfo projectInfo)
+GenerateCompilationDbResult generateCompilationDB(CppTools::ProjectInfo projectInfo,
+ CompilationDbPurpose purpose)
{
const FilePath buildDir = buildDirectory(*projectInfo.project());
QTC_ASSERT(!buildDir.isEmpty(), return GenerateCompilationDbResult(QString(),
@@ -400,9 +404,12 @@ GenerateCompilationDbResult generateCompilationDB(CppTools::ProjectInfo projectI
compileCommandsFile.write("[");
for (ProjectPart::Ptr projectPart : projectInfo.projectParts()) {
- const QStringList args = projectPartArguments(*projectPart);
+ QStringList args;
+ if (purpose == CompilationDbPurpose::Project)
+ args = projectPartArguments(*projectPart);
for (const ProjectFile &projFile : projectPart->files) {
- const QJsonObject json = createFileObject(buildDir, args, *projectPart, projFile);
+ const QJsonObject json = createFileObject(buildDir, args, *projectPart, projFile,
+ purpose);
if (compileCommandsFile.size() > 1)
compileCommandsFile.write(",");
compileCommandsFile.write('\n' + QJsonDocument(json).toJson().trimmed());
@@ -474,5 +481,142 @@ QString DiagnosticTextInfo::clazyCheckName(const QString &option)
return option;
}
+
+namespace {
+static ClangProjectSettings &getProjectSettings(ProjectExplorer::Project *project)
+{
+ QTC_CHECK(project);
+ return ClangModelManagerSupport::instance()->projectSettings(project);
+}
+
+// TODO: Can we marry this with CompilerOptionsBuilder?
+class FileOptionsBuilder
+{
+public:
+ FileOptionsBuilder(const QString &filePath, const CppTools::ProjectPart &projectPart)
+ : m_filePath(filePath)
+ , m_projectPart(projectPart)
+ , m_builder(projectPart)
+ {
+ // Determine the driver mode from toolchain and flags.
+ m_builder.evaluateCompilerFlags();
+ m_isClMode = m_builder.isClStyle();
+
+ addLanguageOptions();
+ addGlobalDiagnosticOptions(); // Before addDiagnosticOptions() so users still can overwrite.
+ addDiagnosticOptions();
+ addGlobalOptions();
+ addPrecompiledHeaderOptions();
+ }
+
+ const QStringList &options() const { return m_options; }
+ const ::Utils::Id &diagnosticConfigId() const { return m_diagnosticConfigId; }
+ CppTools::UseBuildSystemWarnings useBuildSystemWarnings() const
+ {
+ return m_useBuildSystemWarnings;
+ }
+
+private:
+ void addLanguageOptions()
+ {
+ // Determine file kind with respect to ambiguous headers.
+ CppTools::ProjectFile::Kind fileKind = CppTools::ProjectFile::classify(m_filePath);
+ if (fileKind == CppTools::ProjectFile::AmbiguousHeader) {
+ fileKind = m_projectPart.languageVersion <= ::Utils::LanguageVersion::LatestC
+ ? CppTools::ProjectFile::CHeader
+ : CppTools::ProjectFile::CXXHeader;
+ }
+
+ m_builder.reset();
+ m_builder.updateFileLanguage(fileKind);
+
+ m_options.append(m_builder.options());
+ }
+
+ void addDiagnosticOptions()
+ {
+ if (m_projectPart.project) {
+ ClangProjectSettings &projectSettings = getProjectSettings(m_projectPart.project);
+ if (!projectSettings.useGlobalConfig()) {
+ const ::Utils::Id warningConfigId = projectSettings.warningConfigId();
+ const CppTools::ClangDiagnosticConfigsModel configsModel
+ = CppTools::diagnosticConfigsModel();
+ if (configsModel.hasConfigWithId(warningConfigId)) {
+ addDiagnosticOptionsForConfig(configsModel.configWithId(warningConfigId));
+ return;
+ }
+ }
+ }
+
+ addDiagnosticOptionsForConfig(CppTools::codeModelSettings()->clangDiagnosticConfig());
+ }
+
+ void addDiagnosticOptionsForConfig(const CppTools::ClangDiagnosticConfig &diagnosticConfig)
+ {
+ m_diagnosticConfigId = diagnosticConfig.id();
+ m_useBuildSystemWarnings = diagnosticConfig.useBuildSystemWarnings()
+ ? CppTools::UseBuildSystemWarnings::Yes
+ : CppTools::UseBuildSystemWarnings::No;
+
+ const QStringList options = m_isClMode
+ ? CppTools::clangArgsForCl(diagnosticConfig.clangOptions())
+ : diagnosticConfig.clangOptions();
+ m_options.append(options);
+ }
+
+ void addGlobalDiagnosticOptions()
+ {
+ m_options += CppTools::ClangDiagnosticConfigsModel::globalDiagnosticOptions();
+ }
+
+ void addGlobalOptions()
+ {
+ if (!m_projectPart.project)
+ m_options.append(ClangProjectSettings::globalCommandLineOptions());
+ else
+ m_options.append(getProjectSettings(m_projectPart.project).commandLineOptions());
+ }
+
+ void addPrecompiledHeaderOptions()
+ {
+ using namespace CppTools;
+
+ if (getPchUsage() == UsePrecompiledHeaders::No)
+ return;
+
+ if (m_projectPart.precompiledHeaders.contains(m_filePath))
+ return;
+
+ m_builder.reset();
+ m_builder.addPrecompiledHeaderOptions(UsePrecompiledHeaders::Yes);
+
+ m_options.append(m_builder.options());
+ }
+
+private:
+ const QString &m_filePath;
+ const CppTools::ProjectPart &m_projectPart;
+
+ ::Utils::Id m_diagnosticConfigId;
+ CppTools::UseBuildSystemWarnings m_useBuildSystemWarnings = CppTools::UseBuildSystemWarnings::No;
+ CppTools::CompilerOptionsBuilder m_builder;
+ bool m_isClMode = false;
+ QStringList m_options;
+};
+} // namespace
+
+QPair<Utils::Id, QStringList> createClangOptions(const CppTools::ProjectPart &projectPart,
+ const QString &filePath)
+{
+ QPair<Utils::Id, QStringList> value;
+ const FileOptionsBuilder fileOptions(filePath, projectPart);
+ value.first = fileOptions.diagnosticConfigId();
+ LibClangOptionsBuilder optionsBuilder(projectPart, fileOptions.useBuildSystemWarnings());
+ const QStringList projectPartOptions = optionsBuilder.build(CppTools::ProjectFile::Unsupported,
+ UsePrecompiledHeaders::No);
+ value.second = projectPartOptions + fileOptions.options();
+ return value;
+}
+
} // namespace Internal
} // namespace Clang
diff --git a/src/plugins/clangcodemodel/clangutils.h b/src/plugins/clangcodemodel/clangutils.h
index 43d4de2224..7e59eb886e 100644
--- a/src/plugins/clangcodemodel/clangutils.h
+++ b/src/plugins/clangcodemodel/clangutils.h
@@ -30,6 +30,7 @@
#include <cpptools/projectpart.h>
#include <cpptools/compileroptionsbuilder.h>
+#include <QPair>
#include <QTextCursor>
QT_BEGIN_NAMESPACE
@@ -49,9 +50,8 @@ namespace Internal {
CppTools::CppEditorDocumentHandle *cppDocument(const QString &filePath);
void setLastSentDocumentRevision(const QString &filePath, uint revision);
-QStringList createClangOptions(const CppTools::ProjectPart &projectPart,
- CppTools::UseBuildSystemWarnings useBuildSystemWarnings,
- CppTools::ProjectFile::Kind fileKind);
+QPair<Utils::Id, QStringList> createClangOptions(const CppTools::ProjectPart &projectPart,
+ const QString &filePath);
CppTools::ProjectPart::Ptr projectPartForFile(const QString &filePath);
CppTools::ProjectPart::Ptr projectPartForFileBasedOnProcessor(const QString &filePath);
@@ -78,7 +78,9 @@ public:
QString error;
};
-GenerateCompilationDbResult generateCompilationDB(CppTools::ProjectInfo projectInfo);
+enum CompilationDbPurpose { Project, CodeModel };
+GenerateCompilationDbResult generateCompilationDB(CppTools::ProjectInfo projectInfo,
+ CompilationDbPurpose purpose);
class DiagnosticTextInfo
{
diff --git a/src/plugins/clangcodemodel/test/clangautomationutils.cpp b/src/plugins/clangcodemodel/test/clangautomationutils.cpp
index 269b29acd4..45030f7fba 100644
--- a/src/plugins/clangcodemodel/test/clangautomationutils.cpp
+++ b/src/plugins/clangcodemodel/test/clangautomationutils.cpp
@@ -138,5 +138,10 @@ TextEditor::ProposalModelPtr completionResults(TextEditor::BaseTextEditor *textE
return waitForCompletions.proposalModel;
}
+QString qrcPath(const QByteArray &relativeFilePath)
+{
+ return QLatin1String(":/unittests/ClangCodeModel/") + QString::fromUtf8(relativeFilePath);
+}
+
} // namespace Internal
} // namespace ClangCodeModel
diff --git a/src/plugins/clangcodemodel/test/clangautomationutils.h b/src/plugins/clangcodemodel/test/clangautomationutils.h
index 4e16db9f2d..dcb62eda76 100644
--- a/src/plugins/clangcodemodel/test/clangautomationutils.h
+++ b/src/plugins/clangcodemodel/test/clangautomationutils.h
@@ -39,5 +39,7 @@ TextEditor::ProposalModelPtr completionResults(TextEditor::BaseTextEditor *textE
const QStringList &includePaths = QStringList(),
int timeOutInMs = 10000);
+QString qrcPath(const QByteArray &relativeFilePath);
+
} // namespace Internal
} // namespace ClangCodeModel
diff --git a/src/plugins/clangcodemodel/test/clangcodecompletion_test.cpp b/src/plugins/clangcodemodel/test/clangcodecompletion_test.cpp
index c4dd8e882e..a0d8aef463 100644
--- a/src/plugins/clangcodemodel/test/clangcodecompletion_test.cpp
+++ b/src/plugins/clangcodemodel/test/clangcodecompletion_test.cpp
@@ -58,9 +58,6 @@ using namespace ClangCodeModel::Internal;
namespace {
-QString qrcPath(const QByteArray relativeFilePath)
-{ return QLatin1String(":/unittests/ClangCodeModel/") + QString::fromUtf8(relativeFilePath); }
-
CppTools::Tests::TemporaryDir *globalTemporaryDir()
{
static CppTools::Tests::TemporaryDir dir;
diff --git a/src/plugins/clangcodemodel/test/clangdtests.cpp b/src/plugins/clangcodemodel/test/clangdtests.cpp
new file mode 100644
index 0000000000..4c109c888a
--- /dev/null
+++ b/src/plugins/clangcodemodel/test/clangdtests.cpp
@@ -0,0 +1,329 @@
+/****************************************************************************
+**
+** Copyright (C) 2021 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of Qt Creator.
+**
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3 as published by the Free Software
+** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-3.0.html.
+**
+****************************************************************************/
+
+#include "clangdtests.h"
+
+#include "clangautomationutils.h"
+#include "clangbatchfileprocessor.h"
+#include "../clangdclient.h"
+#include "../clangmodelmanagersupport.h"
+
+#include <cplusplus/FindUsages.h>
+#include <cpptools/cppcodemodelsettings.h>
+#include <cpptools/cpptoolsreuse.h>
+#include <cpptools/cpptoolstestcase.h>
+#include <coreplugin/editormanager/editormanager.h>
+#include <coreplugin/find/searchresultitem.h>
+#include <projectexplorer/kitmanager.h>
+#include <projectexplorer/project.h>
+#include <projectexplorer/projectexplorer.h>
+#include <qtsupport/qtkitinformation.h>
+#include <utils/algorithm.h>
+
+#include <QEventLoop>
+#include <QScopedPointer>
+#include <QTimer>
+#include <QtTest>
+
+using namespace CPlusPlus;
+using namespace Core;
+using namespace ProjectExplorer;
+
+namespace ClangCodeModel {
+namespace Internal {
+namespace Tests {
+
+void ClangdTests::initTestCase()
+{
+ const auto settings = CppTools::codeModelSettings();
+ const QString clangdFromEnv = qEnvironmentVariable("QTC_CLANGD");
+ if (!clangdFromEnv.isEmpty())
+ settings->setClangdFilePath(Utils::FilePath::fromString(clangdFromEnv));
+ const auto clangd = settings->clangdFilePath();
+ if (clangd.isEmpty() || !clangd.exists())
+ QSKIP("clangd binary not found");
+ settings->setUseClangd(true);
+}
+
+template <typename Signal> static bool waitForSignalOrTimeout(
+ const typename QtPrivate::FunctionPointer<Signal>::Object *sender, Signal signal)
+{
+ QTimer timer;
+ timer.setSingleShot(true);
+ timer.setInterval(timeOutInMs());
+ QEventLoop loop;
+ QObject::connect(&timer, &QTimer::timeout, &loop, &QEventLoop::quit);
+ QObject::connect(sender, signal, &loop, &QEventLoop::quit);
+ timer.start();
+ loop.exec();
+ return timer.isActive();
+}
+
+// The main point here is to test our access type categorization.
+// We do not try to stress-test clangd's "Find References" functionality; such tests belong
+// into LLVM.
+void ClangdTests::testFindReferences()
+{
+ // Find suitable kit.
+ const QList<Kit *> allKits = KitManager::kits();
+ if (allKits.isEmpty())
+ QSKIP("This test requires at least one kit to be present");
+ Kit * const kit = Utils::findOr(allKits, nullptr, [](const Kit *k) {
+ return k->isValid() && QtSupport::QtKitAspect::qtVersion(k);
+ });
+ if (!kit)
+ QSKIP("The test requires at least one valid kit with a valid Qt");
+
+ // Copy project out of qrc file, open it, and set up target.
+ CppTools::Tests::TemporaryCopiedDir testDir(qrcPath("find-usages"));
+ QVERIFY(testDir.isValid());
+ const auto openProjectResult = ProjectExplorerPlugin::openProject(
+ testDir.absolutePath("find-usages.pro"));
+ QVERIFY2(openProjectResult, qPrintable(openProjectResult.errorMessage()));
+ openProjectResult.project()->configureAsExampleProject(kit);
+
+ // Setting up the project should result in a clangd client being created.
+ // Wait until that has happened.
+ const auto modelManagerSupport = ClangModelManagerSupport::instance();
+ ClangdClient *client = modelManagerSupport->clientForProject(openProjectResult.project());
+ if (!client) {
+ QVERIFY(waitForSignalOrTimeout(modelManagerSupport,
+ &ClangModelManagerSupport::createdClient));
+ client = modelManagerSupport->clientForProject(openProjectResult.project());
+ }
+ QVERIFY(client);
+ client->enableTesting();
+
+ // Wait until the client is fully initialized, i.e. it's completed the handshake
+ // with the server.
+ if (!client->reachable())
+ QVERIFY(waitForSignalOrTimeout(client, &ClangdClient::initialized));
+ QVERIFY(client->reachable());
+
+ // The kind of AST support we need was introduced in LLVM 13.
+ if (client->versionNumber() < QVersionNumber(13))
+ QSKIP("Find Usages test needs clang >= 13");
+
+ // Wait for index to build.
+ if (!client->isFullyIndexed())
+ QVERIFY(waitForSignalOrTimeout(client, &ClangdClient::indexingFinished));
+ QVERIFY(client->isFullyIndexed());
+
+ // Open cpp documents.
+ struct EditorCloser {
+ static void cleanup(IEditor *editor) { EditorManager::closeEditors({editor}); }
+ };
+ const auto headerPath = Utils::FilePath::fromString(testDir.absolutePath("defs.h"));
+ QVERIFY2(headerPath.exists(), qPrintable(headerPath.toUserOutput()));
+ QScopedPointer<IEditor, EditorCloser> headerEditor(EditorManager::openEditor(headerPath));
+ QVERIFY(headerEditor);
+ const auto headerDoc = qobject_cast<TextEditor::TextDocument *>(headerEditor->document());
+ QVERIFY(headerDoc);
+ QVERIFY(client->documentForFilePath(headerPath) == headerDoc);
+ const auto cppFilePath = Utils::FilePath::fromString(testDir.absolutePath("main.cpp"));
+ QVERIFY2(cppFilePath.exists(), qPrintable(cppFilePath.toUserOutput()));
+ QScopedPointer<IEditor, EditorCloser> cppFileEditor(EditorManager::openEditor(cppFilePath));
+ QVERIFY(cppFileEditor);
+ const auto cppDoc = qobject_cast<TextEditor::TextDocument *>(cppFileEditor->document());
+ QVERIFY(cppDoc);
+ QVERIFY(client->documentForFilePath(cppFilePath) == cppDoc);
+
+ // ... and we're ready to go.
+ QList<SearchResultItem> searchResults;
+ connect(client, &ClangdClient::foundReferences, this,
+ [&searchResults](const QList<SearchResultItem> &results) {
+ if (results.isEmpty())
+ return;
+ if (results.first().path().first().endsWith("defs.h"))
+ searchResults = results + searchResults; // Guarantee expected file order.
+ else
+ searchResults += results;
+ });
+
+#define FIND_USAGES(doc, pos) do { \
+ QTextCursor cursor((doc)->document()); \
+ cursor.setPosition((pos)); \
+ searchResults.clear(); \
+ client->findUsages((doc), cursor, {}); \
+ QVERIFY(waitForSignalOrTimeout(client, &ClangdClient::findUsagesDone)); \
+} while (false)
+
+#define EXPECT_RESULT(index, lne, col, type) \
+ QCOMPARE(searchResults.at(index).mainRange().begin.line, lne); \
+ QCOMPARE(searchResults.at(index).mainRange().begin.column, col); \
+ QCOMPARE(searchResults.at(index).userData().toInt(), int(type))
+
+ // All kinds of checks involving a struct member.
+ FIND_USAGES(headerDoc, 55);
+ QCOMPARE(searchResults.size(), 32);
+ EXPECT_RESULT(0, 2, 17, Usage::Type::Read);
+ EXPECT_RESULT(1, 3, 15, Usage::Type::Declaration);
+ EXPECT_RESULT(2, 6, 17, Usage::Type::WritableRef);
+ EXPECT_RESULT(3, 8, 11, Usage::Type::WritableRef);
+ EXPECT_RESULT(4, 9, 13, Usage::Type::WritableRef);
+ EXPECT_RESULT(5, 10, 12, Usage::Type::WritableRef);
+ EXPECT_RESULT(6, 11, 13, Usage::Type::WritableRef);
+ EXPECT_RESULT(7, 12, 14, Usage::Type::WritableRef);
+ EXPECT_RESULT(8, 13, 26, Usage::Type::WritableRef);
+ EXPECT_RESULT(9, 14, 23, Usage::Type::Read);
+ EXPECT_RESULT(10, 15, 14, Usage::Type::Read);
+ EXPECT_RESULT(11, 16, 24, Usage::Type::WritableRef);
+ EXPECT_RESULT(12, 17, 15, Usage::Type::WritableRef);
+ EXPECT_RESULT(13, 18, 22, Usage::Type::Read);
+ EXPECT_RESULT(14, 19, 12, Usage::Type::WritableRef);
+ EXPECT_RESULT(15, 20, 12, Usage::Type::Read);
+ EXPECT_RESULT(16, 21, 13, Usage::Type::WritableRef);
+ EXPECT_RESULT(17, 22, 13, Usage::Type::Read);
+ EXPECT_RESULT(18, 23, 12, Usage::Type::Read);
+ EXPECT_RESULT(19, 42, 20, Usage::Type::Read);
+ EXPECT_RESULT(20, 44, 15, Usage::Type::Read);
+ EXPECT_RESULT(21, 47, 15, Usage::Type::Write);
+ EXPECT_RESULT(22, 50, 11, Usage::Type::Read);
+ EXPECT_RESULT(23, 51, 11, Usage::Type::Write);
+ EXPECT_RESULT(24, 52, 9, Usage::Type::Write);
+ EXPECT_RESULT(25, 53, 7, Usage::Type::Write);
+ EXPECT_RESULT(26, 56, 7, Usage::Type::Write);
+ EXPECT_RESULT(27, 56, 25, Usage::Type::Other);
+ EXPECT_RESULT(28, 58, 13, Usage::Type::Read);
+ EXPECT_RESULT(29, 58, 25, Usage::Type::Read);
+ EXPECT_RESULT(30, 59, 7, Usage::Type::Write);
+ EXPECT_RESULT(31, 59, 24, Usage::Type::Read);
+
+ // Detect constructor member initialization as a write access.
+ FIND_USAGES(headerDoc, 68);
+ QCOMPARE(searchResults.size(), 2);
+ EXPECT_RESULT(0, 2, 10, Usage::Type::Write);
+ EXPECT_RESULT(1, 4, 8, Usage::Type::Declaration);
+
+ // Detect direct member initialization.
+ FIND_USAGES(headerDoc, 101);
+ QCOMPARE(searchResults.size(), 2);
+ EXPECT_RESULT(0, 5, 21, Usage::Type::Initialization);
+ EXPECT_RESULT(1, 45, 16, Usage::Type::Read);
+
+ // Make sure that pure virtual declaration is not mistaken for an assignment.
+ FIND_USAGES(headerDoc, 420);
+ QCOMPARE(searchResults.size(), 3); // FIXME: The override gets reported twice. clang bug?
+ EXPECT_RESULT(0, 17, 17, Usage::Type::Declaration);
+ EXPECT_RESULT(1, 21, 9, Usage::Type::Declaration);
+ EXPECT_RESULT(2, 21, 9, Usage::Type::Declaration);
+
+ // References to pointer variable.
+ FIND_USAGES(cppDoc, 52);
+ QCOMPARE(searchResults.size(), 11);
+ EXPECT_RESULT(0, 6, 10, Usage::Type::Initialization);
+ EXPECT_RESULT(1, 8, 4, Usage::Type::Write);
+ EXPECT_RESULT(2, 10, 4, Usage::Type::Write);
+ EXPECT_RESULT(3, 24, 5, Usage::Type::Write);
+ EXPECT_RESULT(4, 25, 11, Usage::Type::WritableRef);
+ EXPECT_RESULT(5, 26, 11, Usage::Type::Read);
+ EXPECT_RESULT(6, 27, 10, Usage::Type::WritableRef);
+ EXPECT_RESULT(7, 28, 10, Usage::Type::Read);
+ EXPECT_RESULT(8, 29, 11, Usage::Type::Read);
+ EXPECT_RESULT(9, 30, 15, Usage::Type::WritableRef);
+ EXPECT_RESULT(10, 31, 22, Usage::Type::Read);
+
+ // References to struct variable, directly and via members.
+ FIND_USAGES(cppDoc, 39);
+ QCOMPARE(searchResults.size(), 34);
+ EXPECT_RESULT(0, 5, 7, Usage::Type::Declaration);
+ EXPECT_RESULT(1, 6, 15, Usage::Type::WritableRef);
+ EXPECT_RESULT(2, 8, 9, Usage::Type::WritableRef);
+ EXPECT_RESULT(3, 9, 11, Usage::Type::WritableRef);
+ EXPECT_RESULT(4, 11, 4, Usage::Type::Write);
+ EXPECT_RESULT(5, 11, 11, Usage::Type::WritableRef);
+ EXPECT_RESULT(6, 12, 12, Usage::Type::WritableRef);
+ EXPECT_RESULT(7, 13, 6, Usage::Type::Write);
+ EXPECT_RESULT(8, 14, 21, Usage::Type::Read);
+ EXPECT_RESULT(9, 15, 4, Usage::Type::Write);
+ EXPECT_RESULT(10, 15, 12, Usage::Type::Read);
+ EXPECT_RESULT(11, 16, 22, Usage::Type::WritableRef);
+ EXPECT_RESULT(12, 17, 13, Usage::Type::WritableRef);
+ EXPECT_RESULT(13, 18, 20, Usage::Type::Read);
+ EXPECT_RESULT(14, 19, 10, Usage::Type::WritableRef);
+ EXPECT_RESULT(15, 20, 10, Usage::Type::Read);
+ EXPECT_RESULT(16, 21, 11, Usage::Type::WritableRef);
+ EXPECT_RESULT(17, 22, 11, Usage::Type::Read);
+ EXPECT_RESULT(18, 23, 10, Usage::Type::Read);
+ EXPECT_RESULT(19, 32, 4, Usage::Type::Write);
+ EXPECT_RESULT(20, 33, 23, Usage::Type::WritableRef);
+ EXPECT_RESULT(21, 34, 23, Usage::Type::Read);
+ EXPECT_RESULT(22, 35, 15, Usage::Type::WritableRef);
+ EXPECT_RESULT(23, 36, 22, Usage::Type::WritableRef);
+ EXPECT_RESULT(24, 37, 4, Usage::Type::Read);
+ EXPECT_RESULT(25, 38, 4, Usage::Type::WritableRef);
+ EXPECT_RESULT(26, 39, 6, Usage::Type::WritableRef);
+ EXPECT_RESULT(27, 40, 4, Usage::Type::Read);
+ EXPECT_RESULT(28, 41, 4, Usage::Type::WritableRef);
+ EXPECT_RESULT(29, 42, 4, Usage::Type::Read);
+ EXPECT_RESULT(30, 42, 18, Usage::Type::Read);
+ EXPECT_RESULT(31, 43, 11, Usage::Type::Write);
+ EXPECT_RESULT(32, 54, 4, Usage::Type::Other);
+ EXPECT_RESULT(33, 55, 4, Usage::Type::Other);
+
+ // References to struct type.
+ FIND_USAGES(headerDoc, 7);
+ QCOMPARE(searchResults.size(), 18);
+ EXPECT_RESULT(0, 1, 7, Usage::Type::Declaration);
+ EXPECT_RESULT(1, 2, 4, Usage::Type::Declaration);
+ EXPECT_RESULT(2, 20, 19, Usage::Type::Other);
+
+ // These are conceptually questionable, as S is a type and thus we cannot "read from"
+ // or "write to" it. But it probably matches the intuitive user expectation.
+ EXPECT_RESULT(3, 10, 9, Usage::Type::WritableRef);
+ EXPECT_RESULT(4, 12, 4, Usage::Type::Write);
+ EXPECT_RESULT(5, 44, 12, Usage::Type::Read);
+ EXPECT_RESULT(6, 45, 13, Usage::Type::Read);
+ EXPECT_RESULT(7, 47, 12, Usage::Type::Write);
+ EXPECT_RESULT(8, 50, 8, Usage::Type::Read);
+ EXPECT_RESULT(9, 51, 8, Usage::Type::Write);
+ EXPECT_RESULT(10, 52, 6, Usage::Type::Write);
+ EXPECT_RESULT(11, 53, 4, Usage::Type::Write);
+ EXPECT_RESULT(12, 56, 4, Usage::Type::Write);
+ EXPECT_RESULT(13, 56, 22, Usage::Type::Other);
+ EXPECT_RESULT(14, 58, 10, Usage::Type::Read);
+ EXPECT_RESULT(15, 58, 22, Usage::Type::Read);
+ EXPECT_RESULT(16, 59, 4, Usage::Type::Write);
+ EXPECT_RESULT(17, 59, 21, Usage::Type::Read);
+
+ // References to subclass type.
+ FIND_USAGES(headerDoc, 450);
+ QCOMPARE(searchResults.size(), 4);
+ EXPECT_RESULT(0, 20, 7, Usage::Type::Declaration);
+ EXPECT_RESULT(1, 5, 4, Usage::Type::Other);
+ EXPECT_RESULT(2, 13, 21, Usage::Type::Other);
+ EXPECT_RESULT(3, 32, 8, Usage::Type::Other);
+
+ // References to array variables.
+ FIND_USAGES(cppDoc, 1134);
+ QCOMPARE(searchResults.size(), 3);
+ EXPECT_RESULT(0, 57, 8, Usage::Type::Declaration);
+ EXPECT_RESULT(1, 58, 4, Usage::Type::Write);
+ EXPECT_RESULT(2, 59, 15, Usage::Type::Read);
+}
+
+} // namespace Tests
+} // namespace Internal
+} // namespace ClangCodeModel
diff --git a/src/plugins/bazaar/optionspage.h b/src/plugins/clangcodemodel/test/clangdtests.h
index 4e6c69e9fb..ddf2c1b1d2 100644
--- a/src/plugins/bazaar/optionspage.h
+++ b/src/plugins/clangcodemodel/test/clangdtests.h
@@ -1,6 +1,6 @@
/****************************************************************************
**
-** Copyright (C) 2016 Hugues Delorme
+** Copyright (C) 2021 The Qt Company Ltd.
** Contact: https://www.qt.io/licensing/
**
** This file is part of Qt Creator.
@@ -25,18 +25,23 @@
#pragma once
-#include <coreplugin/dialogs/ioptionspage.h>
+#include <QObject>
-namespace Bazaar {
+namespace ClangCodeModel {
namespace Internal {
+namespace Tests {
-class BazaarSettings;
-
-class OptionsPage final : public Core::IOptionsPage
+class ClangdTests : public QObject
{
-public:
- OptionsPage(const std::function<void()> &onApply, BazaarSettings *settings);
+ Q_OBJECT
+
+private slots:
+ void initTestCase();
+
+ void testFindReferences();
};
+} // namespace Tests
} // namespace Internal
-} // namespace Bazaar
+} // namespace ClangCodeModel
+
diff --git a/src/plugins/clangcodemodel/test/data/clangtestdata.qrc b/src/plugins/clangcodemodel/test/data/clangtestdata.qrc
index d1013a7d29..073e9fa309 100644
--- a/src/plugins/clangcodemodel/test/data/clangtestdata.qrc
+++ b/src/plugins/clangcodemodel/test/data/clangtestdata.qrc
@@ -29,5 +29,8 @@
<file>membercompletion-friend.cpp</file>
<file>functionCompletionFiltered.cpp</file>
<file>functionCompletionFiltered2.cpp</file>
+ <file>find-usages/defs.h</file>
+ <file>find-usages/main.cpp</file>
+ <file>find-usages/find-usages.pro</file>
</qresource>
</RCC>
diff --git a/src/plugins/clangcodemodel/test/data/find-usages/defs.h b/src/plugins/clangcodemodel/test/data/find-usages/defs.h
new file mode 100644
index 0000000000..8480e6f6e5
--- /dev/null
+++ b/src/plugins/clangcodemodel/test/data/find-usages/defs.h
@@ -0,0 +1,28 @@
+struct S {
+ S() : value2(value) {}
+ static int value;
+ int value2 : 2;
+ static const int value3 = 0;
+ static void *p;
+ static const void *p2;
+ struct Nested {
+ int constFunc() const;
+ void constFunc(int) const;
+ void nonConstFunc();
+ } n;
+ Nested constFunc() const;
+ void nonConstFunc();
+ static void staticFunc1() {}
+ static void staticFunc2();
+ virtual void pureVirtual() = 0;
+};
+
+struct S2 : public S {
+ void pureVirtual() override {}
+};
+
+void func1(int &);
+void func2(const int &);
+void func3(int *);
+void func4(const int *);
+void func5(int);
diff --git a/src/plugins/clangcodemodel/test/data/find-usages/find-usages.pro b/src/plugins/clangcodemodel/test/data/find-usages/find-usages.pro
new file mode 100644
index 0000000000..c447485530
--- /dev/null
+++ b/src/plugins/clangcodemodel/test/data/find-usages/find-usages.pro
@@ -0,0 +1,4 @@
+TEMPLATE = app
+QT = core
+HEADERS = defs.h
+SOURCES = main.cpp
diff --git a/src/plugins/clangcodemodel/test/data/find-usages/main.cpp b/src/plugins/clangcodemodel/test/data/find-usages/main.cpp
new file mode 100644
index 0000000000..36941dc473
--- /dev/null
+++ b/src/plugins/clangcodemodel/test/data/find-usages/main.cpp
@@ -0,0 +1,60 @@
+#include "defs.h"
+
+int main()
+{
+ S2 s;
+ auto *p = &s.value;
+ int **pp;
+ p = &s.value;
+ *pp = &s.value;
+ p = &S::value;
+ s.p = &s.value;
+ S::p = &s.value;
+ (&s)->p = &((new S2)->value);
+ const int *p2 = &s.value;
+ s.p2 = &s.value;
+ int * const p3 = &s.value;
+ int &r = s.value;
+ const int &cr = s.value;
+ func1(s.value);
+ func2(s.value);
+ func3(&s.value);
+ func4(&s.value);
+ func5(s.value);
+ *p = 5;
+ func1(*p);
+ func2(*p);
+ func3(p);
+ func4(p);
+ func5(*p);
+ int &r2 = *p;
+ const int &cr2 = *p;
+ s = S2();
+ auto * const ps = &s;
+ const auto *ps2 = &s;
+ auto &pr = s;
+ const auto pr2 = &s;
+ s.constFunc().nonConstFunc();
+ s.nonConstFunc();
+ (&s)->nonConstFunc();
+ s.n.constFunc();
+ s.n.nonConstFunc();
+ s.n.constFunc(s.value);
+ delete s.p;
+ switch (S::value) {
+ case S::value3: break;
+ }
+ switch (S::value = 5) {
+ default: break;
+ }
+ if (S::value) {}
+ if (S::value = 0) {}
+ ++S::value;
+ S::value--;
+ s.staticFunc1();
+ s.staticFunc2();
+ S::value = sizeof S::value;
+ int array[3];
+ array[S::value] = S::value;
+ S::value = array[S::value];
+}
diff --git a/src/plugins/clangformat/clangformatbaseindenter.cpp b/src/plugins/clangformat/clangformatbaseindenter.cpp
index fb8e693809..4a595dd411 100644
--- a/src/plugins/clangformat/clangformatbaseindenter.cpp
+++ b/src/plugins/clangformat/clangformatbaseindenter.cpp
@@ -42,7 +42,11 @@ void adjustFormatStyleForLineBreak(clang::format::FormatStyle &style,
ReplacementsToKeep replacementsToKeep)
{
style.MaxEmptyLinesToKeep = 100;
+#if LLVM_VERSION_MAJOR >= 13
+ style.SortIncludes = clang::format::FormatStyle::SI_Never;
+#else
style.SortIncludes = false;
+#endif
style.SortUsingDeclarations = false;
// This is a separate pass, don't do it unless it's the full formatting.
@@ -246,6 +250,9 @@ int forceIndentWithExtraText(QByteArray &buffer,
const QTextBlock &block,
bool secondTry)
{
+ if (!block.isValid())
+ return 0;
+
const QString blockText = block.text();
int firstNonWhitespace = Utils::indexOf(blockText,
[](const QChar &ch) { return !ch.isSpace(); });
@@ -283,7 +290,16 @@ int forceIndentWithExtraText(QByteArray &buffer,
dummyText = dummyTextForContext(charContext, closingBraceBlock);
}
- buffer.insert(utf8Offset, dummyText);
+ // A comment at the end of the line appears to prevent clang-format from removing line breaks.
+ if (dummyText == "/**/" || dummyText.isEmpty()) {
+ if (block.previous().isValid()) {
+ const int prevEndOffset = Utils::Text::utf8NthLineOffset(block.document(), buffer,
+ block.blockNumber()) + block.previous().text().length();
+ buffer.insert(prevEndOffset, "//");
+ extraLength += 2;
+ }
+ }
+ buffer.insert(utf8Offset + extraLength, dummyText);
extraLength += dummyText.length();
if (secondTry) {
diff --git a/src/plugins/clangformat/clangformatconfigwidget.cpp b/src/plugins/clangformat/clangformatconfigwidget.cpp
index f1fa2c82ce..d50e9b6e32 100644
--- a/src/plugins/clangformat/clangformatconfigwidget.cpp
+++ b/src/plugins/clangformat/clangformatconfigwidget.cpp
@@ -173,8 +173,7 @@ void ClangFormatConfigWidget::initChecksAndPreview()
connect(m_ui->applyButton, &QPushButton::clicked, this, &ClangFormatConfigWidget::apply);
fileName = m_project->projectFilePath().pathAppended("snippet.cpp");
} else {
- fileName = Utils::FilePath::fromString(Core::ICore::userResourcePath())
- .pathAppended("snippet.cpp");
+ fileName = Core::ICore::userResourcePath("snippet.cpp");
}
m_preview->textDocument()->indenter()->setFileName(fileName);
}
@@ -240,10 +239,10 @@ void ClangFormatConfigWidget::showGlobalCheckboxes()
static bool projectConfigExists()
{
- return Utils::FilePath::fromString(Core::ICore::userResourcePath())
+ return Core::ICore::userResourcePath()
.pathAppended("clang-format")
.pathAppended(currentProjectUniqueId())
- .pathAppended((Constants::SETTINGS_FILE_NAME))
+ .pathAppended(Constants::SETTINGS_FILE_NAME)
.exists();
}
@@ -478,7 +477,7 @@ void ClangFormatConfigWidget::apply()
void ClangFormatConfigWidget::saveConfig(const std::string &text) const
{
- QString filePath = Core::ICore::userResourcePath();
+ QString filePath = Core::ICore::userResourcePath().toString();
if (m_project)
filePath += "/clang-format/" + currentProjectUniqueId();
filePath += "/" + QLatin1String(Constants::SETTINGS_FILE_NAME);
diff --git a/src/plugins/clangformat/clangformatutils.cpp b/src/plugins/clangformat/clangformatutils.cpp
index a249327d0e..2f9a306b99 100644
--- a/src/plugins/clangformat/clangformatutils.cpp
+++ b/src/plugins/clangformat/clangformatutils.cpp
@@ -145,7 +145,11 @@ static clang::format::FormatStyle qtcStyle()
style.PenaltyReturnTypeOnItsOwnLine = 300;
style.PointerAlignment = FormatStyle::PAS_Right;
style.ReflowComments = false;
+#if LLVM_VERSION_MAJOR >= 13
+ style.SortIncludes = FormatStyle::SI_CaseSensitive;
+#else
style.SortIncludes = true;
+#endif
style.SortUsingDeclarations = true;
style.SpaceAfterCStyleCast = true;
style.SpaceAfterTemplateKeyword = false;
@@ -158,6 +162,9 @@ static clang::format::FormatStyle qtcStyle()
style.SpacesInCStyleCastParentheses = false;
style.SpacesInParentheses = false;
style.SpacesInSquareBrackets = false;
+ style.StatementMacros.emplace_back("Q_OBJECT");
+ style.StatementMacros.emplace_back("QT_BEGIN_NAMESPACE");
+ style.StatementMacros.emplace_back("QT_END_NAMESPACE");
style.Standard = FormatStyle::LS_Cpp11;
style.TabWidth = 4;
style.UseTab = FormatStyle::UT_Never;
@@ -188,7 +195,7 @@ static bool useProjectOverriddenSettings()
static Utils::FilePath globalPath()
{
- return Utils::FilePath::fromString(Core::ICore::userResourcePath());
+ return Core::ICore::userResourcePath();
}
static Utils::FilePath projectPath()
diff --git a/src/plugins/clangpchmanager/pchmanagerconnectionclient.cpp b/src/plugins/clangpchmanager/pchmanagerconnectionclient.cpp
index 536d80bfb3..324f0e2884 100644
--- a/src/plugins/clangpchmanager/pchmanagerconnectionclient.cpp
+++ b/src/plugins/clangpchmanager/pchmanagerconnectionclient.cpp
@@ -51,13 +51,13 @@ ClangPchManager::PchManagerConnectionClient::PchManagerConnectionClient(
{
m_processCreator.setTemporaryDirectoryPattern("clangpchmanagerbackend-XXXXXX");
- QDir pchsDirectory(Core::ICore::cacheResourcePath());
+ QDir pchsDirectory(Core::ICore::cacheResourcePath().toString());
pchsDirectory.mkdir("pchs");
pchsDirectory.cd("pchs");
m_processCreator.setArguments({connectionName(),
- Core::ICore::cacheResourcePath() + "/symbol-experimental-v1.db",
+ Core::ICore::cacheResourcePath("symbol-experimental-v1.db").toString(),
pchsDirectory.absolutePath(),
- Core::ICore::resourcePath()});
+ Core::ICore::resourcePath().toString()});
stdErrPrefixer().setPrefix("PchManagerConnectionClient.stderr: ");
stdOutPrefixer().setPrefix("PchManagerConnectionClient.stdout: ");
diff --git a/src/plugins/clangrefactoring/refactoringconnectionclient.cpp b/src/plugins/clangrefactoring/refactoringconnectionclient.cpp
index e94e8a311f..d26d20df3f 100644
--- a/src/plugins/clangrefactoring/refactoringconnectionclient.cpp
+++ b/src/plugins/clangrefactoring/refactoringconnectionclient.cpp
@@ -49,8 +49,8 @@ RefactoringConnectionClient::RefactoringConnectionClient(RefactoringClientInterf
{
m_processCreator.setTemporaryDirectoryPattern("clangrefactoringbackend-XXXXXX");
m_processCreator.setArguments({connectionName(),
- Core::ICore::cacheResourcePath() + "/symbol-experimental-v1.db",
- Core::ICore::resourcePath()});
+ Core::ICore::cacheResourcePath("symbol-experimental-v1.db").toString(),
+ Core::ICore::resourcePath().toString()});
stdErrPrefixer().setPrefix("RefactoringConnectionClient.stderr: ");
stdOutPrefixer().setPrefix("RefactoringConnectionClient.stdout: ");
diff --git a/src/plugins/clangrefactoring/refactoringengine.cpp b/src/plugins/clangrefactoring/refactoringengine.cpp
index 1b6c81538d..f376d5806b 100644
--- a/src/plugins/clangrefactoring/refactoringengine.cpp
+++ b/src/plugins/clangrefactoring/refactoringengine.cpp
@@ -132,7 +132,7 @@ void RefactoringEngine::globalFollowSymbol(const CppTools::CursorInEditor &data,
});
- processLinkCallback(Link(usage.path, usage.line, usage.column - 1));
+ processLinkCallback(Link(Utils::FilePath::fromString(usage.path), usage.line, usage.column - 1));
}
bool RefactoringEngine::isRefactoringEngineAvailable() const
diff --git a/src/plugins/clangtools/clangfixitsrefactoringchanges.cpp b/src/plugins/clangtools/clangfixitsrefactoringchanges.cpp
index 98d26069b7..93b248ea1b 100644
--- a/src/plugins/clangtools/clangfixitsrefactoringchanges.cpp
+++ b/src/plugins/clangtools/clangfixitsrefactoringchanges.cpp
@@ -122,7 +122,9 @@ bool FixitsRefactoringFile::apply()
QString error;
for (auto it = m_documents.begin(); it != m_documents.end(); ++it) {
- if (!m_textFileFormat.writeFile(it.key(), it.value()->toPlainText(), &error)) {
+ if (!m_textFileFormat.writeFile(FilePath::fromString(it.key()),
+ it.value()->toPlainText(),
+ &error)) {
qCDebug(fixitsLog) << "ERROR: Could not write file" << it.key() << ":" << error;
return false; // Error writing file
}
@@ -163,10 +165,12 @@ QTextDocument *FixitsRefactoringFile::document(const QString &filePath) const
if (!filePath.isEmpty()) {
QString error;
QTextCodec *defaultCodec = Core::EditorManager::defaultTextCodec();
- TextFileFormat::ReadResult result = TextFileFormat::readFile(
- filePath, defaultCodec,
- &fileContents, &m_textFileFormat,
- &error);
+ TextFileFormat::ReadResult result = TextFileFormat::readFile(FilePath::fromString(
+ filePath),
+ defaultCodec,
+ &fileContents,
+ &m_textFileFormat,
+ &error);
if (result != TextFileFormat::ReadSuccess) {
qCDebug(fixitsLog) << "ERROR: Could not read " << filePath << ":" << error;
m_textFileFormat.codec = nullptr;
diff --git a/src/plugins/clangtools/clangtidyclazyrunner.cpp b/src/plugins/clangtools/clangtidyclazyrunner.cpp
index b8f55e8374..3d3e83115a 100644
--- a/src/plugins/clangtools/clangtidyclazyrunner.cpp
+++ b/src/plugins/clangtools/clangtidyclazyrunner.cpp
@@ -34,8 +34,8 @@
#include <cpptools/compileroptionsbuilder.h>
#include <cpptools/cpptoolsreuse.h>
-#include <utils/synchronousprocess.h>
#include <utils/qtcassert.h>
+#include <utils/qtcprocess.h>
#include <QDebug>
#include <QDir>
diff --git a/src/plugins/clangtools/clangtool.cpp b/src/plugins/clangtools/clangtool.cpp
index 5866103df4..668031da21 100644
--- a/src/plugins/clangtools/clangtool.cpp
+++ b/src/plugins/clangtools/clangtool.cpp
@@ -56,6 +56,7 @@
#include <projectexplorer/projectexplorericons.h>
#include <projectexplorer/session.h>
#include <projectexplorer/target.h>
+#include <projectexplorer/taskhub.h>
#include <texteditor/textdocument.h>
@@ -650,6 +651,8 @@ void ClangTool::startTool(ClangTool::FileSelection fileSelection,
return;
}
+ TaskHub::clearTasks(taskCategory());
+
// Collect files to analyze
const FileInfos fileInfos = collectFileInfos(project, fileSelection);
if (fileInfos.empty())
@@ -726,8 +729,12 @@ FileInfos ClangTool::collectFileInfos(Project *project, FileSelection fileSelect
FileSelectionType *selectionType = get_if<FileSelectionType>(&fileSelection);
// early bailout
if (selectionType && *selectionType == FileSelectionType::CurrentFile
- && !EditorManager::currentDocument())
+ && !EditorManager::currentDocument()) {
+ TaskHub::addTask(Task::Error, tr("Cannot analyze current file: No files open."),
+ taskCategory());
+ TaskHub::requestPopup();
return {};
+ }
auto projectInfo = CppTools::CppModelManager::instance()->projectInfo(project);
QTC_ASSERT(projectInfo.isValid(), return FileInfos());
@@ -757,6 +764,11 @@ FileInfos ClangTool::collectFileInfos(Project *project, FileSelection fileSelect
});
if (!fileInfo.file.isEmpty())
return {fileInfo};
+ TaskHub::addTask(Task::Error,
+ tr("Cannot analyze current file: \"%1\" is not a known source file.")
+ .arg(filePath.toUserOutput()),
+ taskCategory());
+ TaskHub::requestPopup();
}
return {};
diff --git a/src/plugins/clangtools/clangtoolrunner.cpp b/src/plugins/clangtools/clangtoolrunner.cpp
index 38ad6d4eff..6c27ed8aa7 100644
--- a/src/plugins/clangtools/clangtoolrunner.cpp
+++ b/src/plugins/clangtools/clangtoolrunner.cpp
@@ -30,7 +30,6 @@
#include <utils/environment.h>
#include <utils/qtcassert.h>
#include <utils/qtcprocess.h>
-#include <utils/synchronousprocess.h>
#include <utils/temporaryfile.h>
#include <QDebug>
@@ -40,6 +39,8 @@
static Q_LOGGING_CATEGORY(LOG, "qtc.clangtools.runner", QtWarningMsg)
+using namespace Utils;
+
namespace ClangTools {
namespace Internal {
@@ -59,7 +60,7 @@ static QString finishedWithBadExitCode(const QString &name, int exitCode)
}
ClangToolRunner::ClangToolRunner(QObject *parent)
- : QObject(parent), m_process(new QProcess)
+ : QObject(parent), m_process(new Utils::QtcProcess)
{}
ClangToolRunner::~ClangToolRunner()
@@ -70,21 +71,20 @@ ClangToolRunner::~ClangToolRunner()
m_process->kill();
m_process->waitForFinished(100);
} else {
- Utils::SynchronousProcess::stopProcess(*m_process);
+ m_process->stopProcess();
}
}
m_process->deleteLater();
}
-void ClangToolRunner::init(const QString &outputDirPath,
- const Utils::Environment &environment)
+void ClangToolRunner::init(const QString &outputDirPath, const Environment &environment)
{
m_outputDirPath = outputDirPath;
QTC_CHECK(!m_outputDirPath.isEmpty());
m_process->setProcessChannelMode(QProcess::MergedChannels);
- m_process->setProcessEnvironment(environment.toProcessEnvironment());
+ m_process->setEnvironment(environment);
m_process->setWorkingDirectory(m_outputDirPath); // Current clang-cl puts log file into working dir.
connect(m_process, QOverload<int, QProcess::ExitStatus>::of(&QProcess::finished),
this, &ClangToolRunner::onProcessFinished);
@@ -107,10 +107,10 @@ bool ClangToolRunner::supportsVFSOverlay() const
static QMap<QString, bool> vfsCapabilities;
auto it = vfsCapabilities.find(m_executable);
if (it == vfsCapabilities.end()) {
- Utils::SynchronousProcess p;
- Utils::SynchronousProcessResponse response = p.runBlocking(
- Utils::CommandLine(m_executable, {"--help"}));
- it = vfsCapabilities.insert(m_executable, response.allOutput().contains("vfsoverlay"));
+ SynchronousProcess p;
+ p.setCommand({m_executable, {"--help"}});
+ p.runBlocking();
+ it = vfsCapabilities.insert(m_executable, p.allOutput().contains("vfsoverlay"));
}
return it.value();
}
@@ -142,11 +142,11 @@ bool ClangToolRunner::run(const QString &fileToAnalyze, const QStringList &compi
m_outputFilePath = createOutputFilePath(m_outputDirPath, fileToAnalyze);
QTC_ASSERT(!m_outputFilePath.isEmpty(), return false);
- const QStringList arguments = m_argsCreator(compilerOptions);
- m_commandLine = Utils::QtcProcess::joinArgs(QStringList(m_executable) + arguments);
+ m_commandLine = {m_executable, m_argsCreator(compilerOptions)};
- qCDebug(LOG).noquote() << "Starting" << m_commandLine;
- m_process->start(m_executable, arguments);
+ qCDebug(LOG).noquote() << "Starting" << m_commandLine.toUserOutput();
+ m_process->setCommand(m_commandLine);
+ m_process->start();
return true;
}
@@ -154,7 +154,7 @@ void ClangToolRunner::onProcessFinished(int exitCode, QProcess::ExitStatus exitS
{
if (exitStatus == QProcess::NormalExit) {
if (exitCode == 0) {
- qCDebug(LOG).noquote() << "Output:\n" << Utils::SynchronousProcess::normalizeNewlines(
+ qCDebug(LOG).noquote() << "Output:\n" << QtcProcess::normalizeNewlines(
QString::fromLocal8Bit(m_processOutput));
emit finishedWithSuccess(m_fileToAnalyze);
} else {
@@ -184,9 +184,9 @@ QString ClangToolRunner::commandlineAndOutput() const
return tr("Command line: %1\n"
"Process Error: %2\n"
"Output:\n%3")
- .arg(m_commandLine,
+ .arg(m_commandLine.toUserOutput(),
QString::number(m_process->error()),
- Utils::SynchronousProcess::normalizeNewlines(QString::fromLocal8Bit(m_processOutput)));
+ QtcProcess::normalizeNewlines(QString::fromLocal8Bit(m_processOutput)));
}
} // namespace Internal
diff --git a/src/plugins/clangtools/clangtoolrunner.h b/src/plugins/clangtools/clangtoolrunner.h
index 71ddde4be8..d42967da35 100644
--- a/src/plugins/clangtools/clangtoolrunner.h
+++ b/src/plugins/clangtools/clangtoolrunner.h
@@ -27,13 +27,10 @@
#include "clangtoolslogfilereader.h"
-#include <QString>
-#include <QProcess>
+#include <utils/qtcprocess.h>
#include <memory>
-namespace Utils { class Environment; }
-
namespace ClangTools {
namespace Internal {
@@ -83,7 +80,7 @@ private:
private:
QString m_outputDirPath;
- QProcess *m_process = nullptr;
+ Utils::QtcProcess *m_process = nullptr;
QByteArray m_processOutput;
QString m_name;
@@ -93,7 +90,7 @@ private:
QString m_fileToAnalyze;
QString m_outputFilePath;
- QString m_commandLine;
+ Utils::CommandLine m_commandLine;
};
} // namespace Internal
diff --git a/src/plugins/clangtools/clangtoolsdiagnosticview.cpp b/src/plugins/clangtools/clangtoolsdiagnosticview.cpp
index bd1ce09ae9..c73fc7e579 100644
--- a/src/plugins/clangtools/clangtoolsdiagnosticview.cpp
+++ b/src/plugins/clangtools/clangtoolsdiagnosticview.cpp
@@ -48,7 +48,6 @@
#include <QHeaderView>
#include <QPainter>
#include <QSet>
-#include <QUuid>
#include <set>
@@ -241,37 +240,8 @@ void DiagnosticView::suppressCurrentDiagnostic()
void DiagnosticView::disableCheckForCurrentDiagnostic()
{
- ClangToolsSettings * const settings = ClangToolsSettings::instance();
- ClangDiagnosticConfigs configs = settings->diagnosticConfigs();
- Utils::Id activeConfigId = settings->runSettings().diagnosticConfigId();
- ClangToolsProjectSettings::ClangToolsProjectSettingsPtr projectSettings;
- if (ProjectExplorer::Project * const project
- = static_cast<DiagnosticFilterModel *>(model())->project()) {
- projectSettings = ClangToolsProjectSettings::getSettings(project);
- if (!projectSettings->useGlobalSettings())
- activeConfigId = projectSettings->runSettings().diagnosticConfigId();
- }
- ClangDiagnosticConfig config = Utils::findOrDefault(configs,
- [activeConfigId](const ClangDiagnosticConfig &c) { return c.id() == activeConfigId; });
- const bool defaultWasActive = !config.id().isValid();
- if (defaultWasActive) {
- QTC_ASSERT(configs.isEmpty(), return);
- config = builtinConfig();
- config.setIsReadOnly(false);
- config.setId(Utils::Id::fromString(QUuid::createUuid().toString()));
- config.setDisplayName(tr("Custom Configuration"));
- configs << config;
- RunSettings runSettings = settings->runSettings();
- runSettings.setDiagnosticConfigId(config.id());
- settings->setRunSettings(runSettings);
- if (projectSettings && !projectSettings->useGlobalSettings()) {
- runSettings = projectSettings->runSettings();
- runSettings.setDiagnosticConfigId(config.id());
- projectSettings->setRunSettings(runSettings);
- }
- }
-
std::set<QString> handledNames;
+ QList<Diagnostic> diagnostics;
const QModelIndexList indexes = selectionModel()->selectedRows();
for (const QModelIndex &index : indexes) {
const Diagnostic diag = model()->data(index, ClangToolsDiagnosticModel::DiagnosticRole)
@@ -280,34 +250,9 @@ void DiagnosticView::disableCheckForCurrentDiagnostic()
continue;
if (!handledNames.insert(diag.name).second)
continue;
-
- if (diag.name.startsWith("clazy-")) {
- if (config.clazyMode() == ClangDiagnosticConfig::ClazyMode::UseDefaultChecks) {
- config.setClazyMode(ClangDiagnosticConfig::ClazyMode::UseCustomChecks);
- const ClazyStandaloneInfo clazyInfo(clazyStandaloneExecutable());
- config.setClazyChecks(clazyInfo.defaultChecks.join(','));
- }
- config.setClazyChecks(removeClazyCheck(config.clazyChecks(), diag.name));
- } else if (config.clangTidyMode() != ClangDiagnosticConfig::TidyMode::UseConfigFile) {
- if (config.clangTidyMode() == ClangDiagnosticConfig::TidyMode::UseDefaultChecks) {
- config.setClangTidyMode(ClangDiagnosticConfig::TidyMode::UseCustomChecks);
- const ClangTidyInfo tidyInfo(clangTidyExecutable());
- config.setClangTidyChecks(tidyInfo.defaultChecks.join(','));
- }
- config.setClangTidyChecks(removeClangTidyCheck(config.clangTidyChecks(), diag.name));
- }
- }
-
- if (!defaultWasActive) {
- for (ClangDiagnosticConfig &c : configs) {
- if (c.id() == config.id()) {
- c = config;
- break;
- }
- }
+ diagnostics << diag;
}
- settings->setDiagnosticConfigs(configs);
- settings->writeSettings();
+ disableChecks(diagnostics);
}
void DiagnosticView::goNext()
diff --git a/src/plugins/clangtools/clangtoolslogfilereader.cpp b/src/plugins/clangtools/clangtoolslogfilereader.cpp
index 9acfe6c00e..96ec0da16c 100644
--- a/src/plugins/clangtools/clangtoolslogfilereader.cpp
+++ b/src/plugins/clangtools/clangtoolslogfilereader.cpp
@@ -136,7 +136,7 @@ private:
Utils::FileReader reader;
// Do not use QIODevice::Text as we have to deal with byte offsets.
- if (reader.fetch(filePath, QIODevice::ReadOnly))
+ if (reader.fetch(Utils::FilePath::fromString(filePath), QIODevice::ReadOnly))
return reader.data();
return {};
diff --git a/src/plugins/clangtools/clangtoolsplugin.cpp b/src/plugins/clangtools/clangtoolsplugin.cpp
index 9a22ea8b5a..d9c937dadb 100644
--- a/src/plugins/clangtools/clangtoolsplugin.cpp
+++ b/src/plugins/clangtools/clangtoolsplugin.cpp
@@ -60,6 +60,7 @@
#include <projectexplorer/kitinformation.h>
#include <projectexplorer/projectpanelfactory.h>
#include <projectexplorer/target.h>
+#include <projectexplorer/taskhub.h>
#include <QAction>
#include <QDebug>
@@ -114,6 +115,8 @@ bool ClangToolsPlugin::initialize(const QStringList &arguments, QString *errorSt
Q_UNUSED(arguments)
Q_UNUSED(errorString)
+ TaskHub::addCategory(taskCategory(), tr("Clang Tools"));
+
// Import tidy/clazy diagnostic configs from CppTools now
// instead of at opening time of the settings page
ClangToolsSettings::instance();
diff --git a/src/plugins/clangtools/clangtoolsutils.cpp b/src/plugins/clangtools/clangtoolsutils.cpp
index 4a32165786..1e64403b67 100644
--- a/src/plugins/clangtools/clangtoolsutils.cpp
+++ b/src/plugins/clangtools/clangtoolsutils.cpp
@@ -35,11 +35,10 @@
#include <cpptools/cpptoolsreuse.h>
#include <projectexplorer/projectexplorerconstants.h>
-#include <utils/qtcprocess.h>
#include <utils/checkablemessagebox.h>
#include <utils/environment.h>
#include <utils/hostosinfo.h>
-#include <utils/synchronousprocess.h>
+#include <utils/qtcprocess.h>
#include <QFileInfo>
@@ -322,21 +321,12 @@ ClangDiagnosticConfig diagnosticConfig(const Utils::Id &diagConfigId)
return configs.configWithId(diagConfigId);
}
-QStringList splitArgs(QString &argsString)
-{
- QStringList result;
- Utils::QtcProcess::ArgIterator it(&argsString);
- while (it.next())
- result.append(it.value());
- return result;
-}
-
-QStringList extraOptions(const char *envVar)
+static QStringList extraOptions(const char *envVar)
{
if (!qEnvironmentVariableIsSet(envVar))
return QStringList();
- QString arguments = QString::fromLocal8Bit(qgetenv(envVar));
- return splitArgs(arguments);
+ QString arguments = qEnvironmentVariable(envVar);
+ return Utils::ProcessArgs::splitArgs(arguments);
}
QStringList extraClangToolsPrependOptions()
diff --git a/src/plugins/clangtools/clangtoolsutils.h b/src/plugins/clangtools/clangtoolsutils.h
index 7b49dd9e0f..4ee378cdc1 100644
--- a/src/plugins/clangtools/clangtoolsutils.h
+++ b/src/plugins/clangtools/clangtoolsutils.h
@@ -27,6 +27,7 @@
#include <cpptools/clangdiagnosticconfig.h>
+#include <utils/id.h>
#include <utils/optional.h>
#include <QtGlobal>
@@ -87,5 +88,7 @@ CppTools::ClangDiagnosticConfig diagnosticConfig(const Utils::Id &diagConfigId);
QStringList extraClangToolsPrependOptions();
QStringList extraClangToolsAppendOptions();
+inline Utils::Id taskCategory() { return "ClangTools"; }
+
} // namespace Internal
} // namespace ClangTools
diff --git a/src/plugins/clangtools/diagnosticconfigswidget.cpp b/src/plugins/clangtools/diagnosticconfigswidget.cpp
index 1407e8b876..a2c7e420b3 100644
--- a/src/plugins/clangtools/diagnosticconfigswidget.cpp
+++ b/src/plugins/clangtools/diagnosticconfigswidget.cpp
@@ -25,6 +25,9 @@
#include "diagnosticconfigswidget.h"
+#include "clangtoolsdiagnostic.h"
+#include "clangtoolsprojectsettings.h"
+#include "clangtoolssettings.h"
#include "clangtoolsutils.h"
#include "executableinfo.h"
@@ -35,8 +38,10 @@
#include <cpptools/cpptoolsconstants.h>
#include <cpptools/cpptoolsreuse.h>
#include <projectexplorer/selectablefilesmodel.h>
+#include <projectexplorer/session.h>
#include <utils/algorithm.h>
+#include <utils/fileutils.h>
#include <utils/qtcassert.h>
#include <utils/stringutils.h>
@@ -49,6 +54,7 @@
#include <QStringListModel>
#include <QTreeWidget>
#include <QTreeWidgetItem>
+#include <QUuid>
#include <QVBoxLayout>
using namespace CppTools;
@@ -1146,6 +1152,72 @@ QString removeClazyCheck(const QString &checks, const QString &check)
return model.enabledChecks().join(',');
}
+void disableChecks(const QList<Diagnostic> &diagnostics)
+{
+ if (diagnostics.isEmpty())
+ return;
+
+ ClangToolsSettings * const settings = ClangToolsSettings::instance();
+ ClangDiagnosticConfigs configs = settings->diagnosticConfigs();
+ Utils::Id activeConfigId = settings->runSettings().diagnosticConfigId();
+ ClangToolsProjectSettings::ClangToolsProjectSettingsPtr projectSettings;
+
+ if (ProjectExplorer::Project *project = ProjectExplorer::SessionManager
+ ::projectForFile(Utils::FilePath::fromString(diagnostics.first().location.filePath))) {
+ projectSettings = ClangToolsProjectSettings::getSettings(project);
+ if (!projectSettings->useGlobalSettings())
+ activeConfigId = projectSettings->runSettings().diagnosticConfigId();
+ }
+ ClangDiagnosticConfig config = Utils::findOrDefault(configs,
+ [activeConfigId](const ClangDiagnosticConfig &c) { return c.id() == activeConfigId; });
+ const bool defaultWasActive = !config.id().isValid();
+ if (defaultWasActive) {
+ QTC_ASSERT(configs.isEmpty(), return);
+ config = builtinConfig();
+ config.setIsReadOnly(false);
+ config.setId(Utils::Id::fromString(QUuid::createUuid().toString()));
+ config.setDisplayName(QCoreApplication::translate("Clang Tools", "Custom Configuration"));
+ configs << config;
+ RunSettings runSettings = settings->runSettings();
+ runSettings.setDiagnosticConfigId(config.id());
+ settings->setRunSettings(runSettings);
+ if (projectSettings && !projectSettings->useGlobalSettings()) {
+ runSettings = projectSettings->runSettings();
+ runSettings.setDiagnosticConfigId(config.id());
+ projectSettings->setRunSettings(runSettings);
+ }
+ }
+
+ for (const Diagnostic &diag : diagnostics) {
+ if (diag.name.startsWith("clazy-")) {
+ if (config.clazyMode() == ClangDiagnosticConfig::ClazyMode::UseDefaultChecks) {
+ config.setClazyMode(ClangDiagnosticConfig::ClazyMode::UseCustomChecks);
+ const ClazyStandaloneInfo clazyInfo(clazyStandaloneExecutable());
+ config.setClazyChecks(clazyInfo.defaultChecks.join(','));
+ }
+ config.setClazyChecks(removeClazyCheck(config.clazyChecks(), diag.name));
+ } else if (config.clangTidyMode() != ClangDiagnosticConfig::TidyMode::UseConfigFile) {
+ if (config.clangTidyMode() == ClangDiagnosticConfig::TidyMode::UseDefaultChecks) {
+ config.setClangTidyMode(ClangDiagnosticConfig::TidyMode::UseCustomChecks);
+ const ClangTidyInfo tidyInfo(clangTidyExecutable());
+ config.setClangTidyChecks(tidyInfo.defaultChecks.join(','));
+ }
+ config.setClangTidyChecks(removeClangTidyCheck(config.clangTidyChecks(), diag.name));
+ }
+ }
+
+ if (!defaultWasActive) {
+ for (ClangDiagnosticConfig &c : configs) {
+ if (c.id() == config.id()) {
+ c = config;
+ break;
+ }
+ }
+ }
+ settings->setDiagnosticConfigs(configs);
+ settings->writeSettings();
+}
+
} // namespace Internal
} // namespace ClangTools
diff --git a/src/plugins/clangtools/diagnosticconfigswidget.h b/src/plugins/clangtools/diagnosticconfigswidget.h
index fdf961df41..7eb2423901 100644
--- a/src/plugins/clangtools/diagnosticconfigswidget.h
+++ b/src/plugins/clangtools/diagnosticconfigswidget.h
@@ -33,10 +33,12 @@
namespace ClangTools {
namespace Internal {
+class Diagnostic;
// Not UI-related, but requires the tree model (or else a huge refactoring or code duplication).
QString removeClangTidyCheck(const QString &checks, const QString &check);
QString removeClazyCheck(const QString &checks, const QString &check);
+void disableChecks(const QList<Diagnostic> &diagnostics);
namespace Ui {
class ClazyChecks;
diff --git a/src/plugins/clangtools/diagnosticmark.cpp b/src/plugins/clangtools/diagnosticmark.cpp
index f20a13a148..68adec147e 100644
--- a/src/plugins/clangtools/diagnosticmark.cpp
+++ b/src/plugins/clangtools/diagnosticmark.cpp
@@ -27,6 +27,7 @@
#include "clangtoolsconstants.h"
#include "clangtoolsutils.h"
+#include "diagnosticconfigswidget.h"
#include <utils/utilsicons.h>
@@ -68,6 +69,13 @@ DiagnosticMark::DiagnosticMark(const Diagnostic &diagnostic)
});
actions << action;
+ // Disable diagnostic action
+ action = new QAction();
+ action->setIcon(Utils::Icons::BROKEN.icon());
+ action->setToolTip(tr("Disable Diagnostic"));
+ QObject::connect(action, &QAction::triggered, [diagnostic] { disableChecks({diagnostic}); });
+ actions << action;
+
setActions(actions);
}
diff --git a/src/plugins/clangtools/executableinfo.cpp b/src/plugins/clangtools/executableinfo.cpp
index bd5a2b0880..3ac7693577 100644
--- a/src/plugins/clangtools/executableinfo.cpp
+++ b/src/plugins/clangtools/executableinfo.cpp
@@ -29,7 +29,7 @@
#include <coreplugin/messagemanager.h>
#include <utils/environment.h>
-#include <utils/synchronousprocess.h>
+#include <utils/qtcprocess.h>
#include <QDir>
#include <QFileInfo>
@@ -51,20 +51,21 @@ static QString runExecutable(const Utils::CommandLine &commandLine,
return {};
SynchronousProcess cpp;
- Utils::Environment env = Environment::systemEnvironment();
- Environment::setupEnglishOutput(&env);
- cpp.setEnvironment(env.toStringList());
+ Environment env = Environment::systemEnvironment();
+ env.setupEnglishOutput();
+ cpp.setEnvironment(env);
+ cpp.setCommand(commandLine);
- const SynchronousProcessResponse response = cpp.runBlocking(commandLine);
- if (response.result != SynchronousProcessResponse::Finished
+ cpp.runBlocking();
+ if (cpp.result() != QtcProcess::Finished
&& (failSilently == FailSilently::No
- || response.result != SynchronousProcessResponse::FinishedError)) {
- Core::MessageManager::writeFlashing(response.exitMessage(commandLine.toUserOutput(), 10));
- Core::MessageManager::writeFlashing(QString::fromUtf8(response.allRawOutput()));
+ || cpp.result() != QtcProcess::FinishedError)) {
+ Core::MessageManager::writeFlashing(cpp.exitMessage());
+ Core::MessageManager::writeFlashing(QString::fromUtf8(cpp.allRawOutput()));
return {};
}
- return response.stdOut();
+ return cpp.stdOut();
}
static QStringList queryClangTidyChecks(const QString &executable,
diff --git a/src/plugins/clangtools/virtualfilesystemoverlay.cpp b/src/plugins/clangtools/virtualfilesystemoverlay.cpp
index db3e060e89..faf43db05b 100644
--- a/src/plugins/clangtools/virtualfilesystemoverlay.cpp
+++ b/src/plugins/clangtools/virtualfilesystemoverlay.cpp
@@ -69,7 +69,7 @@ void VirtualFileSystemOverlay::update()
.pathAppended(doc->filePath().fileName() + ".auto");
while (saved.path.exists())
saved.path = saved.path + ".1";
- if (!doc->save(&error, saved.path.toString(), true)) {
+ if (!doc->save(&error, saved.path, true)) {
qCDebug(LOG) << error;
continue;
}
diff --git a/src/plugins/classview/classviewnavigationwidgetfactory.cpp b/src/plugins/classview/classviewnavigationwidgetfactory.cpp
index 217fedea9a..cc71dda2f7 100644
--- a/src/plugins/classview/classviewnavigationwidgetfactory.cpp
+++ b/src/plugins/classview/classviewnavigationwidgetfactory.cpp
@@ -57,11 +57,8 @@ NavigationWidgetFactory::NavigationWidgetFactory()
Core::NavigationView NavigationWidgetFactory::createWidget()
{
- Core::NavigationView navigationView;
auto widget = new NavigationWidget();
- navigationView.widget = widget;
- navigationView.dockToolBarWidgets = widget->createToolButtons();
- return navigationView;
+ return {widget, widget->createToolButtons()};
}
diff --git a/src/plugins/clearcase/clearcaseplugin.cpp b/src/plugins/clearcase/clearcaseplugin.cpp
index be4464181c..2654b3fbe5 100644
--- a/src/plugins/clearcase/clearcaseplugin.cpp
+++ b/src/plugins/clearcase/clearcaseplugin.cpp
@@ -60,9 +60,9 @@
#include <utils/infobar.h>
#include <utils/parameteraction.h>
#include <utils/qtcassert.h>
+#include <utils/qtcprocess.h>
#include <utils/runextensions.h>
#include <utils/stringutils.h>
-#include <utils/synchronousprocess.h>
#include <utils/temporarydirectory.h>
#include <vcsbase/basevcseditorfactory.h>
@@ -660,6 +660,7 @@ ClearCasePluginPrivate::ClearCasePluginPrivate()
const QString prefix = QLatin1String("cc");
// register cc prefix in Locator
m_commandLocator = new CommandLocator("cc", description, prefix, this);
+ m_commandLocator->setDescription(tr("Triggers a ClearCase version control operation."));
//register actions
ActionContainer *toolsContainer = ActionManager::actionContainer(M_TOOLS);
@@ -1436,7 +1437,7 @@ void ClearCasePluginPrivate::startCheckIn(const QString &workingDir, const QStri
VcsOutputWindow::appendError(saver.errorString());
return;
}
- m_checkInMessageFileName = saver.fileName();
+ m_checkInMessageFileName = saver.filePath().toString();
m_checkInView = workingDir;
// Create a submit editor and set file list
ClearCaseSubmitEditor *editor = openClearCaseSubmitEditor(m_checkInMessageFileName, m_viewData.isUcm);
@@ -1666,17 +1667,19 @@ ClearCasePluginPrivate::runCleartool(const QString &workingDir,
return response;
}
- const SynchronousProcessResponse sp_resp =
- VcsBase::runVcs(workingDir,
- {executable, arguments},
- timeOutS,
- flags, outputCodec);
+ SynchronousProcess proc;
+ proc.setTimeoutS(timeOutS);
- response.error = sp_resp.result != SynchronousProcessResponse::Finished;
+ VcsCommand command(workingDir, Environment::systemEnvironment());
+ command.addFlags(flags);
+ command.setCodec(outputCodec);
+ command.runCommand(proc, {executable, arguments});
+
+ response.error = proc.result() != QtcProcess::Finished;
if (response.error)
- response.message = sp_resp.exitMessage(executable, timeOutS);
- response.stdErr = sp_resp.stdErr();
- response.stdOut = sp_resp.stdOut();
+ response.message = proc.exitMessage();
+ response.stdErr = proc.stdErr();
+ response.stdOut = proc.stdOut();
return response;
}
@@ -2355,10 +2358,12 @@ QString ClearCasePluginPrivate::runExtDiff(const QString &workingDir, const QStr
process.setTimeoutS(timeOutS);
process.setWorkingDirectory(workingDir);
process.setCodec(outputCodec ? outputCodec : QTextCodec::codecForName("UTF-8"));
- SynchronousProcessResponse response = process.run(diff);
- if (response.result != SynchronousProcessResponse::Finished)
+ process.setCommand(diff);
+ process.setProcessUserEventWhileRunning();
+ process.runBlocking();
+ if (process.result() != QtcProcess::Finished)
return QString();
- return response.allOutput();
+ return process.allOutput();
}
void ClearCasePluginPrivate::syncSlot()
@@ -2600,7 +2605,7 @@ void ClearCasePlugin::testLogResolving()
void ClearCasePlugin::initTestCase()
{
dd->m_tempFile = QDir::currentPath() + QLatin1String("/cc_file.cpp");
- FileSaver srcSaver(dd->m_tempFile);
+ FileSaver srcSaver(Utils::FilePath::fromString(dd->m_tempFile));
srcSaver.write(QByteArray());
srcSaver.finalize();
}
@@ -2692,7 +2697,7 @@ public:
ClearCasePluginPrivate::instance()->setFakeCleartool(true);
VcsManager::clearVersionControlCache();
- FileSaver srcSaver(fileName);
+ FileSaver srcSaver(Utils::FilePath::fromString(fileName));
srcSaver.write(QByteArray());
srcSaver.finalize();
m_editor = EditorManager::openEditor(fileName);
diff --git a/src/plugins/clearcase/clearcasesync.cpp b/src/plugins/clearcase/clearcasesync.cpp
index e6eaca528a..ba678c7021 100644
--- a/src/plugins/clearcase/clearcasesync.cpp
+++ b/src/plugins/clearcase/clearcasesync.cpp
@@ -275,7 +275,7 @@ public:
TempFile(const QString &fileName)
: m_fileName(fileName)
{
- Utils::FileSaver srcSaver(fileName);
+ Utils::FileSaver srcSaver(Utils::FilePath::fromString(fileName));
srcSaver.write(QByteArray());
srcSaver.finalize();
diff --git a/src/plugins/cmakeprojectmanager/CMakeLists.txt b/src/plugins/cmakeprojectmanager/CMakeLists.txt
index d8a7479e3d..259db24cac 100644
--- a/src/plugins/cmakeprojectmanager/CMakeLists.txt
+++ b/src/plugins/cmakeprojectmanager/CMakeLists.txt
@@ -27,7 +27,6 @@ add_qtc_plugin(CMakeProjectManager
cmakeprojectplugin.cpp cmakeprojectplugin.h
cmakesettingspage.cpp cmakesettingspage.h
cmakespecificsettings.cpp cmakespecificsettings.h
- cmakespecificsettingspage.cpp cmakespecificsettingspage.h cmakespecificsettingspage.ui
cmaketool.cpp cmaketool.h
cmaketoolmanager.cpp cmaketoolmanager.h
cmaketoolsettingsaccessor.cpp cmaketoolsettingsaccessor.h
diff --git a/src/plugins/cmakeprojectmanager/builddirparameters.cpp b/src/plugins/cmakeprojectmanager/builddirparameters.cpp
index 005a87cabf..dc71a5eb62 100644
--- a/src/plugins/cmakeprojectmanager/builddirparameters.cpp
+++ b/src/plugins/cmakeprojectmanager/builddirparameters.cpp
@@ -85,8 +85,8 @@ BuildDirParameters::BuildDirParameters(CMakeBuildConfiguration *bc)
environment.set("ICECC", "no");
CMakeSpecificSettings *settings = CMakeProjectPlugin::projectTypeSpecificSettings();
- if (!settings->ninjaPath().isEmpty()) {
- const Utils::FilePath setting = settings->ninjaPath();
+ if (!settings->ninjaPath.filePath().isEmpty()) {
+ const Utils::FilePath setting = settings->ninjaPath.filePath();
const Utils::FilePath path = setting.toFileInfo().isFile() ? setting.parentDir() : setting;
environment.appendOrSetPath(path.toString());
}
diff --git a/src/plugins/cmakeprojectmanager/cmakebuildconfiguration.cpp b/src/plugins/cmakeprojectmanager/cmakebuildconfiguration.cpp
index 95b9f21975..d0c3762a5f 100644
--- a/src/plugins/cmakeprojectmanager/cmakebuildconfiguration.cpp
+++ b/src/plugins/cmakeprojectmanager/cmakebuildconfiguration.cpp
@@ -38,6 +38,7 @@
#include <android/androidconstants.h>
#include <ios/iosconstants.h>
+#include <qnx/qnxconstants.h>
#include <webassembly/webassemblyconstants.h>
#include <coreplugin/find/itemviewfind.h>
@@ -134,7 +135,6 @@ private:
CategorySortFilterModel *m_configTextFilterModel;
ProgressIndicator *m_progressIndicator;
QPushButton *m_addButton;
- QMenu *m_addButtonMenu;
QPushButton *m_editButton;
QPushButton *m_setButton;
QPushButton *m_unsetButton;
@@ -181,29 +181,18 @@ CMakeBuildSettingsWidget::CMakeBuildSettingsWidget(CMakeBuildConfiguration *bc)
auto details = new QWidget(container);
container->setWidget(details);
- auto mainLayout = new QGridLayout(details);
- mainLayout->setContentsMargins(0, 0, 0, 0);
- mainLayout->setColumnStretch(1, 10);
-
- int row = 0;
auto buildDirAspect = bc->buildDirectoryAspect();
connect(buildDirAspect, &BaseAspect::changed, this, [this]() {
m_configModel->flush(); // clear out config cache...;
});
- auto initialCMakeAspect = bc->aspect<InitialCMakeArgumentsAspect>();
- auto aspectWidget = new QWidget;
- LayoutBuilder aspectWidgetBuilder(aspectWidget);
- buildDirAspect->addToLayout(aspectWidgetBuilder);
- aspectWidgetBuilder.finishRow();
- initialCMakeAspect->addToLayout(aspectWidgetBuilder);
- aspectWidgetBuilder.finishRow();
+
auto clearCMakeConfiguration = new QPushButton(tr("Re-configure with Initial Parameters"));
connect(clearCMakeConfiguration, &QPushButton::clicked, this, [bc]() {
auto *settings = CMakeProjectPlugin::projectTypeSpecificSettings();
- bool doNotAsk{!settings->askBeforeReConfigureInitialParams()};
+ bool doNotAsk = !settings->askBeforeReConfigureInitialParams.value();
if (!doNotAsk) {
QDialogButtonBox::StandardButton reply = Utils::CheckableMessageBox::question(
- nullptr,
+ Core::ICore::dialogParent(),
tr("Re-configure with Initial Parameters"),
tr("Clear CMake configuration and configure with initial parameters?"),
tr("Do not ask again"),
@@ -211,8 +200,8 @@ CMakeBuildSettingsWidget::CMakeBuildSettingsWidget(CMakeBuildConfiguration *bc)
QDialogButtonBox::Yes | QDialogButtonBox::No,
QDialogButtonBox::Yes);
- settings->setAskBeforeReConfigureInitialParams(!doNotAsk);
- settings->toSettings(Core::ICore::settings());
+ settings->askBeforeReConfigureInitialParams.setValue(!doNotAsk);
+ settings->writeSettings(Core::ICore::settings());
if (reply != QDialogButtonBox::Yes) {
return;
@@ -224,9 +213,7 @@ CMakeBuildSettingsWidget::CMakeBuildSettingsWidget(CMakeBuildConfiguration *bc)
if (ProjectExplorerPlugin::saveModifiedFiles())
cbc->runCMake();
});
- aspectWidgetBuilder.addItem(LayoutBuilder::LayoutItem(new QLabel("")));
- aspectWidgetBuilder.addItem(LayoutBuilder::LayoutItem(clearCMakeConfiguration));
- aspectWidgetBuilder.finishRow();
+
auto buildTypeAspect = bc->aspect<BuildTypeAspect>();
connect(buildTypeAspect, &BaseAspect::changed, this, [this, buildTypeAspect]() {
if (!m_buildConfiguration->isMultiConfig()) {
@@ -236,37 +223,18 @@ CMakeBuildSettingsWidget::CMakeBuildSettingsWidget(CMakeBuildConfiguration *bc)
m_configModel->setBatchEditConfiguration(config);
}
});
- buildTypeAspect->addToLayout(aspectWidgetBuilder);
- mainLayout->addWidget(aspectWidget, row, 0, 1, -1);
- ++row;
auto qmlDebugAspect = bc->aspect<QtSupport::QmlDebuggingAspect>();
connect(qmlDebugAspect, &QtSupport::QmlDebuggingAspect::changed, this, [this]() {
updateButtonState();
});
- auto widget = new QWidget;
- LayoutBuilder builder(widget);
- qmlDebugAspect->addToLayout(builder);
- mainLayout->addWidget(widget, row, 0, 1, -1);
- ++row;
- mainLayout->addItem(new QSpacerItem(20, 10), row, 0);
-
- ++row;
m_warningMessageLabel = new InfoLabel({}, InfoLabel::Warning);
m_warningMessageLabel->setVisible(false);
- mainLayout->addWidget(m_warningMessageLabel, row, 0, 1, -1, Qt::AlignHCenter);
-
- ++row;
- mainLayout->addItem(new QSpacerItem(20, 10), row, 0);
- ++row;
m_filterEdit = new FancyLineEdit;
m_filterEdit->setPlaceholderText(tr("Filter"));
m_filterEdit->setFiltering(true);
- mainLayout->addWidget(m_filterEdit, row, 0, 1, 2);
-
- ++row;
auto tree = new TreeView;
connect(tree, &TreeView::activated,
tree, [tree](const QModelIndex &idx) { tree->edit(idx); });
@@ -311,60 +279,81 @@ CMakeBuildSettingsWidget::CMakeBuildSettingsWidget(CMakeBuildConfiguration *bc)
m_showProgressTimer.setInterval(50); // don't show progress for < 50ms tasks
connect(&m_showProgressTimer, &QTimer::timeout, [this]() { m_progressIndicator->show(); });
- mainLayout->addWidget(findWrapper, row, 0, 1, 2);
-
- auto buttonLayout = new QVBoxLayout;
m_addButton = new QPushButton(tr("&Add"));
m_addButton->setToolTip(tr("Add a new configuration value."));
- buttonLayout->addWidget(m_addButton);
- {
- m_addButtonMenu = new QMenu(this);
- m_addButtonMenu->addAction(tr("&Boolean"))->setData(
- QVariant::fromValue(static_cast<int>(ConfigModel::DataItem::BOOLEAN)));
- m_addButtonMenu->addAction(tr("&String"))->setData(
- QVariant::fromValue(static_cast<int>(ConfigModel::DataItem::STRING)));
- m_addButtonMenu->addAction(tr("&Directory"))->setData(
- QVariant::fromValue(static_cast<int>(ConfigModel::DataItem::DIRECTORY)));
- m_addButtonMenu->addAction(tr("&File"))->setData(
- QVariant::fromValue(static_cast<int>(ConfigModel::DataItem::FILE)));
- m_addButton->setMenu(m_addButtonMenu);
- }
+ auto addButtonMenu = new QMenu(this);
+ addButtonMenu->addAction(tr("&Boolean"))->setData(
+ QVariant::fromValue(static_cast<int>(ConfigModel::DataItem::BOOLEAN)));
+ addButtonMenu->addAction(tr("&String"))->setData(
+ QVariant::fromValue(static_cast<int>(ConfigModel::DataItem::STRING)));
+ addButtonMenu->addAction(tr("&Directory"))->setData(
+ QVariant::fromValue(static_cast<int>(ConfigModel::DataItem::DIRECTORY)));
+ addButtonMenu->addAction(tr("&File"))->setData(
+ QVariant::fromValue(static_cast<int>(ConfigModel::DataItem::FILE)));
+ m_addButton->setMenu(addButtonMenu);
+
m_editButton = new QPushButton(tr("&Edit"));
m_editButton->setToolTip(tr("Edit the current CMake configuration value."));
- buttonLayout->addWidget(m_editButton);
+
m_setButton = new QPushButton(tr("&Set"));
m_setButton->setToolTip(tr("Set a value in the CMake configuration."));
- buttonLayout->addWidget(m_setButton);
+
m_unsetButton = new QPushButton(tr("&Unset"));
m_unsetButton->setToolTip(tr("Unset a value in the CMake configuration."));
- buttonLayout->addWidget(m_unsetButton);
+
m_resetButton = new QPushButton(tr("&Reset"));
m_resetButton->setToolTip(tr("Reset all unapplied changes."));
m_resetButton->setEnabled(false);
+
m_clearSelectionButton = new QPushButton(tr("Clear Selection"));
m_clearSelectionButton->setToolTip(tr("Clear selection."));
m_clearSelectionButton->setEnabled(false);
- buttonLayout->addWidget(m_clearSelectionButton);
- buttonLayout->addWidget(m_resetButton);
+
m_batchEditButton = new QPushButton(tr("Batch Edit..."));
m_batchEditButton->setToolTip(tr("Set or reset multiple values in the CMake Configuration."));
- buttonLayout->addWidget(m_batchEditButton);
- buttonLayout->addItem(new QSpacerItem(10, 10, QSizePolicy::Fixed, QSizePolicy::Fixed));
- m_showAdvancedCheckBox = new QCheckBox(tr("Advanced"));
- buttonLayout->addWidget(m_showAdvancedCheckBox);
- buttonLayout->addItem(new QSpacerItem(10, 10, QSizePolicy::Minimum, QSizePolicy::Expanding));
- mainLayout->addLayout(buttonLayout, row, 2);
+ m_showAdvancedCheckBox = new QCheckBox(tr("Advanced"));
connect(m_configView->selectionModel(), &QItemSelectionModel::selectionChanged,
this, [this](const QItemSelection &, const QItemSelection &) {
updateSelection();
});
- ++row;
m_reconfigureButton = new QPushButton(tr("Apply Configuration Changes"));
m_reconfigureButton->setEnabled(false);
- mainLayout->addWidget(m_reconfigureButton, row, 0, 1, 3);
+
+ using namespace Layouting;
+ Grid cmakeConfiguration {
+ m_filterEdit, Break(),
+ findWrapper,
+ Column {
+ m_addButton,
+ m_editButton,
+ m_setButton,
+ m_unsetButton,
+ m_clearSelectionButton,
+ m_resetButton,
+ m_batchEditButton,
+ Space(10),
+ m_showAdvancedCheckBox,
+ Stretch()
+ }
+ };
+
+ Column {
+ Form {
+ buildDirAspect,
+ bc->aspect<InitialCMakeArgumentsAspect>(),
+ bc->aspect<BuildTypeAspect>(),
+ QString(), clearCMakeConfiguration,
+ qmlDebugAspect
+ },
+ Space(10),
+ m_warningMessageLabel,
+ Space(10),
+ cmakeConfiguration,
+ m_reconfigureButton,
+ }.attachTo(details, false);
updateAdvancedCheckBox();
setError(bc->error());
@@ -445,7 +434,7 @@ CMakeBuildSettingsWidget::CMakeBuildSettingsWidget(CMakeBuildConfiguration *bc)
connect(m_clearSelectionButton, &QPushButton::clicked, this, [this]() {
m_configView->selectionModel()->clear();
});
- connect(m_addButtonMenu, &QMenu::triggered, this, [this](QAction *action) {
+ connect(addButtonMenu, &QMenu::triggered, this, [this](QAction *action) {
ConfigModel::DataItem::Type type =
static_cast<ConfigModel::DataItem::Type>(action->data().value<int>());
QString value = tr("<UNSET>");
@@ -801,6 +790,11 @@ static bool isWebAssembly(const Kit *k)
return DeviceTypeKitAspect::deviceTypeId(k) == WebAssembly::Constants::WEBASSEMBLY_DEVICE_TYPE;
}
+static bool isQnx(const Kit *k)
+{
+ return DeviceTypeKitAspect::deviceTypeId(k) == Qnx::Constants::QNX_QNX_OS_TYPE;
+}
+
static QStringList defaultInitialCMakeArguments(const Kit *k, const QString buildType)
{
// Generator:
@@ -815,7 +809,7 @@ static QStringList defaultInitialCMakeArguments(const Kit *k, const QString buil
= Internal::CMakeProjectPlugin::projectTypeSpecificSettings();
// Package manager
- if (settings->packageManagerAutoSetup())
+ if (settings->packageManagerAutoSetup.value())
initialArgs.append(QString::fromLatin1("-DCMAKE_PROJECT_INCLUDE_BEFORE:PATH=%1")
.arg("%{IDE:ResourcePath}/package-manager/auto-setup.cmake"));
@@ -975,7 +969,7 @@ CMakeBuildConfiguration::CMakeBuildConfiguration(Target *target, Id id)
}
}
- if (isWebAssembly(k)) {
+ if (isWebAssembly(k) || isQnx(k)) {
const QtSupport::BaseQtVersion *qt = QtSupport::QtKitAspect::qtVersion(k);
if (qt && qt->qtVersion().majorVersion >= 6)
initialArgs.append(CMAKE_QT6_TOOLCHAIN_FILE_ARG);
diff --git a/src/plugins/cmakeprojectmanager/cmakebuildstep.cpp b/src/plugins/cmakeprojectmanager/cmakebuildstep.cpp
index ff4463c700..42015dd72c 100644
--- a/src/plugins/cmakeprojectmanager/cmakebuildstep.cpp
+++ b/src/plugins/cmakeprojectmanager/cmakebuildstep.cpp
@@ -192,7 +192,7 @@ CMakeBuildStep::CMakeBuildStep(BuildStepList *bsl, Utils::Id id) :
setEnvironmentModifier([](Environment &env) {
const QString ninjaProgressString = "[%f/%t "; // ninja: [33/100
- Environment::setupEnglishOutput(&env);
+ env.setupEnglishOutput();
if (!env.expandedValueForKey("NINJA_STATUS").startsWith(ninjaProgressString))
env.set("NINJA_STATUS", ninjaProgressString + "%o/sec] ");
});
@@ -442,8 +442,6 @@ QString CMakeBuildStep::activeRunConfigTarget() const
QWidget *CMakeBuildStep::createConfigWidget()
{
- auto widget = new QWidget;
-
auto updateDetails = [this] {
ProcessParameters param;
setupProcessParameters(&param);
@@ -453,10 +451,6 @@ QWidget *CMakeBuildStep::createConfigWidget()
setDisplayName(tr("Build", "ConfigWidget display name."));
- LayoutBuilder builder(widget);
- builder.addRow(m_cmakeArguments);
- builder.addRow(m_toolArguments);
-
auto buildTargetsView = new QTreeView;
buildTargetsView->setMinimumHeight(200);
buildTargetsView->setModel(&m_buildTargetModel);
@@ -466,7 +460,11 @@ QWidget *CMakeBuildStep::createConfigWidget()
auto frame = ItemViewFind::createSearchableWrapper(buildTargetsView,
ItemViewFind::LightColored);
+ Layouting::Form builder;
+ builder.addRow(m_cmakeArguments);
+ builder.addRow(m_toolArguments);
builder.addRow({new QLabel(tr("Targets:")), frame});
+ auto widget = builder.emerge();
updateDetails();
diff --git a/src/plugins/cmakeprojectmanager/cmakebuildsystem.cpp b/src/plugins/cmakeprojectmanager/cmakebuildsystem.cpp
index 0fe4bfe3b3..8fb3a7b45f 100644
--- a/src/plugins/cmakeprojectmanager/cmakebuildsystem.cpp
+++ b/src/plugins/cmakeprojectmanager/cmakebuildsystem.cpp
@@ -70,16 +70,14 @@
#include <QJsonDocument>
#include <QJsonObject>
#include <QLoggingCategory>
-#include <QPushButton>
-#include <QRegularExpression>
using namespace ProjectExplorer;
using namespace Utils;
-namespace {
+namespace CMakeProjectManager {
+namespace Internal {
-void copySourcePathsToClipboard(const QStringList &srcPaths,
- const ProjectExplorer::ProjectNode *node)
+static void copySourcePathsToClipboard(QStringList srcPaths, const ProjectNode *node)
{
QClipboard *clip = QGuiApplication::clipboard();
@@ -90,7 +88,7 @@ void copySourcePathsToClipboard(const QStringList &srcPaths,
clip->setText(data);
}
-void noAutoAdditionNotify(const QStringList &filePaths, const ProjectExplorer::ProjectNode *node)
+static void noAutoAdditionNotify(const QStringList &filePaths, const ProjectNode *node)
{
const QStringList srcPaths = Utils::filtered(filePaths, [](const QString& file) {
const auto mimeType = Utils::mimeTypeForFile(file).name();
@@ -104,13 +102,12 @@ void noAutoAdditionNotify(const QStringList &filePaths, const ProjectExplorer::P
});
if (!srcPaths.empty()) {
- CMakeProjectManager::Internal::CMakeSpecificSettings *settings
- = CMakeProjectManager::Internal::CMakeProjectPlugin::projectTypeSpecificSettings();
- switch (settings->afterAddFileSetting()) {
- case CMakeProjectManager::Internal::ASK_USER: {
+ CMakeSpecificSettings *settings = CMakeProjectPlugin::projectTypeSpecificSettings();
+ switch (settings->afterAddFileSetting.value()) {
+ case AskUser: {
bool checkValue{false};
- QDialogButtonBox::StandardButton reply = Utils::CheckableMessageBox::question(
- nullptr,
+ QDialogButtonBox::StandardButton reply = CheckableMessageBox::question(
+ Core::ICore::dialogParent(),
QMessageBox::tr("Copy to Clipboard?"),
QMessageBox::tr("Files are not automatically added to the "
"CMakeLists.txt file of the CMake project."
@@ -121,37 +118,30 @@ void noAutoAdditionNotify(const QStringList &filePaths, const ProjectExplorer::P
QDialogButtonBox::Yes);
if (checkValue) {
if (QDialogButtonBox::Yes == reply)
- settings->setAfterAddFileSetting(
- CMakeProjectManager::Internal::AfterAddFileAction::COPY_FILE_PATH);
+ settings->afterAddFileSetting.setValue(CopyFilePath);
else if (QDialogButtonBox::No == reply)
- settings->setAfterAddFileSetting(
- CMakeProjectManager::Internal::AfterAddFileAction::NEVER_COPY_FILE_PATH);
+ settings->afterAddFileSetting.setValue(NeverCopyFilePath);
- settings->toSettings(Core::ICore::settings());
+ settings->writeSettings(Core::ICore::settings());
}
- if (QDialogButtonBox::Yes == reply) {
+ if (QDialogButtonBox::Yes == reply)
copySourcePathsToClipboard(srcPaths, node);
- }
+
break;
}
- case CMakeProjectManager::Internal::COPY_FILE_PATH: {
+ case CopyFilePath: {
copySourcePathsToClipboard(srcPaths, node);
break;
}
- case CMakeProjectManager::Internal::NEVER_COPY_FILE_PATH:
+ case NeverCopyFilePath:
break;
}
}
}
-} // namespace
-
-namespace CMakeProjectManager {
-namespace Internal {
-
static Q_LOGGING_CATEGORY(cmakeBuildSystemLog, "qtc.cmake.buildsystem", QtWarningMsg);
// --------------------------------------------------------------------
@@ -185,7 +175,7 @@ CMakeBuildSystem::CMakeBuildSystem(CMakeBuildConfiguration *bc)
return isIgnored;
});
- m_treeScanner.setTypeFactory([](const Utils::MimeType &mimeType, const Utils::FilePath &fn) {
+ m_treeScanner.setTypeFactory([](const MimeType &mimeType, const FilePath &fn) {
auto type = TreeScanner::genericFileType(mimeType, fn);
if (type == FileType::Unknown) {
if (mimeType.isValid()) {
@@ -382,7 +372,7 @@ QString CMakeBuildSystem::reparseParametersString(int reparseFlags)
void CMakeBuildSystem::writeConfigurationIntoBuildDirectory()
{
- const Utils::MacroExpander *expander = cmakeBuildConfiguration()->macroExpander();
+ const MacroExpander *expander = cmakeBuildConfiguration()->macroExpander();
const FilePath buildDir = workDirectory(m_parameters);
QTC_ASSERT(buildDir.exists(), return );
@@ -556,7 +546,7 @@ void CMakeBuildSystem::clearCMakeCache()
for (const FilePath &path : pathsToDelete) {
if (path.exists())
- Utils::FileUtils::removeRecursively(path);
+ FileUtils::removeRecursively(path);
}
}
@@ -614,7 +604,7 @@ void CMakeBuildSystem::updateProjectData()
QSet<QString> res;
QStringList apps;
for (const auto &target : qAsConst(m_buildTargets)) {
- if (target.targetType == CMakeProjectManager::DynamicLibraryType) {
+ if (target.targetType == DynamicLibraryType) {
res.insert(target.executable.parentDir().toString());
apps.push_back(target.executable.toUserOutput());
}
@@ -668,13 +658,13 @@ void CMakeBuildSystem::updateProjectData()
QtSupport::CppKitInfo kitInfo(kit());
QTC_ASSERT(kitInfo.isValid(), return );
- {
- QString errorMessage;
- RawProjectParts rpps = m_reader.createRawProjectParts(errorMessage);
- if (!errorMessage.isEmpty())
- cmakeBuildConfiguration()->setError(errorMessage);
- qCDebug(cmakeBuildSystemLog) << "Raw project parts created." << errorMessage;
+ QString errorMessage;
+ RawProjectParts rpps = m_reader.createRawProjectParts(errorMessage);
+ if (!errorMessage.isEmpty())
+ cmakeBuildConfiguration()->setError(errorMessage);
+ qCDebug(cmakeBuildSystemLog) << "Raw project parts created." << errorMessage;
+ {
for (RawProjectPart &rpp : rpps) {
rpp.setQtVersion(
kitInfo.projectPartQtVersion); // TODO: Check if project actually uses Qt.
@@ -692,7 +682,33 @@ void CMakeBuildSystem::updateProjectData()
m_cppCodeModelUpdater->update({p, kitInfo, cmakeBuildConfiguration()->environment(), rpps});
}
{
- updateQmlJSCodeModel();
+ const bool mergedHeaderPathsAndQmlImportPaths = kit()->value(
+ QtSupport::KitHasMergedHeaderPathsWithQmlImportPaths::id(), false).toBool();
+ QStringList extraHeaderPaths;
+ QList<QByteArray> moduleMappings;
+ for (const RawProjectPart &rpp : qAsConst(rpps)) {
+ FilePath moduleMapFile = cmakeBuildConfiguration()->buildDirectory()
+ .pathAppended("/qml_module_mappings/" + rpp.buildSystemTarget);
+ if (moduleMapFile.exists()) {
+ QFile mmf(moduleMapFile.toString());
+ if (mmf.open(QFile::ReadOnly)) {
+ QByteArray content = mmf.readAll();
+ auto lines = content.split('\n');
+ for (const auto &line : lines) {
+ if (!line.isEmpty())
+ moduleMappings.append(line.simplified());
+ }
+ }
+ }
+
+ if (mergedHeaderPathsAndQmlImportPaths) {
+ for (const auto &headerPath : rpp.headerPaths) {
+ if (headerPath.type == HeaderPathType::User)
+ extraHeaderPaths.append(headerPath.path);
+ }
+ }
+ }
+ updateQmlJSCodeModel(extraHeaderPaths, moduleMappings);
}
emit cmakeBuildConfiguration()->buildTypeChanged();
@@ -868,7 +884,7 @@ void CMakeBuildSystem::wireUpConnections()
FilePath CMakeBuildSystem::workDirectory(const BuildDirParameters &parameters)
{
- const Utils::FilePath bdir = parameters.buildDirectory;
+ const FilePath bdir = parameters.buildDirectory;
const CMakeTool *cmake = parameters.cmakeTool();
// use the build directory if it already exists anyhow
@@ -889,7 +905,7 @@ FilePath CMakeBuildSystem::workDirectory(const BuildDirParameters &parameters)
auto tmpDirIt = m_buildDirToTempDir.find(bdir);
if (tmpDirIt == m_buildDirToTempDir.end()) {
auto ret = m_buildDirToTempDir.emplace(
- std::make_pair(bdir, std::make_unique<Utils::TemporaryDirectory>("qtc-cmake-XXXXXXXX")));
+ std::make_pair(bdir, std::make_unique<TemporaryDirectory>("qtc-cmake-XXXXXXXX")));
QTC_ASSERT(ret.second, return bdir);
tmpDirIt = ret.first;
@@ -899,7 +915,7 @@ FilePath CMakeBuildSystem::workDirectory(const BuildDirParameters &parameters)
return bdir;
}
}
- return Utils::FilePath::fromString(tmpDirIt->second->path());
+ return FilePath::fromString(tmpDirIt->second->path());
}
void CMakeBuildSystem::stopParsingAndClearState()
@@ -978,7 +994,9 @@ void CMakeBuildSystem::runCTest()
const QJsonArray cmakelists = btGraph.value("files").toArray();
const QJsonArray nodes = btGraph.value("nodes").toArray();
const QJsonArray tests = jsonObj.value("tests").toArray();
+ int counter = 0;
for (const QJsonValue &testVal : tests) {
+ ++counter;
const QJsonObject test = testVal.toObject();
QTC_ASSERT(!test.isEmpty(), continue);
const int bt = test.value("backtrace").toInt(-1);
@@ -987,7 +1005,7 @@ void CMakeBuildSystem::runCTest()
int file = btRef.value("file").toInt(-1);
int line = btRef.value("line").toInt(-1);
QTC_ASSERT(file != -1 && line != -1, continue);
- m_testNames.append({ test.value("name").toString(),
+ m_testNames.append({ test.value("name").toString(), counter,
FilePath::fromString(cmakelists.at(file).toString()), line });
}
}
@@ -1098,14 +1116,17 @@ CommandLine CMakeBuildSystem::commandLineForTests(const QList<QString> &tests,
const QStringList &options) const
{
QStringList args = options;
+ const QSet<QString> testsSet = Utils::toSet(tests);
auto current = Utils::transform<QSet<QString>>(m_testNames, &TestCaseInfo::name);
- if (tests.isEmpty() || current == Utils::toSet(tests))
+ if (tests.isEmpty() || current == testsSet)
return {m_ctestPath, args};
- const QString regex = Utils::transform(tests, [](const QString &current) {
- return QRegularExpression::escape(current);
- }).join('|');
- args << "-R" << QString('(' + regex + ')');
+ QString testNumbers("0,0,0"); // start, end, stride
+ for (const TestCaseInfo &info : m_testNames) {
+ if (testsSet.contains(info.name))
+ testNumbers += QString(",%1").arg(info.number);
+ }
+ args << "-I" << testNumbers;
return {m_ctestPath, args};
}
@@ -1143,11 +1164,11 @@ DeploymentData CMakeBuildSystem::deploymentData() const
return result;
}
-QList<ProjectExplorer::ExtraCompiler *> CMakeBuildSystem::findExtraCompilers()
+QList<ExtraCompiler *> CMakeBuildSystem::findExtraCompilers()
{
qCDebug(cmakeBuildSystemLog) << "Finding Extra Compilers: start.";
- QList<ProjectExplorer::ExtraCompiler *> extraCompilers;
+ QList<ExtraCompiler *> extraCompilers;
const QList<ExtraCompilerFactory *> factories = ExtraCompilerFactory::extraCompilerFactories();
qCDebug(cmakeBuildSystemLog) << "Finding Extra Compilers: Got factories.";
@@ -1200,7 +1221,8 @@ QList<ProjectExplorer::ExtraCompiler *> CMakeBuildSystem::findExtraCompilers()
return extraCompilers;
}
-void CMakeBuildSystem::updateQmlJSCodeModel()
+void CMakeBuildSystem::updateQmlJSCodeModel(const QStringList &extraHeaderPaths,
+ const QList<QByteArray> &moduleMappings)
{
QmlJS::ModelManagerInterface *modelManager = QmlJS::ModelManagerInterface::instance();
@@ -1213,11 +1235,37 @@ void CMakeBuildSystem::updateQmlJSCodeModel()
projectInfo.importPaths.clear();
+ auto addImports = [&projectInfo](const QString &imports) {
+ foreach (const QString &import, CMakeConfigItem::cmakeSplitValue(imports))
+ projectInfo.importPaths.maybeInsert(FilePath::fromString(import), QmlJS::Dialect::Qml);
+ };
+
const CMakeConfig &cm = cmakeBuildConfiguration()->configurationFromCMake();
const QString cmakeImports = QString::fromUtf8(CMakeConfigItem::valueOf("QML_IMPORT_PATH", cm));
+ addImports(cmakeImports);
+ addImports(kit()->value(QtSupport::KitQmlImportPath::id()).toString());
+
+ for (const QString &extraHeaderPath : extraHeaderPaths)
+ projectInfo.importPaths.maybeInsert(FilePath::fromString(extraHeaderPath),
+ QmlJS::Dialect::Qml);
- foreach (const QString &cmakeImport, CMakeConfigItem::cmakeSplitValue(cmakeImports))
- projectInfo.importPaths.maybeInsert(FilePath::fromString(cmakeImport), QmlJS::Dialect::Qml);
+ for (const QByteArray &mm : moduleMappings) {
+ auto kvPair = mm.split('=');
+ if (kvPair.size() != 2)
+ continue;
+ QString from = QString::fromUtf8(kvPair.at(0).trimmed());
+ QString to = QString::fromUtf8(kvPair.at(1).trimmed());
+ if (!from.isEmpty() && !to.isEmpty() && from != to) {
+ // The QML code-model does not support sub-projects, so if there are multiple mappings for a single module,
+ // choose the shortest one.
+ if (projectInfo.moduleMappings.contains(from)) {
+ if (to.size() < projectInfo.moduleMappings.value(from).size())
+ projectInfo.moduleMappings.insert(from, to);
+ } else {
+ projectInfo.moduleMappings.insert(from, to);
+ }
+ }
+ }
project()->setProjectLanguage(ProjectExplorer::Constants::QMLJS_LANGUAGE_ID,
!projectInfo.sourceFiles.isEmpty());
diff --git a/src/plugins/cmakeprojectmanager/cmakebuildsystem.h b/src/plugins/cmakeprojectmanager/cmakebuildsystem.h
index 3b591c1581..39e849830e 100644
--- a/src/plugins/cmakeprojectmanager/cmakebuildsystem.h
+++ b/src/plugins/cmakeprojectmanager/cmakebuildsystem.h
@@ -33,10 +33,9 @@
#include <projectexplorer/buildsystem.h>
#include <utils/fileutils.h>
+#include <utils/futuresynchronizer.h>
#include <utils/temporarydirectory.h>
-#include <QFutureSynchronizer>
-
namespace ProjectExplorer { class ExtraCompiler; }
namespace CppTools {
@@ -142,7 +141,8 @@ private:
void updateProjectData();
void updateFallbackProjectData();
QList<ProjectExplorer::ExtraCompiler *> findExtraCompilers();
- void updateQmlJSCodeModel();
+ void updateQmlJSCodeModel(const QStringList &extraHeaderPaths,
+ const QList<QByteArray> &moduleMappings);
void handleParsingSucceeded();
void handleParsingFailed(const QString &msg);
@@ -185,7 +185,7 @@ private:
// CTest integration
QString m_ctestPath;
QList<ProjectExplorer::TestCaseInfo> m_testNames;
- QFutureSynchronizer<QByteArray> m_futureSynchronizer;
+ Utils::FutureSynchronizer m_futureSynchronizer;
};
} // namespace Internal
diff --git a/src/plugins/cmakeprojectmanager/cmakeeditor.cpp b/src/plugins/cmakeprojectmanager/cmakeeditor.cpp
index 6948eedf00..1ec3414b2d 100644
--- a/src/plugins/cmakeprojectmanager/cmakeeditor.cpp
+++ b/src/plugins/cmakeprojectmanager/cmakeeditor.cpp
@@ -119,11 +119,36 @@ void CMakeEditorWidget::contextMenuEvent(QContextMenuEvent *e)
showDefaultContextMenu(e, Constants::M_CONTEXT);
}
-static bool isValidFileNameChar(const QChar &c)
+static bool mustBeQuotedInFileName(const QChar &c)
{
- return c.isLetterOrNumber() || c == QLatin1Char('.') || c == QLatin1Char('_')
- || c == QLatin1Char('-') || c == QLatin1Char('/') || c == QLatin1Char('\\') || c == '{'
- || c == '}' || c == '$';
+ return c.isSpace() || c == '"' || c == '(' || c == ')';
+}
+
+static bool isValidFileNameChar(const QString &block, int pos)
+{
+ const QChar c = block.at(pos);
+ return !mustBeQuotedInFileName(c) || (pos > 0 && block.at(pos - 1) == '\\');
+}
+
+static QString unescape(const QString &s)
+{
+ QString result;
+ int i = 0;
+ const int size = s.size();
+ while (i < size) {
+ const QChar c = s.at(i);
+ if (c == '\\' && i < size - 1) {
+ const QChar nc = s.at(i + 1);
+ if (mustBeQuotedInFileName(nc)) {
+ result += nc;
+ i += 2;
+ continue;
+ }
+ }
+ result += c;
+ ++i;
+ }
+ return result;
}
void CMakeEditorWidget::findLinkAt(const QTextCursor &cursor,
@@ -149,9 +174,8 @@ void CMakeEditorWidget::findLinkAt(const QTextCursor &cursor,
QString buffer;
int beginPos = positionInBlock - 1;
while (beginPos >= 0) {
- QChar c = block.at(beginPos);
- if (isValidFileNameChar(c)) {
- buffer.prepend(c);
+ if (isValidFileNameChar(block, beginPos)) {
+ buffer.prepend(block.at(beginPos));
beginPos--;
} else {
break;
@@ -161,9 +185,8 @@ void CMakeEditorWidget::findLinkAt(const QTextCursor &cursor,
// find the end of a filename
int endPos = positionInBlock;
while (endPos < block.count()) {
- QChar c = block.at(endPos);
- if (isValidFileNameChar(c)) {
- buffer.append(c);
+ if (isValidFileNameChar(block, endPos)) {
+ buffer.append(block.at(endPos));
endPos++;
} else {
break;
@@ -176,10 +199,9 @@ void CMakeEditorWidget::findLinkAt(const QTextCursor &cursor,
QDir dir(textDocument()->filePath().toFileInfo().absolutePath());
buffer.replace("${CMAKE_CURRENT_SOURCE_DIR}", dir.path());
buffer.replace("${CMAKE_CURRENT_LIST_DIR}", dir.path());
-
// TODO: Resolve more variables
- QString fileName = dir.filePath(buffer);
+ QString fileName = dir.filePath(unescape(buffer));
QFileInfo fi(fileName);
if (fi.exists()) {
if (fi.isDir()) {
@@ -190,7 +212,7 @@ void CMakeEditorWidget::findLinkAt(const QTextCursor &cursor,
else
return processLinkCallback(link);
}
- link.targetFileName = fileName;
+ link.targetFilePath = Utils::FilePath::fromString(fileName);
link.linkTextStart = cursor.position() - positionInBlock + beginPos + 1;
link.linkTextEnd = cursor.position() - positionInBlock + endPos;
}
diff --git a/src/plugins/cmakeprojectmanager/cmakekitinformation.cpp b/src/plugins/cmakeprojectmanager/cmakekitinformation.cpp
index 1a338af1a3..e8cc867ae9 100644
--- a/src/plugins/cmakeprojectmanager/cmakekitinformation.cpp
+++ b/src/plugins/cmakeprojectmanager/cmakekitinformation.cpp
@@ -31,22 +31,26 @@
#include "cmaketool.h"
#include "cmaketoolmanager.h"
+#include <app/app_version.h>
+
#include <coreplugin/icore.h>
+
#include <ios/iosconstants.h>
+
#include <projectexplorer/kitinformation.h>
#include <projectexplorer/projectexplorer.h>
#include <projectexplorer/projectexplorerconstants.h>
#include <projectexplorer/projectexplorersettings.h>
#include <projectexplorer/task.h>
#include <projectexplorer/toolchain.h>
+
#include <qtsupport/baseqtversion.h>
#include <qtsupport/qtkitinformation.h>
-#include <app/app_version.h>
-
#include <utils/algorithm.h>
#include <utils/elidinglabel.h>
#include <utils/environment.h>
+#include <utils/layoutbuilder.h>
#include <utils/macroexpander.h>
#include <utils/qtcassert.h>
#include <utils/variablechooser.h>
@@ -87,8 +91,8 @@ class CMakeKitAspectWidget final : public KitAspectWidget
Q_DECLARE_TR_FUNCTIONS(CMakeProjectManager::Internal::CMakeKitAspect)
public:
CMakeKitAspectWidget(Kit *kit, const KitAspect *ki) : KitAspectWidget(kit, ki),
- m_comboBox(new QComboBox),
- m_manageButton(new QPushButton(KitAspectWidget::msgManage()))
+ m_comboBox(createSubWidget<QComboBox>()),
+ m_manageButton(createManageButton(Constants::CMAKE_SETTINGS_PAGE_ID))
{
m_comboBox->setSizePolicy(QSizePolicy::Ignored, m_comboBox->sizePolicy().verticalPolicy());
m_comboBox->setEnabled(false);
@@ -102,10 +106,6 @@ public:
connect(m_comboBox, QOverload<int>::of(&QComboBox::currentIndexChanged),
this, &CMakeKitAspectWidget::currentCMakeToolChanged);
- m_manageButton->setContentsMargins(0, 0, 0, 0);
- connect(m_manageButton, &QPushButton::clicked,
- this, &CMakeKitAspectWidget::manageCMakeTools);
-
CMakeToolManager *cmakeMgr = CMakeToolManager::instance();
connect(cmakeMgr, &CMakeToolManager::cmakeAdded,
this, &CMakeKitAspectWidget::cmakeToolAdded);
@@ -124,8 +124,13 @@ public:
private:
// KitAspectWidget interface
void makeReadOnly() override { m_comboBox->setEnabled(false); }
- QWidget *mainWidget() const override { return m_comboBox; }
- QWidget *buttonWidget() const override { return m_manageButton; }
+
+ void addToLayout(Utils::LayoutBuilder &builder) override
+ {
+ addMutableAction(m_comboBox);
+ builder.addItem(m_comboBox);
+ builder.addItem(m_manageButton);
+ }
void refresh() override
{
@@ -203,14 +208,9 @@ private:
CMakeKitAspect::setCMakeTool(m_kit, id);
}
- void manageCMakeTools()
- {
- Core::ICore::showOptionsDialog(Constants::CMAKE_SETTINGS_PAGE_ID, buttonWidget());
- }
-
bool m_removingItem = false;
QComboBox *m_comboBox;
- QPushButton *m_manageButton;
+ QWidget *m_manageButton;
};
CMakeKitAspect::CMakeKitAspect()
@@ -334,8 +334,8 @@ class CMakeGeneratorKitAspectWidget final : public KitAspectWidget
public:
CMakeGeneratorKitAspectWidget(Kit *kit, const ::KitAspect *ki)
: KitAspectWidget(kit, ki),
- m_label(new Utils::ElidingLabel),
- m_changeButton(new QPushButton)
+ m_label(createSubWidget<Utils::ElidingLabel>()),
+ m_changeButton(createSubWidget<QPushButton>())
{
m_label->setToolTip(ki->description());
m_changeButton->setText(tr("Change..."));
@@ -353,8 +353,13 @@ public:
private:
// KitAspectWidget interface
void makeReadOnly() override { m_changeButton->setEnabled(false); }
- QWidget *mainWidget() const override { return m_label; }
- QWidget *buttonWidget() const override { return m_changeButton; }
+
+ void addToLayout(Utils::LayoutBuilder &builder) override
+ {
+ addMutableAction(m_label);
+ builder.addItem(m_label);
+ builder.addItem(m_changeButton);
+ }
void refresh() override
{
@@ -655,9 +660,8 @@ QVariant CMakeGeneratorKitAspect::defaultValue(const Kit *k) const
Internal::CMakeSpecificSettings *settings
= Internal::CMakeProjectPlugin::projectTypeSpecificSettings();
- if (settings->ninjaPath().isEmpty()) {
- Utils::Environment env = Utils::Environment::systemEnvironment();
- k->addToEnvironment(env);
+ if (settings->ninjaPath.filePath().isEmpty()) {
+ Utils::Environment env = k->buildEnvironment();
return !env.searchInPath("ninja").isEmpty();
}
return true;
@@ -824,13 +828,14 @@ KitAspectWidget *CMakeGeneratorKitAspect::createConfigWidget(Kit *k) const
return new CMakeGeneratorKitAspectWidget(k, this);
}
-void CMakeGeneratorKitAspect::addToEnvironment(const Kit *k, Utils::Environment &env) const
+void CMakeGeneratorKitAspect::addToBuildEnvironment(const Kit *k, Utils::Environment &env) const
{
GeneratorInfo info = generatorInfo(k);
if (info.generator == "NMake Makefiles JOM") {
if (env.searchInPath("jom.exe").exists())
return;
- env.appendOrSetPath(QCoreApplication::applicationDirPath());
+ env.appendOrSetPath(Core::ICore::libexecPath().toUserOutput());
+ env.appendOrSetPath(Core::ICore::libexecPath("jom").toUserOutput());
}
}
@@ -851,8 +856,8 @@ class CMakeConfigurationKitAspectWidget final : public KitAspectWidget
public:
CMakeConfigurationKitAspectWidget(Kit *kit, const KitAspect *ki)
: KitAspectWidget(kit, ki),
- m_summaryLabel(new Utils::ElidingLabel),
- m_manageButton(new QPushButton)
+ m_summaryLabel(createSubWidget<Utils::ElidingLabel>()),
+ m_manageButton(createSubWidget<QPushButton>())
{
refresh();
m_manageButton->setText(tr("Change..."));
@@ -862,8 +867,12 @@ public:
private:
// KitAspectWidget interface
- QWidget *mainWidget() const override { return m_summaryLabel; }
- QWidget *buttonWidget() const override { return m_manageButton; }
+ void addToLayout(Utils::LayoutBuilder &builder) override
+ {
+ addMutableAction(m_summaryLabel);
+ builder.addItem(m_summaryLabel);
+ builder.addItem(m_manageButton);
+ }
void makeReadOnly() override
{
diff --git a/src/plugins/cmakeprojectmanager/cmakekitinformation.h b/src/plugins/cmakeprojectmanager/cmakekitinformation.h
index 5d3456892d..5745ae525f 100644
--- a/src/plugins/cmakeprojectmanager/cmakekitinformation.h
+++ b/src/plugins/cmakeprojectmanager/cmakekitinformation.h
@@ -86,7 +86,7 @@ public:
void upgrade(ProjectExplorer::Kit *k) final;
ItemList toUserOutput(const ProjectExplorer::Kit *k) const final;
ProjectExplorer::KitAspectWidget *createConfigWidget(ProjectExplorer::Kit *k) const final;
- void addToEnvironment(const ProjectExplorer::Kit *k, Utils::Environment &env) const final;
+ void addToBuildEnvironment(const ProjectExplorer::Kit *k, Utils::Environment &env) const final;
private:
QVariant defaultValue(const ProjectExplorer::Kit *k) const;
diff --git a/src/plugins/cmakeprojectmanager/cmakelocatorfilter.cpp b/src/plugins/cmakeprojectmanager/cmakelocatorfilter.cpp
index 65ee922918..d9cf133fea 100644
--- a/src/plugins/cmakeprojectmanager/cmakelocatorfilter.cpp
+++ b/src/plugins/cmakeprojectmanager/cmakelocatorfilter.cpp
@@ -116,6 +116,7 @@ BuildCMakeTargetLocatorFilter::BuildCMakeTargetLocatorFilter()
{
setId("Build CMake target");
setDisplayName(tr("Build CMake target"));
+ setDescription(tr("Builds a target of any open CMake project."));
setDefaultShortcutString("cm");
setPriority(High);
}
@@ -165,6 +166,7 @@ OpenCMakeTargetLocatorFilter::OpenCMakeTargetLocatorFilter()
{
setId("Open CMake target definition");
setDisplayName(tr("Open CMake target"));
+ setDescription(tr("Jumps to the definition of a target of any open CMake project."));
setDefaultShortcutString("cmo");
setPriority(Medium);
}
diff --git a/src/plugins/cmakeprojectmanager/cmakeprocess.cpp b/src/plugins/cmakeprojectmanager/cmakeprocess.cpp
index 8a4615a90e..e4daea6845 100644
--- a/src/plugins/cmakeprojectmanager/cmakeprocess.cpp
+++ b/src/plugins/cmakeprojectmanager/cmakeprocess.cpp
@@ -35,8 +35,6 @@
#include <utils/stringutils.h>
-#include <QDir>
-
namespace CMakeProjectManager {
namespace Internal {
@@ -44,7 +42,7 @@ using namespace ProjectExplorer;
static QString lineSplit(const QString &rest, const QByteArray &array, std::function<void(const QString &)> f)
{
- QString tmp = rest + Utils::SynchronousProcess::normalizeNewlines(QString::fromLocal8Bit(array));
+ QString tmp = rest + Utils::QtcProcess::normalizeNewlines(QString::fromLocal8Bit(array));
int start = 0;
int end = tmp.indexOf(QLatin1Char('\n'), start);
while (end >= 0) {
diff --git a/src/plugins/cmakeprojectmanager/cmakeprojectimporter.cpp b/src/plugins/cmakeprojectmanager/cmakeprojectimporter.cpp
index d83169402c..921f1c8c75 100644
--- a/src/plugins/cmakeprojectmanager/cmakeprojectimporter.cpp
+++ b/src/plugins/cmakeprojectmanager/cmakeprojectimporter.cpp
@@ -200,10 +200,10 @@ static FilePath qmakeFromCMakeCache(const CMakeConfig &config)
SynchronousProcess cmake;
cmake.setTimeoutS(5);
- cmake.setFlags(SynchronousProcess::UnixTerminalDisabled);
+ cmake.setDisableUnixTerminal();
Environment env = Environment::systemEnvironment();
- Environment::setupEnglishOutput(&env);
- cmake.setProcessEnvironment(env.toProcessEnvironment());
+ env.setupEnglishOutput();
+ cmake.setEnvironment(env);
cmake.setTimeOutMessageBoxEnabled(false);
QString cmakeGenerator
@@ -239,8 +239,8 @@ static FilePath qmakeFromCMakeCache(const CMakeConfig &config)
}
qCDebug(cmInputLog) << "CMake probing for qmake path: " << cmakeExecutable.toUserOutput() << args;
- cmake.runBlocking({cmakeExecutable, args});
-
+ cmake.setCommand({cmakeExecutable, args});
+ cmake.runBlocking();
QFile qmakeLocationTxt(qtcQMakeProbeDir.path() + "/qmake-location.txt");
if (!qmakeLocationTxt.open(QIODevice::ReadOnly)) {
diff --git a/src/plugins/cmakeprojectmanager/cmakeprojectmanager.cpp b/src/plugins/cmakeprojectmanager/cmakeprojectmanager.cpp
index f5e165b795..fcf52408e5 100644
--- a/src/plugins/cmakeprojectmanager/cmakeprojectmanager.cpp
+++ b/src/plugins/cmakeprojectmanager/cmakeprojectmanager.cpp
@@ -76,7 +76,7 @@ CMakeManager::CMakeManager()
Constants::RUN_CMAKE,
globalContext);
command->setAttribute(Core::Command::CA_Hide);
- mbuild->addAction(command, ProjectExplorer::Constants::G_BUILD_DEPLOY);
+ mbuild->addAction(command, ProjectExplorer::Constants::G_BUILD_BUILD);
connect(m_runCMakeAction, &QAction::triggered, [this]() {
runCMake(SessionManager::startupBuildSystem());
});
@@ -85,7 +85,7 @@ CMakeManager::CMakeManager()
Constants::CLEAR_CMAKE_CACHE,
globalContext);
command->setAttribute(Core::Command::CA_Hide);
- mbuild->addAction(command, ProjectExplorer::Constants::G_BUILD_DEPLOY);
+ mbuild->addAction(command, ProjectExplorer::Constants::G_BUILD_BUILD);
connect(m_clearCMakeCacheAction, &QAction::triggered, [this]() {
clearCMakeCache(SessionManager::startupBuildSystem());
});
@@ -113,7 +113,7 @@ CMakeManager::CMakeManager()
Constants::RESCAN_PROJECT,
globalContext);
command->setAttribute(Core::Command::CA_Hide);
- mbuild->addAction(command, ProjectExplorer::Constants::G_BUILD_DEPLOY);
+ mbuild->addAction(command, ProjectExplorer::Constants::G_BUILD_BUILD);
connect(m_rescanProjectAction, &QAction::triggered, [this]() {
rescanProject(ProjectTree::currentBuildSystem());
});
diff --git a/src/plugins/cmakeprojectmanager/cmakeprojectmanager.pro b/src/plugins/cmakeprojectmanager/cmakeprojectmanager.pro
index 1ba791a64b..95eec93051 100644
--- a/src/plugins/cmakeprojectmanager/cmakeprojectmanager.pro
+++ b/src/plugins/cmakeprojectmanager/cmakeprojectmanager.pro
@@ -27,7 +27,6 @@ HEADERS = builddirparameters.h \
cmakeindenter.h \
cmakeautocompleter.h \
cmakespecificsettings.h \
- cmakespecificsettingspage.h \
configmodel.h \
configmodelitemdelegate.h \
fileapidataextractor.h \
@@ -58,7 +57,6 @@ SOURCES = builddirparameters.cpp \
cmakeindenter.cpp \
cmakeautocompleter.cpp \
cmakespecificsettings.cpp \
- cmakespecificsettingspage.cpp \
configmodel.cpp \
configmodelitemdelegate.cpp \
fileapidataextractor.cpp \
@@ -67,6 +65,3 @@ SOURCES = builddirparameters.cpp \
projecttreehelper.cpp
RESOURCES += cmakeproject.qrc
-
-FORMS += \
- cmakespecificsettingspage.ui
diff --git a/src/plugins/cmakeprojectmanager/cmakeprojectmanager.qbs b/src/plugins/cmakeprojectmanager/cmakeprojectmanager.qbs
index 31c6126339..751efd49bd 100644
--- a/src/plugins/cmakeprojectmanager/cmakeprojectmanager.qbs
+++ b/src/plugins/cmakeprojectmanager/cmakeprojectmanager.qbs
@@ -69,9 +69,6 @@ QtcPlugin {
"cmakeautocompleter.cpp",
"cmakespecificsettings.h",
"cmakespecificsettings.cpp",
- "cmakespecificsettingspage.h",
- "cmakespecificsettingspage.cpp",
- "cmakespecificsettingspage.ui",
"configmodel.cpp",
"configmodel.h",
"configmodelitemdelegate.cpp",
diff --git a/src/plugins/cmakeprojectmanager/cmakeprojectnodes.cpp b/src/plugins/cmakeprojectmanager/cmakeprojectnodes.cpp
index 211aca4065..201e1ccca1 100644
--- a/src/plugins/cmakeprojectmanager/cmakeprojectnodes.cpp
+++ b/src/plugins/cmakeprojectmanager/cmakeprojectnodes.cpp
@@ -46,17 +46,14 @@ CMakeInputsNode::CMakeInputsNode(const Utils::FilePath &cmakeLists) :
{
setPriority(Node::DefaultPriority - 10); // Bottom most!
setDisplayName(QCoreApplication::translate("CMakeFilesProjectNode", "CMake Modules"));
- static const QIcon modulesIcon = Core::FileIconProvider::directoryIcon(
- ProjectExplorer::Constants::FILEOVERLAY_MODULES);
- setIcon(modulesIcon);
+ setIcon(DirectoryIcon(ProjectExplorer::Constants::FILEOVERLAY_MODULES));
setListInProject(false);
}
CMakeListsNode::CMakeListsNode(const Utils::FilePath &cmakeListPath) :
ProjectExplorer::ProjectNode(cmakeListPath)
{
- static QIcon folderIcon = Core::FileIconProvider::directoryIcon(Constants::FILE_OVERLAY_CMAKE);
- setIcon(folderIcon);
+ setIcon(DirectoryIcon(Constants::FILE_OVERLAY_CMAKE));
setListInProject(false);
}
@@ -74,9 +71,7 @@ CMakeProjectNode::CMakeProjectNode(const Utils::FilePath &directory) :
ProjectExplorer::ProjectNode(directory)
{
setPriority(Node::DefaultProjectPriority + 1000);
- static const QIcon productIcon = Core::FileIconProvider::directoryIcon(
- ProjectExplorer::Constants::FILEOVERLAY_PRODUCT);
- setIcon(productIcon);
+ setIcon(DirectoryIcon(ProjectExplorer::Constants::FILEOVERLAY_PRODUCT));
setListInProject(false);
}
@@ -90,7 +85,7 @@ CMakeTargetNode::CMakeTargetNode(const Utils::FilePath &directory, const QString
{
m_target = target;
setPriority(Node::DefaultProjectPriority + 900);
- setIcon(QIcon(":/projectexplorer/images/build.png")); // TODO: Use proper icon!
+ setIcon(":/projectexplorer/images/build.png"); // TODO: Use proper icon!
setListInProject(false);
setProductType(ProductType::Other);
}
diff --git a/src/plugins/cmakeprojectmanager/cmakeprojectplugin.cpp b/src/plugins/cmakeprojectmanager/cmakeprojectplugin.cpp
index 1dae39f036..c1cce18df9 100644
--- a/src/plugins/cmakeprojectmanager/cmakeprojectplugin.cpp
+++ b/src/plugins/cmakeprojectmanager/cmakeprojectplugin.cpp
@@ -37,7 +37,6 @@
#include "cmakeprojectnodes.h"
#include "cmakesettingspage.h"
#include "cmakespecificsettings.h"
-#include "cmakespecificsettingspage.h"
#include "cmaketoolmanager.h"
#include <coreplugin/actionmanager/actioncontainer.h>
@@ -100,7 +99,7 @@ bool CMakeProjectPlugin::initialize(const QStringList & /*arguments*/, QString *
Q_UNUSED(errorMessage)
d = new CMakeProjectPluginPrivate;
- projectTypeSpecificSettings()->fromSettings(ICore::settings());
+ projectTypeSpecificSettings()->readSettings(ICore::settings());
const Context projectContext{CMakeProjectManager::Constants::CMAKE_PROJECT_ID};
diff --git a/src/plugins/cmakeprojectmanager/cmakesettingspage.cpp b/src/plugins/cmakeprojectmanager/cmakesettingspage.cpp
index 5dbd43feed..6a8edb5269 100644
--- a/src/plugins/cmakeprojectmanager/cmakesettingspage.cpp
+++ b/src/plugins/cmakeprojectmanager/cmakesettingspage.cpp
@@ -237,7 +237,7 @@ public:
CMakeToolItemModel::CMakeToolItemModel()
{
- setHeader({tr("Name"), tr("Location")});
+ setHeader({tr("Name"), tr("Path")});
rootItem()->appendChild(
new StaticTreeItem({ProjectExplorer::Constants::msgAutoDetected()},
{ProjectExplorer::Constants::msgAutoDetectedToolTip()}));
diff --git a/src/plugins/cmakeprojectmanager/cmakespecificsettings.cpp b/src/plugins/cmakeprojectmanager/cmakespecificsettings.cpp
index 070610fd7d..8c00c4f5a3 100644
--- a/src/plugins/cmakeprojectmanager/cmakespecificsettings.cpp
+++ b/src/plugins/cmakeprojectmanager/cmakespecificsettings.cpp
@@ -25,37 +25,71 @@
#include "cmakespecificsettings.h"
+#include <projectexplorer/projectexplorerconstants.h>
+
+#include <utils/layoutbuilder.h>
+
+using namespace Utils;
+
namespace CMakeProjectManager {
namespace Internal {
-namespace {
-static const char SETTINGS_KEY[] = "CMakeSpecificSettings";
-static const char AFTER_ADD_FILE_ACTION_KEY[] = "ProjectPopupSetting";
-static const char NINJA_PATH[] = "NinjaPath";
-static const char PACKAGE_MANAGER_AUTO_SETUP[] = "PackageManagerAutoSetup";
-static const char ASK_RECONFIGURE_INITIAL_PARAMS[] = "AskReConfigureInitialParams";
-}
-
-void CMakeSpecificSettings::fromSettings(QSettings *settings)
+CMakeSpecificSettings::CMakeSpecificSettings()
{
- const QString rootKey = QString(SETTINGS_KEY) + '/';
- m_afterAddFileToProjectSetting = static_cast<AfterAddFileAction>(
- settings->value(rootKey + AFTER_ADD_FILE_ACTION_KEY,
- static_cast<int>(AfterAddFileAction::ASK_USER)).toInt());
+ setSettingsGroup("CMakeSpecificSettings");
+ setAutoApply(false);
+
+ registerAspect(&afterAddFileSetting);
+ afterAddFileSetting.setSettingsKey("ProjectPopupSetting");
+ afterAddFileSetting.setDefaultValue(AfterAddFileAction::AskUser);
+ afterAddFileSetting.addOption(tr("Ask about copying file paths"));
+ afterAddFileSetting.addOption(tr("Do not copy file paths"));
+ afterAddFileSetting.addOption(tr("Copy file paths"));
+ afterAddFileSetting.setToolTip(tr("Determines whether file paths are copied "
+ "to the clipboard for pasting to the CMakeLists.txt file when you "
+ "add new files to CMake projects."));
- m_ninjaPath = Utils::FilePath::fromUserInput(
- settings->value(rootKey + NINJA_PATH, QString()).toString());
+ registerAspect(&ninjaPath);
+ ninjaPath.setSettingsKey("NinjaPath");
- m_packageManagerAutoSetup = settings->value(rootKey + PACKAGE_MANAGER_AUTO_SETUP, true).toBool();
+ registerAspect(&packageManagerAutoSetup);
+ packageManagerAutoSetup.setSettingsKey("PackageManagerAutoSetup");
+ packageManagerAutoSetup.setDefaultValue(true);
+ packageManagerAutoSetup.setLabelText(tr("Package manager auto setup"));
+ packageManagerAutoSetup.setToolTip(tr("Add the CMAKE_PROJECT_INCLUDE_BEFORE variable "
+ "pointing to a CMake script that will install dependencies from the conanfile.txt, "
+ "conanfile.py, or vcpkg.json file from the project source directory."));
+
+ registerAspect(&askBeforeReConfigureInitialParams);
+ askBeforeReConfigureInitialParams.setSettingsKey("AskReConfigureInitialParams");
+ askBeforeReConfigureInitialParams.setDefaultValue(true);
+ askBeforeReConfigureInitialParams.setLabelText(tr("Ask before re-configuring with "
+ "initial parameters"));
}
-void CMakeSpecificSettings::toSettings(QSettings *settings) const
+// CMakeSpecificSettingsPage
+
+CMakeSpecificSettingsPage::CMakeSpecificSettingsPage(CMakeSpecificSettings *settings)
{
- settings->beginGroup(QString(SETTINGS_KEY));
- settings->setValue(QString(AFTER_ADD_FILE_ACTION_KEY), static_cast<int>(m_afterAddFileToProjectSetting));
- settings->setValue(QString(PACKAGE_MANAGER_AUTO_SETUP), m_packageManagerAutoSetup);
- settings->setValue(QString(ASK_RECONFIGURE_INITIAL_PARAMS), m_askBeforeReConfigureInitialParams);
- settings->endGroup();
-}
-}
+ setId("CMakeSpecificSettings");
+ setDisplayName(CMakeSpecificSettings::tr("CMake"));
+ setCategory(ProjectExplorer::Constants::BUILD_AND_RUN_SETTINGS_CATEGORY);
+ setSettings(settings);
+
+ setLayouter([settings](QWidget *widget) {
+ CMakeSpecificSettings &s = *settings;
+ using namespace Layouting;
+ Column {
+ Group {
+ Title(CMakeSpecificSettings::tr("Adding Files")),
+ s.afterAddFileSetting
+ },
+ s.packageManagerAutoSetup,
+ s.askBeforeReConfigureInitialParams,
+ Stretch(),
+ }.attachTo(widget);
+ });
}
+
+} // Internal
+} // CMakeProjectManager
diff --git a/src/plugins/cmakeprojectmanager/cmakespecificsettings.h b/src/plugins/cmakeprojectmanager/cmakespecificsettings.h
index 273ae7937e..1c673fdc66 100644
--- a/src/plugins/cmakeprojectmanager/cmakespecificsettings.h
+++ b/src/plugins/cmakeprojectmanager/cmakespecificsettings.h
@@ -25,42 +25,37 @@
#pragma once
-#include <utils/fileutils.h>
+#include <coreplugin/dialogs/ioptionspage.h>
-#include <QSettings>
+#include <utils/aspects.h>
namespace CMakeProjectManager {
namespace Internal {
enum AfterAddFileAction : int {
- ASK_USER,
- COPY_FILE_PATH,
- NEVER_COPY_FILE_PATH
+ AskUser,
+ CopyFilePath,
+ NeverCopyFilePath
};
-class CMakeSpecificSettings
+class CMakeSpecificSettings final : public Utils::AspectContainer
{
-public:
- CMakeSpecificSettings() = default;
- void fromSettings(QSettings *settings);
- void toSettings(QSettings *settings) const;
-
- void setAfterAddFileSetting(AfterAddFileAction settings) { m_afterAddFileToProjectSetting = settings; }
- AfterAddFileAction afterAddFileSetting() const { return m_afterAddFileToProjectSetting; }
+ Q_DECLARE_TR_FUNCTIONS(CMakeProjectManager::Internal::CMakeSpecificSettings)
- Utils::FilePath ninjaPath() const { return m_ninjaPath; }
+public:
+ CMakeSpecificSettings();
- void setPackageManagerAutoSetup(bool checked) { m_packageManagerAutoSetup = checked; }
- bool packageManagerAutoSetup() const { return m_packageManagerAutoSetup; }
+ Utils::SelectionAspect afterAddFileSetting;
+ Utils::StringAspect ninjaPath;
+ Utils::BoolAspect packageManagerAutoSetup;
+ Utils::BoolAspect askBeforeReConfigureInitialParams;
+};
- bool askBeforeReConfigureInitialParams() const { return m_askBeforeReConfigureInitialParams; }
- void setAskBeforeReConfigureInitialParams(bool doAsk) { m_askBeforeReConfigureInitialParams = doAsk; }
-private:
- AfterAddFileAction m_afterAddFileToProjectSetting;
- Utils::FilePath m_ninjaPath;
- bool m_packageManagerAutoSetup = true;
- bool m_askBeforeReConfigureInitialParams = true;
+class CMakeSpecificSettingsPage final : public Core::IOptionsPage
+{
+public:
+ explicit CMakeSpecificSettingsPage(CMakeSpecificSettings *settings);
};
-}
-}
+} // Internal
+} // CMakeProjectManager
diff --git a/src/plugins/cmakeprojectmanager/cmakespecificsettingspage.cpp b/src/plugins/cmakeprojectmanager/cmakespecificsettingspage.cpp
deleted file mode 100644
index 9653e32b7c..0000000000
--- a/src/plugins/cmakeprojectmanager/cmakespecificsettingspage.cpp
+++ /dev/null
@@ -1,99 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2018 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of Qt Creator.
-**
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 3 as published by the Free Software
-** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-3.0.html.
-**
-****************************************************************************/
-
-#include "cmakespecificsettingspage.h"
-#include "cmakespecificsettings.h"
-#include "ui_cmakespecificsettingspage.h"
-
-#include <coreplugin/icore.h>
-#include <projectexplorer/projectexplorerconstants.h>
-
-namespace CMakeProjectManager {
-namespace Internal {
-
-class CMakeSpecificSettingWidget final : public Core::IOptionsPageWidget
-{
- Q_DECLARE_TR_FUNCTIONS(CMakeProjectManager::Internal::CMakeSpecificSettingWidget)
-
-public:
- explicit CMakeSpecificSettingWidget(CMakeSpecificSettings *settings);
-
- void apply() final;
-
-private:
- Ui::CMakeSpecificSettingForm m_ui;
- CMakeSpecificSettings *m_settings;
-};
-
-CMakeSpecificSettingWidget::CMakeSpecificSettingWidget(CMakeSpecificSettings *settings)
- : m_settings(settings)
-{
- m_ui.setupUi(this);
- m_ui.newFileAddedCopyToCpliSettingGroup->setId(m_ui.alwaysAskRadio,
- AfterAddFileAction::ASK_USER);
- m_ui.newFileAddedCopyToCpliSettingGroup->setId(m_ui.neverCopyRadio,
- AfterAddFileAction::NEVER_COPY_FILE_PATH);
- m_ui.newFileAddedCopyToCpliSettingGroup->setId(m_ui.alwaysCopyRadio,
- AfterAddFileAction::COPY_FILE_PATH);
-
- const AfterAddFileAction mode = settings->afterAddFileSetting();
- switch (mode) {
- case ASK_USER:
- m_ui.alwaysAskRadio->setChecked(true);
- break;
- case COPY_FILE_PATH:
- m_ui.alwaysCopyRadio->setChecked(true);
- break;
- case NEVER_COPY_FILE_PATH:
- m_ui.neverCopyRadio->setChecked(true);
- break;
- }
-
- m_ui.packageManagerAutoSetup->setChecked(settings->packageManagerAutoSetup());
- m_ui.askBeforeReConfigureWithInitialParams->setChecked(settings->askBeforeReConfigureInitialParams());
-}
-
-void CMakeSpecificSettingWidget::apply()
-{
- int popupSetting = m_ui.newFileAddedCopyToCpliSettingGroup->checkedId();
- m_settings->setAfterAddFileSetting(popupSetting == -1 ? AfterAddFileAction::ASK_USER
- : static_cast<AfterAddFileAction>(popupSetting));
- m_settings->setPackageManagerAutoSetup(m_ui.packageManagerAutoSetup->isChecked());
- m_settings->setAskBeforeReConfigureInitialParams(m_ui.askBeforeReConfigureWithInitialParams->isChecked());
- m_settings->toSettings(Core::ICore::settings());
-}
-
-// CMakeSpecificSettingsPage
-
-CMakeSpecificSettingsPage::CMakeSpecificSettingsPage(CMakeSpecificSettings *settings)
-{
- setId("CMakeSpecificSettings");
- setDisplayName(CMakeSpecificSettingWidget::tr("CMake"));
- setCategory(ProjectExplorer::Constants::BUILD_AND_RUN_SETTINGS_CATEGORY);
- setWidgetCreator([settings] { return new CMakeSpecificSettingWidget(settings); });
-}
-
-} // Internal
-} // CMakeProjectManager
diff --git a/src/plugins/cmakeprojectmanager/cmakespecificsettingspage.h b/src/plugins/cmakeprojectmanager/cmakespecificsettingspage.h
deleted file mode 100644
index b277b5de89..0000000000
--- a/src/plugins/cmakeprojectmanager/cmakespecificsettingspage.h
+++ /dev/null
@@ -1,42 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2018 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of Qt Creator.
-**
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 3 as published by the Free Software
-** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-3.0.html.
-**
-****************************************************************************/
-
-#pragma once
-
-#include <coreplugin/dialogs/ioptionspage.h>
-
-namespace CMakeProjectManager {
-namespace Internal {
-
-class CMakeSpecificSettings;
-
-class CMakeSpecificSettingsPage final : public Core::IOptionsPage
-{
-public:
- explicit CMakeSpecificSettingsPage(CMakeSpecificSettings *settings);
-};
-
-} // Internal
-} // CMakeProjectManager
diff --git a/src/plugins/cmakeprojectmanager/cmakespecificsettingspage.ui b/src/plugins/cmakeprojectmanager/cmakespecificsettingspage.ui
deleted file mode 100644
index b232685974..0000000000
--- a/src/plugins/cmakeprojectmanager/cmakespecificsettingspage.ui
+++ /dev/null
@@ -1,100 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<ui version="4.0">
- <class>CMakeProjectManager::Internal::CMakeSpecificSettingForm</class>
- <widget class="QWidget" name="CMakeProjectManager::Internal::CMakeSpecificSettingForm">
- <property name="geometry">
- <rect>
- <x>0</x>
- <y>0</y>
- <width>852</width>
- <height>567</height>
- </rect>
- </property>
- <property name="windowTitle">
- <string notr="true">Form</string>
- </property>
- <layout class="QVBoxLayout" name="verticalLayout_3">
- <item>
- <widget class="QGroupBox" name="groupBox_2">
- <property name="toolTip">
- <string>Determines whether file paths are copied to the clipboard for pasting to the CMakeLists.txt file when you add new files to CMake projects.</string>
- </property>
- <property name="title">
- <string>Adding Files</string>
- </property>
- <layout class="QVBoxLayout" name="verticalLayout_4">
- <item>
- <layout class="QVBoxLayout" name="verticalLayout">
- <item>
- <widget class="QRadioButton" name="alwaysAskRadio">
- <property name="text">
- <string>Ask about copying file paths</string>
- </property>
- <attribute name="buttonGroup">
- <string notr="true">newFileAddedCopyToCpliSettingGroup</string>
- </attribute>
- </widget>
- </item>
- <item>
- <widget class="QRadioButton" name="neverCopyRadio">
- <property name="text">
- <string>Do not copy file paths</string>
- </property>
- <attribute name="buttonGroup">
- <string notr="true">newFileAddedCopyToCpliSettingGroup</string>
- </attribute>
- </widget>
- </item>
- <item>
- <widget class="QRadioButton" name="alwaysCopyRadio">
- <property name="text">
- <string>Copy file paths</string>
- </property>
- <attribute name="buttonGroup">
- <string notr="true">newFileAddedCopyToCpliSettingGroup</string>
- </attribute>
- </widget>
- </item>
- </layout>
- </item>
- </layout>
- </widget>
- </item>
- <item>
- <widget class="QCheckBox" name="packageManagerAutoSetup">
- <property name="toolTip">
- <string>Add the CMAKE_PROJECT_INCLUDE_BEFORE variable pointing to a CMake script that will install dependencies from the conanfile.txt, conanfile.py, or vcpkg.json file from the project source directory.</string>
- </property>
- <property name="text">
- <string>Package manager auto setup</string>
- </property>
- </widget>
- </item>
- <item>
- <widget class="QCheckBox" name="askBeforeReConfigureWithInitialParams">
- <property name="text">
- <string>Ask before re-configuring with initial parameters</string>
- </property>
- </widget>
- </item>
- <item>
- <spacer name="verticalSpacer">
- <property name="orientation">
- <enum>Qt::Vertical</enum>
- </property>
- <property name="sizeHint" stdset="0">
- <size>
- <width>20</width>
- <height>40</height>
- </size>
- </property>
- </spacer>
- </item>
- </layout>
- </widget>
- <resources/>
- <connections/>
- <buttongroups>
- <buttongroup name="newFileAddedCopyToCpliSettingGroup"/>
- </buttongroups>
-</ui>
diff --git a/src/plugins/cmakeprojectmanager/cmaketool.cpp b/src/plugins/cmakeprojectmanager/cmaketool.cpp
index 678acdf554..81b06387a4 100644
--- a/src/plugins/cmakeprojectmanager/cmaketool.cpp
+++ b/src/plugins/cmakeprojectmanager/cmaketool.cpp
@@ -30,6 +30,7 @@
#include <utils/algorithm.h>
#include <utils/environment.h>
#include <utils/qtcassert.h>
+#include <utils/qtcprocess.h>
#include <QDir>
#include <QJsonDocument>
@@ -40,6 +41,8 @@
#include <memory>
+using namespace Utils;
+
namespace CMakeProjectManager {
const char CMAKE_INFORMATION_ID[] = "Id";
@@ -107,17 +110,17 @@ public:
///////////////////////////
// CMakeTool
///////////////////////////
-CMakeTool::CMakeTool(Detection d, const Utils::Id &id)
+CMakeTool::CMakeTool(Detection d, const Id &id)
: m_id(id)
, m_isAutoDetected(d == AutoDetection)
, m_introspection(std::make_unique<Internal::IntrospectionData>())
{
- QTC_ASSERT(m_id.isValid(), m_id = Utils::Id::fromString(QUuid::createUuid().toString()));
+ QTC_ASSERT(m_id.isValid(), m_id = Id::fromString(QUuid::createUuid().toString()));
}
CMakeTool::CMakeTool(const QVariantMap &map, bool fromSdk) :
CMakeTool(fromSdk ? CMakeTool::AutoDetection : CMakeTool::ManualDetection,
- Utils::Id::fromSetting(map.value(CMAKE_INFORMATION_ID)))
+ Id::fromSetting(map.value(CMAKE_INFORMATION_ID)))
{
m_displayName = map.value(CMAKE_INFORMATION_DISPLAYNAME).toString();
m_isAutoRun = map.value(CMAKE_INFORMATION_AUTORUN, true).toBool();
@@ -129,9 +132,9 @@ CMakeTool::CMakeTool(const QVariantMap &map, bool fromSdk) :
if (!fromSdk)
m_isAutoDetected = map.value(CMAKE_INFORMATION_AUTODETECTED, false).toBool();
- setFilePath(Utils::FilePath::fromString(map.value(CMAKE_INFORMATION_COMMAND).toString()));
+ setFilePath(FilePath::fromString(map.value(CMAKE_INFORMATION_COMMAND).toString()));
- m_qchFilePath = Utils::FilePath::fromVariant(map.value(CMAKE_INFORMATION_QCH_FILE_PATH));
+ m_qchFilePath = FilePath::fromVariant(map.value(CMAKE_INFORMATION_QCH_FILE_PATH));
if (m_qchFilePath.isEmpty())
m_qchFilePath = searchQchFile(m_executable);
@@ -139,12 +142,12 @@ CMakeTool::CMakeTool(const QVariantMap &map, bool fromSdk) :
CMakeTool::~CMakeTool() = default;
-Utils::Id CMakeTool::createId()
+Id CMakeTool::createId()
{
- return Utils::Id::fromString(QUuid::createUuid().toString());
+ return Id::fromString(QUuid::createUuid().toString());
}
-void CMakeTool::setFilePath(const Utils::FilePath &executable)
+void CMakeTool::setFilePath(const FilePath &executable)
{
if (m_executable == executable)
return;
@@ -155,7 +158,7 @@ void CMakeTool::setFilePath(const Utils::FilePath &executable)
CMakeToolManager::notifyAboutUpdate(this);
}
-Utils::FilePath CMakeTool::filePath() const
+FilePath CMakeTool::filePath() const
{
return m_executable;
}
@@ -189,17 +192,16 @@ bool CMakeTool::isValid() const
return m_introspection->m_didRun && !m_introspection->m_fileApis.isEmpty();
}
-Utils::SynchronousProcessResponse CMakeTool::run(const QStringList &args, int timeoutS) const
+void CMakeTool::runCMake(SynchronousProcess &cmake, const QStringList &args, int timeoutS) const
{
- Utils::SynchronousProcess cmake;
cmake.setTimeoutS(timeoutS);
- cmake.setFlags(Utils::SynchronousProcess::UnixTerminalDisabled);
- Utils::Environment env = Utils::Environment::systemEnvironment();
- Utils::Environment::setupEnglishOutput(&env);
- cmake.setProcessEnvironment(env.toProcessEnvironment());
+ cmake.setDisableUnixTerminal();
+ Environment env = Environment::systemEnvironment();
+ env.setupEnglishOutput();
+ cmake.setEnvironment(env);
cmake.setTimeOutMessageBoxEnabled(false);
-
- return cmake.runBlocking({cmakeExecutable(), args});
+ cmake.setCommand({cmakeExecutable(), args});
+ cmake.runBlocking();
}
QVariantMap CMakeTool::toMap() const
@@ -218,24 +220,24 @@ QVariantMap CMakeTool::toMap() const
return data;
}
-Utils::FilePath CMakeTool::cmakeExecutable() const
+FilePath CMakeTool::cmakeExecutable() const
{
return cmakeExecutable(m_executable);
}
-void CMakeTool::setQchFilePath(const Utils::FilePath &path)
+void CMakeTool::setQchFilePath(const FilePath &path)
{
m_qchFilePath = path;
}
-Utils::FilePath CMakeTool::qchFilePath() const
+FilePath CMakeTool::qchFilePath() const
{
return m_qchFilePath;
}
-Utils::FilePath CMakeTool::cmakeExecutable(const Utils::FilePath &path)
+FilePath CMakeTool::cmakeExecutable(const FilePath &path)
{
- if (Utils::HostOsInfo::isMacHost()) {
+ if (HostOsInfo::isMacHost()) {
const QString executableString = path.toString();
const int appIndex = executableString.lastIndexOf(".app");
const int appCutIndex = appIndex + 4;
@@ -243,17 +245,16 @@ Utils::FilePath CMakeTool::cmakeExecutable(const Utils::FilePath &path)
const bool containsApp = appIndex >= 0 && !endsWithApp
&& executableString.at(appCutIndex) == '/';
if (endsWithApp || containsApp) {
- const Utils::FilePath toTest = Utils::FilePath::fromString(
- executableString.left(appCutIndex))
- .pathAppended("Contents/bin/cmake");
+ const FilePath toTest = FilePath::fromString(executableString.left(appCutIndex))
+ .pathAppended("Contents/bin/cmake");
if (toTest.exists())
return toTest.canonicalPath();
}
}
- const Utils::FilePath resolvedPath = path.canonicalPath();
+ const FilePath resolvedPath = path.canonicalPath();
// Evil hack to make snap-packages of CMake work. See QTCREATORBUG-23376
- if (Utils::HostOsInfo::isLinuxHost() && resolvedPath.fileName() == "snap")
+ if (HostOsInfo::isLinuxHost() && resolvedPath.fileName() == "snap")
return path;
return resolvedPath;
@@ -280,22 +281,22 @@ TextEditor::Keywords CMakeTool::keywords()
return {};
if (m_introspection->m_functions.isEmpty() && m_introspection->m_didRun) {
- Utils::SynchronousProcessResponse response;
- response = run({"--help-command-list"}, 5);
- if (response.result == Utils::SynchronousProcessResponse::Finished)
- m_introspection->m_functions = response.stdOut().split('\n');
-
- response = run({"--help-commands"}, 5);
- if (response.result == Utils::SynchronousProcessResponse::Finished)
- parseFunctionDetailsOutput(response.stdOut());
-
- response = run({"--help-property-list"}, 5);
- if (response.result == Utils::SynchronousProcessResponse::Finished)
- m_introspection->m_variables = parseVariableOutput(response.stdOut());
-
- response = run({"--help-variable-list"}, 5);
- if (response.result == Utils::SynchronousProcessResponse::Finished) {
- m_introspection->m_variables.append(parseVariableOutput(response.stdOut()));
+ SynchronousProcess proc;
+ runCMake(proc, {"--help-command-list"}, 5);
+ if (proc.result() == QtcProcess::Finished)
+ m_introspection->m_functions = proc.stdOut().split('\n');
+
+ runCMake(proc, {"--help-commands"}, 5);
+ if (proc.result() == QtcProcess::Finished)
+ parseFunctionDetailsOutput(proc.stdOut());
+
+ runCMake(proc, {"--help-property-list"}, 5);
+ if (proc.result() == QtcProcess::Finished)
+ m_introspection->m_variables = parseVariableOutput(proc.stdOut());
+
+ runCMake(proc, {"--help-variable-list"}, 5);
+ if (proc.result() == QtcProcess::Finished) {
+ m_introspection->m_variables.append(parseVariableOutput(proc.stdOut()));
m_introspection->m_variables = Utils::filteredUnique(m_introspection->m_variables);
Utils::sort(m_introspection->m_variables);
}
@@ -311,11 +312,6 @@ bool CMakeTool::hasFileApi() const
return isValid() ? !m_introspection->m_fileApis.isEmpty() : false;
}
-QVector<std::pair<QString, int>> CMakeTool::supportedFileApiObjects() const
-{
- return isValid() ? Utils::transform(m_introspection->m_fileApis, [](const Internal::FileApi &api) { return std::make_pair(api.kind, api.version.first); }) : QVector<std::pair<QString, int>>();
-}
-
CMakeTool::Version CMakeTool::version() const
{
return m_introspection ? m_introspection->m_version : CMakeTool::Version();
@@ -346,7 +342,7 @@ CMakeTool::PathMapper CMakeTool::pathMapper() const
{
if (m_pathMapper)
return m_pathMapper;
- return [](const Utils::FilePath &fn) { return fn; };
+ return [](const FilePath &fn) { return fn; };
}
Utils::optional<CMakeTool::ReaderType> CMakeTool::readerType() const
@@ -360,12 +356,12 @@ Utils::optional<CMakeTool::ReaderType> CMakeTool::readerType() const
return {};
}
-Utils::FilePath CMakeTool::searchQchFile(const Utils::FilePath &executable)
+FilePath CMakeTool::searchQchFile(const FilePath &executable)
{
if (executable.isEmpty())
return {};
- Utils::FilePath prefixDir = executable.parentDir().parentDir();
+ FilePath prefixDir = executable.parentDir().parentDir();
QDir docDir{prefixDir.pathAppended("doc/cmake").toString()};
if (!docDir.exists())
docDir.setPath(prefixDir.pathAppended("share/doc/cmake").toString());
@@ -375,7 +371,7 @@ Utils::FilePath CMakeTool::searchQchFile(const Utils::FilePath &executable)
const QStringList files = docDir.entryList(QStringList("*.qch"));
for (const QString &docFile : files) {
if (docFile.startsWith("cmake", Qt::CaseInsensitive)) {
- return Utils::FilePath::fromString(docDir.absoluteFilePath(docFile));
+ return FilePath::fromString(docDir.absoluteFilePath(docFile));
}
}
@@ -486,11 +482,12 @@ QStringList CMakeTool::parseVariableOutput(const QString &output)
void CMakeTool::fetchFromCapabilities() const
{
- Utils::SynchronousProcessResponse response = run({"-E", "capabilities"});
+ SynchronousProcess cmake;
+ runCMake(cmake, {"-E", "capabilities"});
- if (response.result == Utils::SynchronousProcessResponse::Finished) {
+ if (cmake.result() == QtcProcess::Finished) {
m_introspection->m_didRun = true;
- parseFromCapabilities(response.stdOut());
+ parseFromCapabilities(cmake.stdOut());
} else {
m_introspection->m_didRun = false;
}
diff --git a/src/plugins/cmakeprojectmanager/cmaketool.h b/src/plugins/cmakeprojectmanager/cmaketool.h
index 12a71c546c..4ffc8c82a0 100644
--- a/src/plugins/cmakeprojectmanager/cmaketool.h
+++ b/src/plugins/cmakeprojectmanager/cmaketool.h
@@ -32,11 +32,8 @@
#include <utils/fileutils.h>
#include <utils/id.h>
#include <utils/optional.h>
-#include <utils/synchronousprocess.h>
-QT_FORWARD_DECLARE_CLASS(QProcess)
-
-namespace ProjectExplorer { class Kit; }
+namespace Utils { class SynchronousProcess; }
namespace CMakeProjectManager {
@@ -99,7 +96,6 @@ public:
QList<Generator> supportedGenerators() const;
TextEditor::Keywords keywords();
bool hasFileApi() const;
- QVector<std::pair<QString, int>> supportedFileApiObjects() const;
Version version() const;
bool isAutoDetected() const;
@@ -116,7 +112,7 @@ public:
private:
void readInformation() const;
- Utils::SynchronousProcessResponse run(const QStringList &args, int timeoutS = 1) const;
+ void runCMake(Utils::SynchronousProcess &proc, const QStringList &args, int timeoutS = 1) const;
void parseFunctionDetailsOutput(const QString &output);
QStringList parseVariableOutput(const QString &output);
diff --git a/src/plugins/cmakeprojectmanager/cmaketoolmanager.cpp b/src/plugins/cmakeprojectmanager/cmaketoolmanager.cpp
index 85884edb46..a250b1cf4f 100644
--- a/src/plugins/cmakeprojectmanager/cmaketoolmanager.cpp
+++ b/src/plugins/cmakeprojectmanager/cmaketoolmanager.cpp
@@ -27,6 +27,8 @@
#include "cmaketoolsettingsaccessor.h"
+#include <extensionsystem/pluginmanager.h>
+
#include <coreplugin/helpmanager.h>
#include <coreplugin/icore.h>
@@ -69,10 +71,14 @@ CMakeToolManager::CMakeToolManager()
connect(this, &CMakeToolManager::cmakeAdded, this, &CMakeToolManager::cmakeToolsChanged);
connect(this, &CMakeToolManager::cmakeRemoved, this, &CMakeToolManager::cmakeToolsChanged);
connect(this, &CMakeToolManager::cmakeUpdated, this, &CMakeToolManager::cmakeToolsChanged);
+
+ setObjectName("CMakeToolManager");
+ ExtensionSystem::PluginManager::addObject(this);
}
CMakeToolManager::~CMakeToolManager()
{
+ ExtensionSystem::PluginManager::removeObject(this);
delete d;
}
@@ -171,6 +177,20 @@ void CMakeToolManager::updateDocumentation()
Core::HelpManager::registerDocumentation(docs);
}
+void CMakeToolManager::registerCMakeByPath(const FilePath &cmakePath)
+{
+ const Id id = Id::fromString(cmakePath.toUserOutput());
+
+ CMakeTool *cmakeTool = findById(id);
+ if (cmakeTool)
+ return;
+
+ auto newTool = std::make_unique<CMakeTool>(CMakeTool::ManualDetection, id);
+ newTool->setFilePath(cmakePath);
+ newTool->setDisplayName(cmakePath.toUserOutput());
+ registerCMakeTool(std::move(newTool));
+}
+
void CMakeToolManager::notifyAboutUpdate(CMakeTool *tool)
{
if (!tool || !Utils::contains(d->m_cmakeTools, tool))
diff --git a/src/plugins/cmakeprojectmanager/cmaketoolmanager.h b/src/plugins/cmakeprojectmanager/cmaketoolmanager.h
index b84532b27e..a8fb3a2432 100644
--- a/src/plugins/cmakeprojectmanager/cmaketoolmanager.h
+++ b/src/plugins/cmakeprojectmanager/cmaketoolmanager.h
@@ -62,6 +62,9 @@ public:
static void updateDocumentation();
+public slots:
+ void registerCMakeByPath(const Utils::FilePath &cmakePath);
+
signals:
void cmakeAdded (const Utils::Id &id);
void cmakeRemoved (const Utils::Id &id);
diff --git a/src/plugins/cmakeprojectmanager/cmaketoolsettingsaccessor.cpp b/src/plugins/cmakeprojectmanager/cmaketoolsettingsaccessor.cpp
index 808cf7b3eb..0ebfb1fb36 100644
--- a/src/plugins/cmakeprojectmanager/cmaketoolsettingsaccessor.cpp
+++ b/src/plugins/cmakeprojectmanager/cmaketoolsettingsaccessor.cpp
@@ -48,11 +48,11 @@ namespace Internal {
// CMakeToolSettingsUpgraders:
// --------------------------------------------------------------------
-class CMakeToolSettingsUpgraderV0 : public Utils::VersionUpgrader
+class CMakeToolSettingsUpgraderV0 : public VersionUpgrader
{
// Necessary to make Version 1 supported.
public:
- CMakeToolSettingsUpgraderV0() : Utils::VersionUpgrader(0, "4.6") { }
+ CMakeToolSettingsUpgraderV0() : VersionUpgrader(0, "4.6") { }
// NOOP
QVariantMap upgrade(const QVariantMap &data) final { return data; }
@@ -62,39 +62,38 @@ public:
// Helpers:
// --------------------------------------------------------------------
-static const char CMAKE_TOOL_COUNT_KEY[] = "CMakeTools.Count";
-static const char CMAKE_TOOL_DATA_KEY[] = "CMakeTools.";
-static const char CMAKE_TOOL_DEFAULT_KEY[] = "CMakeTools.Default";
-static const char CMAKE_TOOL_FILENAME[] = "/cmaketools.xml";
-
+const char CMAKE_TOOL_COUNT_KEY[] = "CMakeTools.Count";
+const char CMAKE_TOOL_DATA_KEY[] = "CMakeTools.";
+const char CMAKE_TOOL_DEFAULT_KEY[] = "CMakeTools.Default";
+const char CMAKE_TOOL_FILENAME[] = "cmaketools.xml";
static std::vector<std::unique_ptr<CMakeTool>> autoDetectCMakeTools()
{
- Utils::Environment env = Environment::systemEnvironment();
+ Environment env = Environment::systemEnvironment();
- Utils::FilePaths path = env.path();
+ FilePaths path = env.path();
path = Utils::filteredUnique(path);
if (HostOsInfo::isWindowsHost()) {
for (auto envVar : {"ProgramFiles", "ProgramFiles(x86)", "ProgramW6432"}) {
if (qEnvironmentVariableIsSet(envVar)) {
const QString progFiles = qEnvironmentVariable(envVar);
- path.append(Utils::FilePath::fromString(progFiles + "/CMake"));
- path.append(Utils::FilePath::fromString(progFiles + "/CMake/bin"));
+ path.append(FilePath::fromString(progFiles + "/CMake"));
+ path.append(FilePath::fromString(progFiles + "/CMake/bin"));
}
}
}
if (HostOsInfo::isMacHost()) {
- path.append(Utils::FilePath::fromString("/Applications/CMake.app/Contents/bin"));
- path.append(Utils::FilePath::fromString("/usr/local/bin"));
- path.append(Utils::FilePath::fromString("/opt/local/bin"));
+ path.append(FilePath::fromString("/Applications/CMake.app/Contents/bin"));
+ path.append(FilePath::fromString("/usr/local/bin"));
+ path.append(FilePath::fromString("/opt/local/bin"));
}
const QStringList execs = env.appendExeExtensions(QLatin1String("cmake"));
FilePaths suspects;
- foreach (const Utils::FilePath &base, path) {
+ foreach (const FilePath &base, path) {
if (base.isEmpty())
continue;
@@ -165,7 +164,7 @@ CMakeToolSettingsAccessor::CMakeToolSettingsAccessor() :
QCoreApplication::translate("CMakeProjectManager::CMakeToolManager", "CMake"),
Core::Constants::IDE_DISPLAY_NAME)
{
- setBaseFilePath(FilePath::fromString(Core::ICore::userResourcePath() + CMAKE_TOOL_FILENAME));
+ setBaseFilePath(Core::ICore::userResourcePath(CMAKE_TOOL_FILENAME));
addVersionUpgrader(std::make_unique<CMakeToolSettingsUpgraderV0>());
}
@@ -174,8 +173,7 @@ CMakeToolSettingsAccessor::CMakeTools CMakeToolSettingsAccessor::restoreCMakeToo
{
CMakeTools result;
- const FilePath sdkSettingsFile = FilePath::fromString(Core::ICore::installerResourcePath()
- + CMAKE_TOOL_FILENAME);
+ const FilePath sdkSettingsFile = Core::ICore::installerResourcePath(CMAKE_TOOL_FILENAME);
CMakeTools sdkTools = cmakeTools(restoreSettings(sdkSettingsFile, parent), true);
@@ -201,7 +199,7 @@ CMakeToolSettingsAccessor::CMakeTools CMakeToolSettingsAccessor::restoreCMakeToo
}
void CMakeToolSettingsAccessor::saveCMakeTools(const QList<CMakeTool *> &cmakeTools,
- const Utils::Id &defaultId,
+ const Id &defaultId,
QWidget *parent)
{
QVariantMap data;
@@ -246,8 +244,7 @@ CMakeToolSettingsAccessor::cmakeTools(const QVariantMap &data, bool fromSdk) con
result.cmakeTools.emplace_back(std::move(item));
}
- result.defaultToolId = Utils::Id::fromSetting(data.value(CMAKE_TOOL_DEFAULT_KEY,
- Utils::Id().toSetting()));
+ result.defaultToolId = Id::fromSetting(data.value(CMAKE_TOOL_DEFAULT_KEY, Id().toSetting()));
return result;
}
diff --git a/src/plugins/cmakeprojectmanager/fileapidataextractor.cpp b/src/plugins/cmakeprojectmanager/fileapidataextractor.cpp
index 1474a8da4d..186a74b13b 100644
--- a/src/plugins/cmakeprojectmanager/fileapidataextractor.cpp
+++ b/src/plugins/cmakeprojectmanager/fileapidataextractor.cpp
@@ -264,7 +264,7 @@ QList<CMakeBuildTarget> generateBuildTargets(const PreprocessedData &input,
continue;
// CMake sometimes mixes several shell-escaped pieces into one fragment. Disentangle that again:
- const QStringList parts = QtcProcess::splitArgs(f.fragment);
+ const QStringList parts = ProcessArgs::splitArgs(f.fragment);
for (const QString &part : parts) {
// Some projects abuse linking to libraries to pass random flags to the linker, so ignore
// flags mixed into a fragment
@@ -315,7 +315,7 @@ static QStringList splitFragments(const QStringList &fragments)
{
QStringList result;
for (const QString &f : fragments) {
- result += QtcProcess::splitArgs(f);
+ result += ProcessArgs::splitArgs(f);
}
return result;
}
@@ -474,7 +474,8 @@ FolderNode *createSourceGroupNode(const QString &sourceGroupName,
if (!existingNode) {
auto node = createCMakeVFolder(sourceDirectory, Node::DefaultFolderPriority + 5, p);
node->setListInProject(false);
- node->setIcon(QIcon::fromTheme("edit-copy", ::Utils::Icons::COPY.icon()));
+ node->setIcon(
+ [] { return QIcon::fromTheme("edit-copy", ::Utils::Icons::COPY.icon()); });
existingNode = node.get();
diff --git a/src/plugins/cmakeprojectmanager/projecttreehelper.cpp b/src/plugins/cmakeprojectmanager/projecttreehelper.cpp
index df63f64bdd..edd3dd3c77 100644
--- a/src/plugins/cmakeprojectmanager/projecttreehelper.cpp
+++ b/src/plugins/cmakeprojectmanager/projecttreehelper.cpp
@@ -182,14 +182,12 @@ void addHeaderNodes(ProjectNode *root,
if (root->isEmpty())
return;
- static QIcon headerNodeIcon = Core::FileIconProvider::directoryIcon(
- ProjectExplorer::Constants::FILEOVERLAY_H);
auto headerNode = std::make_unique<VirtualFolderNode>(root->filePath());
headerNode->setPriority(Node::DefaultPriority - 5);
headerNode->setDisplayName(
QCoreApplication::translate("CMakeProjectManager::Internal::ProjectTreeHelper",
"<Headers>"));
- headerNode->setIcon(headerNodeIcon);
+ headerNode->setIcon(DirectoryIcon(ProjectExplorer::Constants::FILEOVERLAY_H));
// Add scanned headers:
for (const FileNode *fn : allFiles) {
@@ -212,15 +210,13 @@ void addFileSystemNodes(ProjectNode *root, const QList<const FileNode *> &allFil
{
QTC_ASSERT(root, return );
- static QIcon fileSystemNodeIcon = Core::FileIconProvider::directoryIcon(
- ProjectExplorer::Constants::FILEOVERLAY_UNKNOWN);
auto fileSystemNode = std::make_unique<VirtualFolderNode>(root->filePath());
// just before special nodes like "CMake Modules"
fileSystemNode->setPriority(Node::DefaultPriority - 6);
fileSystemNode->setDisplayName(
QCoreApplication::translate("CMakeProjectManager::Internal::ProjectTreeHelper",
"<File System>"));
- fileSystemNode->setIcon(fileSystemNodeIcon);
+ fileSystemNode->setIcon(DirectoryIcon(ProjectExplorer::Constants::FILEOVERLAY_UNKNOWN));
for (const FileNode *fn : allFiles) {
if (!fn->filePath().isChildOf(root->filePath()))
diff --git a/src/plugins/compilationdatabaseprojectmanager/compilationdatabaseprojectmanagerplugin.cpp b/src/plugins/compilationdatabaseprojectmanager/compilationdatabaseprojectmanagerplugin.cpp
index 04d9af3e91..fa7f425432 100644
--- a/src/plugins/compilationdatabaseprojectmanager/compilationdatabaseprojectmanagerplugin.cpp
+++ b/src/plugins/compilationdatabaseprojectmanager/compilationdatabaseprojectmanagerplugin.cpp
@@ -71,12 +71,11 @@ bool CompilationDatabaseProjectManagerPlugin::initialize(const QStringList &argu
d = new CompilationDatabaseProjectManagerPluginPrivate;
+ FileIconProvider::registerIconOverlayForFilename(Utils::Icons::PROJECT.imageFilePath().toString(),
+ COMPILE_COMMANDS_JSON);
FileIconProvider::registerIconOverlayForFilename(
- Utils::Icons::PROJECT.imageFileName(),
- COMPILE_COMMANDS_JSON);
- FileIconProvider::registerIconOverlayForFilename(
- Utils::Icons::PROJECT.imageFileName(),
- QString(COMPILE_COMMANDS_JSON) + Constants::COMPILATIONDATABASEPROJECT_FILES_SUFFIX);
+ Utils::Icons::PROJECT.imageFilePath().toString(),
+ QString(COMPILE_COMMANDS_JSON) + Constants::COMPILATIONDATABASEPROJECT_FILES_SUFFIX);
ProjectManager::registerProjectType<CompilationDatabaseProject>(
Constants::COMPILATIONDATABASEMIMETYPE);
diff --git a/src/plugins/conan/conaninstallstep.cpp b/src/plugins/conan/conaninstallstep.cpp
index cb47cf8b22..43a793eddd 100644
--- a/src/plugins/conan/conaninstallstep.cpp
+++ b/src/plugins/conan/conaninstallstep.cpp
@@ -91,7 +91,7 @@ ConanInstallStep::ConanInstallStep(BuildStepList *bsl, Id id)
const QString buildType = bt == BuildConfiguration::Release ? QString("Release")
: QString("Debug");
- CommandLine cmd(ConanPlugin::conanSettings()->conanFilePath());
+ CommandLine cmd(ConanPlugin::conanSettings()->conanFilePath.filePath());
cmd.addArgs({"install", "-s", "build_type=" + buildType});
if (buildMissing->value())
cmd.addArg("--build=missing");
diff --git a/src/plugins/conan/conanplugin.cpp b/src/plugins/conan/conanplugin.cpp
index 4e548774f2..e4f5235c64 100644
--- a/src/plugins/conan/conanplugin.cpp
+++ b/src/plugins/conan/conanplugin.cpp
@@ -65,7 +65,7 @@ bool ConanPlugin::initialize(const QStringList &arguments, QString *errorString)
Q_UNUSED(errorString)
m_runData = new ConanPluginRunData;
- conanSettings()->fromSettings(ICore::settings());
+ conanSettings()->readSettings(ICore::settings());
connect(SessionManager::instance(), &SessionManager::projectAdded,
this, &ConanPlugin::projectAdded);
diff --git a/src/plugins/conan/conansettings.cpp b/src/plugins/conan/conansettings.cpp
index 7e5285dc41..2d93756694 100644
--- a/src/plugins/conan/conansettings.cpp
+++ b/src/plugins/conan/conansettings.cpp
@@ -24,30 +24,25 @@
****************************************************************************/
#include "conansettings.h"
+
#include <utils/hostosinfo.h>
+using namespace Utils;
+
namespace ConanPackageManager {
namespace Internal {
-namespace {
-static const char SETTINGS_KEY[] = "ConanSettings";
-static const char CONAN_FILE_PATH[] = "ConanFilePath";
-}
-
-void ConanSettings::fromSettings(QSettings *settings)
+ConanSettings::ConanSettings()
{
- const QString rootKey = QString(SETTINGS_KEY) + '/';
+ setSettingsGroup("ConanSettings");
+ setAutoApply(false);
- const QString defaultExe = Utils::HostOsInfo::withExecutableSuffix(QString("conan"));
- m_conanFilePath = Utils::FilePath::fromUserInput(
- settings->value(rootKey + CONAN_FILE_PATH, defaultExe).toString());
+ registerAspect(&conanFilePath);
+ conanFilePath.setSettingsKey("ConanFilePath");
+ conanFilePath.setDisplayStyle(StringAspect::PathChooserDisplay);
+ conanFilePath.setExpectedKind(PathChooser::ExistingCommand);
+ conanFilePath.setDefaultValue(HostOsInfo::withExecutableSuffix("conan"));
}
-void ConanSettings::toSettings(QSettings *settings) const
-{
- settings->beginGroup(QString(SETTINGS_KEY));
- settings->endGroup();
-}
-
-}
-}
+} // Internal
+} // ConanPackageManager
diff --git a/src/plugins/conan/conansettings.h b/src/plugins/conan/conansettings.h
index c21b09a0d2..b03fd0e901 100644
--- a/src/plugins/conan/conansettings.h
+++ b/src/plugins/conan/conansettings.h
@@ -25,6 +25,7 @@
#pragma once
+#include <utils/aspects.h>
#include <utils/fileutils.h>
#include <QSettings>
@@ -32,18 +33,13 @@
namespace ConanPackageManager {
namespace Internal {
-class ConanSettings
+class ConanSettings : public Utils::AspectContainer
{
public:
- ConanSettings() = default;
- void fromSettings(QSettings *settings);
- void toSettings(QSettings *settings) const;
+ ConanSettings();
- Utils::FilePath conanFilePath() const { return m_conanFilePath; }
-
-private:
- Utils::FilePath m_conanFilePath;
+ Utils::StringAspect conanFilePath;
};
-}
-}
+} // Internal
+} // ConanPackageManager
diff --git a/src/plugins/coreplugin/CMakeLists.txt b/src/plugins/coreplugin/CMakeLists.txt
index 5544d49a8d..5c04a179e8 100644
--- a/src/plugins/coreplugin/CMakeLists.txt
+++ b/src/plugins/coreplugin/CMakeLists.txt
@@ -1,5 +1,3 @@
-option(SHOW_BUILD_DATE "Show build date in about dialog" OFF)
-
add_qtc_plugin(Core
DEPENDS Qt5::PrintSupport Qt5::Qml Qt5::Sql Qt5::Gui Qt5::GuiPrivate
PUBLIC_DEPENDS Aggregation ExtensionSystem Utils app_version
diff --git a/src/plugins/coreplugin/actionmanager/commandsfile.cpp b/src/plugins/coreplugin/actionmanager/commandsfile.cpp
index 665ff16074..498661d7b2 100644
--- a/src/plugins/coreplugin/actionmanager/commandsfile.cpp
+++ b/src/plugins/coreplugin/actionmanager/commandsfile.cpp
@@ -130,7 +130,7 @@ QMap<QString, QList<QKeySequence>> CommandsFile::importCommands() const
bool CommandsFile::exportCommands(const QList<ShortcutItem *> &items)
{
- Utils::FileSaver saver(m_filename, QIODevice::Text);
+ Utils::FileSaver saver(Utils::FilePath::fromString(m_filename), QIODevice::Text);
if (!saver.hasError()) {
const Context ctx;
QXmlStreamWriter w(saver.file());
diff --git a/src/plugins/coreplugin/coreplugin.cpp b/src/plugins/coreplugin/coreplugin.cpp
index 253c0d62e5..647636b8f1 100644
--- a/src/plugins/coreplugin/coreplugin.cpp
+++ b/src/plugins/coreplugin/coreplugin.cpp
@@ -50,6 +50,7 @@
#include <extensionsystem/pluginspec.h>
#include <utils/algorithm.h>
#include <utils/checkablemessagebox.h>
+#include <utils/commandline.h>
#include <utils/infobar.h>
#include <utils/macroexpander.h>
#include <utils/mimetypes/mimedatabase.h>
@@ -225,7 +226,7 @@ bool CorePlugin::initialize(const QStringList &arguments, QString *errorMessage)
expander->registerVariable("IDE:ResourcePath",
tr("The directory where %1 finds its pre-installed resources.")
.arg(Constants::IDE_DISPLAY_NAME),
- []() { return ICore::resourcePath(); });
+ []() { return ICore::resourcePath().toString(); });
expander->registerPrefix("CurrentDate:", tr("The current date (QDate formatstring)."),
[](const QString &fmt) { return QDate::currentDate().toString(fmt); });
expander->registerPrefix("CurrentTime:", tr("The current time (QTime formatstring)."),
diff --git a/src/plugins/coreplugin/coreplugin.h b/src/plugins/coreplugin/coreplugin.h
index 29fe6491a8..f8f9dab8a5 100644
--- a/src/plugins/coreplugin/coreplugin.h
+++ b/src/plugins/coreplugin/coreplugin.h
@@ -77,8 +77,6 @@ public slots:
private slots:
void testVcsManager_data();
void testVcsManager();
- void testSplitLineAndColumnNumber();
- void testSplitLineAndColumnNumber_data();
// Locator:
void test_basefilefilter();
void test_basefilefilter_data();
diff --git a/src/plugins/coreplugin/dialogs/externaltoolconfig.cpp b/src/plugins/coreplugin/dialogs/externaltoolconfig.cpp
index 87b713f453..2288edfc14 100644
--- a/src/plugins/coreplugin/dialogs/externaltoolconfig.cpp
+++ b/src/plugins/coreplugin/dialogs/externaltoolconfig.cpp
@@ -632,23 +632,22 @@ void ExternalToolConfig::showInfoForItem(const QModelIndex &index)
static QString getUserFilePath(const QString &proposalFileName)
{
- const QDir resourceDir(ICore::userResourcePath());
+ const QDir resourceDir(ICore::userResourcePath().toDir());
if (!resourceDir.exists(QLatin1String("externaltools")))
resourceDir.mkpath(QLatin1String("externaltools"));
const QFileInfo fi(proposalFileName);
const QString &suffix = QLatin1Char('.') + fi.completeSuffix();
- const QString &newFilePath = ICore::userResourcePath()
- + QLatin1String("/externaltools/") + fi.baseName();
+ const FilePath newFilePath = ICore::userResourcePath("externaltools") / fi.baseName();
int count = 0;
- QString tryPath = newFilePath + suffix;
- while (QFile::exists(tryPath)) {
+ FilePath tryPath = newFilePath + suffix;
+ while (tryPath.exists()) {
if (++count > 15)
return QString();
// add random number
const int number = QRandomGenerator::global()->generate() % 1000;
tryPath = newFilePath + QString::number(number) + suffix;
}
- return tryPath;
+ return tryPath.toString();
}
static QString idFromDisplayName(const QString &displayName)
diff --git a/src/plugins/coreplugin/dialogs/filepropertiesdialog.cpp b/src/plugins/coreplugin/dialogs/filepropertiesdialog.cpp
index fef059d7fa..e60ead6f37 100644
--- a/src/plugins/coreplugin/dialogs/filepropertiesdialog.cpp
+++ b/src/plugins/coreplugin/dialogs/filepropertiesdialog.cpp
@@ -62,6 +62,83 @@ FilePropertiesDialog::~FilePropertiesDialog()
delete m_ui;
}
+void FilePropertiesDialog::detectTextFileSettings()
+{
+ QFile file(m_fileName);
+ if (!file.open(QIODevice::ReadOnly)) {
+ m_ui->lineEndings->setText(tr("Unknown"));
+ m_ui->indentation->setText(tr("Unknown"));
+ return;
+ }
+
+ char lineSeparator = '\n';
+ const QByteArray data = file.read(50000);
+ file.close();
+
+ // Try to guess the files line endings
+ if (data.contains("\r\n")) {
+ m_ui->lineEndings->setText(tr("Windows (CRLF)"));
+ } else if (data.contains("\n")) {
+ m_ui->lineEndings->setText(tr("Unix (LF)"));
+ } else if (data.contains("\r")) {
+ m_ui->lineEndings->setText(tr("Mac (CR)"));
+ lineSeparator = '\r';
+ } else {
+ // That does not look like a text file at all
+ m_ui->lineEndings->setText(tr("Unknown"));
+ return;
+ }
+
+ auto leadingSpaces = [](const QByteArray &line) {
+ for (int i = 0, max = line.size(); i < max; ++i) {
+ if (line.at(i) != ' ') {
+ return i;
+ }
+ }
+ return 0;
+ };
+
+ // Try to guess the files indentation style
+ bool tabIndented = false;
+ int lastLineIndent = 0;
+ std::map<int, int> indents;
+ const QList<QByteArray> list = data.split(lineSeparator);
+ for (const QByteArray &line : list) {
+ if (line.startsWith(' ')) {
+ int spaces = leadingSpaces(line);
+ int relativeCurrentLineIndent = qAbs(spaces - lastLineIndent);
+ // Ignore zero or one character indentation changes
+ if (relativeCurrentLineIndent < 2)
+ continue;
+ indents[relativeCurrentLineIndent]++;
+ lastLineIndent = spaces;
+ } else if (line.startsWith('\t')) {
+ tabIndented = true;
+ }
+
+ if (!indents.empty() && tabIndented)
+ break;
+ }
+
+ const std::map<int, int>::iterator max = std::max_element(
+ indents.begin(), indents.end(),
+ [](const std::pair<int, int> &a, const std::pair<int, int> &b) {
+ return a.second < b.second;
+ });
+
+ if (!indents.empty()) {
+ if (tabIndented) {
+ m_ui->indentation->setText(tr("Mixed"));
+ } else {
+ m_ui->indentation->setText(tr("%1 Spaces").arg(max->first));
+ }
+ } else if (tabIndented) {
+ m_ui->indentation->setText(tr("Tabs"));
+ } else {
+ m_ui->indentation->setText(tr("Unknown"));
+ }
+}
+
void FilePropertiesDialog::refresh()
{
Utils::withNtfsPermissions<void>([this] {
@@ -71,7 +148,8 @@ void FilePropertiesDialog::refresh()
m_ui->name->setText(fileInfo.fileName());
m_ui->path->setText(QDir::toNativeSeparators(fileInfo.canonicalPath()));
- m_ui->mimeType->setText(Utils::mimeTypeForFile(fileInfo).name());
+ const Utils::MimeType mimeType = Utils::mimeTypeForFile(fileInfo);
+ m_ui->mimeType->setText(mimeType.name());
const Core::EditorFactoryList factories = Core::IEditorFactory::preferredEditorFactories(m_fileName);
m_ui->defaultEditor->setText(!factories.isEmpty() ? factories.at(0)->displayName() : tr("Undefined"));
@@ -85,6 +163,12 @@ void FilePropertiesDialog::refresh()
m_ui->symLink->setChecked(fileInfo.isSymLink());
m_ui->lastRead->setText(fileInfo.lastRead().toString(locale.dateTimeFormat()));
m_ui->lastModified->setText(fileInfo.lastModified().toString(locale.dateTimeFormat()));
+ if (mimeType.inherits("text/plain")) {
+ detectTextFileSettings();
+ } else {
+ m_ui->lineEndings->setText(tr("Unknown"));
+ m_ui->indentation->setText(tr("Unknown"));
+ }
});
}
diff --git a/src/plugins/coreplugin/dialogs/filepropertiesdialog.h b/src/plugins/coreplugin/dialogs/filepropertiesdialog.h
index 95d8bfbceb..3825748475 100644
--- a/src/plugins/coreplugin/dialogs/filepropertiesdialog.h
+++ b/src/plugins/coreplugin/dialogs/filepropertiesdialog.h
@@ -47,6 +47,7 @@ public:
private:
void refresh();
void setPermission(QFile::Permissions newPermissions, bool set);
+ void detectTextFileSettings();
private:
Ui::FilePropertiesDialog *m_ui = nullptr;
diff --git a/src/plugins/coreplugin/dialogs/filepropertiesdialog.ui b/src/plugins/coreplugin/dialogs/filepropertiesdialog.ui
index a9a9e10058..c194e0fad6 100644
--- a/src/plugins/coreplugin/dialogs/filepropertiesdialog.ui
+++ b/src/plugins/coreplugin/dialogs/filepropertiesdialog.ui
@@ -16,14 +16,14 @@
<layout class="QVBoxLayout" name="verticalLayout">
<item>
<layout class="QFormLayout" name="formLayout">
- <item row="4" column="0">
+ <item row="6" column="0">
<widget class="QLabel" name="label">
<property name="text">
<string>Owner:</string>
</property>
</widget>
</item>
- <item row="4" column="1">
+ <item row="6" column="1">
<widget class="QLabel" name="owner">
<property name="text">
<string/>
@@ -33,14 +33,14 @@
</property>
</widget>
</item>
- <item row="5" column="0">
+ <item row="7" column="0">
<widget class="QLabel" name="label_2">
<property name="text">
<string>Group:</string>
</property>
</widget>
</item>
- <item row="5" column="1">
+ <item row="7" column="1">
<widget class="QLabel" name="group">
<property name="text">
<string/>
@@ -50,14 +50,14 @@
</property>
</widget>
</item>
- <item row="6" column="0">
+ <item row="8" column="0">
<widget class="QLabel" name="label_3">
<property name="text">
<string>Size:</string>
</property>
</widget>
</item>
- <item row="6" column="1">
+ <item row="8" column="1">
<widget class="QLabel" name="size">
<property name="text">
<string/>
@@ -67,7 +67,7 @@
</property>
</widget>
</item>
- <item row="9" column="1">
+ <item row="11" column="1">
<widget class="QCheckBox" name="readable">
<property name="enabled">
<bool>true</bool>
@@ -80,7 +80,7 @@
</property>
</widget>
</item>
- <item row="10" column="1">
+ <item row="12" column="1">
<widget class="QCheckBox" name="writable">
<property name="enabled">
<bool>true</bool>
@@ -93,7 +93,7 @@
</property>
</widget>
</item>
- <item row="11" column="1">
+ <item row="13" column="1">
<widget class="QCheckBox" name="executable">
<property name="enabled">
<bool>true</bool>
@@ -106,7 +106,7 @@
</property>
</widget>
</item>
- <item row="12" column="1">
+ <item row="14" column="1">
<widget class="QCheckBox" name="symLink">
<property name="enabled">
<bool>false</bool>
@@ -119,7 +119,7 @@
</property>
</widget>
</item>
- <item row="7" column="1">
+ <item row="9" column="1">
<widget class="QLabel" name="lastRead">
<property name="text">
<string/>
@@ -129,7 +129,7 @@
</property>
</widget>
</item>
- <item row="8" column="1">
+ <item row="10" column="1">
<widget class="QLabel" name="lastModified">
<property name="text">
<string/>
@@ -173,42 +173,42 @@
</property>
</widget>
</item>
- <item row="7" column="0">
+ <item row="9" column="0">
<widget class="QLabel" name="label_6">
<property name="text">
<string>Last read:</string>
</property>
</widget>
</item>
- <item row="8" column="0">
+ <item row="10" column="0">
<widget class="QLabel" name="label_7">
<property name="text">
<string>Last modified:</string>
</property>
</widget>
</item>
- <item row="9" column="0">
+ <item row="11" column="0">
<widget class="QLabel" name="label_8">
<property name="text">
<string>Readable:</string>
</property>
</widget>
</item>
- <item row="10" column="0">
+ <item row="12" column="0">
<widget class="QLabel" name="label_9">
<property name="text">
<string>Writable:</string>
</property>
</widget>
</item>
- <item row="11" column="0">
+ <item row="13" column="0">
<widget class="QLabel" name="label_10">
<property name="text">
<string>Executable:</string>
</property>
</widget>
</item>
- <item row="12" column="0">
+ <item row="14" column="0">
<widget class="QLabel" name="label_11">
<property name="text">
<string>Symbolic link:</string>
@@ -243,6 +243,34 @@
</property>
</widget>
</item>
+ <item row="4" column="0">
+ <widget class="QLabel" name="label_14">
+ <property name="text">
+ <string>Line endings:</string>
+ </property>
+ </widget>
+ </item>
+ <item row="5" column="0">
+ <widget class="QLabel" name="label_15">
+ <property name="text">
+ <string>Indentation:</string>
+ </property>
+ </widget>
+ </item>
+ <item row="5" column="1">
+ <widget class="QLabel" name="indentation">
+ <property name="text">
+ <string/>
+ </property>
+ </widget>
+ </item>
+ <item row="4" column="1">
+ <widget class="QLabel" name="lineEndings">
+ <property name="text">
+ <string/>
+ </property>
+ </widget>
+ </item>
</layout>
</item>
<item>
diff --git a/src/plugins/coreplugin/dialogs/ioptionspage.cpp b/src/plugins/coreplugin/dialogs/ioptionspage.cpp
index a3a0f7eb38..6f03c23668 100644
--- a/src/plugins/coreplugin/dialogs/ioptionspage.cpp
+++ b/src/plugins/coreplugin/dialogs/ioptionspage.cpp
@@ -28,8 +28,11 @@
#include "ioptionspage.h"
-#include <utils/stringutils.h>
+#include <coreplugin/icore.h>
+
+#include <utils/aspects.h>
#include <utils/qtcassert.h>
+#include <utils/stringutils.h>
#include <QCheckBox>
#include <QGroupBox>
@@ -40,6 +43,8 @@
using namespace Utils;
+namespace Core {
+
/*!
\class Core::IOptionsPageProvider
\inmodule QtCreator
@@ -94,7 +99,7 @@ using namespace Utils;
Returns the category icon of the options page. This icon is displayed in the list on the left
side of the \uicontrol Options dialog.
*/
-QIcon Core::IOptionsPage::categoryIcon() const
+QIcon IOptionsPage::categoryIcon() const
{
return m_categoryIcon.icon();
}
@@ -103,7 +108,7 @@ QIcon Core::IOptionsPage::categoryIcon() const
Sets the \a widgetCreator callback to create page widgets on demand. The
widget will be destroyed on finish().
*/
-void Core::IOptionsPage::setWidgetCreator(const WidgetCreator &widgetCreator)
+void IOptionsPage::setWidgetCreator(const WidgetCreator &widgetCreator)
{
m_widgetCreator = widgetCreator;
}
@@ -119,11 +124,18 @@ void Core::IOptionsPage::setWidgetCreator(const WidgetCreator &widgetCreator)
Either override this function in a derived class, or set a widget creator.
*/
-QWidget *Core::IOptionsPage::widget()
+QWidget *IOptionsPage::widget()
{
- QTC_ASSERT(m_widgetCreator, return nullptr);
- if (!m_widget)
- m_widget = m_widgetCreator();
+ if (!m_widget) {
+ if (m_widgetCreator) {
+ m_widget = m_widgetCreator();
+ } else if (m_layouter) {
+ m_widget = new QWidget;
+ m_layouter(m_widget);
+ } else {
+ QTC_CHECK(false);
+ }
+ }
return m_widget;
}
@@ -136,11 +148,16 @@ QWidget *Core::IOptionsPage::widget()
\sa setWidgetCreator()
*/
-void Core::IOptionsPage::apply()
+void IOptionsPage::apply()
{
- QTC_ASSERT(m_widgetCreator, return);
- if (m_widget)
- m_widget->apply();
+ if (auto widget = qobject_cast<IOptionsPageWidget *>(m_widget)) {
+ widget->apply();
+ } else if (m_settings) {
+ if (m_settings->isDirty()) {
+ m_settings->apply();
+ m_settings->writeSettings(ICore::settings());
+ }
+ }
}
/*!
@@ -152,24 +169,35 @@ void Core::IOptionsPage::apply()
\sa setWidgetCreator()
*/
-void Core::IOptionsPage::finish()
+void IOptionsPage::finish()
{
- QTC_ASSERT(m_widgetCreator, return);
- if (m_widget) {
- m_widget->finish();
- delete m_widget;
- }
+ if (auto widget = qobject_cast<IOptionsPageWidget *>(m_widget))
+ widget->finish();
+ else if (m_settings)
+ m_settings->finish();
+
+ delete m_widget;
}
/*!
Sets \a categoryIconPath as the path to the category icon of the options
page.
*/
-void Core::IOptionsPage::setCategoryIconPath(const QString &categoryIconPath)
+void IOptionsPage::setCategoryIconPath(const QString &categoryIconPath)
{
m_categoryIcon = Icon({{categoryIconPath, Theme::PanelTextColorDark}}, Icon::Tint);
}
+void IOptionsPage::setSettings(AspectContainer *settings)
+{
+ m_settings = settings;
+}
+
+void IOptionsPage::setLayouter(const std::function<void(QWidget *w)> &layouter)
+{
+ m_layouter = layouter;
+}
+
/*!
\fn void Core::IOptionsPage::setId(Utils::Id id)
@@ -200,13 +228,13 @@ void Core::IOptionsPage::setCategoryIconPath(const QString &categoryIconPath)
Sets \a categoryIcon as the category icon of the options page.
*/
-static QList<Core::IOptionsPage *> g_optionsPages;
+static QList<IOptionsPage *> g_optionsPages;
/*!
Constructs an options page with the given \a parent and registers it
at the global options page pool if \a registerGlobally is \c true.
*/
-Core::IOptionsPage::IOptionsPage(QObject *parent, bool registerGlobally)
+IOptionsPage::IOptionsPage(QObject *parent, bool registerGlobally)
: QObject(parent)
{
if (registerGlobally)
@@ -216,7 +244,7 @@ Core::IOptionsPage::IOptionsPage(QObject *parent, bool registerGlobally)
/*!
\internal
*/
-Core::IOptionsPage::~IOptionsPage()
+IOptionsPage::~IOptionsPage()
{
g_optionsPages.removeOne(this);
}
@@ -224,7 +252,7 @@ Core::IOptionsPage::~IOptionsPage()
/*!
Returns a list of all options pages.
*/
-const QList<Core::IOptionsPage *> Core::IOptionsPage::allOptionsPages()
+const QList<IOptionsPage *> IOptionsPage::allOptionsPages()
{
return g_optionsPages;
}
@@ -234,7 +262,7 @@ const QList<Core::IOptionsPage *> Core::IOptionsPage::allOptionsPages()
page. This defaults to take the widget and then looks for all child labels, check boxes, push
buttons, and group boxes. Should return \c true when a match is found.
*/
-bool Core::IOptionsPage::matches(const QRegularExpression &regexp) const
+bool IOptionsPage::matches(const QRegularExpression &regexp) const
{
if (!m_keywordsInitialized) {
auto that = const_cast<IOptionsPage *>(this);
@@ -259,25 +287,27 @@ bool Core::IOptionsPage::matches(const QRegularExpression &regexp) const
return false;
}
-static QList<Core::IOptionsPageProvider *> g_optionsPagesProviders;
+static QList<IOptionsPageProvider *> g_optionsPagesProviders;
-Core::IOptionsPageProvider::IOptionsPageProvider(QObject *parent)
+IOptionsPageProvider::IOptionsPageProvider(QObject *parent)
: QObject(parent)
{
g_optionsPagesProviders.append(this);
}
-Core::IOptionsPageProvider::~IOptionsPageProvider()
+IOptionsPageProvider::~IOptionsPageProvider()
{
g_optionsPagesProviders.removeOne(this);
}
-const QList<Core::IOptionsPageProvider *> Core::IOptionsPageProvider::allOptionsPagesProviders()
+const QList<IOptionsPageProvider *> IOptionsPageProvider::allOptionsPagesProviders()
{
return g_optionsPagesProviders;
}
-QIcon Core::IOptionsPageProvider::categoryIcon() const
+QIcon IOptionsPageProvider::categoryIcon() const
{
return m_categoryIcon.icon();
}
+
+} // Core
diff --git a/src/plugins/coreplugin/dialogs/ioptionspage.h b/src/plugins/coreplugin/dialogs/ioptionspage.h
index 36ee209b38..abc0bf9350 100644
--- a/src/plugins/coreplugin/dialogs/ioptionspage.h
+++ b/src/plugins/coreplugin/dialogs/ioptionspage.h
@@ -37,10 +37,13 @@
#include <functional>
+namespace Utils { class AspectContainer; };
+
namespace Core {
class CORE_EXPORT IOptionsPageWidget : public QWidget
{
+ Q_OBJECT
public:
virtual void apply() = 0;
virtual void finish() {}
@@ -77,6 +80,8 @@ protected:
void setDisplayCategory(const QString &displayCategory) { m_displayCategory = displayCategory; }
void setCategoryIcon(const Utils::Icon &categoryIcon) { m_categoryIcon = categoryIcon; }
void setCategoryIconPath(const QString &categoryIconPath);
+ void setSettings(Utils::AspectContainer *settings);
+ void setLayouter(const std::function<void(QWidget *w)> &layouter);
Utils::Id m_id;
Utils::Id m_category;
@@ -84,10 +89,13 @@ protected:
QString m_displayCategory;
Utils::Icon m_categoryIcon;
WidgetCreator m_widgetCreator;
- QPointer<IOptionsPageWidget> m_widget; // Used in conjunction with m_widgetCreator
+ QPointer<QWidget> m_widget; // Used in conjunction with m_widgetCreator
mutable bool m_keywordsInitialized = false;
mutable QStringList m_keywords;
+
+ Utils::AspectContainer *m_settings = nullptr;
+ std::function<void(QWidget *w)> m_layouter;
};
/*
diff --git a/src/plugins/coreplugin/dialogs/shortcutsettings.cpp b/src/plugins/coreplugin/dialogs/shortcutsettings.cpp
index 83b6c279ce..5dec4bb4f9 100644
--- a/src/plugins/coreplugin/dialogs/shortcutsettings.cpp
+++ b/src/plugins/coreplugin/dialogs/shortcutsettings.cpp
@@ -52,6 +52,9 @@ using namespace Utils;
Q_DECLARE_METATYPE(Core::Internal::ShortcutItem*)
+namespace Core {
+namespace Internal {
+
const char kSeparator[] = " | ";
static int translateModifiers(Qt::KeyboardModifiers state,
@@ -145,8 +148,10 @@ static bool isTextKeySequence(const QKeySequence &sequence)
return false;
}
-namespace Core {
-namespace Internal {
+static FilePath schemesPath()
+{
+ return Core::ICore::resourcePath("schemes");
+}
ShortcutButton::ShortcutButton(QWidget *parent)
: QPushButton(parent)
@@ -485,9 +490,10 @@ void ShortcutSettingsWidget::resetToDefault()
void ShortcutSettingsWidget::importAction()
{
- QString fileName = QFileDialog::getOpenFileName(ICore::dialogParent(), tr("Import Keyboard Mapping Scheme"),
- ICore::resourcePath() + QLatin1String("/schemes/"),
- tr("Keyboard Mapping Scheme (*.kms)"));
+ QString fileName = QFileDialog::getOpenFileName(ICore::dialogParent(),
+ tr("Import Keyboard Mapping Scheme"),
+ schemesPath().toString(),
+ tr("Keyboard Mapping Scheme (*.kms)"));
if (!fileName.isEmpty()) {
CommandsFile cf(fileName);
@@ -524,10 +530,10 @@ void ShortcutSettingsWidget::defaultAction()
void ShortcutSettingsWidget::exportAction()
{
- QString fileName = DocumentManager::getSaveFileNameWithExtension(
- tr("Export Keyboard Mapping Scheme"),
- ICore::resourcePath() + QLatin1String("/schemes/"),
- tr("Keyboard Mapping Scheme (*.kms)"));
+ QString fileName
+ = DocumentManager::getSaveFileNameWithExtension(tr("Export Keyboard Mapping Scheme"),
+ schemesPath().toString(),
+ tr("Keyboard Mapping Scheme (*.kms)"));
if (!fileName.isEmpty()) {
CommandsFile cf(fileName);
cf.exportCommands(m_scitems);
diff --git a/src/plugins/coreplugin/documentmanager.cpp b/src/plugins/coreplugin/documentmanager.cpp
index 904f82f850..7189182736 100644
--- a/src/plugins/coreplugin/documentmanager.cpp
+++ b/src/plugins/coreplugin/documentmanager.cpp
@@ -744,17 +744,19 @@ static bool saveModifiedFilesHelper(const QList<IDocument *> &documents,
return notSaved.isEmpty();
}
-bool DocumentManager::saveDocument(IDocument *document, const QString &fileName, bool *isReadOnly)
+bool DocumentManager::saveDocument(IDocument *document,
+ const Utils::FilePath &filePath,
+ bool *isReadOnly)
{
bool ret = true;
- QString effName = fileName.isEmpty() ? document->filePath().toString() : fileName;
- expectFileChange(effName); // This only matters to other IDocuments which refer to this file
+ const Utils::FilePath &savePath = filePath.isEmpty() ? document->filePath() : filePath;
+ expectFileChange(savePath.toString()); // This only matters to other IDocuments which refer to this file
bool addWatcher = removeDocument(document); // So that our own IDocument gets no notification at all
QString errorString;
- if (!document->save(&errorString, fileName, false)) {
+ if (!document->save(&errorString, filePath, false)) {
if (isReadOnly) {
- QFile ofi(effName);
+ QFile ofi(savePath.toString());
// Check whether the existing file is writable
if (!ofi.open(QIODevice::ReadWrite) && ofi.open(QIODevice::ReadOnly)) {
*isReadOnly = true;
@@ -769,7 +771,7 @@ bool DocumentManager::saveDocument(IDocument *document, const QString &fileName,
}
addDocument(document, addWatcher);
- unexpectFileChange(effName);
+ unexpectFileChange(savePath.toString());
m_instance->updateSaveAll();
return ret;
}
@@ -1314,7 +1316,7 @@ void DocumentManager::checkForReload()
// handle deleted files
EditorManager::closeDocuments(documentsToClose, false);
for (auto it = documentsToSave.cbegin(), end = documentsToSave.cend(); it != end; ++it) {
- saveDocument(it.key(), it.value());
+ saveDocument(it.key(), Utils::FilePath::fromString(it.value()));
it.key()->checkPermissions();
}
@@ -1375,7 +1377,9 @@ void DocumentManager::saveSettings()
s->setValueWithDefault(editorsKeyC, recentEditorIds);
s->endGroup();
s->beginGroup(directoryGroupC);
- s->setValueWithDefault(projectDirectoryKeyC, d->m_projectsDirectory.toString());
+ s->setValueWithDefault(projectDirectoryKeyC,
+ d->m_projectsDirectory.toString(),
+ PathChooser::homePath());
s->setValueWithDefault(useProjectDirectoryKeyC,
d->m_useProjectsDirectory,
kUseProjectsDirectoryDefault);
diff --git a/src/plugins/coreplugin/documentmanager.h b/src/plugins/coreplugin/documentmanager.h
index f05c7d0f10..4072187ba8 100644
--- a/src/plugins/coreplugin/documentmanager.h
+++ b/src/plugins/coreplugin/documentmanager.h
@@ -27,6 +27,7 @@
#include <coreplugin/core_global.h>
+#include <utils/fileutils.h>
#include <utils/id.h>
#include <QObject>
@@ -79,7 +80,7 @@ public:
static QString filePathKey(const QString &filePath, ResolveMode resolveMode);
static bool saveDocument(IDocument *document,
- const QString &fileName = QString(),
+ const Utils::FilePath &filePath = Utils::FilePath(),
bool *isReadOnly = nullptr);
static QString allDocumentFactoryFiltersString(QString *allFilesFilter);
diff --git a/src/plugins/coreplugin/editormanager/editormanager.cpp b/src/plugins/coreplugin/editormanager/editormanager.cpp
index 1e254813ba..206598b238 100644
--- a/src/plugins/coreplugin/editormanager/editormanager.cpp
+++ b/src/plugins/coreplugin/editormanager/editormanager.cpp
@@ -68,6 +68,7 @@
#include <utils/fileutils.h>
#include <utils/hostosinfo.h>
#include <utils/infobar.h>
+#include <utils/link.h>
#include <utils/macroexpander.h>
#include <utils/mimetypes/mimedatabase.h>
#include <utils/mimetypes/mimetype.h>
@@ -740,22 +741,23 @@ EditorArea *EditorManagerPrivate::mainEditorArea()
return d->m_editorAreas.at(0);
}
-bool EditorManagerPrivate::skipOpeningBigTextFile(const QString &filePath)
+bool EditorManagerPrivate::skipOpeningBigTextFile(const FilePath &filePath)
{
- if (!d->m_warnBeforeOpeningBigFilesEnabled)
+ if (!d->m_settings.warnBeforeOpeningBigFilesEnabled)
return false;
- if (!QFileInfo::exists(filePath))
+ if (!filePath.exists())
return false;
- Utils::MimeType mimeType = Utils::mimeTypeForFile(filePath);
+ Utils::MimeType mimeType = Utils::mimeTypeForFile(filePath.toString());
if (!mimeType.inherits("text/plain"))
return false;
- const QFileInfo fileInfo(filePath);
+ const QFileInfo fileInfo = filePath.toFileInfo();
const qint64 fileSize = fileInfo.size();
const double fileSizeInMB = fileSize / 1000.0 / 1000.0;
- if (fileSizeInMB > d->m_bigFileSizeLimitInMB && fileSize < EditorManager::maxTextFileSize()) {
+ if (fileSizeInMB > d->m_settings.bigFileSizeLimitInMB
+ && fileSize < EditorManager::maxTextFileSize()) {
const QString title = EditorManager::tr("Continue Opening Huge Text File?");
const QString text = EditorManager::tr(
"The text file \"%1\" has the size %2MB and might take more memory to open"
@@ -781,29 +783,16 @@ bool EditorManagerPrivate::skipOpeningBigTextFile(const QString &filePath)
return false;
}
-IEditor *EditorManagerPrivate::openEditor(EditorView *view, const QString &fileName, Id editorId,
+IEditor *EditorManagerPrivate::openEditor(EditorView *view, const FilePath &filePath, Id editorId,
EditorManager::OpenEditorFlags flags, bool *newEditor)
{
if (debugEditorManager)
- qDebug() << Q_FUNC_INFO << fileName << editorId.name();
-
- QString fn = fileName;
- QFileInfo fi(fn);
- int lineNumber = -1;
- int columnNumber = -1;
- if ((flags & EditorManager::CanContainLineAndColumnNumber) && !fi.exists()) {
- const EditorManager::FilePathInfo fp = EditorManager::splitLineAndColumnNumber(fn);
- fn = Utils::FileUtils::normalizePathName(fp.filePath);
- lineNumber = fp.lineNumber;
- columnNumber = fp.columnNumber;
- } else {
- fn = Utils::FileUtils::normalizePathName(fn);
- }
+ qDebug() << Q_FUNC_INFO << filePath << editorId.name();
+ const QString fn = Utils::FileUtils::normalizePathName(filePath.toString());
if (fn.isEmpty())
return nullptr;
- if (fn != fileName)
- fi.setFile(fn);
+ const QFileInfo fi(fn);
if (newEditor)
*newEditor = false;
@@ -822,10 +811,7 @@ IEditor *EditorManagerPrivate::openEditor(EditorView *view, const QString &fileN
}
}
}
- editor = activateEditor(view, editor, flags);
- if (editor && flags & EditorManager::CanContainLineAndColumnNumber)
- editor->gotoLine(lineNumber, columnNumber);
- return editor;
+ return activateEditor(view, editor, flags);
}
QString realFn = autoSaveName(fn);
@@ -854,12 +840,15 @@ IEditor *EditorManagerPrivate::openEditor(EditorView *view, const QString &fileN
}
}
- if (skipOpeningBigTextFile(fileName))
+ if (skipOpeningBigTextFile(filePath))
return nullptr;
IEditor *editor = nullptr;
auto overrideCursor = Utils::OverrideCursor(QCursor(Qt::WaitCursor));
+ auto fp = Utils::FilePath::fromString(fn);
+ auto realFp = Utils::FilePath::fromString(realFn);
+
IEditorFactory *factory = factories.takeFirst();
while (factory) {
editor = createEditor(factory, fn);
@@ -869,7 +858,7 @@ IEditor *EditorManagerPrivate::openEditor(EditorView *view, const QString &fileN
}
QString errorString;
- IDocument::OpenResult openResult = editor->document()->open(&errorString, fn, realFn);
+ IDocument::OpenResult openResult = editor->document()->open(&errorString, fp, realFp);
if (openResult == IDocument::OpenResult::Success)
break;
@@ -932,7 +921,7 @@ IEditor *EditorManagerPrivate::openEditor(EditorView *view, const QString &fileN
return nullptr;
if (realFn != fn)
- editor->document()->setRestoredFrom(realFn);
+ editor->document()->setRestoredFrom(realFp);
addEditor(editor);
if (newEditor)
@@ -942,32 +931,30 @@ IEditor *EditorManagerPrivate::openEditor(EditorView *view, const QString &fileN
if (editor == result)
restoreEditorState(editor);
- if (flags & EditorManager::CanContainLineAndColumnNumber)
- editor->gotoLine(lineNumber, columnNumber);
-
return result;
}
-IEditor *EditorManagerPrivate::openEditorAt(EditorView *view, const QString &fileName, int line,
- int column, Id editorId,
- EditorManager::OpenEditorFlags flags, bool *newEditor)
+IEditor *EditorManagerPrivate::openEditorAt(EditorView *view,
+ const Link &link,
+ Id editorId,
+ EditorManager::OpenEditorFlags flags,
+ bool *newEditor)
{
EditorManager::cutForwardNavigationHistory();
EditorManager::addCurrentPositionToNavigationHistory();
EditorManager::OpenEditorFlags tempFlags = flags | EditorManager::IgnoreNavigationHistory;
- IEditor *editor = openEditor(view, fileName, editorId, tempFlags, newEditor);
- if (editor && line != -1)
- editor->gotoLine(line, column);
+ IEditor *editor = openEditor(view, link.targetFilePath, editorId, tempFlags, newEditor);
+ if (editor && link.targetLine != -1)
+ editor->gotoLine(link.targetLine, link.targetColumn);
return editor;
}
-IEditor *EditorManagerPrivate::openEditorWith(const QString &fileName, Utils::Id editorId)
+IEditor *EditorManagerPrivate::openEditorWith(const FilePath &filePath, Id editorId)
{
// close any open editors that have this file open
// remember the views to open new editors in there
QList<EditorView *> views;
- QList<IEditor *> editorsOpenForFile = DocumentModel::editorsForFilePath(
- FilePath::fromString(fileName));
+ QList<IEditor *> editorsOpenForFile = DocumentModel::editorsForFilePath(filePath);
foreach (IEditor *openEditor, editorsOpenForFile) {
EditorView *view = EditorManagerPrivate::viewForEditor(openEditor);
if (view && view->currentEditor() == openEditor) // visible
@@ -978,7 +965,7 @@ IEditor *EditorManagerPrivate::openEditorWith(const QString &fileName, Utils::Id
IEditor *openedEditor = nullptr;
if (views.isEmpty()) {
- openedEditor = EditorManager::openEditor(fileName, editorId);
+ openedEditor = EditorManager::openEditor(filePath, editorId);
} else {
if (EditorView *currentView = EditorManagerPrivate::currentEditorView()) {
if (views.removeOne(currentView))
@@ -986,7 +973,7 @@ IEditor *EditorManagerPrivate::openEditorWith(const QString &fileName, Utils::Id
}
EditorManager::OpenEditorFlags flags;
foreach (EditorView *view, views) {
- IEditor *editor = EditorManagerPrivate::openEditor(view, fileName, editorId, flags);
+ IEditor *editor = EditorManagerPrivate::openEditor(view, filePath, editorId, flags);
if (!openedEditor && editor)
openedEditor = editor;
// Do not change the current editor after opening the first one. That
@@ -1246,39 +1233,52 @@ void EditorManagerPrivate::saveSettings()
{
ICore::settingsDatabase()->setValue(documentStatesKey, d->m_editorStates);
- QSettings *qsettings = ICore::settings();
- qsettings->setValue(reloadBehaviorKey, d->m_reloadSetting);
- qsettings->setValue(autoSaveEnabledKey, d->m_autoSaveEnabled);
- qsettings->setValue(autoSaveIntervalKey, d->m_autoSaveInterval);
- qsettings->setValue(autoSuspendEnabledKey, d->m_autoSuspendEnabled);
- qsettings->setValue(autoSuspendMinDocumentCountKey, d->m_autoSuspendMinDocumentCount);
- qsettings->setValue(warnBeforeOpeningBigTextFilesKey,
- d->m_warnBeforeOpeningBigFilesEnabled);
- qsettings->setValue(bigTextFileSizeLimitKey, d->m_bigFileSizeLimitInMB);
- qsettings->setValue(maxRecentFilesKey, d->m_maxRecentFiles);
-
- Qt::CaseSensitivity defaultSensitivity
- = OsSpecificAspects::fileNameCaseSensitivity(HostOsInfo::hostOs());
- Qt::CaseSensitivity sensitivity = HostOsInfo::fileNameCaseSensitivity();
- if (defaultSensitivity == sensitivity)
- qsettings->remove(fileSystemCaseSensitivityKey);
- else
- qsettings->setValue(fileSystemCaseSensitivityKey, sensitivity);
- qsettings->setValue(preferredEditorFactoriesKey, toMap(userPreferredEditorFactories()));
+ const Settings def;
+ QtcSettings *qsettings = ICore::settings();
+ qsettings->setValueWithDefault(reloadBehaviorKey,
+ int(d->m_settings.reloadSetting),
+ int(def.reloadSetting));
+ qsettings->setValueWithDefault(autoSaveEnabledKey,
+ d->m_settings.autoSaveEnabled,
+ def.autoSaveEnabled);
+ qsettings->setValueWithDefault(autoSaveIntervalKey,
+ d->m_settings.autoSaveInterval,
+ def.autoSaveInterval);
+ qsettings->setValueWithDefault(autoSuspendEnabledKey,
+ d->m_settings.autoSuspendEnabled,
+ def.autoSuspendEnabled);
+ qsettings->setValueWithDefault(autoSuspendMinDocumentCountKey,
+ d->m_settings.autoSuspendMinDocumentCount,
+ def.autoSuspendMinDocumentCount);
+ qsettings->setValueWithDefault(warnBeforeOpeningBigTextFilesKey,
+ d->m_settings.warnBeforeOpeningBigFilesEnabled,
+ def.warnBeforeOpeningBigFilesEnabled);
+ qsettings->setValueWithDefault(bigTextFileSizeLimitKey,
+ d->m_settings.bigFileSizeLimitInMB,
+ def.bigFileSizeLimitInMB);
+ qsettings->setValueWithDefault(maxRecentFilesKey,
+ d->m_settings.maxRecentFiles,
+ def.maxRecentFiles);
+
+ qsettings->setValueWithDefault(fileSystemCaseSensitivityKey,
+ HostOsInfo::fileNameCaseSensitivity(),
+ OsSpecificAspects::fileNameCaseSensitivity(HostOsInfo::hostOs()));
+ qsettings->setValueWithDefault(preferredEditorFactoriesKey,
+ toMap(userPreferredEditorFactories()));
}
void EditorManagerPrivate::readSettings()
{
+ Settings def;
QSettings *qs = ICore::settings();
- if (qs->contains(warnBeforeOpeningBigTextFilesKey)) {
- d->m_warnBeforeOpeningBigFilesEnabled
- = qs->value(warnBeforeOpeningBigTextFilesKey).toBool();
- d->m_bigFileSizeLimitInMB = qs->value(bigTextFileSizeLimitKey).toInt();
- }
+ d->m_settings.warnBeforeOpeningBigFilesEnabled
+ = qs->value(warnBeforeOpeningBigTextFilesKey, def.warnBeforeOpeningBigFilesEnabled).toBool();
+ d->m_settings.bigFileSizeLimitInMB
+ = qs->value(bigTextFileSizeLimitKey, def.bigFileSizeLimitInMB).toInt();
- const int maxRecentFiles = qs->value(maxRecentFilesKey).toInt();
+ const int maxRecentFiles = qs->value(maxRecentFilesKey, def.maxRecentFiles).toInt();
if (maxRecentFiles > 0)
- d->m_maxRecentFiles = maxRecentFiles;
+ d->m_settings.maxRecentFiles = maxRecentFiles;
if (qs->contains(fileSystemCaseSensitivityKey)) {
Qt::CaseSensitivity defaultSensitivity
@@ -1310,104 +1310,90 @@ void EditorManagerPrivate::readSettings()
.value<QMap<QString, QVariant> >();
}
- if (settings->contains(reloadBehaviorKey)) {
- d->m_reloadSetting = IDocument::ReloadSetting(settings->value(reloadBehaviorKey).toInt());
- settings->remove(reloadBehaviorKey);
- }
-
- if (settings->contains(autoSaveEnabledKey)) {
- d->m_autoSaveEnabled = settings->value(autoSaveEnabledKey).toBool();
- d->m_autoSaveInterval = settings->value(autoSaveIntervalKey).toInt();
- settings->remove(autoSaveEnabledKey);
- settings->remove(autoSaveIntervalKey);
- }
+ d->m_settings.reloadSetting = IDocument::ReloadSetting(
+ qs->value(reloadBehaviorKey, def.reloadSetting).toInt());
- if (qs->contains(reloadBehaviorKey))
- d->m_reloadSetting = IDocument::ReloadSetting(qs->value(reloadBehaviorKey).toInt());
+ d->m_settings.autoSaveEnabled = qs->value(autoSaveEnabledKey, def.autoSaveEnabled).toBool();
+ d->m_settings.autoSaveInterval = qs->value(autoSaveIntervalKey, def.autoSaveInterval).toInt();
- if (qs->contains(autoSaveEnabledKey)) {
- d->m_autoSaveEnabled = qs->value(autoSaveEnabledKey).toBool();
- d->m_autoSaveInterval = qs->value(autoSaveIntervalKey).toInt();
- }
-
- if (qs->contains(autoSuspendEnabledKey)) {
- d->m_autoSuspendEnabled = qs->value(autoSuspendEnabledKey).toBool();
- d->m_autoSuspendMinDocumentCount = qs->value(autoSuspendMinDocumentCountKey).toInt();
- }
+ d->m_settings.autoSuspendEnabled = qs->value(autoSuspendEnabledKey, def.autoSuspendEnabled)
+ .toBool();
+ d->m_settings.autoSuspendMinDocumentCount
+ = qs->value(autoSuspendMinDocumentCountKey, def.autoSuspendMinDocumentCount).toInt();
updateAutoSave();
}
void EditorManagerPrivate::setAutoSaveEnabled(bool enabled)
{
- d->m_autoSaveEnabled = enabled;
+ d->m_settings.autoSaveEnabled = enabled;
updateAutoSave();
}
bool EditorManagerPrivate::autoSaveEnabled()
{
- return d->m_autoSaveEnabled;
+ return d->m_settings.autoSaveEnabled;
}
void EditorManagerPrivate::setAutoSaveInterval(int interval)
{
- d->m_autoSaveInterval = interval;
+ d->m_settings.autoSaveInterval = interval;
updateAutoSave();
}
int EditorManagerPrivate::autoSaveInterval()
{
- return d->m_autoSaveInterval;
+ return d->m_settings.autoSaveInterval;
}
void EditorManagerPrivate::setAutoSuspendEnabled(bool enabled)
{
- d->m_autoSuspendEnabled = enabled;
+ d->m_settings.autoSuspendEnabled = enabled;
}
bool EditorManagerPrivate::autoSuspendEnabled()
{
- return d->m_autoSuspendEnabled;
+ return d->m_settings.autoSuspendEnabled;
}
void EditorManagerPrivate::setAutoSuspendMinDocumentCount(int count)
{
- d->m_autoSuspendMinDocumentCount = count;
+ d->m_settings.autoSuspendMinDocumentCount = count;
}
int EditorManagerPrivate::autoSuspendMinDocumentCount()
{
- return d->m_autoSuspendMinDocumentCount;
+ return d->m_settings.autoSuspendMinDocumentCount;
}
bool EditorManagerPrivate::warnBeforeOpeningBigFilesEnabled()
{
- return d->m_warnBeforeOpeningBigFilesEnabled;
+ return d->m_settings.warnBeforeOpeningBigFilesEnabled;
}
void EditorManagerPrivate::setWarnBeforeOpeningBigFilesEnabled(bool enabled)
{
- d->m_warnBeforeOpeningBigFilesEnabled = enabled;
+ d->m_settings.warnBeforeOpeningBigFilesEnabled = enabled;
}
int EditorManagerPrivate::bigFileSizeLimit()
{
- return d->m_bigFileSizeLimitInMB;
+ return d->m_settings.bigFileSizeLimitInMB;
}
void EditorManagerPrivate::setMaxRecentFiles(int count)
{
- d->m_maxRecentFiles = count;
+ d->m_settings.maxRecentFiles = count;
}
int EditorManagerPrivate::maxRecentFiles()
{
- return d->m_maxRecentFiles;
+ return d->m_settings.maxRecentFiles;
}
void EditorManagerPrivate::setBigFileSizeLimit(int limitInMB)
{
- d->m_bigFileSizeLimitInMB = limitInMB;
+ d->m_settings.bigFileSizeLimitInMB = limitInMB;
}
EditorFactoryList EditorManagerPrivate::findFactories(Id editorId, const QString &fileName)
@@ -1589,7 +1575,7 @@ bool EditorManagerPrivate::activateEditorForEntry(EditorView *view, DocumentMode
return editor != nullptr;
}
- if (!openEditor(view, entry->fileName().toString(), entry->id(), flags)) {
+ if (!openEditor(view, entry->fileName(), entry->id(), flags)) {
DocumentModelPrivate::removeEntry(entry);
return false;
}
@@ -2005,8 +1991,8 @@ void EditorManagerPrivate::addDocumentToRecentFiles(IDocument *document)
void EditorManagerPrivate::updateAutoSave()
{
- if (d->m_autoSaveEnabled)
- d->m_autoSaveTimer->start(d->m_autoSaveInterval * (60 * 1000));
+ if (d->m_settings.autoSaveEnabled)
+ d->m_autoSaveTimer->start(d->m_settings.autoSaveInterval * (60 * 1000));
else
d->m_autoSaveTimer->stop();
}
@@ -2351,7 +2337,7 @@ void EditorManagerPrivate::autoSave()
|| !QFileInfo(savePath).isWritable()) // FIXME: save them to a dedicated directory
continue;
QString errorString;
- if (!document->autoSave(&errorString, saveName))
+ if (!document->autoSave(&errorString, Utils::FilePath::fromUserInput(saveName)))
errors << errorString;
}
if (!errors.isEmpty())
@@ -2463,7 +2449,7 @@ bool EditorManagerPrivate::saveDocument(IDocument *document)
emit m_instance->aboutToSave(document);
// try saving, no matter what isReadOnly tells us
- success = DocumentManager::saveDocument(document, QString(), &isReadOnly);
+ success = DocumentManager::saveDocument(document, FilePath(), &isReadOnly);
if (!success && isReadOnly) {
MakeWritableResult answer = makeFileWritable(document);
@@ -2503,7 +2489,7 @@ bool EditorManagerPrivate::saveDocumentAs(IDocument *document)
}
emit m_instance->aboutToSave(document);
- const bool success = DocumentManager::saveDocument(document, absoluteFilePath.toString());
+ const bool success = DocumentManager::saveDocument(document, absoluteFilePath);
document->checkPermissions();
// TODO: There is an issue to be treated here. The new file might be of a different mime
@@ -2574,7 +2560,7 @@ void EditorManagerPrivate::revertToSaved(IDocument *document)
void EditorManagerPrivate::autoSuspendDocuments()
{
- if (!d->m_autoSuspendEnabled)
+ if (!d->m_settings.autoSuspendEnabled)
return;
auto visibleDocuments = Utils::transform<QSet>(EditorManager::visibleEditors(),
@@ -2587,7 +2573,7 @@ void EditorManagerPrivate::autoSuspendDocuments()
|| document->isTemporary() || document->filePath().isEmpty()
|| visibleDocuments.contains(document))
continue;
- if (keptEditorCount >= d->m_autoSuspendMinDocumentCount)
+ if (keptEditorCount >= d->m_settings.autoSuspendMinDocumentCount)
documentsToSuspend.append(document);
else
++keptEditorCount;
@@ -2929,7 +2915,7 @@ void EditorManager::populateOpenWithMenu(QMenu *menu, const QString &fileName)
// while the menu is still being processed.
connect(action, &QAction::triggered, d,
[fileName, editorId]() {
- EditorManagerPrivate::openEditorWith(fileName, editorId);
+ EditorManagerPrivate::openEditorWith(FilePath::fromString(fileName), editorId);
}, Qt::QueuedConnection);
}
// Add all suitable external editors
@@ -2937,7 +2923,7 @@ void EditorManager::populateOpenWithMenu(QMenu *menu, const QString &fileName)
QAction *action = menu->addAction(externalEditor->displayName());
Utils::Id editorId = externalEditor->id();
connect(action, &QAction::triggered, [fileName, editorId]() {
- EditorManager::openExternalEditor(fileName, editorId);
+ EditorManager::openExternalEditor(FilePath::fromString(fileName), editorId);
});
}
}
@@ -2949,7 +2935,7 @@ void EditorManager::populateOpenWithMenu(QMenu *menu, const QString &fileName)
*/
IDocument::ReloadSetting EditorManager::reloadSetting()
{
- return d->m_reloadSetting;
+ return d->m_settings.reloadSetting;
}
/*!
@@ -2959,7 +2945,7 @@ IDocument::ReloadSetting EditorManager::reloadSetting()
*/
void EditorManager::setReloadSetting(IDocument::ReloadSetting behavior)
{
- d->m_reloadSetting = behavior;
+ d->m_settings.reloadSetting = behavior;
}
/*!
@@ -3058,7 +3044,7 @@ IEditor *EditorManager::activateEditorForDocument(IDocument *document, OpenEdito
}
/*!
- Opens the document specified by \a fileName using the editor type \a
+ Opens the document specified by \a filePath using the editor type \a
editorId and the specified \a flags.
If \a editorId is \c Id(), the editor type is derived from the file's MIME
@@ -3072,18 +3058,27 @@ IEditor *EditorManager::activateEditorForDocument(IDocument *document, OpenEdito
\sa openEditorWithContents()
\sa openExternalEditor()
*/
-IEditor *EditorManager::openEditor(const QString &fileName, Id editorId,
+IEditor *EditorManager::openEditor(const FilePath &filePath, Id editorId,
OpenEditorFlags flags, bool *newEditor)
{
if (flags & EditorManager::OpenInOtherSplit)
EditorManager::gotoOtherSplit();
return EditorManagerPrivate::openEditor(EditorManagerPrivate::currentEditorView(),
- fileName, editorId, flags, newEditor);
+ filePath, editorId, flags, newEditor);
+}
+
+IEditor *EditorManager::openEditor(const QString &fileName, Id editorId,
+ OpenEditorFlags flags, bool *newEditor)
+{
+ QFileInfo fi(fileName);
+ if ((flags & CanContainLineAndColumnNumber) && !fi.exists())
+ return openEditorAt(Link::fromString(fileName, true), editorId, flags, newEditor);
+ return openEditor(FilePath::fromString(fileName), editorId, flags, newEditor);
}
/*!
- Opens the document specified by \a fileName using the editor type \a
+ Opens the document specified by \a filePath using the editor type \a
editorId and the specified \a flags.
Moves the text cursor to the \a line and \a column.
@@ -3101,14 +3096,25 @@ IEditor *EditorManager::openEditor(const QString &fileName, Id editorId,
\sa openExternalEditor()
\sa IEditor::gotoLine()
*/
-IEditor *EditorManager::openEditorAt(const QString &fileName, int line, int column,
- Id editorId, OpenEditorFlags flags, bool *newEditor)
+IEditor *EditorManager::openEditorAt(const Link &link,
+ Id editorId,
+ OpenEditorFlags flags,
+ bool *newEditor)
{
if (flags & EditorManager::OpenInOtherSplit)
EditorManager::gotoOtherSplit();
return EditorManagerPrivate::openEditorAt(EditorManagerPrivate::currentEditorView(),
- fileName, line, column, editorId, flags, newEditor);
+ link,
+ editorId,
+ flags,
+ newEditor);
+}
+
+IEditor *EditorManager::openEditorAt(const QString &fileName, int line, int column,
+ Id editorId, OpenEditorFlags flags, bool *newEditor)
+{
+ return openEditorAt(Link(FilePath::fromString(fileName), line, column), editorId, flags, newEditor);
}
/*!
@@ -3143,53 +3149,15 @@ void EditorManager::openEditorAtSearchResult(const SearchResultItem &item,
}
/*!
- Returns the file path \a fullFilePath split into its file path, line
- number, and column number components.
-
- The following patterns are supported: \c {filepath.txt:19},
- \c{filepath.txt:19:12}, \c {filepath.txt+19},
- \c {filepath.txt+19+12}, and \c {filepath.txt(19)}.
-*/
-EditorManager::FilePathInfo EditorManager::splitLineAndColumnNumber(const QString &fullFilePath)
-{
- // :10:2 GCC/Clang-style
- static const auto regexp = QRegularExpression("[:+](\\d+)?([:+](\\d+)?)?$");
- // (10) MSVC-style
- static const auto vsRegexp = QRegularExpression("[(]((\\d+)[)]?)?$");
- const QRegularExpressionMatch match = regexp.match(fullFilePath);
- QString postfix;
- QString filePath = fullFilePath;
- int line = -1;
- int column = -1;
- if (match.hasMatch()) {
- postfix = match.captured(0);
- filePath = fullFilePath.left(match.capturedStart(0));
- line = 0; // for the case that there's only a : at the end
- if (match.lastCapturedIndex() > 0) {
- line = match.captured(1).toInt();
- if (match.lastCapturedIndex() > 2) // index 2 includes the + or : for the column number
- column = match.captured(3).toInt() - 1; //column is 0 based, despite line being 1 based
- }
- } else {
- const QRegularExpressionMatch vsMatch = vsRegexp.match(fullFilePath);
- postfix = vsMatch.captured(0);
- filePath = fullFilePath.left(vsMatch.capturedStart(0));
- if (vsMatch.lastCapturedIndex() > 1) // index 1 includes closing )
- line = vsMatch.captured(2).toInt();
- }
- return {filePath, postfix, line, column};
-}
-
-/*!
Returns whether \a fileName is an auto-save file created by \QC.
*/
-bool EditorManager::isAutoSaveFile(const QString &fileName)
+bool EditorManager::isAutoSaveFile(const QString &filePath)
{
- return fileName.endsWith(".autosave");
+ return filePath.endsWith(".autosave");
}
/*!
- Opens the document specified by \a fileName in the external editor specified
+ Opens the document specified by \a filePath in the external editor specified
by \a editorId.
Returns \c false and displays an error message if \a editorId is not the ID
@@ -3197,7 +3165,7 @@ bool EditorManager::isAutoSaveFile(const QString &fileName)
\sa openEditor()
*/
-bool EditorManager::openExternalEditor(const QString &fileName, Id editorId)
+bool EditorManager::openExternalEditor(const FilePath &filePath, Id editorId)
{
IExternalEditor *ee = Utils::findOrDefault(IExternalEditor::allExternalEditors(),
Utils::equal(&IExternalEditor::id, editorId));
@@ -3205,7 +3173,7 @@ bool EditorManager::openExternalEditor(const QString &fileName, Id editorId)
return false;
QString errorMessage;
QApplication::setOverrideCursor(QCursor(Qt::WaitCursor));
- const bool ok = ee->startEditor(fileName, &errorMessage);
+ const bool ok = ee->startEditor(filePath, &errorMessage);
QApplication::restoreOverrideCursor();
if (!ok)
QMessageBox::critical(ICore::dialogParent(), tr("Opening File"), errorMessage);
@@ -3345,7 +3313,7 @@ IEditor *EditorManager::openEditorWithContents(Id editorId,
though it is big. Depending on the settings this might ask the user to
decide whether the file should be opened.
*/
-bool EditorManager::skipOpeningBigTextFile(const QString &filePath)
+bool EditorManager::skipOpeningBigTextFile(const FilePath &filePath)
{
return EditorManagerPrivate::skipOpeningBigTextFile(filePath);
}
@@ -3446,7 +3414,7 @@ void EditorManager::setLastEditLocation(const IEditor* editor)
const QByteArray &state = editor->saveState();
EditLocation location;
location.document = document;
- location.fileName = document->filePath().toString();
+ location.filePath = document->filePath();
location.id = document->id();
location.state = QVariant(state);
@@ -3801,79 +3769,3 @@ void EditorManager::setWindowTitleVcsTopicHandler(WindowTitleHandler handler)
{
d->m_titleVcsTopicHandler = handler;
}
-
-#if defined(WITH_TESTS)
-
-void CorePlugin::testSplitLineAndColumnNumber()
-{
- QFETCH(QString, testFile);
- QFETCH(QString, filePath);
- QFETCH(QString, postfix);
- QFETCH(int, line);
- QFETCH(int, column);
- const EditorManager::FilePathInfo fp = EditorManager::splitLineAndColumnNumber(testFile);
- QCOMPARE(fp.filePath, filePath);
- QCOMPARE(fp.postfix, postfix);
- QCOMPARE(fp.lineNumber, line);
- QCOMPARE(fp.columnNumber, column);
-}
-
-void CorePlugin::testSplitLineAndColumnNumber_data()
-{
- QTest::addColumn<QString>("testFile");
- QTest::addColumn<QString>("filePath");
- QTest::addColumn<QString>("postfix");
- QTest::addColumn<int>("line");
- QTest::addColumn<int>("column");
-
- QTest::newRow("no-line-no-column") << QString::fromLatin1("someFile.txt")
- << QString::fromLatin1("someFile.txt")
- << QString() << -1 << -1;
- QTest::newRow(": at end") << QString::fromLatin1("someFile.txt:")
- << QString::fromLatin1("someFile.txt")
- << QString::fromLatin1(":") << 0 << -1;
- QTest::newRow("+ at end") << QString::fromLatin1("someFile.txt+")
- << QString::fromLatin1("someFile.txt")
- << QString::fromLatin1("+") << 0 << -1;
- QTest::newRow(": for column") << QString::fromLatin1("someFile.txt:10:")
- << QString::fromLatin1("someFile.txt")
- << QString::fromLatin1(":10:") << 10 << -1;
- QTest::newRow("+ for column") << QString::fromLatin1("someFile.txt:10+")
- << QString::fromLatin1("someFile.txt")
- << QString::fromLatin1(":10+") << 10 << -1;
- QTest::newRow(": and + at end") << QString::fromLatin1("someFile.txt:+")
- << QString::fromLatin1("someFile.txt")
- << QString::fromLatin1(":+") << 0 << -1;
- QTest::newRow("empty line") << QString::fromLatin1("someFile.txt:+10")
- << QString::fromLatin1("someFile.txt")
- << QString::fromLatin1(":+10") << 0 << 9;
- QTest::newRow(":line-no-column") << QString::fromLatin1("/some/path/file.txt:42")
- << QString::fromLatin1("/some/path/file.txt")
- << QString::fromLatin1(":42") << 42 << -1;
- QTest::newRow("+line-no-column") << QString::fromLatin1("/some/path/file.txt+42")
- << QString::fromLatin1("/some/path/file.txt")
- << QString::fromLatin1("+42") << 42 << -1;
- QTest::newRow(":line-:column") << QString::fromLatin1("/some/path/file.txt:42:3")
- << QString::fromLatin1("/some/path/file.txt")
- << QString::fromLatin1(":42:3") << 42 << 2;
- QTest::newRow(":line-+column") << QString::fromLatin1("/some/path/file.txt:42+33")
- << QString::fromLatin1("/some/path/file.txt")
- << QString::fromLatin1(":42+33") << 42 << 32;
- QTest::newRow("+line-:column") << QString::fromLatin1("/some/path/file.txt+142:30")
- << QString::fromLatin1("/some/path/file.txt")
- << QString::fromLatin1("+142:30") << 142 << 29;
- QTest::newRow("+line-+column") << QString::fromLatin1("/some/path/file.txt+142+33")
- << QString::fromLatin1("/some/path/file.txt")
- << QString::fromLatin1("+142+33") << 142 << 32;
- QTest::newRow("( at end") << QString::fromLatin1("/some/path/file.txt(")
- << QString::fromLatin1("/some/path/file.txt")
- << QString::fromLatin1("(") << -1 << -1;
- QTest::newRow("(42 at end") << QString::fromLatin1("/some/path/file.txt(42")
- << QString::fromLatin1("/some/path/file.txt")
- << QString::fromLatin1("(42") << 42 << -1;
- QTest::newRow("(42) at end") << QString::fromLatin1("/some/path/file.txt(42)")
- << QString::fromLatin1("/some/path/file.txt")
- << QString::fromLatin1("(42)") << 42 << -1;
-}
-
-#endif // WITH_TESTS
diff --git a/src/plugins/coreplugin/editormanager/editormanager.h b/src/plugins/coreplugin/editormanager/editormanager.h
index 38c4b7add3..1bea80ceca 100644
--- a/src/plugins/coreplugin/editormanager/editormanager.h
+++ b/src/plugins/coreplugin/editormanager/editormanager.h
@@ -31,6 +31,7 @@
#include "documentmodel.h"
#include "ieditor.h"
+#include "utils/link.h"
#include "utils/textfileformat.h"
#include <QList>
@@ -40,7 +41,9 @@
QT_FORWARD_DECLARE_CLASS(QMenu)
-namespace Utils { class MimeType; }
+namespace Utils {
+class MimeType;
+}
namespace Core {
@@ -86,19 +89,22 @@ public:
};
Q_DECLARE_FLAGS(OpenEditorFlags, OpenEditorFlag)
- struct FilePathInfo {
- QString filePath; // file path without line/column suffix
- QString postfix; // line/column suffix as string, e.g. ":10:1"
- int lineNumber; // extracted line number, -1 if none
- int columnNumber; // extracted column number, -1 if none
- };
+ static IEditor *openEditor(const Utils::FilePath &filePath,
+ Utils::Id editorId = {},
+ OpenEditorFlags flags = NoFlags,
+ bool *newEditor = nullptr);
+ static IEditor *openEditorAt(const Utils::Link &link,
+ Utils::Id editorId = {},
+ OpenEditorFlags flags = NoFlags,
+ bool *newEditor = nullptr);
- static FilePathInfo splitLineAndColumnNumber(const QString &filePath);
+ // Kept for a while for transition.
static IEditor *openEditor(const QString &fileName, Utils::Id editorId = {},
- OpenEditorFlags flags = NoFlags, bool *newEditor = nullptr);
+ OpenEditorFlags flags = NoFlags, bool *newEditor = nullptr); // FIXME: Remove overload
static IEditor *openEditorAt(const QString &fileName, int line, int column = 0,
Utils::Id editorId = {}, OpenEditorFlags flags = NoFlags,
- bool *newEditor = nullptr);
+ bool *newEditor = nullptr); // FIXME: Remove overload
+
static void openEditorAtSearchResult(const SearchResultItem &item,
Utils::Id editorId = {},
OpenEditorFlags flags = NoFlags,
@@ -107,10 +113,10 @@ public:
const QByteArray &contents = QByteArray(),
const QString &uniqueId = QString(),
OpenEditorFlags flags = NoFlags);
- static bool skipOpeningBigTextFile(const QString &filePath);
+ static bool skipOpeningBigTextFile(const Utils::FilePath &filePath);
static void clearUniqueId(IDocument *document);
- static bool openExternalEditor(const QString &fileName, Utils::Id editorId);
+ static bool openExternalEditor(const Utils::FilePath &filePath, Utils::Id editorId);
static void addCloseEditorListener(const std::function<bool(IEditor *)> &listener);
static QStringList getOpenFileNames();
diff --git a/src/plugins/coreplugin/editormanager/editormanager_p.h b/src/plugins/coreplugin/editormanager/editormanager_p.h
index c65526db7f..43b25eefba 100644
--- a/src/plugins/coreplugin/editormanager/editormanager_p.h
+++ b/src/plugins/coreplugin/editormanager/editormanager_p.h
@@ -80,18 +80,16 @@ public:
static EditorView *currentEditorView();
static void setCurrentEditor(IEditor *editor, bool ignoreNavigationHistory = false);
static IEditor *openEditor(EditorView *view,
- const QString &fileName,
+ const Utils::FilePath &filePath,
Utils::Id editorId = {},
EditorManager::OpenEditorFlags flags = EditorManager::NoFlags,
bool *newEditor = nullptr);
static IEditor *openEditorAt(EditorView *view,
- const QString &fileName,
- int line,
- int column = 0,
+ const Utils::Link &filePath,
Utils::Id editorId = {},
EditorManager::OpenEditorFlags flags = EditorManager::NoFlags,
bool *newEditor = nullptr);
- static IEditor *openEditorWith(const QString &fileName, Utils::Id editorId);
+ static IEditor *openEditorWith(const Utils::FilePath &filePath, Utils::Id editorId);
static IEditor *duplicateEditor(IEditor *editor);
static IEditor *activateEditor(EditorView *view, IEditor *editor,
EditorManager::OpenEditorFlags flags = EditorManager::NoFlags);
@@ -209,7 +207,7 @@ private:
static void setupSaveActions(IDocument *document, QAction *saveAction,
QAction *saveAsAction, QAction *revertToSavedAction);
static void updateWindowTitle();
- static bool skipOpeningBigTextFile(const QString &filePath);
+ static bool skipOpeningBigTextFile(const Utils::FilePath &filePath);
private:
explicit EditorManagerPrivate(QObject *parent);
@@ -270,22 +268,26 @@ private:
QMap<QString, QVariant> m_editorStates;
OpenEditorsViewFactory *m_openEditorsFactory = nullptr;
- IDocument::ReloadSetting m_reloadSetting = IDocument::AlwaysAsk;
-
EditorManager::WindowTitleHandler m_titleAdditionHandler;
EditorManager::WindowTitleHandler m_sessionTitleHandler;
EditorManager::WindowTitleHandler m_titleVcsTopicHandler;
- bool m_autoSaveEnabled = true;
- int m_autoSaveInterval = 5;
+ struct Settings
+ {
+ IDocument::ReloadSetting reloadSetting = IDocument::AlwaysAsk;
+
+ bool autoSaveEnabled = true;
+ int autoSaveInterval = 5;
- bool m_autoSuspendEnabled = true;
- int m_autoSuspendMinDocumentCount = 30;
+ bool autoSuspendEnabled = true;
+ int autoSuspendMinDocumentCount = 30;
- bool m_warnBeforeOpeningBigFilesEnabled = true;
- int m_bigFileSizeLimitInMB = 5;
- int m_maxRecentFiles = 8;
+ bool warnBeforeOpeningBigFilesEnabled = true;
+ int bigFileSizeLimitInMB = 5;
+ int maxRecentFiles = 8;
+ };
+ Settings m_settings;
QString m_placeholderText;
QList<std::function<bool(IEditor *)>> m_closeEditorListeners;
};
diff --git a/src/plugins/coreplugin/editormanager/editorview.cpp b/src/plugins/coreplugin/editormanager/editorview.cpp
index 8a2a2dbe4f..22f7c24d5e 100644
--- a/src/plugins/coreplugin/editormanager/editorview.cpp
+++ b/src/plugins/coreplugin/editormanager/editorview.cpp
@@ -41,6 +41,7 @@
#include <utils/infobar.h>
#include <utils/qtcassert.h>
#include <utils/theme/theme.h>
+#include <utils/link.h>
#include <utils/utilsicons.h>
#include <QDebug>
@@ -261,15 +262,14 @@ void EditorView::updateEditorHistory(IEditor *editor, QList<EditLocation> &histo
EditLocation location;
location.document = document;
- location.fileName = document->filePath().toString();
+ location.filePath = document->filePath();
location.id = document->id();
location.state = QVariant(state);
for (int i = 0; i < history.size(); ++i) {
const EditLocation &item = history.at(i);
if (item.document == document
- || (!item.document
- && !DocumentModel::indexOfFilePath(FilePath::fromString(item.fileName)))) {
+ || (!item.document && !DocumentModel::indexOfFilePath(item.filePath))) {
history.removeAt(i--);
}
}
@@ -402,15 +402,16 @@ void EditorView::closeSplit()
void EditorView::openDroppedFiles(const QList<DropSupport::FileSpec> &files)
{
bool first = true;
+ auto specToLink = [](const DropSupport::FileSpec &spec) {
+ return Utils::Link(FilePath::fromString(spec.filePath), spec.line, spec.column);
+ };
auto openEntry = [&](const DropSupport::FileSpec &spec) {
if (first) {
first = false;
- EditorManagerPrivate::openEditorAt(this, spec.filePath, spec.line, spec.column);
+ EditorManagerPrivate::openEditorAt(this, specToLink(spec));
} else if (spec.column != -1 || spec.line != -1) {
EditorManagerPrivate::openEditorAt(this,
- spec.filePath,
- spec.line,
- spec.column,
+ specToLink(spec),
Id(),
EditorManager::DoNotChangeCurrentEditor
| EditorManager::DoNotMakeVisible);
@@ -495,7 +496,7 @@ void EditorView::addCurrentPositionToNavigationHistory(const QByteArray &saveSta
EditLocation location;
location.document = document;
- location.fileName = document->filePath().toString();
+ location.filePath = document->filePath();
location.id = document->id();
location.state = QVariant(state);
m_currentNavigationHistoryPosition = qMin(m_currentNavigationHistoryPosition, m_navigationHistory.size()); // paranoia
@@ -550,17 +551,15 @@ void EditorView::updateCurrentPositionInNavigationHistory()
location = &m_navigationHistory[m_navigationHistory.size()-1];
}
location->document = document;
- location->fileName = document->filePath().toString();
+ location->filePath = document->filePath();
location->id = document->id();
location->state = QVariant(editor->saveState());
}
-namespace {
-static inline bool fileNameWasRemoved(const QString &fileName)
+static bool fileNameWasRemoved(const FilePath &filePath)
{
- return !fileName.isEmpty() && !QFileInfo::exists(fileName);
+ return !filePath.isEmpty() && !filePath.exists();
}
-} // End of anonymous namespace
void EditorView::goBackInNavigationHistory()
{
@@ -574,11 +573,11 @@ void EditorView::goBackInNavigationHistory()
EditorManager::IgnoreNavigationHistory);
}
if (!editor) {
- if (fileNameWasRemoved(location.fileName)) {
+ if (fileNameWasRemoved(location.filePath)) {
m_navigationHistory.removeAt(m_currentNavigationHistoryPosition);
continue;
}
- editor = EditorManagerPrivate::openEditor(this, location.fileName, location.id,
+ editor = EditorManagerPrivate::openEditor(this, location.filePath, location.id,
EditorManager::IgnoreNavigationHistory);
if (!editor) {
m_navigationHistory.removeAt(m_currentNavigationHistoryPosition);
@@ -605,11 +604,11 @@ void EditorView::goForwardInNavigationHistory()
EditorManager::IgnoreNavigationHistory);
}
if (!editor) {
- if (fileNameWasRemoved(location.fileName)) {
+ if (fileNameWasRemoved(location.filePath)) {
m_navigationHistory.removeAt(m_currentNavigationHistoryPosition);
continue;
}
- editor = EditorManagerPrivate::openEditor(this, location.fileName, location.id,
+ editor = EditorManagerPrivate::openEditor(this, location.filePath, location.id,
EditorManager::IgnoreNavigationHistory);
if (!editor) {
m_navigationHistory.removeAt(m_currentNavigationHistoryPosition);
@@ -634,10 +633,10 @@ void EditorView::goToEditLocation(const EditLocation &location)
}
if (!editor) {
- if (fileNameWasRemoved(location.fileName))
+ if (fileNameWasRemoved(location.filePath))
return;
- editor = EditorManagerPrivate::openEditor(this, location.fileName, location.id,
+ editor = EditorManagerPrivate::openEditor(this, location.filePath, location.id,
EditorManager::IgnoreNavigationHistory);
}
@@ -967,7 +966,7 @@ void SplitterOrView::restoreState(const QByteArray &state)
stream >> fileName >> id >> editorState;
if (!QFile::exists(fileName))
return;
- IEditor *e = EditorManagerPrivate::openEditor(view(), fileName, Id::fromString(id),
+ IEditor *e = EditorManagerPrivate::openEditor(view(), FilePath::fromString(fileName), Id::fromString(id),
EditorManager::IgnoreNavigationHistory
| EditorManager::DoNotChangeCurrentEditor);
diff --git a/src/plugins/coreplugin/editormanager/editorview.h b/src/plugins/coreplugin/editormanager/editorview.h
index ebf98dfa1c..6dca73353a 100644
--- a/src/plugins/coreplugin/editormanager/editorview.h
+++ b/src/plugins/coreplugin/editormanager/editorview.h
@@ -26,6 +26,7 @@
#pragma once
#include <utils/dropsupport.h>
+#include <utils/fileutils.h>
#include <utils/id.h>
#include <QMap>
@@ -62,7 +63,7 @@ namespace Internal {
struct EditLocation {
QPointer<IDocument> document;
- QString fileName;
+ Utils::FilePath filePath;
Utils::Id id;
QVariant state;
};
diff --git a/src/plugins/coreplugin/editormanager/iexternaleditor.h b/src/plugins/coreplugin/editormanager/iexternaleditor.h
index fea99e35f3..b105f37640 100644
--- a/src/plugins/coreplugin/editormanager/iexternaleditor.h
+++ b/src/plugins/coreplugin/editormanager/iexternaleditor.h
@@ -32,6 +32,8 @@
#include <QObject>
+namespace Utils { class FilePath; }
+
namespace Core {
class IExternalEditor;
@@ -52,7 +54,7 @@ public:
virtual QStringList mimeTypes() const = 0;
virtual Utils::Id id() const = 0;
virtual QString displayName() const = 0;
- virtual bool startEditor(const QString &fileName, QString *errorMessage) = 0;
+ virtual bool startEditor(const Utils::FilePath &filePath, QString *errorMessage) = 0;
};
} // namespace Core
diff --git a/src/plugins/coreplugin/editormanager/openeditorsview.cpp b/src/plugins/coreplugin/editormanager/openeditorsview.cpp
index 9d2500d952..e4e4a81c08 100644
--- a/src/plugins/coreplugin/editormanager/openeditorsview.cpp
+++ b/src/plugins/coreplugin/editormanager/openeditorsview.cpp
@@ -140,7 +140,7 @@ OpenEditorsViewFactory::OpenEditorsViewFactory()
NavigationView OpenEditorsViewFactory::createWidget()
{
- return NavigationView(new OpenEditorsWidget());
+ return {new OpenEditorsWidget, {}};
}
ProxyModel::ProxyModel(QObject *parent) : QAbstractProxyModel(parent)
diff --git a/src/plugins/coreplugin/editormanager/openeditorswindow.cpp b/src/plugins/coreplugin/editormanager/openeditorswindow.cpp
index d7af47f372..fdcd6b57be 100644
--- a/src/plugins/coreplugin/editormanager/openeditorswindow.cpp
+++ b/src/plugins/coreplugin/editormanager/openeditorswindow.cpp
@@ -217,7 +217,7 @@ static DocumentModel::Entry *entryForEditLocation(const EditLocation &item)
{
if (!item.document.isNull())
return DocumentModel::entryForDocument(item.document);
- return DocumentModel::entryForFilePath(Utils::FilePath::fromString(item.fileName));
+ return DocumentModel::entryForFilePath(item.filePath);
}
void OpenEditorsWindow::addHistoryItems(const QList<EditLocation> &history, EditorView *view,
diff --git a/src/plugins/coreplugin/editormanager/systemeditor.cpp b/src/plugins/coreplugin/editormanager/systemeditor.cpp
index c8ccd88ca7..3084088100 100644
--- a/src/plugins/coreplugin/editormanager/systemeditor.cpp
+++ b/src/plugins/coreplugin/editormanager/systemeditor.cpp
@@ -25,6 +25,8 @@
#include "systemeditor.h"
+#include <utils/fileutils.h>
+
#include <QStringList>
#include <QUrl>
#include <QDesktopServices>
@@ -53,11 +55,11 @@ QString SystemEditor::displayName() const
return tr("System Editor");
}
-bool SystemEditor::startEditor(const QString &fileName, QString *errorMessage)
+bool SystemEditor::startEditor(const FilePath &filePath, QString *errorMessage)
{
Q_UNUSED(errorMessage)
QUrl url;
- url.setPath(fileName);
+ url.setPath(filePath.toString());
url.setScheme(QLatin1String("file"));
if (!QDesktopServices::openUrl(url)) {
if (errorMessage)
diff --git a/src/plugins/coreplugin/editormanager/systemeditor.h b/src/plugins/coreplugin/editormanager/systemeditor.h
index 9d260def05..870bc5c315 100644
--- a/src/plugins/coreplugin/editormanager/systemeditor.h
+++ b/src/plugins/coreplugin/editormanager/systemeditor.h
@@ -41,7 +41,7 @@ public:
Utils::Id id() const override;
QString displayName() const override;
- bool startEditor(const QString &fileName, QString *errorMessage) override;
+ bool startEditor(const Utils::FilePath &filePath, QString *errorMessage) override;
};
} // namespace Internal
diff --git a/src/plugins/coreplugin/externaltool.cpp b/src/plugins/coreplugin/externaltool.cpp
index 2a8391f703..ceaa1465e4 100644
--- a/src/plugins/coreplugin/externaltool.cpp
+++ b/src/plugins/coreplugin/externaltool.cpp
@@ -474,7 +474,7 @@ ExternalTool * ExternalTool::createFromFile(const QString &fileName, QString *er
{
QString absFileName = QFileInfo(fileName).absoluteFilePath();
FileReader reader;
- if (!reader.fetch(absFileName, errorMessage))
+ if (!reader.fetch(FilePath::fromString(absFileName), errorMessage))
return nullptr;
ExternalTool *tool = ExternalTool::createFromXml(reader.data(), errorMessage, locale);
if (!tool)
@@ -500,7 +500,7 @@ bool ExternalTool::save(QString *errorMessage) const
{
if (m_fileName.isEmpty())
return false;
- FileSaver saver(m_fileName);
+ FileSaver saver(FilePath::fromString(m_fileName));
if (!saver.hasError()) {
QXmlStreamWriter out(saver.file());
out.setAutoFormatting(true);
diff --git a/src/plugins/coreplugin/externaltoolmanager.cpp b/src/plugins/coreplugin/externaltoolmanager.cpp
index 99858beebd..72b4a3fa5c 100644
--- a/src/plugins/coreplugin/externaltoolmanager.cpp
+++ b/src/plugins/coreplugin/externaltoolmanager.cpp
@@ -90,10 +90,10 @@ ExternalToolManager::ExternalToolManager()
QMap<QString, QMultiMap<int, ExternalTool*> > categoryPriorityMap;
QMap<QString, ExternalTool *> tools;
- parseDirectory(ICore::userResourcePath() + QLatin1String("/externaltools"),
+ parseDirectory(ICore::userResourcePath("externaltools").toString(),
&categoryPriorityMap,
&tools);
- parseDirectory(ICore::resourcePath() + QLatin1String("/externaltools"),
+ parseDirectory(ICore::resourcePath("externaltools").toString(),
&categoryPriorityMap,
&tools,
true);
diff --git a/src/plugins/coreplugin/fileutils.cpp b/src/plugins/coreplugin/fileutils.cpp
index 314a54015d..0f9cc1d3c8 100644
--- a/src/plugins/coreplugin/fileutils.cpp
+++ b/src/plugins/coreplugin/fileutils.cpp
@@ -34,7 +34,7 @@
#include <utils/consoleprocess.h>
#include <utils/environment.h>
#include <utils/hostosinfo.h>
-#include <utils/qtcprocess.h>
+#include <utils/commandline.h>
#include <utils/textfileformat.h>
#include <utils/unixutils.h>
@@ -103,7 +103,7 @@ void FileUtils::showInGraphicalShell(QWidget *parent, const QString &pathIn)
// we cannot select a file here, because no file browser really supports it...
const QString folder = fileInfo.isDir() ? fileInfo.absoluteFilePath() : fileInfo.filePath();
const QString app = UnixUtils::fileBrowser(ICore::settings());
- QStringList browserArgs = Utils::QtcProcess::splitArgs(
+ QStringList browserArgs = ProcessArgs::splitArgs(
UnixUtils::substituteFileBrowserParameters(app, folder));
QString error;
if (browserArgs.isEmpty()) {
diff --git a/src/plugins/coreplugin/find/searchresultitem.h b/src/plugins/coreplugin/find/searchresultitem.h
index b1058db453..f4e7a78162 100644
--- a/src/plugins/coreplugin/find/searchresultitem.h
+++ b/src/plugins/coreplugin/find/searchresultitem.h
@@ -124,6 +124,9 @@ public:
SearchResultColor::Style style() const { return m_style; }
void setStyle(SearchResultColor::Style style) { m_style = style; }
+ bool selectForReplacement() const { return m_selectForReplacement; }
+ void setSelectForReplacement(bool select) { m_selectForReplacement = select; }
+
private:
QStringList m_path; // hierarchy to the parent item of this item
QString m_lineText; // text to show for the item itself
@@ -131,6 +134,7 @@ private:
QVariant m_userData; // user data for identification of the item
Search::TextRange m_mainRange;
bool m_useTextEditorFont = false;
+ bool m_selectForReplacement = true;
SearchResultColor::Style m_style = SearchResultColor::Style::Default;
};
diff --git a/src/plugins/coreplugin/find/searchresulttreeitems.cpp b/src/plugins/coreplugin/find/searchresulttreeitems.cpp
index 9f25167fcd..af2d21099f 100644
--- a/src/plugins/coreplugin/find/searchresulttreeitems.cpp
+++ b/src/plugins/coreplugin/find/searchresulttreeitems.cpp
@@ -33,7 +33,7 @@ SearchResultTreeItem::SearchResultTreeItem(const SearchResultItem &item,
: item(item),
m_parent(parent),
m_isGenerated(false),
- m_checkState(Qt::Checked)
+ m_checkState(item.selectForReplacement() ? Qt::Checked : Qt::Unchecked)
{
}
diff --git a/src/plugins/coreplugin/find/searchresulttreemodel.cpp b/src/plugins/coreplugin/find/searchresulttreemodel.cpp
index a7d680b76b..71712c18fe 100644
--- a/src/plugins/coreplugin/find/searchresulttreemodel.cpp
+++ b/src/plugins/coreplugin/find/searchresulttreemodel.cpp
@@ -77,6 +77,7 @@ private:
QSet<SearchResultTreeItem *> addPath(const QStringList &path);
QVariant data(const SearchResultTreeItem *row, int role) const;
bool setCheckState(const QModelIndex &idx, Qt::CheckState checkState, bool firstCall = true);
+ void updateCheckStateFromChildren(const QModelIndex &idx, SearchResultTreeItem *item);
QModelIndex nextIndex(const QModelIndex &idx, bool *wrapped = nullptr) const;
QModelIndex prevIndex(const QModelIndex &idx, bool *wrapped = nullptr) const;
@@ -247,31 +248,7 @@ bool SearchResultTreeModel::setCheckState(const QModelIndex &idx, Qt::CheckState
item->setCheckState(checkState);
if (firstCall) {
emit dataChanged(idx, idx);
- // check parents
- SearchResultTreeItem *currentItem = item;
- QModelIndex currentIndex = idx;
- while (SearchResultTreeItem *parent = currentItem->parent()) {
- bool hasChecked = false;
- bool hasUnchecked = false;
- for (int i = 0; i < parent->childrenCount(); ++i) {
- SearchResultTreeItem *child = parent->childAt(i);
- if (child->checkState() == Qt::Checked)
- hasChecked = true;
- else if (child->checkState() == Qt::Unchecked)
- hasUnchecked = true;
- else if (child->checkState() == Qt::PartiallyChecked)
- hasChecked = hasUnchecked = true;
- }
- if (hasChecked && hasUnchecked)
- parent->setCheckState(Qt::PartiallyChecked);
- else if (hasChecked)
- parent->setCheckState(Qt::Checked);
- else
- parent->setCheckState(Qt::Unchecked);
- emit dataChanged(idx.parent(), idx.parent());
- currentItem = parent;
- currentIndex = idx.parent();
- }
+ updateCheckStateFromChildren(idx.parent(), item->parent());
}
// check children
if (int children = item->childrenCount()) {
@@ -282,6 +259,34 @@ bool SearchResultTreeModel::setCheckState(const QModelIndex &idx, Qt::CheckState
return true;
}
+void SearchResultTreeModel::updateCheckStateFromChildren(const QModelIndex &idx,
+ SearchResultTreeItem *item)
+{
+ if (!item || item == m_rootItem)
+ return;
+
+ bool hasChecked = false;
+ bool hasUnchecked = false;
+ for (int i = 0; i < item->childrenCount(); ++i) {
+ SearchResultTreeItem *child = item->childAt(i);
+ if (child->checkState() == Qt::Checked)
+ hasChecked = true;
+ else if (child->checkState() == Qt::Unchecked)
+ hasUnchecked = true;
+ else if (child->checkState() == Qt::PartiallyChecked)
+ hasChecked = hasUnchecked = true;
+ }
+ if (hasChecked && hasUnchecked)
+ item->setCheckState(Qt::PartiallyChecked);
+ else if (hasChecked)
+ item->setCheckState(Qt::Checked);
+ else
+ item->setCheckState(Qt::Unchecked);
+ emit dataChanged(idx, idx);
+
+ updateCheckStateFromChildren(idx.parent(), item->parent());
+}
+
void setDataInternal(const QModelIndex &index, const QVariant &value, int role);
QVariant SearchResultTreeModel::data(const SearchResultTreeItem *row, int role) const
@@ -418,6 +423,7 @@ void SearchResultTreeModel::addResultsToCurrentParent(const QList<SearchResultIt
}
}
}
+ updateCheckStateFromChildren(index(m_currentParent), m_currentParent);
emit dataChanged(m_currentIndex, m_currentIndex); // Make sure that the number after the file name gets updated
}
diff --git a/src/plugins/coreplugin/find/searchresultwidget.cpp b/src/plugins/coreplugin/find/searchresultwidget.cpp
index 41df8c16ce..f6d8b3e37a 100644
--- a/src/plugins/coreplugin/find/searchresultwidget.cpp
+++ b/src/plugins/coreplugin/find/searchresultwidget.cpp
@@ -303,6 +303,11 @@ void SearchResultWidget::setSupportsReplace(bool replaceSupported, const QString
m_dontAskAgainGroup = group;
}
+bool SearchResultWidget::supportsReplace() const
+{
+ return m_replaceSupported;
+}
+
void SearchResultWidget::setTextToReplace(const QString &textToReplace)
{
m_replaceTextEdit->setText(textToReplace);
diff --git a/src/plugins/coreplugin/find/searchresultwidget.h b/src/plugins/coreplugin/find/searchresultwidget.h
index e018a9e693..49e7e6ed5b 100644
--- a/src/plugins/coreplugin/find/searchresultwidget.h
+++ b/src/plugins/coreplugin/find/searchresultwidget.h
@@ -60,6 +60,7 @@ public:
int count() const;
void setSupportsReplace(bool replaceSupported, const QString &group);
+ bool supportsReplace() const;
void setTextToReplace(const QString &textToReplace);
QString textToReplace() const;
diff --git a/src/plugins/coreplugin/find/searchresultwindow.cpp b/src/plugins/coreplugin/find/searchresultwindow.cpp
index fb04e7b8b8..9fcbda4e80 100644
--- a/src/plugins/coreplugin/find/searchresultwindow.cpp
+++ b/src/plugins/coreplugin/find/searchresultwindow.cpp
@@ -760,6 +760,11 @@ QVariant SearchResult::userData() const
return m_userData;
}
+bool SearchResult::supportsReplace() const
+{
+ return m_widget->supportsReplace();
+}
+
/*!
Returns the text that should replace the text in search results.
*/
diff --git a/src/plugins/coreplugin/find/searchresultwindow.h b/src/plugins/coreplugin/find/searchresultwindow.h
index a4b8315565..c7f4af7c56 100644
--- a/src/plugins/coreplugin/find/searchresultwindow.h
+++ b/src/plugins/coreplugin/find/searchresultwindow.h
@@ -69,6 +69,7 @@ public:
void setUserData(const QVariant &data);
QVariant userData() const;
+ bool supportsReplace() const;
QString textToReplace() const;
int count() const;
void setSearchAgainSupported(bool supported);
diff --git a/src/plugins/coreplugin/generalsettings.cpp b/src/plugins/coreplugin/generalsettings.cpp
index d04dd5e569..81d83df322 100644
--- a/src/plugins/coreplugin/generalsettings.cpp
+++ b/src/plugins/coreplugin/generalsettings.cpp
@@ -94,9 +94,6 @@ GeneralSettingsWidget::GeneralSettingsWidget(GeneralSettings *q)
tr("Show keyboard shortcuts in context menus (default: %1)")
.arg(q->m_defaultShowShortcutsInContextMenu ? tr("on") : tr("off")));
m_ui.showShortcutsInContextMenus->setChecked(GeneralSettings::showShortcutsInContextMenu());
-#if (QT_VERSION < QT_VERSION_CHECK(5, 13, 0))
- m_ui.showShortcutsInContextMenus->setVisible(false);
-#endif
if (Utils::HostOsInfo::isMacHost()) {
m_ui.dpiCheckbox->setVisible(false);
@@ -135,15 +132,16 @@ void GeneralSettingsWidget::fillLanguageBox() const
if (currentLocale == QLatin1String("C"))
m_ui.languageBox->setCurrentIndex(m_ui.languageBox->count() - 1);
- const QString creatorTrPath = ICore::resourcePath() + QLatin1String("/translations");
- const QStringList languageFiles = QDir(creatorTrPath).entryList(QStringList(QLatin1String("qtcreator*.qm")));
+ const FilePath creatorTrPath = ICore::resourcePath("translations");
+ const QStringList languageFiles = creatorTrPath.toDir().entryList(
+ QStringList(QLatin1String("qtcreator*.qm")));
for (const QString &languageFile : languageFiles) {
int start = languageFile.indexOf('_') + 1;
int end = languageFile.lastIndexOf('.');
const QString locale = languageFile.mid(start, end-start);
// no need to show a language that creator will not load anyway
- if (hasQmFilesForLocale(locale, creatorTrPath)) {
+ if (hasQmFilesForLocale(locale, creatorTrPath.toString())) {
QLocale tmpLocale(locale);
QString languageItem = QLocale::languageToString(tmpLocale.language()) + QLatin1String(" (")
+ QLocale::countryToString(tmpLocale.country()) + QLatin1Char(')');
@@ -250,9 +248,7 @@ void GeneralSettings::setShowShortcutsInContextMenu(bool show)
ICore::settings()->setValueWithDefault(settingsKeyShortcutsInContextMenu,
show,
m_defaultShowShortcutsInContextMenu);
-#if (QT_VERSION >= QT_VERSION_CHECK(5, 13, 0))
QGuiApplication::styleHints()->setShowShortcutsInContextMenus(show);
-#endif
}
GeneralSettings::GeneralSettings()
diff --git a/src/plugins/coreplugin/generatedfile.cpp b/src/plugins/coreplugin/generatedfile.cpp
index 2ddeeeb1a9..339a3cd73e 100644
--- a/src/plugins/coreplugin/generatedfile.cpp
+++ b/src/plugins/coreplugin/generatedfile.cpp
@@ -157,7 +157,7 @@ bool GeneratedFile::write(QString *errorMessage) const
// Write out
if (isBinary()) {
QIODevice::OpenMode flags = QIODevice::WriteOnly | QIODevice::Truncate;
- Utils::FileSaver saver(m_d->path, flags);
+ Utils::FileSaver saver(FilePath::fromString(m_d->path), flags);
saver.write(m_d->contents);
return saver.finalize(errorMessage);
}
@@ -165,7 +165,7 @@ bool GeneratedFile::write(QString *errorMessage) const
Utils::TextFileFormat format;
format.codec = EditorManager::defaultTextCodec();
format.lineTerminationMode = EditorManager::defaultLineEnding();
- return format.writeFile(m_d->path, contents(), errorMessage);
+ return format.writeFile(Utils::FilePath::fromString(m_d->path), contents(), errorMessage);
}
GeneratedFile::Attributes GeneratedFile::attributes() const
diff --git a/src/plugins/coreplugin/icore.cpp b/src/plugins/coreplugin/icore.cpp
index 2adf220b91..52695e3cf6 100644
--- a/src/plugins/coreplugin/icore.cpp
+++ b/src/plugins/coreplugin/icore.cpp
@@ -386,6 +386,14 @@ QString ICore::userInterfaceLanguage()
return qApp->property("qtc_locale").toString();
}
+static QString pathHelper(const QString &rel)
+{
+ if (rel.isEmpty())
+ return rel;
+ if (rel.startsWith('/'))
+ return rel;
+ return '/' + rel;
+}
/*!
Returns the absolute path that is used for resources like
project templates and the debugger macros.
@@ -396,9 +404,11 @@ QString ICore::userInterfaceLanguage()
\sa userResourcePath()
*/
-QString ICore::resourcePath()
+FilePath ICore::resourcePath(const QString &rel)
{
- return QDir::cleanPath(QCoreApplication::applicationDirPath() + '/' + RELATIVE_DATA_PATH);
+ return FilePath::fromString(
+ QDir::cleanPath(QCoreApplication::applicationDirPath() + '/' + RELATIVE_DATA_PATH))
+ / rel;
}
/*!
@@ -411,7 +421,7 @@ QString ICore::resourcePath()
\sa resourcePath()
*/
-QString ICore::userResourcePath()
+FilePath ICore::userResourcePath(const QString &rel)
{
// Create qtcreator dir if it doesn't yet exist
const QString configDir = QFileInfo(settings(QSettings::UserScope)->fileName()).path();
@@ -423,24 +433,26 @@ QString ICore::userResourcePath()
qWarning() << "could not create" << urp;
}
- return urp;
+ return FilePath::fromString(urp + pathHelper(rel));
}
/*!
Returns a writable path that can be used for persistent cache files.
*/
-QString ICore::cacheResourcePath()
+FilePath ICore::cacheResourcePath(const QString &rel)
{
- return QStandardPaths::writableLocation(QStandardPaths::CacheLocation);
+ return FilePath::fromString(QStandardPaths::writableLocation(QStandardPaths::CacheLocation)
+ + pathHelper(rel));
}
/*!
Returns the path to resources written by the installer, for example
pre-defined kits and toolchains.
*/
-QString ICore::installerResourcePath()
+FilePath ICore::installerResourcePath(const QString &rel)
{
- return QFileInfo(settings(QSettings::SystemScope)->fileName()).path() + '/' + Constants::IDE_ID;
+ return FilePath::fromString(settings(QSettings::SystemScope)->fileName()).parentDir()
+ / Constants::IDE_ID / rel;
}
/*!
@@ -476,17 +488,19 @@ QString ICore::userPluginPath()
Returns the path to the command line tools that are included in the \QC
installation.
*/
-QString ICore::libexecPath()
+FilePath ICore::libexecPath(const QString &rel)
{
- return QDir::cleanPath(QApplication::applicationDirPath() + '/' + RELATIVE_LIBEXEC_PATH);
+ return FilePath::fromString(QDir::cleanPath(QApplication::applicationDirPath()
+ + pathHelper(RELATIVE_LIBEXEC_PATH)))
+ / rel;
}
-QString ICore::crashReportsPath()
+FilePath ICore::crashReportsPath()
{
if (Utils::HostOsInfo::isMacHost())
- return libexecPath() + "/crashpad_reports/completed";
+ return libexecPath("crashpad_reports/completed");
else
- return libexecPath() + "/crashpad_reports/reports";
+ return libexecPath("crashpad_reports/reports");
}
QString ICore::ideDisplayName()
@@ -505,10 +519,10 @@ static QString clangIncludePath(const QString &clangVersion)
QString ICore::clangIncludeDirectory(const QString &clangVersion,
const QString &clangFallbackIncludeDir)
{
- QDir dir(libexecPath() + "/clang" + clangIncludePath(clangVersion));
- if (!dir.exists() || !QFileInfo(dir, "stdint.h").exists())
- dir = QDir(clangFallbackIncludeDir);
- return QDir::toNativeSeparators(dir.canonicalPath());
+ FilePath dir = libexecPath("clang" + clangIncludePath(clangVersion));
+ if (!dir.exists() || !dir.pathAppended("stdint.h").exists())
+ dir = FilePath::fromString(clangFallbackIncludeDir);
+ return dir.canonicalPath().toUserOutput();
}
/*!
@@ -517,10 +531,10 @@ QString ICore::clangIncludeDirectory(const QString &clangVersion,
static QString clangBinary(const QString &binaryBaseName, const QString &clangBinDirectory)
{
const QString hostExeSuffix(QTC_HOST_EXE_SUFFIX);
- QFileInfo executable(ICore::libexecPath() + "/clang/bin/" + binaryBaseName + hostExeSuffix);
+ FilePath executable = ICore::libexecPath("clang/bin") / binaryBaseName + hostExeSuffix;
if (!executable.exists())
- executable = QFileInfo(clangBinDirectory + "/" + binaryBaseName + hostExeSuffix);
- return QDir::toNativeSeparators(executable.canonicalFilePath());
+ executable = FilePath::fromString(clangBinDirectory) / binaryBaseName + hostExeSuffix;
+ return executable.canonicalPath().toUserOutput();
}
/*!
@@ -534,6 +548,14 @@ QString ICore::clangExecutable(const QString &clangBinDirectory)
/*!
\internal
*/
+QString ICore::clangdExecutable(const QString &clangBinDirectory)
+{
+ return clangBinary("clangd", clangBinDirectory);
+}
+
+/*!
+ \internal
+*/
QString ICore::clangTidyExecutable(const QString &clangBinDirectory)
{
return clangBinary("clang-tidy", clangBinDirectory);
diff --git a/src/plugins/coreplugin/icore.h b/src/plugins/coreplugin/icore.h
index 565e0b8faa..2e02fb43f8 100644
--- a/src/plugins/coreplugin/icore.h
+++ b/src/plugins/coreplugin/icore.h
@@ -28,6 +28,7 @@
#include "core_global.h"
#include "icontext.h"
+#include <utils/fileutils.h>
#include <utils/qtcsettings.h>
#include <QList>
@@ -94,12 +95,12 @@ public:
static QPrinter *printer();
static QString userInterfaceLanguage();
- static QString resourcePath();
- static QString userResourcePath();
- static QString cacheResourcePath();
- static QString installerResourcePath();
- static QString libexecPath();
- static QString crashReportsPath();
+ static Utils::FilePath resourcePath(const QString &rel = {});
+ static Utils::FilePath userResourcePath(const QString &rel = {});
+ static Utils::FilePath cacheResourcePath(const QString &rel = {});
+ static Utils::FilePath installerResourcePath(const QString &rel = {});
+ static Utils::FilePath libexecPath(const QString &rel = {});
+ static Utils::FilePath crashReportsPath();
static QString ideDisplayName();
@@ -164,6 +165,7 @@ public:
static QString pluginPath();
static QString userPluginPath();
static QString clangExecutable(const QString &clangBinDirectory);
+ static QString clangdExecutable(const QString &clangBinDirectory);
static QString clangTidyExecutable(const QString &clangBinDirectory);
static QString clazyStandaloneExecutable(const QString &clangBinDirectory);
static QString clangIncludeDirectory(const QString &clangVersion,
diff --git a/src/plugins/coreplugin/idocument.cpp b/src/plugins/coreplugin/idocument.cpp
index 4a177a711f..11c2d97839 100644
--- a/src/plugins/coreplugin/idocument.cpp
+++ b/src/plugins/coreplugin/idocument.cpp
@@ -224,7 +224,7 @@ public:
Utils::FilePath filePath;
QString preferredDisplayName;
QString uniqueDisplayName;
- QString autoSaveName;
+ Utils::FilePath autoSavePath;
Utils::InfoBar *infoBar = nullptr;
Id id;
optional<bool> fileIsReadOnly;
@@ -291,14 +291,14 @@ Id IDocument::id() const
The open() method is used to load the contents of a file when a document is
opened in an editor.
- If the document is opened from an auto save file, \a realFileName is the
- name of the auto save file that should be loaded, and \a fileName is the
+ If the document is opened from an auto save file, \a realFilePath is the
+ name of the auto save file that should be loaded, and \a filePath is the
file name of the resulting file. In that case, the contents of the auto
save file should be loaded, the file name of the IDocument should be set to
- \a fileName, and the document state be set to modified.
+ \a filePath, and the document state be set to modified.
- If the editor is opened from a regular file, \a fileName and \a
- realFileName are the same.
+ If the editor is opened from a regular file, \a filePath and \a
+ filePath are the same.
Use \a errorString to return an error message if this document cannot
handle the file contents.
@@ -312,16 +312,16 @@ Id IDocument::id() const
\sa shouldAutoSave()
\sa setFilePath()
*/
-IDocument::OpenResult IDocument::open(QString *errorString, const QString &fileName, const QString &realFileName)
+IDocument::OpenResult IDocument::open(QString *errorString, const Utils::FilePath &filePath, const Utils::FilePath &realFilePath)
{
Q_UNUSED(errorString)
- Q_UNUSED(fileName)
- Q_UNUSED(realFileName)
+ Q_UNUSED(filePath)
+ Q_UNUSED(realFilePath)
return OpenResult::CannotHandle;
}
/*!
- Saves the contents of the document to the \a fileName on disk.
+ Saves the contents of the document to the \a filePath on disk.
If \a autoSave is \c true, the saving is done for an auto-save, so the
document should avoid cleanups or other operations that it does for
@@ -335,10 +335,10 @@ IDocument::OpenResult IDocument::open(QString *errorString, const QString &fileN
\sa shouldAutoSave()
*/
-bool IDocument::save(QString *errorString, const QString &fileName, bool autoSave)
+bool IDocument::save(QString *errorString, const Utils::FilePath &filePath, bool autoSave)
{
Q_UNUSED(errorString)
- Q_UNUSED(fileName)
+ Q_UNUSED(filePath)
Q_UNUSED(autoSave)
return false;
}
@@ -613,11 +613,11 @@ void IDocument::setMimeType(const QString &mimeType)
/*!
\internal
*/
-bool IDocument::autoSave(QString *errorString, const QString &fileName)
+bool IDocument::autoSave(QString *errorString, const FilePath &filePath)
{
- if (!save(errorString, fileName, true))
+ if (!save(errorString, filePath, true))
return false;
- d->autoSaveName = fileName;
+ d->autoSavePath = filePath;
return true;
}
@@ -626,9 +626,9 @@ static const char kRestoredAutoSave[] = "RestoredAutoSave";
/*!
\internal
*/
-void IDocument::setRestoredFrom(const QString &name)
+void IDocument::setRestoredFrom(const Utils::FilePath &path)
{
- d->autoSaveName = name;
+ d->autoSavePath = path;
d->restored = true;
Utils::InfoBarEntry info(Id(kRestoredAutoSave),
tr("File was restored from auto-saved copy. "
@@ -641,9 +641,9 @@ void IDocument::setRestoredFrom(const QString &name)
*/
void IDocument::removeAutoSaveFile()
{
- if (!d->autoSaveName.isEmpty()) {
- QFile::remove(d->autoSaveName);
- d->autoSaveName.clear();
+ if (!d->autoSavePath.isEmpty()) {
+ QFile::remove(d->autoSavePath.toString());
+ d->autoSavePath.clear();
if (d->restored) {
d->restored = false;
infoBar()->removeInfo(Id(kRestoredAutoSave));
diff --git a/src/plugins/coreplugin/idocument.h b/src/plugins/coreplugin/idocument.h
index b468bf1a62..4e1860032b 100644
--- a/src/plugins/coreplugin/idocument.h
+++ b/src/plugins/coreplugin/idocument.h
@@ -27,6 +27,7 @@
#include "core_global.h"
+#include <utils/fileutils.h>
#include <utils/id.h>
#include <QObject>
@@ -87,9 +88,9 @@ public:
void setId(Utils::Id id);
Utils::Id id() const;
- virtual OpenResult open(QString *errorString, const QString &fileName, const QString &realFileName);
+ virtual OpenResult open(QString *errorString, const Utils::FilePath &filePath, const Utils::FilePath &realFilePath);
- virtual bool save(QString *errorString, const QString &fileName = QString(), bool autoSave = false);
+ virtual bool save(QString *errorString, const Utils::FilePath &filePath = Utils::FilePath(), bool autoSave = false);
virtual QByteArray contents() const;
virtual bool setContents(const QByteArray &contents);
@@ -124,8 +125,8 @@ public:
void checkPermissions();
- bool autoSave(QString *errorString, const QString &filePath);
- void setRestoredFrom(const QString &name);
+ bool autoSave(QString *errorString, const Utils::FilePath &filePath);
+ void setRestoredFrom(const Utils::FilePath &path);
void removeAutoSaveFile();
bool hasWriteWarning() const;
diff --git a/src/plugins/coreplugin/inavigationwidgetfactory.h b/src/plugins/coreplugin/inavigationwidgetfactory.h
index cd918de6f3..5b3b38455e 100644
--- a/src/plugins/coreplugin/inavigationwidgetfactory.h
+++ b/src/plugins/coreplugin/inavigationwidgetfactory.h
@@ -47,8 +47,6 @@ namespace Core {
struct NavigationView
{
- NavigationView(QWidget *w = nullptr) : widget(w) {}
-
QWidget *widget;
QList<QToolButton *> dockToolBarWidgets;
};
diff --git a/src/plugins/coreplugin/jsexpander.cpp b/src/plugins/coreplugin/jsexpander.cpp
index 22a4562685..25411ca509 100644
--- a/src/plugins/coreplugin/jsexpander.cpp
+++ b/src/plugins/coreplugin/jsexpander.cpp
@@ -36,20 +36,6 @@
#include <unordered_map>
-#if (QT_VERSION < QT_VERSION_CHECK(5, 14, 0))
-namespace std {
-template<> struct hash<QString>
-{
- using argument_type = QString;
- using result_type = size_t;
- result_type operator()(const argument_type &v) const
- {
- return hash<string>()(v.toStdString());
- }
-};
-} // namespace std
-#endif
-
using ExtensionMap = std::unordered_map<QString, Core::JsExpander::ObjectFactory>;
Q_GLOBAL_STATIC(ExtensionMap, globalJsExtensions);
diff --git a/src/plugins/coreplugin/locator/basefilefilter.cpp b/src/plugins/coreplugin/locator/basefilefilter.cpp
index ef75c683dc..ea6e82c7fe 100644
--- a/src/plugins/coreplugin/locator/basefilefilter.cpp
+++ b/src/plugins/coreplugin/locator/basefilefilter.cpp
@@ -28,6 +28,7 @@
#include <coreplugin/editormanager/editormanager.h>
#include <utils/algorithm.h>
#include <utils/fileutils.h>
+#include <utils/link.h>
#include <utils/qtcassert.h>
#include <QDir>
@@ -137,9 +138,10 @@ QList<LocatorFilterEntry> BaseFileFilter::matchesFor(QFutureInterface<LocatorFil
QList<LocatorFilterEntry> entries[int(MatchLevel::Count)];
// If search string contains spaces, treat them as wildcard '*' and search in full path
const QString entry = QDir::fromNativeSeparators(origEntry).replace(' ', '*');
- const EditorManager::FilePathInfo fp = EditorManager::splitLineAndColumnNumber(entry);
+ QString postfix;
+ Link link = Link::fromString(entry, true, &postfix);
- const QRegularExpression regexp = createRegExp(fp.filePath);
+ const QRegularExpression regexp = createRegExp(link.targetFilePath.toString());
if (!regexp.isValid()) {
d->m_current.clear(); // free memory
return {};
@@ -148,9 +150,9 @@ QList<LocatorFilterEntry> BaseFileFilter::matchesFor(QFutureInterface<LocatorFil
return candidate.contains('/') || candidate.contains('*');
};
- const bool hasPathSeparator = containsPathSeparator(fp.filePath);
+ const bool hasPathSeparator = containsPathSeparator(link.targetFilePath.toString());
const bool containsPreviousEntry = !d->m_current.previousEntry.isEmpty()
- && fp.filePath.contains(d->m_current.previousEntry);
+ && link.targetFilePath.toString().contains(d->m_current.previousEntry);
const bool pathSeparatorAdded = !containsPathSeparator(d->m_current.previousEntry)
&& hasPathSeparator;
const bool searchInPreviousResults = !d->m_current.forceNewSearchList && containsPreviousEntry
@@ -160,7 +162,7 @@ QList<LocatorFilterEntry> BaseFileFilter::matchesFor(QFutureInterface<LocatorFil
QTC_ASSERT(d->m_current.iterator.data(), return QList<LocatorFilterEntry>());
d->m_current.previousResultPaths.clear();
- d->m_current.previousEntry = fp.filePath;
+ d->m_current.previousEntry = link.targetFilePath.toString();
d->m_current.iterator->toFront();
bool canceled = false;
while (d->m_current.iterator->hasNext()) {
@@ -176,7 +178,7 @@ QList<LocatorFilterEntry> BaseFileFilter::matchesFor(QFutureInterface<LocatorFil
if (match.hasMatch()) {
QFileInfo fi(path.toString());
- LocatorFilterEntry filterEntry(this, fi.fileName(), QString(path.toString() + fp.postfix));
+ LocatorFilterEntry filterEntry(this, fi.fileName(), QString(path.toString() + postfix));
filterEntry.fileName = path.toString();
filterEntry.extraInfo = FilePath::fromFileInfo(fi).shortNativePath();
diff --git a/src/plugins/coreplugin/locator/directoryfilter.cpp b/src/plugins/coreplugin/locator/directoryfilter.cpp
index 6a730b0e07..69ddfc2eb3 100644
--- a/src/plugins/coreplugin/locator/directoryfilter.cpp
+++ b/src/plugins/coreplugin/locator/directoryfilter.cpp
@@ -67,6 +67,9 @@ DirectoryFilter::DirectoryFilter(Id id)
setId(id);
setDefaultIncludedByDefault(true);
setDisplayName(defaultDisplayName());
+ setDescription(tr("Matches all files from a custom set of directories. Append \"+<number>\" or "
+ "\":<number>\" to jump to the given line number. Append another "
+ "\"+<number>\" or \":<number>\" to jump to the column number as well."));
}
void DirectoryFilter::saveState(QJsonObject &object) const
diff --git a/src/plugins/coreplugin/locator/executefilter.cpp b/src/plugins/coreplugin/locator/executefilter.cpp
index 6110f13f71..be0af47dde 100644
--- a/src/plugins/coreplugin/locator/executefilter.cpp
+++ b/src/plugins/coreplugin/locator/executefilter.cpp
@@ -38,6 +38,9 @@ ExecuteFilter::ExecuteFilter()
{
setId("Execute custom commands");
setDisplayName(tr("Execute Custom Commands"));
+ setDescription(tr(
+ "Runs an arbitrary command with arguments. The command is searched for in the PATH "
+ "environment variable if needed. Note that the command is run directly, not in a shell."));
setDefaultShortcutString("!");
setPriority(High);
setDefaultIncludedByDefault(false);
diff --git a/src/plugins/coreplugin/locator/externaltoolsfilter.cpp b/src/plugins/coreplugin/locator/externaltoolsfilter.cpp
index 11e142f47b..159af87caf 100644
--- a/src/plugins/coreplugin/locator/externaltoolsfilter.cpp
+++ b/src/plugins/coreplugin/locator/externaltoolsfilter.cpp
@@ -37,6 +37,8 @@ ExternalToolsFilter::ExternalToolsFilter()
{
setId("Run external tool");
setDisplayName(tr("Run External Tool"));
+ setDescription(tr("Runs an external tool that you have set up in the options (Environment > "
+ "External Tools)."));
setDefaultShortcutString("x");
setPriority(Medium);
}
diff --git a/src/plugins/coreplugin/locator/filesystemfilter.cpp b/src/plugins/coreplugin/locator/filesystemfilter.cpp
index 118ebb2532..47c9be47c6 100644
--- a/src/plugins/coreplugin/locator/filesystemfilter.cpp
+++ b/src/plugins/coreplugin/locator/filesystemfilter.cpp
@@ -36,6 +36,7 @@
#include <coreplugin/vcsmanager.h>
#include <utils/checkablemessagebox.h>
#include <utils/fileutils.h>
+#include <utils/link.h>
#include <QDir>
#include <QJsonObject>
@@ -66,6 +67,9 @@ FileSystemFilter::FileSystemFilter()
{
setId("Files in file system");
setDisplayName(tr("Files in File System"));
+ setDescription(tr("Opens a file given by a relative path to the current document, or absolute "
+ "path. \"~\" refers to your home directory. You have the option to create a "
+ "file if it does not exist yet."));
setDefaultShortcutString("f");
setDefaultIncludedByDefault(false);
}
@@ -125,11 +129,11 @@ QList<LocatorFilterEntry> FileSystemFilter::matchesFor(QFutureInterface<LocatorF
}
}
// file names can match with +linenumber or :linenumber
- const EditorManager::FilePathInfo fp = EditorManager::splitLineAndColumnNumber(entryFileName);
- regExp = createRegExp(fp.filePath, caseSensitivity_);
+ QString postfix;
+ Link link = Link::fromString(entryFileName, true, &postfix);
+ regExp = createRegExp(link.targetFilePath.toString(), caseSensitivity_);
if (!regExp.isValid())
return {};
- const QString fileName = QFileInfo(fp.filePath).fileName();
for (const QString &file : files) {
if (future.isCanceled())
break;
@@ -138,7 +142,7 @@ QList<LocatorFilterEntry> FileSystemFilter::matchesFor(QFutureInterface<LocatorF
if (match.hasMatch()) {
const MatchLevel level = matchLevelFor(match, file);
const QString fullPath = dirInfo.filePath(file);
- LocatorFilterEntry filterEntry(this, file, QString(fullPath + fp.postfix));
+ LocatorFilterEntry filterEntry(this, file, QString(fullPath + postfix));
filterEntry.fileName = fullPath;
filterEntry.highlightInfo = highlightInfo(match);
@@ -147,7 +151,7 @@ QList<LocatorFilterEntry> FileSystemFilter::matchesFor(QFutureInterface<LocatorF
}
// "create and open" functionality
- const QString fullFilePath = dirInfo.filePath(fileName);
+ const QString fullFilePath = dirInfo.filePath(link.targetFilePath.fileName());
const bool containsWildcard = entry.contains('?') || entry.contains('*');
if (!containsWildcard && !QFileInfo::exists(fullFilePath) && dirInfo.exists()) {
LocatorFilterEntry createAndOpen(this, tr("Create and Open \"%1\"").arg(entry), fullFilePath);
diff --git a/src/plugins/coreplugin/locator/ilocatorfilter.cpp b/src/plugins/coreplugin/locator/ilocatorfilter.cpp
index 66a2b86e2c..aee4fe4906 100644
--- a/src/plugins/coreplugin/locator/ilocatorfilter.cpp
+++ b/src/plugins/coreplugin/locator/ilocatorfilter.cpp
@@ -460,6 +460,26 @@ void ILocatorFilter::setDisplayName(const QString &displayString)
}
/*!
+ Returns a longer, human-readable description of what the filter does.
+
+ \sa setDescription()
+*/
+QString ILocatorFilter::description() const
+{
+ return m_description;
+}
+
+/*!
+ Sets the longer, human-readable \a description of what the filter does.
+
+ \sa description()
+*/
+void ILocatorFilter::setDescription(const QString &description)
+{
+ m_description = description;
+}
+
+/*!
Sets whether the filter provides a configuration dialog to \a configurable.
Most filters should at least provide the default dialog.
diff --git a/src/plugins/coreplugin/locator/ilocatorfilter.h b/src/plugins/coreplugin/locator/ilocatorfilter.h
index 7bf15d284b..2efe446d65 100644
--- a/src/plugins/coreplugin/locator/ilocatorfilter.h
+++ b/src/plugins/coreplugin/locator/ilocatorfilter.h
@@ -85,6 +85,8 @@ struct LocatorFilterEntry
QString displayName;
/* extra information displayed in light-gray in a second column (optional) */
QString extraInfo;
+ /* additional tooltip */
+ QString toolTip;
/* can be used by the filter to save more information about the entry */
QVariant internalData;
/* icon to display along with the entry */
@@ -132,6 +134,9 @@ public:
QString displayName() const;
void setDisplayName(const QString &displayString);
+ QString description() const;
+ void setDescription(const QString &description);
+
Priority priority() const;
QString shortcutString() const;
@@ -193,6 +198,7 @@ private:
QString m_shortcut;
Priority m_priority = Medium;
QString m_displayName;
+ QString m_description;
QString m_defaultShortcut;
bool m_defaultIncludedByDefault = false;
bool m_includedByDefault = m_defaultIncludedByDefault;
diff --git a/src/plugins/coreplugin/locator/javascriptfilter.cpp b/src/plugins/coreplugin/locator/javascriptfilter.cpp
index 952cd0d094..257f133dda 100644
--- a/src/plugins/coreplugin/locator/javascriptfilter.cpp
+++ b/src/plugins/coreplugin/locator/javascriptfilter.cpp
@@ -38,6 +38,7 @@ JavaScriptFilter::JavaScriptFilter()
{
setId("JavaScriptFilter");
setDisplayName(tr("Evaluate JavaScript"));
+ setDescription(tr("Evaluates arbitrary JavaScript expressions and copies the result."));
setDefaultIncludedByDefault(false);
setDefaultShortcutString("=");
m_abortTimer.setSingleShot(true);
diff --git a/src/plugins/coreplugin/locator/locator.cpp b/src/plugins/coreplugin/locator/locator.cpp
index 670f77e201..8db747845c 100644
--- a/src/plugins/coreplugin/locator/locator.cpp
+++ b/src/plugins/coreplugin/locator/locator.cpp
@@ -250,6 +250,7 @@ void Locator::updateFilterActions()
action = actionCopy.take(filterId);
action->setText(filter->displayName());
}
+ action->setToolTip(filter->description());
m_filterActionMap.insert(filterId, action);
}
diff --git a/src/plugins/coreplugin/locator/locatorfiltersfilter.cpp b/src/plugins/coreplugin/locator/locatorfiltersfilter.cpp
index d753907cec..7b62ff1bf1 100644
--- a/src/plugins/coreplugin/locator/locatorfiltersfilter.cpp
+++ b/src/plugins/coreplugin/locator/locatorfiltersfilter.cpp
@@ -51,6 +51,7 @@ void LocatorFiltersFilter::prepareSearch(const QString &entry)
{
m_filterShortcutStrings.clear();
m_filterDisplayNames.clear();
+ m_filterDescriptions.clear();
if (!entry.isEmpty())
return;
@@ -65,6 +66,7 @@ void LocatorFiltersFilter::prepareSearch(const QString &entry)
if (!filter->shortcutString().isEmpty() && !filter->isHidden() && filter->isEnabled()) {
m_filterShortcutStrings.append(filter->shortcutString());
m_filterDisplayNames.append(filter->displayName());
+ m_filterDescriptions.append(filter->description());
}
}
}
@@ -81,6 +83,7 @@ QList<LocatorFilterEntry> LocatorFiltersFilter::matchesFor(QFutureInterface<Loca
i,
m_icon);
filterEntry.extraInfo = m_filterDisplayNames.at(i);
+ filterEntry.toolTip = m_filterDescriptions.at(i);
entries.append(filterEntry);
}
return entries;
diff --git a/src/plugins/coreplugin/locator/locatorfiltersfilter.h b/src/plugins/coreplugin/locator/locatorfiltersfilter.h
index cbdc0761ad..c316670fad 100644
--- a/src/plugins/coreplugin/locator/locatorfiltersfilter.h
+++ b/src/plugins/coreplugin/locator/locatorfiltersfilter.h
@@ -55,6 +55,7 @@ public:
private:
QStringList m_filterShortcutStrings;
QStringList m_filterDisplayNames;
+ QStringList m_filterDescriptions;
QIcon m_icon;
};
diff --git a/src/plugins/coreplugin/locator/locatorsettingspage.cpp b/src/plugins/coreplugin/locator/locatorsettingspage.cpp
index 02ddbf6337..e0c569d05e 100644
--- a/src/plugins/coreplugin/locator/locatorsettingspage.cpp
+++ b/src/plugins/coreplugin/locator/locatorsettingspage.cpp
@@ -111,6 +111,9 @@ QVariant FilterItem::data(int column, int role) const
default:
break;
}
+
+ if (role == Qt::ToolTipRole)
+ return m_filter->description();
return QVariant();
}
diff --git a/src/plugins/coreplugin/locator/locatorwidget.cpp b/src/plugins/coreplugin/locator/locatorwidget.cpp
index 9c93c81f70..f70550bd5f 100644
--- a/src/plugins/coreplugin/locator/locatorwidget.cpp
+++ b/src/plugins/coreplugin/locator/locatorwidget.cpp
@@ -197,13 +197,15 @@ QVariant LocatorModel::data(const QModelIndex &index, int role) const
else if (index.column() == ExtraInfoColumn)
return mEntries.at(index.row()).extraInfo;
break;
- case Qt::ToolTipRole:
- if (mEntries.at(index.row()).extraInfo.isEmpty())
- return QVariant(mEntries.at(index.row()).displayName);
- else
- return QVariant(mEntries.at(index.row()).displayName
- + "\n\n" + mEntries.at(index.row()).extraInfo);
- break;
+ case Qt::ToolTipRole: {
+ const LocatorFilterEntry &entry = mEntries.at(index.row());
+ QString toolTip = entry.displayName;
+ if (!entry.extraInfo.isEmpty())
+ toolTip += "\n\n" + entry.extraInfo;
+ if (!entry.toolTip.isEmpty())
+ toolTip += "\n\n" + entry.toolTip;
+ return QVariant(toolTip);
+ }
case Qt::DecorationRole:
if (index.column() == DisplayNameColumn) {
LocatorFilterEntry &entry = mEntries[index.row()];
diff --git a/src/plugins/coreplugin/locator/opendocumentsfilter.cpp b/src/plugins/coreplugin/locator/opendocumentsfilter.cpp
index f3d14cdb08..6a74cc8d7a 100644
--- a/src/plugins/coreplugin/locator/opendocumentsfilter.cpp
+++ b/src/plugins/coreplugin/locator/opendocumentsfilter.cpp
@@ -28,6 +28,7 @@
#include <coreplugin/editormanager/editormanager.h>
#include <coreplugin/editormanager/ieditor.h>
#include <utils/fileutils.h>
+#include <utils/link.h>
#include <QAbstractItemModel>
#include <QFileInfo>
@@ -59,9 +60,10 @@ QList<LocatorFilterEntry> OpenDocumentsFilter::matchesFor(QFutureInterface<Locat
{
QList<LocatorFilterEntry> goodEntries;
QList<LocatorFilterEntry> betterEntries;
- const EditorManager::FilePathInfo fp = EditorManager::splitLineAndColumnNumber(entry);
+ QString postfix;
+ Link link = Link::fromString(entry, true, &postfix);
- const QRegularExpression regexp = createRegExp(fp.filePath);
+ const QRegularExpression regexp = createRegExp(link.targetFilePath.toString());
if (!regexp.isValid())
return goodEntries;
@@ -75,7 +77,7 @@ QList<LocatorFilterEntry> OpenDocumentsFilter::matchesFor(QFutureInterface<Locat
QString displayName = editorEntry.displayName;
const QRegularExpressionMatch match = regexp.match(displayName);
if (match.hasMatch()) {
- LocatorFilterEntry filterEntry(this, displayName, QString(fileName + fp.postfix));
+ LocatorFilterEntry filterEntry(this, displayName, QString(fileName + postfix));
filterEntry.extraInfo = FilePath::fromString(fileName).shortNativePath();
filterEntry.fileName = fileName;
filterEntry.highlightInfo = highlightInfo(match);
diff --git a/src/plugins/coreplugin/locator/spotlightlocatorfilter.cpp b/src/plugins/coreplugin/locator/spotlightlocatorfilter.cpp
index f333d11b30..1c507174c7 100644
--- a/src/plugins/coreplugin/locator/spotlightlocatorfilter.cpp
+++ b/src/plugins/coreplugin/locator/spotlightlocatorfilter.cpp
@@ -30,8 +30,10 @@
#include <coreplugin/editormanager/editormanager.h>
#include <coreplugin/reaper.h>
#include <utils/algorithm.h>
+#include <utils/commandline.h>
#include <utils/environment.h>
#include <utils/fancylineedit.h>
+#include <utils/link.h>
#include <utils/macroexpander.h>
#include <utils/pathchooser.h>
#include <utils/qtcassert.h>
@@ -72,7 +74,7 @@ public:
private:
void ensureNext();
- std::unique_ptr<QProcess> m_process;
+ std::unique_ptr<QtcProcess> m_process;
QMutex m_mutex;
QWaitCondition m_waitForItems;
QList<FilePath> m_queue;
@@ -86,11 +88,10 @@ SpotlightIterator::SpotlightIterator(const QStringList &command)
, m_finished(false)
{
QTC_ASSERT(!command.isEmpty(), return );
- m_process.reset(new QProcess);
- m_process->setProgram(
- Utils::Environment::systemEnvironment().searchInPath(command.first()).toString());
- m_process->setArguments(command.mid(1));
- m_process->setProcessEnvironment(Utils::Environment::systemEnvironment().toProcessEnvironment());
+ m_process.reset(new QtcProcess);
+ m_process->setCommand({Environment::systemEnvironment().searchInPath(command.first()),
+ command.mid(1)});
+ m_process->setEnvironment(Utils::Environment::systemEnvironment());
QObject::connect(m_process.get(),
QOverload<int, QProcess::ExitStatus>::of(&QProcess::finished),
[this] { scheduleKillProcess(); });
@@ -110,7 +111,8 @@ SpotlightIterator::SpotlightIterator(const QStringList &command)
scheduleKillProcess();
m_waitForItems.wakeAll();
});
- m_process->start(QIODevice::ReadOnly);
+ m_process->setOpenMode(QIODevice::ReadOnly);
+ m_process->start();
}
SpotlightIterator::~SpotlightIterator()
@@ -241,25 +243,29 @@ SpotlightLocatorFilter::SpotlightLocatorFilter()
setDefaultShortcutString("md");
setDefaultIncludedByDefault(false);
setDisplayName(tr("File Name Index"));
+ setDescription(
+ tr("Matches files from a global file system index (Spotlight, Locate, Everything). Append "
+ "\"+<number>\" or \":<number>\" to jump to the given line number. Append another "
+ "\"+<number>\" or \":<number>\" to jump to the column number as well."));
setConfigurable(true);
reset();
}
void SpotlightLocatorFilter::prepareSearch(const QString &entry)
{
- const EditorManager::FilePathInfo fp = EditorManager::splitLineAndColumnNumber(entry);
- if (fp.filePath.isEmpty()) {
+ Link link = Utils::Link::fromString(entry, true);
+ if (link.targetFilePath.isEmpty()) {
setFileIterator(new BaseFileFilter::ListIterator(Utils::FilePaths()));
} else {
// only pass the file name part to allow searches like "somepath/*foo"
- int lastSlash = fp.filePath.lastIndexOf(QLatin1Char('/'));
- const QString query = fp.filePath.mid(lastSlash + 1);
- std::unique_ptr<MacroExpander> expander(createMacroExpander(query));
+
+ std::unique_ptr<MacroExpander> expander(createMacroExpander(link.targetFilePath.fileName()));
const QString argumentString = expander->expand(
- caseSensitivity(fp.filePath) == Qt::CaseInsensitive ? m_arguments
- : m_caseSensitiveArguments);
+ caseSensitivity(link.targetFilePath.toString()) == Qt::CaseInsensitive
+ ? m_arguments
+ : m_caseSensitiveArguments);
setFileIterator(
- new SpotlightIterator(QStringList(m_command) + QtcProcess::splitArgs(argumentString)));
+ new SpotlightIterator(QStringList(m_command) + ProcessArgs::splitArgs(argumentString)));
}
BaseFileFilter::prepareSearch(entry);
}
diff --git a/src/plugins/coreplugin/mainwindow.cpp b/src/plugins/coreplugin/mainwindow.cpp
index 9f7b9274e7..ec73da4afa 100644
--- a/src/plugins/coreplugin/mainwindow.cpp
+++ b/src/plugins/coreplugin/mainwindow.cpp
@@ -948,9 +948,9 @@ void MainWindow::openFileWith()
if (!editorId.isValid())
continue;
if (isExternal)
- EditorManager::openExternalEditor(fileName, editorId);
+ EditorManager::openExternalEditor(FilePath::fromString(fileName), editorId);
else
- EditorManagerPrivate::openEditorWith(fileName, editorId);
+ EditorManagerPrivate::openEditorWith(FilePath::fromString(fileName), editorId);
}
}
diff --git a/src/plugins/coreplugin/menubarfilter.cpp b/src/plugins/coreplugin/menubarfilter.cpp
index ad8f904148..354a0e7b36 100644
--- a/src/plugins/coreplugin/menubarfilter.cpp
+++ b/src/plugins/coreplugin/menubarfilter.cpp
@@ -54,6 +54,9 @@ MenuBarFilter::MenuBarFilter()
{
setId("Actions from the menu");
setDisplayName(tr("Actions from the Menu"));
+ setDescription(
+ tr("Triggers an action from the menu. Matches any part of a menu hierarchy, separated by "
+ "\">\". For example \"sess def\" matches \"File > Sessions > Default\"."));
setDefaultShortcutString("t");
connect(ICore::instance(), &ICore::contextAboutToChange, this, [this] {
if (LocatorManager::locatorHasFocus())
diff --git a/src/plugins/coreplugin/mimetypesettings.cpp b/src/plugins/coreplugin/mimetypesettings.cpp
index 5cfe6ea84c..232de2334d 100644
--- a/src/plugins/coreplugin/mimetypesettings.cpp
+++ b/src/plugins/coreplugin/mimetypesettings.cpp
@@ -53,7 +53,7 @@
#include <QStyledItemDelegate>
#include <QSortFilterProxyModel>
-static const char kModifiedMimeTypesFile[] = "/mimetypes/modifiedmimetypes.xml";
+static const char kModifiedMimeTypesFile[] = "mimetypes/modifiedmimetypes.xml";
static const char mimeInfoTagC[] = "mime-info";
static const char mimeTypeTagC[] = "mime-type";
@@ -502,8 +502,8 @@ void MimeTypeSettingsPrivate::ensurePendingMimeType(const Utils::MimeType &mimeT
void MimeTypeSettingsPrivate::writeUserModifiedMimeTypes()
{
- static Utils::FilePath modifiedMimeTypesFile = Utils::FilePath::fromString(
- ICore::userResourcePath() + QLatin1String(kModifiedMimeTypesFile));
+ static Utils::FilePath modifiedMimeTypesFile = ICore::userResourcePath()
+ + kModifiedMimeTypesFile;
if (QFile::exists(modifiedMimeTypesFile.toString())
|| QDir().mkpath(modifiedMimeTypesFile.parentDir().toString())) {
@@ -564,10 +564,9 @@ static QPair<int, int> rangeFromString(const QString &offset)
MimeTypeSettingsPrivate::UserMimeTypeHash MimeTypeSettingsPrivate::readUserModifiedMimeTypes()
{
- static QString modifiedMimeTypesPath = ICore::userResourcePath()
- + QLatin1String(kModifiedMimeTypesFile);
+ static Utils::FilePath modifiedMimeTypesPath = ICore::userResourcePath(kModifiedMimeTypesFile);
UserMimeTypeHash userMimeTypes;
- QFile file(modifiedMimeTypesPath);
+ QFile file(modifiedMimeTypesPath.toString());
if (file.open(QFile::ReadOnly)) {
UserMimeType mt;
QXmlStreamReader reader(&file);
diff --git a/src/plugins/coreplugin/outputwindow.cpp b/src/plugins/coreplugin/outputwindow.cpp
index 1e69c475f7..e04c3cd71d 100644
--- a/src/plugins/coreplugin/outputwindow.cpp
+++ b/src/plugins/coreplugin/outputwindow.cpp
@@ -148,9 +148,8 @@ OutputWindow::OutputWindow(Context context, const QString &settingsKey, QWidget
Core::ICore::settings()->setValueWithDefault(d->settingsKey, fontZoom(), 0.f);
});
- connect(outputFormatter(), &OutputFormatter::openInEditorRequested, this,
- [](const Utils::FilePath &fp, int line, int column) {
- EditorManager::openEditorAt(fp.toString(), line, column);
+ connect(outputFormatter(), &OutputFormatter::openInEditorRequested, this, [](const Link &link) {
+ EditorManager::openEditorAt(link);
});
connect(verticalScrollBar(), &QAbstractSlider::actionTriggered,
diff --git a/src/plugins/coreplugin/patchtool.cpp b/src/plugins/coreplugin/patchtool.cpp
index 1fdb9a34ba..345673e117 100644
--- a/src/plugins/coreplugin/patchtool.cpp
+++ b/src/plugins/coreplugin/patchtool.cpp
@@ -26,11 +26,10 @@
#include "patchtool.h"
#include "messagemanager.h"
#include "icore.h"
-#include <utils/synchronousprocess.h>
+
#include <utils/environment.h>
+#include <utils/qtcprocess.h>
-#include <QProcess>
-#include <QProcessEnvironment>
#include <QDir>
#include <QApplication>
@@ -38,6 +37,8 @@ static const char settingsGroupC[] = "General";
static const char patchCommandKeyC[] = "PatchCommand";
static const char patchCommandDefaultC[] = "patch";
+using namespace Utils;
+
namespace Core {
QString PatchTool::patchCommand()
@@ -79,12 +80,12 @@ static bool runPatchHelper(const QByteArray &input, const QString &workingDirect
return false;
}
- QProcess patchProcess;
+ QtcProcess patchProcess;
if (!workingDirectory.isEmpty())
patchProcess.setWorkingDirectory(workingDirectory);
- QProcessEnvironment env = QProcessEnvironment::systemEnvironment();
- Utils::Environment::setupEnglishOutput(&env);
- patchProcess.setProcessEnvironment(env);
+ Environment env = Environment::systemEnvironment();
+ env.setupEnglishOutput();
+ patchProcess.setEnvironment(env);
QStringList args;
// Add argument 'apply' when git is used as patch command since git 2.5/Windows
// no longer ships patch.exe.
@@ -103,7 +104,8 @@ static bool runPatchHelper(const QByteArray &input, const QString &workingDirect
.arg(QDir::toNativeSeparators(workingDirectory),
QDir::toNativeSeparators(patch),
args.join(QLatin1Char(' '))));
- patchProcess.start(patch, args);
+ patchProcess.setCommand({patch, args});
+ patchProcess.start();
if (!patchProcess.waitForStarted()) {
MessageManager::writeFlashing(
QApplication::translate("Core::PatchTool", "Unable to launch \"%1\": %2")
@@ -114,8 +116,8 @@ static bool runPatchHelper(const QByteArray &input, const QString &workingDirect
patchProcess.closeWriteChannel();
QByteArray stdOut;
QByteArray stdErr;
- if (!Utils::SynchronousProcess::readDataFromProcess(patchProcess, 30, &stdOut, &stdErr, true)) {
- Utils::SynchronousProcess::stopProcess(patchProcess);
+ if (!patchProcess.readDataFromProcess(30, &stdOut, &stdErr, true)) {
+ patchProcess.stopProcess();
MessageManager::writeFlashing(
QApplication::translate("Core::PatchTool", "A timeout occurred running \"%1\"")
.arg(patch));
diff --git a/src/plugins/coreplugin/plugininstallwizard.cpp b/src/plugins/coreplugin/plugininstallwizard.cpp
index 91230b658e..16200daf3f 100644
--- a/src/plugins/coreplugin/plugininstallwizard.cpp
+++ b/src/plugins/coreplugin/plugininstallwizard.cpp
@@ -36,8 +36,8 @@
#include <utils/infolabel.h>
#include <utils/pathchooser.h>
#include <utils/qtcassert.h>
+#include <utils/qtcprocess.h>
#include <utils/runextensions.h>
-#include <utils/synchronousprocess.h>
#include <utils/temporarydirectory.h>
#include <utils/wizard.h>
#include <utils/wizardpage.h>
@@ -429,7 +429,8 @@ static std::function<void(QFileInfo)> postCopyOperation()
// to get it loaded as a plugin in Qt Creator.
SynchronousProcess xattr;
xattr.setTimeoutS(1);
- xattr.runBlocking({"/usr/bin/xattr", {"-d", "com.apple.quarantine", fi.absoluteFilePath()}});
+ xattr.setCommand({"/usr/bin/xattr", {"-d", "com.apple.quarantine", fi.absoluteFilePath()}});
+ xattr.runBlocking();
};
}
diff --git a/src/plugins/coreplugin/progressmanager/progressmanager.cpp b/src/plugins/coreplugin/progressmanager/progressmanager.cpp
index 7ac8b174fa..f0b42da7d6 100644
--- a/src/plugins/coreplugin/progressmanager/progressmanager.cpp
+++ b/src/plugins/coreplugin/progressmanager/progressmanager.cpp
@@ -377,7 +377,6 @@ FutureProgress *ProgressManagerPrivate::doAddTask(const QFuture<void> &future, c
connect(watcher, &QFutureWatcherBase::progressValueChanged,
this, &ProgressManagerPrivate::updateSummaryProgressBar);
connect(watcher, &QFutureWatcherBase::finished, this, &ProgressManagerPrivate::taskFinished);
- watcher->setFuture(future);
// handle application task
if (flags & ShowInApplicationIcon) {
@@ -393,6 +392,8 @@ FutureProgress *ProgressManagerPrivate::doAddTask(const QFuture<void> &future, c
setApplicationProgressVisible(true);
}
+ watcher->setFuture(future);
+
// create FutureProgress and manage task list
removeOldTasks(type);
if (m_taskList.size() == 10)
diff --git a/src/plugins/coreplugin/progressmanager/progressmanager_win.cpp b/src/plugins/coreplugin/progressmanager/progressmanager_win.cpp
index 9102626863..7f353b0e22 100644
--- a/src/plugins/coreplugin/progressmanager/progressmanager_win.cpp
+++ b/src/plugins/coreplugin/progressmanager/progressmanager_win.cpp
@@ -41,6 +41,7 @@
// for windows progress bar
#ifndef __GNUC__
+# define CALLBACK WINAPI
# include <shobjidl.h>
#endif
diff --git a/src/plugins/coreplugin/reaper.cpp b/src/plugins/coreplugin/reaper.cpp
index ff7bcd6713..540a80303e 100644
--- a/src/plugins/coreplugin/reaper.cpp
+++ b/src/plugins/coreplugin/reaper.cpp
@@ -34,31 +34,17 @@
#include <QThread>
#include <QTimer>
+using namespace Utils;
+
namespace Core {
namespace Internal {
static ProcessReapers *d = nullptr;
-static void killProcess(QProcess *process)
-{
- if (auto qtcProcess = qobject_cast<Utils::QtcProcess*>(process))
- qtcProcess->kill();
- else
- process->kill();
-}
-
-static void terminateProcess(QProcess *process)
-{
- if (auto qtcProcess = qobject_cast<Utils::QtcProcess*>(process))
- qtcProcess->terminate();
- else
- process->terminate();
-}
-
class ProcessReaper final : public QObject
{
public:
- ProcessReaper(QProcess *p, int timeoutMs);
+ ProcessReaper(QtcProcess *p, int timeoutMs);
~ProcessReaper() final;
int timeoutMs() const;
@@ -67,12 +53,12 @@ public:
private:
mutable QTimer m_iterationTimer;
- QProcess *m_process;
+ QtcProcess *m_process;
int m_emergencyCounter = 0;
QProcess::ProcessState m_lastState = QProcess::NotRunning;
};
-ProcessReaper::ProcessReaper(QProcess *p, int timeoutMs) : m_process(p)
+ProcessReaper::ProcessReaper(QtcProcess *p, int timeoutMs) : m_process(p)
{
d->m_reapers.append(this);
@@ -113,12 +99,12 @@ void ProcessReaper::nextIteration()
if (state == QProcess::Starting) {
if (m_lastState == QProcess::Starting)
- killProcess(m_process);
+ m_process->kill();
} else if (state == QProcess::Running) {
if (m_lastState == QProcess::Running)
- killProcess(m_process);
+ m_process->kill();
else
- terminateProcess(m_process);
+ m_process->terminate();
}
m_lastState = state;
@@ -165,7 +151,7 @@ ProcessReapers::~ProcessReapers()
namespace Reaper {
-void reap(QProcess *process, int timeoutMs)
+void reap(QtcProcess *process, int timeoutMs)
{
if (!process)
return;
diff --git a/src/plugins/coreplugin/reaper.h b/src/plugins/coreplugin/reaper.h
index 7c2b2a356a..9ea61b219c 100644
--- a/src/plugins/coreplugin/reaper.h
+++ b/src/plugins/coreplugin/reaper.h
@@ -27,12 +27,12 @@
#include "core_global.h"
-QT_FORWARD_DECLARE_CLASS(QProcess);
+namespace Utils { class QtcProcess; }
namespace Core {
namespace Reaper {
-CORE_EXPORT void reap(QProcess *p, int timeoutMs = 500);
+CORE_EXPORT void reap(Utils::QtcProcess *p, int timeoutMs = 500);
} // namespace Reaper
} // namespace Core
diff --git a/src/plugins/coreplugin/shellcommand.cpp b/src/plugins/coreplugin/shellcommand.cpp
index 0e643d5df4..38dbfdea44 100644
--- a/src/plugins/coreplugin/shellcommand.cpp
+++ b/src/plugins/coreplugin/shellcommand.cpp
@@ -33,7 +33,7 @@
namespace Core {
-ShellCommand::ShellCommand(const QString &workingDirectory, const QProcessEnvironment &environment) :
+ShellCommand::ShellCommand(const QString &workingDirectory, const Utils::Environment &environment) :
Utils::ShellCommand(workingDirectory, environment)
{
connect(Core::ICore::instance(), &Core::ICore::coreAboutToClose,
diff --git a/src/plugins/coreplugin/shellcommand.h b/src/plugins/coreplugin/shellcommand.h
index b960bae94d..37026a82d7 100644
--- a/src/plugins/coreplugin/shellcommand.h
+++ b/src/plugins/coreplugin/shellcommand.h
@@ -40,7 +40,7 @@ class CORE_EXPORT ShellCommand : public Utils::ShellCommand
Q_OBJECT
public:
- ShellCommand(const QString &workingDirectory, const QProcessEnvironment &environment);
+ ShellCommand(const QString &workingDirectory, const Utils::Environment &environment);
FutureProgress *futureProgress() const;
diff --git a/src/plugins/coreplugin/textdocument.cpp b/src/plugins/coreplugin/textdocument.cpp
index 3040dd9a45..4d6c45dadf 100644
--- a/src/plugins/coreplugin/textdocument.cpp
+++ b/src/plugins/coreplugin/textdocument.cpp
@@ -82,7 +82,7 @@ QByteArray BaseTextDocument::decodingErrorSample() const
}
/*!
- Writes out the contents (\a data) of the text file \a fileName.
+ Writes out the contents (\a data) of the text file \a filePath.
Uses the format obtained from the last read() of the file.
If an error occurs while writing the file, \a errorMessage is set to the
@@ -91,13 +91,15 @@ QByteArray BaseTextDocument::decodingErrorSample() const
Returns whether the operation was successful.
*/
-bool BaseTextDocument::write(const QString &fileName, const QString &data, QString *errorMessage) const
+bool BaseTextDocument::write(const Utils::FilePath &filePath,
+ const QString &data,
+ QString *errorMessage) const
{
- return write(fileName, format(), data, errorMessage);
+ return write(filePath, format(), data, errorMessage);
}
/*!
- Writes out the contents (\a data) of the text file \a fileName.
+ Writes out the contents (\a data) of the text file \a filePath.
Uses the custom format \a format.
If an error occurs while writing the file, \a errorMessage is set to the
@@ -106,11 +108,14 @@ bool BaseTextDocument::write(const QString &fileName, const QString &data, QStri
Returns whether the operation was successful.
*/
-bool BaseTextDocument::write(const QString &fileName, const Utils::TextFileFormat &format, const QString &data, QString *errorMessage) const
+bool BaseTextDocument::write(const Utils::FilePath &filePath,
+ const Utils::TextFileFormat &format,
+ const QString &data,
+ QString *errorMessage) const
{
if (debug)
- qDebug() << Q_FUNC_INFO << this << fileName;
- return format.writeFile(fileName, data, errorMessage);
+ qDebug() << Q_FUNC_INFO << this << filePath;
+ return format.writeFile(filePath, data, errorMessage);
}
void BaseTextDocument::setSupportsUtf8Bom(bool value)
@@ -124,7 +129,7 @@ void BaseTextDocument::setLineTerminationMode(Utils::TextFileFormat::LineTermina
}
/*!
- Autodetects file format and reads the text file specified by \a fileName
+ Autodetects file format and reads the text file specified by \a filePath
into a list of strings specified by \a plainTextList.
If an error occurs while writing the file, \a errorString is set to the
@@ -133,16 +138,21 @@ void BaseTextDocument::setLineTerminationMode(Utils::TextFileFormat::LineTermina
Returns whether the operation was successful.
*/
-BaseTextDocument::ReadResult BaseTextDocument::read(const QString &fileName, QStringList *plainTextList, QString *errorString)
+BaseTextDocument::ReadResult BaseTextDocument::read(const Utils::FilePath &filePath,
+ QStringList *plainTextList,
+ QString *errorString)
{
- d->m_readResult =
- Utils::TextFileFormat::readFile(fileName, codec(),
- plainTextList, &d->m_format, errorString, &d->m_decodingErrorSample);
+ d->m_readResult = Utils::TextFileFormat::readFile(filePath,
+ codec(),
+ plainTextList,
+ &d->m_format,
+ errorString,
+ &d->m_decodingErrorSample);
return d->m_readResult;
}
/*!
- Autodetects file format and reads the text file specified by \a fileName
+ Autodetects file format and reads the text file specified by \a filePath
into \a plainText.
If an error occurs while writing the file, \a errorString is set to the
@@ -151,11 +161,16 @@ BaseTextDocument::ReadResult BaseTextDocument::read(const QString &fileName, QSt
Returns whether the operation was successful.
*/
-BaseTextDocument::ReadResult BaseTextDocument::read(const QString &fileName, QString *plainText, QString *errorString)
+BaseTextDocument::ReadResult BaseTextDocument::read(const Utils::FilePath &filePath,
+ QString *plainText,
+ QString *errorString)
{
- d->m_readResult =
- Utils::TextFileFormat::readFile(fileName, codec(),
- plainText, &d->m_format, errorString, &d->m_decodingErrorSample);
+ d->m_readResult = Utils::TextFileFormat::readFile(filePath,
+ codec(),
+ plainText,
+ &d->m_format,
+ errorString,
+ &d->m_decodingErrorSample);
return d->m_readResult;
}
diff --git a/src/plugins/coreplugin/textdocument.h b/src/plugins/coreplugin/textdocument.h
index f1b1b4fc85..7d16b6fa81 100644
--- a/src/plugins/coreplugin/textdocument.h
+++ b/src/plugins/coreplugin/textdocument.h
@@ -50,14 +50,14 @@ public:
bool supportsUtf8Bom() const;
Utils::TextFileFormat::LineTerminationMode lineTerminationMode() const;
- ReadResult read(const QString &fileName, QStringList *plainTextList, QString *errorString);
- ReadResult read(const QString &fileName, QString *plainText, QString *errorString);
+ ReadResult read(const Utils::FilePath &filePath, QStringList *plainTextList, QString *errorString);
+ ReadResult read(const Utils::FilePath &filePath, QString *plainText, QString *errorString);
bool hasDecodingError() const;
QByteArray decodingErrorSample() const;
- bool write(const QString &fileName, const QString &data, QString *errorMessage) const;
- bool write(const QString &fileName, const Utils::TextFileFormat &format, const QString &data, QString *errorMessage) const;
+ bool write(const Utils::FilePath &filePath, const QString &data, QString *errorMessage) const;
+ bool write(const Utils::FilePath &filePath, const Utils::TextFileFormat &format, const QString &data, QString *errorMessage) const;
void setSupportsUtf8Bom(bool value);
void setLineTerminationMode(Utils::TextFileFormat::LineTerminationMode mode);
diff --git a/src/plugins/coreplugin/themechooser.cpp b/src/plugins/coreplugin/themechooser.cpp
index 13af462167..f3d828d4b4 100644
--- a/src/plugins/coreplugin/themechooser.cpp
+++ b/src/plugins/coreplugin/themechooser.cpp
@@ -211,19 +211,19 @@ QList<ThemeEntry> ThemeEntry::availableThemes()
{
QList<ThemeEntry> themes;
- static const QString installThemeDir = ICore::resourcePath() + QLatin1String("/themes");
- static const QString userThemeDir = ICore::userResourcePath() + QLatin1String("/themes");
- addThemesFromPath(installThemeDir, &themes);
+ static const FilePath installThemeDir = ICore::resourcePath("themes");
+ static const FilePath userThemeDir = ICore::userResourcePath("themes");
+ addThemesFromPath(installThemeDir.toString(), &themes);
if (themes.isEmpty())
qWarning() << "Warning: No themes found in installation: "
- << QDir::toNativeSeparators(installThemeDir);
+ << installThemeDir.toUserOutput();
// move default theme to front
int defaultIndex = Utils::indexOf(themes, Utils::equal(&ThemeEntry::id, Id(Constants::DEFAULT_THEME)));
if (defaultIndex > 0) { // == exists and not at front
ThemeEntry defaultEntry = themes.takeAt(defaultIndex);
themes.prepend(defaultEntry);
}
- addThemesFromPath(userThemeDir, &themes);
+ addThemesFromPath(userThemeDir.toString(), &themes);
return themes;
}
diff --git a/src/plugins/cpaster/CMakeLists.txt b/src/plugins/cpaster/CMakeLists.txt
index 39ab53da64..6b915fbcef 100644
--- a/src/plugins/cpaster/CMakeLists.txt
+++ b/src/plugins/cpaster/CMakeLists.txt
@@ -14,7 +14,6 @@ add_qtc_plugin(CodePaster
dpastedotcomprotocol.cpp dpastedotcomprotocol.h
fileshareprotocol.cpp fileshareprotocol.h
fileshareprotocolsettingspage.cpp fileshareprotocolsettingspage.h
- fileshareprotocolsettingswidget.ui
frontend/argumentscollector.cpp frontend/argumentscollector.h
frontend/main.cpp
pastebindotcomprotocol.cpp pastebindotcomprotocol.h
@@ -24,7 +23,6 @@ add_qtc_plugin(CodePaster
pasteview.cpp pasteview.h pasteview.ui
protocol.cpp protocol.h
settings.cpp settings.h
- settingspage.cpp settingspage.h settingspage.ui
stickynotespasteprotocol.cpp stickynotespasteprotocol.h
urlopenprotocol.cpp urlopenprotocol.h
diff --git a/src/plugins/cpaster/cpaster.pro b/src/plugins/cpaster/cpaster.pro
index c824caa681..d35c042964 100644
--- a/src/plugins/cpaster/cpaster.pro
+++ b/src/plugins/cpaster/cpaster.pro
@@ -2,7 +2,6 @@ QT += network
include(../../qtcreatorplugin.pri)
HEADERS += cpasterplugin.h \
dpastedotcomprotocol.h \
- settingspage.h \
protocol.h \
pasteview.h \
cpasterconstants.h \
@@ -18,7 +17,6 @@ HEADERS += cpasterplugin.h \
SOURCES += cpasterplugin.cpp \
dpastedotcomprotocol.cpp \
- settingspage.cpp \
protocol.cpp \
pasteview.cpp \
pastebindotcomprotocol.cpp \
@@ -30,11 +28,10 @@ SOURCES += cpasterplugin.cpp \
stickynotespasteprotocol.cpp \
urlopenprotocol.cpp
-FORMS += settingspage.ui \
+FORMS += \
pasteselect.ui \
pasteview.ui \
- pastebindotcomsettings.ui \
- fileshareprotocolsettingswidget.ui
+ pastebindotcomsettings.ui
include(../../shared/cpaster/cpaster.pri)
RESOURCES += \
diff --git a/src/plugins/cpaster/cpaster.qbs b/src/plugins/cpaster/cpaster.qbs
index e4aa433130..716f961632 100644
--- a/src/plugins/cpaster/cpaster.qbs
+++ b/src/plugins/cpaster/cpaster.qbs
@@ -25,7 +25,6 @@ QtcPlugin {
"fileshareprotocol.h",
"fileshareprotocolsettingspage.cpp",
"fileshareprotocolsettingspage.h",
- "fileshareprotocolsettingswidget.ui",
"pastebindotcomprotocol.cpp",
"pastebindotcomprotocol.h",
"pastebindotcomsettings.ui",
@@ -39,9 +38,6 @@ QtcPlugin {
"protocol.h",
"settings.cpp",
"settings.h",
- "settingspage.cpp",
- "settingspage.h",
- "settingspage.ui",
"stickynotespasteprotocol.cpp",
"stickynotespasteprotocol.h",
"urlopenprotocol.cpp",
diff --git a/src/plugins/cpaster/cpasterplugin.cpp b/src/plugins/cpaster/cpasterplugin.cpp
index 455d674877..bd725d555d 100644
--- a/src/plugins/cpaster/cpasterplugin.cpp
+++ b/src/plugins/cpaster/cpasterplugin.cpp
@@ -30,7 +30,6 @@
#include "pastebindotcomprotocol.h"
#include "pasteselectdialog.h"
#include "pasteview.h"
-#include "settingspage.h"
#include "settings.h"
#include "urlopenprotocol.h"
@@ -98,10 +97,7 @@ public:
&dpasteProto
};
- SettingsPage m_settingsPage {
- &m_settings,
- Utils::transform(m_protocols, &Protocol::name)
- };
+ SettingsPage m_settingsPage{&m_settings};
QStringList m_fetchedSnippets;
@@ -154,15 +150,19 @@ bool CodePasterPlugin::initialize(const QStringList &arguments, QString *errorMe
CodePasterPluginPrivate::CodePasterPluginPrivate()
{
- // Create the settings Page
- m_settings.fromSettings(ICore::settings());
-
// Connect protocols
- for (Protocol *proto : m_protocols) {
- connect(proto, &Protocol::pasteDone, this, &CodePasterPluginPrivate::finishPost);
- connect(proto, &Protocol::fetchDone, this, &CodePasterPluginPrivate::finishFetch);
+ if (!m_protocols.isEmpty()) {
+ for (Protocol *proto : m_protocols) {
+ m_settings.protocols.addOption(proto->name());
+ connect(proto, &Protocol::pasteDone, this, &CodePasterPluginPrivate::finishPost);
+ connect(proto, &Protocol::fetchDone, this, &CodePasterPluginPrivate::finishFetch);
+ }
+ m_settings.protocols.setDefaultValue(m_protocols.at(0)->name());
}
+ // Create the settings Page
+ m_settings.readSettings(ICore::settings());
+
connect(&m_urlOpen, &Protocol::fetchDone, this, &CodePasterPluginPrivate::finishFetch);
//register actions
@@ -267,20 +267,20 @@ void CodePasterPluginPrivate::post(QString data, const QString &mimeType)
{
fixSpecialCharacters(data);
- const QString username = m_settings.username;
+ const QString username = m_settings.username.value();
PasteView view(m_protocols, mimeType, ICore::dialogParent());
- view.setProtocol(m_settings.protocol);
+ view.setProtocol(m_settings.protocols.stringValue());
const FileDataList diffChunks = splitDiffToFiles(data);
const int dialogResult = diffChunks.isEmpty() ?
- view.show(username, QString(), QString(), m_settings.expiryDays, m_settings.publicPaste, data) :
- view.show(username, QString(), QString(), m_settings.expiryDays, m_settings.publicPaste, diffChunks);
+ view.show(username, {}, {}, m_settings.expiryDays.value(), m_settings.publicPaste.value(), data) :
+ view.show(username, {}, {}, m_settings.expiryDays.value(), m_settings.publicPaste.value(), diffChunks);
// Save new protocol in case user changed it.
- if (dialogResult == QDialog::Accepted && m_settings.protocol != view.protocol()) {
- m_settings.protocol = view.protocol();
- m_settings.toSettings(ICore::settings());
+ if (dialogResult == QDialog::Accepted && m_settings.protocols.value() != view.protocol()) {
+ m_settings.protocols.setValue(view.protocol());
+ m_settings.writeSettings(ICore::settings());
}
}
@@ -304,29 +304,29 @@ void CodePasterPluginPrivate::pasteSnippet()
void CodePasterPluginPrivate::fetch()
{
PasteSelectDialog dialog(m_protocols, ICore::dialogParent());
- dialog.setProtocol(m_settings.protocol);
+ dialog.setProtocol(m_settings.protocols.stringValue());
if (dialog.exec() != QDialog::Accepted)
return;
// Save new protocol in case user changed it.
- if (m_settings.protocol != dialog.protocol()) {
- m_settings.protocol = dialog.protocol();
- m_settings.toSettings(ICore::settings());
+ if (m_settings.protocols.value() != dialog.protocol()) {
+ m_settings.protocols.setValue(dialog.protocol());
+ m_settings.writeSettings(ICore::settings());
}
const QString pasteID = dialog.pasteId();
if (pasteID.isEmpty())
return;
- Protocol *protocol = m_protocols[dialog.protocolIndex()];
+ Protocol *protocol = m_protocols[dialog.protocol()];
if (Protocol::ensureConfiguration(protocol))
protocol->fetch(pasteID);
}
void CodePasterPluginPrivate::finishPost(const QString &link)
{
- if (m_settings.copyToClipboard)
+ if (m_settings.copyToClipboard.value())
QApplication::clipboard()->setText(link);
- if (m_settings.displayOutput)
+ if (m_settings.displayOutput.value())
MessageManager::writeDisrupting(link);
else
MessageManager::writeSilently(link);
@@ -400,7 +400,7 @@ void CodePasterPluginPrivate::finishFetch(const QString &titleDescription,
MessageManager::writeDisrupting(saver.errorString());
return;
}
- const QString fileName = saver.fileName();
+ const QString fileName = saver.filePath().toString();
m_fetchedSnippets.push_back(fileName);
// Open editor with title.
IEditor *editor = EditorManager::openEditor(fileName);
diff --git a/src/plugins/cpaster/fileshareprotocol.cpp b/src/plugins/cpaster/fileshareprotocol.cpp
index 216e9069ae..b9e0dd9b22 100644
--- a/src/plugins/cpaster/fileshareprotocol.cpp
+++ b/src/plugins/cpaster/fileshareprotocol.cpp
@@ -48,10 +48,9 @@ static const char textElementC[] = "text";
namespace CodePaster {
FileShareProtocol::FileShareProtocol() :
- m_settings(new FileShareProtocolSettings),
- m_settingsPage(new FileShareProtocolSettingsPage(m_settings))
+ m_settingsPage(new FileShareProtocolSettingsPage(&m_settings))
{
- m_settings->fromSettings(Core::ICore::settings());
+ m_settings.readSettings(Core::ICore::settings());
}
FileShareProtocol::~FileShareProtocol()
@@ -127,7 +126,7 @@ static bool parse(const QString &fileName,
bool FileShareProtocol::checkConfiguration(QString *errorMessage)
{
- if (m_settings->path.isEmpty()) {
+ if (m_settings.path.value().isEmpty()) {
if (errorMessage)
*errorMessage = tr("Please configure a path.");
return false;
@@ -140,7 +139,7 @@ void FileShareProtocol::fetch(const QString &id)
// Absolute or relative path name.
QFileInfo fi(id);
if (fi.isRelative())
- fi = QFileInfo(m_settings->path + QLatin1Char('/') + id);
+ fi = QFileInfo(m_settings.path.value() + '/' + id);
QString errorMessage;
QString text;
if (parse(fi.absoluteFilePath(), &errorMessage, nullptr, nullptr, &text))
@@ -152,7 +151,7 @@ void FileShareProtocol::fetch(const QString &id)
void FileShareProtocol::list()
{
// Read out directory, display by date (latest first)
- QDir dir(m_settings->path, QLatin1String(tempGlobPatternC),
+ QDir dir(m_settings.path.value(), tempGlobPatternC,
QDir::Time, QDir::Files|QDir::NoDotAndDotDot|QDir::Readable);
QStringList entries;
QString user;
@@ -160,7 +159,7 @@ void FileShareProtocol::list()
QString errorMessage;
const QChar blank = QLatin1Char(' ');
const QFileInfoList entryInfoList = dir.entryInfoList();
- const int count = qMin(m_settings->displayCount, entryInfoList.size());
+ const int count = qMin(int(m_settings.displayCount.value()), entryInfoList.size());
for (int i = 0; i < count; i++) {
const QFileInfo& entryFi = entryInfoList.at(i);
if (parse(entryFi.absoluteFilePath(), &errorMessage, &user, &description)) {
@@ -188,7 +187,7 @@ void FileShareProtocol::paste(
)
{
// Write out temp XML file
- Utils::TempFileSaver saver(m_settings->path + QLatin1Char('/') + QLatin1String(tempPatternC));
+ Utils::TempFileSaver saver(m_settings.path.value() + '/' + tempPatternC);
saver.setAutoRemove(false);
if (!saver.hasError()) {
// Flat text sections embedded into pasterElement
@@ -210,6 +209,6 @@ void FileShareProtocol::paste(
return;
}
- Core::MessageManager::writeSilently(tr("Pasted: %1").arg(saver.fileName()));
+ Core::MessageManager::writeSilently(tr("Pasted: %1").arg(saver.filePath().toUserOutput()));
}
} // namespace CodePaster
diff --git a/src/plugins/cpaster/fileshareprotocol.h b/src/plugins/cpaster/fileshareprotocol.h
index a22fa62a97..316cdf867a 100644
--- a/src/plugins/cpaster/fileshareprotocol.h
+++ b/src/plugins/cpaster/fileshareprotocol.h
@@ -26,13 +26,11 @@
#pragma once
#include "protocol.h"
-
-#include <QSharedPointer>
+#include "fileshareprotocolsettingspage.h"
namespace CodePaster {
class FileShareProtocolSettingsPage;
-class FileShareProtocolSettings;
/* FileShareProtocol: Allows for pasting via a shared network
* drive by writing XML files. */
@@ -60,7 +58,7 @@ public:
const QString &description = QString()) override;
private:
- const QSharedPointer<FileShareProtocolSettings> m_settings;
+ FileShareProtocolSettings m_settings;
FileShareProtocolSettingsPage *m_settingsPage;
};
diff --git a/src/plugins/cpaster/fileshareprotocolsettingspage.cpp b/src/plugins/cpaster/fileshareprotocolsettingspage.cpp
index 8d7737934f..494ba78f32 100644
--- a/src/plugins/cpaster/fileshareprotocolsettingspage.cpp
+++ b/src/plugins/cpaster/fileshareprotocolsettingspage.cpp
@@ -26,95 +26,58 @@
#include "fileshareprotocolsettingspage.h"
#include "cpasterconstants.h"
-#include <coreplugin/icore.h>
-
+#include <utils/layoutbuilder.h>
#include <utils/temporarydirectory.h>
-#include <QSettings>
-#include <QCoreApplication>
-
-static const char settingsGroupC[] = "FileSharePasterSettings";
-static const char pathKeyC[] = "Path";
-static const char displayCountKeyC[] = "DisplayCount";
+using namespace Utils;
namespace CodePaster {
-FileShareProtocolSettings::FileShareProtocolSettings() :
- path(Utils::TemporaryDirectory::masterDirectoryPath()), displayCount(10)
+FileShareProtocolSettings::FileShareProtocolSettings()
{
+ setSettingsGroup("FileSharePasterSettings");
+ setAutoApply(false);
+
+ registerAspect(&path);
+ path.setSettingsKey("Path");
+ path.setDisplayStyle(StringAspect::PathChooserDisplay);
+ path.setExpectedKind(PathChooser::ExistingDirectory);
+ path.setDefaultValue(TemporaryDirectory::masterDirectoryPath());
+ path.setLabelText(tr("&Path:"));
+
+ registerAspect(&displayCount);
+ displayCount.setSettingsKey("DisplayCount");
+ displayCount.setDefaultValue(10);
+ displayCount.setSuffix(' ' + tr("entries"));
+ displayCount.setLabelText(tr("&Display:"));
}
-void FileShareProtocolSettings::toSettings(QSettings *s) const
-{
- s->beginGroup(QLatin1String(settingsGroupC));
- s->setValue(QLatin1String(pathKeyC), path);
- s->setValue(QLatin1String(displayCountKeyC), displayCount);
- s->endGroup();
-}
-
-void FileShareProtocolSettings::fromSettings(const QSettings *s)
-{
- FileShareProtocolSettings defaultValues;
- const QString keyRoot = QLatin1String(settingsGroupC) + QLatin1Char('/');
- path = s->value(keyRoot + QLatin1String(pathKeyC), defaultValues.path).toString();
- displayCount = s->value(keyRoot + QLatin1String(displayCountKeyC), defaultValues.displayCount).toInt();
-}
+// Settings page
-bool FileShareProtocolSettings::equals(const FileShareProtocolSettings &rhs) const
-{
- return displayCount == rhs.displayCount && path == rhs.path;
-}
-
-FileShareProtocolSettingsWidget::FileShareProtocolSettingsWidget()
-{
- m_ui.setupUi(this);
-
- // Add a space in front of the suffix
- QString suffix = m_ui.displayCountSpinBox->suffix();
- suffix.prepend(QLatin1Char(' '));
- m_ui.displayCountSpinBox->setSuffix(suffix);
-}
-
-void FileShareProtocolSettingsWidget::setSettings(const FileShareProtocolSettings &s)
-{
- m_ui.pathChooser->setPath(s.path);
- m_ui.displayCountSpinBox->setValue(s.displayCount);
-}
-
-FileShareProtocolSettings FileShareProtocolSettingsWidget::settings() const
-{
- FileShareProtocolSettings rc;
- rc.path = m_ui.pathChooser->filePath().toString();
- rc.displayCount = m_ui.displayCountSpinBox->value();
- return rc;
-}
-
-// ----------FileShareProtocolSettingsPage
-FileShareProtocolSettingsPage::FileShareProtocolSettingsPage(const QSharedPointer<FileShareProtocolSettings> &s)
- : m_settings(s), m_widget(nullptr)
+FileShareProtocolSettingsPage::FileShareProtocolSettingsPage(FileShareProtocolSettings *settings)
{
setId("X.CodePaster.FileSharePaster");
- setDisplayName(tr("Fileshare"));
+ setDisplayName(FileShareProtocolSettings::tr("Fileshare"));
setCategory(Constants::CPASTER_SETTINGS_CATEGORY);
+ setSettings(settings);
+
+ setLayouter([&s = *settings](QWidget *widget) {
+ using namespace Layouting;
+
+ auto label = new QLabel(FileShareProtocolSettingsPage::tr(
+ "The fileshare-based paster protocol allows for sharing code snippets using "
+ "simple files on a shared network drive. Files are never deleted."));
+ label->setWordWrap(true);
+
+ Column {
+ Form {
+ label, Break(),
+ s.path,
+ s.displayCount
+ },
+ Stretch()
+ }.attachTo(widget);
+ });
}
-QWidget *FileShareProtocolSettingsPage::widget()
-{
- if (!m_widget) {
- m_widget = new FileShareProtocolSettingsWidget;
- m_widget->setSettings(*m_settings);
- }
- return m_widget;
-}
-
-void FileShareProtocolSettingsPage::apply()
-{
- if (!m_widget) // page was never shown
- return;
- const FileShareProtocolSettings newSettings = m_widget->settings();
- if (newSettings != *m_settings) {
- *m_settings = newSettings;
- m_settings->toSettings(Core::ICore::settings());
- }
-}
} // namespace CodePaster
diff --git a/src/plugins/cpaster/fileshareprotocolsettingspage.h b/src/plugins/cpaster/fileshareprotocolsettingspage.h
index aecd5d475c..1ee12b5bee 100644
--- a/src/plugins/cpaster/fileshareprotocolsettingspage.h
+++ b/src/plugins/cpaster/fileshareprotocolsettingspage.h
@@ -26,61 +26,26 @@
#pragma once
#include <coreplugin/dialogs/ioptionspage.h>
-#include "ui_fileshareprotocolsettingswidget.h"
-#include <QSharedPointer>
-#include <QPointer>
-#include <QWidget>
-
-QT_BEGIN_NAMESPACE
-class QSettings;
-QT_END_NAMESPACE
+#include <utils/aspects.h>
namespace CodePaster {
-class FileShareProtocolSettings {
-public:
- FileShareProtocolSettings();
- void toSettings(QSettings *) const;
- void fromSettings(const QSettings *);
- bool equals(const FileShareProtocolSettings &rhs) const;
-
- QString path;
- int displayCount;
-};
-
-inline bool operator==(const FileShareProtocolSettings &s1, const FileShareProtocolSettings &s2)
-{ return s1.equals(s2); }
-inline bool operator!=(const FileShareProtocolSettings &s1, const FileShareProtocolSettings &s2)
-{ return !s1.equals(s2); }
-
-class FileShareProtocolSettingsWidget : public QWidget
+class FileShareProtocolSettings : public Utils::AspectContainer
{
- Q_OBJECT
+ Q_DECLARE_TR_FUNCTIONS(CodePaster::FileShareProtocolSettings)
public:
- FileShareProtocolSettingsWidget();
-
- void setSettings(const FileShareProtocolSettings &);
- FileShareProtocolSettings settings() const;
+ FileShareProtocolSettings();
-private:
- Internal::Ui::FileShareProtocolSettingsWidget m_ui;
+ Utils::StringAspect path;
+ Utils::IntegerAspect displayCount;
};
-class FileShareProtocolSettingsPage : public Core::IOptionsPage
+class FileShareProtocolSettingsPage final : public Core::IOptionsPage
{
- Q_OBJECT
-
public:
- explicit FileShareProtocolSettingsPage(const QSharedPointer<FileShareProtocolSettings> &s);
-
- QWidget *widget() override;
- void apply() override;
- void finish() override { }
-
-private:
- const QSharedPointer<FileShareProtocolSettings> m_settings;
- QPointer<FileShareProtocolSettingsWidget> m_widget;
+ explicit FileShareProtocolSettingsPage(FileShareProtocolSettings *settings);
};
+
} // namespace CodePaster
diff --git a/src/plugins/cpaster/fileshareprotocolsettingswidget.ui b/src/plugins/cpaster/fileshareprotocolsettingswidget.ui
deleted file mode 100644
index 3634c828b1..0000000000
--- a/src/plugins/cpaster/fileshareprotocolsettingswidget.ui
+++ /dev/null
@@ -1,101 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<ui version="4.0">
- <class>CodePaster::Internal::FileShareProtocolSettingsWidget</class>
- <widget class="QWidget" name="CodePaster::Internal::FileShareProtocolSettingsWidget">
- <property name="geometry">
- <rect>
- <x>0</x>
- <y>0</y>
- <width>438</width>
- <height>101</height>
- </rect>
- </property>
- <property name="windowTitle">
- <string/>
- </property>
- <layout class="QFormLayout" name="formLayout">
- <property name="fieldGrowthPolicy">
- <enum>QFormLayout::AllNonFixedFieldsGrow</enum>
- </property>
- <item row="0" column="0" colspan="2">
- <widget class="QLabel" name="helpLabel">
- <property name="text">
- <string>The fileshare-based paster protocol allows for sharing code snippets using simple files on a shared network drive. Files are never deleted.</string>
- </property>
- <property name="wordWrap">
- <bool>true</bool>
- </property>
- </widget>
- </item>
- <item row="1" column="0">
- <spacer name="verticalSpacer">
- <property name="orientation">
- <enum>Qt::Vertical</enum>
- </property>
- <property name="sizeType">
- <enum>QSizePolicy::Fixed</enum>
- </property>
- <property name="sizeHint" stdset="0">
- <size>
- <width>20</width>
- <height>3</height>
- </size>
- </property>
- </spacer>
- </item>
- <item row="2" column="0">
- <widget class="QLabel" name="pathLabel">
- <property name="text">
- <string>&amp;Path:</string>
- </property>
- <property name="buddy">
- <cstring>pathChooser</cstring>
- </property>
- </widget>
- </item>
- <item row="2" column="1">
- <widget class="Utils::PathChooser" name="pathChooser" native="true"/>
- </item>
- <item row="3" column="0">
- <widget class="QLabel" name="displayCountLabel">
- <property name="text">
- <string>&amp;Display:</string>
- </property>
- <property name="buddy">
- <cstring>displayCountSpinBox</cstring>
- </property>
- </widget>
- </item>
- <item row="3" column="1">
- <widget class="QSpinBox" name="displayCountSpinBox">
- <property name="suffix">
- <string>entries</string>
- </property>
- <property name="minimum">
- <number>2</number>
- </property>
- <property name="maximum">
- <number>100</number>
- </property>
- <property name="value">
- <number>11</number>
- </property>
- </widget>
- </item>
- </layout>
- </widget>
- <customwidgets>
- <customwidget>
- <class>Utils::PathChooser</class>
- <extends>QWidget</extends>
- <header location="global">utils/pathchooser.h</header>
- <container>1</container>
- <slots>
- <signal>editingFinished()</signal>
- <signal>browsingFinished()</signal>
- </slots>
- </customwidget>
- </customwidgets>
- <resources/>
- <connections/>
-</ui>
diff --git a/src/plugins/cpaster/pasteselectdialog.cpp b/src/plugins/cpaster/pasteselectdialog.cpp
index 193c49525b..55a33ad570 100644
--- a/src/plugins/cpaster/pasteselectdialog.cpp
+++ b/src/plugins/cpaster/pasteselectdialog.cpp
@@ -84,20 +84,20 @@ void PasteSelectDialog::setProtocol(const QString &p)
}
}
-QString PasteSelectDialog::protocol() const
+int PasteSelectDialog::protocol() const
{
- return m_ui.protocolBox->currentText();
+ return m_ui.protocolBox->currentIndex();
}
-int PasteSelectDialog::protocolIndex() const
+QString PasteSelectDialog::protocolName() const
{
- return m_ui.protocolBox->currentIndex();
+ return m_ui.protocolBox->currentText();
}
void PasteSelectDialog::listDone(const QString &name, const QStringList &items)
{
// Set if the protocol is still current
- if (name == protocol()) {
+ if (name == protocolName()) {
m_ui.listWidget->clear();
m_ui.listWidget->addItems(items);
}
@@ -105,7 +105,7 @@ void PasteSelectDialog::listDone(const QString &name, const QStringList &items)
void PasteSelectDialog::list()
{
- const int index = protocolIndex();
+ const int index = protocol();
Protocol *protocol = m_protocols[index];
QTC_ASSERT((protocol->capabilities() & Protocol::ListCapability), return);
diff --git a/src/plugins/cpaster/pasteselectdialog.h b/src/plugins/cpaster/pasteselectdialog.h
index b6b57fae08..60ddbbe347 100644
--- a/src/plugins/cpaster/pasteselectdialog.h
+++ b/src/plugins/cpaster/pasteselectdialog.h
@@ -44,12 +44,11 @@ public:
QString pasteId() const;
- QString protocol() const;
+ int protocol() const;
void setProtocol(const QString &);
- int protocolIndex() const;
-
private:
+ QString protocolName() const;
void protocolChanged(int);
void list();
void listDone(const QString &name, const QStringList &items);
diff --git a/src/plugins/cpaster/pasteview.cpp b/src/plugins/cpaster/pasteview.cpp
index d5775adb5e..adaf099200 100644
--- a/src/plugins/cpaster/pasteview.cpp
+++ b/src/plugins/cpaster/pasteview.cpp
@@ -94,9 +94,9 @@ QString PasteView::content() const
return newContent;
}
-QString PasteView::protocol() const
+int PasteView::protocol() const
{
- return m_ui.protocolBox->currentText();
+ return m_ui.protocolBox->currentIndex();
}
void PasteView::contentChanged()
diff --git a/src/plugins/cpaster/pasteview.h b/src/plugins/cpaster/pasteview.h
index 6a2b78c64e..73804b53b4 100644
--- a/src/plugins/cpaster/pasteview.h
+++ b/src/plugins/cpaster/pasteview.h
@@ -63,7 +63,7 @@ public:
QString description() const;
QString comment() const;
QString content() const;
- QString protocol() const;
+ int protocol() const;
void setExpiryDays(int d);
void setMakePublic(bool p);
int expiryDays() const;
diff --git a/src/plugins/cpaster/settings.cpp b/src/plugins/cpaster/settings.cpp
index 61508a201d..bf6f9f6d47 100644
--- a/src/plugins/cpaster/settings.cpp
+++ b/src/plugins/cpaster/settings.cpp
@@ -24,51 +24,84 @@
****************************************************************************/
#include "settings.h"
-#include "pastebindotcomprotocol.h"
-#include <utils/environment.h>
+#include "cpasterconstants.h"
-#include <QSettings>
+#include <utils/layoutbuilder.h>
-static const char groupC[] = "CodePaster";
-static const char userNameKeyC[] = "UserName";
-static const char expiryDaysKeyC[] = "ExpiryDays";
-static const char defaultProtocolKeyC[] = "DefaultProtocol";
-static const char copyToClipboardKeyC[] = "CopyToClipboard";
-static const char displayOutputKeyC[] = "DisplayOutput";
-static const char publicPasteKeyC[] = "DisplayOutput";
+using namespace Utils;
namespace CodePaster {
-bool Settings::equals(const Settings &rhs) const
+Settings::Settings()
{
- return copyToClipboard == rhs.copyToClipboard && displayOutput == rhs.displayOutput
- && expiryDays == rhs.expiryDays && username == rhs.username
- && protocol == rhs.protocol && publicPaste == rhs.publicPaste;
-}
+ setSettingsGroup("CodePaster");
+ setAutoApply(false);
-void Settings::toSettings(QSettings *settings) const
-{
- settings->beginGroup(QLatin1String(groupC));
- settings->setValue(QLatin1String(userNameKeyC), username);
- settings->setValue(QLatin1String(defaultProtocolKeyC), protocol);
- settings->setValue(QLatin1String(expiryDaysKeyC), expiryDays);
- settings->setValue(QLatin1String(copyToClipboardKeyC), copyToClipboard);
- settings->setValue(QLatin1String(displayOutputKeyC), displayOutput);
- settings->setValue(publicPasteKeyC, publicPaste);
- settings->endGroup();
+ registerAspect(&username);
+ username.setDisplayStyle(StringAspect::LineEditDisplay);
+ username.setSettingsKey("UserName");
+ username.setLabelText(tr("Username:"));
+
+ registerAspect(&protocols);
+ protocols.setSettingsKey("DefaultProtocol");
+ protocols.setDisplayStyle(SelectionAspect::DisplayStyle::ComboBox);
+ protocols.setLabelText(tr("Default protocol:"));
+ protocols.setToSettingsTransformation([this](const QVariant &val) {
+ return protocols.displayForIndex(val.toInt());
+ });
+ protocols.setFromSettingsTransformation([this](const QVariant &val) {
+ return protocols.indexForDisplay(val.toString());
+ });
+
+ registerAspect(&expiryDays);
+ expiryDays.setSettingsKey("ExpiryDays");
+ expiryDays.setDefaultValue(1);
+ expiryDays.setSuffix(tr(" Days"));
+ expiryDays.setLabelText(tr("&Expires after:"));
+
+ registerAspect(&copyToClipboard);
+ copyToClipboard.setSettingsKey("CopyToClipboard");
+ copyToClipboard.setDefaultValue(true);
+ copyToClipboard.setLabelText(tr("Copy-paste URL to clipboard"));
+
+ registerAspect(&displayOutput);
+ displayOutput.setSettingsKey("DisplayOutput");
+ displayOutput.setDefaultValue(true);
+ displayOutput.setLabelText(tr("Display Output pane after sending a post"));
+
+ registerAspect(&publicPaste);
+ publicPaste.setSettingsKey("DisplayOutput");
+ publicPaste.setLabelText(tr("Make pasted content public by default"));
}
-void Settings::fromSettings(const QSettings *settings)
+// SettingsPage
+
+SettingsPage::SettingsPage(Settings *settings)
{
- const QString rootKey = QLatin1String(groupC) + QLatin1Char('/');
- const QString defaultUser = Utils::Environment::systemEnvironment().userName();
- expiryDays = settings->value(rootKey + QLatin1String(expiryDaysKeyC), 1).toInt();
- username = settings->value(rootKey + QLatin1String(userNameKeyC), defaultUser).toString();
- protocol = settings->value(rootKey + QLatin1String(defaultProtocolKeyC), PasteBinDotComProtocol::protocolName()).toString();
- copyToClipboard = settings->value(rootKey + QLatin1String(copyToClipboardKeyC), true).toBool();
- displayOutput = settings->value(rootKey + QLatin1String(displayOutputKeyC), true).toBool();
- publicPaste = settings->value(rootKey + publicPasteKeyC, false).toBool();
+ setId("A.CodePaster.General");
+ setDisplayName(Settings::tr("General"));
+ setCategory(Constants::CPASTER_SETTINGS_CATEGORY);
+ setDisplayCategory(Settings::tr("Code Pasting"));
+ setCategoryIconPath(":/cpaster/images/settingscategory_cpaster.png");
+ setSettings(settings);
+
+ setLayouter([settings](QWidget *widget) {
+ Settings &s = *settings;
+ using namespace Layouting;
+
+ Column {
+ Form {
+ s.protocols,
+ s.username,
+ s.expiryDays
+ },
+ s.copyToClipboard,
+ s.displayOutput,
+ s.publicPaste,
+ Stretch()
+ }.attachTo(widget);
+ });
}
} // namespace CodePaster
diff --git a/src/plugins/cpaster/settings.h b/src/plugins/cpaster/settings.h
index 451f85e0f3..26f1aaada1 100644
--- a/src/plugins/cpaster/settings.h
+++ b/src/plugins/cpaster/settings.h
@@ -25,29 +25,31 @@
#pragma once
-#include <QString>
+#include <coreplugin/dialogs/ioptionspage.h>
-QT_BEGIN_NAMESPACE
-class QSettings;
-QT_END_NAMESPACE
+#include <utils/aspects.h>
namespace CodePaster {
-class Settings {
+class Settings : public Utils::AspectContainer
+{
+ Q_DECLARE_TR_FUNCTIONS(CodePaster::Settings)
+
public:
- void toSettings(QSettings *s) const;
- void fromSettings(const QSettings *s);
- bool equals(const Settings &s) const;
-
- QString username;
- QString protocol;
- int expiryDays = 1;
- bool copyToClipboard = true;
- bool displayOutput = true;
- bool publicPaste = false;
+ Settings();
+
+ Utils::StringAspect username;
+ Utils::SelectionAspect protocols;
+ Utils::IntegerAspect expiryDays;
+ Utils::BoolAspect copyToClipboard;
+ Utils::BoolAspect displayOutput;
+ Utils::BoolAspect publicPaste;
};
-inline bool operator==(const Settings &s1, const Settings &s2) { return s1.equals(s2); }
-inline bool operator!=(const Settings &s1, const Settings &s2) { return !s1.equals(s2); }
+class SettingsPage final : public Core::IOptionsPage
+{
+public:
+ SettingsPage(Settings *settings);
+};
} // namespace CodePaster
diff --git a/src/plugins/cpaster/settingspage.cpp b/src/plugins/cpaster/settingspage.cpp
deleted file mode 100644
index c21b0fe485..0000000000
--- a/src/plugins/cpaster/settingspage.cpp
+++ /dev/null
@@ -1,92 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of Qt Creator.
-**
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 3 as published by the Free Software
-** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-3.0.html.
-**
-****************************************************************************/
-
-#include "settingspage.h"
-#include "settings.h"
-#include "cpasterconstants.h"
-
-#include <coreplugin/icore.h>
-
-#include <QTextStream>
-#include <QCoreApplication>
-
-namespace CodePaster {
-
-class SettingsWidget final : public Core::IOptionsPageWidget
-{
-public:
- SettingsWidget(const QStringList &protocols, Settings *settings);
-
-private:
- void apply() final;
-
- Settings *m_settings;
- Internal::Ui::SettingsPage m_ui;
-};
-
-SettingsWidget::SettingsWidget(const QStringList &protocols, Settings *settings)
- : m_settings(settings)
-{
- m_ui.setupUi(this);
- m_ui.defaultProtocol->addItems(protocols);
-
- m_ui.userEdit->setText(m_settings->username);
- const int index = m_ui.defaultProtocol->findText(m_settings->protocol);
- m_ui.defaultProtocol->setCurrentIndex(index == -1 ? 0 : index);
- m_ui.expirySpinBox->setValue(m_settings->expiryDays);
- m_ui.publicCheckBox->setChecked(m_settings->publicPaste);
- m_ui.clipboardBox->setChecked(m_settings->copyToClipboard);
- m_ui.displayBox->setChecked(m_settings->displayOutput);
-}
-
-void SettingsWidget::apply()
-{
- Settings rc;
- rc.username = m_ui.userEdit->text();
- rc.protocol = m_ui.defaultProtocol->currentText();
- rc.expiryDays = m_ui.expirySpinBox->value();
- rc.publicPaste = m_ui.publicCheckBox->isChecked();
- rc.copyToClipboard = m_ui.clipboardBox->isChecked();
- rc.displayOutput = m_ui.displayBox->isChecked();
-
- if (rc != *m_settings) {
- *m_settings = rc;
- m_settings->toSettings(Core::ICore::settings());
- }
-}
-
-SettingsPage::SettingsPage(Settings *settings, const QStringList &protocolNames)
-{
- setId("A.CodePaster.General");
- setDisplayName(tr("General"));
- setCategory(Constants::CPASTER_SETTINGS_CATEGORY);
- setDisplayCategory(QCoreApplication::translate("CodePaster", "Code Pasting"));
- setCategoryIconPath(":/cpaster/images/settingscategory_cpaster.png");
- setWidgetCreator([settings, protocolNames] {
- return new SettingsWidget(protocolNames, settings);
- });
-}
-
-} // namespace CodePaster
diff --git a/src/plugins/cpaster/settingspage.ui b/src/plugins/cpaster/settingspage.ui
deleted file mode 100644
index de4020433d..0000000000
--- a/src/plugins/cpaster/settingspage.ui
+++ /dev/null
@@ -1,102 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<ui version="4.0">
- <class>CodePaster::Internal::SettingsPage</class>
- <widget class="QWidget" name="CodePaster::Internal::SettingsPage">
- <property name="geometry">
- <rect>
- <x>0</x>
- <y>0</y>
- <width>370</width>
- <height>229</height>
- </rect>
- </property>
- <layout class="QGridLayout" name="gridLayout">
- <item row="4" column="0" colspan="2">
- <widget class="QCheckBox" name="clipboardBox">
- <property name="text">
- <string>Copy-paste URL to clipboard</string>
- </property>
- </widget>
- </item>
- <item row="9" column="0" colspan="2">
- <spacer name="verticalSpacer">
- <property name="orientation">
- <enum>Qt::Vertical</enum>
- </property>
- <property name="sizeHint" stdset="0">
- <size>
- <width>223</width>
- <height>100</height>
- </size>
- </property>
- </spacer>
- </item>
- <item row="1" column="1">
- <widget class="QLineEdit" name="userEdit"/>
- </item>
- <item row="0" column="1">
- <widget class="QComboBox" name="defaultProtocol"/>
- </item>
- <item row="0" column="0">
- <widget class="QLabel" name="protocolLabel">
- <property name="text">
- <string>Default protocol:</string>
- </property>
- </widget>
- </item>
- <item row="2" column="0">
- <widget class="QLabel" name="expiryLabel">
- <property name="text">
- <string>&amp;Expires after:</string>
- </property>
- <property name="buddy">
- <cstring>expirySpinBox</cstring>
- </property>
- </widget>
- </item>
- <item row="5" column="0" colspan="2">
- <widget class="QCheckBox" name="displayBox">
- <property name="text">
- <string>Display Output pane after sending a post</string>
- </property>
- </widget>
- </item>
- <item row="1" column="0">
- <widget class="QLabel" name="userNameLabel">
- <property name="text">
- <string>Username:</string>
- </property>
- </widget>
- </item>
- <item row="2" column="1">
- <widget class="QSpinBox" name="expirySpinBox">
- <property name="suffix">
- <string> Days</string>
- </property>
- <property name="minimum">
- <number>1</number>
- </property>
- <property name="maximum">
- <number>365</number>
- </property>
- </widget>
- </item>
- <item row="6" column="0">
- <widget class="QCheckBox" name="publicCheckBox">
- <property name="text">
- <string>Make pasted content public by default</string>
- </property>
- </widget>
- </item>
- </layout>
- </widget>
- <tabstops>
- <tabstop>defaultProtocol</tabstop>
- <tabstop>userEdit</tabstop>
- <tabstop>expirySpinBox</tabstop>
- <tabstop>clipboardBox</tabstop>
- <tabstop>displayBox</tabstop>
- </tabstops>
- <resources/>
- <connections/>
-</ui>
diff --git a/src/plugins/cppeditor/cppeditordocument.cpp b/src/plugins/cppeditor/cppeditordocument.cpp
index 1de9413348..7fef7b5eff 100644
--- a/src/plugins/cppeditor/cppeditordocument.cpp
+++ b/src/plugins/cppeditor/cppeditordocument.cpp
@@ -447,7 +447,7 @@ TextEditor::TabSettings CppEditorDocument::tabSettings() const
return indenter()->tabSettings().value_or(TextEditor::TextDocument::tabSettings());
}
-bool CppEditorDocument::save(QString *errorString, const QString &fileName, bool autoSave)
+bool CppEditorDocument::save(QString *errorString, const Utils::FilePath &filePath, bool autoSave)
{
Utils::ExecuteOnDestruction resetSettingsOnScopeExit;
@@ -490,7 +490,7 @@ bool CppEditorDocument::save(QString *errorString, const QString &fileName, bool
setStorageSettings(settings);
}
- return TextEditor::TextDocument::save(errorString, fileName, autoSave);
+ return TextEditor::TextDocument::save(errorString, filePath, autoSave);
}
} // namespace Internal
diff --git a/src/plugins/cppeditor/cppeditordocument.h b/src/plugins/cppeditor/cppeditordocument.h
index b7a0219e0a..ebb3e498b8 100644
--- a/src/plugins/cppeditor/cppeditordocument.h
+++ b/src/plugins/cppeditor/cppeditordocument.h
@@ -71,7 +71,7 @@ public:
TextEditor::TabSettings tabSettings() const override;
bool save(QString *errorString,
- const QString &fileName = QString(),
+ const Utils::FilePath &filePath = Utils::FilePath(),
bool autoSave = false) override;
signals:
diff --git a/src/plugins/cppeditor/cppeditorplugin.h b/src/plugins/cppeditor/cppeditorplugin.h
index 9666b6c2f9..523c8e46a5 100644
--- a/src/plugins/cppeditor/cppeditorplugin.h
+++ b/src/plugins/cppeditor/cppeditorplugin.h
@@ -194,6 +194,8 @@ private slots:
void test_quickfix_MoveFuncDefOutside_macroUses();
void test_quickfix_MoveFuncDefOutside_template();
void test_quickfix_MoveFuncDefOutside_unnamedTemplate();
+ void test_quickfix_MoveFuncDefOutside_MemberFuncToCpp_Static();
+ void test_quickfix_MoveFuncDefOutside_MemberFuncToCpp_WithInlinePartOfName();
void test_quickfix_MoveAllFuncDefOutside_MemberFuncToCpp();
void test_quickfix_MoveAllFuncDefOutside_MemberFuncOutside();
diff --git a/src/plugins/cppeditor/cppeditorwidget.cpp b/src/plugins/cppeditor/cppeditorwidget.cpp
index 7643b1976b..3c317ae063 100644
--- a/src/plugins/cppeditor/cppeditorwidget.cpp
+++ b/src/plugins/cppeditor/cppeditorwidget.cpp
@@ -361,8 +361,12 @@ static std::unique_ptr<QTextDocument> getCurrentDocument(const QString &path)
QString contents;
Utils::TextFileFormat format;
QString error;
- if (Utils::TextFileFormat::readFile(path, defaultCodec, &contents, &format, &error)
- != Utils::TextFileFormat::ReadSuccess) {
+ if (Utils::TextFileFormat::readFile(Utils::FilePath::fromString(path),
+ defaultCodec,
+ &contents,
+ &format,
+ &error)
+ != Utils::TextFileFormat::ReadSuccess) {
qWarning() << "Error reading file " << path << " : " << error;
return {};
}
@@ -472,7 +476,8 @@ void CppEditorWidget::findUsages()
void CppEditorWidget::findUsages(QTextCursor cursor)
{
// 'this' in cursorInEditor is never used (and must never be used) asynchronously.
- const CppTools::CursorInEditor cursorInEditor{cursor, textDocument()->filePath(), this};
+ const CppTools::CursorInEditor cursorInEditor{cursor, textDocument()->filePath(), this,
+ textDocument()};
QPointer<CppEditorWidget> cppEditorWidget = this;
d->m_modelManager->findUsages(cursorInEditor,
[=](const CppTools::Usages &usages) {
@@ -486,7 +491,8 @@ void CppEditorWidget::renameUsages(const QString &replacement, QTextCursor curso
{
if (cursor.isNull())
cursor = textCursor();
- CppTools::CursorInEditor cursorInEditor{cursor, textDocument()->filePath(), this};
+ CppTools::CursorInEditor cursorInEditor{cursor, textDocument()->filePath(), this,
+ textDocument()};
QPointer<CppEditorWidget> cppEditorWidget = this;
d->m_modelManager->globalRename(cursorInEditor,
[=](const CppTools::Usages &usages) {
@@ -780,13 +786,14 @@ void CppEditorWidget::findLinkAt(const QTextCursor &cursor,
const Utils::FilePath &filePath = textDocument()->filePath();
- followSymbolInterface().findLink(CppTools::CursorInEditor{cursor, filePath, this},
- std::move(processLinkCallback),
- resolveTarget,
- d->m_modelManager->snapshot(),
- d->m_lastSemanticInfo.doc,
- d->m_modelManager->symbolFinder(),
- inNextSplit);
+ followSymbolInterface().findLink(
+ CppTools::CursorInEditor{cursor, filePath, this, textDocument()},
+ std::move(processLinkCallback),
+ resolveTarget,
+ d->m_modelManager->snapshot(),
+ d->m_lastSemanticInfo.doc,
+ d->m_modelManager->symbolFinder(),
+ inNextSplit);
}
unsigned CppEditorWidget::documentRevision() const
diff --git a/src/plugins/cppeditor/cppincludehierarchy.cpp b/src/plugins/cppeditor/cppincludehierarchy.cpp
index 2a9e9b7cfe..1c4e8be8d8 100644
--- a/src/plugins/cppeditor/cppincludehierarchy.cpp
+++ b/src/plugins/cppeditor/cppincludehierarchy.cpp
@@ -162,7 +162,7 @@ private:
Qt::ItemFlags flags(int) const override
{
- Utils::Link link(m_filePath, m_line);
+ const Utils::Link link(Utils::FilePath::fromString(m_filePath), m_line);
if (link.hasValidTarget())
return Qt::ItemIsDragEnabled | Qt::ItemIsEnabled | Qt::ItemIsSelectable;
return Qt::ItemIsEnabled | Qt::ItemIsSelectable;
@@ -199,7 +199,7 @@ QVariant CppIncludeHierarchyItem::data(int column, int role) const
case Qt::DecorationRole:
return FileIconProvider::icon(QFileInfo(m_filePath));
case LinkRole:
- return QVariant::fromValue(Utils::Link(m_filePath, m_line));
+ return QVariant::fromValue(Utils::Link(Utils::FilePath::fromString(m_filePath), m_line));
}
return QVariant();
@@ -282,7 +282,7 @@ QMimeData *CppIncludeHierarchyModel::mimeData(const QModelIndexList &indexes) co
for (const QModelIndex &index : indexes) {
auto link = index.data(LinkRole).value<Utils::Link>();
if (link.hasValidTarget())
- data->addFile(link.targetFileName, link.targetLine, link.targetColumn);
+ data->addFile(link.targetFilePath.toString(), link.targetLine, link.targetColumn);
}
return data;
}
@@ -434,11 +434,11 @@ void CppIncludeHierarchyWidget::perform()
if (!m_editor)
return;
- QString document = m_editor->textDocument()->filePath().toString();
- m_model.buildHierarchy(document);
+ const Utils::FilePath documentPath = m_editor->textDocument()->filePath();
+ m_model.buildHierarchy(documentPath.toString());
m_inspectedFile->setText(m_editor->textDocument()->displayName());
- m_inspectedFile->setLink(Utils::Link(document));
+ m_inspectedFile->setLink(Utils::Link(documentPath));
// expand "Includes" and "Included by"
m_treeView->expand(m_model.index(0, 0));
@@ -465,10 +465,7 @@ void CppIncludeHierarchyWidget::onItemActivated(const QModelIndex &index)
{
const auto link = index.data(LinkRole).value<Utils::Link>();
if (link.hasValidTarget())
- EditorManager::openEditorAt(link.targetFileName,
- link.targetLine,
- link.targetColumn,
- Constants::CPPEDITOR_ID);
+ EditorManager::openEditorAt(link, Constants::CPPEDITOR_ID);
}
void CppIncludeHierarchyWidget::editorsClosed(const QList<IEditor *> &editors)
diff --git a/src/plugins/cppeditor/cppquickfix_test.cpp b/src/plugins/cppeditor/cppquickfix_test.cpp
index 0fcbe92e98..849201d8a5 100644
--- a/src/plugins/cppeditor/cppquickfix_test.cpp
+++ b/src/plugins/cppeditor/cppquickfix_test.cpp
@@ -5897,7 +5897,7 @@ void CppEditorPlugin::test_quickfix_MoveFuncDefOutside_MemberFuncToCpp()
"};\n";
expected =
"class Foo {\n"
- " inline int number() const;\n"
+ " int number() const;\n"
"\n"
" void bar();\n"
"};\n";
@@ -5920,6 +5920,86 @@ void CppEditorPlugin::test_quickfix_MoveFuncDefOutside_MemberFuncToCpp()
QuickFixOperationTest(testDocuments, &factory);
}
+void CppEditorPlugin::test_quickfix_MoveFuncDefOutside_MemberFuncToCpp_Static()
+{
+ QList<QuickFixTestDocument::Ptr> testDocuments;
+ QByteArray original;
+ QByteArray expected;
+
+ // Header File
+ original =
+ "class Foo {\n"
+ " static inline int numbe@r() const\n"
+ " {\n"
+ " return 5;\n"
+ " }\n"
+ "\n"
+ " void bar();\n"
+ "};\n";
+ expected =
+ "class Foo {\n"
+ " static int number() const;\n"
+ "\n"
+ " void bar();\n"
+ "};\n";
+ testDocuments << QuickFixTestDocument::create("file.h", original, expected);
+
+ // Source File
+ original =
+ "#include \"file.h\"\n";
+ expected =
+ "#include \"file.h\"\n"
+ "\n"
+ "int Foo::number() const\n"
+ "{\n"
+ " return 5;\n"
+ "}\n";
+ testDocuments << QuickFixTestDocument::create("file.cpp", original, expected);
+
+ MoveFuncDefOutside factory;
+ QuickFixOperationTest(testDocuments, &factory);
+}
+
+void CppEditorPlugin::test_quickfix_MoveFuncDefOutside_MemberFuncToCpp_WithInlinePartOfName()
+{
+ QList<QuickFixTestDocument::Ptr> testDocuments;
+ QByteArray original;
+ QByteArray expected;
+
+ // Header File
+ original =
+ "class Foo {\n"
+ " static inline int numbe@r_inline () const\n"
+ " {\n"
+ " return 5;\n"
+ " }\n"
+ "\n"
+ " void bar();\n"
+ "};\n";
+ expected =
+ "class Foo {\n"
+ " static int number_inline () const;\n"
+ "\n"
+ " void bar();\n"
+ "};\n";
+ testDocuments << QuickFixTestDocument::create("file.h", original, expected);
+
+ // Source File
+ original =
+ "#include \"file.h\"\n";
+ expected =
+ "#include \"file.h\"\n"
+ "\n"
+ "int Foo::number_inline() const\n"
+ "{\n"
+ " return 5;\n"
+ "}\n";
+ testDocuments << QuickFixTestDocument::create("file.cpp", original, expected);
+
+ MoveFuncDefOutside factory;
+ QuickFixOperationTest(testDocuments, &factory);
+}
+
void CppEditorPlugin::test_quickfix_MoveFuncDefOutside_MemberFuncToCppInsideNS()
{
QList<QuickFixTestDocument::Ptr> testDocuments;
@@ -5984,7 +6064,7 @@ void CppEditorPlugin::test_quickfix_MoveFuncDefOutside_MemberFuncOutside1()
QByteArray expected =
"class Foo {\n"
" void f1();\n"
- " inline int f2@() const;\n"
+ " int f2@() const;\n"
" void f3();\n"
" void f4();\n"
"};\n"
@@ -6062,7 +6142,7 @@ void CppEditorPlugin::test_quickfix_MoveFuncDefOutside_MemberFuncToCppNS()
expected =
"namespace MyNs {\n"
"class Foo {\n"
- " inline int number() const;\n"
+ " int number() const;\n"
"};\n"
"}\n";
testDocuments << QuickFixTestDocument::create("file.h", original, expected);
@@ -6103,7 +6183,7 @@ void CppEditorPlugin::test_quickfix_MoveFuncDefOutside_MemberFuncToCppNSUsing()
expected =
"namespace MyNs {\n"
"class Foo {\n"
- " inline int number() const;\n"
+ " int number() const;\n"
"};\n"
"}\n";
testDocuments << QuickFixTestDocument::create("file.h", original, expected);
@@ -6140,7 +6220,7 @@ void CppEditorPlugin::test_quickfix_MoveFuncDefOutside_MemberFuncOutsideWithNs()
QByteArray expected =
"namespace MyNs {\n"
"class Foo {\n"
- " inline int number() const;\n"
+ " int number() const;\n"
"};\n"
"\n"
"int Foo::number() const\n"
diff --git a/src/plugins/cppeditor/cppquickfixes.cpp b/src/plugins/cppeditor/cppquickfixes.cpp
index 433b2416b0..b7aa2f5d41 100644
--- a/src/plugins/cppeditor/cppquickfixes.cpp
+++ b/src/plugins/cppeditor/cppquickfixes.cpp
@@ -2068,7 +2068,7 @@ void AddIncludeForUndefinedIdentifier::match(const CppQuickFixInterface &interfa
const Snapshot forwardHeaders = forwardingHeaders(interface);
foreach (const Core::LocatorFilterEntry &entry, matches) {
IndexItem::Ptr info = entry.internalData.value<IndexItem::Ptr>();
- if (info->symbolName() != className)
+ if (!info || info->symbolName() != className)
continue;
indexItems << info;
@@ -6262,6 +6262,10 @@ public:
} else {
QString textFuncDecl = m_fromFile->textOf(funcAST);
textFuncDecl.truncate(startPosition - m_fromFile->startOf(funcAST));
+ if (textFuncDecl.left(7) == QLatin1String("inline "))
+ textFuncDecl = textFuncDecl.mid(7);
+ else
+ textFuncDecl.replace(" inline ", QLatin1String(" "));
textFuncDecl = textFuncDecl.trimmed() + QLatin1Char(';');
m_fromFileChangeSet.replace(m_fromFile->range(funcAST), textFuncDecl);
}
diff --git a/src/plugins/cppeditor/cpptypehierarchy.cpp b/src/plugins/cppeditor/cpptypehierarchy.cpp
index d2e1b8c7a5..819c3b427c 100644
--- a/src/plugins/cppeditor/cpptypehierarchy.cpp
+++ b/src/plugins/cppeditor/cpptypehierarchy.cpp
@@ -182,18 +182,6 @@ CppTypeHierarchyWidget::CppTypeHierarchyWidget()
m_synchronizer.setCancelOnWait(true);
}
-void CppTypeHierarchyWidget::updateSynchronizer()
-{
- const QList<QFuture<void>> futures = m_synchronizer.futures();
-
- m_synchronizer.clearFutures();
-
- for (const QFuture<void> &future : futures) {
- if (!future.isFinished())
- m_synchronizer.addFuture(future);
- }
-}
-
void CppTypeHierarchyWidget::perform()
{
if (m_future.isRunning())
@@ -201,8 +189,6 @@ void CppTypeHierarchyWidget::perform()
m_showOldClass = false;
- updateSynchronizer();
-
auto editor = qobject_cast<CppEditor *>(Core::EditorManager::currentEditor());
if (!editor) {
showNoTypeHierarchyLabel();
@@ -219,7 +205,7 @@ void CppTypeHierarchyWidget::perform()
m_future = CppElementEvaluator::asyncExecute(widget);
m_futureWatcher.setFuture(QFuture<void>(m_future));
- m_synchronizer.addFuture(QFuture<void>(m_future));
+ m_synchronizer.addFuture(m_future);
Core::ProgressManager::addTask(m_future, tr("Evaluating Type Hierarchy"), "TypeHierarchy");
}
@@ -231,20 +217,18 @@ void CppTypeHierarchyWidget::performFromExpression(const QString &expression, co
m_showOldClass = true;
- updateSynchronizer();
-
showProgress();
m_future = CppElementEvaluator::asyncExecute(expression, fileName);
m_futureWatcher.setFuture(QFuture<void>(m_future));
- m_synchronizer.addFuture(QFuture<void>(m_future));
+ m_synchronizer.addFuture(m_future);
Core::ProgressManager::addTask(m_future, tr("Evaluating Type Hierarchy"), "TypeHierarchy");
}
void CppTypeHierarchyWidget::displayHierarchy()
{
- updateSynchronizer();
+ m_synchronizer.flushFinishedFutures();
hideProgress();
clearTypeHierarchy();
@@ -348,21 +332,18 @@ void CppTypeHierarchyWidget::onItemActivated(const QModelIndex &index)
return;
const Link updatedLink = CppElementEvaluator::linkFromExpression(
- getExpression(index), link.targetFileName);
+ getExpression(index), link.targetFilePath.toString());
if (updatedLink.hasValidTarget())
link = updatedLink;
- Core::EditorManager::openEditorAt(link.targetFileName,
- link.targetLine,
- link.targetColumn,
- Constants::CPPEDITOR_ID);
+ Core::EditorManager::openEditorAt(link, Constants::CPPEDITOR_ID);
}
void CppTypeHierarchyWidget::onItemDoubleClicked(const QModelIndex &index)
{
const auto link = index.data(LinkRole).value<Link>();
if (link.hasValidTarget())
- performFromExpression(getExpression(index), link.targetFileName);
+ performFromExpression(getExpression(index), link.targetFilePath.toString());
}
// CppTypeHierarchyFactory
@@ -377,7 +358,7 @@ Core::NavigationView CppTypeHierarchyFactory::createWidget()
{
auto w = new CppTypeHierarchyWidget;
w->perform();
- return Core::NavigationView(w);
+ return {w, {}};
}
CppTypeHierarchyModel::CppTypeHierarchyModel(QObject *parent)
@@ -406,7 +387,7 @@ QMimeData *CppTypeHierarchyModel::mimeData(const QModelIndexList &indexes) const
foreach (const QModelIndex &index, indexes) {
auto link = index.data(LinkRole).value<Link>();
if (link.hasValidTarget())
- data->addFile(link.targetFileName, link.targetLine, link.targetColumn);
+ data->addFile(link.targetFilePath.toString(), link.targetLine, link.targetColumn);
}
return data;
}
diff --git a/src/plugins/cppeditor/cpptypehierarchy.h b/src/plugins/cppeditor/cpptypehierarchy.h
index a8c6a1745b..5f09996876 100644
--- a/src/plugins/cppeditor/cpptypehierarchy.h
+++ b/src/plugins/cppeditor/cpptypehierarchy.h
@@ -26,10 +26,10 @@
#pragma once
#include <coreplugin/inavigationwidgetfactory.h>
+#include <utils/futuresynchronizer.h>
#include <QFuture>
#include <QFutureWatcher>
-#include <QFutureSynchronizer>
#include <QList>
#include <QSharedPointer>
#include <QStackedWidget>
@@ -94,7 +94,6 @@ private:
void clearTypeHierarchy();
void onItemActivated(const QModelIndex &index);
void onItemDoubleClicked(const QModelIndex &index);
- void updateSynchronizer();
CppEditorWidget *m_cppEditor = nullptr;
Utils::NavigationTreeView *m_treeView = nullptr;
@@ -106,7 +105,7 @@ private:
QLabel *m_infoLabel = nullptr;
QFuture<QSharedPointer<CppTools::CppElement>> m_future;
QFutureWatcher<void> m_futureWatcher;
- QFutureSynchronizer<void> m_synchronizer;
+ Utils::FutureSynchronizer m_synchronizer;
Utils::ProgressIndicator *m_progressIndicator = nullptr;
QString m_oldClass;
bool m_showOldClass = false;
diff --git a/src/plugins/cppeditor/resourcepreviewhoverhandler.cpp b/src/plugins/cppeditor/resourcepreviewhoverhandler.cpp
index 07fb181d7b..8ebb0339a8 100644
--- a/src/plugins/cppeditor/resourcepreviewhoverhandler.cpp
+++ b/src/plugins/cppeditor/resourcepreviewhoverhandler.cpp
@@ -85,7 +85,7 @@ static QString makeResourcePath(const QStringList &prefixList, const QString &fi
static QString findResourceInFile(const QString &resName, const QString &filePathName)
{
Utils::FileReader reader;
- if (!reader.fetch(filePathName))
+ if (!reader.fetch(Utils::FilePath::fromString(filePathName)))
return QString();
const QByteArray contents = reader.data();
diff --git a/src/plugins/cpptools/abstractoverviewmodel.h b/src/plugins/cpptools/abstractoverviewmodel.h
index 444d19e548..1035494a37 100644
--- a/src/plugins/cpptools/abstractoverviewmodel.h
+++ b/src/plugins/cpptools/abstractoverviewmodel.h
@@ -38,7 +38,7 @@ namespace CPlusPlus { class Document; }
namespace Utils {
class LineColumn;
-struct Link;
+class Link;
}
namespace CppTools {
diff --git a/src/plugins/cpptools/builtinindexingsupport.cpp b/src/plugins/cpptools/builtinindexingsupport.cpp
index ebdd35509f..d7aebe580d 100644
--- a/src/plugins/cpptools/builtinindexingsupport.cpp
+++ b/src/plugins/cpptools/builtinindexingsupport.cpp
@@ -356,18 +356,6 @@ QFuture<void> BuiltinIndexingSupport::refreshSourceFiles(
params.sourceFiles = sourceFiles;
QFuture<void> result = Utils::runAsync(mgr->sharedThreadPool(), parse, params);
-
- if (m_synchronizer.futures().size() > 10) {
- QList<QFuture<void> > futures = m_synchronizer.futures();
-
- m_synchronizer.clearFutures();
-
- foreach (const QFuture<void> &future, futures) {
- if (!(future.isFinished() || future.isCanceled()))
- m_synchronizer.addFuture(future);
- }
- }
-
m_synchronizer.addFuture(result);
if (mode == CppModelManager::ForcedProgressNotification || sourceFiles.count() > 1) {
diff --git a/src/plugins/cpptools/builtinindexingsupport.h b/src/plugins/cpptools/builtinindexingsupport.h
index 9a61d60ec9..ddc797e2a0 100644
--- a/src/plugins/cpptools/builtinindexingsupport.h
+++ b/src/plugins/cpptools/builtinindexingsupport.h
@@ -28,7 +28,7 @@
#include "cppindexingsupport.h"
#include "cppmodelmanager.h"
-#include <QFutureSynchronizer>
+#include <utils/futuresynchronizer.h>
namespace CppTools {
namespace Internal {
@@ -47,7 +47,7 @@ public:
static bool isFindErrorsIndexingActive();
private:
- QFutureSynchronizer<void> m_synchronizer;
+ Utils::FutureSynchronizer m_synchronizer;
};
} // namespace Internal
diff --git a/src/plugins/cpptools/compileroptionsbuilder.cpp b/src/plugins/cpptools/compileroptionsbuilder.cpp
index b40d6e1ac8..030d2b16cd 100644
--- a/src/plugins/cpptools/compileroptionsbuilder.cpp
+++ b/src/plugins/cpptools/compileroptionsbuilder.cpp
@@ -303,7 +303,7 @@ void CompilerOptionsBuilder::insertWrappedMingwHeaders()
static QString creatorResourcePath()
{
#ifndef UNIT_TESTS
- return Core::ICore::resourcePath();
+ return Core::ICore::resourcePath().toString();
#else
return QDir::toNativeSeparators(QString::fromUtf8(QTC_RESOURCE_DIR ""));
#endif
diff --git a/src/plugins/cpptools/cppclassesfilter.h b/src/plugins/cpptools/cppclassesfilter.h
index 638d9a1867..a89cae256e 100644
--- a/src/plugins/cpptools/cppclassesfilter.h
+++ b/src/plugins/cpptools/cppclassesfilter.h
@@ -32,7 +32,7 @@
namespace CppTools {
class CppLocatorData;
-class CppClassesFilter : public Internal::CppLocatorFilter
+class CPPTOOLS_EXPORT CppClassesFilter : public CppLocatorFilter
{
Q_OBJECT
diff --git a/src/plugins/cpptools/cppcodemodelsettings.cpp b/src/plugins/cpptools/cppcodemodelsettings.cpp
index feb1c7f09a..5c5113d004 100644
--- a/src/plugins/cpptools/cppcodemodelsettings.cpp
+++ b/src/plugins/cpptools/cppcodemodelsettings.cpp
@@ -35,6 +35,7 @@
#include <QSettings>
using namespace CppTools;
+using namespace Utils;
static Utils::Id initialClangDiagnosticConfigId()
{ return Constants::CPP_CLANG_DIAG_CONFIG_BUILDSYSTEM; }
@@ -60,6 +61,17 @@ static QString skipIndexingBigFilesKey()
static QString indexerFileSizeLimitKey()
{ return QLatin1String(Constants::CPPTOOLS_INDEXER_FILE_SIZE_LIMIT); }
+static QString useClangdKey() { return QLatin1String("UseClangd"); }
+static QString clangdPathKey() { return QLatin1String("ClangdPath"); }
+
+static FilePath g_defaultClangdFilePath;
+static FilePath fallbackClangdFilePath()
+{
+ if (g_defaultClangdFilePath.exists())
+ return g_defaultClangdFilePath;
+ return FilePath::fromString("clangd");
+}
+
static Utils::Id clangDiagnosticConfigIdFromSettings(QSettings *s)
{
QTC_ASSERT(s->group() == QLatin1String(Constants::CPPTOOLS_SETTINGSGROUP), return Utils::Id());
@@ -160,6 +172,9 @@ void CppCodeModelSettings::fromSettings(QSettings *s)
const QVariant indexerFileSizeLimit = s->value(indexerFileSizeLimitKey(), 5);
setIndexerFileSizeLimitInMb(indexerFileSizeLimit.toInt());
+ setUseClangd(s->value(useClangdKey(), false).toBool());
+ setClangdFilePath(FilePath::fromString(s->value(clangdPathKey()).toString()));
+
s->endGroup();
if (write)
@@ -183,6 +198,8 @@ void CppCodeModelSettings::toSettings(QSettings *s)
s->setValue(interpretAmbiguousHeadersAsCHeadersKey(), interpretAmbigiousHeadersAsCHeaders());
s->setValue(skipIndexingBigFilesKey(), skipIndexingBigFiles());
s->setValue(indexerFileSizeLimitKey(), indexerFileSizeLimitInMb());
+ s->setValue(useClangdKey(), useClangd());
+ s->setValue(clangdPathKey(), m_clangdFilePath.toString());
s->endGroup();
@@ -282,3 +299,15 @@ void CppCodeModelSettings::setEnableLowerClazyLevels(bool yesno)
{
m_enableLowerClazyLevels = yesno;
}
+
+void CppCodeModelSettings::setDefaultClangdPath(const Utils::FilePath &filePath)
+{
+ g_defaultClangdFilePath = filePath;
+}
+
+FilePath CppCodeModelSettings::clangdFilePath() const
+{
+ if (!m_clangdFilePath.isEmpty())
+ return m_clangdFilePath;
+ return fallbackClangdFilePath();
+}
diff --git a/src/plugins/cpptools/cppcodemodelsettings.h b/src/plugins/cpptools/cppcodemodelsettings.h
index afc326dedc..475c7dda9e 100644
--- a/src/plugins/cpptools/cppcodemodelsettings.h
+++ b/src/plugins/cpptools/cppcodemodelsettings.h
@@ -29,6 +29,8 @@
#include "clangdiagnosticconfigsmodel.h"
+#include <utils/fileutils.h>
+
#include <QObject>
#include <QStringList>
@@ -76,6 +78,13 @@ public:
int indexerFileSizeLimitInMb() const;
void setIndexerFileSizeLimitInMb(int sizeInMB);
+ void setUseClangd(bool use) { m_useClangd = use; }
+ bool useClangd() const { return m_useClangd; }
+
+ static void setDefaultClangdPath(const Utils::FilePath &filePath);
+ void setClangdFilePath(const Utils::FilePath &filePath) { m_clangdFilePath = filePath; }
+ Utils::FilePath clangdFilePath() const;
+
signals:
void clangDiagnosticConfigsInvalidated(const QVector<Utils::Id> &configId);
void changed();
@@ -88,6 +97,8 @@ private:
ClangDiagnosticConfigs m_clangCustomDiagnosticConfigs;
Utils::Id m_clangDiagnosticConfigId;
bool m_enableLowerClazyLevels = true; // For UI behavior only
+ Utils::FilePath m_clangdFilePath;
+ bool m_useClangd = false;
};
} // namespace CppTools
diff --git a/src/plugins/cpptools/cppcodemodelsettingspage.cpp b/src/plugins/cpptools/cppcodemodelsettingspage.cpp
index 2c1b0ddc02..00e7b8081a 100644
--- a/src/plugins/cpptools/cppcodemodelsettingspage.cpp
+++ b/src/plugins/cpptools/cppcodemodelsettingspage.cpp
@@ -100,6 +100,9 @@ void CppCodeModelSettingsWidget::setupClangCodeModelWidgets()
const bool isClangActive = CppModelManager::instance()->isClangCodeModelActive();
m_ui->clangCodeModelIsDisabledHint->setVisible(!isClangActive);
m_ui->clangCodeModelIsEnabledHint->setVisible(isClangActive);
+ m_ui->clangdCheckBox->setVisible(isClangActive);
+ m_ui->clangdChooser->setVisible(isClangActive);
+
for (int i = 0; i < m_ui->clangDiagnosticConfigsSelectionWidget->layout()->count(); ++i) {
QWidget *widget = m_ui->clangDiagnosticConfigsSelectionWidget->layout()->itemAt(i)->widget();
if (widget)
@@ -117,6 +120,16 @@ void CppCodeModelSettingsWidget::setupGeneralWidgets()
const bool ignorePch = m_settings->pchUsage() == CppCodeModelSettings::PchUse_None;
m_ui->ignorePCHCheckBox->setChecked(ignorePch);
+
+ m_ui->clangdCheckBox->setChecked(m_settings->useClangd());
+ m_ui->clangdCheckBox->setToolTip(tr("Use clangd for locators and \"Find References\".\n"
+ "Changing this option does not affect projects that are already open."));
+ m_ui->clangdChooser->setExpectedKind(Utils::PathChooser::ExistingCommand);
+ m_ui->clangdChooser->setFilePath(codeModelSettings()->clangdFilePath());
+ m_ui->clangdChooser->setEnabled(m_ui->clangdCheckBox->isChecked());
+ connect(m_ui->clangdCheckBox, &QCheckBox::toggled, m_ui->clangdChooser, [this](bool checked) {
+ m_ui->clangdChooser->setEnabled(checked);
+ });
}
bool CppCodeModelSettingsWidget::applyClangCodeModelWidgetsToSettings() const
@@ -163,6 +176,16 @@ bool CppCodeModelSettingsWidget::applyGeneralWidgetsToSettings() const
m_settings->setIndexerFileSizeLimitInMb(newFileSizeLimit);
settingsChanged = true;
}
+ const bool newUseClangd = m_ui->clangdCheckBox->isChecked();
+ if (m_settings->useClangd() != newUseClangd) {
+ m_settings->setUseClangd(newUseClangd);
+ settingsChanged = true;
+ }
+ const Utils::FilePath newClangdPath = m_ui->clangdChooser->rawFilePath();
+ if (m_settings->clangdFilePath() != newClangdPath) {
+ m_settings->setClangdFilePath(newClangdPath);
+ settingsChanged = true;
+ }
const bool newIgnorePch = m_ui->ignorePCHCheckBox->isChecked();
const bool previousIgnorePch = m_settings->pchUsage() == CppCodeModelSettings::PchUse_None;
diff --git a/src/plugins/cpptools/cppcodemodelsettingspage.ui b/src/plugins/cpptools/cppcodemodelsettingspage.ui
index 996ddc9e75..2362131cbe 100644
--- a/src/plugins/cpptools/cppcodemodelsettingspage.ui
+++ b/src/plugins/cpptools/cppcodemodelsettingspage.ui
@@ -6,7 +6,7 @@
<rect>
<x>0</x>
<y>0</y>
- <width>647</width>
+ <width>697</width>
<height>440</height>
</rect>
</property>
@@ -80,6 +80,33 @@
</item>
</layout>
</item>
+ <item>
+ <layout class="QHBoxLayout" name="horizontalLayout_3">
+ <item>
+ <widget class="QCheckBox" name="clangdCheckBox">
+ <property name="text">
+ <string>Use clangd (EXPERIMENTAL)</string>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <widget class="Utils::PathChooser" name="clangdChooser"/>
+ </item>
+ <item>
+ <spacer name="horizontalSpacer_3">
+ <property name="orientation">
+ <enum>Qt::Horizontal</enum>
+ </property>
+ <property name="sizeHint" stdset="0">
+ <size>
+ <width>40</width>
+ <height>20</height>
+ </size>
+ </property>
+ </spacer>
+ </item>
+ </layout>
+ </item>
</layout>
</widget>
</item>
@@ -147,6 +174,11 @@
<extends>QWidget</extends>
<header>cpptools/clangdiagnosticconfigsselectionwidget.h</header>
</customwidget>
+ <customwidget>
+ <class>Utils::PathChooser</class>
+ <extends>QLineEdit</extends>
+ <header location="global">utils/pathchooser.h</header>
+ </customwidget>
</customwidgets>
<resources/>
<connections/>
diff --git a/src/plugins/cpptools/cppelementevaluator.cpp b/src/plugins/cpptools/cppelementevaluator.cpp
index 9cb6c6f807..2fff470bf7 100644
--- a/src/plugins/cpptools/cppelementevaluator.cpp
+++ b/src/plugins/cpptools/cppelementevaluator.cpp
@@ -90,7 +90,7 @@ public:
helpCategory = Core::HelpItem::Brief;
helpIdCandidates = QStringList(fileName);
helpMark = fileName;
- link = Utils::Link(path);
+ link = Utils::Link(Utils::FilePath::fromString(path));
tooltip = path;
}
@@ -108,7 +108,7 @@ public:
const QString macroName = QString::fromUtf8(macro.name(), macro.name().size());
helpIdCandidates = QStringList(macroName);
helpMark = macroName;
- link = Utils::Link(macro.fileName(), macro.line());
+ link = Utils::Link(Utils::FilePath::fromString(macro.fileName()), macro.line());
tooltip = macro.toStringWithLineBreaks();
}
};
diff --git a/src/plugins/cpptools/cppfilesettingspage.cpp b/src/plugins/cpptools/cppfilesettingspage.cpp
index 4d1d738e8c..f63eb41b24 100644
--- a/src/plugins/cpptools/cppfilesettingspage.cpp
+++ b/src/plugins/cpptools/cppfilesettingspage.cpp
@@ -369,7 +369,7 @@ void CppFileSettingsWidget::slotEdit()
path = QFileDialog::getSaveFileName(this, tr("Choose Location for New License Template File"));
if (path.isEmpty())
return;
- Utils::FileSaver saver(path, QIODevice::Text);
+ Utils::FileSaver saver(Utils::FilePath::fromString(path), QIODevice::Text);
saver.write(tr(licenseTemplateTemplate).arg(Core::Constants::IDE_DISPLAY_NAME).toUtf8());
if (!saver.finalize(this))
return;
diff --git a/src/plugins/cpptools/cppfindreferences.cpp b/src/plugins/cpptools/cppfindreferences.cpp
index c0860c073e..e93fc545ea 100644
--- a/src/plugins/cpptools/cppfindreferences.cpp
+++ b/src/plugins/cpptools/cppfindreferences.cpp
@@ -37,6 +37,7 @@
#include <projectexplorer/projectexplorer.h>
#include <projectexplorer/projectnodes.h>
#include <projectexplorer/projecttree.h>
+#include <projectexplorer/session.h>
#include <texteditor/basefilefind.h>
#include <utils/algorithm.h>
@@ -54,10 +55,127 @@
#include <functional>
using namespace Core;
-using namespace CppTools::Internal;
-using namespace CppTools;
using namespace ProjectExplorer;
+namespace CppTools {
+
+namespace { static bool isAllLowerCase(const QString &text) { return text.toLower() == text; } }
+
+SearchResultColor::Style colorStyleForUsageType(CPlusPlus::Usage::Type type)
+{
+ switch (type) {
+ case CPlusPlus::Usage::Type::Read:
+ return SearchResultColor::Style::Alt1;
+ case CPlusPlus::Usage::Type::Initialization:
+ case CPlusPlus::Usage::Type::Write:
+ case CPlusPlus::Usage::Type::WritableRef:
+ return SearchResultColor::Style::Alt2;
+ case CPlusPlus::Usage::Type::Declaration:
+ case CPlusPlus::Usage::Type::Other:
+ return SearchResultColor::Style::Default;
+ }
+ return SearchResultColor::Style::Default; // For dumb compilers.
+}
+
+void renameFilesForSymbol(const QString &oldSymbolName, const QString &newSymbolName,
+ const QVector<Node *> &files)
+{
+ Internal::CppFileSettings settings;
+ settings.fromSettings(Core::ICore::settings());
+
+ const QStringList newPaths =
+ Utils::transform<QList>(files,
+ [&oldSymbolName, newSymbolName, &settings](const Node *node) -> QString {
+ const QFileInfo fi = node->filePath().toFileInfo();
+ const QString oldBaseName = fi.baseName();
+ QString newBaseName = newSymbolName;
+
+ // 1) new symbol lowercase: new base name lowercase
+ if (isAllLowerCase(newSymbolName)) {
+ newBaseName = newSymbolName;
+
+ // 2) old base name mixed case: new base name is verbatim symbol name
+ } else if (!isAllLowerCase(oldBaseName)) {
+ newBaseName = newSymbolName;
+
+ // 3) old base name lowercase, old symbol mixed case: new base name lowercase
+ } else if (!isAllLowerCase(oldSymbolName)) {
+ newBaseName = newSymbolName.toLower();
+
+ // 4) old base name lowercase, old symbol lowercase, new symbol mixed case:
+ // use the preferences setting for new base name case
+ } else if (settings.lowerCaseFiles) {
+ newBaseName = newSymbolName.toLower();
+ }
+
+ if (newBaseName == oldBaseName)
+ return QString();
+
+ return fi.absolutePath() + "/" + newBaseName + '.' + fi.completeSuffix();
+ });
+
+ for (int i = 0; i < files.size(); ++i) {
+ if (!newPaths.at(i).isEmpty()) {
+ Node *node = files.at(i);
+ ProjectExplorerPlugin::renameFile(node, newPaths.at(i));
+ }
+ }
+}
+
+QWidget *CppSearchResultFilter::createWidget()
+{
+ const auto widget = new QWidget;
+ const auto layout = new QVBoxLayout(widget);
+ layout->setContentsMargins(0, 0, 0, 0);
+ const auto readsCheckBox = new QCheckBox(Internal::CppFindReferences::tr("Reads"));
+ readsCheckBox->setChecked(m_showReads);
+ const auto writesCheckBox = new QCheckBox(Internal::CppFindReferences::tr("Writes"));
+ writesCheckBox->setChecked(m_showWrites);
+ const auto declsCheckBox = new QCheckBox(Internal::CppFindReferences::tr("Declarations"));
+ declsCheckBox->setChecked(m_showDecls);
+ const auto otherCheckBox = new QCheckBox(Internal::CppFindReferences::tr("Other"));
+ otherCheckBox->setChecked(m_showOther);
+ layout->addWidget(readsCheckBox);
+ layout->addWidget(writesCheckBox);
+ layout->addWidget(declsCheckBox);
+ layout->addWidget(otherCheckBox);
+ connect(readsCheckBox, &QCheckBox::toggled,
+ this, [this](bool checked) { setValue(m_showReads, checked); });
+ connect(writesCheckBox, &QCheckBox::toggled,
+ this, [this](bool checked) { setValue(m_showWrites, checked); });
+ connect(declsCheckBox, &QCheckBox::toggled,
+ this, [this](bool checked) { setValue(m_showDecls, checked); });
+ connect(otherCheckBox, &QCheckBox::toggled,
+ this, [this](bool checked) { setValue(m_showOther, checked); });
+ return widget;
+}
+
+bool CppSearchResultFilter::matches(const SearchResultItem &item) const
+{
+ switch (static_cast<CPlusPlus::Usage::Type>(item.userData().toInt())) {
+ case CPlusPlus::Usage::Type::Read:
+ return m_showReads;
+ case CPlusPlus::Usage::Type::Write:
+ case CPlusPlus::Usage::Type::WritableRef:
+ case CPlusPlus::Usage::Type::Initialization:
+ return m_showWrites;
+ case CPlusPlus::Usage::Type::Declaration:
+ return m_showDecls;
+ case CPlusPlus::Usage::Type::Other:
+ return m_showOther;
+ }
+ return false;
+}
+
+void CppSearchResultFilter::setValue(bool &member, bool value)
+{
+ member = value;
+ emit filterChanged();
+}
+
+namespace Internal {
+
+
static QByteArray getSource(const Utils::FilePath &fileName,
const WorkingCopy &workingCopy)
{
@@ -69,7 +187,7 @@ static QByteArray getSource(const Utils::FilePath &fileName,
QString error;
QTextCodec *defaultCodec = EditorManager::defaultTextCodec();
Utils::TextFileFormat::ReadResult result = Utils::TextFileFormat::readFile(
- fileName.toString(), defaultCodec, &fileContents, &format, &error);
+ fileName, defaultCodec, &fileContents, &format, &error);
if (result != Utils::TextFileFormat::ReadSuccess)
qWarning() << "Could not read " << fileName << ". Error: " << error;
@@ -170,65 +288,6 @@ static QList<QByteArray> fullIdForSymbol(CPlusPlus::Symbol *symbol)
namespace {
-class Filter : public Core::SearchResultFilter
-{
- QWidget *createWidget() override
- {
- const auto widget = new QWidget;
- const auto layout = new QVBoxLayout(widget);
- layout->setContentsMargins(0, 0, 0, 0);
- const auto readsCheckBox = new QCheckBox(CppFindReferences::tr("Reads"));
- readsCheckBox->setChecked(m_showReads);
- const auto writesCheckBox = new QCheckBox(CppFindReferences::tr("Writes"));
- writesCheckBox->setChecked(m_showWrites);
- const auto declsCheckBox = new QCheckBox(CppFindReferences::tr("Declarations"));
- declsCheckBox->setChecked(m_showDecls);
- const auto otherCheckBox = new QCheckBox(CppFindReferences::tr("Other"));
- otherCheckBox->setChecked(m_showOther);
- layout->addWidget(readsCheckBox);
- layout->addWidget(writesCheckBox);
- layout->addWidget(declsCheckBox);
- layout->addWidget(otherCheckBox);
- connect(readsCheckBox, &QCheckBox::toggled,
- this, [this](bool checked) { setValue(m_showReads, checked); });
- connect(writesCheckBox, &QCheckBox::toggled,
- this, [this](bool checked) { setValue(m_showWrites, checked); });
- connect(declsCheckBox, &QCheckBox::toggled,
- this, [this](bool checked) { setValue(m_showDecls, checked); });
- connect(otherCheckBox, &QCheckBox::toggled,
- this, [this](bool checked) { setValue(m_showOther, checked); });
- return widget;
- }
-
- bool matches(const SearchResultItem &item) const override
- {
- switch (static_cast<CPlusPlus::Usage::Type>(item.userData().toInt())) {
- case CPlusPlus::Usage::Type::Read:
- return m_showReads;
- case CPlusPlus::Usage::Type::Write:
- case CPlusPlus::Usage::Type::WritableRef:
- case CPlusPlus::Usage::Type::Initialization:
- return m_showWrites;
- case CPlusPlus::Usage::Type::Declaration:
- return m_showDecls;
- case CPlusPlus::Usage::Type::Other:
- return m_showOther;
- }
- return false;
- }
-
- void setValue(bool &member, bool value)
- {
- member = value;
- emit filterChanged();
- }
-
- bool m_showReads = true;
- bool m_showWrites = true;
- bool m_showDecls = true;
- bool m_showOther = true;
-};
-
class ProcessFile
{
const WorkingCopy workingCopy;
@@ -399,7 +458,7 @@ void CppFindReferences::findUsages(CPlusPlus::Symbol *symbol,
SearchResultWindow::PreserveCaseDisabled,
QLatin1String("CppEditor"));
search->setTextToReplace(replacement);
- search->setFilter(new Filter);
+ search->setFilter(new CppSearchResultFilter);
auto renameFilesCheckBox = new QCheckBox();
renameFilesCheckBox->setVisible(false);
search->setAdditionalReplaceWidget(renameFilesCheckBox);
@@ -457,11 +516,6 @@ void CppFindReferences::findAll_helper(SearchResult *search, CPlusPlus::Symbol *
connect(progress, &FutureProgress::clicked, search, &SearchResult::popup);
}
-static bool isAllLowerCase(const QString &text)
-{
- return text.toLower() == text;
-}
-
void CppFindReferences::onReplaceButtonClicked(const QString &text,
const QList<SearchResultItem> &items,
bool preserveCase)
@@ -483,48 +537,7 @@ void CppFindReferences::onReplaceButtonClicked(const QString &text,
if (!renameFilesCheckBox || !renameFilesCheckBox->isChecked())
return;
- CppFileSettings settings;
- settings.fromSettings(Core::ICore::settings());
-
- const QStringList newPaths =
- Utils::transform<QList>(parameters.filesToRename,
- [&parameters, text, &settings](const Node *node) -> QString {
- const QFileInfo fi = node->filePath().toFileInfo();
- const QString oldSymbolName = parameters.prettySymbolName;
- const QString oldBaseName = fi.baseName();
- const QString newSymbolName = text;
- QString newBaseName = newSymbolName;
-
- // 1) new symbol lowercase: new base name lowercase
- if (isAllLowerCase(newSymbolName)) {
- newBaseName = newSymbolName;
-
- // 2) old base name mixed case: new base name is verbatim symbol name
- } else if (!isAllLowerCase(oldBaseName)) {
- newBaseName = newSymbolName;
-
- // 3) old base name lowercase, old symbol mixed case: new base name lowercase
- } else if (!isAllLowerCase(oldSymbolName)) {
- newBaseName = newSymbolName.toLower();
-
- // 4) old base name lowercase, old symbol lowercase, new symbol mixed case:
- // use the preferences setting for new base name case
- } else if (settings.lowerCaseFiles) {
- newBaseName = newSymbolName.toLower();
- }
-
- if (newBaseName == oldBaseName)
- return QString();
-
- return fi.absolutePath() + "/" + newBaseName + '.' + fi.completeSuffix();
- });
-
- for (int i = 0; i < parameters.filesToRename.size(); ++i) {
- if (!newPaths.at(i).isEmpty()) {
- Node *node = parameters.filesToRename.at(i);
- ProjectExplorerPlugin::renameFile(node, newPaths.at(i));
- }
- }
+ renameFilesForSymbol(parameters.prettySymbolName, text, parameters.filesToRename);
}
void CppFindReferences::searchAgain()
@@ -614,20 +627,6 @@ static void displayResults(SearchResult *search, QFutureWatcher<CPlusPlus::Usage
{
CppFindReferencesParameters parameters = search->userData().value<CppFindReferencesParameters>();
- static const auto colorStyleForUsageType = [](CPlusPlus::Usage::Type type) {
- switch (type) {
- case CPlusPlus::Usage::Type::Read:
- return SearchResultColor::Style::Alt1;
- case CPlusPlus::Usage::Type::Initialization:
- case CPlusPlus::Usage::Type::Write:
- case CPlusPlus::Usage::Type::WritableRef:
- return SearchResultColor::Style::Alt2;
- case CPlusPlus::Usage::Type::Declaration:
- case CPlusPlus::Usage::Type::Other:
- return SearchResultColor::Style::Default;
- }
- return SearchResultColor::Style::Default; // For dumb compilers.
- };
for (int index = first; index != last; ++index) {
const CPlusPlus::Usage result = watcher->future().resultAt(index);
SearchResultItem item;
@@ -637,6 +636,8 @@ static void displayResults(SearchResult *search, QFutureWatcher<CPlusPlus::Usage
item.setUserData(int(result.type));
item.setStyle(colorStyleForUsageType(result.type));
item.setUseTextEditorFont(true);
+ if (search->supportsReplace())
+ item.setSelectForReplacement(SessionManager::projectForFile(result.path));
search->addResult(item);
if (parameters.prettySymbolName.isEmpty())
@@ -829,10 +830,13 @@ void CppFindReferences::findMacroUses(const CPlusPlus::Macro &macro, const QStri
const QString line = FindMacroUsesInFile::matchingLine(macro.bytesOffset(), source,
&column);
SearchResultItem item;
- item.setFilePath(Utils::FilePath::fromString(macro.fileName()));
+ const Utils::FilePath filePath = Utils::FilePath::fromString(macro.fileName());
+ item.setFilePath(filePath);
item.setLineText(line);
item.setMainRange(macro.line(), column, macro.nameToQString().length());
item.setUseTextEditorFont(true);
+ if (search->supportsReplace())
+ item.setSelectForReplacement(SessionManager::projectForFile(filePath));
search->addResult(item);
}
@@ -875,3 +879,6 @@ void CppFindReferences::createWatcher(const QFuture<CPlusPlus::Usage> &future, S
watcher->setPendingResultsLimit(1);
watcher->setFuture(future);
}
+
+} // namespace Internal
+} // namespace CppTools
diff --git a/src/plugins/cpptools/cppfindreferences.h b/src/plugins/cpptools/cppfindreferences.h
index 7b2b35b2df..8d74c2ddd3 100644
--- a/src/plugins/cpptools/cppfindreferences.h
+++ b/src/plugins/cpptools/cppfindreferences.h
@@ -25,6 +25,9 @@
#pragma once
+#include "cpptools_global.h"
+
+#include <coreplugin/find/searchresultwindow.h>
#include <cplusplus/FindUsages.h>
#include <QObject>
@@ -45,6 +48,24 @@ class Node;
namespace CppTools {
class CppModelManager;
+Core::SearchResultColor::Style CPPTOOLS_EXPORT colorStyleForUsageType(CPlusPlus::Usage::Type type);
+void CPPTOOLS_EXPORT renameFilesForSymbol(const QString &oldSymbolName,
+ const QString &newSymbolName,
+ const QVector<ProjectExplorer::Node *> &files);
+
+class CPPTOOLS_EXPORT CppSearchResultFilter : public Core::SearchResultFilter
+{
+ QWidget *createWidget() override;
+ bool matches(const Core::SearchResultItem &item) const override;
+
+ void setValue(bool &member, bool value);
+
+ bool m_showReads = true;
+ bool m_showWrites = true;
+ bool m_showDecls = true;
+ bool m_showOther = true;
+};
+
namespace Internal {
class CppFindReferencesParameters
diff --git a/src/plugins/cpptools/cppfollowsymbolundercursor.cpp b/src/plugins/cpptools/cppfollowsymbolundercursor.cpp
index 4fc2c8e316..a9cfe89360 100644
--- a/src/plugins/cpptools/cppfollowsymbolundercursor.cpp
+++ b/src/plugins/cpptools/cppfollowsymbolundercursor.cpp
@@ -208,7 +208,7 @@ Link findMacroLink_helper(const QByteArray &name, Document::Ptr doc, const Snaps
foreach (const Macro &macro, doc->definedMacros()) {
if (macro.name() == name) {
Link link;
- link.targetFileName = macro.fileName();
+ link.targetFilePath = Utils::FilePath::fromString(macro.fileName());
link.targetLine = macro.line();
return link;
}
@@ -643,7 +643,7 @@ void FollowSymbolUnderCursor::findLink(
const int lineno = cursor.blockNumber() + 1;
foreach (const Document::Include &incl, doc->resolvedIncludes()) {
if (incl.line() == lineno) {
- link.targetFileName = incl.resolvedFileName();
+ link.targetFilePath = Utils::FilePath::fromString(incl.resolvedFileName());
link.linkTextStart = beginOfToken + 1;
link.linkTextEnd = endOfToken - 1;
processLinkCallback(link);
@@ -671,7 +671,7 @@ void FollowSymbolUnderCursor::findLink(
editorWidget->showPreProcessorWidget();
} else if (fileName != CppModelManager::configurationFileName()) {
const Macro &macro = use->macro();
- link.targetFileName = macro.fileName();
+ link.targetFilePath = Utils::FilePath::fromString(macro.fileName());
link.targetLine = macro.line();
link.linkTextStart = use->utf16charsBegin();
link.linkTextEnd = use->utf16charsEnd();
diff --git a/src/plugins/cpptools/cppfunctionsfilter.cpp b/src/plugins/cpptools/cppfunctionsfilter.cpp
index 8b83508e42..3f3773580f 100644
--- a/src/plugins/cpptools/cppfunctionsfilter.cpp
+++ b/src/plugins/cpptools/cppfunctionsfilter.cpp
@@ -30,7 +30,6 @@
#include <utils/fileutils.h>
using namespace CppTools;
-using namespace CppTools::Internal;
CppFunctionsFilter::CppFunctionsFilter(CppLocatorData *locatorData)
: CppLocatorFilter(locatorData)
diff --git a/src/plugins/cpptools/cppfunctionsfilter.h b/src/plugins/cpptools/cppfunctionsfilter.h
index 04ba9b8612..0eee85c6d8 100644
--- a/src/plugins/cpptools/cppfunctionsfilter.h
+++ b/src/plugins/cpptools/cppfunctionsfilter.h
@@ -30,9 +30,8 @@
namespace CppTools {
-namespace Internal {
-class CppFunctionsFilter : public CppLocatorFilter
+class CPPTOOLS_EXPORT CppFunctionsFilter : public CppLocatorFilter
{
Q_OBJECT
@@ -45,5 +44,4 @@ protected:
Core::LocatorFilterEntry filterEntryFromIndexItem(IndexItem::Ptr info) override;
};
-} // namespace Internal
} // namespace CppTools
diff --git a/src/plugins/cpptools/cppincludesfilter.cpp b/src/plugins/cpptools/cppincludesfilter.cpp
index 32eef13349..57a1b6b47f 100644
--- a/src/plugins/cpptools/cppincludesfilter.cpp
+++ b/src/plugins/cpptools/cppincludesfilter.cpp
@@ -121,6 +121,10 @@ CppIncludesFilter::CppIncludesFilter()
{
setId(Constants::INCLUDES_FILTER_ID);
setDisplayName(Constants::INCLUDES_FILTER_DISPLAY_NAME);
+ setDescription(
+ tr("Matches all files that are included by all C++ files in all projects. Append "
+ "\"+<number>\" or \":<number>\" to jump to the given line number. Append another "
+ "\"+<number>\" or \":<number>\" to jump to the column number as well."));
setDefaultShortcutString("ai");
setDefaultIncludedByDefault(true);
setPriority(ILocatorFilter::Low);
diff --git a/src/plugins/cpptools/cpplocatordata.h b/src/plugins/cpptools/cpplocatordata.h
index f8c853471f..61cfda8169 100644
--- a/src/plugins/cpptools/cpplocatordata.h
+++ b/src/plugins/cpptools/cpplocatordata.h
@@ -35,7 +35,7 @@
namespace CppTools {
-class CppLocatorData : public QObject
+class CPPTOOLS_EXPORT CppLocatorData : public QObject
{
Q_OBJECT
diff --git a/src/plugins/cpptools/cpplocatorfilter.cpp b/src/plugins/cpptools/cpplocatorfilter.cpp
index 0d2ae76b80..73403a5e6b 100644
--- a/src/plugins/cpptools/cpplocatorfilter.cpp
+++ b/src/plugins/cpptools/cpplocatorfilter.cpp
@@ -35,8 +35,7 @@
#include <algorithm>
#include <numeric>
-using namespace CppTools;
-using namespace CppTools::Internal;
+namespace CppTools {
CppLocatorFilter::CppLocatorFilter(CppLocatorData *locatorData)
: m_data(locatorData)
@@ -145,3 +144,5 @@ void CppLocatorFilter::accept(Core::LocatorFilterEntry selection,
IndexItem::Ptr info = qvariant_cast<IndexItem::Ptr>(selection.internalData);
Core::EditorManager::openEditorAt(info->fileName(), info->line(), info->column());
}
+
+} // namespace CppTools
diff --git a/src/plugins/cpptools/cpplocatorfilter.h b/src/plugins/cpptools/cpplocatorfilter.h
index 63df955117..5c4c2bfaf1 100644
--- a/src/plugins/cpptools/cpplocatorfilter.h
+++ b/src/plugins/cpptools/cpplocatorfilter.h
@@ -25,15 +25,15 @@
#pragma once
+#include "cpptools_global.h"
#include "cpplocatordata.h"
#include "searchsymbols.h"
#include <coreplugin/locator/ilocatorfilter.h>
namespace CppTools {
-namespace Internal {
-class CppLocatorFilter : public Core::ILocatorFilter
+class CPPTOOLS_EXPORT CppLocatorFilter : public Core::ILocatorFilter
{
Q_OBJECT
@@ -54,5 +54,4 @@ protected:
CppLocatorData *m_data = nullptr;
};
-} // namespace Internal
} // namespace CppTools
diff --git a/src/plugins/cpptools/cppmodelmanager.cpp b/src/plugins/cpptools/cppmodelmanager.cpp
index a4652e8baf..cbddd8f764 100644
--- a/src/plugins/cpptools/cppmodelmanager.cpp
+++ b/src/plugins/cpptools/cppmodelmanager.cpp
@@ -61,6 +61,8 @@
#include <cplusplus/ASTPath.h>
#include <cplusplus/TypeOfExpression.h>
#include <extensionsystem/pluginmanager.h>
+#include <projectexplorer/kitinformation.h>
+#include <projectexplorer/kitmanager.h>
#include <projectexplorer/project.h>
#include <projectexplorer/projectexplorer.h>
#include <projectexplorer/projectmacro.h>
@@ -90,6 +92,7 @@ static const bool DumpProjectInfo = qgetenv("QTC_DUMP_PROJECT_INFO") == "1";
using namespace CppTools;
using namespace CppTools::Internal;
using namespace CPlusPlus;
+using namespace ProjectExplorer;
#ifdef QTCREATOR_WITH_DUMP_AST
@@ -292,12 +295,11 @@ QString CppModelManager::editorConfigurationFileName()
return QLatin1String("<per-editor-defines>");
}
-static RefactoringEngineInterface *getRefactoringEngine(
- CppModelManagerPrivate::REHash &engines, bool excludeClangCodeModel = true)
+static RefactoringEngineInterface *getRefactoringEngine(CppModelManagerPrivate::REHash &engines)
{
QTC_ASSERT(!engines.empty(), return nullptr;);
RefactoringEngineInterface *currentEngine = engines[REType::BuiltIn];
- if (!excludeClangCodeModel && engines.find(REType::ClangCodeModel) != engines.end()) {
+ if (engines.find(REType::ClangCodeModel) != engines.end()) {
currentEngine = engines[REType::ClangCodeModel];
} else if (engines.find(REType::ClangRefactoring) != engines.end()) {
RefactoringEngineInterface *engine = engines[REType::ClangRefactoring];
@@ -311,8 +313,7 @@ void CppModelManager::startLocalRenaming(const CursorInEditor &data,
CppTools::ProjectPart *projectPart,
RenameCallback &&renameSymbolsCallback)
{
- RefactoringEngineInterface *engine = getRefactoringEngine(d->m_refactoringEngines,
- false);
+ RefactoringEngineInterface *engine = getRefactoringEngine(d->m_refactoringEngines);
QTC_ASSERT(engine, return;);
engine->startLocalRenaming(data, projectPart, std::move(renameSymbolsCallback));
}
@@ -466,6 +467,11 @@ void CppModelManager::removeRefactoringEngine(RefactoringEngineType type)
instance()->d->m_refactoringEngines.remove(type);
}
+RefactoringEngineInterface *CppModelManager::builtinRefactoringEngine()
+{
+ return instance()->d->m_refactoringEngines.value(RefactoringEngineType::BuiltIn);
+}
+
template<class FilterClass>
static void setFilter(std::unique_ptr<FilterClass> &filter,
std::unique_ptr<FilterClass> &&newFilter)
@@ -917,6 +923,11 @@ QByteArray CppModelManager::codeModelConfiguration() const
return QByteArray::fromRawData(pp_configuration, qstrlen(pp_configuration));
}
+CppLocatorData *CppModelManager::locatorData() const
+{
+ return &d->m_locatorData;
+}
+
static QSet<QString> tooBigFilesRemoved(const QSet<QString> &files, int fileSizeLimitInMb)
{
if (fileSizeLimitInMb <= 0)
@@ -1268,6 +1279,22 @@ ProjectPart::Ptr CppModelManager::fallbackProjectPart()
Utils::LanguageExtension::ObjectiveC);
part->qtVersion = Utils::QtVersion::Qt5;
+
+ // TODO: Use different fallback toolchain for different kinds of files
+ const auto * const defaultKit = KitManager::defaultKit();
+ const ToolChain * const defaultTc = ToolChainKitAspect::cxxToolChain(defaultKit);
+ if (defaultKit && defaultTc) {
+ Utils::FilePath sysroot = SysRootKitAspect::sysRoot(defaultKit);
+ if (sysroot.isEmpty())
+ sysroot = Utils::FilePath::fromString(defaultTc->sysRoot());
+ Utils::Environment env = defaultKit->buildEnvironment();
+ ToolChainInfo tcInfo(defaultTc, sysroot.toString(), env);
+ part->setupToolchainProperties(tcInfo, {});
+ if (part->language == Language::C)
+ part->languageVersion = Utils::LanguageVersion::LatestC;
+ else
+ part->languageVersion = Utils::LanguageVersion::LatestCxx;
+ }
part->updateLanguageFeatures();
return part;
@@ -1391,6 +1418,38 @@ void CppModelManager::onAboutToLoadSession()
GC();
}
+QSet<QString> CppModelManager::dependingInternalTargets(const Utils::FilePath &file) const
+{
+ QSet<QString> result;
+ const Snapshot snapshot = this->snapshot();
+ QTC_ASSERT(snapshot.contains(file), return result);
+ bool wasHeader;
+ const QString correspondingFile
+ = correspondingHeaderOrSource(file.toString(), &wasHeader, CacheUsage::ReadOnly);
+ const Utils::FilePaths dependingFiles = snapshot.filesDependingOn(
+ wasHeader ? file : Utils::FilePath::fromString(correspondingFile));
+ for (const Utils::FilePath &fn : qAsConst(dependingFiles)) {
+ for (const ProjectPart::Ptr &part : projectPart(fn))
+ result.insert(part->buildSystemTarget);
+ }
+ return result;
+}
+
+QSet<QString> CppModelManager::internalTargets(const Utils::FilePath &filePath) const
+{
+ const QList<ProjectPart::Ptr> projectParts = projectPart(filePath);
+ // if we have no project parts it's most likely a header with declarations only and CMake based
+ if (projectParts.isEmpty())
+ return dependingInternalTargets(filePath);
+ QSet<QString> targets;
+ for (const ProjectPart::Ptr &part : projectParts) {
+ targets.insert(part->buildSystemTarget);
+ if (part->buildTargetType != ProjectExplorer::BuildTargetType::Executable)
+ targets.unite(dependingInternalTargets(filePath));
+ }
+ return targets;
+}
+
void CppModelManager::renameIncludes(const QString &oldFileName, const QString &newFileName)
{
if (oldFileName.isEmpty() || newFileName.isEmpty())
diff --git a/src/plugins/cpptools/cppmodelmanager.h b/src/plugins/cpptools/cppmodelmanager.h
index 253e4856cc..ff987caf93 100644
--- a/src/plugins/cpptools/cppmodelmanager.h
+++ b/src/plugins/cpptools/cppmodelmanager.h
@@ -60,6 +60,7 @@ class BaseEditorDocumentProcessor;
class CppCompletionAssistProvider;
class CppEditorDocumentHandle;
class CppIndexingSupport;
+class CppLocatorData;
class ModelManagerSupportProvider;
class FollowSymbolInterface;
class SymbolFinder;
@@ -111,6 +112,7 @@ public:
void updateCppEditorDocuments(bool projectsUpdated = false) const;
WorkingCopy workingCopy() const;
QByteArray codeModelConfiguration() const;
+ CppLocatorData *locatorData() const;
QList<ProjectInfo> projectInfos() const;
ProjectInfo projectInfo(ProjectExplorer::Project *project) const;
@@ -215,6 +217,7 @@ public:
static void addRefactoringEngine(RefactoringEngineType type,
RefactoringEngineInterface *refactoringEngine);
static void removeRefactoringEngine(RefactoringEngineType type);
+ static RefactoringEngineInterface *builtinRefactoringEngine();
void setLocatorFilter(std::unique_ptr<Core::ILocatorFilter> &&filter);
void setClassesFilter(std::unique_ptr<Core::ILocatorFilter> &&filter);
@@ -230,6 +233,14 @@ public:
Core::IFindFilter *symbolsFindFilter() const;
Core::ILocatorFilter *currentDocumentFilter() const;
+ /*
+ * try to find build system target that depends on the given file - if the file is no header
+ * try to find the corresponding header and use this instead to find the respective target
+ */
+ QSet<QString> dependingInternalTargets(const Utils::FilePath &file) const;
+
+ QSet<QString> internalTargets(const Utils::FilePath &filePath) const;
+
void renameIncludes(const QString &oldFileName, const QString &newFileName);
// for VcsBaseSubmitEditor
diff --git a/src/plugins/cpptools/cppmodelmanager_test.cpp b/src/plugins/cpptools/cppmodelmanager_test.cpp
index 2b77700cb8..c4a3637986 100644
--- a/src/plugins/cpptools/cppmodelmanager_test.cpp
+++ b/src/plugins/cpptools/cppmodelmanager_test.cpp
@@ -139,7 +139,7 @@ public:
bool readContents(QByteArray *contents)
{
Utils::FileReader fileReader;
- const bool isFetchOk = fileReader.fetch(m_filePath);
+ const bool isFetchOk = fileReader.fetch(Utils::FilePath::fromString(m_filePath));
if (isFetchOk) {
m_originalFileContents = fileReader.data();
if (contents)
diff --git a/src/plugins/cpptools/cpppointerdeclarationformatter_test.cpp b/src/plugins/cpptools/cpppointerdeclarationformatter_test.cpp
index bd2959b83c..6e8bf332e6 100644
--- a/src/plugins/cpptools/cpppointerdeclarationformatter_test.cpp
+++ b/src/plugins/cpptools/cpppointerdeclarationformatter_test.cpp
@@ -106,7 +106,9 @@ public:
QScopedPointer<TextEditor::BaseTextEditor> editor(
TextEditor::PlainTextEditorFactory::createPlainTextEditor());
QString error;
- editor->document()->open(&error, document->fileName(), document->fileName());
+ editor->document()->open(&error,
+ Utils::FilePath::fromString(document->fileName()),
+ Utils::FilePath::fromString(document->fileName()));
QVERIFY(error.isEmpty());
// Set cursor position
diff --git a/src/plugins/cpptools/cppprojectfilecategorizer.cpp b/src/plugins/cpptools/cppprojectfilecategorizer.cpp
index 036022bb43..683765d3c2 100644
--- a/src/plugins/cpptools/cppprojectfilecategorizer.cpp
+++ b/src/plugins/cpptools/cppprojectfilecategorizer.cpp
@@ -72,6 +72,8 @@ ProjectFiles ProjectFileCategorizer::classifyFiles(const QStringList &filePaths,
break;
case ProjectFile::CXXSource:
case ProjectFile::CXXHeader:
+ case ProjectFile::CudaSource:
+ case ProjectFile::OpenCLSource:
m_cxxSources += projectFile;
break;
case ProjectFile::ObjCXXSource:
@@ -86,7 +88,8 @@ ProjectFiles ProjectFileCategorizer::classifyFiles(const QStringList &filePaths,
case ProjectFile::ObjCHeader:
m_objcSources += projectFile;
break;
- default:
+ case ProjectFile::Unclassified:
+ case ProjectFile::Unsupported:
continue;
}
}
diff --git a/src/plugins/cpptools/cppprojectinfogenerator.cpp b/src/plugins/cpptools/cppprojectinfogenerator.cpp
index f5da863a33..cf3152163f 100644
--- a/src/plugins/cpptools/cppprojectinfogenerator.cpp
+++ b/src/plugins/cpptools/cppprojectinfogenerator.cpp
@@ -196,51 +196,10 @@ ProjectPart::Ptr ProjectInfoGenerator::createProjectPart(
ProjectPart::Ptr part(templateProjectPart->copy());
part->displayName = partName;
part->files = projectFiles;
- part->toolchainType = tcInfo.type;
- part->isMsvc2015Toolchain = tcInfo.isMsvc2015ToolChain;
- part->toolChainWordWidth = tcInfo.wordWidth == 64 ? ProjectPart::WordWidth64Bit
- : ProjectPart::WordWidth32Bit;
- part->toolChainInstallDir = tcInfo.installDir;
- part->toolChainTargetTriple = tcInfo.targetTriple;
- part->extraCodeModelFlags = tcInfo.extraCodeModelFlags;
- part->compilerFlags = flags.commandLineFlags;
part->warningFlags = flags.warningFlags;
- if (part->includedFiles.isEmpty()) {
- // The project manager did not provide the included files, so take
- // the ones we were able to detect from the toolchain's command line.
- part->includedFiles = flags.includedFiles;
- }
part->language = language;
- part->languageExtensions = flags.languageExtensions;
-
- // Toolchain macros and language version
- if (tcInfo.macroInspectionRunner) {
- auto macroInspectionReport = tcInfo.macroInspectionRunner(flags.commandLineFlags);
- part->toolChainMacros = macroInspectionReport.macros;
- part->languageVersion = macroInspectionReport.languageVersion;
- // No compiler set in kit.
- } else if (language == Language::C) {
- part->languageVersion = Utils::LanguageVersion::LatestC;
- } else {
- part->languageVersion = Utils::LanguageVersion::LatestCxx;
- }
-
- // Header paths
- if (tcInfo.headerPathsRunner) {
- const HeaderPaths builtInHeaderPaths
- = tcInfo.headerPathsRunner(flags.commandLineFlags,
- tcInfo.sysRootPath,
- tcInfo.targetTriple);
-
- HeaderPaths &headerPaths = part->headerPaths;
- for (const HeaderPath &header : builtInHeaderPaths) {
- const HeaderPath headerPath{header.path, header.type};
- if (!headerPaths.contains(headerPath))
- headerPaths.push_back(headerPath);
- }
- }
-
- part->languageExtensions |= languageExtensions;
+ part->languageExtensions = flags.languageExtensions | languageExtensions;
+ part->setupToolchainProperties(tcInfo, flags.commandLineFlags);
part->updateLanguageFeatures();
return part;
diff --git a/src/plugins/cpptools/cppprojectupdater.cpp b/src/plugins/cpptools/cppprojectupdater.cpp
index 567aabde5e..794fd7abe7 100644
--- a/src/plugins/cpptools/cppprojectupdater.cpp
+++ b/src/plugins/cpptools/cppprojectupdater.cpp
@@ -43,11 +43,7 @@ CppProjectUpdater::CppProjectUpdater()
&QFutureWatcher<ProjectInfo>::finished,
this,
&CppProjectUpdater::onProjectInfoGenerated);
-}
-
-CppProjectUpdater::~CppProjectUpdater()
-{
- cancelAndWaitForFinished();
+ m_futureSynchronizer.setCancelOnWait(true);
}
void CppProjectUpdater::update(const ProjectExplorer::ProjectUpdateInfo &projectUpdateInfo)
@@ -63,30 +59,21 @@ void CppProjectUpdater::update(const ProjectExplorer::ProjectUpdateInfo &project
this, &CppProjectUpdater::onToolChainRemoved);
// Run the project info generator in a worker thread and continue if that one is finished.
- m_generateFuture = Utils::runAsync([=](QFutureInterface<ProjectInfo> &futureInterface) {
+ auto generateFuture = Utils::runAsync([=](QFutureInterface<ProjectInfo> &futureInterface) {
ProjectUpdateInfo fullProjectUpdateInfo = projectUpdateInfo;
if (fullProjectUpdateInfo.rppGenerator)
fullProjectUpdateInfo.rawProjectParts = fullProjectUpdateInfo.rppGenerator();
Internal::ProjectInfoGenerator generator(futureInterface, fullProjectUpdateInfo);
futureInterface.reportResult(generator.generate());
});
- m_generateFutureWatcher.setFuture(m_generateFuture);
+ m_generateFutureWatcher.setFuture(generateFuture);
+ m_futureSynchronizer.addFuture(generateFuture);
}
void CppProjectUpdater::cancel()
{
m_generateFutureWatcher.setFuture({});
- m_generateFuture.cancel();
- m_updateFuture.cancel();
-}
-
-void CppProjectUpdater::cancelAndWaitForFinished()
-{
- cancel();
- if (m_generateFuture.isRunning())
- m_generateFuture.waitForFinished();
- if (m_updateFuture.isRunning())
- m_updateFuture.waitForFinished();
+ m_futureSynchronizer.cancelAllFutures();
}
void CppProjectUpdater::onToolChainRemoved(ProjectExplorer::ToolChain *t)
@@ -106,8 +93,9 @@ void CppProjectUpdater::onProjectInfoGenerated()
if (m_generateFutureWatcher.isCanceled() || m_generateFutureWatcher.future().resultCount() < 1)
return;
- m_updateFuture = CppModelManager::instance()->updateProjectInfo(
+ auto updateFuture = CppModelManager::instance()->updateProjectInfo(
m_generateFutureWatcher.result());
+ m_futureSynchronizer.addFuture(updateFuture);
}
CppProjectUpdaterFactory::CppProjectUpdaterFactory()
diff --git a/src/plugins/cpptools/cppprojectupdater.h b/src/plugins/cpptools/cppprojectupdater.h
index f3f85a8a14..6b994871ef 100644
--- a/src/plugins/cpptools/cppprojectupdater.h
+++ b/src/plugins/cpptools/cppprojectupdater.h
@@ -29,6 +29,8 @@
#include "cpptools_global.h"
#include "projectinfo.h"
+#include <utils/futuresynchronizer.h>
+
#include <QFutureWatcher>
namespace CppTools {
@@ -52,23 +54,19 @@ class CPPTOOLS_EXPORT CppProjectUpdater final : public QObject, public CppProjec
public:
CppProjectUpdater();
- ~CppProjectUpdater() override;
void update(const ProjectExplorer::ProjectUpdateInfo &projectUpdateInfo) override;
void cancel() override;
private:
- void cancelAndWaitForFinished();
-
void onToolChainRemoved(ProjectExplorer::ToolChain *);
void onProjectInfoGenerated();
private:
ProjectExplorer::ProjectUpdateInfo m_projectUpdateInfo;
- QFuture<ProjectInfo> m_generateFuture;
- QFuture<void> m_updateFuture;
QFutureWatcher<ProjectInfo> m_generateFutureWatcher;
+ Utils::FutureSynchronizer m_futureSynchronizer;
};
} // namespace CppTools
diff --git a/src/plugins/cpptools/cppsourceprocessor.cpp b/src/plugins/cpptools/cppsourceprocessor.cpp
index 7f232c1ad7..b9585f7aca 100644
--- a/src/plugins/cpptools/cppsourceprocessor.cpp
+++ b/src/plugins/cpptools/cppsourceprocessor.cpp
@@ -220,8 +220,11 @@ bool CppSourceProcessor::getFileContents(const QString &absoluteFilePath,
// Get from file
*revision = 0;
QString error;
- if (Utils::TextFileFormat::readFileUTF8(absoluteFilePath, m_defaultCodec, contents, &error)
- != Utils::TextFileFormat::ReadSuccess) {
+ if (Utils::TextFileFormat::readFileUTF8(Utils::FilePath::fromString(absoluteFilePath),
+ m_defaultCodec,
+ contents,
+ &error)
+ != Utils::TextFileFormat::ReadSuccess) {
qWarning("Error reading file \"%s\": \"%s\".", qPrintable(absoluteFilePath),
qPrintable(error));
return false;
diff --git a/src/plugins/cpptools/cpptoolstestcase.cpp b/src/plugins/cpptools/cpptoolstestcase.cpp
index d72101d802..8a714b7df7 100644
--- a/src/plugins/cpptools/cpptoolstestcase.cpp
+++ b/src/plugins/cpptools/cpptoolstestcase.cpp
@@ -243,7 +243,7 @@ bool TestCase::waitUntilProjectIsFullyOpened(Project *project, int timeOutInMs)
bool TestCase::writeFile(const QString &filePath, const QByteArray &contents)
{
- Utils::FileSaver saver(filePath);
+ Utils::FileSaver saver(Utils::FilePath::fromString(filePath));
if (!saver.write(contents) || !saver.finalize()) {
const QString warning = QLatin1String("Failed to write file to disk: ") + filePath;
QWARN(qPrintable(warning));
diff --git a/src/plugins/cpptools/cppvirtualfunctionproposalitem.cpp b/src/plugins/cpptools/cppvirtualfunctionproposalitem.cpp
index c0e1a1308e..dbdac77b7e 100644
--- a/src/plugins/cpptools/cppvirtualfunctionproposalitem.cpp
+++ b/src/plugins/cpptools/cppvirtualfunctionproposalitem.cpp
@@ -46,11 +46,7 @@ void VirtualFunctionProposalItem::apply(TextEditor::TextDocumentManipulatorInter
Core::EditorManager::OpenEditorFlags flags = Core::EditorManager::NoFlags;
if (m_openInSplit)
flags |= Core::EditorManager::OpenInOtherSplit;
- Core::EditorManager::openEditorAt(m_link.targetFileName,
- m_link.targetLine,
- m_link.targetColumn,
- CppEditor::Constants::CPPEDITOR_ID,
- flags);
+ Core::EditorManager::openEditorAt(m_link, CppEditor::Constants::CPPEDITOR_ID, flags);
}
} // namespace CppTools
diff --git a/src/plugins/cpptools/cursorineditor.h b/src/plugins/cpptools/cursorineditor.h
index b84633d9bc..8e9a4b70a1 100644
--- a/src/plugins/cpptools/cursorineditor.h
+++ b/src/plugins/cpptools/cursorineditor.h
@@ -31,24 +31,30 @@
#include <QTextCursor>
+namespace TextEditor { class TextDocument; }
+
namespace CppTools {
class CursorInEditor
{
public:
CursorInEditor(const QTextCursor &cursor, const Utils::FilePath &filePath,
- CppEditorWidgetInterface *editorWidget = nullptr)
+ CppEditorWidgetInterface *editorWidget = nullptr,
+ TextEditor::TextDocument *textDocument = nullptr)
: m_cursor(cursor)
, m_filePath(filePath)
, m_editorWidget(editorWidget)
+ , m_textDocument(textDocument)
{}
CppEditorWidgetInterface *editorWidget() const { return m_editorWidget; }
+ TextEditor::TextDocument *textDocument() const { return m_textDocument; }
const QTextCursor &cursor() const { return m_cursor; }
const Utils::FilePath &filePath() const { return m_filePath; }
private:
QTextCursor m_cursor;
Utils::FilePath m_filePath;
CppEditorWidgetInterface *m_editorWidget = nullptr;
+ TextEditor::TextDocument * const m_textDocument;
};
} // namespace CppTools
diff --git a/src/plugins/cpptools/projectpart.cpp b/src/plugins/cpptools/projectpart.cpp
index f88fefac82..d3d4668a81 100644
--- a/src/plugins/cpptools/projectpart.cpp
+++ b/src/plugins/cpptools/projectpart.cpp
@@ -31,6 +31,8 @@
#include <QDir>
#include <QTextStream>
+using namespace ProjectExplorer;
+
namespace CppTools {
void ProjectPart::updateLanguageFeatures()
@@ -53,6 +55,41 @@ void ProjectPart::updateLanguageFeatures()
}
}
+void ProjectPart::setupToolchainProperties(const ToolChainInfo &tcInfo, const QStringList &flags)
+{
+ toolchainType = tcInfo.type;
+ isMsvc2015Toolchain = tcInfo.isMsvc2015ToolChain;
+ toolChainWordWidth = tcInfo.wordWidth == 64 ? ProjectPart::WordWidth64Bit
+ : ProjectPart::WordWidth32Bit;
+ toolChainInstallDir = tcInfo.installDir;
+ toolChainTargetTriple = tcInfo.targetTriple;
+ extraCodeModelFlags = tcInfo.extraCodeModelFlags;
+ compilerFlags = flags;
+
+ // Toolchain macros and language version
+ if (tcInfo.macroInspectionRunner) {
+ const auto macroInspectionReport = tcInfo.macroInspectionRunner(compilerFlags);
+ toolChainMacros = macroInspectionReport.macros;
+ languageVersion = macroInspectionReport.languageVersion;
+ // No compiler set in kit.
+ } else if (language == Utils::Language::C) {
+ languageVersion = Utils::LanguageVersion::LatestC;
+ } else {
+ languageVersion = Utils::LanguageVersion::LatestCxx;
+ }
+
+ // Header paths
+ if (tcInfo.headerPathsRunner) {
+ const HeaderPaths builtInHeaderPaths
+ = tcInfo.headerPathsRunner(compilerFlags, tcInfo.sysRootPath, tcInfo.targetTriple);
+ for (const HeaderPath &header : builtInHeaderPaths) {
+ const HeaderPath headerPath{header.path, header.type};
+ if (!headerPaths.contains(headerPath))
+ headerPaths.push_back(headerPath);
+ }
+ }
+}
+
ProjectPart::Ptr ProjectPart::copy() const
{
return Ptr(new ProjectPart(*this));
diff --git a/src/plugins/cpptools/projectpart.h b/src/plugins/cpptools/projectpart.h
index 2f38563687..010a21a312 100644
--- a/src/plugins/cpptools/projectpart.h
+++ b/src/plugins/cpptools/projectpart.h
@@ -65,6 +65,8 @@ public:
Ptr copy() const;
void updateLanguageFeatures();
+ void setupToolchainProperties(const ProjectExplorer::ToolChainInfo &tcInfo,
+ const QStringList &flags);
static QByteArray readProjectConfigFile(const Ptr &projectPart);
diff --git a/src/plugins/cpptools/searchsymbols.cpp b/src/plugins/cpptools/searchsymbols.cpp
index 8f92d7a97b..b74ac0d8c3 100644
--- a/src/plugins/cpptools/searchsymbols.cpp
+++ b/src/plugins/cpptools/searchsymbols.cpp
@@ -49,6 +49,7 @@ SearchSymbols::SymbolTypes SearchSymbols::AllTypes =
SearchSymbols::SearchSymbols()
: symbolsToSearchFor(SymbolSearcher::Classes | SymbolSearcher::Functions | SymbolSearcher::Enums)
{
+ overview.showTemplateParameters = true;
}
void SearchSymbols::setSymbolsToSearchFor(const SymbolTypes &types)
diff --git a/src/plugins/cpptools/stringtable.cpp b/src/plugins/cpptools/stringtable.cpp
index 5122c3a8a9..331a56faa1 100644
--- a/src/plugins/cpptools/stringtable.cpp
+++ b/src/plugins/cpptools/stringtable.cpp
@@ -26,6 +26,7 @@
#include "stringtable.h"
#include <utils/qtcassert.h>
+#include <utils/runextensions.h>
#include <QDebug>
#include <QElapsedTimer>
@@ -48,21 +49,15 @@ class StringTablePrivate : public QObject
{
public:
StringTablePrivate();
+ ~StringTablePrivate() override { cancelAndWait(); }
+ void cancelAndWait();
QString insert(const QString &string);
- void startGC() { QThreadPool::globalInstance()->start(&m_gcRunner); }
- void GC();
+ void startGC();
+ void GC(QFutureInterface<void> &futureInterface);
- class GCRunner: public QRunnable {
- StringTablePrivate &m_stringTable;
-
- public:
- explicit GCRunner(StringTablePrivate &stringTable): m_stringTable(stringTable) {}
- void run() override { m_stringTable.GC(); }
- } m_gcRunner;
-
- mutable QMutex m_lock;
- QAtomicInt m_stopGCRequested{false};
+ QFuture<void> m_future;
+ QMutex m_lock;
QSet<QString> m_strings;
QTimer m_gcCountDown;
};
@@ -70,12 +65,9 @@ public:
static StringTablePrivate *m_instance = nullptr;
StringTablePrivate::StringTablePrivate()
- : m_gcRunner(*this)
{
m_strings.reserve(1000);
- m_gcRunner.setAutoDelete(false);
-
m_gcCountDown.setObjectName(QLatin1String("StringTable::m_gcCountDown"));
m_gcCountDown.setSingleShot(true);
m_gcCountDown.setInterval(GCTimeOut);
@@ -87,6 +79,14 @@ QString StringTable::insert(const QString &string)
return m_instance->insert(string);
}
+void StringTablePrivate::cancelAndWait()
+{
+ if (!m_future.isRunning())
+ return;
+ m_future.cancel();
+ m_future.waitForFinished();
+}
+
QString StringTablePrivate::insert(const QString &string)
{
if (string.isEmpty())
@@ -98,12 +98,21 @@ QString StringTablePrivate::insert(const QString &string)
#endif
#endif
- m_stopGCRequested.fetchAndStoreAcquire(true);
+ QMutexLocker locker(&m_lock);
+ // From this point of time any possible new call to startGC() will be held until
+ // we finish this function. So we are sure that after canceling the running GC() method now,
+ // no new call to GC() will be executed until we finish this function.
+ cancelAndWait();
+ // A possibly running GC() thread already finished, so it's safe to modify m_strings from
+ // now until we unlock the mutex.
+ return *m_strings.insert(string);
+}
+void StringTablePrivate::startGC()
+{
QMutexLocker locker(&m_lock);
- QString result = *m_strings.insert(string);
- m_stopGCRequested.fetchAndStoreRelease(false);
- return result;
+ cancelAndWait();
+ m_future = Utils::runAsync(&StringTablePrivate::GC, this);
}
void StringTable::scheduleGC()
@@ -134,10 +143,8 @@ static inline bool isQStringInUse(const QString &string)
#endif
}
-void StringTablePrivate::GC()
+void StringTablePrivate::GC(QFutureInterface<void> &futureInterface)
{
- QMutexLocker locker(&m_lock);
-
int initialSize = 0;
QElapsedTimer timer;
if (DebugStringTable) {
@@ -147,7 +154,7 @@ void StringTablePrivate::GC()
// Collect all QStrings which have refcount 1. (One reference in m_strings and nowhere else.)
for (QSet<QString>::iterator i = m_strings.begin(); i != m_strings.end();) {
- if (m_stopGCRequested.testAndSetRelease(true, false))
+ if (futureInterface.isCanceled())
return;
if (!isQStringInUse(*i))
diff --git a/src/plugins/cvs/CMakeLists.txt b/src/plugins/cvs/CMakeLists.txt
index 2498cc9e94..2612f9a795 100644
--- a/src/plugins/cvs/CMakeLists.txt
+++ b/src/plugins/cvs/CMakeLists.txt
@@ -7,5 +7,4 @@ add_qtc_plugin(CVS
cvssettings.cpp cvssettings.h
cvssubmiteditor.cpp cvssubmiteditor.h
cvsutils.cpp cvsutils.h
- settingspage.cpp settingspage.h settingspage.ui
)
diff --git a/src/plugins/cvs/cvs.pro b/src/plugins/cvs/cvs.pro
index c7b84d117d..03f59129ab 100644
--- a/src/plugins/cvs/cvs.pro
+++ b/src/plugins/cvs/cvs.pro
@@ -2,7 +2,6 @@ include(../../qtcreatorplugin.pri)
HEADERS += annotationhighlighter.h \
cvsplugin.h \
- settingspage.h \
cvseditor.h \
cvssubmiteditor.h \
cvssettings.h \
@@ -10,10 +9,7 @@ HEADERS += annotationhighlighter.h \
SOURCES += annotationhighlighter.cpp \
cvsplugin.cpp \
- settingspage.cpp \
cvseditor.cpp \
cvssubmiteditor.cpp \
cvssettings.cpp \
cvsutils.cpp
-
-FORMS += settingspage.ui
diff --git a/src/plugins/cvs/cvs.qbs b/src/plugins/cvs/cvs.qbs
index f86c0144a6..cbc1dbaa0f 100644
--- a/src/plugins/cvs/cvs.qbs
+++ b/src/plugins/cvs/cvs.qbs
@@ -23,8 +23,5 @@ QtcPlugin {
"cvssubmiteditor.h",
"cvsutils.cpp",
"cvsutils.h",
- "settingspage.cpp",
- "settingspage.h",
- "settingspage.ui",
]
}
diff --git a/src/plugins/cvs/cvsplugin.cpp b/src/plugins/cvs/cvsplugin.cpp
index 8361111bda..445b9378fa 100644
--- a/src/plugins/cvs/cvsplugin.cpp
+++ b/src/plugins/cvs/cvsplugin.cpp
@@ -24,7 +24,6 @@
****************************************************************************/
#include "cvsplugin.h"
-#include "settingspage.h"
#include "cvseditor.h"
#include "cvssubmiteditor.h"
#include "cvsutils.h"
@@ -43,9 +42,9 @@
#include <texteditor/textdocument.h>
-#include <utils/synchronousprocess.h>
#include <utils/parameteraction.h>
#include <utils/qtcassert.h>
+#include <utils/qtcprocess.h>
#include <utils/stringutils.h>
#include <coreplugin/icore.h>
@@ -170,26 +169,25 @@ static inline bool messageBoxQuestion(const QString &title, const QString &quest
class CvsDiffConfig : public VcsBaseEditorConfig
{
public:
- CvsDiffConfig(VcsBaseClientSettings &settings, QToolBar *toolBar) :
+ CvsDiffConfig(CvsSettings &settings, QToolBar *toolBar) :
VcsBaseEditorConfig(toolBar),
m_settings(settings)
{
- mapSetting(addToggleButton(QLatin1String("-w"), CvsPlugin::tr("Ignore Whitespace")),
- settings.boolPointer(CvsSettings::diffIgnoreWhiteSpaceKey));
- mapSetting(addToggleButton(QLatin1String("-B"), CvsPlugin::tr("Ignore Blank Lines")),
- settings.boolPointer(CvsSettings::diffIgnoreBlankLinesKey));
+ mapSetting(addToggleButton("-w", CvsPlugin::tr("Ignore Whitespace")),
+ &settings.diffIgnoreWhiteSpace);
+ mapSetting(addToggleButton("-B", CvsPlugin::tr("Ignore Blank Lines")),
+ &settings.diffIgnoreBlankLines);
}
QStringList arguments() const override
{
- QStringList args;
- args = m_settings.stringValue(CvsSettings::diffOptionsKey).split(' ', SkipEmptyParts);
+ QStringList args = m_settings.diffOptions.value().split(' ', SkipEmptyParts);
args += VcsBaseEditorConfig::arguments();
return args;
}
private:
- VcsBaseClientSettings &m_settings;
+ CvsSettings &m_settings;
};
class CvsClient : public VcsBaseClient
@@ -206,11 +204,11 @@ public:
{
if (cmd == DiffCommand) {
return [](int code) {
- return (code < 0 || code > 2) ? SynchronousProcessResponse::FinishedError
- : SynchronousProcessResponse::Finished;
+ return (code < 0 || code > 2) ? QtcProcess::FinishedError
+ : QtcProcess::Finished;
};
}
- return Utils::defaultExitCodeInterpreter;
+ return {};
}
Utils::Id vcsEditorKind(VcsCommandTag cmd) const override
@@ -366,7 +364,7 @@ private:
QAction *m_menuAction = nullptr;
bool m_submitActionTriggered = false;
- CvsSettingsPage m_settingsPage{[this] { configurationChanged(); }, &m_settings};
+ CvsSettingsPage m_settingsPage{&m_settings};
public:
VcsSubmitEditorFactory submitEditorFactory {
@@ -413,7 +411,7 @@ bool CvsPluginPrivate::isVcsFileOrDirectory(const Utils::FilePath &fileName) con
bool CvsPluginPrivate::isConfigured() const
{
- const Utils::FilePath binary = m_settings.binaryPath();
+ const Utils::FilePath binary = m_settings.binaryPath.filePath();
if (binary.isEmpty())
return false;
QFileInfo fi = binary.toFileInfo();
@@ -489,9 +487,9 @@ Core::ShellCommand *CvsPluginPrivate::createInitialCheckoutCommand(const QString
args << QLatin1String("checkout") << url << extraArgs;
auto command = new VcsBase::VcsCommand(baseDirectory.toString(),
- QProcessEnvironment::systemEnvironment());
+ Environment::systemEnvironment());
command->setDisplayName(tr("CVS Checkout"));
- command->addJob({m_settings.binaryPath(), m_settings.addOptions(args)}, -1);
+ command->addJob({m_settings.binaryPath.filePath(), m_settings.addOptions(args)}, -1);
return command;
}
@@ -548,6 +546,7 @@ CvsPluginPrivate::CvsPluginPrivate()
const QString prefix = QLatin1String("cvs");
m_commandLocator = new CommandLocator("CVS", prefix, prefix, this);
+ m_commandLocator->setDescription(tr("Triggers a CVS version control operation."));
// Register actions
ActionContainer *toolsContainer = ActionManager::actionContainer(M_TOOLS);
@@ -737,6 +736,8 @@ CvsPluginPrivate::CvsPluginPrivate()
connect(m_revertRepositoryAction, &QAction::triggered, this, &CvsPluginPrivate::revertAll);
cvsMenu->addAction(command);
m_commandLocator->appendCommand(command);
+
+ connect(&m_settings, &AspectContainer::applied, this, &IVersionControl::configurationChanged);
}
void CvsPluginPrivate::vcsDescribe(const QString &source, const QString &changeNr)
@@ -766,8 +767,10 @@ bool CvsPluginPrivate::submitEditorAboutToClose()
// Prompt user. Force a prompt unless submit was actually invoked (that
// is, the editor was closed or shutdown).
const VcsBaseSubmitEditor::PromptSubmitResult answer = editor->promptSubmit(
- this, m_settings.boolPointer(CvsSettings::promptOnSubmitKey),
- !m_submitActionTriggered);
+ this, nullptr,
+ !m_submitActionTriggered,
+ true,
+ &m_settings.promptOnSubmit);
m_submitActionTriggered = false;
switch (answer) {
case VcsBaseSubmitEditor::SubmitCanceled:
@@ -873,7 +876,7 @@ void CvsPluginPrivate::revertAll()
QStringList args;
args << QLatin1String("update") << QLatin1String("-C") << state.topLevel();
const CvsResponse revertResponse =
- runCvs(state.topLevel(), args, m_settings.vcsTimeoutS(),
+ runCvs(state.topLevel(), args, m_settings.timeout.value(),
VcsCommand::SshPasswordPrompt | VcsCommand::ShowStdOut);
if (revertResponse.result == CvsResponse::Ok)
emit repositoryChanged(state.topLevel());
@@ -889,7 +892,7 @@ void CvsPluginPrivate::revertCurrentFile()
QStringList args;
args << QLatin1String("diff") << state.relativeCurrentFile();
const CvsResponse diffResponse =
- runCvs(state.currentFileTopLevel(), args, m_settings.vcsTimeoutS(), 0);
+ runCvs(state.currentFileTopLevel(), args, m_settings.timeout.value(), 0);
switch (diffResponse.result) {
case CvsResponse::Ok:
return; // Not modified, diff exit code 0
@@ -911,7 +914,7 @@ void CvsPluginPrivate::revertCurrentFile()
args.clear();
args << QLatin1String("update") << QLatin1String("-C") << state.relativeCurrentFile();
const CvsResponse revertResponse =
- runCvs(state.currentFileTopLevel(), args, m_settings.vcsTimeoutS(),
+ runCvs(state.currentFileTopLevel(), args, m_settings.timeout.value(),
VcsCommand::SshPasswordPrompt | VcsCommand::ShowStdOut);
if (revertResponse.result == CvsResponse::Ok)
emit filesChanged(QStringList(state.currentFile()));
@@ -976,7 +979,7 @@ void CvsPluginPrivate::startCommit(const QString &workingDir, const QString &fil
// where we are, so, have stdout/stderr channels merged.
QStringList args = QStringList(QLatin1String("status"));
const CvsResponse response =
- runCvs(workingDir, args, m_settings.vcsTimeoutS(), VcsCommand::MergeOutputChannels);
+ runCvs(workingDir, args, m_settings.timeout.value(), VcsCommand::MergeOutputChannels);
if (response.result != CvsResponse::Ok)
return;
// Get list of added/modified/deleted files and purge out undesired ones
@@ -1007,7 +1010,7 @@ void CvsPluginPrivate::startCommit(const QString &workingDir, const QString &fil
VcsOutputWindow::appendError(saver.errorString());
return;
}
- m_commitMessageFileName = saver.fileName();
+ m_commitMessageFileName = saver.filePath().toString();
// Create a submit editor and set file list
CvsSubmitEditor *editor = openCVSSubmitEditor(m_commitMessageFileName);
setSubmitEditor(editor);
@@ -1022,7 +1025,7 @@ bool CvsPluginPrivate::commit(const QString &messageFile,
args << QLatin1String("-F") << messageFile;
args.append(fileList);
const CvsResponse response =
- runCvs(m_commitRepository, args, 10 * m_settings.vcsTimeoutS(),
+ runCvs(m_commitRepository, args, 10 * m_settings.timeout.value(),
VcsCommand::SshPasswordPrompt | VcsCommand::ShowStdOut);
return response.result == CvsResponse::Ok ;
}
@@ -1060,7 +1063,7 @@ void CvsPluginPrivate::filelog(const QString &workingDir,
args << QLatin1String("log");
args.append(file);
const CvsResponse response =
- runCvs(workingDir, args, m_settings.vcsTimeoutS(),
+ runCvs(workingDir, args, m_settings.timeout.value(),
VcsCommand::SshPasswordPrompt, codec);
if (response.result != CvsResponse::Ok)
return;
@@ -1101,7 +1104,7 @@ bool CvsPluginPrivate::update(const QString &topLevel, const QString &file)
if (!file.isEmpty())
args.append(file);
const CvsResponse response =
- runCvs(topLevel, args, 10 * m_settings.vcsTimeoutS(),
+ runCvs(topLevel, args, 10 * m_settings.timeout.value(),
VcsCommand::SshPasswordPrompt | VcsCommand::ShowStdOut);
const bool ok = response.result == CvsResponse::Ok;
if (ok)
@@ -1148,7 +1151,7 @@ bool CvsPluginPrivate::edit(const QString &topLevel, const QStringList &files)
QStringList args(QLatin1String("edit"));
args.append(files);
const CvsResponse response =
- runCvs(topLevel, args, m_settings.vcsTimeoutS(),
+ runCvs(topLevel, args, m_settings.timeout.value(),
VcsCommand::ShowStdOut | VcsCommand::SshPasswordPrompt);
return response.result == CvsResponse::Ok;
}
@@ -1160,7 +1163,7 @@ bool CvsPluginPrivate::diffCheckModified(const QString &topLevel, const QStringL
QStringList args(QLatin1String("-q"));
args << QLatin1String("diff");
args.append(files);
- const CvsResponse response = runCvs(topLevel, args, m_settings.vcsTimeoutS(), 0);
+ const CvsResponse response = runCvs(topLevel, args, m_settings.timeout.value(), 0);
if (response.result == CvsResponse::OtherError)
return false;
*modified = response.result == CvsResponse::NonNullExitCode;
@@ -1188,7 +1191,7 @@ bool CvsPluginPrivate::unedit(const QString &topLevel, const QStringList &files)
args.append(QLatin1String("-y"));
args.append(files);
const CvsResponse response =
- runCvs(topLevel, args, m_settings.vcsTimeoutS(),
+ runCvs(topLevel, args, m_settings.timeout.value(),
VcsCommand::ShowStdOut | VcsCommand::SshPasswordPrompt);
return response.result == CvsResponse::Ok;
}
@@ -1207,7 +1210,7 @@ void CvsPluginPrivate::annotate(const QString &workingDir, const QString &file,
args << QLatin1String("-r") << revision;
args << file;
const CvsResponse response =
- runCvs(workingDir, args, m_settings.vcsTimeoutS(),
+ runCvs(workingDir, args, m_settings.timeout.value(),
VcsCommand::SshPasswordPrompt, codec);
if (response.result != CvsResponse::Ok)
return;
@@ -1236,7 +1239,7 @@ bool CvsPluginPrivate::status(const QString &topLevel, const QString &file, cons
if (!file.isEmpty())
args.append(file);
const CvsResponse response =
- runCvs(topLevel, args, m_settings.vcsTimeoutS(), 0);
+ runCvs(topLevel, args, m_settings.timeout.value(), 0);
const bool ok = response.result == CvsResponse::Ok;
if (ok)
showOutputInEditor(title, response.stdOut, commandLogEditorParameters.id, topLevel, nullptr);
@@ -1311,7 +1314,7 @@ bool CvsPluginPrivate::describe(const QString &toplevel, const QString &file, co
QStringList args;
args << QLatin1String("log") << (QLatin1String("-r") + changeNr) << file;
const CvsResponse logResponse =
- runCvs(toplevel, args, m_settings.vcsTimeoutS(), VcsCommand::SshPasswordPrompt);
+ runCvs(toplevel, args, m_settings.timeout.value(), VcsCommand::SshPasswordPrompt);
if (logResponse.result != CvsResponse::Ok) {
*errorMessage = logResponse.message;
return false;
@@ -1321,7 +1324,7 @@ bool CvsPluginPrivate::describe(const QString &toplevel, const QString &file, co
*errorMessage = tr("Parsing of the log output failed.");
return false;
}
- if (m_settings.boolValue(CvsSettings::describeByCommitIdKey)) {
+ if (m_settings.describeByCommitId.value()) {
// Run a log command over the repo, filtering by the commit date
// and commit id, collecting all files touched by the commit.
const QString commitId = fileLog.front().revisions.front().commitId;
@@ -1333,7 +1336,7 @@ bool CvsPluginPrivate::describe(const QString &toplevel, const QString &file, co
args << QLatin1String("log") << QLatin1String("-d") << (dateS + QLatin1Char('<') + nextDayS);
const CvsResponse repoLogResponse =
- runCvs(toplevel, args, 10 * m_settings.vcsTimeoutS(), VcsCommand::SshPasswordPrompt);
+ runCvs(toplevel, args, 10 * m_settings.timeout.value(), VcsCommand::SshPasswordPrompt);
if (repoLogResponse.result != CvsResponse::Ok) {
*errorMessage = repoLogResponse.message;
return false;
@@ -1370,7 +1373,7 @@ bool CvsPluginPrivate::describe(const QString &repositoryPath,
QStringList args(QLatin1String("log"));
args << (QLatin1String("-r") + it->revisions.front().revision) << it->file;
const CvsResponse logResponse =
- runCvs(repositoryPath, args, m_settings.vcsTimeoutS(), VcsCommand::SshPasswordPrompt);
+ runCvs(repositoryPath, args, m_settings.timeout.value(), VcsCommand::SshPasswordPrompt);
if (logResponse.result != CvsResponse::Ok) {
*errorMessage = logResponse.message;
return false;
@@ -1383,11 +1386,11 @@ bool CvsPluginPrivate::describe(const QString &repositoryPath,
if (!isFirstRevision(revision)) {
const QString previousRev = previousRevision(revision);
QStringList args(QLatin1String("diff"));
- args << m_settings.stringValue(CvsSettings::diffOptionsKey)
+ args << m_settings.diffOptions.value()
<< QLatin1String("-r") << previousRev << QLatin1String("-r")
<< it->revisions.front().revision << it->file;
const CvsResponse diffResponse =
- runCvs(repositoryPath, args, m_settings.vcsTimeoutS(), 0, codec);
+ runCvs(repositoryPath, args, m_settings.timeout.value(), 0, codec);
switch (diffResponse.result) {
case CvsResponse::Ok:
case CvsResponse::NonNullExitCode: // Diff exit code != 0
@@ -1435,7 +1438,7 @@ CvsResponse CvsPluginPrivate::runCvs(const QString &workingDirectory,
unsigned flags,
QTextCodec *outputCodec) const
{
- const FilePath executable = m_settings.binaryPath();
+ const FilePath executable = m_settings.binaryPath.filePath();
CvsResponse response;
if (executable.isEmpty()) {
response.result = CvsResponse::OtherError;
@@ -1443,28 +1446,32 @@ CvsResponse CvsPluginPrivate::runCvs(const QString &workingDirectory,
return response;
}
// Run, connect stderr to the output window
- const SynchronousProcessResponse sp_resp =
- runVcs(workingDirectory, {executable, m_settings.addOptions(arguments)},
- timeOutS, flags, outputCodec);
+ SynchronousProcess proc;
+ proc.setTimeoutS(timeOutS);
+
+ VcsCommand command(workingDirectory, Environment::systemEnvironment());
+ command.addFlags(flags);
+ command.setCodec(outputCodec);
+ command.runCommand(proc, {executable, m_settings.addOptions(arguments)});
response.result = CvsResponse::OtherError;
- response.stdErr = sp_resp.stdErr();
- response.stdOut = sp_resp.stdOut();
- switch (sp_resp.result) {
- case SynchronousProcessResponse::Finished:
+ response.stdErr = proc.stdErr();
+ response.stdOut = proc.stdOut();
+ switch (proc.result()) {
+ case QtcProcess::Finished:
response.result = CvsResponse::Ok;
break;
- case SynchronousProcessResponse::FinishedError:
+ case QtcProcess::FinishedError:
response.result = CvsResponse::NonNullExitCode;
break;
- case SynchronousProcessResponse::TerminatedAbnormally:
- case SynchronousProcessResponse::StartFailed:
- case SynchronousProcessResponse::Hang:
+ case QtcProcess::TerminatedAbnormally:
+ case QtcProcess::StartFailed:
+ case QtcProcess::Hang:
break;
}
if (response.result != CvsResponse::Ok)
- response.message = sp_resp.exitMessage(executable.toString(), timeOutS);
+ response.message = proc.exitMessage();
return response;
}
@@ -1494,7 +1501,7 @@ bool CvsPluginPrivate::vcsAdd(const QString &workingDir, const QString &rawFileN
QStringList args;
args << QLatin1String("add") << rawFileName;
const CvsResponse response =
- runCvs(workingDir, args, m_settings.vcsTimeoutS(),
+ runCvs(workingDir, args, m_settings.timeout.value(),
VcsCommand::SshPasswordPrompt | VcsCommand::ShowStdOut);
return response.result == CvsResponse::Ok;
}
@@ -1504,7 +1511,7 @@ bool CvsPluginPrivate::vcsDelete(const QString &workingDir, const QString &rawFi
QStringList args;
args << QLatin1String("remove") << QLatin1String("-f") << rawFileName;
const CvsResponse response =
- runCvs(workingDir, args, m_settings.vcsTimeoutS(),
+ runCvs(workingDir, args, m_settings.timeout.value(),
VcsCommand::SshPasswordPrompt | VcsCommand::ShowStdOut);
return response.result == CvsResponse::Ok;
}
@@ -1545,7 +1552,7 @@ bool CvsPluginPrivate::managesFile(const QString &workingDirectory, const QStrin
QStringList args;
args << QLatin1String("status") << fileName;
const CvsResponse response =
- runCvs(workingDirectory, args, m_settings.vcsTimeoutS(), VcsCommand::SshPasswordPrompt);
+ runCvs(workingDirectory, args, m_settings.timeout.value(), VcsCommand::SshPasswordPrompt);
if (response.result != CvsResponse::Ok)
return false;
return !response.stdOut.contains(QLatin1String("Status: Unknown"));
diff --git a/src/plugins/cvs/cvssettings.cpp b/src/plugins/cvs/cvssettings.cpp
index 2f3c2897f0..7ec116d79b 100644
--- a/src/plugins/cvs/cvssettings.cpp
+++ b/src/plugins/cvs/cvssettings.cpp
@@ -25,40 +25,61 @@
#include "cvssettings.h"
-#include <utils/environment.h>
-#include <utils/hostosinfo.h>
+#include <coreplugin/icore.h>
-#include <QSettings>
-#include <QTextStream>
+#include <utils/layoutbuilder.h>
+#include <utils/pathchooser.h>
+
+#include <vcsbase/vcsbaseconstants.h>
+
+using namespace Utils;
namespace Cvs {
namespace Internal {
-const QLatin1String CvsSettings::cvsRootKey("Root");
-const QLatin1String CvsSettings::diffOptionsKey("DiffOptions");
-const QLatin1String CvsSettings::describeByCommitIdKey("DescribeByCommitId");
-const QLatin1String CvsSettings::diffIgnoreWhiteSpaceKey("DiffIgnoreWhiteSpace");
-const QLatin1String CvsSettings::diffIgnoreBlankLinesKey("DiffIgnoreBlankLines");
+// CvsSettings
CvsSettings::CvsSettings()
{
- setSettingsGroup(QLatin1String("CVS"));
- declareKey(binaryPathKey, QLatin1String("cvs" QTC_HOST_EXE_SUFFIX));
- declareKey(cvsRootKey, QString());
- declareKey(diffOptionsKey, QLatin1String("-du"));
- declareKey(describeByCommitIdKey, true);
- declareKey(diffIgnoreWhiteSpaceKey, false);
- declareKey(diffIgnoreBlankLinesKey, false);
-}
+ setSettingsGroup("CVS");
-int CvsSettings::timeOutMs() const
-{
- return 1000 * intValue(timeoutKey);
+ registerAspect(&binaryPath);
+ binaryPath.setDefaultValue("cvs" QTC_HOST_EXE_SUFFIX);
+ binaryPath.setDisplayStyle(StringAspect::PathChooserDisplay);
+ binaryPath.setExpectedKind(PathChooser::ExistingCommand);
+ binaryPath.setHistoryCompleter(QLatin1String("Cvs.Command.History"));
+ binaryPath.setDisplayName(tr("CVS Command"));
+ binaryPath.setLabelText(tr("CVS command:"));
+
+ registerAspect(&cvsRoot);
+ cvsRoot.setDisplayStyle(StringAspect::LineEditDisplay);
+ cvsRoot.setSettingsKey("Root");
+ cvsRoot.setLabelText(tr("CVS root:"));
+
+ registerAspect(&diffOptions);
+ diffOptions.setDisplayStyle(StringAspect::LineEditDisplay);
+ diffOptions.setSettingsKey("DiffOptions");
+ diffOptions.setDefaultValue("-du");
+ diffOptions.setLabelText("Diff options:");
+
+ registerAspect(&describeByCommitId);
+ describeByCommitId.setSettingsKey("DescribeByCommitId");
+ describeByCommitId.setDefaultValue(true);
+ describeByCommitId.setLabelText(tr("Describe all files matching commit id"));
+ describeByCommitId.setToolTip(tr("When checked, all files touched by a commit will be "
+ "displayed when clicking on a revision number in the annotation view "
+ "(retrieved via commit ID). Otherwise, only the respective file will be displayed."));
+
+ registerAspect(&diffIgnoreWhiteSpace);
+ diffIgnoreWhiteSpace.setSettingsKey("DiffIgnoreWhiteSpace");
+
+ registerAspect(&diffIgnoreBlankLines);
+ diffIgnoreBlankLines.setSettingsKey("DiffIgnoreBlankLines");
}
QStringList CvsSettings::addOptions(const QStringList &args) const
{
- const QString cvsRoot = stringValue(cvsRootKey);
+ const QString cvsRoot = this->cvsRoot.value();
if (cvsRoot.isEmpty())
return args;
@@ -69,5 +90,38 @@ QStringList CvsSettings::addOptions(const QStringList &args) const
return rc;
}
-} // namespace Internal
-} // namespace Cvs
+CvsSettingsPage::CvsSettingsPage(CvsSettings *settings)
+{
+ setId(VcsBase::Constants::VCS_ID_CVS);
+ setDisplayName(CvsSettings::tr("CVS"));
+ setCategory(VcsBase::Constants::VCS_SETTINGS_CATEGORY);
+ setSettings(settings);
+
+ setLayouter([settings](QWidget *widget) {
+ CvsSettings &s = *settings;
+ using namespace Layouting;
+
+ Column {
+ Group {
+ Title(CvsSettings::tr("Configuration")),
+ Form {
+ s.binaryPath,
+ s.cvsRoot
+ }
+ },
+ Group {
+ Title(CvsSettings::tr("Miscellaneous")),
+ Form {
+ s.timeout,
+ s.diffOptions,
+ },
+ s.promptOnSubmit,
+ s.describeByCommitId,
+ },
+ Stretch()
+ }.attachTo(widget);
+ });
+}
+
+} // Internal
+} // Cvs
diff --git a/src/plugins/cvs/cvssettings.h b/src/plugins/cvs/cvssettings.h
index 1294e33bf2..8e811db891 100644
--- a/src/plugins/cvs/cvssettings.h
+++ b/src/plugins/cvs/cvssettings.h
@@ -25,26 +25,34 @@
#pragma once
+#include <coreplugin/dialogs/ioptionspage.h>
+
#include <vcsbase/vcsbaseclientsettings.h>
namespace Cvs {
namespace Internal {
-class CvsSettings : public VcsBase::VcsBaseClientSettings
+class CvsSettings : public VcsBase::VcsBaseSettings
{
+ Q_DECLARE_TR_FUNCTIONS(Cvs::Internal::SettingsPage)
+
public:
- static const QLatin1String cvsRootKey;
- static const QLatin1String diffOptionsKey;
- static const QLatin1String describeByCommitIdKey;
- static const QLatin1String diffIgnoreWhiteSpaceKey;
- static const QLatin1String diffIgnoreBlankLinesKey;
+ Utils::StringAspect cvsRoot;
+ Utils::StringAspect diffOptions;
+ Utils::BoolAspect diffIgnoreWhiteSpace;
+ Utils::BoolAspect diffIgnoreBlankLines;
+ Utils::BoolAspect describeByCommitId;
CvsSettings();
- int timeOutMs() const;
-
QStringList addOptions(const QStringList &args) const;
};
+class CvsSettingsPage final : public Core::IOptionsPage
+{
+public:
+ explicit CvsSettingsPage(CvsSettings *settings);
+};
+
} // namespace Internal
} // namespace Cvs
diff --git a/src/plugins/cvs/settingspage.cpp b/src/plugins/cvs/settingspage.cpp
deleted file mode 100644
index 82f9cad886..0000000000
--- a/src/plugins/cvs/settingspage.cpp
+++ /dev/null
@@ -1,101 +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 "settingspage.h"
-
-#include "cvssettings.h"
-#include "ui_settingspage.h"
-
-#include <coreplugin/icore.h>
-#include <vcsbase/vcsbaseconstants.h>
-#include <utils/pathchooser.h>
-
-#include <QCoreApplication>
-
-using namespace Utils;
-using namespace VcsBase;
-
-namespace Cvs {
-namespace Internal {
-
-class CvsSettingsPageWidget final : public Core::IOptionsPageWidget
-{
- Q_DECLARE_TR_FUNCTIONS(Cvs::Internal::SettingsPageWidget)
-
-public:
- CvsSettingsPageWidget(const std::function<void()> & onApply, CvsSettings *settings);
-
- void apply() final;
-
-private:
- Ui::SettingsPage m_ui;
- std::function<void()> m_onApply;
- CvsSettings *m_settings;
-};
-
-CvsSettingsPageWidget::CvsSettingsPageWidget(const std::function<void()> &onApply, CvsSettings *settings)
- : m_onApply(onApply), m_settings(settings)
-{
- m_ui.setupUi(this);
- m_ui.commandPathChooser->setExpectedKind(PathChooser::ExistingCommand);
- m_ui.commandPathChooser->setHistoryCompleter(QLatin1String("Cvs.Command.History"));
- m_ui.commandPathChooser->setPromptDialogTitle(tr("CVS Command"));
-
- const VcsBaseClientSettings &s = *settings;
- m_ui.commandPathChooser->setFilePath(s.binaryPath());
- m_ui.rootLineEdit->setText(s.stringValue(CvsSettings::cvsRootKey));
- m_ui.diffOptionsLineEdit->setText(s.stringValue(CvsSettings::diffOptionsKey));
- m_ui.timeOutSpinBox->setValue(s.intValue(CvsSettings::timeoutKey));
- m_ui.promptToSubmitCheckBox->setChecked(s.boolValue(CvsSettings::promptOnSubmitKey));
- m_ui.describeByCommitIdCheckBox->setChecked(s.boolValue(CvsSettings::describeByCommitIdKey));
-}
-
-void CvsSettingsPageWidget::apply()
-{
- CvsSettings rc = *m_settings;
- rc.setValue(CvsSettings::binaryPathKey, m_ui.commandPathChooser->rawPath());
- rc.setValue(CvsSettings::cvsRootKey, m_ui.rootLineEdit->text());
- rc.setValue(CvsSettings::diffOptionsKey, m_ui.diffOptionsLineEdit->text());
- rc.setValue(CvsSettings::timeoutKey, m_ui.timeOutSpinBox->value());
- rc.setValue(CvsSettings::promptOnSubmitKey, m_ui.promptToSubmitCheckBox->isChecked());
- rc.setValue(CvsSettings::describeByCommitIdKey, m_ui.describeByCommitIdCheckBox->isChecked());
-
- if (rc == *m_settings)
- return;
-
- *m_settings = rc;
- m_onApply();
-}
-
-CvsSettingsPage::CvsSettingsPage(const std::function<void()> &onApply, CvsSettings *settings)
-{
- setId(VcsBase::Constants::VCS_ID_CVS);
- setDisplayName(CvsSettingsPageWidget::tr("CVS"));
- setCategory(VcsBase::Constants::VCS_SETTINGS_CATEGORY);
- setWidgetCreator([onApply, settings] { return new CvsSettingsPageWidget(onApply, settings); });
-}
-
-} // Internal
-} // Cvs
diff --git a/src/plugins/cvs/settingspage.ui b/src/plugins/cvs/settingspage.ui
deleted file mode 100644
index 08395ca627..0000000000
--- a/src/plugins/cvs/settingspage.ui
+++ /dev/null
@@ -1,144 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<ui version="4.0">
- <class>Cvs::Internal::SettingsPage</class>
- <widget class="QWidget" name="Cvs::Internal::SettingsPage">
- <property name="geometry">
- <rect>
- <x>0</x>
- <y>0</y>
- <width>447</width>
- <height>281</height>
- </rect>
- </property>
- <layout class="QVBoxLayout" name="verticalLayout">
- <item>
- <widget class="QGroupBox" name="configGroupBox">
- <property name="title">
- <string>Configuration</string>
- </property>
- <layout class="QFormLayout" name="formLayout_2">
- <property name="fieldGrowthPolicy">
- <enum>QFormLayout::ExpandingFieldsGrow</enum>
- </property>
- <item row="0" column="0">
- <widget class="QLabel" name="commandLabel">
- <property name="text">
- <string>CVS command:</string>
- </property>
- </widget>
- </item>
- <item row="0" column="1">
- <widget class="Utils::PathChooser" name="commandPathChooser" native="true"/>
- </item>
- <item row="1" column="0">
- <widget class="QLabel" name="rootLabel">
- <property name="text">
- <string>CVS root:</string>
- </property>
- </widget>
- </item>
- <item row="1" column="1">
- <widget class="QLineEdit" name="rootLineEdit"/>
- </item>
- </layout>
- </widget>
- </item>
- <item>
- <widget class="QGroupBox" name="miscGroupBox">
- <property name="title">
- <string>Miscellaneous</string>
- </property>
- <layout class="QFormLayout" name="formLayout">
- <property name="fieldGrowthPolicy">
- <enum>QFormLayout::ExpandingFieldsGrow</enum>
- </property>
- <item row="1" column="0">
- <widget class="QLabel" name="diffOptionsLabel">
- <property name="text">
- <string>Diff options:</string>
- </property>
- </widget>
- </item>
- <item row="1" column="1">
- <widget class="QLineEdit" name="diffOptionsLineEdit"/>
- </item>
- <item row="2" column="0" colspan="2">
- <widget class="QCheckBox" name="promptToSubmitCheckBox">
- <property name="text">
- <string>Prompt on submit</string>
- </property>
- </widget>
- </item>
- <item row="3" column="0" colspan="2">
- <widget class="QCheckBox" name="describeByCommitIdCheckBox">
- <property name="toolTip">
- <string>When checked, all files touched by a commit will be displayed when clicking on a revision number in the annotation view (retrieved via commit ID). Otherwise, only the respective file will be displayed.</string>
- </property>
- <property name="text">
- <string>Describe all files matching commit id</string>
- </property>
- </widget>
- </item>
- <item row="0" column="0">
- <widget class="QLabel" name="timeOutLabel">
- <property name="text">
- <string>Timeout:</string>
- </property>
- </widget>
- </item>
- <item row="0" column="1">
- <widget class="QSpinBox" name="timeOutSpinBox">
- <property name="suffix">
- <string>s</string>
- </property>
- <property name="minimum">
- <number>1</number>
- </property>
- <property name="maximum">
- <number>360</number>
- </property>
- <property name="value">
- <number>30</number>
- </property>
- </widget>
- </item>
- </layout>
- </widget>
- </item>
- <item>
- <spacer name="verticalSpacer">
- <property name="orientation">
- <enum>Qt::Vertical</enum>
- </property>
- <property name="sizeHint" stdset="0">
- <size>
- <width>20</width>
- <height>40</height>
- </size>
- </property>
- </spacer>
- </item>
- </layout>
- </widget>
- <customwidgets>
- <customwidget>
- <class>Utils::PathChooser</class>
- <extends>QWidget</extends>
- <header location="global">utils/pathchooser.h</header>
- <container>1</container>
- <slots>
- <signal>editingFinished()</signal>
- <signal>browsingFinished()</signal>
- </slots>
- </customwidget>
- </customwidgets>
- <tabstops>
- <tabstop>rootLineEdit</tabstop>
- <tabstop>timeOutSpinBox</tabstop>
- <tabstop>diffOptionsLineEdit</tabstop>
- <tabstop>promptToSubmitCheckBox</tabstop>
- <tabstop>describeByCommitIdCheckBox</tabstop>
- </tabstops>
- <resources/>
- <connections/>
-</ui>
diff --git a/src/plugins/debugger/CMakeLists.txt b/src/plugins/debugger/CMakeLists.txt
index 0a9ec99a1f..9148645437 100644
--- a/src/plugins/debugger/CMakeLists.txt
+++ b/src/plugins/debugger/CMakeLists.txt
@@ -17,7 +17,6 @@ add_qtc_plugin(Debugger
breakpoint.cpp breakpoint.h
cdb/cdbengine.cpp cdb/cdbengine.h
cdb/cdboptionspage.cpp cdb/cdboptionspage.h
- cdb/cdboptionspagewidget.ui
cdb/cdbparsehelpers.cpp cdb/cdbparsehelpers.h
cdb/stringinputstream.cpp cdb/stringinputstream.h
commonoptionspage.cpp commonoptionspage.h
diff --git a/src/plugins/debugger/analyzer/analyzerrunconfigwidget.cpp b/src/plugins/debugger/analyzer/analyzerrunconfigwidget.cpp
index 39a3684ab3..0c3479a61c 100644
--- a/src/plugins/debugger/analyzer/analyzerrunconfigwidget.cpp
+++ b/src/plugins/debugger/analyzer/analyzerrunconfigwidget.cpp
@@ -27,76 +27,62 @@
#include "analyzerrunconfigwidget.h"
#include <utils/detailswidget.h>
-#include <utils/qtcassert.h>
+#include <utils/layoutbuilder.h>
-#include <QDebug>
-#include <QApplication>
-#include <QLabel>
-#include <QVBoxLayout>
#include <QComboBox>
+#include <QLayout>
#include <QPushButton>
+using namespace Utils;
+
namespace Debugger {
AnalyzerRunConfigWidget::AnalyzerRunConfigWidget(ProjectExplorer::GlobalOrProjectAspect *aspect)
{
- m_aspect = aspect;
-
- auto globalSetting = new QWidget;
- auto globalSettingLayout = new QHBoxLayout(globalSetting);
- globalSettingLayout->setContentsMargins(0, 0, 0, 0);
-
- m_settingsCombo = new QComboBox(globalSetting);
- m_settingsCombo->addItems(QStringList({
- QApplication::translate("ProjectExplorer::Internal::EditorSettingsPropertiesPage", "Global"),
- QApplication::translate("ProjectExplorer::Internal::EditorSettingsPropertiesPage", "Custom")
- }));
- globalSettingLayout->addWidget(m_settingsCombo);
- connect(m_settingsCombo, QOverload<int>::of(&QComboBox::activated),
- this, &AnalyzerRunConfigWidget::chooseSettings);
- m_restoreButton = new QPushButton(
- QApplication::translate("ProjectExplorer::Internal::EditorSettingsPropertiesPage", "Restore Global"),
- globalSetting);
- globalSettingLayout->addWidget(m_restoreButton);
- connect(m_restoreButton, &QPushButton::clicked, this, &AnalyzerRunConfigWidget::restoreGlobal);
- globalSettingLayout->addStretch(2);
-
- QWidget *innerPane = new QWidget;
- m_configWidget = aspect->projectSettings()->createConfigWidget();
-
- auto layout = new QVBoxLayout(innerPane);
- layout->setContentsMargins(0, 0, 0, 0);
- layout->addWidget(globalSetting);
- layout->addWidget(m_configWidget);
-
- m_details = new Utils::DetailsWidget;
- m_details->setWidget(innerPane);
-
- auto outerLayout = new QVBoxLayout(this);
- outerLayout->addWidget(m_details);
- outerLayout->setContentsMargins(0, 0, 0, 0);
-
- chooseSettings(m_aspect->isUsingGlobalSettings() ? 0 : 1);
-}
+ using namespace Layouting;
-void AnalyzerRunConfigWidget::chooseSettings(int setting)
-{
- QTC_ASSERT(m_aspect, return);
- bool isCustom = (setting == 1);
-
- m_settingsCombo->setCurrentIndex(setting);
- m_aspect->setUsingGlobalSettings(!isCustom);
- m_configWidget->setEnabled(isCustom);
- m_restoreButton->setEnabled(isCustom);
- m_details->setSummaryText(isCustom
- ? tr("Use Customized Settings")
- : tr("Use Global Settings"));
-}
+ auto settingsCombo = new QComboBox;
+ settingsCombo->addItem(tr("Global"));
+ settingsCombo->addItem(tr("Custom"));
-void AnalyzerRunConfigWidget::restoreGlobal()
-{
- QTC_ASSERT(m_aspect, return);
- m_aspect->resetProjectToGlobalSettings();
+ auto restoreButton = new QPushButton(tr("Restore Global"));
+
+ auto innerPane = new QWidget;
+ auto configWidget = aspect->projectSettings()->createConfigWidget();
+
+ auto details = new DetailsWidget;
+ details->setWidget(innerPane);
+
+ Column {
+ Row { settingsCombo, restoreButton, Stretch() },
+ configWidget
+ }.attachTo(innerPane);
+
+ Column { details }.attachTo(this);
+
+ details->layout()->setContentsMargins(0, 0, 0, 0);
+ innerPane->layout()->setContentsMargins(0, 0, 0, 0);
+ layout()->setContentsMargins(0, 0, 0, 0);
+
+ auto chooseSettings = [=](int setting) {
+ const bool isCustom = (setting == 1);
+
+ settingsCombo->setCurrentIndex(setting);
+ aspect->setUsingGlobalSettings(!isCustom);
+ configWidget->setEnabled(isCustom);
+ restoreButton->setEnabled(isCustom);
+ details->setSummaryText(isCustom
+ ? tr("Use Customized Settings")
+ : tr("Use Global Settings"));
+ };
+
+ chooseSettings(aspect->isUsingGlobalSettings() ? 0 : 1);
+
+ connect(settingsCombo, QOverload<int>::of(&QComboBox::activated),
+ this, chooseSettings);
+
+ connect(restoreButton, &QPushButton::clicked,
+ aspect, &ProjectExplorer::GlobalOrProjectAspect::resetProjectToGlobalSettings);
}
} // namespace Debugger
diff --git a/src/plugins/debugger/analyzer/analyzerrunconfigwidget.h b/src/plugins/debugger/analyzer/analyzerrunconfigwidget.h
index ec35f2f5a9..3924dfc61b 100644
--- a/src/plugins/debugger/analyzer/analyzerrunconfigwidget.h
+++ b/src/plugins/debugger/analyzer/analyzerrunconfigwidget.h
@@ -30,31 +30,16 @@
#include <projectexplorer/runconfiguration.h>
-QT_BEGIN_NAMESPACE
-class QComboBox;
-class QPushButton;
-QT_END_NAMESPACE
-
-namespace Utils { class DetailsWidget; }
+#include <QCoreApplication>
namespace Debugger {
class DEBUGGER_EXPORT AnalyzerRunConfigWidget : public QWidget
{
- Q_OBJECT
+ Q_DECLARE_TR_FUNCTIONS(ProjectExplorer::Internal::EditorSettingsPropertiesPage);
public:
AnalyzerRunConfigWidget(ProjectExplorer::GlobalOrProjectAspect *aspect);
-
-private:
- void chooseSettings(int setting);
- void restoreGlobal();
-
- QWidget *m_configWidget;
- ProjectExplorer::GlobalOrProjectAspect *m_aspect;
- QComboBox *m_settingsCombo;
- QPushButton *m_restoreButton;
- Utils::DetailsWidget *m_details;
};
} // namespace Debugger
diff --git a/src/plugins/debugger/breakhandler.cpp b/src/plugins/debugger/breakhandler.cpp
index 73f0f518cf..3c8ff25345 100644
--- a/src/plugins/debugger/breakhandler.cpp
+++ b/src/plugins/debugger/breakhandler.cpp
@@ -51,7 +51,6 @@
#include <utils/hostosinfo.h>
#include <utils/pathchooser.h>
#include <utils/qtcassert.h>
-#include <utils/savedaction.h>
#include <utils/theme/theme.h>
#if USE_BREAK_MODEL_TEST
@@ -1121,7 +1120,7 @@ QVariant BreakpointItem::data(int column, int role) const
break;
}
- if (role == Qt::ToolTipRole && boolSetting(UseToolTipsInBreakpointsView))
+ if (role == Qt::ToolTipRole && debuggerSettings()->useToolTipsInBreakpointsView.value())
return toolTip();
return QVariant();
@@ -1491,7 +1490,7 @@ void BreakHandler::gotoLocation(const Breakpoint &bp) const
// Don't use gotoLocation unconditionally as this ends up in
// disassembly if OperateByInstruction is on. But fallback
// to disassembly if we can't open the file.
- if (IEditor *editor = EditorManager::openEditor(bp->markerFileName().toString()))
+ if (IEditor *editor = EditorManager::openEditor(bp->markerFileName()))
editor->gotoLine(bp->markerLineNumber(), 0);
else
m_engine->openDisassemblerView(Location(bp->m_parameters.address));
@@ -1698,8 +1697,8 @@ bool BreakHandler::contextMenuEvent(const ItemViewEvent &ev)
menu->addSeparator();
- menu->addAction(action(UseToolTipsInBreakpointsView)->action());
- menu->addAction(action(SettingsDialog)->action());
+ menu->addAction(debuggerSettings()->useToolTipsInBreakpointsView.action());
+ menu->addAction(debuggerSettings()->settingsDialog.action());
menu->popup(ev.globalPos());
@@ -2225,7 +2224,7 @@ QVariant GlobalBreakpointItem::data(int column, int role) const
break;
}
- if (role == Qt::ToolTipRole && boolSetting(UseToolTipsInBreakpointsView))
+ if (role == Qt::ToolTipRole && debuggerSettings()->useToolTipsInBreakpointsView.value())
return toolTip();
return QVariant();
@@ -2502,7 +2501,7 @@ void BreakpointManager::toggleBreakpoint(const ContextData &location, const QStr
BreakpointParameters data;
if (location.type == LocationByFile) {
data.type = BreakpointByFileAndLine;
- if (boolSetting(BreakpointsFullPathByDefault))
+ if (debuggerSettings()->breakpointsFullPathByDefault.value())
data.pathUsage = BreakpointUseFullPath;
data.tracepoint = !tracePointMessage.isEmpty();
data.message = tracePointMessage;
@@ -2684,8 +2683,8 @@ bool BreakpointManager::contextMenuEvent(const ItemViewEvent &ev)
menu->addSeparator();
- menu->addAction(action(UseToolTipsInBreakpointsView)->action());
- menu->addAction(action(SettingsDialog)->action());
+ menu->addAction(debuggerSettings()->useToolTipsInBreakpointsView.action());
+ menu->addAction(debuggerSettings()->settingsDialog.action());
menu->popup(ev.globalPos());
@@ -2695,7 +2694,7 @@ bool BreakpointManager::contextMenuEvent(const ItemViewEvent &ev)
void BreakpointManager::gotoLocation(const GlobalBreakpoint &gbp) const
{
QTC_ASSERT(gbp, return);
- if (IEditor *editor = EditorManager::openEditor(gbp->markerFileName().toString()))
+ if (IEditor *editor = EditorManager::openEditor(gbp->markerFileName()))
editor->gotoLine(gbp->markerLineNumber(), 0);
}
diff --git a/src/plugins/debugger/cdb/cdb.pri b/src/plugins/debugger/cdb/cdb.pri
index 2be8c3c91b..1fa1dac810 100644
--- a/src/plugins/debugger/cdb/cdb.pri
+++ b/src/plugins/debugger/cdb/cdb.pri
@@ -7,6 +7,3 @@ SOURCES += $$PWD/cdbengine.cpp \
cdb/cdbparsehelpers.cpp \
cdb/cdboptionspage.cpp \
cdb/stringinputstream.cpp
-
-FORMS += cdb/cdboptionspagewidget.ui
-
diff --git a/src/plugins/debugger/cdb/cdbengine.cpp b/src/plugins/debugger/cdb/cdbengine.cpp
index cdfc54cf3b..44cc230c93 100644
--- a/src/plugins/debugger/cdb/cdbengine.cpp
+++ b/src/plugins/debugger/cdb/cdbengine.cpp
@@ -64,9 +64,7 @@
#include <utils/hostosinfo.h>
#include <utils/qtcassert.h>
#include <utils/qtcprocess.h>
-#include <utils/savedaction.h>
#include <utils/stringutils.h>
-#include <utils/synchronousprocess.h>
#include <utils/winutils.h>
#include <cplusplus/findcdbbreakpoint.h>
@@ -204,7 +202,8 @@ CdbEngine::CdbEngine() :
wh->addTypeFormats("QImage", imageFormats);
wh->addTypeFormats("QImage *", imageFormats);
- connect(action(CreateFullBacktrace)->action(), &QAction::triggered,
+ DebuggerSettings *s = debuggerSettings();
+ connect(s->createFullBacktrace.action(), &QAction::triggered,
this, &CdbEngine::createFullBacktrace);
connect(&m_process, QOverload<int, QProcess::ExitStatus>::of(&QProcess::finished),
this, &CdbEngine::processFinished);
@@ -213,10 +212,10 @@ CdbEngine::CdbEngine() :
this, &CdbEngine::readyReadStandardOut);
connect(&m_process, &QProcess::readyReadStandardError,
this, &CdbEngine::readyReadStandardOut);
- connect(action(UseDebuggingHelpers), &SavedAction::valueChanged,
+ connect(&s->useDebuggingHelpers, &BaseAspect::changed,
this, &CdbEngine::updateLocals);
- if (action(UseCodeModel)->action()->isChecked())
+ if (s->useCodeModel.value())
m_codeModelSnapshot = CppTools::CppModelManager::instance()->snapshot();
}
@@ -254,7 +253,7 @@ void CdbEngine::init()
}
}
- const SourcePathMap &sourcePathMap = Internal::globalDebuggerOptions()->sourcePathMap;
+ const SourcePathMap &sourcePathMap = debuggerSettings()->sourcePathMap.value();
if (!sourcePathMap.isEmpty()) {
for (auto it = sourcePathMap.constBegin(), cend = sourcePathMap.constEnd(); it != cend; ++it) {
m_sourcePathMappings.push_back({QDir::toNativeSeparators(it.key()),
@@ -263,7 +262,7 @@ void CdbEngine::init()
}
// update source path maps from debugger start params
mergeStartParametersSourcePathMap();
- QTC_ASSERT(m_process.state() != QProcess::Running, SynchronousProcess::stopProcess(m_process));
+ QTC_ASSERT(m_process.state() != QProcess::Running, m_process.stopProcess());
}
CdbEngine::~CdbEngine() = default;
@@ -389,16 +388,17 @@ void CdbEngine::setupEngine()
if (sp.useTerminal) // Separate console
debugger.addArg("-2");
- if (boolSetting(IgnoreFirstChanceAccessViolation))
+ const DebuggerSettings &s = *debuggerSettings();
+ if (s.ignoreFirstChanceAccessViolation.value())
debugger.addArg("-x");
- const QStringList &sourcePaths = stringListSetting(CdbSourcePaths);
+ const QStringList &sourcePaths = s.cdbSourcePaths.value();
if (!sourcePaths.isEmpty())
debugger.addArgs({"-srcpath", sourcePaths.join(';')});
- debugger.addArgs({"-y", QChar('"') + stringListSetting(CdbSymbolPaths).join(';') + '"'});
+ debugger.addArgs({"-y", QChar('"') + s.cdbSymbolPaths.value().join(';') + '"'});
- debugger.addArgs(expand(stringSetting(CdbAdditionalArguments)), CommandLine::Raw);
+ debugger.addArgs(expand(s.cdbAdditionalArguments.value()), CommandLine::Raw);
switch (sp.startMode) {
case StartInternal:
@@ -500,7 +500,8 @@ void CdbEngine::handleInitialSessionIdle()
// Take ownership of the breakpoint. Requests insertion. TODO: Cpp only?
BreakpointManager::claimBreakpointsForEngine(this);
- QStringList symbolPaths = stringListSetting(CdbSymbolPaths);
+ const DebuggerSettings &s = *debuggerSettings();
+ QStringList symbolPaths = s.cdbSymbolPaths.value();
QString symbolPath = rp.inferior.environment.expandedValueForKey("_NT_ALT_SYMBOL_PATH");
if (!symbolPath.isEmpty())
symbolPaths += symbolPath;
@@ -514,13 +515,13 @@ void CdbEngine::handleInitialSessionIdle()
runCommand({"sxn ibp", NoFlags}); // Do not break on initial breakpoints.
runCommand({".asm source_line", NoFlags}); // Source line in assembly
runCommand({m_extensionCommandPrefix
- + "setparameter maxStringLength=" + action(MaximalStringLength)->value().toString()
- + " maxStackDepth=" + action(MaximalStackDepth)->value().toString()
- + " firstChance=" + (action(FirstChanceExceptionTaskEntry)->value().toBool() ? "1" : "0")
- + " secondChance=" + (action(SecondChanceExceptionTaskEntry)->value().toBool() ? "1" : "0")
+ + "setparameter maxStringLength=" + QString::number(s.maximalStringLength.value())
+ + " maxStackDepth=" + QString::number(s.maximalStackDepth.value())
+ + " firstChance=" + (s.firstChanceExceptionTaskEntry.value() ? "1" : "0")
+ + " secondChance=" + (s.secondChanceExceptionTaskEntry.value() ? "1" : "0")
, NoFlags});
- if (boolSetting(CdbUsePythonDumper))
+ if (s.cdbUsePythonDumper.value())
runCommand({"print(sys.version)", ScriptCommand, CB(setupScripting)});
runCommand({"pid", ExtensionCommand, [this](const DebuggerResponse &response) {
@@ -578,30 +579,30 @@ void CdbEngine::runEngine()
if (debug)
qDebug("runEngine");
- const QStringList breakEvents = stringListSetting(CdbBreakEvents);
+ const QStringList breakEvents = debuggerSettings()->cdbBreakEvents.value();
for (const QString &breakEvent : breakEvents)
runCommand({"sxe " + breakEvent, NoFlags});
// Break functions: each function must be fully qualified,
// else the debugger will slow down considerably.
const auto cb = [this](const DebuggerResponse &r) { handleBreakInsert(r, Breakpoint()); };
- if (boolSetting(CdbBreakOnCrtDbgReport)) {
+ if (debuggerSettings()->cdbBreakOnCrtDbgReport.value()) {
Abi::OSFlavor flavor = runParameters().toolChainAbi.osFlavor();
// CrtDebugReport cannot be safely resolved for vc 19
if ((flavor > Abi::WindowsMsvc2005Flavor && flavor <= Abi::WindowsMsvc2013Flavor) ||
flavor > Abi::WindowsMSysFlavor || flavor <= Abi::WindowsCEFlavor) {
const QString module = msvcRunTime(flavor);
const QString debugModule = module + 'D';
- const QString wideFunc = QString::fromLatin1(CdbOptionsPage::crtDbgReport).append('W');
- runCommand({breakAtFunctionCommand(QLatin1String(CdbOptionsPage::crtDbgReport), module), BuiltinCommand, cb});
+ const QString wideFunc = QString(Constants::CRT_DEBUG_REPORT).append('W');
+ runCommand({breakAtFunctionCommand(Constants::CRT_DEBUG_REPORT, module), BuiltinCommand, cb});
runCommand({breakAtFunctionCommand(wideFunc, module), BuiltinCommand, cb});
- runCommand({breakAtFunctionCommand(QLatin1String(CdbOptionsPage::crtDbgReport), debugModule), BuiltinCommand, cb});
+ runCommand({breakAtFunctionCommand(Constants::CRT_DEBUG_REPORT, debugModule), BuiltinCommand, cb});
}
}
-// if (boolSetting(BreakOnWarning)) {
+// if (debuggerSettings()->breakOnWarning.value())) {
// runCommand({"bm /( QtCored4!qWarning", BuiltinCommand}); // 'bm': All overloads.
// runCommand({"bm /( Qt5Cored!QMessageLogger::warning", BuiltinCommand});
// }
-// if (boolSetting(BreakOnFatal)) {
+// if (debuggerSettion()->breakOnFatal.value()) {
// runCommand({"bm /( QtCored4!qFatal", BuiltinCommand}); // 'bm': All overloads.
// runCommand({"bm /( Qt5Cored!QMessageLogger::fatal", BuiltinCommand});
// }
@@ -688,7 +689,7 @@ void CdbEngine::shutdownEngine()
}
} else {
// Remote process. No can do, currently
- SynchronousProcess::stopProcess(m_process);
+ m_process.stopProcess();
}
}
@@ -1089,6 +1090,7 @@ void CdbEngine::activateFrame(int index)
void CdbEngine::doUpdateLocals(const UpdateParameters &updateParameters)
{
+ const DebuggerSettings &s = *debuggerSettings();
if (m_pythonVersion > 0x030000) {
watchHandler()->notifyUpdateStarted(updateParameters);
@@ -1098,21 +1100,21 @@ void CdbEngine::doUpdateLocals(const UpdateParameters &updateParameters)
const static bool alwaysVerbose = qEnvironmentVariableIsSet("QTC_DEBUGGER_PYTHON_VERBOSE");
cmd.arg("passexceptions", alwaysVerbose);
- cmd.arg("fancy", boolSetting(UseDebuggingHelpers));
- cmd.arg("autoderef", boolSetting(AutoDerefPointers));
- cmd.arg("dyntype", boolSetting(UseDynamicType));
+ cmd.arg("fancy", s.useDebuggingHelpers.value());
+ cmd.arg("autoderef", s.autoDerefPointers.value());
+ cmd.arg("dyntype", s.useDynamicType.value());
cmd.arg("partialvar", updateParameters.partialVariable);
- cmd.arg("qobjectnames", boolSetting(ShowQObjectNames));
- cmd.arg("timestamps", boolSetting(LogTimeStamps));
+ cmd.arg("qobjectnames", s.showQObjectNames.value());
+ cmd.arg("timestamps", s.logTimeStamps.value());
StackFrame frame = stackHandler()->currentFrame();
cmd.arg("context", frame.context);
cmd.arg("nativemixed", isNativeMixedActive());
- cmd.arg("stringcutoff", action(MaximalStringLength)->value().toString());
- cmd.arg("displaystringlimit", action(DisplayStringLimit)->value().toString());
+ cmd.arg("stringcutoff", s.maximalStringLength.value());
+ cmd.arg("displaystringlimit", s.displayStringLimit.value());
- if (boolSetting(UseCodeModel)) {
+ if (s.useCodeModel.value()) {
QStringList variables = getUninitializedVariables(m_codeModelSnapshot,
frame.function, frame.file, frame.line);
cmd.arg("uninitialized", variables);
@@ -1171,9 +1173,9 @@ void CdbEngine::doUpdateLocals(const UpdateParameters &updateParameters)
}
}
str << blankSeparator << "-v";
- if (boolSetting(UseDebuggingHelpers))
+ if (s.useDebuggingHelpers.value())
str << blankSeparator << "-c";
- if (boolSetting(SortStructMembers))
+ if (s.sortStructMembers.value())
str << blankSeparator << "-a";
const QString typeFormats = watchHandler()->typeFormatRequests();
if (!typeFormats.isEmpty())
@@ -1183,7 +1185,7 @@ void CdbEngine::doUpdateLocals(const UpdateParameters &updateParameters)
str << blankSeparator << "-I " << individualFormats;
// Uninitialized variables if desired. Quote as safeguard against shadowed
// variables in case of errors in uninitializedVariables().
- if (boolSetting(UseCodeModel)) {
+ if (s.useCodeModel.value()) {
const QStringList variables = getUninitializedVariables(m_codeModelSnapshot,
frame.function, frame.file, frame.line);
if (!variables.isEmpty()) {
@@ -2435,45 +2437,45 @@ public:
const CppTools::WorkingCopy &workingCopy) :
m_snapshot(s), m_workingCopy(workingCopy) {}
- unsigned fixLineNumber(const QString &fileName, unsigned lineNumber) const;
+ unsigned fixLineNumber(const Utils::FilePath &filePath, unsigned lineNumber) const;
private:
const CPlusPlus::Snapshot m_snapshot;
CppTools::WorkingCopy m_workingCopy;
};
-static CPlusPlus::Document::Ptr getParsedDocument(const QString &fileName,
+static CPlusPlus::Document::Ptr getParsedDocument(const Utils::FilePath &filePath,
const CppTools::WorkingCopy &workingCopy,
const CPlusPlus::Snapshot &snapshot)
{
QByteArray src;
- if (workingCopy.contains(fileName)) {
- src = workingCopy.source(fileName);
- } else {
- FileReader reader;
- if (reader.fetch(fileName)) // ### FIXME error reporting
- src = QString::fromLocal8Bit(reader.data()).toUtf8();
- }
+ if (workingCopy.contains(filePath))
+ src = workingCopy.source(filePath);
+ else
+ src = QString::fromLocal8Bit(filePath.fileContents()).toUtf8();
- CPlusPlus::Document::Ptr doc = snapshot.preprocessedDocument(src, fileName);
+ CPlusPlus::Document::Ptr doc = snapshot.preprocessedDocument(src, filePath.toString());
doc->parse();
return doc;
}
-unsigned BreakpointCorrectionContext::fixLineNumber(const QString &fileName,
+unsigned BreakpointCorrectionContext::fixLineNumber(const Utils::FilePath &filePath,
unsigned lineNumber) const
{
- const CPlusPlus::Document::Ptr doc = getParsedDocument(fileName, m_workingCopy, m_snapshot);
+ const CPlusPlus::Document::Ptr doc = getParsedDocument(filePath,
+ m_workingCopy,
+ m_snapshot);
CPlusPlus::FindCdbBreakpoint findVisitor(doc->translationUnit());
const unsigned correctedLine = findVisitor(lineNumber);
if (!correctedLine) {
qWarning("Unable to find breakpoint location for %s:%d",
- qPrintable(QDir::toNativeSeparators(fileName)), lineNumber);
+ qPrintable(filePath.toUserOutput()),
+ lineNumber);
return lineNumber;
}
if (debug)
qDebug("Code model: Breakpoint line %u -> %u in %s",
- lineNumber, correctedLine, qPrintable(fileName));
+ lineNumber, correctedLine, qPrintable(filePath.toString()));
return correctedLine;
}
@@ -2487,8 +2489,8 @@ void CdbEngine::insertBreakpoint(const Breakpoint &bp)
new BreakpointCorrectionContext(m_codeModelSnapshot, CppTools::CppModelManager::instance()->workingCopy()));
if (!m_autoBreakPointCorrection
&& parameters.type == BreakpointByFileAndLine
- && boolSetting(CdbBreakPointCorrection)) {
- response.lineNumber = int(lineCorrection->fixLineNumber(parameters.fileName.toString(),
+ && debuggerSettings()->cdbBreakPointCorrection.value()) {
+ response.lineNumber = int(lineCorrection->fixLineNumber(parameters.fileName,
unsigned(parameters.lineNumber)));
QString cmd = cdbAddBreakpointCommand(response, m_sourcePathMappings, responseId);
runCommand({cmd, BuiltinCommand, handleBreakInsertCB});
@@ -2752,20 +2754,20 @@ void CdbEngine::setupScripting(const DebuggerResponse &response)
return;
}
- QString dumperPath = QDir::toNativeSeparators(Core::ICore::resourcePath() + "/debugger");
+ QString dumperPath = Core::ICore::resourcePath("debugger").toUserOutput();
dumperPath.replace('\\', "\\\\");
runCommand({"sys.path.insert(1, '" + dumperPath + "')", ScriptCommand});
runCommand({"from cdbbridge import Dumper", ScriptCommand});
runCommand({"print(dir())", ScriptCommand});
runCommand({"theDumper = Dumper()", ScriptCommand});
- const QString path = stringSetting(ExtraDumperFile);
+ const QString path = debuggerSettings()->extraDumperFile.value();
if (!path.isEmpty() && QFileInfo(path).isReadable()) {
DebuggerCommand cmd("theDumper.addDumperModule", ScriptCommand);
cmd.arg("path", path);
runCommand(cmd);
}
- const QString commands = stringSetting(ExtraDumperCommands);
+ const QString commands = debuggerSettings()->extraDumperCommands.value();
if (!commands.isEmpty()) {
for (const auto &command : commands.split('\n', Qt::SkipEmptyParts))
runCommand({command, ScriptCommand});
diff --git a/src/plugins/debugger/cdb/cdboptionspage.cpp b/src/plugins/debugger/cdb/cdboptionspage.cpp
index d2cc842721..a58038aa35 100644
--- a/src/plugins/debugger/cdb/cdboptionspage.cpp
+++ b/src/plugins/debugger/cdb/cdboptionspage.cpp
@@ -26,7 +26,7 @@
#include "cdboptionspage.h"
#include "cdbengine.h"
-#include "ui_cdboptionspagewidget.h"
+
#include <debugger/commonoptionspage.h>
#include <debugger/debuggeractions.h>
#include <debugger/debuggercore.h>
@@ -35,16 +35,18 @@
#include <coreplugin/icore.h>
-#include <utils/savedaction.h>
+#include <utils/aspects.h>
+#include <utils/layoutbuilder.h>
-#include <QDialogButtonBox>
+#include <QCheckBox>
+#include <QFormLayout>
#include <QTextStream>
+using namespace Utils;
+
namespace Debugger {
namespace Internal {
-const char *CdbOptionsPage::crtDbgReport = "CrtDbgReport";
-
struct EventsDescription {
const char *abbreviation;
bool hasParameter;
@@ -192,56 +194,61 @@ private:
void apply() final;
void finish() final;
- Utils::SavedActionSet m_group;
- Ui::CdbOptionsPageWidget m_ui;
+ Utils::AspectContainer &m_group = debuggerSettings()->page5;
CdbBreakEventWidget *m_breakEventWidget;
};
CdbOptionsPageWidget::CdbOptionsPageWidget()
: m_breakEventWidget(new CdbBreakEventWidget)
{
- m_ui.setupUi(this);
- // Squeeze the groupbox layouts vertically to
- // accommodate all options. This page only shows on
- // Windows, which has large margins by default.
-
- int left, top, right, bottom;
- layout()->getContentsMargins(&left, &top, &right, &bottom);
- const QMargins margins(left, top / 3, right, bottom / 3);
-
- m_ui.startupFormLayout->setContentsMargins(margins);
-
- auto eventLayout = new QVBoxLayout;
- eventLayout->setContentsMargins(margins);
- eventLayout->addWidget(m_breakEventWidget);
- m_ui.eventGroupBox->setLayout(eventLayout);
- m_ui.breakCrtDbgReportCheckBox
- ->setText(CommonOptionsPage::msgSetBreakpointAtFunction(CdbOptionsPage::crtDbgReport));
- const QString hint = tr("This is useful to catch runtime error messages, for example caused by assert().");
- m_ui.breakCrtDbgReportCheckBox
- ->setToolTip(CommonOptionsPage::msgSetBreakpointAtFunctionToolTip(CdbOptionsPage::crtDbgReport, hint));
-
- m_group.insert(action(CdbAdditionalArguments), m_ui.additionalArgumentsLineEdit);
- m_group.insert(action(CdbBreakOnCrtDbgReport), m_ui.breakCrtDbgReportCheckBox);
- m_group.insert(action(UseCdbConsole), m_ui.consoleCheckBox);
- m_group.insert(action(CdbBreakPointCorrection), m_ui.breakpointCorrectionCheckBox);
- m_group.insert(action(CdbUsePythonDumper), m_ui.usePythonDumper);
- m_group.insert(action(FirstChanceExceptionTaskEntry), m_ui.firstChance);
- m_group.insert(action(SecondChanceExceptionTaskEntry), m_ui.secondChance);
- m_group.insert(action(IgnoreFirstChanceAccessViolation),
- m_ui.ignoreFirstChanceAccessViolationCheckBox);
-
- m_breakEventWidget->setBreakEvents(stringListSetting(CdbBreakEvents));
+ using namespace Layouting;
+ DebuggerSettings &s = *debuggerSettings();
+
+ m_breakEventWidget->setBreakEvents(debuggerSettings()->cdbBreakEvents.value());
+
+ Column {
+ Row {
+ Group {
+ Title(tr("Startup")),
+ s.cdbAdditionalArguments,
+ s.useCdbConsole,
+ Stretch()
+ },
+
+ Group {
+ Title(tr("Various")),
+ s.ignoreFirstChanceAccessViolation,
+ s.cdbBreakOnCrtDbgReport,
+ s.cdbBreakPointCorrection,
+ s.cdbUsePythonDumper
+ }
+ },
+
+ Group {
+ Title(tr("Break on")),
+ m_breakEventWidget
+ },
+
+ Group {
+ Title(tr("Add Exceptions to Issues View")),
+ s.firstChanceExceptionTaskEntry,
+ s.secondChanceExceptionTaskEntry
+ },
+
+ Stretch()
+
+ }.attachTo(this);
}
void CdbOptionsPageWidget::apply()
{
- m_group.apply(Core::ICore::settings());
- action(CdbBreakEvents)->setValue(m_breakEventWidget->breakEvents());
+ m_group.apply(); m_group.writeSettings(Core::ICore::settings());
+ debuggerSettings()->cdbBreakEvents.setValue(m_breakEventWidget->breakEvents());
}
void CdbOptionsPageWidget::finish()
{
+ m_breakEventWidget->setBreakEvents(debuggerSettings()->cdbBreakEvents.value());
m_group.finish();
}
@@ -263,33 +270,41 @@ class CdbPathsPageWidget : public Core::IOptionsPageWidget
public:
CdbPathsPageWidget();
- void apply() final { m_group.apply(Core::ICore::settings()); }
- void finish() final { m_group.finish(); }
+ void apply() final;
+ void finish() final;
+
+ AspectContainer &m_group = debuggerSettings()->page6;
- Utils::SavedActionSet m_group;
+private:
+ PathListEditor *m_symbolPaths = nullptr;
+ PathListEditor *m_sourcePaths = nullptr;
};
CdbPathsPageWidget::CdbPathsPageWidget()
+ : m_symbolPaths(new CdbSymbolPathListEditor)
+ , m_sourcePaths(new PathListEditor)
{
- auto layout = new QVBoxLayout(this);
-
- auto gbSymbolPath = new QGroupBox(tr("Symbol Paths"), this);
- auto gbSymbolPathLayout = new QVBoxLayout(gbSymbolPath);
-
- auto symbolPathListEditor = new CdbSymbolPathListEditor(gbSymbolPath);
- gbSymbolPathLayout->addWidget(symbolPathListEditor);
-
- auto gbSourcePath = new QGroupBox(tr("Source Paths"), this);
-
- auto gbSourcePathLayout = new QVBoxLayout(gbSourcePath);
- auto sourcePathListEditor = new Utils::PathListEditor(gbSourcePath);
- gbSourcePathLayout->addWidget(sourcePathListEditor);
+ using namespace Layouting;
+
+ finish();
+ Column {
+ Group { Title(tr("Symbol Paths")), m_symbolPaths },
+ Group { Title(tr("Source Paths")), m_sourcePaths },
+ Stretch()
+ }.attachTo(this);
+}
- layout->addWidget(gbSymbolPath);
- layout->addWidget(gbSourcePath);
+void CdbPathsPageWidget::apply()
+{
+ debuggerSettings()->cdbSymbolPaths.setValue(m_symbolPaths->pathList());
+ debuggerSettings()->cdbSourcePaths.setValue(m_sourcePaths->pathList());
+ m_group.writeSettings(Core::ICore::settings());
+}
- m_group.insert(action(CdbSymbolPaths), symbolPathListEditor);
- m_group.insert(action(CdbSourcePaths), sourcePathListEditor);
+void CdbPathsPageWidget::finish()
+{
+ m_symbolPaths->setPathList(debuggerSettings()->cdbSymbolPaths.value());
+ m_sourcePaths->setPathList(debuggerSettings()->cdbSourcePaths.value());
}
CdbPathsPage::CdbPathsPage()
diff --git a/src/plugins/debugger/cdb/cdboptionspage.h b/src/plugins/debugger/cdb/cdboptionspage.h
index aac0b91d2a..d78b0af2e4 100644
--- a/src/plugins/debugger/cdb/cdboptionspage.h
+++ b/src/plugins/debugger/cdb/cdboptionspage.h
@@ -34,8 +34,6 @@ class CdbOptionsPage final : public Core::IOptionsPage
{
public:
CdbOptionsPage();
-
- static const char *crtDbgReport;
};
class CdbPathsPage final : public Core::IOptionsPage
diff --git a/src/plugins/debugger/cdb/cdboptionspagewidget.ui b/src/plugins/debugger/cdb/cdboptionspagewidget.ui
deleted file mode 100644
index 345b85c756..0000000000
--- a/src/plugins/debugger/cdb/cdboptionspagewidget.ui
+++ /dev/null
@@ -1,152 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<ui version="4.0">
- <class>Debugger::Internal::CdbOptionsPageWidget</class>
- <widget class="QWidget" name="Debugger::Internal::CdbOptionsPageWidget">
- <property name="geometry">
- <rect>
- <x>0</x>
- <y>0</y>
- <width>629</width>
- <height>807</height>
- </rect>
- </property>
- <layout class="QVBoxLayout" name="verticalLayout">
- <item>
- <layout class="QGridLayout" name="gridLayout_2">
- <item row="0" column="0">
- <widget class="QGroupBox" name="cdbPathGroupBox">
- <property name="title">
- <string extracomment="Placeholder">Startup</string>
- </property>
- <property name="checkable">
- <bool>false</bool>
- </property>
- <property name="checked">
- <bool>false</bool>
- </property>
- <layout class="QFormLayout" name="startupFormLayout">
- <property name="fieldGrowthPolicy">
- <enum>QFormLayout::AllNonFixedFieldsGrow</enum>
- </property>
- <item row="0" column="0">
- <widget class="QLabel" name="additionalArgumentsLabel">
- <property name="text">
- <string>Additional &amp;arguments:</string>
- </property>
- <property name="buddy">
- <cstring>additionalArgumentsLineEdit</cstring>
- </property>
- </widget>
- </item>
- <item row="0" column="1">
- <widget class="QLineEdit" name="additionalArgumentsLineEdit"/>
- </item>
- <item row="1" column="0" colspan="2">
- <widget class="QCheckBox" name="consoleCheckBox">
- <property name="toolTip">
- <string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;Uses CDB's native console for console applications. This overrides the setting in Environment &gt; System. The native console does not prompt on application exit. It is suitable for diagnosing cases in which the application does not start up properly in the configured console and the subsequent attach fails.&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
- </property>
- <property name="text">
- <string>Use CDB &amp;console</string>
- </property>
- </widget>
- </item>
- </layout>
- </widget>
- </item>
- <item row="2" column="0" colspan="2">
- <widget class="QGroupBox" name="eventGroupBox">
- <property name="title">
- <string>Break on:</string>
- </property>
- </widget>
- </item>
- <item row="0" column="1">
- <layout class="QVBoxLayout" name="verticalLayout_4">
- <item>
- <widget class="QGroupBox" name="variousGroupBox">
- <property name="title">
- <string>Various</string>
- </property>
- <layout class="QVBoxLayout" name="verticalLayout_3">
- <item>
- <widget class="QCheckBox" name="ignoreFirstChanceAccessViolationCheckBox">
- <property name="text">
- <string>Ignore first chance access violations</string>
- </property>
- </widget>
- </item>
- <item>
- <widget class="QCheckBox" name="breakCrtDbgReportCheckBox"/>
- </item>
- <item>
- <widget class="QCheckBox" name="breakpointCorrectionCheckBox">
- <property name="toolTip">
- <string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;Attempts to correct the location of a breakpoint based on file and line number should it be in a comment or in a line for which no code is generated. The correction is based on the code model.&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
- </property>
- <property name="text">
- <string>Correct breakpoint location</string>
- </property>
- </widget>
- </item>
- <item>
- <widget class="QCheckBox" name="usePythonDumper">
- <property name="text">
- <string>Use Python dumper</string>
- </property>
- </widget>
- </item>
- </layout>
- </widget>
- </item>
- </layout>
- </item>
- </layout>
- </item>
- <item>
- <widget class="QGroupBox" name="exceptions">
- <property name="title">
- <string>Add Exceptions to Issues View</string>
- </property>
- <layout class="QHBoxLayout" name="horizontalLayout">
- <item>
- <widget class="QCheckBox" name="firstChance">
- <property name="text">
- <string>First chance exceptions</string>
- </property>
- <property name="checked">
- <bool>true</bool>
- </property>
- </widget>
- </item>
- <item>
- <widget class="QCheckBox" name="secondChance">
- <property name="text">
- <string>Second chance exceptions</string>
- </property>
- <property name="checked">
- <bool>true</bool>
- </property>
- </widget>
- </item>
- </layout>
- </widget>
- </item>
- <item>
- <spacer name="verticalSpacer">
- <property name="orientation">
- <enum>Qt::Vertical</enum>
- </property>
- <property name="sizeHint" stdset="0">
- <size>
- <width>0</width>
- <height>0</height>
- </size>
- </property>
- </spacer>
- </item>
- </layout>
- </widget>
- <resources/>
- <connections/>
-</ui>
diff --git a/src/plugins/debugger/commonoptionspage.cpp b/src/plugins/debugger/commonoptionspage.cpp
index 0169fca2c1..2f0bc5c758 100644
--- a/src/plugins/debugger/commonoptionspage.cpp
+++ b/src/plugins/debugger/commonoptionspage.cpp
@@ -27,31 +27,13 @@
#include "debuggeractions.h"
#include "debuggerinternalconstants.h"
-#include "debuggercore.h"
-#include "debuggersourcepathmappingwidget.h"
#include <coreplugin/icore.h>
-#include <app/app_version.h>
-
-#include <utils/hostosinfo.h>
-#include <utils/pathchooser.h>
-#include <utils/qtcassert.h>
-#include <utils/savedaction.h>
-#include <utils/variablechooser.h>
-
-#include <QCheckBox>
-#include <QCoreApplication>
-#include <QFormLayout>
-#include <QHBoxLayout>
-#include <QLabel>
-#include <QSpinBox>
-#include <QTextEdit>
-#include <QTextStream>
+#include <utils/layoutbuilder.h>
using namespace Core;
using namespace Debugger::Constants;
-using namespace ProjectExplorer;
using namespace Utils;
namespace Debugger {
@@ -70,185 +52,45 @@ class CommonOptionsPageWidget : public Core::IOptionsPageWidget
public:
explicit CommonOptionsPageWidget()
{
- auto behaviorBox = new QGroupBox(this);
- behaviorBox->setTitle(tr("Behavior"));
-
- auto checkBoxUseAlternatingRowColors = new QCheckBox(behaviorBox);
- checkBoxUseAlternatingRowColors->setText(tr("Use alternating row colors in debug views"));
-
- auto checkBoxFontSizeFollowsEditor = new QCheckBox(behaviorBox);
- checkBoxFontSizeFollowsEditor->setToolTip(tr("Changes the font size in the debugger views when the font size in the main editor changes."));
- checkBoxFontSizeFollowsEditor->setText(tr("Debugger font size follows main editor"));
-
- auto checkBoxUseToolTipsInMainEditor = new QCheckBox(behaviorBox);
- checkBoxUseToolTipsInMainEditor->setText(tr("Use tooltips in main editor while debugging"));
-
- auto checkBoxUseAnnotationsInMainEditor = new QCheckBox(behaviorBox);
- checkBoxUseAnnotationsInMainEditor->setText(tr("Use annotations in main editor while debugging"));
-
- QString t = tr("Stopping and stepping in the debugger "
- "will automatically open views associated with the current location.") + '\n';
- auto checkBoxCloseSourceBuffersOnExit = new QCheckBox(behaviorBox);
- checkBoxCloseSourceBuffersOnExit->setText(tr("Close temporary source views on debugger exit"));
- checkBoxCloseSourceBuffersOnExit->setToolTip(t + tr("Closes automatically opened source views when the debugger exits."));
-
- auto checkBoxCloseMemoryBuffersOnExit = new QCheckBox(behaviorBox);
- checkBoxCloseMemoryBuffersOnExit->setText(tr("Close temporary memory views on debugger exit"));
- checkBoxCloseMemoryBuffersOnExit->setToolTip(t + tr("Closes automatically opened memory views when the debugger exits."));
-
- auto checkBoxSwitchModeOnExit = new QCheckBox(behaviorBox);
- checkBoxSwitchModeOnExit->setText(tr("Switch to previous mode on debugger exit"));
-
- auto checkBoxBringToForegroundOnInterrrupt = new QCheckBox(behaviorBox);
- checkBoxBringToForegroundOnInterrrupt->setText(
- tr("Bring %1 to foreground when application interrupts")
- .arg(Core::Constants::IDE_DISPLAY_NAME));
-
- auto checkBoxShowQmlObjectTree = new QCheckBox(behaviorBox);
- checkBoxShowQmlObjectTree->setToolTip(tr("Shows QML object tree in Locals and Expressions when connected and not stepping."));
- checkBoxShowQmlObjectTree->setText(tr("Show QML object tree"));
-
- auto checkBoxBreakpointsFullPath = new QCheckBox(behaviorBox);
- checkBoxBreakpointsFullPath->setToolTip(tr("Enables a full file path in breakpoints by default also for GDB."));
- checkBoxBreakpointsFullPath->setText(tr("Set breakpoints using a full absolute path"));
-
- auto checkBoxRegisterForPostMortem = new QCheckBox(behaviorBox);
- checkBoxRegisterForPostMortem->setToolTip(
- tr("Registers %1 for debugging crashed applications.")
- .arg(Core::Constants::IDE_DISPLAY_NAME));
- checkBoxRegisterForPostMortem->setText(
- tr("Use %1 for post-mortem debugging")
- .arg(Core::Constants::IDE_DISPLAY_NAME));
-
- auto checkBoxWarnOnReleaseBuilds = new QCheckBox(behaviorBox);
- checkBoxWarnOnReleaseBuilds->setText(tr("Warn when debugging \"Release\" builds"));
- checkBoxWarnOnReleaseBuilds->setToolTip(tr("Shows a warning when starting the debugger "
- "on a binary with insufficient debug information."));
-
- auto checkBoxKeepEditorStationaryWhileStepping = new QCheckBox(behaviorBox);
- checkBoxKeepEditorStationaryWhileStepping->setText(tr("Keep editor stationary when stepping"));
- checkBoxKeepEditorStationaryWhileStepping->setToolTip(tr("Scrolls the editor only when it is necessary "
- "to keep the current line in view, "
- "instead of keeping the next statement centered at "
- "all times."));
-
- auto labelMaximalStackDepth = new QLabel(tr("Maximum stack depth:"), behaviorBox);
-
- auto spinBoxMaximalStackDepth = new QSpinBox(behaviorBox);
- spinBoxMaximalStackDepth->setSpecialValueText(tr("<unlimited>"));
- spinBoxMaximalStackDepth->setMaximum(999);
- spinBoxMaximalStackDepth->setSingleStep(5);
- spinBoxMaximalStackDepth->setValue(10);
-
- m_sourceMappingWidget = new DebuggerSourcePathMappingWidget(this);
-
- auto horizontalLayout = new QHBoxLayout;
- horizontalLayout->addWidget(labelMaximalStackDepth);
- horizontalLayout->addWidget(spinBoxMaximalStackDepth);
- horizontalLayout->addStretch();
-
- auto gridLayout = new QGridLayout(behaviorBox);
- gridLayout->addWidget(checkBoxUseAlternatingRowColors, 0, 0, 1, 1);
- gridLayout->addWidget(checkBoxUseAnnotationsInMainEditor, 1, 0, 1, 1);
- gridLayout->addWidget(checkBoxUseToolTipsInMainEditor, 2, 0, 1, 1);
- gridLayout->addWidget(checkBoxCloseSourceBuffersOnExit, 3, 0, 1, 1);
- gridLayout->addWidget(checkBoxCloseMemoryBuffersOnExit, 4, 0, 1, 1);
- gridLayout->addWidget(checkBoxBringToForegroundOnInterrrupt, 5, 0, 1, 1);
- gridLayout->addWidget(checkBoxBreakpointsFullPath, 6, 0, 1, 1);
- gridLayout->addWidget(checkBoxWarnOnReleaseBuilds, 7, 0, 1, 1);
- gridLayout->addLayout(horizontalLayout, 8, 0, 1, 2);
-
- gridLayout->addWidget(checkBoxFontSizeFollowsEditor, 0, 1, 1, 1);
- gridLayout->addWidget(checkBoxSwitchModeOnExit, 1, 1, 1, 1);
- gridLayout->addWidget(checkBoxShowQmlObjectTree, 2, 1, 1, 1);
- gridLayout->addWidget(checkBoxKeepEditorStationaryWhileStepping, 3, 1, 1, 1);
- gridLayout->addWidget(checkBoxRegisterForPostMortem, 4, 1, 1, 1);
-
- auto verticalLayout = new QVBoxLayout(this);
- verticalLayout->addWidget(behaviorBox);
- verticalLayout->addWidget(m_sourceMappingWidget);
- verticalLayout->addStretch();
-
- m_group.insert(action(UseAlternatingRowColors),
- checkBoxUseAlternatingRowColors);
- m_group.insert(action(UseAnnotationsInMainEditor),
- checkBoxUseAnnotationsInMainEditor);
- m_group.insert(action(UseToolTipsInMainEditor),
- checkBoxUseToolTipsInMainEditor);
- m_group.insert(action(CloseSourceBuffersOnExit),
- checkBoxCloseSourceBuffersOnExit);
- m_group.insert(action(CloseMemoryBuffersOnExit),
- checkBoxCloseMemoryBuffersOnExit);
- m_group.insert(action(SwitchModeOnExit),
- checkBoxSwitchModeOnExit);
- m_group.insert(action(BreakpointsFullPathByDefault),
- checkBoxBreakpointsFullPath);
- m_group.insert(action(RaiseOnInterrupt),
- checkBoxBringToForegroundOnInterrrupt);
- m_group.insert(action(ShowQmlObjectTree),
- checkBoxShowQmlObjectTree);
- m_group.insert(action(WarnOnReleaseBuilds),
- checkBoxWarnOnReleaseBuilds);
- m_group.insert(action(StationaryEditorWhileStepping),
- checkBoxKeepEditorStationaryWhileStepping);
- m_group.insert(action(FontSizeFollowsEditor),
- checkBoxFontSizeFollowsEditor);
- m_group.insert(action(AutoDerefPointers), nullptr);
- m_group.insert(action(UseToolTipsInLocalsView), nullptr);
- m_group.insert(action(AlwaysAdjustColumnWidths), nullptr);
- m_group.insert(action(UseToolTipsInBreakpointsView), nullptr);
- m_group.insert(action(UseToolTipsInStackView), nullptr);
- m_group.insert(action(MaximalStackDepth), spinBoxMaximalStackDepth);
- m_group.insert(action(ShowStdNamespace), nullptr);
- m_group.insert(action(ShowQtNamespace), nullptr);
- m_group.insert(action(ShowQObjectNames), nullptr);
- m_group.insert(action(SortStructMembers), nullptr);
- m_group.insert(action(LogTimeStamps), nullptr);
- m_group.insert(action(BreakOnThrow), nullptr);
- m_group.insert(action(BreakOnCatch), nullptr);
- if (HostOsInfo::isWindowsHost()) {
- SavedAction *registerAction = action(RegisterForPostMortem);
- m_group.insert(registerAction, checkBoxRegisterForPostMortem);
- connect(registerAction->action(), &QAction::toggled,
- checkBoxRegisterForPostMortem, &QAbstractButton::setChecked);
- } else {
- checkBoxRegisterForPostMortem->setVisible(false);
- }
-
- GlobalDebuggerOptions *options = Internal::globalDebuggerOptions();
- SourcePathMap allPathMap = options->sourcePathMap;
- for (const auto &regExpMap : qAsConst(options->sourcePathRegExpMap))
- allPathMap.insert(regExpMap.first.pattern(), regExpMap.second);
- m_sourceMappingWidget->setSourcePathMap(allPathMap);
+ DebuggerSettings &s = *debuggerSettings();
+ using namespace Layouting;
+
+ Column col1 {
+ s.useAlternatingRowColors,
+ s.useAnnotationsInMainEditor,
+ s.useToolTipsInMainEditor,
+ s.closeSourceBuffersOnExit,
+ s.closeMemoryBuffersOnExit,
+ s.raiseOnInterrupt,
+ s.breakpointsFullPathByDefault,
+ s.warnOnReleaseBuilds,
+ Row { s.maximalStackDepth, Stretch() }
+ };
+
+ Column col2 {
+ s.fontSizeFollowsEditor,
+ s.switchModeOnExit,
+ s.showQmlObjectTree,
+ s.stationaryEditorWhileStepping,
+ s.forceLoggingToConsole,
+ s.registerForPostMortem,
+ Stretch()
+ };
+
+ Column {
+ Group { Title("Behavior"), Row { col1, col2, Stretch() } },
+ s.sourcePathMap,
+ Stretch()
+ }.attachTo(this);
}
- void apply() final;
+ void apply() final { m_group.apply(); m_group.writeSettings(ICore::settings()); }
void finish() final { m_group.finish(); }
private:
- SavedActionSet m_group;
- DebuggerSourcePathMappingWidget *m_sourceMappingWidget = nullptr;
+ AspectContainer &m_group = debuggerSettings()->page1;
};
-void CommonOptionsPageWidget::apply()
-{
- m_group.apply(ICore::settings());
-
- GlobalDebuggerOptions *options = Internal::globalDebuggerOptions();
- options->sourcePathMap.clear();
- options->sourcePathRegExpMap.clear();
-
- SourcePathMap allPathMap = m_sourceMappingWidget->sourcePathMap();
- for (auto it = allPathMap.begin(), end = allPathMap.end(); it != end; ++it) {
- const QString key = it.key();
- if (key.startsWith('('))
- options->sourcePathRegExpMap.append(qMakePair(QRegularExpression(key), it.value()));
- else
- options->sourcePathMap.insert(key, it.value());
- }
- options->toSettings();
-}
-
CommonOptionsPage::CommonOptionsPage()
{
setId(DEBUGGER_COMMON_SETTINGS_ID);
@@ -292,11 +134,10 @@ class LocalsAndExpressionsOptionsPageWidget : public IOptionsPageWidget
public:
LocalsAndExpressionsOptionsPageWidget()
{
- auto debuggingHelperGroupBox = new QGroupBox(this);
- debuggingHelperGroupBox->setTitle(tr("Use Debugging Helper"));
- debuggingHelperGroupBox->setCheckable(true);
+ using namespace Layouting;
+ DebuggerSettings &s = *debuggerSettings();
- auto label = new QLabel(debuggingHelperGroupBox);
+ auto label = new QLabel; //(useHelperGroup);
label->setTextFormat(Qt::AutoText);
label->setWordWrap(true);
label->setText("<html><head/><body>\n<p>"
@@ -305,97 +146,44 @@ public:
"std::map in the &quot;Locals&quot; and &quot;Expressions&quot; views.")
+ "</p></body></html>");
- auto groupBoxCustomDumperCommands = new QGroupBox(debuggingHelperGroupBox);
- groupBoxCustomDumperCommands->setTitle(tr("Debugging Helper Customization"));
- groupBoxCustomDumperCommands->setToolTip("<html><head/><body><p>"
- + tr("Python commands entered here will be executed after built-in "
- "debugging helpers have been loaded and fully initialized. You can "
- "load additional debugging helpers or modify existing ones here.")
- + "</p></body></html>");
-
- auto textEditCustomDumperCommands = new QTextEdit(groupBoxCustomDumperCommands);
- textEditCustomDumperCommands->setAcceptRichText(false);
- textEditCustomDumperCommands->setToolTip(groupBoxCustomDumperCommands->toolTip());
-
- auto groupBoxExtraDumperFile = new QGroupBox(debuggingHelperGroupBox);
- groupBoxExtraDumperFile->setTitle(tr("Extra Debugging Helpers"));
- groupBoxExtraDumperFile->setToolTip(tr(
- "Path to a Python file containing additional data dumpers."));
-
- auto pathChooserExtraDumperFile = new Utils::PathChooser(groupBoxExtraDumperFile);
- pathChooserExtraDumperFile->setExpectedKind(Utils::PathChooser::File);
-
- auto checkBoxUseCodeModel = new QCheckBox(debuggingHelperGroupBox);
- auto checkBoxShowThreadNames = new QCheckBox(debuggingHelperGroupBox);
- auto checkBoxShowStdNamespace = new QCheckBox(this);
- auto checkBoxShowQtNamespace = new QCheckBox(this);
- auto checkBoxShowQObjectNames = new QCheckBox(this);
-
- auto spinBoxMaximalStringLength = new QSpinBox(this);
- spinBoxMaximalStringLength->setSpecialValueText(tr("<unlimited>"));
- spinBoxMaximalStringLength->setMaximum(10000000);
- spinBoxMaximalStringLength->setSingleStep(1000);
- spinBoxMaximalStringLength->setValue(10000);
-
- auto spinBoxDisplayStringLimit = new QSpinBox(this);
- spinBoxDisplayStringLimit->setSpecialValueText(tr("<unlimited>"));
- spinBoxDisplayStringLimit->setMaximum(10000);
- spinBoxDisplayStringLimit->setSingleStep(10);
- spinBoxDisplayStringLimit->setValue(100);
-
- auto chooser = new VariableChooser(this);
- chooser->addSupportedWidget(textEditCustomDumperCommands);
- chooser->addSupportedWidget(pathChooserExtraDumperFile->lineEdit());
-
- auto gridLayout = new QGridLayout(debuggingHelperGroupBox);
- gridLayout->addWidget(label, 0, 0, 1, 1);
- gridLayout->addWidget(checkBoxUseCodeModel, 1, 0, 1, 1);
- gridLayout->addWidget(checkBoxShowThreadNames, 2, 0, 1, 1);
- gridLayout->addWidget(groupBoxExtraDumperFile, 3, 0, 1, 1);
- gridLayout->addWidget(groupBoxCustomDumperCommands, 0, 1, 4, 1);
-
- auto layout1 = new QFormLayout;
- layout1->addItem(new QSpacerItem(10, 10));
- layout1->addRow(checkBoxShowStdNamespace);
- layout1->addRow(checkBoxShowQtNamespace);
- layout1->addRow(checkBoxShowQObjectNames);
- layout1->addItem(new QSpacerItem(10, 10));
- layout1->addRow(tr("Maximum string length:"), spinBoxMaximalStringLength);
- layout1->addRow(tr("Display string length:"), spinBoxDisplayStringLimit);
-
- auto lowerLayout = new QHBoxLayout;
- lowerLayout->addLayout(layout1);
- lowerLayout->addStretch();
-
- auto layout = new QVBoxLayout(this);
- layout->addWidget(debuggingHelperGroupBox);
- layout->addLayout(lowerLayout);
- layout->addStretch();
-
- auto customDumperLayout = new QGridLayout(groupBoxCustomDumperCommands);
- customDumperLayout->addWidget(textEditCustomDumperCommands, 0, 0, 1, 1);
-
- auto extraDumperLayout = new QGridLayout(groupBoxExtraDumperFile);
- extraDumperLayout->addWidget(pathChooserExtraDumperFile, 0, 0, 1, 1);
-
- m_group.clear();
- m_group.insert(action(UseDebuggingHelpers), debuggingHelperGroupBox);
- m_group.insert(action(ExtraDumperFile), pathChooserExtraDumperFile);
- m_group.insert(action(ExtraDumperCommands), textEditCustomDumperCommands);
- m_group.insert(action(UseCodeModel), checkBoxUseCodeModel);
- m_group.insert(action(ShowThreadNames), checkBoxShowThreadNames);
- m_group.insert(action(ShowStdNamespace), checkBoxShowStdNamespace);
- m_group.insert(action(ShowQtNamespace), checkBoxShowQtNamespace);
- m_group.insert(action(ShowQObjectNames), checkBoxShowQObjectNames);
- m_group.insert(action(DisplayStringLimit), spinBoxDisplayStringLimit);
- m_group.insert(action(MaximalStringLength), spinBoxMaximalStringLength);
+ Column left {
+ label,
+ s.useCodeModel,
+ s.showThreadNames,
+ Group { Title(tr("Extra Debugging Helper")), s.extraDumperFile }
+ };
+
+ Group useHelper {
+ Row {
+ left,
+ Group { Title(tr("Debugging Helper Customization")), s.extraDumperCommands }
+ }
+ };
+
+ Grid limits {
+ s.maximalStringLength,
+ Break(),
+ s.displayStringLimit
+ };
+
+ Column {
+ s.useDebuggingHelpers,
+ useHelper,
+ Space(10),
+ s.showStdNamespace,
+ s.showQtNamespace,
+ s.showQObjectNames,
+ Space(10),
+ Row { limits, Stretch() },
+ Stretch()
+ }.attachTo(this);
}
- void apply() final { m_group.apply(ICore::settings()); }
+ void apply() final { m_group.apply(); m_group.writeSettings(ICore::settings()); }
void finish() final { m_group.finish(); }
private:
- Utils::SavedActionSet m_group;
+ AspectContainer &m_group = debuggerSettings()->page4;
};
LocalsAndExpressionsOptionsPage::LocalsAndExpressionsOptionsPage()
diff --git a/src/plugins/debugger/console/console.cpp b/src/plugins/debugger/console/console.cpp
index 074d1f3c8c..d6a911d972 100644
--- a/src/plugins/debugger/console/console.cpp
+++ b/src/plugins/debugger/console/console.cpp
@@ -31,11 +31,11 @@
#include <coreplugin/coreconstants.h>
#include <coreplugin/findplaceholder.h>
#include <coreplugin/icore.h>
-#include <utils/savedaction.h>
#include <utils/utilsicons.h>
#include <aggregation/aggregate.h>
#include <coreplugin/find/itemviewfind.h>
+#include <QAction>
#include <QCoreApplication>
#include <QToolButton>
#include <QLabel>
@@ -101,42 +101,39 @@ Console::Console()
m_showDebugButton = new QToolButton(m_consoleWidget);
- m_showDebugButtonAction = new Utils::SavedAction(this);
- m_showDebugButtonAction->setDefaultValue(true);
- m_showDebugButtonAction->setSettingsKey(CONSOLE, SHOW_LOG);
- m_showDebugButtonAction->setToolTip(tr("Show debug, log, and info messages."));
- m_showDebugButtonAction->setCheckable(true);
- m_showDebugButtonAction->setChecked(true);
- m_showDebugButtonAction->setIcon(Utils::Icons::INFO_TOOLBAR.icon());
- connect(m_showDebugButtonAction->action(), &QAction::toggled,
+ m_showDebug.setDefaultValue(true);
+ m_showDebug.setSettingsKey(CONSOLE, SHOW_LOG);
+ m_showDebug.setLabelText(tr("Show debug, log, and info messages."));
+ m_showDebug.setToolTip(tr("Show debug, log, and info messages."));
+ m_showDebug.setValue(true);
+ m_showDebug.action()->setIcon(Utils::Icons::INFO_TOOLBAR.icon());
+ connect(&m_showDebug, &Utils::BoolAspect::valueChanged,
proxyModel, &ConsoleProxyModel::setShowLogs);
- m_showDebugButton->setDefaultAction(m_showDebugButtonAction->action());
+ m_showDebugButton->setDefaultAction(m_showDebug.action());
m_showWarningButton = new QToolButton(m_consoleWidget);
- m_showWarningButtonAction = new Utils::SavedAction(this);
- m_showWarningButtonAction->setDefaultValue(true);
- m_showWarningButtonAction->setSettingsKey(CONSOLE, SHOW_WARNING);
- m_showWarningButtonAction->setToolTip(tr("Show warning messages."));
- m_showWarningButtonAction->setCheckable(true);
- m_showWarningButtonAction->setChecked(true);
- m_showWarningButtonAction->setIcon(Utils::Icons::WARNING_TOOLBAR.icon());
- connect(m_showWarningButtonAction->action(), &QAction::toggled,
+ m_showWarning.setDefaultValue(true);
+ m_showWarning.setSettingsKey(CONSOLE, SHOW_WARNING);
+ m_showWarning.setLabelText(tr("Show warning messages."));
+ m_showWarning.setToolTip(tr("Show warning messages."));
+ m_showWarning.setValue(true);
+ m_showWarning.action()->setIcon(Utils::Icons::WARNING_TOOLBAR.icon());
+ connect(m_showWarning.action(), &QAction::toggled,
proxyModel, &ConsoleProxyModel::setShowWarnings);
- m_showWarningButton->setDefaultAction(m_showWarningButtonAction->action());
+ m_showWarningButton->setDefaultAction(m_showWarning.action());
m_showErrorButton = new QToolButton(m_consoleWidget);
- m_showErrorButtonAction = new Utils::SavedAction(this);
- m_showErrorButtonAction->setDefaultValue(true);
- m_showErrorButtonAction->setSettingsKey(CONSOLE, SHOW_ERROR);
- m_showErrorButtonAction->setToolTip(tr("Show error messages."));
- m_showErrorButtonAction->setCheckable(true);
- m_showErrorButtonAction->setChecked(true);
- m_showErrorButtonAction->setIcon(Utils::Icons::CRITICAL_TOOLBAR.icon());
- connect(m_showErrorButtonAction->action(), &QAction::toggled,
+ m_showError.setDefaultValue(true);
+ m_showError.setSettingsKey(CONSOLE, SHOW_ERROR);
+ m_showError.setLabelText(tr("Show error messages."));
+ m_showError.setToolTip(tr("Show error messages."));
+ m_showError.setValue(true);
+ m_showError.action()->setIcon(Utils::Icons::CRITICAL_TOOLBAR.icon());
+ connect(m_showError.action(), &QAction::toggled,
proxyModel, &ConsoleProxyModel::setShowErrors);
- m_showErrorButton->setDefaultAction(m_showErrorButtonAction->action());
+ m_showErrorButton->setDefaultAction(m_showError.action());
m_spacer = new QWidget(m_consoleWidget);
m_spacer->setMinimumWidth(30);
@@ -221,9 +218,9 @@ bool Console::canNavigate() const
void Console::readSettings()
{
QSettings *settings = Core::ICore::settings();
- m_showDebugButtonAction->readSettings(settings);
- m_showWarningButtonAction->readSettings(settings);
- m_showErrorButtonAction->readSettings(settings);
+ m_showDebug.readSettings(settings);
+ m_showWarning.readSettings(settings);
+ m_showError.readSettings(settings);
}
void Console::setContext(const QString &context)
@@ -234,9 +231,9 @@ void Console::setContext(const QString &context)
void Console::writeSettings() const
{
QSettings *settings = Core::ICore::settings();
- m_showDebugButtonAction->writeSettings(settings);
- m_showWarningButtonAction->writeSettings(settings);
- m_showErrorButtonAction->writeSettings(settings);
+ m_showDebug.writeSettings(settings);
+ m_showWarning.writeSettings(settings);
+ m_showError.writeSettings(settings);
}
void Console::setScriptEvaluator(const ScriptEvaluator &evaluator)
diff --git a/src/plugins/debugger/console/console.h b/src/plugins/debugger/console/console.h
index 21fbc277b5..eee5185195 100644
--- a/src/plugins/debugger/console/console.h
+++ b/src/plugins/debugger/console/console.h
@@ -28,6 +28,7 @@
#include "consoleitem.h"
#include <coreplugin/ioutputpane.h>
+#include <utils/aspects.h>
#include <functional>
@@ -38,7 +39,7 @@ class QToolButton;
class QLabel;
QT_END_NAMESPACE
-namespace Utils { class SavedAction; }
+namespace Utils { class BoolAspect; }
namespace Debugger {
namespace Internal {
@@ -87,9 +88,9 @@ private:
QToolButton *m_showDebugButton;
QToolButton *m_showWarningButton;
QToolButton *m_showErrorButton;
- Utils::SavedAction *m_showDebugButtonAction;
- Utils::SavedAction *m_showWarningButtonAction;
- Utils::SavedAction *m_showErrorButtonAction;
+ Utils::BoolAspect m_showDebug;
+ Utils::BoolAspect m_showWarning;
+ Utils::BoolAspect m_showError;
QWidget *m_spacer;
QLabel *m_statusLabel;
ConsoleItemModel *m_consoleItemModel;
diff --git a/src/plugins/debugger/debugger.qbs b/src/plugins/debugger/debugger.qbs
index 16e9a6cd0c..aee4675f72 100644
--- a/src/plugins/debugger/debugger.qbs
+++ b/src/plugins/debugger/debugger.qbs
@@ -95,7 +95,6 @@ Project {
files: [
"cdbengine.cpp", "cdbengine.h",
"cdboptionspage.cpp", "cdboptionspage.h",
- "cdboptionspagewidget.ui",
"cdbparsehelpers.cpp", "cdbparsehelpers.h",
"stringinputstream.cpp", "stringinputstream.h",
]
diff --git a/src/plugins/debugger/debuggeractions.cpp b/src/plugins/debugger/debuggeractions.cpp
index 14f571ab31..9dd8475f00 100644
--- a/src/plugins/debugger/debuggeractions.cpp
+++ b/src/plugins/debugger/debuggeractions.cpp
@@ -24,672 +24,666 @@
****************************************************************************/
#include "debuggeractions.h"
+
+#include "commonoptionspage.h"
#include "debuggericons.h"
+#include "debuggerinternalconstants.h"
#ifdef Q_OS_WIN
#include "registerpostmortemaction.h"
#endif
+#include <app/app_version.h>
+
#include <coreplugin/coreconstants.h>
#include <coreplugin/icore.h>
-#include <utils/savedaction.h>
+
#include <utils/qtcassert.h>
#include <QDebug>
-#include <QSettings>
using namespace Utils;
-static const char debugModeSettingsGroupC[] = "DebugMode";
-static const char cdbSettingsGroupC[] = "CDB2";
-static const char sourcePathMappingArrayNameC[] = "SourcePathMappings";
-static const char sourcePathMappingSourceKeyC[] = "Source";
-static const char sourcePathMappingTargetKeyC[] = "Target";
+const char debugModeSettingsGroupC[] = "DebugMode";
+const char cdbSettingsGroupC[] = "CDB2";
namespace Debugger {
namespace Internal {
-void GlobalDebuggerOptions::toSettings() const
-{
- QSettings *s = Core::ICore::settings();
- s->beginWriteArray(sourcePathMappingArrayNameC);
- if (!sourcePathMap.isEmpty() || !sourcePathRegExpMap.isEmpty()) {
- const QString sourcePathMappingSourceKey(sourcePathMappingSourceKeyC);
- const QString sourcePathMappingTargetKey(sourcePathMappingTargetKeyC);
- int i = 0;
- for (auto it = sourcePathMap.constBegin(), cend = sourcePathMap.constEnd();
- it != cend;
- ++it, ++i) {
- s->setArrayIndex(i);
- s->setValue(sourcePathMappingSourceKey, it.key());
- s->setValue(sourcePathMappingTargetKey, it.value());
- }
- for (auto it = sourcePathRegExpMap.constBegin(), cend = sourcePathRegExpMap.constEnd();
- it != cend;
- ++it, ++i) {
- s->setArrayIndex(i);
- s->setValue(sourcePathMappingSourceKey, it->first.pattern());
- s->setValue(sourcePathMappingTargetKey, it->second);
- }
- }
- s->endArray();
-}
-
-void GlobalDebuggerOptions::fromSettings()
-{
- QSettings *s = Core::ICore::settings();
- sourcePathMap.clear();
- if (const int count = s->beginReadArray(sourcePathMappingArrayNameC)) {
- const QString sourcePathMappingSourceKey(sourcePathMappingSourceKeyC);
- const QString sourcePathMappingTargetKey(sourcePathMappingTargetKeyC);
- for (int i = 0; i < count; ++i) {
- s->setArrayIndex(i);
- const QString key = s->value(sourcePathMappingSourceKey).toString();
- const QString value = s->value(sourcePathMappingTargetKey).toString();
- if (key.startsWith('('))
- sourcePathRegExpMap.append(qMakePair(QRegularExpression(key), value));
- else
- sourcePathMap.insert(key, value);
- }
- }
- s->endArray();
-}
-
//////////////////////////////////////////////////////////////////////////
//
// DebuggerSettings
//
//////////////////////////////////////////////////////////////////////////
-static DebuggerSettings *theDebuggerSettings = nullptr;
+static DebuggerSettings *theDebuggerSettings_ = nullptr;
+
+DebuggerSettings *debuggerSettings()
+{
+ QTC_CHECK(theDebuggerSettings_);
+ return theDebuggerSettings_;
+}
DebuggerSettings::DebuggerSettings()
{
- theDebuggerSettings = this;
+ theDebuggerSettings_ = this;
const QString debugModeGroup(debugModeSettingsGroupC);
const QString cdbSettingsGroup(cdbSettingsGroupC);
- SavedAction *item = nullptr;
+ settingsDialog.setLabelText(tr("Configure Debugger..."));
+
+ /*
+ groupBoxPluginDebugging = new QGroupBox(q);
+ groupBoxPluginDebugging->setTitle(GdbOptionsPage::tr(
+ "Behavior of Breakpoint Setting in Plugins"));
+
+ radioButtonAllPluginBreakpoints = new QRadioButton(groupBoxPluginDebugging);
+ radioButtonAllPluginBreakpoints->setText(GdbOptionsPage::tr(
+ "Always try to set breakpoints in plugins automatically"));
+ radioButtonAllPluginBreakpoints->setToolTip(GdbOptionsPage::tr(
+ "This is the slowest but safest option."));
+
+ radioButtonSelectedPluginBreakpoints = new QRadioButton(groupBoxPluginDebugging);
+ radioButtonSelectedPluginBreakpoints->setText(GdbOptionsPage::tr(
+ "Try to set breakpoints in selected plugins"));
+
+ radioButtonNoPluginBreakpoints = new QRadioButton(groupBoxPluginDebugging);
+ radioButtonNoPluginBreakpoints->setText(GdbOptionsPage::tr(
+ "Never set breakpoints in plugins automatically"));
+
+ lineEditSelectedPluginBreakpointsPattern = new QLineEdit(groupBoxPluginDebugging);
- item = new SavedAction;
- insertItem(SettingsDialog, item);
- item->setText(tr("Configure Debugger..."));
+ labelSelectedPluginBreakpoints = new QLabel(groupBoxPluginDebugging);
+ labelSelectedPluginBreakpoints->setText(GdbOptionsPage::tr(
+ "Matching regular expression: "));
+ */
//
// View
//
- item = new SavedAction;
- item->setText(tr("Always Adjust View Column Widths to Contents"));
- item->setCheckable(true);
- item->setValue(true);
- item->setDefaultValue(true);
- item->setSettingsKey(debugModeGroup, "AlwaysAdjustColumnWidths");
- insertItem(AlwaysAdjustColumnWidths, item);
+ alwaysAdjustColumnWidths.setLabelText(tr("Always Adjust View Column Widths to Contents"));
+ alwaysAdjustColumnWidths.setSettingsKey(debugModeGroup, "AlwaysAdjustColumnWidths");
+ alwaysAdjustColumnWidths.setDefaultValue(true);
// Needed by QML Inspector
- item = new SavedAction;
- item->setText(tr("Use Alternating Row Colors"));
- item->setSettingsKey(debugModeGroup, "UseAlternatingRowColours");
- item->setCheckable(true);
- item->setDefaultValue(false);
- insertItem(UseAlternatingRowColors, item);
-
- item = new SavedAction;
- item->setText(tr("Keep Editor Stationary When Stepping"));
- item->setSettingsKey(debugModeGroup, "StationaryEditorWhileStepping");
- item->setCheckable(true);
- item->setDefaultValue(false);
- insertItem(StationaryEditorWhileStepping, item);
-
- item = new SavedAction;
- item->setText(tr("Debugger Font Size Follows Main Editor"));
- item->setSettingsKey(debugModeGroup, "FontSizeFollowsEditor");
- item->setCheckable(true);
- item->setDefaultValue(false);
- insertItem(FontSizeFollowsEditor, item);
-
- item = new SavedAction;
- item->setText(tr("Show a Message Box When Receiving a Signal"));
- item->setSettingsKey(debugModeGroup, "UseMessageBoxForSignals");
- item->setCheckable(true);
- item->setDefaultValue(true);
- item->setValue(true);
- insertItem(UseMessageBoxForSignals, item);
-
- item = new SavedAction;
- item->setText(tr("Log Time Stamps"));
- item->setSettingsKey(debugModeGroup, "LogTimeStamps");
- item->setCheckable(true);
- item->setDefaultValue(false);
- insertItem(LogTimeStamps, item);
-
- item = new SavedAction;
- item->setText(tr("Dereference Pointers Automatically"));
- item->setCheckable(true);
- item->setDefaultValue(true);
- item->setSettingsKey(debugModeGroup, "AutoDerefPointers");
- item->setToolTip(tr("<p>This switches the Locals and Expressions views to "
+ //useAlternatingRowColors.setLabelText(tr("Use Alternating Row Colors"));
+ useAlternatingRowColors.setSettingsKey(debugModeGroup, "UseAlternatingRowColours");
+ useAlternatingRowColors.setLabelText(tr("Use alternating row colors in debug views"));
+
+ stationaryEditorWhileStepping.setSettingsKey(debugModeGroup, "StationaryEditorWhileStepping");
+ stationaryEditorWhileStepping.setLabelText(tr("Keep editor stationary when stepping"));
+ stationaryEditorWhileStepping.setToolTip(tr("Scrolls the editor only when it is necessary "
+ "to keep the current line in view, "
+ "instead of keeping the next statement centered at "
+ "all times."));
+
+ forceLoggingToConsole.setSettingsKey(debugModeGroup, "ForceLoggingToConsole");
+ forceLoggingToConsole.setLabelText(tr("Force logging to console"));
+ forceLoggingToConsole.setToolTip(tr("This sets QT_LOGGING_TO_CONSOLE=1 in the environment "
+ "of the debugged program, preventing storing debug output "
+ "in system logs."));
+
+ fontSizeFollowsEditor.setSettingsKey(debugModeGroup, "FontSizeFollowsEditor");
+ fontSizeFollowsEditor.setToolTip(tr("Changes the font size in the debugger views when"
+ "the font size in the main editor changes."));
+ fontSizeFollowsEditor.setLabelText(tr("Debugger font size follows main editor"));
+
+ useMessageBoxForSignals.setSettingsKey(debugModeGroup, "UseMessageBoxForSignals");
+ useMessageBoxForSignals.setDefaultValue(true);
+ useMessageBoxForSignals.setLabelText(/*GdbOptionsPage::*/tr(
+ "Show a message box when receiving a signal"));
+ useMessageBoxForSignals.setToolTip(/*GdbOptionsPage::*/tr(
+ "Displays a message box as soon as your application\n"
+ "receives a signal like SIGSEGV during debugging."));
+
+ logTimeStamps.setLabelText(tr("Log Time Stamps"));
+ logTimeStamps.setSettingsKey(debugModeGroup, "LogTimeStamps");
+
+ autoDerefPointers.setLabelText(tr("Dereference Pointers Automatically"));
+ autoDerefPointers.setDefaultValue(true);
+ autoDerefPointers.setSettingsKey(debugModeGroup, "AutoDerefPointers");
+ autoDerefPointers.setToolTip(tr("<p>This switches the Locals and Expressions views to "
"automatically dereference pointers. This saves a level in the "
"tree view, but also loses data for the now-missing intermediate "
"level."));
- insertItem(AutoDerefPointers, item);
//
// Cdb Options
//
- item = new SavedAction;
- item->setDefaultValue(QString());
- item->setSettingsKey(cdbSettingsGroup, "AdditionalArguments");
- insertItem(CdbAdditionalArguments, item);
-
- item = new SavedAction;
- item->setDefaultValue(QStringList());
- item->setSettingsKey(cdbSettingsGroup, "SymbolPaths");
- insertItem(CdbSymbolPaths, item);
-
- item = new SavedAction;
- item->setDefaultValue(QStringList());
- item->setSettingsKey(cdbSettingsGroup, "SourcePaths");
- insertItem(CdbSourcePaths, item);
-
- item = new SavedAction;
- item->setDefaultValue(QStringList());
- item->setSettingsKey(cdbSettingsGroup, "BreakEvent");
- insertItem(CdbBreakEvents, item);
-
- item = new SavedAction;
- item->setCheckable(true);
- item->setDefaultValue(false);
- item->setSettingsKey(cdbSettingsGroup, "BreakOnCrtDbgReport");
- insertItem(CdbBreakOnCrtDbgReport, item);
-
- item = new SavedAction;
- item->setCheckable(true);
- item->setDefaultValue(false);
- item->setSettingsKey(cdbSettingsGroup, "CDB_Console");
- insertItem(UseCdbConsole, item);
-
- item = new SavedAction;
- item->setCheckable(true);
- item->setDefaultValue(true);
- item->setSettingsKey(cdbSettingsGroup, "BreakpointCorrection");
- insertItem(CdbBreakPointCorrection, item);
-
- item = new SavedAction;
- item->setCheckable(true);
- item->setDefaultValue(true);
- item->setSettingsKey(cdbSettingsGroup, "UsePythonDumper");
- insertItem(CdbUsePythonDumper, item);
-
- item = new SavedAction;
- item->setCheckable(true);
- item->setDefaultValue(true);
- item->setSettingsKey(cdbSettingsGroup, "FirstChanceExceptionTaskEntry");
- insertItem(FirstChanceExceptionTaskEntry, item);
-
- item = new SavedAction;
- item->setCheckable(true);
- item->setDefaultValue(true);
- item->setSettingsKey(cdbSettingsGroup, "SecondChanceExceptionTaskEntry");
- insertItem(SecondChanceExceptionTaskEntry, item);
-
- item = new SavedAction;
- item->setCheckable(true);
- item->setDefaultValue(false);
- item->setSettingsKey(cdbSettingsGroup, "IgnoreFirstChanceAccessViolation");
- insertItem(IgnoreFirstChanceAccessViolation, item);
+ cdbAdditionalArguments.setSettingsKey(cdbSettingsGroup, "AdditionalArguments");
+ cdbAdditionalArguments.setDisplayStyle(StringAspect::LineEditDisplay);
+ cdbAdditionalArguments.setLabelText(tr("Additional arguments:"));
+
+ cdbSymbolPaths.setSettingsKey(cdbSettingsGroup, "SymbolPaths");
+ cdbSourcePaths.setSettingsKey(cdbSettingsGroup, "SourcePaths");
+
+ cdbBreakEvents.setSettingsKey(cdbSettingsGroup, "BreakEvent");
+ cdbBreakOnCrtDbgReport.setSettingsKey(cdbSettingsGroup, "BreakOnCrtDbgReport");
+ cdbBreakOnCrtDbgReport.setLabelText(
+ CommonOptionsPage::msgSetBreakpointAtFunction(Constants::CRT_DEBUG_REPORT));
+ cdbBreakOnCrtDbgReport.setToolTip(
+ CommonOptionsPage::msgSetBreakpointAtFunctionToolTip(Constants::CRT_DEBUG_REPORT,
+ tr("This is useful to catch runtime error messages for example caused by assert().")));
+
+ useCdbConsole.setSettingsKey(cdbSettingsGroup, "CDB_Console");
+ useCdbConsole.setToolTip("<html><head/><body><p>" + tr(
+ "Uses CDB's native console for console applications. "
+ "This overrides the setting in Environment > System. "
+ "The native console does not prompt on application exit. "
+ "It is suitable for diagnosing cases in which the application does not "
+ "start up properly in the configured console and the subsequent attach fails.")
+ + "</p></body></html>");
+ useCdbConsole.setLabelText(tr("Use CDB &console"));
+
+ cdbBreakPointCorrection.setSettingsKey(cdbSettingsGroup, "BreakpointCorrection");
+ cdbBreakPointCorrection.setDefaultValue(true);
+ cdbBreakPointCorrection.setToolTip("<html><head/><body><p>" + tr(
+ "Attempts to correct the location of a breakpoint based on file and line number should"
+ "it be in a comment or in a line for which no code is generated. "
+ "The correction is based on the code model.") + "</p></body></html>");
+ cdbBreakPointCorrection.setLabelText(tr("Correct breakpoint location"));
+
+ cdbUsePythonDumper.setSettingsKey(cdbSettingsGroup, "UsePythonDumper");
+ cdbUsePythonDumper.setDefaultValue(true);
+ cdbUsePythonDumper.setLabelText(tr("Use Python dumper"));
+
+ firstChanceExceptionTaskEntry.setSettingsKey(cdbSettingsGroup, "FirstChanceExceptionTaskEntry");
+ firstChanceExceptionTaskEntry.setDefaultValue(true);
+ firstChanceExceptionTaskEntry.setLabelText(tr("First chance exceptions"));
+
+ secondChanceExceptionTaskEntry.setSettingsKey(cdbSettingsGroup, "SecondChanceExceptionTaskEntry");
+ secondChanceExceptionTaskEntry.setDefaultValue(true);
+ secondChanceExceptionTaskEntry.setLabelText(tr("Second chance exceptions"));
+
+ ignoreFirstChanceAccessViolation.setSettingsKey(cdbSettingsGroup, "IgnoreFirstChanceAccessViolation");
+ ignoreFirstChanceAccessViolation.setLabelText(tr("Ignore first chance access violations"));
//
// Locals & Watchers
//
- item = new SavedAction;
- item->setSettingsKey(debugModeGroup, "ShowStandardNamespace");
- item->setText(tr("Show \"std::\" Namespace in Types"));
- item->setDialogText(tr("Show \"std::\" namespace in types"));
- item->setToolTip(tr("<p>Shows \"std::\" prefix for types from the standard library."));
- item->setCheckable(true);
- item->setDefaultValue(true);
- item->setValue(true);
- insertItem(ShowStdNamespace, item);
-
- item = new SavedAction;
- item->setSettingsKey(debugModeGroup, "ShowQtNamespace");
- item->setText(tr("Show Qt's Namespace in Types"));
- item->setDialogText(tr("Show Qt's namespace in types"));
- item->setToolTip(tr("<p>Shows Qt namespace prefix for Qt types. This is only "
+ showStdNamespace.setSettingsKey(debugModeGroup, "ShowStandardNamespace");
+ showStdNamespace.setDefaultValue(true);
+ showStdNamespace.setDisplayName(tr("Show \"std::\" Namespace in Types"));
+ showStdNamespace.setLabelText(tr("Show \"std::\" namespace in types"));
+ showStdNamespace.setToolTip(tr("<p>Shows \"std::\" prefix for types from the standard library."));
+
+ showQtNamespace.setSettingsKey(debugModeGroup, "ShowQtNamespace");
+ showQtNamespace.setDefaultValue(true);
+ showQtNamespace.setDisplayName(tr("Show Qt's Namespace in Types"));
+ showQtNamespace.setLabelText(tr("Show Qt's namespace in types"));
+ showQtNamespace.setToolTip(tr("<p>Shows Qt namespace prefix for Qt types. This is only "
"relevant if Qt was configured with \"-qtnamespace\"."));
- item->setCheckable(true);
- item->setDefaultValue(true);
- item->setValue(true);
- insertItem(ShowQtNamespace, item);
-
- item = new SavedAction;
- item->setSettingsKey(debugModeGroup, "ShowQObjectNames2");
- item->setText(tr("Show QObject names if available"));
- item->setDialogText(tr("Show QObject names if available"));
- item->setToolTip(tr("<p>Displays the objectName property of QObject based items. "
+
+ showQObjectNames.setSettingsKey(debugModeGroup, "ShowQObjectNames2");
+ showQObjectNames.setDefaultValue(true);
+ showQObjectNames.setDisplayName(tr("Show QObject names if available"));
+ showQObjectNames.setLabelText(tr("Show QObject names if available"));
+ showQObjectNames.setToolTip(tr("<p>Displays the objectName property of QObject based items. "
"Note that this can negatively impact debugger performance "
"even if no QObjects are present."));
- item->setCheckable(true);
- item->setDefaultValue(true);
- item->setValue(true);
- insertItem(ShowQObjectNames, item);
-
- item = new SavedAction;
- item->setSettingsKey(debugModeGroup, "SortStructMembers");
- item->setText(tr("Sort Members of Classes and Structs Alphabetically"));
- item->setDialogText(tr("Sort members of classes and structs alphabetically"));
- item->setCheckable(true);
- item->setDefaultValue(true);
- item->setValue(true);
- insertItem(SortStructMembers, item);
+
+ sortStructMembers.setSettingsKey(debugModeGroup, "SortStructMembers");
+ sortStructMembers.setDisplayName(tr("Sort Members of Classes and Structs Alphabetically"));
+ sortStructMembers.setLabelText(tr("Sort members of classes and structs alphabetically"));
+ sortStructMembers.setDefaultValue(true);
//
// DebuggingHelper
//
- item = new SavedAction;
- item->setSettingsKey(debugModeGroup, "UseDebuggingHelper");
- item->setText(tr("Use Debugging Helpers"));
- item->setCheckable(true);
- item->setDefaultValue(true);
- item->setValue(true);
- insertItem(UseDebuggingHelpers, item);
-
- item = new SavedAction;
- item->setSettingsKey(debugModeGroup, "UseCodeModel");
- item->setDialogText(tr("Use code model"));
- item->setToolTip(tr("<p>Selecting this causes the C++ Code Model being asked "
+ useDebuggingHelpers.setSettingsKey(debugModeGroup, "UseDebuggingHelper");
+ useDebuggingHelpers.setDefaultValue(true);
+ useDebuggingHelpers.setLabelText(tr("Use Debugging Helpers"));
+
+ useCodeModel.setSettingsKey(debugModeGroup, "UseCodeModel");
+ useCodeModel.setDefaultValue(true);
+ useCodeModel.setLabelText(tr("Use code model"));
+ useCodeModel.setToolTip(tr("<p>Selecting this causes the C++ Code Model being asked "
"for variable scope information. This might result in slightly faster "
"debugger operation but may fail for optimized code."));
- item->setCheckable(true);
- item->setDefaultValue(true);
- item->setValue(true);
- insertItem(UseCodeModel, item);
- item = new SavedAction;
- item->setSettingsKey(debugModeGroup, "ShowThreadNames");
- item->setToolTip(tr("<p>Displays names of QThread based threads."));
- item->setDialogText(tr("Display thread names"));
- item->setCheckable(true);
- item->setDefaultValue(false);
- item->setValue(false);
- insertItem(ShowThreadNames, item);
+ showThreadNames.setSettingsKey(debugModeGroup, "ShowThreadNames");
+ showThreadNames.setLabelText(tr("Display thread names"));
+ showThreadNames.setToolTip(tr("<p>Displays names of QThread based threads."));
//
// Breakpoints
//
- item = new SavedAction;
- item->setText(tr("Synchronize Breakpoints"));
- insertItem(SynchronizeBreakpoints, item);
+ synchronizeBreakpoints.setLabelText(tr("Synchronize Breakpoints"));
- item = new SavedAction;
- item->setText(tr("Adjust Breakpoint Locations"));
- item->setToolTip(tr("<p>Not all source code lines generate "
+ adjustBreakpointLocations.setDisplayName(tr("Adjust Breakpoint Locations"));
+ adjustBreakpointLocations.setToolTip(tr("<p>Not all source code lines generate "
"executable code. Putting a breakpoint on such a line acts as "
"if the breakpoint was set on the next line that generated code. "
"Selecting 'Adjust Breakpoint Locations' shifts the red "
"breakpoint markers in such cases to the location of the true "
"breakpoint."));
- item->setCheckable(true);
- item->setDefaultValue(true);
- item->setValue(true);
- item->setSettingsKey(debugModeGroup, "AdjustBreakpointLocations");
- insertItem(AdjustBreakpointLocations, item);
-
- item = new SavedAction;
- item->setText(tr("Break on \"throw\""));
- item->setCheckable(true);
- item->setDefaultValue(false);
- item->setValue(false);
- item->setSettingsKey(debugModeGroup, "BreakOnThrow");
- insertItem(BreakOnThrow, item);
-
- item = new SavedAction;
- item->setText(tr("Break on \"catch\""));
- item->setCheckable(true);
- item->setDefaultValue(false);
- item->setValue(false);
- item->setSettingsKey(debugModeGroup, "BreakOnCatch");
- insertItem(BreakOnCatch, item);
-
- item = new SavedAction;
- item->setText(tr("Break on \"qWarning\""));
- item->setCheckable(true);
- item->setDefaultValue(false);
- item->setValue(false);
- item->setSettingsKey(debugModeGroup, "BreakOnWarning");
- insertItem(BreakOnWarning, item);
-
- item = new SavedAction;
- item->setText(tr("Break on \"qFatal\""));
- item->setCheckable(true);
- item->setDefaultValue(false);
- item->setValue(false);
- item->setSettingsKey(debugModeGroup, "BreakOnFatal");
- insertItem(BreakOnFatal, item);
-
- item = new SavedAction;
- item->setText(tr("Break on \"abort\""));
- item->setCheckable(true);
- item->setDefaultValue(false);
- item->setValue(false);
- item->setSettingsKey(debugModeGroup, "BreakOnAbort");
- insertItem(BreakOnAbort, item);
+ adjustBreakpointLocations.setDefaultValue(true);
+ adjustBreakpointLocations.setSettingsKey(debugModeGroup, "AdjustBreakpointLocations");
+ adjustBreakpointLocations.setLabelText(/*GdbOptionsPage::*/tr(
+ "Adjust breakpoint locations"));
+ adjustBreakpointLocations.setToolTip(/*GdbOptionsPage::*/tr(
+ "GDB allows setting breakpoints on source lines for which no code \n"
+ "was generated. In such situations the breakpoint is shifted to the\n"
+ "next source code line for which code was actually generated.\n"
+ "This option reflects such temporary change by moving the breakpoint\n"
+ "markers in the source code editor."));
+
+
+ breakOnThrow.setLabelText(tr("Break on \"throw\""));
+ breakOnThrow.setSettingsKey(debugModeGroup, "BreakOnThrow");
+
+ breakOnCatch.setLabelText(tr("Break on \"catch\""));
+ breakOnCatch.setSettingsKey(debugModeGroup, "BreakOnCatch");
+
+ breakOnWarning.setLabelText(tr("Break on \"qWarning\""));
+ breakOnWarning.setSettingsKey(debugModeGroup, "BreakOnWarning");
+ // FIXME: Move to common settings page.
+ breakOnWarning.setLabelText(CommonOptionsPage::msgSetBreakpointAtFunction("qWarning"));
+ breakOnWarning.setToolTip(CommonOptionsPage::msgSetBreakpointAtFunctionToolTip("qWarning"));
+
+ breakOnFatal.setLabelText(tr("Break on \"qFatal\""));
+ breakOnFatal.setSettingsKey(debugModeGroup, "BreakOnFatal");
+ breakOnFatal.setLabelText(CommonOptionsPage::msgSetBreakpointAtFunction("qFatal"));
+ breakOnFatal.setToolTip(CommonOptionsPage::msgSetBreakpointAtFunctionToolTip("qFatal"));
+
+ breakOnAbort.setLabelText(tr("Break on \"abort\""));
+ breakOnAbort.setSettingsKey(debugModeGroup, "BreakOnAbort");
+ breakOnAbort.setLabelText(CommonOptionsPage::msgSetBreakpointAtFunction("abort"));
+ breakOnAbort.setToolTip(CommonOptionsPage::msgSetBreakpointAtFunctionToolTip("abort"));
//
// Settings
//
- item = new SavedAction;
- item->setSettingsKey(debugModeGroup, "LoadGdbInit");
- item->setDefaultValue(QString());
- item->setCheckable(true);
- item->setDefaultValue(true);
- item->setValue(true);
- insertItem(LoadGdbInit, item);
-
- item = new SavedAction;
- item->setSettingsKey(debugModeGroup, "LoadGdbDumpers2");
- item->setDefaultValue(QString());
- item->setCheckable(true);
- item->setDefaultValue(false);
- item->setValue(false);
- insertItem(LoadGdbDumpers, item);
-
- item = new SavedAction;
- item->setSettingsKey(debugModeGroup, "AutoEnrichParameters");
- item->setDefaultValue(QString());
- item->setCheckable(true);
- item->setDefaultValue(true);
- item->setValue(true);
- insertItem(AutoEnrichParameters, item);
-
- item = new SavedAction;
- item->setSettingsKey(debugModeGroup, "UseDynamicType");
- item->setText(tr("Use Dynamic Object Type for Display"));
- item->setCheckable(true);
- item->setDefaultValue(true);
- item->setValue(true);
- insertItem(UseDynamicType, item);
-
- item = new SavedAction;
- item->setSettingsKey(debugModeGroup, "TargetAsync");
- item->setCheckable(true);
- item->setDefaultValue(false);
- item->setValue(false);
- insertItem(TargetAsync, item);
-
- item = new SavedAction;
- item->setSettingsKey(debugModeGroup, "WarnOnReleaseBuilds");
- item->setCheckable(true);
- item->setDefaultValue(true);
- insertItem(WarnOnReleaseBuilds, item);
-
- item = new SavedAction;
- item->setSettingsKey(debugModeGroup, "GdbStartupCommands");
- item->setDefaultValue(QString());
- insertItem(GdbStartupCommands, item);
-
- item = new SavedAction;
- item->setSettingsKey(debugModeGroup, "GdbCustomDumperCommands");
- item->setDefaultValue(QString());
- insertItem(ExtraDumperCommands, item);
-
- item = new SavedAction;
- item->setSettingsKey(debugModeGroup, "ExtraDumperFile");
- item->setDefaultValue(QString());
- insertItem(ExtraDumperFile, item);
-
- item = new SavedAction;
- item->setSettingsKey(debugModeGroup, "GdbPostAttachCommands");
- item->setDefaultValue(QString());
- insertItem(GdbPostAttachCommands, item);
-
- item = new SavedAction;
- item->setSettingsKey(debugModeGroup, "CloseBuffersOnExit");
- item->setCheckable(true);
- item->setDefaultValue(false);
- insertItem(CloseSourceBuffersOnExit, item);
-
- item = new SavedAction;
- item->setSettingsKey(debugModeGroup, "CloseMemoryBuffersOnExit");
- item->setCheckable(true);
- item->setDefaultValue(true);
- insertItem(CloseMemoryBuffersOnExit, item);
-
- item = new SavedAction;
- item->setSettingsKey(debugModeGroup, "SwitchModeOnExit");
- item->setCheckable(true);
- item->setDefaultValue(false);
- insertItem(SwitchModeOnExit, item);
-
- item = new SavedAction;
- item->setSettingsKey(debugModeGroup, "BreakpointsFullPath");
- item->setCheckable(true);
- item->setDefaultValue(false);
- insertItem(BreakpointsFullPathByDefault, item);
-
- item = new SavedAction;
- item->setSettingsKey(debugModeGroup, "RaiseOnInterrupt");
- item->setCheckable(true);
- item->setDefaultValue(true);
- insertItem(RaiseOnInterrupt, item);
-
- item = new SavedAction;
- item->setSettingsKey(debugModeGroup, "AutoQuit");
- item->setText(tr("Automatically Quit Debugger"));
- item->setCheckable(true);
- item->setDefaultValue(false);
- insertItem(AutoQuit, item);
-
- item = new SavedAction;
- item->setSettingsKey(debugModeGroup, "MultiInferior");
- item->setCheckable(true);
- item->setDefaultValue(false);
- insertItem(MultiInferior, item);
-
- item = new SavedAction;
- item->setSettingsKey(debugModeGroup, "IntelFlavor");
- item->setCheckable(true);
- item->setDefaultValue(false);
- insertItem(IntelFlavor, item);
-
- item = new SavedAction;
- item->setSettingsKey(debugModeGroup, "UseAnnotations");
- item->setText(tr("Use annotations in main editor when debugging"));
- item->setToolTip(tr("<p>Checking this will show simple variable values "
+ loadGdbInit.setSettingsKey(debugModeGroup, "LoadGdbInit");
+ loadGdbInit.setDefaultValue(true);
+ loadGdbInit.setLabelText(/*GdbOptionsPage::*/tr("Load .gdbinit file on startup"));
+ loadGdbInit.setToolTip(/*GdbOptionsPage::*/tr(
+ "Allows or inhibits reading the user's default\n"
+ ".gdbinit file on debugger startup."));
+
+ loadGdbDumpers.setSettingsKey(debugModeGroup, "LoadGdbDumpers2");
+ loadGdbDumpers.setLabelText(/*GdbOptionsPage::*/tr("Load system GDB pretty printers"));
+ loadGdbDumpers.setToolTip(/*GdbOptionsPage::*/tr(
+ "Uses the default GDB pretty printers installed in your "
+ "system or linked to the libraries your application uses."));
+
+ autoEnrichParameters.setSettingsKey(debugModeGroup, "AutoEnrichParameters");
+ autoEnrichParameters.setDefaultValue(true);
+ autoEnrichParameters.setLabelText(/*GdbOptionsPage::*/tr(
+ "Use common locations for debug information"));
+ autoEnrichParameters.setToolTip(/*GdbOptionsPage::*/tr(
+ "<html><head/><body>Adds common paths to locations "
+ "of debug information such as <i>/usr/src/debug</i> "
+ "when starting GDB.</body></html>"));
+
+ useDynamicType.setSettingsKey(debugModeGroup, "UseDynamicType");
+ useDynamicType.setDefaultValue(true);
+ useDynamicType.setDisplayName(tr("Use Dynamic Object Type for Display"));
+ useDynamicType.setLabelText(/*GdbOptionsPage::*/tr(
+ "Use dynamic object type for display"));
+ useDynamicType.setToolTip(/*GdbOptionsPage::*/tr(
+ "Specifies whether the dynamic or the static type of objects will be "
+ "displayed. Choosing the dynamic type might be slower."));
+
+ targetAsync.setSettingsKey(debugModeGroup, "TargetAsync");
+ targetAsync.setLabelText(/*GdbOptionsPage::*/tr(
+ "Use asynchronous mode to control the inferior"));
+
+ warnOnReleaseBuilds.setSettingsKey(debugModeGroup, "WarnOnReleaseBuilds");
+ warnOnReleaseBuilds.setDefaultValue(true);
+ warnOnReleaseBuilds.setLabelText(tr("Warn when debugging \"Release\" builds"));
+ warnOnReleaseBuilds.setToolTip(tr("Shows a warning when starting the debugger "
+ "on a binary with insufficient debug information."));
+
+ QString howToUsePython = /*GdbOptionsPage::*/tr(
+ "<p>To execute simple Python commands, prefix them with \"python\".</p>"
+ "<p>To execute sequences of Python commands spanning multiple lines "
+ "prepend the block with \"python\" on a separate line, and append "
+ "\"end\" on a separate line.</p>"
+ "<p>To execute arbitrary Python scripts, "
+ "use <i>python execfile('/path/to/script.py')</i>.</p>");
+
+ gdbStartupCommands.setSettingsKey(debugModeGroup, "GdbStartupCommands");
+ gdbStartupCommands.setDisplayStyle(StringAspect::TextEditDisplay);
+ gdbStartupCommands.setUseGlobalMacroExpander();
+ gdbStartupCommands.setToolTip("<html><head/><body><p>" + /*GdbOptionsPage::*/tr(
+ "GDB commands entered here will be executed after "
+ "GDB has been started, but before the debugged program is started or "
+ "attached, and before the debugging helpers are initialized.") + "</p>"
+ + howToUsePython + "</body></html>");
+
+ gdbPostAttachCommands.setSettingsKey(debugModeGroup, "GdbPostAttachCommands");
+ gdbPostAttachCommands.setDisplayStyle(StringAspect::TextEditDisplay);
+ gdbPostAttachCommands.setUseGlobalMacroExpander();
+ gdbPostAttachCommands.setToolTip("<html><head/><body><p>" + /*GdbOptionsPage::*/tr(
+ "GDB commands entered here will be executed after "
+ "GDB has successfully attached to remote targets.</p>"
+ "<p>You can add commands to further set up the target here, "
+ "such as \"monitor reset\" or \"load\".") + "</p>"
+ + howToUsePython + "</body></html>");
+
+ extraDumperCommands.setSettingsKey(debugModeGroup, "GdbCustomDumperCommands");
+ extraDumperCommands.setDisplayStyle(StringAspect::TextEditDisplay);
+ extraDumperCommands.setUseGlobalMacroExpander();
+ extraDumperCommands.setToolTip("<html><head/><body><p>"
+ + tr("Python commands entered here will be executed after built-in "
+ "debugging helpers have been loaded and fully initialized. You can "
+ "load additional debugging helpers or modify existing ones here.")
+ + "</p></body></html>");
+
+ extraDumperFile.setSettingsKey(debugModeGroup, "ExtraDumperFile");
+ extraDumperFile.setDisplayStyle(StringAspect::PathChooserDisplay);
+ extraDumperFile.setDisplayName(tr("Extra Debugging Helpers"));
+ // Label text is intentional empty in the GUI.
+ extraDumperFile.setToolTip(tr("Path to a Python file containing additional data dumpers."));
+
+ const QString t = tr("Stopping and stepping in the debugger "
+ "will automatically open views associated with the current location.") + '\n';
+
+ closeSourceBuffersOnExit.setSettingsKey(debugModeGroup, "CloseBuffersOnExit");
+ closeSourceBuffersOnExit.setLabelText(tr("Close temporary source views on debugger exit"));
+ closeSourceBuffersOnExit.setToolTip(t + tr("Closes automatically opened source views when the debugger exits."));
+
+ closeMemoryBuffersOnExit.setSettingsKey(debugModeGroup, "CloseMemoryBuffersOnExit");
+ closeMemoryBuffersOnExit.setDefaultValue(true);
+ closeMemoryBuffersOnExit.setLabelText(tr("Close temporary memory views on debugger exit"));
+ closeMemoryBuffersOnExit.setToolTip(t + tr("Closes automatically opened memory views when the debugger exits."));
+
+ switchModeOnExit.setSettingsKey(debugModeGroup, "SwitchModeOnExit");
+ switchModeOnExit.setLabelText(tr("Switch to previous mode on debugger exit"));
+
+ breakpointsFullPathByDefault.setSettingsKey(debugModeGroup, "BreakpointsFullPath");
+ breakpointsFullPathByDefault.setToolTip(tr("Enables a full file path in breakpoints by default also for GDB."));
+ breakpointsFullPathByDefault.setLabelText(tr("Set breakpoints using a full absolute path"));
+
+ raiseOnInterrupt.setSettingsKey(debugModeGroup, "RaiseOnInterrupt");
+ raiseOnInterrupt.setDefaultValue(true);
+ raiseOnInterrupt.setLabelText(tr("Bring %1 to foreground when application interrupts")
+ .arg(Core::Constants::IDE_DISPLAY_NAME));
+
+ autoQuit.setSettingsKey(debugModeGroup, "AutoQuit");
+ autoQuit.setLabelText(tr("Automatically Quit Debugger"));
+
+ multiInferior.setSettingsKey(debugModeGroup, "MultiInferior");
+ multiInferior.setLabelText(/*GdbOptionsPage::*/tr("Debug all child processes"));
+ multiInferior.setToolTip(/*GdbOptionsPage::*/tr(
+ "<html><head/><body>Keeps debugging all children after a fork."
+ "</body></html>"));
+
+ intelFlavor.setSettingsKey(debugModeGroup, "IntelFlavor");
+ intelFlavor.setLabelText(/*GdbOptionsPage::*/tr("Use Intel style disassembly"));
+ intelFlavor.setToolTip(/*GdbOptionsPage::*/tr(
+ "GDB shows by default AT&&T style disassembly."));
+
+ useAnnotationsInMainEditor.setSettingsKey(debugModeGroup, "UseAnnotations");
+ useAnnotationsInMainEditor.setLabelText(tr("Use annotations in main editor when debugging"));
+ useAnnotationsInMainEditor.setToolTip(tr("<p>Checking this will show simple variable values "
"as annotations in the main editor during debugging."));
- item->setCheckable(true);
- item->setDefaultValue(true);
- insertItem(UseAnnotationsInMainEditor, item);
-
- item = new SavedAction;
- item->setSettingsKey(debugModeGroup, "UsePseudoTracepoints");
- item->setCheckable(true);
- item->setDefaultValue(true);
- insertItem(UsePseudoTracepoints, item);
-
- item = new SavedAction;
- item->setSettingsKey(debugModeGroup, "UseToolTips");
- item->setText(tr("Use tooltips in main editor when debugging"));
- item->setToolTip(tr("<p>Checking this will enable tooltips for variable "
+ useAnnotationsInMainEditor.setDefaultValue(true);
+
+ usePseudoTracepoints.setSettingsKey(debugModeGroup, "UsePseudoTracepoints");
+ usePseudoTracepoints.setLabelText(/*GdbOptionsPage::*/tr("Use pseudo message tracepoints"));
+ usePseudoTracepoints.setToolTip(
+ /*GdbOptionsPage::*/ tr("Uses Python to extend the ordinary GDB breakpoint class."));
+ usePseudoTracepoints.setDefaultValue(true);
+
+ useToolTipsInMainEditor.setSettingsKey(debugModeGroup, "UseToolTips");
+ useToolTipsInMainEditor.setLabelText(tr("Use tooltips in main editor when debugging"));
+ useToolTipsInMainEditor.setToolTip(tr("<p>Checking this will enable tooltips for variable "
"values during debugging. Since this can slow down debugging and "
"does not provide reliable information as it does not use scope "
"information, it is switched off by default."));
- item->setCheckable(true);
- item->setDefaultValue(true);
- insertItem(UseToolTipsInMainEditor, item);
-
- item = new SavedAction;
- item->setSettingsKey(debugModeGroup, "UseToolTipsInLocalsView");
- item->setText(tr("Use Tooltips in Locals View when Debugging"));
- item->setToolTip(tr("<p>Checking this will enable tooltips in the locals "
+ useToolTipsInMainEditor.setDefaultValue(true);
+
+ useToolTipsInLocalsView.setSettingsKey(debugModeGroup, "UseToolTipsInLocalsView");
+ useToolTipsInLocalsView.setLabelText(tr("Use Tooltips in Locals View when Debugging"));
+ useToolTipsInLocalsView.setToolTip(tr("<p>Checking this will enable tooltips in the locals "
"view during debugging."));
- item->setCheckable(true);
- item->setDefaultValue(false);
- insertItem(UseToolTipsInLocalsView, item);
-
- item = new SavedAction;
- item->setSettingsKey(debugModeGroup, "UseToolTipsInBreakpointsView");
- item->setText(tr("Use Tooltips in Breakpoints View when Debugging"));
- item->setToolTip(tr("<p>Checking this will enable tooltips in the breakpoints "
+
+ useToolTipsInBreakpointsView.setSettingsKey(debugModeGroup, "UseToolTipsInBreakpointsView");
+ useToolTipsInBreakpointsView.setLabelText(tr("Use Tooltips in Breakpoints View when Debugging"));
+ useToolTipsInBreakpointsView.setToolTip(tr("<p>Checking this will enable tooltips in the breakpoints "
"view during debugging."));
- item->setCheckable(true);
- item->setDefaultValue(false);
- insertItem(UseToolTipsInBreakpointsView, item);
-
- item = new SavedAction;
- item->setSettingsKey(debugModeGroup, "UseToolTipsInStackView");
- item->setText(tr("Use Tooltips in Stack View when Debugging"));
- item->setToolTip(tr("<p>Checking this will enable tooltips in the stack "
+
+ useToolTipsInStackView.setSettingsKey(debugModeGroup, "UseToolTipsInStackView");
+ useToolTipsInStackView.setLabelText(tr("Use Tooltips in Stack View when Debugging"));
+ useToolTipsInStackView.setToolTip(tr("<p>Checking this will enable tooltips in the stack "
"view during debugging."));
- item->setCheckable(true);
- item->setDefaultValue(true);
- insertItem(UseToolTipsInStackView, item);
-
- item = new SavedAction;
- item->setSettingsKey(debugModeGroup, "SkipKnownFrames");
- item->setText(tr("Skip Known Frames"));
- item->setCheckable(true);
- item->setDefaultValue(false);
- insertItem(SkipKnownFrames, item);
-
- item = new SavedAction;
- item->setSettingsKey(debugModeGroup, "EnableReverseDebugging");
- item->setText(tr("Enable Reverse Debugging"));
- item->setCheckable(true);
- item->setDefaultValue(false);
- item->setIcon(Icons::REVERSE_MODE.icon());
- insertItem(EnableReverseDebugging, item);
+ useToolTipsInStackView.setDefaultValue(true);
+
+ skipKnownFrames.setSettingsKey(debugModeGroup, "SkipKnownFrames");
+ skipKnownFrames.setDisplayName(tr("Skip Known Frames"));
+ skipKnownFrames.setLabelText(/*GdbOptionsPage::*/tr("Skip known frames when stepping"));
+ skipKnownFrames.setToolTip(/*GdbOptionsPage::*/tr(
+ "<html><head/><body><p>"
+ "Allows <i>Step Into</i> to compress several steps into one step\n"
+ "for less noisy debugging. For example, the atomic reference\n"
+ "counting code is skipped, and a single <i>Step Into</i> for a signal\n"
+ "emission ends up directly in the slot connected to it."));
+
+ enableReverseDebugging.setSettingsKey(debugModeGroup, "EnableReverseDebugging");
+ enableReverseDebugging.setIcon(Icons::REVERSE_MODE.icon());
+ enableReverseDebugging.setDisplayName(tr("Enable Reverse Debugging"));
+ enableReverseDebugging.setLabelText(/*GdbOptionsPage::*/tr("Enable reverse debugging"));
+ enableReverseDebugging.setToolTip(/*GdbOptionsPage::*/tr(
+ "<html><head/><body><p>Enables stepping backwards.</p><p>"
+ "<b>Note:</b> This feature is very slow and unstable on the GDB side. "
+ "It exhibits unpredictable behavior when going backwards over system "
+ "calls and is very likely to destroy your debugging session.</p></body></html>"));
+
#ifdef Q_OS_WIN
- item = new RegisterPostMortemAction;
- item->setSettingsKey(debugModeGroup, "RegisterForPostMortem");
- item->setText(tr("Register For Post-Mortem Debugging"));
- item->setCheckable(true);
- item->setDefaultValue(false);
- insertItem(RegisterForPostMortem, item);
+ registerForPostMortem = new RegisterPostMortemAction;
+ registerForPostMortem->setSettingsKey(debugModeGroup, "RegisterForPostMortem");
+ registerForPostMortem->setToolTip(
+ tr("Registers %1 for debugging crashed applications.")
+ .arg(Core::Constants::IDE_DISPLAY_NAME));
+ registerForPostMortem->setLabelText(
+ tr("Use %1 for post-mortem debugging")
+ .arg(Core::Constants::IDE_DISPLAY_NAME));
+#else
+ // Some dummy.
+ registerForPostMortem = new BoolAspect;
+ registerForPostMortem->setVisible(false);
#endif
- item = new SavedAction;
- item->setSettingsKey(debugModeGroup, "AllPluginBreakpoints");
- item->setDefaultValue(true);
- insertItem(AllPluginBreakpoints, item);
-
- item = new SavedAction;
- item->setSettingsKey(debugModeGroup, "SelectedPluginBreakpoints");
- item->setDefaultValue(false);
- insertItem(SelectedPluginBreakpoints, item);
-
- item = new SavedAction;
- item->setSettingsKey(debugModeGroup, "NoPluginBreakpoints");
- item->setDefaultValue(false);
- insertItem(NoPluginBreakpoints, item);
-
- item = new SavedAction;
- item->setSettingsKey(debugModeGroup, "SelectedPluginBreakpointsPattern");
- item->setDefaultValue(".*");
- insertItem(SelectedPluginBreakpointsPattern, item);
-
- item = new SavedAction;
- item->setSettingsKey(debugModeGroup, "MaximalStackDepth");
- item->setDefaultValue(20);
- insertItem(MaximalStackDepth, item);
-
- item = new SavedAction;
- item->setSettingsKey(debugModeGroup, "DisplayStringLimit");
- item->setToolTip(tr("<p>The maximum length of string entries in the "
+ allPluginBreakpoints.setSettingsKey(debugModeGroup, "AllPluginBreakpoints");
+ allPluginBreakpoints.setDefaultValue(true);
+
+ selectedPluginBreakpoints.setSettingsKey(debugModeGroup, "SelectedPluginBreakpoints");
+
+ noPluginBreakpoints.setSettingsKey(debugModeGroup, "NoPluginBreakpoints");
+
+ selectedPluginBreakpointsPattern.setSettingsKey(debugModeGroup, "SelectedPluginBreakpointsPattern");
+ selectedPluginBreakpointsPattern.setDefaultValue(QString(".*"));
+
+ maximalStackDepth.setSettingsKey(debugModeGroup, "MaximalStackDepth");
+ maximalStackDepth.setDefaultValue(20);
+ maximalStackDepth.setSpecialValueText(tr("<unlimited>"));
+ maximalStackDepth.setRange(0, 1000);
+ maximalStackDepth.setSingleStep(5);
+ maximalStackDepth.setLabelText(tr("Maximum stack depth:"));
+
+ displayStringLimit.setSettingsKey(debugModeGroup, "DisplayStringLimit");
+ displayStringLimit.setDefaultValue(100);
+ displayStringLimit.setSpecialValueText(tr("<unlimited>"));
+ displayStringLimit.setRange(20, 10000);
+ displayStringLimit.setSingleStep(10);
+ displayStringLimit.setLabelText(tr("Display string length:"));
+ displayStringLimit.setToolTip(tr("<p>The maximum length of string entries in the "
"Locals and Expressions views. Longer than that are cut off "
"and displayed with an ellipsis attached."));
- item->setDefaultValue(100);
- insertItem(DisplayStringLimit, item);
- item = new SavedAction;
- item->setSettingsKey(debugModeGroup, "MaximalStringLength");
- item->setToolTip(tr("<p>The maximum length for strings in separated windows. "
+ maximalStringLength.setSettingsKey(debugModeGroup, "MaximalStringLength");
+ maximalStringLength.setDefaultValue(10000);
+ maximalStringLength.setSpecialValueText(tr("<unlimited>"));
+ maximalStringLength.setRange(20, 10000000);
+ maximalStringLength.setSingleStep(20);
+ maximalStringLength.setLabelText(tr("Maximum string length:"));
+ maximalStringLength.setToolTip(tr("<p>The maximum length for strings in separated windows. "
"Longer strings are cut off and displayed with an ellipsis attached."));
- item->setDefaultValue(10000);
- insertItem(MaximalStringLength, item);
- item = new SavedAction;
- item->setText(tr("Reload Full Stack"));
- insertItem(ExpandStack, item);
+ expandStack.setLabelText(tr("Reload Full Stack"));
- item = new SavedAction;
- item->setText(tr("Create Full Backtrace"));
- insertItem(CreateFullBacktrace, item);
+ createFullBacktrace.setLabelText(tr("Create Full Backtrace"));
- item = new SavedAction;
- item->setSettingsKey(debugModeGroup, "WatchdogTimeout");
- item->setDefaultValue(20);
- insertItem(GdbWatchdogTimeout, item);
+ gdbWatchdogTimeout.setSettingsKey(debugModeGroup, "WatchdogTimeout");
+ gdbWatchdogTimeout.setDefaultValue(20);
+ gdbWatchdogTimeout.setSuffix(/*GdbOptionsPage::*/tr("sec"));
+ gdbWatchdogTimeout.setRange(20, 1000000);
+ gdbWatchdogTimeout.setLabelText(/*GdbOptionsPage::*/tr("GDB timeout:"));
+ gdbWatchdogTimeout.setToolTip(/*GdbOptionsPage::*/tr(
+ "The number of seconds before a non-responsive GDB process is terminated.\n"
+ "The default value of 20 seconds should be sufficient for most\n"
+ "applications, but there are situations when loading big libraries or\n"
+ "listing source files takes much longer than that on slow machines.\n"
+ "In this case, the value should be increased."));
//
// QML Tools
//
- item = new SavedAction;
- item->setSettingsKey(debugModeGroup, "ShowQmlObjectTree");
- item->setDefaultValue(true);
- insertItem(ShowQmlObjectTree, item);
+ showQmlObjectTree.setSettingsKey(debugModeGroup, "ShowQmlObjectTree");
+ showQmlObjectTree.setDefaultValue(true);
+ showQmlObjectTree.setToolTip(tr("Shows QML object tree in Locals and Expressions when connected and not stepping."));
+ showQmlObjectTree.setLabelText(tr("Show QML object tree"));
const QString qmlInspectorGroup = "QML.Inspector";
- item = new SavedAction;
- item->setSettingsKey(qmlInspectorGroup, "QmlInspector.ShowAppOnTop");
- item->setDefaultValue(false);
- insertItem(ShowAppOnTop, item);
+ showAppOnTop.setSettingsKey(qmlInspectorGroup, "QmlInspector.ShowAppOnTop");
+
+ // Page 1
+ page1.registerAspect(&useAlternatingRowColors);
+ page1.registerAspect(&useAnnotationsInMainEditor);
+ page1.registerAspect(&useToolTipsInMainEditor);
+ page1.registerAspect(&closeSourceBuffersOnExit);
+ page1.registerAspect(&closeMemoryBuffersOnExit);
+ page1.registerAspect(&raiseOnInterrupt);
+ page1.registerAspect(&breakpointsFullPathByDefault);
+ page1.registerAspect(&warnOnReleaseBuilds);
+ page1.registerAspect(&maximalStackDepth);
+
+ page1.registerAspect(&fontSizeFollowsEditor);
+ page1.registerAspect(&switchModeOnExit);
+ page1.registerAspect(&showQmlObjectTree);
+ page1.registerAspect(&stationaryEditorWhileStepping);
+ page1.registerAspect(&forceLoggingToConsole);
+
+ page1.registerAspect(&sourcePathMap);
+
+ // Page 2
+ page2.registerAspect(&gdbWatchdogTimeout);
+ page2.registerAspect(&skipKnownFrames);
+ page2.registerAspect(&useMessageBoxForSignals);
+ page2.registerAspect(&adjustBreakpointLocations);
+ page2.registerAspect(&useDynamicType);
+ page2.registerAspect(&loadGdbInit);
+ page2.registerAspect(&loadGdbDumpers);
+ page2.registerAspect(&intelFlavor);
+ page2.registerAspect(&skipKnownFrames);
+ page2.registerAspect(&usePseudoTracepoints);
+ page2.registerAspect(&gdbStartupCommands);
+ page2.registerAspect(&gdbPostAttachCommands);
+
+ // Page 3
+ page3.registerAspect(&targetAsync);
+ page3.registerAspect(&autoEnrichParameters);
+ page3.registerAspect(&breakOnWarning);
+ page3.registerAspect(&breakOnFatal);
+ page3.registerAspect(&breakOnAbort);
+ page3.registerAspect(&enableReverseDebugging);
+ page3.registerAspect(&multiInferior);
+
+ // Page 4
+ page4.registerAspect(&useDebuggingHelpers);
+ page4.registerAspect(&useCodeModel);
+ page4.registerAspect(&showThreadNames);
+ page4.registerAspect(&showStdNamespace);
+ page4.registerAspect(&showQtNamespace);
+ page4.registerAspect(&extraDumperFile);
+ page4.registerAspect(&extraDumperCommands);
+ page4.registerAspect(&showQObjectNames);
+ page4.registerAspect(&displayStringLimit);
+ page4.registerAspect(&maximalStringLength);
+
+ // Page 5
+ page5.registerAspect(&cdbAdditionalArguments);
+ page5.registerAspect(&cdbBreakEvents);
+ page5.registerAspect(&cdbBreakOnCrtDbgReport);
+ page5.registerAspect(&useCdbConsole);
+ page5.registerAspect(&cdbBreakPointCorrection);
+ page5.registerAspect(&cdbUsePythonDumper);
+ page5.registerAspect(&firstChanceExceptionTaskEntry);
+ page5.registerAspect(&secondChanceExceptionTaskEntry);
+ page5.registerAspect(&ignoreFirstChanceAccessViolation);
+ if (HostOsInfo::isWindowsHost())
+ page5.registerAspect(registerForPostMortem);
+
+ // Page 6
+ page6.registerAspect(&cdbSymbolPaths);
+ page6.registerAspect(&cdbSourcePaths);
+
+ // Pageless
+ all.registerAspect(&autoDerefPointers);
+ all.registerAspect(&useToolTipsInLocalsView);
+ all.registerAspect(&alwaysAdjustColumnWidths);
+ all.registerAspect(&useToolTipsInBreakpointsView);
+ all.registerAspect(&useToolTipsInStackView);
+ all.registerAspect(&logTimeStamps);
+ all.registerAspect(&sortStructMembers);
+ all.registerAspect(&breakOnThrow); // ??
+ all.registerAspect(&breakOnCatch); // ??
+
+ // Collect all
+ all.registerAspects(page1);
+ all.registerAspects(page2);
+ all.registerAspects(page3);
+ all.registerAspects(page4);
+ all.registerAspects(page5);
+ all.registerAspects(page6);
+
+ all.forEachAspect([](BaseAspect *aspect) {
+ aspect->setAutoApply(false);
+ // FIXME: Make the positioning part of the LayoutBuilder later
+ if (auto boolAspect = dynamic_cast<BoolAspect *>(aspect))
+ boolAspect->setLabelPlacement(BoolAspect::LabelPlacement::AtCheckBoxWithoutDummyLabel);
+ });
}
DebuggerSettings::~DebuggerSettings()
{
- qDeleteAll(m_items);
-}
-
-void DebuggerSettings::insertItem(int code, SavedAction *item)
-{
- QTC_ASSERT(!m_items.contains(code),
- qDebug() << code << item->toString(); return);
- QTC_ASSERT(item->settingsKey().isEmpty() || item->defaultValue().isValid(),
- qDebug() << "NO DEFAULT VALUE FOR " << item->settingsKey());
- m_items[code] = item;
+ delete registerForPostMortem;
}
void DebuggerSettings::readSettings()
{
- QSettings *settings = Core::ICore::settings();
- for (SavedAction *item : qAsConst(m_items))
- item->readSettings(settings);
+ all.readSettings(Core::ICore::settings());
}
void DebuggerSettings::writeSettings() const
{
- QSettings *settings = Core::ICore::settings();
- for (SavedAction *item : qAsConst(m_items))
- item->writeSettings(settings);
-}
-
-SavedAction *DebuggerSettings::item(int code) const
-{
- QTC_ASSERT(m_items.value(code, nullptr), qDebug() << "CODE: " << code; return nullptr);
- return m_items.value(code, nullptr);
+ all.writeSettings(Core::ICore::settings());
}
QString DebuggerSettings::dump()
{
QStringList settings;
- for (SavedAction *item : qAsConst(theDebuggerSettings->m_items)) {
- QString key = item->settingsKey();
+ debuggerSettings()->all.forEachAspect([&settings](BaseAspect *aspect) {
+ QString key = aspect->settingsKey();
if (!key.isEmpty()) {
- const QString current = item->value().toString();
- const QString default_ = item->defaultValue().toString();
+ const int pos = key.indexOf('/');
+ if (pos >= 0)
+ key = key.mid(pos);
+ const QString current = aspect->value().toString();
+ const QString default_ = aspect->defaultValue().toString();
QString setting = key + ": " + current + " (default: " + default_ + ')';
if (current != default_)
setting += " ***";
settings << setting;
}
- }
+ });
settings.sort();
return "Debugger settings:\n" + settings.join('\n');
}
diff --git a/src/plugins/debugger/debuggeractions.h b/src/plugins/debugger/debuggeractions.h
index 6f590b3512..0f07cdf226 100644
--- a/src/plugins/debugger/debuggeractions.h
+++ b/src/plugins/debugger/debuggeractions.h
@@ -28,26 +28,49 @@
#include <QCoreApplication>
#include <QHash>
#include <QMap>
-#include <QRegularExpression>
#include <QVector>
-namespace Utils { class SavedAction; }
+#include <utils/aspects.h>
namespace Debugger {
namespace Internal {
+class SourcePathMapAspectPrivate;
+
+// Entries starting with '(' are considered regular expressions in the ElfReader.
+// This is useful when there are multiple build machines with different
+// path, and the user would like to match anything up to some known
+// directory to his local project.
+// Syntax: (/home/.*)/KnownSubdir -> /home/my/project
using SourcePathMap = QMap<QString, QString>;
-using SourcePathRegExpMap = QVector<QPair<QRegularExpression, QString>>;
-// Global debugger options that are not stored as saved action.
-class GlobalDebuggerOptions
+class SourcePathMapAspect : public Utils::BaseAspect
{
public:
- void toSettings() const;
- void fromSettings();
+ SourcePathMapAspect();
+ ~SourcePathMapAspect() override;
+
+ void fromMap(const QVariantMap &map) override;
+ void toMap(QVariantMap &map) const override;
+
+ void addToLayout(Utils::LayoutBuilder &builder) override;
+
+ QVariant volatileValue() const override;
+ void setVolatileValue(const QVariant &val) override;
+
+ void readSettings(const QSettings *settings) override;
+ void writeSettings(QSettings *settings) const override;
+
+ SourcePathMap value() const;
+
+private:
+ SourcePathMapAspectPrivate *d = nullptr;
+};
- SourcePathMap sourcePathMap;
- SourcePathRegExpMap sourcePathRegExpMap;
+class GeneralSettings
+{
+ GeneralSettings();
+ ~GeneralSettings();
};
class DebuggerSettings
@@ -58,119 +81,130 @@ public:
explicit DebuggerSettings();
~DebuggerSettings();
- void insertItem(int code, Utils::SavedAction *item);
- Utils::SavedAction *item(int code) const;
-
static QString dump();
- void readSettings();
- void writeSettings() const;
-
-private:
- DebuggerSettings(const DebuggerSettings &) = delete;
- DebuggerSettings &operator=(const DebuggerSettings &) = delete;
-
- QHash<int, Utils::SavedAction *> m_items;
-};
-
-///////////////////////////////////////////////////////////
-
-enum DebuggerActionCode
-{
- // General
- SettingsDialog,
- UseAlternatingRowColors,
- FontSizeFollowsEditor,
- UseMessageBoxForSignals,
- AutoQuit,
- LockView,
- LogTimeStamps,
- CloseSourceBuffersOnExit,
- CloseMemoryBuffersOnExit,
- SwitchModeOnExit,
- BreakpointsFullPathByDefault,
- RaiseOnInterrupt,
- StationaryEditorWhileStepping,
-
- UseDebuggingHelpers,
-
- UseCodeModel,
- ShowThreadNames,
-
- UseToolTipsInMainEditor,
- UseAnnotationsInMainEditor,
- UseToolTipsInLocalsView,
- UseToolTipsInBreakpointsView,
- UseToolTipsInStackView,
-
- RegisterForPostMortem,
- AlwaysAdjustColumnWidths,
-
- ExtraDumperFile, // For loading a file. Recommended.
- ExtraDumperCommands, // To modify an existing setup.
-
- // Cdb
- CdbAdditionalArguments,
- CdbSymbolPaths,
- CdbSourcePaths,
- CdbBreakEvents,
- CdbBreakOnCrtDbgReport,
- UseCdbConsole,
- CdbBreakPointCorrection,
- CdbUsePythonDumper,
- FirstChanceExceptionTaskEntry,
- SecondChanceExceptionTaskEntry,
- IgnoreFirstChanceAccessViolation,
-
- // Gdb
- LoadGdbInit,
- LoadGdbDumpers,
- GdbStartupCommands,
- GdbPostAttachCommands,
- GdbWatchdogTimeout,
- AutoEnrichParameters,
- UseDynamicType,
- TargetAsync,
- WarnOnReleaseBuilds,
- MultiInferior,
- IntelFlavor,
- UsePseudoTracepoints,
+ // Page 1: General
+ Utils::BoolAspect useAlternatingRowColors;
+ Utils::BoolAspect useAnnotationsInMainEditor;
+ Utils::BoolAspect useToolTipsInMainEditor;
+ Utils::BoolAspect closeSourceBuffersOnExit;
+ Utils::BoolAspect closeMemoryBuffersOnExit;
+ Utils::BoolAspect raiseOnInterrupt;
+ Utils::BoolAspect breakpointsFullPathByDefault;
+ Utils::BoolAspect warnOnReleaseBuilds;
+ Utils::IntegerAspect maximalStackDepth;
+
+ Utils::BoolAspect fontSizeFollowsEditor;
+ Utils::BoolAspect switchModeOnExit;
+ Utils::BoolAspect showQmlObjectTree;
+ Utils::BoolAspect stationaryEditorWhileStepping;
+ Utils::BoolAspect forceLoggingToConsole;
+
+ SourcePathMapAspect sourcePathMap;
+
+ // Page 2: GDB
+ Utils::IntegerAspect gdbWatchdogTimeout;
+ Utils::BoolAspect skipKnownFrames;
+ Utils::BoolAspect useMessageBoxForSignals;
+ Utils::BoolAspect adjustBreakpointLocations;
+ Utils::BoolAspect useDynamicType;
+ Utils::BoolAspect loadGdbInit;
+ Utils::BoolAspect loadGdbDumpers;
+ Utils::BoolAspect intelFlavor;
+ Utils::BoolAspect usePseudoTracepoints;
+ Utils::StringAspect gdbStartupCommands;
+ Utils::StringAspect gdbPostAttachCommands;
+
+ // Page 3: GDB Extended
+ Utils::BoolAspect targetAsync;
+ Utils::BoolAspect autoEnrichParameters;
+ Utils::BoolAspect breakOnThrow;
+ Utils::BoolAspect breakOnCatch;
+ Utils::BoolAspect breakOnWarning;
+ Utils::BoolAspect breakOnFatal;
+ Utils::BoolAspect breakOnAbort;
+ Utils::BoolAspect enableReverseDebugging;
+ Utils::BoolAspect multiInferior;
+
+ // Page 4: Locals and expressions
+ Utils::BoolAspect useDebuggingHelpers;
+ Utils::BoolAspect useCodeModel;
+ Utils::BoolAspect showThreadNames;
+ Utils::StringAspect extraDumperFile; // For loading a file. Recommended.
+ Utils::StringAspect extraDumperCommands; // To modify an existing setup.
+
+ Utils::BoolAspect showStdNamespace;
+ Utils::BoolAspect showQtNamespace;
+ Utils::BoolAspect showQObjectNames;
+
+ // Page 5: CDB
+ Utils::StringAspect cdbAdditionalArguments;
+ Utils::StringListAspect cdbBreakEvents;
+ Utils::BoolAspect cdbBreakOnCrtDbgReport;
+ Utils::BoolAspect useCdbConsole;
+ Utils::BoolAspect cdbBreakPointCorrection;
+ Utils::BoolAspect cdbUsePythonDumper;
+ Utils::BoolAspect firstChanceExceptionTaskEntry;
+ Utils::BoolAspect secondChanceExceptionTaskEntry;
+ Utils::BoolAspect ignoreFirstChanceAccessViolation;
+
+ Utils::BoolAspect *registerForPostMortem = nullptr;
+
+ // Page 6: CDB Paths
+ Utils::StringListAspect cdbSymbolPaths;
+ Utils::StringListAspect cdbSourcePaths;
+
+ // Without pages
+ Utils::BoolAspect alwaysAdjustColumnWidths;
+ Utils::BaseAspect settingsDialog;
+ Utils::BoolAspect autoQuit;
+ Utils::BoolAspect lockView;
+ Utils::BoolAspect logTimeStamps;
// Stack
- MaximalStackDepth,
- ExpandStack,
- CreateFullBacktrace,
+ Utils::BaseAspect expandStack;
+ Utils::BaseAspect createFullBacktrace;
+ Utils::BoolAspect useToolTipsInStackView;
// Watchers & Locals
- ShowStdNamespace,
- ShowQtNamespace,
- ShowQObjectNames,
- SortStructMembers,
- AutoDerefPointers,
- MaximalStringLength,
- DisplayStringLimit,
-
- // Running
- SkipKnownFrames,
- EnableReverseDebugging,
+ Utils::BoolAspect autoDerefPointers;
+ Utils::IntegerAspect maximalStringLength;
+ Utils::IntegerAspect displayStringLimit;
+ Utils::BoolAspect sortStructMembers;
+ Utils::BoolAspect useToolTipsInLocalsView;
// Breakpoints
- SynchronizeBreakpoints,
- AllPluginBreakpoints,
- SelectedPluginBreakpoints,
- AdjustBreakpointLocations,
- NoPluginBreakpoints,
- SelectedPluginBreakpointsPattern,
- BreakOnThrow,
- BreakOnCatch,
- BreakOnWarning,
- BreakOnFatal,
- BreakOnAbort,
+ Utils::BoolAspect synchronizeBreakpoints; // ?
+ Utils::BoolAspect allPluginBreakpoints;
+ Utils::BoolAspect selectedPluginBreakpoints;
+ Utils::BoolAspect noPluginBreakpoints;
+ Utils::StringAspect selectedPluginBreakpointsPattern;
+ Utils::BoolAspect useToolTipsInBreakpointsView;
// QML Tools
- ShowQmlObjectTree,
- ShowAppOnTop
+ Utils::BoolAspect showAppOnTop;
+
+ Utils::AspectContainer all; // All
+ Utils::AspectContainer page1; // General
+ Utils::AspectContainer page2; // GDB
+ Utils::AspectContainer page3; // GDB Extended
+ Utils::AspectContainer page4; // Locals & Expressions
+ Utils::AspectContainer page5; // CDB
+ Utils::AspectContainer page6; // CDB Paths
+
+ void readSettings();
+ void writeSettings() const;
+
+private:
+ DebuggerSettings(const DebuggerSettings &) = delete;
+ DebuggerSettings &operator=(const DebuggerSettings &) = delete;
};
+DebuggerSettings *debuggerSettings();
+
+///////////////////////////////////////////////////////////
+
} // namespace Internal
} // namespace Debugger
+
+Q_DECLARE_METATYPE(Debugger::Internal::SourcePathMap)
diff --git a/src/plugins/debugger/debuggercore.h b/src/plugins/debugger/debuggercore.h
index 60881d8f98..bd228b2560 100644
--- a/src/plugins/debugger/debuggercore.h
+++ b/src/plugins/debugger/debuggercore.h
@@ -37,16 +37,11 @@ class QMenu;
class QAction;
QT_END_NAMESPACE
-namespace Utils {
-class BaseTreeView;
-class SavedAction;
-}
+namespace Utils { class BaseTreeView; }
namespace Debugger {
namespace Internal {
-class GlobalDebuggerOptions;
-
enum TestCases
{
// Gdb
@@ -56,16 +51,8 @@ enum TestCases
// Some convenience.
void openTextEditor(const QString &titlePattern, const QString &contents);
-GlobalDebuggerOptions *globalDebuggerOptions();
-
bool isTestRun();
-Utils::SavedAction *action(int code);
-
-bool boolSetting(int code);
-QString stringSetting(int code);
-QStringList stringListSetting(int code);
-
QAction *addAction(QMenu *menu, const QString &display, bool on,
const std::function<void()> &onTriggered = {});
QAction *addAction(QMenu *menu, const QString &d1, const QString &d2, bool on,
diff --git a/src/plugins/debugger/debuggerdialogs.cpp b/src/plugins/debugger/debuggerdialogs.cpp
index 45a79b4155..7dc5bf6706 100644
--- a/src/plugins/debugger/debuggerdialogs.cpp
+++ b/src/plugins/debugger/debuggerdialogs.cpp
@@ -83,6 +83,7 @@ public:
PathChooser *workingDirectory;
QCheckBox *breakAtMainCheckBox;
QCheckBox *runInTerminalCheckBox;
+ QCheckBox *useTargetExtendedCheckBox;
PathChooser *debuginfoPathChooser;
QLabel *serverStartScriptLabel;
PathChooser *serverStartScriptPathChooser;
@@ -127,6 +128,7 @@ public:
Runnable runnable;
bool breakAtMain = false;
bool runInTerminal = false;
+ bool useTargetExtended = false;
FilePath serverStartScript;
FilePath sysRoot;
QString serverInitCommands;
@@ -181,6 +183,7 @@ void StartApplicationParameters::toSettings(QSettings *settings) const
settings->setValue("LastExternalWorkingDirectory", runnable.workingDirectory);
settings->setValue("LastExternalBreakAtMain", breakAtMain);
settings->setValue("LastExternalRunInTerminal", runInTerminal);
+ settings->setValue("LastExternalUseTargetExtended", useTargetExtended);
settings->setValue("LastServerStartScript", serverStartScript.toVariant());
settings->setValue("LastServerInitCommands", serverInitCommands);
settings->setValue("LastServerResetCommands", serverResetCommands);
@@ -198,6 +201,7 @@ void StartApplicationParameters::fromSettings(const QSettings *settings)
runnable.workingDirectory = settings->value("LastExternalWorkingDirectory").toString();
breakAtMain = settings->value("LastExternalBreakAtMain").toBool();
runInTerminal = settings->value("LastExternalRunInTerminal").toBool();
+ useTargetExtended = settings->value("LastExternalUseTargetExtended").toBool();
serverStartScript = FilePath::fromVariant(settings->value("LastServerStartScript"));
serverInitCommands = settings->value("LastServerInitCommands").toString();
serverResetCommands = settings->value("LastServerResetCommands").toString();
@@ -254,6 +258,8 @@ StartApplicationDialog::StartApplicationDialog(QWidget *parent)
d->breakAtMainCheckBox = new QCheckBox(this);
d->breakAtMainCheckBox->setText(QString());
+ d->useTargetExtendedCheckBox = new QCheckBox(this);
+
d->serverStartScriptPathChooser = new PathChooser(this);
d->serverStartScriptPathChooser->setExpectedKind(PathChooser::File);
d->serverStartScriptPathChooser->setPromptDialogTitle(tr("Select Server Start Script"));
@@ -321,6 +327,7 @@ StartApplicationDialog::StartApplicationDialog(QWidget *parent)
formLayout->addRow(tr("&Working directory:"), d->workingDirectory);
formLayout->addRow(tr("Run in &terminal:"), d->runInTerminalCheckBox);
formLayout->addRow(tr("Break at \"&main\":"), d->breakAtMainCheckBox);
+ formLayout->addRow(tr("Use target-extended to connect:"), d->useTargetExtendedCheckBox);
formLayout->addRow(d->serverStartScriptLabel, d->serverStartScriptPathChooser);
formLayout->addRow(d->sysRootLabel, d->sysRootPathChooser);
formLayout->addRow(d->serverInitCommandsLabel, d->serverInitCommandsTextEdit);
@@ -462,15 +469,14 @@ void StartApplicationDialog::run(bool attachRemote)
debugger->setCommandsAfterConnect(newParameters.serverInitCommands);
debugger->setCommandsForReset(newParameters.serverResetCommands);
debugger->setUseTerminal(newParameters.runInTerminal);
+ debugger->setUseExtendedRemote(newParameters.useTargetExtended);
if (!newParameters.sysRoot.isEmpty())
debugger->setSysRoot(newParameters.sysRoot);
bool isLocal = !dev || (dev->type() == ProjectExplorer::Constants::DESKTOP_DEVICE_TYPE);
- if (isLocal) {
- Environment inferiorEnvironment = Environment::systemEnvironment();
- k->addToEnvironment(inferiorEnvironment);
- debugger->setInferiorEnvironment(inferiorEnvironment);
- }
+ if (isLocal) // FIXME: Restriction needed?
+ debugger->setInferiorEnvironment(k->runEnvironment());
+
if (!attachRemote)
debugger->setStartMode(isLocal ? StartExternal : StartRemoteProcess);
@@ -509,6 +515,7 @@ StartApplicationParameters StartApplicationDialog::parameters() const
result.runnable.workingDirectory = d->workingDirectory->filePath().toString();
result.breakAtMain = d->breakAtMainCheckBox->isChecked();
result.runInTerminal = d->runInTerminalCheckBox->isChecked();
+ result.useTargetExtended = d->useTargetExtendedCheckBox->isChecked();
return result;
}
@@ -525,8 +532,9 @@ void StartApplicationDialog::setParameters(const StartApplicationParameters &p)
d->debuginfoPathChooser->setPath(p.debugInfoLocation);
d->arguments->setText(p.runnable.commandLineArguments);
d->workingDirectory->setPath(p.runnable.workingDirectory);
- d->runInTerminalCheckBox->setChecked(p.runInTerminal);
d->breakAtMainCheckBox->setChecked(p.breakAtMain);
+ d->runInTerminalCheckBox->setChecked(p.runInTerminal);
+ d->useTargetExtendedCheckBox->setChecked(p.useTargetExtended);
updateState();
}
diff --git a/src/plugins/debugger/debuggerengine.cpp b/src/plugins/debugger/debuggerengine.cpp
index 7f306bb8a5..b156ff1e18 100644
--- a/src/plugins/debugger/debuggerengine.cpp
+++ b/src/plugins/debugger/debuggerengine.cpp
@@ -78,7 +78,6 @@
#include <utils/processhandle.h>
#include <utils/qtcassert.h>
#include <utils/qtcprocess.h>
-#include <utils/savedaction.h>
#include <utils/styledbar.h>
#include <utils/utilsicons.h>
@@ -286,7 +285,7 @@ public:
m_logWindow = new LogWindow(m_engine); // Needed before start()
m_logWindow->setObjectName("Debugger.Dock.Output");
- connect(action(EnableReverseDebugging), &SavedAction::valueChanged, this, [this] {
+ connect(&debuggerSettings()->enableReverseDebugging, &BaseAspect::changed, this, [this] {
updateState();
if (m_companionEngine)
m_companionEngine->d->updateState();
@@ -427,7 +426,7 @@ public:
m_watchHandler.cleanup();
m_engine->showMessage(tr("Debugger finished."), StatusBar);
m_engine->setState(DebuggerFinished); // Also destroys views.
- if (boolSetting(SwitchModeOnExit))
+ if (debuggerSettings()->switchModeOnExit.value())
EngineManager::deactivateDebugMode();
}
@@ -831,7 +830,7 @@ void DebuggerEnginePrivate::setupViews()
connect(TextEditorSettings::instance(), &TextEditorSettings::fontSettingsChanged,
this, [this](const FontSettings &settings) {
- if (!boolSetting(FontSizeFollowsEditor))
+ if (!debuggerSettings()->fontSizeFollowsEditor.value())
return;
const qreal size = settings.fontZoom() * settings.fontSize() / 100.;
QFont font = m_breakWindow->font();
@@ -1107,7 +1106,7 @@ void DebuggerEngine::gotoLocation(const Location &loc)
&newEditor);
QTC_ASSERT(editor, return); // Unreadable file?
- editor->gotoLine(line, 0, !boolSetting(StationaryEditorWhileStepping));
+ editor->gotoLine(line, 0, !debuggerSettings()->stationaryEditorWhileStepping.value());
if (newEditor)
editor->document()->setProperty(Constants::OPENED_BY_DEBUGGER, true);
@@ -1369,7 +1368,7 @@ void DebuggerEngine::notifyInferiorSpontaneousStop()
d->m_perspective->select();
showMessage(tr("Stopped."), StatusBar);
setState(InferiorStopOk);
- if (boolSetting(RaiseOnInterrupt))
+ if (debuggerSettings()->raiseOnInterrupt.value())
ICore::raiseWindow(DebuggerMainWindow::instance());
}
@@ -1427,8 +1426,8 @@ void DebuggerEnginePrivate::setInitialActionStates()
m_jumpToLineAction.setVisible(false);
m_stepOverAction.setEnabled(true);
- action(AutoDerefPointers)->setEnabled(true);
- action(ExpandStack)->setEnabled(false);
+ debuggerSettings()->autoDerefPointers.setEnabled(true);
+ debuggerSettings()->expandStack.setEnabled(false);
m_threadLabel->setEnabled(false);
}
@@ -1566,9 +1565,9 @@ void DebuggerEnginePrivate::updateState()
const bool actionsEnabled = m_engine->debuggerActionsEnabled();
const bool canDeref = actionsEnabled && m_engine->hasCapability(AutoDerefPointersCapability);
- action(AutoDerefPointers)->setEnabled(canDeref);
- action(AutoDerefPointers)->setEnabled(true);
- action(ExpandStack)->setEnabled(actionsEnabled);
+ debuggerSettings()->autoDerefPointers.setEnabled(canDeref);
+ debuggerSettings()->autoDerefPointers.setEnabled(true);
+ debuggerSettings()->expandStack.setEnabled(actionsEnabled);
const bool notbusy = state == InferiorStopOk
|| state == DebuggerNotReady
@@ -1580,7 +1579,7 @@ void DebuggerEnginePrivate::updateState()
void DebuggerEnginePrivate::updateReverseActions()
{
const bool stopped = m_state == InferiorStopOk;
- const bool reverseEnabled = boolSetting(EnableReverseDebugging);
+ const bool reverseEnabled = debuggerSettings()->enableReverseDebugging.value();
const bool canReverse = reverseEnabled && m_engine->hasCapability(ReverseSteppingCapability);
const bool doesRecord = m_recordForReverseOperationAction.isChecked();
@@ -1598,8 +1597,8 @@ void DebuggerEnginePrivate::updateReverseActions()
void DebuggerEnginePrivate::cleanupViews()
{
- const bool closeSource = boolSetting(CloseSourceBuffersOnExit);
- const bool closeMemory = boolSetting(CloseMemoryBuffersOnExit);
+ const bool closeSource = debuggerSettings()->closeSourceBuffersOnExit.value();
+ const bool closeMemory = debuggerSettings()->closeMemoryBuffersOnExit.value();
QList<IDocument *> toClose;
foreach (IDocument *document, DocumentModel::openedDocuments()) {
@@ -1885,8 +1884,15 @@ QString DebuggerEngine::expand(const QString &string) const
QString DebuggerEngine::nativeStartupCommands() const
{
- return expand(QStringList({stringSetting(GdbStartupCommands),
- runParameters().additionalStartupCommands}).join('\n'));
+ QStringList lines = debuggerSettings()->gdbStartupCommands.value().split('\n');
+ lines += runParameters().additionalStartupCommands.split('\n');
+
+ lines = Utils::filtered(lines, [](const QString line) {
+ const QString trimmed = line.trimmed();
+ return !trimmed.isEmpty() && !trimmed.startsWith('#');
+ });
+
+ return lines.join('\n');
}
Perspective *DebuggerEngine::perspective() const
@@ -2723,7 +2729,8 @@ Context CppDebuggerEngine::languageContext() const
void CppDebuggerEngine::validateRunParameters(DebuggerRunParameters &rp)
{
- const bool warnOnRelease = boolSetting(WarnOnReleaseBuilds) && rp.toolChainAbi.osFlavor() != Abi::AndroidLinuxFlavor;
+ const bool warnOnRelease = debuggerSettings()->warnOnReleaseBuilds.value()
+ && rp.toolChainAbi.osFlavor() != Abi::AndroidLinuxFlavor;
bool warnOnInappropriateDebugger = false;
QString detailedWarning;
switch (rp.toolChainAbi.binaryFormat()) {
@@ -2817,13 +2824,16 @@ void CppDebuggerEngine::validateRunParameters(DebuggerRunParameters &rp)
bool hasEmbeddedInfo = elfData.indexOf(".debug_info") >= 0;
bool hasLink = elfData.indexOf(".gnu_debuglink") >= 0;
if (hasEmbeddedInfo) {
- const GlobalDebuggerOptions *options = Internal::globalDebuggerOptions();
- SourcePathRegExpMap globalRegExpSourceMap;
- globalRegExpSourceMap.reserve(options->sourcePathRegExpMap.size());
- for (const auto &entry : qAsConst(options->sourcePathRegExpMap)) {
- const QString expanded = Utils::globalMacroExpander()->expand(entry.second);
- if (!expanded.isEmpty())
- globalRegExpSourceMap.push_back(qMakePair(entry.first, expanded));
+ const SourcePathMap sourcePathMap = debuggerSettings()->sourcePathMap.value();
+ QList<QPair<QRegularExpression, QString>> globalRegExpSourceMap;
+ globalRegExpSourceMap.reserve(sourcePathMap.size());
+ for (auto it = sourcePathMap.begin(), end = sourcePathMap.end(); it != end; ++it) {
+ if (it.key().startsWith('(')) {
+ const QString expanded = Utils::globalMacroExpander()->expand(it.value());
+ if (!expanded.isEmpty())
+ globalRegExpSourceMap.push_back(
+ qMakePair(QRegularExpression(it.key()), expanded));
+ }
}
if (globalRegExpSourceMap.isEmpty())
return;
@@ -2833,13 +2843,11 @@ void CppDebuggerEngine::validateRunParameters(DebuggerRunParameters &rp)
bool found = false;
while (str < limit) {
const QString string = QString::fromUtf8(str);
- for (auto itExp = globalRegExpSourceMap.begin(), itEnd = globalRegExpSourceMap.end();
- itExp != itEnd;
- ++itExp) {
- const QRegularExpressionMatch match = itExp->first.match(string);
+ for (auto pair : qAsConst(globalRegExpSourceMap)) {
+ const QRegularExpressionMatch match = pair.first.match(string);
if (match.hasMatch()) {
rp.sourcePathMap.insert(string.left(match.capturedStart()) + match.captured(1),
- itExp->second);
+ pair.second);
found = true;
break;
}
diff --git a/src/plugins/debugger/debuggerinternalconstants.h b/src/plugins/debugger/debuggerinternalconstants.h
index 908a02c5d8..330f11485a 100644
--- a/src/plugins/debugger/debuggerinternalconstants.h
+++ b/src/plugins/debugger/debuggerinternalconstants.h
@@ -74,6 +74,8 @@ const char OPENED_BY_DEBUGGER[] = "OpenedByDebugger";
const char OPENED_WITH_DISASSEMBLY[] = "DisassemblerView";
const char DISASSEMBLER_SOURCE_FILE[] = "DisassemblerSourceFile";
+const char CRT_DEBUG_REPORT[] = "CrtDbgReport";
+
} // namespace Constants
enum ModelRoles
diff --git a/src/plugins/debugger/debuggeritem.cpp b/src/plugins/debugger/debuggeritem.cpp
index 6dc8c6acdb..df3915a009 100644
--- a/src/plugins/debugger/debuggeritem.cpp
+++ b/src/plugins/debugger/debuggeritem.cpp
@@ -35,8 +35,8 @@
#include <utils/hostosinfo.h>
#include <utils/macroexpander.h>
#include <utils/qtcassert.h>
+#include <utils/qtcprocess.h>
#include <utils/stringutils.h>
-#include <utils/synchronousprocess.h>
#include <utils/utilsicons.h>
#include <utils/winutils.h>
@@ -66,13 +66,14 @@ const char DEBUGGER_INFORMATION_WORKINGDIRECTORY[] = "WorkingDirectory";
//! Return the configuration of gdb as a list of --key=value
//! \note That the list will also contain some output not in this format.
-static QString getConfigurationOfGdbCommand(const FilePath &command)
+static QString getConfigurationOfGdbCommand(const FilePath &command, const Utils::Environment &sysEnv)
{
// run gdb with the --configuration opion
- Utils::SynchronousProcess gdbConfigurationCall;
- Utils::SynchronousProcessResponse output =
- gdbConfigurationCall.runBlocking({command, {"--configuration"}});
- return output.allOutput();
+ SynchronousProcess proc;
+ proc.setEnvironment(sysEnv);
+ proc.setCommand({command, {"--configuration"}});
+ proc.runBlocking();
+ return proc.allOutput();
}
//! Extract the target ABI identifier from GDB output
@@ -148,7 +149,7 @@ static bool isUVisionExecutable(const QFileInfo &fileInfo)
return baseName == "UV4";
}
-void DebuggerItem::reinitializeFromFile()
+void DebuggerItem::reinitializeFromFile(const Utils::Environment &sysEnv)
{
// CDB only understands the single-dash -version, whereas GDB and LLDB are
// happy with both -version and --version. So use the "working" -version
@@ -184,13 +185,15 @@ void DebuggerItem::reinitializeFromFile()
}
SynchronousProcess proc;
- SynchronousProcessResponse response = proc.runBlocking({m_command, {version}});
- if (response.result != SynchronousProcessResponse::Finished) {
+ proc.setEnvironment(sysEnv);
+ proc.setCommand({m_command, {version}});
+ proc.runBlocking();
+ if (proc.result() != QtcProcess::Finished) {
m_engineType = NoEngineType;
return;
}
m_abis.clear();
- const QString output = response.allOutput().trimmed();
+ const QString output = proc.allOutput().trimmed();
if (output.contains("gdb")) {
m_engineType = GdbEngineType;
@@ -207,7 +210,7 @@ void DebuggerItem::reinitializeFromFile()
const bool unableToFindAVersion = (0 == version);
const bool gdbSupportsConfigurationFlag = (version >= 70700);
if (gdbSupportsConfigurationFlag || unableToFindAVersion) {
- const auto gdbConfiguration = getConfigurationOfGdbCommand(m_command);
+ const auto gdbConfiguration = getConfigurationOfGdbCommand(m_command, sysEnv);
const auto gdbTargetAbiString =
extractGdbTargetAbiStringFromGdbOutput(gdbConfiguration);
if (!gdbTargetAbiString.isEmpty()) {
diff --git a/src/plugins/debugger/debuggeritem.h b/src/plugins/debugger/debuggeritem.h
index 77e18bff46..fb1760f8f1 100644
--- a/src/plugins/debugger/debuggeritem.h
+++ b/src/plugins/debugger/debuggeritem.h
@@ -31,6 +31,7 @@
#include <projectexplorer/abi.h>
#include <utils/fileutils.h>
+#include <utils/environment.h>
#include <QDateTime>
#include <QList>
@@ -97,7 +98,7 @@ public:
bool operator==(const DebuggerItem &other) const;
bool operator!=(const DebuggerItem &other) const { return !operator==(other); }
- void reinitializeFromFile();
+ void reinitializeFromFile(const Utils::Environment &sysEnv = Utils::Environment::systemEnvironment());
Utils::FilePath workingDirectory() const { return m_workingDirectory; }
void setWorkingDirectory(const Utils::FilePath &workingPath) { m_workingDirectory = workingPath; }
diff --git a/src/plugins/debugger/debuggeritemmanager.cpp b/src/plugins/debugger/debuggeritemmanager.cpp
index 668b560793..3b42bcf50f 100644
--- a/src/plugins/debugger/debuggeritemmanager.cpp
+++ b/src/plugins/debugger/debuggeritemmanager.cpp
@@ -43,7 +43,7 @@
#include <utils/pathchooser.h>
#include <utils/persistentsettings.h>
#include <utils/qtcassert.h>
-#include <utils/synchronousprocess.h>
+#include <utils/qtcprocess.h>
#include <utils/treemodel.h>
#include <utils/winutils.h>
@@ -72,7 +72,7 @@ namespace Internal {
const char DEBUGGER_COUNT_KEY[] = "DebuggerItem.Count";
const char DEBUGGER_DATA_KEY[] = "DebuggerItem.";
const char DEBUGGER_FILE_VERSION_KEY[] = "Version";
-const char DEBUGGER_FILENAME[] = "/debuggers.xml";
+const char DEBUGGER_FILENAME[] = "debuggers.xml";
const char debuggingToolsWikiLinkC[] = "http://wiki.qt.io/Qt_Creator_Windows_Debugging";
class DebuggerItemModel;
@@ -222,7 +222,7 @@ const DebuggerItem *findDebugger(const Predicate &pred)
DebuggerItemModel::DebuggerItemModel()
{
- setHeader({tr("Name"), tr("Location"), tr("Type")});
+ setHeader({tr("Name"), tr("Path"), tr("Type")});
rootItem()->appendChild(
new StaticTreeItem({ProjectExplorer::Constants::msgAutoDetected()},
{ProjectExplorer::Constants::msgAutoDetectedToolTip()}));
@@ -743,11 +743,12 @@ void DebuggerItemManagerPrivate::autoDetectGdbOrLldbDebuggers()
FilePaths suspects;
if (HostOsInfo::isMacHost()) {
- SynchronousProcess lldbInfo;
- lldbInfo.setTimeoutS(2);
- SynchronousProcessResponse response = lldbInfo.runBlocking({"xcrun", {"--find", "lldb"}});
- if (response.result == Utils::SynchronousProcessResponse::Finished) {
- QString lPath = response.allOutput().trimmed();
+ SynchronousProcess proc;
+ proc.setTimeoutS(2);
+ proc.setCommand({"xcrun", {"--find", "lldb"}});
+ proc.runBlocking();
+ if (proc.result() == QtcProcess::Finished) {
+ QString lPath = proc.allOutput().trimmed();
if (!lPath.isEmpty()) {
const QFileInfo fi(lPath);
if (fi.exists() && fi.isExecutable() && !fi.isDir())
@@ -835,7 +836,7 @@ void DebuggerItemManagerPrivate::autoDetectUvscDebuggers()
static FilePath userSettingsFileName()
{
- return FilePath::fromString(ICore::userResourcePath() + DEBUGGER_FILENAME);
+ return ICore::userResourcePath(DEBUGGER_FILENAME);
}
DebuggerItemManagerPrivate::DebuggerItemManagerPrivate()
@@ -931,7 +932,7 @@ void DebuggerItemManagerPrivate::readDebuggers(const FilePath &fileName, bool is
void DebuggerItemManagerPrivate::restoreDebuggers()
{
// Read debuggers from SDK
- readDebuggers(FilePath::fromString(ICore::installerResourcePath() + DEBUGGER_FILENAME), true);
+ readDebuggers(ICore::installerResourcePath(DEBUGGER_FILENAME), true);
// Read all debuggers from user file.
readDebuggers(userSettingsFileName(), false);
diff --git a/src/plugins/debugger/debuggerkitinformation.cpp b/src/plugins/debugger/debuggerkitinformation.cpp
index bf3a5977aa..90ea0ac89e 100644
--- a/src/plugins/debugger/debuggerkitinformation.cpp
+++ b/src/plugins/debugger/debuggerkitinformation.cpp
@@ -28,20 +28,19 @@
#include "debuggeritemmanager.h"
#include "debuggeritem.h"
-#include <coreplugin/icore.h>
-
#include <projectexplorer/toolchain.h>
#include <projectexplorer/projectexplorerconstants.h>
#include <projectexplorer/runcontrol.h>
#include <utils/environment.h>
#include <utils/fileutils.h>
+#include <utils/layoutbuilder.h>
#include <utils/macroexpander.h>
#include <utils/qtcassert.h>
#include <QComboBox>
#include <QFileInfo>
-#include <QPushButton>
+
#include <utility>
using namespace ProjectExplorer;
@@ -63,7 +62,7 @@ public:
DebuggerKitAspectWidget(Kit *workingCopy, const KitAspect *ki)
: KitAspectWidget(workingCopy, ki)
{
- m_comboBox = new QComboBox;
+ m_comboBox = createSubWidget<QComboBox>();
m_comboBox->setSizePolicy(QSizePolicy::Ignored, m_comboBox->sizePolicy().verticalPolicy());
m_comboBox->setEnabled(true);
@@ -72,10 +71,7 @@ public:
connect(m_comboBox, QOverload<int>::of(&QComboBox::currentIndexChanged),
this, &DebuggerKitAspectWidget::currentDebuggerChanged);
- m_manageButton = new QPushButton(KitAspectWidget::msgManage());
- m_manageButton->setContentsMargins(0, 0, 0, 0);
- connect(m_manageButton, &QAbstractButton::clicked,
- this, &DebuggerKitAspectWidget::manageDebuggers);
+ m_manageButton = createManageButton(ProjectExplorer::Constants::DEBUGGER_SETTINGS_PAGE_ID);
}
~DebuggerKitAspectWidget() override
@@ -85,8 +81,12 @@ public:
}
private:
- QWidget *buttonWidget() const override { return m_manageButton; }
- QWidget *mainWidget() const override { return m_comboBox; }
+ void addToLayout(Utils::LayoutBuilder &builder) override
+ {
+ addMutableAction(m_comboBox);
+ builder.addItem(m_comboBox);
+ builder.addItem(m_manageButton);
+ }
void makeReadOnly() override
{
@@ -107,12 +107,6 @@ private:
m_ignoreChanges = false;
}
- void manageDebuggers()
- {
- Core::ICore::showOptionsDialog(ProjectExplorer::Constants::DEBUGGER_SETTINGS_PAGE_ID,
- buttonWidget());
- }
-
void currentDebuggerChanged(int idx)
{
Q_UNUSED(idx)
@@ -139,7 +133,7 @@ private:
bool m_ignoreChanges = false;
QComboBox *m_comboBox;
- QPushButton *m_manageButton;
+ QWidget *m_manageButton;
};
} // namespace Internal
@@ -350,7 +344,7 @@ Runnable DebuggerKitAspect::runnable(const Kit *kit)
if (const DebuggerItem *item = debugger(kit)) {
runnable.executable = item->command();
runnable.workingDirectory = item->workingDirectory().toString();
- runnable.environment = Utils::Environment::systemEnvironment();
+ runnable.environment = kit->runEnvironment();
runnable.environment.set("LC_NUMERIC", "C");
}
return runnable;
diff --git a/src/plugins/debugger/debuggerplugin.cpp b/src/plugins/debugger/debuggerplugin.cpp
index 42b8bc12da..add73dfc9c 100644
--- a/src/plugins/debugger/debuggerplugin.cpp
+++ b/src/plugins/debugger/debuggerplugin.cpp
@@ -116,7 +116,6 @@
#include <utils/hostosinfo.h>
#include <utils/proxyaction.h>
#include <utils/qtcassert.h>
-#include <utils/savedaction.h>
#include <utils/statuslabel.h>
#include <utils/styledbar.h>
#include <utils/temporarydirectory.h>
@@ -657,7 +656,6 @@ public:
void parseCommandLineArguments();
void updatePresetState();
- SavedAction *action(int code);
QWidget *addSearch(BaseTreeView *treeView);
public:
@@ -696,7 +694,6 @@ public:
Console m_console; // ensure Debugger Console is created before settings are taken into account
DebuggerSettings m_debuggerSettings;
QStringList m_arguments;
- GlobalDebuggerOptions m_globalDebuggerOptions;
DebuggerItemManager m_debuggerItemManager;
@@ -796,7 +793,7 @@ DebuggerPluginPrivate::DebuggerPluginPrivate(const QStringList &arguments)
const auto addFontSizeAdaptation = [this](QWidget *widget) {
QObject::connect(TextEditorSettings::instance(), &TextEditorSettings::fontSettingsChanged,
[widget](const FontSettings &settings) {
- if (!boolSetting(FontSizeFollowsEditor))
+ if (!debuggerSettings()->fontSizeFollowsEditor.value())
return;
qreal size = settings.fontZoom() * settings.fontSize() / 100.;
QFont font = widget->font();
@@ -1173,7 +1170,7 @@ DebuggerPluginPrivate::DebuggerPluginPrivate(const QStringList &arguments)
this, &DebuggerPluginPrivate::updateBreakMenuItem);
// Application interaction
- connect(action(SettingsDialog)->action(), &QAction::triggered,
+ connect(debuggerSettings()->settingsDialog.action(), &QAction::triggered,
[] { ICore::showOptionsDialog(DEBUGGER_COMMON_SETTINGS_ID); });
m_perspective.useSubPerspectiveSwitcher(EngineManager::engineChooser());
@@ -1191,8 +1188,6 @@ DebuggerPluginPrivate::DebuggerPluginPrivate(const QStringList &arguments)
this, &DebuggerPluginPrivate::updatePresetState);
connect(EngineManager::instance(), &EngineManager::currentEngineChanged,
this, &DebuggerPluginPrivate::updatePresetState);
-
- m_globalDebuggerOptions.fromSettings();
}
@@ -1478,9 +1473,10 @@ void DebuggerPluginPrivate::updatePresetState()
// FIXME: Decentralize the actions below
const bool actionsEnabled = currentEngine->debuggerActionsEnabled();
const bool canDeref = actionsEnabled && currentEngine->hasCapability(AutoDerefPointersCapability);
- action(AutoDerefPointers)->setEnabled(canDeref);
- action(AutoDerefPointers)->setEnabled(true);
- action(ExpandStack)->setEnabled(actionsEnabled);
+ DebuggerSettings *s = debuggerSettings();
+ s->autoDerefPointers.setEnabled(canDeref);
+ s->autoDerefPointers.setEnabled(true);
+ s->expandStack.setEnabled(actionsEnabled);
m_startAndDebugApplicationAction.setEnabled(true);
m_attachToQmlPortAction.setEnabled(true);
@@ -1924,8 +1920,8 @@ void DebuggerPluginPrivate::setInitialState()
m_breakAction.setEnabled(false);
//m_snapshotAction.setEnabled(false);
- action(AutoDerefPointers)->setEnabled(true);
- action(ExpandStack)->setEnabled(false);
+ debuggerSettings()->autoDerefPointers.setEnabled(true);
+ debuggerSettings()->expandStack.setEnabled(false);
}
void DebuggerPluginPrivate::updateDebugWithoutDeployMenu()
@@ -1946,7 +1942,7 @@ void DebuggerPluginPrivate::dumpLog()
tr("Save Debugger Log"), Utils::TemporaryDirectory::masterDirectoryPath());
if (fileName.isEmpty())
return;
- FileSaver saver(fileName);
+ FileSaver saver(Utils::FilePath::fromUserInput(fileName));
if (!saver.hasError()) {
QTextStream ts(saver.file());
ts << logWindow->inputContents();
@@ -2016,17 +2012,14 @@ void DebuggerPluginPrivate::extensionsInitialized()
DebuggerMainWindow::ensureMainWindowExists();
}
-SavedAction *DebuggerPluginPrivate::action(int code)
-{
- return m_debuggerSettings.item(code);
-}
-
QWidget *DebuggerPluginPrivate::addSearch(BaseTreeView *treeView)
{
- QAction *act = action(UseAlternatingRowColors)->action();
- treeView->setAlternatingRowColors(act->isChecked());
+ BoolAspect &act = debuggerSettings()->useAlternatingRowColors;
+ treeView->setAlternatingRowColors(act.value());
treeView->setProperty(PerspectiveState::savesHeaderKey(), true);
- connect(act, &QAction::toggled, treeView, &BaseTreeView::setAlternatingRowColors);
+ connect(&act, &BaseAspect::changed, treeView, [treeView] {
+ treeView->setAlternatingRowColors(debuggerSettings()->useAlternatingRowColors.value());
+ });
return ItemViewFind::createSearchableWrapper(treeView);
}
@@ -2036,31 +2029,11 @@ Console *debuggerConsole()
return &dd->m_console;
}
-SavedAction *action(int code)
-{
- return dd->action(code);
-}
-
QWidget *addSearch(BaseTreeView *treeView)
{
return dd->addSearch(treeView);
}
-bool boolSetting(int code)
-{
- return action(code)->value().toBool();
-}
-
-QString stringSetting(int code)
-{
- return action(code)->value().toString();
-}
-
-QStringList stringListSetting(int code)
-{
- return action(code)->value().toStringList();
-}
-
void openTextEditor(const QString &titlePattern0, const QString &contents)
{
if (dd->m_shuttingDown)
@@ -2078,11 +2051,6 @@ void openTextEditor(const QString &titlePattern0, const QString &contents)
QTC_ASSERT(editor, return);
}
-Internal::GlobalDebuggerOptions *globalDebuggerOptions()
-{
- return &dd->m_globalDebuggerOptions;
-}
-
///////////////////////////////////////////////////////////////////////
//
// DebuggerPlugin
diff --git a/src/plugins/debugger/debuggerrunconfigurationaspect.cpp b/src/plugins/debugger/debuggerrunconfigurationaspect.cpp
index 9c998c0093..155658aba8 100644
--- a/src/plugins/debugger/debuggerrunconfigurationaspect.cpp
+++ b/src/plugins/debugger/debuggerrunconfigurationaspect.cpp
@@ -170,8 +170,7 @@ DebuggerRunConfigurationAspect::DebuggerRunConfigurationAspect(Target *target)
setDisplayName(tr("Debugger settings"));
setConfigWidgetCreator([this] {
- QWidget *w = new QWidget;
- LayoutBuilder builder(w);
+ Layouting::Form builder;
builder.addRow(m_cppAspect);
builder.addRow(m_qmlAspect);
builder.addRow(m_overrideStartupAspect);
@@ -179,8 +178,7 @@ DebuggerRunConfigurationAspect::DebuggerRunConfigurationAspect(Target *target)
static const QByteArray env = qgetenv("QTC_DEBUGGER_MULTIPROCESS");
if (env.toInt())
builder.addRow(m_multiProcessAspect);
-
- return w;
+ return builder.emerge(false);
});
m_cppAspect = new DebuggerLanguageAspect;
diff --git a/src/plugins/debugger/debuggerruncontrol.cpp b/src/plugins/debugger/debuggerruncontrol.cpp
index c350651acf..b92d355369 100644
--- a/src/plugins/debugger/debuggerruncontrol.cpp
+++ b/src/plugins/debugger/debuggerruncontrol.cpp
@@ -391,10 +391,11 @@ void DebuggerRunTool::setUseTerminal(bool on)
bool useCdbConsole = m_runParameters.cppEngineType == CdbEngineType
&& (m_runParameters.startMode == StartInternal
|| m_runParameters.startMode == StartExternal)
- && boolSetting(UseCdbConsole);
+ && debuggerSettings()->useCdbConsole.value();
if (on && !d->terminalRunner && !useCdbConsole) {
- d->terminalRunner = new TerminalRunner(runControl(), m_runParameters.inferior);
+ d->terminalRunner =
+ new TerminalRunner(runControl(), [this] { return m_runParameters.inferior; });
d->terminalRunner->setRunAsRoot(m_runParameters.runAsRoot);
addStartDependency(d->terminalRunner);
}
@@ -862,7 +863,7 @@ bool DebuggerRunTool::fixupParameters()
}
}
- if (!boolSetting(AutoEnrichParameters)) {
+ if (!debuggerSettings()->autoEnrichParameters.value()) {
const QString sysroot = rp.sysRoot.toString();
if (rp.debugInfoLocation.isEmpty())
rp.debugInfoLocation = sysroot + "/usr/lib/debug";
@@ -889,7 +890,7 @@ bool DebuggerRunTool::fixupParameters()
QString qmlarg = rp.isCppDebugging() && rp.nativeMixedEnabled
? QmlDebug::qmlDebugNativeArguments(service, false)
: QmlDebug::qmlDebugTcpArguments(service, rp.qmlServer);
- QtcProcess::addArg(&rp.inferior.commandLineArguments, qmlarg);
+ ProcessArgs::addArg(&rp.inferior.commandLineArguments, qmlarg);
}
}
@@ -902,12 +903,12 @@ bool DebuggerRunTool::fixupParameters()
}
if (HostOsInfo::isWindowsHost()) {
- QtcProcess::SplitError perr;
+ ProcessArgs::SplitError perr;
rp.inferior.commandLineArguments =
- QtcProcess::prepareArgs(rp.inferior.commandLineArguments, &perr,
- HostOsInfo::hostOs(), nullptr,
- &rp.inferior.workingDirectory).toWindowsArgs();
- if (perr != QtcProcess::SplitOk) {
+ ProcessArgs::prepareArgs(rp.inferior.commandLineArguments, &perr,
+ HostOsInfo::hostOs(), nullptr,
+ &rp.inferior.workingDirectory).toWindowsArgs();
+ if (perr != ProcessArgs::SplitOk) {
// perr == BadQuoting is never returned on Windows
// FIXME? QTCREATORBUG-2809
reportFailure(DebuggerPlugin::tr("Debugging complex command lines "
@@ -919,6 +920,9 @@ bool DebuggerRunTool::fixupParameters()
if (rp.isNativeMixedDebugging())
rp.inferior.environment.set("QV4_FORCE_INTERPRETER", "1");
+ if (debuggerSettings()->forceLoggingToConsole.value())
+ rp.inferior.environment.set("QT_LOGGING_TO_CONSOLE", "1");
+
return true;
}
@@ -1126,7 +1130,7 @@ DebugServerRunner::DebugServerRunner(RunControl *runControl, DebugServerPortsGat
debugServer.environment = mainRunnable.environment;
debugServer.workingDirectory = mainRunnable.workingDirectory;
- QStringList args = QtcProcess::splitArgs(mainRunnable.commandLineArguments, OsTypeLinux);
+ QStringList args = ProcessArgs::splitArgs(mainRunnable.commandLineArguments, OsTypeLinux);
const bool isQmlDebugging = portsGatherer->useQmlServer();
const bool isCppDebugging = portsGatherer->useGdbServer();
@@ -1158,7 +1162,7 @@ DebugServerRunner::DebugServerRunner(RunControl *runControl, DebugServerPortsGat
args.append(QString::number(m_pid.pid()));
}
}
- debugServer.commandLineArguments = QtcProcess::joinArgs(args, OsTypeLinux);
+ debugServer.commandLineArguments = ProcessArgs::joinArgs(args, OsTypeLinux);
doStart(debugServer, runControl->device());
});
diff --git a/src/plugins/debugger/debuggersourcepathmappingwidget.cpp b/src/plugins/debugger/debuggersourcepathmappingwidget.cpp
index d73fd47dac..92858969ec 100644
--- a/src/plugins/debugger/debuggersourcepathmappingwidget.cpp
+++ b/src/plugins/debugger/debuggersourcepathmappingwidget.cpp
@@ -24,33 +24,73 @@
****************************************************************************/
#include "debuggersourcepathmappingwidget.h"
+
+#include "debuggeractions.h"
#include "debuggerengine.h"
#include <utils/buildablehelperlibrary.h>
#include <utils/fancylineedit.h>
#include <utils/hostosinfo.h>
+#include <utils/layoutbuilder.h>
#include <utils/pathchooser.h>
#include <utils/qtcassert.h>
-#include <utils/synchronousprocess.h>
#include <utils/variablechooser.h>
-#include <QStandardItemModel>
-#include <QTreeView>
-#include <QLineEdit>
-#include <QPushButton>
-#include <QFormLayout>
#include <QFileDialog>
+#include <QFormLayout>
+#include <QGroupBox>
#include <QLabel>
+#include <QLineEdit>
+#include <QPushButton>
+#include <QSettings>
+#include <QStandardItemModel>
+#include <QTreeView>
using namespace Utils;
-enum { SourceColumn, TargetColumn, ColumnCount };
-
namespace Debugger {
namespace Internal {
+class SourcePathMappingModel;
+
+enum { SourceColumn, TargetColumn, ColumnCount };
+
using Mapping = QPair<QString, QString>;
-using SourcePathMap = DebuggerSourcePathMappingWidget::SourcePathMap;
+
+class DebuggerSourcePathMappingWidget : public QGroupBox
+{
+ Q_DECLARE_TR_FUNCTIONS(Debugger::Internal::DebuggerSourcePathMappingWidget)
+
+public:
+ DebuggerSourcePathMappingWidget();
+
+ SourcePathMap sourcePathMap() const;
+ void setSourcePathMap(const SourcePathMap &);
+
+private:
+ void slotAdd();
+ void slotAddQt();
+ void slotRemove();
+ void slotCurrentRowChanged(const QModelIndex &,const QModelIndex &);
+ void slotEditSourceFieldChanged();
+ void slotEditTargetFieldChanged();
+
+ void resizeColumns();
+ void updateEnabled();
+ QString editSourceField() const;
+ QString editTargetField() const;
+ void setEditFieldMapping(const QPair<QString, QString> &m);
+ int currentRow() const;
+ void setCurrentRow(int r);
+
+ SourcePathMappingModel *m_model;
+ QTreeView *m_treeView;
+ QPushButton *m_addButton;
+ QPushButton *m_addQtButton;
+ QPushButton *m_removeButton;
+ QLineEdit *m_sourceLineEdit;
+ Utils::PathChooser *m_targetChooser;
+};
// Qt's various build paths for unpatched versions.
QStringList qtBuildPaths()
@@ -198,8 +238,7 @@ void SourcePathMappingModel::setTarget(int row, const QString &t)
Path mappings to be applied using source path substitution in GDB.
*/
-DebuggerSourcePathMappingWidget::DebuggerSourcePathMappingWidget(QWidget *parent) :
- QGroupBox(parent),
+DebuggerSourcePathMappingWidget::DebuggerSourcePathMappingWidget() :
m_model(new SourcePathMappingModel(this)),
m_treeView(new QTreeView(this)),
m_addButton(new QPushButton(tr("Add"), this)),
@@ -404,11 +443,9 @@ static QString findQtInstallPath(const FilePath &qmakePath)
{
if (qmakePath.isEmpty())
return QString();
- QProcess proc;
- QStringList args;
- args.append("-query");
- args.append("QT_INSTALL_HEADERS");
- proc.start(qmakePath.toString(), args);
+ QtcProcess proc;
+ proc.setCommand({qmakePath, {"-query", "QT_INSTALL_HEADERS"}});
+ proc.start();
if (!proc.waitForStarted()) {
qWarning("%s: Cannot start '%s': %s", Q_FUNC_INFO, qPrintable(qmakePath.toString()),
qPrintable(proc.errorString()));
@@ -416,7 +453,7 @@ static QString findQtInstallPath(const FilePath &qmakePath)
}
proc.closeWriteChannel();
if (!proc.waitForFinished()) {
- SynchronousProcess::stopProcess(proc);
+ proc.stopProcess();
qWarning("%s: Timeout running '%s'.", Q_FUNC_INFO, qPrintable(qmakePath.toString()));
return QString();
}
@@ -431,11 +468,8 @@ static QString findQtInstallPath(const FilePath &qmakePath)
return QString();
}
-/* Merge settings for an installed Qt (unless another setting
- * is already in the map. */
-DebuggerSourcePathMappingWidget::SourcePathMap
- DebuggerSourcePathMappingWidget::mergePlatformQtPath(const DebuggerRunParameters &sp,
- const SourcePathMap &in)
+/* Merge settings for an installed Qt (unless another setting is already in the map. */
+SourcePathMap mergePlatformQtPath(const DebuggerRunParameters &sp, const SourcePathMap &in)
{
const FilePath qmake = BuildableHelperLibrary::findSystemQt(sp.inferior.environment);
// FIXME: Get this from the profile?
@@ -456,5 +490,105 @@ DebuggerSourcePathMappingWidget::SourcePathMap
return rc;
}
+//
+// SourcePathMapAspect
+//
+
+class SourcePathMapAspectPrivate
+{
+public:
+ QPointer<DebuggerSourcePathMappingWidget> m_widget;
+};
+
+
+SourcePathMapAspect::SourcePathMapAspect()
+ : d(new SourcePathMapAspectPrivate)
+{
+}
+
+SourcePathMapAspect::~SourcePathMapAspect()
+{
+ delete d;
+}
+
+void SourcePathMapAspect::fromMap(const QVariantMap &)
+{
+ QTC_CHECK(false); // This is only used via read/writeSettings
+}
+
+void SourcePathMapAspect::toMap(QVariantMap &) const
+{
+ QTC_CHECK(false);
+}
+
+void SourcePathMapAspect::addToLayout(LayoutBuilder &builder)
+{
+ QTC_CHECK(!d->m_widget);
+ d->m_widget = createSubWidget<DebuggerSourcePathMappingWidget>();
+ d->m_widget->setSourcePathMap(value());
+ builder.addRow(d->m_widget.data());
+}
+
+QVariant SourcePathMapAspect::volatileValue() const
+{
+ QTC_CHECK(!isAutoApply());
+ QTC_ASSERT(d->m_widget, return {});
+ return QVariant::fromValue(d->m_widget->sourcePathMap());
+}
+
+void SourcePathMapAspect::setVolatileValue(const QVariant &val)
+{
+ QTC_CHECK(!isAutoApply());
+ if (d->m_widget)
+ d->m_widget->setSourcePathMap(val.value<SourcePathMap>());
+}
+
+const char sourcePathMappingArrayNameC[] = "SourcePathMappings";
+const char sourcePathMappingSourceKeyC[] = "Source";
+const char sourcePathMappingTargetKeyC[] = "Target";
+
+SourcePathMap SourcePathMapAspect::value() const
+{
+ return BaseAspect::value().value<SourcePathMap>();
+}
+
+void SourcePathMapAspect::writeSettings(QSettings *s) const
+{
+ const SourcePathMap sourcePathMap = value();
+ s->beginWriteArray(sourcePathMappingArrayNameC);
+ if (!sourcePathMap.isEmpty()) {
+ const QString sourcePathMappingSourceKey(sourcePathMappingSourceKeyC);
+ const QString sourcePathMappingTargetKey(sourcePathMappingTargetKeyC);
+ int i = 0;
+ for (auto it = sourcePathMap.constBegin(), cend = sourcePathMap.constEnd();
+ it != cend;
+ ++it, ++i) {
+ s->setArrayIndex(i);
+ s->setValue(sourcePathMappingSourceKey, it.key());
+ s->setValue(sourcePathMappingTargetKey, it.value());
+ }
+ }
+ s->endArray();
+}
+
+void SourcePathMapAspect::readSettings(const QSettings *settings)
+{
+ // Eeks. But legitimate, this operates on ICore::settings();
+ QSettings *s = const_cast<QSettings *>(settings);
+ SourcePathMap sourcePathMap;
+ if (const int count = s->beginReadArray(sourcePathMappingArrayNameC)) {
+ const QString sourcePathMappingSourceKey(sourcePathMappingSourceKeyC);
+ const QString sourcePathMappingTargetKey(sourcePathMappingTargetKeyC);
+ for (int i = 0; i < count; ++i) {
+ s->setArrayIndex(i);
+ const QString key = s->value(sourcePathMappingSourceKey).toString();
+ const QString value = s->value(sourcePathMappingTargetKey).toString();
+ sourcePathMap.insert(key, value);
+ }
+ }
+ s->endArray();
+ setValue(QVariant::fromValue(sourcePathMap));
+}
+
} // namespace Internal
} // namespace Debugger
diff --git a/src/plugins/debugger/debuggersourcepathmappingwidget.h b/src/plugins/debugger/debuggersourcepathmappingwidget.h
index 5d6624bb6d..a1f07a67c5 100644
--- a/src/plugins/debugger/debuggersourcepathmappingwidget.h
+++ b/src/plugins/debugger/debuggersourcepathmappingwidget.h
@@ -25,67 +25,17 @@
#pragma once
-#include <QGroupBox>
#include <QMap>
-
-QT_BEGIN_NAMESPACE
-class QStandardItemModel;
-class QTreeView;
-class QLineEdit;
-class QPushButton;
-class QLineEdit;
-class QModelIndex;
-QT_END_NAMESPACE
-
-namespace Utils { class PathChooser; }
+#include <QString>
namespace Debugger {
namespace Internal {
class DebuggerRunParameters;
-class SourcePathMappingModel;
-
-class DebuggerSourcePathMappingWidget : public QGroupBox
-{
- Q_OBJECT
-
-public:
- using SourcePathMap = QMap<QString, QString>;
-
- explicit DebuggerSourcePathMappingWidget(QWidget *parent = nullptr);
-
- SourcePathMap sourcePathMap() const;
- void setSourcePathMap(const SourcePathMap &);
-
- /* Merge settings for an installed Qt (unless another setting
- * is already in the map. */
- static SourcePathMap mergePlatformQtPath(const DebuggerRunParameters &sp,
- const SourcePathMap &in);
-
-private:
- void slotAdd();
- void slotAddQt();
- void slotRemove();
- void slotCurrentRowChanged(const QModelIndex &,const QModelIndex &);
- void slotEditSourceFieldChanged();
- void slotEditTargetFieldChanged();
-
- void resizeColumns();
- void updateEnabled();
- QString editSourceField() const;
- QString editTargetField() const;
- void setEditFieldMapping(const QPair<QString, QString> &m);
- int currentRow() const;
- void setCurrentRow(int r);
-
- SourcePathMappingModel *m_model;
- QTreeView *m_treeView;
- QPushButton *m_addButton;
- QPushButton *m_addQtButton;
- QPushButton *m_removeButton;
- QLineEdit *m_sourceLineEdit;
- Utils::PathChooser *m_targetChooser;
-};
+using SourcePathMap = QMap<QString, QString>;
+/* Merge settings for an installed Qt (unless another setting
+ * is already in the map. */
+SourcePathMap mergePlatformQtPath(const DebuggerRunParameters &sp, const SourcePathMap &in);
} // namespace Internal
} // namespace Debugger
diff --git a/src/plugins/debugger/debuggertooltipmanager.cpp b/src/plugins/debugger/debuggertooltipmanager.cpp
index 546a68fac6..6c6f314bb1 100644
--- a/src/plugins/debugger/debuggertooltipmanager.cpp
+++ b/src/plugins/debugger/debuggertooltipmanager.cpp
@@ -1188,7 +1188,7 @@ void DebuggerToolTipManagerPrivate::slotTooltipOverrideRequested
QTC_ASSERT(handled, return);
QTC_ASSERT(editorWidget, return);
- if (!boolSetting(UseToolTipsInMainEditor))
+ if (!debuggerSettings()->useToolTipsInMainEditor.value())
return;
const TextDocument *document = editorWidget->textDocument();
diff --git a/src/plugins/debugger/disassembleragent.cpp b/src/plugins/debugger/disassembleragent.cpp
index 31d672a986..1b313efaea 100644
--- a/src/plugins/debugger/disassembleragent.cpp
+++ b/src/plugins/debugger/disassembleragent.cpp
@@ -42,9 +42,9 @@
#include <texteditor/textdocument.h>
#include <texteditor/texteditor.h>
+#include <utils/aspects.h>
#include <utils/mimetypes/mimedatabase.h>
#include <utils/qtcassert.h>
-#include <utils/savedaction.h>
#include <QTextBlock>
#include <QDir>
@@ -181,7 +181,7 @@ int DisassemblerAgentPrivate::lineForAddress(quint64 address) const
DisassemblerAgent::DisassemblerAgent(DebuggerEngine *engine)
: d(new DisassemblerAgentPrivate(engine))
{
- connect(action(IntelFlavor), &Utils::SavedAction::valueChanged,
+ connect(&debuggerSettings()->intelFlavor, &Utils::BaseAspect::changed,
this, &DisassemblerAgent::reload);
}
diff --git a/src/plugins/debugger/gdb/gdbengine.cpp b/src/plugins/debugger/gdb/gdbengine.cpp
index df2d6511aa..67ced04fb2 100644
--- a/src/plugins/debugger/gdb/gdbengine.cpp
+++ b/src/plugins/debugger/gdb/gdbengine.cpp
@@ -63,9 +63,7 @@
#include <utils/hostosinfo.h>
#include <utils/qtcassert.h>
#include <utils/qtcprocess.h>
-#include <utils/savedaction.h>
#include <utils/stringutils.h>
-#include <utils/synchronousprocess.h>
#include <utils/temporaryfile.h>
#include <QDirIterator>
@@ -158,13 +156,14 @@ GdbEngine::GdbEngine()
connect(&m_commandTimer, &QTimer::timeout,
this, &GdbEngine::commandTimeout);
- connect(action(AutoDerefPointers), &SavedAction::valueChanged,
+ DebuggerSettings &s = *debuggerSettings();
+ connect(&s.autoDerefPointers, &BaseAspect::changed,
this, &GdbEngine::reloadLocals);
- connect(action(CreateFullBacktrace)->action(), &QAction::triggered,
+ connect(s.createFullBacktrace.action(), &QAction::triggered,
this, &GdbEngine::createFullBacktrace);
- connect(action(UseDebuggingHelpers), &SavedAction::valueChanged,
+ connect(&s.useDebuggingHelpers, &BaseAspect::changed,
this, &GdbEngine::reloadLocals);
- connect(action(UseDynamicType), &SavedAction::valueChanged,
+ connect(&s.useDynamicType, &BaseAspect::changed,
this, &GdbEngine::reloadLocals);
connect(&m_gdbProc, &QProcess::errorOccurred,
@@ -804,7 +803,7 @@ void GdbEngine::runCommand(const DebuggerCommand &command)
int GdbEngine::commandTimeoutTime() const
{
- int time = action(GdbWatchdogTimeout)->value().toInt();
+ const int time = debuggerSettings()->gdbWatchdogTimeout.value();
return 1000 * qMax(20, time);
}
@@ -946,7 +945,7 @@ void GdbEngine::handleResultRecord(DebuggerResponse *response)
DebuggerCommand cmd = m_commandForToken.take(token);
const int flags = m_flagsForToken.take(token);
- if (boolSetting(LogTimeStamps)) {
+ if (debuggerSettings()->logTimeStamps.value()) {
showMessage(QString("Response time: %1: %2 s")
.arg(cmd.function)
.arg(QTime::fromMSecsSinceStartOfDay(cmd.postTime).msecsTo(QTime::currentTime()) / 1000.),
@@ -1020,7 +1019,7 @@ void GdbEngine::updateAll()
{
//PENDING_DEBUG("UPDATING ALL\n");
QTC_CHECK(state() == InferiorUnrunnable || state() == InferiorStopOk);
- DebuggerCommand cmd(stackCommand(action(MaximalStackDepth)->value().toInt()));
+ DebuggerCommand cmd(stackCommand(debuggerSettings()->maximalStackDepth.value()));
cmd.callback = [this](const DebuggerResponse &r) { handleStackListFrames(r, false); };
runCommand(cmd);
stackHandler()->setCurrentIndex(0);
@@ -1275,7 +1274,7 @@ void GdbEngine::handleStop1(const GdbMi &data)
// Jump over well-known frames.
static int stepCounter = 0;
- if (boolSetting(SkipKnownFrames)) {
+ if (debuggerSettings()->skipKnownFrames.value()) {
if (reason == "end-stepping-range" || reason == "function-finished") {
//showMessage(frame.toString());
QString funcName = frame["function"].data();
@@ -1312,7 +1311,7 @@ void GdbEngine::handleStop1(const GdbMi &data)
if (!m_systemDumpersLoaded) {
m_systemDumpersLoaded = true;
- if (m_gdbVersion >= 70400 && boolSetting(LoadGdbDumpers))
+ if (m_gdbVersion >= 70400 && debuggerSettings()->loadGdbDumpers.value())
runCommand({"importPlainDumpers on"});
else
runCommand({"importPlainDumpers off"});
@@ -1425,7 +1424,7 @@ void GdbEngine::handleStop2(const GdbMi &data)
showMessage("SIGNAL 0 CONSIDERED BOGUS.");
} else {
showMessage("HANDLING SIGNAL " + name);
- if (boolSetting(UseMessageBoxForSignals) && !isStopperThread)
+ if (debuggerSettings()->useMessageBoxForSignals.value() && !isStopperThread)
if (!showStoppedBySignalMessageBox(meaning, name)) {
showMessage("SIGNAL RECEIVED WHILE SHOWING SIGNAL MESSAGE");
return;
@@ -1584,7 +1583,7 @@ QString GdbEngine::cleanupFullName(const QString &fileName)
cleanFilePath = QDir::cleanPath(fi.absoluteFilePath());
}
- if (!boolSetting(AutoEnrichParameters))
+ if (!debuggerSettings()->autoEnrichParameters.value())
return cleanFilePath;
const QString sysroot = runParameters().sysRoot.toString();
@@ -2041,7 +2040,7 @@ void GdbEngine::setTokenBarrier()
QTC_ASSERT(good, return);
PENDING_DEBUG("\n--- token barrier ---\n");
showMessage("--- token barrier ---", LogMiscInput);
- if (boolSetting(LogTimeStamps))
+ if (debuggerSettings()->logTimeStamps.value())
showMessage(LogWindow::logTimeStamp(), LogMiscInput);
m_oldestAcceptableToken = currentToken();
m_stackNeeded = false;
@@ -2073,7 +2072,7 @@ QString GdbEngine::breakpointLocation(const BreakpointParameters &data)
if (data.type == BreakpointAtMain)
return mainFunction();
if (data.type == BreakpointByFunction)
- return '"' + data.functionName + '"';
+ return "--function \"" + data.functionName + '"';
if (data.type == BreakpointByAddress)
return addressSpec(data.address);
@@ -2163,7 +2162,7 @@ void GdbEngine::handleCatchInsert(const DebuggerResponse &response, const Breakp
void GdbEngine::handleBkpt(const GdbMi &bkpt, const Breakpoint &bp)
{
QTC_ASSERT(bp, return);
- bool usePseudoTracepoints = boolSetting(UsePseudoTracepoints);
+ const bool usePseudoTracepoints = debuggerSettings()->usePseudoTracepoints.value();
const QString nr = bkpt["number"].data();
if (nr.contains('.')) {
// A sub-breakpoint.
@@ -2578,7 +2577,7 @@ void GdbEngine::insertBreakpoint(const Breakpoint &bp)
int spec = requested.threadSpec;
if (requested.isTracepoint()) {
- if (boolSetting(UsePseudoTracepoints)) {
+ if (debuggerSettings()->usePseudoTracepoints.value()) {
cmd.function = "createTracepoint";
if (requested.oneShot)
@@ -2613,14 +2612,15 @@ void GdbEngine::insertBreakpoint(const Breakpoint &bp)
// for dumping of expressions
const static bool alwaysVerbose = qEnvironmentVariableIsSet("QTC_DEBUGGER_PYTHON_VERBOSE");
+ const DebuggerSettings &s = *debuggerSettings();
cmd.arg("passexceptions", alwaysVerbose);
- cmd.arg("fancy", boolSetting(UseDebuggingHelpers));
- cmd.arg("autoderef", boolSetting(AutoDerefPointers));
- cmd.arg("dyntype", boolSetting(UseDynamicType));
- cmd.arg("qobjectnames", boolSetting(ShowQObjectNames));
+ cmd.arg("fancy", s.useDebuggingHelpers.value());
+ cmd.arg("autoderef", s.autoDerefPointers.value());
+ cmd.arg("dyntype", s.useDynamicType.value());
+ cmd.arg("qobjectnames", s.showQObjectNames.value());
cmd.arg("nativemixed", isNativeMixedActive());
- cmd.arg("stringcutoff", action(MaximalStringLength)->value().toString());
- cmd.arg("displaystringlimit", action(DisplayStringLimit)->value().toString());
+ cmd.arg("stringcutoff", s.maximalStringLength.value());
+ cmd.arg("displaystringlimit", s.displayStringLimit.value());
cmd.arg("spec", breakpointLocation2(requested));
cmd.callback = [this, bp](const DebuggerResponse &r) { handleTracepointInsert(r, bp); };
@@ -3116,7 +3116,7 @@ DebuggerCommand GdbEngine::stackCommand(int depth)
void GdbEngine::reloadStack()
{
PENDING_DEBUG("RELOAD STACK");
- DebuggerCommand cmd = stackCommand(action(MaximalStackDepth)->value().toInt());
+ DebuggerCommand cmd = stackCommand(debuggerSettings()->maximalStackDepth.value());
cmd.callback = [this](const DebuggerResponse &r) { handleStackListFrames(r, false); };
cmd.flags = Discardable;
runCommand(cmd);
@@ -3180,8 +3180,8 @@ void GdbEngine::handleThreadInfo(const DebuggerResponse &response)
ThreadsHandler *handler = threadsHandler();
handler->setThreads(response.data);
updateState(); // Adjust Threads combobox.
- if (boolSetting(ShowThreadNames)) {
- runCommand({"threadnames " + action(MaximalStackDepth)->value().toString(),
+ if (debuggerSettings()->showThreadNames.value()) {
+ runCommand({QString("threadnames %1").arg(debuggerSettings()->maximalStackDepth.value()),
Discardable, CB(handleThreadNames)});
}
reloadStack(); // Will trigger register reload.
@@ -3649,7 +3649,7 @@ public:
void GdbEngine::fetchDisassembler(DisassemblerAgent *agent)
{
- if (boolSetting(IntelFlavor))
+ if (debuggerSettings()->intelFlavor.value())
runCommand({"set disassembly-flavor intel"});
else
runCommand({"set disassembly-flavor att"});
@@ -3834,7 +3834,7 @@ void GdbEngine::setupEngine()
}
gdbCommand.addArgs({"-i", "mi"});
- if (!boolSetting(LoadGdbInit))
+ if (!debuggerSettings()->loadGdbInit.value())
gdbCommand.addArg("-n");
Environment gdbEnv = rp.debugger.environment;
@@ -3932,8 +3932,7 @@ void GdbEngine::setupEngine()
// Apply source path mappings from global options.
//showMessage(_("Assuming Qt is installed at %1").arg(qtInstallPath));
const SourcePathMap sourcePathMap =
- DebuggerSourcePathMappingWidget::mergePlatformQtPath(rp,
- Internal::globalDebuggerOptions()->sourcePathMap);
+ mergePlatformQtPath(rp, debuggerSettings()->sourcePathMap.value());
const SourcePathMap completeSourcePathMap =
mergeStartParametersSourcePathMap(rp, sourcePathMap);
for (auto it = completeSourcePathMap.constBegin(), cend = completeSourcePathMap.constEnd();
@@ -3961,7 +3960,7 @@ void GdbEngine::setupEngine()
//if (!ba.isEmpty())
// runCommand("set solib-search-path " + ba);
- if (boolSetting(MultiInferior) || runParameters().multiProcess) {
+ if (debuggerSettings()->multiInferior.value() || runParameters().multiProcess) {
//runCommand("set follow-exec-mode new");
runCommand({"set detach-on-fork off"});
}
@@ -3970,7 +3969,7 @@ void GdbEngine::setupEngine()
// We need to guarantee a roundtrip before the adapter proceeds.
// Make sure this stays the last command in startGdb().
// Don't use ConsoleCommand, otherwise Mac won't markup the output.
- const QString dumperSourcePath = ICore::resourcePath() + "/debugger/";
+ const QString dumperSourcePath = ICore::resourcePath("debugger/").toString();
//if (terminal()->isUsable())
// runCommand({"set inferior-tty " + QString::fromUtf8(terminal()->slaveDevice())});
@@ -3982,14 +3981,14 @@ void GdbEngine::setupEngine()
runCommand({"python sys.path.append('" + uninstalledData + "')"});
runCommand({"python from gdbbridge import *"});
- const QString path = stringSetting(ExtraDumperFile);
+ const QString path = debuggerSettings()->extraDumperFile.value();
if (!path.isEmpty() && QFileInfo(path).isReadable()) {
DebuggerCommand cmd("addDumperModule");
cmd.arg("path", path);
runCommand(cmd);
}
- const QString commands = stringSetting(ExtraDumperCommands);
+ const QString commands = debuggerSettings()->extraDumperCommands.value();
if (!commands.isEmpty())
runCommand({commands});
@@ -4197,7 +4196,7 @@ bool GdbEngine::usesExecInterrupt() const
bool GdbEngine::usesTargetAsync() const
{
- return runParameters().useTargetAsync || boolSetting(TargetAsync);
+ return runParameters().useTargetAsync || debuggerSettings()->targetAsync.value();
}
void GdbEngine::scheduleTestResponse(int testCase, const QString &response)
@@ -4306,9 +4305,10 @@ void GdbEngine::claimInitialBreakpoints()
showMessage(tr("Setting breakpoints..."));
BreakpointManager::claimBreakpointsForEngine(this);
- const bool onAbort = boolSetting(BreakOnAbort);
- const bool onWarning = boolSetting(BreakOnWarning);
- const bool onFatal = boolSetting(BreakOnFatal);
+ const DebuggerSettings &s = *debuggerSettings();
+ const bool onAbort = s.breakOnAbort.value();
+ const bool onWarning = s.breakOnWarning.value();
+ const bool onFatal = s.breakOnFatal.value();
if (onAbort || onWarning || onFatal) {
DebuggerCommand cmd("createSpecialBreakpoints");
cmd.arg("breakonabort", onAbort);
@@ -4766,7 +4766,7 @@ void GdbEngine::handleTargetRemote(const DebuggerResponse &response)
// gdb server will stop the remote application itself.
showMessage("INFERIOR STARTED");
showMessage(msgAttachedToStoppedInferior(), StatusBar);
- QString commands = expand(stringSetting(GdbPostAttachCommands));
+ QString commands = expand(debuggerSettings()->gdbPostAttachCommands.value());
if (!commands.isEmpty())
runCommand({commands, NativeCommand});
handleInferiorPrepared();
@@ -4782,7 +4782,7 @@ void GdbEngine::handleTargetExtendedRemote(const DebuggerResponse &response)
if (response.resultClass == ResultDone) {
showMessage("ATTACHED TO GDB SERVER STARTED");
showMessage(msgAttachedToStoppedInferior(), StatusBar);
- QString commands = expand(stringSetting(GdbPostAttachCommands));
+ QString commands = expand(debuggerSettings()->gdbPostAttachCommands.value());
if (!commands.isEmpty())
runCommand({commands, NativeCommand});
if (runParameters().attachPID.isValid()) { // attach to pid if valid
@@ -4975,13 +4975,14 @@ CoreInfo CoreInfo::readExecutableNameFromCore(const Runnable &debugger, const QS
args += {"-ex", "core " + coreFile};
SynchronousProcess proc;
- QStringList envLang = QProcess::systemEnvironment();
- Utils::Environment::setupEnglishOutput(&envLang);
+ Environment envLang(Environment::systemEnvironment());
+ envLang.setupEnglishOutput();
proc.setEnvironment(envLang);
- SynchronousProcessResponse response = proc.runBlocking({debugger.executable, args});
+ proc.setCommand({debugger.executable, args});
+ proc.runBlocking();
- if (response.result == SynchronousProcessResponse::Finished) {
- QString output = response.stdOut();
+ if (proc.result() == QtcProcess::Finished) {
+ QString output = proc.stdOut();
// Core was generated by `/data/dev/creator-2.6/bin/qtcreator'.
// Program terminated with signal 11, Segmentation fault.
int pos1 = output.indexOf("Core was generated by");
@@ -5037,19 +5038,20 @@ void GdbEngine::doUpdateLocals(const UpdateParameters &params)
watchHandler()->appendWatchersAndTooltipRequests(&cmd);
const static bool alwaysVerbose = qEnvironmentVariableIsSet("QTC_DEBUGGER_PYTHON_VERBOSE");
+ const DebuggerSettings &s = *debuggerSettings();
cmd.arg("passexceptions", alwaysVerbose);
- cmd.arg("fancy", boolSetting(UseDebuggingHelpers));
- cmd.arg("autoderef", boolSetting(AutoDerefPointers));
- cmd.arg("dyntype", boolSetting(UseDynamicType));
- cmd.arg("qobjectnames", boolSetting(ShowQObjectNames));
- cmd.arg("timestamps", boolSetting(LogTimeStamps));
+ cmd.arg("fancy", s.useDebuggingHelpers.value());
+ cmd.arg("autoderef", s.autoDerefPointers.value());
+ cmd.arg("dyntype", s.useDynamicType.value());
+ cmd.arg("qobjectnames", s.showQObjectNames.value());
+ cmd.arg("timestamps", s.logTimeStamps.value());
StackFrame frame = stackHandler()->currentFrame();
cmd.arg("context", frame.context);
cmd.arg("nativemixed", isNativeMixedActive());
- cmd.arg("stringcutoff", action(MaximalStringLength)->value().toString());
- cmd.arg("displaystringlimit", action(DisplayStringLimit)->value().toString());
+ cmd.arg("stringcutoff", s.maximalStringLength.value());
+ cmd.arg("displaystringlimit", s.displayStringLimit.value());
cmd.arg("resultvarname", m_resultVarName);
cmd.arg("partialvar", params.partialVariable);
diff --git a/src/plugins/debugger/gdb/gdboptionspage.cpp b/src/plugins/debugger/gdb/gdboptionspage.cpp
index 8ba9122f09..c531f5d133 100644
--- a/src/plugins/debugger/gdb/gdboptionspage.cpp
+++ b/src/plugins/debugger/gdb/gdboptionspage.cpp
@@ -23,30 +23,14 @@
**
****************************************************************************/
-#include <debugger/commonoptionspage.h>
#include <debugger/debuggeractions.h>
#include <debugger/debuggercore.h>
#include <debugger/debuggerinternalconstants.h>
#include <debugger/debuggerconstants.h>
#include <coreplugin/dialogs/ioptionspage.h>
-#include <coreplugin/icore.h>
-#include <utils/fancylineedit.h>
-#include <utils/pathchooser.h>
-#include <utils/savedaction.h>
-#include <utils/variablechooser.h>
-
-#include <QCheckBox>
-#include <QCoreApplication>
-#include <QDebug>
-#include <QFormLayout>
-#include <QGroupBox>
-#include <QLabel>
-#include <QLineEdit>
-#include <QPointer>
-#include <QSpinBox>
-#include <QTextEdit>
+#include <utils/layoutbuilder.h>
using namespace Core;
using namespace Utils;
@@ -56,7 +40,7 @@ namespace Internal {
/////////////////////////////////////////////////////////////////////////
//
-// GdbOptionsPageWidget - harmless options
+// GdbOptionsPage - harmless options
//
/////////////////////////////////////////////////////////////////////////
@@ -65,305 +49,48 @@ class GdbOptionsPage : public Core::IOptionsPage
Q_DECLARE_TR_FUNCTIONS(Debugger::Internal::GdbOptionsPage)
public:
- GdbOptionsPage();
-};
-
-class GdbOptionsPageWidget : public IOptionsPageWidget
-{
-public:
- GdbOptionsPageWidget();
-
- void apply() final { group.apply(ICore::settings()); }
- void finish() final { group.finish(); }
-
- SavedActionSet group;
+ GdbOptionsPage()
+ {
+ setId("M.Gdb");
+ setDisplayName(tr("GDB"));
+ setCategory(Constants::DEBUGGER_SETTINGS_CATEGORY);
+ setSettings(&debuggerSettings()->page2);
+
+ setLayouter([](QWidget *w) {
+ using namespace Layouting;
+ DebuggerSettings &s = *debuggerSettings();
+
+ Group general {
+ Title { tr("General") },
+ Row { s.gdbWatchdogTimeout, Stretch() },
+ s.skipKnownFrames,
+ s.useMessageBoxForSignals,
+ s.adjustBreakpointLocations,
+ s.useDynamicType,
+ s.loadGdbInit,
+ s.loadGdbDumpers,
+ s.intelFlavor,
+ s.usePseudoTracepoints,
+ Stretch()
+ };
+
+ Column commands {
+ Group { Title { tr("Additional Startup Commands") }, s.gdbStartupCommands },
+ Group { Title { tr("Additional Attach Commands") }, s.gdbPostAttachCommands },
+ Stretch()
+ };
+
+ Row { general, commands }.attachTo(w);
+ });
+ }
};
-GdbOptionsPageWidget::GdbOptionsPageWidget()
-{
- auto groupBoxGeneral = new QGroupBox(this);
- groupBoxGeneral->setTitle(GdbOptionsPage::tr("General"));
-
- auto labelGdbWatchdogTimeout = new QLabel(groupBoxGeneral);
- labelGdbWatchdogTimeout->setText(GdbOptionsPage::tr("GDB timeout:"));
- labelGdbWatchdogTimeout->setToolTip(GdbOptionsPage::tr(
- "The number of seconds before a non-responsive GDB process is terminated.\n"
- "The default value of 20 seconds should be sufficient for most\n"
- "applications, but there are situations when loading big libraries or\n"
- "listing source files takes much longer than that on slow machines.\n"
- "In this case, the value should be increased."));
-
- auto spinBoxGdbWatchdogTimeout = new QSpinBox(groupBoxGeneral);
- spinBoxGdbWatchdogTimeout->setToolTip(labelGdbWatchdogTimeout->toolTip());
- spinBoxGdbWatchdogTimeout->setSuffix(GdbOptionsPage::tr("sec"));
- spinBoxGdbWatchdogTimeout->setLayoutDirection(Qt::LeftToRight);
- spinBoxGdbWatchdogTimeout->setMinimum(20);
- spinBoxGdbWatchdogTimeout->setMaximum(1000000);
- spinBoxGdbWatchdogTimeout->setSingleStep(20);
- spinBoxGdbWatchdogTimeout->setValue(20);
-
- auto checkBoxSkipKnownFrames = new QCheckBox(groupBoxGeneral);
- checkBoxSkipKnownFrames->setText(GdbOptionsPage::tr("Skip known frames when stepping"));
- checkBoxSkipKnownFrames->setToolTip(GdbOptionsPage::tr(
- "<html><head/><body><p>"
- "Allows <i>Step Into</i> to compress several steps into one step\n"
- "for less noisy debugging. For example, the atomic reference\n"
- "counting code is skipped, and a single <i>Step Into</i> for a signal\n"
- "emission ends up directly in the slot connected to it."));
-
- auto checkBoxUseMessageBoxForSignals = new QCheckBox(groupBoxGeneral);
- checkBoxUseMessageBoxForSignals->setText(GdbOptionsPage::tr(
- "Show a message box when receiving a signal"));
- checkBoxUseMessageBoxForSignals->setToolTip(GdbOptionsPage::tr(
- "Displays a message box as soon as your application\n"
- "receives a signal like SIGSEGV during debugging."));
-
- auto checkBoxAdjustBreakpointLocations = new QCheckBox(groupBoxGeneral);
- checkBoxAdjustBreakpointLocations->setText(GdbOptionsPage::tr(
- "Adjust breakpoint locations"));
- checkBoxAdjustBreakpointLocations->setToolTip(GdbOptionsPage::tr(
- "GDB allows setting breakpoints on source lines for which no code \n"
- "was generated. In such situations the breakpoint is shifted to the\n"
- "next source code line for which code was actually generated.\n"
- "This option reflects such temporary change by moving the breakpoint\n"
- "markers in the source code editor."));
-
- auto checkBoxUseDynamicType = new QCheckBox(groupBoxGeneral);
- checkBoxUseDynamicType->setText(GdbOptionsPage::tr(
- "Use dynamic object type for display"));
- checkBoxUseDynamicType->setToolTip(GdbOptionsPage::tr(
- "Specifies whether the dynamic or the static type of objects will be "
- "displayed. Choosing the dynamic type might be slower."));
-
- auto checkBoxLoadGdbInit = new QCheckBox(groupBoxGeneral);
- checkBoxLoadGdbInit->setText(GdbOptionsPage::tr("Load .gdbinit file on startup"));
- checkBoxLoadGdbInit->setToolTip(GdbOptionsPage::tr(
- "Allows or inhibits reading the user's default\n"
- ".gdbinit file on debugger startup."));
-
- auto checkBoxLoadGdbDumpers = new QCheckBox(groupBoxGeneral);
- checkBoxLoadGdbDumpers->setText(GdbOptionsPage::tr("Load system GDB pretty printers"));
- checkBoxLoadGdbDumpers->setToolTip(GdbOptionsPage::tr(
- "Uses the default GDB pretty printers installed in your "
- "system or linked to the libraries your application uses."));
-
- auto checkBoxIntelFlavor = new QCheckBox(groupBoxGeneral);
- checkBoxIntelFlavor->setText(GdbOptionsPage::tr("Use Intel style disassembly"));
- checkBoxIntelFlavor->setToolTip(GdbOptionsPage::tr(
- "<html><head/><body>GDB shows by default AT&&T style disassembly."
- "</body></html>"));
-
- auto checkBoxUsePseudoTracepoints = new QCheckBox(groupBoxGeneral);
- checkBoxUsePseudoTracepoints->setText(GdbOptionsPage::tr("Use pseudo message tracepoints"));
- checkBoxUsePseudoTracepoints->setToolTip(GdbOptionsPage::tr(
- "Uses Python to extend the ordinary GDB breakpoint class."));
-
- QString howToUsePython = GdbOptionsPage::tr(
- "<p>To execute simple Python commands, prefix them with \"python\".</p>"
- "<p>To execute sequences of Python commands spanning multiple lines "
- "prepend the block with \"python\" on a separate line, and append "
- "\"end\" on a separate line.</p>"
- "<p>To execute arbitrary Python scripts, "
- "use <i>python execfile('/path/to/script.py')</i>.</p>");
-
- auto groupBoxStartupCommands = new QGroupBox(this);
- groupBoxStartupCommands->setTitle(GdbOptionsPage::tr("Additional Startup Commands"));
- groupBoxStartupCommands->setToolTip(GdbOptionsPage::tr(
- "<html><head/><body><p>GDB commands entered here will be executed after "
- "GDB has been started, but before the debugged program is started or "
- "attached, and before the debugging helpers are initialized.</p>%1"
- "</body></html>").arg(howToUsePython));
-
- auto textEditStartupCommands = new QTextEdit(groupBoxStartupCommands);
- textEditStartupCommands->setAcceptRichText(false);
- textEditStartupCommands->setToolTip(groupBoxStartupCommands->toolTip());
-
- auto groupBoxPostAttachCommands = new QGroupBox(this);
- groupBoxPostAttachCommands->setTitle(GdbOptionsPage::tr("Additional Attach Commands"));
- groupBoxPostAttachCommands->setToolTip(GdbOptionsPage::tr(
- "<html><head/><body><p>GDB commands entered here will be executed after "
- "GDB has successfully attached to remote targets.</p>"
- "<p>You can add commands to further set up the target here, "
- "such as \"monitor reset\" or \"load\"."
- "</body></html>"));
-
- auto textEditPostAttachCommands = new QTextEdit(groupBoxPostAttachCommands);
- textEditPostAttachCommands->setAcceptRichText(false);
- textEditPostAttachCommands->setToolTip(groupBoxPostAttachCommands->toolTip());
-
- /*
- groupBoxPluginDebugging = new QGroupBox(q);
- groupBoxPluginDebugging->setTitle(GdbOptionsPage::tr(
- "Behavior of Breakpoint Setting in Plugins"));
-
- radioButtonAllPluginBreakpoints = new QRadioButton(groupBoxPluginDebugging);
- radioButtonAllPluginBreakpoints->setText(GdbOptionsPage::tr(
- "Always try to set breakpoints in plugins automatically"));
- radioButtonAllPluginBreakpoints->setToolTip(GdbOptionsPage::tr(
- "This is the slowest but safest option."));
-
- radioButtonSelectedPluginBreakpoints = new QRadioButton(groupBoxPluginDebugging);
- radioButtonSelectedPluginBreakpoints->setText(GdbOptionsPage::tr(
- "Try to set breakpoints in selected plugins"));
-
- radioButtonNoPluginBreakpoints = new QRadioButton(groupBoxPluginDebugging);
- radioButtonNoPluginBreakpoints->setText(GdbOptionsPage::tr(
- "Never set breakpoints in plugins automatically"));
-
- lineEditSelectedPluginBreakpointsPattern = new QLineEdit(groupBoxPluginDebugging);
-
- labelSelectedPluginBreakpoints = new QLabel(groupBoxPluginDebugging);
- labelSelectedPluginBreakpoints->setText(GdbOptionsPage::tr(
- "Matching regular expression: "));
- */
-
- auto chooser = new VariableChooser(this);
- chooser->addSupportedWidget(textEditPostAttachCommands);
- chooser->addSupportedWidget(textEditStartupCommands);
-
- auto formLayout = new QFormLayout(groupBoxGeneral);
- formLayout->addRow(labelGdbWatchdogTimeout, spinBoxGdbWatchdogTimeout);
- formLayout->addRow(checkBoxSkipKnownFrames);
- formLayout->addRow(checkBoxUseMessageBoxForSignals);
- formLayout->addRow(checkBoxAdjustBreakpointLocations);
- formLayout->addRow(checkBoxUseDynamicType);
- formLayout->addRow(checkBoxLoadGdbInit);
- formLayout->addRow(checkBoxLoadGdbDumpers);
- formLayout->addRow(checkBoxIntelFlavor);
- formLayout->addRow(checkBoxUsePseudoTracepoints);
-
- auto startLayout = new QGridLayout(groupBoxStartupCommands);
- startLayout->addWidget(textEditStartupCommands, 0, 0, 1, 1);
-
- auto postAttachLayout = new QGridLayout(groupBoxPostAttachCommands);
- postAttachLayout->addWidget(textEditPostAttachCommands, 0, 0, 1, 1);
-
- auto gridLayout = new QGridLayout(this);
- gridLayout->addWidget(groupBoxGeneral, 0, 0, 5, 1);
-
- gridLayout->addWidget(groupBoxStartupCommands, 0, 1, 2, 1);
- gridLayout->addWidget(groupBoxPostAttachCommands, 2, 1, 2, 1);
-
- group.insert(action(GdbStartupCommands), textEditStartupCommands);
- group.insert(action(GdbPostAttachCommands), textEditPostAttachCommands);
- group.insert(action(LoadGdbInit), checkBoxLoadGdbInit);
- group.insert(action(LoadGdbDumpers), checkBoxLoadGdbDumpers);
- group.insert(action(UseDynamicType), checkBoxUseDynamicType);
- group.insert(action(AdjustBreakpointLocations), checkBoxAdjustBreakpointLocations);
- group.insert(action(GdbWatchdogTimeout), spinBoxGdbWatchdogTimeout);
- group.insert(action(IntelFlavor), checkBoxIntelFlavor);
- group.insert(action(UseMessageBoxForSignals), checkBoxUseMessageBoxForSignals);
- group.insert(action(SkipKnownFrames), checkBoxSkipKnownFrames);
- group.insert(action(UsePseudoTracepoints), checkBoxUsePseudoTracepoints);
-
- //lineEditSelectedPluginBreakpointsPattern->
- // setEnabled(action(SelectedPluginBreakpoints)->value().toBool());
- //connect(radioButtonSelectedPluginBreakpoints, &QRadioButton::toggled,
- // lineEditSelectedPluginBreakpointsPattern, &QLineEdit::setEnabled);
-}
-
-GdbOptionsPage::GdbOptionsPage()
-{
- setId("M.Gdb");
- setDisplayName(tr("GDB"));
- setCategory(Constants::DEBUGGER_SETTINGS_CATEGORY);
- setWidgetCreator([] { return new GdbOptionsPageWidget; });
-}
-
/////////////////////////////////////////////////////////////////////////
//
-// GdbOptionsPageWidget2 - dangerous options
+// GdbOptionsPage2 - dangerous options
//
/////////////////////////////////////////////////////////////////////////
-class GdbOptionsPageWidget2 : public IOptionsPageWidget
-{
-public:
- GdbOptionsPageWidget2();
-
- void apply() final { group.apply(ICore::settings()); }
- void finish() final { group.finish(); }
-
- Utils::SavedActionSet group;
-};
-
-GdbOptionsPageWidget2::GdbOptionsPageWidget2()
-{
- auto groupBoxDangerous = new QGroupBox(this);
- groupBoxDangerous->setTitle(GdbOptionsPage::tr("Extended"));
-
- auto labelDangerous = new QLabel(GdbOptionsPage::tr(
- "<html><head/><body>The options below give access to advanced "
- "or experimental functions of GDB. Enabling them may negatively "
- "impact your debugging experience.</body></html>"));
- QFont f = labelDangerous->font();
- f.setItalic(true);
- labelDangerous->setFont(f);
-
- auto checkBoxTargetAsync = new QCheckBox(groupBoxDangerous);
- checkBoxTargetAsync->setText(GdbOptionsPage::tr(
- "Use asynchronous mode to control the inferior"));
-
- auto checkBoxAutoEnrichParameters = new QCheckBox(groupBoxDangerous);
- checkBoxAutoEnrichParameters->setText(GdbOptionsPage::tr(
- "Use common locations for debug information"));
- checkBoxAutoEnrichParameters->setToolTip(GdbOptionsPage::tr(
- "<html><head/><body>Adds common paths to locations "
- "of debug information such as <i>/usr/src/debug</i> "
- "when starting GDB.</body></html>"));
-
- // FIXME: Move to common settings page.
- auto checkBoxBreakOnWarning = new QCheckBox(groupBoxDangerous);
- checkBoxBreakOnWarning->setText(CommonOptionsPage::msgSetBreakpointAtFunction("qWarning"));
- checkBoxBreakOnWarning->setToolTip(CommonOptionsPage::msgSetBreakpointAtFunctionToolTip("qWarning"));
-
- auto checkBoxBreakOnFatal = new QCheckBox(groupBoxDangerous);
- checkBoxBreakOnFatal->setText(CommonOptionsPage::msgSetBreakpointAtFunction("qFatal"));
- checkBoxBreakOnFatal->setToolTip(CommonOptionsPage::msgSetBreakpointAtFunctionToolTip("qFatal"));
-
- auto checkBoxBreakOnAbort = new QCheckBox(groupBoxDangerous);
- checkBoxBreakOnAbort->setText(CommonOptionsPage::msgSetBreakpointAtFunction("abort"));
- checkBoxBreakOnAbort->setToolTip(CommonOptionsPage::msgSetBreakpointAtFunctionToolTip("abort"));
-
- auto checkBoxEnableReverseDebugging = new QCheckBox(groupBoxDangerous);
- checkBoxEnableReverseDebugging->setText(GdbOptionsPage::tr("Enable reverse debugging"));
- checkBoxEnableReverseDebugging->setToolTip(GdbOptionsPage::tr(
- "<html><head/><body><p>Enables stepping backwards.</p><p>"
- "<b>Note:</b> This feature is very slow and unstable on the GDB side. "
- "It exhibits unpredictable behavior when going backwards over system "
- "calls and is very likely to destroy your debugging session.</p></body></html>"));
-
- auto checkBoxMultiInferior = new QCheckBox(groupBoxDangerous);
- checkBoxMultiInferior->setText(GdbOptionsPage::tr("Debug all child processes"));
- checkBoxMultiInferior->setToolTip(GdbOptionsPage::tr(
- "<html><head/><body>Keeps debugging all children after a fork."
- "</body></html>"));
-
-
- auto formLayout = new QFormLayout(groupBoxDangerous);
- formLayout->addRow(labelDangerous);
- formLayout->addRow(checkBoxTargetAsync);
- formLayout->addRow(checkBoxAutoEnrichParameters);
- formLayout->addRow(checkBoxBreakOnWarning);
- formLayout->addRow(checkBoxBreakOnFatal);
- formLayout->addRow(checkBoxBreakOnAbort);
- if (checkBoxEnableReverseDebugging)
- formLayout->addRow(checkBoxEnableReverseDebugging);
- formLayout->addRow(checkBoxMultiInferior);
-
- auto gridLayout = new QGridLayout(this);
- gridLayout->addWidget(groupBoxDangerous, 0, 0, 2, 1);
-
- group.insert(action(AutoEnrichParameters), checkBoxAutoEnrichParameters);
- group.insert(action(TargetAsync), checkBoxTargetAsync);
- group.insert(action(BreakOnWarning), checkBoxBreakOnWarning);
- group.insert(action(BreakOnFatal), checkBoxBreakOnFatal);
- group.insert(action(BreakOnAbort), checkBoxBreakOnAbort);
- group.insert(action(MultiInferior), checkBoxMultiInferior);
- if (checkBoxEnableReverseDebugging)
- group.insert(action(EnableReverseDebugging), checkBoxEnableReverseDebugging);
-}
-
// The "Dangerous" options.
class GdbOptionsPage2 : public Core::IOptionsPage
{
@@ -373,7 +100,31 @@ public:
setId("M.Gdb2");
setDisplayName(GdbOptionsPage::tr("GDB Extended"));
setCategory(Constants::DEBUGGER_SETTINGS_CATEGORY);
- setWidgetCreator([] { return new GdbOptionsPageWidget2; });
+ setSettings(&debuggerSettings()->page3);
+
+ setLayouter([](QWidget *w) {
+ auto labelDangerous = new QLabel("<html><head/><body><i>" +
+ GdbOptionsPage::tr("The options below give access to advanced "
+ "or experimental functions of GDB.<br>Enabling them may negatively "
+ "impact your debugging experience.") + "</i></body></html>");
+
+ using namespace Layouting;
+ DebuggerSettings &s = *debuggerSettings();
+
+ Group extended {
+ Title(GdbOptionsPage::tr("Extended")),
+ labelDangerous,
+ s.targetAsync,
+ s.autoEnrichParameters,
+ s.breakOnWarning,
+ s.breakOnFatal,
+ s.breakOnAbort,
+ s.enableReverseDebugging,
+ s.multiInferior,
+ };
+
+ Column { extended, Stretch() }.attachTo(w);
+ });
}
};
diff --git a/src/plugins/debugger/lldb/lldbengine.cpp b/src/plugins/debugger/lldb/lldbengine.cpp
index bd20dcb4f1..516035226e 100644
--- a/src/plugins/debugger/lldb/lldbengine.cpp
+++ b/src/plugins/debugger/lldb/lldbengine.cpp
@@ -50,7 +50,6 @@
#include <coreplugin/icore.h>
#include <utils/qtcassert.h>
-#include <utils/savedaction.h>
#include <utils/qtcprocess.h>
#include <QApplication>
@@ -87,15 +86,16 @@ LldbEngine::LldbEngine()
setObjectName("LldbEngine");
setDebuggerName("LLDB");
- connect(action(AutoDerefPointers), &SavedAction::valueChanged,
+ DebuggerSettings &ds = *debuggerSettings();
+ connect(&ds.autoDerefPointers, &BaseAspect::changed,
this, &LldbEngine::updateLocals);
- connect(action(CreateFullBacktrace)->action(), &QAction::triggered,
+ connect(ds.createFullBacktrace.action(), &QAction::triggered,
this, &LldbEngine::fetchFullBacktrace);
- connect(action(UseDebuggingHelpers), &SavedAction::valueChanged,
+ connect(&ds.useDebuggingHelpers, &BaseAspect::changed,
this, &LldbEngine::updateLocals);
- connect(action(UseDynamicType), &SavedAction::valueChanged,
+ connect(&ds.useDynamicType, &BaseAspect::changed,
this, &LldbEngine::updateLocals);
- connect(action(IntelFlavor), &SavedAction::valueChanged,
+ connect(&ds.intelFlavor, &BaseAspect::changed,
this, &LldbEngine::updateAll);
connect(&m_lldbProc, &QProcess::errorOccurred,
@@ -232,8 +232,7 @@ void LldbEngine::setupEngine()
showStatusMessage(tr("Setting up inferior..."));
- const QByteArray dumperSourcePath =
- ICore::resourcePath().toLocal8Bit() + "/debugger/";
+ const QByteArray dumperSourcePath = ICore::resourcePath("debugger/").toString().toLocal8Bit();
executeCommand("script sys.path.insert(1, '" + dumperSourcePath + "')");
// This triggers reportState("enginesetupok") or "enginesetupfailed":
@@ -244,14 +243,14 @@ void LldbEngine::setupEngine()
executeCommand(commands.toLocal8Bit());
- const QString path = stringSetting(ExtraDumperFile);
+ const QString path = debuggerSettings()->extraDumperFile.value();
if (!path.isEmpty() && QFileInfo(path).isReadable()) {
DebuggerCommand cmd("addDumperModule");
cmd.arg("path", path);
runCommand(cmd);
}
- commands = stringSetting(ExtraDumperCommands);
+ commands = debuggerSettings()->extraDumperCommands.value();
if (!commands.isEmpty()) {
DebuggerCommand cmd("executeDebuggerCommand");
cmd.arg("command", commands);
@@ -267,8 +266,7 @@ void LldbEngine::setupEngine()
const DebuggerRunParameters &rp = runParameters();
const SourcePathMap sourcePathMap =
- DebuggerSourcePathMappingWidget::mergePlatformQtPath(rp,
- Internal::globalDebuggerOptions()->sourcePathMap);
+ mergePlatformQtPath(rp, debuggerSettings()->sourcePathMap.value());
for (auto it = sourcePathMap.constBegin(), cend = sourcePathMap.constEnd();
it != cend;
++it) {
@@ -284,7 +282,7 @@ void LldbEngine::setupEngine()
cmd2.arg("nativemixed", isNativeMixedActive());
cmd2.arg("workingdirectory", rp.inferior.workingDirectory);
cmd2.arg("environment", rp.inferior.environment.toStringList());
- cmd2.arg("processargs", toHex(QtcProcess::splitArgs(rp.inferior.commandLineArguments).join(QChar(0))));
+ cmd2.arg("processargs", toHex(ProcessArgs::splitArgs(rp.inferior.commandLineArguments).join(QChar(0))));
cmd2.arg("platform", rp.platform);
cmd2.arg("symbolfile", rp.symbolFile);
@@ -480,7 +478,7 @@ void LldbEngine::selectThread(const Thread &thread)
DebuggerCommand cmd("selectThread");
cmd.arg("id", thread->id());
cmd.callback = [this](const DebuggerResponse &) {
- fetchStack(action(MaximalStackDepth)->value().toInt());
+ fetchStack(debuggerSettings()->maximalStackDepth.value());
};
runCommand(cmd);
}
@@ -711,33 +709,12 @@ void LldbEngine::updateAll()
DebuggerCommand cmd("fetchThreads");
cmd.callback = [this](const DebuggerResponse &response) {
threadsHandler()->setThreads(response.data);
- fetchStack(action(MaximalStackDepth)->value().toInt());
+ fetchStack(debuggerSettings()->maximalStackDepth.value());
reloadRegisters();
};
runCommand(cmd);
}
-void LldbEngine::reloadFullStack()
-{
- fetchStack(-1);
-}
-
-void LldbEngine::fetchStack(int limit)
-{
- DebuggerCommand cmd("fetchStack");
- cmd.arg("nativemixed", isNativeMixedActive());
- cmd.arg("stacklimit", limit);
- cmd.arg("context", stackHandler()->currentFrame().context);
- cmd.callback = [this](const DebuggerResponse &response) {
- const GdbMi &stack = response.data["stack"];
- const bool isFull = !stack["hasmore"].toInt();
- stackHandler()->setFramesAndCurrentIndex(stack["frames"], isFull);
- activateFrame(stackHandler()->currentIndex());
- };
- runCommand(cmd);
-}
-
-
//////////////////////////////////////////////////////////////////////
//
// Watch specific stuff
@@ -765,20 +742,21 @@ void LldbEngine::doUpdateLocals(const UpdateParameters &params)
watchHandler()->appendWatchersAndTooltipRequests(&cmd);
const static bool alwaysVerbose = qEnvironmentVariableIsSet("QTC_DEBUGGER_PYTHON_VERBOSE");
+ const DebuggerSettings &s = *debuggerSettings();
cmd.arg("passexceptions", alwaysVerbose);
- cmd.arg("fancy", boolSetting(UseDebuggingHelpers));
- cmd.arg("autoderef", boolSetting(AutoDerefPointers));
- cmd.arg("dyntype", boolSetting(UseDynamicType));
+ cmd.arg("fancy", s.useDebuggingHelpers.value());
+ cmd.arg("autoderef", s.autoDerefPointers.value());
+ cmd.arg("dyntype", s.useDynamicType.value());
cmd.arg("partialvar", params.partialVariable);
- cmd.arg("qobjectnames", boolSetting(ShowQObjectNames));
- cmd.arg("timestamps", boolSetting(LogTimeStamps));
+ cmd.arg("qobjectnames", s.showQObjectNames.value());
+ cmd.arg("timestamps", s.logTimeStamps.value());
StackFrame frame = stackHandler()->currentFrame();
cmd.arg("context", frame.context);
cmd.arg("nativemixed", isNativeMixedActive());
- cmd.arg("stringcutoff", action(MaximalStringLength)->value().toString());
- cmd.arg("displaystringlimit", action(DisplayStringLimit)->value().toString());
+ cmd.arg("stringcutoff", s.maximalStringLength.value());
+ cmd.arg("displaystringlimit", s.displayStringLimit.value());
//cmd.arg("resultvarname", m_resultVarName);
cmd.arg("partialvar", params.partialVariable);
@@ -981,6 +959,33 @@ void LldbEngine::reloadDebuggingHelpers()
updateAll();
}
+void LldbEngine::loadAdditionalQmlStack()
+{
+ fetchStack(-1, true);
+}
+
+void LldbEngine::reloadFullStack()
+{
+ fetchStack(-1, false);
+}
+
+void LldbEngine::fetchStack(int limit, bool extraQml)
+{
+ DebuggerCommand cmd("fetchStack");
+ cmd.arg("nativemixed", isNativeMixedActive());
+ cmd.arg("stacklimit", limit);
+ cmd.arg("context", stackHandler()->currentFrame().context);
+ cmd.arg("extraqml", int(extraQml));
+ cmd.callback = [this](const DebuggerResponse &response) {
+ const GdbMi &stack = response.data["stack"];
+ const bool isFull = !stack["hasmore"].toInt();
+ stackHandler()->setFramesAndCurrentIndex(stack["frames"], isFull);
+ activateFrame(stackHandler()->currentIndex());
+ };
+ runCommand(cmd);
+}
+
+
void LldbEngine::fetchDisassembler(DisassemblerAgent *agent)
{
QPointer<DisassemblerAgent> p(agent);
@@ -993,7 +998,7 @@ void LldbEngine::fetchDisassembler(DisassemblerAgent *agent)
DebuggerCommand cmd("fetchDisassembler");
cmd.arg("address", loc.address());
cmd.arg("function", loc.functionName());
- cmd.arg("flavor", boolSetting(IntelFlavor) ? "intel" : "att");
+ cmd.arg("flavor", debuggerSettings()->intelFlavor.value() ? "intel" : "att");
cmd.callback = [this, id](const DebuggerResponse &response) {
DisassemblerLines result;
QPointer<DisassemblerAgent> agent = m_disassemblerAgents.key(id);
@@ -1091,7 +1096,8 @@ bool LldbEngine::hasCapability(unsigned cap) const
| OperateByInstructionCapability
| RunToLineCapability
| WatchComplexExpressionsCapability
- | MemoryAddressCapability))
+ | MemoryAddressCapability
+ | AdditionalQmlStackCapability))
return true;
if (runParameters().startMode == AttachToCore)
diff --git a/src/plugins/debugger/lldb/lldbengine.h b/src/plugins/debugger/lldb/lldbengine.h
index 95da756880..fa2becb742 100644
--- a/src/plugins/debugger/lldb/lldbengine.h
+++ b/src/plugins/debugger/lldb/lldbengine.h
@@ -101,6 +101,7 @@ private:
void reloadSourceFiles() override {}
void reloadFullStack() override;
void reloadDebuggingHelpers() override;
+ void loadAdditionalQmlStack() override;
void fetchDisassembler(Internal::DisassemblerAgent *) override;
void setRegisterValue(const QString &name, const QString &value) override;
@@ -125,7 +126,7 @@ private:
void updateAll() override;
void doUpdateLocals(const UpdateParameters &params) override;
void updateBreakpointData(const Breakpoint &bp, const GdbMi &bkpt, bool added);
- void fetchStack(int limit);
+ void fetchStack(int limit, bool alsoQml = false);
void runCommand(const DebuggerCommand &cmd) override;
void debugLastCommand() override;
diff --git a/src/plugins/debugger/logwindow.cpp b/src/plugins/debugger/logwindow.cpp
index c30401902f..5bb552e09f 100644
--- a/src/plugins/debugger/logwindow.cpp
+++ b/src/plugins/debugger/logwindow.cpp
@@ -50,7 +50,6 @@
#include <coreplugin/minisplitter.h>
#include <coreplugin/find/basetextfind.h>
-#include <utils/savedaction.h>
#include <utils/fancylineedit.h>
#include <utils/fileutils.h>
#include <utils/theme/theme.h>
@@ -96,7 +95,7 @@ static bool writeLogContents(const QPlainTextEdit *editor, QWidget *parent)
const QString fileName = QFileDialog::getSaveFileName(parent, LogWindow::tr("Log File"));
if (fileName.isEmpty())
break;
- Utils::FileSaver saver(fileName, QIODevice::Text);
+ Utils::FileSaver saver(Utils::FilePath::fromString(fileName), QIODevice::Text);
saver.write(editor->toPlainText().toUtf8());
if (saver.finalize(parent))
success = true;
@@ -220,10 +219,10 @@ public:
QMenu *menu = createStandardContextMenu();
menu->addAction(m_clearContentsAction);
menu->addAction(m_saveContentsAction); // X11 clipboard is unreliable for long texts
- menu->addAction(action(LogTimeStamps)->action());
+ menu->addAction(debuggerSettings()->logTimeStamps.action());
menu->addAction(m_reloadDebuggingHelpersAction);
menu->addSeparator();
- menu->addAction(action(SettingsDialog)->action());
+ menu->addAction(debuggerSettings()->settingsDialog.action());
menu->exec(ev->globalPos());
delete menu;
}
@@ -526,7 +525,7 @@ void LogWindow::showOutput(int channel, const QString &output)
QString out;
out.reserve(output.size() + 1000);
- if (output.at(0) != '~' && boolSetting(LogTimeStamps)) {
+ if (output.at(0) != '~' && debuggerSettings()->logTimeStamps.value()) {
out.append(charForChannel(LogTime));
out.append(logTimeStamp());
out.append(nchar);
@@ -594,7 +593,7 @@ void LogWindow::showInput(int channel, const QString &input)
m_inputText->setTextCursor(cursor);
return;
}
- if (boolSetting(LogTimeStamps))
+ if (debuggerSettings()->logTimeStamps.value())
m_inputText->append(logTimeStamp());
m_inputText->append(input);
QTextCursor cursor = m_inputText->textCursor();
@@ -726,7 +725,7 @@ void GlobalLogWindow::doOutput(const QString &output)
void GlobalLogWindow::doInput(const QString &input)
{
- if (boolSetting(LogTimeStamps))
+ if (debuggerSettings()->logTimeStamps.value())
m_leftPane->append(LogWindow::logTimeStamp());
m_leftPane->append(input);
QTextCursor cursor = m_leftPane->textCursor();
diff --git a/src/plugins/debugger/moduleshandler.cpp b/src/plugins/debugger/moduleshandler.cpp
index 29ab553de8..8ab9d3e277 100644
--- a/src/plugins/debugger/moduleshandler.cpp
+++ b/src/plugins/debugger/moduleshandler.cpp
@@ -33,7 +33,6 @@
#include <utils/basetreeview.h>
#include <utils/hostosinfo.h>
#include <utils/qtcassert.h>
-#include <utils/savedaction.h>
#include <utils/treemodel.h>
#include <QCoreApplication>
@@ -223,7 +222,7 @@ bool ModulesModel::contextMenuEvent(const ItemViewEvent &ev)
canShowSymbols && moduleNameValid,
[this, modulePath] { engine->requestModuleSections(modulePath); });
- menu->addAction(action(SettingsDialog)->action());
+ menu->addAction(debuggerSettings()->settingsDialog.action());
menu->popup(ev.globalPos());
return true;
diff --git a/src/plugins/debugger/pdb/pdbengine.cpp b/src/plugins/debugger/pdb/pdbengine.cpp
index 665f5aa8c9..d2c68c942b 100644
--- a/src/plugins/debugger/pdb/pdbengine.cpp
+++ b/src/plugins/debugger/pdb/pdbengine.cpp
@@ -115,7 +115,7 @@ void PdbEngine::setupEngine()
QTC_ASSERT(state() == EngineSetupRequested, qDebug() << state());
m_interpreter = runParameters().interpreter;
- QString bridge = ICore::resourcePath() + "/debugger/pdbbridge.py";
+ QString bridge = ICore::resourcePath("debugger/pdbbridge.py").toString();
connect(&m_proc, &QProcess::errorOccurred, this, &PdbEngine::handlePdbError);
connect(&m_proc, QOverload<int, QProcess::ExitStatus>::of(&QProcess::finished),
@@ -134,7 +134,7 @@ void PdbEngine::setupEngine()
}
QStringList args = {bridge, scriptFile.fileName()};
- args.append(Utils::QtcProcess::splitArgs(runParameters().inferior.workingDirectory));
+ args.append(Utils::ProcessArgs::splitArgs(runParameters().inferior.workingDirectory));
showMessage("STARTING " + m_interpreter + ' ' + args.join(' '));
m_proc.setEnvironment(runParameters().debugger.environment.toStringList());
m_proc.start(m_interpreter, args);
@@ -572,7 +572,7 @@ void PdbEngine::updateLocals()
const static bool alwaysVerbose = qEnvironmentVariableIsSet("QTC_DEBUGGER_PYTHON_VERBOSE");
cmd.arg("passexceptions", alwaysVerbose);
- cmd.arg("fancy", boolSetting(UseDebuggingHelpers));
+ cmd.arg("fancy", debuggerSettings()->useDebuggingHelpers.value());
//cmd.arg("resultvarname", m_resultVarName);
//m_lastDebuggableCommand = cmd;
diff --git a/src/plugins/debugger/peripheralregisterhandler.cpp b/src/plugins/debugger/peripheralregisterhandler.cpp
index 4bbeb8451e..3f466ab180 100644
--- a/src/plugins/debugger/peripheralregisterhandler.cpp
+++ b/src/plugins/debugger/peripheralregisterhandler.cpp
@@ -30,7 +30,6 @@
#include "debuggerdialogs.h"
#include <utils/basetreeview.h>
-#include <utils/savedaction.h>
#include <QActionGroup>
#include <QFile>
@@ -799,7 +798,7 @@ bool PeripheralRegisterHandler::contextMenuEvent(const ItemViewEvent &ev)
menu->addMenu(fmtMenu);
}
- menu->addAction(action(SettingsDialog)->action());
+ menu->addAction(debuggerSettings()->settingsDialog.action());
menu->popup(ev.globalPos());
return true;
}
diff --git a/src/plugins/debugger/qml/qmlengine.cpp b/src/plugins/debugger/qml/qmlengine.cpp
index 6100179e65..82085020e5 100644
--- a/src/plugins/debugger/qml/qmlengine.cpp
+++ b/src/plugins/debugger/qml/qmlengine.cpp
@@ -862,7 +862,7 @@ bool compareConsoleItems(const ConsoleItem *a, const ConsoleItem *b)
static ConsoleItem *constructLogItemTree(const QVariant &result,
const QString &key = QString())
{
- bool sorted = boolSetting(SortStructMembers);
+ bool sorted = debuggerSettings()->sortStructMembers.value();
if (!result.isValid())
return nullptr;
@@ -2226,7 +2226,7 @@ void QmlEnginePrivate::constructChildLogItems(ConsoleItem *item, const QmlV8Obje
for (const QVariant &property : objectData.properties)
*(it++) = constructLogItemTree(extractData(property), seenHandles);
- if (boolSetting(SortStructMembers))
+ if (debuggerSettings()->sortStructMembers.value())
std::sort(children.begin(), children.end(), compareConsoleItems);
foreach (ConsoleItem *child, children)
@@ -2339,7 +2339,7 @@ void QmlEnginePrivate::insertSubItems(WatchItem *parent, const QVariantList &pro
parent->appendChild(item.release());
}
- if (boolSetting(SortStructMembers)) {
+ if (debuggerSettings()->sortStructMembers.value()) {
parent->sortChildren([](const WatchItem *item1, const WatchItem *item2) {
return item1->name < item2->name;
});
diff --git a/src/plugins/debugger/qml/qmlinspectoragent.cpp b/src/plugins/debugger/qml/qmlinspectoragent.cpp
index 6ed8883b0d..97a61c93d7 100644
--- a/src/plugins/debugger/qml/qmlinspectoragent.cpp
+++ b/src/plugins/debugger/qml/qmlinspectoragent.cpp
@@ -45,8 +45,8 @@
#include <utils/fileutils.h>
#include <utils/qtcassert.h>
-#include <utils/savedaction.h>
+#include <QAction>
#include <QElapsedTimer>
#include <QFileInfo>
#include <QLoggingCategory>
@@ -68,12 +68,12 @@ QmlInspectorAgent::QmlInspectorAgent(QmlEngine *engine, QmlDebugConnection *conn
: m_qmlEngine(engine)
, m_inspectorToolsContext("Debugger.QmlInspector")
, m_selectAction(new QAction(this))
- , m_showAppOnTopAction(action(ShowAppOnTop)->action())
+ , m_showAppOnTopAction(debuggerSettings()->showAppOnTop.action())
{
m_debugIdToIname.insert(WatchItem::InvalidId, "inspect");
- connect(action(ShowQmlObjectTree),
- &Utils::SavedAction::valueChanged, this, &QmlInspectorAgent::updateState);
- connect(action(SortStructMembers), &Utils::SavedAction::valueChanged,
+ connect(&debuggerSettings()->showQmlObjectTree, &Utils::BaseAspect::changed,
+ this, &QmlInspectorAgent::updateState);
+ connect(&debuggerSettings()->sortStructMembers, &Utils::BaseAspect::changed,
this, &QmlInspectorAgent::updateState);
m_delayQueryTimer.setSingleShot(true);
m_delayQueryTimer.setInterval(100);
@@ -193,7 +193,7 @@ void QmlInspectorAgent::addObjectWatch(int objectDebugId)
if (objectDebugId == WatchItem::InvalidId)
return;
- if (!isConnected() || !boolSetting(ShowQmlObjectTree))
+ if (!isConnected() || !debuggerSettings()->showQmlObjectTree.value())
return;
// already set
@@ -212,7 +212,8 @@ void QmlInspectorAgent::updateState()
m_qmlEngine->logServiceStateChange(m_engineClient->name(), m_engineClient->serviceVersion(),
m_engineClient->state());
- if (m_engineClient->state() == QmlDebugClient::Enabled && boolSetting(ShowQmlObjectTree))
+ if (m_engineClient->state() == QmlDebugClient::Enabled
+ && debuggerSettings()->showQmlObjectTree.value())
reloadEngines();
else
clearObjectTree();
@@ -301,7 +302,7 @@ void QmlInspectorAgent::newObject(int engineId, int /*objectId*/, int /*parentId
static void sortChildrenIfNecessary(WatchItem *propertiesWatch)
{
- if (boolSetting(SortStructMembers)) {
+ if (debuggerSettings()->sortStructMembers.value()) {
propertiesWatch->sortChildren([](const WatchItem *item1, const WatchItem *item2) {
return item1->name < item2->name;
});
@@ -375,7 +376,7 @@ void QmlInspectorAgent::queryEngineContext()
{
qCDebug(qmlInspectorLog) << __FUNCTION__ << "pending queries:" << m_rootContextQueryIds;
- if (!isConnected() || !boolSetting(ShowQmlObjectTree))
+ if (!isConnected() || !debuggerSettings()->showQmlObjectTree.value())
return;
log(LogSend, "LIST_OBJECTS");
@@ -390,7 +391,7 @@ void QmlInspectorAgent::fetchObject(int debugId)
{
qCDebug(qmlInspectorLog) << __FUNCTION__ << '(' << debugId << ')';
- if (!isConnected() || !boolSetting(ShowQmlObjectTree))
+ if (!isConnected() || !debuggerSettings()->showQmlObjectTree.value())
return;
log(LogSend, "FETCH_OBJECT " + QString::number(debugId));
@@ -404,7 +405,7 @@ void QmlInspectorAgent::updateObjectTree(const ContextReference &context, int en
{
qCDebug(qmlInspectorLog) << __FUNCTION__ << '(' << context << ')';
- if (!isConnected() || !boolSetting(ShowQmlObjectTree))
+ if (!isConnected() || !debuggerSettings()->showQmlObjectTree.value())
return;
for (const ObjectReference &obj : context.objects())
diff --git a/src/plugins/debugger/registerhandler.cpp b/src/plugins/debugger/registerhandler.cpp
index 4acfa7af20..7ed8af6300 100644
--- a/src/plugins/debugger/registerhandler.cpp
+++ b/src/plugins/debugger/registerhandler.cpp
@@ -36,7 +36,6 @@
#include <utils/basetreeview.h>
#include <utils/qtcassert.h>
-#include <utils/savedaction.h>
#include <QDebug>
#include <QItemDelegate>
@@ -834,7 +833,7 @@ bool RegisterHandler::contextMenuEvent(const ItemViewEvent &ev)
addFormatAction(tr("Octal"), OctalFormat);
addFormatAction(tr("Binary"), BinaryFormat);
- menu->addAction(action(SettingsDialog)->action());
+ menu->addAction(debuggerSettings()->settingsDialog.action());
menu->popup(ev.globalPos());
return true;
}
diff --git a/src/plugins/debugger/registerpostmortemaction.cpp b/src/plugins/debugger/registerpostmortemaction.cpp
index 477b04b354..5a7e631248 100644
--- a/src/plugins/debugger/registerpostmortemaction.cpp
+++ b/src/plugins/debugger/registerpostmortemaction.cpp
@@ -31,6 +31,9 @@
#include <QDir>
#include <QString>
+#ifdef QTCREATOR_PCH_H
+#define CALLBACK WINAPI
+#endif
#include <windows.h>
#include <objbase.h>
#include <shellapi.h>
@@ -40,9 +43,8 @@ using namespace RegistryAccess;
namespace Debugger {
namespace Internal {
-void RegisterPostMortemAction::registerNow(const QVariant &value)
+void RegisterPostMortemAction::registerNow(bool value)
{
- const bool boolValue = value.toBool();
const QString debuggerExe = QDir::toNativeSeparators(QCoreApplication::applicationDirPath() + '/'
+ QLatin1String(debuggerApplicationFileC) + ".exe");
const ushort *debuggerWString = debuggerExe.utf16();
@@ -54,7 +56,7 @@ void RegisterPostMortemAction::registerNow(const QVariant &value)
shExecInfo.hwnd = NULL;
shExecInfo.lpVerb = L"runas";
shExecInfo.lpFile = reinterpret_cast<LPCWSTR>(debuggerWString);
- shExecInfo.lpParameters = boolValue ? L"-register" : L"-unregister";
+ shExecInfo.lpParameters = value ? L"-register" : L"-unregister";
shExecInfo.lpDirectory = NULL;
shExecInfo.nShow = SW_SHOWNORMAL;
shExecInfo.hProcess = NULL;
@@ -64,9 +66,9 @@ void RegisterPostMortemAction::registerNow(const QVariant &value)
readSettings();
}
-RegisterPostMortemAction::RegisterPostMortemAction(QObject *parent) : Utils::SavedAction(parent)
+RegisterPostMortemAction::RegisterPostMortemAction()
{
- connect(this, &SavedAction::valueChanged, this, &RegisterPostMortemAction::registerNow);
+ connect(this, &BoolAspect::valueChanged, this, &RegisterPostMortemAction::registerNow);
}
void RegisterPostMortemAction::readSettings(const QSettings *)
@@ -80,7 +82,7 @@ void RegisterPostMortemAction::readSettings(const QSettings *)
registered = isRegistered(handle, debuggerCall(), &errorMessage);
if (handle)
RegCloseKey(handle);
- setValue(registered, false);
+ setValueQuietly(registered);
}
} // namespace Internal
diff --git a/src/plugins/debugger/registerpostmortemaction.h b/src/plugins/debugger/registerpostmortemaction.h
index 3555d984c8..00f3b9e53a 100644
--- a/src/plugins/debugger/registerpostmortemaction.h
+++ b/src/plugins/debugger/registerpostmortemaction.h
@@ -25,20 +25,20 @@
#pragma once
-#include <utils/savedaction.h>
+#include <utils/aspects.h>
namespace Debugger {
namespace Internal {
-class RegisterPostMortemAction : public Utils::SavedAction
+class RegisterPostMortemAction : public Utils::BoolAspect
{
public:
- RegisterPostMortemAction(QObject *parent = nullptr);
+ RegisterPostMortemAction();
void readSettings(const QSettings *settings = nullptr) override;
- void writeSettings(QSettings *) override {}
+ void writeSettings(QSettings *) const override {}
private:
- void registerNow(const QVariant &value);
+ void registerNow(bool value);
};
} // namespace Internal
diff --git a/src/plugins/debugger/sourcefileshandler.cpp b/src/plugins/debugger/sourcefileshandler.cpp
index 30c5810ec8..36b35ec63f 100644
--- a/src/plugins/debugger/sourcefileshandler.cpp
+++ b/src/plugins/debugger/sourcefileshandler.cpp
@@ -30,7 +30,6 @@
#include "debuggerengine.h"
#include <utils/basetreeview.h>
-#include <utils/savedaction.h>
#include <QDebug>
#include <QFileInfo>
@@ -137,7 +136,7 @@ bool SourceFilesHandler::setData(const QModelIndex &idx, const QVariant &data, i
addAction(tr("Open File \"%1\"").arg(name), true,
[this, name] { m_engine->gotoLocation(FilePath::fromString(name)); });
- menu->addAction(action(SettingsDialog)->action());
+ menu->addAction(debuggerSettings()->settingsDialog.action());
menu->popup(ev.globalPos());
return true;
}
diff --git a/src/plugins/debugger/stackhandler.cpp b/src/plugins/debugger/stackhandler.cpp
index fe94cc5f20..a81433b99e 100644
--- a/src/plugins/debugger/stackhandler.cpp
+++ b/src/plugins/debugger/stackhandler.cpp
@@ -40,7 +40,6 @@
#include <utils/basetreeview.h>
#include <utils/fileutils.h>
#include <utils/qtcassert.h>
-#include <utils/savedaction.h>
#include <QApplication>
#include <QClipboard>
@@ -52,6 +51,7 @@
#include <QInputDialog>
#include <QMenu>
#include <QTextStream>
+#include <QTimer>
using namespace Utils;
@@ -70,9 +70,9 @@ StackHandler::StackHandler(DebuggerEngine *engine)
setObjectName("StackModel");
setHeader({tr("Level"), tr("Function"), tr("File"), tr("Line"), tr("Address") });
- connect(action(ExpandStack)->action(), &QAction::triggered,
+ connect(debuggerSettings()->expandStack.action(), &QAction::triggered,
this, &StackHandler::reloadFullStack);
- connect(action(MaximalStackDepth)->action(), &QAction::triggered,
+ connect(debuggerSettings()->maximalStackDepth.action(), &QAction::triggered,
this, &StackHandler::reloadFullStack);
// For now there's always only "the" current thread.
@@ -115,7 +115,7 @@ QVariant StackFrameItem::data(int column, int role) const
if (role == Qt::DecorationRole && column == StackLevelColumn)
return handler->iconForRow(row);
- if (role == Qt::ToolTipRole && boolSetting(UseToolTipsInStackView))
+ if (role == Qt::ToolTipRole && debuggerSettings()->useToolTipsInStackView.value())
return frame.toToolTip();
return QVariant();
@@ -257,8 +257,8 @@ void StackHandler::setFramesAndCurrentIndex(const GdbMi &frames, bool isFull)
targetFrame = i;
}
- bool canExpand = !isFull && (n >= action(MaximalStackDepth)->value().toInt());
- action(ExpandStack)->setEnabled(canExpand);
+ bool canExpand = !isFull && (n >= debuggerSettings()->maximalStackDepth.value());
+ debuggerSettings()->expandStack.setEnabled(canExpand);
setFrames(stackFrames, canExpand);
// We can't jump to any file if we don't have any frames.
@@ -455,7 +455,7 @@ bool StackHandler::contextMenuEvent(const ItemViewEvent &ev)
frame = frameAt(row);
const quint64 address = frame.address;
- menu->addAction(action(ExpandStack)->action());
+ menu->addAction(debuggerSettings()->expandStack.action());
addAction(menu, tr("Copy Contents to Clipboard"), true, [ev] {
copyTextToClipboard(selectedText(ev.view(), true));
@@ -468,7 +468,7 @@ bool StackHandler::contextMenuEvent(const ItemViewEvent &ev)
addAction(menu, tr("Save as Task File..."), true, [this] { saveTaskFile(); });
if (m_engine->hasCapability(CreateFullBacktraceCapability))
- menu->addAction(action(CreateFullBacktrace)->action());
+ menu->addAction(debuggerSettings()->createFullBacktrace.action());
if (m_engine->hasCapability(AdditionalQmlStackCapability))
addAction(menu, tr("Load QML Stack"), true, [this] { m_engine->loadAdditionalQmlStack(); });
@@ -516,8 +516,8 @@ bool StackHandler::contextMenuEvent(const ItemViewEvent &ev)
}
menu->addSeparator();
- menu->addAction(action(UseToolTipsInStackView)->action());
- menu->addAction(action(SettingsDialog)->action());
+ menu->addAction(debuggerSettings()->useToolTipsInStackView.action());
+ menu->addAction(debuggerSettings()->settingsDialog.action());
menu->popup(ev.globalPos());
return true;
}
diff --git a/src/plugins/debugger/stackwindow.cpp b/src/plugins/debugger/stackwindow.cpp
index e810fbec0c..df71e361c6 100644
--- a/src/plugins/debugger/stackwindow.cpp
+++ b/src/plugins/debugger/stackwindow.cpp
@@ -29,8 +29,6 @@
#include "debuggercore.h"
#include "stackhandler.h"
-#include <utils/savedaction.h>
-
#include <QAction>
#include <QHeaderView>
diff --git a/src/plugins/debugger/terminal.cpp b/src/plugins/debugger/terminal.cpp
index 24b1f72f23..7f4996cd5b 100644
--- a/src/plugins/debugger/terminal.cpp
+++ b/src/plugins/debugger/terminal.cpp
@@ -168,13 +168,12 @@ void Terminal::onSlaveReaderActivated(int fd)
#endif
}
-TerminalRunner::TerminalRunner(RunControl *runControl, const Runnable &stubRunnable)
- : RunWorker(runControl)
+TerminalRunner::TerminalRunner(RunControl *runControl,
+ const std::function<Runnable()> &stubRunnable)
+ : RunWorker(runControl), m_stubRunnable(stubRunnable)
{
setId("TerminalRunner");
- m_stubRunnable = stubRunnable;
-
connect(&m_stubProc, &ConsoleProcess::processError,
this, &TerminalRunner::stubError);
connect(&m_stubProc, &ConsoleProcess::processStarted,
@@ -200,13 +199,16 @@ void TerminalRunner::setRunAsRoot(bool on)
void TerminalRunner::start()
{
+ QTC_ASSERT(m_stubRunnable, reportFailure({}); return);
+ Runnable stub = m_stubRunnable();
+
if (m_runAsRoot) {
m_stubProc.setRunAsRoot(true);
- RunControl::provideAskPassEntry(m_stubRunnable.environment);
+ RunControl::provideAskPassEntry(stub.environment);
}
- m_stubProc.setEnvironment(m_stubRunnable.environment);
- m_stubProc.setWorkingDirectory(m_stubRunnable.workingDirectory);
+ m_stubProc.setEnvironment(stub.environment);
+ m_stubProc.setWorkingDirectory(stub.workingDirectory);
if (HostOsInfo::isWindowsHost()) {
m_stubProc.setMode(ConsoleProcess::Suspend);
@@ -216,7 +218,7 @@ void TerminalRunner::start()
}
// Error message for user is delivered via a signal.
- m_stubProc.setCommand(m_stubRunnable.commandLine());
+ m_stubProc.setCommand(stub.commandLine());
m_stubProc.start();
}
diff --git a/src/plugins/debugger/terminal.h b/src/plugins/debugger/terminal.h
index ceacf3fddd..896fec855a 100644
--- a/src/plugins/debugger/terminal.h
+++ b/src/plugins/debugger/terminal.h
@@ -72,7 +72,7 @@ class TerminalRunner : public ProjectExplorer::RunWorker
{
public:
TerminalRunner(ProjectExplorer::RunControl *runControl,
- const ProjectExplorer::Runnable &stubRunnable);
+ const std::function<ProjectExplorer::Runnable()> &stubRunnable);
qint64 applicationPid() const { return m_applicationPid; }
qint64 applicationMainThreadId() const { return m_applicationMainThreadId; }
@@ -89,7 +89,7 @@ private:
void stubError(const QString &msg);
Utils::ConsoleProcess m_stubProc;
- ProjectExplorer::Runnable m_stubRunnable;
+ std::function<ProjectExplorer::Runnable()> m_stubRunnable;
qint64 m_applicationPid = 0;
qint64 m_applicationMainThreadId = 0;
bool m_runAsRoot = false;
diff --git a/src/plugins/debugger/threadshandler.cpp b/src/plugins/debugger/threadshandler.cpp
index a574909469..aa96264e31 100644
--- a/src/plugins/debugger/threadshandler.cpp
+++ b/src/plugins/debugger/threadshandler.cpp
@@ -35,7 +35,6 @@
#include <utils/algorithm.h>
#include <utils/basetreeview.h>
#include <utils/qtcassert.h>
-#include <utils/savedaction.h>
#include <QCoreApplication>
#include <QDebug>
@@ -258,7 +257,7 @@ bool ThreadsHandler::setData(const QModelIndex &idx, const QVariant &data, int r
if (ev.as<QContextMenuEvent>()) {
auto menu = new QMenu;
- menu->addAction(action(SettingsDialog)->action());
+ menu->addAction(debuggerSettings()->settingsDialog.action());
menu->popup(ev.globalPos());
return true;
}
diff --git a/src/plugins/debugger/watchhandler.cpp b/src/plugins/debugger/watchhandler.cpp
index bba04a5d49..790fd4d848 100644
--- a/src/plugins/debugger/watchhandler.cpp
+++ b/src/plugins/debugger/watchhandler.cpp
@@ -56,7 +56,6 @@
#include <utils/checkablemessagebox.h>
#include <utils/fancylineedit.h>
#include <utils/qtcassert.h>
-#include <utils/savedaction.h>
#include <utils/stringutils.h>
#include <utils/theme/theme.h>
@@ -278,11 +277,15 @@ static void loadSessionData()
class SeparatedView : public QTabWidget
{
+ Q_OBJECT
public:
SeparatedView() : QTabWidget(DebuggerMainWindow::instance())
{
setTabsClosable(true);
connect(this, &QTabWidget::tabCloseRequested, this, &SeparatedView::closeTab);
+ connect(tabBar(), &QTabBar::customContextMenuRequested,
+ this, &SeparatedView::tabBarContextMenuRequested);
+ tabBar()->setContextMenuPolicy(Qt::CustomContextMenu);
setWindowFlags(windowFlags() | Qt::Window);
setWindowTitle(WatchHandler::tr("Debugger - %1").arg(Core::Constants::IDE_DISPLAY_NAME));
@@ -328,6 +331,15 @@ public:
sanitize();
}
+ void tabBarContextMenuRequested(const QPoint &point)
+ {
+ const QWidget *w = widget(tabBar()->tabAt(point));
+ if (!w)
+ return;
+ emit tabBarContextMenuRequestedSignal(tabBar()->mapToGlobal(point),
+ w->property(INameProperty).toString());
+ }
+
void sanitize()
{
if (count() == 0)
@@ -357,6 +369,7 @@ public:
if (!t) {
t = new T;
t->setProperty(KeyProperty, key);
+ t->setProperty(INameProperty, item->iname);
addTab(t, item->name);
}
setProperty(INameProperty, item->iname);
@@ -366,6 +379,9 @@ public:
raise();
return t;
}
+
+Q_SIGNALS:
+ void tabBarContextMenuRequestedSignal(const QPoint &position, const QString &watchiName);
};
class TextEdit : public QTextEdit
@@ -477,6 +493,9 @@ public:
QHash<QString, QString> m_valueCache;
Location m_location;
+
+private:
+ void separatedViewTabBarContextMenuRequested(const QPoint &point, const QString &iname);
};
WatchModel::WatchModel(WatchHandler *handler, DebuggerEngine *engine)
@@ -514,17 +533,21 @@ WatchModel::WatchModel(WatchHandler *handler, DebuggerEngine *engine)
connect(&m_requestUpdateTimer, &QTimer::timeout,
this, &WatchModel::updateStarted);
- connect(action(SortStructMembers), &SavedAction::valueChanged,
+ DebuggerSettings &s = *debuggerSettings();
+ connect(&s.sortStructMembers, &BaseAspect::changed,
m_engine, &DebuggerEngine::updateLocals);
- connect(action(ShowStdNamespace), &SavedAction::valueChanged,
+ connect(&s.showStdNamespace, &BaseAspect::changed,
m_engine, &DebuggerEngine::updateAll);
- connect(action(ShowQtNamespace), &SavedAction::valueChanged,
+ connect(&s.showQtNamespace, &BaseAspect::changed,
m_engine, &DebuggerEngine::updateAll);
- connect(action(ShowQObjectNames), &SavedAction::valueChanged,
+ connect(&s.showQObjectNames, &BaseAspect::changed,
m_engine, &DebuggerEngine::updateAll);
- connect(action(UseAnnotationsInMainEditor), &SavedAction::valueChanged,
+ connect(&s.useAnnotationsInMainEditor, &BaseAspect::changed,
m_engine, &DebuggerEngine::updateAll);
+ connect(m_separatedView, &SeparatedView::tabBarContextMenuRequestedSignal,
+ this, &WatchModel::separatedViewTabBarContextMenuRequested);
+
connect(SessionManager::instance(), &SessionManager::sessionLoaded,
this, &loadSessionData);
connect(SessionManager::instance(), &SessionManager::aboutToSaveSession,
@@ -566,9 +589,9 @@ static QString niceTypeHelper(const QString &typeIn)
QString WatchModel::removeNamespaces(QString str) const
{
- if (!boolSetting(ShowStdNamespace))
+ if (!debuggerSettings()->showStdNamespace.value())
str.remove("std::");
- if (!boolSetting(ShowQtNamespace)) {
+ if (!debuggerSettings()->showQtNamespace.value()) {
const QString qtNamespace = m_engine->qtNamespace();
if (!qtNamespace.isEmpty())
str.remove(qtNamespace);
@@ -1055,7 +1078,7 @@ QVariant WatchModel::data(const QModelIndex &idx, int role) const
}
case Qt::ToolTipRole:
- return boolSetting(UseToolTipsInLocalsView)
+ return debuggerSettings()->useToolTipsInLocalsView.value()
? item->toToolTip() : QVariant();
case Qt::ForegroundRole:
@@ -1757,12 +1780,13 @@ bool WatchModel::contextMenuEvent(const ItemViewEvent &ev)
menu->addSeparator();
- menu->addAction(action(UseDebuggingHelpers)->action());
- menu->addAction(action(UseToolTipsInLocalsView)->action());
- menu->addAction(action(AutoDerefPointers)->action());
- menu->addAction(action(SortStructMembers)->action());
- menu->addAction(action(UseDynamicType)->action());
- menu->addAction(action(SettingsDialog)->action());
+ DebuggerSettings &s = *debuggerSettings();
+ menu->addAction(s.useDebuggingHelpers.action());
+ menu->addAction(s.useToolTipsInLocalsView.action());
+ menu->addAction(s.autoDerefPointers.action());
+ menu->addAction(s.sortStructMembers.action());
+ menu->addAction(s.useDynamicType.action());
+ menu->addAction(s.settingsDialog.action());
connect(menu, &QMenu::aboutToHide, menu, &QObject::deleteLater);
menu->popup(ev.globalPos());
@@ -1885,6 +1909,12 @@ void WatchModel::addCharsPrintableMenu(QMenu *menu)
addBaseChangeAction(tr("Show Unprintable Characters as Hexadecimal"), 16);
}
+void WatchModel::separatedViewTabBarContextMenuRequested(const QPoint &point, const QString &iname)
+{
+ auto menu = createFormatMenu(findItem(iname), m_separatedView);
+ menu->exec(point);
+}
+
QMenu *WatchModel::createFormatMenu(WatchItem *item, QWidget *parent)
{
auto menu = new QMenu(tr("Change Value Display Format"), parent);
@@ -2114,7 +2144,7 @@ void WatchHandler::insertItems(const GdbMi &data)
{
QSet<WatchItem *> itemsToSort;
- const bool sortStructMembers = boolSetting(SortStructMembers);
+ const bool sortStructMembers = debuggerSettings()->sortStructMembers.value();
for (const GdbMi &child : data) {
auto item = new WatchItem;
item->parse(child, sortStructMembers);
@@ -2255,7 +2285,7 @@ void WatchHandler::notifyUpdateFinished()
});
QMap<QString, QString> values;
- if (boolSetting(UseAnnotationsInMainEditor)) {
+ if (debuggerSettings()->useAnnotationsInMainEditor.value()) {
m_model->forAllItems([&values](WatchItem *item) {
const QString expr = item->sourceExpression();
if (!expr.isEmpty())
diff --git a/src/plugins/debugger/watchwindow.cpp b/src/plugins/debugger/watchwindow.cpp
index d7af82b05b..3f9971a1e7 100644
--- a/src/plugins/debugger/watchwindow.cpp
+++ b/src/plugins/debugger/watchwindow.cpp
@@ -30,8 +30,8 @@
#include "debuggercore.h"
#include "watchhandler.h"
+#include <utils/aspects.h>
#include <utils/qtcassert.h>
-#include <utils/savedaction.h>
#include <QHeaderView>
#include <QScrollBar>
@@ -54,7 +54,7 @@ WatchTreeView::WatchTreeView(WatchType type)
connect(this, &QTreeView::expanded, this, &WatchTreeView::expandNode);
connect(this, &QTreeView::collapsed, this, &WatchTreeView::collapseNode);
- connect(action(LogTimeStamps)->action(), &QAction::triggered,
+ connect(&debuggerSettings()->logTimeStamps, &Utils::BaseAspect::changed,
this, &WatchTreeView::updateTimeColumn);
}
@@ -106,7 +106,8 @@ void WatchTreeView::setModel(QAbstractItemModel *model)
void WatchTreeView::updateTimeColumn()
{
if (header())
- header()->setSectionHidden(WatchModelBase::TimeColumn, !boolSetting(LogTimeStamps));
+ header()->setSectionHidden(WatchModelBase::TimeColumn,
+ !debuggerSettings()->logTimeStamps.value());
}
void WatchTreeView::handleItemIsExpanded(const QModelIndex &idx)
diff --git a/src/plugins/designer/formeditorplugin.cpp b/src/plugins/designer/formeditorplugin.cpp
index 9a912ac68e..05e46e23a4 100644
--- a/src/plugins/designer/formeditorplugin.cpp
+++ b/src/plugins/designer/formeditorplugin.cpp
@@ -106,9 +106,9 @@ bool FormEditorPlugin::initialize(const QStringList &arguments, QString *error)
const QString locale = ICore::userInterfaceLanguage();
if (!locale.isEmpty()) {
auto qtr = new QTranslator(this);
- const QString &creatorTrPath = ICore::resourcePath() + "/translations";
- const QString &qtTrPath = QLibraryInfo::location(QLibraryInfo::TranslationsPath);
- const QString &trFile = "designer_" + locale;
+ const QString creatorTrPath = ICore::resourcePath("translations").toString();
+ const QString qtTrPath = QLibraryInfo::location(QLibraryInfo::TranslationsPath);
+ const QString trFile = "designer_" + locale;
if (qtr->load(trFile, qtTrPath) || qtr->load(trFile, creatorTrPath))
QCoreApplication::installTranslator(qtr);
}
diff --git a/src/plugins/designer/formwindowfile.cpp b/src/plugins/designer/formwindowfile.cpp
index 7e85f13e47..5744256813 100644
--- a/src/plugins/designer/formwindowfile.cpp
+++ b/src/plugins/designer/formwindowfile.cpp
@@ -65,51 +65,51 @@ FormWindowFile::FormWindowFile(QDesignerFormWindowInterface *form, QObject *pare
m_resourceHandler, &ResourceHandler::updateResources);
}
-Core::IDocument::OpenResult FormWindowFile::open(QString *errorString, const QString &fileName,
- const QString &realFileName)
+Core::IDocument::OpenResult FormWindowFile::open(QString *errorString,
+ const Utils::FilePath &filePath,
+ const Utils::FilePath &realFilePath)
{
if (Designer::Constants::Internal::debug)
- qDebug() << "FormWindowFile::open" << fileName;
+ qDebug() << "FormWindowFile::open" << filePath.toUserOutput();
QDesignerFormWindowInterface *form = formWindow();
QTC_ASSERT(form, return OpenResult::CannotHandle);
- if (fileName.isEmpty())
+ if (filePath.isEmpty())
return OpenResult::ReadError;
- const QFileInfo fi(fileName);
- const QString absfileName = fi.absoluteFilePath();
-
QString contents;
- Utils::TextFileFormat::ReadResult readResult = read(absfileName, &contents, errorString);
+ Utils::TextFileFormat::ReadResult readResult = read(filePath.absoluteFilePath(),
+ &contents,
+ errorString);
if (readResult == Utils::TextFileFormat::ReadEncodingError)
return OpenResult::CannotHandle;
if (readResult != Utils::TextFileFormat::ReadSuccess)
return OpenResult::ReadError;
- form->setFileName(absfileName);
+ form->setFileName(filePath.absoluteFilePath().toString());
const QByteArray contentsBA = contents.toUtf8();
QBuffer str;
str.setData(contentsBA);
str.open(QIODevice::ReadOnly);
if (!form->setContents(&str, errorString))
return OpenResult::CannotHandle;
- form->setDirty(fileName != realFileName);
+ form->setDirty(filePath != realFilePath);
syncXmlFromFormWindow();
- setFilePath(Utils::FilePath::fromString(absfileName));
+ setFilePath(filePath.absoluteFilePath());
setShouldAutoSave(false);
resourceHandler()->updateProjectResources();
return OpenResult::Success;
}
-bool FormWindowFile::save(QString *errorString, const QString &name, bool autoSave)
+bool FormWindowFile::save(QString *errorString, const FilePath &filePath, bool autoSave)
{
- const FilePath actualName = name.isEmpty() ? filePath() : FilePath::fromString(name);
+ const FilePath &actualName = filePath.isEmpty() ? this->filePath() : filePath;
if (Designer::Constants::Internal::debug)
- qDebug() << Q_FUNC_INFO << name << "->" << actualName;
+ qDebug() << Q_FUNC_INFO << filePath << "->" << actualName;
QTC_ASSERT(m_formWindow, return false);
@@ -119,7 +119,7 @@ bool FormWindowFile::save(QString *errorString, const QString &name, bool autoSa
const QString oldFormName = m_formWindow->fileName();
if (!autoSave)
m_formWindow->setFileName(actualName.toString());
- const bool writeOK = writeFile(actualName.toString(), errorString);
+ const bool writeOK = writeFile(actualName, errorString);
m_shouldAutoSave = false;
if (autoSave)
return writeOK;
@@ -228,7 +228,7 @@ bool FormWindowFile::reload(QString *errorString, ReloadFlag flag, ChangeType ty
} else {
emit aboutToReload();
const bool success
- = (open(errorString, filePath().toString(), filePath().toString()) == OpenResult::Success);
+ = (open(errorString, filePath(), filePath()) == OpenResult::Success);
emit reloadFinished(success);
return success;
}
@@ -247,11 +247,11 @@ QString FormWindowFile::fallbackSaveAsFileName() const
return m_suggestedName;
}
-bool FormWindowFile::writeFile(const QString &fn, QString *errorString) const
+bool FormWindowFile::writeFile(const Utils::FilePath &filePath, QString *errorString) const
{
if (Designer::Constants::Internal::debug)
- qDebug() << Q_FUNC_INFO << filePath() << fn;
- return write(fn, format(), m_formWindow->contents(), errorString);
+ qDebug() << Q_FUNC_INFO << this->filePath() << filePath;
+ return write(filePath, format(), m_formWindow->contents(), errorString);
}
QDesignerFormWindowInterface *FormWindowFile::formWindow() const
diff --git a/src/plugins/designer/formwindowfile.h b/src/plugins/designer/formwindowfile.h
index d5791e7461..ca0ad50b3f 100644
--- a/src/plugins/designer/formwindowfile.h
+++ b/src/plugins/designer/formwindowfile.h
@@ -48,9 +48,9 @@ public:
~FormWindowFile() override { }
// IDocument
- OpenResult open(QString *errorString, const QString &fileName,
- const QString &realFileName) override;
- bool save(QString *errorString, const QString &fileName, bool autoSave) override;
+ OpenResult open(QString *errorString, const Utils::FilePath &filePath,
+ const Utils::FilePath &realFilePath) override;
+ bool save(QString *errorString, const Utils::FilePath &filePath, bool autoSave) override;
QByteArray contents() const override;
bool setContents(const QByteArray &contents) override;
bool shouldAutoSave() const override;
@@ -62,7 +62,7 @@ public:
// Internal
void setFallbackSaveAsFileName(const QString &fileName);
- bool writeFile(const QString &fileName, QString *errorString) const;
+ bool writeFile(const Utils::FilePath &filePath, QString *errorString) const;
QDesignerFormWindowInterface *formWindow() const;
void syncXmlFromFormWindow();
diff --git a/src/plugins/designer/qtcreatorintegration.cpp b/src/plugins/designer/qtcreatorintegration.cpp
index 9ab38d9b08..c11756674c 100644
--- a/src/plugins/designer/qtcreatorintegration.cpp
+++ b/src/plugins/designer/qtcreatorintegration.cpp
@@ -409,7 +409,7 @@ static Document::Ptr getParsedDocument(const QString &fileName,
src = workingCopy.source(fileName);
} else {
Utils::FileReader reader;
- if (reader.fetch(fileName)) // ### FIXME error reporting
+ if (reader.fetch(Utils::FilePath::fromString(fileName))) // ### FIXME error reporting
src = QString::fromLocal8Bit(reader.data()).toUtf8();
}
diff --git a/src/plugins/diffeditor/diffeditorconstants.h b/src/plugins/diffeditor/diffeditorconstants.h
index 8d5d635fa6..09283cccb1 100644
--- a/src/plugins/diffeditor/diffeditorconstants.h
+++ b/src/plugins/diffeditor/diffeditorconstants.h
@@ -40,7 +40,7 @@ const char SIDE_BY_SIDE_VIEW_ID[] = "DiffEditor.SideBySide";
const char UNIFIED_VIEW_ID[] = "DiffEditor.Unified";
const char SELECT_ENCODING[] = "DiffEditor.SelectEncoding";
-const char G_TOOLS_DIFF[] = "QtCreator.Group.Tools.Options";
+const char G_TOOLS_DIFF[] = "QtCreator.Group.Tools.Diff";
} // namespace Constants
} // namespace DiffEditor
diff --git a/src/plugins/diffeditor/diffeditordocument.cpp b/src/plugins/diffeditor/diffeditordocument.cpp
index 546fe9e27e..d4a8f7851d 100644
--- a/src/plugins/diffeditor/diffeditordocument.cpp
+++ b/src/plugins/diffeditor/diffeditordocument.cpp
@@ -265,7 +265,7 @@ bool DiffEditorDocument::isSaveAsAllowed() const
return state() == LoadOK;
}
-bool DiffEditorDocument::save(QString *errorString, const QString &fileName, bool autoSave)
+bool DiffEditorDocument::save(QString *errorString, const Utils::FilePath &filePath, bool autoSave)
{
Q_UNUSED(errorString)
Q_UNUSED(autoSave)
@@ -273,7 +273,7 @@ bool DiffEditorDocument::save(QString *errorString, const QString &fileName, boo
if (state() != LoadOK)
return false;
- const bool ok = write(fileName, format(), plainText(), errorString);
+ const bool ok = write(filePath, format(), plainText(), errorString);
if (!ok)
return false;
@@ -282,9 +282,8 @@ bool DiffEditorDocument::save(QString *errorString, const QString &fileName, boo
setDescription(QString());
Core::EditorManager::clearUniqueId(this);
- const QFileInfo fi(fileName);
setTemporary(false);
- setFilePath(FilePath::fromString(fi.absoluteFilePath()));
+ setFilePath(filePath.absoluteFilePath());
setPreferredDisplayName(QString());
emit temporaryStateChanged();
@@ -306,16 +305,16 @@ bool DiffEditorDocument::reload(QString *errorString, ReloadFlag flag, ChangeTyp
Q_UNUSED(type)
if (flag == FlagIgnore)
return true;
- return open(errorString, filePath().toString(), filePath().toString()) == OpenResult::Success;
+ return open(errorString, filePath(), filePath()) == OpenResult::Success;
}
-Core::IDocument::OpenResult DiffEditorDocument::open(QString *errorString, const QString &fileName,
- const QString &realFileName)
+Core::IDocument::OpenResult DiffEditorDocument::open(QString *errorString, const Utils::FilePath &filePath,
+ const Utils::FilePath &realFilePath)
{
- QTC_CHECK(fileName == realFileName); // does not support autosave
+ QTC_CHECK(filePath == realFilePath); // does not support autosave
beginReload();
QString patch;
- ReadResult readResult = read(fileName, &patch, errorString);
+ ReadResult readResult = read(filePath, &patch, errorString);
if (readResult == TextFileFormat::ReadIOError
|| readResult == TextFileFormat::ReadMemoryAllocationError) {
return OpenResult::ReadError;
@@ -326,13 +325,12 @@ Core::IDocument::OpenResult DiffEditorDocument::open(QString *errorString, const
if (!ok) {
*errorString = tr("Could not parse patch file \"%1\". "
"The content is not of unified diff format.")
- .arg(fileName);
+ .arg(filePath.toUserOutput());
} else {
- const QFileInfo fi(fileName);
setTemporary(false);
emit temporaryStateChanged();
- setFilePath(FilePath::fromString(fi.absoluteFilePath()));
- setDiffFiles(fileDataList, fi.absolutePath());
+ setFilePath(filePath.absoluteFilePath());
+ setDiffFiles(fileDataList, filePath.absoluteFilePath().toString());
}
endReload(ok);
if (!ok && readResult == TextFileFormat::ReadEncodingError)
diff --git a/src/plugins/diffeditor/diffeditordocument.h b/src/plugins/diffeditor/diffeditordocument.h
index a034feb439..a4dc866553 100644
--- a/src/plugins/diffeditor/diffeditordocument.h
+++ b/src/plugins/diffeditor/diffeditordocument.h
@@ -81,11 +81,11 @@ public:
QString fallbackSaveAsFileName() const override;
bool isSaveAsAllowed() const override;
- bool save(QString *errorString, const QString &fileName, bool autoSave) override;
+ bool save(QString *errorString, const Utils::FilePath &filePath, bool autoSave) override;
void reload();
bool reload(QString *errorString, ReloadFlag flag, ChangeType type) override;
- OpenResult open(QString *errorString, const QString &fileName,
- const QString &realFileName) override;
+ OpenResult open(QString *errorString, const Utils::FilePath &filePath,
+ const Utils::FilePath &realFilePath) override;
bool selectEncoding();
State state() const { return m_state; }
diff --git a/src/plugins/diffeditor/diffeditorplugin.cpp b/src/plugins/diffeditor/diffeditorplugin.cpp
index ca234eb6f8..a83c5a7fbb 100644
--- a/src/plugins/diffeditor/diffeditorplugin.cpp
+++ b/src/plugins/diffeditor/diffeditorplugin.cpp
@@ -199,7 +199,7 @@ QList<ReloadInput> DiffCurrentFileController::reloadInputList() const
QList<ReloadInput> result;
auto textDocument = qobject_cast<TextEditor::TextDocument *>(
- DocumentModel::documentForFilePath(Utils::FilePath::fromString(m_fileName)));
+ DocumentModel::documentForFilePath(FilePath::fromString(m_fileName)));
if (textDocument && textDocument->isModified()) {
QString errorString;
@@ -207,7 +207,7 @@ QList<ReloadInput> DiffCurrentFileController::reloadInputList() const
QString leftText;
const Utils::TextFileFormat::ReadResult leftResult
- = Utils::TextFileFormat::readFile(m_fileName, format.codec,
+ = Utils::TextFileFormat::readFile(FilePath::fromString(m_fileName), format.codec,
&leftText, &format, &errorString);
const QString rightText = textDocument->plainText();
@@ -262,9 +262,8 @@ QList<ReloadInput> DiffOpenFilesController::reloadInputList() const
QString leftText;
const QString fileName = textDocument->filePath().toString();
- const Utils::TextFileFormat::ReadResult leftResult
- = Utils::TextFileFormat::readFile(fileName, format.codec,
- &leftText, &format, &errorString);
+ const Utils::TextFileFormat::ReadResult leftResult = Utils::TextFileFormat::readFile(
+ FilePath::fromString(fileName), format.codec, &leftText, &format, &errorString);
const QString rightText = textDocument->plainText();
@@ -321,9 +320,8 @@ QList<ReloadInput> DiffModifiedFilesController::reloadInputList() const
QString leftText;
const QString fileName = textDocument->filePath().toString();
- const Utils::TextFileFormat::ReadResult leftResult
- = Utils::TextFileFormat::readFile(fileName, format.codec,
- &leftText, &format, &errorString);
+ const Utils::TextFileFormat::ReadResult leftResult = Utils::TextFileFormat::readFile(
+ FilePath::fromString(fileName), format.codec, &leftText, &format, &errorString);
const QString rightText = textDocument->plainText();
@@ -378,12 +376,10 @@ QList<ReloadInput> DiffExternalFilesController::reloadInputList() const
QString leftText;
QString rightText;
- const Utils::TextFileFormat::ReadResult leftResult
- = Utils::TextFileFormat::readFile(m_leftFileName, format.codec,
- &leftText, &format, &errorString);
- const Utils::TextFileFormat::ReadResult rightResult
- = Utils::TextFileFormat::readFile(m_rightFileName, format.codec,
- &rightText, &format, &errorString);
+ const Utils::TextFileFormat::ReadResult leftResult = Utils::TextFileFormat::readFile(
+ FilePath::fromString(m_leftFileName), format.codec, &leftText, &format, &errorString);
+ const Utils::TextFileFormat::ReadResult rightResult = Utils::TextFileFormat::readFile(
+ FilePath::fromString(m_rightFileName), format.codec, &rightText, &format, &errorString);
ReloadInput reloadInput;
reloadInput.leftText = leftText;
@@ -575,7 +571,7 @@ void DiffEditorPluginPrivate::diffExternalFiles()
QString());
if (fileName1.isNull())
return;
- if (EditorManager::skipOpeningBigTextFile(fileName1))
+ if (EditorManager::skipOpeningBigTextFile(FilePath::fromString(fileName1)))
return;
const QString fileName2 = QFileDialog::getOpenFileName(ICore::dialogParent(),
@@ -583,7 +579,7 @@ void DiffEditorPluginPrivate::diffExternalFiles()
QString());
if (fileName2.isNull())
return;
- if (EditorManager::skipOpeningBigTextFile(fileName2))
+ if (EditorManager::skipOpeningBigTextFile(FilePath::fromString(fileName2)))
return;
const QString documentId = Constants::DIFF_EDITOR_PLUGIN
diff --git a/src/plugins/diffeditor/diffeditorwidgetcontroller.cpp b/src/plugins/diffeditor/diffeditorwidgetcontroller.cpp
index 3cddcdf55d..e1221e63ae 100644
--- a/src/plugins/diffeditor/diffeditorwidgetcontroller.cpp
+++ b/src/plugins/diffeditor/diffeditorwidgetcontroller.cpp
@@ -202,7 +202,7 @@ void DiffEditorWidgetController::patch(bool revert, int fileIndex, int chunkInde
if (PatchTool::runPatch(EditorManager::defaultTextCodec()->fromUnicode(patch),
contentsCopyDir, 0, revert)) {
QString errorString;
- if (textDocument->reload(&errorString, contentsCopyFileName))
+ if (textDocument->reload(&errorString, FilePath::fromString(contentsCopyFileName)))
m_document->reload();
}
}
diff --git a/src/plugins/docker/CMakeLists.txt b/src/plugins/docker/CMakeLists.txt
new file mode 100644
index 0000000000..095d7b41c7
--- /dev/null
+++ b/src/plugins/docker/CMakeLists.txt
@@ -0,0 +1,15 @@
+add_qtc_plugin(Docker
+ PLUGIN_DEPENDS Core ProjectExplorer QtSupport
+ SOURCES
+ docker_global.h
+ dockerbuildstep.cpp dockerbuildstep.h
+ dockerconstants.h
+ dockerdevice.cpp
+ dockerdevice.h
+ dockerplugin.cpp
+ dockerplugin.h
+ dockerrunconfiguration.cpp
+ dockerrunconfiguration.h
+ dockersettings.cpp
+ dockersettings.h
+)
diff --git a/src/plugins/docker/Docker.json.in b/src/plugins/docker/Docker.json.in
new file mode 100644
index 0000000000..c2854973d4
--- /dev/null
+++ b/src/plugins/docker/Docker.json.in
@@ -0,0 +1,19 @@
+{
+ \"Name\" : \"Docker\",
+ \"Version\" : \"$$QTCREATOR_VERSION\",
+ \"CompatVersion\" : \"$$QTCREATOR_COMPAT_VERSION\",
+ \"Vendor\" : \"The Qt Company Ltd\",
+ \"Copyright\" : \"(C) $$QTCREATOR_COPYRIGHT_YEAR The Qt Company Ltd\",
+ \"License\" : [ \"Commercial Usage\",
+ \"\",
+ \"Licensees holding valid Qt Commercial licenses may use this plugin in accordance with the Qt 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.\",
+ \"\",
+ \"GNU General Public License Usage\",
+ \"\",
+ \"Alternatively, this plugin 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 plugin. 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.\"
+ ],
+ \"Experimental\" : true,
+ \"Description\" : \"Basic support for Docker\",
+ \"Url\" : \"http://www.qt.io\",
+ $$dependencyList
+}
diff --git a/src/plugins/docker/docker.pro b/src/plugins/docker/docker.pro
new file mode 100644
index 0000000000..ac012006b7
--- /dev/null
+++ b/src/plugins/docker/docker.pro
@@ -0,0 +1,19 @@
+include(../../qtcreatorplugin.pri)
+
+DEFINES += QT_RESTRICTED_CAST_FROM_ASCII
+
+SOURCES += \
+ dockerbuildstep.cpp \
+ dockerdevice.cpp \
+ dockerplugin.cpp \
+ dockerrunconfiguration.cpp \
+ dockersettings.cpp
+
+HEADERS += \
+ docker_global.h \
+ dockerbuildstep.h \
+ dockerconstants.h \
+ dockerdevice.h \
+ dockerplugin.h \
+ dockerrunconfiguration.h \
+ dockersettings.h
diff --git a/src/plugins/docker/docker.qbs b/src/plugins/docker/docker.qbs
new file mode 100644
index 0000000000..93ea8a84ba
--- /dev/null
+++ b/src/plugins/docker/docker.qbs
@@ -0,0 +1,28 @@
+import qbs 1.0
+
+QtcPlugin {
+ name: "Docker"
+
+ Depends { name: "Qt.widgets" }
+ Depends { name: "Utils" }
+
+ Depends { name: "Core" }
+ Depends { name: "ProjectExplorer" }
+ Depends { name: "QtSupport" }
+
+ files: [
+ "docker_global.h",
+ "dockerbuildstep.h",
+ "dockerbuildstep.cpp",
+ "dockerconstants.h",
+ "dockerdevice.h",
+ "dockerdevice.cpp",
+ "dockerplugin.h",
+ "dockerplugin.cpp",
+ "dockerrunconfiguration.h",
+ "dockerrunconfiguration.cpp",
+ "dockersettings.h",
+ "dockersettings.cpp"
+ ]
+}
+
diff --git a/src/plugins/docker/docker_dependencies.pri b/src/plugins/docker/docker_dependencies.pri
new file mode 100644
index 0000000000..8fdb21e97e
--- /dev/null
+++ b/src/plugins/docker/docker_dependencies.pri
@@ -0,0 +1,7 @@
+QTC_PLUGIN_NAME = Docker
+QTC_LIB_DEPENDS += \
+ utils
+QTC_PLUGIN_DEPENDS += \
+ coreplugin \
+ projectexplorer \
+ qtsupport
diff --git a/src/plugins/docker/docker_global.h b/src/plugins/docker/docker_global.h
new file mode 100644
index 0000000000..5dd732b10b
--- /dev/null
+++ b/src/plugins/docker/docker_global.h
@@ -0,0 +1,10 @@
+#ifndef DOCKER_GLOBAL_H
+#define DOCKER_GLOBAL_H
+
+#if defined(DOCKER_LIBRARY)
+# define DOCKER_EXPORT Q_DECL_EXPORT
+#else
+# define DOCKER_EXPORT Q_DECL_IMPORT
+#endif
+
+#endif // DOCKER_GLOBAL_H
diff --git a/src/plugins/docker/dockerbuildstep.cpp b/src/plugins/docker/dockerbuildstep.cpp
new file mode 100644
index 0000000000..332803f687
--- /dev/null
+++ b/src/plugins/docker/dockerbuildstep.cpp
@@ -0,0 +1,166 @@
+/****************************************************************************
+**
+** Copyright (C) 2021 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of Qt Creator.
+**
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3 as published by the Free Software
+** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-3.0.html.
+**
+****************************************************************************/
+
+#include "dockerbuildstep.h"
+
+#include "dockerconstants.h"
+#include "dockerdevice.h"
+#include "dockersettings.h"
+
+#include <projectexplorer/abstractprocessstep.h>
+#include <projectexplorer/kitinformation.h>
+#include <projectexplorer/processparameters.h>
+#include <projectexplorer/runcontrol.h>
+#include <projectexplorer/target.h>
+
+#include <QRegularExpression>
+
+using namespace ProjectExplorer;
+using namespace Utils;
+
+namespace Docker {
+namespace Internal {
+
+const char DOCKER_COMMAND[] = "docker";
+const char DEFAULT_DOCKER_COMMAND[] = "run --read-only --rm %{BuildDevice:DockerImage}";
+
+class DockerBuildStep : public AbstractProcessStep
+{
+public:
+ DockerBuildStep(BuildStepList *bsl, Id id)
+ : AbstractProcessStep(bsl, id)
+ {
+ setDisplayName(tr("Docker build host step"));
+
+ m_dockerCommand = addAspect<StringAspect>();
+ m_dockerCommand->setDisplayStyle(StringAspect::DisplayStyle::TextEditDisplay);
+ m_dockerCommand->setLabelText(tr("Docker Command:"));
+ m_dockerCommand->setMacroExpanderProvider([=] { return macroExpander(); });
+ m_dockerCommand->setDefaultValue(QLatin1String(DEFAULT_DOCKER_COMMAND));
+ m_dockerCommand->setPlaceHolderText(QLatin1String(DEFAULT_DOCKER_COMMAND));
+ m_dockerCommand->setSettingsKey("DockerCommand");
+
+ auto setupField = [=](Utils::StringAspect* &aspect, const QString &label,
+ const QString &settingsKey) {
+ aspect = addAspect<StringAspect>();
+ aspect->setDisplayStyle(StringAspect::DisplayStyle::LineEditDisplay);
+ aspect->setLabelText(label);
+ aspect->setSettingsKey(settingsKey);
+ aspect->setMacroExpanderProvider([=] { return target()->kit()->macroExpander(); });
+ };
+ setupField(m_command, tr("Command:"), "Command");
+ setupField(m_arguments, tr("Arguments:"), "Arguments");
+ setupField(m_workingDirectory, tr("Working Directory:"), "WorkingDirectory");
+
+ setCommandLineProvider([=] { return commandLine(); });
+ setWorkingDirectoryProvider([=] {
+ return dockerBuildDevice() ? FilePath() : workingDirectory();
+ });
+ setSummaryUpdater([=] { return summary(); });
+ }
+
+private:
+ const DockerDevice *dockerBuildDevice() const
+ {
+ const IDevice::ConstPtr device = BuildDeviceKitAspect::device(target()->kit());
+ return dynamic_cast<const DockerDevice *>(device.get());
+ }
+
+ MacroExpander *macroExpander() const
+ {
+ MacroExpander *expander = target()->kit()->macroExpander();
+ expander->registerVariable("BuildDevice:DockerImage",
+ "Build Host Docker Image ID", [=]() -> QString {
+ const DockerDevice *dockerDevice = dockerBuildDevice();
+ return dockerDevice ? dockerDevice->data().imageId : QString();
+ }, true);
+ return expander;
+ }
+
+ CommandLine commandLine() const
+ {
+ MacroExpander *expander = target()->kit()->macroExpander();
+ CommandLine cmd;
+ if (dockerBuildDevice()) {
+ CommandLine dockerCmd(QString::fromLatin1(DOCKER_COMMAND));
+ QString dockerCommand = m_dockerCommand->value();
+
+ // Sneak working directory into docker "run" or "exec" call
+ const QString workDir = m_workingDirectory->value();
+ if (!workDir.isEmpty())
+ dockerCommand.replace(QRegularExpression("[[:<:]](run|exec)[[:>:]]"),
+ "\\1 --workdir " + workDir);
+
+ dockerCmd.addArgs(expander->expand(dockerCommand), CommandLine::Raw);
+ dockerCmd.addArgs(expander->expand(m_command->value()), CommandLine::Raw);
+ cmd = dockerCmd;
+ } else {
+ CommandLine localCmd(expander->expand(m_command->value()));
+ cmd = localCmd;
+ }
+ cmd.addArgs(expander->expand(m_arguments->value()), CommandLine::Raw);
+ return cmd;
+ }
+
+ FilePath workingDirectory() const
+ {
+ return FilePath::fromUserInput(target()->kit()->macroExpander()->
+ expand(m_workingDirectory->value()));
+ }
+
+ QString summary() const
+ {
+ const IDevice::ConstPtr d = BuildDeviceKitAspect::device(target()->kit());
+ if (!d)
+ return QString(); // No build device selected in kit
+ m_dockerCommand->setEnabled(dockerBuildDevice() != nullptr);
+ const QString title = tr("Build on %1").arg(d->displayName());
+ if (m_command->value().isEmpty()) {
+ // Procuring the red "Invalid command" summary.
+ ProcessParameters params;
+ params.effectiveCommand();
+ return params.summary(title);
+ } else {
+ return tr("<b>%1:</b> %2").arg(title).arg(commandLine().toUserOutput());
+ }
+ }
+
+ Utils::StringAspect *m_dockerCommand = nullptr;
+ Utils::StringAspect *m_command = nullptr;
+ Utils::StringAspect *m_arguments = nullptr;
+ Utils::StringAspect *m_workingDirectory = nullptr;
+};
+
+
+DockerBuildStepFactory::DockerBuildStepFactory()
+{
+ registerStep<DockerBuildStep>(Constants::DOCKER_BUILDHOST_BUILDSTEP_ID);
+ setDisplayName(DockerBuildStep::tr("Docker build host step"));
+ setSupportedStepLists({ProjectExplorer::Constants::BUILDSTEPS_BUILD,
+ ProjectExplorer::Constants::BUILDSTEPS_CLEAN});
+}
+
+} // Internal
+} // Docker
diff --git a/src/plugins/projectexplorer/buildpropertiessettingspage.h b/src/plugins/docker/dockerbuildstep.h
index bd40d0e222..c00184edd0 100644
--- a/src/plugins/projectexplorer/buildpropertiessettingspage.h
+++ b/src/plugins/docker/dockerbuildstep.h
@@ -1,6 +1,6 @@
/****************************************************************************
**
-** Copyright (C) 2019 The Qt Company Ltd.
+** Copyright (C) 2021 The Qt Company Ltd.
** Contact: https://www.qt.io/licensing/
**
** This file is part of Qt Creator.
@@ -25,16 +25,16 @@
#pragma once
-#include <coreplugin/dialogs/ioptionspage.h>
+#include <projectexplorer/buildstep.h>
-namespace ProjectExplorer {
+namespace Docker {
namespace Internal {
-class BuildPropertiesSettingsPage final : public Core::IOptionsPage
+class DockerBuildStepFactory final : public ProjectExplorer::BuildStepFactory
{
public:
- BuildPropertiesSettingsPage();
+ DockerBuildStepFactory();
};
-} // namespace Internal
-} // namespace ProjectExplorer
+} // Internal
+} // Docker
diff --git a/src/plugins/cpaster/settingspage.h b/src/plugins/docker/dockerconstants.h
index 5d8ecefe75..10660696ce 100644
--- a/src/plugins/cpaster/settingspage.h
+++ b/src/plugins/docker/dockerconstants.h
@@ -1,6 +1,6 @@
/****************************************************************************
**
-** Copyright (C) 2016 The Qt Company Ltd.
+** Copyright (C) 2021 The Qt Company Ltd.
** Contact: https://www.qt.io/licensing/
**
** This file is part of Qt Creator.
@@ -23,23 +23,22 @@
**
****************************************************************************/
-#pragma once
+#ifndef DOCKERCONSTANTS_H
+#define DOCKERCONSTANTS_H
-#include "ui_settingspage.h"
+namespace Docker {
+namespace Constants {
-#include <coreplugin/dialogs/ioptionspage.h>
+const char DOCKER_SETTINGS_ID[] = "Docker.Settings";
+const char ACTION_ID[] = "Docker.Action";
+const char MENU_ID[] = "Docker.Menu";
-#include <QStringList>
+const char DOCKER_DEVICE_TYPE[] = "DockerDeviceType";
+const char DOCKER_RUN_FLAGS[] = "DockerRunFlags";
-namespace CodePaster {
+const char DOCKER_BUILDHOST_BUILDSTEP_ID[] = "Docker.BuildStep.BuildHost";
-class Settings;
+} // namespace Constants
+} // namespace Docker
-class SettingsPage final : public Core::IOptionsPage
-{
- Q_DECLARE_TR_FUNCTIONS(CodePaster::SettingsPage)
-public:
- SettingsPage(Settings *settings, const QStringList &protocolNames);
-};
-
-} // namespace CodePaster
+#endif // DOCKERCONSTANTS_H
diff --git a/src/plugins/docker/dockerdevice.cpp b/src/plugins/docker/dockerdevice.cpp
new file mode 100644
index 0000000000..d0db0b1b7a
--- /dev/null
+++ b/src/plugins/docker/dockerdevice.cpp
@@ -0,0 +1,921 @@
+/****************************************************************************
+**
+** 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 "dockerdevice.h"
+
+#include "dockerconstants.h"
+
+#include <extensionsystem/pluginmanager.h>
+
+#include <coreplugin/icore.h>
+#include <coreplugin/messagemanager.h>
+
+#include <projectexplorer/devicesupport/idevicewidget.h>
+#include <projectexplorer/kitinformation.h>
+#include <projectexplorer/kitmanager.h>
+#include <projectexplorer/runcontrol.h>
+#include <projectexplorer/toolchain.h>
+#include <projectexplorer/toolchainmanager.h>
+
+#include <qtsupport/baseqtversion.h>
+#include <qtsupport/qtkitinformation.h>
+#include <qtsupport/qtversionfactory.h>
+#include <qtsupport/qtversionmanager.h>
+
+#include <utils/algorithm.h>
+#include <utils/basetreeview.h>
+#include <utils/environment.h>
+#include <utils/hostosinfo.h>
+#include <utils/layoutbuilder.h>
+#include <utils/port.h>
+#include <utils/qtcassert.h>
+#include <utils/qtcprocess.h>
+#include <utils/stringutils.h>
+#include <utils/temporaryfile.h>
+#include <utils/treemodel.h>
+
+#include <QDialog>
+#include <QDialogButtonBox>
+#include <QFileSystemWatcher>
+#include <QHeaderView>
+#include <QPushButton>
+#include <QTextBrowser>
+#include <QThread>
+
+using namespace Core;
+using namespace ProjectExplorer;
+using namespace QtSupport;
+using namespace Utils;
+
+#define LOG(x)
+//#define LOG(x) qDebug() << x
+
+namespace Docker {
+namespace Internal {
+
+const QByteArray pidMarker = "__qtc";
+
+class DockerDeviceProcess : public ProjectExplorer::DeviceProcess
+{
+public:
+ DockerDeviceProcess(const QSharedPointer<const IDevice> &device, QObject *parent = nullptr);
+ ~DockerDeviceProcess() {}
+
+ void start(const Runnable &runnable) override;
+
+ void interrupt() override;
+ void terminate() override { m_process.terminate(); }
+ void kill() override;
+
+ QProcess::ProcessState state() const override;
+ QProcess::ExitStatus exitStatus() const override;
+ int exitCode() const override;
+ QString errorString() const override;
+
+ QByteArray readAllStandardOutput() override;
+ QByteArray readAllStandardError() override;
+
+ qint64 write(const QByteArray &data) override { return m_process.write(data); }
+
+private:
+ QtcProcess m_process;
+};
+
+DockerDeviceProcess::DockerDeviceProcess(const QSharedPointer<const IDevice> &device,
+ QObject *parent)
+ : DeviceProcess(device, parent)
+{
+}
+
+void DockerDeviceProcess::start(const Runnable &runnable)
+{
+ QTC_ASSERT(m_process.state() == QProcess::NotRunning, return);
+ DockerDevice::ConstPtr dockerDevice = qSharedPointerCast<const DockerDevice>(device());
+ QTC_ASSERT(dockerDevice, return);
+
+ const QStringList dockerRunFlags = runnable.extraData[Constants::DOCKER_RUN_FLAGS].toStringList();
+
+ connect(this, &DeviceProcess::readyReadStandardOutput, this, [this] {
+ MessageManager::writeSilently(QString::fromLocal8Bit(readAllStandardError()));
+ });
+ connect(this, &DeviceProcess::readyReadStandardError, this, [this] {
+ MessageManager::writeDisrupting(QString::fromLocal8Bit(readAllStandardError()));
+ });
+
+ disconnect(&m_process);
+
+ m_process.setCommand(runnable.commandLine());
+ m_process.setEnvironment(runnable.environment);
+ m_process.setWorkingDirectory(runnable.workingDirectory);
+ connect(&m_process, &QProcess::errorOccurred, this, &DeviceProcess::error);
+ connect(&m_process, QOverload<int, QProcess::ExitStatus>::of(&QProcess::finished),
+ this, &DeviceProcess::finished);
+ connect(&m_process, &QProcess::readyReadStandardOutput,
+ this, &DeviceProcess::readyReadStandardOutput);
+ connect(&m_process, &QProcess::readyReadStandardError,
+ this, &DeviceProcess::readyReadStandardError);
+ connect(&m_process, &QProcess::started, this, &DeviceProcess::started);
+ dockerDevice->runProcess(m_process);
+}
+
+void DockerDeviceProcess::interrupt()
+{
+ device()->signalOperation()->interruptProcess(m_process.processId());
+}
+
+void DockerDeviceProcess::kill()
+{
+ m_process.kill();
+}
+
+QProcess::ProcessState DockerDeviceProcess::state() const
+{
+ return m_process.state();
+}
+
+QProcess::ExitStatus DockerDeviceProcess::exitStatus() const
+{
+ return m_process.exitStatus();
+}
+
+int DockerDeviceProcess::exitCode() const
+{
+ return m_process.exitCode();
+}
+
+QString DockerDeviceProcess::errorString() const
+{
+ return m_process.errorString();
+}
+
+QByteArray DockerDeviceProcess::readAllStandardOutput()
+{
+ return m_process.readAllStandardOutput();
+}
+
+QByteArray DockerDeviceProcess::readAllStandardError()
+{
+ return m_process.readAllStandardError();
+}
+
+
+class DockerPortsGatheringMethod : public PortsGatheringMethod
+{
+ Runnable runnable(QAbstractSocket::NetworkLayerProtocol protocol) const override
+ {
+ // We might encounter the situation that protocol is given IPv6
+ // but the consumer of the free port information decides to open
+ // an IPv4(only) port. As a result the next IPv6 scan will
+ // report the port again as open (in IPv6 namespace), while the
+ // same port in IPv4 namespace might still be blocked, and
+ // re-use of this port fails.
+ // GDBserver behaves exactly like this.
+
+ Q_UNUSED(protocol)
+
+ // /proc/net/tcp* covers /proc/net/tcp and /proc/net/tcp6
+ Runnable runnable;
+ runnable.executable = FilePath::fromString("sed");
+ runnable.commandLineArguments
+ = "-e 's/.*: [[:xdigit:]]*:\\([[:xdigit:]]\\{4\\}\\).*/\\1/g' /proc/net/tcp*";
+ return runnable;
+ }
+
+ QList<Utils::Port> usedPorts(const QByteArray &output) const override
+ {
+ QList<Utils::Port> ports;
+ QList<QByteArray> portStrings = output.split('\n');
+ foreach (const QByteArray &portString, portStrings) {
+ if (portString.size() != 4)
+ continue;
+ bool ok;
+ const Utils::Port port(portString.toInt(&ok, 16));
+ if (ok) {
+ if (!ports.contains(port))
+ ports << port;
+ } else {
+ qWarning("%s: Unexpected string '%s' is not a port.",
+ Q_FUNC_INFO, portString.data());
+ }
+ }
+ return ports;
+ }
+};
+
+class DockerDeviceWidget final : public IDeviceWidget
+{
+public:
+ explicit DockerDeviceWidget(const IDevice::Ptr &device)
+ : IDeviceWidget(device)
+ {
+ auto dockerDevice = device.dynamicCast<DockerDevice>();
+ QTC_ASSERT(dockerDevice, return);
+
+ m_idLabel = new QLabel(tr("Image Id:"));
+ m_idLineEdit = new QLineEdit;
+ m_idLineEdit->setText(dockerDevice->data().imageId);
+ m_idLineEdit->setEnabled(false);
+
+ m_repoLabel = new QLabel(tr("Repository:"));
+ m_repoLineEdit = new QLineEdit;
+ m_repoLineEdit->setText(dockerDevice->data().repo);
+ m_repoLineEdit->setEnabled(false);
+
+ using namespace Layouting;
+
+ Form {
+ m_idLabel, m_idLineEdit, Break(),
+ m_repoLabel, m_repoLineEdit, Break(),
+ }.attachTo(this);
+ }
+
+ void updateDeviceFromUi() final {}
+
+private:
+ QLabel *m_idLabel;
+ QLineEdit *m_idLineEdit;
+ QLabel *m_repoLabel;
+ QLineEdit *m_repoLineEdit;
+};
+
+IDeviceWidget *DockerDevice::createWidget()
+{
+ return new DockerDeviceWidget(sharedFromThis());
+}
+
+
+// DockerDevice
+
+class DockerDevicePrivate : public QObject
+{
+public:
+ DockerDevicePrivate(DockerDevice *parent) : q(parent)
+ {
+ connect(&m_mergedDirWatcher, &QFileSystemWatcher::fileChanged, this, [](const QString &path) {
+ Q_UNUSED(path)
+ LOG("Container watcher change, file: " << path);
+ });
+ connect(&m_mergedDirWatcher, &QFileSystemWatcher::directoryChanged, this, [](const QString &path) {
+ Q_UNUSED(path)
+ LOG("Container watcher change, directory: " << path);
+ });
+ }
+
+ ~DockerDevicePrivate() { delete m_shell; }
+
+ int runSynchronously(const CommandLine &cmd) const;
+
+ void tryCreateLocalFileAccess();
+
+ void setupKit();
+ BaseQtVersion *autoDetectQtVersion() const;
+ QList<ToolChain *> autoDetectToolChains();
+ void autoDetectCMake();
+
+ void fetchSystemEnviroment();
+
+ DockerDevice *q;
+ DockerDeviceData m_data;
+
+ // For local file access
+ QPointer<QtcProcess> m_shell;
+ QString m_container;
+ QString m_mergedDir;
+ QFileSystemWatcher m_mergedDirWatcher;
+
+ Environment m_cachedEnviroment;
+};
+
+DockerDevice::DockerDevice(const DockerDeviceData &data)
+ : d(new DockerDevicePrivate(this))
+{
+ d->m_data = data;
+
+ setDisplayType(tr("Docker"));
+ setOsType(OsTypeOtherUnix);
+ setDefaultDisplayName(tr("Docker Image"));;
+ setDisplayName(tr("Docker Image \"%1\" (%2)").arg(data.repo).arg(data.imageId));
+ setAllowEmptyCommand(true);
+
+ setOpenTerminal([this](const Environment &env, const QString &workingDir) {
+ DeviceProcess * const proc = createProcess(nullptr);
+ QObject::connect(proc, &DeviceProcess::finished, [proc] {
+ if (!proc->errorString().isEmpty()) {
+ MessageManager::writeDisrupting(
+ tr("Error running remote shell: %1").arg(proc->errorString()));
+ }
+ proc->deleteLater();
+ });
+ QObject::connect(proc, &DeviceProcess::error, [proc] {
+ MessageManager::writeDisrupting(tr("Error starting remote shell."));
+ proc->deleteLater();
+ });
+
+ Runnable runnable;
+ runnable.executable = FilePath::fromString("/bin/sh");
+ runnable.device = sharedFromThis();
+ runnable.environment = env;
+ runnable.workingDirectory = workingDir;
+ runnable.extraData[Constants::DOCKER_RUN_FLAGS] = QStringList({"--interactive", "--tty"});
+
+ proc->setRunInTerminal(true);
+ proc->start(runnable);
+ });
+
+ if (HostOsInfo::isAnyUnixHost()) {
+ addDeviceAction({tr("Open Shell in Container"), [](const IDevice::Ptr &device, QWidget *) {
+ device->openTerminal(Environment(), QString());
+ }});
+ }
+}
+
+DockerDevice::~DockerDevice()
+{
+ delete d;
+}
+
+const DockerDeviceData &DockerDevice::data() const
+{
+ return d->m_data;
+}
+
+BaseQtVersion *DockerDevicePrivate::autoDetectQtVersion() const
+{
+ QString error;
+ QString source = "docker:" + m_data.imageId;
+ const QStringList candidates = {"/usr/local/bin/qmake", "/usr/bin/qmake"};
+ for (const QString &candidate : candidates) {
+ const FilePath qmake = q->mapToGlobalPath(FilePath::fromString(candidate));
+ if (auto qtVersion = QtVersionFactory::createQtVersionFromQMakePath(qmake, false, source, &error)) {
+ QtVersionManager::addVersion(qtVersion);
+ return qtVersion;
+ }
+ }
+ return nullptr;
+}
+
+QList<ToolChain *> DockerDevicePrivate::autoDetectToolChains()
+{
+ const QList<ToolChainFactory *> factories = ToolChainFactory::allToolChainFactories();
+
+ QList<ToolChain *> toolChains;
+ for (ToolChainFactory *factory : factories) {
+ const QList<ToolChain *> newToolChains = factory->autoDetect(toolChains, q->sharedFromThis());
+ for (ToolChain *toolChain : newToolChains) {
+ LOG("Found ToolChain: " << toolChain->compilerCommand().toUserOutput());
+ ToolChainManager::registerToolChain(toolChain);
+ toolChains.append(toolChain);
+ }
+ }
+
+ return toolChains;
+}
+
+void DockerDevicePrivate::autoDetectCMake()
+{
+ QObject *cmakeManager = ExtensionSystem::PluginManager::getObjectByName("CMakeToolManager");
+ if (!cmakeManager)
+ return;
+
+ QString error;
+ QString source = "docker:" + m_data.imageId;
+ const QStringList candidates = {"/usr/local/bin/cmake", "/usr/bin/cmake"};
+ for (const QString &candidate : candidates) {
+ const FilePath cmake = q->mapToGlobalPath(FilePath::fromString(candidate));
+ QTC_CHECK(q->hasLocalFileAccess());
+ if (cmake.isExecutableFile()) {
+ const bool res = QMetaObject::invokeMethod(cmakeManager,
+ "registerCMakeByPath",
+ Q_ARG(Utils::FilePath, cmake));
+ QTC_CHECK(res);
+ }
+ }
+}
+
+void DockerDevicePrivate::setupKit()
+{
+ tryCreateLocalFileAccess();
+
+ QList<ToolChain *> toolChains = autoDetectToolChains();
+
+ BaseQtVersion *qt = autoDetectQtVersion();
+
+ autoDetectCMake();
+
+ const auto initializeKit = [this, toolChains, qt](Kit *k) {
+ k->setAutoDetected(false);
+ k->setAutoDetectionSource("DockerDevice:" + m_data.imageId);
+ k->setUnexpandedDisplayName("%{Device:Name}");
+
+ DeviceTypeKitAspect::setDeviceTypeId(k, Constants::DOCKER_DEVICE_TYPE);
+ DeviceKitAspect::setDevice(k, q->sharedFromThis());
+ for (ToolChain *tc : toolChains)
+ ToolChainKitAspect::setToolChain(k, tc);
+ QtSupport::QtKitAspect::setQtVersion(k, qt);
+
+ k->setSticky(ToolChainKitAspect::id(), true);
+ k->setSticky(QtSupport::QtKitAspect::id(), true);
+ k->setSticky(DeviceKitAspect::id(), true);
+ k->setSticky(DeviceTypeKitAspect::id(), true);
+ };
+
+ KitManager::registerKit(initializeKit);
+}
+
+void DockerDevice::tryCreateLocalFileAccess() const
+{
+ d->tryCreateLocalFileAccess();
+}
+
+void DockerDevicePrivate::tryCreateLocalFileAccess()
+{
+ if (!m_container.isEmpty())
+ return;
+
+ QString tempFileName;
+
+ {
+ TemporaryFile temp("qtc-docker-XXXXXX");
+ temp.open();
+ tempFileName = temp.fileName();
+ }
+
+ m_shell = new QtcProcess;
+ // FIXME: Make mounts flexible
+ m_shell->setCommand({"docker", {"run", "-i", "--cidfile=" + tempFileName,
+ "-v", "/opt:/opt",
+ "-v", "/data:/data",
+ "-e", "DISPLAY=:0",
+ "-e", "XAUTHORITY=/.Xauthority",
+ "--net", "host",
+ m_data.imageId, "/bin/sh"}});
+ LOG("RUNNING: " << m_shell->commandLine().toUserOutput());
+ m_shell->start();
+ m_shell->waitForStarted();
+
+ LOG("CHECKING: " << tempFileName);
+ for (int i = 0; i <= 10; ++i) {
+ QFile file(tempFileName);
+ file.open(QIODevice::ReadOnly);
+ m_container = QString::fromUtf8(file.readAll()).trimmed();
+ if (!m_container.isEmpty()) {
+ LOG("Container: " << d->m_container);
+ break;
+ }
+ if (i == 10) {
+ qWarning("Docker cid file empty.");
+ return; // No
+ }
+ QThread::msleep(100);
+ }
+
+ QtcProcess proc;
+ proc.setCommand({"docker", {"inspect", "--format={{.GraphDriver.Data.MergedDir}}", m_container}});
+ //LOG(proc2.commandLine().toUserOutput());
+ proc.start();
+ proc.waitForFinished();
+ const QByteArray out = proc.readAllStandardOutput();
+ m_mergedDir = QString::fromUtf8(out).trimmed();
+ if (m_mergedDir.endsWith('/'))
+ m_mergedDir.chop(1);
+
+ m_mergedDirWatcher.addPath(m_mergedDir);
+}
+
+bool DockerDevice::hasLocalFileAccess() const
+{
+ return !d->m_mergedDir.isEmpty();
+}
+
+FilePath DockerDevice::mapToLocalAccess(const FilePath &filePath) const
+{
+ QTC_ASSERT(!d->m_mergedDir.isEmpty(), return {});
+ QString path = filePath.path();
+ if (path.startsWith('/'))
+ return FilePath::fromString(d->m_mergedDir + path);
+ return FilePath::fromString(d->m_mergedDir + '/' + path);
+}
+
+FilePath DockerDevice::mapFromLocalAccess(const FilePath &filePath) const
+{
+ QTC_ASSERT(!filePath.needsDevice(), return {});
+ return mapFromLocalAccess(filePath.toString());
+}
+
+FilePath DockerDevice::mapFromLocalAccess(const QString &filePath) const
+{
+ QTC_ASSERT(!d->m_mergedDir.isEmpty(), return {});
+ QTC_ASSERT(filePath.startsWith(d->m_mergedDir), return FilePath::fromString(filePath));
+ return mapToGlobalPath(FilePath::fromString(filePath.mid(d->m_mergedDir.size())));
+}
+
+const char DockerDeviceDataImageIdKey[] = "DockerDeviceDataImageId";
+const char DockerDeviceDataRepoKey[] = "DockerDeviceDataRepo";
+const char DockerDeviceDataTagKey[] = "DockerDeviceDataTag";
+const char DockerDeviceDataSizeKey[] = "DockerDeviceDataSize";
+
+void DockerDevice::fromMap(const QVariantMap &map)
+{
+ ProjectExplorer::IDevice::fromMap(map);
+ d->m_data.imageId = map.value(DockerDeviceDataImageIdKey).toString();
+ d->m_data.repo = map.value(DockerDeviceDataRepoKey).toString();
+ d->m_data.tag = map.value(DockerDeviceDataTagKey).toString();
+ d->m_data.size = map.value(DockerDeviceDataSizeKey).toString();
+}
+
+QVariantMap DockerDevice::toMap() const
+{
+ QVariantMap map = ProjectExplorer::IDevice::toMap();
+ map.insert(DockerDeviceDataImageIdKey, d->m_data.imageId);
+ map.insert(DockerDeviceDataRepoKey, d->m_data.repo);
+ map.insert(DockerDeviceDataTagKey, d->m_data.tag);
+ map.insert(DockerDeviceDataSizeKey, d->m_data.size);
+ return map;
+}
+
+DeviceProcess *DockerDevice::createProcess(QObject *parent) const
+{
+ return new DockerDeviceProcess(sharedFromThis(), parent);
+}
+
+bool DockerDevice::canAutoDetectPorts() const
+{
+ return true;
+}
+
+PortsGatheringMethod::Ptr DockerDevice::portsGatheringMethod() const
+{
+ return DockerPortsGatheringMethod::Ptr(new DockerPortsGatheringMethod);
+}
+
+DeviceProcessList *DockerDevice::createProcessListModel(QObject *) const
+{
+ return nullptr;
+}
+
+DeviceTester *DockerDevice::createDeviceTester() const
+{
+ return nullptr;
+}
+
+DeviceProcessSignalOperation::Ptr DockerDevice::signalOperation() const
+{
+ return DeviceProcessSignalOperation::Ptr();
+}
+
+DeviceEnvironmentFetcher::Ptr DockerDevice::environmentFetcher() const
+{
+ return DeviceEnvironmentFetcher::Ptr();
+}
+
+FilePath DockerDevice::mapToGlobalPath(const FilePath &pathOnDevice) const
+{
+ if (pathOnDevice.needsDevice()) {
+ // Already correct form, only sanity check it's ours...
+ QTC_CHECK(handlesFile(pathOnDevice));
+ return pathOnDevice;
+ }
+ FilePath result;
+ result.setScheme("docker");
+ result.setHost(d->m_data.imageId);
+ result.setPath(pathOnDevice.path());
+ return result;
+}
+
+bool DockerDevice::handlesFile(const FilePath &filePath) const
+{
+ return filePath.scheme() == "docker" && filePath.host() == d->m_data.imageId;
+}
+
+bool DockerDevice::isExecutableFile(const FilePath &filePath) const
+{
+ QTC_ASSERT(handlesFile(filePath), return false);
+ tryCreateLocalFileAccess();
+ if (hasLocalFileAccess()) {
+ const FilePath localAccess = mapToLocalAccess(filePath);
+ const bool res = localAccess.isExecutableFile();
+ LOG("Executable? " << filePath.toUserOutput() << localAccess.toUserOutput() << res);
+ return res;
+ }
+ const QString path = filePath.toUrl().path();
+ const CommandLine cmd("test", {"-x", path});
+ const int exitCode = d->runSynchronously(cmd);
+ return exitCode == 0;
+}
+
+bool DockerDevice::isReadableFile(const FilePath &filePath) const
+{
+ QTC_ASSERT(handlesFile(filePath), return false);
+ tryCreateLocalFileAccess();
+ if (hasLocalFileAccess()) {
+ const FilePath localAccess = mapToLocalAccess(filePath);
+ const bool res = localAccess.isReadableFile();
+ LOG("ReadableFile? " << filePath.toUserOutput() << localAccess.toUserOutput() << res);
+ return res;
+ }
+ const QString path = filePath.toUrl().path();
+ const CommandLine cmd("test", {"-r", path, "-a", "-f", path});
+ const int exitCode = d->runSynchronously(cmd);
+ return exitCode == 0;
+}
+
+bool DockerDevice::isReadableDirectory(const FilePath &filePath) const
+{
+ QTC_ASSERT(handlesFile(filePath), return false);
+ tryCreateLocalFileAccess();
+ if (hasLocalFileAccess()) {
+ const FilePath localAccess = mapToLocalAccess(filePath);
+ const bool res = localAccess.isReadableDir();
+ LOG("ReadableDirectory? " << filePath.toUserOutput() << localAccess.toUserOutput() << res);
+ return res;
+ }
+ const QString path = filePath.toUrl().path();
+ const CommandLine cmd("test", {"-x", path, "-a", "-d", path});
+ const int exitCode = d->runSynchronously(cmd);
+ return exitCode == 0;
+}
+
+bool DockerDevice::isWritableDirectory(const FilePath &filePath) const
+{
+ QTC_ASSERT(handlesFile(filePath), return false);
+ tryCreateLocalFileAccess();
+ if (hasLocalFileAccess()) {
+ const FilePath localAccess = mapToLocalAccess(filePath);
+ const bool res = localAccess.isReadableDir();
+ LOG("WritableDirectory? " << filePath.toUserOutput() << localAccess.toUserOutput() << res);
+ return res;
+ }
+ const QString path = filePath.toUrl().path();
+ const CommandLine cmd("test", {"-x", path, "-a", "-d", path});
+ const int exitCode = d->runSynchronously(cmd);
+ return exitCode == 0;
+}
+
+bool DockerDevice::createDirectory(const FilePath &filePath) const
+{
+ QTC_ASSERT(handlesFile(filePath), return false);
+ tryCreateLocalFileAccess();
+ if (hasLocalFileAccess()) {
+ const FilePath localAccess = mapToLocalAccess(filePath);
+ const bool res = localAccess.createDir();
+ LOG("CreateDirectory? " << filePath.toUserOutput() << localAccess.toUserOutput() << res);
+ return res;
+ }
+ const QString path = filePath.toUrl().path();
+ const CommandLine cmd("mkdir", {"-p", path});
+ const int exitCode = d->runSynchronously(cmd);
+ return exitCode == 0;
+}
+
+QList<FilePath> DockerDevice::directoryEntries(const FilePath &filePath,
+ const QStringList &nameFilters,
+ QDir::Filters filters) const
+{
+ QTC_ASSERT(handlesFile(filePath), return {});
+ tryCreateLocalFileAccess();
+ if (hasLocalFileAccess()) {
+ const FilePath localAccess = mapToLocalAccess(filePath);
+ const QFileInfoList entryInfoList = QDir(localAccess.toString()).entryInfoList(nameFilters, filters);
+ return Utils::transform(entryInfoList, [this](const QFileInfo &fi) {
+ return mapFromLocalAccess(fi.absoluteFilePath());
+ });
+ }
+ QTC_CHECK(false); // FIXME: Implement
+ return {};
+}
+
+QByteArray DockerDevice::fileContents(const FilePath &filePath, int limit) const
+{
+ QTC_ASSERT(handlesFile(filePath), return {});
+ tryCreateLocalFileAccess();
+ if (hasLocalFileAccess())
+ return mapToLocalAccess(filePath).fileContents(limit);
+
+ QTC_CHECK(false); // FIXME: Implement
+ return {};
+}
+
+void DockerDevice::runProcess(QtcProcess &process) const
+{
+ const QString origWd = process.workingDirectory();
+ const CommandLine origCmd = process.commandLine();
+
+ CommandLine cmd{"docker", {"exec"}};
+ cmd.addArgs({"-w", process.workingDirectory()});
+ cmd.addArg(d->m_container);
+ cmd.addArg(origCmd.executable().path()); // Cut off the docker://.../ bits.
+ cmd.addArgs(origCmd.splitArguments(osType()));
+
+ LOG("Run" << cmd.toUserOutput());
+
+ process.setCommand(cmd);
+ process.start();
+}
+
+Environment DockerDevice::systemEnvironment() const
+{
+ if (d->m_cachedEnviroment.size() == 0)
+ d->fetchSystemEnviroment();
+
+ QTC_CHECK(d->m_cachedEnviroment.size() != 0);
+ return d->m_cachedEnviroment;
+}
+
+void DockerDevicePrivate::fetchSystemEnviroment()
+{
+ SynchronousProcess proc;
+ proc.setCommand({"env", {}});
+
+ proc.runBlocking();
+
+ const QString remoteOutput = proc.stdOut();
+ m_cachedEnviroment = Environment(remoteOutput.split('\n', Qt::SkipEmptyParts), q->osType());
+}
+
+int DockerDevicePrivate::runSynchronously(const CommandLine &cmd) const
+{
+ CommandLine dcmd{"docker", {"exec", m_container}};
+ dcmd.addArgs(cmd);
+
+ QtcProcess proc;
+ proc.setCommand(dcmd);
+ proc.setWorkingDirectory("/tmp");
+ proc.start();
+ proc.waitForFinished();
+
+ LOG("Run sync:" << dcmd.toUserOutput() << " result: " << proc.exitCode());
+ return proc.exitCode();
+}
+
+// Factory
+
+DockerDeviceFactory::DockerDeviceFactory()
+ : IDeviceFactory(Constants::DOCKER_DEVICE_TYPE)
+{
+ setDisplayName(DockerDevice::tr("Docker Device"));
+ setIcon(QIcon());
+ setCanCreate(true);
+ setConstructionFunction([] { return DockerDevice::create({}); });
+}
+
+class DockerImageItem final : public TreeItem, public DockerDeviceData
+{
+public:
+ DockerImageItem() {}
+
+ QVariant data(int column, int role) const final
+ {
+ switch (column) {
+ case 0:
+ if (role == Qt::DisplayRole)
+ return imageId;
+ break;
+ case 1:
+ if (role == Qt::DisplayRole)
+ return repo;
+ break;
+ case 2:
+ if (role == Qt::DisplayRole)
+ return tag;
+ break;
+ case 3:
+ if (role == Qt::DisplayRole)
+ return size;
+ break;
+ }
+
+ return QVariant();
+ }
+};
+
+class DockerDeviceSetupWizard final : public QDialog
+{
+public:
+ DockerDeviceSetupWizard()
+ : QDialog(ICore::dialogParent())
+ {
+ setWindowTitle(tr("Docker Image Selection"));
+ resize(800, 600);
+
+ m_model.setHeader({"Image", "Repository", "Tag", "Size"});
+
+ m_view = new TreeView;
+ m_view->setModel(&m_model);
+ m_view->header()->setStretchLastSection(true);
+ m_view->header()->setSectionResizeMode(QHeaderView::ResizeToContents);
+ m_view->setSelectionBehavior(QAbstractItemView::SelectRows);
+ m_view->setSelectionMode(QAbstractItemView::SingleSelection);
+
+ auto output = new QTextBrowser;
+ output->setEnabled(false);
+ output->setVisible(false);
+
+ auto buttons = new QDialogButtonBox(QDialogButtonBox::Ok | QDialogButtonBox::Cancel,
+ Qt::Horizontal);
+
+ using namespace Layouting;
+ Column {
+ m_view,
+ output,
+ buttons,
+ }.attachTo(this);
+
+ connect(buttons, &QDialogButtonBox::accepted, this, &QDialog::accept);
+ connect(buttons, &QDialogButtonBox::rejected, this, &QDialog::reject);
+ buttons->button(QDialogButtonBox::Ok)->setEnabled(false);
+
+ CommandLine cmd{"docker", {"images", "--format", "{{.ID}}\\t{{.Repository}}\\t{{.Tag}}\\t{{.Size}}"}};
+ output->append(tr("Running \"%1\"\n").arg(cmd.toUserOutput()));
+
+ m_process = new QtcProcess(this);
+ m_process->setCommand(cmd);
+
+ connect(m_process, &QtcProcess::readyReadStandardOutput, [this, output] {
+ const QString out = QString::fromUtf8(m_process->readAllStandardOutput().trimmed());
+ output->append(out);
+ for (const QString &line : out.split('\n')) {
+ const QStringList parts = line.trimmed().split('\t');
+ if (parts.size() != 4) {
+ output->append(tr("Unexpected result: %1").arg(line) + '\n');
+ continue;
+ }
+ auto item = new DockerImageItem;
+ item->imageId = parts.at(0);
+ item->repo = parts.at(1);
+ item->tag = parts.at(2);
+ item->size = parts.at(3);
+ m_model.rootItem()->appendChild(item);
+ }
+ output->append(tr("\nDone."));
+
+ });
+
+ connect(m_process, &Utils::QtcProcess::readyReadStandardError, [this, output] {
+ const QString out = tr("Error: %1").arg(QString::fromUtf8(m_process->readAllStandardError()));
+ output->append(tr("Error: %1").arg(out));
+ });
+
+ connect(m_view->selectionModel(), &QItemSelectionModel::selectionChanged, [this, buttons] {
+ const QModelIndexList selectedRows = m_view->selectionModel()->selectedRows();
+ QTC_ASSERT(selectedRows.size() == 1, return);
+ buttons->button(QDialogButtonBox::Ok)->setEnabled(selectedRows.size() == 1);
+ });
+
+ m_process->start();
+ }
+
+ DockerDevice::Ptr device() const
+ {
+ const QModelIndexList selectedRows = m_view->selectionModel()->selectedRows();
+ QTC_ASSERT(selectedRows.size() == 1, return {});
+ DockerImageItem *item = m_model.itemForIndex(selectedRows.front());
+ QTC_ASSERT(item, return {});
+
+ auto device = DockerDevice::create(*item);
+ device->setupId(IDevice::ManuallyAdded, Utils::Id());
+ device->setType(Constants::DOCKER_DEVICE_TYPE);
+ device->setMachineType(IDevice::Hardware);
+
+ device->d->setupKit();
+ return device;
+ }
+
+public:
+ TreeModel<DockerImageItem> m_model;
+ TreeView *m_view = nullptr;
+ QtcProcess *m_process = nullptr;
+ QString m_selectedId;
+};
+
+IDevice::Ptr DockerDeviceFactory::create() const
+{
+ DockerDeviceSetupWizard wizard;
+ if (wizard.exec() != QDialog::Accepted)
+ return IDevice::Ptr();
+ return wizard.device();
+}
+
+} // Internal
+} // Docker
diff --git a/src/plugins/docker/dockerdevice.h b/src/plugins/docker/dockerdevice.h
new file mode 100644
index 0000000000..ee9b6a90eb
--- /dev/null
+++ b/src/plugins/docker/dockerdevice.h
@@ -0,0 +1,117 @@
+/****************************************************************************
+**
+** Copyright (C) 2021 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of Qt Creator.
+**
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3 as published by the Free Software
+** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-3.0.html.
+**
+****************************************************************************/
+
+#pragma once
+
+#include <projectexplorer/devicesupport/idevice.h>
+#include <projectexplorer/devicesupport/idevicefactory.h>
+#include <projectexplorer/devicesupport/sshdeviceprocess.h>
+
+#include <utils/aspects.h>
+#include <utils/qtcprocess.h>
+
+namespace Docker {
+namespace Internal {
+
+class DockerDeviceData
+{
+public:
+ QString imageId;
+ QString repo;
+ QString tag;
+ QString size;
+};
+
+class DockerDevice : public ProjectExplorer::IDevice
+{
+ Q_DECLARE_TR_FUNCTIONS(Docker::Internal::DockerDevice)
+
+public:
+ using Ptr = QSharedPointer<DockerDevice>;
+ using ConstPtr = QSharedPointer<const DockerDevice>;
+
+ explicit DockerDevice(const DockerDeviceData &data);
+ ~DockerDevice();
+
+ static Ptr create(const DockerDeviceData &data) { return Ptr(new DockerDevice(data)); }
+
+ ProjectExplorer::IDeviceWidget *createWidget() override;
+
+ bool canCreateProcess() const override { return true; }
+ ProjectExplorer::DeviceProcess *createProcess(QObject *parent) const override;
+ bool canAutoDetectPorts() const override;
+ ProjectExplorer::PortsGatheringMethod::Ptr portsGatheringMethod() const override;
+ bool canCreateProcessModel() const override { return false; }
+ ProjectExplorer::DeviceProcessList *createProcessListModel(QObject *parent) const override;
+ bool hasDeviceTester() const override { return false; }
+ ProjectExplorer::DeviceTester *createDeviceTester() const override;
+ ProjectExplorer::DeviceProcessSignalOperation::Ptr signalOperation() const override;
+ ProjectExplorer::DeviceEnvironmentFetcher::Ptr environmentFetcher() const override;
+
+ Utils::FilePath mapToGlobalPath(const Utils::FilePath &pathOnDevice) const override;
+
+ bool handlesFile(const Utils::FilePath &filePath) const override;
+ bool isExecutableFile(const Utils::FilePath &filePath) const override;
+ bool isReadableFile(const Utils::FilePath &filePath) const override;
+ bool isReadableDirectory(const Utils::FilePath &filePath) const override;
+ bool isWritableDirectory(const Utils::FilePath &filePath) const override;
+ bool createDirectory(const Utils::FilePath &filePath) const override;
+ QList<Utils::FilePath> directoryEntries(const Utils::FilePath &filePath,
+ const QStringList &nameFilters,
+ QDir::Filters filters) const override;
+ QByteArray fileContents(const Utils::FilePath &filePath, int limit) const override;
+ void runProcess(Utils::QtcProcess &process) const override;
+
+ Utils::Environment systemEnvironment() const override;
+
+ const DockerDeviceData &data() const;
+
+ void tryCreateLocalFileAccess() const;
+ bool hasLocalFileAccess() const;
+
+ Utils::FilePath mapToLocalAccess(const Utils::FilePath &filePath) const;
+ Utils::FilePath mapFromLocalAccess(const Utils::FilePath &filePath) const;
+ Utils::FilePath mapFromLocalAccess(const QString &filePath) const;
+
+private:
+ void fromMap(const QVariantMap &map) final;
+ QVariantMap toMap() const final;
+
+ class DockerDevicePrivate *d = nullptr;
+ friend class DockerDeviceSetupWizard;
+};
+
+class DockerDeviceFactory final : public ProjectExplorer::IDeviceFactory
+{
+public:
+ DockerDeviceFactory();
+
+ ProjectExplorer::IDevice::Ptr create() const override;
+};
+
+} // Internal
+} // Docker
+
+Q_DECLARE_METATYPE(Docker::Internal::DockerDeviceData)
diff --git a/src/plugins/docker/dockerplugin.cpp b/src/plugins/docker/dockerplugin.cpp
new file mode 100644
index 0000000000..6100c7a9c3
--- /dev/null
+++ b/src/plugins/docker/dockerplugin.cpp
@@ -0,0 +1,79 @@
+/****************************************************************************
+**
+** Copyright (C) 2021 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of Qt Creator.
+**
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3 as published by the Free Software
+** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-3.0.html.
+**
+****************************************************************************/
+
+#include "dockerplugin.h"
+
+#include "dockerconstants.h"
+
+#include "dockerbuildstep.h"
+#include "dockerdevice.h"
+#include "dockerrunconfiguration.h"
+#include "dockersettings.h"
+
+#include <projectexplorer/projectexplorerconstants.h>
+#include <projectexplorer/runcontrol.h>
+
+using namespace Core;
+using namespace ProjectExplorer;
+using namespace Utils;
+
+namespace Docker {
+namespace Internal {
+
+class DockerPluginPrivate
+{
+public:
+ DockerSettings settings;
+ DockerOptionsPage optionsPage{&settings};
+
+ DockerDeviceFactory deviceFactory;
+ DockerContainerRunConfigurationFactory containerRunConfigFactory;
+
+ RunWorkerFactory containerRunWorkerFactory{
+ RunWorkerFactory::make<SimpleTargetRunner>(),
+ {ProjectExplorer::Constants::NORMAL_RUN_MODE},
+ {containerRunConfigFactory.runConfigurationId()}
+ };
+
+ DockerBuildStepFactory buildStepFactory;
+};
+
+DockerPlugin::~DockerPlugin()
+{
+ delete d;
+}
+
+bool DockerPlugin::initialize(const QStringList &arguments, QString *errorString)
+{
+ Q_UNUSED(arguments)
+ Q_UNUSED(errorString)
+
+ d = new DockerPluginPrivate;
+
+ return true;
+}
+
+} // namespace Internal
+} // namespace Docker
diff --git a/src/plugins/mesonprojectmanager/settings/general/generalsettingspage.h b/src/plugins/docker/dockerplugin.h
index 30ebe94b84..a76aad710a 100644
--- a/src/plugins/mesonprojectmanager/settings/general/generalsettingspage.h
+++ b/src/plugins/docker/dockerplugin.h
@@ -1,6 +1,6 @@
/****************************************************************************
**
-** Copyright (C) 2020 Alexis Jeandet.
+** Copyright (C) 2021 The Qt Company Ltd.
** Contact: https://www.qt.io/licensing/
**
** This file is part of Qt Creator.
@@ -25,23 +25,23 @@
#pragma once
-#include <coreplugin/dialogs/ioptionspage.h>
+#include <extensionsystem/iplugin.h>
-#include <QCoreApplication>
-
-namespace MesonProjectManager {
+namespace Docker {
namespace Internal {
-class MesonTools;
-
-class GeneralSettingsPage final : public Core::IOptionsPage
+class DockerPlugin final : public ExtensionSystem::IPlugin
{
- Q_DECLARE_TR_FUNCTIONS(MesonProjectManager::Internal::GeneralSettingsPage)
+ Q_OBJECT
+ Q_PLUGIN_METADATA(IID "org.qt-project.Qt.QtCreatorPlugin" FILE "Docker.json")
+
+private:
+ ~DockerPlugin() final;
+
+ bool initialize(const QStringList &arguments, QString *errorString) final;
-public:
- GeneralSettingsPage();
- void saveAll();
+ class DockerPluginPrivate *d = nullptr;
};
} // namespace Internal
-} // namespace MesonProjectManager
+} // namespace Docker
diff --git a/src/plugins/docker/dockerrunconfiguration.cpp b/src/plugins/docker/dockerrunconfiguration.cpp
new file mode 100644
index 0000000000..c9018ae84b
--- /dev/null
+++ b/src/plugins/docker/dockerrunconfiguration.cpp
@@ -0,0 +1,126 @@
+/****************************************************************************
+**
+** 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 "dockerrunconfiguration.h"
+
+#include "dockerconstants.h"
+#include "dockerdevice.h"
+
+#include <projectexplorer/kitinformation.h>
+#include <projectexplorer/project.h>
+#include <projectexplorer/runconfigurationaspects.h>
+#include <projectexplorer/runcontrol.h>
+#include <projectexplorer/target.h>
+
+#include <utils/stringutils.h>
+
+using namespace ProjectExplorer;
+using namespace Utils;
+
+namespace Docker {
+namespace Internal {
+
+class DockerContainerRunConfiguration : public RunConfiguration
+{
+ Q_DECLARE_TR_FUNCTIONS(Docker::Internal::DockerRunConfiguration)
+
+public:
+ DockerContainerRunConfiguration(Target *target, Id id)
+ : RunConfiguration(target, id)
+ {
+ auto rmOption = addAspect<BoolAspect>();
+ rmOption->setSettingsKey("Docker.RunConfiguration.RmOption");
+ rmOption->setDefaultValue(true);
+ rmOption->setLabelText(tr("Automatically remove the container when it exits"));
+
+ auto ttyOption = addAspect<BoolAspect>();
+ ttyOption->setSettingsKey("Docker.RunConfiguration.TtyOption");
+ ttyOption->setLabelText(tr("Allocate a pseudo-TTY"));
+ ttyOption->setVisible(false); // Not yet.
+
+ auto interactiveOption = addAspect<BoolAspect>();
+ interactiveOption->setSettingsKey("Docker.RunConfiguration.InteractiveOption");
+ interactiveOption->setLabelText(tr("Keep STDIN open even if not attached"));
+ interactiveOption->setVisible(false); // Not yet.
+
+ auto effectiveCommand = addAspect<StringAspect>();
+ effectiveCommand->setLabelText(tr("Effective command call:"));
+ effectiveCommand->setDisplayStyle(StringAspect::TextEditDisplay);
+ effectiveCommand->setReadOnly(true);
+
+ setUpdater([this, effectiveCommand] {
+ IDevice::ConstPtr device = DeviceKitAspect::device(kit());
+ QTC_ASSERT(device, return);
+ DockerDevice::ConstPtr dockerDevice = qSharedPointerCast<const DockerDevice>(device);
+ QTC_ASSERT(dockerDevice, return);
+ const DockerDeviceData &data = dockerDevice->data();
+
+ const Runnable r = runnable();
+ const QStringList dockerRunFlags = r.extraData[Constants::DOCKER_RUN_FLAGS].toStringList();
+
+ CommandLine cmd("docker");
+ cmd.addArg("run");
+ cmd.addArgs(dockerRunFlags);
+ cmd.addArg(data.imageId);
+
+ // FIXME: the global one above is apparently not sufficient.
+ effectiveCommand->setReadOnly(true);
+ effectiveCommand->setValue(cmd.toUserOutput());
+ });
+
+ setRunnableModifier([rmOption, interactiveOption, ttyOption](Runnable &runnable) {
+ QStringList runArgs;
+ if (!rmOption->value())
+ runArgs.append("--rm=false");
+ if (interactiveOption->value())
+ runArgs.append("--interactive");
+ if (ttyOption->value())
+ runArgs.append("--tty");
+ runnable.extraData[Constants::DOCKER_RUN_FLAGS].toStringList();
+ });
+
+ setCommandLineGetter([] {
+ return CommandLine();
+ });
+
+ update();
+ connect(rmOption, &BaseAspect::changed, this, &RunConfiguration::update);
+ }
+
+private:
+ bool isEnabled() const override { return true; }
+};
+
+
+DockerContainerRunConfigurationFactory::DockerContainerRunConfigurationFactory() :
+ FixedRunConfigurationFactory(DockerContainerRunConfiguration::tr("Docker Container"))
+{
+ registerRunConfiguration<DockerContainerRunConfiguration>
+ ("Docker.DockerContainerRunConfiguration");
+ addSupportedTargetDeviceType(Constants::DOCKER_DEVICE_TYPE);
+}
+
+} // Internal
+} // Docker
diff --git a/src/plugins/cvs/settingspage.h b/src/plugins/docker/dockerrunconfiguration.h
index 8e64ec7841..37eef9ba6c 100644
--- a/src/plugins/cvs/settingspage.h
+++ b/src/plugins/docker/dockerrunconfiguration.h
@@ -25,18 +25,17 @@
#pragma once
-#include <coreplugin/dialogs/ioptionspage.h>
+#include <projectexplorer/runconfiguration.h>
-namespace Cvs {
+namespace Docker {
namespace Internal {
-class CvsSettings;
-
-class CvsSettingsPage final : public Core::IOptionsPage
+class DockerContainerRunConfigurationFactory
+ : public ProjectExplorer::FixedRunConfigurationFactory
{
public:
- CvsSettingsPage(const std::function<void()> &onApply, CvsSettings *settings);
+ DockerContainerRunConfigurationFactory();
};
-} // namespace Cvs
-} // namespace Internal
+} // Internal
+} // Docker
diff --git a/src/plugins/docker/dockersettings.cpp b/src/plugins/docker/dockersettings.cpp
new file mode 100644
index 0000000000..8161ba88c3
--- /dev/null
+++ b/src/plugins/docker/dockersettings.cpp
@@ -0,0 +1,135 @@
+/****************************************************************************
+**
+** Copyright (C) 2021 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of Qt Creator.
+**
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3 as published by the Free Software
+** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-3.0.html.
+**
+****************************************************************************/
+
+#include "dockerconstants.h"
+#include "dockersettings.h"
+
+#include <coreplugin/icore.h>
+
+#include <projectexplorer/projectexplorerconstants.h>
+
+#include <utils/layoutbuilder.h>
+#include <utils/qtcprocess.h>
+#include <utils/qtcsettings.h>
+
+using namespace Utils;
+
+namespace Docker {
+namespace Internal {
+
+// DockerSettings
+
+const char SETTINGS_KEY[] = "Docker";
+
+static DockerSettings *theSettings = nullptr;
+
+DockerSettings::DockerSettings()
+{
+ theSettings = this;
+ setAutoApply(false);
+ readSettings(Core::ICore::settings());
+
+ imageListFilter.setSettingsKey("DockerListFilter");
+ imageListFilter.setPlaceHolderText(tr("<filter>"));
+ imageListFilter.setDisplayStyle(StringAspect::LineEditDisplay);
+ imageListFilter.setLabelText(tr("Filter:"));
+
+ imageList.setDisplayStyle(StringAspect::TextEditDisplay);
+ imageList.setLabelText(tr("Images:"));
+
+ connect(&imageListFilter, &BaseAspect::changed, this, &DockerSettings::updateImageList);
+}
+
+DockerSettings *DockerSettings::instance()
+{
+ return theSettings;
+}
+
+void DockerSettings::writeSettings(QSettings *settings) const
+{
+ settings->remove(SETTINGS_KEY);
+ settings->beginGroup(SETTINGS_KEY);
+ forEachAspect([settings](BaseAspect *aspect) {
+ QtcSettings::setValueWithDefault(settings, aspect->settingsKey(),
+ aspect->value(), aspect->defaultValue());
+ });
+ settings->endGroup();
+}
+
+void DockerSettings::updateImageList()
+{
+ QtcProcess process;
+ process.setCommand({"docker", {"search", imageListFilter.value()}});
+
+ const auto finished = QOverload<int, QProcess::ExitStatus>::of(&QProcess::finished);
+ connect(&process, finished, this, [&process, this] {
+ const QString data = QString::fromUtf8(process.readAll());
+ imageList.setValue(data);
+ });
+
+ process.start();
+ process.waitForFinished();
+}
+
+void DockerSettings::readSettings(const QSettings *settings)
+{
+ const QString keyRoot = QString(SETTINGS_KEY) + '/';
+ forEachAspect([settings, keyRoot](BaseAspect *aspect) {
+ QString key = aspect->settingsKey();
+ const QVariant value = settings->value(keyRoot + key, aspect->defaultValue());
+ aspect->setValue(value);
+ });
+}
+
+// DockerOptionsPage
+
+DockerOptionsPage::DockerOptionsPage(DockerSettings *settings)
+{
+ setId(Constants::DOCKER_SETTINGS_ID);
+ setDisplayName(DockerSettings::tr("Docker"));
+ setCategory(ProjectExplorer::Constants::DEVICE_SETTINGS_CATEGORY);
+ setDisplayCategory(QCoreApplication::translate("ProjectExplorer", "Devices"));
+ setCategoryIconPath(":/projectexplorer/images/settingscategory_devices.png");
+ setSettings(settings);
+
+ setLayouter([settings](QWidget *widget) {
+ using namespace Layouting;
+ DockerSettings &s = *settings;
+
+ Column {
+ Group {
+ Title(DockerSettings::tr("Search images on Docker Hub")),
+ Form {
+ s.imageListFilter,
+ s.imageList
+ },
+ },
+ Stretch()
+ }.attachTo(widget);
+ });
+}
+
+} // Internal
+} // Docker
diff --git a/src/plugins/qmlprofiler/qmlprofileroptionspage.h b/src/plugins/docker/dockersettings.h
index 3278de15d7..42470427cb 100644
--- a/src/plugins/qmlprofiler/qmlprofileroptionspage.h
+++ b/src/plugins/docker/dockersettings.h
@@ -1,6 +1,6 @@
/****************************************************************************
**
-** Copyright (C) 2016 The Qt Company Ltd.
+** Copyright (C) 2021 The Qt Company Ltd.
** Contact: https://www.qt.io/licensing/
**
** This file is part of Qt Creator.
@@ -25,24 +25,34 @@
#pragma once
+#include <utils/aspects.h>
+#include <utils/fileutils.h>
+
#include <coreplugin/dialogs/ioptionspage.h>
-#include <QPointer>
-namespace QmlProfiler {
+namespace Docker {
namespace Internal {
-class QmlProfilerOptionsPage final : public Core::IOptionsPage
+class DockerSettings : public Utils::AspectContainer
{
public:
- QmlProfilerOptionsPage();
+ DockerSettings();
+ static DockerSettings *instance();
+
+ void readSettings(const QSettings *settings);
+ void writeSettings(QSettings *settings) const;
+
+ void updateImageList();
- QWidget *widget() override;
- void apply() override;
- void finish() override;
+ Utils::StringAspect imageListFilter;
+ Utils::StringAspect imageList;
+};
-private:
- QPointer<QWidget> m_widget;
+class DockerOptionsPage final : public Core::IOptionsPage
+{
+public:
+ explicit DockerOptionsPage(DockerSettings *settings);
};
} // Internal
-} // QmlProfiler
+} // Docker
diff --git a/src/plugins/fakevim/CMakeLists.txt b/src/plugins/fakevim/CMakeLists.txt
index ddb6f3c1f1..a7c1cf736c 100644
--- a/src/plugins/fakevim/CMakeLists.txt
+++ b/src/plugins/fakevim/CMakeLists.txt
@@ -5,7 +5,6 @@ add_qtc_plugin(FakeVim
fakevim.qrc
fakevimactions.cpp fakevimactions.h
fakevimhandler.cpp fakevimhandler.h
- fakevimoptions.ui
fakevimplugin.cpp fakevimplugin.h
fakevimtr.h
)
diff --git a/src/plugins/fakevim/fakevim.pro b/src/plugins/fakevim/fakevim.pro
index 2ee8c0afbf..9ec458b82e 100644
--- a/src/plugins/fakevim/fakevim.pro
+++ b/src/plugins/fakevim/fakevim.pro
@@ -2,14 +2,15 @@
include(../../qtcreatorplugin.pri)
QT += gui
+
SOURCES += fakevimactions.cpp \
fakevimhandler.cpp \
fakevimplugin.cpp
+
HEADERS += fakevimactions.h \
fakevimhandler.h \
fakevimplugin.h \
fakevimtr.h
-FORMS += fakevimoptions.ui
equals(TEST, 1) {
SOURCES += fakevim_test.cpp
diff --git a/src/plugins/fakevim/fakevim.qbs b/src/plugins/fakevim/fakevim.qbs
index e16041166c..230cd50de0 100644
--- a/src/plugins/fakevim/fakevim.qbs
+++ b/src/plugins/fakevim/fakevim.qbs
@@ -21,7 +21,6 @@ QtcPlugin {
"fakevimactions.h",
"fakevimhandler.cpp",
"fakevimhandler.h",
- "fakevimoptions.ui",
"fakevimplugin.cpp",
"fakevimplugin.h",
"fakevimtr.h",
diff --git a/src/plugins/fakevim/fakevimactions.cpp b/src/plugins/fakevim/fakevimactions.cpp
index 3d549c176c..520bf564f5 100644
--- a/src/plugins/fakevim/fakevimactions.cpp
+++ b/src/plugins/fakevim/fakevimactions.cpp
@@ -31,7 +31,7 @@
// Qt Creator. The idea is to keep this file here in a "clean" state that
// allows easy reuse with any QTextEdit or QPlainTextEdit derived class.
-
+#include <utils/layoutbuilder.h>
#include <utils/qtcassert.h>
#include <QDebug>
@@ -41,168 +41,177 @@ using namespace Utils;
namespace FakeVim {
namespace Internal {
-DummyAction::DummyAction(void *)
+#ifdef FAKEVIM_STANDALONE
+FvBaseAspect::FvBaseAspect()
{
}
-void DummyAction::setValue(const QVariant &value)
+void FvBaseAspect::setValue(const QVariant &value)
{
m_value = value;
}
-QVariant DummyAction::value() const
+QVariant FvBaseAspect::value() const
{
return m_value;
}
-void DummyAction::setDefaultValue(const QVariant &value)
+void FvBaseAspect::setDefaultValue(const QVariant &value)
{
m_defaultValue = value;
+ m_value = value;
}
-QVariant DummyAction::defaultValue() const
+QVariant FvBaseAspect::defaultValue() const
{
return m_defaultValue;
}
-void DummyAction::setSettingsKey(const QString &group, const QString &key)
+void FvBaseAspect::setSettingsKey(const QString &group, const QString &key)
{
m_settingsGroup = group;
m_settingsKey = key;
}
-QString DummyAction::settingsKey() const
+QString FvBaseAspect::settingsKey() const
{
return m_settingsKey;
}
+// unused but kept for compile
+void setAutoApply(bool ) {}
+#endif
+
FakeVimSettings::FakeVimSettings()
{
- // Specific FakeVim settings
- createAction(ConfigReadVimRc, false, "ReadVimRc");
- createAction(ConfigVimRcPath, QString(), "VimRcPath");
+ setAutoApply(false);
+
#ifndef FAKEVIM_STANDALONE
- createAction(ConfigUseFakeVim, false, "UseFakeVim");
- item(ConfigUseFakeVim)->setText(tr("Use Vim-style Editing"));
- item(ConfigReadVimRc)->setText(tr("Read .vimrc"));
- item(ConfigVimRcPath)->setText(tr("Path to .vimrc"));
+ setup(&useFakeVim, false, "UseFakeVim", {}, tr("Use FakeVim"));
#endif
- createAction(ConfigShowMarks, false, "ShowMarks", "sm");
- createAction(ConfigPassControlKey, false, "PassControlKey", "pck");
- createAction(ConfigPassKeys, true, "PassKeys", "pk");
+ // Specific FakeVim settings
+ setup(&readVimRc, false, "ReadVimRc", {}, tr("Read .vimrc from location:"));
+ setup(&vimRcPath, QString(), "VimRcPath", {}, {}); // tr("Path to .vimrc")
+ setup(&showMarks, false, "ShowMarks", "sm", tr("Show position of text marks"));
+ setup(&passControlKey, false, "PassControlKey", "pck", tr("Pass control keys"));
+ setup(&passKeys, true, "PassKeys", "pk", tr("Pass keys in insert mode"));
// Emulated Vsetting
- createAction(ConfigStartOfLine, true, "StartOfLine", "sol");
- createAction(ConfigTabStop, 8, "TabStop", "ts");
- createAction(ConfigSmartTab, false, "SmartTab", "sta");
- createAction(ConfigHlSearch, true, "HlSearch", "hls");
- createAction(ConfigShiftWidth, 8, "ShiftWidth", "sw");
- createAction(ConfigExpandTab, false, "ExpandTab", "et");
- createAction(ConfigAutoIndent, false, "AutoIndent", "ai");
- createAction(ConfigSmartIndent, false, "SmartIndent", "si");
- createAction(ConfigIncSearch, true, "IncSearch", "is");
- createAction(ConfigUseCoreSearch, false, "UseCoreSearch", "ucs");
- createAction(ConfigSmartCase, false, "SmartCase", "scs");
- createAction(ConfigIgnoreCase, false, "IgnoreCase", "ic");
- createAction(ConfigWrapScan, true, "WrapScan", "ws");
- createAction(ConfigTildeOp, false, "TildeOp", "top");
- createAction(ConfigShowCmd, true, "ShowCmd", "sc");
- createAction(ConfigRelativeNumber, false, "RelativeNumber", "rnu");
- createAction(ConfigBlinkingCursor, false, "BlinkingCursor", "bc");
- createAction(ConfigScrollOff, 0, "ScrollOff", "so");
- createAction(ConfigBackspace, QString("indent,eol,start"), "ConfigBackspace", "bs");
- createAction(ConfigIsKeyword, QString("@,48-57,_,192-255,a-z,A-Z"), "IsKeyword", "isk");
- createAction(ConfigClipboard, QString(), "Clipboard", "cb");
- createAction(ConfigFormatOptions, QString(), "formatoptions", "fo");
+ setup(&startOfLine, true, "StartOfLine", "sol", tr("Start of line"));
+ setup(&tabStop, 8, "TabStop", "ts", tr("Tabulator size:"));
+ setup(&smartTab, false, "SmartTab", "sta", tr("Smart tabulators"));
+ setup(&hlSearch, true, "HlSearch", "hls", tr("Highlight search results"));
+ setup(&shiftWidth, 8, "ShiftWidth", "sw", tr("Shift width:"));
+ setup(&expandTab, false, "ExpandTab", "et", tr("Expand tabulators"));
+ setup(&autoIndent, false, "AutoIndent", "ai", tr("Automatic indentation"));
+ setup(&smartIndent, false, "SmartIndent", "si", tr("Smart tabulators"));
+ setup(&incSearch, true, "IncSearch", "is", tr("Incremental search"));
+ setup(&useCoreSearch, false, "UseCoreSearch", "ucs", tr("Use search dialog"));
+ setup(&smartCase, false, "SmartCase", "scs", tr("Use smartcase"));
+ setup(&ignoreCase, false, "IgnoreCase", "ic", tr("Use ignorecase"));
+ setup(&wrapScan, true, "WrapScan", "ws", tr("Use wrapscan"));
+ setup(&tildeOp, false, "TildeOp", "top", tr("Use tildeop"));
+ setup(&showCmd, true, "ShowCmd", "sc", tr("Show partial command"));
+ setup(&relativeNumber, false, "RelativeNumber", "rnu", tr("Show line numbers relative to cursor"));
+ setup(&blinkingCursor, false, "BlinkingCursor", "bc", tr("Blinking cursor"));
+ setup(&scrollOff, 0, "ScrollOff", "so", tr("Scroll offset:"));
+ setup(&backspace, "indent,eol,start",
+ "Backspace", "bs", tr("Backspace:"));
+ setup(&isKeyword, "@,48-57,_,192-255,a-z,A-Z",
+ "IsKeyword", "isk", tr("Keyword characters:"));
+ setup(&clipboard, {}, "Clipboard", "cb", tr(""));
+ setup(&formatOptions, {}, "formatoptions", "fo", tr(""));
// Emulated plugins
- createAction(ConfigEmulateVimCommentary, false, "commentary");
- createAction(ConfigEmulateReplaceWithRegister, false, "ReplaceWithRegister");
- createAction(ConfigEmulateExchange, false, "exchange");
- createAction(ConfigEmulateArgTextObj, false, "argtextobj");
- createAction(ConfigEmulateSurround, false, "surround");
-}
+ setup(&emulateVimCommentary, false, "commentary", {}, "vim-commentary");
+ setup(&emulateReplaceWithRegister, false, "ReplaceWithRegister", {}, "ReplaceWithRegister");
+ setup(&emulateExchange, false, "exchange", {}, "vim-exchange");
+ setup(&emulateArgTextObj, false, "argtextobj", {}, "argtextobj.vim");
+ setup(&emulateSurround, false, "surround", {}, "vim-surround");
-FakeVimSettings::~FakeVimSettings()
-{
- qDeleteAll(m_items);
-}
+ // Some polish
+ useFakeVim.setDisplayName(tr("Use Vim-style Editing"));
-void FakeVimSettings::insertItem(int code, FakeVimAction *item,
- const QString &longName, const QString &shortName)
-{
- QTC_ASSERT(!m_items.contains(code), qDebug() << code; return);
- m_items[code] = item;
- if (!longName.isEmpty()) {
- m_nameToCode[longName] = code;
- m_codeToName[code] = longName;
- }
- if (!shortName.isEmpty())
- m_nameToCode[shortName] = code;
-}
+ relativeNumber.setToolTip(tr("Displays line numbers relative to the line containing "
+ "text cursor."));
-void FakeVimSettings::readSettings(QSettings *settings)
-{
- foreach (FakeVimAction *item, m_items)
- item->readSettings(settings);
-}
+ passControlKey.setToolTip(tr("Does not interpret key sequences like Ctrl-S in FakeVim "
+ "but handles them as regular shortcuts. This gives easier access to core functionality "
+ "at the price of losing some features of FakeVim."));
-void FakeVimSettings::writeSettings(QSettings *settings)
-{
- foreach (FakeVimAction *item, m_items)
- item->writeSettings(settings);
-}
+ passKeys.setToolTip(tr("Does not interpret some key presses in insert mode so that "
+ "code can be properly completed and expanded."));
-FakeVimAction *FakeVimSettings::item(int code)
-{
- QTC_ASSERT(m_items.value(code, 0), qDebug() << "CODE: " << code; return nullptr);
- return m_items.value(code, 0);
+ tabStop.setToolTip(tr("Vim tabstop option."));
+
+#ifndef FAKEVIM_STANDALONE
+ backspace.setDisplayStyle(FvStringAspect::LineEditDisplay);
+ isKeyword.setDisplayStyle(FvStringAspect::LineEditDisplay);
+
+ const QString vimrcDefault = QLatin1String(HostOsInfo::isAnyUnixHost()
+ ? "$HOME/.vimrc" : "%USERPROFILE%\\_vimrc");
+ vimRcPath.setExpectedKind(PathChooser::File);
+ vimRcPath.setToolTip(tr("Keep empty to use the default path, i.e. "
+ "%USERPROFILE%\\_vimrc on Windows, ~/.vimrc otherwise."));
+ vimRcPath.setPlaceHolderText(tr("Default: %1").arg(vimrcDefault));
+ vimRcPath.setDisplayStyle(FvStringAspect::PathChooserDisplay);
+#endif
}
-FakeVimAction *FakeVimSettings::item(const QString &name)
+FakeVimSettings::~FakeVimSettings() = default;
+
+FvBaseAspect *FakeVimSettings::item(const QString &name)
{
- return m_items.value(m_nameToCode.value(name, -1), 0);
+ return m_nameToAspect.value(name, nullptr);
}
QString FakeVimSettings::trySetValue(const QString &name, const QString &value)
{
- int code = m_nameToCode.value(name, -1);
- if (code == -1)
+ FvBaseAspect *aspect = m_nameToAspect.value(name, nullptr);
+ if (!aspect)
return tr("Unknown option: %1").arg(name);
- if (code == ConfigTabStop || code == ConfigShiftWidth) {
+ if (aspect == &tabStop || aspect == &shiftWidth) {
if (value.toInt() <= 0)
return tr("Argument must be positive: %1=%2")
.arg(name).arg(value);
}
- FakeVimAction *act = item(code);
- if (!act)
- return tr("Unknown option: %1").arg(name);
- act->setValue(value);
+ aspect->setValue(value);
return QString();
}
-void FakeVimSettings::createAction(int code, const QVariant &value,
- const QString &settingsKey,
- const QString &shortKey)
+void FakeVimSettings::setup(FvBaseAspect *aspect,
+ const QVariant &value,
+ const QString &settingsKey,
+ const QString &shortName,
+ const QString &labelText)
{
- auto item = new FakeVimAction(nullptr);
- item->setValue(value);
- item->setSettingsKey("FakeVim", settingsKey);
- item->setDefaultValue(value);
- item->setCheckable(value.canConvert<bool>());
- insertItem(code, item, settingsKey.toLower(), shortKey);
+ aspect->setSettingsKey("FakeVim", settingsKey);
+ aspect->setDefaultValue(value);
+#ifndef FAKEVIM_STANDALONE
+ aspect->setLabelText(labelText);
+ aspect->setAutoApply(false);
+ registerAspect(aspect);
+
+ if (auto boolAspect = dynamic_cast<FvBoolAspect *>(aspect))
+ boolAspect->setLabelPlacement(FvBoolAspect::LabelPlacement::AtCheckBoxWithoutDummyLabel);
+#else
+ Q_UNUSED(labelText)
+#endif
+
+ const QString longName = settingsKey.toLower();
+ if (!longName.isEmpty()) {
+ m_nameToAspect[longName] = aspect;
+ m_aspectToName[aspect] = longName;
+ }
+ if (!shortName.isEmpty())
+ m_nameToAspect[shortName] = aspect;
}
-FakeVimSettings *theFakeVimSettings()
+FakeVimSettings *fakeVimSettings()
{
static FakeVimSettings s;
return &s;
}
-FakeVimAction *theFakeVimSetting(int code)
-{
- return theFakeVimSettings()->item(code);
-}
-
} // namespace Internal
} // namespace FakeVim
diff --git a/src/plugins/fakevim/fakevimactions.h b/src/plugins/fakevim/fakevimactions.h
index 419232aeb8..69131c7669 100644
--- a/src/plugins/fakevim/fakevimactions.h
+++ b/src/plugins/fakevim/fakevimactions.h
@@ -26,23 +26,25 @@
#pragma once
#ifndef FAKEVIM_STANDALONE
-# include <utils/savedaction.h>
+# include <utils/aspects.h>
#endif
#include <QCoreApplication>
#include <QHash>
#include <QObject>
#include <QString>
-#include <QSettings>
#include <QVariant>
namespace FakeVim {
namespace Internal {
-class DummyAction
+#ifdef FAKEVIM_STANDALONE
+class FvBaseAspect
{
public:
- DummyAction(void *parent);
+ FvBaseAspect();
+ virtual ~FvBaseAspect() {}
+
void setValue(const QVariant &value);
QVariant value() const;
void setDefaultValue(const QVariant &value);
@@ -50,105 +52,121 @@ public:
void setSettingsKey(const QString &group, const QString &key);
QString settingsKey() const;
void setCheckable(bool) {}
+ void setDisplayName(const QString &) {}
+ void setToolTip(const QString &) {}
- void readSettings(QSettings *) {}
- void writeSettings(QSettings *) {}
-
+private:
QVariant m_value;
QVariant m_defaultValue;
QString m_settingsGroup;
QString m_settingsKey;
};
-#ifdef FAKEVIM_STANDALONE
-using FakeVimAction = DummyAction;
+class FvBoolAspect : public FvBaseAspect
+{
+public:
+ bool value() const { return FvBaseAspect::value().toBool(); }
+};
+
+class FvIntegerAspect : public FvBaseAspect
+{
+public:
+ qint64 value() const { return FvBaseAspect::value().toLongLong(); }
+};
+
+class FvStringAspect : public FvBaseAspect
+{
+public:
+ QString value() const { return FvBaseAspect::value().toString(); }
+};
+
+class FvAspectContainer : public FvBaseAspect
+{
+public:
+};
+
#else
-using FakeVimAction = Utils::SavedAction;
+
+using FvAspectContainer = Utils::AspectContainer;
+using FvBaseAspect = Utils::BaseAspect;
+using FvBoolAspect = Utils::BoolAspect;
+using FvIntegerAspect = Utils::IntegerAspect;
+using FvStringAspect = Utils::StringAspect;
+
#endif
-enum FakeVimSettingsCode
+class FakeVimSettings final : public FvAspectContainer
{
- ConfigUseFakeVim,
- ConfigReadVimRc,
- ConfigVimRcPath,
-
- ConfigStartOfLine,
- ConfigHlSearch,
- ConfigTabStop,
- ConfigSmartTab,
- ConfigShiftWidth,
- ConfigExpandTab,
- ConfigAutoIndent,
- ConfigSmartIndent,
-
- ConfigIncSearch,
- ConfigUseCoreSearch,
- ConfigSmartCase,
- ConfigIgnoreCase,
- ConfigWrapScan,
+ Q_DECLARE_TR_FUNCTIONS(FakeVim)
+
+public:
+ FakeVimSettings();
+ ~FakeVimSettings();
+
+ FvBaseAspect *item(const QString &name);
+ QString trySetValue(const QString &name, const QString &value);
+
+ FvBoolAspect useFakeVim;
+ FvBoolAspect readVimRc;
+ FvStringAspect vimRcPath;
+
+ FvBoolAspect startOfLine;
+ FvIntegerAspect tabStop;
+ FvBoolAspect hlSearch;
+ FvBoolAspect smartTab;
+ FvIntegerAspect shiftWidth;
+ FvBoolAspect expandTab;
+ FvBoolAspect autoIndent;
+ FvBoolAspect smartIndent;
+
+ FvBoolAspect incSearch;
+ FvBoolAspect useCoreSearch;
+ FvBoolAspect smartCase;
+ FvBoolAspect ignoreCase;
+ FvBoolAspect wrapScan;
// command ~ behaves as g~
- ConfigTildeOp,
+ FvBoolAspect tildeOp;
// indent allow backspacing over autoindent
// eol allow backspacing over line breaks (join lines)
// start allow backspacing over the start of insert; CTRL-W and CTRL-U
// stop once at the start of insert.
- ConfigBackspace,
+ FvStringAspect backspace;
// @,48-57,_,192-255
- ConfigIsKeyword,
+ FvStringAspect isKeyword;
// other actions
- ConfigShowMarks,
- ConfigPassControlKey,
- ConfigPassKeys,
- ConfigClipboard,
- ConfigShowCmd,
- ConfigScrollOff,
- ConfigRelativeNumber,
- ConfigFormatOptions,
+ FvBoolAspect showMarks;
+ FvBoolAspect passControlKey;
+ FvBoolAspect passKeys;
+ FvStringAspect clipboard;
+ FvBoolAspect showCmd;
+ FvIntegerAspect scrollOff;
+ FvBoolAspect relativeNumber;
+ FvStringAspect formatOptions;
// Plugin emulation
- ConfigEmulateVimCommentary,
- ConfigEmulateReplaceWithRegister,
- ConfigEmulateExchange,
- ConfigEmulateArgTextObj,
- ConfigEmulateSurround,
-
- ConfigBlinkingCursor
-};
-
-class FakeVimSettings
-{
- Q_DECLARE_TR_FUNCTIONS(FakeVim)
-
-public:
- FakeVimSettings();
- ~FakeVimSettings();
- void insertItem(int code, FakeVimAction *item,
- const QString &longname = QString(),
- const QString &shortname = QString());
-
- FakeVimAction *item(int code);
- FakeVimAction *item(const QString &name);
- QString trySetValue(const QString &name, const QString &value);
+ FvBoolAspect emulateVimCommentary;
+ FvBoolAspect emulateReplaceWithRegister;
+ FvBoolAspect emulateExchange;
+ FvBoolAspect emulateArgTextObj;
+ FvBoolAspect emulateSurround;
- void readSettings(QSettings *settings);
- void writeSettings(QSettings *settings);
+ FvBoolAspect blinkingCursor;
private:
- void createAction(int code, const QVariant &value,
- const QString &settingsKey = QString(),
- const QString &shortKey = QString());
+ void setup(FvBaseAspect *aspect, const QVariant &value,
+ const QString &settingsKey,
+ const QString &shortName,
+ const QString &label);
- QHash<int, FakeVimAction *> m_items;
- QHash<QString, int> m_nameToCode;
- QHash<int, QString> m_codeToName;
+ QHash<QString, FvBaseAspect *> m_nameToAspect;
+ QHash<FvBaseAspect *, QString> m_aspectToName;
};
-FakeVimSettings *theFakeVimSettings();
-FakeVimAction *theFakeVimSetting(int code);
+FakeVimSettings *fakeVimSettings();
} // namespace Internal
} // namespace FakeVim
diff --git a/src/plugins/fakevim/fakevimhandler.cpp b/src/plugins/fakevim/fakevimhandler.cpp
index a00d43a6fe..0ced6f42f2 100644
--- a/src/plugins/fakevim/fakevimhandler.cpp
+++ b/src/plugins/fakevim/fakevimhandler.cpp
@@ -289,21 +289,6 @@ QDebug operator<<(QDebug ts, const CursorPosition &pos)
}
// vi style configuration
-static QVariant config(int code)
-{
- return theFakeVimSetting(code)->value();
-}
-
-static bool hasConfig(int code)
-{
- return config(code).toBool();
-}
-
-static bool hasConfig(int code, const QString &value)
-{
- return config(code).toString().contains(value);
-}
-
class Mark
{
@@ -447,8 +432,8 @@ static QRegularExpression vimPatternToQtPattern(const QString &needle)
*/
// FIXME: Option smartcase should be used only if search was typed by user.
- const bool ignoreCaseOption = hasConfig(ConfigIgnoreCase);
- const bool smartCaseOption = hasConfig(ConfigSmartCase);
+ const bool ignoreCaseOption = fakeVimSettings()->ignoreCase.value();
+ const bool smartCaseOption = fakeVimSettings()->smartCase.value();
const bool initialIgnoreCase = ignoreCaseOption
&& !(smartCaseOption && needle.contains(QRegularExpression("[A-Z]")));
@@ -2448,6 +2433,8 @@ public:
bool surroundUpperCaseS; // True for yS and cS, false otherwise
QString surroundFunction; // Used for storing the function name provided to ys{motion}f
} g;
+
+ FakeVimSettings &s = *fakeVimSettings();
};
FakeVimHandler::Private::GlobalData FakeVimHandler::Private::g;
@@ -2586,7 +2573,7 @@ void FakeVimHandler::Private::leaveFakeVim(bool needUpdate)
// The command might have destroyed the editor.
if (m_textedit || m_plaintextedit) {
- if (hasConfig(ConfigShowMarks))
+ if (s.showMarks.value())
updateSelection();
updateMiniBuffer();
@@ -2635,7 +2622,7 @@ bool FakeVimHandler::Private::wantsOverride(QKeyEvent *ev)
// We are interested in overriding most Ctrl key combinations.
if (isOnlyControlModifier(mods)
- && !config(ConfigPassControlKey).toBool()
+ && !s.passControlKey.value()
&& ((key >= Key_A && key <= Key_Z && key != Key_K)
|| key == Key_BracketLeft || key == Key_BracketRight)) {
// Ctrl-K is special as it is the Core's default notion of Locator
@@ -2845,7 +2832,7 @@ void FakeVimHandler::Private::ensureCursorVisible()
void FakeVimHandler::Private::updateEditor()
{
- setTabSize(config(ConfigTabStop).toInt());
+ setTabSize(s.tabStop.value());
setupCharClass();
}
@@ -3118,7 +3105,7 @@ void FakeVimHandler::Private::stopIncrementalFind()
void FakeVimHandler::Private::updateFind(bool isComplete)
{
- if (!isComplete && !hasConfig(ConfigIncSearch))
+ if (!isComplete && !s.incSearch.value())
return;
g.currentMessage.clear();
@@ -3220,7 +3207,7 @@ void FakeVimHandler::Private::pushUndoState(bool overwrite)
pos = firstPositionInLine(lineForPosition(pos));
else if (isVisualBlockMode())
pos = blockAt(pos).position() + qMin(columnAt(anchor()), columnAt(position()));
- } else if (g.movetype == MoveLineWise && hasConfig(ConfigStartOfLine)) {
+ } else if (g.movetype == MoveLineWise && s.startOfLine.value()) {
QTextCursor tc = m_cursor;
if (g.submode == ShiftLeftSubMode || g.submode == ShiftRightSubMode
|| g.submode == IndentSubMode) {
@@ -3680,8 +3667,7 @@ void FakeVimHandler::Private::finishMovement(const QString &dotCommandMovement)
return;
} else if (g.submode == ExchangeSubMode) {
exchangeRange(currentRange());
- } else if (g.submode == ReplaceWithRegisterSubMode
- && hasConfig(ConfigEmulateReplaceWithRegister)) {
+ } else if (g.submode == ReplaceWithRegisterSubMode && s.emulateReplaceWithRegister.value()) {
pushUndoState(false);
beginEditBlock();
replaceWithRegister(currentRange());
@@ -3794,7 +3780,7 @@ void FakeVimHandler::Private::clearCurrentMode()
void FakeVimHandler::Private::updateSelection()
{
QList<QTextEdit::ExtraSelection> selections = m_extraSelections;
- if (hasConfig(ConfigShowMarks)) {
+ if (s.showMarks.value()) {
for (auto it = m_buffer->marks.cbegin(), end = m_buffer->marks.cend(); it != end; ++it) {
QTextEdit::ExtraSelection sel;
sel.cursor = m_cursor;
@@ -3813,7 +3799,7 @@ void FakeVimHandler::Private::updateSelection()
void FakeVimHandler::Private::updateHighlights()
{
- if (hasConfig(ConfigUseCoreSearch) || !hasConfig(ConfigHlSearch) || g.highlightsCleared) {
+ if (s.useCoreSearch.value() || !s.hlSearch.value() || g.highlightsCleared) {
if (m_highlighted.isEmpty())
return;
m_highlighted.clear();
@@ -3860,7 +3846,7 @@ void FakeVimHandler::Private::updateMiniBuffer()
} else if (!g.mapStates.isEmpty() && !g.mapStates.last().silent) {
// Do not reset previous message when after running a mapped command.
return;
- } else if (g.mode == CommandMode && !g.currentCommand.isEmpty() && hasConfig(ConfigShowCmd)) {
+ } else if (g.mode == CommandMode && !g.currentCommand.isEmpty() && s.showCmd.value()) {
msg = g.currentCommand;
messageLevel = MessageShowCmd;
} else if (g.mode == CommandMode && isVisualMode()) {
@@ -3967,7 +3953,7 @@ bool FakeVimHandler::Private::handleCommandSubSubMode(const Input &input)
handled = selectBlockTextObject(g.subsubdata.is('i'), '{', '}');
else if (input.is('"') || input.is('\'') || input.is('`'))
handled = selectQuotedStringTextObject(g.subsubdata.is('i'), input.asChar());
- else if (input.is('a') && hasConfig(ConfigEmulateArgTextObj))
+ else if (input.is('a') && s.emulateArgTextObj.value())
handled = selectArgumentTextObject(g.subsubdata.is('i'));
else
handled = false;
@@ -4110,7 +4096,7 @@ bool FakeVimHandler::Private::handleMovement(const Input &input)
g.subsubmode = NoSubSubMode;
} else if (input.is('/') || input.is('?')) {
g.lastSearchForward = input.is('/');
- if (hasConfig(ConfigUseCoreSearch)) {
+ if (s.useCoreSearch.value()) {
// re-use the core dialog.
g.findPending = true;
m_findStartPosition = position();
@@ -4285,7 +4271,7 @@ bool FakeVimHandler::Private::handleMovement(const Input &input)
m_cursor = EDITOR(cursorForPosition(QPoint(0, EDITOR(height()) / 2)));
handleStartOfLine();
} else if (input.is('n') || input.is('N')) {
- if (hasConfig(ConfigUseCoreSearch)) {
+ if (s.useCoreSearch.value()) {
bool forward = (input.is('n')) ? g.lastSearchForward : !g.lastSearchForward;
int pos = position();
q->findNextRequested(!forward);
@@ -4374,7 +4360,7 @@ EventResult FakeVimHandler::Private::handleCommandMode(const Input &input)
handled = handleNoSubMode(input);
} else if (g.submode == ExchangeSubMode) {
handled = handleExchangeSubMode(input);
- } else if (g.submode == ChangeSubMode && input.is('x') && hasConfig(ConfigEmulateExchange)) {
+ } else if (g.submode == ChangeSubMode && input.is('x') && s.emulateExchange.value()) {
// Exchange submode is "cx", so we need to switch over from ChangeSubMode here
g.submode = ExchangeSubMode;
handled = true;
@@ -4384,15 +4370,15 @@ EventResult FakeVimHandler::Private::handleCommandMode(const Input &input)
} else if (g.submode == AddSurroundingSubMode) {
handled = handleAddSurroundingSubMode(input);
} else if (g.submode == ChangeSubMode && (input.is('s') || input.is('S'))
- && hasConfig(ConfigEmulateSurround)) {
+ && s.emulateSurround.value()) {
g.submode = ChangeSurroundingSubMode;
g.surroundUpperCaseS = input.is('S');
handled = true;
- } else if (g.submode == DeleteSubMode && input.is('s') && hasConfig(ConfigEmulateSurround)) {
+ } else if (g.submode == DeleteSubMode && input.is('s') && s.emulateSurround.value()) {
g.submode = DeleteSurroundingSubMode;
handled = true;
} else if (g.submode == YankSubMode && (input.is('s') || input.is('S'))
- && hasConfig(ConfigEmulateSurround)) {
+ && s.emulateSurround.value()) {
g.submode = AddSurroundingSubMode;
g.movetype = MoveInclusive;
g.surroundUpperCaseS = input.is('S');
@@ -4401,10 +4387,10 @@ EventResult FakeVimHandler::Private::handleCommandMode(const Input &input)
|| g.submode == DeleteSubMode
|| g.submode == YankSubMode) {
handled = handleChangeDeleteYankSubModes(input);
- } else if (g.submode == CommentSubMode && hasConfig(ConfigEmulateVimCommentary)) {
+ } else if (g.submode == CommentSubMode && s.emulateVimCommentary.value()) {
handled = handleCommentSubMode(input);
} else if (g.submode == ReplaceWithRegisterSubMode
- && hasConfig(ConfigEmulateReplaceWithRegister)) {
+ && s.emulateReplaceWithRegister.value()) {
handled = handleReplaceWithRegisterSubMode(input);
} else if (g.submode == ReplaceSubMode) {
handled = handleReplaceSubMode(input);
@@ -4547,7 +4533,7 @@ bool FakeVimHandler::Private::handleNoSubMode(const Input &input)
setTargetColumn();
} else if (input.isControl('a')) {
changeNumberTextObject(count());
- } else if (g.gflag && input.is('c') && hasConfig(ConfigEmulateVimCommentary)) {
+ } else if (g.gflag && input.is('c') && s.emulateVimCommentary.value()) {
if (isVisualMode()) {
pushUndoState();
@@ -4572,7 +4558,7 @@ bool FakeVimHandler::Private::handleNoSubMode(const Input &input)
pushUndoState();
setAnchor();
}
- } else if (g.gflag && input.is('r') && hasConfig(ConfigEmulateReplaceWithRegister)) {
+ } else if (g.gflag && input.is('r') && s.emulateReplaceWithRegister.value()) {
g.submode = ReplaceWithRegisterSubMode;
if (isVisualMode()) {
dotCommand = visualDotCommand() + QString::number(count()) + "gr";
@@ -4731,7 +4717,7 @@ bool FakeVimHandler::Private::handleNoSubMode(const Input &input)
int repeat = count();
while (--repeat >= 0)
redo();
- } else if (input.is('S') && isVisualMode() && hasConfig(ConfigEmulateSurround)) {
+ } else if (input.is('S') && isVisualMode() && s.emulateSurround.value()) {
g.submode = AddSurroundingSubMode;
g.subsubmode = SurroundSubSubMode;
} else if (input.is('s')) {
@@ -4816,7 +4802,7 @@ bool FakeVimHandler::Private::handleNoSubMode(const Input &input)
if (isVisualMode()) {
leaveVisualMode();
finishMovement();
- } else if (g.gflag || (g.submode == InvertCaseSubMode && hasConfig(ConfigTildeOp))) {
+ } else if (g.gflag || (g.submode == InvertCaseSubMode && s.tildeOp.value())) {
if (atEndOfLine())
moveLeft();
setAnchor();
@@ -5462,15 +5448,15 @@ void FakeVimHandler::Private::handleInsertMode(const Input &input)
if (!handleInsertInEditor(Input(Qt::Key_Backspace, Qt::NoModifier))) {
joinPreviousEditBlock();
if (!m_buffer->lastInsertion.isEmpty()
- || hasConfig(ConfigBackspace, "start")
- || hasConfig(ConfigBackspace, "2")) {
+ || s.backspace.value().contains("start")
+ || s.backspace.value().contains("2")) {
const int line = cursorLine() + 1;
const Column col = cursorColumn();
QString data = lineContents(line);
const Column ind = indentation(data);
if (col.logical <= ind.logical && col.logical
&& startsWithWhitespace(data, col.physical)) {
- const int ts = config(ConfigTabStop).toInt();
+ const int ts = s.tabStop.value();
const int newl = col.logical - 1 - (col.logical - 1) % ts;
const QString prefix = tabExpand(newl);
setLineContents(line, prefix + data.mid(col.physical));
@@ -5495,8 +5481,8 @@ void FakeVimHandler::Private::handleInsertMode(const Input &input)
movePageUp();
} else if (input.isKey(Key_Tab)) {
m_buffer->insertState.insertingSpaces = true;
- if (hasConfig(ConfigExpandTab)) {
- const int ts = config(ConfigTabStop).toInt();
+ if (s.expandTab.value()) {
+ const int ts = s.tabStop.value();
const int col = logicalCursorColumn();
QString str = QString(ts - col % ts, ' ');
insertText(str);
@@ -5506,8 +5492,8 @@ void FakeVimHandler::Private::handleInsertMode(const Input &input)
m_buffer->insertState.insertingSpaces = false;
} else if (input.isControl('d')) {
// remove one level of indentation from the current line
- int shift = config(ConfigShiftWidth).toInt();
- int tab = config(ConfigTabStop).toInt();
+ const int shift = s.shiftWidth.value();
+ const int tab = s.tabStop.value();
int line = cursorLine() + 1;
int pos = firstPositionInLine(line);
QString text = lineContents(line);
@@ -5550,7 +5536,7 @@ void FakeVimHandler::Private::insertInInsertMode(const QString &text)
{
joinPreviousEditBlock();
insertText(text);
- if (hasConfig(ConfigSmartIndent) && isElectricCharacter(text.at(0))) {
+ if (s.smartIndent.value() && isElectricCharacter(text.at(0))) {
const QString leftText = block().text()
.left(position() - 1 - block().position());
if (leftText.simplified().isEmpty()) {
@@ -6179,8 +6165,7 @@ bool FakeVimHandler::Private::handleExSetCommand(const ExCommand &cmd)
if (cmd.args.contains('=')) {
// Non-boolean config to set.
int p = cmd.args.indexOf('=');
- QString error = theFakeVimSettings()
- ->trySetValue(cmd.args.left(p), cmd.args.mid(p + 1));
+ QString error = s.trySetValue(cmd.args.left(p), cmd.args.mid(p + 1));
if (!error.isEmpty())
showMessage(MessageError, error);
} else {
@@ -6195,7 +6180,7 @@ bool FakeVimHandler::Private::handleExSetCommand(const ExCommand &cmd)
if (negateOption)
optionName.remove(0, 2);
- FakeVimAction *act = theFakeVimSettings()->item(optionName);
+ FvBaseAspect *act = s.item(optionName);
if (!act) {
showMessage(MessageError, Tr::tr("Unknown option:") + ' ' + cmd.args);
} else if (act->defaultValue().type() == QVariant::Bool) {
@@ -6322,7 +6307,7 @@ bool FakeVimHandler::Private::handleExMoveCommand(const ExCommand &cmd)
if (!insertAtEnd)
moveUp(1);
- if (hasConfig(ConfigStartOfLine))
+ if (s.startOfLine.value())
moveToFirstNonBlankOnLine();
if (lastAnchor.line >= startLine && lastAnchor.line <= endLine)
@@ -6795,7 +6780,7 @@ QTextCursor FakeVimHandler::Private::search(const SearchData &sd, int startPos,
}
if (tc.isNull()) {
- if (hasConfig(ConfigWrapScan)) {
+ if (s.wrapScan.value()) {
tc = QTextCursor(document());
tc.movePosition(sd.forward ? StartOfDocument : EndOfDocument);
if (sd.forward)
@@ -6955,10 +6940,10 @@ void FakeVimHandler::Private::shiftRegionRight(int repeat)
std::swap(beginLine, endLine);
targetPos = position();
}
- if (hasConfig(ConfigStartOfLine))
+ if (s.startOfLine.value())
targetPos = firstPositionInLine(beginLine);
- const int sw = config(ConfigShiftWidth).toInt();
+ const int sw = s.shiftWidth.value();
g.movetype = MoveLineWise;
beginEditBlock();
QTextBlock block = document()->findBlockByLineNumber(beginLine - 1);
@@ -7107,7 +7092,7 @@ void FakeVimHandler::Private::setupCharClass()
const QChar c = QLatin1Char(i);
m_charClass[i] = c.isSpace() ? 0 : 1;
}
- const QString conf = config(ConfigIsKeyword).toString();
+ const QString conf = s.isKeyword.value();
for (const QString &part : conf.split(',')) {
if (part.contains('-')) {
const int from = someInt(part.section('-', 0, 0));
@@ -7296,7 +7281,7 @@ int FakeVimHandler::Private::physicalCursorColumn() const
int FakeVimHandler::Private::physicalToLogicalColumn
(const int physical, const QString &line) const
{
- const int ts = config(ConfigTabStop).toInt();
+ const int ts = s.tabStop.value();
int p = 0;
int logical = 0;
while (p < physical) {
@@ -7317,7 +7302,7 @@ int FakeVimHandler::Private::physicalToLogicalColumn
int FakeVimHandler::Private::logicalToPhysicalColumn
(const int logical, const QString &line) const
{
- const int ts = config(ConfigTabStop).toInt();
+ const int ts = s.tabStop.value();
int physical = 0;
for (int l = 0; l < logical && physical < line.size(); ++physical) {
QChar c = line.at(physical);
@@ -7331,7 +7316,7 @@ int FakeVimHandler::Private::logicalToPhysicalColumn
int FakeVimHandler::Private::windowScrollOffset() const
{
- return qMin(theFakeVimSetting(ConfigScrollOff)->value().toInt(), linesOnScreen() / 2);
+ return qMin(static_cast<int>(s.scrollOff.value()), linesOnScreen() / 2);
}
int FakeVimHandler::Private::logicalCursorColumn() const
@@ -7595,7 +7580,7 @@ void FakeVimHandler::Private::transformText(const Range &range, const Transforma
void FakeVimHandler::Private::insertText(QTextCursor &tc, const QString &text)
{
- if (hasConfig(ConfigPassKeys)) {
+ if (s.passKeys.value()) {
if (tc.hasSelection() && text.isEmpty()) {
QKeyEvent event(QEvent::KeyPress, Qt::Key_Delete, Qt::NoModifier, QString());
passEventToEditor(event, tc);
@@ -7732,7 +7717,8 @@ void FakeVimHandler::Private::surroundCurrentRange(const Input &input, const QSt
leaveVisualMode();
if (dotCommand.isEmpty()) { // i.e. we came from normal mode
- dotCommand = dotCommandFromSubMode(g.submode) + (g.surroundUpperCaseS ? "S" : "s")
+ dotCommand = dotCommandFromSubMode(g.submode)
+ + QLatin1Char(g.surroundUpperCaseS ? 'S' : 's')
+ g.dotCommand + input.asChar();
}
@@ -7937,7 +7923,7 @@ void FakeVimHandler::Private::joinLines(int count, bool preserveSpace)
moveRight();
// If the line we started from is a comment, remove the comment string from the next line
- if (startingLineIsComment && config(ConfigFormatOptions).toString().contains('f')) {
+ if (startingLineIsComment && s.formatOptions.value().contains('f')) {
if (characterAtCursor() == '/' && characterAt(position() + 1) == '/')
moveRight(2);
else if (characterAtCursor() == '*' || characterAtCursor() == '#')
@@ -7955,7 +7941,7 @@ void FakeVimHandler::Private::joinLines(int count, bool preserveSpace)
void FakeVimHandler::Private::insertNewLine()
{
- if ( m_buffer->editBlockLevel <= 1 && hasConfig(ConfigPassKeys) ) {
+ if (m_buffer->editBlockLevel <= 1 && s.passKeys.value()) {
QKeyEvent event(QEvent::KeyPress, Qt::Key_Return, Qt::NoModifier, "\n");
if (passEventToEditor(event, m_cursor))
return;
@@ -7967,7 +7953,7 @@ void FakeVimHandler::Private::insertNewLine()
bool FakeVimHandler::Private::handleInsertInEditor(const Input &input)
{
- if (m_buffer->editBlockLevel > 0 || !hasConfig(ConfigPassKeys))
+ if (m_buffer->editBlockLevel > 0 || !s.passKeys.value())
return false;
joinPreviousEditBlock();
@@ -8654,7 +8640,7 @@ void FakeVimHandler::Private::jump(int distance)
Column FakeVimHandler::Private::indentation(const QString &line) const
{
- int ts = config(ConfigTabStop).toInt();
+ int ts = s.tabStop.value();
int physical = 0;
int logical = 0;
int n = line.size();
@@ -8673,8 +8659,8 @@ Column FakeVimHandler::Private::indentation(const QString &line) const
QString FakeVimHandler::Private::tabExpand(int n) const
{
- int ts = config(ConfigTabStop).toInt();
- if (hasConfig(ConfigExpandTab) || ts < 1)
+ int ts = s.tabStop.value();
+ if (s.expandTab.value() || ts < 1)
return QString(n, ' ');
return QString(n / ts, '\t')
+ QString(n % ts, ' ');
@@ -8682,10 +8668,10 @@ QString FakeVimHandler::Private::tabExpand(int n) const
void FakeVimHandler::Private::insertAutomaticIndentation(bool goingDown, bool forceAutoIndent)
{
- if (!forceAutoIndent && !hasConfig(ConfigAutoIndent) && !hasConfig(ConfigSmartIndent))
+ if (!forceAutoIndent && !s.autoIndent.value() && !s.smartIndent.value())
return;
- if (hasConfig(ConfigSmartIndent)) {
+ if (s.smartIndent.value()) {
QTextBlock bl = block();
Range range(bl.position(), bl.position());
indentText(range, '\n');
@@ -8704,7 +8690,7 @@ void FakeVimHandler::Private::insertAutomaticIndentation(bool goingDown, bool fo
void FakeVimHandler::Private::handleStartOfLine()
{
- if (hasConfig(ConfigStartOfLine))
+ if (s.startOfLine.value())
moveToFirstNonBlankOnLine();
}
@@ -9301,7 +9287,7 @@ void FakeVimHandler::Private::getRegisterType(int *reg, bool *isClipboard, bool
*reg = c.toLower().unicode();
if (c == '"') {
- QStringList list = config(ConfigClipboard).toString().split(',');
+ QStringList list = s.clipboard.value().split(',');
clipboard = list.contains("unnamedplus");
selection = list.contains("unnamed");
} else if (c == '+') {
@@ -9355,7 +9341,7 @@ void FakeVimHandler::updateGlobalMarksFilenames(const QString &oldFileName, cons
bool FakeVimHandler::eventFilter(QObject *ob, QEvent *ev)
{
#ifndef FAKEVIM_STANDALONE
- if (!theFakeVimSetting(ConfigUseFakeVim)->value().toBool())
+ if (!fakeVimSettings()->useFakeVim.value())
return QObject::eventFilter(ob, ev);
#endif
diff --git a/src/plugins/fakevim/fakevimoptions.ui b/src/plugins/fakevim/fakevimoptions.ui
deleted file mode 100644
index b9f7a1845f..0000000000
--- a/src/plugins/fakevim/fakevimoptions.ui
+++ /dev/null
@@ -1,443 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<ui version="4.0">
- <class>FakeVim::Internal::FakeVimOptionPage</class>
- <widget class="QWidget" name="FakeVim::Internal::FakeVimOptionPage">
- <property name="geometry">
- <rect>
- <x>0</x>
- <y>0</y>
- <width>580</width>
- <height>568</height>
- </rect>
- </property>
- <layout class="QVBoxLayout" name="verticalLayout_2">
- <item>
- <widget class="QCheckBox" name="checkBoxUseFakeVim">
- <property name="text">
- <string>Use FakeVim</string>
- </property>
- </widget>
- </item>
- <item>
- <widget class="QGroupBox" name="behaviorBox">
- <property name="title">
- <string>Vim Behavior</string>
- </property>
- <layout class="QVBoxLayout" name="verticalLayout">
- <item>
- <layout class="QGridLayout" name="gridLayout_3">
- <item row="2" column="1">
- <widget class="QCheckBox" name="checkBoxIgnoreCase">
- <property name="text">
- <string>Use ignorecase</string>
- </property>
- </widget>
- </item>
- <item row="3" column="1">
- <widget class="QCheckBox" name="checkBoxSmartCase">
- <property name="text">
- <string>Use smartcase</string>
- </property>
- </widget>
- </item>
- <item row="6" column="0">
- <widget class="QCheckBox" name="checkBoxStartOfLine">
- <property name="text">
- <string>Start of line</string>
- </property>
- </widget>
- </item>
- <item row="3" column="0">
- <widget class="QCheckBox" name="checkBoxSmartTab">
- <property name="text">
- <string>Smart tabulators</string>
- </property>
- </widget>
- </item>
- <item row="1" column="1">
- <widget class="QCheckBox" name="checkBoxUseCoreSearch">
- <property name="text">
- <string>Use search dialog</string>
- </property>
- </widget>
- </item>
- <item row="7" column="1">
- <widget class="QCheckBox" name="checkBoxRelativeNumber">
- <property name="toolTip">
- <string>Displays line numbers relative to the line containing text cursor.</string>
- </property>
- <property name="text">
- <string>Show line numbers relative to cursor</string>
- </property>
- </widget>
- </item>
- <item row="4" column="0">
- <widget class="QCheckBox" name="checkBoxHlSearch">
- <property name="text">
- <string>Highlight search results</string>
- </property>
- </widget>
- </item>
- <item row="0" column="1">
- <widget class="QCheckBox" name="checkBoxIncSearch">
- <property name="text">
- <string>Incremental search</string>
- </property>
- </widget>
- </item>
- <item row="5" column="1">
- <widget class="QCheckBox" name="checkBoxShowMarks">
- <property name="text">
- <string>Show position of text marks</string>
- </property>
- </widget>
- </item>
- <item row="6" column="1">
- <widget class="QCheckBox" name="checkBoxPassControlKey">
- <property name="toolTip">
- <string>Does not interpret key sequences like Ctrl-S in FakeVim but handles them as regular shortcuts. This gives easier access to core functionality at the price of losing some features of FakeVim.</string>
- </property>
- <property name="text">
- <string>Pass control key</string>
- </property>
- </widget>
- </item>
- <item row="0" column="0">
- <widget class="QCheckBox" name="checkBoxAutoIndent">
- <property name="text">
- <string>Automatic indentation</string>
- </property>
- </widget>
- </item>
- <item row="5" column="0">
- <widget class="QCheckBox" name="checkBoxShowCmd">
- <property name="text">
- <string>Show partial command</string>
- </property>
- </widget>
- </item>
- <item row="8" column="0">
- <widget class="QCheckBox" name="checkBoxBlinkingCursor">
- <property name="text">
- <string>Blinking cursor</string>
- </property>
- </widget>
- </item>
- <item row="2" column="0">
- <widget class="QCheckBox" name="checkBoxExpandTab">
- <property name="text">
- <string>Expand tabulators</string>
- </property>
- </widget>
- </item>
- <item row="4" column="1">
- <widget class="QCheckBox" name="checkBoxWrapScan">
- <property name="text">
- <string>Use wrapscan</string>
- </property>
- </widget>
- </item>
- <item row="7" column="0">
- <widget class="QCheckBox" name="checkBoxPassKeys">
- <property name="toolTip">
- <string>Does not interpret some key presses in insert mode so that code can be properly completed and expanded.</string>
- </property>
- <property name="text">
- <string>Pass keys in insert mode</string>
- </property>
- </widget>
- </item>
- <item row="1" column="0">
- <widget class="QCheckBox" name="checkBoxSmartIndent">
- <property name="text">
- <string>Smart indentation</string>
- </property>
- </widget>
- </item>
- </layout>
- </item>
- <item>
- <widget class="QGroupBox" name="groupBox">
- <property name="title">
- <string>Plugin Emulation</string>
- </property>
- <layout class="QGridLayout" name="gridLayout">
- <item row="3" column="0">
- <widget class="QCheckBox" name="checkBoxExchange">
- <property name="text">
- <string>vim-exchange</string>
- </property>
- </widget>
- </item>
- <item row="2" column="0">
- <widget class="QCheckBox" name="checkBoxArgTextObj">
- <property name="text">
- <string>argtextobj.vim</string>
- </property>
- </widget>
- </item>
- <item row="1" column="0">
- <widget class="QCheckBox" name="checkBoxReplaceWithRegister">
- <property name="text">
- <string>ReplaceWithRegister</string>
- </property>
- </widget>
- </item>
- <item row="0" column="0">
- <widget class="QCheckBox" name="checkBoxVimCommentary">
- <property name="text">
- <string>vim-commentary</string>
- </property>
- <property name="checked">
- <bool>false</bool>
- </property>
- </widget>
- </item>
- <item row="4" column="0">
- <widget class="QCheckBox" name="checkBoxVimSurround">
- <property name="text">
- <string>vim-surround</string>
- </property>
- </widget>
- </item>
- </layout>
- </widget>
- </item>
- <item>
- <layout class="QHBoxLayout" name="horizontalLayout_5">
- <item>
- <widget class="QLabel" name="labelShiftWidth">
- <property name="text">
- <string>Shift width:</string>
- </property>
- <property name="buddy">
- <cstring>spinBoxShiftWidth</cstring>
- </property>
- </widget>
- </item>
- <item>
- <widget class="QSpinBox" name="spinBoxShiftWidth">
- <property name="minimum">
- <number>1</number>
- </property>
- <property name="maximum">
- <number>80</number>
- </property>
- </widget>
- </item>
- <item>
- <spacer name="horizontalSpacer_3">
- <property name="orientation">
- <enum>Qt::Horizontal</enum>
- </property>
- <property name="sizeHint" stdset="0">
- <size>
- <width>40</width>
- <height>20</height>
- </size>
- </property>
- </spacer>
- </item>
- <item>
- <widget class="QLabel" name="labelTabulator">
- <property name="toolTip">
- <string>Vim tabstop option.</string>
- </property>
- <property name="text">
- <string>Tabulator size:</string>
- </property>
- <property name="buddy">
- <cstring>spinBoxTabStop</cstring>
- </property>
- </widget>
- </item>
- <item>
- <widget class="QSpinBox" name="spinBoxTabStop">
- <property name="minimum">
- <number>1</number>
- </property>
- <property name="maximum">
- <number>80</number>
- </property>
- </widget>
- </item>
- <item>
- <spacer name="horizontalSpacer_4">
- <property name="orientation">
- <enum>Qt::Horizontal</enum>
- </property>
- <property name="sizeHint" stdset="0">
- <size>
- <width>40</width>
- <height>20</height>
- </size>
- </property>
- </spacer>
- </item>
- <item>
- <widget class="QLabel" name="labelScrollOff">
- <property name="text">
- <string>Scroll offset:</string>
- </property>
- <property name="buddy">
- <cstring>spinBoxScrollOff</cstring>
- </property>
- </widget>
- </item>
- <item>
- <widget class="QSpinBox" name="spinBoxScrollOff"/>
- </item>
- <item>
- <spacer name="horizontalSpacer_2">
- <property name="orientation">
- <enum>Qt::Horizontal</enum>
- </property>
- <property name="sizeHint" stdset="0">
- <size>
- <width>40</width>
- <height>20</height>
- </size>
- </property>
- </spacer>
- </item>
- </layout>
- </item>
- <item>
- <layout class="QFormLayout" name="formLayout">
- <property name="fieldGrowthPolicy">
- <enum>QFormLayout::ExpandingFieldsGrow</enum>
- </property>
- <item row="0" column="0">
- <widget class="QLabel" name="labelBackspace">
- <property name="text">
- <string>Backspace:</string>
- </property>
- <property name="buddy">
- <cstring>lineEditBackspace</cstring>
- </property>
- </widget>
- </item>
- <item row="0" column="1">
- <widget class="QLineEdit" name="lineEditBackspace"/>
- </item>
- <item row="1" column="0">
- <widget class="QLabel" name="labelIsKeyword">
- <property name="text">
- <string>Keyword characters:</string>
- </property>
- <property name="buddy">
- <cstring>lineEditIsKeyword</cstring>
- </property>
- </widget>
- </item>
- <item row="1" column="1">
- <widget class="QLineEdit" name="lineEditIsKeyword"/>
- </item>
- <item row="2" column="0">
- <widget class="QCheckBox" name="checkBoxReadVimRc">
- <property name="text">
- <string>Read .vimrc from location:</string>
- </property>
- </widget>
- </item>
- <item row="2" column="1">
- <widget class="Utils::PathChooser" name="pathChooserVimRcPath" native="true"/>
- </item>
- </layout>
- </item>
- <item>
- <layout class="QHBoxLayout" name="horizontalLayout">
- <item>
- <widget class="QPushButton" name="pushButtonCopyTextEditorSettings">
- <property name="text">
- <string>Copy Text Editor Settings</string>
- </property>
- </widget>
- </item>
- <item>
- <widget class="QPushButton" name="pushButtonSetQtStyle">
- <property name="text">
- <string>Set Qt Style</string>
- </property>
- </widget>
- </item>
- <item>
- <widget class="QPushButton" name="pushButtonSetPlainStyle">
- <property name="text">
- <string>Set Plain Style</string>
- </property>
- </widget>
- </item>
- <item>
- <spacer name="horizontalSpacer">
- <property name="orientation">
- <enum>Qt::Horizontal</enum>
- </property>
- <property name="sizeHint" stdset="0">
- <size>
- <width>40</width>
- <height>20</height>
- </size>
- </property>
- </spacer>
- </item>
- </layout>
- </item>
- <item>
- <spacer name="verticalSpacer">
- <property name="orientation">
- <enum>Qt::Vertical</enum>
- </property>
- <property name="sizeHint" stdset="0">
- <size>
- <width>20</width>
- <height>40</height>
- </size>
- </property>
- </spacer>
- </item>
- </layout>
- </widget>
- </item>
- </layout>
- </widget>
- <customwidgets>
- <customwidget>
- <class>Utils::PathChooser</class>
- <extends>QWidget</extends>
- <header location="global">utils/pathchooser.h</header>
- <container>1</container>
- </customwidget>
- </customwidgets>
- <tabstops>
- <tabstop>checkBoxUseFakeVim</tabstop>
- <tabstop>checkBoxAutoIndent</tabstop>
- <tabstop>checkBoxSmartIndent</tabstop>
- <tabstop>checkBoxExpandTab</tabstop>
- <tabstop>checkBoxSmartTab</tabstop>
- <tabstop>checkBoxHlSearch</tabstop>
- <tabstop>checkBoxShowCmd</tabstop>
- <tabstop>checkBoxStartOfLine</tabstop>
- <tabstop>checkBoxPassKeys</tabstop>
- <tabstop>checkBoxIncSearch</tabstop>
- <tabstop>checkBoxUseCoreSearch</tabstop>
- <tabstop>checkBoxIgnoreCase</tabstop>
- <tabstop>checkBoxSmartCase</tabstop>
- <tabstop>checkBoxWrapScan</tabstop>
- <tabstop>checkBoxShowMarks</tabstop>
- <tabstop>checkBoxPassControlKey</tabstop>
- <tabstop>checkBoxRelativeNumber</tabstop>
- <tabstop>spinBoxShiftWidth</tabstop>
- <tabstop>spinBoxTabStop</tabstop>
- <tabstop>spinBoxScrollOff</tabstop>
- <tabstop>lineEditBackspace</tabstop>
- <tabstop>lineEditIsKeyword</tabstop>
- <tabstop>checkBoxReadVimRc</tabstop>
- <tabstop>pathChooserVimRcPath</tabstop>
- <tabstop>pushButtonCopyTextEditorSettings</tabstop>
- <tabstop>pushButtonSetQtStyle</tabstop>
- <tabstop>pushButtonSetPlainStyle</tabstop>
- </tabstops>
- <resources/>
- <connections/>
-</ui>
diff --git a/src/plugins/fakevim/fakevimplugin.cpp b/src/plugins/fakevim/fakevimplugin.cpp
index 72f19334e4..3c32384aa0 100644
--- a/src/plugins/fakevim/fakevimplugin.cpp
+++ b/src/plugins/fakevim/fakevimplugin.cpp
@@ -28,7 +28,6 @@
#include "fakevimactions.h"
#include "fakevimhandler.h"
#include "fakevimtr.h"
-#include "ui_fakevimoptions.h"
#include <coreplugin/actionmanager/actioncontainer.h>
#include <coreplugin/actionmanager/actionmanager.h>
@@ -67,26 +66,31 @@
#include <texteditor/codeassist/assistinterface.h>
#include <texteditor/codeassist/genericproposal.h>
+#include <utils/aspects.h>
#include <utils/fancylineedit.h>
#include <utils/hostosinfo.h>
-#include <utils/qtcassert.h>
+#include <utils/layoutbuilder.h>
#include <utils/pathchooser.h>
#include <utils/qtcassert.h>
-#include <utils/savedaction.h>
+#include <utils/qtcassert.h>
#include <utils/stylehelper.h>
#include <cpptools/cpptoolsconstants.h>
#include <extensionsystem/pluginmanager.h>
+#include <QAction>
#include <QAbstractTableModel>
#include <QDebug>
#include <QFile>
+#include <QGridLayout>
+#include <QGroupBox>
#include <QGuiApplication>
#include <QItemDelegate>
#include <QPainter>
#include <QPlainTextEdit>
#include <QPointer>
+#include <QPushButton>
#include <QRegularExpression>
#include <QScrollBar>
#include <QSettings>
@@ -367,142 +371,142 @@ public:
setCategory(SETTINGS_CATEGORY);
setDisplayCategory(Tr::tr("FakeVim"));
setCategoryIconPath(":/fakevim/images/settingscategory_fakevim.png");
+ setLayouter([this](QWidget *widget) { return layoutPage(widget); });
+ setSettings(fakeVimSettings());
}
- QWidget *widget() override;
- void apply() override;
- void finish() override;
-
private:
+ void layoutPage(QWidget *);
void copyTextEditorSettings();
void setQtStyle();
void setPlainStyle();
void updateVimRcWidgets();
-
- QPointer<QWidget> m_widget;
- Ui::FakeVimOptionPage m_ui;
- SavedActionSet m_group;
};
-QWidget *FakeVimOptionPage::widget()
-{
- if (!m_widget) {
- m_widget = new QWidget;
- m_ui.setupUi(m_widget);
- const QString vimrcDefault = QLatin1String(HostOsInfo::isAnyUnixHost()
- ? "$HOME/.vimrc" : "%USERPROFILE%\\_vimrc");
- m_ui.pathChooserVimRcPath->setExpectedKind(PathChooser::File);
- m_ui.pathChooserVimRcPath->lineEdit()->setToolTip(Tr::tr("Keep empty to use the default path, i.e. "
- "%USERPROFILE%\\_vimrc on Windows, ~/.vimrc otherwise."));
- m_ui.pathChooserVimRcPath->lineEdit()->setPlaceholderText(Tr::tr("Default: %1").arg(vimrcDefault));
-
- m_group.clear();
- m_group.insert(theFakeVimSetting(ConfigUseFakeVim), m_ui.checkBoxUseFakeVim);
- m_group.insert(theFakeVimSetting(ConfigReadVimRc), m_ui.checkBoxReadVimRc);
- m_group.insert(theFakeVimSetting(ConfigVimRcPath), m_ui.pathChooserVimRcPath);
-
- m_group.insert(theFakeVimSetting(ConfigExpandTab), m_ui.checkBoxExpandTab);
- m_group.insert(theFakeVimSetting(ConfigHlSearch), m_ui.checkBoxHlSearch);
- m_group.insert(theFakeVimSetting(ConfigShiftWidth), m_ui.spinBoxShiftWidth);
- m_group.insert(theFakeVimSetting(ConfigShowMarks), m_ui.checkBoxShowMarks);
-
- m_group.insert(theFakeVimSetting(ConfigSmartTab), m_ui.checkBoxSmartTab);
- m_group.insert(theFakeVimSetting(ConfigStartOfLine), m_ui.checkBoxStartOfLine);
- m_group.insert(theFakeVimSetting(ConfigPassKeys), m_ui.checkBoxPassKeys);
- m_group.insert(theFakeVimSetting(ConfigTabStop), m_ui.spinBoxTabStop);
- m_group.insert(theFakeVimSetting(ConfigScrollOff), m_ui.spinBoxScrollOff);
- m_group.insert(theFakeVimSetting(ConfigBackspace), m_ui.lineEditBackspace);
- m_group.insert(theFakeVimSetting(ConfigIsKeyword), m_ui.lineEditIsKeyword);
-
- m_group.insert(theFakeVimSetting(ConfigPassControlKey), m_ui.checkBoxPassControlKey);
- m_group.insert(theFakeVimSetting(ConfigAutoIndent), m_ui.checkBoxAutoIndent);
- m_group.insert(theFakeVimSetting(ConfigSmartIndent), m_ui.checkBoxSmartIndent);
-
- m_group.insert(theFakeVimSetting(ConfigIncSearch), m_ui.checkBoxIncSearch);
- m_group.insert(theFakeVimSetting(ConfigUseCoreSearch), m_ui.checkBoxUseCoreSearch);
- m_group.insert(theFakeVimSetting(ConfigSmartCase), m_ui.checkBoxSmartCase);
- m_group.insert(theFakeVimSetting(ConfigIgnoreCase), m_ui.checkBoxIgnoreCase);
- m_group.insert(theFakeVimSetting(ConfigWrapScan), m_ui.checkBoxWrapScan);
-
- m_group.insert(theFakeVimSetting(ConfigShowCmd), m_ui.checkBoxShowCmd);
-
- m_group.insert(theFakeVimSetting(ConfigRelativeNumber), m_ui.checkBoxRelativeNumber);
- m_group.insert(theFakeVimSetting(ConfigBlinkingCursor), m_ui.checkBoxBlinkingCursor);
-
- m_group.insert(theFakeVimSetting(ConfigEmulateVimCommentary), m_ui.checkBoxVimCommentary);
- m_group.insert(theFakeVimSetting(ConfigEmulateReplaceWithRegister), m_ui.checkBoxReplaceWithRegister);
- m_group.insert(theFakeVimSetting(ConfigEmulateExchange), m_ui.checkBoxExchange);
- m_group.insert(theFakeVimSetting(ConfigEmulateArgTextObj), m_ui.checkBoxArgTextObj);
- m_group.insert(theFakeVimSetting(ConfigEmulateSurround), m_ui.checkBoxVimSurround);
-
- connect(m_ui.pushButtonCopyTextEditorSettings, &QAbstractButton::clicked,
- this, &FakeVimOptionPage::copyTextEditorSettings);
- connect(m_ui.pushButtonSetQtStyle, &QAbstractButton::clicked,
- this, &FakeVimOptionPage::setQtStyle);
- connect(m_ui.pushButtonSetPlainStyle, &QAbstractButton::clicked,
- this, &FakeVimOptionPage::setPlainStyle);
- connect(m_ui.checkBoxReadVimRc, &QCheckBox::stateChanged,
- this, &FakeVimOptionPage::updateVimRcWidgets);
- updateVimRcWidgets();
-
- }
- return m_widget;
-}
-
-void FakeVimOptionPage::apply()
-{
- m_group.apply(ICore::settings());
-}
-
-void FakeVimOptionPage::finish()
-{
- m_group.finish();
- delete m_widget;
+void FakeVimOptionPage::layoutPage(QWidget *widget)
+{
+ auto copyTextEditorSettings = new QPushButton(Tr::tr("Copy Text Editor Settings"));
+ auto setQtStyle = new QPushButton(Tr::tr("Set Qt Style"));
+ auto setPlainStyle = new QPushButton(Tr::tr("Set Plain Style"));
+
+ using namespace Layouting;
+ FakeVimSettings &s = *fakeVimSettings();
+
+ Row bools {
+ Column {
+ s.autoIndent,
+ s.smartIndent,
+ s.expandTab,
+ s.smartTab,
+ s.hlSearch,
+ s.showCmd,
+ s.startOfLine,
+ s.passKeys,
+ s.blinkingCursor
+ },
+ Column {
+ s.incSearch,
+ s.useCoreSearch,
+ s.ignoreCase,
+ s.smartCase,
+ s.wrapScan,
+ s.showMarks,
+ s.passControlKey,
+ s.relativeNumber,
+ s.tildeOp
+ }
+ };
+
+ Row ints { s.shiftWidth, s.tabStop, s.scrollOff, Stretch() };
+
+ Column strings {
+ s.backspace,
+ s.isKeyword,
+ Row {s.readVimRc, s.vimRcPath}
+ };
+
+ Column {
+ s.useFakeVim,
+
+ Group {
+ Title(Tr::tr("Vim Behavior")),
+ bools,
+ ints,
+ strings
+ },
+
+ Group {
+ Title(Tr::tr("Plugin Emulation")),
+ s.emulateVimCommentary,
+ s.emulateReplaceWithRegister,
+ s.emulateArgTextObj,
+ s.emulateExchange,
+ s.emulateSurround
+ },
+
+ Row { copyTextEditorSettings, setQtStyle, setPlainStyle, Stretch() },
+ Stretch()
+
+ }.attachTo(widget, true);
+
+ connect(copyTextEditorSettings, &QAbstractButton::clicked,
+ this, &FakeVimOptionPage::copyTextEditorSettings);
+ connect(setQtStyle, &QAbstractButton::clicked,
+ this, &FakeVimOptionPage::setQtStyle);
+ connect(setPlainStyle, &QAbstractButton::clicked,
+ this, &FakeVimOptionPage::setPlainStyle);
+ connect(&s.readVimRc, &FvBaseAspect::changed,
+ this, &FakeVimOptionPage::updateVimRcWidgets);
+ updateVimRcWidgets();
}
void FakeVimOptionPage::copyTextEditorSettings()
{
+ FakeVimSettings &s = *fakeVimSettings();
TabSettings ts = TextEditorSettings::codeStyle()->tabSettings();
TypingSettings tps = TextEditorSettings::typingSettings();
- m_ui.checkBoxExpandTab->setChecked(ts.m_tabPolicy != TabSettings::TabsOnlyTabPolicy);
- m_ui.spinBoxTabStop->setValue(ts.m_tabSize);
- m_ui.spinBoxShiftWidth->setValue(ts.m_indentSize);
- m_ui.checkBoxSmartTab->setChecked(
- tps.m_smartBackspaceBehavior == TypingSettings::BackspaceFollowsPreviousIndents);
- m_ui.checkBoxAutoIndent->setChecked(true);
- m_ui.checkBoxSmartIndent->setChecked(tps.m_autoIndent);
- m_ui.checkBoxIncSearch->setChecked(true);
+ s.expandTab.setValue(ts.m_tabPolicy != TabSettings::TabsOnlyTabPolicy);
+ s.tabStop.setValue(ts.m_tabSize);
+ s.shiftWidth.setValue(ts.m_indentSize);
+ s.smartTab.setValue(tps.m_smartBackspaceBehavior
+ == TypingSettings::BackspaceFollowsPreviousIndents);
+ s.autoIndent.setValue(true);
+ s.smartIndent.setValue(tps.m_autoIndent);
+ s.incSearch.setValue(true);
}
void FakeVimOptionPage::setQtStyle()
{
- m_ui.checkBoxExpandTab->setChecked(true);
- m_ui.spinBoxTabStop->setValue(4);
- m_ui.spinBoxShiftWidth->setValue(4);
- m_ui.checkBoxSmartTab->setChecked(true);
- m_ui.checkBoxAutoIndent->setChecked(true);
- m_ui.checkBoxSmartIndent->setChecked(true);
- m_ui.checkBoxIncSearch->setChecked(true);
- m_ui.lineEditBackspace->setText("indent,eol,start");
- m_ui.checkBoxPassKeys->setChecked(true);
+ FakeVimSettings &s = *fakeVimSettings();
+ s.expandTab.setVolatileValue(true);
+ s.tabStop.setVolatileValue(4);
+ s.shiftWidth.setVolatileValue(4);
+ s.smartTab.setVolatileValue(true);
+ s.autoIndent.setVolatileValue(true);
+ s.smartIndent.setVolatileValue(true);
+ s.incSearch.setVolatileValue(true);
+ s.backspace.setVolatileValue(QString("indent,eol,start"));
+ s.passKeys.setVolatileValue(true);
}
void FakeVimOptionPage::setPlainStyle()
{
- m_ui.checkBoxExpandTab->setChecked(false);
- m_ui.spinBoxTabStop->setValue(8);
- m_ui.spinBoxShiftWidth->setValue(8);
- m_ui.checkBoxSmartTab->setChecked(false);
- m_ui.checkBoxAutoIndent->setChecked(false);
- m_ui.checkBoxSmartIndent->setChecked(false);
- m_ui.checkBoxIncSearch->setChecked(false);
- m_ui.lineEditBackspace->clear();
- m_ui.checkBoxPassKeys->setChecked(false);
+ FakeVimSettings &s = *fakeVimSettings();
+ s.expandTab.setVolatileValue(false);
+ s.tabStop.setVolatileValue(8);
+ s.shiftWidth.setVolatileValue(8);
+ s.smartTab.setVolatileValue(false);
+ s.autoIndent.setVolatileValue(false);
+ s.smartIndent.setVolatileValue(false);
+ s.incSearch.setVolatileValue(false);
+ s.backspace.setVolatileValue(QString());
+ s.passKeys.setVolatileValue(false);
}
void FakeVimOptionPage::updateVimRcWidgets()
{
- m_ui.pathChooserVimRcPath->setEnabled(m_ui.checkBoxReadVimRc->isChecked());
+ FakeVimSettings &s = *fakeVimSettings();
+ s.vimRcPath.setEnabled(s.readVimRc.value());
}
@@ -531,13 +535,13 @@ public:
void documentRenamed(Core::IDocument *document, const QString &oldName, const QString &newName);
void renameFileNameInEditors(const QString &oldName, const QString &newName);
- void setUseFakeVim(const QVariant &value);
+ void setUseFakeVim(bool on);
void setUseFakeVimInternal(bool on);
void quitFakeVim();
void fold(FakeVimHandler *handler, int depth, bool fold);
void maybeReadVimRc();
- void setShowRelativeLineNumbers(const QVariant &value);
- void updateCursorBlinking(const QVariant &value);
+ void setShowRelativeLineNumbers(bool on);
+ void setCursorBlinking(bool on);
void resetCommandBuffer();
void showCommandBuffer(FakeVimHandler *handler, const QString &contents,
@@ -1199,8 +1203,13 @@ bool FakeVimPluginPrivate::initialize()
*/
readSettings();
+ // Vimrc can break test so don't source it if running tests.
+ if (!ExtensionSystem::PluginManager::testRunRequested())
+ maybeReadVimRc();
+
Command *cmd = nullptr;
- cmd = ActionManager::registerAction(theFakeVimSetting(ConfigUseFakeVim)->action(),
+
+ cmd = ActionManager::registerAction(fakeVimSettings()->useFakeVim.action(),
INSTALL_HANDLER, Context(Core::Constants::C_GLOBAL), true);
cmd->setDefaultKeySequence(QKeySequence(useMacShortcuts ? Tr::tr("Meta+Shift+Y,Meta+Shift+Y")
: Tr::tr("Alt+Y,Alt+Y")));
@@ -1238,16 +1247,17 @@ bool FakeVimPluginPrivate::initialize()
connect(DocumentManager::instance(), &DocumentManager::documentRenamed,
this, &FakeVimPluginPrivate::documentRenamed);
- connect(theFakeVimSetting(ConfigUseFakeVim), &SavedAction::valueChanged,
+ FakeVimSettings &s = *fakeVimSettings();
+ connect(&s.useFakeVim, &FvBoolAspect::valueChanged,
this, &FakeVimPluginPrivate::setUseFakeVim);
- connect(theFakeVimSetting(ConfigReadVimRc), &SavedAction::valueChanged,
+ connect(&s.readVimRc, &FvBaseAspect::changed,
this, &FakeVimPluginPrivate::maybeReadVimRc);
- connect(theFakeVimSetting(ConfigVimRcPath), &SavedAction::valueChanged,
+ connect(&s.vimRcPath, &FvBaseAspect::changed,
this, &FakeVimPluginPrivate::maybeReadVimRc);
- connect(theFakeVimSetting(ConfigRelativeNumber), &SavedAction::valueChanged,
+ connect(&s.relativeNumber, &FvBoolAspect::valueChanged,
this, &FakeVimPluginPrivate::setShowRelativeLineNumbers);
- connect(theFakeVimSetting(ConfigBlinkingCursor), &SavedAction::valueChanged,
- this, &FakeVimPluginPrivate::updateCursorBlinking);
+ connect(&s.blinkingCursor, &FvBoolAspect::valueChanged,
+ this, &FakeVimPluginPrivate::setCursorBlinking);
// Delayed operations.
connect(this, &FakeVimPluginPrivate::delayedQuitRequested,
@@ -1255,12 +1265,7 @@ bool FakeVimPluginPrivate::initialize()
connect(this, &FakeVimPluginPrivate::delayedQuitAllRequested,
this, &FakeVimPluginPrivate::handleDelayedQuitAll, Qt::QueuedConnection);
- // Vimrc can break test so don't source it if running tests.
- if (!ExtensionSystem::PluginManager::testRunRequested())
- maybeReadVimRc();
- // << "MODE: " << theFakeVimSetting(ConfigUseFakeVim)->value();
-
- updateCursorBlinking(theFakeVimSetting(ConfigBlinkingCursor)->value());
+ setCursorBlinking(s.blinkingCursor.value());
return true;
}
@@ -1271,7 +1276,7 @@ void FakeVimPluginPrivate::userActionTriggered(int key)
FakeVimHandler *handler = m_editorToHandler[editor];
if (handler) {
// If disabled, enable FakeVim mode just for single user command.
- bool enableFakeVim = !theFakeVimSetting(ConfigUseFakeVim)->value().toBool();
+ bool enableFakeVim = !fakeVimSettings()->useFakeVim.value();
if (enableFakeVim)
setUseFakeVimInternal(true);
@@ -1287,9 +1292,9 @@ void FakeVimPluginPrivate::createRelativeNumberWidget(IEditor *editor)
{
if (auto textEditor = TextEditorWidget::fromEditor(editor)) {
auto relativeNumbers = new RelativeNumbersColumn(textEditor);
- connect(theFakeVimSetting(ConfigRelativeNumber), &SavedAction::valueChanged,
+ connect(&fakeVimSettings()->relativeNumber, &FvBaseAspect::changed,
relativeNumbers, &QObject::deleteLater);
- connect(theFakeVimSetting(ConfigUseFakeVim), &SavedAction::valueChanged,
+ connect(&fakeVimSettings()->useFakeVim, &FvBaseAspect::changed,
relativeNumbers, &QObject::deleteLater);
relativeNumbers->show();
}
@@ -1298,14 +1303,14 @@ void FakeVimPluginPrivate::createRelativeNumberWidget(IEditor *editor)
void FakeVimPluginPrivate::writeSettings()
{
QSettings *settings = ICore::settings();
- theFakeVimSettings()->writeSettings(settings);
+ fakeVimSettings()->writeSettings(settings);
}
void FakeVimPluginPrivate::readSettings()
{
QSettings *settings = ICore::settings();
- theFakeVimSettings()->readSettings(settings);
+ fakeVimSettings()->readSettings(settings);
m_exCommandMap = m_defaultExCommandMap;
int size = settings->beginReadArray(exCommandMapGroup);
@@ -1333,9 +1338,9 @@ void FakeVimPluginPrivate::maybeReadVimRc()
//qDebug() << theFakeVimSetting(ConfigReadVimRc)
// << theFakeVimSetting(ConfigReadVimRc)->value();
//qDebug() << theFakeVimSetting(ConfigShiftWidth)->value();
- if (!theFakeVimSetting(ConfigReadVimRc)->value().toBool())
+ if (!fakeVimSettings()->readVimRc.value())
return;
- QString fileName = theFakeVimSetting(ConfigVimRcPath)->value().toString();
+ QString fileName = fakeVimSettings()->vimRcPath.value();
if (fileName.isEmpty()) {
fileName = QStandardPaths::writableLocation(QStandardPaths::HomeLocation)
+ QLatin1String(HostOsInfo::isWindowsHost() ? "/_vimrc" : "/.vimrc");
@@ -1642,9 +1647,9 @@ void FakeVimPluginPrivate::editorOpened(IEditor *editor)
return;
TabSettings tabSettings;
- tabSettings.m_indentSize = theFakeVimSetting(ConfigShiftWidth)->value().toInt();
- tabSettings.m_tabSize = theFakeVimSetting(ConfigTabStop)->value().toInt();
- tabSettings.m_tabPolicy = theFakeVimSetting(ConfigExpandTab)->value().toBool()
+ tabSettings.m_indentSize = fakeVimSettings()->shiftWidth.value();
+ tabSettings.m_tabSize = fakeVimSettings()->tabStop.value();
+ tabSettings.m_tabPolicy = fakeVimSettings()->expandTab.value()
? TabSettings::SpacesOnlyTabPolicy : TabSettings::TabsOnlyTabPolicy;
tabSettings.m_continuationAlignBehavior =
tew->textDocument()->tabSettings().m_continuationAlignBehavior;
@@ -1847,11 +1852,11 @@ void FakeVimPluginPrivate::editorOpened(IEditor *editor)
handler->installEventFilter();
// pop up the bar
- if (theFakeVimSetting(ConfigUseFakeVim)->value().toBool()) {
+ if (fakeVimSettings()->useFakeVim.value()) {
resetCommandBuffer();
handler->setupWidget();
- if (theFakeVimSetting(ConfigRelativeNumber)->value().toBool())
+ if (fakeVimSettings()->relativeNumber.value())
createRelativeNumberWidget(editor);
}
}
@@ -1888,14 +1893,13 @@ void FakeVimPluginPrivate::renameFileNameInEditors(const QString &oldName, const
}
}
-void FakeVimPluginPrivate::setUseFakeVim(const QVariant &value)
+void FakeVimPluginPrivate::setUseFakeVim(bool on)
{
- //qDebug() << "SET USE FAKEVIM" << value;
- bool on = value.toBool();
+ //qDebug() << "SET USE FAKEVIM" << on;
Find::setUseFakeVim(on);
setUseFakeVimInternal(on);
- setShowRelativeLineNumbers(theFakeVimSetting(ConfigRelativeNumber)->value());
- updateCursorBlinking(theFakeVimSetting(ConfigBlinkingCursor)->value());
+ setShowRelativeLineNumbers(fakeVimSettings()->relativeNumber.value());
+ setCursorBlinking(fakeVimSettings()->blinkingCursor.value());
}
void FakeVimPluginPrivate::setUseFakeVimInternal(bool on)
@@ -1918,20 +1922,20 @@ void FakeVimPluginPrivate::setUseFakeVimInternal(bool on)
}
}
-void FakeVimPluginPrivate::setShowRelativeLineNumbers(const QVariant &value)
+void FakeVimPluginPrivate::setShowRelativeLineNumbers(bool on)
{
- if (value.toBool() && theFakeVimSetting(ConfigUseFakeVim)->value().toBool()) {
+ if (on && fakeVimSettings()->useFakeVim.value()) {
foreach (IEditor *editor, m_editorToHandler.keys())
createRelativeNumberWidget(editor);
}
}
-void FakeVimPluginPrivate::updateCursorBlinking(const QVariant &value)
+void FakeVimPluginPrivate::setCursorBlinking(bool on)
{
if (m_savedCursorFlashTime == 0)
m_savedCursorFlashTime = QGuiApplication::styleHints()->cursorFlashTime();
- bool blink = value.toBool() || !theFakeVimSetting(ConfigUseFakeVim)->value().toBool();
+ const bool blink = on || !fakeVimSettings()->useFakeVim.value();
QGuiApplication::styleHints()->setCursorFlashTime(blink ? m_savedCursorFlashTime : 0);
}
@@ -2062,7 +2066,7 @@ void FakeVimPluginPrivate::handleDelayedQuitAll(bool forced)
void FakeVimPluginPrivate::quitFakeVim()
{
- theFakeVimSetting(ConfigUseFakeVim)->setValue(false);
+ fakeVimSettings()->useFakeVim.setValue(false);
}
void FakeVimPluginPrivate::resetCommandBuffer()
diff --git a/src/plugins/genericprojectmanager/genericproject.cpp b/src/plugins/genericprojectmanager/genericproject.cpp
index e2e1715b6c..28201a4d6b 100644
--- a/src/plugins/genericprojectmanager/genericproject.cpp
+++ b/src/plugins/genericprojectmanager/genericproject.cpp
@@ -39,6 +39,7 @@
#include <extensionsystem/pluginmanager.h>
#include <projectexplorer/abi.h>
+#include <projectexplorer/buildinfo.h>
#include <projectexplorer/buildsteplist.h>
#include <projectexplorer/buildsystem.h>
#include <projectexplorer/customexecutablerunconfiguration.h>
@@ -184,7 +185,8 @@ private:
static bool writeFile(const QString &filePath, const QString &contents)
{
- Utils::FileSaver saver(filePath, QIODevice::Text | QIODevice::WriteOnly);
+ Utils::FileSaver saver(Utils::FilePath::fromString(filePath),
+ QIODevice::Text | QIODevice::WriteOnly);
return saver.write(contents.toUtf8()) && saver.finalize();
}
@@ -302,7 +304,7 @@ bool GenericBuildSystem::saveRawList(const QStringList &rawList, const QString &
{
FileChangeBlocker changeGuard(fileName);
// Make sure we can open the file for writing
- Utils::FileSaver saver(fileName, QIODevice::Text);
+ Utils::FileSaver saver(Utils::FilePath::fromString(fileName), QIODevice::Text);
if (!saver.hasError()) {
QTextStream stream(saver.file());
for (const QString &filePath : rawList)
@@ -412,7 +414,7 @@ static QStringList readFlags(const QString &filePath)
return QStringList();
QStringList flags;
for (const auto &line : lines)
- flags.append(QtcProcess::splitArgs(line));
+ flags.append(ProcessArgs::splitArgs(line));
return flags;
}
@@ -647,6 +649,25 @@ ProjectExplorer::DeploymentKnowledge GenericProject::deploymentKnowledge() const
return DeploymentKnowledge::Approximative;
}
+void GenericProject::configureAsExampleProject(ProjectExplorer::Kit *kit)
+{
+ QList<BuildInfo> infoList;
+ const QList<Kit *> kits(kit != nullptr ? QList<Kit *>({kit}) : KitManager::kits());
+ for (Kit *k : kits) {
+ if (auto factory = BuildConfigurationFactory::find(k, projectFilePath())) {
+ for (int i = 0; i < 5; ++i) {
+ BuildInfo buildInfo;
+ buildInfo.displayName = tr("Build %1").arg(i + 1);
+ buildInfo.factory = factory;
+ buildInfo.kitId = kit->id();
+ buildInfo.buildDirectory = projectFilePath();
+ infoList << buildInfo;
+ }
+ }
+ }
+ setup(infoList);
+}
+
bool GenericProjectFile::reload(QString *errorString, IDocument::ReloadFlag flag, IDocument::ChangeType type)
{
Q_UNUSED(errorString)
diff --git a/src/plugins/genericprojectmanager/genericproject.h b/src/plugins/genericprojectmanager/genericproject.h
index f1a1763032..9129c1399b 100644
--- a/src/plugins/genericprojectmanager/genericproject.h
+++ b/src/plugins/genericprojectmanager/genericproject.h
@@ -43,6 +43,7 @@ public:
private:
RestoreResult fromMap(const QVariantMap &map, QString *errorMessage) final;
ProjectExplorer::DeploymentKnowledge deploymentKnowledge() const final;
+ void configureAsExampleProject(ProjectExplorer::Kit *kit) override;
};
} // namespace Internal
diff --git a/src/plugins/git/CMakeLists.txt b/src/plugins/git/CMakeLists.txt
index 03d0d882e5..8c9bd94ac9 100644
--- a/src/plugins/git/CMakeLists.txt
+++ b/src/plugins/git/CMakeLists.txt
@@ -35,6 +35,5 @@ add_qtc_plugin(Git
remoteadditiondialog.ui
remotedialog.cpp remotedialog.h remotedialog.ui
remotemodel.cpp remotemodel.h
- settingspage.cpp settingspage.h settingspage.ui
stashdialog.cpp stashdialog.h stashdialog.ui
)
diff --git a/src/plugins/git/branchmodel.cpp b/src/plugins/git/branchmodel.cpp
index 6160790384..146c051ea2 100644
--- a/src/plugins/git/branchmodel.cpp
+++ b/src/plugins/git/branchmodel.cpp
@@ -793,7 +793,7 @@ void BranchModel::Private::parseOutputLine(const QString &line, bool force)
const qint64 age = dateTime.daysTo(QDateTime::currentDateTime());
isOld = age > Constants::OBSOLETE_COMMIT_AGE_IN_DAYS;
}
- bool showTags = client->settings().boolValue(GitSettings::showTagsKey);
+ const bool showTags = client->settings().showTags.value();
// insert node into tree:
QStringList nameParts = fullName.split('/');
diff --git a/src/plugins/git/branchview.cpp b/src/plugins/git/branchview.cpp
index 959429569f..04fe69ebed 100644
--- a/src/plugins/git/branchview.cpp
+++ b/src/plugins/git/branchview.cpp
@@ -75,24 +75,22 @@ protected:
}
};
-BranchView::BranchView() :
- m_includeOldEntriesAction(new QAction(tr("Include Old Entries"), this)),
- m_includeTagsAction(new QAction(tr("Include Tags"), this)),
- m_addButton(new QToolButton(this)),
- m_refreshButton(new QToolButton(this)),
- m_repositoryLabel(new Utils::ElidingLabel(this)),
- m_branchView(new Utils::NavigationTreeView(this)),
- m_model(new BranchModel(GitClient::instance(), this)),
- m_filterModel(new BranchFilterModel(this))
+BranchView::BranchView()
+ : m_includeOldEntriesAction(new QAction(tr("Include Old Entries"), this))
+ , m_includeTagsAction(new QAction(tr("Include Tags"), this))
+ , m_addAction(new QAction(this))
+ , m_refreshAction(new QAction(this))
+ , m_repositoryLabel(new Utils::ElidingLabel(this))
+ , m_branchView(new Utils::NavigationTreeView(this))
+ , m_model(new BranchModel(GitClient::instance(), this))
+ , m_filterModel(new BranchFilterModel(this))
{
- m_addButton->setIcon(Utils::Icons::PLUS_TOOLBAR.icon());
- m_addButton->setProperty("noArrow", true);
- connect(m_addButton, &QToolButton::clicked, this, &BranchView::add);
+ m_addAction->setIcon(Utils::Icons::PLUS_TOOLBAR.icon());
+ connect(m_addAction, &QAction::triggered, this, &BranchView::add);
- m_refreshButton->setIcon(Utils::Icons::RELOAD_TOOLBAR.icon());
- m_refreshButton->setToolTip(tr("Refresh"));
- m_refreshButton->setProperty("noArrow", true);
- connect(m_refreshButton, &QToolButton::clicked, this, &BranchView::refreshCurrentRepository);
+ m_refreshAction->setIcon(Utils::Icons::RELOAD_TOOLBAR.icon());
+ m_refreshAction->setToolTip(tr("Refresh"));
+ connect(m_refreshAction, &QAction::triggered, this, &BranchView::refreshCurrentRepository);
m_branchView->setHeaderHidden(true);
setFocus();
@@ -121,8 +119,7 @@ BranchView::BranchView() :
connect(m_includeOldEntriesAction, &QAction::toggled,
this, &BranchView::setIncludeOldEntries);
m_includeTagsAction->setCheckable(true);
- m_includeTagsAction->setChecked(
- GitClient::instance()->settings().boolValue(GitSettings::showTagsKey));
+ m_includeTagsAction->setChecked(GitClient::settings().showTags.value());
connect(m_includeTagsAction, &QAction::toggled,
this, &BranchView::setIncludeTags);
@@ -156,12 +153,12 @@ void BranchView::refresh(const QString &repository, bool force)
m_repository = repository;
if (m_repository.isEmpty()) {
m_repositoryLabel->setText(tr("<No repository>"));
- m_addButton->setToolTip(tr("Create Git Repository..."));
+ m_addAction->setToolTip(tr("Create Git Repository..."));
m_branchView->setEnabled(false);
} else {
m_repositoryLabel->setText(QDir::toNativeSeparators(m_repository));
m_repositoryLabel->setToolTip(GitPlugin::msgRepositoryLabel(m_repository));
- m_addButton->setToolTip(tr("Add Branch..."));
+ m_addAction->setToolTip(tr("Add Branch..."));
m_branchView->setEnabled(true);
}
@@ -184,14 +181,28 @@ void BranchView::showEvent(QShowEvent *)
refreshCurrentRepository();
}
-QToolButton *BranchView::addButton() const
+QList<QToolButton *> BranchView::createToolButtons()
{
- return m_addButton;
-}
+ auto filter = new QToolButton;
+ filter->setIcon(Utils::Icons::FILTER.icon());
+ filter->setToolTip(tr("Filter"));
+ filter->setPopupMode(QToolButton::InstantPopup);
+ filter->setProperty("noArrow", true);
-QToolButton *BranchView::refreshButton() const
-{
- return m_refreshButton;
+ auto filterMenu = new QMenu(filter);
+ filterMenu->addAction(m_includeOldEntriesAction);
+ filterMenu->addAction(m_includeTagsAction);
+ filter->setMenu(filterMenu);
+
+ auto addButton = new QToolButton;
+ addButton->setDefaultAction(m_addAction);
+ addButton->setProperty("noArrow", true);
+
+ auto refreshButton = new QToolButton;
+ refreshButton->setDefaultAction(m_refreshAction);
+ refreshButton->setProperty("noArrow", true);
+
+ return {filter, addButton, refreshButton};
}
void BranchView::refreshCurrentRepository()
@@ -309,7 +320,7 @@ void BranchView::setIncludeOldEntries(bool filter)
void BranchView::setIncludeTags(bool includeTags)
{
- GitClient::instance()->settings().setValue(GitSettings::showTagsKey, includeTags);
+ GitClient::settings().showTags.setValue(includeTags);
refreshCurrentRepository();
}
@@ -607,20 +618,7 @@ BranchViewFactory::BranchViewFactory()
NavigationView BranchViewFactory::createWidget()
{
m_view = new BranchView;
- Core::NavigationView navigationView(m_view);
-
- auto filter = new QToolButton;
- filter->setIcon(Utils::Icons::FILTER.icon());
- filter->setToolTip(tr("Filter"));
- filter->setPopupMode(QToolButton::InstantPopup);
- filter->setProperty("noArrow", true);
- auto filterMenu = new QMenu(filter);
- filterMenu->addAction(m_view->m_includeOldEntriesAction);
- filterMenu->addAction(m_view->m_includeTagsAction);
- filter->setMenu(filterMenu);
-
- navigationView.dockToolBarWidgets << filter << m_view->addButton() << m_view->refreshButton();
- return navigationView;
+ return {m_view, m_view->createToolButtons()};
}
BranchView *BranchViewFactory::view() const
diff --git a/src/plugins/git/branchview.h b/src/plugins/git/branchview.h
index a02bfa2567..85dc700bd9 100644
--- a/src/plugins/git/branchview.h
+++ b/src/plugins/git/branchview.h
@@ -59,11 +59,7 @@ public:
void refresh(const QString &repository, bool force);
void refreshCurrentBranch();
- QToolButton *addButton() const;
- QToolButton *refreshButton() const;
-
- QAction *m_includeOldEntriesAction = nullptr;
- QAction *m_includeTagsAction = nullptr;
+ QList<QToolButton *> createToolButtons();
protected:
void showEvent(QShowEvent *) override;
@@ -89,8 +85,11 @@ private:
void reflog(const QModelIndex &idx);
void push();
- QToolButton *m_addButton = nullptr;
- QToolButton *m_refreshButton = nullptr;
+ QAction *m_includeOldEntriesAction = nullptr;
+ QAction *m_includeTagsAction = nullptr;
+ QAction *m_addAction = nullptr;
+ QAction *m_refreshAction = nullptr;
+
Utils::ElidingLabel *m_repositoryLabel = nullptr;
Utils::NavigationTreeView *m_branchView = nullptr;
BranchModel *m_model = nullptr;
diff --git a/src/plugins/git/changeselectiondialog.cpp b/src/plugins/git/changeselectiondialog.cpp
index 7e79778396..a5bc3f6a47 100644
--- a/src/plugins/git/changeselectiondialog.cpp
+++ b/src/plugins/git/changeselectiondialog.cpp
@@ -32,9 +32,9 @@
#include <utils/pathchooser.h>
#include <utils/theme/theme.h>
+
#include <vcsbase/vcscommand.h>
-#include <QProcess>
#include <QFormLayout>
#include <QHBoxLayout>
#include <QPushButton>
@@ -230,7 +230,7 @@ void ChangeSelectionDialog::recalculateDetails()
m_process = new QProcess(this);
m_process->setWorkingDirectory(workingDir);
- m_process->setProcessEnvironment(m_gitEnvironment);
+ m_process->setProcessEnvironment(m_gitEnvironment.toProcessEnvironment());
connect(m_process, QOverload<int, QProcess::ExitStatus>::of(&QProcess::finished),
this, &ChangeSelectionDialog::setDetails);
diff --git a/src/plugins/git/changeselectiondialog.h b/src/plugins/git/changeselectiondialog.h
index d49cc18b22..32fd47590f 100644
--- a/src/plugins/git/changeselectiondialog.h
+++ b/src/plugins/git/changeselectiondialog.h
@@ -25,11 +25,11 @@
#pragma once
+#include <utils/environment.h>
#include <utils/fileutils.h>
#include <utils/id.h>
#include <QDialog>
-#include <QProcessEnvironment>
QT_BEGIN_NAMESPACE
class QProcess;
@@ -77,7 +77,7 @@ private:
QProcess *m_process = nullptr;
Utils::FilePath m_gitExecutable;
- QProcessEnvironment m_gitEnvironment;
+ Utils::Environment m_gitEnvironment;
ChangeCommand m_command = NoCommand;
QStringListModel *m_changeModel = nullptr;
QString m_oldWorkingDir;
diff --git a/src/plugins/git/gerrit/authenticationdialog.cpp b/src/plugins/git/gerrit/authenticationdialog.cpp
index ba0516df59..a78b569fee 100644
--- a/src/plugins/git/gerrit/authenticationdialog.cpp
+++ b/src/plugins/git/gerrit/authenticationdialog.cpp
@@ -154,7 +154,8 @@ bool AuthenticationDialog::setupCredentials()
}
if (!found)
out << "machine " << m_server->host << " login " << user << " password " << password << '\n';
- Utils::FileSaver saver(m_netrcFileName, QFile::WriteOnly | QFile::Truncate | QFile::Text);
+ Utils::FileSaver saver(Utils::FilePath::fromString(m_netrcFileName),
+ QFile::WriteOnly | QFile::Truncate | QFile::Text);
saver.write(netrcContents.toUtf8());
return saver.finalize();
}
diff --git a/src/plugins/git/gerrit/gerritmodel.cpp b/src/plugins/git/gerrit/gerritmodel.cpp
index 9f3a1014b6..5a4312c60c 100644
--- a/src/plugins/git/gerrit/gerritmodel.cpp
+++ b/src/plugins/git/gerrit/gerritmodel.cpp
@@ -31,7 +31,7 @@
#include <vcsbase/vcsoutputwindow.h>
#include <utils/algorithm.h>
-#include <utils/synchronousprocess.h>
+#include <utils/qtcprocess.h>
#include <QJsonArray>
#include <QJsonDocument>
@@ -225,7 +225,8 @@ QString GerritChange::fullTitle() const
// In theory, querying uses a continuation/limit protocol, but we assume
// we will never reach a limit with those queries.
-class QueryContext : public QObject {
+class QueryContext : public QObject
+{
Q_OBJECT
public:
QueryContext(const QString &query,
@@ -249,7 +250,7 @@ private:
void errorTermination(const QString &msg);
- QProcess m_process;
+ Utils::QtcProcess m_process;
QTimer m_timer;
QString m_binary;
QByteArray m_output;
@@ -295,7 +296,7 @@ QueryContext::QueryContext(const QString &query,
connect(&m_process, &QProcess::errorOccurred, this, &QueryContext::processError);
connect(&m_watcher, &QFutureWatcherBase::canceled, this, &QueryContext::terminate);
m_watcher.setFuture(m_progress.future());
- m_process.setProcessEnvironment(Git::Internal::GitClient::instance()->processEnvironment());
+ m_process.setEnvironment(Git::Internal::GitClient::instance()->processEnvironment());
m_progress.setProgressRange(0, 1);
m_timer.setInterval(timeOutMS);
@@ -322,7 +323,8 @@ void QueryContext::start()
// Order: synchronous call to error handling if something goes wrong.
VcsOutputWindow::appendCommand(m_process.workingDirectory(), {m_binary, m_arguments});
m_timer.start();
- m_process.start(m_binary, m_arguments);
+ m_process.setCommand({m_binary, m_arguments});
+ m_process.start();
m_process.closeWriteChannel();
}
@@ -337,7 +339,7 @@ void QueryContext::errorTermination(const QString &msg)
void QueryContext::terminate()
{
- Utils::SynchronousProcess::stopProcess(m_process);
+ m_process.stopProcess();
}
void QueryContext::processError(QProcess::ProcessError e)
diff --git a/src/plugins/git/gerrit/gerritplugin.cpp b/src/plugins/git/gerrit/gerritplugin.cpp
index c67db2f8b4..84a2e6abcb 100644
--- a/src/plugins/git/gerrit/gerritplugin.cpp
+++ b/src/plugins/git/gerrit/gerritplugin.cpp
@@ -47,11 +47,11 @@
#include <coreplugin/actionmanager/command.h>
#include <coreplugin/editormanager/editormanager.h>
#include <coreplugin/locator/commandlocator.h>
+#include <coreplugin/messagebox.h>
#include <vcsbase/vcsoutputwindow.h>
-#include <utils/synchronousprocess.h>
-#include <coreplugin/messagebox.h>
+#include <utils/qtcprocess.h>
#include <QDebug>
#include <QProcess>
@@ -64,6 +64,8 @@
#include <QFutureWatcher>
using namespace Core;
+using namespace Utils;
+
using namespace Git::Internal;
enum { debug = 0 };
@@ -121,7 +123,7 @@ private:
const Utils::FilePath m_git;
const GerritServer m_server;
State m_state;
- QProcess m_process;
+ QtcProcess m_process;
QFutureInterface<void> m_progress;
QFutureWatcher<void> m_watcher;
};
@@ -148,7 +150,7 @@ FetchContext::FetchContext(const QSharedPointer<GerritChange> &change,
connect(&m_watcher, &QFutureWatcher<void>::canceled, this, &FetchContext::terminate);
m_watcher.setFuture(m_progress.future());
m_process.setWorkingDirectory(repository);
- m_process.setProcessEnvironment(GitClient::instance()->processEnvironment());
+ m_process.setEnvironment(GitClient::instance()->processEnvironment());
m_process.closeWriteChannel();
}
@@ -170,7 +172,8 @@ void FetchContext::start()
// Order: initialize future before starting the process in case error handling is invoked.
const QStringList args = m_change->gitFetchArguments(m_server);
VcsBase::VcsOutputWindow::appendCommand(m_repository, {m_git, args});
- m_process.start(m_git.toString(), args);
+ m_process.setCommand({m_git, args});
+ m_process.start();
m_process.closeWriteChannel();
}
@@ -258,7 +261,7 @@ void FetchContext::checkout()
void FetchContext::terminate()
{
- Utils::SynchronousProcess::stopProcess(m_process);
+ m_process.stopProcess();
}
diff --git a/src/plugins/git/gerrit/gerritserver.cpp b/src/plugins/git/gerrit/gerritserver.cpp
index a0a6a65046..0944b7ee82 100644
--- a/src/plugins/git/gerrit/gerritserver.cpp
+++ b/src/plugins/git/gerrit/gerritserver.cpp
@@ -31,8 +31,9 @@
#include <coreplugin/icore.h>
#include <coreplugin/shellcommand.h>
+
#include <utils/hostosinfo.h>
-#include <utils/synchronousprocess.h>
+#include <utils/qtcprocess.h>
#include <QFile>
#include <QJsonDocument>
@@ -243,11 +244,11 @@ int GerritServer::testConnection()
{
static GitClient *const client = GitClient::instance();
const QStringList arguments = curlArguments() << (url(RestUrl) + accountUrlC);
- const SynchronousProcessResponse resp = client->vcsFullySynchronousExec(
- QString(), {curlBinary, arguments},
- Core::ShellCommand::NoOutput);
- if (resp.result == SynchronousProcessResponse::Finished) {
- QString output = resp.stdOut();
+ SynchronousProcess proc;
+ client->vcsFullySynchronousExec(proc, QString(), {curlBinary, arguments},
+ Core::ShellCommand::NoOutput);
+ if (proc.result() == QtcProcess::Finished) {
+ QString output = proc.stdOut();
// Gerrit returns an empty response for /p/qt-creator/a/accounts/self
// so consider this as 404.
if (output.isEmpty())
@@ -263,10 +264,10 @@ int GerritServer::testConnection()
}
return Success;
}
- if (resp.exitCode == CertificateError)
+ if (proc.exitCode() == CertificateError)
return CertificateError;
const QRegularExpression errorRegexp("returned error: (\\d+)");
- QRegularExpressionMatch match = errorRegexp.match(resp.stdErr());
+ QRegularExpressionMatch match = errorRegexp.match(proc.stdErr());
if (match.hasMatch())
return match.captured(1).toInt();
return UnknownError;
@@ -340,26 +341,25 @@ void GerritServer::resolveVersion(const GerritParameters &p, bool forceReload)
if (!version.isEmpty() && !forceReload)
return;
if (type == Ssh) {
- SynchronousProcess process;
+ SynchronousProcess proc;
QStringList arguments;
if (port)
arguments << p.portFlag << QString::number(port);
arguments << hostArgument() << "gerrit" << "version";
- const SynchronousProcessResponse resp = client->vcsFullySynchronousExec(
- QString(), {p.ssh, arguments},
- Core::ShellCommand::NoOutput);
- QString stdOut = resp.stdOut().trimmed();
+ client->vcsFullySynchronousExec(proc, QString(), {p.ssh, arguments},
+ Core::ShellCommand::NoOutput);
+ QString stdOut = proc.stdOut().trimmed();
stdOut.remove("gerrit version ");
version = stdOut;
} else {
const QStringList arguments = curlArguments() << (url(RestUrl) + versionUrlC);
- const SynchronousProcessResponse resp = client->vcsFullySynchronousExec(
- QString(), {curlBinary, arguments},
- Core::ShellCommand::NoOutput);
+ SynchronousProcess proc;
+ client->vcsFullySynchronousExec(proc, QString(), {curlBinary, arguments},
+ Core::ShellCommand::NoOutput);
// REST endpoint for version is only available from 2.8 and up. Do not consider invalid
// if it fails.
- if (resp.result == SynchronousProcessResponse::Finished) {
- QString output = resp.stdOut();
+ if (proc.result() == QtcProcess::Finished) {
+ QString output = proc.stdOut();
if (output.isEmpty())
return;
output.remove(0, output.indexOf('\n')); // Strip first line
diff --git a/src/plugins/git/git.pro b/src/plugins/git/git.pro
index c8cdec3dab..36a7eb0477 100644
--- a/src/plugins/git/git.pro
+++ b/src/plugins/git/git.pro
@@ -7,7 +7,6 @@ HEADERS += gitplugin.h \
gitclient.h \
changeselectiondialog.h \
commitdata.h \
- settingspage.h \
giteditor.h \
annotationhighlighter.h \
gitsubmiteditorwidget.h \
@@ -30,7 +29,6 @@ SOURCES += gitplugin.cpp \
gitclient.cpp \
changeselectiondialog.cpp \
commitdata.cpp \
- settingspage.cpp \
giteditor.cpp \
annotationhighlighter.cpp \
gitsubmiteditorwidget.cpp \
@@ -50,7 +48,6 @@ SOURCES += gitplugin.cpp \
branchview.cpp
FORMS += changeselectiondialog.ui \
- settingspage.ui \
gitsubmitpanel.ui \
stashdialog.ui \
remotedialog.ui \
diff --git a/src/plugins/git/git.qbs b/src/plugins/git/git.qbs
index 7f2be51cc6..de9effea89 100644
--- a/src/plugins/git/git.qbs
+++ b/src/plugins/git/git.qbs
@@ -62,9 +62,6 @@ QtcPlugin {
"remotedialog.ui",
"remotemodel.cpp",
"remotemodel.h",
- "settingspage.cpp",
- "settingspage.h",
- "settingspage.ui",
"stashdialog.cpp",
"stashdialog.h",
"stashdialog.ui",
diff --git a/src/plugins/git/gitclient.cpp b/src/plugins/git/gitclient.cpp
index 09053e77ba..59942086dd 100644
--- a/src/plugins/git/gitclient.cpp
+++ b/src/plugins/git/gitclient.cpp
@@ -46,10 +46,10 @@
#include <utils/checkablemessagebox.h>
#include <utils/fileutils.h>
#include <utils/hostosinfo.h>
+#include <utils/mimetypes/mimedatabase.h>
#include <utils/qtcassert.h>
#include <utils/qtcprocess.h>
#include <utils/stringutils.h>
-#include <utils/synchronousprocess.h>
#include <utils/temporaryfile.h>
#include <utils/theme/theme.h>
@@ -493,17 +493,16 @@ class BaseGitDiffArgumentsWidget : public VcsBaseEditorConfig
Q_OBJECT
public:
- BaseGitDiffArgumentsWidget(VcsBaseClientSettings &settings, QToolBar *toolBar) :
+ BaseGitDiffArgumentsWidget(GitSettings &settings, QToolBar *toolBar) :
VcsBaseEditorConfig(toolBar)
{
m_patienceButton
= addToggleButton("--patience", tr("Patience"),
tr("Use the patience algorithm for calculating the differences."));
- mapSetting(m_patienceButton, settings.boolPointer(GitSettings::diffPatienceKey));
+ mapSetting(m_patienceButton, &settings.diffPatience);
m_ignoreWSButton = addToggleButton("--ignore-space-change", tr("Ignore Whitespace"),
tr("Ignore whitespace only changes."));
- mapSetting(m_ignoreWSButton,
- settings.boolPointer(GitSettings::ignoreSpaceChangesInDiffKey));
+ mapSetting(m_ignoreWSButton, &settings.ignoreSpaceChangesInDiff);
}
protected:
@@ -516,15 +515,15 @@ class GitBlameArgumentsWidget : public VcsBaseEditorConfig
Q_OBJECT
public:
- GitBlameArgumentsWidget(VcsBaseClientSettings &settings, QToolBar *toolBar) :
+ GitBlameArgumentsWidget(GitSettings &settings, QToolBar *toolBar) :
VcsBaseEditorConfig(toolBar)
{
mapSetting(addToggleButton(QString(), tr("Omit Date"),
tr("Hide the date of a change from the output.")),
- settings.boolPointer(GitSettings::omitAnnotationDateKey));
+ &settings.omitAnnotationDate);
mapSetting(addToggleButton("-w", tr("Ignore Whitespace"),
tr("Ignore whitespace only changes.")),
- settings.boolPointer(GitSettings::ignoreSpaceChangesInBlameKey));
+ &settings.ignoreSpaceChangesInBlame);
const QList<ChoiceItem> logChoices = {
ChoiceItem(tr("No Move Detection"), ""),
@@ -533,7 +532,7 @@ public:
ChoiceItem(tr("Detect Moves and Copies Between Files"), "-M -C -C")
};
mapSetting(addChoices(tr("Move detection"), {}, logChoices),
- settings.intPointer(GitSettings::blameMoveDetection));
+ &settings.blameMoveDetection);
addReloadButton();
}
@@ -544,13 +543,13 @@ class BaseGitLogArgumentsWidget : public BaseGitDiffArgumentsWidget
Q_OBJECT
public:
- BaseGitLogArgumentsWidget(VcsBaseClientSettings &settings, GitEditorWidget *editor) :
+ BaseGitLogArgumentsWidget(GitSettings &settings, GitEditorWidget *editor) :
BaseGitDiffArgumentsWidget(settings, editor->toolBar())
{
QToolBar *toolBar = editor->toolBar();
QAction *diffButton = addToggleButton(patchOption, tr("Diff"),
tr("Show difference."));
- mapSetting(diffButton, settings.boolPointer(GitSettings::logDiffKey));
+ mapSetting(diffButton, &settings.logDiff);
connect(diffButton, &QAction::toggled, m_patienceButton, &QAction::setVisible);
connect(diffButton, &QAction::toggled, m_ignoreWSButton, &QAction::setVisible);
m_patienceButton->setVisible(diffButton->isChecked());
@@ -585,27 +584,27 @@ class GitLogArgumentsWidget : public BaseGitLogArgumentsWidget
Q_OBJECT
public:
- GitLogArgumentsWidget(VcsBaseClientSettings &settings, bool fileRelated, GitEditorWidget *editor) :
+ GitLogArgumentsWidget(GitSettings &settings, bool fileRelated, GitEditorWidget *editor) :
BaseGitLogArgumentsWidget(settings, editor)
{
QAction *firstParentButton =
addToggleButton({"-m", "--first-parent"},
tr("First Parent"),
tr("Follow only the first parent on merge commits."));
- mapSetting(firstParentButton, settings.boolPointer(GitSettings::firstParentKey));
+ mapSetting(firstParentButton, &settings.firstParent);
QAction *graphButton = addToggleButton(graphArguments(), tr("Graph"),
tr("Show textual graph log."));
- mapSetting(graphButton, settings.boolPointer(GitSettings::graphLogKey));
+ mapSetting(graphButton, &settings.graphLog);
QAction *colorButton = addToggleButton(QStringList{colorOption},
tr("Color"), tr("Use colors in log."));
- mapSetting(colorButton, settings.boolPointer(GitSettings::colorLogKey));
+ mapSetting(colorButton, &settings.colorLog);
if (fileRelated) {
QAction *followButton = addToggleButton(
"--follow", tr("Follow"),
tr("Show log also for previous names of the file."));
- mapSetting(followButton, settings.boolPointer(GitSettings::followRenamesKey));
+ mapSetting(followButton, &settings.followRenames);
}
addReloadButton();
@@ -644,14 +643,14 @@ class GitRefLogArgumentsWidget : public BaseGitLogArgumentsWidget
Q_OBJECT
public:
- GitRefLogArgumentsWidget(VcsBaseClientSettings &settings, GitEditorWidget *editor) :
+ GitRefLogArgumentsWidget(GitSettings &settings, GitEditorWidget *editor) :
BaseGitLogArgumentsWidget(settings, editor)
{
QAction *showDateButton =
addToggleButton("--date=iso",
tr("Show Date"),
tr("Show date instead of sequence."));
- mapSetting(showDateButton, settings.boolPointer(GitSettings::refLogShowDateKey));
+ mapSetting(showDateButton, &settings.refLogShowDate);
addReloadButton();
}
@@ -670,16 +669,16 @@ public:
connect(command, &VcsCommand::stdErrText, handler, &ConflictHandler::readStdErr);
}
- static void handleResponse(const Utils::SynchronousProcessResponse &response,
+ static void handleResponse(const Utils::SynchronousProcess &proc,
const QString &workingDirectory,
const QString &abortCommand = QString())
{
ConflictHandler handler(workingDirectory, abortCommand);
// No conflicts => do nothing
- if (response.result == SynchronousProcessResponse::Finished)
+ if (proc.result() == QtcProcess::Finished)
return;
- handler.readStdOut(response.stdOut());
- handler.readStdErr(response.stdErr());
+ handler.readStdOut(proc.stdOut());
+ handler.readStdErr(proc.stdErr());
}
private:
@@ -784,9 +783,8 @@ static inline void msgCannotRun(const QStringList &args, const QString &workingD
// ---------------- GitClient
-GitClient::GitClient(GitSettings *settings) : VcsBase::VcsBaseClientImpl(settings),
- m_cachedGitVersion(0),
- m_disableEditor(false)
+GitClient::GitClient(GitSettings *settings)
+ : VcsBase::VcsBaseClientImpl(settings)
{
m_instance = this;
m_gitQtcEditor = QString::fromLatin1("\"%1\" -client -block -pid %2")
@@ -799,6 +797,11 @@ GitClient *GitClient::instance()
return m_instance;
}
+GitSettings &GitClient::settings()
+{
+ return static_cast<GitSettings &>(m_instance->VcsBaseClientImpl::settings());
+}
+
QString GitClient::findRepositoryForDirectory(const QString &directory) const
{
if (directory.isEmpty() || directory.endsWith("/.git") || directory.contains("/.git/"))
@@ -835,9 +838,10 @@ QString GitClient::findGitDirForRepository(const QString &repositoryDir) const
bool GitClient::managesFile(const QString &workingDirectory, const QString &fileName) const
{
- return vcsFullySynchronousExec(workingDirectory, {"ls-files", "--error-unmatch", fileName},
- Core::ShellCommand::NoOutput).result
- == SynchronousProcessResponse::Finished;
+ SynchronousProcess proc;
+ vcsFullySynchronousExec(proc, workingDirectory, {"ls-files", "--error-unmatch", fileName},
+ Core::ShellCommand::NoOutput);
+ return proc.result() == QtcProcess::Finished;
}
QStringList GitClient::unmanagedFiles(const QStringList &filePaths) const
@@ -852,12 +856,12 @@ QStringList GitClient::unmanagedFiles(const QStringList &filePaths) const
QStringList args({"ls-files", "-z"});
const QDir wd(it.key());
args << transform(it.value(), [&wd](const QString &fp) { return wd.relativeFilePath(fp); });
- const SynchronousProcessResponse response
- = vcsFullySynchronousExec(it.key(), args, Core::ShellCommand::NoOutput);
- if (response.result != SynchronousProcessResponse::Finished)
+ SynchronousProcess proc;
+ vcsFullySynchronousExec(proc, it.key(), args, Core::ShellCommand::NoOutput);
+ if (proc.result() != QtcProcess::Finished)
return filePaths;
const QStringList managedFilePaths
- = transform(response.stdOut().split('\0', Qt::SkipEmptyParts),
+ = transform(proc.stdOut().split('\0', Qt::SkipEmptyParts),
[&wd](const QString &fp) { return wd.absoluteFilePath(fp); });
res += filtered(it.value(), [&managedFilePaths, &wd](const QString &fp) {
return !managedFilePaths.contains(wd.absoluteFilePath(fp));
@@ -977,8 +981,8 @@ void GitClient::requestReload(const QString &documentId, const QString &source,
QTC_ASSERT(document, return);
GitBaseDiffEditorController *controller = factory(document);
QTC_ASSERT(controller, return);
- controller->setVcsBinary(settings().binaryPath());
- controller->setVcsTimeoutS(settings().vcsTimeoutS());
+ controller->setVcsBinary(settings().binaryPath.filePath());
+ controller->setVcsTimeoutS(settings().timeout.value());
controller->setProcessEnvironment(processEnvironment());
controller->setWorkingDirectory(workingDirectory);
controller->initialize();
@@ -1118,7 +1122,7 @@ void GitClient::log(const QString &workingDirectory, const QString &fileName,
editor->setWorkingDirectory(workingDir);
QStringList arguments = {"log", decorateOption};
- int logCount = settings().intValue(GitSettings::logCountKey);
+ int logCount = settings().logCount.value();
if (logCount > 0)
arguments << "-n" << QString::number(logCount);
@@ -1171,7 +1175,7 @@ void GitClient::reflog(const QString &workingDirectory, const QString &ref)
QStringList arguments = {"reflog", noColorOption, decorateOption};
arguments << argWidget->arguments();
- int logCount = settings().intValue(GitSettings::logCountKey);
+ int logCount = settings().logCount.value();
if (logCount > 0)
arguments << "-n" << QString::number(logCount);
@@ -1216,15 +1220,19 @@ void GitClient::archive(const QString &workingDirectory, QString commit)
repoDirectory = workingDirectory;
QString repoName = QFileInfo(repoDirectory).fileName();
- QHash<QString, QString> filters {
- { tr("Tarball (*.tar.gz)"), ".tar.gz" },
- { tr("Zip archive (*.zip)"), ".zip" }
- };
+ QHash<QString, QString> filters;
QString selectedFilter;
- if (HostOsInfo::isWindowsHost())
- selectedFilter = filters.key(".zip");
- else
- selectedFilter = filters.key(".tar.gz");
+ auto appendFilter = [&filters, &selectedFilter](const QString &name, bool isSelected){
+ const auto mimeType = Utils::mimeTypeForName(name);
+ const auto filterString = mimeType.filterString();
+ filters.insert(filterString, "." + mimeType.preferredSuffix());
+ if (isSelected)
+ selectedFilter = filterString;
+ };
+
+ bool windows = HostOsInfo::isWindowsHost();
+ appendFilter("application/zip", windows);
+ appendFilter("application/x-compressed-tar", !windows);
QString output;
if (synchronousRevParseCmd(repoDirectory, commit, &output))
@@ -1416,11 +1424,11 @@ void GitClient::removeStaleRemoteBranches(const QString &workingDirectory, const
void GitClient::recoverDeletedFiles(const QString &workingDirectory)
{
- const SynchronousProcessResponse response =
- vcsFullySynchronousExec(workingDirectory, {"ls-files", "--deleted"},
- VcsCommand::SuppressCommandLogging);
- if (response.result == SynchronousProcessResponse::Finished) {
- const QString stdOut = response.stdOut().trimmed();
+ SynchronousProcess proc;
+ vcsFullySynchronousExec(proc, workingDirectory, {"ls-files", "--deleted"},
+ VcsCommand::SuppressCommandLogging);
+ if (proc.result() == QtcProcess::Finished) {
+ const QString stdOut = proc.stdOut().trimmed();
if (stdOut.isEmpty()) {
VcsOutputWindow::appendError(tr("Nothing to recover"));
return;
@@ -1443,15 +1451,15 @@ bool GitClient::synchronousLog(const QString &workingDirectory, const QStringLis
allArguments.append(arguments);
- const SynchronousProcessResponse resp = vcsFullySynchronousExec(
- workingDirectory, allArguments, flags, vcsTimeoutS(),
- encoding(workingDirectory, "i18n.logOutputEncoding"));
- if (resp.result == SynchronousProcessResponse::Finished) {
- *output = resp.stdOut();
+ SynchronousProcess proc;
+ vcsFullySynchronousExec(proc, workingDirectory, allArguments, flags, vcsTimeoutS(),
+ encoding(workingDirectory, "i18n.logOutputEncoding"));
+ if (proc.result() == QtcProcess::Finished) {
+ *output = proc.stdOut();
return true;
} else {
msgCannotRun(tr("Cannot obtain log of \"%1\": %2")
- .arg(QDir::toNativeSeparators(workingDirectory), resp.stdErr()), errorMessageIn);
+ .arg(QDir::toNativeSeparators(workingDirectory), proc.stdErr()), errorMessageIn);
return false;
}
}
@@ -1462,7 +1470,9 @@ bool GitClient::synchronousAdd(const QString &workingDirectory,
{
QStringList args{"add"};
args += extraOptions + files;
- return vcsFullySynchronousExec(workingDirectory, args).result == SynchronousProcessResponse::Finished;
+ SynchronousProcess proc;
+ vcsFullySynchronousExec(proc, workingDirectory, args);
+ return proc.result() == QtcProcess::Finished;
}
bool GitClient::synchronousDelete(const QString &workingDirectory,
@@ -1473,16 +1483,18 @@ bool GitClient::synchronousDelete(const QString &workingDirectory,
if (force)
arguments << "--force";
arguments.append(files);
- return vcsFullySynchronousExec(workingDirectory, arguments).result
- == SynchronousProcessResponse::Finished;
+ SynchronousProcess proc;
+ vcsFullySynchronousExec(proc, workingDirectory, arguments);
+ return proc.result() == QtcProcess::Finished;
}
bool GitClient::synchronousMove(const QString &workingDirectory,
const QString &from,
const QString &to)
{
- return vcsFullySynchronousExec(workingDirectory, {"mv", from, to}).result
- == SynchronousProcessResponse::Finished;
+ SynchronousProcess proc;
+ vcsFullySynchronousExec(proc, workingDirectory, {"mv", from, to});
+ return proc.result() == QtcProcess::Finished;
}
bool GitClient::synchronousReset(const QString &workingDirectory,
@@ -1495,19 +1507,20 @@ bool GitClient::synchronousReset(const QString &workingDirectory,
else
arguments << HEAD << "--" << files;
- const SynchronousProcessResponse resp = vcsFullySynchronousExec(workingDirectory, arguments);
- const QString stdOut = resp.stdOut();
+ SynchronousProcess proc;
+ vcsFullySynchronousExec(proc, workingDirectory, arguments);
+ const QString stdOut = proc.stdOut();
VcsOutputWindow::append(stdOut);
// Note that git exits with 1 even if the operation is successful
// Assume real failure if the output does not contain "foo.cpp modified"
// or "Unstaged changes after reset" (git 1.7.0).
- if (resp.result != SynchronousProcessResponse::Finished
+ if (proc.result() != QtcProcess::Finished
&& (!stdOut.contains("modified") && !stdOut.contains("Unstaged changes after reset"))) {
if (files.isEmpty()) {
- msgCannotRun(arguments, workingDirectory, resp.stdErr(), errorMessage);
+ msgCannotRun(arguments, workingDirectory, proc.stdErr(), errorMessage);
} else {
msgCannotRun(tr("Cannot reset %n files in \"%1\": %2", nullptr, files.size())
- .arg(QDir::toNativeSeparators(workingDirectory), resp.stdErr()),
+ .arg(QDir::toNativeSeparators(workingDirectory), proc.stdErr()),
errorMessage);
}
return false;
@@ -1518,11 +1531,11 @@ bool GitClient::synchronousReset(const QString &workingDirectory,
// Initialize repository
bool GitClient::synchronousInit(const QString &workingDirectory)
{
- const SynchronousProcessResponse resp = vcsFullySynchronousExec(workingDirectory,
- QStringList{"init"});
+ SynchronousProcess proc;
+ vcsFullySynchronousExec(proc, workingDirectory, QStringList{"init"});
// '[Re]Initialized...'
- VcsOutputWindow::append(resp.stdOut());
- if (resp.result == SynchronousProcessResponse::Finished) {
+ VcsOutputWindow::append(proc.stdOut());
+ if (proc.result() == QtcProcess::Finished) {
resetCachedVcsInfo(workingDirectory);
return true;
} else {
@@ -1546,14 +1559,14 @@ bool GitClient::synchronousCheckoutFiles(const QString &workingDirectory, QStrin
if (revertStaging)
arguments << revision;
arguments << "--" << files;
- const SynchronousProcessResponse resp = vcsFullySynchronousExec(
- workingDirectory, arguments, VcsCommand::ExpectRepoChanges);
- if (resp.result != SynchronousProcessResponse::Finished) {
+ SynchronousProcess proc;
+ vcsFullySynchronousExec(proc, workingDirectory, arguments, VcsCommand::ExpectRepoChanges);
+ if (proc.result() != QtcProcess::Finished) {
const QString fileArg = files.join(", ");
//: Meaning of the arguments: %1: revision, %2: files, %3: repository,
//: %4: Error message
msgCannotRun(tr("Cannot checkout \"%1\" of %2 in \"%3\": %4")
- .arg(revision, fileArg, workingDirectory, resp.stdErr()),
+ .arg(revision, fileArg, workingDirectory, proc.stdErr()),
errorMessage);
return false;
}
@@ -1597,13 +1610,13 @@ bool GitClient::synchronousRevListCmd(const QString &workingDirectory, const QSt
QString *output, QString *errorMessage) const
{
const QStringList arguments = QStringList({"rev-list", noColorOption}) + extraArguments;
- const SynchronousProcessResponse resp = vcsFullySynchronousExec(
- workingDirectory, arguments, silentFlags);
- if (resp.result != SynchronousProcessResponse::Finished) {
- msgCannotRun(arguments, workingDirectory, resp.stdErr(), errorMessage);
+ SynchronousProcess proc;
+ vcsFullySynchronousExec(proc, workingDirectory, arguments, silentFlags);
+ if (proc.result() != QtcProcess::Finished) {
+ msgCannotRun(arguments, workingDirectory, proc.stdErr(), errorMessage);
return false;
}
- *output = resp.stdOut();
+ *output = proc.stdOut();
return true;
}
@@ -1661,10 +1674,10 @@ QString GitClient::synchronousShortDescription(const QString &workingDirectory,
QString GitClient::synchronousCurrentLocalBranch(const QString &workingDirectory) const
{
QString branch;
- const SynchronousProcessResponse resp = vcsFullySynchronousExec(
- workingDirectory, {"symbolic-ref", HEAD}, silentFlags);
- if (resp.result == SynchronousProcessResponse::Finished) {
- branch = resp.stdOut().trimmed();
+ SynchronousProcess proc;
+ vcsFullySynchronousExec(proc, workingDirectory, {"symbolic-ref", HEAD}, silentFlags);
+ if (proc.result() == QtcProcess::Finished) {
+ branch = proc.stdOut().trimmed();
} else {
const QString gitDir = findGitDirForRepository(workingDirectory);
const QString rebaseHead = gitDir + "/rebase-merge/head-name";
@@ -1686,14 +1699,14 @@ bool GitClient::synchronousHeadRefs(const QString &workingDirectory, QStringList
QString *errorMessage) const
{
const QStringList arguments = {"show-ref", "--head", "--abbrev=10", "--dereference"};
- const SynchronousProcessResponse resp = vcsFullySynchronousExec(
- workingDirectory, arguments, silentFlags);
- if (resp.result != SynchronousProcessResponse::Finished) {
- msgCannotRun(arguments, workingDirectory, resp.stdErr(), errorMessage);
+ SynchronousProcess proc;
+ vcsFullySynchronousExec(proc, workingDirectory, arguments, silentFlags);
+ if (proc.result() != QtcProcess::Finished) {
+ msgCannotRun(arguments, workingDirectory, proc.stdErr(), errorMessage);
return false;
}
- const QString stdOut = resp.stdOut();
+ const QString stdOut = proc.stdOut();
const QString headSha = stdOut.left(10);
QString rest = stdOut.mid(15);
@@ -1735,10 +1748,10 @@ QString GitClient::synchronousTopic(const QString &workingDirectory) const
return remoteBranch;
// No tag or remote branch - try git describe
- const SynchronousProcessResponse resp =
- vcsFullySynchronousExec(workingDirectory, QStringList{"describe"}, VcsCommand::NoOutput);
- if (resp.result == SynchronousProcessResponse::Finished) {
- const QString stdOut = resp.stdOut().trimmed();
+ SynchronousProcess proc;
+ vcsFullySynchronousExec(proc, workingDirectory, QStringList{"describe"}, VcsCommand::NoOutput);
+ if (proc.result() == QtcProcess::Finished) {
+ const QString stdOut = proc.stdOut().trimmed();
if (!stdOut.isEmpty())
return stdOut;
}
@@ -1749,11 +1762,11 @@ bool GitClient::synchronousRevParseCmd(const QString &workingDirectory, const QS
QString *output, QString *errorMessage) const
{
const QStringList arguments = {"rev-parse", ref};
- const SynchronousProcessResponse resp = vcsFullySynchronousExec(
- workingDirectory, arguments, silentFlags);
- *output = resp.stdOut().trimmed();
- if (resp.result != SynchronousProcessResponse::Finished) {
- msgCannotRun(arguments, workingDirectory, resp.stdErr(), errorMessage);
+ SynchronousProcess proc;
+ vcsFullySynchronousExec(proc, workingDirectory, arguments, silentFlags);
+ *output = proc.stdOut().trimmed();
+ if (proc.result() != QtcProcess::Finished) {
+ msgCannotRun(arguments, workingDirectory, proc.stdErr(), errorMessage);
return false;
}
@@ -1764,11 +1777,11 @@ bool GitClient::synchronousRevParseCmd(const QString &workingDirectory, const QS
QString GitClient::synchronousTopRevision(const QString &workingDirectory, QDateTime *dateTime)
{
const QStringList arguments = {"show", "-s", "--pretty=format:%H:%ct", HEAD};
- const SynchronousProcessResponse resp = vcsFullySynchronousExec(
- workingDirectory, arguments, silentFlags);
- if (resp.result != SynchronousProcessResponse::Finished)
+ SynchronousProcess proc;
+ vcsFullySynchronousExec(proc, workingDirectory, arguments, silentFlags);
+ if (proc.result() != QtcProcess::Finished)
return QString();
- const QStringList output = resp.stdOut().trimmed().split(':');
+ const QStringList output = proc.stdOut().trimmed().split(':');
if (dateTime && output.size() > 1) {
bool ok = false;
const qint64 timeT = output.at(1).toLongLong(&ok);
@@ -1780,9 +1793,9 @@ QString GitClient::synchronousTopRevision(const QString &workingDirectory, QDate
void GitClient::synchronousTagsForCommit(const QString &workingDirectory, const QString &revision,
QString &precedes, QString &follows) const
{
- const SynchronousProcessResponse resp1 = vcsFullySynchronousExec(
- workingDirectory, {"describe", "--contains", revision}, silentFlags);
- precedes = resp1.stdOut();
+ SynchronousProcess proc1;
+ vcsFullySynchronousExec(proc1, workingDirectory, {"describe", "--contains", revision}, silentFlags);
+ precedes = proc1.stdOut();
int tilde = precedes.indexOf('~');
if (tilde != -1)
precedes.truncate(tilde);
@@ -1793,9 +1806,10 @@ void GitClient::synchronousTagsForCommit(const QString &workingDirectory, const
QString errorMessage;
synchronousParentRevisions(workingDirectory, revision, &parents, &errorMessage);
for (const QString &p : qAsConst(parents)) {
- const SynchronousProcessResponse resp2 = vcsFullySynchronousExec(
+ SynchronousProcess proc2;
+ vcsFullySynchronousExec(proc2,
workingDirectory, {"describe", "--tags", "--abbrev=0", p}, silentFlags);
- QString pf = resp2.stdOut();
+ QString pf = proc2.stdOut();
pf.truncate(pf.lastIndexOf('\n'));
if (!pf.isEmpty()) {
if (!follows.isEmpty())
@@ -1807,15 +1821,16 @@ void GitClient::synchronousTagsForCommit(const QString &workingDirectory, const
bool GitClient::isRemoteCommit(const QString &workingDirectory, const QString &commit)
{
- return !vcsFullySynchronousExec(
- workingDirectory, {"branch", "-r", "--contains", commit}, silentFlags).rawStdOut.isEmpty();
+ SynchronousProcess proc;
+ vcsFullySynchronousExec(proc, workingDirectory, {"branch", "-r", "--contains", commit}, silentFlags);
+ return proc.rawStdOut().isEmpty();
}
bool GitClient::isFastForwardMerge(const QString &workingDirectory, const QString &branch)
{
- const SynchronousProcessResponse resp = vcsFullySynchronousExec(
- workingDirectory, {"merge-base", HEAD, branch}, silentFlags);
- return resp.stdOut().trimmed() == synchronousTopRevision(workingDirectory);
+ SynchronousProcess proc;
+ vcsFullySynchronousExec(proc, workingDirectory, {"merge-base", HEAD, branch}, silentFlags);
+ return proc.stdOut().trimmed() == synchronousTopRevision(workingDirectory);
}
// Format an entry in a one-liner for selection list using git log.
@@ -1824,14 +1839,14 @@ QString GitClient::synchronousShortDescription(const QString &workingDirectory,
{
const QStringList arguments = {"log", noColorOption, ("--pretty=format:" + format),
"--max-count=1", revision};
- const SynchronousProcessResponse resp = vcsFullySynchronousExec(
- workingDirectory, arguments, silentFlags);
- if (resp.result != SynchronousProcessResponse::Finished) {
+ SynchronousProcess proc;
+ vcsFullySynchronousExec(proc, workingDirectory, arguments, silentFlags);
+ if (proc.result() != QtcProcess::Finished) {
VcsOutputWindow::appendSilently(tr("Cannot describe revision \"%1\" in \"%2\": %3")
- .arg(revision, workingDirectory, resp.stdErr()));
+ .arg(revision, workingDirectory, proc.stdErr()));
return revision;
}
- return stripLastNewline(resp.stdOut());
+ return stripLastNewline(proc.stdOut());
}
// Create a default message to be used for describing stashes
@@ -1905,9 +1920,10 @@ bool GitClient::executeSynchronousStash(const QString &workingDirectory,
const unsigned flags = VcsCommand::ShowStdOut
| VcsCommand::ExpectRepoChanges
| VcsCommand::ShowSuccessMessage;
- const SynchronousProcessResponse resp = vcsSynchronousExec(workingDirectory, arguments, flags);
- if (resp.result != SynchronousProcessResponse::Finished) {
- msgCannotRun(arguments, workingDirectory, resp.stdErr(), errorMessage);
+ SynchronousProcess proc;
+ vcsSynchronousExec(proc, workingDirectory, arguments, flags);
+ if (proc.result() != QtcProcess::Finished) {
+ msgCannotRun(arguments, workingDirectory, proc.stdErr(), errorMessage);
return false;
}
@@ -1944,10 +1960,11 @@ bool GitClient::synchronousBranchCmd(const QString &workingDirectory, QStringLis
QString *output, QString *errorMessage) const
{
branchArgs.push_front("branch");
- const SynchronousProcessResponse resp = vcsFullySynchronousExec(workingDirectory, branchArgs);
- *output = resp.stdOut();
- if (resp.result != SynchronousProcessResponse::Finished) {
- msgCannotRun(branchArgs, workingDirectory, resp.stdErr(), errorMessage);
+ SynchronousProcess proc;
+ vcsFullySynchronousExec(proc, workingDirectory, branchArgs);
+ *output = proc.stdOut();
+ if (proc.result() != QtcProcess::Finished) {
+ msgCannotRun(branchArgs, workingDirectory, proc.stdErr(), errorMessage);
return false;
}
return true;
@@ -1957,10 +1974,11 @@ bool GitClient::synchronousTagCmd(const QString &workingDirectory, QStringList t
QString *output, QString *errorMessage) const
{
tagArgs.push_front("tag");
- const SynchronousProcessResponse resp = vcsFullySynchronousExec(workingDirectory, tagArgs);
- *output = resp.stdOut();
- if (resp.result != SynchronousProcessResponse::Finished) {
- msgCannotRun(tagArgs, workingDirectory, resp.stdErr(), errorMessage);
+ SynchronousProcess proc;
+ vcsFullySynchronousExec(proc, workingDirectory, tagArgs);
+ *output = proc.stdOut();
+ if (proc.result() != QtcProcess::Finished) {
+ msgCannotRun(tagArgs, workingDirectory, proc.stdErr(), errorMessage);
return false;
}
return true;
@@ -1970,11 +1988,11 @@ bool GitClient::synchronousForEachRefCmd(const QString &workingDirectory, QStrin
QString *output, QString *errorMessage) const
{
args.push_front("for-each-ref");
- const SynchronousProcessResponse resp = vcsFullySynchronousExec(workingDirectory, args,
- silentFlags);
- *output = resp.stdOut();
- if (resp.result != SynchronousProcessResponse::Finished) {
- msgCannotRun(args, workingDirectory, resp.stdErr(), errorMessage);
+ SynchronousProcess proc;
+ vcsFullySynchronousExec(proc, workingDirectory, args, silentFlags);
+ *output = proc.stdOut();
+ if (proc.result() != QtcProcess::Finished) {
+ msgCannotRun(args, workingDirectory, proc.stdErr(), errorMessage);
return false;
}
return true;
@@ -1990,14 +2008,14 @@ bool GitClient::synchronousRemoteCmd(const QString &workingDirectory, QStringLis
QString *output, QString *errorMessage, bool silent) const
{
remoteArgs.push_front("remote");
- const SynchronousProcessResponse resp = vcsFullySynchronousExec(workingDirectory, remoteArgs,
- silent ? silentFlags : 0);
+ SynchronousProcess proc;
+ vcsFullySynchronousExec(proc, workingDirectory, remoteArgs, silent ? silentFlags : 0);
- const QString stdErr = resp.stdErr();
+ const QString stdErr = proc.stdErr();
*errorMessage = stdErr;
- *output = resp.stdOut();
+ *output = proc.stdOut();
- if (resp.result != SynchronousProcessResponse::Finished) {
+ if (proc.result() != QtcProcess::Finished) {
msgCannotRun(remoteArgs, workingDirectory, stdErr, errorMessage);
return false;
}
@@ -2034,15 +2052,15 @@ QStringList GitClient::synchronousSubmoduleStatus(const QString &workingDirector
QString *errorMessage) const
{
// get submodule status
- const SynchronousProcessResponse resp =
- vcsFullySynchronousExec(workingDirectory, {"submodule", "status"}, silentFlags);
+ SynchronousProcess proc;
+ vcsFullySynchronousExec(proc, workingDirectory, {"submodule", "status"}, silentFlags);
- if (resp.result != SynchronousProcessResponse::Finished) {
+ if (proc.result() != QtcProcess::Finished) {
msgCannotRun(tr("Cannot retrieve submodule status of \"%1\": %2")
- .arg(QDir::toNativeSeparators(workingDirectory), resp.stdErr()), errorMessage);
+ .arg(QDir::toNativeSeparators(workingDirectory), proc.stdErr()), errorMessage);
return QStringList();
}
- return splitLines(resp.stdOut());
+ return splitLines(proc.stdOut());
}
SubmoduleDataMap GitClient::submoduleList(const QString &workingDirectory) const
@@ -2115,12 +2133,13 @@ QByteArray GitClient::synchronousShow(const QString &workingDirectory, const QSt
return {};
}
const QStringList arguments = {"show", decorateOption, noColorOption, "--no-patch", id};
- const SynchronousProcessResponse resp = vcsFullySynchronousExec(workingDirectory, arguments, flags);
- if (resp.result != SynchronousProcessResponse::Finished) {
- msgCannotRun(arguments, workingDirectory, resp.stdErr(), nullptr);
+ SynchronousProcess proc;
+ vcsFullySynchronousExec(proc, workingDirectory, arguments, flags);
+ if (proc.result() != QtcProcess::Finished) {
+ msgCannotRun(arguments, workingDirectory, proc.stdErr(), nullptr);
return {};
}
- return resp.rawStdOut;
+ return proc.rawStdOut();
}
// Retrieve list of files to be cleaned
@@ -2130,10 +2149,10 @@ bool GitClient::cleanList(const QString &workingDirectory, const QString &module
const QString directory = workingDirectory + '/' + modulePath;
const QStringList arguments = {"clean", "--dry-run", flag};
- const SynchronousProcessResponse resp = vcsFullySynchronousExec(directory, arguments,
- VcsCommand::ForceCLocale);
- if (resp.result != SynchronousProcessResponse::Finished) {
- msgCannotRun(arguments, directory, resp.stdErr(), errorMessage);
+ SynchronousProcess proc;
+ vcsFullySynchronousExec(proc, directory, arguments, VcsCommand::ForceCLocale);
+ if (proc.result() != QtcProcess::Finished) {
+ msgCannotRun(arguments, directory, proc.stdErr(), errorMessage);
return false;
}
@@ -2141,7 +2160,7 @@ bool GitClient::cleanList(const QString &workingDirectory, const QString &module
const QString relativeBase = modulePath.isEmpty() ? QString() : modulePath + '/';
const QString prefix = "Would remove ";
const QStringList removeLines = Utils::filtered(
- splitLines(resp.stdOut()), [](const QString &s) {
+ splitLines(proc.stdOut()), [](const QString &s) {
return s.startsWith("Would remove ");
});
*files = Utils::transform(removeLines, [&relativeBase, &prefix](const QString &s) -> QString {
@@ -2177,9 +2196,10 @@ bool GitClient::synchronousApplyPatch(const QString &workingDirectory,
QStringList arguments = {"apply", "--whitespace=fix"};
arguments << extraArguments << file;
- const SynchronousProcessResponse resp = vcsFullySynchronousExec(workingDirectory, arguments);
- const QString stdErr = resp.stdErr();
- if (resp.result == SynchronousProcessResponse::Finished) {
+ SynchronousProcess proc;
+ vcsFullySynchronousExec(proc, workingDirectory, arguments);
+ const QString stdErr = proc.stdErr();
+ if (proc.result() == QtcProcess::Finished) {
if (!stdErr.isEmpty())
*errorMessage = tr("There were warnings while applying \"%1\" to \"%2\":\n%3")
.arg(file, workingDirectory, stdErr);
@@ -2191,20 +2211,14 @@ bool GitClient::synchronousApplyPatch(const QString &workingDirectory,
}
}
-QProcessEnvironment GitClient::processEnvironment() const
+Environment GitClient::processEnvironment() const
{
- QProcessEnvironment environment = VcsBaseClientImpl::processEnvironment();
- QString gitPath = settings().stringValue(GitSettings::pathKey);
- if (!gitPath.isEmpty()) {
- gitPath += HostOsInfo::pathListSeparator();
- gitPath += environment.value("PATH");
- environment.insert("PATH", gitPath);
- }
- if (HostOsInfo::isWindowsHost()
- && settings().boolValue(GitSettings::winSetHomeEnvironmentKey)) {
- environment.insert("HOME", QDir::toNativeSeparators(QDir::homePath()));
- }
- environment.insert("GIT_EDITOR", m_disableEditor ? "true" : m_gitQtcEditor);
+ Environment environment = VcsBaseClientImpl::processEnvironment();
+ QString gitPath = settings().path.value();
+ environment.prependOrSetPath(gitPath);
+ if (HostOsInfo::isWindowsHost() && settings().winSetHomeEnvironment.value())
+ environment.set("HOME", QDir::toNativeSeparators(QDir::homePath()));
+ environment.set("GIT_EDITOR", m_disableEditor ? "true" : m_gitQtcEditor);
return environment;
}
@@ -2311,19 +2325,19 @@ GitClient::StatusResult GitClient::gitStatus(const QString &workingDirectory, St
arguments << "--ignore-submodules=all";
arguments << "--porcelain" << "-b";
- const SynchronousProcessResponse resp = vcsFullySynchronousExec(
- workingDirectory, arguments, silentFlags);
- const QString stdOut = resp.stdOut();
+ SynchronousProcess proc;
+ vcsFullySynchronousExec(proc, workingDirectory, arguments, silentFlags);
+ const QString stdOut = proc.stdOut();
if (output)
*output = stdOut;
- const bool statusRc = resp.result == SynchronousProcessResponse::Finished;
+ const bool statusRc = proc.result() == QtcProcess::Finished;
const bool branchKnown = !stdOut.startsWith("## HEAD (no branch)\n");
// Is it something really fatal?
if (!statusRc && !branchKnown) {
if (errorMessage) {
- *errorMessage = tr("Cannot obtain status: %1").arg(resp.stdErr());
+ *errorMessage = tr("Cannot obtain status: %1").arg(proc.stdErr());
}
return StatusFailed;
}
@@ -2479,7 +2493,8 @@ QStringList GitClient::synchronousRepositoryBranches(const QString &repositoryUR
const unsigned flags = VcsCommand::SshPasswordPrompt
| VcsCommand::SuppressStdErr
| VcsCommand::SuppressFailMessage;
- const SynchronousProcessResponse resp = vcsSynchronousExec(
+ SynchronousProcess proc;
+ vcsSynchronousExec(proc,
workingDirectory, {"ls-remote", repositoryURL, HEAD, "refs/heads/*"}, flags);
QStringList branches;
branches << tr("<Detached HEAD>");
@@ -2487,7 +2502,7 @@ QStringList GitClient::synchronousRepositoryBranches(const QString &repositoryUR
// split "82bfad2f51d34e98b18982211c82220b8db049b<tab>refs/heads/master"
bool headFound = false;
bool branchFound = false;
- const QStringList lines = resp.stdOut().split('\n');
+ const QStringList lines = proc.stdOut().split('\n');
for (const QString &line : lines) {
if (line.endsWith("\tHEAD")) {
QTC_CHECK(headSha.isNull());
@@ -2518,7 +2533,7 @@ void GitClient::launchGitK(const QString &workingDirectory, const QString &fileN
const QFileInfo binaryInfo = vcsBinary().toFileInfo();
QDir foundBinDir(binaryInfo.dir());
const bool foundBinDirIsBinDir = foundBinDir.dirName() == "bin";
- QProcessEnvironment env = processEnvironment();
+ Environment env = processEnvironment();
if (tryLauchingGitK(env, workingDirectory, fileName, foundBinDir.path()))
return;
@@ -2551,12 +2566,12 @@ void GitClient::launchGitK(const QString &workingDirectory, const QString &fileN
void GitClient::launchRepositoryBrowser(const QString &workingDirectory) const
{
- const QString repBrowserBinary = settings().stringValue(GitSettings::repositoryBrowserCmd);
+ const QString repBrowserBinary = settings().repositoryBrowserCmd.value();
if (!repBrowserBinary.isEmpty())
QProcess::startDetached(repBrowserBinary, {workingDirectory}, workingDirectory);
}
-bool GitClient::tryLauchingGitK(const QProcessEnvironment &env,
+bool GitClient::tryLauchingGitK(const Environment &env,
const QString &workingDirectory,
const QString &fileName,
const QString &gitBinDirectory) const
@@ -2571,19 +2586,19 @@ bool GitClient::tryLauchingGitK(const QProcessEnvironment &env,
binary = wish;
}
}
- const QString gitkOpts = settings().stringValue(GitSettings::gitkOptionsKey);
+ const QString gitkOpts = settings().gitkOptions.value();
if (!gitkOpts.isEmpty())
- arguments.append(QtcProcess::splitArgs(gitkOpts, HostOsInfo::hostOs()));
+ arguments.append(ProcessArgs::splitArgs(gitkOpts, HostOsInfo::hostOs()));
if (!fileName.isEmpty())
arguments << "--" << fileName;
VcsOutputWindow::appendCommand(workingDirectory, {binary, arguments});
// This should always use QProcess::startDetached (as not to kill
// the child), but that does not have an environment parameter.
bool success = false;
- if (!settings().stringValue(GitSettings::pathKey).isEmpty()) {
+ if (!settings().path.value().isEmpty()) {
auto process = new QProcess;
process->setWorkingDirectory(workingDirectory);
- process->setProcessEnvironment(env);
+ process->setProcessEnvironment(env.toProcessEnvironment());
process->start(binary, arguments);
success = process->waitForStarted();
if (success)
@@ -2693,9 +2708,10 @@ bool GitClient::readDataFromCommit(const QString &repoDirectory, const QString &
{
// Get commit data as "SHA1<lf>author<lf>email<lf>message".
const QStringList arguments = {"log", "--max-count=1", "--pretty=format:%h\n%an\n%ae\n%B", commit};
- const SynchronousProcessResponse resp = vcsFullySynchronousExec(repoDirectory, arguments, silentFlags);
+ SynchronousProcess proc;
+ vcsFullySynchronousExec(proc, repoDirectory, arguments, silentFlags);
- if (resp.result != SynchronousProcessResponse::Finished) {
+ if (proc.result() != QtcProcess::Finished) {
if (errorMessage) {
*errorMessage = tr("Cannot retrieve last commit data of repository \"%1\".")
.arg(QDir::toNativeSeparators(repoDirectory));
@@ -2706,7 +2722,7 @@ bool GitClient::readDataFromCommit(const QString &repoDirectory, const QString &
QTextCodec *authorCodec = HostOsInfo::isWindowsHost()
? QTextCodec::codecForName("UTF-8")
: commitData.commitEncoding;
- QByteArray stdOut = resp.rawStdOut;
+ QByteArray stdOut = proc.rawStdOut();
commitData.amendSHA1 = QLatin1String(shiftLogLine(stdOut));
commitData.panelData.author = authorCodec->toUnicode(shiftLogLine(stdOut));
commitData.panelData.email = authorCodec->toUnicode(shiftLogLine(stdOut));
@@ -2839,7 +2855,7 @@ bool GitClient::getCommitData(const QString &workingDirectory,
if (templateFileInfo.isRelative())
templateFilename = repoDirectory + '/' + templateFilename;
FileReader reader;
- if (!reader.fetch(templateFilename, QIODevice::Text, errorMessage))
+ if (!reader.fetch(Utils::FilePath::fromString(templateFilename), QIODevice::Text, errorMessage))
return false;
*commitTemplate = QString::fromLocal8Bit(reader.data());
}
@@ -2949,9 +2965,9 @@ bool GitClient::addAndCommit(const QString &repositoryDirectory,
arguments << "--signoff";
}
- const SynchronousProcessResponse resp = vcsSynchronousExec(repositoryDirectory, arguments,
- VcsCommand::NoFullySync);
- if (resp.result == SynchronousProcessResponse::Finished) {
+ SynchronousProcess proc;
+ vcsSynchronousExec(proc, repositoryDirectory, arguments, VcsCommand::NoFullySync);
+ if (proc.result() == QtcProcess::Finished) {
VcsOutputWindow::appendMessage(msgCommitted(amendSHA1, commitCount));
GitPlugin::updateCurrentBranch();
return true;
@@ -3088,10 +3104,11 @@ bool GitClient::executeAndHandleConflicts(const QString &workingDirectory,
| VcsCommand::ShowStdOut
| VcsCommand::ExpectRepoChanges
| VcsCommand::ShowSuccessMessage;
- const SynchronousProcessResponse resp = vcsSynchronousExec(workingDirectory, arguments, flags);
+ SynchronousProcess proc;
+ vcsSynchronousExec(proc, workingDirectory, arguments, flags);
// Notify about changed files or abort the rebase.
- ConflictHandler::handleResponse(resp, workingDirectory, abortCommand);
- return resp.result == SynchronousProcessResponse::Finished;
+ ConflictHandler::handleResponse(proc, workingDirectory, abortCommand);
+ return proc.result() == QtcProcess::Finished;
}
void GitClient::pull(const QString &workingDirectory, bool rebase)
@@ -3121,10 +3138,10 @@ void GitClient::synchronousAbortCommand(const QString &workingDir, const QString
return;
}
- const SynchronousProcessResponse resp = vcsFullySynchronousExec(
- workingDir, {abortCommand, "--abort"},
- VcsCommand::ExpectRepoChanges | VcsCommand::ShowSuccessMessage);
- VcsOutputWindow::append(resp.stdOut());
+ SynchronousProcess proc;
+ vcsFullySynchronousExec(proc, workingDir, {abortCommand, "--abort"},
+ VcsCommand::ExpectRepoChanges | VcsCommand::ShowSuccessMessage);
+ VcsOutputWindow::append(proc.stdOut());
}
QString GitClient::synchronousTrackingBranch(const QString &workingDirectory, const QString &branch)
@@ -3147,9 +3164,10 @@ QString GitClient::synchronousTrackingBranch(const QString &workingDirectory, co
bool GitClient::synchronousSetTrackingBranch(const QString &workingDirectory,
const QString &branch, const QString &tracking)
{
- return vcsFullySynchronousExec(
- workingDirectory, {"branch", "--set-upstream-to=" + tracking, branch}).result
- == SynchronousProcessResponse::Finished;
+ SynchronousProcess proc;
+ vcsFullySynchronousExec(proc,
+ workingDirectory, {"branch", "--set-upstream-to=" + tracking, branch});
+ return proc.result() == QtcProcess::Finished;
}
VcsBase::VcsCommand *GitClient::asyncUpstreamStatus(const QString &workingDirectory,
@@ -3220,13 +3238,14 @@ void GitClient::synchronousSubversionFetch(const QString &workingDirectory) cons
const unsigned flags = VcsCommand::SshPasswordPrompt
| VcsCommand::ShowStdOut
| VcsCommand::ShowSuccessMessage;
- vcsSynchronousExec(workingDirectory, {"svn", "fetch"}, flags);
+ SynchronousProcess proc;
+ vcsSynchronousExec(proc, workingDirectory, {"svn", "fetch"}, flags);
}
void GitClient::subversionLog(const QString &workingDirectory) const
{
QStringList arguments = {"svn", "log"};
- int logCount = settings().intValue(GitSettings::logCountKey);
+ int logCount = settings().logCount.value();
if (logCount > 0)
arguments << ("--limit=" + QString::number(logCount));
@@ -3469,14 +3488,15 @@ bool GitClient::synchronousStashRemove(const QString &workingDirectory, const QS
else
arguments << "drop" << stash;
- const SynchronousProcessResponse resp = vcsFullySynchronousExec(workingDirectory, arguments);
- if (resp.result == SynchronousProcessResponse::Finished) {
- const QString output = resp.stdOut();
+ SynchronousProcess proc;
+ vcsFullySynchronousExec(proc, workingDirectory, arguments);
+ if (proc.result() == QtcProcess::Finished) {
+ const QString output = proc.stdOut();
if (!output.isEmpty())
VcsOutputWindow::append(output);
return true;
} else {
- msgCannotRun(arguments, workingDirectory, resp.stdErr(), errorMessage);
+ msgCannotRun(arguments, workingDirectory, proc.stdErr(), errorMessage);
return false;
}
}
@@ -3487,14 +3507,14 @@ bool GitClient::synchronousStashList(const QString &workingDirectory, QList<Stas
stashes->clear();
const QStringList arguments = {"stash", "list", noColorOption};
- const SynchronousProcessResponse resp = vcsFullySynchronousExec(workingDirectory, arguments,
- VcsCommand::ForceCLocale);
- if (resp.result != SynchronousProcessResponse::Finished) {
- msgCannotRun(arguments, workingDirectory, resp.stdErr(), errorMessage);
+ SynchronousProcess proc;
+ vcsFullySynchronousExec(proc, workingDirectory, arguments, VcsCommand::ForceCLocale);
+ if (proc.result() != QtcProcess::Finished) {
+ msgCannotRun(arguments, workingDirectory, proc.stdErr(), errorMessage);
return false;
}
Stash stash;
- const QStringList lines = splitLines(resp.stdOut());
+ const QStringList lines = splitLines(proc.stdOut());
for (const QString &line : lines) {
if (stash.parseStashLine(line))
stashes->push_back(stash);
@@ -3527,11 +3547,11 @@ QString GitClient::readOneLine(const QString &workingDirectory, const QStringLis
? QTextCodec::codecForName("UTF-8")
: QTextCodec::codecForLocale();
- const SynchronousProcessResponse resp = vcsFullySynchronousExec(
- workingDirectory, arguments, silentFlags, vcsTimeoutS(), codec);
- if (resp.result != SynchronousProcessResponse::Finished)
+ SynchronousProcess proc;
+ vcsFullySynchronousExec(proc, workingDirectory, arguments, silentFlags, vcsTimeoutS(), codec);
+ if (proc.result() != QtcProcess::Finished)
return QString();
- return resp.stdOut().trimmed();
+ return proc.stdOut().trimmed();
}
// determine version as '(major << 16) + (minor << 8) + patch' or 0.
@@ -3554,16 +3574,16 @@ unsigned GitClient::synchronousGitVersion(QString *errorMessage) const
return 0;
// run git --version
- const SynchronousProcessResponse resp = vcsSynchronousExec(
- QString(), {"--version"}, silentFlags);
- if (resp.result != SynchronousProcessResponse::Finished) {
- msgCannotRun(tr("Cannot determine Git version: %1").arg(resp.stdErr()), errorMessage);
+ SynchronousProcess proc;
+ vcsSynchronousExec(proc, QString(), {"--version"}, silentFlags);
+ if (proc.result() != QtcProcess::Finished) {
+ msgCannotRun(tr("Cannot determine Git version: %1").arg(proc.stdErr()), errorMessage);
return 0;
}
// cut 'git version 1.6.5.1.sha'
// another form: 'git version 1.9.rc1'
- const QString output = resp.stdOut();
+ const QString output = proc.stdOut();
const QRegularExpression versionPattern("^[^\\d]+(\\d+)\\.(\\d+)\\.(\\d+|rc\\d).*$");
QTC_ASSERT(versionPattern.isValid(), return 0);
const QRegularExpressionMatch match = versionPattern.match(output);
@@ -3816,8 +3836,11 @@ IEditor *GitClient::openShowEditor(const QString &workingDirectory, const QStrin
if (content.isEmpty())
return nullptr;
QByteArray fileContent;
- if (TextFileFormat::readFileUTF8(path, nullptr, &fileContent, nullptr)
- == TextFileFormat::ReadSuccess) {
+ if (TextFileFormat::readFileUTF8(Utils::FilePath::fromString(path),
+ nullptr,
+ &fileContent,
+ nullptr)
+ == TextFileFormat::ReadSuccess) {
if (fileContent == content)
return nullptr; // open the file for read/write
}
diff --git a/src/plugins/git/gitclient.h b/src/plugins/git/gitclient.h
index 84ad0cf81c..a8056fd6ea 100644
--- a/src/plugins/git/gitclient.h
+++ b/src/plugins/git/gitclient.h
@@ -33,8 +33,8 @@
#include <vcsbase/vcsbaseclient.h>
#include <utils/fileutils.h>
+#include <utils/futuresynchronizer.h>
-#include <QFutureSynchronizer>
#include <QObject>
#include <QString>
#include <QStringList>
@@ -140,6 +140,7 @@ public:
explicit GitClient(GitSettings *settings);
static GitClient *instance();
+ static GitSettings &settings();
Utils::FilePath vcsBinary() const override;
unsigned gitVersion(QString *errorMessage = nullptr) const;
@@ -344,7 +345,7 @@ public:
QStringList synchronousRepositoryBranches(const QString &repositoryURL,
const QString &workingDirectory = QString()) const;
- QProcessEnvironment processEnvironment() const override;
+ Utils::Environment processEnvironment() const override;
bool beginStashScope(const QString &workingDirectory, const QString &command,
StashFlag flag = Default, PushAction pushAction = NoPush);
@@ -399,7 +400,7 @@ private:
void connectRepositoryChanged(const QString & repository, VcsBase::VcsCommand *cmd);
bool executeAndHandleConflicts(const QString &workingDirectory, const QStringList &arguments,
const QString &abortCommand = QString()) const;
- bool tryLauchingGitK(const QProcessEnvironment &env,
+ bool tryLauchingGitK(const Utils::Environment &env,
const QString &workingDirectory,
const QString &fileName,
const QString &gitBinDirectory) const;
@@ -416,15 +417,15 @@ private:
const QString &gitCommand, ContinueCommandMode continueMode);
mutable Utils::FilePath m_gitVersionForBinary;
- mutable unsigned m_cachedGitVersion;
+ mutable unsigned m_cachedGitVersion = 0;
QString m_gitQtcEditor;
QMap<QString, StashInfo> m_stashInfo;
QString m_pushFallbackCommand;
QString m_diffCommit;
QStringList m_updatedSubmodules;
- bool m_disableEditor;
- QFutureSynchronizer<void> m_synchronizer; // for commit updates
+ bool m_disableEditor = false;
+ Utils::FutureSynchronizer m_synchronizer; // for commit updates
};
class GitRemote : public Core::IVersionControl::RepoUrl
diff --git a/src/plugins/git/giteditor.cpp b/src/plugins/git/giteditor.cpp
index 7a220bae8b..476f0d2cd5 100644
--- a/src/plugins/git/giteditor.cpp
+++ b/src/plugins/git/giteditor.cpp
@@ -152,8 +152,7 @@ static QString sanitizeBlameOutput(const QString &b)
if (b.isEmpty())
return b;
- const bool omitDate = GitClient::instance()->settings().boolValue(
- GitSettings::omitAnnotationDateKey);
+ const bool omitDate = GitClient::instance()->settings().omitAnnotationDate.value();
const QChar space(' ');
const int parenPos = b.indexOf(')');
if (parenPos == -1)
@@ -284,14 +283,14 @@ void GitEditorWidget::addDiffActions(QMenu *menu, const DiffChunk &chunk)
});
}
-void GitEditorWidget::aboutToOpen(const QString &fileName, const QString &realFileName)
+void GitEditorWidget::aboutToOpen(const Utils::FilePath &filePath,
+ const Utils::FilePath &realFilePath)
{
- Q_UNUSED(realFileName)
+ Q_UNUSED(realFilePath)
Utils::Id editorId = textDocument()->id();
if (editorId == Git::Constants::GIT_COMMIT_TEXT_EDITOR_ID
|| editorId == Git::Constants::GIT_REBASE_EDITOR_ID) {
- QFileInfo fi(fileName);
- const QString gitPath = fi.absolutePath();
+ const QString gitPath = filePath.absolutePath().toString();
setSource(gitPath);
textDocument()->setCodec(
GitClient::instance()->encoding(gitPath, "i18n.commitEncoding"));
diff --git a/src/plugins/git/giteditor.h b/src/plugins/git/giteditor.h
index b24639a1d6..6eaf454a35 100644
--- a/src/plugins/git/giteditor.h
+++ b/src/plugins/git/giteditor.h
@@ -59,7 +59,7 @@ private:
void init() override;
void addDiffActions(QMenu *menu, const VcsBase::DiffChunk &chunk) override;
- void aboutToOpen(const QString &fileName, const QString &realFileName) override;
+ void aboutToOpen(const Utils::FilePath &filePath, const Utils::FilePath &realFilePath) override;
QString changeUnderCursor(const QTextCursor &) const override;
VcsBase::BaseAnnotationHighlighter *createAnnotationHighlighter(const QSet<QString> &changes) const override;
QString decorateVersion(const QString &revision) const override;
diff --git a/src/plugins/git/gitgrep.cpp b/src/plugins/git/gitgrep.cpp
index 79c035cd72..ed78a18459 100644
--- a/src/plugins/git/gitgrep.cpp
+++ b/src/plugins/git/gitgrep.cpp
@@ -39,8 +39,8 @@
#include <utils/filesearch.h>
#include <utils/fileutils.h>
#include <utils/qtcassert.h>
+#include <utils/qtcprocess.h>
#include <utils/runextensions.h>
-#include <utils/synchronousprocess.h>
#include <utils/textfileformat.h>
#include <QCheckBox>
@@ -190,19 +190,21 @@ public:
command->addFlags(VcsCommand::SilentOutput | VcsCommand::SuppressFailMessage);
command->setProgressiveOutput(true);
QFutureWatcher<FileSearchResultList> watcher;
- watcher.setFuture(m_fi.future());
connect(&watcher, &QFutureWatcher<FileSearchResultList>::canceled,
command.data(), &VcsCommand::cancel);
+ watcher.setFuture(m_fi.future());
connect(command.data(), &VcsCommand::stdOutText, this, &GitGrepRunner::read);
- SynchronousProcessResponse resp = command->runCommand({GitClient::instance()->vcsBinary(), arguments}, 0);
- switch (resp.result) {
- case SynchronousProcessResponse::TerminatedAbnormally:
- case SynchronousProcessResponse::StartFailed:
- case SynchronousProcessResponse::Hang:
+ SynchronousProcess proc;
+ proc.setTimeoutS(0);
+ command->runCommand(proc, {GitClient::instance()->vcsBinary(), arguments});
+ switch (proc.result()) {
+ case QtcProcess::TerminatedAbnormally:
+ case QtcProcess::StartFailed:
+ case QtcProcess::Hang:
m_fi.reportCanceled();
break;
- case SynchronousProcessResponse::Finished:
- case SynchronousProcessResponse::FinishedError:
+ case QtcProcess::Finished:
+ case QtcProcess::FinishedError:
// When no results are found, git-grep exits with non-zero status.
// Do not consider this as an error.
break;
diff --git a/src/plugins/git/gitplugin.cpp b/src/plugins/git/gitplugin.cpp
index ee4992bd75..8d7e264e77 100644
--- a/src/plugins/git/gitplugin.cpp
+++ b/src/plugins/git/gitplugin.cpp
@@ -34,7 +34,6 @@
#include "gitsubmiteditor.h"
#include "remotedialog.h"
#include "stashdialog.h"
-#include "settingspage.h"
#include "logchangedialog.h"
#include "mergetool.h"
#include "gitutils.h"
@@ -409,7 +408,7 @@ public:
QString m_commitMessageFileName;
bool m_submitActionTriggered = false;
- GitSettingsPage settingPage{&m_settings, std::bind(&GitPluginPrivate::onApplySettings, this)};
+ GitSettingsPage settingPage{&m_settings};
GitGrep gitGrep{&m_gitClient};
@@ -663,6 +662,7 @@ GitPluginPrivate::GitPluginPrivate()
const QString prefix = "git";
m_commandLocator = new CommandLocator("Git", prefix, prefix, this);
+ m_commandLocator->setDescription(tr("Triggers a Git version control operation."));
//register actions
ActionContainer *toolsContainer = ActionManager::actionContainer(Core::Constants::M_TOOLS);
@@ -1022,6 +1022,7 @@ GitPluginPrivate::GitPluginPrivate()
m_gerritPlugin->updateActions(currentState());
m_gerritPlugin->addToLocator(m_commandLocator);
+ connect(&m_settings, &AspectContainer::applied, this, &GitPluginPrivate::onApplySettings);
}
void GitPluginPrivate::diffCurrentFile()
@@ -1353,7 +1354,7 @@ void GitPluginPrivate::startCommit(CommitType commitType)
VcsOutputWindow::appendError(saver.errorString());
return;
}
- m_commitMessageFileName = saver.fileName();
+ m_commitMessageFileName = saver.filePath().toString();
openSubmitEditor(m_commitMessageFileName, data);
}
@@ -1486,7 +1487,7 @@ void GitPluginPrivate::pull()
const VcsBasePluginState state = currentState();
QTC_ASSERT(state.hasTopLevel(), return);
QString topLevel = state.topLevel();
- bool rebase = m_settings.boolValue(GitSettings::pullRebaseKey);
+ bool rebase = m_settings.pullRebase.value();
if (!rebase) {
QString currentBranch = m_gitClient.synchronousCurrentLocalBranch(topLevel);
@@ -1821,8 +1822,7 @@ QObject *GitPlugin::remoteCommand(const QStringList &options, const QString &wor
void GitPluginPrivate::updateRepositoryBrowserAction()
{
const bool repositoryEnabled = currentState().hasTopLevel();
- const bool hasRepositoryBrowserCmd
- = !m_settings.stringValue(GitSettings::repositoryBrowserCmd).isEmpty();
+ const bool hasRepositoryBrowserCmd = !m_settings.repositoryBrowserCmd.value().isEmpty();
m_repositoryBrowserAction->setEnabled(repositoryEnabled && hasRepositoryBrowserCmd);
}
diff --git a/src/plugins/git/gitsettings.cpp b/src/plugins/git/gitsettings.cpp
index 39b0cbaffe..a8e4a97785 100644
--- a/src/plugins/git/gitsettings.cpp
+++ b/src/plugins/git/gitsettings.cpp
@@ -25,76 +25,171 @@
#include "gitsettings.h"
-#include <utils/fileutils.h>
-#include <utils/hostosinfo.h>
-#include <QCoreApplication>
+#include <utils/layoutbuilder.h>
+
+#include <vcsbase/vcsbaseconstants.h>
+
+#include <QDir>
+
+using namespace Utils;
+using namespace VcsBase;
namespace Git {
namespace Internal {
-const QLatin1String GitSettings::pullRebaseKey("PullRebase");
-const QLatin1String GitSettings::showTagsKey("ShowTags");
-const QLatin1String GitSettings::omitAnnotationDateKey("OmitAnnotationDate");
-const QLatin1String GitSettings::ignoreSpaceChangesInDiffKey("SpaceIgnorantDiff");
-const QLatin1String GitSettings::ignoreSpaceChangesInBlameKey("SpaceIgnorantBlame");
-const QLatin1String GitSettings::blameMoveDetection("BlameDetectMove");
-const QLatin1String GitSettings::diffPatienceKey("DiffPatience");
-const QLatin1String GitSettings::winSetHomeEnvironmentKey("WinSetHomeEnvironment");
-const QLatin1String GitSettings::gitkOptionsKey("GitKOptions");
-const QLatin1String GitSettings::logDiffKey("LogDiff");
-const QLatin1String GitSettings::repositoryBrowserCmd("RepositoryBrowserCmd");
-const QLatin1String GitSettings::graphLogKey("GraphLog");
-const QLatin1String GitSettings::colorLogKey("ColorLog");
-const QLatin1String GitSettings::firstParentKey("FirstParent");
-const QLatin1String GitSettings::followRenamesKey("FollowRenames");
-const QLatin1String GitSettings::lastResetIndexKey("LastResetIndex");
-const QLatin1String GitSettings::refLogShowDateKey("RefLogShowDate");
-
GitSettings::GitSettings()
{
setSettingsGroup("Git");
- declareKey(binaryPathKey, "git");
- declareKey(timeoutKey, Utils::HostOsInfo::isWindowsHost() ? 60 : 30);
- declareKey(pullRebaseKey, false);
- declareKey(showTagsKey, false);
- declareKey(omitAnnotationDateKey, false);
- declareKey(ignoreSpaceChangesInDiffKey, true);
- declareKey(blameMoveDetection, 0);
- declareKey(ignoreSpaceChangesInBlameKey, true);
- declareKey(diffPatienceKey, true);
- declareKey(winSetHomeEnvironmentKey, true);
- declareKey(gitkOptionsKey, QString());
- declareKey(logDiffKey, false);
- declareKey(repositoryBrowserCmd, QString());
- declareKey(graphLogKey, false);
- declareKey(colorLogKey, true);
- declareKey(firstParentKey, false);
- declareKey(followRenamesKey, true);
- declareKey(lastResetIndexKey, 0);
- declareKey(refLogShowDateKey, false);
+ path.setDisplayStyle(StringAspect::LineEditDisplay);
+ path.setLabelText(tr("Prepend to PATH:"));
+
+ registerAspect(&binaryPath);
+ binaryPath.setDefaultValue("git");
+
+ registerAspect(&pullRebase);
+ pullRebase.setSettingsKey("PullRebase");
+ pullRebase.setLabelText(tr("Pull with rebase"));
+
+ registerAspect(&showTags);
+ showTags.setSettingsKey("ShowTags");
+
+ registerAspect(&omitAnnotationDate);
+ omitAnnotationDate.setSettingsKey("OmitAnnotationDate");
+
+ registerAspect(&ignoreSpaceChangesInDiff);
+ ignoreSpaceChangesInDiff.setSettingsKey("SpaceIgnorantDiff");
+ ignoreSpaceChangesInDiff.setDefaultValue(true);
+
+ registerAspect(&ignoreSpaceChangesInBlame);
+ ignoreSpaceChangesInBlame.setSettingsKey("SpaceIgnorantBlame");
+ ignoreSpaceChangesInBlame.setDefaultValue(true);
+
+ registerAspect(&blameMoveDetection);
+ blameMoveDetection.setSettingsKey("BlameDetectMove");
+ blameMoveDetection.setDefaultValue(0);
+
+ registerAspect(&diffPatience);
+ diffPatience.setSettingsKey("DiffPatience");
+ diffPatience.setDefaultValue(true);
+
+ registerAspect(&winSetHomeEnvironment);
+ winSetHomeEnvironment.setSettingsKey("WinSetHomeEnvironment");
+ winSetHomeEnvironment.setDefaultValue(true);
+ winSetHomeEnvironment.setLabelText(tr("Set \"HOME\" environment variable"));
+ if (HostOsInfo::isWindowsHost()) {
+ const QByteArray currentHome = qgetenv("HOME");
+ const QString toolTip
+ = tr("Set the environment variable HOME to \"%1\"\n(%2).\n"
+ "This causes Git to look for the SSH-keys in that location\n"
+ "instead of its installation directory when run outside git bash.").
+ arg(QDir::homePath(),
+ currentHome.isEmpty() ? tr("not currently set") :
+ tr("currently set to \"%1\"").arg(QString::fromLocal8Bit(currentHome)));
+ winSetHomeEnvironment.setToolTip(toolTip);
+ } else {
+ winSetHomeEnvironment.setVisible(false);
+ }
+
+ registerAspect(&gitkOptions);
+ gitkOptions.setDisplayStyle(StringAspect::LineEditDisplay);
+ gitkOptions.setSettingsKey("GitKOptions");
+ gitkOptions.setLabelText(tr("Arguments:"));
+
+ registerAspect(&logDiff);
+ logDiff.setSettingsKey("LogDiff");
+ logDiff.setToolTip(tr("Note that huge amount of commits might take some time."));
+
+ registerAspect(&repositoryBrowserCmd);
+ repositoryBrowserCmd.setDisplayStyle(StringAspect::PathChooserDisplay);
+ repositoryBrowserCmd.setSettingsKey("RepositoryBrowserCmd");
+ repositoryBrowserCmd.setExpectedKind(PathChooser::ExistingCommand);
+ repositoryBrowserCmd.setHistoryCompleter("Git.RepoCommand.History");
+ repositoryBrowserCmd.setDisplayName(tr("Git Repository Browser Command"));
+ repositoryBrowserCmd.setLabelText(tr("Command:"));
+
+ registerAspect(&graphLog);
+ graphLog.setSettingsKey("GraphLog");
+
+ registerAspect(&colorLog);
+ colorLog.setSettingsKey("ColorLog");
+ colorLog.setDefaultValue(true);
+
+ registerAspect(&firstParent);
+ firstParent.setSettingsKey("FirstParent");
+
+ registerAspect(&followRenames);
+ followRenames.setSettingsKey("FollowRenames");
+ followRenames.setDefaultValue(true);
+
+ registerAspect(&lastResetIndex);
+ lastResetIndex.setSettingsKey("LastResetIndex");
+
+ registerAspect(&refLogShowDate);
+ refLogShowDate.setSettingsKey("RefLogShowDate");
+
+ timeout.setDefaultValue(Utils::HostOsInfo::isWindowsHost() ? 60 : 30);
}
-Utils::FilePath GitSettings::gitExecutable(bool *ok, QString *errorMessage) const
+FilePath GitSettings::gitExecutable(bool *ok, QString *errorMessage) const
{
- // Locate binary in path if one is specified, otherwise default
- // to pathless binary
+ // Locate binary in path if one is specified, otherwise default to pathless binary.
if (ok)
*ok = true;
if (errorMessage)
errorMessage->clear();
- Utils::FilePath binPath = binaryPath();
+ FilePath binPath = binaryPath.filePath();
if (binPath.isEmpty()) {
if (ok)
*ok = false;
if (errorMessage)
- *errorMessage = QCoreApplication::translate("Git::Internal::GitSettings",
- "The binary \"%1\" could not be located in the path \"%2\"")
- .arg(stringValue(binaryPathKey), stringValue(pathKey));
+ *errorMessage = tr("The binary \"%1\" could not be located in the path \"%2\"")
+ .arg(binaryPath.value(), path.value());
}
return binPath;
}
+// GitSettingsPage
+
+GitSettingsPage::GitSettingsPage(GitSettings *settings)
+{
+ setId(VcsBase::Constants::VCS_ID_GIT);
+ setDisplayName(GitSettings::tr("Git"));
+ setCategory(VcsBase::Constants::VCS_SETTINGS_CATEGORY);
+ setSettings(settings);
+
+ setLayouter([settings](QWidget *widget) {
+ GitSettings &s = *settings;
+ using namespace Layouting;
+
+ Column {
+ Group {
+ Title(GitSettings::tr("Configuration")),
+ Row { s.path },
+ s.winSetHomeEnvironment,
+ },
+
+ Group {
+ Title(GitSettings::tr("Miscellaneous")),
+ Row { s.logCount, s.timeout, Stretch() },
+ s.pullRebase
+ },
+
+ Group {
+ Title(GitSettings::tr("Gitk")),
+ Row { s.gitkOptions }
+ },
+
+ Group {
+ Title(GitSettings::tr("Repository Browser")),
+ Row { s.repositoryBrowserCmd }
+ },
+
+ Stretch()
+ }.attachTo(widget);
+ });
+}
+
} // namespace Internal
} // namespace Git
diff --git a/src/plugins/git/gitsettings.h b/src/plugins/git/gitsettings.h
index 521bb91dbf..4949c4b98f 100644
--- a/src/plugins/git/gitsettings.h
+++ b/src/plugins/git/gitsettings.h
@@ -25,6 +25,7 @@
#pragma once
+#include <coreplugin/dialogs/ioptionspage.h>
#include <vcsbase/vcsbaseclientsettings.h>
namespace Git {
@@ -38,32 +39,38 @@ enum CommitType
};
// Todo: Add user name and password?
-class GitSettings : public VcsBase::VcsBaseClientSettings
+class GitSettings : public VcsBase::VcsBaseSettings
{
+ Q_DECLARE_TR_FUNCTIONS(Git::Internal::GitSettings)
+
public:
GitSettings();
- static const QLatin1String pullRebaseKey;
- static const QLatin1String showTagsKey;
- static const QLatin1String omitAnnotationDateKey;
- static const QLatin1String ignoreSpaceChangesInDiffKey;
- static const QLatin1String ignoreSpaceChangesInBlameKey;
- static const QLatin1String blameMoveDetection;
- static const QLatin1String diffPatienceKey;
- static const QLatin1String winSetHomeEnvironmentKey;
- static const QLatin1String gitkOptionsKey;
- static const QLatin1String logDiffKey;
- static const QLatin1String repositoryBrowserCmd;
- static const QLatin1String graphLogKey;
- static const QLatin1String colorLogKey;
- static const QLatin1String firstParentKey;
- static const QLatin1String followRenamesKey;
- static const QLatin1String lastResetIndexKey;
- static const QLatin1String refLogShowDateKey;
+ Utils::BoolAspect pullRebase;
+ Utils::BoolAspect showTags;
+ Utils::BoolAspect omitAnnotationDate;
+ Utils::BoolAspect ignoreSpaceChangesInDiff;
+ Utils::BoolAspect ignoreSpaceChangesInBlame;
+ Utils::IntegerAspect blameMoveDetection;
+ Utils::BoolAspect diffPatience;
+ Utils::BoolAspect winSetHomeEnvironment;
+ Utils::StringAspect gitkOptions;
+ Utils::BoolAspect logDiff;
+ Utils::StringAspect repositoryBrowserCmd;
+ Utils::BoolAspect graphLog;
+ Utils::BoolAspect colorLog;
+ Utils::BoolAspect firstParent;
+ Utils::BoolAspect followRenames;
+ Utils::IntegerAspect lastResetIndex;
+ Utils::BoolAspect refLogShowDate;
Utils::FilePath gitExecutable(bool *ok = nullptr, QString *errorMessage = nullptr) const;
+};
- GitSettings &operator=(const GitSettings &s) = default;
+class GitSettingsPage final : public Core::IOptionsPage
+{
+public:
+ explicit GitSettingsPage(GitSettings *settings);
};
} // namespace Internal
diff --git a/src/plugins/git/logchangedialog.cpp b/src/plugins/git/logchangedialog.cpp
index 6988dd28dd..bb923ced9d 100644
--- a/src/plugins/git/logchangedialog.cpp
+++ b/src/plugins/git/logchangedialog.cpp
@@ -244,8 +244,7 @@ LogChangeDialog::LogChangeDialog(bool isReset, QWidget *parent) :
m_resetTypeComboBox->addItem(tr("Hard"), "--hard");
m_resetTypeComboBox->addItem(tr("Mixed"), "--mixed");
m_resetTypeComboBox->addItem(tr("Soft"), "--soft");
- m_resetTypeComboBox->setCurrentIndex(
- GitClient::instance()->settings().intValue(GitSettings::lastResetIndexKey));
+ m_resetTypeComboBox->setCurrentIndex(GitClient::settings().lastResetIndex.value());
popUpLayout->addWidget(m_resetTypeComboBox);
popUpLayout->addItem(new QSpacerItem(0, 0, QSizePolicy::Expanding, QSizePolicy::Ignored));
}
@@ -271,10 +270,8 @@ bool LogChangeDialog::runDialog(const QString &repository,
return false;
if (QDialog::exec() == QDialog::Accepted) {
- if (m_resetTypeComboBox) {
- GitClient::instance()->settings().setValue(
- GitSettings::lastResetIndexKey, m_resetTypeComboBox->currentIndex());
- }
+ if (m_resetTypeComboBox)
+ GitClient::settings().lastResetIndex.setValue(m_resetTypeComboBox->currentIndex());
return true;
}
return false;
diff --git a/src/plugins/git/settingspage.cpp b/src/plugins/git/settingspage.cpp
deleted file mode 100644
index 8ef14a6286..0000000000
--- a/src/plugins/git/settingspage.cpp
+++ /dev/null
@@ -1,138 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of Qt Creator.
-**
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 3 as published by the Free Software
-** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-3.0.html.
-**
-****************************************************************************/
-
-#include "settingspage.h"
-#include "gitsettings.h"
-#include "gitplugin.h"
-#include "gitclient.h"
-
-#include "ui_settingspage.h"
-
-#include <coreplugin/icore.h>
-#include <coreplugin/messagebox.h>
-#include <vcsbase/vcsbaseconstants.h>
-
-#include <utils/environment.h>
-#include <utils/hostosinfo.h>
-
-#include <QDir>
-
-using namespace VcsBase;
-
-namespace Git {
-namespace Internal {
-
-class GitSettingsPageWidget final : public Core::IOptionsPageWidget
-{
- Q_DECLARE_TR_FUNCTIONS(Git::Internal::SettingsPageWidget)
-
-public:
- GitSettingsPageWidget(GitSettings *settings, const std::function<void()> &onChange);
-
- void apply() final;
-
-private:
- void updateNoteField();
-
- std::function<void()> m_onChange;
- GitSettings *m_settings;
- Ui::SettingsPage m_ui;
-};
-
-GitSettingsPageWidget::GitSettingsPageWidget(GitSettings *settings, const std::function<void()> &onChange)
- : m_onChange(onChange), m_settings(settings)
-{
- m_ui.setupUi(this);
- if (Utils::HostOsInfo::isWindowsHost()) {
- const QByteArray currentHome = qgetenv("HOME");
- const QString toolTip
- = tr("Set the environment variable HOME to \"%1\"\n(%2).\n"
- "This causes Git to look for the SSH-keys in that location\n"
- "instead of its installation directory when run outside git bash.").
- arg(QDir::homePath(),
- currentHome.isEmpty() ? tr("not currently set") :
- tr("currently set to \"%1\"").arg(QString::fromLocal8Bit(currentHome)));
- m_ui.winHomeCheckBox->setToolTip(toolTip);
- } else {
- m_ui.winHomeCheckBox->setVisible(false);
- }
- updateNoteField();
-
- m_ui.repBrowserCommandPathChooser->setExpectedKind(Utils::PathChooser::ExistingCommand);
- m_ui.repBrowserCommandPathChooser->setHistoryCompleter("Git.RepoCommand.History");
- m_ui.repBrowserCommandPathChooser->setPromptDialogTitle(tr("Git Repository Browser Command"));
-
- connect(m_ui.pathLineEdit, &QLineEdit::textChanged, this, &GitSettingsPageWidget::updateNoteField);
-
- GitSettings &s = *m_settings;
- m_ui.pathLineEdit->setText(s.stringValue(GitSettings::pathKey));
- m_ui.logCountSpinBox->setValue(s.intValue(GitSettings::logCountKey));
- m_ui.timeoutSpinBox->setValue(s.intValue(GitSettings::timeoutKey));
- m_ui.pullRebaseCheckBox->setChecked(s.boolValue(GitSettings::pullRebaseKey));
- m_ui.winHomeCheckBox->setChecked(s.boolValue(GitSettings::winSetHomeEnvironmentKey));
- m_ui.gitkOptionsLineEdit->setText(s.stringValue(GitSettings::gitkOptionsKey));
- m_ui.repBrowserCommandPathChooser->setPath(s.stringValue(GitSettings::repositoryBrowserCmd));
-}
-
-void GitSettingsPageWidget::apply()
-{
- GitSettings rc = *m_settings;
- rc.setValue(GitSettings::pathKey, m_ui.pathLineEdit->text());
- rc.setValue(GitSettings::logCountKey, m_ui.logCountSpinBox->value());
- rc.setValue(GitSettings::timeoutKey, m_ui.timeoutSpinBox->value());
- rc.setValue(GitSettings::pullRebaseKey, m_ui.pullRebaseCheckBox->isChecked());
- rc.setValue(GitSettings::winSetHomeEnvironmentKey, m_ui.winHomeCheckBox->isChecked());
- rc.setValue(GitSettings::gitkOptionsKey, m_ui.gitkOptionsLineEdit->text().trimmed());
- rc.setValue(GitSettings::repositoryBrowserCmd, m_ui.repBrowserCommandPathChooser->path().trimmed());
-
- if (rc != *m_settings) {
- *m_settings = rc;
- m_onChange();
- }
-}
-
-void GitSettingsPageWidget::updateNoteField()
-{
- Utils::Environment env = Utils::Environment::systemEnvironment();
- env.prependOrSetPath(m_ui.pathLineEdit->text());
-
- bool showNote = env.searchInPath("perl").isEmpty();
-
- m_ui.noteFieldlabel->setVisible(showNote);
- m_ui.noteLabel->setVisible(showNote);
-}
-
-// -------- SettingsPage
-
-GitSettingsPage::GitSettingsPage(GitSettings *settings, const std::function<void()> &onChange)
-{
- setId(VcsBase::Constants::VCS_ID_GIT);
- setDisplayName(GitSettingsPageWidget::tr("Git"));
- setCategory(VcsBase::Constants::VCS_SETTINGS_CATEGORY);
- setWidgetCreator([settings, onChange] { return new GitSettingsPageWidget(settings, onChange); });
-}
-
-} // namespace Internal
-} // namespace Git
diff --git a/src/plugins/git/settingspage.ui b/src/plugins/git/settingspage.ui
deleted file mode 100644
index dd2e447fc9..0000000000
--- a/src/plugins/git/settingspage.ui
+++ /dev/null
@@ -1,214 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<ui version="4.0">
- <class>Git::Internal::SettingsPage</class>
- <widget class="QWidget" name="Git::Internal::SettingsPage">
- <property name="geometry">
- <rect>
- <x>0</x>
- <y>0</y>
- <width>705</width>
- <height>403</height>
- </rect>
- </property>
- <layout class="QVBoxLayout" name="verticalLayout">
- <item>
- <widget class="QGroupBox" name="configurationGroupBox">
- <property name="enabled">
- <bool>true</bool>
- </property>
- <property name="title">
- <string>Configuration</string>
- </property>
- <layout class="QGridLayout" name="gridLayout_2">
- <item row="0" column="0">
- <widget class="QLabel" name="pathlabel">
- <property name="text">
- <string>Prepend to PATH:</string>
- </property>
- </widget>
- </item>
- <item row="0" column="1">
- <widget class="QLineEdit" name="pathLineEdit"/>
- </item>
- <item row="1" column="0" colspan="3">
- <widget class="QCheckBox" name="winHomeCheckBox">
- <property name="text">
- <string>Set &quot;HOME&quot; environment variable</string>
- </property>
- </widget>
- </item>
- <item row="2" column="0">
- <widget class="QLabel" name="noteLabel">
- <property name="text">
- <string>&lt;b&gt;Note:&lt;/b&gt;</string>
- </property>
- </widget>
- </item>
- <item row="2" column="1" colspan="2">
- <widget class="QLabel" name="noteFieldlabel">
- <property name="text">
- <string>Git needs to find Perl in the environment.</string>
- </property>
- </widget>
- </item>
- </layout>
- </widget>
- </item>
- <item>
- <widget class="QGroupBox" name="groupBox">
- <property name="title">
- <string>Miscellaneous</string>
- </property>
- <layout class="QGridLayout" name="gridLayout">
- <item row="1" column="0" colspan="2">
- <widget class="QCheckBox" name="pullRebaseCheckBox">
- <property name="text">
- <string>Pull with rebase</string>
- </property>
- </widget>
- </item>
- <item row="0" column="4">
- <spacer name="horizontalSpacer">
- <property name="orientation">
- <enum>Qt::Horizontal</enum>
- </property>
- <property name="sizeHint" stdset="0">
- <size>
- <width>211</width>
- <height>20</height>
- </size>
- </property>
- </spacer>
- </item>
- <item row="0" column="3">
- <widget class="QSpinBox" name="timeoutSpinBox">
- <property name="suffix">
- <string>s</string>
- </property>
- <property name="minimum">
- <number>10</number>
- </property>
- <property name="maximum">
- <number>360</number>
- </property>
- <property name="value">
- <number>30</number>
- </property>
- </widget>
- </item>
- <item row="0" column="0">
- <widget class="QLabel" name="logCountLabel">
- <property name="text">
- <string>Log count:</string>
- </property>
- </widget>
- </item>
- <item row="0" column="2">
- <widget class="QLabel" name="timeoutLabel">
- <property name="text">
- <string>Timeout:</string>
- </property>
- </widget>
- </item>
- <item row="0" column="1">
- <widget class="QSpinBox" name="logCountSpinBox">
- <property name="toolTip">
- <string>Note that huge amount of commits might take some time.</string>
- </property>
- <property name="maximum">
- <number>1000</number>
- </property>
- <property name="value">
- <number>1000</number>
- </property>
- </widget>
- </item>
- </layout>
- </widget>
- </item>
- <item>
- <widget class="QGroupBox" name="gitkGroupBox">
- <property name="title">
- <string>Gitk</string>
- </property>
- <layout class="QFormLayout" name="formLayout_2">
- <property name="fieldGrowthPolicy">
- <enum>QFormLayout::ExpandingFieldsGrow</enum>
- </property>
- <item row="0" column="0">
- <widget class="QLabel" name="gitkOptionsLabel">
- <property name="text">
- <string>Arguments:</string>
- </property>
- </widget>
- </item>
- <item row="0" column="1">
- <widget class="QLineEdit" name="gitkOptionsLineEdit"/>
- </item>
- </layout>
- </widget>
- </item>
- <item>
- <widget class="QGroupBox" name="repBrowserGroupBox">
- <property name="title">
- <string>Repository Browser</string>
- </property>
- <layout class="QHBoxLayout" name="horizontalLayout_2">
- <item>
- <widget class="QLabel" name="repBrowserCommandLabel">
- <property name="text">
- <string>Command:</string>
- </property>
- </widget>
- </item>
- <item>
- <widget class="Utils::PathChooser" name="repBrowserCommandPathChooser" native="true">
- <property name="sizePolicy">
- <sizepolicy hsizetype="Expanding" vsizetype="Preferred">
- <horstretch>0</horstretch>
- <verstretch>0</verstretch>
- </sizepolicy>
- </property>
- </widget>
- </item>
- </layout>
- </widget>
- </item>
- <item>
- <spacer name="verticalSpacer">
- <property name="orientation">
- <enum>Qt::Vertical</enum>
- </property>
- <property name="sizeHint" stdset="0">
- <size>
- <width>20</width>
- <height>40</height>
- </size>
- </property>
- </spacer>
- </item>
- </layout>
- </widget>
- <customwidgets>
- <customwidget>
- <class>Utils::PathChooser</class>
- <extends>QWidget</extends>
- <header location="global">utils/pathchooser.h</header>
- <container>1</container>
- <slots>
- <signal>editingFinished()</signal>
- <signal>browsingFinished()</signal>
- </slots>
- </customwidget>
- </customwidgets>
- <tabstops>
- <tabstop>pathLineEdit</tabstop>
- <tabstop>winHomeCheckBox</tabstop>
- <tabstop>logCountSpinBox</tabstop>
- <tabstop>timeoutSpinBox</tabstop>
- <tabstop>pullRebaseCheckBox</tabstop>
- <tabstop>gitkOptionsLineEdit</tabstop>
- </tabstops>
- <resources/>
- <connections/>
-</ui>
diff --git a/src/plugins/glsleditor/glsleditorplugin.cpp b/src/plugins/glsleditor/glsleditorplugin.cpp
index ca953fc90f..44785ba36e 100644
--- a/src/plugins/glsleditor/glsleditorplugin.cpp
+++ b/src/plugins/glsleditor/glsleditorplugin.cpp
@@ -84,7 +84,7 @@ void GlslEditorPlugin::InitFile::initialize() const
const int variant = GLSL::Lexer::Variant_All;
QByteArray code;
- QFile file(ICore::resourcePath() + "/glsl/" + m_fileName);
+ QFile file(ICore::resourcePath("glsl").pathAppended(m_fileName).toString());
if (file.open(QFile::ReadOnly))
code = file.readAll();
diff --git a/src/plugins/help/generalsettingspage.cpp b/src/plugins/help/generalsettingspage.cpp
index f42f6ac316..9c8f8c6a2b 100644
--- a/src/plugins/help/generalsettingspage.cpp
+++ b/src/plugins/help/generalsettingspage.cpp
@@ -248,7 +248,7 @@ void GeneralSettingsPage::exportBookmarks()
if (!fileName.endsWith(suffix))
fileName.append(suffix);
- Utils::FileSaver saver(fileName);
+ Utils::FileSaver saver(Utils::FilePath::fromString(fileName));
if (!saver.hasError()) {
XbelWriter writer(LocalHelpManager::bookmarkManager().treeBookmarkModel());
writer.writeToFile(saver.file());
diff --git a/src/plugins/help/helpmanager.cpp b/src/plugins/help/helpmanager.cpp
index 91b2f2b640..b0755b703f 100644
--- a/src/plugins/help/helpmanager.cpp
+++ b/src/plugins/help/helpmanager.cpp
@@ -125,8 +125,7 @@ HelpManager *HelpManager::instance()
QString HelpManager::collectionFilePath()
{
- return QDir::cleanPath(ICore::userResourcePath()
- + QLatin1String("/helpcollection.qhc"));
+ return ICore::userResourcePath("helpcollection.qhc").toString();
}
void HelpManager::registerDocumentation(const QStringList &files)
diff --git a/src/plugins/help/helpplugin.cpp b/src/plugins/help/helpplugin.cpp
index 00a1b28e5a..b25fe0aec2 100644
--- a/src/plugins/help/helpplugin.cpp
+++ b/src/plugins/help/helpplugin.cpp
@@ -189,14 +189,14 @@ bool HelpPlugin::initialize(const QStringList &arguments, QString *error)
HelpPluginPrivate::HelpPluginPrivate()
{
- const QString &locale = ICore::userInterfaceLanguage();
+ const QString locale = ICore::userInterfaceLanguage();
if (!locale.isEmpty()) {
auto qtr = new QTranslator(this);
auto qhelptr = new QTranslator(this);
- const QString &creatorTrPath = ICore::resourcePath() + "/translations";
- const QString &qtTrPath = QLibraryInfo::location(QLibraryInfo::TranslationsPath);
- const QString &trFile = QLatin1String("assistant_") + locale;
- const QString &helpTrFile = QLatin1String("qt_help_") + locale;
+ const QString creatorTrPath = ICore::resourcePath("translations").toString();
+ const QString qtTrPath = QLibraryInfo::location(QLibraryInfo::TranslationsPath);
+ const QString trFile = QLatin1String("assistant_") + locale;
+ const QString helpTrFile = QLatin1String("qt_help_") + locale;
if (qtr->load(trFile, qtTrPath) || qtr->load(trFile, creatorTrPath))
QCoreApplication::installTranslator(qtr);
if (qhelptr->load(helpTrFile, qtTrPath) || qhelptr->load(helpTrFile, creatorTrPath))
@@ -266,11 +266,16 @@ HelpPluginPrivate::HelpPluginPrivate()
Core::HelpManager::HelpModeAlways);
});
+ const QString qdsStandaloneEntry = "QML/Designer/StandAloneMode"; //entry from designer settings
+ const bool isDesigner = Core::ICore::settings()->value(qdsStandaloneEntry, false).toBool();
+
action = new QAction(HelpPlugin::tr("Report Bug..."), this);
cmd = ActionManager::registerAction(action, "Help.ReportBug");
ActionManager::actionContainer(Core::Constants::M_HELP)->addAction(cmd, Core::Constants::G_HELP_SUPPORT);
- connect(action, &QAction::triggered, this, [] {
- QDesktopServices::openUrl(QUrl("https://bugreports.qt.io/secure/CreateIssue.jspa?pid=10512"));
+ connect(action, &QAction::triggered, this, [isDesigner] {
+ const QUrl bugreportUrl = isDesigner ? QString("https://bugreports.qt.io/secure/CreateIssue.jspa?pid=11740") //QDS
+ : QString("https://bugreports.qt.io/secure/CreateIssue.jspa?pid=10512"); //QtC
+ QDesktopServices::openUrl(bugreportUrl);
});
action = new QAction(HelpPlugin::tr("System Information..."), this);
diff --git a/src/plugins/help/helpviewer.cpp b/src/plugins/help/helpviewer.cpp
index 806c73ab25..da1054bc1c 100644
--- a/src/plugins/help/helpviewer.cpp
+++ b/src/plugins/help/helpviewer.cpp
@@ -164,7 +164,7 @@ bool HelpViewer::launchWithExternalApp(const QUrl &url)
if (!saver.hasError())
saver.write(helpEngine.fileData(resolvedUrl));
if (saver.finalize(Core::ICore::dialogParent()))
- QDesktopServices::openUrl(QUrl(saver.fileName()));
+ QDesktopServices::openUrl(QUrl(saver.filePath().toString()));
return true;
}
return false;
diff --git a/src/plugins/help/localhelpmanager.cpp b/src/plugins/help/localhelpmanager.cpp
index 4615e9716e..49d09d2885 100644
--- a/src/plugins/help/localhelpmanager.cpp
+++ b/src/plugins/help/localhelpmanager.cpp
@@ -33,10 +33,8 @@
#ifdef QTC_WEBENGINE_HELPVIEWER
#include "webenginehelpviewer.h"
-#if QT_VERSION >= QT_VERSION_CHECK(5, 12, 0)
#include <QWebEngineUrlScheme>
#endif
-#endif
#ifdef QTC_LITEHTML_HELPVIEWER
#include "litehtmlhelpviewer.h"
#endif
diff --git a/src/plugins/help/macwebkithelpviewer.mm b/src/plugins/help/macwebkithelpviewer.mm
index 1cb2aa2596..be8a1c1c17 100644
--- a/src/plugins/help/macwebkithelpviewer.mm
+++ b/src/plugins/help/macwebkithelpviewer.mm
@@ -584,8 +584,9 @@ void MacWebKitHelpViewer::setHtml(const QString &html)
{
@autoreleasepool {
[m_widget->webView().mainFrame
- loadHTMLString:html.toNSString()
- baseURL:[NSURL fileURLWithPath:Core::ICore::resourcePath().toNSString()]];
+ loadHTMLString:html.toNSString()
+ baseURL:[NSURL
+ fileURLWithPath:Core::ICore::resourcePath().toString().toNSString()]];
}
}
diff --git a/src/plugins/help/searchwidget.cpp b/src/plugins/help/searchwidget.cpp
index cb2db9f76d..99793d4111 100644
--- a/src/plugins/help/searchwidget.cpp
+++ b/src/plugins/help/searchwidget.cpp
@@ -185,9 +185,9 @@ void SearchWidget::indexingStarted()
m_progress->setProgressValueAndText(1, tr("Indexing Documentation"));
m_progress->reportStarted();
- m_watcher.setFuture(m_progress->future());
connect(&m_watcher, &QFutureWatcherBase::canceled,
searchEngine, &QHelpSearchEngine::cancelIndexing);
+ m_watcher.setFuture(m_progress->future());
m_queryWidget->hide();
m_indexingDocumentationLabel->show();
diff --git a/src/plugins/help/webenginehelpviewer.cpp b/src/plugins/help/webenginehelpviewer.cpp
index 32c780113c..65d80c4d30 100644
--- a/src/plugins/help/webenginehelpviewer.cpp
+++ b/src/plugins/help/webenginehelpviewer.cpp
@@ -152,11 +152,7 @@ WebEngineHelpViewer::WebEngineHelpViewer(QWidget *parent) :
QTC_ASSERT(viewProfile, return);
if (!viewProfile->urlSchemeHandler("qthelp"))
viewProfile->installUrlSchemeHandler("qthelp", helpUrlSchemeHandler());
-#if (QT_VERSION >= QT_VERSION_CHECK(5, 13, 0))
viewProfile->setUrlRequestInterceptor(helpurlRequestInterceptor());
-#else
- viewProfile->setRequestInterceptor(helpurlRequestInterceptor());
-#endif
}
void WebEngineHelpViewer::setViewerFont(const QFont &font)
diff --git a/src/plugins/imageviewer/imageview.cpp b/src/plugins/imageviewer/imageview.cpp
index cb86d38c8a..c435666d15 100644
--- a/src/plugins/imageviewer/imageview.cpp
+++ b/src/plugins/imageviewer/imageview.cpp
@@ -67,6 +67,7 @@ ImageView::ImageView(ImageViewerFile *file)
setScene(new QGraphicsScene(this));
setTransformationAnchor(AnchorUnderMouse);
setDragMode(ScrollHandDrag);
+ setInteractive(false);
setViewportUpdateMode(FullViewportUpdate);
setFrameShape(QFrame::NoFrame);
setRenderHint(QPainter::SmoothPixmapTransform);
diff --git a/src/plugins/imageviewer/imageviewer.qbs b/src/plugins/imageviewer/imageviewer.qbs
index fd4bb8433e..ff6c6f977f 100644
--- a/src/plugins/imageviewer/imageviewer.qbs
+++ b/src/plugins/imageviewer/imageviewer.qbs
@@ -1,16 +1,15 @@
-import qbs 1.0
-
QtcPlugin {
name: "ImageViewer"
Depends { name: "Qt.svg"; required: false }
+ Depends { name: "Qt.svgwidgets"; condition: usesQt6; required: false }
Depends { name: "Qt.widgets" }
Depends { name: "Utils" }
Depends { name: "Core" }
Properties {
- condition: !Qt.svg.present
+ condition: !Qt.svg.present || (usesQt6 && !Qt.svgwidgets.present)
cpp.defines: base.concat("QT_NO_SVG")
}
diff --git a/src/plugins/imageviewer/imageviewerfile.cpp b/src/plugins/imageviewer/imageviewerfile.cpp
index 821e6ba77c..d39e4931ba 100644
--- a/src/plugins/imageviewer/imageviewerfile.cpp
+++ b/src/plugins/imageviewer/imageviewerfile.cpp
@@ -80,22 +80,25 @@ ImageViewerFile::~ImageViewerFile()
cleanUp();
}
-Core::IDocument::OpenResult ImageViewerFile::open(QString *errorString, const QString &fileName,
- const QString &realFileName)
+Core::IDocument::OpenResult ImageViewerFile::open(QString *errorString,
+ const Utils::FilePath &filePath,
+ const Utils::FilePath &realfilePath)
{
- QTC_CHECK(fileName == realFileName); // does not support auto save
- OpenResult success = openImpl(errorString, fileName);
+ QTC_CHECK(filePath == realfilePath); // does not support auto save
+ OpenResult success = openImpl(errorString, filePath);
emit openFinished(success == OpenResult::Success);
return success;
}
-Core::IDocument::OpenResult ImageViewerFile::openImpl(QString *errorString, const QString &fileName)
+Core::IDocument::OpenResult ImageViewerFile::openImpl(QString *errorString,
+ const Utils::FilePath &filePath)
{
cleanUp();
- if (!QFileInfo(fileName).isReadable())
+ if (!filePath.isReadableFile())
return OpenResult::ReadError;
+ const QString &fileName = filePath.toString();
QByteArray format = QImageReader::imageFormat(fileName);
// if it is impossible to recognize a file format - file will not be open correctly
if (format.isEmpty()) {
@@ -141,7 +144,7 @@ Core::IDocument::OpenResult ImageViewerFile::openImpl(QString *errorString, cons
emit imageSizeChanged(m_pixmap->size());
}
- setFilePath(Utils::FilePath::fromString(fileName));
+ setFilePath(filePath);
setMimeType(Utils::mimeTypeForFile(fileName).name());
return OpenResult::Success;
}
@@ -163,7 +166,7 @@ bool ImageViewerFile::reload(QString *errorString,
if (flag == FlagIgnore)
return true;
emit aboutToReload();
- bool success = (openImpl(errorString, filePath().toString()) == OpenResult::Success);
+ bool success = (openImpl(errorString, filePath()) == OpenResult::Success);
emit reloadFinished(success);
return success;
}
diff --git a/src/plugins/imageviewer/imageviewerfile.h b/src/plugins/imageviewer/imageviewerfile.h
index cf8c29fc60..4cab47a45c 100644
--- a/src/plugins/imageviewer/imageviewerfile.h
+++ b/src/plugins/imageviewer/imageviewerfile.h
@@ -57,8 +57,8 @@ public:
ImageViewerFile();
~ImageViewerFile() override;
- OpenResult open(QString *errorString, const QString &fileName,
- const QString &realFileName) override;
+ OpenResult open(QString *errorString, const Utils::FilePath &filePath,
+ const Utils::FilePath &realFilePath) override;
ReloadBehavior reloadBehavior(ChangeTrigger state, ChangeType type) const override;
bool reload(QString *errorString, ReloadFlag flag, ChangeType type) override;
@@ -78,7 +78,7 @@ signals:
private:
void cleanUp();
- OpenResult openImpl(QString *errorString, const QString &fileName);
+ OpenResult openImpl(QString *errorString, const Utils::FilePath &filePath);
ImageType m_type = TypeInvalid;
#ifndef QT_NO_SVG
diff --git a/src/plugins/incredibuild/cmakecommandbuilder.cpp b/src/plugins/incredibuild/cmakecommandbuilder.cpp
index 23fe80c215..b505c4b5ef 100644
--- a/src/plugins/incredibuild/cmakecommandbuilder.cpp
+++ b/src/plugins/incredibuild/cmakecommandbuilder.cpp
@@ -63,7 +63,7 @@ QString CMakeCommandBuilder::defaultArguments() const
if (buildDir.isEmpty())
buildDir = ".";
- return Utils::QtcProcess::joinArgs({"--build", buildDir, "--target", "all"});
+ return Utils::ProcessArgs::joinArgs({"--build", buildDir, "--target", "all"});
}
QString CMakeCommandBuilder::setMultiProcessArg(QString args)
diff --git a/src/plugins/ios/createsimulatordialog.cpp b/src/plugins/ios/createsimulatordialog.cpp
index 8dfda8ccec..19d49451c8 100644
--- a/src/plugins/ios/createsimulatordialog.cpp
+++ b/src/plugins/ios/createsimulatordialog.cpp
@@ -38,10 +38,9 @@ namespace Internal {
using namespace std::placeholders;
-CreateSimulatorDialog::CreateSimulatorDialog(QWidget *parent) :
- QDialog(parent),
- m_ui(new Ui::CreateSimulatorDialog),
- m_simControl(new SimulatorControl(this))
+CreateSimulatorDialog::CreateSimulatorDialog(QWidget *parent)
+ : QDialog(parent)
+ , m_ui(new Ui::CreateSimulatorDialog)
{
m_ui->setupUi(this);
m_ui->buttonBox->button(QDialogButtonBox::Ok)->setEnabled(false);
@@ -62,14 +61,14 @@ CreateSimulatorDialog::CreateSimulatorDialog(QWidget *parent) :
});
m_futureSync.setCancelOnWait(true);
- m_futureSync.addFuture(QFuture<void>(Utils::onResultReady(SimulatorControl::updateDeviceTypes(), this,
- &CreateSimulatorDialog::populateDeviceTypes)));
+ m_futureSync.addFuture(Utils::onResultReady(SimulatorControl::updateDeviceTypes(), this,
+ &CreateSimulatorDialog::populateDeviceTypes));
QFuture<QList<RuntimeInfo>> runtimesfuture = SimulatorControl::updateRuntimes();
Utils::onResultReady(runtimesfuture, this, [this](const QList<RuntimeInfo> &runtimes) {
m_runtimes = runtimes;
});
- m_futureSync.addFuture(QFuture<void>(runtimesfuture));
+ m_futureSync.addFuture(runtimesfuture);
populateRuntimes(DeviceTypeInfo());
}
diff --git a/src/plugins/ios/createsimulatordialog.h b/src/plugins/ios/createsimulatordialog.h
index 5c1a0c1ba5..d46b3b8da8 100644
--- a/src/plugins/ios/createsimulatordialog.h
+++ b/src/plugins/ios/createsimulatordialog.h
@@ -26,7 +26,8 @@
#pragma once
#include <QDialog>
-#include <QFutureSynchronizer>
+
+#include <utils/futuresynchronizer.h>
namespace Ios {
namespace Internal {
@@ -57,9 +58,8 @@ private:
void populateRuntimes(const DeviceTypeInfo &deviceType);
private:
- QFutureSynchronizer<void> m_futureSync;
+ Utils::FutureSynchronizer m_futureSync;
Ui::CreateSimulatorDialog *m_ui = nullptr;
- SimulatorControl *m_simControl = nullptr;
QList<RuntimeInfo> m_runtimes;
};
diff --git a/src/plugins/ios/iosbuildstep.cpp b/src/plugins/ios/iosbuildstep.cpp
index fdad257c2d..05904fae34 100644
--- a/src/plugins/ios/iosbuildstep.cpp
+++ b/src/plugins/ios/iosbuildstep.cpp
@@ -95,7 +95,7 @@ QWidget *IosBuildStep::createConfigWidget()
auto buildArgumentsLabel = new QLabel(tr("Base arguments:"), widget);
auto buildArgumentsTextEdit = new QPlainTextEdit(widget);
- buildArgumentsTextEdit->setPlainText(QtcProcess::joinArgs(baseArguments()));
+ buildArgumentsTextEdit->setPlainText(ProcessArgs::joinArgs(baseArguments()));
auto resetDefaultsButton = new QPushButton(widget);
resetDefaultsButton->setLayoutDirection(Qt::RightToLeft);
@@ -105,7 +105,7 @@ QWidget *IosBuildStep::createConfigWidget()
auto extraArgumentsLabel = new QLabel(tr("Extra arguments:"), widget);
auto extraArgumentsLineEdit = new QLineEdit(widget);
- extraArgumentsLineEdit->setText(QtcProcess::joinArgs(m_extraArguments));
+ extraArgumentsLineEdit->setText(ProcessArgs::joinArgs(m_extraArguments));
auto gridLayout = new QGridLayout(widget);
gridLayout->addWidget(buildArgumentsLabel, 0, 0, 1, 1);
@@ -125,19 +125,19 @@ QWidget *IosBuildStep::createConfigWidget()
updateDetails();
connect(buildArgumentsTextEdit, &QPlainTextEdit::textChanged, this, [=] {
- setBaseArguments(QtcProcess::splitArgs(buildArgumentsTextEdit->toPlainText()));
+ setBaseArguments(ProcessArgs::splitArgs(buildArgumentsTextEdit->toPlainText()));
resetDefaultsButton->setEnabled(!m_useDefaultArguments);
updateDetails();
});
connect(resetDefaultsButton, &QAbstractButton::clicked, this, [=] {
setBaseArguments(defaultArguments());
- buildArgumentsTextEdit->setPlainText(QtcProcess::joinArgs(baseArguments()));
+ buildArgumentsTextEdit->setPlainText(ProcessArgs::joinArgs(baseArguments()));
resetDefaultsButton->setEnabled(!m_useDefaultArguments);
});
connect(extraArgumentsLineEdit, &QLineEdit::editingFinished, [=] {
- setExtraArguments(QtcProcess::splitArgs(extraArgumentsLineEdit->text()));
+ setExtraArguments(ProcessArgs::splitArgs(extraArgumentsLineEdit->text()));
});
connect(ProjectExplorerPlugin::instance(), &ProjectExplorerPlugin::settingsChanged,
diff --git a/src/plugins/ios/iosconfigurations.cpp b/src/plugins/ios/iosconfigurations.cpp
index 4007f06a35..80b7ba766d 100644
--- a/src/plugins/ios/iosconfigurations.cpp
+++ b/src/plugins/ios/iosconfigurations.cpp
@@ -31,10 +31,7 @@
#include "iosprobe.h"
#include <coreplugin/icore.h>
-#include <utils/algorithm.h>
-#include <utils/synchronousprocess.h>
-#include <utils/qtcassert.h>
-#include <utils/synchronousprocess.h>
+
#include <projectexplorer/kitmanager.h>
#include <projectexplorer/kitinformation.h>
#include <projectexplorer/devicesupport/devicemanager.h>
@@ -42,14 +39,20 @@
#include <projectexplorer/toolchain.h>
#include <projectexplorer/gcctoolchain.h>
#include <projectexplorer/projectexplorerconstants.h>
+
#include <debugger/debuggeritemmanager.h>
#include <debugger/debuggeritem.h>
#include <debugger/debuggerkitinformation.h>
+
#include <qtsupport/baseqtversion.h>
#include <qtsupport/qtkitinformation.h>
#include <qtsupport/qtversionmanager.h>
#include <qtsupport/qtversionfactory.h>
+#include <utils/algorithm.h>
+#include <utils/qtcassert.h>
+#include <utils/qtcprocess.h>
+
#include <QDir>
#include <QDomDocument>
#include <QFileInfo>
@@ -232,11 +235,11 @@ static QByteArray decodeProvisioningProfile(const QString &path)
Utils::SynchronousProcess p;
p.setTimeoutS(3);
// path is assumed to be valid file path to .mobileprovision
- const QStringList args = {"smime", "-inform", "der", "-verify", "-in", path};
- Utils::SynchronousProcessResponse res = p.runBlocking({"openssl", args});
- if (res.result != Utils::SynchronousProcessResponse::Finished)
+ p.setCommand({"openssl", {"smime", "-inform", "der", "-verify", "-in", path}});
+ p.runBlocking();
+ if (p.result() != Utils::QtcProcess::Finished)
qCDebug(iosCommonLog) << "Reading signed provisioning file failed" << path;
- return res.stdOut().toLatin1();
+ return p.stdOut().toLatin1();
}
void IosConfigurations::updateAutomaticKitList()
@@ -580,8 +583,10 @@ IosToolChainFactory::IosToolChainFactory()
ProjectExplorer::Constants::CXX_LANGUAGE_ID});
}
-QList<ToolChain *> IosToolChainFactory::autoDetect(const QList<ToolChain *> &existingToolChains)
+QList<ToolChain *> IosToolChainFactory::autoDetect(const QList<ToolChain *> &existingToolChains,
+ const IDevice::Ptr &device)
{
+ Q_UNUSED(device);
QList<ClangToolChain *> existingClangToolChains = clangToolChains(existingToolChains);
const QList<XcodePlatform> platforms = XcodeProbe::detectPlatforms().values();
QList<ToolChain *> toolChains;
diff --git a/src/plugins/ios/iosconfigurations.h b/src/plugins/ios/iosconfigurations.h
index d041ac3f21..01cfb16ff6 100644
--- a/src/plugins/ios/iosconfigurations.h
+++ b/src/plugins/ios/iosconfigurations.h
@@ -98,7 +98,9 @@ class IosToolChainFactory : public ProjectExplorer::ToolChainFactory
public:
IosToolChainFactory();
- QList<ProjectExplorer::ToolChain *> autoDetect(const QList<ProjectExplorer::ToolChain *> &existingToolChains) override;
+ QList<ProjectExplorer::ToolChain *> autoDetect(
+ const QList<ProjectExplorer::ToolChain *> &existingToolChains,
+ const ProjectExplorer::IDevice::Ptr &device) override;
};
class IosConfigurations : public QObject
diff --git a/src/plugins/ios/iosdeploystep.cpp b/src/plugins/ios/iosdeploystep.cpp
index 0d24378a5a..6fbc08f5f7 100644
--- a/src/plugins/ios/iosdeploystep.cpp
+++ b/src/plugins/ios/iosdeploystep.cpp
@@ -235,8 +235,6 @@ QWidget *IosDeployStep::createConfigWidget()
auto widget = new QWidget;
widget->setObjectName("IosDeployStepWidget");
- setDisplayName(QString("<b>%1</b>").arg(displayName()));
- setSummaryText(displayName());
connect(this, &ProjectConfiguration::displayNameChanged,
this, &BuildStep::updateSummary);
diff --git a/src/plugins/ios/iosdsymbuildstep.cpp b/src/plugins/ios/iosdsymbuildstep.cpp
index 25a538665d..3c79ba9c0b 100644
--- a/src/plugins/ios/iosdsymbuildstep.cpp
+++ b/src/plugins/ios/iosdsymbuildstep.cpp
@@ -213,7 +213,7 @@ QWidget *IosDsymBuildStep::createConfigWidget()
commandLineEdit->setText(command().toString());
auto argumentsTextEdit = new QPlainTextEdit(widget);
- argumentsTextEdit->setPlainText(Utils::QtcProcess::joinArgs(arguments()));
+ argumentsTextEdit->setPlainText(Utils::ProcessArgs::joinArgs(arguments()));
auto argumentsLabel = new QLabel(tr("Arguments:"), widget);
@@ -238,7 +238,7 @@ QWidget *IosDsymBuildStep::createConfigWidget()
connect(argumentsTextEdit, &QPlainTextEdit::textChanged, this,
[this, argumentsTextEdit, resetDefaultsButton, updateDetails] {
- setArguments(Utils::QtcProcess::splitArgs(argumentsTextEdit->toPlainText()));
+ setArguments(Utils::ProcessArgs::splitArgs(argumentsTextEdit->toPlainText()));
resetDefaultsButton->setEnabled(!isDefault());
updateDetails();
});
@@ -255,7 +255,7 @@ QWidget *IosDsymBuildStep::createConfigWidget()
setCommand(defaultCommand());
setArguments(defaultArguments());
commandLineEdit->setText(command().toString());
- argumentsTextEdit->setPlainText(Utils::QtcProcess::joinArgs(arguments()));
+ argumentsTextEdit->setPlainText(Utils::ProcessArgs::joinArgs(arguments()));
resetDefaultsButton->setEnabled(!isDefault());
updateDetails();
});
diff --git a/src/plugins/ios/iosprobe.cpp b/src/plugins/ios/iosprobe.cpp
index 66518ad778..7adaea6d61 100644
--- a/src/plugins/ios/iosprobe.cpp
+++ b/src/plugins/ios/iosprobe.cpp
@@ -26,7 +26,7 @@
#include "iosprobe.h"
#include <utils/algorithm.h>
-#include <utils/synchronousprocess.h>
+#include <utils/qtcprocess.h>
#include <QDir>
#include <QFileInfo>
@@ -67,13 +67,14 @@ void XcodeProbe::detectDeveloperPaths()
{
Utils::SynchronousProcess selectedXcode;
selectedXcode.setTimeoutS(5);
- const CommandLine xcodeSelect{"/usr/bin/xcode-select", {"--print-path"}};
- Utils::SynchronousProcessResponse response = selectedXcode.run(xcodeSelect);
- if (response.result != Utils::SynchronousProcessResponse::Finished)
+ selectedXcode.setCommand({"/usr/bin/xcode-select", {"--print-path"}});
+ selectedXcode.setProcessUserEventWhileRunning();
+ selectedXcode.runBlocking();
+ if (selectedXcode.result() != QtcProcess::Finished)
qCWarning(probeLog)
<< QString::fromLatin1("Could not detect selected Xcode using xcode-select");
else
- addDeveloperPath(response.stdOut().trimmed());
+ addDeveloperPath(selectedXcode.stdOut().trimmed());
addDeveloperPath(defaultDeveloperPath);
}
diff --git a/src/plugins/ios/iosrunner.cpp b/src/plugins/ios/iosrunner.cpp
index 24bfe1fb6c..ffbd4f7f01 100644
--- a/src/plugins/ios/iosrunner.cpp
+++ b/src/plugins/ios/iosrunner.cpp
@@ -197,7 +197,7 @@ void IosRunner::start()
this, &IosRunner::handleFinished);
const Runnable runnable = runControl()->runnable();
- QStringList args = QtcProcess::splitArgs(runnable.commandLineArguments, OsTypeMac);
+ QStringList args = ProcessArgs::splitArgs(runnable.commandLineArguments, OsTypeMac);
if (m_qmlServerPort.isValid()) {
QUrl qmlServer;
qmlServer.setPort(m_qmlServerPort.number());
diff --git a/src/plugins/ios/iossettingswidget.cpp b/src/plugins/ios/iossettingswidget.cpp
index 24209f0b75..b1e767be4d 100644
--- a/src/plugins/ios/iossettingswidget.cpp
+++ b/src/plugins/ios/iossettingswidget.cpp
@@ -63,8 +63,7 @@ static void onSimOperation(const SimulatorInfo &simInfo, SimulatorOperationDialo
}
IosSettingsWidget::IosSettingsWidget()
- : m_ui(new Ui::IosSettingsWidget),
- m_simControl(new SimulatorControl(this))
+ : m_ui(new Ui::IosSettingsWidget)
{
m_ui->setupUi(this);
auto proxyModel = new QSortFilterProxyModel(this);
@@ -134,9 +133,9 @@ void IosSettingsWidget::onStart()
.arg(info.name).arg(info.runtimeName).arg(info.state),
Utils::StdErrFormat);
} else {
- futureList << QFuture<void>(Utils::onResultReady(m_simControl->startSimulator(info.identifier),
- std::bind(onSimOperation, info, statusDialog,
- tr("simulator start"), _1)));
+ futureList << QFuture<void>(Utils::onResultReady(
+ SimulatorControl::startSimulator(info.identifier),
+ std::bind(onSimOperation, info, statusDialog, tr("simulator start"), _1)));
}
}
@@ -167,12 +166,11 @@ void IosSettingsWidget::onCreate()
CreateSimulatorDialog createDialog(this);
if (createDialog.exec() == QDialog::Accepted) {
- QFuture<void> f = QFuture<void>(Utils::onResultReady(
- m_simControl->createSimulator(
- createDialog.name(),
- createDialog.deviceType(),
- createDialog.runtime()),
- std::bind(onSimulatorCreate, createDialog.name(), _1)));
+ QFuture<void> f = QFuture<void>(
+ Utils::onResultReady(SimulatorControl::createSimulator(createDialog.name(),
+ createDialog.deviceType(),
+ createDialog.runtime()),
+ std::bind(onSimulatorCreate, createDialog.name(), _1)));
statusDialog->addFutures({ f });
statusDialog->exec(); // Modal dialog returns only when all the operations are done or cancelled.
}
@@ -201,9 +199,9 @@ void IosSettingsWidget::onReset()
QList<QFuture<void>> futureList;
foreach (const SimulatorInfo &info, simulatorInfoList) {
- futureList << QFuture<void>(Utils::onResultReady(m_simControl->resetSimulator(info.identifier),
- std::bind(onSimOperation, info, statusDialog,
- tr("simulator reset"), _1)));
+ futureList << QFuture<void>(Utils::onResultReady(
+ SimulatorControl::resetSimulator(info.identifier),
+ std::bind(onSimOperation, info, statusDialog, tr("simulator reset"), _1)));
}
statusDialog->addFutures(futureList);
@@ -229,9 +227,9 @@ void IosSettingsWidget::onRename()
QPointer<SimulatorOperationDialog> statusDialog = new SimulatorOperationDialog(this);
statusDialog->setAttribute(Qt::WA_DeleteOnClose);
statusDialog->addMessage(tr("Renaming simulator device..."), Utils::NormalMessageFormat);
- QFuture<void> f = QFuture<void>(Utils::onResultReady(m_simControl->renameSimulator(simInfo.identifier, newName),
- std::bind(onSimOperation, simInfo, statusDialog,
- tr("simulator rename"), _1)));
+ QFuture<void> f = QFuture<void>(Utils::onResultReady(
+ SimulatorControl::renameSimulator(simInfo.identifier, newName),
+ std::bind(onSimOperation, simInfo, statusDialog, tr("simulator rename"), _1)));
statusDialog->addFutures({f});
statusDialog->exec(); // Modal dialog returns only when all the operations are done or cancelled.
}
@@ -258,9 +256,9 @@ void IosSettingsWidget::onDelete()
Utils::NormalMessageFormat);
QList<QFuture<void>> futureList;
foreach (const SimulatorInfo &info, simulatorInfoList) {
- futureList << QFuture<void>(Utils::onResultReady(m_simControl->deleteSimulator(info.identifier),
- std::bind(onSimOperation, info, statusDialog,
- tr("simulator delete"), _1)));
+ futureList << QFuture<void>(Utils::onResultReady(
+ SimulatorControl::deleteSimulator(info.identifier),
+ std::bind(onSimOperation, info, statusDialog, tr("simulator delete"), _1)));
}
statusDialog->addFutures(futureList);
@@ -289,10 +287,9 @@ void IosSettingsWidget::onScreenshot()
simulatorInfoList.count()), Utils::NormalMessageFormat);
QList<QFuture<void>> futureList;
foreach (const SimulatorInfo &info, simulatorInfoList) {
- futureList << QFuture<void>(Utils::onResultReady(m_simControl->takeSceenshot(info.identifier,
- generatePath(info)),
- std::bind(onSimOperation, info, statusDialog,
- tr("simulator screenshot"), _1)));
+ futureList << QFuture<void>(Utils::onResultReady(
+ SimulatorControl::takeSceenshot(info.identifier, generatePath(info)),
+ std::bind(onSimOperation, info, statusDialog, tr("simulator screenshot"), _1)));
}
statusDialog->addFutures(futureList);
diff --git a/src/plugins/ios/iossettingswidget.h b/src/plugins/ios/iossettingswidget.h
index e99afb448d..f0d3f74294 100644
--- a/src/plugins/ios/iossettingswidget.h
+++ b/src/plugins/ios/iossettingswidget.h
@@ -58,7 +58,6 @@ private:
private:
Ui::IosSettingsWidget *m_ui = nullptr;
- SimulatorControl *m_simControl = nullptr;
};
} // namespace Internal
diff --git a/src/plugins/ios/iostoolhandler.cpp b/src/plugins/ios/iostoolhandler.cpp
index f9318712a6..c64a273142 100644
--- a/src/plugins/ios/iostoolhandler.cpp
+++ b/src/plugins/ios/iostoolhandler.cpp
@@ -29,12 +29,15 @@
#include "iossimulator.h"
#include "simulatorcontrol.h"
-#include "debugger/debuggerconstants.h"
#include <coreplugin/icore.h>
-#include <utils/qtcassert.h>
+
+#include <debugger/debuggerconstants.h>
+
#include <utils/fileutils.h>
+#include <utils/futuresynchronizer.h>
+#include <utils/qtcassert.h>
+#include <utils/qtcprocess.h>
#include <utils/runextensions.h>
-#include <utils/synchronousprocess.h>
#include <QCoreApplication>
#include <QDir>
@@ -304,7 +307,6 @@ class IosSimulatorToolHandlerPrivate : public IosToolHandlerPrivate
{
public:
explicit IosSimulatorToolHandlerPrivate(const IosDeviceType &devType, IosToolHandler *q);
- ~IosSimulatorToolHandlerPrivate() override;
// IosToolHandlerPrivate overrides
public:
@@ -324,9 +326,8 @@ private:
private:
qint64 m_pid = -1;
- SimulatorControl *simCtl;
LogTailFiles outputLogger;
- QList<QFuture<void>> futureList;
+ Utils::FutureSynchronizer futureSynchronizer;
};
IosToolHandlerPrivate::IosToolHandlerPrivate(const IosDeviceType &devType,
@@ -799,22 +800,14 @@ void IosDeviceToolHandlerPrivate::stop(int errorCode)
// IosSimulatorToolHandlerPrivate
IosSimulatorToolHandlerPrivate::IosSimulatorToolHandlerPrivate(const IosDeviceType &devType,
- IosToolHandler *q)
- : IosToolHandlerPrivate(devType, q),
- simCtl(new SimulatorControl)
+ IosToolHandler *q)
+ : IosToolHandlerPrivate(devType, q)
{
QObject::connect(&outputLogger, &LogTailFiles::logMessage,
std::bind(&IosToolHandlerPrivate::appOutput, this, _1));
+ futureSynchronizer.setCancelOnWait(true);
}
-IosSimulatorToolHandlerPrivate::~IosSimulatorToolHandlerPrivate()
-{
- foreach (auto f, futureList) {
- if (!f.isFinished())
- f.cancel();
- }
- delete simCtl;
-}
void IosSimulatorToolHandlerPrivate::requestTransferApp(const QString &appBundlePath,
const QString &deviceIdentifier, int timeout)
{
@@ -839,7 +832,8 @@ void IosSimulatorToolHandlerPrivate::requestTransferApp(const QString &appBundle
if (SimulatorControl::isSimulatorRunning(m_deviceId))
installAppOnSimulator();
else
- futureList << QFuture<void>(Utils::onResultReady(simCtl->startSimulator(m_deviceId), onSimulatorStart));
+ futureSynchronizer.addFuture(
+ Utils::onResultReady(SimulatorControl::startSimulator(m_deviceId), onSimulatorStart));
}
void IosSimulatorToolHandlerPrivate::requestRunApp(const QString &appBundlePath,
@@ -875,7 +869,8 @@ void IosSimulatorToolHandlerPrivate::requestRunApp(const QString &appBundlePath,
if (SimulatorControl::isSimulatorRunning(m_deviceId))
launchAppOnSimulator(extraArgs);
else
- futureList << QFuture<void>(Utils::onResultReady(simCtl->startSimulator(m_deviceId), onSimulatorStart));
+ futureSynchronizer.addFuture(
+ Utils::onResultReady(SimulatorControl::startSimulator(m_deviceId), onSimulatorStart));
}
void IosSimulatorToolHandlerPrivate::requestDeviceInfo(const QString &deviceId, int timeout)
@@ -900,10 +895,8 @@ void IosSimulatorToolHandlerPrivate::stop(int errorCode)
kill(m_pid, SIGKILL);
#endif
m_pid = -1;
- foreach (auto f, futureList) {
- if (!f.isFinished())
- f.cancel();
- }
+ futureSynchronizer.cancelAllFutures();
+ futureSynchronizer.flushFinishedFutures();
toolExited(errorCode);
emit q->finished(q);
@@ -927,8 +920,9 @@ void IosSimulatorToolHandlerPrivate::installAppOnSimulator()
};
isTransferringApp(m_bundlePath, m_deviceId, 20, 100, "");
- auto installFuture = simCtl->installApp(m_deviceId, Utils::FilePath::fromString(m_bundlePath));
- futureList << QFuture<void>(Utils::onResultReady(installFuture, onResponseAppInstall));
+ auto installFuture = SimulatorControl::installApp(m_deviceId,
+ Utils::FilePath::fromString(m_bundlePath));
+ futureSynchronizer.addFuture(Utils::onResultReady(installFuture, onResponseAppInstall));
}
void IosSimulatorToolHandlerPrivate::launchAppOnSimulator(const QStringList &extraArgs)
@@ -977,10 +971,10 @@ void IosSimulatorToolHandlerPrivate::launchAppOnSimulator(const QStringList &ext
gotInferiorPid(m_bundlePath, m_deviceId, response.pID);
didStartApp(m_bundlePath, m_deviceId, Ios::IosToolHandler::Success);
// Start monitoring app's life signs.
- futureList << Utils::runAsync(monitorPid, response.pID);
+ futureSynchronizer.addFuture(Utils::runAsync(monitorPid, response.pID));
if (captureConsole)
- futureList << Utils::runAsync(&LogTailFiles::exec, &outputLogger, stdoutFile,
- stderrFile);
+ futureSynchronizer.addFuture(Utils::runAsync(&LogTailFiles::exec, &outputLogger,
+ stdoutFile, stderrFile));
} else {
m_pid = -1;
errorMsg(IosToolHandler::tr("Application launch on simulator failed. %1")
@@ -991,11 +985,16 @@ void IosSimulatorToolHandlerPrivate::launchAppOnSimulator(const QStringList &ext
}
};
- futureList << QFuture<void>(Utils::onResultReady(
- simCtl->launchApp(m_deviceId, bundleId, debugRun, extraArgs,
- captureConsole ? stdoutFile->fileName() : QString(),
- captureConsole ? stderrFile->fileName() : QString()),
- onResponseAppLaunch));
+ futureSynchronizer.addFuture(
+ Utils::onResultReady(SimulatorControl::launchApp(m_deviceId,
+ bundleId,
+ debugRun,
+ extraArgs,
+ captureConsole ? stdoutFile->fileName()
+ : QString(),
+ captureConsole ? stderrFile->fileName()
+ : QString()),
+ onResponseAppLaunch));
}
bool IosSimulatorToolHandlerPrivate::isResponseValid(const SimulatorControl::ResponseData &responseData)
@@ -1015,8 +1014,7 @@ bool IosSimulatorToolHandlerPrivate::isResponseValid(const SimulatorControl::Res
QString IosToolHandler::iosDeviceToolPath()
{
- QString res = Core::ICore::libexecPath() + QLatin1String("/ios/iostool");
- return res;
+ return Core::ICore::libexecPath("ios/iostool").toString();
}
IosToolHandler::IosToolHandler(const Internal::IosDeviceType &devType, QObject *parent) :
diff --git a/src/plugins/ios/simulatorcontrol.cpp b/src/plugins/ios/simulatorcontrol.cpp
index 19dbe3c1bb..099de44b9f 100644
--- a/src/plugins/ios/simulatorcontrol.cpp
+++ b/src/plugins/ios/simulatorcontrol.cpp
@@ -29,7 +29,7 @@
#include <utils/algorithm.h>
#include <utils/runextensions.h>
#include <utils/qtcassert.h>
-#include <utils/synchronousprocess.h>
+#include <utils/qtcprocess.h>
#ifdef Q_OS_MAC
#include <CoreFoundation/CoreFoundation.h>
@@ -83,12 +83,13 @@ static bool runCommand(const CommandLine &command, QString *stdOutput, QString *
{
SynchronousProcess p;
p.setTimeoutS(-1);
- SynchronousProcessResponse resp = p.runBlocking(command);
+ p.setCommand(command);
+ p.runBlocking();
if (stdOutput)
- *stdOutput = resp.stdOut();
+ *stdOutput = p.stdOut();
if (allOutput)
- *allOutput = resp.allOutput();
- return resp.result == SynchronousProcessResponse::Finished;
+ *allOutput = p.allOutput();
+ return p.result() == QtcProcess::Finished;
}
static bool runSimCtlCommand(QStringList args, QString *output, QString *allOutput = nullptr)
@@ -177,54 +178,44 @@ static QList<RuntimeInfo> getAvailableRuntimes()
return runtimes;
}
-class SimulatorControlPrivate {
-private:
- SimulatorControlPrivate();
- ~SimulatorControlPrivate();
-
- static SimulatorInfo deviceInfo(const QString &simUdid);
- static QString bundleIdentifier(const Utils::FilePath &bundlePath);
- static QString bundleExecutable(const Utils::FilePath &bundlePath);
-
- void startSimulator(QFutureInterface<SimulatorControl::ResponseData> &fi, const QString &simUdid);
- void installApp(QFutureInterface<SimulatorControl::ResponseData> &fi, const QString &simUdid,
- const Utils::FilePath &bundlePath);
- void launchApp(QFutureInterface<SimulatorControl::ResponseData> &fi, const QString &simUdid,
- const QString &bundleIdentifier, bool waitForDebugger,
- const QStringList &extraArgs, const QString &stdoutPath,
- const QString &stderrPath);
- void deleteSimulator(QFutureInterface<SimulatorControl::ResponseData> &fi,
- const QString &simUdid);
- void resetSimulator(QFutureInterface<SimulatorControl::ResponseData> &fi,
- const QString &simUdid);
- void renameSimulator(QFutureInterface<SimulatorControl::ResponseData> &fi,
- const QString &simUdid, const QString &newName);
- void createSimulator(QFutureInterface<SimulatorControl::ResponseData> &fi,
- const QString &name, const DeviceTypeInfo &deviceType,
- const RuntimeInfo &runtime);
- void takeSceenshot(QFutureInterface<SimulatorControl::ResponseData> &fi, const QString &simUdid,
- const QString &filePath);
-
- static QList<SimulatorInfo> availableDevices;
- static QList<DeviceTypeInfo> availableDeviceTypes;
- static QList<RuntimeInfo> availableRuntimes;
- friend class SimulatorControl;
-};
-
-SimulatorControl::SimulatorControl(QObject *parent) :
- QObject(parent),
- d(new SimulatorControlPrivate)
-{
-}
-
-SimulatorControl::~SimulatorControl()
-{
- delete d;
-}
+static SimulatorInfo deviceInfo(const QString &simUdid);
+static QString bundleIdentifier(const Utils::FilePath &bundlePath);
+static QString bundleExecutable(const Utils::FilePath &bundlePath);
+
+static void startSimulator(QFutureInterface<SimulatorControl::ResponseData> &fi,
+ const QString &simUdid);
+static void installApp(QFutureInterface<SimulatorControl::ResponseData> &fi,
+ const QString &simUdid,
+ const Utils::FilePath &bundlePath);
+static void launchApp(QFutureInterface<SimulatorControl::ResponseData> &fi,
+ const QString &simUdid,
+ const QString &bundleIdentifier,
+ bool waitForDebugger,
+ const QStringList &extraArgs,
+ const QString &stdoutPath,
+ const QString &stderrPath);
+static void deleteSimulator(QFutureInterface<SimulatorControl::ResponseData> &fi,
+ const QString &simUdid);
+static void resetSimulator(QFutureInterface<SimulatorControl::ResponseData> &fi,
+ const QString &simUdid);
+static void renameSimulator(QFutureInterface<SimulatorControl::ResponseData> &fi,
+ const QString &simUdid,
+ const QString &newName);
+static void createSimulator(QFutureInterface<SimulatorControl::ResponseData> &fi,
+ const QString &name,
+ const DeviceTypeInfo &deviceType,
+ const RuntimeInfo &runtime);
+static void takeSceenshot(QFutureInterface<SimulatorControl::ResponseData> &fi,
+ const QString &simUdid,
+ const QString &filePath);
+
+static QList<SimulatorInfo> s_availableDevices;
+static QList<DeviceTypeInfo> s_availableDeviceTypes;
+static QList<RuntimeInfo> s_availableRuntimes;
QList<SimulatorInfo> SimulatorControl::availableSimulators()
{
- return SimulatorControlPrivate::availableDevices;
+ return s_availableDevices;
}
static QList<SimulatorInfo> getAllSimulatorDevices()
@@ -266,21 +257,21 @@ QFuture<QList<DeviceTypeInfo> > SimulatorControl::updateDeviceTypes()
{
QFuture< QList<DeviceTypeInfo> > future = Utils::runAsync(getAvailableDeviceTypes);
Utils::onResultReady(future, [](const QList<DeviceTypeInfo> &deviceTypes) {
- SimulatorControlPrivate::availableDeviceTypes = deviceTypes;
+ s_availableDeviceTypes = deviceTypes;
});
return future;
}
QList<RuntimeInfo> SimulatorControl::availableRuntimes()
{
- return SimulatorControlPrivate::availableRuntimes;
+ return s_availableRuntimes;
}
QFuture<QList<RuntimeInfo> > SimulatorControl::updateRuntimes()
{
QFuture< QList<RuntimeInfo> > future = Utils::runAsync(getAvailableRuntimes);
Utils::onResultReady(future, [](const QList<RuntimeInfo> &runtimes) {
- SimulatorControlPrivate::availableRuntimes = runtimes;
+ s_availableRuntimes = runtimes;
});
return future;
}
@@ -288,9 +279,8 @@ QFuture<QList<RuntimeInfo> > SimulatorControl::updateRuntimes()
QFuture< QList<SimulatorInfo> > SimulatorControl::updateAvailableSimulators()
{
QFuture< QList<SimulatorInfo> > future = Utils::runAsync(getAvailableSimulators);
- Utils::onResultReady(future, [](const QList<SimulatorInfo> &devices) {
- SimulatorControlPrivate::availableDevices = devices;
- });
+ Utils::onResultReady(future,
+ [](const QList<SimulatorInfo> &devices) { s_availableDevices = devices; });
return future;
}
@@ -298,53 +288,60 @@ bool SimulatorControl::isSimulatorRunning(const QString &simUdid)
{
if (simUdid.isEmpty())
return false;
- return SimulatorControlPrivate::deviceInfo(simUdid).isBooted();
+ return deviceInfo(simUdid).isBooted();
}
QString SimulatorControl::bundleIdentifier(const Utils::FilePath &bundlePath)
{
- return SimulatorControlPrivate::bundleIdentifier(bundlePath);
+ return Internal::bundleIdentifier(bundlePath);
}
QString SimulatorControl::bundleExecutable(const Utils::FilePath &bundlePath)
{
- return SimulatorControlPrivate::bundleExecutable(bundlePath);
+ return Internal::bundleExecutable(bundlePath);
}
-QFuture<SimulatorControl::ResponseData> SimulatorControl::startSimulator(const QString &simUdid) const
+QFuture<SimulatorControl::ResponseData> SimulatorControl::startSimulator(const QString &simUdid)
{
- return Utils::runAsync(&SimulatorControlPrivate::startSimulator, d, simUdid);
+ return Utils::runAsync(Internal::startSimulator, simUdid);
}
-QFuture<SimulatorControl::ResponseData>
-SimulatorControl::installApp(const QString &simUdid, const Utils::FilePath &bundlePath) const
+QFuture<SimulatorControl::ResponseData> SimulatorControl::installApp(
+ const QString &simUdid, const Utils::FilePath &bundlePath)
{
- return Utils::runAsync(&SimulatorControlPrivate::installApp, d, simUdid, bundlePath);
+ return Utils::runAsync(Internal::installApp, simUdid, bundlePath);
}
-QFuture<SimulatorControl::ResponseData>
-SimulatorControl::launchApp(const QString &simUdid, const QString &bundleIdentifier,
- bool waitForDebugger, const QStringList &extraArgs,
- const QString &stdoutPath, const QString &stderrPath) const
+QFuture<SimulatorControl::ResponseData> SimulatorControl::launchApp(const QString &simUdid,
+ const QString &bundleIdentifier,
+ bool waitForDebugger,
+ const QStringList &extraArgs,
+ const QString &stdoutPath,
+ const QString &stderrPath)
{
- return Utils::runAsync(&SimulatorControlPrivate::launchApp, d, simUdid, bundleIdentifier,
- waitForDebugger, extraArgs, stdoutPath, stderrPath);
+ return Utils::runAsync(Internal::launchApp,
+ simUdid,
+ bundleIdentifier,
+ waitForDebugger,
+ extraArgs,
+ stdoutPath,
+ stderrPath);
}
-QFuture<SimulatorControl::ResponseData> SimulatorControl::deleteSimulator(const QString &simUdid) const
+QFuture<SimulatorControl::ResponseData> SimulatorControl::deleteSimulator(const QString &simUdid)
{
- return Utils::runAsync(&SimulatorControlPrivate::deleteSimulator, d, simUdid);
+ return Utils::runAsync(Internal::deleteSimulator, simUdid);
}
-QFuture<SimulatorControl::ResponseData> SimulatorControl::resetSimulator(const QString &simUdid) const
+QFuture<SimulatorControl::ResponseData> SimulatorControl::resetSimulator(const QString &simUdid)
{
- return Utils::runAsync(&SimulatorControlPrivate::resetSimulator, d, simUdid);
+ return Utils::runAsync(Internal::resetSimulator, simUdid);
}
QFuture<SimulatorControl::ResponseData> SimulatorControl::renameSimulator(const QString &simUdid,
- const QString &newName) const
+ const QString &newName)
{
- return Utils::runAsync(&SimulatorControlPrivate::renameSimulator, d, simUdid, newName);
+ return Utils::runAsync(Internal::renameSimulator, simUdid, newName);
}
QFuture<SimulatorControl::ResponseData>
@@ -352,25 +349,18 @@ SimulatorControl::createSimulator(const QString &name,
const DeviceTypeInfo &deviceType,
const RuntimeInfo &runtime)
{
- return Utils::runAsync(&SimulatorControlPrivate::createSimulator, d, name, deviceType, runtime);
+ return Utils::runAsync(Internal::createSimulator, name, deviceType, runtime);
}
QFuture<SimulatorControl::ResponseData> SimulatorControl::takeSceenshot(const QString &simUdid,
const QString &filePath)
{
- return Utils::runAsync(&SimulatorControlPrivate::takeSceenshot, d, simUdid, filePath);
+ return Utils::runAsync(Internal::takeSceenshot, simUdid, filePath);
}
// Static members
-QList<SimulatorInfo> SimulatorControlPrivate::availableDevices;
-QList<DeviceTypeInfo> SimulatorControlPrivate::availableDeviceTypes;
-QList<RuntimeInfo> SimulatorControlPrivate::availableRuntimes;
-
-SimulatorControlPrivate::SimulatorControlPrivate() = default;
-
-SimulatorControlPrivate::~SimulatorControlPrivate() = default;
-SimulatorInfo SimulatorControlPrivate::deviceInfo(const QString &simUdid)
+SimulatorInfo deviceInfo(const QString &simUdid)
{
auto matchDevice = [simUdid](const SimulatorInfo &device) {
return device.identifier == simUdid;
@@ -382,7 +372,7 @@ SimulatorInfo SimulatorControlPrivate::deviceInfo(const QString &simUdid)
return device;
}
-QString SimulatorControlPrivate::bundleIdentifier(const Utils::FilePath &bundlePath)
+QString bundleIdentifier(const Utils::FilePath &bundlePath)
{
QString bundleID;
#ifdef Q_OS_MAC
@@ -402,7 +392,7 @@ QString SimulatorControlPrivate::bundleIdentifier(const Utils::FilePath &bundleP
return bundleID;
}
-QString SimulatorControlPrivate::bundleExecutable(const Utils::FilePath &bundlePath)
+QString bundleExecutable(const Utils::FilePath &bundlePath)
{
QString executable;
#ifdef Q_OS_MAC
@@ -421,8 +411,7 @@ QString SimulatorControlPrivate::bundleExecutable(const Utils::FilePath &bundleP
return executable;
}
-void SimulatorControlPrivate::startSimulator(QFutureInterface<SimulatorControl::ResponseData> &fi,
- const QString &simUdid)
+void startSimulator(QFutureInterface<SimulatorControl::ResponseData> &fi, const QString &simUdid)
{
SimulatorControl::ResponseData response(simUdid);
SimulatorInfo simInfo = deviceInfo(simUdid);
@@ -479,8 +468,9 @@ void SimulatorControlPrivate::startSimulator(QFutureInterface<SimulatorControl::
}
}
-void SimulatorControlPrivate::installApp(QFutureInterface<SimulatorControl::ResponseData> &fi,
- const QString &simUdid, const Utils::FilePath &bundlePath)
+void installApp(QFutureInterface<SimulatorControl::ResponseData> &fi,
+ const QString &simUdid,
+ const Utils::FilePath &bundlePath)
{
QTC_CHECK(bundlePath.exists());
@@ -492,10 +482,13 @@ void SimulatorControlPrivate::installApp(QFutureInterface<SimulatorControl::Resp
fi.reportResult(response);
}
-void SimulatorControlPrivate::launchApp(QFutureInterface<SimulatorControl::ResponseData> &fi,
- const QString &simUdid, const QString &bundleIdentifier,
- bool waitForDebugger, const QStringList &extraArgs,
- const QString &stdoutPath, const QString &stderrPath)
+void launchApp(QFutureInterface<SimulatorControl::ResponseData> &fi,
+ const QString &simUdid,
+ const QString &bundleIdentifier,
+ bool waitForDebugger,
+ const QStringList &extraArgs,
+ const QString &stdoutPath,
+ const QString &stderrPath)
{
SimulatorControl::ResponseData response(simUdid);
if (!bundleIdentifier.isEmpty() && !fi.isCanceled()) {
@@ -530,8 +523,7 @@ void SimulatorControlPrivate::launchApp(QFutureInterface<SimulatorControl::Respo
}
}
-void SimulatorControlPrivate::deleteSimulator(QFutureInterface<SimulatorControl::ResponseData> &fi,
- const QString &simUdid)
+void deleteSimulator(QFutureInterface<SimulatorControl::ResponseData> &fi, const QString &simUdid)
{
SimulatorControl::ResponseData response(simUdid);
response.success = runSimCtlCommand({"delete", simUdid}, nullptr, &response.commandOutput);
@@ -540,8 +532,7 @@ void SimulatorControlPrivate::deleteSimulator(QFutureInterface<SimulatorControl:
fi.reportResult(response);
}
-void SimulatorControlPrivate::resetSimulator(QFutureInterface<SimulatorControl::ResponseData> &fi,
- const QString &simUdid)
+void resetSimulator(QFutureInterface<SimulatorControl::ResponseData> &fi, const QString &simUdid)
{
SimulatorControl::ResponseData response(simUdid);
response.success = runSimCtlCommand({"erase", simUdid}, nullptr, &response.commandOutput);
@@ -550,8 +541,9 @@ void SimulatorControlPrivate::resetSimulator(QFutureInterface<SimulatorControl::
fi.reportResult(response);
}
-void SimulatorControlPrivate::renameSimulator(QFutureInterface<SimulatorControl::ResponseData> &fi,
- const QString &simUdid, const QString &newName)
+void renameSimulator(QFutureInterface<SimulatorControl::ResponseData> &fi,
+ const QString &simUdid,
+ const QString &newName)
{
SimulatorControl::ResponseData response(simUdid);
response.success = runSimCtlCommand({"rename", simUdid, newName},
@@ -562,10 +554,10 @@ void SimulatorControlPrivate::renameSimulator(QFutureInterface<SimulatorControl:
fi.reportResult(response);
}
-void SimulatorControlPrivate::createSimulator(QFutureInterface<SimulatorControl::ResponseData> &fi,
- const QString &name,
- const DeviceTypeInfo &deviceType,
- const RuntimeInfo &runtime)
+void createSimulator(QFutureInterface<SimulatorControl::ResponseData> &fi,
+ const QString &name,
+ const DeviceTypeInfo &deviceType,
+ const RuntimeInfo &runtime)
{
SimulatorControl::ResponseData response("Invalid");
if (!name.isEmpty()) {
@@ -581,8 +573,9 @@ void SimulatorControlPrivate::createSimulator(QFutureInterface<SimulatorControl:
fi.reportResult(response);
}
-void SimulatorControlPrivate::takeSceenshot(QFutureInterface<SimulatorControl::ResponseData> &fi,
- const QString &simUdid, const QString &filePath)
+void takeSceenshot(QFutureInterface<SimulatorControl::ResponseData> &fi,
+ const QString &simUdid,
+ const QString &filePath)
{
SimulatorControl::ResponseData response(simUdid);
response.success = runSimCtlCommand({"io", simUdid, "screenshot", filePath},
diff --git a/src/plugins/ios/simulatorcontrol.h b/src/plugins/ios/simulatorcontrol.h
index 5d4351ae50..a79c24eab4 100644
--- a/src/plugins/ios/simulatorcontrol.h
+++ b/src/plugins/ios/simulatorcontrol.h
@@ -74,9 +74,8 @@ public:
class DeviceTypeInfo : public SimulatorEntity {};
-class SimulatorControl : public QObject
+class SimulatorControl
{
- Q_OBJECT
public:
struct ResponseData {
ResponseData(const QString & udid):
@@ -89,10 +88,6 @@ public:
};
public:
- explicit SimulatorControl(QObject* parent = nullptr);
- ~SimulatorControl() override;
-
-public:
static QList<DeviceTypeInfo> availableDeviceTypes();
static QFuture<QList<DeviceTypeInfo> > updateDeviceTypes();
static QList<RuntimeInfo> availableRuntimes();
@@ -104,23 +99,24 @@ public:
static QString bundleExecutable(const Utils::FilePath &bundlePath);
public:
- QFuture<ResponseData> startSimulator(const QString &simUdid) const;
- QFuture<ResponseData> installApp(const QString &simUdid, const Utils::FilePath &bundlePath) const;
- QFuture<ResponseData> launchApp(const QString &simUdid, const QString &bundleIdentifier,
- bool waitForDebugger, const QStringList &extraArgs,
- const QString& stdoutPath = QString(),
- const QString& stderrPath = QString()) const;
- QFuture<ResponseData> deleteSimulator(const QString &simUdid) const;
- QFuture<ResponseData> resetSimulator(const QString &simUdid) const;
- QFuture<ResponseData> renameSimulator(const QString &simUdid, const QString &newName) const;
- QFuture<ResponseData> createSimulator(const QString &name,
- const DeviceTypeInfo &deviceType,
- const RuntimeInfo &runtime);
- QFuture<ResponseData> takeSceenshot(const QString &simUdid, const QString &filePath);
-
-private:
- SimulatorControlPrivate *d;
+ static QFuture<ResponseData> startSimulator(const QString &simUdid);
+ static QFuture<ResponseData> installApp(const QString &simUdid,
+ const Utils::FilePath &bundlePath);
+ static QFuture<ResponseData> launchApp(const QString &simUdid,
+ const QString &bundleIdentifier,
+ bool waitForDebugger,
+ const QStringList &extraArgs,
+ const QString &stdoutPath = QString(),
+ const QString &stderrPath = QString());
+ static QFuture<ResponseData> deleteSimulator(const QString &simUdid);
+ static QFuture<ResponseData> resetSimulator(const QString &simUdid);
+ static QFuture<ResponseData> renameSimulator(const QString &simUdid, const QString &newName);
+ static QFuture<ResponseData> createSimulator(const QString &name,
+ const DeviceTypeInfo &deviceType,
+ const RuntimeInfo &runtime);
+ static QFuture<ResponseData> takeSceenshot(const QString &simUdid, const QString &filePath);
};
+
} // namespace Internal
} // namespace Ios
diff --git a/src/plugins/ios/simulatorinfomodel.cpp b/src/plugins/ios/simulatorinfomodel.cpp
index 2ca0427aac..923338ccff 100644
--- a/src/plugins/ios/simulatorinfomodel.cpp
+++ b/src/plugins/ios/simulatorinfomodel.cpp
@@ -126,13 +126,12 @@ QModelIndex SimulatorInfoModel::parent(const QModelIndex &) const
void SimulatorInfoModel::requestSimulatorInfo()
{
- if (!m_fetchFuture.futures().isEmpty() && !m_fetchFuture.futures().at(0).isFinished())
+ m_fetchFuture.flushFinishedFutures();
+ if (!m_fetchFuture.isEmpty())
return; // Ignore the request if the last request is still pending.
- m_fetchFuture.clearFutures();
- m_fetchFuture.addFuture(QFuture<void>(Utils::onResultReady(
- SimulatorControl::updateAvailableSimulators(),
- this, &SimulatorInfoModel::populateSimulators)));
+ m_fetchFuture.addFuture(Utils::onResultReady(SimulatorControl::updateAvailableSimulators(),
+ this, &SimulatorInfoModel::populateSimulators));
}
void SimulatorInfoModel::populateSimulators(const SimulatorInfoList &simulatorList)
diff --git a/src/plugins/ios/simulatorinfomodel.h b/src/plugins/ios/simulatorinfomodel.h
index 174865e7b5..1810dda304 100644
--- a/src/plugins/ios/simulatorinfomodel.h
+++ b/src/plugins/ios/simulatorinfomodel.h
@@ -27,8 +27,10 @@
#include "simulatorcontrol.h"
+#include <utils/futuresynchronizer.h>
+
#include <QAbstractListModel>
-#include <QFutureSynchronizer>
+
namespace Ios {
namespace Internal {
@@ -55,7 +57,7 @@ private:
void populateSimulators(const SimulatorInfoList &simulatorList);
private:
- QFutureSynchronizer<void> m_fetchFuture;
+ Utils::FutureSynchronizer m_fetchFuture;
SimulatorInfoList m_simList;
};
diff --git a/src/plugins/ios/simulatoroperationdialog.cpp b/src/plugins/ios/simulatoroperationdialog.cpp
index 88ce5d48a6..6327ca6887 100644
--- a/src/plugins/ios/simulatoroperationdialog.cpp
+++ b/src/plugins/ios/simulatoroperationdialog.cpp
@@ -75,9 +75,9 @@ void SimulatorOperationDialog::addFutures(const QList<QFuture<void> > &futureLis
foreach (auto future, futureList) {
if (!future.isFinished() || !future.isCanceled()) {
auto watcher = new QFutureWatcher<void>;
- watcher->setFuture(future);
connect(watcher, &QFutureWatcher<void>::finished,
this, &SimulatorOperationDialog::futureFinished);
+ watcher->setFuture(future);
m_futureWatchList << watcher;
}
}
diff --git a/src/plugins/languageclient/CMakeLists.txt b/src/plugins/languageclient/CMakeLists.txt
index 04ffe805a9..c624860b80 100644
--- a/src/plugins/languageclient/CMakeLists.txt
+++ b/src/plugins/languageclient/CMakeLists.txt
@@ -22,5 +22,6 @@ add_qtc_plugin(LanguageClient
languageclient_global.h
locatorfilter.cpp locatorfilter.h
lspinspector.cpp lspinspector.h
+ progressmanager.cpp progressmanager.h
semantichighlightsupport.cpp semantichighlightsupport.h
)
diff --git a/src/plugins/languageclient/client.cpp b/src/plugins/languageclient/client.cpp
index ece007c27d..9424c0323c 100644
--- a/src/plugins/languageclient/client.cpp
+++ b/src/plugins/languageclient/client.cpp
@@ -34,14 +34,19 @@
#include <coreplugin/icore.h>
#include <coreplugin/idocument.h>
#include <coreplugin/messagemanager.h>
+#include <coreplugin/progressmanager/progressmanager.h>
+
#include <languageserverprotocol/completion.h>
#include <languageserverprotocol/diagnostics.h>
#include <languageserverprotocol/languagefeatures.h>
#include <languageserverprotocol/messages.h>
#include <languageserverprotocol/servercapabilities.h>
#include <languageserverprotocol/workspace.h>
+#include <languageserverprotocol/progresssupport.h>
+
#include <projectexplorer/project.h>
#include <projectexplorer/session.h>
+
#include <texteditor/codeassist/documentcontentcompletion.h>
#include <texteditor/codeassist/iassistprocessor.h>
#include <texteditor/ioutlinewidget.h>
@@ -51,9 +56,10 @@
#include <texteditor/texteditor.h>
#include <texteditor/texteditoractionhandler.h>
#include <texteditor/texteditorsettings.h>
+
#include <utils/mimetypes/mimedatabase.h>
#include <utils/qtcprocess.h>
-#include <utils/synchronousprocess.h>
+
#include <QDebug>
#include <QLoggingCategory>
@@ -79,6 +85,7 @@ Client::Client(BaseClientInterface *clientInterface)
, m_documentSymbolCache(this)
, m_hoverHandler(this)
, m_symbolSupport(this)
+ , m_tokentSupport(this)
{
m_clientProviders.completionAssistProvider = new LanguageClientCompletionAssistProvider(this);
m_clientProviders.functionHintProvider = new FunctionHintAssistProvider(this);
@@ -98,6 +105,9 @@ Client::Client(BaseClientInterface *clientInterface)
&TextEditor::TextEditorSettings::fontSettingsChanged,
this,
&Client::rehighlight);
+
+ m_tokentSupport.setTokenTypesMap(SemanticTokens::defaultTokenTypesMap());
+ m_tokentSupport.setTokenModifiersMap(SemanticTokens::defaultTokenModifiersMap());
}
QString Client::name() const
@@ -158,6 +168,7 @@ static ClientCapabilities generateClientCapabilities()
allowDynamicRegistration.setDynamicRegistration(true);
workspaceCapabilities.setDidChangeConfiguration(allowDynamicRegistration);
workspaceCapabilities.setExecuteCommand(allowDynamicRegistration);
+ workspaceCapabilities.setConfiguration(true);
capabilities.setWorkspace(workspaceCapabilities);
TextDocumentClientCapabilities documentCapabilities;
@@ -246,8 +257,35 @@ static ClientCapabilities generateClientCapabilities()
documentCapabilities.setFormatting(allowDynamicRegistration);
documentCapabilities.setRangeFormatting(allowDynamicRegistration);
documentCapabilities.setOnTypeFormatting(allowDynamicRegistration);
+ SemanticTokensClientCapabilities tokens;
+ tokens.setDynamicRegistration(true);
+ FullSemanticTokenOptions tokenOptions;
+ tokenOptions.setDelta(true);
+ SemanticTokensClientCapabilities::Requests tokenRequests;
+ tokenRequests.setFull(tokenOptions);
+ tokens.setRequests(tokenRequests);
+ tokens.setTokenTypes({"type",
+ "class",
+ "enumMember",
+ "typeParameter",
+ "parameter",
+ "variable",
+ "function",
+ "macro",
+ "keyword",
+ "comment",
+ "string",
+ "number",
+ "operator"});
+ tokens.setTokenModifiers({"declaration", "definition"});
+ tokens.setFormats({"relative"});
+ documentCapabilities.setSemanticTokens(tokens);
capabilities.setTextDocument(documentCapabilities);
+ WindowClientClientCapabilities window;
+ window.setWorkDoneProgress(true);
+ capabilities.setWindow(window);
+
return capabilities;
}
@@ -258,7 +296,7 @@ void Client::initialize()
QTC_ASSERT(m_state == Uninitialized, return);
qCDebug(LOGLSPCLIENT) << "initializing language server " << m_displayName;
InitializeParams params;
- params.setCapabilities(generateClientCapabilities());
+ params.setCapabilities(m_clientCapabilities);
params.setInitializationOptions(m_initializationOptions);
if (m_project) {
params.setRootUri(DocumentUri::fromFilePath(m_project->projectDirectory()));
@@ -299,6 +337,16 @@ Client::State Client::state() const
return m_state;
}
+ClientCapabilities Client::defaultClientCapabilities()
+{
+ return generateClientCapabilities();
+}
+
+void Client::setClientCapabilities(const LanguageServerProtocol::ClientCapabilities &caps)
+{
+ m_clientCapabilities = caps;
+}
+
void Client::openDocument(TextEditor::TextDocument *document)
{
using namespace TextEditor;
@@ -306,6 +354,7 @@ void Client::openDocument(TextEditor::TextDocument *document)
return;
m_openedDocument[document] = document->plainText();
+
if (m_state != Initialized)
return;
@@ -316,7 +365,7 @@ void Client::openDocument(TextEditor::TextDocument *document)
return;
const TextDocumentRegistrationOptions option(
m_dynamicCapabilities.option(method).toObject());
- if (option.isValid(nullptr)
+ if (option.isValid()
&& !option.filterApplies(filePath, Utils::mimeTypeForName(document->mimeType()))) {
return;
}
@@ -339,10 +388,13 @@ void Client::openDocument(TextEditor::TextDocument *document)
sendContent(DidOpenTextDocumentNotification(DidOpenTextDocumentParams(item)));
const Client *currentClient = LanguageClientManager::clientForDocument(document);
- if (currentClient == this) // this is the active client for the document so directly activate it
+ if (currentClient == this) {
+ // this is the active client for the document so directly activate it
activateDocument(document);
- else if (currentClient == nullptr) // there is no client for this document so assign it to this server
+ } else if (m_activateDocAutomatically && currentClient == nullptr) {
+ // there is no client for this document so assign it to this server
LanguageClientManager::openDocumentWithClient(document, this);
+ }
}
void Client::sendContent(const IContent &content)
@@ -389,7 +441,7 @@ void Client::updateCompletionProvider(TextEditor::TextDocument *document)
Utils::mimeTypeForName(document->mimeType()));
const ServerCapabilities::CompletionOptions completionOptions(options);
- if (completionOptions.isValid(nullptr))
+ if (completionOptions.isValid())
clientCompletionProvider->setTriggerCharacters(completionOptions.triggerCharacters());
}
@@ -417,7 +469,7 @@ void Client::updateFunctionHintProvider(TextEditor::TextDocument *document)
Utils::mimeTypeForName(document->mimeType()));
const ServerCapabilities::SignatureHelpOptions signatureOptions(options);
- if (signatureOptions.isValid(nullptr))
+ if (signatureOptions.isValid())
clientFunctionHintProvider->setTriggerCharacters(signatureOptions.triggerCharacters());
}
@@ -497,6 +549,7 @@ void Client::activateDocument(TextEditor::TextDocument *document)
auto uri = DocumentUri::fromFilePath(document->filePath());
m_diagnosticManager.showDiagnostics(uri);
SemanticHighligtingSupport::applyHighlight(document, m_highlights.value(uri), capabilities());
+ m_tokentSupport.updateSemanticTokens(document);
// only replace the assist provider if the language server support it
updateCompletionProvider(document);
updateFunctionHintProvider(document);
@@ -540,6 +593,15 @@ bool Client::documentOpen(const TextEditor::TextDocument *document) const
return m_openedDocument.contains(const_cast<TextEditor::TextDocument *>(document));
}
+TextEditor::TextDocument *Client::documentForFilePath(const Utils::FilePath &file) const
+{
+ for (auto it = m_openedDocument.cbegin(); it != m_openedDocument.cend(); ++it) {
+ if (it.key()->filePath() == file)
+ return it.key();
+ }
+ return nullptr;
+}
+
void Client::documentContentsSaved(TextEditor::TextDocument *document)
{
if (!m_openedDocument.contains(document))
@@ -552,7 +614,7 @@ void Client::documentContentsSaved(TextEditor::TextDocument *document)
if (sendMessage) {
const TextDocumentSaveRegistrationOptions option(
m_dynamicCapabilities.option(method).toObject());
- if (option.isValid(nullptr)) {
+ if (option.isValid()) {
sendMessage = option.filterApplies(document->filePath(),
Utils::mimeTypeForName(document->mimeType()));
includeText = option.includeText().value_or(includeText);
@@ -586,7 +648,7 @@ void Client::documentWillSave(Core::IDocument *document)
sendMessage = registered.value();
if (sendMessage) {
const TextDocumentRegistrationOptions option(m_dynamicCapabilities.option(method));
- if (option.isValid(nullptr)) {
+ if (option.isValid()) {
sendMessage = option.filterApplies(filePath,
Utils::mimeTypeForName(document->mimeType()));
}
@@ -617,7 +679,7 @@ void Client::documentContentsChanged(TextEditor::TextDocument *document,
if (syncKind != TextDocumentSyncKind::None) {
const TextDocumentChangeRegistrationOptions option(
m_dynamicCapabilities.option(method).toObject());
- syncKind = option.isValid(nullptr) ? option.syncKind() : syncKind;
+ syncKind = option.isValid() ? option.syncKind() : syncKind;
}
}
@@ -660,16 +722,22 @@ void Client::documentContentsChanged(TextEditor::TextDocument *document,
void Client::registerCapabilities(const QList<Registration> &registrations)
{
m_dynamicCapabilities.registerCapability(registrations);
- auto methodRegistered = [&](const QString &method) {
- return Utils::anyOf(registrations, Utils::equal(&Registration::method, method));
- };
- if (methodRegistered(CompletionRequest::methodName)) {
- for (auto document : m_openedDocument.keys())
- updateCompletionProvider(document);
- }
- if (methodRegistered(SignatureHelpRequest::methodName)) {
- for (auto document : m_openedDocument.keys())
- updateFunctionHintProvider(document);
+ for (const Registration &registration : registrations) {
+ if (registration.method() == CompletionRequest::methodName) {
+ for (auto document : m_openedDocument.keys())
+ updateCompletionProvider(document);
+ }
+ if (registration.method() == SignatureHelpRequest::methodName) {
+ for (auto document : m_openedDocument.keys())
+ updateFunctionHintProvider(document);
+ }
+ if (registration.method() == "textDocument/semanticTokens") {
+ SemanticTokensOptions options(registration.registerOptions());
+ if (options.isValid())
+ m_tokentSupport.setLegend(options.legend());
+ for (auto document : m_openedDocument.keys())
+ m_tokentSupport.updateSemanticTokens(document);
+ }
}
emit capabilitiesChanged(m_dynamicCapabilities);
}
@@ -677,12 +745,26 @@ void Client::registerCapabilities(const QList<Registration> &registrations)
void Client::unregisterCapabilities(const QList<Unregistration> &unregistrations)
{
m_dynamicCapabilities.unregisterCapability(unregistrations);
+ for (const Unregistration &unregistration : unregistrations) {
+ if (unregistration.method() == CompletionRequest::methodName) {
+ for (auto document : m_openedDocument.keys())
+ updateCompletionProvider(document);
+ }
+ if (unregistration.method() == SignatureHelpRequest::methodName) {
+ for (auto document : m_openedDocument.keys())
+ updateFunctionHintProvider(document);
+ }
+ if (unregistration.method() == "textDocument/semanticTokens") {
+ for (auto document : m_openedDocument.keys())
+ m_tokentSupport.updateSemanticTokens(document);
+ }
+ }
emit capabilitiesChanged(m_dynamicCapabilities);
}
TextEditor::HighlightingResult createHighlightingResult(const SymbolInformation &info)
{
- if (!info.isValid(nullptr))
+ if (!info.isValid())
return {};
const Position &start = info.location().range().start();
return TextEditor::HighlightingResult(start.line() + 1,
@@ -771,7 +853,7 @@ void Client::requestCodeActions(const CodeActionRequest &request)
return;
const TextDocumentRegistrationOptions option(
m_dynamicCapabilities.option(method).toObject());
- if (option.isValid(nullptr) && !option.filterApplies(fileName))
+ if (option.isValid() && !option.filterApplies(fileName))
return;
} else {
Utils::variant<bool, CodeActionOptions> provider
@@ -863,6 +945,11 @@ void Client::setSupportedLanguage(const LanguageFilter &filter)
m_languagFilter = filter;
}
+void Client::setActivateDocumentAutomatically(bool enabled)
+{
+ m_activateDocAutomatically = enabled;
+}
+
void Client::setInitializationOptions(const QJsonObject &initializationOptions)
{
m_initializationOptions = initializationOptions;
@@ -922,6 +1009,7 @@ bool Client::reset()
m_diagnosticManager.clearDiagnostics();
for (auto it = m_openedDocument.cbegin(); it != m_openedDocument.cend(); ++it)
it.key()->disconnect(this);
+ m_openedDocument.clear();
// temporary container needed since m_resetAssistProvider is changed in resetAssistProviders
for (TextEditor::TextDocument *document : m_resetAssistProvider.keys())
resetAssistProviders(document);
@@ -939,6 +1027,12 @@ void Client::setError(const QString &message)
m_state = Error;
}
+void Client::setProgressTitleForToken(const LanguageServerProtocol::ProgressToken &token,
+ const QString &message)
+{
+ m_progressManager.setTitleForToken(token, message);
+}
+
void Client::handleMessage(const BaseMessage &message)
{
LanguageClientManager::logBaseMessage(LspLogMessage::ServerMessage, name(), message);
@@ -1008,8 +1102,8 @@ void Client::showMessageBox(const ShowMessageRequestParams &message, const Messa
connect(box, &QMessageBox::finished, this, [=]{
ShowMessageRequest::Response response(id);
const MessageActionItem &item = itemForButton.value(box->clickedButton());
- response.setResult(item.isValid(nullptr) ? LanguageClientValue<MessageActionItem>(item)
- : LanguageClientValue<MessageActionItem>());
+ response.setResult(item.isValid() ? LanguageClientValue<MessageActionItem>(item)
+ : LanguageClientValue<MessageActionItem>());
sendContent(response);
});
box->show();
@@ -1064,6 +1158,8 @@ void Client::sendPostponedDocumentUpdates()
if (currentWidget && currentWidget->textDocument() == update.document)
cursorPositionChanged(currentWidget);
+
+ m_tokentSupport.updateSemanticTokens(update.document);
}
}
@@ -1075,40 +1171,39 @@ void Client::handleResponse(const MessageId &id, const QByteArray &content, QTex
void Client::handleMethod(const QString &method, const MessageId &id, const IContent *content)
{
- ErrorHierarchy error;
auto logError = [&](const JsonObject &content) {
log(QJsonDocument(content).toJson(QJsonDocument::Indented) + '\n'
- + tr("Invalid parameter in \"%1\": %2").arg(method, error.toString()));
+ + tr("Invalid parameter in \"%1\"").arg(method));
};
if (method == PublishDiagnosticsNotification::methodName) {
auto params = dynamic_cast<const PublishDiagnosticsNotification *>(content)->params().value_or(PublishDiagnosticsParams());
- if (params.isValid(&error))
+ if (params.isValid())
handleDiagnostics(params);
else
logError(params);
} else if (method == LogMessageNotification::methodName) {
auto params = dynamic_cast<const LogMessageNotification *>(content)->params().value_or(LogMessageParams());
- if (params.isValid(&error))
+ if (params.isValid())
log(params);
else
logError(params);
} else if (method == SemanticHighlightNotification::methodName) {
auto params = dynamic_cast<const SemanticHighlightNotification *>(content)->params().value_or(SemanticHighlightingParams());
- if (params.isValid(&error))
+ if (params.isValid())
handleSemanticHighlight(params);
else
logError(params);
} else if (method == ShowMessageNotification::methodName) {
auto params = dynamic_cast<const ShowMessageNotification *>(content)->params().value_or(ShowMessageParams());
- if (params.isValid(&error))
+ if (params.isValid())
log(params);
else
logError(params);
} else if (method == ShowMessageRequest::methodName) {
auto request = dynamic_cast<const ShowMessageRequest *>(content);
auto params = request->params().value_or(ShowMessageRequestParams());
- if (params.isValid(&error)) {
+ if (params.isValid()) {
showMessageBox(params, request->id());
} else {
ShowMessageRequest::Response response(request->id());
@@ -1123,19 +1218,19 @@ void Client::handleMethod(const QString &method, const MessageId &id, const ICon
}
} else if (method == RegisterCapabilityRequest::methodName) {
auto params = dynamic_cast<const RegisterCapabilityRequest *>(content)->params().value_or(RegistrationParams());
- if (params.isValid(&error))
+ if (params.isValid())
registerCapabilities(params.registrations());
else
logError(params);
} else if (method == UnregisterCapabilityRequest::methodName) {
auto params = dynamic_cast<const UnregisterCapabilityRequest *>(content)->params().value_or(UnregistrationParams());
- if (params.isValid(&error))
+ if (params.isValid())
unregisterCapabilities(params.unregistrations());
else
logError(params);
} else if (method == ApplyWorkspaceEditRequest::methodName) {
auto params = dynamic_cast<const ApplyWorkspaceEditRequest *>(content)->params().value_or(ApplyWorkspaceEditParams());
- if (params.isValid(&error))
+ if (params.isValid())
applyWorkspaceEdit(params.edit());
else
logError(params);
@@ -1154,7 +1249,19 @@ void Client::handleMethod(const QString &method, const MessageId &id, const ICon
}
response.setResult(result);
sendContent(response);
- } else if (id.isValid(&error)) {
+ } else if (method == WorkDoneProgressCreateRequest::methodName) {
+ sendContent(WorkDoneProgressCreateRequest::Response(
+ dynamic_cast<const WorkDoneProgressCreateRequest *>(content)->id()));
+ } else if (method == ProgressNotification::methodName) {
+ if (Utils::optional<ProgressParams> params
+ = dynamic_cast<const ProgressNotification *>(content)->params()) {
+ if (!params->isValid())
+ logError(*params);
+ m_progressManager.handleProgress(*params);
+ if (ProgressManager::isProgressEndMessage(*params))
+ emit workDone(params->token());
+ }
+ } else if (id.isValid()) {
Response<JsonObject, JsonObject> response(id);
ResponseError<JsonObject> error;
error.setCode(ResponseError<JsonObject>::MethodNotFound);
@@ -1228,8 +1335,7 @@ void Client::initializeCallback(const InitializeRequest::Response &initResponse)
{
QTC_ASSERT(m_state == InitializeRequested, return);
if (optional<ResponseError<InitializeError>> error = initResponse.error()) {
- if (error.value().data().has_value()
- && error.value().data().value().retry().value_or(false)) {
+ if (error.value().data().has_value() && error.value().data().value().retry()) {
const QString title(tr("Language Server \"%1\" Initialize Error").arg(m_displayName));
auto result = QMessageBox::warning(Core::ICore::dialogParent(),
title,
@@ -1251,13 +1357,23 @@ void Client::initializeCallback(const InitializeRequest::Response &initResponse)
log(tr("No initialize result."));
} else {
const InitializeResult &result = _result.value();
- ErrorHierarchy error;
- if (!result.isValid(&error)) { // continue on ill formed result
+ if (!result.isValid()) { // continue on ill formed result
log(QJsonDocument(result).toJson(QJsonDocument::Indented) + '\n'
- + tr("Initialize result is not valid: ") + error.toString());
+ + tr("Initialize result is not valid"));
+ }
+ const Utils::optional<ServerInfo> serverInfo = result.serverInfo();
+ if (serverInfo) {
+ if (!serverInfo->isValid()) {
+ log(QJsonDocument(result).toJson(QJsonDocument::Indented) + '\n'
+ + tr("Server Info is not valid"));
+ } else {
+ m_serverName = serverInfo->name();
+ if (const Utils::optional<QString> version = serverInfo->version())
+ m_serverVersion = version.value();
+ }
}
- m_serverCapabilities = result.capabilities().value_or(ServerCapabilities());
+ m_serverCapabilities = result.capabilities();
}
if (auto completionProvider = qobject_cast<LanguageClientCompletionAssistProvider *>(
@@ -1274,6 +1390,10 @@ void Client::initializeCallback(const InitializeRequest::Response &initResponse)
.value_or(ServerCapabilities::SignatureHelpOptions())
.triggerCharacters());
}
+ auto tokenProvider = m_serverCapabilities.semanticTokensProvider().value_or(
+ SemanticTokensOptions());
+ if (tokenProvider.isValid())
+ m_tokentSupport.setLegend(tokenProvider.legend());
qCDebug(LOGLSPCLIENT) << "language server " << m_displayName << " initialized";
m_state = Initialized;
diff --git a/src/plugins/languageclient/client.h b/src/plugins/languageclient/client.h
index fca5a6a040..f9a4617681 100644
--- a/src/plugins/languageclient/client.h
+++ b/src/plugins/languageclient/client.h
@@ -36,6 +36,8 @@
#include "languageclientquickfix.h"
#include "languageclientsettings.h"
#include "languageclientsymbolsupport.h"
+#include "progressmanager.h"
+#include "semantichighlightsupport.h"
#include <coreplugin/messagemanager.h>
@@ -47,6 +49,8 @@
#include <languageserverprotocol/initializemessages.h>
#include <languageserverprotocol/languagefeatures.h>
#include <languageserverprotocol/messages.h>
+#include <languageserverprotocol/progresssupport.h>
+#include <languageserverprotocol/semantictokens.h>
#include <languageserverprotocol/shutdownmessages.h>
#include <languageserverprotocol/textsynchronization.h>
@@ -109,13 +113,21 @@ public:
bool reachable() const { return m_state == Initialized; }
// capabilities
+ static LanguageServerProtocol::ClientCapabilities defaultClientCapabilities();
+ void setClientCapabilities(const LanguageServerProtocol::ClientCapabilities &caps);
const LanguageServerProtocol::ServerCapabilities &capabilities() const;
+ QString serverName() const { return m_serverName; }
+ QString serverVersion() const { return m_serverVersion; }
const DynamicCapabilities &dynamicCapabilities() const;
void registerCapabilities(const QList<LanguageServerProtocol::Registration> &registrations);
void unregisterCapabilities(const QList<LanguageServerProtocol::Unregistration> &unregistrations);
+ void setLocatorsEnabled(bool enabled) { m_locatorsEnabled = enabled; }
+ bool locatorsEnabled() const { return m_locatorsEnabled; }
+
// document synchronization
void setSupportedLanguage(const LanguageFilter &filter);
+ void setActivateDocumentAutomatically(bool enabled);
bool isSupportedDocument(const TextEditor::TextDocument *document) const;
bool isSupportedFile(const Utils::FilePath &filePath, const QString &mimeType) const;
bool isSupportedUri(const LanguageServerProtocol::DocumentUri &uri) const;
@@ -124,6 +136,7 @@ public:
void activateDocument(TextEditor::TextDocument *document);
void deactivateDocument(TextEditor::TextDocument *document);
bool documentOpen(const TextEditor::TextDocument *document) const;
+ TextEditor::TextDocument *documentForFilePath(const Utils::FilePath &file) const;
void documentContentsSaved(TextEditor::TextDocument *document);
void documentWillSave(Core::IDocument *document);
void documentContentsChanged(TextEditor::TextDocument *document,
@@ -167,10 +180,13 @@ signals:
void initialized(const LanguageServerProtocol::ServerCapabilities &capabilities);
void capabilitiesChanged(const DynamicCapabilities &capabilities);
void documentUpdated(TextEditor::TextDocument *document);
+ void workDone(const LanguageServerProtocol::ProgressToken &token);
void finished();
protected:
void setError(const QString &message);
+ void setProgressTitleForToken(const LanguageServerProtocol::ProgressToken &token,
+ const QString &message);
void handleMessage(const LanguageServerProtocol::BaseMessage &message);
private:
@@ -198,6 +214,9 @@ private:
void updateFunctionHintProvider(TextEditor::TextDocument *document);
void requestDocumentHighlights(TextEditor::TextEditorWidget *widget);
+ LanguageServerProtocol::SemanticRequestTypes supportedSemanticRequests(TextEditor::TextDocument *document) const;
+ void requestSemanticTokens(TextEditor::TextEditorWidget *widget);
+ void handleSemanticTokens(const LanguageServerProtocol::SemanticTokens &tokens);
void rehighlight();
using ContentHandler = std::function<void(const QByteArray &, QTextCodec *, QString &,
@@ -218,6 +237,7 @@ private:
QMap<TextEditor::TextEditorWidget *, QTimer *> m_documentHighlightsTimer;
QTimer m_documentUpdateTimer;
Utils::Id m_id;
+ LanguageServerProtocol::ClientCapabilities m_clientCapabilities = defaultClientCapabilities();
LanguageServerProtocol::ServerCapabilities m_serverCapabilities;
DynamicCapabilities m_dynamicCapabilities;
struct AssistProviders
@@ -239,6 +259,12 @@ private:
const ProjectExplorer::Project *m_project = nullptr;
QSet<TextEditor::IAssistProcessor *> m_runningAssistProcessors;
SymbolSupport m_symbolSupport;
+ ProgressManager m_progressManager;
+ bool m_activateDocAutomatically = false;
+ SemanticTokenSupport m_tokentSupport;
+ QString m_serverName;
+ QString m_serverVersion;
+ bool m_locatorsEnabled = true;
};
} // namespace LanguageClient
diff --git a/src/plugins/languageclient/languageclient.pro b/src/plugins/languageclient/languageclient.pro
index 79619e1ca6..a29a27c910 100644
--- a/src/plugins/languageclient/languageclient.pro
+++ b/src/plugins/languageclient/languageclient.pro
@@ -22,7 +22,8 @@ HEADERS += \
languageclientutils.h \
locatorfilter.h \
lspinspector.h \
- semantichighlightsupport.h
+ progressmanager.h \
+ semantichighlightsupport.h \
SOURCES += \
@@ -44,7 +45,8 @@ SOURCES += \
languageclientutils.cpp \
locatorfilter.cpp \
lspinspector.cpp \
- semantichighlightsupport.cpp
+ progressmanager.cpp \
+ semantichighlightsupport.cpp \
RESOURCES += \
languageclient.qrc
diff --git a/src/plugins/languageclient/languageclient.qbs b/src/plugins/languageclient/languageclient.qbs
index 4fd0e69cec..a5dbc641f6 100644
--- a/src/plugins/languageclient/languageclient.qbs
+++ b/src/plugins/languageclient/languageclient.qbs
@@ -52,7 +52,11 @@ QtcPlugin {
"locatorfilter.h",
"lspinspector.cpp",
"lspinspector.h",
+ "progressmanager.cpp",
+ "progressmanager.h",
"semantichighlightsupport.cpp",
"semantichighlightsupport.h",
]
+
+ Export { Depends { name: "LanguageServerProtocol" } }
}
diff --git a/src/plugins/languageclient/languageclient_global.h b/src/plugins/languageclient/languageclient_global.h
index 3755671537..8a63c660ac 100644
--- a/src/plugins/languageclient/languageclient_global.h
+++ b/src/plugins/languageclient/languageclient_global.h
@@ -48,6 +48,7 @@ const char LANGUAGECLIENT_WORKSPACE_CLASS_FILTER_ID[] = "Workspace Classes and S
const char LANGUAGECLIENT_WORKSPACE_CLASS_FILTER_DISPLAY_NAME[] = QT_TRANSLATE_NOOP("LanguageClient", "Classes and Structs in Workspace");
const char LANGUAGECLIENT_WORKSPACE_METHOD_FILTER_ID[] = "Workspace Functions and Methods";
const char LANGUAGECLIENT_WORKSPACE_METHOD_FILTER_DISPLAY_NAME[] = QT_TRANSLATE_NOOP("LanguageClient", "Functions and Methods in Workspace");
+const char G_TOOLS_LANGUAGECLIENT[] = "QtCreator.Group.Tools.LanguageClient";
} // namespace Constants
} // namespace LanguageClient
diff --git a/src/plugins/languageclient/languageclientcompletionassist.cpp b/src/plugins/languageclient/languageclientcompletionassist.cpp
index a0a9abd6cf..0affc6fe8a 100644
--- a/src/plugins/languageclient/languageclientcompletionassist.cpp
+++ b/src/plugins/languageclient/languageclientcompletionassist.cpp
@@ -31,9 +31,10 @@
#include <languageserverprotocol/completion.h>
#include <texteditor/codeassist/assistinterface.h>
#include <texteditor/codeassist/assistproposalitem.h>
-#include <texteditor/codeassist/iassistprocessor.h>
#include <texteditor/codeassist/genericproposal.h>
#include <texteditor/codeassist/genericproposalmodel.h>
+#include <texteditor/codeassist/iassistprocessor.h>
+#include <texteditor/snippets/snippet.h>
#include <texteditor/texteditorsettings.h>
#include <utils/algorithm.h>
#include <utils/textutils.h>
@@ -131,7 +132,9 @@ void LanguageClientCompletionItem::apply(TextDocumentManipulatorInterface &manip
applyTextEdit(manipulator, edit);
}
if (!m_triggeredCommitCharacter.isNull())
- manipulator.insertCodeSnippet(manipulator.currentPosition(), m_triggeredCommitCharacter);
+ manipulator.insertCodeSnippet(manipulator.currentPosition(),
+ m_triggeredCommitCharacter,
+ &Snippet::parse);
}
QIcon LanguageClientCompletionItem::icon() const
@@ -184,7 +187,7 @@ bool LanguageClientCompletionItem::isSnippet() const
bool LanguageClientCompletionItem::isValid() const
{
- return m_item.isValid(nullptr);
+ return m_item.isValid();
}
quint64 LanguageClientCompletionItem::hash() const
diff --git a/src/plugins/languageclient/languageclientformatter.cpp b/src/plugins/languageclient/languageclientformatter.cpp
index 31883d5fef..6233d79bcc 100644
--- a/src/plugins/languageclient/languageclientformatter.cpp
+++ b/src/plugins/languageclient/languageclientformatter.cpp
@@ -80,7 +80,7 @@ QFutureWatcher<ChangeSet> *LanguageClientFormatter::format(
if (!registered.value())
return nullptr;
const TextDocumentRegistrationOptions option(dynamicCapabilities.option(method).toObject());
- if (option.isValid(nullptr)
+ if (option.isValid()
&& !option.filterApplies(filePath, Utils::mimeTypeForName(m_document->mimeType()))) {
return nullptr;
}
@@ -113,10 +113,10 @@ QFutureWatcher<ChangeSet> *LanguageClientFormatter::format(
m_ignoreCancel = true;
m_progress.reportStarted();
auto watcher = new QFutureWatcher<ChangeSet>();
- watcher->setFuture(m_progress.future());
QObject::connect(watcher, &QFutureWatcher<Text::Replacements>::canceled, [this]() {
cancelCurrentRequest();
});
+ watcher->setFuture(m_progress.future());
return watcher;
}
diff --git a/src/plugins/languageclient/languageclienthoverhandler.cpp b/src/plugins/languageclient/languageclienthoverhandler.cpp
index d930fd8a8c..bf537d6f00 100644
--- a/src/plugins/languageclient/languageclienthoverhandler.cpp
+++ b/src/plugins/languageclient/languageclienthoverhandler.cpp
@@ -86,7 +86,7 @@ void HoverHandler::identifyMatch(TextEditor::TextEditorWidget *editorWidget,
if (sendMessage) {
const TextDocumentRegistrationOptions option(
m_client->dynamicCapabilities().option(HoverRequest::methodName).toObject());
- if (option.isValid(nullptr)) {
+ if (option.isValid()) {
sendMessage = option.filterApplies(editorWidget->textDocument()->filePath(),
Utils::mimeTypeForName(
editorWidget->textDocument()->mimeType()));
diff --git a/src/plugins/languageclient/languageclientinterface.cpp b/src/plugins/languageclient/languageclientinterface.cpp
index be1f2bdb20..203c497897 100644
--- a/src/plugins/languageclient/languageclientinterface.cpp
+++ b/src/plugins/languageclient/languageclientinterface.cpp
@@ -27,9 +27,6 @@
#include "languageclientsettings.h"
-#include <utils/qtcprocess.h>
-#include <utils/synchronousprocess.h>
-
#include <QLoggingCategory>
using namespace LanguageServerProtocol;
@@ -101,7 +98,7 @@ StdIOClientInterface::StdIOClientInterface()
StdIOClientInterface::~StdIOClientInterface()
{
- Utils::SynchronousProcess::stopProcess(m_process);
+ m_process.stopProcess();
}
bool StdIOClientInterface::start()
@@ -114,14 +111,9 @@ bool StdIOClientInterface::start()
return true;
}
-void StdIOClientInterface::setExecutable(const QString &executable)
-{
- m_process.setProgram(executable);
-}
-
-void StdIOClientInterface::setArguments(const QString &arguments)
+void StdIOClientInterface::setCommandLine(const Utils::CommandLine &cmd)
{
- m_process.setArguments(Utils::QtcProcess::splitArgs(arguments));
+ m_process.setCommand(cmd);
}
void StdIOClientInterface::setWorkingDirectory(const QString &workingDirectory)
diff --git a/src/plugins/languageclient/languageclientinterface.h b/src/plugins/languageclient/languageclientinterface.h
index 69055bc49e..770784931f 100644
--- a/src/plugins/languageclient/languageclientinterface.h
+++ b/src/plugins/languageclient/languageclientinterface.h
@@ -29,8 +29,9 @@
#include <languageserverprotocol/basemessage.h>
+#include <utils/qtcprocess.h>
+
#include <QBuffer>
-#include <QProcess>
namespace LanguageClient {
@@ -78,13 +79,12 @@ public:
bool start() override;
// These functions only have an effect if they are called before start
- void setExecutable(const QString &executable);
- void setArguments(const QString &arguments);
+ void setCommandLine(const Utils::CommandLine &cmd);
void setWorkingDirectory(const QString &workingDirectory);
protected:
void sendData(const QByteArray &data) final;
- QProcess m_process;
+ Utils::QtcProcess m_process;
private:
void readError();
diff --git a/src/plugins/languageclient/languageclientmanager.cpp b/src/plugins/languageclient/languageclientmanager.cpp
index 412c3042d6..24afdaac64 100644
--- a/src/plugins/languageclient/languageclientmanager.cpp
+++ b/src/plugins/languageclient/languageclientmanager.cpp
@@ -33,12 +33,14 @@
#include <coreplugin/find/searchresultwindow.h>
#include <coreplugin/icore.h>
#include <languageserverprotocol/messages.h>
+#include <languageserverprotocol/progresssupport.h>
#include <projectexplorer/project.h>
#include <projectexplorer/projectexplorer.h>
#include <projectexplorer/session.h>
#include <texteditor/textdocument.h>
#include <texteditor/texteditor.h>
#include <texteditor/textmark.h>
+#include <utils/algorithm.h>
#include <utils/executeondestruction.h>
#include <utils/mimetypes/mimedatabase.h>
#include <utils/theme/theme.h>
@@ -67,6 +69,8 @@ LanguageClientManager::LanguageClientManager(QObject *parent)
JsonRpcMessageHandler::registerMessageProvider<WorkSpaceFolderRequest>();
JsonRpcMessageHandler::registerMessageProvider<RegisterCapabilityRequest>();
JsonRpcMessageHandler::registerMessageProvider<UnregisterCapabilityRequest>();
+ JsonRpcMessageHandler::registerMessageProvider<WorkDoneProgressCreateRequest>();
+ JsonRpcMessageHandler::registerMessageProvider<ProgressNotification>();
connect(EditorManager::instance(), &EditorManager::editorOpened,
this, &LanguageClientManager::editorOpened);
connect(EditorManager::instance(), &EditorManager::documentOpened,
@@ -372,6 +376,14 @@ Client *LanguageClientManager::clientForUri(const DocumentUri &uri)
return clientForFilePath(uri.toFilePath());
}
+const QList<Client *> LanguageClientManager::clientsForProject(
+ const ProjectExplorer::Project *project)
+{
+ return Utils::filtered(managerInstance->m_clients, [project](const Client *c) {
+ return c->project() == project;
+ }).toList();
+}
+
void LanguageClientManager::openDocumentWithClient(TextEditor::TextDocument *document, Client *client)
{
Client *currentClient = clientForDocument(document);
@@ -455,9 +467,9 @@ void LanguageClientManager::documentOpened(Core::IDocument *document)
// check whether we have to start servers for this document
const QList<BaseSettings *> settings = currentSettings();
for (BaseSettings *setting : settings) {
- QVector<Client *> clients = clientForSetting(setting);
if (setting->isValid() && setting->m_enabled
&& setting->m_languageFilter.isSupported(document)) {
+ QVector<Client *> clients = clientForSetting(setting);
if (setting->m_startBehavior == BaseSettings::RequiresProject) {
const Utils::FilePath &filePath = document->filePath();
for (ProjectExplorer::Project *project :
@@ -472,12 +484,14 @@ void LanguageClientManager::documentOpened(Core::IDocument *document)
return client->project()
== project;
});
- if (!clientForProject) {
+ if (!clientForProject)
clientForProject = startClient(setting, project);
- clients << clientForProject;
- }
+
QTC_ASSERT(clientForProject, continue);
openDocumentWithClient(textDocument, clientForProject);
+ // Since we already opened the document in this client we remove the client
+ // from the list of clients that receive the openDocument call
+ clients.removeAll(clientForProject);
}
} else if (setting->m_startBehavior == BaseSettings::RequiresFile && clients.isEmpty()) {
clients << startClient(setting);
diff --git a/src/plugins/languageclient/languageclientmanager.h b/src/plugins/languageclient/languageclientmanager.h
index 0867104e9c..9800db8a13 100644
--- a/src/plugins/languageclient/languageclientmanager.h
+++ b/src/plugins/languageclient/languageclientmanager.h
@@ -84,6 +84,7 @@ public:
static Client *clientForDocument(TextEditor::TextDocument *document);
static Client *clientForFilePath(const Utils::FilePath &filePath);
static Client *clientForUri(const LanguageServerProtocol::DocumentUri &uri);
+ static const QList<Client *> clientsForProject(const ProjectExplorer::Project *project);
///
/// \brief openDocumentWithClient
diff --git a/src/plugins/languageclient/languageclientoutline.cpp b/src/plugins/languageclient/languageclientoutline.cpp
index 622b0100f0..c83a35411f 100644
--- a/src/plugins/languageclient/languageclientoutline.cpp
+++ b/src/plugins/languageclient/languageclientoutline.cpp
@@ -231,7 +231,7 @@ bool LanguageClientOutlineWidgetFactory::clientSupportsDocumentSymbols(
DynamicCapabilities dc = client->dynamicCapabilities();
if (dc.isRegistered(DocumentSymbolsRequest::methodName).value_or(false)) {
TextDocumentRegistrationOptions options(dc.option(DocumentSymbolsRequest::methodName));
- return !options.isValid(nullptr)
+ return !options.isValid()
|| options.filterApplies(doc->filePath(), Utils::mimeTypeForName(doc->mimeType()));
}
const Utils::optional<Utils::variant<bool, WorkDoneProgressOptions>> &provider
diff --git a/src/plugins/languageclient/languageclientplugin.cpp b/src/plugins/languageclient/languageclientplugin.cpp
index 26702c4a6d..8f530f7013 100644
--- a/src/plugins/languageclient/languageclientplugin.cpp
+++ b/src/plugins/languageclient/languageclientplugin.cpp
@@ -25,9 +25,14 @@
#include "languageclientplugin.h"
+#include "client.h"
#include "languageclientmanager.h"
-#include "client.h"
+#include <coreplugin/actionmanager/actioncontainer.h>
+#include <coreplugin/actionmanager/actionmanager.h>
+
+#include <QAction>
+#include <QMenu>
namespace LanguageClient {
@@ -50,10 +55,26 @@ LanguageClientPlugin *LanguageClientPlugin::instance()
bool LanguageClientPlugin::initialize(const QStringList & /*arguments*/, QString * /*errorString*/)
{
+ using namespace Core;
+
LanguageClientManager::init();
LanguageClientSettings::registerClientType({Constants::LANGUAGECLIENT_STDIO_SETTINGS_ID,
tr("Generic StdIO Language Server"),
[]() { return new StdIOSettings; }});
+
+ //register actions
+ ActionContainer *toolsContainer
+ = ActionManager::actionContainer(Core::Constants::M_TOOLS);
+ toolsContainer->insertGroup(Core::Constants::G_TOOLS_OPTIONS, Constants::G_TOOLS_LANGUAGECLIENT);
+ ActionContainer *container = ActionManager::createMenu("Language Client");
+ container->menu()->setTitle(tr("&Language Client"));
+ toolsContainer->addMenu(container, Constants::G_TOOLS_LANGUAGECLIENT);
+
+ auto inspectAction = new QAction(tr("Inspect Language Clients"), this);
+ connect(inspectAction, &QAction::triggered, this, &LanguageClientManager::showInspector);
+ container->addAction(
+ ActionManager::registerAction(inspectAction, "LanguageClient.InspectLanguageClients"));
+
return true;
}
diff --git a/src/plugins/languageclient/languageclientsettings.cpp b/src/plugins/languageclient/languageclientsettings.cpp
index 1845eef276..8787a37b1a 100644
--- a/src/plugins/languageclient/languageclientsettings.cpp
+++ b/src/plugins/languageclient/languageclientsettings.cpp
@@ -566,6 +566,7 @@ Client *BaseSettings::createClient()
client->setName(Utils::globalMacroExpander()->expand(m_name));
client->setSupportedLanguage(m_languageFilter);
client->setInitializationOptions(initializationOptions());
+ client->setActivateDocumentAutomatically(true);
return client;
}
@@ -735,8 +736,7 @@ Utils::CommandLine StdIOSettings::command() const
BaseClientInterface *StdIOSettings::createInterface() const
{
auto interface = new StdIOClientInterface;
- interface->setExecutable(m_executable);
- interface->setArguments(arguments());
+ interface->setCommandLine(command());
return interface;
}
diff --git a/src/plugins/languageclient/languageclientsettings.h b/src/plugins/languageclient/languageclientsettings.h
index be190987ef..5ee567b071 100644
--- a/src/plugins/languageclient/languageclientsettings.h
+++ b/src/plugins/languageclient/languageclientsettings.h
@@ -29,9 +29,8 @@
#include <coreplugin/dialogs/ioptionspage.h>
-#include <utils/fileutils.h>
-
#include <QAbstractItemModel>
+#include <QCoreApplication>
#include <QJsonObject>
#include <QLabel>
#include <QPointer>
@@ -44,6 +43,7 @@ class QLineEdit;
QT_END_NAMESPACE
namespace Utils {
+class CommandLine;
class FilePath;
class PathChooser;
class FancyLineEdit;
diff --git a/src/plugins/languageclient/languageclientsymbolsupport.cpp b/src/plugins/languageclient/languageclientsymbolsupport.cpp
index 8a29d0e510..fabb628beb 100644
--- a/src/plugins/languageclient/languageclientsymbolsupport.cpp
+++ b/src/plugins/languageclient/languageclientsymbolsupport.cpp
@@ -56,7 +56,7 @@ static void sendTextDocumentPositionParamsRequest(Client *client,
if (sendMessage) {
const TextDocumentRegistrationOptions option(
dynamicCapabilities.option(Request::methodName));
- if (option.isValid(nullptr))
+ if (option.isValid())
sendMessage = option.filterApplies(
Utils::FilePath::fromString(QUrl(uri).adjusted(QUrl::PreferLocalFile).toString()));
else
@@ -110,7 +110,7 @@ void SymbolSupport::findLinkAt(TextEditor::TextDocument *document,
if (!resolveTarget) {
QTextCursor linkCursor = cursor;
linkCursor.select(QTextCursor::WordUnderCursor);
- Utils::Link link(document->filePath().toString(),
+ Utils::Link link(document->filePath(),
linkCursor.blockNumber() + 1,
linkCursor.positionInBlock());
link.linkTextStart = linkCursor.selectionStart();
@@ -129,25 +129,17 @@ void SymbolSupport::findLinkAt(TextEditor::TextDocument *document,
}
-Core::Search::TextRange convertRange(const Range &range)
-{
- auto convertPosition = [](const Position &pos) {
- return Core::Search::TextPosition(pos.line() + 1, pos.character());
- };
- return Core::Search::TextRange(convertPosition(range.start()), convertPosition(range.end()));
-}
-
struct ItemData
{
Core::Search::TextRange range;
QVariant userData;
};
-static QStringList getFileContents(const QString &filePath)
+QStringList SymbolSupport::getFileContents(const Utils::FilePath &filePath)
{
QString fileContent;
if (TextEditor::TextDocument *document = TextEditor::TextDocument::textDocumentForFilePath(
- Utils::FilePath::fromString(filePath))) {
+ filePath)) {
fileContent = document->plainText();
} else {
Utils::TextFileFormat format;
@@ -163,17 +155,17 @@ static QStringList getFileContents(const QString &filePath)
}
QList<Core::SearchResultItem> generateSearchResultItems(
- const QMap<QString, QList<ItemData>> &rangesInDocument)
+ const QMap<Utils::FilePath, QList<ItemData>> &rangesInDocument)
{
QList<Core::SearchResultItem> result;
for (auto it = rangesInDocument.begin(); it != rangesInDocument.end(); ++it) {
- const QString &fileName = it.key();
+ const Utils::FilePath &filePath = it.key();
Core::SearchResultItem item;
- item.setFilePath(Utils::FilePath::fromString(fileName));
+ item.setFilePath(filePath);
item.setUseTextEditorFont(true);
- QStringList lines = getFileContents(fileName);
+ QStringList lines = SymbolSupport::getFileContents(filePath);
for (const ItemData &data : it.value()) {
item.setMainRange(data.range);
if (data.range.begin.line > 0 && data.range.begin.line <= lines.size())
@@ -190,17 +182,24 @@ QList<Core::SearchResultItem> generateSearchResultItems(
{
if (locations.isNull())
return {};
- QMap<QString, QList<ItemData>> rangesInDocument;
+ QMap<Utils::FilePath, QList<ItemData>> rangesInDocument;
for (const Location &location : locations.toList())
- rangesInDocument[location.uri().toFilePath().toString()]
- << ItemData{convertRange(location.range()), {}};
+ rangesInDocument[location.uri().toFilePath()]
+ << ItemData{SymbolSupport::convertRange(location.range()), {}};
return generateSearchResultItems(rangesInDocument);
}
void SymbolSupport::handleFindReferencesResponse(const FindReferencesRequest::Response &response,
- const QString &wordUnderCursor)
+ const QString &wordUnderCursor,
+ const ResultHandler &handler)
{
- if (auto result = response.result()) {
+ const auto result = response.result();
+ if (handler) {
+ const LanguageClientArray<Location> locations = result.value_or(nullptr);
+ handler(locations.isNull() ? QList<Location>() : locations.toList());
+ return;
+ }
+ if (result) {
Core::SearchResult *search = Core::SearchResultWindow::instance()->startNewSearch(
tr("Find References with %1 for:").arg(m_client->name()), "", wordUnderCursor);
search->addResults(generateSearchResultItems(result.value()),
@@ -215,24 +214,26 @@ void SymbolSupport::handleFindReferencesResponse(const FindReferencesRequest::Re
}
}
-void SymbolSupport::findUsages(TextEditor::TextDocument *document, const QTextCursor &cursor)
+Utils::optional<MessageId> SymbolSupport::findUsages(
+ TextEditor::TextDocument *document, const QTextCursor &cursor, const ResultHandler &handler)
{
if (!m_client->reachable())
- return;
+ return {};
ReferenceParams params(generateDocPosParams(document, cursor));
params.setContext(ReferenceParams::ReferenceContext(true));
FindReferencesRequest request(params);
QTextCursor termCursor(cursor);
termCursor.select(QTextCursor::WordUnderCursor);
- request.setResponseCallback([this, wordUnderCursor = termCursor.selectedText()](
- const FindReferencesRequest::Response &response) {
- handleFindReferencesResponse(response, wordUnderCursor);
+ request.setResponseCallback([this, wordUnderCursor = termCursor.selectedText(), handler](
+ const FindReferencesRequest::Response &response) {
+ handleFindReferencesResponse(response, wordUnderCursor, handler);
});
sendTextDocumentPositionParamsRequest(m_client,
request,
m_client->dynamicCapabilities(),
m_client->capabilities());
+ return request.id();
}
static bool supportsRename(Client *client,
@@ -248,7 +249,7 @@ static bool supportsRename(Client *client,
prepareSupported = ServerCapabilities::RenameOptions(options).prepareProvider().value_or(
false);
const TextDocumentRegistrationOptions docOps(options);
- if (docOps.isValid(nullptr)
+ if (docOps.isValid()
&& !docOps.filterApplies(document->filePath(),
Utils::mimeTypeForName(document->mimeType()))) {
return false;
@@ -332,20 +333,20 @@ QList<Core::SearchResultItem> generateReplaceItems(const WorkspaceEdit &edits)
{
auto convertEdits = [](const QList<TextEdit> &edits) {
return Utils::transform(edits, [](const TextEdit &edit) {
- return ItemData{convertRange(edit.range()), QVariant(edit)};
+ return ItemData{SymbolSupport::convertRange(edit.range()), QVariant(edit)};
});
};
- QMap<QString, QList<ItemData>> rangesInDocument;
+ QMap<Utils::FilePath, QList<ItemData>> rangesInDocument;
auto documentChanges = edits.documentChanges().value_or(QList<TextDocumentEdit>());
if (!documentChanges.isEmpty()) {
for (const TextDocumentEdit &documentChange : qAsConst(documentChanges)) {
- rangesInDocument[documentChange.textDocument().uri().toFilePath().toString()] = convertEdits(
+ rangesInDocument[documentChange.textDocument().uri().toFilePath()] = convertEdits(
documentChange.edits());
}
} else {
auto changes = edits.changes().value_or(WorkspaceEdit::Changes());
for (auto it = changes.begin(), end = changes.end(); it != end; ++it)
- rangesInDocument[it.key().toFilePath().toString()] = convertEdits(it.value());
+ rangesInDocument[it.key().toFilePath()] = convertEdits(it.value());
}
return generateSearchResultItems(rangesInDocument);
}
@@ -411,7 +412,7 @@ void SymbolSupport::applyRename(const QList<Core::SearchResultItem> &checkedItem
for (const Core::SearchResultItem &item : checkedItems) {
auto uri = DocumentUri::fromFilePath(Utils::FilePath::fromString(item.path().value(0)));
TextEdit edit(item.userData().toJsonObject());
- if (edit.isValid(nullptr))
+ if (edit.isValid())
editsForDocuments[uri] << edit;
}
@@ -419,4 +420,12 @@ void SymbolSupport::applyRename(const QList<Core::SearchResultItem> &checkedItem
applyTextEdits(it.key(), it.value());
}
+Core::Search::TextRange SymbolSupport::convertRange(const Range &range)
+{
+ auto convertPosition = [](const Position &pos) {
+ return Core::Search::TextPosition(pos.line() + 1, pos.character());
+ };
+ return Core::Search::TextRange(convertPosition(range.start()), convertPosition(range.end()));
+}
+
} // namespace LanguageClient
diff --git a/src/plugins/languageclient/languageclientsymbolsupport.h b/src/plugins/languageclient/languageclientsymbolsupport.h
index 61dd8e3d05..6ba376a1d5 100644
--- a/src/plugins/languageclient/languageclientsymbolsupport.h
+++ b/src/plugins/languageclient/languageclientsymbolsupport.h
@@ -25,6 +25,9 @@
#pragma once
+#include "languageclient_global.h"
+
+#include <coreplugin/find/searchresultitem.h>
#include <texteditor/textdocument.h>
#include <languageserverprotocol/languagefeatures.h>
@@ -34,11 +37,13 @@ class SearchResult;
class SearchResultItem;
}
+namespace LanguageServerProtocol { class MessageId; }
+
namespace LanguageClient {
class Client;
-class SymbolSupport
+class LANGUAGECLIENT_EXPORT SymbolSupport
{
Q_DECLARE_TR_FUNCTIONS(SymbolSupport)
public:
@@ -48,15 +53,24 @@ public:
const QTextCursor &cursor,
Utils::ProcessLinkCallback callback,
const bool resolveTarget);
- void findUsages(TextEditor::TextDocument *document, const QTextCursor &cursor);
+
+ using ResultHandler = std::function<void(const QList<LanguageServerProtocol::Location> &)>;
+ Utils::optional<LanguageServerProtocol::MessageId> findUsages(
+ TextEditor::TextDocument *document,
+ const QTextCursor &cursor,
+ const ResultHandler &handler = {});
bool supportsRename(TextEditor::TextDocument *document);
void renameSymbol(TextEditor::TextDocument *document, const QTextCursor &cursor);
+ static Core::Search::TextRange convertRange(const LanguageServerProtocol::Range &range);
+ static QStringList getFileContents(const Utils::FilePath &filePath);
+
private:
void handleFindReferencesResponse(
const LanguageServerProtocol::FindReferencesRequest::Response &response,
- const QString &wordUnderCursor);
+ const QString &wordUnderCursor,
+ const ResultHandler &handler);
void requestPrepareRename(const LanguageServerProtocol::TextDocumentPositionParams &params,
const QString &placeholder);
diff --git a/src/plugins/languageclient/languageclientutils.cpp b/src/plugins/languageclient/languageclientutils.cpp
index 7f1f396d1f..b94a9fc1c9 100644
--- a/src/plugins/languageclient/languageclientutils.cpp
+++ b/src/plugins/languageclient/languageclientutils.cpp
@@ -152,7 +152,7 @@ void updateCodeActionRefactoringMarker(Client *client,
RefactorMarkers markers;
RefactorMarker marker;
marker.type = client->id();
- if (action.isValid(nullptr))
+ if (action.isValid())
marker.tooltip = action.title();
if (action.edit().has_value()) {
WorkspaceEdit edit = action.edit().value();
diff --git a/src/plugins/languageclient/locatorfilter.cpp b/src/plugins/languageclient/locatorfilter.cpp
index c26faf90af..b3abe0fc79 100644
--- a/src/plugins/languageclient/locatorfilter.cpp
+++ b/src/plugins/languageclient/locatorfilter.cpp
@@ -47,6 +47,8 @@ DocumentLocatorFilter::DocumentLocatorFilter()
{
setId(Constants::LANGUAGECLIENT_DOCUMENT_FILTER_ID);
setDisplayName(Constants::LANGUAGECLIENT_DOCUMENT_FILTER_DISPLAY_NAME);
+ setDescription(
+ tr("Matches all symbols from the current document, based on a language server."));
setDefaultShortcutString(".");
setDefaultIncludedByDefault(false);
setPriority(ILocatorFilter::Low);
@@ -160,11 +162,11 @@ QList<Core::LocatorFilterEntry> DocumentLocatorFilter::matchesFor(
QEventLoop loop;
connect(this, &DocumentLocatorFilter::symbolsUpToDate, &loop, [&]() { loop.exit(1); });
QFutureWatcher<Core::LocatorFilterEntry> watcher;
- watcher.setFuture(future.future());
connect(&watcher,
&QFutureWatcher<Core::LocatorFilterEntry>::canceled,
&loop,
&QEventLoop::quit);
+ watcher.setFuture(future.future());
locker.unlock();
if (!loop.exec())
return {};
@@ -188,12 +190,10 @@ void DocumentLocatorFilter::accept(Core::LocatorFilterEntry selection,
{
if (selection.internalData.canConvert<Utils::LineColumn>()) {
auto lineColumn = qvariant_cast<Utils::LineColumn>(selection.internalData);
- Core::EditorManager::openEditorAt(m_currentUri.toFilePath().toString(),
- lineColumn.line + 1,
- lineColumn.column);
+ const Utils::Link link(m_currentUri.toFilePath(), lineColumn.line + 1, lineColumn.column);
+ Core::EditorManager::openEditorAt(link);
} else if (selection.internalData.canConvert<Utils::Link>()) {
- auto link = qvariant_cast<Utils::Link>(selection.internalData);
- Core::EditorManager::openEditorAt(link.targetFileName, link.targetLine, link.targetColumn);
+ Core::EditorManager::openEditorAt(qvariant_cast<Utils::Link>(selection.internalData));
}
}
@@ -213,6 +213,18 @@ WorkspaceLocatorFilter::WorkspaceLocatorFilter(const QVector<SymbolKind> &filter
void WorkspaceLocatorFilter::prepareSearch(const QString &entry)
{
+ prepareSearch(entry, LanguageClientManager::clients(), false);
+}
+
+void WorkspaceLocatorFilter::prepareSearch(const QString &entry, const QVector<Client *> &clients)
+{
+ prepareSearch(entry, clients, true);
+}
+
+void WorkspaceLocatorFilter::prepareSearch(const QString &entry,
+ const QVector<Client *> &clients,
+ bool force)
+{
m_pendingRequests.clear();
m_results.clear();
@@ -220,7 +232,11 @@ void WorkspaceLocatorFilter::prepareSearch(const QString &entry)
params.setQuery(entry);
QMutexLocker locker(&m_mutex);
- for (auto client : Utils::filtered(LanguageClientManager::clients(), &Client::reachable)) {
+ for (auto client : qAsConst(clients)) {
+ if (!client->reachable())
+ continue;
+ if (!(force || client->locatorsEnabled()))
+ continue;
Utils::optional<Utils::variant<bool, WorkDoneProgressOptions>> capability
= client->capabilities().workspaceSymbolProvider();
if (!capability.has_value())
@@ -245,11 +261,11 @@ QList<Core::LocatorFilterEntry> WorkspaceLocatorFilter::matchesFor(
QEventLoop loop;
connect(this, &WorkspaceLocatorFilter::allRequestsFinished, &loop, [&]() { loop.exit(1); });
QFutureWatcher<Core::LocatorFilterEntry> watcher;
- watcher.setFuture(future.future());
connect(&watcher,
&QFutureWatcher<Core::LocatorFilterEntry>::canceled,
&loop,
&QEventLoop::quit);
+ watcher.setFuture(future.future());
locker.unlock();
if (!loop.exec())
return {};
@@ -275,10 +291,8 @@ void WorkspaceLocatorFilter::accept(Core::LocatorFilterEntry selection,
int * /*selectionStart*/,
int * /*selectionLength*/) const
{
- if (selection.internalData.canConvert<Utils::Link>()) {
- auto link = qvariant_cast<Utils::Link>(selection.internalData);
- Core::EditorManager::openEditorAt(link.targetFileName, link.targetLine, link.targetColumn);
- }
+ if (selection.internalData.canConvert<Utils::Link>())
+ Core::EditorManager::openEditorAt(qvariant_cast<Utils::Link>(selection.internalData));
}
void WorkspaceLocatorFilter::handleResponse(Client *client,
diff --git a/src/plugins/languageclient/locatorfilter.h b/src/plugins/languageclient/locatorfilter.h
index 24e7ff54c5..58da2ddf9c 100644
--- a/src/plugins/languageclient/locatorfilter.h
+++ b/src/plugins/languageclient/locatorfilter.h
@@ -74,13 +74,16 @@ private:
Utils::optional<LanguageServerProtocol::DocumentSymbolsResult> m_currentSymbols;
};
-class WorkspaceLocatorFilter : public Core::ILocatorFilter
+class LANGUAGECLIENT_EXPORT WorkspaceLocatorFilter : public Core::ILocatorFilter
{
Q_OBJECT
public:
WorkspaceLocatorFilter();
+ /// request workspace symbols for all clients with enabled locator
void prepareSearch(const QString &entry) override;
+ /// force request workspace symbols for all given clients
+ void prepareSearch(const QString &entry, const QVector<Client *> &clients);
QList<Core::LocatorFilterEntry> matchesFor(QFutureInterface<Core::LocatorFilterEntry> &future,
const QString &entry) override;
void accept(Core::LocatorFilterEntry selection,
@@ -95,6 +98,7 @@ protected:
explicit WorkspaceLocatorFilter(const QVector<LanguageServerProtocol::SymbolKind> &filter);
private:
+ void prepareSearch(const QString &entry, const QVector<Client *> &clients, bool force);
void handleResponse(Client *client,
const LanguageServerProtocol::WorkspaceSymbolRequest::Response &response);
@@ -104,13 +108,13 @@ private:
QVector<LanguageServerProtocol::SymbolKind> m_filterKinds;
};
-class WorkspaceClassLocatorFilter : public WorkspaceLocatorFilter
+class LANGUAGECLIENT_EXPORT WorkspaceClassLocatorFilter : public WorkspaceLocatorFilter
{
public:
WorkspaceClassLocatorFilter();
};
-class WorkspaceMethodLocatorFilter : public WorkspaceLocatorFilter
+class LANGUAGECLIENT_EXPORT WorkspaceMethodLocatorFilter : public WorkspaceLocatorFilter
{
public:
WorkspaceMethodLocatorFilter();
diff --git a/src/plugins/languageclient/lspinspector.cpp b/src/plugins/languageclient/lspinspector.cpp
index 64e43155bf..ef832ed865 100644
--- a/src/plugins/languageclient/lspinspector.cpp
+++ b/src/plugins/languageclient/lspinspector.cpp
@@ -344,7 +344,7 @@ void LspLogWidget::saveLog()
const QString fileName = QFileDialog::getSaveFileName(this, LspInspector::tr("Log File"));
if (fileName.isEmpty())
return;
- Utils::FileSaver saver(fileName, QIODevice::Text);
+ Utils::FileSaver saver(Utils::FilePath::fromString(fileName), QIODevice::Text);
saver.write(contents.toUtf8());
if (!saver.finalize(this))
saveLog();
diff --git a/src/plugins/languageclient/progressmanager.cpp b/src/plugins/languageclient/progressmanager.cpp
new file mode 100644
index 0000000000..fe0e219376
--- /dev/null
+++ b/src/plugins/languageclient/progressmanager.cpp
@@ -0,0 +1,134 @@
+/****************************************************************************
+**
+** Copyright (C) 2021 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of Qt Creator.
+**
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3 as published by the Free Software
+** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-3.0.html.
+**
+****************************************************************************/
+
+#include "progressmanager.h"
+
+#include <coreplugin/progressmanager/futureprogress.h>
+#include <coreplugin/progressmanager/progressmanager.h>
+#include <languageserverprotocol/progresssupport.h>
+
+using namespace LanguageServerProtocol;
+
+namespace LanguageClient {
+
+ProgressManager::ProgressManager()
+{}
+
+ProgressManager::~ProgressManager()
+{
+ const QList<ProgressToken> &tokens = m_progress.keys();
+ for (const ProgressToken &token : tokens)
+ endProgress(token);
+}
+
+void ProgressManager::handleProgress(const LanguageServerProtocol::ProgressParams &params)
+{
+ const ProgressToken &token = params.token();
+ ProgressParams::ProgressType value = params.value();
+ if (auto begin = Utils::get_if<WorkDoneProgressBegin>(&value))
+ beginProgress(token, *begin);
+ else if (auto report = Utils::get_if<WorkDoneProgressReport>(&value))
+ reportProgress(token, *report);
+ else if (auto end = Utils::get_if<WorkDoneProgressEnd>(&value))
+ endProgress(token, *end);
+}
+
+void ProgressManager::setTitleForToken(const LanguageServerProtocol::ProgressToken &token,
+ const QString &message)
+{
+ m_titles.insert(token, message);
+}
+
+bool ProgressManager::isProgressEndMessage(const LanguageServerProtocol::ProgressParams &params)
+{
+ return Utils::holds_alternative<WorkDoneProgressEnd>(params.value());
+}
+
+Utils::Id languageClientProgressId(const ProgressToken &token)
+{
+ constexpr char k_LanguageClientProgressId[] = "LanguageClient.ProgressId.";
+ auto toString = [](const ProgressToken &token){
+ if (Utils::holds_alternative<int>(token))
+ return QString::number(Utils::get<int>(token));
+ return Utils::get<QString>(token);
+ };
+ return Utils::Id(k_LanguageClientProgressId).withSuffix(toString(token));
+}
+
+void ProgressManager::beginProgress(const ProgressToken &token, const WorkDoneProgressBegin &begin)
+{
+ auto interface = new QFutureInterface<void>();
+ interface->reportStarted();
+ interface->setProgressRange(0, 100); // LSP always reports percentage of the task
+ const QString title = m_titles.value(token, begin.title());
+ Core::FutureProgress *progress = Core::ProgressManager::addTask(
+ interface->future(), title, languageClientProgressId(token));
+ m_progress[token] = {progress, interface};
+ reportProgress(token, begin);
+}
+
+void ProgressManager::reportProgress(const ProgressToken &token,
+ const WorkDoneProgressReport &report)
+{
+ const LanguageClientProgress &progress = m_progress.value(token);
+ if (progress.progressInterface) {
+ const Utils::optional<QString> &message = report.message();
+ if (message.has_value()) {
+ progress.progressInterface->setSubtitle(*message);
+ const bool showSubtitle = !message->isEmpty();
+ progress.progressInterface->setSubtitleVisibleInStatusBar(showSubtitle);
+ }
+ }
+ if (progress.futureInterface) {
+ const Utils::optional<int> &progressValue = report.percentage();
+ if (progressValue.has_value())
+ progress.futureInterface->setProgressValue(*progressValue);
+ }
+}
+
+void ProgressManager::endProgress(const ProgressToken &token, const WorkDoneProgressEnd &end)
+{
+ const LanguageClientProgress &progress = m_progress.value(token);
+ const QString &message = end.message().value_or(QString());
+ if (progress.progressInterface) {
+ if (!message.isEmpty()) {
+ progress.progressInterface->setKeepOnFinish(
+ Core::FutureProgress::KeepOnFinishTillUserInteraction);
+ }
+ progress.progressInterface->setSubtitle(message);
+ progress.progressInterface->setSubtitleVisibleInStatusBar(!message.isEmpty());
+ }
+ endProgress(token);
+}
+
+void ProgressManager::endProgress(const ProgressToken &token)
+{
+ const LanguageClientProgress &progress = m_progress.take(token);
+ if (progress.futureInterface)
+ progress.futureInterface->reportFinished();
+ delete progress.futureInterface;
+}
+
+} // namespace LanguageClient
diff --git a/src/plugins/languageclient/progressmanager.h b/src/plugins/languageclient/progressmanager.h
new file mode 100644
index 0000000000..6cc93f07ba
--- /dev/null
+++ b/src/plugins/languageclient/progressmanager.h
@@ -0,0 +1,72 @@
+/****************************************************************************
+**
+** Copyright (C) 2021 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of Qt Creator.
+**
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3 as published by the Free Software
+** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-3.0.html.
+**
+****************************************************************************/
+
+#pragma once
+
+#include <coreplugin/progressmanager/futureprogress.h>
+
+#include <QFutureInterface>
+#include <QPointer>
+
+namespace LanguageServerProtocol {
+class ProgressParams;
+class ProgressToken;
+class WorkDoneProgressBegin;
+class WorkDoneProgressReport;
+class WorkDoneProgressEnd;
+} // namespace LanguageServerProtocol
+
+namespace LanguageClient {
+
+class ProgressManager
+{
+public:
+ ProgressManager();
+ ~ProgressManager();
+ void handleProgress(const LanguageServerProtocol::ProgressParams &params);
+ void setTitleForToken(const LanguageServerProtocol::ProgressToken &token,
+ const QString &message);
+
+ static bool isProgressEndMessage(const LanguageServerProtocol::ProgressParams &params);
+
+private:
+ void beginProgress(const LanguageServerProtocol::ProgressToken &token,
+ const LanguageServerProtocol::WorkDoneProgressBegin &begin);
+ void reportProgress(const LanguageServerProtocol::ProgressToken &token,
+ const LanguageServerProtocol::WorkDoneProgressReport &report);
+ void endProgress(const LanguageServerProtocol::ProgressToken &token,
+ const LanguageServerProtocol::WorkDoneProgressEnd &end);
+ void endProgress(const LanguageServerProtocol::ProgressToken &token);
+
+ struct LanguageClientProgress {
+ QPointer<Core::FutureProgress> progressInterface = nullptr;
+ QFutureInterface<void> *futureInterface = nullptr;
+ };
+
+ QMap<LanguageServerProtocol::ProgressToken, LanguageClientProgress> m_progress;
+ QMap<LanguageServerProtocol::ProgressToken, QString> m_titles;
+};
+
+} // namespace LanguageClient
diff --git a/src/plugins/languageclient/semantichighlightsupport.cpp b/src/plugins/languageclient/semantichighlightsupport.cpp
index 591280fa34..2038f91f18 100644
--- a/src/plugins/languageclient/semantichighlightsupport.cpp
+++ b/src/plugins/languageclient/semantichighlightsupport.cpp
@@ -25,9 +25,18 @@
#include "semantichighlightsupport.h"
+#include "client.h"
+#include "languageclientmanager.h"
+
+#include <texteditor/fontsettings.h>
+#include <texteditor/texteditor.h>
+#include <texteditor/texteditorsettings.h>
+#include <utils/mimetypes/mimedatabase.h>
+
#include <QTextDocument>
using namespace LanguageServerProtocol;
+using namespace TextEditor;
namespace LanguageClient {
namespace SemanticHighligtingSupport {
@@ -41,7 +50,7 @@ static const QList<QList<QString>> highlightScopes(const ServerCapabilities &cap
.scopes().value_or(QList<QList<QString>>());
}
-static Utils::optional<TextEditor::TextStyle> styleForScopes(const QList<QString> &scopes)
+static Utils::optional<TextStyle> styleForScopes(const QList<QString> &scopes)
{
// missing "Minimal Scope Coverage" scopes
@@ -63,24 +72,24 @@ static Utils::optional<TextEditor::TextStyle> styleForScopes(const QList<QString
// invalid
// invalid.deprecated
- static const QMap<QString, TextEditor::TextStyle> styleForScopes = {
- {"entity.name", TextEditor::C_TYPE},
- {"entity.name.function", TextEditor::C_FUNCTION},
- {"entity.name.function.method.static", TextEditor::C_GLOBAL},
- {"entity.name.function.preprocessor", TextEditor::C_PREPROCESSOR},
- {"entity.name.label", TextEditor::C_LABEL},
- {"keyword", TextEditor::C_KEYWORD},
- {"storage.type", TextEditor::C_KEYWORD},
- {"constant.numeric", TextEditor::C_NUMBER},
- {"string", TextEditor::C_STRING},
- {"comment", TextEditor::C_COMMENT},
- {"comment.block.documentation", TextEditor::C_DOXYGEN_COMMENT},
- {"variable.function", TextEditor::C_FUNCTION},
- {"variable.other", TextEditor::C_LOCAL},
- {"variable.other.member", TextEditor::C_FIELD},
- {"variable.other.field", TextEditor::C_FIELD},
- {"variable.other.field.static", TextEditor::C_GLOBAL},
- {"variable.parameter", TextEditor::C_LOCAL},
+ static const QMap<QString, TextStyle> styleForScopes = {
+ {"entity.name", C_TYPE},
+ {"entity.name.function", C_FUNCTION},
+ {"entity.name.function.method.static", C_GLOBAL},
+ {"entity.name.function.preprocessor", C_PREPROCESSOR},
+ {"entity.name.label", C_LABEL},
+ {"keyword", C_KEYWORD},
+ {"storage.type", C_KEYWORD},
+ {"constant.numeric", C_NUMBER},
+ {"string", C_STRING},
+ {"comment", C_COMMENT},
+ {"comment.block.documentation", C_DOXYGEN_COMMENT},
+ {"variable.function", C_FUNCTION},
+ {"variable.other", C_LOCAL},
+ {"variable.other.member", C_FIELD},
+ {"variable.other.field", C_FIELD},
+ {"variable.other.field.static", C_GLOBAL},
+ {"variable.parameter", C_PARAMETER},
};
for (QString scope : scopes) {
@@ -98,28 +107,27 @@ static Utils::optional<TextEditor::TextStyle> styleForScopes(const QList<QString
}
static QHash<int, QTextCharFormat> scopesToFormatHash(QList<QList<QString>> scopes,
- const TextEditor::FontSettings &fontSettings)
+ const FontSettings &fontSettings)
{
QHash<int, QTextCharFormat> scopesToFormat;
for (int i = 0; i < scopes.size(); ++i) {
- if (Utils::optional<TextEditor::TextStyle> style = styleForScopes(scopes[i]))
+ if (Utils::optional<TextStyle> style = styleForScopes(scopes[i]))
scopesToFormat[i] = fontSettings.toTextCharFormat(style.value());
}
return scopesToFormat;
}
-TextEditor::HighlightingResult tokenToHighlightingResult(int line,
- const SemanticHighlightToken &token)
+HighlightingResult tokenToHighlightingResult(int line, const SemanticHighlightToken &token)
{
- return TextEditor::HighlightingResult(unsigned(line) + 1,
- unsigned(token.character) + 1,
- token.length,
- int(token.scope));
+ return HighlightingResult(unsigned(line) + 1,
+ unsigned(token.character) + 1,
+ token.length,
+ int(token.scope));
}
-TextEditor::HighlightingResults generateResults(const QList<SemanticHighlightingInformation> &lines)
+HighlightingResults generateResults(const QList<SemanticHighlightingInformation> &lines)
{
- TextEditor::HighlightingResults results;
+ HighlightingResults results;
for (const SemanticHighlightingInformation &info : lines) {
const int line = info.line();
@@ -132,8 +140,8 @@ TextEditor::HighlightingResults generateResults(const QList<SemanticHighlighting
return results;
}
-void applyHighlight(TextEditor::TextDocument *doc,
- const TextEditor::HighlightingResults &results,
+void applyHighlight(TextDocument *doc,
+ const HighlightingResults &results,
const ServerCapabilities &capabilities)
{
if (!doc->syntaxHighlighter())
@@ -145,7 +153,7 @@ void applyHighlight(TextEditor::TextDocument *doc,
auto b = doc->document()->findBlockByNumber(int(result.line - 1));
const QString &text = b.text().mid(int(result.column - 1), int(result.length));
auto resultScupes = scopes[result.kind];
- auto style = styleForScopes(resultScupes).value_or(TextEditor::C_TEXT);
+ auto style = styleForScopes(resultScupes).value_or(C_TEXT);
qCDebug(LOGLSPHIGHLIGHT) << result.line - 1 << '\t'
<< result.column - 1 << '\t'
<< result.length << '\t'
@@ -156,7 +164,7 @@ void applyHighlight(TextEditor::TextDocument *doc,
}
if (capabilities.semanticHighlighting().has_value()) {
- TextEditor::SemanticHighlighter::setExtraAdditionalFormats(
+ SemanticHighlighter::setExtraAdditionalFormats(
doc->syntaxHighlighter(),
results,
scopesToFormatHash(highlightScopes(capabilities), doc->fontSettings()));
@@ -164,4 +172,269 @@ void applyHighlight(TextEditor::TextDocument *doc,
}
} // namespace SemanticHighligtingSupport
+
+constexpr int tokenTypeBitOffset = 16;
+
+SemanticTokenSupport::SemanticTokenSupport(Client *client)
+ : m_client(client)
+{
+ QObject::connect(TextEditorSettings::instance(),
+ &TextEditorSettings::fontSettingsChanged,
+ client,
+ [this]() { updateFormatHash(); });
+}
+
+void SemanticTokenSupport::reloadSemanticTokens(TextDocument *textDocument)
+{
+ const SemanticRequestTypes supportedRequests = supportedSemanticRequests(textDocument);
+ if (supportedRequests.testFlag(SemanticRequestType::None))
+ return;
+ const Utils::FilePath filePath = textDocument->filePath();
+ const TextDocumentIdentifier docId(DocumentUri::fromFilePath(filePath));
+ auto responseCallback = [this, filePath](const SemanticTokensFullRequest::Response &response){
+ handleSemanticTokens(filePath, response.result().value_or(nullptr));
+ };
+ /*if (supportedRequests.testFlag(SemanticRequestType::Range)) {
+ const int start = widget->firstVisibleBlockNumber();
+ const int end = widget->lastVisibleBlockNumber();
+ const int pageSize = end - start;
+ // request one extra page upfront and after the current visible range
+ Range range(Position(qMax(0, start - pageSize), 0),
+ Position(qMin(widget->blockCount() - 1, end + pageSize), 0));
+ SemanticTokensRangeParams params;
+ params.setTextDocument(docId);
+ params.setRange(range);
+ SemanticTokensRangeRequest request(params);
+ request.setResponseCallback(responseCallback);
+ m_client->sendContent(request);
+ } else */
+ if (supportedRequests.testFlag(SemanticRequestType::Full)) {
+ SemanticTokensParams params;
+ params.setTextDocument(docId);
+ SemanticTokensFullRequest request(params);
+ request.setResponseCallback(responseCallback);
+ m_client->sendContent(request);
+ }
+}
+
+void SemanticTokenSupport::updateSemanticTokens(TextDocument *textDocument)
+{
+ const SemanticRequestTypes supportedRequests = supportedSemanticRequests(textDocument);
+ if (supportedRequests.testFlag(SemanticRequestType::FullDelta)) {
+ const Utils::FilePath filePath = textDocument->filePath();
+ const QString &previousResultId = m_tokens.value(filePath).resultId().value_or(QString());
+ if (!previousResultId.isEmpty()) {
+ SemanticTokensDeltaParams params;
+ params.setTextDocument(TextDocumentIdentifier(DocumentUri::fromFilePath(filePath)));
+ params.setPreviousResultId(previousResultId);
+ SemanticTokensFullDeltaRequest request(params);
+ request.setResponseCallback(
+ [this, filePath](const SemanticTokensFullDeltaRequest::Response &response) {
+ handleSemanticTokensDelta(filePath, response.result().value_or(nullptr));
+ });
+ m_client->sendContent(request);
+ return;
+ }
+ }
+ reloadSemanticTokens(textDocument);
+}
+
+void SemanticTokenSupport::rehighlight()
+{
+ for (const Utils::FilePath &filePath : m_tokens.keys())
+ highlight(filePath);
+}
+
+void addModifiers(int key,
+ QHash<int, QTextCharFormat> *formatHash,
+ TextStyles styles,
+ QList<int> tokenModifiers,
+ const TextEditor::FontSettings &fs)
+{
+ if (tokenModifiers.isEmpty())
+ return;
+ int modifier = tokenModifiers.takeLast();
+ auto addModifier = [&](TextStyle style){
+ if (key & modifier) // already there don't add twice
+ return;
+ key = key | modifier;
+ styles.mixinStyles.push_back(style);
+ formatHash->insert(key, fs.toTextCharFormat(styles));
+ };
+ switch (modifier) {
+ case declarationModifier: addModifier(C_DECLARATION); break;
+ case definitionModifier: addModifier(C_FUNCTION_DEFINITION); break;
+ default: break;
+ }
+ addModifiers(key, formatHash, styles, tokenModifiers, fs);
+}
+
+void SemanticTokenSupport::setLegend(const LanguageServerProtocol::SemanticTokensLegend &legend)
+{
+ m_tokenTypes = Utils::transform(legend.tokenTypes(), [&](const QString &tokenTypeString){
+ return m_tokenTypesMap.value(tokenTypeString, -1);
+ });
+ m_tokenModifiers = Utils::transform(legend.tokenModifiers(), [&](const QString &tokenModifierString){
+ return m_tokenModifiersMap.value(tokenModifierString, -1);
+ });
+ updateFormatHash();
+}
+
+void SemanticTokenSupport::updateFormatHash()
+{
+ auto fontSettings = TextEditorSettings::fontSettings();
+ for (int tokenType : qAsConst(m_tokenTypes)) {
+ if (tokenType < 0)
+ continue;
+ TextStyle style;
+ switch (tokenType) {
+ case typeToken: style = C_TYPE; break;
+ case classToken: style = C_TYPE; break;
+ case enumMemberToken: style = C_ENUMERATION; break;
+ case typeParameterToken: style = C_FIELD; break;
+ case parameterToken: style = C_PARAMETER; break;
+ case variableToken: style = C_LOCAL; break;
+ case functionToken: style = C_FUNCTION; break;
+ case macroToken: style = C_PREPROCESSOR; break;
+ case keywordToken: style = C_KEYWORD; break;
+ case commentToken: style = C_COMMENT; break;
+ case stringToken: style = C_STRING; break;
+ case numberToken: style = C_NUMBER; break;
+ case operatorToken: style = C_OPERATOR; break;
+ default:
+ style = m_additionalTypeStyles.value(tokenType, C_TEXT);
+ break;
+ }
+ int mainHashPart = tokenType << tokenTypeBitOffset;
+ m_formatHash[mainHashPart] = fontSettings.toTextCharFormat(style);
+ TextStyles styles;
+ styles.mainStyle = style;
+ styles.mixinStyles.initializeElements();
+ addModifiers(mainHashPart, &m_formatHash, styles, m_tokenModifiers, fontSettings);
+ }
+ rehighlight();
+}
+
+void SemanticTokenSupport::setTokenTypesMap(const QMap<QString, int> &tokenTypesMap)
+{
+ m_tokenTypesMap = tokenTypesMap;
+}
+
+void SemanticTokenSupport::setTokenModifiersMap(const QMap<QString, int> &tokenModifiersMap)
+{
+ m_tokenModifiersMap = tokenModifiersMap;
+}
+
+void SemanticTokenSupport::setAdditionalTokenTypeStyles(
+ const QHash<int, TextStyle> &typeStyles)
+{
+ m_additionalTypeStyles = typeStyles;
+}
+
+//void SemanticTokenSupport::setAdditionalTokenModifierStyles(
+// const QHash<int, TextStyle> &modifierStyles)
+//{
+// m_additionalModifierStyles = modifierStyles;
+//}
+
+SemanticRequestTypes SemanticTokenSupport::supportedSemanticRequests(TextDocument *document) const
+{
+ auto supportedRequests = [&](const QJsonObject &options) -> SemanticRequestTypes {
+ TextDocumentRegistrationOptions docOptions(options);
+ if (docOptions.isValid()
+ && docOptions.filterApplies(document->filePath(),
+ Utils::mimeTypeForName(document->mimeType()))) {
+ return SemanticRequestType::None;
+ }
+ const SemanticTokensOptions semanticOptions(options);
+ return semanticOptions.supportedRequests();
+ };
+ const QString dynamicMethod = "textDocument/semanticTokens";
+ const DynamicCapabilities &dynamicCapabilities = m_client->dynamicCapabilities();
+ if (auto registered = dynamicCapabilities.isRegistered(dynamicMethod);
+ registered.has_value()) {
+ if (!registered.value())
+ return SemanticRequestType::None;
+ return supportedRequests(dynamicCapabilities.option(dynamicMethod).toObject());
+ }
+ if (m_client->capabilities().semanticTokensProvider().has_value())
+ return supportedRequests(m_client->capabilities().semanticTokensProvider().value());
+ return SemanticRequestType::None;
+}
+
+void SemanticTokenSupport::handleSemanticTokens(const Utils::FilePath &filePath,
+ const SemanticTokensResult &result)
+{
+ if (auto tokens = Utils::get_if<SemanticTokens>(&result))
+ m_tokens[filePath] = *tokens;
+ else
+ m_tokens.remove(filePath);
+ highlight(filePath);
+}
+
+void SemanticTokenSupport::handleSemanticTokensDelta(
+ const Utils::FilePath &filePath, const LanguageServerProtocol::SemanticTokensDeltaResult &result)
+{
+ if (auto tokens = Utils::get_if<SemanticTokens>(&result)) {
+ m_tokens[filePath] = *tokens;
+ } else if (auto tokensDelta = Utils::get_if<SemanticTokensDelta>(&result)) {
+ QList<SemanticTokensEdit> edits = tokensDelta->edits();
+ if (edits.isEmpty())
+ return;
+
+ Utils::sort(edits, &SemanticTokensEdit::start);
+
+ SemanticTokens &tokens = m_tokens[filePath];
+ const QList<int> &data = tokens.data();
+
+ int newDataSize = data.size();
+ for (const SemanticTokensEdit &edit : qAsConst(edits))
+ newDataSize += edit.dataSize() - edit.deleteCount();
+ QList<int> newData;
+ newData.reserve(newDataSize);
+
+ auto it = data.begin();
+ for (const SemanticTokensEdit &edit : qAsConst(edits)) {
+ if (edit.start() > data.size()) // prevent edits after the previously reported data
+ return;
+ for (const auto start = data.begin() + edit.start(); it < start; ++it)
+ newData.append(*it);
+ newData.append(edit.data().value_or(QList<int>()));
+ it += edit.deleteCount();
+ }
+ for (const auto end = data.end(); it != end; ++it)
+ newData.append(*it);
+
+ tokens.setData(newData);
+ tokens.setResultId(tokensDelta->resultId());
+ } else {
+ m_tokens.remove(filePath);
+ }
+ highlight(filePath);
+}
+
+void SemanticTokenSupport::highlight(const Utils::FilePath &filePath)
+{
+ TextDocument *doc = TextDocument::textDocumentForFilePath(filePath);
+ if (!doc || LanguageClientManager::clientForDocument(doc) != m_client)
+ return;
+ SyntaxHighlighter *highlighter = doc->syntaxHighlighter();
+ if (!highlighter)
+ return;
+ int line = 1;
+ int column = 1;
+ auto toResult = [&](const SemanticToken &token){
+ line += token.deltaLine;
+ if (token.deltaLine != 0) // reset the current column when we change the current line
+ column = 1;
+ column += token.deltaStart;
+ const int tokenKind = token.tokenType << tokenTypeBitOffset | token.tokenModifiers;
+ return HighlightingResult(line, column, token.length, tokenKind);
+ };
+ const QList<SemanticToken> tokens = m_tokens.value(filePath).toTokens(m_tokenTypes,
+ m_tokenModifiers);
+ const HighlightingResults results = Utils::transform(tokens, toResult);
+ SemanticHighlighter::setExtraAdditionalFormats(highlighter, results, m_formatHash);
+}
+
} // namespace LanguageClient
diff --git a/src/plugins/languageclient/semantichighlightsupport.h b/src/plugins/languageclient/semantichighlightsupport.h
index b9d4fe1555..0b7693ad66 100644
--- a/src/plugins/languageclient/semantichighlightsupport.h
+++ b/src/plugins/languageclient/semantichighlightsupport.h
@@ -32,7 +32,11 @@
#include <texteditor/semantichighlighter.h>
#include <texteditor/textdocument.h>
+#include <QTextCharFormat>
+
namespace LanguageClient {
+class Client;
+
namespace SemanticHighligtingSupport {
TextEditor::HighlightingResults generateResults(
@@ -43,4 +47,46 @@ void applyHighlight(TextEditor::TextDocument *doc,
const LanguageServerProtocol::ServerCapabilities &capabilities);
} // namespace SemanticHighligtingSupport
+
+class SemanticTokenSupport
+{
+public:
+ explicit SemanticTokenSupport(Client *client);
+
+ void reloadSemanticTokens(TextEditor::TextDocument *doc);
+ void updateSemanticTokens(TextEditor::TextDocument *doc);
+ void rehighlight();
+ void setLegend(const LanguageServerProtocol::SemanticTokensLegend &legend);
+
+ void setTokenTypesMap(const QMap<QString, int> &tokenTypesMap);
+ void setTokenModifiersMap(const QMap<QString, int> &tokenModifiersMap);
+
+ void setAdditionalTokenTypeStyles(const QHash<int, TextEditor::TextStyle> &typeStyles);
+ // TODO: currently only declaration and definition modifiers are supported. The TextStyles
+ // mixin capabilities need to be extended to be able to support more
+// void setAdditionalTokenModifierStyles(const QHash<int, TextEditor::TextStyle> &modifierStyles);
+
+private:
+ LanguageServerProtocol::SemanticRequestTypes supportedSemanticRequests(
+ TextEditor::TextDocument *document) const;
+ void handleSemanticTokens(const Utils::FilePath &filePath,
+ const LanguageServerProtocol::SemanticTokensResult &result);
+ void handleSemanticTokensDelta(const Utils::FilePath &filePath,
+ const LanguageServerProtocol::SemanticTokensDeltaResult &result);
+ void highlight(const Utils::FilePath &filePath);
+ void updateFormatHash();
+ void currentEditorChanged();
+
+ Client *m_client = nullptr;
+
+ QHash<Utils::FilePath, LanguageServerProtocol::SemanticTokens> m_tokens;
+ QList<int> m_tokenTypes;
+ QList<int> m_tokenModifiers;
+ QHash<int, QTextCharFormat> m_formatHash;
+ QHash<int, TextEditor::TextStyle> m_additionalTypeStyles;
+// QHash<int, TextEditor::TextStyle> m_additionalModifierStyles;
+ QMap<QString, int> m_tokenTypesMap;
+ QMap<QString, int> m_tokenModifiersMap;
+};
+
} // namespace LanguageClient
diff --git a/src/plugins/macros/macro.cpp b/src/plugins/macros/macro.cpp
index f5719eb076..a102d10040 100644
--- a/src/plugins/macros/macro.cpp
+++ b/src/plugins/macros/macro.cpp
@@ -138,7 +138,7 @@ bool Macro::loadHeader(const QString &fileName)
bool Macro::save(const QString &fileName, QWidget *parent)
{
- Utils::FileSaver saver(fileName);
+ Utils::FileSaver saver(Utils::FilePath::fromString(fileName));
if (!saver.hasError()) {
QDataStream stream(saver.file());
stream << d->version;
diff --git a/src/plugins/macros/macrolocatorfilter.cpp b/src/plugins/macros/macrolocatorfilter.cpp
index 98d69a24e9..35b238454b 100644
--- a/src/plugins/macros/macrolocatorfilter.cpp
+++ b/src/plugins/macros/macrolocatorfilter.cpp
@@ -42,6 +42,8 @@ MacroLocatorFilter::MacroLocatorFilter()
{
setId("Macros");
setDisplayName(tr("Text Editing Macros"));
+ setDescription(tr("Runs a text editing macro that was recorded with Tools > Text Editing "
+ "Macros > Record Macro."));
setDefaultShortcutString("rm");
}
diff --git a/src/plugins/macros/macromanager.cpp b/src/plugins/macros/macromanager.cpp
index 085a8fd032..1db0b30d27 100644
--- a/src/plugins/macros/macromanager.cpp
+++ b/src/plugins/macros/macromanager.cpp
@@ -386,8 +386,7 @@ void MacroManager::saveLastMacro()
QString MacroManager::macrosDirectory()
{
- const QString &path =
- Core::ICore::userResourcePath() + QLatin1String("/macros");
+ const QString path = Core::ICore::userResourcePath("macros").toString();
if (QFile::exists(path) || QDir().mkpath(path))
return path;
return QString();
diff --git a/src/plugins/mcusupport/CMakeLists.txt b/src/plugins/mcusupport/CMakeLists.txt
index 38630ca9b1..3729ac7256 100644
--- a/src/plugins/mcusupport/CMakeLists.txt
+++ b/src/plugins/mcusupport/CMakeLists.txt
@@ -11,4 +11,5 @@ add_qtc_plugin(McuSupport
mcusupportplugin.cpp mcusupportplugin.h
mcusupportsdk.cpp mcusupportsdk.h
mcusupportrunconfiguration.cpp mcusupportrunconfiguration.h
+ mcusupportversiondetection.cpp mcusupportversiondetection.h
)
diff --git a/src/plugins/mcusupport/McuSupport.json.in b/src/plugins/mcusupport/McuSupport.json.in
index a2f4240039..2616ea29dc 100644
--- a/src/plugins/mcusupport/McuSupport.json.in
+++ b/src/plugins/mcusupport/McuSupport.json.in
@@ -2,7 +2,7 @@
\"Name\" : \"McuSupport\",
\"Version\" : \"$$QTCREATOR_VERSION\",
\"CompatVersion\" : \"$$QTCREATOR_COMPAT_VERSION\",
- \"Experimental\" : true,
+ \"DisabledByDefault\" : true,
\"Vendor\" : \"The Qt Company Ltd\",
\"Copyright\" : \"(C) $$QTCREATOR_COPYRIGHT_YEAR The Qt Company Ltd\",
\"License\" : [ \"Commercial Usage\",
diff --git a/src/plugins/mcusupport/mcusupport.pro b/src/plugins/mcusupport/mcusupport.pro
index b6564b27b5..f2d7a1c501 100644
--- a/src/plugins/mcusupport/mcusupport.pro
+++ b/src/plugins/mcusupport/mcusupport.pro
@@ -12,7 +12,8 @@ HEADERS += \
mcusupportoptionspage.h \
mcusupportplugin.h \
mcusupportsdk.h \
- mcusupportrunconfiguration.h
+ mcusupportrunconfiguration.h \
+ mcusupportversiondetection.h
SOURCES += \
mcusupportdevice.cpp \
@@ -20,7 +21,8 @@ SOURCES += \
mcusupportoptionspage.cpp \
mcusupportplugin.cpp \
mcusupportsdk.cpp \
- mcusupportrunconfiguration.cpp
+ mcusupportrunconfiguration.cpp \
+ mcusupportversiondetection.cpp
RESOURCES += \
mcusupport.qrc
diff --git a/src/plugins/mcusupport/mcusupport.qbs b/src/plugins/mcusupport/mcusupport.qbs
index f194ea1b2a..8818514b2b 100644
--- a/src/plugins/mcusupport/mcusupport.qbs
+++ b/src/plugins/mcusupport/mcusupport.qbs
@@ -30,5 +30,7 @@ QtcPlugin {
"mcusupportsdk.h",
"mcusupportrunconfiguration.cpp",
"mcusupportrunconfiguration.h",
+ "mcusupportversiondetection.cpp",
+ "mcusupportversiondetection.h",
]
}
diff --git a/src/plugins/mcusupport/mcusupportoptions.cpp b/src/plugins/mcusupport/mcusupportoptions.cpp
index 56bcf57165..78d359d03b 100644
--- a/src/plugins/mcusupport/mcusupportoptions.cpp
+++ b/src/plugins/mcusupport/mcusupportoptions.cpp
@@ -26,9 +26,11 @@
#include "mcusupportconstants.h"
#include "mcusupportoptions.h"
#include "mcusupportsdk.h"
+#include "mcusupportplugin.h"
#include <baremetal/baremetalconstants.h>
#include <cmakeprojectmanager/cmaketoolmanager.h>
+#include <cmakeprojectmanager/cmakekitinformation.h>
#include <coreplugin/icore.h>
#include <coreplugin/helpmanager.h>
#include <coreplugin/messagemanager.h>
@@ -56,6 +58,8 @@
#include <QDir>
#include <QFileInfo>
#include <QLabel>
+#include <QMessageBox>
+#include <QPushButton>
#include <QToolButton>
#include <QVBoxLayout>
#include <QVariant>
@@ -96,11 +100,13 @@ static bool kitNeedsQtVersion()
}
McuPackage::McuPackage(const QString &label, const QString &defaultPath,
- const QString &detectionPath, const QString &settingsKey)
+ const QString &detectionPath, const QString &settingsKey,
+ const McuPackageVersionDetector *versionDetector)
: m_label(label)
, m_defaultPath(packagePathFromSettings(settingsKey, QSettings::SystemScope, defaultPath))
, m_detectionPath(detectionPath)
, m_settingsKey(settingsKey)
+ , m_versionDetector(versionDetector)
{
m_path = packagePathFromSettings(settingsKey, QSettings::UserScope, m_defaultPath);
m_automaticKitCreation = automaticKitCreationFromSettings(QSettings::UserScope);
@@ -182,6 +188,11 @@ McuPackage::Status McuPackage::status() const
return m_status;
}
+bool McuPackage::validStatus() const
+{
+ return m_status == McuPackage::ValidPackage || m_status == McuPackage::ValidPackageMismatchedVersion;
+}
+
void McuPackage::setDownloadUrl(const QString &url)
{
m_downloadUrl = url;
@@ -215,11 +226,14 @@ void McuPackage::writeGeneralSettings() const
settings->setValue(key, m_automaticKitCreation);
}
-void McuPackage::writeToSettings() const
+bool McuPackage::writeToSettings() const
{
+ const QString savedPath = packagePathFromSettings(m_settingsKey, QSettings::UserScope, m_defaultPath);
const QString key = QLatin1String(Constants::SETTINGS_GROUP) + '/' +
QLatin1String(Constants::SETTINGS_KEY_PACKAGE_PREFIX) + m_settingsKey;
Core::ICore::settings()->setValueWithDefault(key, m_path, m_defaultPath);
+
+ return savedPath != m_path;
}
void McuPackage::setRelativePathModifier(const QString &path)
@@ -227,6 +241,11 @@ void McuPackage::setRelativePathModifier(const QString &path)
m_relativePathModifier = path;
}
+void McuPackage::setVersions(const QVector<QString> &versions)
+{
+ m_versions = versions;
+}
+
bool McuPackage::automaticKitCreationEnabled() const
{
return m_automaticKitCreation;
@@ -249,34 +268,62 @@ void McuPackage::updateStatus()
bool validPath = !m_path.isEmpty() && FilePath::fromString(m_path).exists();
const FilePath detectionPath = FilePath::fromString(basePath() + "/" + m_detectionPath);
const bool validPackage = m_detectionPath.isEmpty() || detectionPath.exists();
+ m_detectedVersion = validPath && validPackage && m_versionDetector ? m_versionDetector->parseVersion(basePath()) : QString();
+ const bool validVersion = m_detectedVersion.isEmpty() ||
+ m_versions.isEmpty() || m_versions.contains(m_detectedVersion);
- m_status = validPath ? (validPackage ? ValidPackage : ValidPathInvalidPackage) :
- m_path.isEmpty() ? EmptyPath : InvalidPath;
+ m_status = validPath ?
+ ( validPackage ?
+ (validVersion ? ValidPackage : ValidPackageMismatchedVersion)
+ : ValidPathInvalidPackage )
+ : m_path.isEmpty() ? EmptyPath : InvalidPath;
emit statusChanged();
}
void McuPackage::updateStatusUi()
{
- m_infoLabel->setType(m_status == ValidPackage ? InfoLabel::Ok : InfoLabel::NotOk);
+ switch (m_status) {
+ case ValidPackage: m_infoLabel->setType(InfoLabel::Ok); break;
+ case ValidPackageMismatchedVersion: m_infoLabel->setType(InfoLabel::Warning); break;
+ default: m_infoLabel->setType(InfoLabel::NotOk); break;
+ }
m_infoLabel->setText(statusText());
}
QString McuPackage::statusText() const
{
const QString displayPackagePath = FilePath::fromString(m_path).toUserOutput();
- const QString displayDetectionPath = FilePath::fromString(m_detectionPath).toUserOutput();
+ const QString displayVersions = QStringList(m_versions.toList()).join(" or ");
+ const QString displayRequiredPath = QString("%1 %2").arg(
+ FilePath::fromString(m_detectionPath).toUserOutput(),
+ displayVersions);
+ const QString displayDetectedPath = QString("%1 %2").arg(
+ FilePath::fromString(m_detectionPath).toUserOutput(),
+ m_detectedVersion);
+
QString response;
switch (m_status) {
case ValidPackage:
response = m_detectionPath.isEmpty()
- ? tr("Path %1 exists.").arg(displayPackagePath)
+ ? ( m_detectedVersion.isEmpty()
+ ? tr("Path %1 exists.").arg(displayPackagePath)
+ : tr("Path %1 exists. Version %2 was found.")
+ .arg(displayPackagePath, m_detectedVersion) )
: tr("Path %1 is valid, %2 was found.")
- .arg(displayPackagePath, displayDetectionPath);
+ .arg(displayPackagePath, displayDetectedPath);
break;
+ case ValidPackageMismatchedVersion: {
+ const QString versionWarning = m_versions.size() == 1 ?
+ tr("but only version %1 is supported").arg(m_versions.first()) :
+ tr("but only versions %1 are supported").arg(displayVersions);
+ response = tr("Path %1 is valid, %2 was found, %3.")
+ .arg(displayPackagePath, displayDetectedPath, versionWarning);
+ break;
+ }
case ValidPathInvalidPackage:
response = tr("Path %1 exists, but does not contain %2.")
- .arg(displayPackagePath, displayDetectionPath);
+ .arg(displayPackagePath, displayRequiredPath);
break;
case InvalidPath:
response = tr("Path %1 does not exist.").arg(displayPackagePath);
@@ -285,7 +332,7 @@ QString McuPackage::statusText() const
response = m_detectionPath.isEmpty()
? tr("Path is empty.")
: tr("Path is empty, %1 not found.")
- .arg(displayDetectionPath);
+ .arg(displayRequiredPath);
break;
}
return response;
@@ -295,8 +342,9 @@ McuToolChainPackage::McuToolChainPackage(const QString &label,
const QString &defaultPath,
const QString &detectionPath,
const QString &settingsKey,
- McuToolChainPackage::Type type)
- : McuPackage(label, defaultPath, detectionPath, settingsKey)
+ McuToolChainPackage::Type type,
+ const McuPackageVersionDetector *versionDetector)
+ : McuPackage(label, defaultPath, detectionPath, settingsKey, versionDetector)
, m_type(type)
{
}
@@ -371,7 +419,7 @@ static ToolChain *iarToolChain(Id language)
return f->supportedToolChainType() == BareMetal::Constants::IAREW_TOOLCHAIN_TYPEID;
});
if (iarFactory) {
- const QList<ToolChain*> detected = iarFactory->autoDetect(QList<ToolChain*>());
+ const QList<ToolChain*> detected = iarFactory->autoDetect({}, {});
for (auto tc: detected) {
if (tc->language() == language) {
toolChain = tc;
@@ -412,11 +460,14 @@ ToolChain *McuToolChainPackage::toolChain(Id language) const
QString McuToolChainPackage::toolChainName() const
{
- return QLatin1String(m_type == TypeArmGcc
- ? "armgcc" : m_type == McuToolChainPackage::TypeIAR
- ? "iar" : m_type == McuToolChainPackage::TypeKEIL
- ? "keil" : m_type == McuToolChainPackage::TypeGHS
- ? "ghs" : "unsupported");
+ switch (m_type) {
+ case TypeArmGcc: return QLatin1String("armgcc");
+ case TypeIAR: return QLatin1String("iar");
+ case TypeKEIL: return QLatin1String("keil");
+ case TypeGHS: return QLatin1String("ghs");
+ case TypeGHSArm: return QLatin1String("ghs-arm");
+ default: return QLatin1String("unsupported");
+ }
}
QString McuToolChainPackage::cmakeToolChainFileName() const
@@ -484,9 +535,9 @@ McuTarget::Platform McuTarget::platform() const
bool McuTarget::isValid() const
{
- return !Utils::anyOf(packages(), [](McuPackage *package) {
+ return Utils::allOf(packages(), [](McuPackage *package) {
package->updateStatus();
- return package->status() != McuPackage::ValidPackage;
+ return package->validStatus();
});
}
@@ -494,12 +545,18 @@ void McuTarget::printPackageProblems() const
{
for (auto package: packages()) {
package->updateStatus();
- if (package->status() != McuPackage::ValidPackage)
- printMessage(QString("Error creating kit for target %1, package %2: %3").arg(
+ if (!package->validStatus())
+ printMessage(tr("Error creating kit for target %1, package %2: %3").arg(
McuSupportOptions::kitName(this),
package->label(),
package->statusText()),
true);
+ if (package->status() == McuPackage::ValidPackageMismatchedVersion)
+ printMessage(tr("Warning creating kit for target %1, package %2: %3").arg(
+ McuSupportOptions::kitName(this),
+ package->label(),
+ package->statusText()),
+ false);
}
}
@@ -598,7 +655,7 @@ void McuSupportOptions::setQulDir(const FilePath &dir)
{
deletePackagesAndTargets();
qtForMCUsSdkPackage->updateStatus();
- if (qtForMCUsSdkPackage->status() == McuPackage::Status::ValidPackage)
+ if (qtForMCUsSdkPackage->validStatus())
Sdk::targetsAndPackages(dir, &packages, &mcuTargets);
for (auto package : qAsConst(packages))
connect(package, &McuPackage::changed, this, &McuSupportOptions::changed);
@@ -613,7 +670,8 @@ FilePath McuSupportOptions::qulDirFromSettings()
QSettings::UserScope));
}
-static void setKitProperties(const QString &kitName, Kit *k, const McuTarget *mcuTarget)
+static void setKitProperties(const QString &kitName, Kit *k, const McuTarget *mcuTarget,
+ const QString &sdkPath)
{
using namespace Constants;
@@ -625,12 +683,19 @@ static void setKitProperties(const QString &kitName, Kit *k, const McuTarget *mc
k->setValue(KIT_MCUTARGET_KITVERSION_KEY, KIT_VERSION);
k->setValue(KIT_MCUTARGET_OS_KEY, static_cast<int>(mcuTarget->os()));
k->setValue(KIT_MCUTARGET_TOOCHAIN_KEY, mcuTarget->toolChainPackage()->toolChainName());
- k->setAutoDetected(true);
+ k->setAutoDetected(false);
k->makeSticky();
if (mcuTarget->toolChainPackage()->isDesktopToolchain())
k->setDeviceTypeForIcon(DEVICE_TYPE);
k->setValue(QtSupport::SuppliesQtQuickImportPath::id(), true);
- QSet<Id> irrelevant = { SysRootKitAspect::id(), QtSupport::SuppliesQtQuickImportPath::id() };
+ k->setValue(QtSupport::KitQmlImportPath::id(), QVariant(sdkPath + "/include/qul"));
+ k->setValue(QtSupport::KitHasMergedHeaderPathsWithQmlImportPaths::id(), true);
+ QSet<Id> irrelevant = {
+ SysRootKitAspect::id(),
+ QtSupport::SuppliesQtQuickImportPath::id(),
+ QtSupport::KitQmlImportPath::id(),
+ QtSupport::KitHasMergedHeaderPathsWithQmlImportPaths::id(),
+ };
if (!kitNeedsQtVersion())
irrelevant.insert(QtSupport::QtKitAspect::id());
k->setIrrelevantAspects(irrelevant);
@@ -700,7 +765,7 @@ static void setKitEnvironment(Kit *k, const McuTarget *mcuTarget,
if (mcuTarget->qulVersion() < QVersionNumber{1,7}) {
const QString path = QLatin1String(HostOsInfo::isWindowsHost() ? "Path" : "PATH");
pathAdditions.append("${" + path + "}");
- pathAdditions.append(QDir::toNativeSeparators(Core::ICore::libexecPath() + "/clang/bin"));
+ pathAdditions.append(Core::ICore::libexecPath("clang/bin").toUserOutput());
changes.append({path, pathAdditions.join(HostOsInfo::pathListSeparator())});
}
@@ -710,6 +775,48 @@ static void setKitEnvironment(Kit *k, const McuTarget *mcuTarget,
EnvironmentKitAspect::setEnvironmentChanges(k, changes);
}
+static void setKitDependencies(Kit *k, const McuTarget *mcuTarget,
+ const McuPackage *qtForMCUsSdkPackage)
+{
+ NameValueItems dependencies;
+
+ auto processPackage = [&dependencies](const McuPackage *package) {
+ if (!package->environmentVariableName().isEmpty())
+ dependencies.append({package->environmentVariableName(),
+ QDir::toNativeSeparators(package->detectionPath())});
+ };
+ for (auto package : mcuTarget->packages())
+ processPackage(package);
+ processPackage(qtForMCUsSdkPackage);
+
+ McuDependenciesKitAspect::setDependencies(k, dependencies);
+
+ auto irrelevant = k->irrelevantAspects();
+ irrelevant.insert(McuDependenciesKitAspect::id());
+ k->setIrrelevantAspects(irrelevant);
+}
+
+static void updateKitEnvironment(Kit *k, const McuTarget *mcuTarget)
+{
+ EnvironmentItems changes = EnvironmentKitAspect::environmentChanges(k);
+ for (auto package : mcuTarget->packages()) {
+ const QString varName = package->environmentVariableName();
+ if (!varName.isEmpty() && package->validStatus()) {
+ const int index = Utils::indexOf(changes, [varName](const EnvironmentItem &item) {
+ return item.name == varName;
+ });
+ const EnvironmentItem item = {package->environmentVariableName(),
+ QDir::toNativeSeparators(package->path())};
+ if (index != -1)
+ changes.replace(index, item);
+ else
+ changes.append(item);
+ }
+ }
+
+ EnvironmentKitAspect::setEnvironmentChanges(k, changes);
+}
+
static void setKitCMakeOptions(Kit *k, const McuTarget* mcuTarget, const QString &qulDir)
{
using namespace CMakeProjectManager;
@@ -754,6 +861,15 @@ static void setKitCMakeOptions(Kit *k, const McuTarget* mcuTarget, const QString
if (kitNeedsQtVersion())
config.append(CMakeConfigItem("CMAKE_PREFIX_PATH", "%{Qt:QT_INSTALL_PREFIX}"));
CMakeConfigurationKitAspect::setConfiguration(k, config);
+
+ if (HostOsInfo::isWindowsHost()) {
+ auto type = mcuTarget->toolChainPackage()->type();
+ if (type == McuToolChainPackage::TypeGHS || type == McuToolChainPackage::TypeGHSArm) {
+ // See https://bugreports.qt.io/browse/UL-4247?focusedCommentId=565802&page=com.atlassian.jira.plugin.system.issuetabpanels:comment-tabpanel#comment-565802
+ // and https://bugreports.qt.io/browse/UL-4247?focusedCommentId=565803&page=com.atlassian.jira.plugin.system.issuetabpanels:comment-tabpanel#comment-565803
+ CMakeGeneratorKitAspect::setGenerator(k, "NMake Makefiles JOM");
+ }
+ }
}
static void setKitQtVersionOptions(Kit *k)
@@ -793,8 +909,7 @@ QList<Kit *> McuSupportOptions::existingKits(const McuTarget *mcuTarget)
{
using namespace Constants;
return Utils::filtered(KitManager::kits(), [mcuTarget](Kit *kit) {
- return kit->isAutoDetected()
- && kit->value(KIT_MCUTARGET_KITVERSION_KEY) == KIT_VERSION
+ return kit->value(KIT_MCUTARGET_KITVERSION_KEY) == KIT_VERSION
&& (!mcuTarget || (
kit->value(KIT_MCUTARGET_VENDOR_KEY) == mcuTarget->platform().vendor
&& kit->value(KIT_MCUTARGET_MODEL_KEY) == mcuTarget->platform().name
@@ -807,11 +922,37 @@ QList<Kit *> McuSupportOptions::existingKits(const McuTarget *mcuTarget)
});
}
+QList<Kit *> McuSupportOptions::matchingKits(const McuTarget *mcuTarget, const McuPackage *qtForMCUsSdkPackage)
+{
+ return Utils::filtered(existingKits(mcuTarget), [mcuTarget, qtForMCUsSdkPackage](Kit *kit) {
+ return kitUpToDate(kit, mcuTarget, qtForMCUsSdkPackage);
+ });
+}
+
+QList<Kit *> McuSupportOptions::upgradeableKits(const McuTarget *mcuTarget, const McuPackage *qtForMCUsSdkPackage)
+{
+ return Utils::filtered(existingKits(mcuTarget), [mcuTarget, qtForMCUsSdkPackage](Kit *kit) {
+ return !kitUpToDate(kit, mcuTarget, qtForMCUsSdkPackage);
+ });
+}
+
+QList<Kit *> McuSupportOptions::kitsWithMismatchedDependencies(const McuTarget *mcuTarget)
+{
+ return Utils::filtered(existingKits(mcuTarget), [mcuTarget](Kit *kit) {
+ const auto environment = Utils::NameValueDictionary(
+ Utils::NameValueItem::toStringList(
+ EnvironmentKitAspect::environmentChanges(kit)));
+ return Utils::anyOf(mcuTarget->packages(), [&environment](const McuPackage *package) {
+ return !package->environmentVariableName().isEmpty() &&
+ environment.value(package->environmentVariableName()) != QDir::toNativeSeparators(package->path());
+ });
+ });
+}
+
QList<Kit *> McuSupportOptions::outdatedKits()
{
return Utils::filtered(KitManager::kits(), [](Kit *kit) {
- return kit->isAutoDetected()
- && !kit->value(Constants::KIT_MCUTARGET_VENDOR_KEY).isNull()
+ return !kit->value(Constants::KIT_MCUTARGET_VENDOR_KEY).isNull()
&& kit->value(Constants::KIT_MCUTARGET_KITVERSION_KEY) != KIT_VERSION;
});
}
@@ -827,11 +968,12 @@ Kit *McuSupportOptions::newKit(const McuTarget *mcuTarget, const McuPackage *qtF
const auto init = [mcuTarget, qtForMCUsSdk](Kit *k) {
KitGuard kitGuard(k);
- setKitProperties(kitName(mcuTarget), k, mcuTarget);
+ setKitProperties(kitName(mcuTarget), k, mcuTarget, qtForMCUsSdk->path());
setKitDevice(k, mcuTarget);
setKitToolchains(k, mcuTarget->toolChainPackage());
setKitDebugger(k, mcuTarget->toolChainPackage());
setKitEnvironment(k, mcuTarget, qtForMCUsSdk);
+ setKitDependencies(k, mcuTarget, qtForMCUsSdk);
setKitCMakeOptions(k, mcuTarget, qtForMCUsSdk->path());
setKitQtVersionOptions(k);
@@ -851,6 +993,49 @@ void printMessage(const QString &message, bool important)
Core::MessageManager::writeSilently(displayMessage);
}
+QVersionNumber McuSupportOptions::kitQulVersion(const Kit *kit)
+{
+ return QVersionNumber::fromString(
+ kit->value(McuSupport::Constants::KIT_MCUTARGET_SDKVERSION_KEY)
+ .toString());
+}
+
+QString kitDependencyPath(const Kit *kit, const QString &variableName)
+{
+ for (const NameValueItem &nameValueItem : EnvironmentKitAspect::environmentChanges(kit)) {
+ if (nameValueItem.name == variableName)
+ return nameValueItem.value;
+ }
+ return QString();
+}
+
+bool McuSupportOptions::kitUpToDate(const Kit *kit, const McuTarget *mcuTarget,
+ const McuPackage *qtForMCUsSdkPackage)
+{
+ return kitQulVersion(kit) == mcuTarget->qulVersion() &&
+ kitDependencyPath(kit, qtForMCUsSdkPackage->environmentVariableName()) == qtForMCUsSdkPackage->path();
+}
+
+McuSupportOptions::UpgradeOption McuSupportOptions::askForKitUpgrades()
+{
+ QMessageBox upgradePopup(Core::ICore::dialogParent());
+ upgradePopup.setStandardButtons(QMessageBox::Cancel);
+ QPushButton *replaceButton = upgradePopup.addButton(tr("Replace existing kits"),QMessageBox::NoRole);
+ QPushButton *keepButton = upgradePopup.addButton(tr("Create new kits"),QMessageBox::NoRole);
+ upgradePopup.setWindowTitle(tr("Qt for MCUs"));
+ upgradePopup.setText(tr("New version of Qt for MCUs detected. Upgrade existing Kits?"));
+
+ upgradePopup.exec();
+
+ if (upgradePopup.clickedButton() == keepButton)
+ return Keep;
+
+ if (upgradePopup.clickedButton() == replaceButton)
+ return Replace;
+
+ return Ignore;
+}
+
void McuSupportOptions::createAutomaticKits()
{
auto qtForMCUsPackage = Sdk::createQtForMCUsPackage();
@@ -858,7 +1043,7 @@ void McuSupportOptions::createAutomaticKits()
const auto createKits = [qtForMCUsPackage]() {
if (qtForMCUsPackage->automaticKitCreationEnabled()) {
qtForMCUsPackage->updateStatus();
- if (qtForMCUsPackage->status() != McuPackage::ValidPackage) {
+ if (!qtForMCUsPackage->validStatus()) {
switch (qtForMCUsPackage->status()) {
case McuPackage::ValidPathInvalidPackage: {
const QString displayPath = FilePath::fromString(qtForMCUsPackage->detectionPath())
@@ -896,16 +1081,27 @@ void McuSupportOptions::createAutomaticKits()
QVector<McuTarget*> mcuTargets;
Sdk::targetsAndPackages(dir, &packages, &mcuTargets);
- for (auto target: qAsConst(mcuTargets))
- if (existingKits(target).isEmpty()) {
+ bool needsUpgrade = false;
+ for (auto target: qAsConst(mcuTargets)) {
+ // if kit already exists, skip
+ if (!matchingKits(target, qtForMCUsPackage).empty())
+ continue;
+ if (!upgradeableKits(target, qtForMCUsPackage).empty()) {
+ // if kit exists but wrong version/path
+ needsUpgrade = true;
+ } else {
+ // if no kits for this target, create
if (target->isValid())
newKit(target, qtForMCUsPackage);
- else
- target->printPackageProblems();
+ target->printPackageProblems();
}
+ }
qDeleteAll(packages);
qDeleteAll(mcuTargets);
+
+ if (needsUpgrade)
+ McuSupportPlugin::askUserAboutMcuSupportKitsUpgrade();
}
};
@@ -913,6 +1109,80 @@ void McuSupportOptions::createAutomaticKits()
delete qtForMCUsPackage;
}
+void McuSupportOptions::checkUpgradeableKits()
+{
+ if (!qtForMCUsSdkPackage->validStatus() || mcuTargets.length() == 0)
+ return;
+
+ if (Utils::anyOf(mcuTargets, [this](const McuTarget *target) {
+ return !upgradeableKits(target, this->qtForMCUsSdkPackage).empty() &&
+ matchingKits(target, this->qtForMCUsSdkPackage).empty();
+ }))
+ upgradeKits(askForKitUpgrades());
+}
+
+void McuSupportOptions::upgradeKits(UpgradeOption upgradeOption)
+{
+ if (upgradeOption == Ignore)
+ return;
+
+ auto qtForMCUsPackage = Sdk::createQtForMCUsPackage();
+
+ auto dir = FilePath::fromUserInput(qtForMCUsPackage->path());
+ QVector<McuPackage*> packages;
+ QVector<McuTarget*> mcuTargets;
+ Sdk::targetsAndPackages(dir, &packages, &mcuTargets);
+
+ for (auto target: qAsConst(mcuTargets)) {
+ if (!matchingKits(target, qtForMCUsPackage).empty())
+ // already up-to-date
+ continue;
+
+ const auto kits = upgradeableKits(target, qtForMCUsPackage);
+ if (!kits.empty()) {
+ if (upgradeOption == Replace)
+ for (auto existingKit : kits)
+ KitManager::deregisterKit(existingKit);
+
+ if (target->isValid())
+ newKit(target, qtForMCUsPackage);
+ target->printPackageProblems();
+ }
+ }
+
+ qDeleteAll(packages);
+ qDeleteAll(mcuTargets);
+ delete qtForMCUsPackage;
+}
+
+void McuSupportOptions::upgradeKitInPlace(ProjectExplorer::Kit *kit, const McuTarget *mcuTarget, const McuPackage *qtForMCUsSdk)
+{
+ setKitProperties(kitName(mcuTarget), kit, mcuTarget, qtForMCUsSdk->path());
+ setKitEnvironment(kit, mcuTarget, qtForMCUsSdk);
+ setKitDependencies(kit, mcuTarget, qtForMCUsSdk);
+}
+
+void McuSupportOptions::fixKitsDependencies()
+{
+ auto qtForMCUsPackage = Sdk::createQtForMCUsPackage();
+
+ auto dir = FilePath::fromUserInput(qtForMCUsPackage->path());
+ QVector<McuPackage*> packages;
+ QVector<McuTarget*> mcuTargets;
+ Sdk::targetsAndPackages(dir, &packages, &mcuTargets);
+ for (auto target: qAsConst(mcuTargets)) {
+ if (target->isValid()) {
+ for (auto kit : kitsWithMismatchedDependencies(target)) {
+ updateKitEnvironment(kit, target);
+ }
+ }
+ }
+
+ qDeleteAll(packages);
+ qDeleteAll(mcuTargets);
+ delete qtForMCUsPackage;
+}
+
/**
* @brief Fix/update existing kits if needed
*/
@@ -922,6 +1192,10 @@ void McuSupportOptions::fixExistingKits()
if (!kit->hasValue(Constants::KIT_MCUTARGET_KITVERSION_KEY) )
continue;
+ if (kit->isAutoDetected()) {
+ kit->setAutoDetected(false);
+ }
+
// Check if the MCU kits are flagged as supplying a QtQuick import path, in order
// to tell the QMLJS code-model that it won't need to add a fall-back import
// path.
@@ -934,8 +1208,150 @@ void McuSupportOptions::fixExistingKits()
if (!kit->hasValue(bringsQtQuickImportPath)) {
kit->setValue(bringsQtQuickImportPath, true);
}
+
+ // Check if the MCU kit supplies its import path.
+ const auto kitQmlImportPath = QtSupport::KitQmlImportPath::id();
+ if (!irrelevantAspects.contains(kitQmlImportPath)) {
+ irrelevantAspects.insert(kitQmlImportPath);
+ kit->setIrrelevantAspects(irrelevantAspects);
+ }
+ if (!kit->hasValue(kitQmlImportPath)) {
+ auto config = CMakeProjectManager::CMakeConfigurationKitAspect::configuration(kit);
+ for (const auto &cfgItem : qAsConst(config)) {
+ if (cfgItem.key == "QUL_GENERATORS") {
+ auto idx = cfgItem.value.indexOf("/lib/cmake/Qul");
+ auto qulDir = cfgItem.value.left(idx);
+ kit->setValue(kitQmlImportPath, QVariant(qulDir + "/include/qul"));
+ break;
+ }
+ }
+ }
+
+ // Check if the MCU kit has the flag for merged header/qml-import paths set.
+ const auto mergedPaths = QtSupport::KitHasMergedHeaderPathsWithQmlImportPaths::id();
+ if (!irrelevantAspects.contains(mergedPaths)) {
+ irrelevantAspects.insert(mergedPaths);
+ kit->setIrrelevantAspects(irrelevantAspects);
+ }
+ if (!kit->value(mergedPaths, false).toBool()) {
+ kit->setValue(mergedPaths, true);
+ }
+ }
+
+ // Fix kit dependencies for known targets
+ auto qtForMCUsPackage = Sdk::createQtForMCUsPackage();
+ qtForMCUsPackage->updateStatus();
+ if (qtForMCUsPackage->validStatus()) {
+ auto dir = FilePath::fromUserInput(qtForMCUsPackage->path());
+ QVector<McuPackage*> packages;
+ QVector<McuTarget*> mcuTargets;
+ Sdk::targetsAndPackages(dir, &packages, &mcuTargets);
+ for (auto target: qAsConst(mcuTargets))
+ for (auto kit: existingKits(target)) {
+ if (McuDependenciesKitAspect::dependencies(kit).isEmpty()) {
+ setKitDependencies(kit, target, qtForMCUsPackage);
+ }
+ }
+
+ qDeleteAll(packages);
+ qDeleteAll(mcuTargets);
}
+ delete qtForMCUsPackage;
}
+class McuDependenciesKitAspectWidget final : public KitAspectWidget
+{
+ Q_DECLARE_TR_FUNCTIONS(McuSupport::McuDependenciesKitAspect)
+
+public:
+ McuDependenciesKitAspectWidget(Kit *workingCopy, const KitAspect *ki)
+ : KitAspectWidget(workingCopy, ki)
+ {}
+
+ void makeReadOnly() override {}
+ void refresh() override {}
+ void addToLayout(Utils::LayoutBuilder &) override {}
+};
+
} // Internal
+
+McuDependenciesKitAspect::McuDependenciesKitAspect()
+{
+ setObjectName(QLatin1String("McuDependenciesKitAspect"));
+ setId(McuDependenciesKitAspect::id());
+ setDisplayName(tr("Mcu Dependencies"));
+ setDescription(tr("Paths to 3rd party dependencies"));
+ setPriority(28500);
+}
+
+Tasks McuDependenciesKitAspect::validate(const Kit *k) const
+{
+ Tasks result;
+ QTC_ASSERT(k, return result);
+
+ const QVariant checkFormat = k->value(McuDependenciesKitAspect::id());
+ if (!checkFormat.isNull() && !checkFormat.canConvert(QVariant::List))
+ return { BuildSystemTask(Task::Error, tr("The mcu dependencies setting value is invalid.")) };
+
+ const QVariant envStringList = k->value(EnvironmentKitAspect::id());
+ if (!envStringList.isNull() && !envStringList.canConvert(QVariant::List))
+ return { BuildSystemTask(Task::Error, tr("The environment setting value is invalid.")) };
+
+ const auto environment = Utils::NameValueDictionary(envStringList.toStringList());
+ for (const auto &dependency: dependencies(k)) {
+ if (!environment.hasKey(dependency.name)) {
+ result << BuildSystemTask(Task::Warning, tr("Environment variable %1 not defined.").arg(dependency.name));
+ } else {
+ const auto path = Utils::FilePath::fromString(environment.value(dependency.name) + "/" + dependency.value);
+ if (!path.exists()) {
+ result << BuildSystemTask(Task::Warning, tr("%1 not found.").arg(path.toUserOutput()));
+ }
+ }
+ }
+
+ return result;
+}
+
+void McuDependenciesKitAspect::fix(Kit *k)
+{
+ QTC_ASSERT(k, return);
+
+ const QVariant variant = k->value(McuDependenciesKitAspect::id());
+ if (!variant.isNull() && !variant.canConvert(QVariant::List)) {
+ qWarning("Kit \"%s\" has a wrong mcu dependencies value set.", qPrintable(k->displayName()));
+ setDependencies(k, Utils::NameValueItems());
+ }
+}
+
+KitAspectWidget *McuDependenciesKitAspect::createConfigWidget(Kit *k) const
+{
+ QTC_ASSERT(k, return nullptr);
+ return new Internal::McuDependenciesKitAspectWidget(k, this);
+}
+
+KitAspect::ItemList McuDependenciesKitAspect::toUserOutput(const Kit *k) const
+{
+ Q_UNUSED(k);
+ return {};
+}
+
+Utils::Id McuDependenciesKitAspect::id()
+{
+ return "PE.Profile.McuDependencies";
+}
+
+
+Utils::NameValueItems McuDependenciesKitAspect::dependencies(const Kit *k)
+{
+ if (k)
+ return Utils::NameValueItem::fromStringList(k->value(McuDependenciesKitAspect::id()).toStringList());
+ return Utils::NameValueItems();
+}
+
+void McuDependenciesKitAspect::setDependencies(Kit *k, const Utils::NameValueItems &dependencies)
+{
+ if (k)
+ k->setValue(McuDependenciesKitAspect::id(), Utils::NameValueItem::toStringList(dependencies));
+}
+
} // McuSupport
diff --git a/src/plugins/mcusupport/mcusupportoptions.h b/src/plugins/mcusupport/mcusupportoptions.h
index 57772bafb2..f70722412d 100644
--- a/src/plugins/mcusupport/mcusupportoptions.h
+++ b/src/plugins/mcusupport/mcusupportoptions.h
@@ -25,7 +25,11 @@
#pragma once
+#include "mcusupportversiondetection.h"
+#include "mcusupport_global.h"
+
#include <utils/id.h>
+#include <projectexplorer/kitinformation.h>
#include <QObject>
#include <QVector>
@@ -58,11 +62,13 @@ public:
EmptyPath,
InvalidPath,
ValidPathInvalidPackage,
+ ValidPackageMismatchedVersion,
ValidPackage
};
- McuPackage(const QString &label, const QString &defaultPath, const QString &detectionPath,
- const QString &settingsKey);
+ McuPackage(const QString &label, const QString &defaultPath,
+ const QString &detectionPath, const QString &settingsKey,
+ const McuPackageVersionDetector *versionDetector = nullptr);
virtual ~McuPackage() = default;
QString basePath() const;
@@ -74,13 +80,15 @@ public:
void updateStatus();
Status status() const;
+ bool validStatus() const;
void setDownloadUrl(const QString &url);
void setEnvironmentVariableName(const QString &name);
void setAddToPath(bool addToPath);
bool addToPath() const;
void writeGeneralSettings() const;
- void writeToSettings() const;
+ bool writeToSettings() const;
void setRelativePathModifier(const QString &path);
+ void setVersions(const QVector<QString> &versions);
bool automaticKitCreationEnabled() const;
void setAutomaticKitCreationEnabled(const bool enabled);
@@ -105,9 +113,12 @@ private:
const QString m_defaultPath;
const QString m_detectionPath;
const QString m_settingsKey;
+ const McuPackageVersionDetector *m_versionDetector;
QString m_path;
QString m_relativePathModifier; // relative path to m_path to be returned by path()
+ QString m_detectedVersion;
+ QVector<QString> m_versions;
QString m_downloadUrl;
QString m_environmentVariableName;
bool m_addToPath = false;
@@ -126,6 +137,7 @@ public:
TypeGHS,
TypeMSVC,
TypeGCC,
+ TypeGHSArm,
TypeUnsupported
};
@@ -133,7 +145,9 @@ public:
const QString &defaultPath,
const QString &detectionPath,
const QString &settingsKey,
- Type type);
+ Type type,
+ const McuPackageVersionDetector *versionDetector = nullptr
+ );
Type type() const;
bool isDesktopToolchain() const;
@@ -191,6 +205,12 @@ class McuSupportOptions : public QObject
Q_OBJECT
public:
+ enum UpgradeOption {
+ Ignore,
+ Keep,
+ Replace
+ };
+
McuSupportOptions(QObject *parent = nullptr);
~McuSupportOptions() override;
@@ -204,10 +224,18 @@ public:
static QString kitName(const McuTarget* mcuTarget);
static QList<ProjectExplorer::Kit *> existingKits(const McuTarget *mcuTarget);
+ static QList<ProjectExplorer::Kit *> matchingKits(const McuTarget *mcuTarget, const McuPackage *qtForMCUsSdkPackage);
+ static QList<ProjectExplorer::Kit *> upgradeableKits(const McuTarget *mcuTarget, const McuPackage *qtForMCUsSdkPackage);
+ static QList<ProjectExplorer::Kit *> kitsWithMismatchedDependencies(const McuTarget *mcuTarget);
static QList<ProjectExplorer::Kit *> outdatedKits();
static void removeOutdatedKits();
static ProjectExplorer::Kit *newKit(const McuTarget *mcuTarget, const McuPackage *qtForMCUsSdk);
static void createAutomaticKits();
+ static UpgradeOption askForKitUpgrades();
+ static void upgradeKits(UpgradeOption upgradeOption);
+ static void upgradeKitInPlace(ProjectExplorer::Kit *kit, const McuTarget *mcuTarget, const McuPackage *qtForMCUsSdk);
+ static void fixKitsDependencies();
+ void checkUpgradeableKits();
static void fixExistingKits();
void populatePackagesAndTargets();
static void registerQchFiles();
@@ -215,6 +243,8 @@ public:
static const QVersionNumber &minimalQulVersion();
+ static QVersionNumber kitQulVersion(const ProjectExplorer::Kit *kit);
+ static bool kitUpToDate(const ProjectExplorer::Kit *kit, const McuTarget *mcuTarget, const McuPackage *qtForMCUsSdkPackage);
private:
void deletePackagesAndTargets();
@@ -223,4 +253,24 @@ signals:
};
} // namespace Internal
+
+class MCUSUPPORTSHARED_EXPORT McuDependenciesKitAspect : public ProjectExplorer::KitAspect
+{
+ Q_OBJECT
+
+public:
+ McuDependenciesKitAspect();
+
+ ProjectExplorer::Tasks validate(const ProjectExplorer::Kit *k) const override;
+ void fix(ProjectExplorer::Kit *k) override;
+
+ ProjectExplorer::KitAspectWidget *createConfigWidget(ProjectExplorer::Kit *k) const override;
+
+ ItemList toUserOutput(const ProjectExplorer::Kit *k) const override;
+
+ static Utils::Id id();
+ static Utils::NameValueItems dependencies(const ProjectExplorer::Kit *k);
+ static void setDependencies(ProjectExplorer::Kit *k, const Utils::NameValueItems &dependencies);
+};
+
} // namespace McuSupport
diff --git a/src/plugins/mcusupport/mcusupportoptionspage.cpp b/src/plugins/mcusupport/mcusupportoptionspage.cpp
index b4e6e2a6b0..9ccffd63e0 100644
--- a/src/plugins/mcusupport/mcusupportoptionspage.cpp
+++ b/src/plugins/mcusupport/mcusupportoptionspage.cpp
@@ -83,7 +83,7 @@ private:
Utils::InfoLabel *m_statusInfoLabel = nullptr;
Utils::InfoLabel *m_mcuTargetsInfoLabel = nullptr;
QPushButton *m_kitCreationPushButton = nullptr;
- QPushButton *m_kitRemovalPushButton = nullptr;
+ QPushButton *m_kitUpdatePushButton = nullptr;
};
McuSupportOptionsWidget::McuSupportOptionsWidget()
@@ -157,15 +157,15 @@ McuSupportOptionsWidget::McuSupportOptionsWidget()
McuSupportOptions::registerQchFiles();
updateStatus();
});
- m_kitRemovalPushButton = new QPushButton(tr("Remove Kit"));
- m_kitRemovalPushButton->setSizePolicy(m_kitCreationPushButton->sizePolicy());
- connect(m_kitRemovalPushButton, &QPushButton::clicked, this, [this] {
- for (auto existingKit : McuSupportOptions::existingKits(currentMcuTarget()))
- ProjectExplorer::KitManager::deregisterKit(existingKit);
+ m_kitUpdatePushButton = new QPushButton(tr("Update Kit"));
+ m_kitUpdatePushButton->setSizePolicy(m_kitCreationPushButton->sizePolicy());
+ connect(m_kitUpdatePushButton, &QPushButton::clicked, this, [this] {
+ for (auto kit: McuSupportOptions::upgradeableKits(currentMcuTarget(), m_options.qtForMCUsSdkPackage))
+ m_options.upgradeKitInPlace(kit, currentMcuTarget(), m_options.qtForMCUsSdkPackage);
updateStatus();
});
vLayout->addWidget(m_kitCreationPushButton);
- vLayout->addWidget(m_kitRemovalPushButton);
+ vLayout->addWidget(m_kitUpdatePushButton);
}
mainLayout->addStretch();
@@ -185,7 +185,7 @@ void McuSupportOptionsWidget::updateStatus()
{
m_qtForMCUsSdkGroupBox->setVisible(cMakeAvailable);
const bool valid = cMakeAvailable &&
- m_options.qtForMCUsSdkPackage->status() == McuPackage::ValidPackage;
+ m_options.qtForMCUsSdkPackage->validStatus();
const bool ready = valid && mcuTarget;
m_mcuTargetsGroupBox->setVisible(ready);
m_packagesGroupBox->setVisible(ready && !mcuTarget->packages().isEmpty());
@@ -193,8 +193,13 @@ void McuSupportOptionsWidget::updateStatus()
m_mcuTargetsInfoLabel->setVisible(valid && m_options.mcuTargets.isEmpty());
if (m_mcuTargetsInfoLabel->isVisible()) {
m_mcuTargetsInfoLabel->setType(Utils::InfoLabel::NotOk);
- auto displayKitsPath = Sdk::kitsPath(Utils::FilePath::fromString(m_options.qtForMCUsSdkPackage->basePath())).toUserOutput();
- m_mcuTargetsInfoLabel->setText(tr("No valid kit descriptions found at %1.").arg(displayKitsPath));
+ const auto sdkPath = Utils::FilePath::fromString(m_options.qtForMCUsSdkPackage->basePath());
+ QString deprecationMessage;
+ if (Sdk::checkDeprecatedSdkError(sdkPath, deprecationMessage))
+ m_mcuTargetsInfoLabel->setText(deprecationMessage);
+ else
+ m_mcuTargetsInfoLabel->setText(tr("No valid kit descriptions found at %1.")
+ .arg(Sdk::kitsPath(sdkPath).toUserOutput()));
}
}
@@ -202,17 +207,27 @@ void McuSupportOptionsWidget::updateStatus()
if (mcuTarget) {
const bool mcuTargetValid = mcuTarget->isValid();
m_kitCreationPushButton->setVisible(mcuTargetValid);
- m_kitRemovalPushButton->setVisible(mcuTargetValid);
+ m_kitUpdatePushButton->setVisible(mcuTargetValid);
if (mcuTargetValid) {
- const bool mcuTargetKitExists = !McuSupportOptions::existingKits(mcuTarget).isEmpty();
- m_kitCreationInfoLabel->setType(mcuTargetKitExists
+ const bool hasMatchingKits = !McuSupportOptions::matchingKits(
+ mcuTarget, m_options.qtForMCUsSdkPackage).isEmpty();
+ const bool hasUpgradeableKits = !hasMatchingKits &&
+ !McuSupportOptions::upgradeableKits(
+ mcuTarget, m_options.qtForMCUsSdkPackage).isEmpty();
+
+ m_kitCreationPushButton->setEnabled(!hasMatchingKits);
+ m_kitUpdatePushButton->setEnabled(hasUpgradeableKits);
+
+ m_kitCreationInfoLabel->setType(!hasMatchingKits
? Utils::InfoLabel::Information
: Utils::InfoLabel::Ok);
- m_kitCreationInfoLabel->setText(mcuTargetKitExists
- ? tr("A kit for the selected target exists.")
- : tr("A kit for the selected target can be created."));
- m_kitCreationPushButton->setEnabled(!mcuTargetKitExists);
- m_kitRemovalPushButton->setEnabled(mcuTargetKitExists);
+
+ m_kitCreationInfoLabel->setText(
+ hasMatchingKits ?
+ tr("A kit for the selected target and SDK version already exists.")
+ : hasUpgradeableKits ?
+ tr("Kits for a different SDK version exist.")
+ : tr("A kit for the selected target can be created."));
} else {
m_kitCreationInfoLabel->setType(Utils::InfoLabel::NotOk);
m_kitCreationInfoLabel->setText("Provide the package paths in order to create a kit "
@@ -273,10 +288,17 @@ void McuSupportOptionsWidget::showEvent(QShowEvent *event)
void McuSupportOptionsWidget::apply()
{
+ bool pathsChanged = false;
+
m_options.qtForMCUsSdkPackage->writeGeneralSettings();
- m_options.qtForMCUsSdkPackage->writeToSettings();
+ pathsChanged |= m_options.qtForMCUsSdkPackage->writeToSettings();
for (auto package : qAsConst(m_options.packages))
- package->writeToSettings();
+ pathsChanged |= package->writeToSettings();
+
+ if (pathsChanged) {
+ m_options.checkUpgradeableKits();
+ m_options.fixKitsDependencies();
+ }
}
void McuSupportOptionsWidget::populateMcuTargetsComboBox()
diff --git a/src/plugins/mcusupport/mcusupportplugin.cpp b/src/plugins/mcusupport/mcusupportplugin.cpp
index dec7c66c71..65b588bce8 100644
--- a/src/plugins/mcusupport/mcusupportplugin.cpp
+++ b/src/plugins/mcusupport/mcusupportplugin.cpp
@@ -59,6 +59,7 @@ public:
{Constants::RUNCONFIGURATION}
};
McuSupportOptionsPage optionsPage;
+ McuDependenciesKitAspect environmentPathsKitAspect;
};
static McuSupportPluginPrivate *dd = nullptr;
@@ -121,5 +122,33 @@ void McuSupportPlugin::askUserAboutMcuSupportKitsSetup()
ICore::infoBar()->addInfo(info);
}
+void McuSupportPlugin::askUserAboutMcuSupportKitsUpgrade()
+{
+ const char upgradeMcuSupportKits[] = "UpgradeMcuSupportKits";
+
+ if (!ICore::infoBar()->canInfoBeAdded(upgradeMcuSupportKits))
+ return;
+
+ Utils::InfoBarEntry info(upgradeMcuSupportKits,
+ tr("New version of Qt for MCUs detected. Upgrade existing Kits?"),
+ Utils::InfoBarEntry::GlobalSuppression::Enabled);
+
+ static McuSupportOptions::UpgradeOption selectedOption;
+ const QStringList options = { tr("Create new kits"), tr("Replace existing kits") };
+ selectedOption = McuSupportOptions::UpgradeOption::Keep;
+ info.setComboInfo(options, [upgradeMcuSupportKits, options](const QString &selected) {
+ selectedOption = options.indexOf(selected) == 0 ?
+ McuSupportOptions::UpgradeOption::Keep :
+ McuSupportOptions::UpgradeOption::Replace;
+ });
+
+ info.setCustomButtonInfo(tr("Proceed"), [upgradeMcuSupportKits] {
+ ICore::infoBar()->removeInfo(upgradeMcuSupportKits);
+ QTimer::singleShot(0, []() { McuSupportOptions::upgradeKits(selectedOption); });
+ });
+
+ ICore::infoBar()->addInfo(info);
+}
+
} // namespace Internal
} // namespace McuSupport
diff --git a/src/plugins/mcusupport/mcusupportplugin.h b/src/plugins/mcusupport/mcusupportplugin.h
index d3a1d8779a..b8237f3412 100644
--- a/src/plugins/mcusupport/mcusupportplugin.h
+++ b/src/plugins/mcusupport/mcusupportplugin.h
@@ -44,6 +44,7 @@ public:
bool initialize(const QStringList &arguments, QString *errorString) override;
void extensionsInitialized() override;
static void askUserAboutMcuSupportKitsSetup();
+ static void askUserAboutMcuSupportKitsUpgrade();
};
} // namespace Internal
diff --git a/src/plugins/mcusupport/mcusupportsdk.cpp b/src/plugins/mcusupport/mcusupportsdk.cpp
index e5bb7f911b..8cd34c0abf 100644
--- a/src/plugins/mcusupport/mcusupportsdk.cpp
+++ b/src/plugins/mcusupport/mcusupportsdk.cpp
@@ -26,6 +26,7 @@
#include "mcusupportconstants.h"
#include "mcusupportoptions.h"
#include "mcusupportsdk.h"
+#include "mcusupportversiondetection.h"
#include <baremetal/baremetalconstants.h>
#include <projectexplorer/toolchain.h>
@@ -62,8 +63,7 @@ static QString findInProgramFiles(const QString &folder)
McuPackage *createQtForMCUsPackage()
{
auto result = new McuPackage(
- McuPackage::tr("Qt for MCUs %1+ SDK").arg(
- McuSupportOptions::minimalQulVersion().toString()),
+ McuPackage::tr("Qt for MCUs SDK"),
QDir::homePath(),
Utils::HostOsInfo::withExecutableSuffix("bin/qmltocpp"),
Constants::SETTINGS_KEY_PACKAGE_QT_FOR_MCUS_SDK);
@@ -107,12 +107,20 @@ static McuToolChainPackage *createArmGccPackage()
if (defaultPath.isEmpty())
defaultPath = QDir::homePath();
+ const QString detectionPath = Utils::HostOsInfo::withExecutableSuffix("bin/arm-none-eabi-g++");
+ const auto versionDetector = new McuPackageExecutableVersionDetector(
+ detectionPath,
+ { "--version" },
+ "\\b(\\d+\\.\\d+\\.\\d+)\\b"
+ );
+
auto result = new McuToolChainPackage(
McuPackage::tr("GNU Arm Embedded Toolchain"),
defaultPath,
- Utils::HostOsInfo::withExecutableSuffix("bin/arm-none-eabi-g++"),
+ detectionPath,
"GNUArmEmbeddedToolchain",
- McuToolChainPackage::TypeArmGcc);
+ McuToolChainPackage::TypeArmGcc,
+ versionDetector);
result->setEnvironmentVariableName(envVar);
return result;
}
@@ -124,12 +132,43 @@ static McuToolChainPackage *createGhsToolchainPackage()
const QString defaultPath =
qEnvironmentVariableIsSet(envVar) ? qEnvironmentVariable(envVar) : QDir::homePath();
+ const auto versionDetector = new McuPackageExecutableVersionDetector(
+ Utils::HostOsInfo::withExecutableSuffix("as850"),
+ {"-V"},
+ "\\bv(\\d+\\.\\d+\\.\\d+)\\b"
+ );
+
auto result = new McuToolChainPackage(
"Green Hills Compiler",
defaultPath,
Utils::HostOsInfo::withExecutableSuffix("ccv850"),
"GHSToolchain",
- McuToolChainPackage::TypeGHS);
+ McuToolChainPackage::TypeGHS,
+ versionDetector);
+ result->setEnvironmentVariableName(envVar);
+ return result;
+}
+
+static McuToolChainPackage *createGhsArmToolchainPackage()
+{
+ const char envVar[] = "GHS_ARM_COMPILER_DIR";
+
+ const QString defaultPath =
+ qEnvironmentVariableIsSet(envVar) ? qEnvironmentVariable(envVar) : QDir::homePath();
+
+ const auto versionDetector = new McuPackageExecutableVersionDetector(
+ Utils::HostOsInfo::withExecutableSuffix("asarm"),
+ {"-V"},
+ "\\bv(\\d+\\.\\d+\\.\\d+)\\b"
+ );
+
+ auto result = new McuToolChainPackage(
+ "Green Hills Compiler for ARM",
+ defaultPath,
+ Utils::HostOsInfo::withExecutableSuffix("cxarm"),
+ "GHSArmToolchain",
+ McuToolChainPackage::TypeGHSArm,
+ versionDetector);
result->setEnvironmentVariableName(envVar);
return result;
}
@@ -154,12 +193,20 @@ static McuToolChainPackage *createIarToolChainPackage()
defaultPath = QDir::homePath();
}
+ const QString detectionPath = Utils::HostOsInfo::withExecutableSuffix("bin/iccarm");
+ const auto versionDetector = new McuPackageExecutableVersionDetector(
+ detectionPath,
+ {"--version"},
+ "\\bV(\\d+\\.\\d+\\.\\d+)\\.\\d+\\b"
+ );
+
auto result = new McuToolChainPackage(
"IAR ARM Compiler",
defaultPath,
- Utils::HostOsInfo::withExecutableSuffix("bin/iccarm"),
+ detectionPath,
"IARToolchain",
- McuToolChainPackage::TypeIAR);
+ McuToolChainPackage::TypeIAR,
+ versionDetector);
result->setEnvironmentVariableName(envVar);
return result;
}
@@ -248,6 +295,35 @@ static McuPackage *createMcuXpressoIdePackage()
return result;
}
+static McuPackage *createCypressProgrammerPackage()
+{
+ const char envVar[] = "CYPRESS_AUTO_FLASH_UTILITY_DIR";
+
+ QString defaultPath;
+ if (qEnvironmentVariableIsSet(envVar)) {
+ defaultPath = qEnvironmentVariable(envVar);
+ } else if (Utils::HostOsInfo::isWindowsHost()) {
+ auto candidate = findInProgramFiles(QLatin1String("/Cypress/Cypress Auto Flash Utility 1.0/"));
+ if (QFileInfo::exists(candidate)) {
+ defaultPath = candidate;
+ }
+ } else {
+ defaultPath = QLatin1String("/usr");
+ }
+
+ if (defaultPath.isEmpty()) {
+ defaultPath = QDir::homePath();
+ }
+
+ auto result = new McuPackage(
+ "Cypress Auto Flash Utility",
+ defaultPath,
+ Utils::HostOsInfo::withExecutableSuffix("/bin/openocd"),
+ "CypressAutoFlashUtil");
+ result->setEnvironmentVariableName(envVar);
+ return result;
+}
+
struct McuTargetDescription
{
enum class TargetType {
@@ -261,14 +337,33 @@ struct McuTargetDescription
QString platformVendor;
QVector<int> colorDepths;
QString toolchainId;
+ QVector<QString> toolchainVersions;
QString boardSdkEnvVar;
QString boardSdkName;
QString boardSdkDefaultPath;
+ QVector<QString> boardSdkVersions;
QString freeRTOSEnvVar;
QString freeRTOSBoardSdkSubDir;
TargetType type;
};
+static McuPackageVersionDetector* generatePackageVersionDetector(QString envVar)
+{
+ if (envVar.startsWith("EVK"))
+ return new McuPackageXmlVersionDetector("*_manifest_*.xml", "ksdk", "version", ".*");
+
+ if (envVar.startsWith("STM32"))
+ return new McuPackageXmlVersionDetector("package.xml", "PackDescription", "Release", "\\b(\\d+\\.\\d+\\.\\d+)\\b");
+
+ if (envVar.startsWith("RGL"))
+ return new McuPackageDirectoryVersionDetector("rgl_*_obj_*", "\\d+\\.\\d+\\.\\w+", false);
+
+ return nullptr;
+}
+
+/// Create the McuPackage by checking the "boardSdk" property in the JSON file for the board.
+/// The name of the environment variable pointing to the the SDK for the board will be defined in the "envVar" property
+/// inside the "boardSdk".
static McuPackage *createBoardSdkPackage(const McuTargetDescription& desc)
{
const auto generateSdkName = [](const QString& envVar) {
@@ -295,11 +390,14 @@ static McuPackage *createBoardSdkPackage(const McuTargetDescription& desc)
return QDir::homePath();
}();
+ const auto versionDetector = generatePackageVersionDetector(desc.boardSdkEnvVar);
+
auto result = new McuPackage(
sdkName,
defaultPath,
{},
- desc.boardSdkEnvVar);
+ desc.boardSdkEnvVar,
+ versionDetector);
result->setEnvironmentVariableName(desc.boardSdkEnvVar);
return result;
}
@@ -433,7 +531,10 @@ protected:
QVector<McuTarget *> mcuTargets;
McuToolChainPackage *tcPkg = tcPkgs.value(desc.toolchainId);
- if (!tcPkg)
+ if (tcPkg) {
+ if (QVersionNumber::fromString(desc.qulVersion) >= QVersionNumber({1,8}))
+ tcPkg->setVersions(desc.toolchainVersions);
+ } else
tcPkg = createUnsupportedToolChainPackage();
for (int colorDepth : desc.colorDepths) {
QVector<McuPackage*> required3rdPartyPkgs;
@@ -455,6 +556,8 @@ protected:
boardSdkPkgs.insert(desc.boardSdkEnvVar, boardSdkPkg);
}
auto boardSdkPkg = boardSdkPkgs.value(desc.boardSdkEnvVar);
+ if (QVersionNumber::fromString(desc.qulVersion) >= QVersionNumber({1,8}))
+ boardSdkPkg->setVersions(desc.boardSdkVersions);
boardSdkDefaultPath = boardSdkPkg->defaultPath();
required3rdPartyPkgs.append(boardSdkPkg);
}
@@ -495,11 +598,15 @@ static QVector<McuTarget *> targetsFromDescriptions(const QList<McuTargetDescrip
{{"iar"}, createIarToolChainPackage()},
{{"msvc"}, createMsvcToolChainPackage()},
{{"gcc"}, createGccToolChainPackage()},
+ {{"arm-greenhills"}, createGhsArmToolchainPackage()},
};
+ // Note: the vendor name (the key of the hash) is case-sensitive. It has to match the "platformVendor" key in the
+ // json file.
const QHash<QString, McuPackage *> vendorPkgs = {
{{"ST"}, createStm32CubeProgrammerPackage()},
{{"NXP"}, createMcuXpressoIdePackage()},
+ {{"CYPRESS"}, createCypressProgrammerPackage()},
};
McuTargetFactory targetFactory(tcPkgs, vendorPkgs);
@@ -541,6 +648,12 @@ static McuTargetDescription parseDescriptionJson(const QByteArray &data)
const QVariantList colorDepths = target.value("colorDepths").toArray().toVariantList();
const auto colorDepthsVector = Utils::transform<QVector<int> >(
colorDepths, [&](const QVariant &colorDepth) { return colorDepth.toInt(); });
+ const QVariantList toolchainVersions = toolchain.value("versions").toArray().toVariantList();
+ const auto toolchainVersionsVector = Utils::transform<QVector<QString> >(
+ toolchainVersions, [&](const QVariant &version) { return version.toString(); });
+ const QVariantList boardSdkVersions = boardSdk.value("versions").toArray().toVariantList();
+ const auto boardSdkVersionsVector = Utils::transform<QVector<QString> >(
+ boardSdkVersions, [&](const QVariant &version) { return version.toString(); });
return {
target.value("qulVersion").toString(),
@@ -549,15 +662,42 @@ static McuTargetDescription parseDescriptionJson(const QByteArray &data)
target.value("platformVendor").toString(),
colorDepthsVector,
toolchain.value("id").toString(),
+ toolchainVersionsVector,
boardSdk.value("envVar").toString(),
boardSdk.value("name").toString(),
boardSdk.value("defaultPath").toString(),
+ boardSdkVersionsVector,
freeRTOS.value("envVar").toString(),
freeRTOS.value("boardSdkSubDir").toString(),
boardSdk.empty() ? McuTargetDescription::TargetType::Desktop : McuTargetDescription::TargetType::MCU
};
}
+// https://doc.qt.io/qtcreator/creator-developing-mcu.html#supported-qt-for-mcus-sdks
+const QHash<QString, QString> oldSdkQtcRequiredVersion = {
+ {{"1.0"}, {"4.11.x"}},
+ {{"1.1"}, {"4.12.0 or 4.12.1"}},
+ {{"1.2"}, {"4.12.2 or 4.12.3"}},
+};
+
+bool checkDeprecatedSdkError(const Utils::FilePath &qulDir, QString &message)
+{
+ const McuPackagePathVersionDetector versionDetector("(?<=\\bQtMCUs.)(\\d+\\.\\d+)");
+ const QString sdkDetectedVersion = versionDetector.parseVersion(qulDir.toString());
+
+ if (oldSdkQtcRequiredVersion.contains(sdkDetectedVersion)) {
+ message = McuTarget::tr("Qt for MCUs SDK version %1 detected, "
+ "only supported by Qt Creator version %2. "
+ "This version of Qt Creator requires Qt for MCUs %3 or greater."
+ ).arg(sdkDetectedVersion,
+ oldSdkQtcRequiredVersion.value(sdkDetectedVersion),
+ McuSupportOptions::minimalQulVersion().toString());
+ return true;
+ }
+
+ return false;
+}
+
void targetsAndPackages(const Utils::FilePath &dir, QVector<McuPackage *> *packages,
QVector<McuTarget *> *mcuTargets)
{
@@ -570,11 +710,16 @@ void targetsAndPackages(const Utils::FilePath &dir, QVector<McuPackage *> *packa
continue;
const McuTargetDescription desc = parseDescriptionJson(file.readAll());
if (QVersionNumber::fromString(desc.qulVersion) < McuSupportOptions::minimalQulVersion()) {
- auto pth = Utils::FilePath::fromString(fileInfo.filePath());
- printMessage(McuTarget::tr("Skipped %1 - Unsupported version \"%2\" (should be >= %3)")
+ const auto pth = Utils::FilePath::fromString(fileInfo.filePath());
+ const QString qtcSupportText = oldSdkQtcRequiredVersion.contains(desc.qulVersion) ?
+ McuTarget::tr("Detected version \"%1\", only supported by Qt Creator %2.")
+ .arg(desc.qulVersion, oldSdkQtcRequiredVersion.value(desc.qulVersion))
+ : McuTarget::tr("Unsupported version \"%1\".")
+ .arg(desc.qulVersion);
+ printMessage(McuTarget::tr("Skipped %1. %2 Qt for MCUs version >= %3 required.")
.arg(
QDir::toNativeSeparators(pth.fileNameWithPathComponents(1)),
- desc.qulVersion,
+ qtcSupportText,
McuSupportOptions::minimalQulVersion().toString()),
false);
continue;
@@ -582,10 +727,19 @@ void targetsAndPackages(const Utils::FilePath &dir, QVector<McuPackage *> *packa
descriptions.append(desc);
}
- // No valid description means invalid SDK installation.
- if (descriptions.empty() && kitsPath(dir).exists()) {
- printMessage(McuTarget::tr("No valid kit descriptions found at %1.").arg(kitsPath(dir).toUserOutput()), true);
- return;
+ // No valid description means invalid or old SDK installation.
+ if (descriptions.empty()) {
+ if (kitsPath(dir).exists()) {
+ printMessage(McuTarget::tr("No valid kit descriptions found at %1.")
+ .arg(kitsPath(dir).toUserOutput()), true);
+ return;
+ } else {
+ QString deprecationMessage;
+ if (checkDeprecatedSdkError(dir, deprecationMessage)) {
+ printMessage(deprecationMessage, true);
+ return;
+ }
+ }
}
// Workaround for missing JSON file for Desktop target.
diff --git a/src/plugins/mcusupport/mcusupportsdk.h b/src/plugins/mcusupport/mcusupportsdk.h
index da47119612..f7519919e5 100644
--- a/src/plugins/mcusupport/mcusupportsdk.h
+++ b/src/plugins/mcusupport/mcusupportsdk.h
@@ -40,6 +40,8 @@ namespace Sdk {
McuPackage *createQtForMCUsPackage();
+bool checkDeprecatedSdkError(const Utils::FilePath &qulDir, QString &message);
+
void targetsAndPackages(const Utils::FilePath &qulDir,
QVector<McuPackage*> *packages, QVector<McuTarget*> *mcuTargets);
diff --git a/src/plugins/mcusupport/mcusupportversiondetection.cpp b/src/plugins/mcusupport/mcusupportversiondetection.cpp
new file mode 100644
index 0000000000..1266202ef8
--- /dev/null
+++ b/src/plugins/mcusupport/mcusupportversiondetection.cpp
@@ -0,0 +1,151 @@
+/****************************************************************************
+**
+** Copyright (C) 2020 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of Qt Creator.
+**
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3 as published by the Free Software
+** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-3.0.html.
+**
+****************************************************************************/
+
+#include "mcusupportversiondetection.h"
+
+#include <utils/fileutils.h>
+#include <QDir>
+#include <QRegularExpression>
+#include <QProcess>
+
+namespace McuSupport {
+namespace Internal {
+
+QString matchRegExp(const QString &text, const QString &regExp)
+{
+ const QRegularExpression regularExpression(regExp);
+ const QRegularExpressionMatch match = regularExpression.match(text);
+ if (match.hasMatch())
+ return match.captured(regularExpression.captureCount());
+ return QString();
+}
+
+McuPackageVersionDetector::McuPackageVersionDetector()
+{
+}
+
+McuPackageExecutableVersionDetector::McuPackageExecutableVersionDetector(
+ const QString &detectionPath,
+ const QStringList &detectionArgs,
+ const QString &detectionRegExp)
+ : McuPackageVersionDetector()
+ , m_detectionPath(detectionPath)
+ , m_detectionArgs(detectionArgs)
+ , m_detectionRegExp(detectionRegExp)
+{
+}
+
+QString McuPackageExecutableVersionDetector::parseVersion(const QString &packagePath) const
+{
+ if (m_detectionPath.isEmpty() || m_detectionRegExp.isEmpty())
+ return QString();
+
+ QString binaryPath = QDir::toNativeSeparators(packagePath + "/" + m_detectionPath);
+ if (!Utils::FilePath::fromString(binaryPath).exists())
+ return QString();
+
+
+ const int execTimeout = 3000; // usually runs below 1s, but we want to be on the safe side
+ QProcess binaryProcess;
+ binaryProcess.start(binaryPath, m_detectionArgs);
+ if (!binaryProcess.waitForStarted())
+ return QString();
+ binaryProcess.waitForFinished(execTimeout);
+ if (binaryProcess.exitCode() == QProcess::ExitStatus::NormalExit) {
+ const QString processOutput = QString::fromUtf8(
+ binaryProcess.readAllStandardOutput().append(
+ binaryProcess.readAllStandardError()));
+ return matchRegExp(processOutput, m_detectionRegExp);
+ }
+
+ // Fail gracefully: return empty string if execution failed
+ return QString();
+}
+
+McuPackageXmlVersionDetector::McuPackageXmlVersionDetector(const QString &filePattern,
+ const QString &versionElement,
+ const QString &versionAttribute,
+ const QString &versionRegExp)
+ : m_filePattern(filePattern),
+ m_versionElement(versionElement),
+ m_versionAttribute(versionAttribute),
+ m_versionRegExp(versionRegExp)
+{
+}
+
+QString McuPackageXmlVersionDetector::parseVersion(const QString &packagePath) const
+{
+ const auto files = QDir(packagePath, m_filePattern).entryInfoList();
+ for (const auto &xmlFile: files) {
+ QFile sdkXmlFile = QFile(xmlFile.absoluteFilePath());
+ sdkXmlFile.open(QFile::OpenModeFlag::ReadOnly);
+ QXmlStreamReader xmlReader(&sdkXmlFile);
+ while (xmlReader.readNext()) {
+ if (xmlReader.name() == m_versionElement) {
+ const QString versionString = xmlReader.attributes().value(m_versionAttribute).toString();
+ const QString matched = matchRegExp(versionString, m_versionRegExp);
+ return !matched.isEmpty() ? matched : versionString;
+ }
+ }
+ }
+
+ return QString();
+}
+
+McuPackageDirectoryVersionDetector::McuPackageDirectoryVersionDetector(const QString &filePattern,
+ const QString &versionRegExp,
+ const bool isFile)
+ : m_filePattern(filePattern),
+ m_versionRegExp(versionRegExp),
+ m_isFile(isFile)
+{
+}
+
+QString McuPackageDirectoryVersionDetector::parseVersion(const QString &packagePath) const
+{
+ const auto files = QDir(packagePath, m_filePattern)
+ .entryInfoList(m_isFile ? QDir::Filter::Files : QDir::Filter::Dirs);
+ for (const auto &entry: files) {
+ const QString matched = matchRegExp(entry.fileName(), m_versionRegExp);
+ if (!matched.isEmpty())
+ return matched;
+ }
+ return QString();
+}
+
+McuPackagePathVersionDetector::McuPackagePathVersionDetector(const QString &versionRegExp)
+ : m_versionRegExp(versionRegExp)
+{
+}
+
+QString McuPackagePathVersionDetector::parseVersion(const QString &packagePath) const
+{
+ if (!Utils::FilePath::fromString(packagePath).exists())
+ return QString();
+ return matchRegExp(packagePath, m_versionRegExp);
+}
+
+} // Internal
+} // McuSupport
diff --git a/src/plugins/mcusupport/mcusupportversiondetection.h b/src/plugins/mcusupport/mcusupportversiondetection.h
new file mode 100644
index 0000000000..b32406f013
--- /dev/null
+++ b/src/plugins/mcusupport/mcusupportversiondetection.h
@@ -0,0 +1,98 @@
+/****************************************************************************
+**
+** Copyright (C) 2020 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of Qt Creator.
+**
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3 as published by the Free Software
+** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-3.0.html.
+**
+****************************************************************************/
+
+#ifndef MCUSUPPORTVERSIONDETECTION_H
+#define MCUSUPPORTVERSIONDETECTION_H
+
+#include <QObject>
+
+namespace McuSupport {
+namespace Internal {
+
+class McuPackageVersionDetector : public QObject
+{
+ Q_OBJECT
+public:
+ McuPackageVersionDetector();
+ virtual ~McuPackageVersionDetector() = default;
+ virtual QString parseVersion(const QString &packagePath) const = 0;
+};
+
+// Get version from the output of an executable
+class McuPackageExecutableVersionDetector : public McuPackageVersionDetector
+{
+public:
+ McuPackageExecutableVersionDetector(const QString &detectionPath,
+ const QStringList &detectionArgs,
+ const QString &detectionRegExp);
+ virtual QString parseVersion(const QString &packagePath) const;
+private:
+ const QString m_detectionPath;
+ const QStringList m_detectionArgs;
+ const QString m_detectionRegExp;
+};
+
+// Get version through parsing an XML file
+class McuPackageXmlVersionDetector : public McuPackageVersionDetector
+{
+public:
+ McuPackageXmlVersionDetector(const QString &filePattern,
+ const QString &elementName,
+ const QString &versionAttribute,
+ const QString &versionRegExp);
+ QString parseVersion(const QString &packagePath) const;
+private:
+ const QString m_filePattern;
+ const QString m_versionElement;
+ const QString m_versionAttribute;
+ const QString m_versionRegExp;
+};
+
+// Get version from the filename of a given file/dir in the package directory
+class McuPackageDirectoryVersionDetector : public McuPackageVersionDetector
+{
+public:
+ McuPackageDirectoryVersionDetector(const QString &filePattern, const QString &versionRegExp, const bool isFile);
+ QString parseVersion(const QString &packagePath) const;
+private:
+ const QString m_filePattern;
+ const QString m_versionRegExp;
+ const bool m_isFile;
+};
+
+// Get version from the path of the package itself
+class McuPackagePathVersionDetector : public McuPackageVersionDetector
+{
+public:
+ McuPackagePathVersionDetector(const QString &versionRegExp);
+ QString parseVersion(const QString &packagePath) const;
+private:
+ const QString m_versionRegExp;
+};
+
+} // Internal
+} // McuSupport
+
+#endif // MCUSUPPORTVERSIONDETECTION_H
diff --git a/src/plugins/mercurial/CMakeLists.txt b/src/plugins/mercurial/CMakeLists.txt
index e81b3e3eaf..915b9a8cdf 100644
--- a/src/plugins/mercurial/CMakeLists.txt
+++ b/src/plugins/mercurial/CMakeLists.txt
@@ -11,7 +11,6 @@ add_qtc_plugin(Mercurial
mercurialeditor.cpp mercurialeditor.h
mercurialplugin.cpp mercurialplugin.h
mercurialsettings.cpp mercurialsettings.h
- optionspage.cpp optionspage.h optionspage.ui
revertdialog.cpp revertdialog.h revertdialog.ui
srcdestdialog.cpp srcdestdialog.h srcdestdialog.ui
)
diff --git a/src/plugins/mercurial/mercurial.pro b/src/plugins/mercurial/mercurial.pro
index 9057e0fcc0..a36edc1e15 100644
--- a/src/plugins/mercurial/mercurial.pro
+++ b/src/plugins/mercurial/mercurial.pro
@@ -1,6 +1,5 @@
include(../../qtcreatorplugin.pri)
SOURCES += mercurialplugin.cpp \
- optionspage.cpp \
mercurialclient.cpp \
annotationhighlighter.cpp \
mercurialeditor.cpp \
@@ -12,7 +11,6 @@ SOURCES += mercurialplugin.cpp \
authenticationdialog.cpp
HEADERS += mercurialplugin.h \
constants.h \
- optionspage.h \
mercurialclient.h \
annotationhighlighter.h \
mercurialeditor.h \
@@ -22,7 +20,7 @@ HEADERS += mercurialplugin.h \
commiteditor.h \
mercurialsettings.h \
authenticationdialog.h
-FORMS += optionspage.ui \
+FORMS += \
revertdialog.ui \
srcdestdialog.ui \
mercurialcommitpanel.ui \
diff --git a/src/plugins/mercurial/mercurial.qbs b/src/plugins/mercurial/mercurial.qbs
index 43a3c68598..0f8b5613bf 100644
--- a/src/plugins/mercurial/mercurial.qbs
+++ b/src/plugins/mercurial/mercurial.qbs
@@ -31,9 +31,6 @@ QtcPlugin {
"mercurialplugin.h",
"mercurialsettings.cpp",
"mercurialsettings.h",
- "optionspage.cpp",
- "optionspage.h",
- "optionspage.ui",
"revertdialog.cpp",
"revertdialog.h",
"revertdialog.ui",
diff --git a/src/plugins/mercurial/mercurialclient.cpp b/src/plugins/mercurial/mercurialclient.cpp
index 3c42617871..9baa912f16 100644
--- a/src/plugins/mercurial/mercurialclient.cpp
+++ b/src/plugins/mercurial/mercurialclient.cpp
@@ -35,10 +35,11 @@
#include <vcsbase/vcsbaseeditor.h>
#include <vcsbase/vcsbaseeditorconfig.h>
#include <vcsbase/vcsbasediffeditorcontroller.h>
-#include <utils/synchronousprocess.h>
+
#include <utils/fileutils.h>
#include <utils/hostosinfo.h>
#include <utils/qtcassert.h>
+#include <utils/qtcprocess.h>
#include <QDateTime>
#include <QDir>
@@ -95,12 +96,13 @@ bool MercurialClient::manifestSync(const QString &repository, const QString &rel
// This only works when called from the repo and outputs paths relative to it.
const QStringList args(QLatin1String("manifest"));
- const SynchronousProcessResponse result = vcsFullySynchronousExec(repository, args);
+ SynchronousProcess proc;
+ vcsFullySynchronousExec(proc, repository, args);
const QDir repositoryDir(repository);
const QFileInfo needle = QFileInfo(repositoryDir, relativeFilename);
- const QStringList files = result.stdOut().split(QLatin1Char('\n'));
+ const QStringList files = proc.stdOut().split(QLatin1Char('\n'));
foreach (const QString &fileName, files) {
const QFileInfo managedFile(repositoryDir, fileName);
if (needle == managedFile)
@@ -125,21 +127,21 @@ bool MercurialClient::synchronousClone(const QString &workingDir,
if (workingDirectory.exists()) {
// Let's make first init
QStringList arguments(QLatin1String("init"));
- const SynchronousProcessResponse resp = vcsFullySynchronousExec(
- workingDirectory.path(), arguments);
- if (resp.result != SynchronousProcessResponse::Finished)
+ SynchronousProcess proc;
+ vcsFullySynchronousExec(proc, workingDirectory.path(), arguments);
+ if (proc.result() != QtcProcess::Finished)
return false;
// Then pull remote repository
arguments.clear();
arguments << QLatin1String("pull") << dstLocation;
- const SynchronousProcessResponse resp1 = vcsSynchronousExec(
- workingDirectory.path(), arguments, flags);
- if (resp1.result != SynchronousProcessResponse::Finished)
+ SynchronousProcess proc1;
+ vcsSynchronousExec(proc1, workingDirectory.path(), arguments, flags);
+ if (proc1.result() != QtcProcess::Finished)
return false;
// By now, there is no hgrc file -> create it
- FileSaver saver(workingDirectory.path() + QLatin1String("/.hg/hgrc"));
+ FileSaver saver(Utils::FilePath::fromString(workingDirectory.path() + "/.hg/hgrc"));
const QString hgrc = QLatin1String("[paths]\ndefault = ") + dstLocation + QLatin1Char('\n');
saver.write(hgrc.toUtf8());
if (!saver.finalize()) {
@@ -150,16 +152,16 @@ bool MercurialClient::synchronousClone(const QString &workingDir,
// And last update repository
arguments.clear();
arguments << QLatin1String("update");
- const SynchronousProcessResponse resp2 = vcsSynchronousExec(
- workingDirectory.path(), arguments, flags);
- return resp2.result == SynchronousProcessResponse::Finished;
+ SynchronousProcess proc2;
+ vcsSynchronousExec(proc2, workingDirectory.path(), arguments, flags);
+ return proc2.result() == QtcProcess::Finished;
} else {
QStringList arguments(QLatin1String("clone"));
arguments << dstLocation << workingDirectory.dirName();
workingDirectory.cdUp();
- const SynchronousProcessResponse resp = vcsSynchronousExec(
- workingDirectory.path(), arguments, flags);
- return resp.result == SynchronousProcessResponse::Finished;
+ SynchronousProcess proc;
+ vcsSynchronousExec(proc, workingDirectory.path(), arguments, flags);
+ return proc.result() == QtcProcess::Finished;
}
}
@@ -174,13 +176,18 @@ bool MercurialClient::synchronousPull(const QString &workingDir, const QString &
| VcsCommand::ShowSuccessMessage;
// cause mercurial doesn`t understand LANG
- QProcessEnvironment env = QProcessEnvironment::systemEnvironment();
- env.insert(QLatin1String("LANGUAGE"), QLatin1String("C"));
- const SynchronousProcessResponse resp = VcsBase::runVcs(
- workingDir, {vcsBinary(), args}, vcsTimeoutS(), flags, nullptr, env);
- const bool ok = resp.result == SynchronousProcessResponse::Finished;
+ Environment env = Environment::systemEnvironment();
+ env.set("LANGUAGE", "C");
+ SynchronousProcess proc;
+ proc.setTimeoutS(vcsTimeoutS());
+
+ VcsCommand command(workingDir, env);
+ command.addFlags(flags);
+ command.runCommand(proc, {vcsBinary(), args});
+
+ const bool ok = proc.result() == QtcProcess::Finished;
- parsePullOutput(resp.stdOut().trimmed());
+ parsePullOutput(proc.stdOut().trimmed());
return ok;
}
@@ -217,22 +224,25 @@ QStringList MercurialClient::parentRevisionsSync(const QString &workingDirectory
args << QLatin1String("parents") << QLatin1String("-r") <<revision;
if (!file.isEmpty())
args << file;
- const SynchronousProcessResponse resp = vcsFullySynchronousExec(workingDirectory, args);
- if (resp.result != SynchronousProcessResponse::Finished)
+ SynchronousProcess proc;
+ vcsFullySynchronousExec(proc, workingDirectory, args);
+ if (proc.result() != QtcProcess::Finished)
return QStringList();
/* Looks like: \code
changeset: 0:031a48610fba
user: ...
\endcode */
// Obtain first line and split by blank-delimited tokens
- const QStringList lines = resp.stdOut().split(QLatin1Char('\n'));
+ const QStringList lines = proc.stdOut().split(QLatin1Char('\n'));
if (lines.size() < 1) {
- VcsOutputWindow::appendSilently(msgParentRevisionFailed(workingDirectory, revision, msgParseParentsOutputFailed(resp.stdOut())));
+ VcsOutputWindow::appendSilently(
+ msgParentRevisionFailed(workingDirectory, revision, msgParseParentsOutputFailed(proc.stdOut())));
return QStringList();
}
QStringList changeSets = lines.front().simplified().split(QLatin1Char(' '));
if (changeSets.size() < 2) {
- VcsOutputWindow::appendSilently(msgParentRevisionFailed(workingDirectory, revision, msgParseParentsOutputFailed(resp.stdOut())));
+ VcsOutputWindow::appendSilently(
+ msgParentRevisionFailed(workingDirectory, revision, msgParseParentsOutputFailed(proc.stdOut())));
return QStringList();
}
// Remove revision numbers
@@ -257,10 +267,11 @@ QString MercurialClient::shortDescriptionSync(const QString &workingDirectory,
if (!format.isEmpty())
args << QLatin1String("--template") << format;
- const SynchronousProcessResponse resp = vcsFullySynchronousExec(workingDirectory, args);
- if (resp.result != SynchronousProcessResponse::Finished)
+ SynchronousProcess proc;
+ vcsFullySynchronousExec(proc, workingDirectory, args);
+ if (proc.result() != QtcProcess::Finished)
return revision;
- return stripLastNewline(resp.stdOut());
+ return stripLastNewline(proc.stdOut());
}
// Default format: "SHA1 (author summmary)"
@@ -276,7 +287,9 @@ bool MercurialClient::managesFile(const QString &workingDirectory, const QString
{
QStringList args;
args << QLatin1String("status") << QLatin1String("--unknown") << fileName;
- return vcsFullySynchronousExec(workingDirectory, args).stdOut().isEmpty();
+ SynchronousProcess proc;
+ vcsFullySynchronousExec(proc, workingDirectory, args);
+ return proc.stdOut().isEmpty();
}
void MercurialClient::incoming(const QString &repositoryRoot, const QString &repository)
@@ -458,8 +471,8 @@ void MercurialClient::requestReload(const QString &documentId, const QString &so
controller->setReloader([controller, args] {
controller->runCommand({controller->addConfigurationArguments(args)});
});
- controller->setVcsBinary(settings().binaryPath());
- controller->setVcsTimeoutS(settings().vcsTimeoutS());
+ controller->setVcsBinary(settings().binaryPath.filePath());
+ controller->setVcsTimeoutS(settings().timeout.value());
controller->setProcessEnvironment(processEnvironment());
controller->setWorkingDirectory(workingDirectory);
diff --git a/src/plugins/mercurial/mercurialplugin.cpp b/src/plugins/mercurial/mercurialplugin.cpp
index db5391b674..f0e0be5d27 100644
--- a/src/plugins/mercurial/mercurialplugin.cpp
+++ b/src/plugins/mercurial/mercurialplugin.cpp
@@ -24,14 +24,14 @@
****************************************************************************/
#include "mercurialplugin.h"
-#include "optionspage.h"
+
+#include "commiteditor.h"
#include "constants.h"
#include "mercurialclient.h"
#include "mercurialeditor.h"
+#include "mercurialsettings.h"
#include "revertdialog.h"
#include "srcdestdialog.h"
-#include "commiteditor.h"
-#include "mercurialsettings.h"
#include <coreplugin/actionmanager/actionmanager.h>
#include <coreplugin/actionmanager/actioncontainer.h>
@@ -196,8 +196,7 @@ private:
// Variables
MercurialSettings m_settings;
MercurialClient m_client{&m_settings};
-
- OptionsPage m_optionsPage{[this] { configurationChanged(); }, &m_settings};
+ MercurialSettingsPage m_settingsPage{&m_settings};
Core::CommandLocator *m_commandLocator = nullptr;
Core::ActionContainer *m_mercurialContainer = nullptr;
@@ -279,8 +278,11 @@ MercurialPluginPrivate::MercurialPluginPrivate()
const QString prefix = QLatin1String("hg");
m_commandLocator = new Core::CommandLocator("Mercurial", prefix, prefix, this);
+ m_commandLocator->setDescription(tr("Triggers a Mercurial version control operation."));
createMenu(context);
+
+ connect(&m_settings, &AspectContainer::applied, this, &IVersionControl::configurationChanged);
}
void MercurialPluginPrivate::createMenu(const Core::Context &context)
@@ -641,8 +643,7 @@ void MercurialPluginPrivate::showCommitWidget(const QList<VcsBaseClient::StatusI
return;
}
- Core::IEditor *editor = Core::EditorManager::openEditor(saver.fileName(),
- Constants::COMMIT_ID);
+ Core::IEditor *editor = Core::EditorManager::openEditor(saver.filePath(), Constants::COMMIT_ID);
if (!editor) {
VcsOutputWindow::appendError(tr("Unable to create an editor for the commit."));
return;
@@ -662,8 +663,8 @@ void MercurialPluginPrivate::showCommitWidget(const QList<VcsBaseClient::StatusI
const QString branch = vcsTopic(m_submitRepository);
commitEditor->setFields(QFileInfo(m_submitRepository), branch,
- m_settings.stringValue(MercurialSettings::userNameKey),
- m_settings.stringValue(MercurialSettings::userEmailKey), status);
+ m_settings.userName.value(),
+ m_settings.userEmail.value(), status);
}
void MercurialPluginPrivate::diffFromEditorSelected(const QStringList &files)
@@ -767,7 +768,7 @@ bool MercurialPluginPrivate::managesFile(const QString &workingDirectory, const
bool MercurialPluginPrivate::isConfigured() const
{
- const Utils::FilePath binary = m_settings.binaryPath();
+ const FilePath binary = m_settings.binaryPath.filePath();
if (binary.isEmpty())
return false;
QFileInfo fi = binary.toFileInfo();
@@ -839,7 +840,7 @@ Core::ShellCommand *MercurialPluginPrivate::createInitialCheckoutCommand(const Q
args << QLatin1String("clone") << extraArgs << url << localName;
auto command = new VcsBase::VcsCommand(baseDirectory.toString(),
m_client.processEnvironment());
- command->addJob({m_settings.binaryPath(), args}, -1);
+ command->addJob({m_settings.binaryPath.filePath(), args}, -1);
return command;
}
diff --git a/src/plugins/mercurial/mercurialsettings.cpp b/src/plugins/mercurial/mercurialsettings.cpp
index 4bc2184634..9473446482 100644
--- a/src/plugins/mercurial/mercurialsettings.cpp
+++ b/src/plugins/mercurial/mercurialsettings.cpp
@@ -24,23 +24,87 @@
****************************************************************************/
#include "mercurialsettings.h"
+
#include "constants.h"
-#include <QSettings>
+#include <utils/layoutbuilder.h>
+
+#include <vcsbase/vcsbaseconstants.h>
+
+using namespace Utils;
namespace Mercurial {
namespace Internal {
-const QLatin1String MercurialSettings::diffIgnoreWhiteSpaceKey("diffIgnoreWhiteSpace");
-const QLatin1String MercurialSettings::diffIgnoreBlankLinesKey("diffIgnoreBlankLines");
-
MercurialSettings::MercurialSettings()
{
- setSettingsGroup(QLatin1String("Mercurial"));
- // Override default binary path
- declareKey(binaryPathKey, QLatin1String(Constants::MERCURIALDEFAULT));
- declareKey(diffIgnoreWhiteSpaceKey, false);
- declareKey(diffIgnoreBlankLinesKey, false);
+ setSettingsGroup("Mercurial");
+ setAutoApply(false);
+
+ registerAspect(&binaryPath);
+ binaryPath.setDisplayStyle(StringAspect::PathChooserDisplay);
+ binaryPath.setExpectedKind(PathChooser::ExistingCommand);
+ binaryPath.setDefaultValue(Constants::MERCURIALDEFAULT);
+ binaryPath.setDisplayName(tr("Mercurial Command"));
+ binaryPath.setHistoryCompleter("Bazaar.Command.History");
+ binaryPath.setLabelText(tr("Command:"));
+
+ registerAspect(&userName);
+ userName.setDisplayStyle(StringAspect::LineEditDisplay);
+ userName.setLabelText(tr("Default username:"));
+ userName.setToolTip(tr("Username to use by default on commit."));
+
+ registerAspect(&userEmail);
+ userEmail.setDisplayStyle(StringAspect::LineEditDisplay);
+ userEmail.setLabelText(tr("Default email:"));
+ userEmail.setToolTip(tr("Email to use by default on commit."));
+
+ registerAspect(&diffIgnoreWhiteSpace);
+ diffIgnoreWhiteSpace.setSettingsKey("diffIgnoreWhiteSpace");
+
+ registerAspect(&diffIgnoreBlankLines);
+ diffIgnoreBlankLines.setSettingsKey("diffIgnoreBlankLines");
+}
+
+// MercurialSettingsPage
+
+MercurialSettingsPage::MercurialSettingsPage(MercurialSettings *settings)
+{
+ setId(VcsBase::Constants::VCS_ID_MERCURIAL);
+ setDisplayName(MercurialSettings::tr("Mercurial"));
+ setCategory(VcsBase::Constants::VCS_SETTINGS_CATEGORY);
+ setSettings(m_settings);
+
+ setLayouter([settings](QWidget *widget) {
+ MercurialSettings &s = *settings;
+ using namespace Layouting;
+
+ Column {
+ Group {
+ Title(MercurialSettings::tr("Configuration")),
+ Row { s.binaryPath }
+ },
+
+ Group {
+ Title(MercurialSettings::tr("User")),
+ Form {
+ s.userName,
+ s.userEmail
+ }
+ },
+
+ Group {
+ Title(MercurialSettings::tr("Miscellaneous")),
+ Row {
+ s.logCount,
+ s.timeout,
+ Stretch()
+ }
+ },
+ Stretch()
+
+ }.attachTo(widget);
+ });
}
} // namespace Internal
diff --git a/src/plugins/mercurial/mercurialsettings.h b/src/plugins/mercurial/mercurialsettings.h
index 4310589eca..14af6d92bd 100644
--- a/src/plugins/mercurial/mercurialsettings.h
+++ b/src/plugins/mercurial/mercurialsettings.h
@@ -25,19 +25,27 @@
#pragma once
+#include <coreplugin/dialogs/ioptionspage.h>
+
#include <vcsbase/vcsbaseclientsettings.h>
namespace Mercurial {
namespace Internal {
-class MercurialSettings : public VcsBase::VcsBaseClientSettings
+class MercurialSettings : public VcsBase::VcsBaseSettings
{
public:
- static const QLatin1String diffIgnoreWhiteSpaceKey;
- static const QLatin1String diffIgnoreBlankLinesKey;
+ Utils::StringAspect diffIgnoreWhiteSpace;
+ Utils::StringAspect diffIgnoreBlankLines;
MercurialSettings();
};
+class MercurialSettingsPage final : public Core::IOptionsPage
+{
+public:
+ explicit MercurialSettingsPage(MercurialSettings *settings);
+};
+
} // namespace Internal
} // namespace Mercurial
diff --git a/src/plugins/mercurial/optionspage.cpp b/src/plugins/mercurial/optionspage.cpp
deleted file mode 100644
index a9c267bf9e..0000000000
--- a/src/plugins/mercurial/optionspage.cpp
+++ /dev/null
@@ -1,98 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 Brian McGillion
-** 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 "optionspage.h"
-
-#include "mercurialclient.h"
-#include "mercurialsettings.h"
-#include "mercurialplugin.h"
-#include "ui_optionspage.h"
-#include "ui_optionspage.h"
-
-#include <coreplugin/icore.h>
-#include <utils/pathchooser.h>
-#include <vcsbase/vcsbaseconstants.h>
-
-using namespace VcsBase;
-
-namespace Mercurial {
-namespace Internal {
-
-class OptionsPageWidget final : public Core::IOptionsPageWidget
-{
- Q_DECLARE_TR_FUNCTIONS(Mercurial::Internal::OptionsPageWidget)
-
-public:
- OptionsPageWidget(const std::function<void()> &onApply, MercurialSettings *settings);
- void apply() final;
-
-private:
- Ui::OptionsPage m_ui;
- std::function<void()> m_onApply;
- MercurialSettings *m_settings;
-};
-
-OptionsPageWidget::OptionsPageWidget(const std::function<void()> &onApply, MercurialSettings *settings)
- : m_onApply(onApply), m_settings(settings)
-{
- m_ui.setupUi(this);
- m_ui.commandChooser->setExpectedKind(Utils::PathChooser::ExistingCommand);
- m_ui.commandChooser->setHistoryCompleter(QLatin1String("Mercurial.Command.History"));
- m_ui.commandChooser->setPromptDialogTitle(tr("Mercurial Command"));
-
- const VcsBaseClientSettings &s = *settings;
-
- m_ui.commandChooser->setPath(s.stringValue(MercurialSettings::binaryPathKey));
- m_ui.defaultUsernameLineEdit->setText(s.stringValue(MercurialSettings::userNameKey));
- m_ui.defaultEmailLineEdit->setText(s.stringValue(MercurialSettings::userEmailKey));
- m_ui.logEntriesCount->setValue(s.intValue(MercurialSettings::logCountKey));
- m_ui.timeout->setValue(s.intValue(MercurialSettings::timeoutKey));
-}
-
-void OptionsPageWidget::apply()
-{
- MercurialSettings ms;
- ms.setValue(MercurialSettings::binaryPathKey, m_ui.commandChooser->rawPath());
- ms.setValue(MercurialSettings::userNameKey, m_ui.defaultUsernameLineEdit->text().trimmed());
- ms.setValue(MercurialSettings::userEmailKey, m_ui.defaultEmailLineEdit->text().trimmed());
- ms.setValue(MercurialSettings::logCountKey, m_ui.logEntriesCount->value());
- ms.setValue(MercurialSettings::timeoutKey, m_ui.timeout->value());
-
- if (*m_settings != ms) {
- *m_settings = ms;
- m_onApply();
- }
-}
-
-OptionsPage::OptionsPage(const std::function<void()> &onApply, MercurialSettings *settings)
-{
- setId(VcsBase::Constants::VCS_ID_MERCURIAL);
- setDisplayName(OptionsPageWidget::tr("Mercurial"));
- setCategory(VcsBase::Constants::VCS_SETTINGS_CATEGORY);
- setWidgetCreator([onApply, settings] { return new OptionsPageWidget(onApply, settings); });
-}
-
-} // namespace Internal
-} // namespace Mercurial
diff --git a/src/plugins/mercurial/optionspage.h b/src/plugins/mercurial/optionspage.h
deleted file mode 100644
index 8279a7d392..0000000000
--- a/src/plugins/mercurial/optionspage.h
+++ /dev/null
@@ -1,42 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 Brian McGillion
-** 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 <coreplugin/dialogs/ioptionspage.h>
-
-namespace Mercurial {
-namespace Internal {
-
-class MercurialSettings;
-
-class OptionsPage final : public Core::IOptionsPage
-{
-public:
- OptionsPage(const std::function<void()> &onApply, MercurialSettings *settings);
-};
-
-} // namespace Internal
-} // namespace Mercurial
diff --git a/src/plugins/mercurial/optionspage.ui b/src/plugins/mercurial/optionspage.ui
deleted file mode 100644
index cf13d326da..0000000000
--- a/src/plugins/mercurial/optionspage.ui
+++ /dev/null
@@ -1,182 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<ui version="4.0">
- <class>Mercurial::Internal::OptionsPage</class>
- <widget class="QWidget" name="Mercurial::Internal::OptionsPage">
- <property name="geometry">
- <rect>
- <x>0</x>
- <y>0</y>
- <width>617</width>
- <height>268</height>
- </rect>
- </property>
- <property name="windowTitle">
- <string/>
- </property>
- <layout class="QVBoxLayout" name="verticalLayout">
- <item>
- <widget class="QGroupBox" name="configGroupBox">
- <property name="title">
- <string>Configuration</string>
- </property>
- <layout class="QFormLayout" name="formLayout_3">
- <property name="fieldGrowthPolicy">
- <enum>QFormLayout::ExpandingFieldsGrow</enum>
- </property>
- <item row="0" column="0">
- <widget class="QLabel" name="mercurialCommandLabel">
- <property name="text">
- <string>Command:</string>
- </property>
- </widget>
- </item>
- <item row="0" column="1">
- <widget class="Utils::PathChooser" name="commandChooser" native="true"/>
- </item>
- </layout>
- </widget>
- </item>
- <item>
- <widget class="QGroupBox" name="userGroupBox">
- <property name="title">
- <string>User</string>
- </property>
- <layout class="QFormLayout" name="formLayout">
- <property name="fieldGrowthPolicy">
- <enum>QFormLayout::ExpandingFieldsGrow</enum>
- </property>
- <item row="0" column="0">
- <widget class="QLabel" name="defaultUsernameLabel">
- <property name="toolTip">
- <string>Username to use by default on commit.</string>
- </property>
- <property name="text">
- <string>Default username:</string>
- </property>
- </widget>
- </item>
- <item row="0" column="1">
- <widget class="QLineEdit" name="defaultUsernameLineEdit">
- <property name="toolTip">
- <string>Username to use by default on commit.</string>
- </property>
- </widget>
- </item>
- <item row="1" column="0">
- <widget class="QLabel" name="defaultEmailLabel">
- <property name="toolTip">
- <string>Email to use by default on commit.</string>
- </property>
- <property name="text">
- <string>Default email:</string>
- </property>
- </widget>
- </item>
- <item row="1" column="1">
- <widget class="QLineEdit" name="defaultEmailLineEdit">
- <property name="toolTip">
- <string>Email to use by default on commit.</string>
- </property>
- </widget>
- </item>
- </layout>
- </widget>
- </item>
- <item>
- <widget class="QGroupBox" name="miscGroupBox">
- <property name="title">
- <string>Miscellaneous</string>
- </property>
- <layout class="QGridLayout" name="gridLayout">
- <item row="0" column="2">
- <widget class="QLabel" name="timeoutSecondsLabel">
- <property name="text">
- <string>Timeout:</string>
- </property>
- </widget>
- </item>
- <item row="0" column="3">
- <widget class="QSpinBox" name="timeout">
- <property name="suffix">
- <string>s</string>
- </property>
- <property name="maximum">
- <number>360</number>
- </property>
- <property name="value">
- <number>30</number>
- </property>
- </widget>
- </item>
- <item row="0" column="4">
- <spacer name="horizontalSpacer">
- <property name="orientation">
- <enum>Qt::Horizontal</enum>
- </property>
- <property name="sizeHint" stdset="0">
- <size>
- <width>217</width>
- <height>20</height>
- </size>
- </property>
- </spacer>
- </item>
- <item row="0" column="1">
- <widget class="QSpinBox" name="logEntriesCount">
- <property name="toolTip">
- <string>The number of recent commit logs to show, choose 0 to see all entries.</string>
- </property>
- <property name="maximum">
- <number>100</number>
- </property>
- <property name="value">
- <number>100</number>
- </property>
- </widget>
- </item>
- <item row="0" column="0">
- <widget class="QLabel" name="showLogEntriesLabel">
- <property name="text">
- <string>Log count:</string>
- </property>
- </widget>
- </item>
- </layout>
- </widget>
- </item>
- <item>
- <spacer name="verticalSpacer">
- <property name="orientation">
- <enum>Qt::Vertical</enum>
- </property>
- <property name="sizeHint" stdset="0">
- <size>
- <width>20</width>
- <height>40</height>
- </size>
- </property>
- </spacer>
- </item>
- </layout>
- </widget>
- <customwidgets>
- <customwidget>
- <class>Utils::PathChooser</class>
- <extends>QWidget</extends>
- <header location="global">utils/pathchooser.h</header>
- <container>1</container>
- <slots>
- <signal>editingFinished()</signal>
- <signal>browsingFinished()</signal>
- </slots>
- </customwidget>
- </customwidgets>
- <tabstops>
- <tabstop>defaultUsernameLineEdit</tabstop>
- <tabstop>defaultEmailLineEdit</tabstop>
- <tabstop>logEntriesCount</tabstop>
- <tabstop>timeout</tabstop>
- </tabstops>
- <resources/>
- <connections/>
-</ui>
diff --git a/src/plugins/mesonprojectmanager/CMakeLists.txt b/src/plugins/mesonprojectmanager/CMakeLists.txt
index 65a023b73d..63479aea43 100644
--- a/src/plugins/mesonprojectmanager/CMakeLists.txt
+++ b/src/plugins/mesonprojectmanager/CMakeLists.txt
@@ -28,11 +28,6 @@ add_qtc_plugin(MesonProjectManager
settings/tools/kitaspect/mesontoolkitaspect.h
settings/tools/toolssettingsaccessor.h
settings/tools/toolssettingsaccessor.cpp
- settings/general/generalsettingswidget.ui
- settings/general/generalsettingswidget.cpp
- settings/general/generalsettingswidget.h
- settings/general/generalsettingspage.h
- settings/general/generalsettingspage.cpp
settings/general/settings.h
settings/general/settings.cpp
exewrappers/mesonwrapper.cpp
diff --git a/src/plugins/mesonprojectmanager/exewrappers/toolwrapper.h b/src/plugins/mesonprojectmanager/exewrappers/toolwrapper.h
index b03f8d4816..a200067745 100644
--- a/src/plugins/mesonprojectmanager/exewrappers/toolwrapper.h
+++ b/src/plugins/mesonprojectmanager/exewrappers/toolwrapper.h
@@ -27,6 +27,7 @@
#include "versionhelper.h"
+#include <utils/commandline.h>
#include <utils/environment.h>
#include <utils/fileutils.h>
#include <utils/id.h>
diff --git a/src/plugins/mesonprojectmanager/machinefiles/machinefilemanager.cpp b/src/plugins/mesonprojectmanager/machinefiles/machinefilemanager.cpp
index 390d4a9190..255a979f15 100644
--- a/src/plugins/mesonprojectmanager/machinefiles/machinefilemanager.cpp
+++ b/src/plugins/mesonprojectmanager/machinefiles/machinefilemanager.cpp
@@ -57,8 +57,7 @@ bool withFile(const Utils::FilePath &path, const F &f)
Utils::FilePath MachineFilesDir()
{
- return Utils::FilePath::fromString(Core::ICore::userResourcePath())
- .pathAppended("Meson-machine-files");
+ return Core::ICore::userResourcePath("Meson-machine-files");
}
MachineFileManager::MachineFileManager()
diff --git a/src/plugins/mesonprojectmanager/mesonpluginconstants.h b/src/plugins/mesonprojectmanager/mesonpluginconstants.h
index 7aff7a7b24..02983d8738 100644
--- a/src/plugins/mesonprojectmanager/mesonpluginconstants.h
+++ b/src/plugins/mesonprojectmanager/mesonpluginconstants.h
@@ -58,12 +58,6 @@ const char NAME_KEY[] = "name";
const char ID_KEY[] = "uuid";
} // namespace ToolsSettings
-namespace GeneralSettings {
-const char SECTION[] = "MesonProjectManager";
-const char AUTORUN_MESON_KEY[] = "meson.autorun";
-const char VERBOSE_NINJA_KEY[] = "ninja.verbose";
-} // namespace GeneralSettings
-
namespace Icons {
const char MESON[] = ":/mesonproject/icons/meson_logo.png";
const char MESON_BW[] = ":/mesonproject/icons/meson_bw_logo.png";
diff --git a/src/plugins/mesonprojectmanager/mesonprojectmanager.pro b/src/plugins/mesonprojectmanager/mesonprojectmanager.pro
index 92a6f8f0a5..96246c8924 100644
--- a/src/plugins/mesonprojectmanager/mesonprojectmanager.pro
+++ b/src/plugins/mesonprojectmanager/mesonprojectmanager.pro
@@ -36,8 +36,6 @@ HEADERS = \
project/mesonprojectparser.h \
project/mesonrunconfiguration.h \
project/ninjabuildstep.h \
- settings/general/generalsettingspage.h \
- settings/general/generalsettingswidget.h \
settings/general/settings.h \
settings/tools/kitaspect/mesontoolkitaspect.h \
settings/tools/kitaspect/ninjatoolkitaspect.h \
@@ -75,8 +73,6 @@ SOURCES = \
project/mesonprojectparser.cpp \
project/mesonrunconfiguration.cpp \
project/ninjabuildstep.cpp \
- settings/general/generalsettingspage.cpp \
- settings/general/generalsettingswidget.cpp \
settings/general/settings.cpp \
settings/tools/kitaspect/mesontoolkitaspect.cpp \
settings/tools/kitaspect/ninjatoolkitaspect.cpp \
@@ -93,7 +89,6 @@ RESOURCES += resources.qrc
FORMS += \
project/buildoptions/mesonbuildsettingswidget.ui \
- settings/general/generalsettingswidget.ui \
settings/tools/toolitemsettings.ui \
settings/tools/toolssettingswidget.ui
diff --git a/src/plugins/mesonprojectmanager/mesonprojectmanager.qbs b/src/plugins/mesonprojectmanager/mesonprojectmanager.qbs
index efcfca832a..2111c087bf 100644
--- a/src/plugins/mesonprojectmanager/mesonprojectmanager.qbs
+++ b/src/plugins/mesonprojectmanager/mesonprojectmanager.qbs
@@ -83,11 +83,6 @@ Project {
"project/projecttree/projecttree.cpp",
"project/projecttree/projecttree.h",
"resources.qrc",
- "settings/general/generalsettingspage.cpp",
- "settings/general/generalsettingspage.h",
- "settings/general/generalsettingswidget.cpp",
- "settings/general/generalsettingswidget.h",
- "settings/general/generalsettingswidget.ui",
"settings/general/settings.cpp",
"settings/general/settings.h",
"settings/tools/kitaspect/mesontoolkitaspect.cpp",
diff --git a/src/plugins/mesonprojectmanager/mesonprojectplugin.cpp b/src/plugins/mesonprojectmanager/mesonprojectplugin.cpp
index a83f489acb..bd2e120d51 100644
--- a/src/plugins/mesonprojectmanager/mesonprojectplugin.cpp
+++ b/src/plugins/mesonprojectmanager/mesonprojectplugin.cpp
@@ -33,7 +33,7 @@
#include "project/mesonproject.h"
#include "project/mesonrunconfiguration.h"
#include "project/ninjabuildstep.h"
-#include "settings/general/generalsettingspage.h"
+#include "settings/general/settings.h"
#include "settings/tools/kitaspect/mesontoolkitaspect.h"
#include "settings/tools/kitaspect/ninjatoolkitaspect.h"
#include "settings/tools/toolssettingsaccessor.h"
@@ -84,7 +84,6 @@ private:
void saveAll()
{
m_toolsSettings.saveMesonTools(MesonTools::tools(), ICore::dialogParent());
- m_generalSettingsPage.saveAll();
}
};
diff --git a/src/plugins/mesonprojectmanager/project/buildoptions/mesonbuildsettingswidget.cpp b/src/plugins/mesonprojectmanager/project/buildoptions/mesonbuildsettingswidget.cpp
index cd5f4d4801..ddc8083e5c 100644
--- a/src/plugins/mesonprojectmanager/project/buildoptions/mesonbuildsettingswidget.cpp
+++ b/src/plugins/mesonprojectmanager/project/buildoptions/mesonbuildsettingswidget.cpp
@@ -51,9 +51,10 @@ MesonBuildSettingsWidget::MesonBuildSettingsWidget(MesonBuildConfiguration *buil
ui->setupUi(this);
ui->container->setState(Utils::DetailsWidget::NoSummary);
ui->container->setWidget(ui->details);
- LayoutBuilder buildDirWBuilder{ui->buildDirWidget};
- auto buildDirAspect = buildCfg->buildDirectoryAspect();
- buildDirAspect->addToLayout(buildDirWBuilder);
+
+ Layouting::Form buildDirWBuilder;
+ buildCfg->buildDirectoryAspect()->addToLayout(buildDirWBuilder);
+ buildDirWBuilder.attachTo(ui->buildDirWidget);
ui->parametersLineEdit->setText(buildCfg->parameters());
ui->optionsFilterLineEdit->setFiltering(true);
diff --git a/src/plugins/mesonprojectmanager/project/mesonbuildconfiguration.cpp b/src/plugins/mesonprojectmanager/project/mesonbuildconfiguration.cpp
index 9159c7de65..518726cb54 100644
--- a/src/plugins/mesonprojectmanager/project/mesonbuildconfiguration.cpp
+++ b/src/plugins/mesonprojectmanager/project/mesonbuildconfiguration.cpp
@@ -120,7 +120,7 @@ void MesonBuildConfiguration::build(const QString &target)
QStringList MesonBuildConfiguration::mesonConfigArgs()
{
- return Utils::QtcProcess::splitArgs(m_parameters) + QStringList{QString("-Dbuildtype=%1").arg(mesonBuildTypeName(m_buildType))};
+ return Utils::ProcessArgs::splitArgs(m_parameters) + QStringList{QString("-Dbuildtype=%1").arg(mesonBuildTypeName(m_buildType))};
}
const QString &MesonBuildConfiguration::parameters() const
diff --git a/src/plugins/mesonprojectmanager/project/mesonbuildsystem.cpp b/src/plugins/mesonprojectmanager/project/mesonbuildsystem.cpp
index 3506e93538..c0212be0a7 100644
--- a/src/plugins/mesonprojectmanager/project/mesonbuildsystem.cpp
+++ b/src/plugins/mesonprojectmanager/project/mesonbuildsystem.cpp
@@ -214,7 +214,7 @@ void MesonBuildSystem::init()
bool MesonBuildSystem::parseProject()
{
QTC_ASSERT(buildConfiguration(), return false);
- if (!isSetup(buildConfiguration()->buildDirectory()) && Settings::autorunMeson())
+ if (!isSetup(buildConfiguration()->buildDirectory()) && Settings::instance()->autorunMeson.value())
return configure();
LEAVE_IF_BUSY();
LOCK();
diff --git a/src/plugins/mesonprojectmanager/project/ninjabuildstep.cpp b/src/plugins/mesonprojectmanager/project/ninjabuildstep.cpp
index fffb3aa012..067e853a59 100644
--- a/src/plugins/mesonprojectmanager/project/ninjabuildstep.cpp
+++ b/src/plugins/mesonprojectmanager/project/ninjabuildstep.cpp
@@ -65,8 +65,8 @@ NinjaBuildStep::NinjaBuildStep(ProjectExplorer::BuildStepList *bsl, Utils::Id id
setUseEnglishOutput();
connect(target(), &ProjectExplorer::Target::parsingFinished, this, &NinjaBuildStep::update);
- connect(Settings::instance(),
- &Settings::verboseNinjaChanged,
+ connect(&Settings::instance()->verboseNinja,
+ &BaseAspect::changed,
this,
&NinjaBuildStep::commandChanged);
}
@@ -152,7 +152,7 @@ Utils::CommandLine NinjaBuildStep::command()
}();
if (!m_commandArgs.isEmpty())
cmd.addArgs(m_commandArgs, Utils::CommandLine::RawType::Raw);
- if (Settings::verboseNinja())
+ if (Settings::instance()->verboseNinja.value())
cmd.addArg("-v");
cmd.addArg(m_targetName);
return cmd;
diff --git a/src/plugins/mesonprojectmanager/project/projecttree/mesonprojectnodes.cpp b/src/plugins/mesonprojectmanager/project/projecttree/mesonprojectnodes.cpp
index 41d202026f..f84ca006d1 100644
--- a/src/plugins/mesonprojectmanager/project/projecttree/mesonprojectnodes.cpp
+++ b/src/plugins/mesonprojectmanager/project/projecttree/mesonprojectnodes.cpp
@@ -38,18 +38,15 @@ namespace Internal {
MesonProjectNode::MesonProjectNode(const Utils::FilePath &directory)
: ProjectExplorer::ProjectNode{directory}
{
- static const auto MesonIcon = QIcon(Constants::Icons::MESON);
setPriority(Node::DefaultProjectPriority + 1000);
- setIcon(MesonIcon);
+ setIcon(Constants::Icons::MESON);
setListInProject(false);
}
MesonFileNode::MesonFileNode(const Utils::FilePath &file)
: ProjectExplorer::ProjectNode{file}
{
- static const auto MesonFolderIcon = Core::FileIconProvider::directoryIcon(
- Constants::Icons::MESON);
- setIcon(MesonFolderIcon);
+ setIcon(ProjectExplorer::DirectoryIcon(Constants::Icons::MESON));
setListInProject(true);
}
@@ -58,7 +55,7 @@ MesonTargetNode::MesonTargetNode(const Utils::FilePath &directory, const QString
, m_name{name}
{
setPriority(Node::DefaultProjectPriority + 900);
- setIcon(QIcon(":/projectexplorer/images/build.png"));
+ setIcon(":/projectexplorer/images/build.png");
setListInProject(false);
setShowWhenEmpty(true);
setProductType(ProjectExplorer::ProductType::Other);
diff --git a/src/plugins/mesonprojectmanager/settings/general/generalsettingswidget.cpp b/src/plugins/mesonprojectmanager/settings/general/generalsettingswidget.cpp
deleted file mode 100644
index f92659fe5f..0000000000
--- a/src/plugins/mesonprojectmanager/settings/general/generalsettingswidget.cpp
+++ /dev/null
@@ -1,55 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2020 Alexis Jeandet.
-** 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 "generalsettingswidget.h"
-
-#include "settings.h"
-#include "ui_generalsettingswidget.h"
-
-namespace MesonProjectManager {
-namespace Internal {
-
-GeneralSettingsWidget::GeneralSettingsWidget()
- : Core::IOptionsPageWidget()
- , ui(new Ui::GeneralSettingsWidget)
-{
- ui->setupUi(this);
- ui->autorunChkBox->setChecked(Settings::autorunMeson());
- ui->verboseNinjaChkBox->setChecked(Settings::verboseNinja());
-}
-
-GeneralSettingsWidget::~GeneralSettingsWidget()
-{
- delete ui;
-}
-
-void GeneralSettingsWidget::apply()
-{
- Settings::setAutorunMeson(ui->autorunChkBox->isChecked());
- Settings::setVerboseNinja(ui->verboseNinjaChkBox->isChecked());
-}
-
-} // namespace Internal
-} // namespace MesonProjectManager
diff --git a/src/plugins/mesonprojectmanager/settings/general/generalsettingswidget.ui b/src/plugins/mesonprojectmanager/settings/general/generalsettingswidget.ui
deleted file mode 100644
index 78a3c14d77..0000000000
--- a/src/plugins/mesonprojectmanager/settings/general/generalsettingswidget.ui
+++ /dev/null
@@ -1,57 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<ui version="4.0">
- <class>MesonProjectManager::Internal::GeneralSettingsWidget</class>
- <widget class="QWidget" name="MesonProjectManager::Internal::GeneralSettingsWidget">
- <property name="geometry">
- <rect>
- <x>0</x>
- <y>0</y>
- <width>625</width>
- <height>349</height>
- </rect>
- </property>
- <layout class="QVBoxLayout" name="verticalLayout">
- <item>
- <widget class="QWidget" name="widget" native="true">
- <layout class="QVBoxLayout" name="verticalLayout_2">
- <item>
- <widget class="QCheckBox" name="autorunChkBox">
- <property name="toolTip">
- <string>Automatically run Meson when needed.</string>
- </property>
- <property name="text">
- <string>Autorun Meson</string>
- </property>
- </widget>
- </item>
- <item>
- <widget class="QCheckBox" name="verboseNinjaChkBox">
- <property name="toolTip">
- <string>Enables verbose mode by default when invoking Ninja.</string>
- </property>
- <property name="text">
- <string>Ninja verbose mode</string>
- </property>
- </widget>
- </item>
- </layout>
- </widget>
- </item>
- <item>
- <spacer name="verticalSpacer">
- <property name="orientation">
- <enum>Qt::Vertical</enum>
- </property>
- <property name="sizeHint" stdset="0">
- <size>
- <width>20</width>
- <height>40</height>
- </size>
- </property>
- </spacer>
- </item>
- </layout>
- </widget>
- <resources/>
- <connections/>
-</ui>
diff --git a/src/plugins/mesonprojectmanager/settings/general/settings.cpp b/src/plugins/mesonprojectmanager/settings/general/settings.cpp
index 49151f7446..03a9ed293a 100644
--- a/src/plugins/mesonprojectmanager/settings/general/settings.cpp
+++ b/src/plugins/mesonprojectmanager/settings/general/settings.cpp
@@ -25,14 +25,53 @@
#include "settings.h"
+#include "mesonpluginconstants.h"
+
+#include <utils/layoutbuilder.h>
+
namespace MesonProjectManager {
namespace Internal {
-Settings::Settings(QObject *parent)
- : QObject(parent)
- , m_autorunMeson(true)
- , m_verboseNinja(true)
-{}
+Settings::Settings()
+{
+ setSettingsGroup("MesonProjectManager");
+ setAutoApply(false);
+
+ autorunMeson.setSettingsKey("meson.autorun");
+ autorunMeson.setLabelText(tr("Autorun Meson"));
+ autorunMeson.setToolTip(tr("Automatically run Meson when needed."));
+
+ verboseNinja.setSettingsKey("meson.autorun");
+ verboseNinja.setLabelText(tr("Ninja verbose mode"));
+ verboseNinja.setToolTip(tr("Enables verbose mode by default when invoking Ninja."));
+}
+
+Settings *Settings::instance()
+{
+ static Settings m_settings;
+ return &m_settings;
+}
+
+GeneralSettingsPage::GeneralSettingsPage()
+{
+ setId(Constants::SettingsPage::GENERAL_ID);
+ setDisplayName(tr("General"));
+ setDisplayCategory("Meson");
+ setCategory(Constants::SettingsPage::CATEGORY);
+ setCategoryIconPath(Constants::Icons::MESON_BW);
+ setSettings(Settings::instance());
+
+ setLayouter([](QWidget *widget) {
+ Settings &s = *Settings::instance();
+ using namespace Utils::Layouting;
+
+ Column {
+ s.autorunMeson,
+ s.verboseNinja,
+ Stretch(),
+ }.attachTo(widget);
+ });
+}
} // namespace Internal
} // namespace MesonProjectManager
diff --git a/src/plugins/mesonprojectmanager/settings/general/settings.h b/src/plugins/mesonprojectmanager/settings/general/settings.h
index e25ff28f58..814cdf42f4 100644
--- a/src/plugins/mesonprojectmanager/settings/general/settings.h
+++ b/src/plugins/mesonprojectmanager/settings/general/settings.h
@@ -25,69 +25,32 @@
#pragma once
-#include "mesonpluginconstants.h"
+#include <coreplugin/dialogs/ioptionspage.h>
-#include <coreplugin/icore.h>
+#include <utils/aspects.h>
namespace MesonProjectManager {
namespace Internal {
-template<class F>
-void with_group(QSettings *settings, const QString &name, const F &f)
+class Settings : public Utils::AspectContainer
{
- settings->beginGroup(name);
- f();
- settings->endGroup();
-};
+ Q_DECLARE_TR_FUNCTIONS(MesonProjectManager::Internal::Settings)
-#define ADD_PROPERTY(name, setter, type) \
-private: \
- type m_##name; \
-\
-public: \
- inline static type name() { return instance()->m_##name; } \
- inline static void setter(type value) \
- { \
- instance()->m_##name = value; \
- emit instance()->name##Changed(value); \
- } \
- Q_SIGNAL void name##Changed(type newValue);
+public:
+ Settings();
-class Settings : public QObject
-{
- Q_OBJECT
- explicit Settings(QObject *parent = nullptr);
+ static Settings *instance();
-public:
- inline static Settings *instance()
- {
- static Settings m_settings;
- return &m_settings;
- }
+ Utils::BoolAspect autorunMeson;
+ Utils::BoolAspect verboseNinja;
+};
- ADD_PROPERTY(autorunMeson, setAutorunMeson, bool)
- ADD_PROPERTY(verboseNinja, setVerboseNinja, bool)
+class GeneralSettingsPage final : public Core::IOptionsPage
+{
+ Q_DECLARE_TR_FUNCTIONS(MesonProjectManager::Internal::GeneralSettingsPage)
- static inline void saveAll()
- {
- using namespace Constants;
- auto settings = Core::ICore::settings(QSettings::Scope::UserScope);
- with_group(settings, GeneralSettings::SECTION, [settings]() {
- settings->setValue(GeneralSettings::AUTORUN_MESON_KEY, Settings::autorunMeson());
- settings->setValue(GeneralSettings::VERBOSE_NINJA_KEY, Settings::verboseNinja());
- });
- }
- static inline void loadAll()
- {
- using namespace Constants;
- auto settings = Core::ICore::settings(QSettings::Scope::UserScope);
- with_group(settings, GeneralSettings::SECTION, [settings]() {
- Settings::setAutorunMeson(
- settings->value(GeneralSettings::AUTORUN_MESON_KEY, true).toBool());
- Settings::setVerboseNinja(
- settings->value(GeneralSettings::VERBOSE_NINJA_KEY, true).toBool());
- });
- }
+public:
+ GeneralSettingsPage();
};
} // namespace Internal
diff --git a/src/plugins/mesonprojectmanager/settings/tools/kitaspect/toolkitaspectwidget.cpp b/src/plugins/mesonprojectmanager/settings/tools/kitaspect/toolkitaspectwidget.cpp
index efd9d3730b..fb0f3e5640 100644
--- a/src/plugins/mesonprojectmanager/settings/tools/kitaspect/toolkitaspectwidget.cpp
+++ b/src/plugins/mesonprojectmanager/settings/tools/kitaspect/toolkitaspectwidget.cpp
@@ -29,7 +29,6 @@
#include "mesontoolkitaspect.h"
#include "ninjatoolkitaspect.h"
-#include <coreplugin/icore.h>
#include <utils/qtcassert.h>
namespace MesonProjectManager {
@@ -39,8 +38,8 @@ ToolKitAspectWidget::ToolKitAspectWidget(ProjectExplorer::Kit *kit,
const ProjectExplorer::KitAspect *ki,
ToolType type)
: ProjectExplorer::KitAspectWidget(kit, ki)
- , m_toolsComboBox{new QComboBox}
- , m_manageButton(new QPushButton(KitAspectWidget::msgManage()))
+ , m_toolsComboBox(createSubWidget<QComboBox>())
+ , m_manageButton(createManageButton(Constants::SettingsPage::TOOLS_ID))
, m_type{type}
{
m_toolsComboBox->setSizePolicy(QSizePolicy::Ignored,
@@ -49,11 +48,6 @@ ToolKitAspectWidget::ToolKitAspectWidget(ProjectExplorer::Kit *kit,
m_toolsComboBox->setToolTip(ki->description());
loadTools();
- m_manageButton->setContentsMargins(0, 0, 0, 0);
- connect(m_manageButton, &QPushButton::clicked, this, [this]() {
- Core::ICore::showOptionsDialog(Constants::SettingsPage::TOOLS_ID, buttonWidget());
- });
-
connect(MesonTools::instance(),
&MesonTools::toolAdded,
this,
diff --git a/src/plugins/mesonprojectmanager/settings/tools/kitaspect/toolkitaspectwidget.h b/src/plugins/mesonprojectmanager/settings/tools/kitaspect/toolkitaspectwidget.h
index 7758c1ed82..0ca8b066a1 100644
--- a/src/plugins/mesonprojectmanager/settings/tools/kitaspect/toolkitaspectwidget.h
+++ b/src/plugins/mesonprojectmanager/settings/tools/kitaspect/toolkitaspectwidget.h
@@ -30,9 +30,10 @@
#include <projectexplorer/kitmanager.h>
+#include <utils/layoutbuilder.h>
+
#include <QComboBox>
#include <QCoreApplication>
-#include <QPushButton>
namespace MesonProjectManager {
namespace Internal {
@@ -58,8 +59,14 @@ private:
void setToDefault();
void makeReadOnly() override { m_toolsComboBox->setEnabled(false); }
- QWidget *mainWidget() const override { return m_toolsComboBox; }
- QWidget *buttonWidget() const override { return m_manageButton; }
+
+ void addToLayout(Utils::LayoutBuilder &builder) override
+ {
+ addMutableAction(m_toolsComboBox);
+ builder.addItem(m_toolsComboBox);
+ builder.addItem(m_manageButton);
+ }
+
void refresh() override
{
const auto id = [this]() {
@@ -75,7 +82,7 @@ private:
}
QComboBox *m_toolsComboBox;
- QPushButton *m_manageButton;
+ QWidget *m_manageButton;
ToolType m_type;
};
diff --git a/src/plugins/mesonprojectmanager/settings/tools/toolssettingsaccessor.cpp b/src/plugins/mesonprojectmanager/settings/tools/toolssettingsaccessor.cpp
index fc20ca4784..7e4727dcb7 100644
--- a/src/plugins/mesonprojectmanager/settings/tools/toolssettingsaccessor.cpp
+++ b/src/plugins/mesonprojectmanager/settings/tools/toolssettingsaccessor.cpp
@@ -54,8 +54,7 @@ ToolsSettingsAccessor::ToolsSettingsAccessor()
"Meson"),
Core::Constants::IDE_DISPLAY_NAME)
{
- setBaseFilePath(Utils::FilePath::fromString(Core::ICore::userResourcePath())
- .pathAppended(Constants::ToolsSettings::FILENAME));
+ setBaseFilePath(Core::ICore::userResourcePath(Constants::ToolsSettings::FILENAME));
}
void ToolsSettingsAccessor::saveMesonTools(const std::vector<MesonTools::Tool_t> &tools,
diff --git a/src/plugins/modeleditor/editordiagramview.cpp b/src/plugins/modeleditor/editordiagramview.cpp
index f2c074b25c..7b25a964ff 100644
--- a/src/plugins/modeleditor/editordiagramview.cpp
+++ b/src/plugins/modeleditor/editordiagramview.cpp
@@ -72,11 +72,7 @@ void EditorDiagramView::wheelEvent(QWheelEvent *wheelEvent)
{
if (wheelEvent->modifiers() == Qt::ControlModifier) {
int degree = wheelEvent->angleDelta().y() / 8;
-#if QT_VERSION < QT_VERSION_CHECK(5, 14, 0)
- QPoint zoomOrigin = wheelEvent->pos();
-#else
QPoint zoomOrigin = wheelEvent->position().toPoint();
-#endif
if (degree > 0)
emit zoomIn(zoomOrigin);
else if (degree < 0)
diff --git a/src/plugins/modeleditor/modeldocument.cpp b/src/plugins/modeleditor/modeldocument.cpp
index bcb1322715..2209bd3601 100644
--- a/src/plugins/modeleditor/modeldocument.cpp
+++ b/src/plugins/modeleditor/modeldocument.cpp
@@ -66,26 +66,25 @@ ModelDocument::~ModelDocument()
delete d;
}
-Core::IDocument::OpenResult ModelDocument::open(QString *errorString, const QString &fileName,
- const QString &realFileName)
+Core::IDocument::OpenResult ModelDocument::open(QString *errorString,
+ const Utils::FilePath &filePath,
+ const Utils::FilePath &realFilePath)
{
- Q_UNUSED(fileName)
+ Q_UNUSED(filePath)
- OpenResult result = load(errorString, realFileName);
+ OpenResult result = load(errorString, realFilePath.toString());
return result;
}
-bool ModelDocument::save(QString *errorString, const QString &name, bool autoSave)
+bool ModelDocument::save(QString *errorString, const Utils::FilePath &filePath, bool autoSave)
{
if (!d->documentController) {
*errorString = tr("No model loaded. Cannot save.");
return false;
}
- QString actualName = filePath().toString();
- if (!name.isEmpty())
- actualName = name;
- d->documentController->projectController()->setFileName(actualName);
+ const Utils::FilePath actualName = filePath.isEmpty() ? this->filePath() : filePath;
+ d->documentController->projectController()->setFileName(actualName.toString());
try {
d->documentController->projectController()->save();
} catch (const qmt::Exception &ex) {
diff --git a/src/plugins/modeleditor/modeldocument.h b/src/plugins/modeleditor/modeldocument.h
index 5f7a99cd56..dc4430623f 100644
--- a/src/plugins/modeleditor/modeldocument.h
+++ b/src/plugins/modeleditor/modeldocument.h
@@ -48,9 +48,10 @@ signals:
void contentSet();
public:
- OpenResult open(QString *errorString, const QString &fileName,
- const QString &realFileName) override;
- bool save(QString *errorString, const QString &fileName, bool autoSave) override;
+ OpenResult open(QString *errorString,
+ const Utils::FilePath &filePath,
+ const Utils::FilePath &realFilePath) override;
+ bool save(QString *errorString, const Utils::FilePath &filePath, bool autoSave) override;
bool shouldAutoSave() const override;
bool isModified() const override;
bool isSaveAsAllowed() const override;
diff --git a/src/plugins/modeleditor/modelsmanager.cpp b/src/plugins/modeleditor/modelsmanager.cpp
index da02d47462..8b2285ba54 100644
--- a/src/plugins/modeleditor/modelsmanager.cpp
+++ b/src/plugins/modeleditor/modelsmanager.cpp
@@ -140,10 +140,9 @@ ModelsManager::~ModelsManager()
ExtDocumentController *ModelsManager::createModel(ModelDocument *modelDocument)
{
auto documentController = new ExtDocumentController(this);
- QDir dir;
- dir.setPath(Core::ICore::resourcePath() + QLatin1String("/modeleditor"));
// TODO error output on reading definition files
- documentController->configController()->readStereotypeDefinitions(dir.path());
+ documentController->configController()->readStereotypeDefinitions(
+ Core::ICore::resourcePath("modeleditor").toString());
d->managedModels.append(ManagedModel(documentController, modelDocument));
return documentController;
diff --git a/src/plugins/nim/CMakeLists.txt b/src/plugins/nim/CMakeLists.txt
index 20a139940e..b658568b9c 100644
--- a/src/plugins/nim/CMakeLists.txt
+++ b/src/plugins/nim/CMakeLists.txt
@@ -28,8 +28,6 @@ add_qtc_plugin(Nim
settings/nimcodestylepreferenceswidget.cpp settings/nimcodestylepreferenceswidget.h settings/nimcodestylepreferenceswidget.ui
settings/nimcodestylesettingspage.cpp settings/nimcodestylesettingspage.h
settings/nimsettings.cpp settings/nimsettings.h
- settings/nimtoolssettingspage.cpp settings/nimtoolssettingspage.h
- settings/nimtoolssettingswidget.ui
suggest/client.cpp suggest/client.h
suggest/clientrequests.cpp suggest/clientrequests.h
suggest/nimsuggest.cpp suggest/nimsuggest.h
diff --git a/src/plugins/nim/editor/nimtexteditorwidget.cpp b/src/plugins/nim/editor/nimtexteditorwidget.cpp
index 56d8dfacb2..7ec1791c96 100644
--- a/src/plugins/nim/editor/nimtexteditorwidget.cpp
+++ b/src/plugins/nim/editor/nimtexteditorwidget.cpp
@@ -105,5 +105,5 @@ void NimTextEditorWidget::onFindLinkFinished()
}
const Line &line = m_request->lines().front();
- m_callback(Utils::Link{line.abs_path, line.row, line.column});
+ m_callback(Utils::Link{Utils::FilePath::fromString(line.abs_path), line.row, line.column});
}
diff --git a/src/plugins/nim/nim.pro b/src/plugins/nim/nim.pro
index 2dca0c8fe6..af151df7a0 100644
--- a/src/plugins/nim/nim.pro
+++ b/src/plugins/nim/nim.pro
@@ -35,7 +35,6 @@ HEADERS += \
settings/nimcodestylepreferencesfactory.h \
settings/nimsettings.h \
settings/nimcodestylepreferenceswidget.h \
- settings/nimtoolssettingspage.h \
project/nimtoolchain.h \
project/nimtoolchainfactory.h \
suggest/client.h \
@@ -71,7 +70,6 @@ SOURCES += \
settings/nimcodestylepreferencesfactory.cpp \
settings/nimsettings.cpp \
settings/nimcodestylepreferenceswidget.cpp \
- settings/nimtoolssettingspage.cpp \
project/nimtoolchain.cpp \
project/nimtoolchainfactory.cpp \
suggest/client.cpp \
@@ -81,5 +79,4 @@ SOURCES += \
suggest/server.cpp
FORMS += \
- settings/nimcodestylepreferenceswidget.ui \
- settings/nimtoolssettingswidget.ui
+ settings/nimcodestylepreferenceswidget.ui
diff --git a/src/plugins/nim/nim.qbs b/src/plugins/nim/nim.qbs
index dad13ff57e..171b853c56 100644
--- a/src/plugins/nim/nim.qbs
+++ b/src/plugins/nim/nim.qbs
@@ -63,7 +63,6 @@ QtcPlugin {
"nimcodestylepreferenceswidget.h", "nimcodestylepreferenceswidget.cpp", "nimcodestylepreferenceswidget.ui",
"nimcodestylesettingspage.h", "nimcodestylesettingspage.cpp",
"nimsettings.h", "nimsettings.cpp",
- "nimtoolssettingspage.h", "nimtoolssettingspage.cpp", "nimtoolssettingswidget.ui"
]
}
diff --git a/src/plugins/nim/nimconstants.h b/src/plugins/nim/nimconstants.h
index e0559f49d9..b43487dc4e 100644
--- a/src/plugins/nim/nimconstants.h
+++ b/src/plugins/nim/nimconstants.h
@@ -65,6 +65,9 @@ const QString C_NIMCOMPILERBUILDSTEP_TARGETNIMFILE = QStringLiteral("Nim.NimComp
// NimCompilerCleanStep
const char C_NIMCOMPILERCLEANSTEP_ID[] = "Nim.NimCompilerCleanStep";
+// Nim task category (Issues pane)
+const char C_NIMPARSE_ID[] = "Nim.NimParse";
+
const char C_NIMLANGUAGE_ID[] = "Nim";
const char C_NIMCODESTYLESETTINGSPAGE_ID[] = "Nim.NimCodeStyleSettings";
const char C_NIMCODESTYLESETTINGSPAGE_DISPLAY[] = QT_TRANSLATE_NOOP("NimCodeStyleSettingsPage", "Code Style");
@@ -103,9 +106,5 @@ const char C_NIM_SCRIPT_MIMETYPE[] = "text/x-nim-script";
const char C_NIM_MIME_ICON[] = "text-x-nim";
const char C_NIM_PROJECT_MIMETYPE[] = "text/x-nim-project";
-const char C_NIM_SETTINGS_GROUP[] = "Nim";
-const char C_NIM_SETTINGS_NIMSUGGEST_GROUP[] = "NimSuggest";
-const char C_NIM_SETTINGS_COMMAND[] = "Command";
-
}
}
diff --git a/src/plugins/nim/nimplugin.cpp b/src/plugins/nim/nimplugin.cpp
index d92ebdff7a..4bd3a326dd 100644
--- a/src/plugins/nim/nimplugin.cpp
+++ b/src/plugins/nim/nimplugin.cpp
@@ -41,7 +41,6 @@
#include "project/nimbletaskstep.h"
#include "settings/nimcodestylepreferencesfactory.h"
#include "settings/nimcodestylesettingspage.h"
-#include "settings/nimtoolssettingspage.h"
#include "settings/nimsettings.h"
#include "suggest/nimsuggestcache.h"
@@ -49,6 +48,7 @@
#include <projectexplorer/projectmanager.h>
#include <projectexplorer/toolchainmanager.h>
#include <projectexplorer/runcontrol.h>
+#include <projectexplorer/taskhub.h>
#include <texteditor/snippets/snippetprovider.h>
using namespace Utils;
@@ -60,10 +60,9 @@ class NimPluginPrivate
{
public:
NimPluginPrivate()
- : toolsSettingsPage(&settings)
{
- Suggest::NimSuggestCache::instance().setExecutablePath(settings.nimSuggestPath());
- QObject::connect(&settings, &NimSettings::nimSuggestPathChanged,
+ Suggest::NimSuggestCache::instance().setExecutablePath(settings.nimSuggestPath.value());
+ QObject::connect(&settings.nimSuggestPath, &StringAspect::valueChanged,
&Suggest::NimSuggestCache::instance(),
&Suggest::NimSuggestCache::setExecutablePath);
}
@@ -95,7 +94,7 @@ public:
NimCompilerBuildStepFactory buildStepFactory;
NimCompilerCleanStepFactory cleanStepFactory;
NimCodeStyleSettingsPage codeStyleSettingsPage;
- NimToolsSettingsPage toolsSettingsPage;
+ NimToolsSettingsPage toolsSettingsPage{&settings};
NimCodeStylePreferencesFactory codeStylePreferencesPage;
NimToolChainFactory toolChainFactory;
};
@@ -135,6 +134,7 @@ void NimPlugin::extensionsInitialized()
Core::FileIconProvider::registerIconOverlayForMimeType(icon, Constants::C_NIM_SCRIPT_MIMETYPE);
Core::FileIconProvider::registerIconOverlayForMimeType(icon, Constants::C_NIMBLE_MIMETYPE);
}
+ TaskHub::addCategory(Constants::C_NIMPARSE_ID, "Nim");
}
} // namespace Nim
diff --git a/src/plugins/nim/project/nimblebuildstep.cpp b/src/plugins/nim/project/nimblebuildstep.cpp
index 389be08de1..a1657dc03f 100644
--- a/src/plugins/nim/project/nimblebuildstep.cpp
+++ b/src/plugins/nim/project/nimblebuildstep.cpp
@@ -26,19 +26,13 @@
#include "nimblebuildstep.h"
#include "nimconstants.h"
-#include "nimbleproject.h"
#include "nimbuildsystem.h"
#include "nimoutputtaskparser.h"
-#include "nimtoolchain.h"
#include <projectexplorer/buildconfiguration.h>
-#include <projectexplorer/ioutputparser.h>
#include <projectexplorer/processparameters.h>
#include <projectexplorer/projectexplorerconstants.h>
#include <projectexplorer/runconfigurationaspects.h>
-#include <projectexplorer/target.h>
-
-#include <QRegularExpression>
using namespace ProjectExplorer;
using namespace Utils;
@@ -48,6 +42,7 @@ namespace Nim {
class NimbleBuildStep : public AbstractProcessStep
{
Q_DECLARE_TR_FUNCTIONS(Nim::NimbleBuilStep)
+
public:
NimbleBuildStep(BuildStepList *parentList, Id id);
@@ -55,22 +50,19 @@ public:
private:
QString defaultArguments() const;
- void onArgumentsChanged();
-
- ArgumentsAspect *m_arguments;
};
NimbleBuildStep::NimbleBuildStep(BuildStepList *parentList, Id id)
: AbstractProcessStep(parentList, id)
{
- m_arguments = addAspect<ArgumentsAspect>();
- m_arguments->setSettingsKey(Constants::C_NIMBLEBUILDSTEP_ARGUMENTS);
- m_arguments->setResetter([this] { return defaultArguments(); });
- m_arguments->setArguments(defaultArguments());
+ auto arguments = addAspect<ArgumentsAspect>();
+ arguments->setSettingsKey(Constants::C_NIMBLEBUILDSTEP_ARGUMENTS);
+ arguments->setResetter([this] { return defaultArguments(); });
+ arguments->setArguments(defaultArguments());
- setCommandLineProvider([this] {
+ setCommandLineProvider([this, arguments] {
return CommandLine(Nim::nimblePathFromKit(kit()),
- {"build", m_arguments->arguments(macroExpander())});
+ {"build", arguments->arguments(macroExpander())});
});
setWorkingDirectoryProvider([this] { return project()->projectDirectory(); });
setEnvironmentModifier([this](Environment &env) {
@@ -85,9 +77,9 @@ NimbleBuildStep::NimbleBuildStep(BuildStepList *parentList, Id id)
QTC_ASSERT(buildConfiguration(), return);
QObject::connect(buildConfiguration(), &BuildConfiguration::buildTypeChanged,
- m_arguments, &ArgumentsAspect::resetArguments);
- QObject::connect(m_arguments, &ArgumentsAspect::changed,
- this, &NimbleBuildStep::onArgumentsChanged);
+ arguments, &ArgumentsAspect::resetArguments);
+ QObject::connect(arguments, &ArgumentsAspect::changed,
+ this, &AbstractProcessStep::updateSummary);
}
void NimbleBuildStep::setupOutputFormatter(OutputFormatter *formatter)
@@ -100,22 +92,9 @@ void NimbleBuildStep::setupOutputFormatter(OutputFormatter *formatter)
QString NimbleBuildStep::defaultArguments() const
{
- switch (buildType()) {
- case BuildConfiguration::Debug:
+ if (buildType() == BuildConfiguration::Debug)
return {"--debugger:native"};
- case BuildConfiguration::Unknown:
- case BuildConfiguration::Profile:
- case BuildConfiguration::Release:
- default:
- return {};
- }
-}
-
-void NimbleBuildStep::onArgumentsChanged()
-{
- ProcessParameters *params = processParameters();
- params->setCommandLine({Nim::nimblePathFromKit(kit()),
- {"build", m_arguments->arguments(macroExpander())}});
+ return {};
}
NimbleBuildStepFactory::NimbleBuildStepFactory()
diff --git a/src/plugins/nim/project/nimblebuildsystem.cpp b/src/plugins/nim/project/nimblebuildsystem.cpp
index ae67800443..b08793087c 100644
--- a/src/plugins/nim/project/nimblebuildsystem.cpp
+++ b/src/plugins/nim/project/nimblebuildsystem.cpp
@@ -28,8 +28,10 @@
#include "nimbuildsystem.h"
#include "nimbleproject.h"
#include "nimproject.h"
+#include "../nimconstants.h"
#include <projectexplorer/target.h>
+#include <projectexplorer/taskhub.h>
#include <utils/algorithm.h>
#include <utils/qtcassert.h>
@@ -60,6 +62,13 @@ static std::vector<NimbleTask> parseTasks(const QString &nimblePath, const QStri
std::vector<NimbleTask> result;
+ if (process.exitCode() != 0) {
+ TaskHub::addTask(Task(Task::Error,
+ QString::fromUtf8(process.readAllStandardOutput()),
+ {}, -1, Constants::C_NIMPARSE_ID));
+ return result;
+ }
+
const QList<QByteArray> &lines = linesFromProcessOutput(&process);
for (const QByteArray &line : lines) {
@@ -82,6 +91,12 @@ static NimbleMetadata parseMetadata(const QString &nimblePath, const QString &wo
NimbleMetadata result = {};
+ if (process.exitCode() != 0) {
+ TaskHub::addTask(Task(Task::Error,
+ QString::fromUtf8(process.readAllStandardOutput()),
+ {}, -1, Constants::C_NIMPARSE_ID));
+ return result;
+ }
const QList<QByteArray> &lines = linesFromProcessOutput(&process);
for (const QByteArray &line : lines) {
@@ -153,6 +168,7 @@ void NimbleBuildSystem::triggerParsing()
void NimbleBuildSystem::updateProject()
{
+ TaskHub::clearTasks(Constants::C_NIMPARSE_ID);
const FilePath projectDir = projectDirectory();
const FilePath nimble = Nim::nimblePathFromKit(kit());
diff --git a/src/plugins/nim/project/nimbletaskstep.cpp b/src/plugins/nim/project/nimbletaskstep.cpp
index f41d53da90..9971f7920d 100644
--- a/src/plugins/nim/project/nimbletaskstep.cpp
+++ b/src/plugins/nim/project/nimbletaskstep.cpp
@@ -102,17 +102,17 @@ NimbleTaskStep::NimbleTaskStep(BuildStepList *parentList, Id id)
QWidget *NimbleTaskStep::createConfigWidget()
{
- auto widget = new QWidget;
-
- auto taskList = new QListView(widget);
+ auto taskList = new QListView;
taskList->setFrameShape(QFrame::StyledPanel);
taskList->setSelectionMode(QAbstractItemView::NoSelection);
taskList->setSelectionBehavior(QAbstractItemView::SelectRows);
taskList->setModel(&m_tasks);
- LayoutBuilder builder(widget);
- builder.addRow(m_taskArgs);
- builder.addRow({tr("Tasks:"), taskList});
+ using namespace Layouting;
+ auto widget = Form {
+ m_taskArgs,
+ tr("Tasks:"), taskList
+ }.emerge(false);
auto buildSystem = dynamic_cast<NimbleBuildSystem *>(this->buildSystem());
QTC_ASSERT(buildSystem, return widget);
diff --git a/src/plugins/nim/project/nimcompilerbuildstep.cpp b/src/plugins/nim/project/nimcompilerbuildstep.cpp
index 829254e0e2..8a02833a7f 100644
--- a/src/plugins/nim/project/nimcompilerbuildstep.cpp
+++ b/src/plugins/nim/project/nimcompilerbuildstep.cpp
@@ -97,7 +97,7 @@ QWidget *NimCompilerBuildStep::createConfigWidget()
auto updateUi = [=] {
const CommandLine cmd = commandLine();
- const QStringList parts = QtcProcess::splitArgs(cmd.toUserOutput());
+ const QStringList parts = ProcessArgs::splitArgs(cmd.toUserOutput());
commandTextEdit->setText(parts.join(QChar::LineFeed));
diff --git a/src/plugins/nim/project/nimtoolchainfactory.cpp b/src/plugins/nim/project/nimtoolchainfactory.cpp
index 7bf2377121..c7ff4500f5 100644
--- a/src/plugins/nim/project/nimtoolchainfactory.cpp
+++ b/src/plugins/nim/project/nimtoolchainfactory.cpp
@@ -49,8 +49,10 @@ NimToolChainFactory::NimToolChainFactory()
setUserCreatable(true);
}
-QList<ToolChain *> NimToolChainFactory::autoDetect(const QList<ToolChain *> &alreadyKnown)
+QList<ToolChain *> NimToolChainFactory::autoDetect(const QList<ToolChain *> &alreadyKnown,
+ const IDevice::Ptr &device)
{
+ Q_UNUSED(device);
QList<ToolChain *> result;
Environment systemEnvironment = Environment::systemEnvironment();
diff --git a/src/plugins/nim/project/nimtoolchainfactory.h b/src/plugins/nim/project/nimtoolchainfactory.h
index 1e9e219e97..bc10921302 100644
--- a/src/plugins/nim/project/nimtoolchainfactory.h
+++ b/src/plugins/nim/project/nimtoolchainfactory.h
@@ -39,7 +39,8 @@ class NimToolChainFactory : public ProjectExplorer::ToolChainFactory
public:
NimToolChainFactory();
- QList<ProjectExplorer::ToolChain *> autoDetect(const QList<ProjectExplorer::ToolChain *> &alreadyKnown) final;
+ QList<ProjectExplorer::ToolChain *> autoDetect(const QList<ProjectExplorer::ToolChain *> &alreadyKnown,
+ const ProjectExplorer::IDevice::Ptr &device) final;
QList<ProjectExplorer::ToolChain *> detectForImport(const ProjectExplorer::ToolChainDescription &tcd) final;
};
diff --git a/src/plugins/nim/settings/nimsettings.cpp b/src/plugins/nim/settings/nimsettings.cpp
index 5762222562..0c2fb95316 100644
--- a/src/plugins/nim/settings/nimsettings.cpp
+++ b/src/plugins/nim/settings/nimsettings.cpp
@@ -28,53 +28,42 @@
#include "../nimconstants.h"
-#include <texteditor/icodestylepreferencesfactory.h>
-#include <texteditor/texteditorsettings.h>
+#include <coreplugin/icore.h>
+
#include <texteditor/codestylepool.h>
+#include <texteditor/icodestylepreferencesfactory.h>
#include <texteditor/simplecodestylepreferences.h>
#include <texteditor/tabsettings.h>
-#include <coreplugin/icore.h>
+#include <texteditor/texteditorsettings.h>
+
+#include <utils/layoutbuilder.h>
using namespace TextEditor;
+using namespace Utils;
namespace Nim {
static SimpleCodeStylePreferences *m_globalCodeStyle = nullptr;
-NimSettings::NimSettings(QObject *parent)
- : QObject(parent)
+NimSettings::NimSettings()
{
- InitializeCodeStyleSettings();
- InitializeNimSuggestSettings();
-}
+ setAutoApply(false);
+ setSettingsGroups("Nim", "NimSuggest");
-NimSettings::~NimSettings()
-{
- TerminateCodeStyleSettings();
-}
+ InitializeCodeStyleSettings();
-QString NimSettings::nimSuggestPath() const
-{
- return m_nimSuggestPath;
-}
+ registerAspect(&nimSuggestPath);
+ nimSuggestPath.setSettingsKey("Command");
+ nimSuggestPath.setDisplayStyle(StringAspect::PathChooserDisplay);
+ nimSuggestPath.setExpectedKind(PathChooser::ExistingCommand);
+ nimSuggestPath.setLabelText(tr("Path:"));
-void NimSettings::setNimSuggestPath(const QString &path)
-{
- if (m_nimSuggestPath == path)
- return;
- m_nimSuggestPath = path;
- emit nimSuggestPathChanged(path);
+ readSettings(Core::ICore::settings());
}
-void NimSettings::save()
+NimSettings::~NimSettings()
{
- QSettings *s = Core::ICore::settings();
- s->beginGroup(Constants::C_NIM_SETTINGS_GROUP);
- s->beginGroup(Constants::C_NIM_SETTINGS_NIMSUGGEST_GROUP);
- s->setValue(QString::fromStdString(Constants::C_NIM_SETTINGS_COMMAND), nimSuggestPath());
- s->endGroup();
- s->endGroup();
- s->sync();
+ TerminateCodeStyleSettings();
}
SimpleCodeStylePreferences *NimSettings::globalCodeStyle()
@@ -127,17 +116,6 @@ void NimSettings::InitializeCodeStyleSettings()
Nim::Constants::C_NIMLANGUAGE_ID);
}
-void NimSettings::InitializeNimSuggestSettings()
-{
- QSettings *s = Core::ICore::settings();
- s->beginGroup(Constants::C_NIM_SETTINGS_GROUP);
- s->beginGroup(Constants::C_NIM_SETTINGS_NIMSUGGEST_GROUP);
- setNimSuggestPath(s->value(QString::fromStdString(Constants::C_NIM_SETTINGS_COMMAND),
- QString()).toString());
- s->endGroup();
- s->endGroup();
-}
-
void NimSettings::TerminateCodeStyleSettings()
{
TextEditorSettings::unregisterCodeStyle(Nim::Constants::C_NIMLANGUAGE_ID);
@@ -148,4 +126,28 @@ void NimSettings::TerminateCodeStyleSettings()
m_globalCodeStyle = nullptr;
}
+
+// NimToolSettingsPage
+
+NimToolsSettingsPage::NimToolsSettingsPage(NimSettings *settings)
+{
+ setId(Nim::Constants::C_NIMTOOLSSETTINGSPAGE_ID);
+ setDisplayName(NimSettings::tr(Nim::Constants::C_NIMTOOLSSETTINGSPAGE_DISPLAY));
+ setCategory(Nim::Constants::C_NIMTOOLSSETTINGSPAGE_CATEGORY);
+ setDisplayCategory(NimSettings::tr("Nim"));
+ setCategoryIconPath(":/nim/images/settingscategory_nim.png");
+ setSettings(settings);
+
+ setLayouter([settings](QWidget *widget) {
+ using namespace Layouting;
+ Column {
+ Group {
+ Title("Nimsuggest"),
+ settings->nimSuggestPath
+ },
+ Stretch()
+ }.attachTo(widget);
+ });
+}
+
} // namespace Nim
diff --git a/src/plugins/nim/settings/nimsettings.h b/src/plugins/nim/settings/nimsettings.h
index 3e648d97c9..764a6efc16 100644
--- a/src/plugins/nim/settings/nimsettings.h
+++ b/src/plugins/nim/settings/nimsettings.h
@@ -25,38 +25,34 @@
#pragma once
-#include <QObject>
+#include <coreplugin/dialogs/ioptionspage.h>
+#include <utils/aspects.h>
namespace TextEditor { class SimpleCodeStylePreferences; }
namespace Nim {
-class NimSettings : public QObject
+class NimSettings : public Utils::AspectContainer
{
- Q_OBJECT
+ Q_DECLARE_TR_FUNCTIONS(Nim::NimSettings)
public:
- NimSettings(QObject *parent = nullptr);
- ~NimSettings() override;
+ NimSettings();
+ ~NimSettings();
- QString nimSuggestPath() const;
- void setNimSuggestPath(const QString &path);
-
- void save();
+ Utils::StringAspect nimSuggestPath;
static TextEditor::SimpleCodeStylePreferences *globalCodeStyle();
-signals:
- void nimSuggestPathChanged(QString path);
-
private:
void InitializeCodeStyleSettings();
void TerminateCodeStyleSettings();
+};
- void InitializeNimSuggestSettings();
- void TerminateNimSuggestSettings();
-
- QString m_nimSuggestPath;
+class NimToolsSettingsPage final : public Core::IOptionsPage
+{
+public:
+ explicit NimToolsSettingsPage(NimSettings *settings);
};
} // namespace Nim
diff --git a/src/plugins/nim/settings/nimtoolssettingspage.cpp b/src/plugins/nim/settings/nimtoolssettingspage.cpp
deleted file mode 100644
index a77aaf1c70..0000000000
--- a/src/plugins/nim/settings/nimtoolssettingspage.cpp
+++ /dev/null
@@ -1,87 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) Filippo Cucchetto <filippocucchetto@gmail.com>
-** Contact: http://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 "nimtoolssettingspage.h"
-#include "nimconstants.h"
-#include "nimsettings.h"
-#include "ui_nimtoolssettingswidget.h"
-
-#include <coreplugin/icore.h>
-
-namespace Nim {
-
-NimToolsSettingsWidget::NimToolsSettingsWidget() : ui(new Ui::NimToolsSettingsWidget)
-{
- ui->setupUi(this);
- ui->pathWidget->setExpectedKind(Utils::PathChooser::ExistingCommand);
-}
-
-NimToolsSettingsWidget::~NimToolsSettingsWidget()
-{
- delete ui;
-}
-
-QString NimToolsSettingsWidget::command() const
-{
- return ui->pathWidget->filePath().toString();
-}
-
-void NimToolsSettingsWidget::setCommand(const QString &filename)
-{
- ui->pathWidget->setPath(filename);
-}
-
-NimToolsSettingsPage::NimToolsSettingsPage(NimSettings *settings)
- : m_settings(settings)
-{
- setId(Nim::Constants::C_NIMTOOLSSETTINGSPAGE_ID);
- setDisplayName(NimToolsSettingsWidget::tr(Nim::Constants::C_NIMTOOLSSETTINGSPAGE_DISPLAY));
- setCategory(Nim::Constants::C_NIMTOOLSSETTINGSPAGE_CATEGORY);
- setDisplayCategory(NimToolsSettingsWidget::tr("Nim"));
- setCategoryIconPath(":/nim/images/settingscategory_nim.png");
-}
-
-NimToolsSettingsPage::~NimToolsSettingsPage() = default;
-
-QWidget *NimToolsSettingsPage::widget()
-{
- if (!m_widget)
- m_widget.reset(new NimToolsSettingsWidget);
- m_widget->setCommand(m_settings->nimSuggestPath());
- return m_widget.get();
-}
-
-void NimToolsSettingsPage::apply()
-{
- m_settings->setNimSuggestPath(m_widget->command());
- m_settings->save();
-}
-
-void NimToolsSettingsPage::finish()
-{
- m_widget.reset();
-}
-
-}
diff --git a/src/plugins/nim/settings/nimtoolssettingspage.h b/src/plugins/nim/settings/nimtoolssettingspage.h
deleted file mode 100644
index 9a8e0df19c..0000000000
--- a/src/plugins/nim/settings/nimtoolssettingspage.h
+++ /dev/null
@@ -1,73 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) Filippo Cucchetto <filippocucchetto@gmail.com>
-** Contact: http://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 <coreplugin/dialogs/ioptionspage.h>
-#include <utils/fileutils.h>
-
-#include <QWidget>
-
-#include <memory>
-
-namespace Nim {
-
-class NimSettings;
-
-namespace Ui { class NimToolsSettingsWidget; }
-
-class NimToolsSettingsWidget : public QWidget
-{
- Q_DECLARE_TR_FUNCTIONS(Nim::ToolSettingsPage)
-
-public:
- NimToolsSettingsWidget();
-
- ~NimToolsSettingsWidget();
-
- QString command() const;
- void setCommand(const QString &filename);
-
-private:
- Ui::NimToolsSettingsWidget *ui;
-};
-
-class NimToolsSettingsPage final : public Core::IOptionsPage
-{
-public:
- explicit NimToolsSettingsPage(NimSettings *settings);
-
- ~NimToolsSettingsPage();
-
- QWidget *widget() final;
- void apply() final;
- void finish() final;
-
-private:
- std::unique_ptr<NimToolsSettingsWidget> m_widget;
- NimSettings *m_settings = nullptr;
-};
-
-}
diff --git a/src/plugins/nim/settings/nimtoolssettingswidget.ui b/src/plugins/nim/settings/nimtoolssettingswidget.ui
deleted file mode 100644
index 28c0d1ac31..0000000000
--- a/src/plugins/nim/settings/nimtoolssettingswidget.ui
+++ /dev/null
@@ -1,66 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<ui version="4.0">
- <class>Nim::NimToolsSettingsWidget</class>
- <widget class="QWidget" name="Nim::NimToolsSettingsWidget">
- <property name="geometry">
- <rect>
- <x>0</x>
- <y>0</y>
- <width>400</width>
- <height>300</height>
- </rect>
- </property>
- <layout class="QVBoxLayout" name="verticalLayout_2">
- <item>
- <widget class="QGroupBox" name="groupBox">
- <property name="title">
- <string>Nimsuggest</string>
- </property>
- <layout class="QVBoxLayout" name="verticalLayout">
- <item>
- <layout class="QFormLayout" name="formLayout">
- <item row="0" column="0">
- <widget class="QLabel" name="pathLabel">
- <property name="text">
- <string>Path</string>
- </property>
- </widget>
- </item>
- <item row="0" column="1">
- <widget class="Utils::PathChooser" name="pathWidget" native="true"/>
- </item>
- </layout>
- </item>
- </layout>
- </widget>
- </item>
- <item>
- <spacer name="verticalSpacer">
- <property name="orientation">
- <enum>Qt::Vertical</enum>
- </property>
- <property name="sizeHint" stdset="0">
- <size>
- <width>20</width>
- <height>40</height>
- </size>
- </property>
- </spacer>
- </item>
- </layout>
- </widget>
- <customwidgets>
- <customwidget>
- <class>Utils::PathChooser</class>
- <extends>QWidget</extends>
- <header location="global">utils/pathchooser.h</header>
- <container>1</container>
- <slots>
- <signal>editingFinished()</signal>
- <signal>browsingFinished()</signal>
- </slots>
- </customwidget>
- </customwidgets>
- <resources/>
- <connections/>
-</ui>
diff --git a/src/plugins/perforce/CMakeLists.txt b/src/plugins/perforce/CMakeLists.txt
index b11ee81b8f..75bb790b6a 100644
--- a/src/plugins/perforce/CMakeLists.txt
+++ b/src/plugins/perforce/CMakeLists.txt
@@ -11,6 +11,5 @@ add_qtc_plugin(Perforce
perforcesubmiteditor.cpp perforcesubmiteditor.h
perforcesubmiteditorwidget.cpp perforcesubmiteditorwidget.h
promptdialog.ui
- settingspage.cpp settingspage.h settingspage.ui
submitpanel.ui
)
diff --git a/src/plugins/perforce/perforce.pro b/src/plugins/perforce/perforce.pro
index e9bc8e48ea..1d55518690 100644
--- a/src/plugins/perforce/perforce.pro
+++ b/src/plugins/perforce/perforce.pro
@@ -3,7 +3,6 @@ include(../../qtcreatorplugin.pri)
HEADERS += \
perforceplugin.h \
perforcechecker.h \
- settingspage.h \
perforceeditor.h \
changenumberdialog.h \
perforcesubmiteditor.h \
@@ -14,7 +13,6 @@ HEADERS += \
SOURCES += perforceplugin.cpp \
perforcechecker.cpp \
- settingspage.cpp \
perforceeditor.cpp \
changenumberdialog.cpp \
perforcesubmiteditor.cpp \
@@ -23,7 +21,7 @@ SOURCES += perforceplugin.cpp \
annotationhighlighter.cpp \
perforcesubmiteditorwidget.cpp
-FORMS += settingspage.ui \
+FORMS += \
changenumberdialog.ui \
pendingchangesdialog.ui \
submitpanel.ui
diff --git a/src/plugins/perforce/perforce.qbs b/src/plugins/perforce/perforce.qbs
index d867e8e34f..66190057e2 100644
--- a/src/plugins/perforce/perforce.qbs
+++ b/src/plugins/perforce/perforce.qbs
@@ -31,9 +31,6 @@ QtcPlugin {
"perforcesubmiteditor.h",
"perforcesubmiteditorwidget.cpp",
"perforcesubmiteditorwidget.h",
- "settingspage.cpp",
- "settingspage.h",
- "settingspage.ui",
"submitpanel.ui",
]
}
diff --git a/src/plugins/perforce/perforcechecker.cpp b/src/plugins/perforce/perforcechecker.cpp
index 544a132b64..060f1c221e 100644
--- a/src/plugins/perforce/perforcechecker.cpp
+++ b/src/plugins/perforce/perforcechecker.cpp
@@ -26,15 +26,13 @@
#include "perforcechecker.h"
#include <utils/qtcassert.h>
-#include <utils/synchronousprocess.h>
-
-#include <QRegularExpression>
-#include <QTimer>
-#include <QFileInfo>
-#include <QDir>
#include <QApplication>
#include <QCursor>
+#include <QDir>
+#include <QFileInfo>
+#include <QRegularExpression>
+#include <QTimer>
namespace Perforce {
namespace Internal {
@@ -90,7 +88,8 @@ void PerforceChecker::start(const QString &binary, const QString &workingDirecto
if (!workingDirectory.isEmpty())
m_process.setWorkingDirectory(workingDirectory);
- m_process.start(m_binary, args);
+ m_process.setCommand({m_binary, args});
+ m_process.start();
m_process.closeWriteChannel();
// Timeout handling
m_timeOutMS = timeoutMS;
@@ -109,9 +108,8 @@ void PerforceChecker::slotTimeOut()
if (!isRunning())
return;
m_timedOut = true;
- Utils::SynchronousProcess::stopProcess(m_process);
- emitFailed(tr("\"%1\" timed out after %2 ms.").
- arg(m_binary).arg(m_timeOutMS));
+ m_process.stopProcess();
+ emitFailed(tr("\"%1\" timed out after %2 ms.").arg(m_binary).arg(m_timeOutMS));
}
void PerforceChecker::slotError(QProcess::ProcessError error)
@@ -129,7 +127,7 @@ void PerforceChecker::slotError(QProcess::ProcessError error)
case QProcess::ReadError:
case QProcess::WriteError:
case QProcess::UnknownError:
- Utils::SynchronousProcess::stopProcess(m_process);
+ m_process.stopProcess();
break;
}
}
diff --git a/src/plugins/perforce/perforcechecker.h b/src/plugins/perforce/perforcechecker.h
index ed346ab431..c4d90d3009 100644
--- a/src/plugins/perforce/perforcechecker.h
+++ b/src/plugins/perforce/perforcechecker.h
@@ -25,8 +25,7 @@
#pragma once
-#include <QObject>
-#include <QProcess>
+#include <utils/qtcprocess.h>
namespace Perforce {
namespace Internal {
@@ -68,7 +67,7 @@ private:
void parseOutput(const QString &);
inline void resetOverrideCursor();
- QProcess m_process;
+ Utils::QtcProcess m_process;
QString m_binary;
int m_timeOutMS = -1;
bool m_timedOut = false;
diff --git a/src/plugins/perforce/perforceplugin.cpp b/src/plugins/perforce/perforceplugin.cpp
index 5eaa7fb6a6..6861ff9a0e 100644
--- a/src/plugins/perforce/perforceplugin.cpp
+++ b/src/plugins/perforce/perforceplugin.cpp
@@ -31,7 +31,6 @@
#include "perforceeditor.h"
#include "perforcesettings.h"
#include "perforcesubmiteditor.h"
-#include "settingspage.h"
#include <coreplugin/actionmanager/actionmanager.h>
#include <coreplugin/actionmanager/actioncontainer.h>
@@ -42,11 +41,13 @@
#include <coreplugin/icore.h>
#include <coreplugin/messagemanager.h>
#include <coreplugin/locator/commandlocator.h>
+
#include <texteditor/textdocument.h>
+
#include <utils/fileutils.h>
#include <utils/parameteraction.h>
#include <utils/qtcassert.h>
-#include <utils/synchronousprocess.h>
+#include <utils/qtcprocess.h>
#include <utils/temporarydirectory.h>
#include <vcsbase/basevcseditorfactory.h>
@@ -107,10 +108,10 @@ static inline QStringList perforceRelativeProjectDirectory(const VcsBasePluginSt
}
// Clean user setting off diff-binary for 'p4 resolve' and 'p4 diff'.
-static inline QProcessEnvironment overrideDiffEnvironmentVariable()
+static Environment overrideDiffEnvironmentVariable()
{
- QProcessEnvironment rc = QProcessEnvironment::systemEnvironment();
- rc.remove(QLatin1String("P4DIFF"));
+ Environment rc = Environment::systemEnvironment();
+ rc.unset("P4DIFF");
return rc;
}
@@ -358,7 +359,7 @@ public:
QAction *m_menuAction = nullptr;
PerforceSettings m_settings;
- SettingsPage m_settingsPage{&m_settings, [this] { applySettings(); }};
+ PerforceSettingsPage m_settingsPage{&m_settings};
ManagedDirectoryCache m_managedDirectoryCache;
@@ -396,10 +397,11 @@ PerforcePluginPrivate::PerforcePluginPrivate()
dd = this;
- m_settings.fromSettings(ICore::settings());
+ m_settings.readSettings(ICore::settings());
const QString prefix = QLatin1String("p4");
m_commandLocator = new CommandLocator("Perforce", prefix, prefix, this);
+ m_commandLocator->setDescription(tr("Triggers a Perforce version control operation."));
ActionContainer *mtools = ActionManager::actionContainer(Core::Constants::M_TOOLS);
@@ -571,6 +573,11 @@ PerforcePluginPrivate::PerforcePluginPrivate()
command = ActionManager::registerAction(m_filelogAction, CMD_ID_FILELOG, context);
connect(m_filelogAction, &QAction::triggered, this, &PerforcePluginPrivate::filelogFile);
perforceContainer->addAction(command);
+
+ QObject::connect(&m_settings, &AspectContainer::applied, [this] {
+ m_settings.clearTopLevel();
+ applySettings();
+ });
}
void PerforcePlugin::extensionsInitialized()
@@ -768,7 +775,7 @@ void PerforcePluginPrivate::startSubmitProject()
cleanCommitMessageFile();
return;
}
- m_commitMessageFileName = saver.fileName();
+ m_commitMessageFileName = saver.filePath().toString();
args.clear();
args << QLatin1String("files");
@@ -908,8 +915,8 @@ void PerforcePluginPrivate::filelog(const QString &workingDir, const QString &fi
QTextCodec *codec = VcsBaseEditor::getCodec(workingDir, QStringList(fileName));
QStringList args;
args << QLatin1String("filelog") << QLatin1String("-li");
- if (m_settings.logCount() > 0)
- args << QLatin1String("-m") << QString::number(m_settings.logCount());
+ if (m_settings.logCount.value() > 0)
+ args << "-m" << QString::number(m_settings.logCount.value());
if (!fileName.isEmpty())
args.append(fileName);
const PerforceResponse result = runP4Cmd(workingDir, args,
@@ -930,8 +937,8 @@ void PerforcePluginPrivate::changelists(const QString &workingDir, const QString
QTextCodec *codec = VcsBaseEditor::getCodec(workingDir, QStringList(fileName));
QStringList args;
args << QLatin1String("changelists") << QLatin1String("-lit");
- if (m_settings.logCount() > 0)
- args << QLatin1String("-m") << QString::number(m_settings.logCount());
+ if (m_settings.logCount.value() > 0)
+ args << "-m" << QString::number(m_settings.logCount.value());
if (!fileName.isEmpty())
args.append(fileName);
const PerforceResponse result = runP4Cmd(workingDir, args,
@@ -1127,7 +1134,7 @@ bool PerforcePluginPrivate::isVcsFileOrDirectory(const FilePath &fileName) const
bool PerforcePluginPrivate::isConfigured() const
{
- const QString binary = m_settings.p4BinaryPath();
+ const QString binary = m_settings.p4BinaryPath.value();
if (binary.isEmpty())
return false;
QFileInfo fi(binary);
@@ -1166,8 +1173,8 @@ bool PerforcePluginPrivate::vcsOpen(const QString &fileName)
IVersionControl::SettingsFlags PerforcePluginPrivate::settingsFlags() const
{
SettingsFlags rc;
- if (m_settings.autoOpen())
- rc|= AutoOpen;
+ if (m_settings.autoOpen.value())
+ rc |= AutoOpen;
return rc;
}
@@ -1242,63 +1249,53 @@ PerforceResponse PerforcePluginPrivate::synchronousProcess(const QString &workin
{
QTC_ASSERT(stdInput.isEmpty(), return PerforceResponse()); // Not supported here
- VcsOutputWindow *outputWindow = VcsOutputWindow::instance();
// Run, connect stderr to the output window
SynchronousProcess process;
- const int timeOutS = (flags & LongTimeOut) ? m_settings.longTimeOutS() : m_settings.timeOutS();
+ const int timeOutS = (flags & LongTimeOut) ? m_settings.longTimeOutS() : m_settings.timeOutS.value();
process.setTimeoutS(timeOutS);
if (outputCodec)
process.setCodec(outputCodec);
if (flags & OverrideDiffEnvironment)
- process.setProcessEnvironment(overrideDiffEnvironmentVariable());
+ process.setEnvironment(overrideDiffEnvironmentVariable());
if (!workingDir.isEmpty())
process.setWorkingDirectory(workingDir);
// connect stderr to the output window if desired
- if (flags & StdErrToWindow) {
- process.setStdErrBufferedSignalsEnabled(true);
- connect(&process, &SynchronousProcess::stdErrBuffered,
- outputWindow, [](const QString &lines) {
- VcsOutputWindow::append(lines);
- });
- }
+ if (flags & StdErrToWindow)
+ process.setStdErrCallback([](const QString &lines) { VcsOutputWindow::append(lines); });
// connect stdout to the output window if desired
if (flags & StdOutToWindow) {
- process.setStdOutBufferedSignalsEnabled(true);
- if (flags & SilentStdOut) {
- connect(&process, &SynchronousProcess::stdOutBuffered,
- outputWindow, &VcsOutputWindow::appendSilently);
- } else {
- connect(&process, &SynchronousProcess::stdOutBuffered,
- outputWindow, [](const QString &lines) {
- VcsOutputWindow::append(lines);
- });
- }
+ if (flags & SilentStdOut)
+ process.setStdOutCallback(&VcsOutputWindow::appendSilently);
+ else
+ process.setStdOutCallback([](const QString &lines) { VcsOutputWindow::append(lines); });
}
process.setTimeOutMessageBoxEnabled(true);
- const SynchronousProcessResponse sp_resp = process.run({m_settings.p4BinaryPath(), args});
+ process.setCommand({m_settings.p4BinaryPath.value(), args});
+ process.setProcessUserEventWhileRunning();
+ process.runBlocking();
PerforceResponse response;
response.error = true;
- response.exitCode = sp_resp.exitCode;
- response.stdErr = sp_resp.stdErr();
- response.stdOut = sp_resp.stdOut();
- switch (sp_resp.result) {
- case SynchronousProcessResponse::Finished:
+ response.exitCode = process.exitCode();
+ response.stdErr = process.stdErr();
+ response.stdOut = process.stdOut();
+ switch (process.result()) {
+ case QtcProcess::Finished:
response.error = false;
break;
- case SynchronousProcessResponse::FinishedError:
- response.message = msgExitCode(sp_resp.exitCode);
+ case QtcProcess::FinishedError:
+ response.message = msgExitCode(process.exitCode());
response.error = !(flags & IgnoreExitCode);
break;
- case SynchronousProcessResponse::TerminatedAbnormally:
+ case QtcProcess::TerminatedAbnormally:
response.message = msgCrash();
break;
- case SynchronousProcessResponse::StartFailed:
- response.message = msgNotStarted(m_settings.p4BinaryPath());
+ case QtcProcess::StartFailed:
+ response.message = msgNotStarted(m_settings.p4BinaryPath.value());
break;
- case SynchronousProcessResponse::Hang:
+ case QtcProcess::Hang:
response.message = msgCrash();
break;
}
@@ -1312,29 +1309,30 @@ PerforceResponse PerforcePluginPrivate::fullySynchronousProcess(const QString &w
const QByteArray &stdInput,
QTextCodec *outputCodec) const
{
- QProcess process;
+ QtcProcess process;
if (flags & OverrideDiffEnvironment)
- process.setProcessEnvironment(overrideDiffEnvironmentVariable());
+ process.setEnvironment(overrideDiffEnvironmentVariable());
if (!workingDir.isEmpty())
process.setWorkingDirectory(workingDir);
PerforceResponse response;
- process.start(m_settings.p4BinaryPath(), args);
+ process.setCommand({m_settings.p4BinaryPath.value(), args});
+ process.start();
if (stdInput.isEmpty())
process.closeWriteChannel();
if (!process.waitForStarted(3000)) {
response.error = true;
- response.message = msgNotStarted(m_settings.p4BinaryPath());
+ response.message = msgNotStarted(m_settings.p4BinaryPath.value());
return response;
}
if (!stdInput.isEmpty()) {
if (process.write(stdInput) == -1) {
- SynchronousProcess::stopProcess(process);
+ process.stopProcess();
response.error = true;
response.message = tr("Unable to write input data to process %1: %2").
- arg(QDir::toNativeSeparators(m_settings.p4BinaryPath()),
+ arg(QDir::toNativeSeparators(m_settings.p4BinaryPath.value()),
process.errorString());
return response;
}
@@ -1343,9 +1341,9 @@ PerforceResponse PerforcePluginPrivate::fullySynchronousProcess(const QString &w
QByteArray stdOut;
QByteArray stdErr;
- const int timeOutS = (flags & LongTimeOut) ? m_settings.longTimeOutS() : m_settings.timeOutS();
- if (!SynchronousProcess::readDataFromProcess(process, timeOutS, &stdOut, &stdErr, true)) {
- SynchronousProcess::stopProcess(process);
+ const int timeOutS = (flags & LongTimeOut) ? m_settings.longTimeOutS() : m_settings.timeOutS.value();
+ if (!process.readDataFromProcess(timeOutS, &stdOut, &stdErr, true)) {
+ process.stopProcess();
response.error = true;
response.message = msgTimeout(timeOutS);
return response;
@@ -1389,7 +1387,7 @@ PerforceResponse PerforcePluginPrivate::runP4Cmd(const QString &workingDir,
QString errorMessage;
QSharedPointer<TempFileSaver> tempFile = createTemporaryArgumentFile(extraArgs, &errorMessage);
if (!tempFile.isNull()) {
- actualArgs << QLatin1String("-x") << tempFile->fileName();
+ actualArgs << QLatin1String("-x") << tempFile->filePath().toString();
} else if (!errorMessage.isEmpty()) {
PerforceResponse tempFailResponse;
tempFailResponse.error = true;
@@ -1399,7 +1397,7 @@ PerforceResponse PerforcePluginPrivate::runP4Cmd(const QString &workingDir,
actualArgs.append(args);
if (flags & CommandToWindow)
- VcsOutputWindow::appendCommand(workingDir, {m_settings.p4BinaryPath(), actualArgs});
+ VcsOutputWindow::appendCommand(workingDir, {m_settings.p4BinaryPath.value(), actualArgs});
if (flags & ShowBusyCursor)
QApplication::setOverrideCursor(QCursor(Qt::WaitCursor));
@@ -1581,7 +1579,7 @@ bool PerforcePluginPrivate::submitEditorAboutToClose()
QTC_ASSERT(editorDocument, return true);
// Prompt the user. Force a prompt unless submit was actually invoked (that
// is, the editor was closed or shutdown).
- bool wantsPrompt = m_settings.promptToSubmit();
+ bool wantsPrompt = m_settings.promptToSubmit.value();
const VcsBaseSubmitEditor::PromptSubmitResult answer =
perforceEditor->promptSubmit(this, &wantsPrompt, !m_submitActionTriggered);
m_submitActionTriggered = false;
@@ -1590,9 +1588,9 @@ bool PerforcePluginPrivate::submitEditorAboutToClose()
return false;
// Set without triggering the checking mechanism
- if (wantsPrompt != m_settings.promptToSubmit()) {
- m_settings.setPromptToSubmit(wantsPrompt);
- m_settings.toSettings(ICore::settings());
+ if (wantsPrompt != m_settings.promptToSubmit.value()) {
+ m_settings.promptToSubmit.setValue(wantsPrompt);
+ m_settings.writeSettings(ICore::settings());
}
if (!DocumentManager::saveDocument(editorDocument))
return false;
@@ -1602,7 +1600,7 @@ bool PerforcePluginPrivate::submitEditorAboutToClose()
}
// Pipe file into p4 submit -i
FileReader reader;
- if (!reader.fetch(m_commitMessageFileName, QIODevice::Text)) {
+ if (!reader.fetch(Utils::FilePath::fromString(m_commitMessageFileName), QIODevice::Text)) {
VcsOutputWindow::appendError(reader.errorString());
return false;
}
@@ -1719,7 +1717,7 @@ void PerforcePluginPrivate::setTopLevel(const QString &topLevel)
void PerforcePluginPrivate::applySettings()
{
- m_settings.toSettings(ICore::settings());
+ m_settings.writeSettings(ICore::settings());
m_managedDirectoryCache.clear();
getTopLevel();
emit configurationChanged();
@@ -1733,7 +1731,7 @@ void PerforcePluginPrivate::slotTopLevelFailed(const QString &errorMessage)
void PerforcePluginPrivate::getTopLevel(const QString &workingDirectory, bool isSync)
{
// Run a new checker
- if (m_settings.p4BinaryPath().isEmpty())
+ if (m_settings.p4BinaryPath.value().isEmpty())
return;
auto checker = new PerforceChecker(dd);
connect(checker, &PerforceChecker::failed, dd, &PerforcePluginPrivate::slotTopLevelFailed);
@@ -1741,7 +1739,7 @@ void PerforcePluginPrivate::getTopLevel(const QString &workingDirectory, bool is
connect(checker, &PerforceChecker::succeeded, dd, &PerforcePluginPrivate::setTopLevel);
connect(checker, &PerforceChecker::succeeded,checker, &QObject::deleteLater);
- checker->start(m_settings.p4BinaryPath(), workingDirectory,
+ checker->start(m_settings.p4BinaryPath.value(), workingDirectory,
m_settings.commonP4Arguments(QString()), 30000);
if (isSync)
diff --git a/src/plugins/perforce/perforcesettings.cpp b/src/plugins/perforce/perforcesettings.cpp
index 116861034e..f8292729b0 100644
--- a/src/plugins/perforce/perforcesettings.cpp
+++ b/src/plugins/perforce/perforcesettings.cpp
@@ -24,64 +24,94 @@
****************************************************************************/
#include "perforcesettings.h"
+
+#include "perforcechecker.h"
#include "perforceplugin.h"
-#include <utils/qtcassert.h>
#include <utils/environment.h>
#include <utils/hostosinfo.h>
+#include <utils/layoutbuilder.h>
+#include <utils/qtcassert.h>
-#include <QSettings>
-#include <QStringList>
-#include <QCoreApplication>
+#include <vcsbase/vcsbaseconstants.h>
+
+#include <QApplication>
#include <QDir>
+#include <QFileDialog>
#include <QFileInfo>
+#include <QPushButton>
+#include <QStringList>
-static const char groupC[] = "Perforce";
-static const char commandKeyC[] = "Command";
-static const char defaultKeyC[] = "Default";
-static const char portKeyC[] = "Port";
-static const char clientKeyC[] = "Client";
-static const char userKeyC[] = "User";
-static const char promptToSubmitKeyC[] = "PromptForSubmit";
-static const char autoOpenKeyC[] = "PromptToOpen";
-static const char timeOutKeyC[] = "TimeOut";
-static const char logCountKeyC[] = "LogCount";
-
-enum { defaultTimeOutS = 30, defaultLogCount = 1000 };
-
-static QString defaultCommand()
-{
- return QLatin1String("p4" QTC_HOST_EXE_SUFFIX);
-}
+using namespace Utils;
namespace Perforce {
namespace Internal {
-Settings::Settings() : logCount(defaultLogCount), timeOutS(defaultTimeOutS)
-{ }
-
-bool Settings::equals(const Settings &rhs) const
+static QString defaultCommand()
{
- return defaultEnv == rhs.defaultEnv
- && logCount == rhs.logCount
- && p4Command == rhs.p4Command && p4Port == rhs.p4Port
- && p4Client == rhs.p4Client && p4User == rhs.p4User
- && timeOutS == rhs.timeOutS && promptToSubmit == rhs.promptToSubmit
- && autoOpen == rhs.autoOpen;
+ return QLatin1String("p4" QTC_HOST_EXE_SUFFIX);
}
-QStringList Settings::commonP4Arguments() const
+PerforceSettings::PerforceSettings()
{
- if (defaultEnv)
- return QStringList();
- QStringList lst;
- if (!p4Client.isEmpty())
- lst << QLatin1String("-c") << p4Client;
- if (!p4Port.isEmpty())
- lst << QLatin1String("-p") << p4Port;
- if (!p4User.isEmpty())
- lst << QLatin1String("-u") << p4User;
- return lst;
+ setSettingsGroup("Perforce");
+ setAutoApply(false);
+
+ registerAspect(&p4BinaryPath);
+ p4BinaryPath.setDisplayStyle(StringAspect::PathChooserDisplay);
+ p4BinaryPath.setSettingsKey("Command");
+ p4BinaryPath.setDefaultValue(
+ Environment::systemEnvironment().searchInPath(defaultCommand()).toString());
+ p4BinaryPath.setHistoryCompleter("Perforce.Command.History");
+ p4BinaryPath.setExpectedKind(PathChooser::Command);
+ p4BinaryPath.setDisplayName(tr("Perforce Command"));
+ p4BinaryPath.setLabelText(tr("P4 command:"));
+
+ registerAspect(&p4Port);
+ p4Port.setDisplayStyle(StringAspect::LineEditDisplay);
+ p4Port.setSettingsKey("Port");
+ p4Port.setLabelText(tr("P4 port:"));
+
+ registerAspect(&p4Client);
+ p4Client.setDisplayStyle(StringAspect::LineEditDisplay);
+ p4Client.setSettingsKey("Client");
+ p4Client.setLabelText(tr("P4 client:"));
+
+ registerAspect(&p4User);
+ p4User.setDisplayStyle(StringAspect::LineEditDisplay);
+ p4User.setSettingsKey("User");
+ p4User.setLabelText(tr("P4 user:"));
+
+ registerAspect(&logCount);
+ logCount.setSettingsKey("LogCount");
+ logCount.setRange(1000, 10000);
+ logCount.setDefaultValue(1000);
+ logCount.setLabelText(tr("Log count:"));
+
+ registerAspect(&customEnv);
+ // The settings value has been stored with the opposite meaning for a while.
+ // Avoid changing the stored value, but flip it on read/write:
+ customEnv.setSettingsKey("Default");
+ const auto invertBoolVariant = [](const QVariant &v) { return QVariant(!v.toBool()); };
+ customEnv.setFromSettingsTransformation(invertBoolVariant);
+ customEnv.setToSettingsTransformation(invertBoolVariant);
+
+ registerAspect(&timeOutS);
+ timeOutS.setSettingsKey("TimeOut");
+ timeOutS.setRange(1, 360);
+ timeOutS.setDefaultValue(30);
+ timeOutS.setLabelText(tr("Timeout:"));
+ timeOutS.setSuffix(tr("s"));
+
+ registerAspect(&promptToSubmit);
+ promptToSubmit.setSettingsKey("PromptForSubmit");
+ promptToSubmit.setDefaultValue(true);
+ promptToSubmit.setLabelText(tr("Prompt on submit"));
+
+ registerAspect(&autoOpen);
+ autoOpen.setSettingsKey("PromptToOpen");
+ autoOpen.setDefaultValue(true);
+ autoOpen.setLabelText(tr("Automatically open files when editing"));
}
// --------------------PerforceSettings
@@ -90,99 +120,28 @@ PerforceSettings::~PerforceSettings()
delete m_topLevelDir;
}
-void PerforceSettings::fromSettings(QSettings *settings)
-{
- settings->beginGroup(QLatin1String(groupC));
- m_settings.p4Command = settings->value(QLatin1String(commandKeyC), defaultCommand()).toString();
- m_settings.p4BinaryPath =
- Utils::Environment::systemEnvironment().searchInPath(m_settings.p4Command).toString();
- m_settings.defaultEnv = settings->value(QLatin1String(defaultKeyC), true).toBool();
- m_settings.p4Port = settings->value(QLatin1String(portKeyC), QString()).toString();
- m_settings.p4Client = settings->value(QLatin1String(clientKeyC), QString()).toString();
- m_settings.p4User = settings->value(QLatin1String(userKeyC), QString()).toString();
- m_settings.timeOutS = settings->value(QLatin1String(timeOutKeyC), defaultTimeOutS).toInt();
- m_settings.promptToSubmit = settings->value(QLatin1String(promptToSubmitKeyC), true).toBool();
- m_settings.logCount = settings->value(QLatin1String(logCountKeyC), int(defaultLogCount)).toInt();
- m_settings.autoOpen = settings->value(QLatin1String(autoOpenKeyC), true).toBool();
- settings->endGroup();
-}
-
-void PerforceSettings::toSettings(QSettings *settings) const
-{
- settings->beginGroup(QLatin1String(groupC));
- settings->setValue(QLatin1String(commandKeyC), m_settings.p4Command);
- settings->setValue(QLatin1String(defaultKeyC), m_settings.defaultEnv);
- settings->setValue(QLatin1String(portKeyC), m_settings.p4Port);
- settings->setValue(QLatin1String(clientKeyC), m_settings.p4Client);
- settings->setValue(QLatin1String(userKeyC), m_settings.p4User);
- settings->setValue(QLatin1String(timeOutKeyC), m_settings.timeOutS);
- settings->setValue(QLatin1String(promptToSubmitKeyC), m_settings.promptToSubmit);
- settings->setValue(QLatin1String(logCountKeyC), m_settings.logCount);
- settings->setValue(QLatin1String(autoOpenKeyC), m_settings.autoOpen);
- settings->endGroup();
-}
-
-void PerforceSettings::setSettings(const Settings &newSettings)
+QStringList PerforceSettings::commonP4Arguments() const
{
- if (newSettings != m_settings) {
- m_settings = newSettings;
- clearTopLevel();
+ QStringList lst;
+ if (customEnv.value()) {
+ if (!p4Client.value().isEmpty())
+ lst << "-c" << p4Client.value();
+ if (!p4Port.value().isEmpty())
+ lst << "-p" << p4Port.value();
+ if (!p4User.value().isEmpty())
+ lst << "-u" << p4User.value();
}
+ return lst;
}
-Settings PerforceSettings::settings() const
-{
- return m_settings;
-}
-
-QString PerforceSettings::p4Command() const
-{
- return m_settings.p4Command;
-}
-
-QString PerforceSettings::p4BinaryPath() const
-{
- return m_settings.p4BinaryPath;
-}
-
-QString PerforceSettings::p4Port() const
-{
- return m_settings.p4Port;
-}
-
-QString PerforceSettings::p4Client() const
-{
- return m_settings.p4Client;
-}
-
-QString PerforceSettings::p4User() const
+bool PerforceSettings::isValid() const
{
- return m_settings.p4User;
+ return !m_topLevel.isEmpty() && !p4BinaryPath.value().isEmpty();
}
bool PerforceSettings::defaultEnv() const
{
- return m_settings.defaultEnv;
-}
-
-bool PerforceSettings::promptToSubmit() const
-{
- return m_settings.promptToSubmit;
-}
-
-void PerforceSettings::setPromptToSubmit(bool p)
-{
- m_settings.promptToSubmit = p;
-}
-
-bool PerforceSettings::autoOpen() const
-{
- return m_settings.autoOpen;
-}
-
-void PerforceSettings::setAutoOpen(bool b)
-{
- m_settings.autoOpen = b;
+ return !customEnv.value(); // Note: negated
}
QString PerforceSettings::topLevel() const
@@ -257,7 +216,7 @@ QStringList PerforceSettings::commonP4Arguments(const QString &workingDir) const
rc << QLatin1String("-d")
<< QDir::toNativeSeparators(mapPathRoot(workingDir, m_topLevelSymLinkTarget, m_topLevel));
}
- rc.append(m_settings.commonP4Arguments());
+ rc.append(commonP4Arguments());
return rc;
}
@@ -266,5 +225,71 @@ QString PerforceSettings::mapToFileSystem(const QString &perforceFilePath) const
return mapPathRoot(perforceFilePath, m_topLevel, m_topLevelSymLinkTarget);
}
+// SettingsPage
+
+PerforceSettingsPage::PerforceSettingsPage(PerforceSettings *settings)
+{
+ setId(VcsBase::Constants::VCS_ID_PERFORCE);
+ setDisplayName(PerforceSettings::tr("Perforce"));
+ setCategory(VcsBase::Constants::VCS_SETTINGS_CATEGORY);
+ setSettings(settings);
+
+ setLayouter([settings, this](QWidget *widget) {
+ PerforceSettings &s = *settings;
+ using namespace Layouting;
+
+ auto errorLabel = new QLabel;
+ auto testButton = new QPushButton(PerforceSettings::tr("Test"));
+ connect(testButton, &QPushButton::clicked, this, [this, settings, errorLabel, testButton] {
+ testButton->setEnabled(false);
+ auto checker = new PerforceChecker(errorLabel);
+ checker->setUseOverideCursor(true);
+ connect(checker, &PerforceChecker::failed, errorLabel,
+ [errorLabel, testButton, checker](const QString &t) {
+ errorLabel->setStyleSheet("background-color: red");
+ errorLabel->setText(t);
+ testButton->setEnabled(true);
+ checker->deleteLater();
+ });
+ connect(checker, &PerforceChecker::succeeded, errorLabel,
+ [errorLabel, testButton, checker](const QString &repo) {
+ errorLabel->setStyleSheet({});
+ errorLabel->setText(tr("Test succeeded (%1).").arg(QDir::toNativeSeparators(repo)));
+ testButton->setEnabled(true);
+ checker->deleteLater();
+ });
+
+ errorLabel->setStyleSheet(QString());
+ errorLabel->setText(PerforceSettings::tr("Testing..."));
+ checker->start(settings->p4BinaryPath.value(), QString(), settings->commonP4Arguments(), 10000);
+ });
+
+ Group config {
+ Title(PerforceSettings::tr("Configuration")),
+ Row { s.p4BinaryPath }
+ };
+
+ Group environment {
+ Title(PerforceSettings::tr("Environment Variables"), &s.customEnv),
+ Row { s.p4Port, s.p4Client, s.p4User }
+ };
+
+ Group misc {
+ Title(PerforceSettings::tr("Miscellaneous")),
+ Row { s.logCount, s.timeOutS, Stretch() },
+ s.promptToSubmit,
+ s.autoOpen
+ };
+
+ Column {
+ config,
+ environment,
+ misc,
+ Row { errorLabel, Stretch(), testButton },
+ Stretch()
+ }.attachTo(widget);
+ });
+}
+
} // Internal
} // Perforce
diff --git a/src/plugins/perforce/perforcesettings.h b/src/plugins/perforce/perforcesettings.h
index e782c14c2f..802d0c3fd7 100644
--- a/src/plugins/perforce/perforcesettings.h
+++ b/src/plugins/perforce/perforcesettings.h
@@ -25,44 +25,18 @@
#pragma once
-#include <QString>
+#include <coreplugin/dialogs/ioptionspage.h>
+
+#include <utils/aspects.h>
QT_BEGIN_NAMESPACE
-class QSettings;
class QDir;
QT_END_NAMESPACE
namespace Perforce {
namespace Internal {
-struct Settings {
- Settings();
- bool equals(const Settings &s) const;
- QStringList commonP4Arguments() const;
-
- // Checks. On success, errorMessage will contains the client root.
- bool check(QString *repositoryRoot /* = 0*/, QString *errorMessage) const;
- static bool doCheck(const QString &binary, const QStringList &basicArgs,
- QString *repositoryRoot /* = 0 */,
- QString *errorMessage);
-
- QString p4Command;
- QString p4BinaryPath;
- QString p4Port;
- QString p4Client;
- QString p4User;
- QString errorString;
- int logCount;
- bool defaultEnv = true;
- int timeOutS;
- bool promptToSubmit = true;
- bool autoOpen = true;
-};
-
-inline bool operator==(const Settings &s1, const Settings &s2) { return s1.equals(s2); }
-inline bool operator!=(const Settings &s1, const Settings &s2) { return !s1.equals(s2); }
-
-/* PerforceSettings: Aggregates settings struct and toplevel directory
+/* PerforceSettings: Aggregates settings items and toplevel directory
* which is determined externally by background checks and provides a convenience
* for determining the common arguments.
* Those must contain (apart from server connection settings) the working directory
@@ -76,29 +50,24 @@ inline bool operator!=(const Settings &s1, const Settings &s2) { return !s1.equa
* p4. This is why the client root portion of working directory must be mapped for the
* "-d" option, so that running p4 in "/depot/dev/foo" results in "-d $HOME/dev/foo". */
-class PerforceSettings
+class PerforceSettings : public Utils::AspectContainer
{
+ Q_DECLARE_TR_FUNCTIONS(Perforce::Internal::SettingsPage)
+
public:
- PerforceSettings() = default;
+ PerforceSettings();
~PerforceSettings();
- PerforceSettings(const PerforceSettings &other) = delete;
-
- inline bool isValid() const
- {
- return !m_topLevel.isEmpty() && !m_settings.p4BinaryPath.isEmpty();
- }
- void fromSettings(QSettings *settings);
- void toSettings(QSettings *) const;
+ bool isValid() const;
- void setSettings(const Settings &s);
- Settings settings() const;
-
- inline int timeOutS() const { return m_settings.timeOutS; }
- inline int longTimeOutS() const { return m_settings.timeOutS * 10; }
- inline int timeOutMS() const { return m_settings.timeOutS * 1000; }
+ // Checks. On success, errorMessage will contains the client root.
+ bool check(QString *repositoryRoot /* = 0*/, QString *errorMessage) const;
+ static bool doCheck(const QString &binary, const QStringList &basicArgs,
+ QString *repositoryRoot /* = 0 */,
+ QString *errorMessage);
- inline int logCount() const { return m_settings.logCount; }
+ int longTimeOutS() const { return timeOutS.value() * 10; }
+ int timeOutMS() const { return timeOutS.value() * 1000; }
QString topLevel() const;
QString topLevelSymLinkTarget() const;
@@ -115,29 +84,36 @@ public:
// Map p4 path back to file system in case of a symlinked top-level
QString mapToFileSystem(const QString &perforceFilePath) const;
- QString p4Command() const;
- QString p4BinaryPath() const;
- QString p4Port() const;
- QString p4Client() const;
- QString p4User() const;
bool defaultEnv() const;
- bool promptToSubmit() const;
- void setPromptToSubmit(bool p);
- bool autoOpen() const;
- void setAutoOpen(bool p);
// Return basic arguments, including -d and server connection parameters.
+ QStringList commonP4Arguments() const;
QStringList commonP4Arguments(const QString &workingDir) const;
-private:
- inline QStringList workingDirectoryArguments(const QString &workingDir) const;
void clearTopLevel();
- Settings m_settings;
+ Utils::StringAspect p4BinaryPath;
+ Utils::StringAspect p4Port;
+ Utils::StringAspect p4Client;
+ Utils::StringAspect p4User;
+ Utils::IntegerAspect logCount;
+ Utils::BoolAspect customEnv;
+ Utils::IntegerAspect timeOutS;
+ Utils::BoolAspect promptToSubmit;
+ Utils::BoolAspect autoOpen;
+
+private:
+ QStringList workingDirectoryArguments(const QString &workingDir) const;
QString m_topLevel;
QString m_topLevelSymLinkTarget;
QDir *m_topLevelDir = nullptr;
};
+class PerforceSettingsPage final : public Core::IOptionsPage
+{
+public:
+ explicit PerforceSettingsPage(PerforceSettings *settings);
+};
+
} // namespace Internal
} // namespace Perforce
diff --git a/src/plugins/perforce/settingspage.cpp b/src/plugins/perforce/settingspage.cpp
deleted file mode 100644
index 17db635270..0000000000
--- a/src/plugins/perforce/settingspage.cpp
+++ /dev/null
@@ -1,158 +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 "settingspage.h"
-#include "perforcesettings.h"
-#include "perforceplugin.h"
-#include "perforcechecker.h"
-
-#include <vcsbase/vcsbaseconstants.h>
-
-#include <QApplication>
-#include <QLineEdit>
-#include <QFileDialog>
-#include <QTextStream>
-
-using namespace Utils;
-
-namespace Perforce {
-namespace Internal {
-
-class SettingsPageWidget final : public Core::IOptionsPageWidget
-{
- Q_DECLARE_TR_FUNCTIONS(Perforce::Internal::SettingsPage)
-
-public:
- SettingsPageWidget(PerforceSettings *settings, const std::function<void()> &onApply);
- ~SettingsPageWidget() final;
-
-private:
- void apply() final;
-
- Settings settings() const;
-
- void slotTest();
- void setStatusText(const QString &);
- void setStatusError(const QString &);
- void testSucceeded(const QString &repo);
-
- Ui::SettingsPage m_ui;
- PerforceChecker *m_checker = nullptr;
- PerforceSettings *m_settings = nullptr;
- std::function<void()> m_onApply;
-};
-
-SettingsPageWidget::SettingsPageWidget(PerforceSettings *settings, const std::function<void()> &onApply)
- : m_settings(settings), m_onApply(onApply)
-{
- m_ui.setupUi(this);
- m_ui.errorLabel->clear();
- m_ui.pathChooser->setPromptDialogTitle(tr("Perforce Command"));
- m_ui.pathChooser->setHistoryCompleter(QLatin1String("Perforce.Command.History"));
- m_ui.pathChooser->setExpectedKind(PathChooser::Command);
- connect(m_ui.testPushButton, &QPushButton::clicked, this, &SettingsPageWidget::slotTest);
-
- const PerforceSettings &s = *settings;
- m_ui.pathChooser->setPath(s.p4Command());
- m_ui.environmentGroupBox->setChecked(!s.defaultEnv());
- m_ui.portLineEdit->setText(s.p4Port());
- m_ui.clientLineEdit->setText(s.p4Client());
- m_ui.userLineEdit->setText(s.p4User());
- m_ui.logCountSpinBox->setValue(s.logCount());
- m_ui.timeOutSpinBox->setValue(s.timeOutS());
- m_ui.promptToSubmitCheckBox->setChecked(s.promptToSubmit());
- m_ui.autoOpenCheckBox->setChecked(s.autoOpen());
-}
-
-SettingsPageWidget::~SettingsPageWidget()
-{
- delete m_checker;
-}
-
-void SettingsPageWidget::slotTest()
-{
- if (!m_checker) {
- m_checker = new PerforceChecker(this);
- m_checker->setUseOverideCursor(true);
- connect(m_checker, &PerforceChecker::failed, this, &SettingsPageWidget::setStatusError);
- connect(m_checker, &PerforceChecker::succeeded, this, &SettingsPageWidget::testSucceeded);
- }
-
- if (m_checker->isRunning())
- return;
-
- setStatusText(tr("Testing..."));
- const Settings s = m_settings->settings();
- m_checker->start(s.p4BinaryPath, QString(), s.commonP4Arguments(), 10000);
-}
-
-void SettingsPageWidget::testSucceeded(const QString &repo)
-{
- setStatusText(tr("Test succeeded (%1).").arg(QDir::toNativeSeparators(repo)));
-}
-
-void SettingsPageWidget::apply()
-{
- Settings settings;
- settings.p4Command = m_ui.pathChooser->rawPath();
- settings.p4BinaryPath = m_ui.pathChooser->path();
- settings.defaultEnv = !m_ui.environmentGroupBox->isChecked();
- settings.p4Port = m_ui.portLineEdit->text();
- settings.p4User = m_ui.userLineEdit->text();
- settings.p4Client= m_ui.clientLineEdit->text();
- settings.timeOutS = m_ui.timeOutSpinBox->value();
- settings.logCount = m_ui.logCountSpinBox->value();
- settings.promptToSubmit = m_ui.promptToSubmitCheckBox->isChecked();
- settings.autoOpen = m_ui.autoOpenCheckBox->isChecked();
-
- if (settings == m_settings->settings())
- return;
-
- m_settings->setSettings(settings);
- m_onApply();
-}
-
-void SettingsPageWidget::setStatusText(const QString &t)
-{
- m_ui.errorLabel->setStyleSheet(QString());
- m_ui.errorLabel->setText(t);
-}
-
-void SettingsPageWidget::setStatusError(const QString &t)
-{
- m_ui.errorLabel->setStyleSheet(QLatin1String("background-color: red"));
- m_ui.errorLabel->setText(t);
-}
-
-SettingsPage::SettingsPage(PerforceSettings *settings, const std::function<void ()> &onApply)
-{
- setId(VcsBase::Constants::VCS_ID_PERFORCE);
- setDisplayName(SettingsPageWidget::tr("Perforce"));
- setCategory(VcsBase::Constants::VCS_SETTINGS_CATEGORY);
- setWidgetCreator([settings, onApply] { return new SettingsPageWidget(settings, onApply); });
-}
-
-} // Internal
-} // Perforce
diff --git a/src/plugins/perforce/settingspage.ui b/src/plugins/perforce/settingspage.ui
deleted file mode 100644
index dafda71008..0000000000
--- a/src/plugins/perforce/settingspage.ui
+++ /dev/null
@@ -1,228 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<ui version="4.0">
- <class>Perforce::Internal::SettingsPage</class>
- <widget class="QWidget" name="Perforce::Internal::SettingsPage">
- <property name="geometry">
- <rect>
- <x>0</x>
- <y>0</y>
- <width>595</width>
- <height>366</height>
- </rect>
- </property>
- <layout class="QVBoxLayout" name="verticalLayout">
- <item>
- <widget class="QGroupBox" name="configGroupBox">
- <property name="title">
- <string>Configuration</string>
- </property>
- <layout class="QHBoxLayout" name="horizontalLayout_5">
- <item>
- <widget class="QLabel" name="commandLabel">
- <property name="text">
- <string>P4 command:</string>
- </property>
- </widget>
- </item>
- <item>
- <widget class="Utils::PathChooser" name="pathChooser" native="true"/>
- </item>
- </layout>
- </widget>
- </item>
- <item>
- <widget class="QGroupBox" name="environmentGroupBox">
- <property name="enabled">
- <bool>true</bool>
- </property>
- <property name="title">
- <string>Environment Variables</string>
- </property>
- <property name="checkable">
- <bool>true</bool>
- </property>
- <property name="checked">
- <bool>false</bool>
- </property>
- <layout class="QGridLayout" name="gridLayout">
- <item row="0" column="0">
- <widget class="QLabel" name="portLabel">
- <property name="text">
- <string>P4 port:</string>
- </property>
- </widget>
- </item>
- <item row="0" column="1">
- <widget class="QLineEdit" name="portLineEdit"/>
- </item>
- <item row="0" column="2">
- <widget class="QLabel" name="clientLabel">
- <property name="text">
- <string>P4 client:</string>
- </property>
- </widget>
- </item>
- <item row="0" column="3">
- <widget class="QLineEdit" name="clientLineEdit"/>
- </item>
- <item row="0" column="4">
- <widget class="QLabel" name="userLabel">
- <property name="text">
- <string>P4 user:</string>
- </property>
- </widget>
- </item>
- <item row="0" column="5">
- <widget class="QLineEdit" name="userLineEdit"/>
- </item>
- </layout>
- </widget>
- </item>
- <item>
- <widget class="QGroupBox" name="miscGroupBox">
- <property name="title">
- <string>Miscellaneous</string>
- </property>
- <layout class="QGridLayout" name="gridLayout_2">
- <item row="0" column="0">
- <widget class="QLabel" name="logCountLabel">
- <property name="text">
- <string>Log count:</string>
- </property>
- </widget>
- </item>
- <item row="0" column="1">
- <widget class="QSpinBox" name="logCountSpinBox">
- <property name="maximum">
- <number>10000</number>
- </property>
- <property name="value">
- <number>1000</number>
- </property>
- </widget>
- </item>
- <item row="0" column="2">
- <widget class="QLabel" name="timeOutLabel">
- <property name="text">
- <string>Timeout:</string>
- </property>
- </widget>
- </item>
- <item row="0" column="3">
- <widget class="QSpinBox" name="timeOutSpinBox">
- <property name="suffix">
- <string>s</string>
- </property>
- <property name="minimum">
- <number>1</number>
- </property>
- <property name="maximum">
- <number>360</number>
- </property>
- <property name="value">
- <number>30</number>
- </property>
- </widget>
- </item>
- <item row="0" column="4">
- <spacer name="horizontalSpacer_2">
- <property name="orientation">
- <enum>Qt::Horizontal</enum>
- </property>
- <property name="sizeHint" stdset="0">
- <size>
- <width>396</width>
- <height>22</height>
- </size>
- </property>
- </spacer>
- </item>
- <item row="1" column="0" colspan="2">
- <widget class="QCheckBox" name="promptToSubmitCheckBox">
- <property name="text">
- <string>Prompt on submit</string>
- </property>
- </widget>
- </item>
- <item row="2" column="0" colspan="4">
- <widget class="QCheckBox" name="autoOpenCheckBox">
- <property name="text">
- <string>Automatically open files when editing</string>
- </property>
- </widget>
- </item>
- </layout>
- </widget>
- </item>
- <item>
- <layout class="QHBoxLayout" name="horizontalLayout">
- <item>
- <widget class="QLabel" name="errorLabel">
- <property name="text">
- <string notr="true" extracomment="Placeholder">errorLabel: blah blubb</string>
- </property>
- </widget>
- </item>
- <item>
- <spacer name="horizontalSpacer">
- <property name="orientation">
- <enum>Qt::Horizontal</enum>
- </property>
- <property name="sizeHint" stdset="0">
- <size>
- <width>40</width>
- <height>20</height>
- </size>
- </property>
- </spacer>
- </item>
- <item>
- <widget class="QPushButton" name="testPushButton">
- <property name="text">
- <string>Test</string>
- </property>
- </widget>
- </item>
- </layout>
- </item>
- <item>
- <spacer name="verticalSpacer">
- <property name="orientation">
- <enum>Qt::Vertical</enum>
- </property>
- <property name="sizeHint" stdset="0">
- <size>
- <width>20</width>
- <height>40</height>
- </size>
- </property>
- </spacer>
- </item>
- </layout>
- </widget>
- <customwidgets>
- <customwidget>
- <class>Utils::PathChooser</class>
- <extends>QWidget</extends>
- <header location="global">utils/pathchooser.h</header>
- <container>1</container>
- <slots>
- <signal>editingFinished()</signal>
- <signal>browsingFinished()</signal>
- </slots>
- </customwidget>
- </customwidgets>
- <tabstops>
- <tabstop>environmentGroupBox</tabstop>
- <tabstop>portLineEdit</tabstop>
- <tabstop>clientLineEdit</tabstop>
- <tabstop>userLineEdit</tabstop>
- <tabstop>logCountSpinBox</tabstop>
- <tabstop>timeOutSpinBox</tabstop>
- <tabstop>promptToSubmitCheckBox</tabstop>
- <tabstop>autoOpenCheckBox</tabstop>
- <tabstop>testPushButton</tabstop>
- </tabstops>
- <resources/>
- <connections/>
-</ui>
diff --git a/src/plugins/perfprofiler/CMakeLists.txt b/src/plugins/perfprofiler/CMakeLists.txt
index 97f82871f0..b7644fb3fc 100644
--- a/src/plugins/perfprofiler/CMakeLists.txt
+++ b/src/plugins/perfprofiler/CMakeLists.txt
@@ -5,7 +5,6 @@ add_qtc_plugin(PerfProfiler
SOURCES
perfconfigeventsmodel.cpp perfconfigeventsmodel.h
perfconfigwidget.cpp perfconfigwidget.h
- perfconfigwidget.ui
perfdatareader.cpp perfdatareader.h
perfevent.h
perfeventtype.h
diff --git a/src/plugins/perfprofiler/perfconfigeventsmodel.cpp b/src/plugins/perfprofiler/perfconfigeventsmodel.cpp
index 744885f3de..9b5763c228 100644
--- a/src/plugins/perfprofiler/perfconfigeventsmodel.cpp
+++ b/src/plugins/perfprofiler/perfconfigeventsmodel.cpp
@@ -40,7 +40,7 @@ PerfConfigEventsModel::PerfConfigEventsModel(PerfSettings *settings, QObject *pa
int PerfConfigEventsModel::rowCount(const QModelIndex &parent) const
{
- return parent.isValid() ? 0 : m_settings->events().length();
+ return parent.isValid() ? 0 : m_settings->events.value().length();
}
int PerfConfigEventsModel::columnCount(const QModelIndex &parent) const
@@ -58,7 +58,7 @@ QVariant PerfConfigEventsModel::data(const QModelIndex &index, int role) const
return QVariant(); // ignore
}
- QString event = m_settings->events().value(index.row());
+ QString event = m_settings->events.value().value(index.row());
const EventDescription description = parseEvent(event);
switch (index.column()) {
case ColumnEventType: {
@@ -142,7 +142,7 @@ bool PerfConfigEventsModel::setData(const QModelIndex &dataIndex, const QVariant
const int row = dataIndex.row();
const int column = dataIndex.column();
- QStringList events = m_settings->events();
+ QStringList events = m_settings->events.value();
EventDescription description = parseEvent(events[row]);
switch (column) {
case ColumnEventType:
@@ -176,7 +176,7 @@ bool PerfConfigEventsModel::setData(const QModelIndex &dataIndex, const QVariant
break;
}
events[row] = generateEvent(description);
- m_settings->setEvents(events);
+ m_settings->events.setValue(events);
emit dataChanged(index(row, ColumnEventType), index(row, ColumnResult));
return true;
}
@@ -201,11 +201,11 @@ bool PerfConfigEventsModel::insertRows(int row, int count, const QModelIndex &pa
if (parent.isValid())
return false;
- QStringList events = m_settings->events();
+ QStringList events = m_settings->events.value();
for (int i = 0; i < count; ++i)
events.insert(row, "dummy");
beginInsertRows(parent, row, row + count - 1);
- m_settings->setEvents(events);
+ m_settings->events.setValue(events);
endInsertRows();
return true;
}
@@ -215,17 +215,17 @@ bool PerfConfigEventsModel::removeRows(int row, int count, const QModelIndex &pa
if (parent.isValid())
return false;
- QStringList events = m_settings->events();
+ QStringList events = m_settings->events.value();
for (int i = 0; i < count; ++i)
events.removeAt(row);
beginRemoveRows(parent, row, row + count - 1);
- m_settings->setEvents(events);
+ m_settings->events.setValue(events);
endRemoveRows();
if (events.isEmpty()) {
beginInsertRows(parent, 0, 0);
events.append("dummy");
- m_settings->setEvents(events);
+ m_settings->events.setValue(events);
endInsertRows();
}
diff --git a/src/plugins/perfprofiler/perfconfigwidget.cpp b/src/plugins/perfprofiler/perfconfigwidget.cpp
index 273194de06..9381f1e147 100644
--- a/src/plugins/perfprofiler/perfconfigwidget.cpp
+++ b/src/plugins/perfprofiler/perfconfigwidget.cpp
@@ -26,7 +26,6 @@
#include "perfconfigeventsmodel.h"
#include "perfconfigwidget.h"
#include "perfprofilerconstants.h"
-#include "ui_perfconfigwidget.h"
#include <coreplugin/messagebox.h>
@@ -36,11 +35,17 @@
#include <projectexplorer/runcontrol.h>
#include <projectexplorer/target.h>
+#include <utils/aspects.h>
+#include <utils/layoutbuilder.h>
#include <utils/qtcprocess.h>
+#include <QComboBox>
+#include <QHeaderView>
+#include <QMessageBox>
#include <QMetaEnum>
#include <QStyledItemDelegate>
-#include <QMessageBox>
+
+using namespace Utils;
namespace PerfProfiler {
namespace Internal {
@@ -63,85 +68,60 @@ public:
};
PerfConfigWidget::PerfConfigWidget(PerfSettings *settings, QWidget *parent)
- : m_settings(settings), m_ui(new Ui::PerfConfigWidget)
+ : m_settings(settings)
{
setParent(parent);
- m_ui->setupUi(this);
- m_ui->useTracePointsButton->setVisible(false);
-
- m_ui->callgraphMode->addItem(tr("dwarf"), QLatin1String(Constants::PerfCallgraphDwarf));
- m_ui->callgraphMode->addItem(tr("frame pointer"), QLatin1String(Constants::PerfCallgraphFP));
- m_ui->callgraphMode->addItem(tr("last branch record"),
- QLatin1String(Constants::PerfCallgraphLBR));
-
- m_ui->sampleMode->addItem(tr("frequency (Hz)"), QLatin1String(Constants::PerfSampleFrequency));
- m_ui->sampleMode->addItem(tr("event count"), QLatin1String(Constants::PerfSampleCount));
-
- auto comboboxChangedSignal = QOverload<int>::of(&QComboBox::currentIndexChanged);
- connect(m_ui->callgraphMode, comboboxChangedSignal, this, [this](int index) {
- QString mode = m_ui->callgraphMode->itemData(index).toString();
- m_settings->setCallgraphMode(mode);
- m_ui->stackSize->setEnabled(mode == QLatin1String(Constants::PerfCallgraphDwarf));
- });
-
- auto spinBoxChangedSignal = QOverload<int>::of(&QSpinBox::valueChanged);
- connect(m_ui->stackSize, spinBoxChangedSignal, m_settings, &PerfSettings::setStackSize);
- connect(m_ui->period, spinBoxChangedSignal, m_settings, &PerfSettings::setPeriod);
- connect(m_ui->sampleMode, comboboxChangedSignal, this, [this](int index) {
- QString sampleMode = m_ui->sampleMode->itemData(index).toString();
- m_settings->setSampleMode(sampleMode);
- });
- connect(m_ui->extraArguments, &QLineEdit::textEdited, this, [this](const QString &text) {
- m_settings->setExtraArguments(Utils::QtcProcess::splitArgs(text));
- });
+ eventsView = new QTableView(this);
+ eventsView->setMinimumSize(QSize(0, 300));
+ eventsView->setEditTriggers(QAbstractItemView::AllEditTriggers);
+ eventsView->setSelectionMode(QAbstractItemView::SingleSelection);
+ eventsView->setSelectionBehavior(QAbstractItemView::SelectRows);
+ eventsView->setModel(new PerfConfigEventsModel(m_settings, this));
+ eventsView->setItemDelegate(new SettingsDelegate(this));
+ eventsView->horizontalHeader()->setSectionResizeMode(QHeaderView::Stretch);
+
+ useTracePointsButton = new QPushButton(this);
+ useTracePointsButton->setText(tr("Use Trace Points"));
+ useTracePointsButton->setVisible(false);
+ connect(useTracePointsButton, &QPushButton::pressed,
+ this, &PerfConfigWidget::readTracePoints);
- m_ui->eventsView->setModel(new PerfConfigEventsModel(m_settings, this));
- m_ui->eventsView->setItemDelegate(new SettingsDelegate(this));
- m_ui->eventsView->horizontalHeader()->setSectionResizeMode(QHeaderView::Stretch);
- connect(m_ui->addEventButton, &QPushButton::pressed, this, [this]() {
- auto model = m_ui->eventsView->model();
+ addEventButton = new QPushButton(this);
+ addEventButton->setText(tr("Add Event"));
+ connect(addEventButton, &QPushButton::pressed, this, [this]() {
+ auto model = eventsView->model();
model->insertRow(model->rowCount());
});
- connect(m_ui->removeEventButton, &QPushButton::pressed, this, [this]() {
- QModelIndex index = m_ui->eventsView->currentIndex();
+
+ removeEventButton = new QPushButton(this);
+ removeEventButton->setText(tr("Remove Event"));
+ connect(removeEventButton, &QPushButton::pressed, this, [this]() {
+ QModelIndex index = eventsView->currentIndex();
if (index.isValid())
- m_ui->eventsView->model()->removeRow(index.row());
+ eventsView->model()->removeRow(index.row());
});
- connect(m_settings, &PerfSettings::changed, this, &PerfConfigWidget::updateUi);
- connect(m_ui->useTracePointsButton, &QPushButton::pressed,
- this, &PerfConfigWidget::readTracePoints);
- connect(m_ui->resetButton, &QPushButton::pressed, m_settings, &PerfSettings::resetToDefault);
- updateUi();
-}
+ resetButton = new QPushButton(this);
+ resetButton->setText(tr("Reset"));
+ connect(resetButton, &QPushButton::pressed, m_settings, &PerfSettings::resetToDefault);
-PerfConfigWidget::~PerfConfigWidget()
-{
- delete m_ui;
-}
+ using namespace Layouting;
+ const Break nl;
-void PerfConfigWidget::updateUi()
-{
- for (int index = 0, end = m_ui->callgraphMode->count(); index != end; ++index) {
- if (m_ui->callgraphMode->itemData(index) == m_settings->callgraphMode()) {
- m_ui->callgraphMode->setCurrentIndex(index);
- break;
- }
- }
+ Column {
+ Row { Stretch(), useTracePointsButton, addEventButton, removeEventButton, resetButton },
- for (int index = 0, end = m_ui->sampleMode->count(); index != end; ++index) {
- if (m_ui->sampleMode->itemData(index) == m_settings->sampleMode()) {
- m_ui->sampleMode->setCurrentIndex(index);
- break;
- }
- }
+ eventsView,
+
+ Grid {
+ m_settings->callgraphMode, m_settings->stackSize, nl,
+ m_settings->sampleMode, m_settings->period, nl,
+ m_settings->extraArguments,
+ },
- m_ui->stackSize->setEnabled(m_settings->callgraphMode()
- == QLatin1String(Constants::PerfCallgraphDwarf));
- m_ui->stackSize->setValue(m_settings->stackSize());
- m_ui->period->setValue(m_settings->period());
- m_ui->extraArguments->setText(m_settings->extraArguments().join(QLatin1Char(' ')));
+ Stretch()
+ }.attachTo(this);
}
void PerfConfigWidget::setTarget(ProjectExplorer::Target *target)
@@ -153,7 +133,7 @@ void PerfConfigWidget::setTarget(ProjectExplorer::Target *target)
}
if (device.isNull()) {
- m_ui->useTracePointsButton->setEnabled(false);
+ useTracePointsButton->setEnabled(false);
return;
}
@@ -162,7 +142,7 @@ void PerfConfigWidget::setTarget(ProjectExplorer::Target *target)
m_process.reset(device->createProcess(nullptr));
if (!m_process) {
- m_ui->useTracePointsButton->setEnabled(false);
+ useTracePointsButton->setEnabled(false);
return;
}
@@ -172,12 +152,12 @@ void PerfConfigWidget::setTarget(ProjectExplorer::Target *target)
connect(m_process.get(), &ProjectExplorer::DeviceProcess::error,
this, &PerfConfigWidget::handleProcessError);
- m_ui->useTracePointsButton->setEnabled(true);
+ useTracePointsButton->setEnabled(true);
}
void PerfConfigWidget::setTracePointsButtonVisible(bool visible)
{
- m_ui->useTracePointsButton->setVisible(visible);
+ useTracePointsButton->setVisible(visible);
}
void PerfConfigWidget::apply()
@@ -198,7 +178,7 @@ void PerfConfigWidget::readTracePoints()
runnable.commandLineArguments = QLatin1String("probe -l");
m_process->start(runnable);
- m_ui->useTracePointsButton->setEnabled(false);
+ useTracePointsButton->setEnabled(false);
}
}
@@ -207,7 +187,7 @@ void PerfConfigWidget::handleProcessFinished()
const QList<QByteArray> lines =
m_process->readAllStandardOutput().append(m_process->readAllStandardError())
.split('\n');
- auto model = m_ui->eventsView->model();
+ auto model = eventsView->model();
const int previousRows = model->rowCount();
QHash<QByteArray, QByteArray> tracePoints;
for (const QByteArray &line : lines) {
@@ -234,10 +214,10 @@ void PerfConfigWidget::handleProcessFinished()
QString::fromUtf8(event));
}
model->removeRows(0, previousRows);
- m_ui->sampleMode->setCurrentText(tr("event count"));
- m_ui->period->setValue(1);
+ m_settings->sampleMode.setVolatileValue(1);
+ m_settings->period.setVolatileValue(1);
}
- m_ui->useTracePointsButton->setEnabled(true);
+ useTracePointsButton->setEnabled(true);
}
void PerfConfigWidget::handleProcessError(QProcess::ProcessError error)
@@ -246,7 +226,7 @@ void PerfConfigWidget::handleProcessError(QProcess::ProcessError error)
Core::AsynchronousMessageBox::warning(
tr("Cannot List Trace Points"),
tr("\"perf probe -l\" failed to start. Is perf installed?"));
- m_ui->useTracePointsButton->setEnabled(true);
+ useTracePointsButton->setEnabled(true);
}
}
diff --git a/src/plugins/perfprofiler/perfconfigwidget.h b/src/plugins/perfprofiler/perfconfigwidget.h
index 4ff5064db9..bb4795a791 100644
--- a/src/plugins/perfprofiler/perfconfigwidget.h
+++ b/src/plugins/perfprofiler/perfconfigwidget.h
@@ -29,17 +29,19 @@
#include <coreplugin/dialogs/ioptionspage.h>
+#include <projectexplorer/devicesupport/deviceprocess.h>
+
+#include <QPushButton>
+#include <QTableView>
+
namespace PerfProfiler {
namespace Internal {
-namespace Ui { class PerfConfigWidget; }
-
class PerfConfigWidget : public Core::IOptionsPageWidget
{
Q_OBJECT
public:
explicit PerfConfigWidget(PerfSettings *settings, QWidget *parent = nullptr);
- ~PerfConfigWidget();
void updateUi();
void setTarget(ProjectExplorer::Target *target);
@@ -53,8 +55,13 @@ private:
void handleProcessError(QProcess::ProcessError error);
PerfSettings *m_settings;
- Ui::PerfConfigWidget *m_ui;
std::unique_ptr<ProjectExplorer::DeviceProcess> m_process;
+
+ QTableView *eventsView;
+ QPushButton *useTracePointsButton;
+ QPushButton *addEventButton;
+ QPushButton *removeEventButton;
+ QPushButton *resetButton;
};
} // namespace Internal
diff --git a/src/plugins/perfprofiler/perfconfigwidget.ui b/src/plugins/perfprofiler/perfconfigwidget.ui
deleted file mode 100644
index 8db310714c..0000000000
--- a/src/plugins/perfprofiler/perfconfigwidget.ui
+++ /dev/null
@@ -1,135 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<ui version="4.0">
- <class>PerfProfiler::Internal::PerfConfigWidget</class>
- <widget class="QWidget" name="PerfProfiler::Internal::PerfConfigWidget">
- <property name="geometry">
- <rect>
- <x>0</x>
- <y>0</y>
- <width>560</width>
- <height>500</height>
- </rect>
- </property>
- <layout class="QGridLayout" name="gridLayout">
- <item row="4" column="1">
- <widget class="QComboBox" name="sampleMode"/>
- </item>
- <item row="3" column="3">
- <widget class="QSpinBox" name="stackSize">
- <property name="maximum">
- <number>65536</number>
- </property>
- <property name="value">
- <number>4096</number>
- </property>
- </widget>
- </item>
- <item row="3" column="2">
- <widget class="QLabel" name="stackSizeLabel">
- <property name="text">
- <string>Stack snapshot size (kB):</string>
- </property>
- </widget>
- </item>
- <item row="4" column="0">
- <widget class="QLabel" name="sampleModeLabel">
- <property name="text">
- <string>Sample mode:</string>
- </property>
- </widget>
- </item>
- <item row="4" column="2">
- <widget class="QLabel" name="periodLabel">
- <property name="text">
- <string>Sample period:</string>
- </property>
- </widget>
- </item>
- <item row="3" column="0">
- <widget class="QLabel" name="callgraphLabel">
- <property name="text">
- <string>Call graph mode:</string>
- </property>
- </widget>
- </item>
- <item row="5" column="1" colspan="3">
- <widget class="QLineEdit" name="extraArguments"/>
- </item>
- <item row="3" column="1">
- <widget class="QComboBox" name="callgraphMode">
- <property name="sizePolicy">
- <sizepolicy hsizetype="Minimum" vsizetype="Fixed">
- <horstretch>0</horstretch>
- <verstretch>0</verstretch>
- </sizepolicy>
- </property>
- </widget>
- </item>
- <item row="5" column="0">
- <widget class="QLabel" name="extraArgumentsLabel">
- <property name="text">
- <string>Additional arguments:</string>
- </property>
- </widget>
- </item>
- <item row="4" column="3">
- <widget class="QSpinBox" name="period">
- <property name="maximum">
- <number>2147483647</number>
- </property>
- <property name="value">
- <number>250</number>
- </property>
- </widget>
- </item>
- <item row="2" column="0" colspan="4">
- <widget class="QTableView" name="eventsView">
- <property name="minimumSize">
- <size>
- <height>300</height>
- </size>
- </property>
- <property name="editTriggers">
- <set>QAbstractItemView::AllEditTriggers</set>
- </property>
- <property name="selectionMode">
- <enum>QAbstractItemView::SingleSelection</enum>
- </property>
- <property name="selectionBehavior">
- <enum>QAbstractItemView::SelectRows</enum>
- </property>
- </widget>
- </item>
- <item row="1" column="0">
- <widget class="QPushButton" name="useTracePointsButton">
- <property name="text">
- <string>Use Trace Points</string>
- </property>
- </widget>
- </item>
- <item row="1" column="1">
- <widget class="QPushButton" name="addEventButton">
- <property name="text">
- <string>Add Event</string>
- </property>
- </widget>
- </item>
- <item row="1" column="2">
- <widget class="QPushButton" name="removeEventButton">
- <property name="text">
- <string>Remove Event</string>
- </property>
- </widget>
- </item>
- <item row="1" column="3">
- <widget class="QPushButton" name="resetButton">
- <property name="text">
- <string>Reset</string>
- </property>
- </widget>
- </item>
- </layout>
- </widget>
- <resources/>
- <connections/>
-</ui>
diff --git a/src/plugins/perfprofiler/perfdatareader.cpp b/src/plugins/perfprofiler/perfdatareader.cpp
index f9f32a7df3..80d4734f6d 100644
--- a/src/plugins/perfprofiler/perfdatareader.cpp
+++ b/src/plugins/perfprofiler/perfdatareader.cpp
@@ -405,10 +405,8 @@ QStringList PerfDataReader::findTargetArguments(const ProjectExplorer::RunContro
QString PerfDataReader::findPerfParser()
{
QString filePath = QString::fromLocal8Bit(qgetenv("PERFPROFILER_PARSER_FILEPATH"));
- if (filePath.isEmpty()) {
- filePath = QString::fromLatin1("%1/perfparser%2").arg(Core::ICore::libexecPath(),
- QString(QTC_HOST_EXE_SUFFIX));
- }
+ if (filePath.isEmpty())
+ filePath = Core::ICore::libexecPath("perfparser" QTC_HOST_EXE_SUFFIX).toString();
return QDir::toNativeSeparators(QDir::cleanPath(filePath));
}
diff --git a/src/plugins/perfprofiler/perfprofiler.pro b/src/plugins/perfprofiler/perfprofiler.pro
index 9e076ec4c0..c7c22022f9 100644
--- a/src/plugins/perfprofiler/perfprofiler.pro
+++ b/src/plugins/perfprofiler/perfprofiler.pro
@@ -69,7 +69,6 @@ OTHER_FILES += \
PerfProfiler.json.in
FORMS += \
- perfconfigwidget.ui \
perfloaddialog.ui \
perftracepointdialog.ui
diff --git a/src/plugins/perfprofiler/perfprofiler.qbs b/src/plugins/perfprofiler/perfprofiler.qbs
index 762c57ceb2..24cadd13e4 100644
--- a/src/plugins/perfprofiler/perfprofiler.qbs
+++ b/src/plugins/perfprofiler/perfprofiler.qbs
@@ -21,7 +21,6 @@ QtcPlugin {
"perfconfigeventsmodel.h",
"perfconfigwidget.cpp",
"perfconfigwidget.h",
- "perfconfigwidget.ui",
"perfdatareader.cpp",
"perfdatareader.h",
"perfevent.h",
diff --git a/src/plugins/perfprofiler/perfprofilerconstants.h b/src/plugins/perfprofiler/perfprofilerconstants.h
index f29cecc7ca..013f46dd54 100644
--- a/src/plugins/perfprofiler/perfprofilerconstants.h
+++ b/src/plugins/perfprofiler/perfprofilerconstants.h
@@ -49,22 +49,9 @@ const char TraceFileExtension[] = ".data";
const char PerfProfilerPerspectiveId[] = "PerfProfiler.Perspective";
const char PerfProfilerLocalActionId[] = "PerfProfiler.Local";
const char AnalyzerSettingsGroupId[] = "Analyzer";
-const char PerfSampleModeId[] = "Analyzer.Perf.SampleMode";
-const char PerfFrequencyId[] = "Analyzer.Perf.Frequency";
-const char PerfStackSizeId[] = "Analyzer.Perf.StackSize";
-const char PerfCallgraphModeId[] = "Analyzer.Perf.CallgraphMode";
-const char PerfEventsId[] = "Analyzer.Perf.Events";
-const char PerfExtraArgumentsId[] = "Analyzer.Perf.ExtraArguments";
-const char PerfSettingsId[] = "Analyzer.Perf.Settings";
-const char PerfRecordArgumentsId[] = "Analyzer.Perf.RecordArguments";
-const unsigned int PerfDefaultPeriod = 250;
-const unsigned int PerfDefaultStackSize = 4096;
+const char PerfSettingsId[] = "Analyzer.Perf.Settings";
const char PerfCallgraphDwarf[] = "dwarf";
-const char PerfCallgraphFP[] = "fp";
-const char PerfCallgraphLBR[] = "lbr";
-const char PerfSampleFrequency[] = "-F";
-const char PerfSampleCount[] = "-c";
const char PerfStreamMagic[] = "QPERFSTREAM";
const char PerfZqfileMagic[] = "PTQFILE4.10";
diff --git a/src/plugins/perfprofiler/perfprofilerruncontrol.cpp b/src/plugins/perfprofiler/perfprofilerruncontrol.cpp
index dfccc06d2c..48bb6cd4bc 100644
--- a/src/plugins/perfprofiler/perfprofilerruncontrol.cpp
+++ b/src/plugins/perfprofiler/perfprofilerruncontrol.cpp
@@ -151,11 +151,11 @@ public:
arguments << "record";
arguments += m_perfRecordArguments;
arguments << "-o" << "-" << "--" << perfRunnable.executable.toString()
- << Utils::QtcProcess::splitArgs(perfRunnable.commandLineArguments,
+ << Utils::ProcessArgs::splitArgs(perfRunnable.commandLineArguments,
Utils::OsTypeLinux);
perfRunnable.executable = FilePath::fromString("perf");
- perfRunnable.commandLineArguments = Utils::QtcProcess::joinArgs(arguments,
+ perfRunnable.commandLineArguments = Utils::ProcessArgs::joinArgs(arguments,
Utils::OsTypeLinux);
m_process->start(perfRunnable);
}
diff --git a/src/plugins/perfprofiler/perfsettings.cpp b/src/plugins/perfprofiler/perfsettings.cpp
index b58e377ad3..9ac361961b 100644
--- a/src/plugins/perfprofiler/perfsettings.cpp
+++ b/src/plugins/perfprofiler/perfsettings.cpp
@@ -31,6 +31,10 @@
#include <QSettings>
+#include <utils/qtcprocess.h>
+
+using namespace Utils;
+
namespace PerfProfiler {
PerfSettings::PerfSettings(ProjectExplorer::Target *target)
@@ -42,6 +46,51 @@ PerfSettings::PerfSettings(ProjectExplorer::Target *target)
return widget;
});
+ registerAspect(&period);
+ period.setSettingsKey("Analyzer.Perf.Frequency");
+ period.setRange(250, 2147483647);
+ period.setDefaultValue(250);
+ period.setLabelText(tr("Sample period:"));
+
+ registerAspect(&stackSize);
+ stackSize.setSettingsKey("Analyzer.Perf.StackSize");
+ stackSize.setRange(4096, 65536);
+ stackSize.setDefaultValue(4096);
+ stackSize.setLabelText(tr("Stack snapshot size (kB):"));
+
+ registerAspect(&sampleMode);
+ sampleMode.setSettingsKey("Analyzer.Perf.SampleMode");
+ sampleMode.setDisplayStyle(SelectionAspect::DisplayStyle::ComboBox);
+ sampleMode.setLabelText(tr("Sample mode:"));
+ sampleMode.addOption({tr("frequency (Hz)"), {}, QString("-F")});
+ sampleMode.addOption({tr("event count"), {}, QString("-c")});
+ sampleMode.setDefaultValue(0);
+
+ registerAspect(&callgraphMode);
+ callgraphMode.setSettingsKey("Analyzer.Perf.CallgraphMode");
+ callgraphMode.setDisplayStyle(SelectionAspect::DisplayStyle::ComboBox);
+ callgraphMode.setLabelText(tr("Call graph mode:"));
+ callgraphMode.addOption({tr("dwarf"), {}, QString(Constants::PerfCallgraphDwarf)});
+ callgraphMode.addOption({tr("frame pointer"), {}, QString("fp")});
+ callgraphMode.addOption({tr("last branch record"), {}, QString("lbr")});
+ callgraphMode.setDefaultValue(0);
+
+ registerAspect(&events);
+ events.setSettingsKey("Analyzer.Perf.Events");
+ events.setDefaultValue({"cpu-cycles"});
+
+ registerAspect(&extraArguments);
+ extraArguments.setSettingsKey("Analyzer.Perf.ExtraArguments");
+ extraArguments.setDisplayStyle(StringAspect::DisplayStyle::LineEditDisplay);
+ extraArguments.setLabelText(tr("Additional arguments:"));
+ extraArguments.setSpan(4);
+
+ connect(&callgraphMode, &SelectionAspect::volatileValueChanged, this, [this](int index) {
+ stackSize.setEnabled(index == 0);
+ });
+
+ connect(this, &AspectContainer::fromMapFinished, this, &PerfSettings::changed);
+
readGlobalSettings();
}
@@ -52,13 +101,6 @@ PerfSettings::~PerfSettings()
void PerfSettings::readGlobalSettings()
{
QVariantMap defaults;
- defaults.insert(QLatin1String(Constants::PerfEventsId), QStringList({"cpu-cycles"}));
- defaults.insert(QLatin1String(Constants::PerfSampleModeId), Constants::PerfSampleFrequency);
- defaults.insert(QLatin1String(Constants::PerfFrequencyId), Constants::PerfDefaultPeriod);
- defaults.insert(QLatin1String(Constants::PerfStackSizeId), Constants::PerfDefaultStackSize);
- defaults.insert(QLatin1String(Constants::PerfCallgraphModeId),
- QLatin1String(Constants::PerfCallgraphDwarf));
- defaults.insert(QLatin1String(Constants::PerfExtraArgumentsId), QStringList());
// Read stored values
QSettings *settings = Core::ICore::settings();
@@ -82,53 +124,14 @@ void PerfSettings::writeGlobalSettings() const
settings->endGroup();
}
-void PerfSettings::toMap(QVariantMap &map) const
-{
- map[QLatin1String(Constants::PerfSampleModeId)] = m_sampleMode;
- map[QLatin1String(Constants::PerfFrequencyId)] = m_period;
- map[QLatin1String(Constants::PerfStackSizeId)] = m_stackSize;
- map[QLatin1String(Constants::PerfCallgraphModeId)] = m_callgraphMode;
- map[QLatin1String(Constants::PerfEventsId)] = m_events;
- map[QLatin1String(Constants::PerfExtraArgumentsId)] = m_extraArguments;
- map[QLatin1String(Constants::PerfRecordArgumentsId)] = perfRecordArguments();
-}
-
-void PerfSettings::fromMap(const QVariantMap &map)
-{
- m_sampleMode = map.value(QLatin1String(Constants::PerfSampleModeId), m_sampleMode).toString();
- m_period = map.value(QLatin1String(Constants::PerfFrequencyId), m_period).toInt();
- m_stackSize = map.value(QLatin1String(Constants::PerfStackSizeId), m_stackSize).toInt();
- m_callgraphMode = map.value(QLatin1String(Constants::PerfCallgraphModeId),
- m_callgraphMode).toString();
- m_events = map.value(QLatin1String(Constants::PerfEventsId), m_events).toStringList();
- m_extraArguments = map.value(QLatin1String(Constants::PerfExtraArgumentsId),
- m_extraArguments).toStringList();
- emit changed();
-}
-
-QString PerfSettings::callgraphMode() const
-{
- return m_callgraphMode;
-}
-
-QStringList PerfSettings::events() const
-{
- return m_events;
-}
-
-QStringList PerfSettings::extraArguments() const
-{
- return m_extraArguments;
-}
-
QStringList PerfSettings::perfRecordArguments() const
{
- QString callgraphArg = m_callgraphMode;
- if (m_callgraphMode == QLatin1String(Constants::PerfCallgraphDwarf))
- callgraphArg += "," + QString::number(m_stackSize);
+ QString callgraphArg = callgraphMode.itemValue().toString();
+ if (callgraphArg == Constants::PerfCallgraphDwarf)
+ callgraphArg += "," + QString::number(stackSize.value());
QString events;
- for (const QString &event : m_events) {
+ for (const QString &event : this->events.value()) {
if (!event.isEmpty()) {
if (!events.isEmpty())
events.append(',');
@@ -136,23 +139,11 @@ QStringList PerfSettings::perfRecordArguments() const
}
}
- return QStringList({"-e", events, "--call-graph", callgraphArg, m_sampleMode,
- QString::number(m_period)}) + m_extraArguments;
-}
-
-void PerfSettings::setCallgraphMode(const QString &callgraphMode)
-{
- m_callgraphMode = callgraphMode;
-}
-
-void PerfSettings::setEvents(const QStringList &events)
-{
- m_events = events;
-}
-
-void PerfSettings::setExtraArguments(const QStringList &args)
-{
- m_extraArguments = args;
+ return QStringList({"-e", events,
+ "--call-graph", callgraphArg,
+ sampleMode.itemValue().toString(),
+ QString::number(period.value())})
+ + ProcessArgs::splitArgs(extraArguments.value());
}
void PerfSettings::resetToDefault()
@@ -163,34 +154,4 @@ void PerfSettings::resetToDefault()
fromMap(map);
}
-int PerfSettings::stackSize() const
-{
- return m_stackSize;
-}
-
-QString PerfSettings::sampleMode() const
-{
- return m_sampleMode;
-}
-
-void PerfSettings::setStackSize(int stackSize)
-{
- m_stackSize = stackSize;
-}
-
-void PerfSettings::setSampleMode(const QString &sampleMode)
-{
- m_sampleMode = sampleMode;
-}
-
-int PerfSettings::period() const
-{
- return m_period;
-}
-
-void PerfSettings::setPeriod(int period)
-{
- m_period = period;
-}
-
} // namespace PerfProfiler
diff --git a/src/plugins/perfprofiler/perfsettings.h b/src/plugins/perfprofiler/perfsettings.h
index c586cd8e71..839f4df689 100644
--- a/src/plugins/perfprofiler/perfsettings.h
+++ b/src/plugins/perfprofiler/perfsettings.h
@@ -45,36 +45,19 @@ public:
void readGlobalSettings();
void writeGlobalSettings() const;
- int period() const;
- int stackSize() const;
- QString sampleMode() const;
- QString callgraphMode() const;
- QStringList events() const;
- QStringList extraArguments() const;
-
QStringList perfRecordArguments() const;
- void setPeriod(int period);
- void setStackSize(int stackSize);
- void setSampleMode(const QString &sampleMode);
- void setCallgraphMode(const QString &callgraphMode);
- void setEvents(const QStringList &events);
- void setExtraArguments(const QStringList &args);
void resetToDefault();
+ Utils::IntegerAspect period;
+ Utils::IntegerAspect stackSize;
+ Utils::SelectionAspect sampleMode;
+ Utils::SelectionAspect callgraphMode;
+ Utils::StringListAspect events;
+ Utils::StringAspect extraArguments;
+
signals:
void changed();
-
-protected:
- void toMap(QVariantMap &map) const final;
- void fromMap(const QVariantMap &map) final;
-
- int m_period;
- int m_stackSize;
- QString m_sampleMode;
- QString m_callgraphMode;
- QStringList m_events;
- QStringList m_extraArguments;
};
} // namespace PerfProfiler
diff --git a/src/plugins/plugins.pro b/src/plugins/plugins.pro
index abf6e510c0..216407558e 100644
--- a/src/plugins/plugins.pro
+++ b/src/plugins/plugins.pro
@@ -67,7 +67,8 @@ SUBDIRS = \
mcusupport \
marketplace \
incredibuild \
- conan
+ conan \
+ docker
qtHaveModule(serialport) {
SUBDIRS += serialterminal
diff --git a/src/plugins/plugins.qbs b/src/plugins/plugins.qbs
index e2310ee1ff..4a2298dc55 100644
--- a/src/plugins/plugins.qbs
+++ b/src/plugins/plugins.qbs
@@ -37,6 +37,7 @@ Project {
"debugger/ptracepreload.qbs",
"designer/designer.qbs",
"diffeditor/diffeditor.qbs",
+ "docker/docker.qbs",
"fakevim/fakevim.qbs",
"emacskeys/emacskeys.qbs",
"genericprojectmanager/genericprojectmanager.qbs",
diff --git a/src/plugins/projectexplorer/CMakeLists.txt b/src/plugins/projectexplorer/CMakeLists.txt
index fbc61e9a1a..2bae7add9c 100644
--- a/src/plugins/projectexplorer/CMakeLists.txt
+++ b/src/plugins/projectexplorer/CMakeLists.txt
@@ -1,6 +1,7 @@
add_qtc_plugin(ProjectExplorer
DEPENDS QtcSsh Qt5::Qml
PLUGIN_DEPENDS Core TextEditor
+ PLUGIN_TEST_DEPENDS GenericProjectManager
SOURCES
abi.cpp abi.h
abiwidget.cpp abiwidget.h
@@ -12,8 +13,7 @@ add_qtc_plugin(ProjectExplorer
appoutputpane.cpp appoutputpane.h
baseprojectwizarddialog.cpp baseprojectwizarddialog.h
buildaspects.cpp buildaspects.h
- buildpropertiessettings.h
- buildpropertiessettingspage.cpp buildpropertiessettingspage.h
+ buildpropertiessettings.cpp buildpropertiessettings.h
buildconfiguration.cpp buildconfiguration.h
buildinfo.cpp buildinfo.h
buildmanager.cpp buildmanager.h
@@ -215,6 +215,15 @@ extend_qtc_plugin(ProjectExplorer
jsonwizard/jsonwizard_test.cpp
outputparser_test.cpp outputparser_test.h
)
+
+file(GLOB_RECURSE test_resources RELATIVE ${CMAKE_CURRENT_SOURCE_DIR} testdata/*)
+qtc_add_resources(ProjectExplorer "testdata"
+ CONDITION WITH_TESTS
+ PREFIX "/projectexplorer"
+ BASE "."
+ FILES ${test_resources}
+)
+
qtc_plugin_enabled(_projectexplorer_enabled ProjectExplorer)
if (WITH_TESTS AND _projectexplorer_enabled)
set_source_files_properties(jsonwizard/jsonwizard_test.cpp
diff --git a/src/plugins/projectexplorer/abi.cpp b/src/plugins/projectexplorer/abi.cpp
index f60d584d56..0fa05caf3b 100644
--- a/src/plugins/projectexplorer/abi.cpp
+++ b/src/plugins/projectexplorer/abi.cpp
@@ -240,6 +240,10 @@ static Abis parseCoffHeader(const QByteArray &data)
arch = Abi::ArmArchitecture;
width = 32;
break;
+ case 0xaa64: // ARM64
+ arch = Abi::ArmArchitecture;
+ width = 64;
+ break;
case 0x8664: // x86_64
arch = Abi::X86Architecture;
width = 64;
@@ -1157,20 +1161,19 @@ Abis Abi::abisOfBinary(const Utils::FilePath &path)
if (path.isEmpty())
return tmp;
- QFile f(path.toString());
- if (!f.exists())
- return tmp;
-
- if (!f.open(QFile::ReadOnly))
- return tmp;
-
- QByteArray data = f.read(1024);
+ QByteArray data = path.fileContents(1024);
if (data.size() >= 67
&& getUint8(data, 0) == '!' && getUint8(data, 1) == '<' && getUint8(data, 2) == 'a'
&& getUint8(data, 3) == 'r' && getUint8(data, 4) == 'c' && getUint8(data, 5) == 'h'
&& getUint8(data, 6) == '>' && getUint8(data, 7) == 0x0a) {
// We got an ar file: possibly a static lib for ELF, PE or Mach-O
+ // FIXME: Implement remote
+ QTC_ASSERT(!path.needsDevice(), return tmp);
+ QFile f(path.toString());
+ if (!f.open(QFile::ReadOnly))
+ return tmp;
+
data = data.mid(8); // Cut of ar file magic
quint64 offset = 8;
@@ -1203,7 +1206,6 @@ Abis Abi::abisOfBinary(const Utils::FilePath &path)
} else {
tmp = abiOf(data);
}
- f.close();
// Remove duplicates:
Abis result;
diff --git a/src/plugins/projectexplorer/abstractprocessstep.cpp b/src/plugins/projectexplorer/abstractprocessstep.cpp
index 03c398719c..8156eb02b2 100644
--- a/src/plugins/projectexplorer/abstractprocessstep.cpp
+++ b/src/plugins/projectexplorer/abstractprocessstep.cpp
@@ -41,11 +41,7 @@
#include <utils/qtcassert.h>
#include <utils/qtcprocess.h>
-#include <QDir>
-#include <QHash>
-#include <QPair>
#include <QTextDecoder>
-#include <QUrl>
#include <algorithm>
#include <memory>
@@ -106,7 +102,7 @@ public:
void cleanUp(QProcess *process);
AbstractProcessStep *q;
- std::unique_ptr<Utils::QtcProcess> m_process;
+ std::unique_ptr<QtcProcess> m_process;
ProcessParameters m_param;
std::function<CommandLine()> m_commandLineProvider;
std::function<FilePath()> m_workingDirectoryProvider;
@@ -118,7 +114,7 @@ public:
OutputFormatter *outputFormatter = nullptr;
};
-AbstractProcessStep::AbstractProcessStep(BuildStepList *bsl, Utils::Id id) :
+AbstractProcessStep::AbstractProcessStep(BuildStepList *bsl, Id id) :
BuildStep(bsl, id),
d(new Private(this))
{
@@ -157,7 +153,7 @@ void AbstractProcessStep::setEnvironmentModifier(const std::function<void (Envir
void AbstractProcessStep::setUseEnglishOutput()
{
- d->m_environmentModifier = [](Environment &env) { Environment::setupEnglishOutput(&env); };
+ d->m_environmentModifier = [](Environment &env) { env.setupEnglishOutput(); };
}
void AbstractProcessStep::setCommandLineProvider(const std::function<CommandLine()> &provider)
@@ -199,11 +195,10 @@ void AbstractProcessStep::setupOutputFormatter(OutputFormatter *formatter)
void AbstractProcessStep::doRun()
{
- QDir wd(d->m_param.effectiveWorkingDirectory().toString());
+ const FilePath wd = d->m_param.effectiveWorkingDirectory();
if (!wd.exists()) {
- if (!wd.mkpath(wd.absolutePath())) {
- emit addOutput(tr("Could not create directory \"%1\"")
- .arg(QDir::toNativeSeparators(wd.absolutePath())),
+ if (!wd.createDir()) {
+ emit addOutput(tr("Could not create directory \"%1\"").arg(wd.toUserOutput()),
BuildStep::OutputFormat::ErrorMessage);
finish(false);
return;
@@ -213,7 +208,7 @@ void AbstractProcessStep::doRun()
const CommandLine effectiveCommand(d->m_param.effectiveCommand(),
d->m_param.effectiveArguments(),
CommandLine::Raw);
- if (!effectiveCommand.executable().exists()) {
+ if (!effectiveCommand.executable().isExecutableFile()) {
processStartupFailed();
finish(false);
return;
@@ -223,9 +218,10 @@ void AbstractProcessStep::doRun()
? QTextCodec::codecForName("UTF-8") : QTextCodec::codecForLocale());
d->stderrStream = std::make_unique<QTextDecoder>(QTextCodec::codecForLocale());
- d->m_process.reset(new Utils::QtcProcess());
- d->m_process->setUseCtrlCStub(Utils::HostOsInfo::isWindowsHost());
- d->m_process->setWorkingDirectory(wd.absolutePath());
+ d->m_process.reset(new QtcProcess());
+ d->m_process->setUseCtrlCStub(HostOsInfo::isWindowsHost());
+ if (!wd.needsDevice()) // FIXME: Make QtcProcess take FilePath as working directory.
+ d->m_process->setWorkingDirectory(wd.toString());
// Enforce PWD in the environment because some build tools use that.
// PWD can be different from getcwd in case of symbolic links (getcwd resolves symlinks).
// For example Clang uses PWD for paths in debug info, see QTCREATORBUG-23788
@@ -268,11 +264,11 @@ ProcessParameters *AbstractProcessStep::processParameters()
return &d->m_param;
}
-void AbstractProcessStep::setupProcessParameters(ProcessParameters *params)
+void AbstractProcessStep::setupProcessParameters(ProcessParameters *params) const
{
params->setMacroExpander(macroExpander());
- Utils::Environment env = buildEnvironment();
+ Environment env = buildEnvironment();
if (d->m_environmentModifier)
d->m_environmentModifier(env);
params->setEnvironment(env);
@@ -309,7 +305,7 @@ void AbstractProcessStep::Private::cleanUp(QProcess *process)
void AbstractProcessStep::processStarted()
{
emit addOutput(tr("Starting: \"%1\" %2")
- .arg(QDir::toNativeSeparators(d->m_param.effectiveCommand().toString()),
+ .arg(d->m_param.effectiveCommand().toUserOutput(),
d->m_param.prettyArguments()),
BuildStep::OutputFormat::NormalMessage);
}
@@ -322,7 +318,7 @@ void AbstractProcessStep::processStarted()
void AbstractProcessStep::processFinished(int exitCode, QProcess::ExitStatus status)
{
- QString command = QDir::toNativeSeparators(d->m_param.effectiveCommand().toString());
+ QString command = d->m_param.effectiveCommand().toUserOutput();
if (status == QProcess::NormalExit && exitCode == 0) {
emit addOutput(tr("The process \"%1\" exited normally.").arg(command),
BuildStep::OutputFormat::NormalMessage);
@@ -344,7 +340,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().toString()),
+ .arg(d->m_param.effectiveCommand().toUserOutput(),
d->m_param.prettyArguments()),
BuildStep::OutputFormat::ErrorMessage);
}
diff --git a/src/plugins/projectexplorer/abstractprocessstep.h b/src/plugins/projectexplorer/abstractprocessstep.h
index 218e68a1bc..283b3ed730 100644
--- a/src/plugins/projectexplorer/abstractprocessstep.h
+++ b/src/plugins/projectexplorer/abstractprocessstep.h
@@ -29,6 +29,10 @@
#include <QProcess>
+namespace Utils {
+class CommandLine;
+}
+
namespace ProjectExplorer {
class ProcessParameters;
@@ -39,7 +43,7 @@ class PROJECTEXPLORER_EXPORT AbstractProcessStep : public BuildStep
public:
ProcessParameters *processParameters();
- void setupProcessParameters(ProcessParameters *params);
+ void setupProcessParameters(ProcessParameters *params) const;
bool ignoreReturnValue() const;
void setIgnoreReturnValue(bool b);
diff --git a/src/plugins/projectexplorer/allprojectsfilter.cpp b/src/plugins/projectexplorer/allprojectsfilter.cpp
index 5367c04510..d0c3e8cade 100644
--- a/src/plugins/projectexplorer/allprojectsfilter.cpp
+++ b/src/plugins/projectexplorer/allprojectsfilter.cpp
@@ -38,6 +38,9 @@ AllProjectsFilter::AllProjectsFilter()
{
setId("Files in any project");
setDisplayName(tr("Files in Any Project"));
+ setDescription(tr("Matches all files of all open projects. Append \"+<number>\" or "
+ "\":<number>\" to jump to the given line number. Append another "
+ "\"+<number>\" or \":<number>\" to jump to the column number as well."));
setDefaultShortcutString("a");
setDefaultIncludedByDefault(true);
diff --git a/src/plugins/projectexplorer/applicationlauncher.cpp b/src/plugins/projectexplorer/applicationlauncher.cpp
index 37a707968a..5ca295f373 100644
--- a/src/plugins/projectexplorer/applicationlauncher.cpp
+++ b/src/plugins/projectexplorer/applicationlauncher.cpp
@@ -419,7 +419,7 @@ void ApplicationLauncherPrivate::start(const Runnable &runnable, const IDevice::
return;
}
- if (runnable.executable.isEmpty()) {
+ if (!device->isEmptyCommandAllowed() && runnable.executable.isEmpty()) {
doReportError(ApplicationLauncher::tr("Cannot run: No command given."));
setFinished();
return;
diff --git a/src/plugins/projectexplorer/buildaspects.cpp b/src/plugins/projectexplorer/buildaspects.cpp
index c8f51a4dff..4e88f810c5 100644
--- a/src/plugins/projectexplorer/buildaspects.cpp
+++ b/src/plugins/projectexplorer/buildaspects.cpp
@@ -89,7 +89,7 @@ void BuildDirectoryAspect::toMap(QVariantMap &map) const
StringAspect::toMap(map);
if (!d->sourceDir.isEmpty()) {
const FilePath shadowDir = isChecked() ? filePath() : d->savedShadowBuildDir;
- saveToMap(map, shadowDir.toString(), QString(), ".shadowDir");
+ saveToMap(map, shadowDir.toString(), QString(), settingsKey() + ".shadowDir");
}
}
@@ -111,7 +111,7 @@ void BuildDirectoryAspect::addToLayout(LayoutBuilder &builder)
builder.addRow({{}, d->problemLabel.data()});
updateProblemLabel();
if (!d->sourceDir.isEmpty()) {
- connect(this, &StringAspect::checkedChanged, builder.layout(), [this] {
+ connect(this, &StringAspect::checkedChanged, this, [this] {
if (isChecked()) {
setFilePath(d->savedShadowBuildDir.isEmpty()
? d->sourceDir : d->savedShadowBuildDir);
@@ -136,7 +136,7 @@ SeparateDebugInfoAspect::SeparateDebugInfoAspect()
{
setDisplayName(tr("Separate debug info:"));
setSettingsKey("SeparateDebugInfo");
- setValue(ProjectExplorerPlugin::buildPropertiesSettings().separateDebugInfo);
+ setValue(ProjectExplorerPlugin::buildPropertiesSettings().separateDebugInfo.value());
}
} // namespace ProjectExplorer
diff --git a/src/plugins/projectexplorer/buildconfiguration.cpp b/src/plugins/projectexplorer/buildconfiguration.cpp
index f665651cb1..c49550f01e 100644
--- a/src/plugins/projectexplorer/buildconfiguration.cpp
+++ b/src/plugins/projectexplorer/buildconfiguration.cpp
@@ -326,11 +326,12 @@ NamedWidget *BuildConfiguration::createConfigWidget()
widget = named;
}
- LayoutBuilder builder(widget);
+ Layouting::Form builder;
for (BaseAspect *aspect : aspects()) {
if (aspect->isVisible())
aspect->addToLayout(builder.finishRow());
}
+ builder.attachTo(widget, false);
return named;
}
@@ -470,7 +471,7 @@ Environment BuildConfiguration::baseEnvironment() const
if (useSystemEnvironment())
result = Environment::systemEnvironment();
addToEnvironment(result);
- kit()->addToEnvironment(result);
+ kit()->addToBuildEnvironment(result);
result.modify(project()->additionalEnvironment());
return result;
}
diff --git a/src/plugins/projectexplorer/buildpropertiessettings.cpp b/src/plugins/projectexplorer/buildpropertiessettings.cpp
new file mode 100644
index 0000000000..f229d9c37a
--- /dev/null
+++ b/src/plugins/projectexplorer/buildpropertiessettings.cpp
@@ -0,0 +1,128 @@
+/****************************************************************************
+**
+** Copyright (C) 2021 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of Qt Creator.
+**
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3 as published by the Free Software
+** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-3.0.html.
+**
+****************************************************************************/
+
+#include "buildpropertiessettings.h"
+
+#include "projectexplorerconstants.h"
+
+#include <utils/layoutbuilder.h>
+
+using namespace Utils;
+
+namespace ProjectExplorer {
+
+// Default directory:
+const char DEFAULT_BUILD_DIRECTORY_TEMPLATE[]
+ = "../%{JS: Util.asciify(\"build-%{Project:Name}-%{Kit:FileSystemName}-%{BuildConfig:Name}\")}";
+
+BuildPropertiesSettings::BuildTriStateAspect::BuildTriStateAspect()
+ : TriStateAspect{
+ BuildPropertiesSettings::tr("Enable"),
+ BuildPropertiesSettings::tr("Disable"),
+ BuildPropertiesSettings::tr("Use Project Default")}
+{}
+
+BuildPropertiesSettings::BuildPropertiesSettings()
+{
+ setAutoApply(false);
+
+ registerAspect(&buildDirectoryTemplate);
+ buildDirectoryTemplate.setDisplayStyle(StringAspect::LineEditDisplay);
+ buildDirectoryTemplate.setSettingsKey("Directories/BuildDirectory.TemplateV2");
+ buildDirectoryTemplate.setDefaultValue(DEFAULT_BUILD_DIRECTORY_TEMPLATE);
+ buildDirectoryTemplate.setLabelText(tr("Default build directory:"));
+ buildDirectoryTemplate.setUseGlobalMacroExpander();
+ buildDirectoryTemplate.setUseResetButton();
+
+ registerAspect(&buildDirectoryTemplateOld); // TODO: Remove in ~4.16
+ buildDirectoryTemplateOld.setSettingsKey("Directories/BuildDirectory.Template");
+ buildDirectoryTemplateOld.setDefaultValue(DEFAULT_BUILD_DIRECTORY_TEMPLATE);
+
+ registerAspect(&separateDebugInfo);
+ separateDebugInfo.setSettingsKey("ProjectExplorer/Settings/SeparateDebugInfo");
+ separateDebugInfo.setLabelText(tr("Separate debug info:"));
+
+ registerAspect(&qmlDebugging);
+ qmlDebugging.setSettingsKey("ProjectExplorer/Settings/QmlDebugging");
+ qmlDebugging.setLabelText(tr("QML debugging:"));
+
+ registerAspect(&qtQuickCompiler);
+ qtQuickCompiler.setSettingsKey("ProjectExplorer/Settings/QtQuickCompiler");
+ qtQuickCompiler.setLabelText(tr("Use qmlcachegen:"));
+
+ QObject::connect(&showQtSettings, &BoolAspect::valueChanged,
+ &qmlDebugging, &BaseAspect::setVisible);
+ QObject::connect(&showQtSettings, &BoolAspect::valueChanged,
+ &qtQuickCompiler, &BaseAspect::setVisible);
+}
+
+void BuildPropertiesSettings::readSettings(QSettings *s)
+{
+ AspectContainer::readSettings(s);
+
+ // TODO: Remove in ~4.16
+ QString v = buildDirectoryTemplate.value();
+ if (v.isEmpty())
+ v = buildDirectoryTemplateOld.value();
+ if (v.isEmpty())
+ v = DEFAULT_BUILD_DIRECTORY_TEMPLATE;
+ v.replace("%{CurrentProject:Name}", "%{Project:Name}");
+ v.replace("%{CurrentKit:FileSystemName}", "%{Kit:FileSystemName}");
+ v.replace("%{CurrentBuild:Name}", "%{BuildConfig:Name}");
+ buildDirectoryTemplate.setValue(v);
+}
+
+QString BuildPropertiesSettings::defaultBuildDirectoryTemplate()
+{
+ return QString(DEFAULT_BUILD_DIRECTORY_TEMPLATE);
+}
+
+namespace Internal {
+
+BuildPropertiesSettingsPage::BuildPropertiesSettingsPage(BuildPropertiesSettings *settings)
+{
+ setId("AB.ProjectExplorer.BuildPropertiesSettingsPage");
+ setDisplayName(BuildPropertiesSettings::tr("Default Build Properties"));
+ setCategory(ProjectExplorer::Constants::BUILD_AND_RUN_SETTINGS_CATEGORY);
+ setSettings(settings);
+
+ setLayouter([settings](QWidget *widget) {
+ BuildPropertiesSettings &s = *settings;
+ using namespace Layouting;
+
+ Column {
+ Form {
+ s.buildDirectoryTemplate,
+ s.separateDebugInfo,
+ s.qmlDebugging,
+ s.qtQuickCompiler
+ },
+ Stretch()
+ }.attachTo(widget);
+ });
+}
+
+} // Internal
+} // ProjectExplorer
diff --git a/src/plugins/projectexplorer/buildpropertiessettings.h b/src/plugins/projectexplorer/buildpropertiessettings.h
index 63c289b5fb..ddec35f0fa 100644
--- a/src/plugins/projectexplorer/buildpropertiessettings.h
+++ b/src/plugins/projectexplorer/buildpropertiessettings.h
@@ -27,19 +27,44 @@
#include "projectexplorer_export.h"
+#include <coreplugin/dialogs/ioptionspage.h>
+
#include <utils/aspects.h>
namespace ProjectExplorer {
-class PROJECTEXPLORER_EXPORT BuildPropertiesSettings
+class PROJECTEXPLORER_EXPORT BuildPropertiesSettings : public Utils::AspectContainer
+{
+ Q_DECLARE_TR_FUNCTIONS(ProjectExplorer::Internal::BuildPropertiesSettings)
+
+public:
+ BuildPropertiesSettings();
+
+ class BuildTriStateAspect : public Utils::TriStateAspect
+ {
+ public:
+ BuildTriStateAspect();
+ };
+
+ Utils::StringAspect buildDirectoryTemplate;
+ Utils::StringAspect buildDirectoryTemplateOld; // TODO: Remove in ~4.16
+ BuildTriStateAspect separateDebugInfo;
+ BuildTriStateAspect qmlDebugging;
+ BuildTriStateAspect qtQuickCompiler;
+ Utils::BoolAspect showQtSettings;
+
+ void readSettings(QSettings *settings);
+
+ QString defaultBuildDirectoryTemplate();
+};
+
+namespace Internal {
+
+class BuildPropertiesSettingsPage final : public Core::IOptionsPage
{
public:
- QString buildDirectoryTemplate;
- QString buildDirectoryTemplateOld; // TODO: Remove in ~4.16
- Utils::TriState separateDebugInfo;
- Utils::TriState qmlDebugging;
- Utils::TriState qtQuickCompiler;
- bool showQtSettings = false;
+ explicit BuildPropertiesSettingsPage(BuildPropertiesSettings *settings);
};
+} // namespace Internal
} // namespace ProjectExplorer
diff --git a/src/plugins/projectexplorer/buildpropertiessettingspage.cpp b/src/plugins/projectexplorer/buildpropertiessettingspage.cpp
deleted file mode 100644
index a3294fd83f..0000000000
--- a/src/plugins/projectexplorer/buildpropertiessettingspage.cpp
+++ /dev/null
@@ -1,118 +0,0 @@
-/****************************************************************************
-**
-** 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 "buildpropertiessettingspage.h"
-
-#include "buildpropertiessettings.h"
-#include "projectexplorer.h"
-
-#include <utils/variablechooser.h>
-
-#include <QComboBox>
-#include <QFormLayout>
-#include <QHBoxLayout>
-#include <QLineEdit>
-#include <QPushButton>
-
-using namespace Utils;
-
-namespace ProjectExplorer {
-namespace Internal {
-
-class BuildPropertiesSettingsWidget final : public Core::IOptionsPageWidget
-{
- Q_DECLARE_TR_FUNCTIONS(ProjectExplorer::Internal::BuildPropertiesSettingsPage)
-
-public:
- BuildPropertiesSettingsWidget()
- {
- const BuildPropertiesSettings &settings = ProjectExplorerPlugin::buildPropertiesSettings();
- for (QComboBox * const comboBox : {&m_separateDebugInfoComboBox, &m_qmlDebuggingComboBox,
- &m_qtQuickCompilerComboBox}) {
- comboBox->addItem(tr("Enable"), TriState::Enabled.toVariant());
- comboBox->addItem(tr("Disable"),TriState::Disabled.toVariant());
- comboBox->addItem(tr("Use Project Default"), TriState::Default.toVariant());
- }
- m_separateDebugInfoComboBox.setCurrentIndex(m_separateDebugInfoComboBox
- .findData(settings.separateDebugInfo.toVariant()));
- m_qmlDebuggingComboBox.setCurrentIndex(m_qmlDebuggingComboBox
- .findData(settings.qmlDebugging.toVariant()));
- m_qtQuickCompilerComboBox.setCurrentIndex(m_qtQuickCompilerComboBox
- .findData(settings.qtQuickCompiler.toVariant()));
- const auto layout = new QFormLayout(this);
- const auto buildDirLayout = new QHBoxLayout;
- const auto resetButton = new QPushButton(tr("Reset"));
- connect(resetButton, &QPushButton::clicked, this, [this] {
- m_buildDirTemplateLineEdit.setText(
- ProjectExplorerPlugin::defaultBuildDirectoryTemplate());
- });
- connect(&m_buildDirTemplateLineEdit, &QLineEdit::textChanged,
- this, [this, resetButton] {
- resetButton->setEnabled(m_buildDirTemplateLineEdit.text()
- != ProjectExplorerPlugin::defaultBuildDirectoryTemplate());
- });
- const auto chooser = new VariableChooser(this);
- chooser->addSupportedWidget(&m_buildDirTemplateLineEdit);
- m_buildDirTemplateLineEdit.setText(settings.buildDirectoryTemplate);
- buildDirLayout->addWidget(&m_buildDirTemplateLineEdit);
- buildDirLayout->addWidget(resetButton);
- layout->addRow(tr("Default build directory:"), buildDirLayout);
- layout->addRow(tr("Separate debug info:"), &m_separateDebugInfoComboBox);
- if (settings.showQtSettings) {
- layout->addRow(tr("QML debugging:"), &m_qmlDebuggingComboBox);
- layout->addRow(tr("Use Qt Quick Compiler:"), &m_qtQuickCompilerComboBox);
- } else {
- m_qmlDebuggingComboBox.hide();
- m_qtQuickCompilerComboBox.hide();
- }
- }
-
- void apply() final
- {
- BuildPropertiesSettings s = ProjectExplorerPlugin::buildPropertiesSettings();
- s.buildDirectoryTemplate = m_buildDirTemplateLineEdit.text();
- s.separateDebugInfo = TriState::fromVariant(m_separateDebugInfoComboBox.currentData());
- s.qmlDebugging = TriState::fromVariant(m_qmlDebuggingComboBox.currentData());
- s.qtQuickCompiler = TriState::fromVariant(m_qtQuickCompilerComboBox.currentData());
- ProjectExplorerPlugin::setBuildPropertiesSettings(s);
- }
-
-private:
- QLineEdit m_buildDirTemplateLineEdit;
- QComboBox m_separateDebugInfoComboBox;
- QComboBox m_qmlDebuggingComboBox;
- QComboBox m_qtQuickCompilerComboBox;
-};
-
-BuildPropertiesSettingsPage::BuildPropertiesSettingsPage()
-{
- setId("AB.ProjectExplorer.BuildPropertiesSettingsPage");
- setDisplayName(BuildPropertiesSettingsWidget::tr("Default Build Properties"));
- setCategory(Constants::BUILD_AND_RUN_SETTINGS_CATEGORY);
- setWidgetCreator([] { return new BuildPropertiesSettingsWidget; });
-}
-
-} // namespace Internal
-} // namespace ProjectExplorer
diff --git a/src/plugins/projectexplorer/buildstep.cpp b/src/plugins/projectexplorer/buildstep.cpp
index b6c6f4d621..41f0b49209 100644
--- a/src/plugins/projectexplorer/buildstep.cpp
+++ b/src/plugins/projectexplorer/buildstep.cpp
@@ -179,13 +179,12 @@ QWidget *BuildStep::doCreateConfigWidget()
QWidget *BuildStep::createConfigWidget()
{
- auto widget = new QWidget;
-
- LayoutBuilder builder(widget);
+ Layouting::Form builder;
for (BaseAspect *aspect : qAsConst(m_aspects)) {
if (aspect->isVisible())
aspect->addToLayout(builder.finishRow());
}
+ auto widget = builder.emerge(false);
if (m_addMacroExpander)
VariableChooser::addSupportForChildWidgets(widget, macroExpander());
diff --git a/src/plugins/projectexplorer/buildsteplist.cpp b/src/plugins/projectexplorer/buildsteplist.cpp
index 759deecead..0a60422dbb 100644
--- a/src/plugins/projectexplorer/buildsteplist.cpp
+++ b/src/plugins/projectexplorer/buildsteplist.cpp
@@ -192,11 +192,7 @@ bool BuildStepList::removeStep(int position)
void BuildStepList::moveStepUp(int position)
{
-#if QT_VERSION >= QT_VERSION_CHECK(5, 13, 0)
m_steps.swapItemsAt(position - 1, position);
-#else
- m_steps.swap(position - 1, position);
-#endif
emit stepMoved(position, position - 1);
}
diff --git a/src/plugins/projectexplorer/buildsystem.cpp b/src/plugins/projectexplorer/buildsystem.cpp
index d91558ea44..3f4bb3b4bb 100644
--- a/src/plugins/projectexplorer/buildsystem.cpp
+++ b/src/plugins/projectexplorer/buildsystem.cpp
@@ -188,10 +188,7 @@ Environment BuildSystem::activeParseEnvironment() const
if (rc)
return rc->runnable().environment;
- Environment result = Utils::Environment::systemEnvironment();
- d->m_target->kit()->addToEnvironment(result);
-
- return result;
+ return d->m_target->kit()->buildEnvironment();
}
void BuildSystem::requestParseHelper(int delay)
diff --git a/src/plugins/projectexplorer/buildsystem.h b/src/plugins/projectexplorer/buildsystem.h
index 8171300980..de610811cf 100644
--- a/src/plugins/projectexplorer/buildsystem.h
+++ b/src/plugins/projectexplorer/buildsystem.h
@@ -33,6 +33,10 @@
#include <QObject>
+namespace Utils {
+class CommandLine;
+}
+
namespace ProjectExplorer {
class BuildConfiguration;
@@ -41,6 +45,7 @@ class Node;
struct TestCaseInfo
{
QString name;
+ int number = -1;
Utils::FilePath path;
int line = 0;
};
diff --git a/src/plugins/projectexplorer/clangparser.cpp b/src/plugins/projectexplorer/clangparser.cpp
index 8409d78832..5dfea0062a 100644
--- a/src/plugins/projectexplorer/clangparser.cpp
+++ b/src/plugins/projectexplorer/clangparser.cpp
@@ -47,7 +47,7 @@ static const char *const FILE_PATTERN = "(<command line>|([A-Za-z]:)?[^:]+\\.[^:
ClangParser::ClangParser() :
m_commandRegExp(QLatin1String("^clang(\\+\\+)?: +(fatal +)?(warning|error|note): (.*)$")),
m_inLineRegExp(QLatin1String("^In (.*?) included from (.*?):(\\d+):$")),
- m_messageRegExp(QLatin1Char('^') + QLatin1String(FILE_PATTERN) + QLatin1String("(:(\\d+):\\d+|\\((\\d+)\\) *): +(fatal +)?(error|warning|note): (.*)$")),
+ m_messageRegExp(QLatin1Char('^') + QLatin1String(FILE_PATTERN) + QLatin1String("(:(\\d+):(\\d+)|\\((\\d+)\\) *): +(fatal +)?(error|warning|note): (.*)$")),
m_summaryRegExp(QLatin1String("^\\d+ (warnings?|errors?)( and \\d (warnings?|errors?))? generated.$")),
m_codesignRegExp(QLatin1String("^Code ?Sign error: (.*)$")),
m_expectSnippet(false)
@@ -84,9 +84,11 @@ OutputLineParser::Result ClangParser::handleLine(const QString &line, OutputForm
m_expectSnippet = true;
const FilePath filePath = absoluteFilePath(FilePath::fromUserInput(match.captured(2)));
const int lineNo = match.captured(3).toInt();
+ const int column = 0;
LinkSpecs linkSpecs;
addLinkSpecForAbsoluteFilePath(linkSpecs, filePath, lineNo, match, 2);
- createOrAmendTask(Task::Unknown, lne.trimmed(), lne, false, filePath, lineNo, linkSpecs);
+ createOrAmendTask(Task::Unknown, lne.trimmed(), lne, false,
+ filePath, lineNo, column, linkSpecs);
return {Status::InProgress, linkSpecs};
}
@@ -95,13 +97,17 @@ OutputLineParser::Result ClangParser::handleLine(const QString &line, OutputForm
m_expectSnippet = true;
bool ok = false;
int lineNo = match.captured(4).toInt(&ok);
- if (!ok)
- lineNo = match.captured(5).toInt(&ok);
+ int column = match.captured(5).toInt();
+ if (!ok) {
+ lineNo = match.captured(6).toInt(&ok);
+ column = 0;
+ }
+
const FilePath filePath = absoluteFilePath(FilePath::fromUserInput(match.captured(1)));
LinkSpecs linkSpecs;
addLinkSpecForAbsoluteFilePath(linkSpecs, filePath, lineNo, match, 1);
- createOrAmendTask(taskType(match.captured(7)), match.captured(8), lne, false,
- filePath, lineNo, linkSpecs);
+ createOrAmendTask(taskType(match.captured(8)), match.captured(9), lne, false,
+ filePath, lineNo, column, linkSpecs);
return {Status::InProgress, linkSpecs};
}
@@ -146,9 +152,10 @@ void ProjectExplorerPlugin::testClangOutputParser_data()
const QString &description,
const Utils::FilePath &file,
int line,
+ int column,
const QVector<QTextLayout::FormatRange> formats)
{
- CompileTask task(type, description, file, line);
+ CompileTask task(type, description, file, line, column);
task.formats = formats;
return task;
};
@@ -206,7 +213,7 @@ void ProjectExplorerPlugin::testClangOutputParser_data()
"class Q_CORE_EXPORT QSysInfo {\n"
" ^",
FilePath::fromUserInput("..\\..\\..\\QtSDK1.1\\Desktop\\Qt\\4.7.3\\mingw\\include/QtCore/qglobal.h"),
- 1425,
+ 1425, 0,
QVector<QTextLayout::FormatRange>()
<< formatRange(61, 278))}
<< QString();
@@ -224,7 +231,7 @@ void ProjectExplorerPlugin::testClangOutputParser_data()
"# define Q_CORE_EXPORT Q_DECL_IMPORT\n"
" ^",
FilePath::fromUserInput("..\\..\\..\\QtSDK1.1\\Desktop\\Qt\\4.7.3\\mingw\\include/QtCore/qglobal.h"),
- 1289,
+ 1289, 27,
QVector<QTextLayout::FormatRange>()
<< formatRange(19, 167)))
<< QString();
@@ -242,7 +249,7 @@ void ProjectExplorerPlugin::testClangOutputParser_data()
"#include <bits/c++config.h>\n"
" ^",
FilePath::fromUserInput("/usr/include/c++/4.6/utility"),
- 68,
+ 68, 10,
QVector<QTextLayout::FormatRange>()
<< formatRange(34, 0)
<< formatRange(34, 28, "olpfile:///usr/include/c++/4.6/utility::68::-1")
@@ -262,7 +269,7 @@ void ProjectExplorerPlugin::testClangOutputParser_data()
" int x = option->rect.x() + horizontal ? 2 : 6;\n"
" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ^",
FilePath::fromUserInput("/home/code/src/creator/src/plugins/coreplugin/manhattanstyle.cpp"),
- 567,
+ 567, 51,
QVector<QTextLayout::FormatRange>()
<< formatRange(74, 0)
<< formatRange(74, 64, "olpfile:///home/code/src/creator/src/plugins/coreplugin/manhattanstyle.cpp::567::-1")
@@ -281,16 +288,6 @@ void ProjectExplorerPlugin::testClangOutputParser_data()
<< CompileTask(Task::Error,
"code signing is required for product type 'Application' in SDK 'iOS 7.0'"))
<< QString();
-
- QTest::newRow("moc note")
- << QString::fromLatin1("/home/qtwebkithelpviewer.h:0: Note: No relevant classes found. No output generated.")
- << OutputParserTester::STDERR
- << QString() << QString()
- << (Tasks()
- << CompileTask(Task::Unknown,
- "Note: No relevant classes found. No output generated.",
- FilePath::fromUserInput("/home/qtwebkithelpviewer.h")))
- << QString();
}
void ProjectExplorerPlugin::testClangOutputParser()
diff --git a/src/plugins/projectexplorer/currentprojectfilter.cpp b/src/plugins/projectexplorer/currentprojectfilter.cpp
index 59a3b5c3bf..61098b9d84 100644
--- a/src/plugins/projectexplorer/currentprojectfilter.cpp
+++ b/src/plugins/projectexplorer/currentprojectfilter.cpp
@@ -38,6 +38,9 @@ CurrentProjectFilter::CurrentProjectFilter()
{
setId("Files in current project");
setDisplayName(tr("Files in Current Project"));
+ setDescription(tr("Matches all files from the current document's project. Append \"+<number>\" "
+ "or \":<number>\" to jump to the given line number. Append another "
+ "\"+<number>\" or \":<number>\" to jump to the column number as well."));
setDefaultShortcutString("p");
setDefaultIncludedByDefault(false);
diff --git a/src/plugins/projectexplorer/customwizard/customwizard.cpp b/src/plugins/projectexplorer/customwizard/customwizard.cpp
index 55850c4333..5b8a3f697f 100644
--- a/src/plugins/projectexplorer/customwizard/customwizard.cpp
+++ b/src/plugins/projectexplorer/customwizard/customwizard.cpp
@@ -198,7 +198,7 @@ static inline bool createFile(CustomWizardFile cwFile,
const QFile::OpenMode openMode
= cwFile.binary ? QIODevice::ReadOnly : (QIODevice::ReadOnly|QIODevice::Text);
Utils::FileReader reader;
- if (!reader.fetch(sourcePath, openMode, errorMessage))
+ if (!reader.fetch(Utils::FilePath::fromString(sourcePath), openMode, errorMessage))
return false;
Core::GeneratedFile generatedFile;
@@ -383,13 +383,9 @@ QList<Core::IWizardFactory *> CustomWizard::createWizards()
{
QString errorMessage;
QString verboseLog;
- const QString templateDirName = Core::ICore::resourcePath() +
- QLatin1Char('/') + QLatin1String(templatePathC);
-
-
- const QString userTemplateDirName = Core::ICore::userResourcePath() +
- QLatin1Char('/') + QLatin1String(templatePathC);
+ const QString templateDirName = Core::ICore::resourcePath(templatePathC).toString();
+ const QString userTemplateDirName = Core::ICore::userResourcePath(templatePathC).toString();
const QDir templateDir(templateDirName);
if (CustomWizardPrivate::verbose)
diff --git a/src/plugins/projectexplorer/customwizard/customwizardscriptgenerator.cpp b/src/plugins/projectexplorer/customwizard/customwizardscriptgenerator.cpp
index 1f8a7c0130..daea2672e2 100644
--- a/src/plugins/projectexplorer/customwizard/customwizardscriptgenerator.cpp
+++ b/src/plugins/projectexplorer/customwizard/customwizardscriptgenerator.cpp
@@ -29,7 +29,7 @@
#include <utils/fileutils.h>
#include <utils/hostosinfo.h>
-#include <utils/synchronousprocess.h>
+#include <utils/qtcprocess.h>
#include <utils/temporarydirectory.h>
#include <QFileInfo>
@@ -112,11 +112,12 @@ static bool
if (CustomWizard::verbose())
qDebug("In %s, running:\n%s\n", qPrintable(workingDirectory),
qPrintable(cmd.toUserOutput()));
- Utils::SynchronousProcessResponse response = process.run(cmd);
- if (response.result != Utils::SynchronousProcessResponse::Finished) {
- *errorMessage = QString::fromLatin1("Generator script failed: %1")
- .arg(response.exitMessage(binary, 30));
- const QString stdErr = response.stdErr();
+ process.setCommand(cmd);
+ process.setProcessUserEventWhileRunning();
+ process.runBlocking();
+ if (process.result() != Utils::QtcProcess::Finished) {
+ *errorMessage = QString("Generator script failed: %1").arg(process.exitMessage());
+ const QString stdErr = process.stdErr();
if (!stdErr.isEmpty()) {
errorMessage->append(QLatin1Char('\n'));
errorMessage->append(stdErr);
@@ -124,7 +125,7 @@ static bool
return false;
}
if (stdOut) {
- *stdOut = response.stdOut();
+ *stdOut = process.stdOut();
if (CustomWizard::verbose())
qDebug("Output: '%s'\n", qPrintable(*stdOut));
}
diff --git a/src/plugins/projectexplorer/desktoprunconfiguration.cpp b/src/plugins/projectexplorer/desktoprunconfiguration.cpp
index dcf100ac9d..e1144c71ab 100644
--- a/src/plugins/projectexplorer/desktoprunconfiguration.cpp
+++ b/src/plugins/projectexplorer/desktoprunconfiguration.cpp
@@ -32,6 +32,7 @@
#include "target.h"
#include <cmakeprojectmanager/cmakeprojectconstants.h>
+#include <docker/dockerconstants.h>
#include <qbsprojectmanager/qbsprojectmanagerconstants.h>
#include <qmakeprojectmanager/qmakeprojectmanagerconstants.h>
@@ -40,8 +41,6 @@
#include <utils/qtcassert.h>
#include <utils/stringutils.h>
-#include <QFileInfo>
-
using namespace Utils;
namespace ProjectExplorer {
@@ -54,17 +53,17 @@ class DesktopRunConfiguration : public RunConfiguration
protected:
enum Kind { Qmake, Qbs, CMake }; // FIXME: Remove
- DesktopRunConfiguration(Target *target, Utils::Id id, Kind kind);
+ DesktopRunConfiguration(Target *target, Id id, Kind kind);
private:
void updateTargetInformation();
- Utils::FilePath executableToRun(const BuildTargetInfo &targetInfo) const;
+ FilePath executableToRun(const BuildTargetInfo &targetInfo) const;
const Kind m_kind;
};
-DesktopRunConfiguration::DesktopRunConfiguration(Target *target, Utils::Id id, Kind kind)
+DesktopRunConfiguration::DesktopRunConfiguration(Target *target, Id id, Kind kind)
: RunConfiguration(target, id), m_kind(kind)
{
auto envAspect = addAspect<LocalEnvironmentAspect>(target);
@@ -150,7 +149,7 @@ void DesktopRunConfiguration::updateTargetInformation()
}
}
-Utils::FilePath DesktopRunConfiguration::executableToRun(const BuildTargetInfo &targetInfo) const
+FilePath DesktopRunConfiguration::executableToRun(const BuildTargetInfo &targetInfo) const
{
const FilePath appInBuildDir = targetInfo.targetFilePath;
const DeploymentData deploymentData = target()->deploymentData();
@@ -171,7 +170,7 @@ Utils::FilePath DesktopRunConfiguration::executableToRun(const BuildTargetInfo &
class DesktopQmakeRunConfiguration final : public DesktopRunConfiguration
{
public:
- DesktopQmakeRunConfiguration(Target *target, Utils::Id id)
+ DesktopQmakeRunConfiguration(Target *target, Id id)
: DesktopRunConfiguration(target, id, Qmake)
{}
};
@@ -179,7 +178,7 @@ public:
class QbsRunConfiguration final : public DesktopRunConfiguration
{
public:
- QbsRunConfiguration(Target *target, Utils::Id id)
+ QbsRunConfiguration(Target *target, Id id)
: DesktopRunConfiguration(target, id, Qbs)
{}
};
@@ -187,7 +186,7 @@ public:
class CMakeRunConfiguration final : public DesktopRunConfiguration
{
public:
- CMakeRunConfiguration(Target *target, Utils::Id id)
+ CMakeRunConfiguration(Target *target, Id id)
: DesktopRunConfiguration(target, id, CMake)
{}
};
@@ -201,6 +200,7 @@ CMakeRunConfigurationFactory::CMakeRunConfigurationFactory()
registerRunConfiguration<CMakeRunConfiguration>(CMAKE_RUNCONFIG_ID);
addSupportedProjectType(CMakeProjectManager::Constants::CMAKE_PROJECT_ID);
addSupportedTargetDeviceType(ProjectExplorer::Constants::DESKTOP_DEVICE_TYPE);
+ addSupportedTargetDeviceType(Docker::Constants::DOCKER_DEVICE_TYPE);
}
QbsRunConfigurationFactory::QbsRunConfigurationFactory()
@@ -208,6 +208,7 @@ QbsRunConfigurationFactory::QbsRunConfigurationFactory()
registerRunConfiguration<QbsRunConfiguration>(QBS_RUNCONFIG_ID);
addSupportedProjectType(QbsProjectManager::Constants::PROJECT_ID);
addSupportedTargetDeviceType(ProjectExplorer::Constants::DESKTOP_DEVICE_TYPE);
+ addSupportedTargetDeviceType(Docker::Constants::DOCKER_DEVICE_TYPE);
}
DesktopQmakeRunConfigurationFactory::DesktopQmakeRunConfigurationFactory()
@@ -215,6 +216,7 @@ DesktopQmakeRunConfigurationFactory::DesktopQmakeRunConfigurationFactory()
registerRunConfiguration<DesktopQmakeRunConfiguration>(QMAKE_RUNCONFIG_ID);
addSupportedProjectType(QmakeProjectManager::Constants::QMAKEPROJECT_ID);
addSupportedTargetDeviceType(ProjectExplorer::Constants::DESKTOP_DEVICE_TYPE);
+ addSupportedTargetDeviceType(Docker::Constants::DOCKER_DEVICE_TYPE);
}
} // namespace Internal
diff --git a/src/plugins/projectexplorer/devicesupport/desktopdevice.cpp b/src/plugins/projectexplorer/devicesupport/desktopdevice.cpp
index 455783855b..44e357a298 100644
--- a/src/plugins/projectexplorer/devicesupport/desktopdevice.cpp
+++ b/src/plugins/projectexplorer/devicesupport/desktopdevice.cpp
@@ -173,4 +173,9 @@ QUrl DesktopDevice::toolControlChannel(const ControlChannelHint &) const
return url;
}
+bool DesktopDevice::handlesFile(const FilePath &filePath) const
+{
+ return !filePath.needsDevice();
+}
+
} // namespace ProjectExplorer
diff --git a/src/plugins/projectexplorer/devicesupport/desktopdevice.h b/src/plugins/projectexplorer/devicesupport/desktopdevice.h
index aacea5f9c7..fd3ac7bf85 100644
--- a/src/plugins/projectexplorer/devicesupport/desktopdevice.h
+++ b/src/plugins/projectexplorer/devicesupport/desktopdevice.h
@@ -54,6 +54,7 @@ public:
DeviceProcessSignalOperation::Ptr signalOperation() const override;
DeviceEnvironmentFetcher::Ptr environmentFetcher() const override;
QUrl toolControlChannel(const ControlChannelHint &) const override;
+ bool handlesFile(const Utils::FilePath &filePath) const override;
protected:
DesktopDevice();
diff --git a/src/plugins/projectexplorer/devicesupport/desktopdeviceprocess.cpp b/src/plugins/projectexplorer/devicesupport/desktopdeviceprocess.cpp
index aec61e50f9..e281e650bc 100644
--- a/src/plugins/projectexplorer/devicesupport/desktopdeviceprocess.cpp
+++ b/src/plugins/projectexplorer/devicesupport/desktopdeviceprocess.cpp
@@ -55,7 +55,7 @@ void DesktopDeviceProcess::start(const Runnable &runnable)
m_process.setProcessEnvironment(runnable.environment.toProcessEnvironment());
m_process.setWorkingDirectory(runnable.workingDirectory);
m_process.start(runnable.executable.toString(),
- Utils::QtcProcess::splitArgs(runnable.commandLineArguments));
+ Utils::ProcessArgs::splitArgs(runnable.commandLineArguments));
}
void DesktopDeviceProcess::interrupt()
diff --git a/src/plugins/projectexplorer/devicesupport/devicemanager.cpp b/src/plugins/projectexplorer/devicesupport/devicemanager.cpp
index bbf6e4bcd8..8ad2ff67f7 100644
--- a/src/plugins/projectexplorer/devicesupport/devicemanager.cpp
+++ b/src/plugins/projectexplorer/devicesupport/devicemanager.cpp
@@ -36,6 +36,7 @@
#include <utils/persistentsettings.h>
#include <utils/portlist.h>
#include <utils/qtcassert.h>
+#include <utils/qtcprocess.h>
#include <utils/stringutils.h>
#include <QFileInfo>
@@ -141,19 +142,17 @@ void DeviceManager::load()
QTC_ASSERT(!d->writer, return);
// Only create writer now: We do not want to save before the settings were read!
- d->writer = new Utils::PersistentSettingsWriter(
- settingsFilePath(QLatin1String("/devices.xml")),
- QLatin1String("QtCreatorDevices"));
+ d->writer = new PersistentSettingsWriter(settingsFilePath("devices.xml"), "QtCreatorDevices");
Utils::PersistentSettingsReader reader;
// read devices file from global settings path
QHash<Utils::Id, Utils::Id> defaultDevices;
QList<IDevice::Ptr> sdkDevices;
- if (reader.load(systemSettingsFilePath(QLatin1String("/devices.xml"))))
+ if (reader.load(systemSettingsFilePath("devices.xml")))
sdkDevices = fromMap(reader.restoreValues().value(DeviceManagerKey).toMap(), &defaultDevices);
// read devices file from user settings path
QList<IDevice::Ptr> userDevices;
- if (reader.load(settingsFilePath(QLatin1String("/devices.xml"))))
+ if (reader.load(settingsFilePath("devices.xml")))
userDevices = fromMap(reader.restoreValues().value(DeviceManagerKey).toMap(), &defaultDevices);
// Insert devices into the model. Prefer the higher device version when there are multiple
// devices with the same id.
@@ -223,15 +222,14 @@ QVariantMap DeviceManager::toMap() const
return map;
}
-Utils::FilePath DeviceManager::settingsFilePath(const QString &extension)
+FilePath DeviceManager::settingsFilePath(const QString &extension)
{
- return Utils::FilePath::fromString(Core::ICore::userResourcePath() + extension);
+ return Core::ICore::userResourcePath(extension);
}
-Utils::FilePath DeviceManager::systemSettingsFilePath(const QString &deviceFileRelativePath)
+FilePath DeviceManager::systemSettingsFilePath(const QString &deviceFileRelativePath)
{
- return Utils::FilePath::fromString(Core::ICore::installerResourcePath()
- + deviceFileRelativePath);
+ return Core::ICore::installerResourcePath(deviceFileRelativePath);
}
void DeviceManager::addDevice(const IDevice::ConstPtr &_device)
@@ -314,6 +312,15 @@ bool DeviceManager::isLoaded() const
return d->writer;
}
+IDevice::ConstPtr DeviceManager::deviceForPath(const FilePath &path)
+{
+ for (IDevice::Ptr &dev : instance()->d->devices) {
+ if (dev->handlesFile(path))
+ return dev;
+ }
+ return {};
+}
+
void DeviceManager::setDefaultDevice(Utils::Id id)
{
QTC_ASSERT(this != instance(), return);
@@ -347,11 +354,78 @@ const IDeviceFactory *DeviceManager::restoreFactory(const QVariantMap &map)
DeviceManager::DeviceManager(bool isInstance) : d(std::make_unique<DeviceManagerPrivate>())
{
- if (isInstance) {
- QTC_ASSERT(!m_instance, return);
- m_instance = this;
- connect(Core::ICore::instance(), &Core::ICore::saveSettingsRequested, this, &DeviceManager::save);
- }
+ QTC_ASSERT(isInstance == !m_instance, return);
+
+ if (!isInstance)
+ return;
+
+ m_instance = this;
+ connect(Core::ICore::instance(), &Core::ICore::saveSettingsRequested,
+ this, &DeviceManager::save);
+
+ DeviceFileHooks deviceHooks;
+
+ deviceHooks.isExecutableFile = [](const FilePath &filePath) {
+ auto device = DeviceManager::deviceForPath(filePath);
+ QTC_ASSERT(device, return false);
+ return device->isExecutableFile(filePath);
+ };
+
+ deviceHooks.isReadableFile = [](const FilePath &filePath) {
+ auto device = DeviceManager::deviceForPath(filePath);
+ QTC_ASSERT(device, return false);
+ return device->isReadableFile(filePath);
+ };
+
+ deviceHooks.isReadableDir = [](const FilePath &filePath) {
+ auto device = DeviceManager::deviceForPath(filePath);
+ QTC_ASSERT(device, return false);
+ return device->isReadableDirectory(filePath);
+ };
+
+ deviceHooks.isWritableDir = [](const FilePath &filePath) {
+ auto device = DeviceManager::deviceForPath(filePath);
+ QTC_ASSERT(device, return false);
+ return device->isWritableDirectory(filePath);
+ };
+
+ deviceHooks.createDir = [](const FilePath &filePath) {
+ auto device = DeviceManager::deviceForPath(filePath);
+ QTC_ASSERT(device, return false);
+ return device->createDirectory(filePath);
+ };
+
+ deviceHooks.dirEntries = [](const FilePath &filePath,
+ const QStringList &nameFilters, QDir::Filters filters) {
+ auto device = DeviceManager::deviceForPath(filePath);
+ QTC_ASSERT(device, return FilePaths());
+ return device->directoryEntries(filePath, nameFilters, filters);
+ };
+
+ deviceHooks.fileContents = [](const FilePath &filePath, int maxSize) {
+ auto device = DeviceManager::deviceForPath(filePath);
+ QTC_ASSERT(device, return QByteArray());
+ return device->fileContents(filePath, maxSize);
+ };
+
+ FilePath::setDeviceFileHooks(deviceHooks);
+
+ DeviceProcessHooks processHooks;
+
+ processHooks.startProcessHook = [](QtcProcess &process) {
+ FilePath filePath = process.commandLine().executable();
+ auto device = DeviceManager::deviceForPath(filePath);
+ QTC_ASSERT(device, return);
+ device->runProcess(process);
+ };
+
+ processHooks.systemEnvironmentForBinary = [](const FilePath &filePath) {
+ auto device = DeviceManager::deviceForPath(filePath);
+ QTC_ASSERT(device, return Environment());
+ return device->systemEnvironment();
+ };
+
+ QtcProcess::setRemoteProcessHooks(processHooks);
}
DeviceManager::~DeviceManager()
diff --git a/src/plugins/projectexplorer/devicesupport/devicemanager.h b/src/plugins/projectexplorer/devicesupport/devicemanager.h
index 0f9c036248..ef8047e0a5 100644
--- a/src/plugins/projectexplorer/devicesupport/devicemanager.h
+++ b/src/plugins/projectexplorer/devicesupport/devicemanager.h
@@ -69,6 +69,7 @@ public:
void setDeviceState(Utils::Id deviceId, IDevice::DeviceState deviceState);
bool isLoaded() const;
+ static IDevice::ConstPtr deviceForPath(const Utils::FilePath &path);
signals:
void deviceAdded(Utils::Id id);
diff --git a/src/plugins/projectexplorer/devicesupport/idevice.cpp b/src/plugins/projectexplorer/devicesupport/idevice.cpp
index f4c4904efb..17e2616e97 100644
--- a/src/plugins/projectexplorer/devicesupport/idevice.cpp
+++ b/src/plugins/projectexplorer/devicesupport/idevice.cpp
@@ -97,6 +97,7 @@
* Creates an identical copy of a device object.
*/
+using namespace Utils;
static Utils::Id newId()
{
@@ -152,6 +153,7 @@ public:
Utils::PortList freePorts;
QString debugServerPath;
QString qmlsceneCommand;
+ bool emptyCommandAllowed = false;
QList<Utils::Icon> deviceIcons;
QList<IDevice::DeviceAction> deviceActions;
@@ -189,6 +191,98 @@ void IDevice::openTerminal(const Utils::Environment &env, const QString &working
d->openTerminal(env, workingDir);
}
+bool IDevice::isEmptyCommandAllowed() const
+{
+ return d->emptyCommandAllowed;
+}
+
+void IDevice::setAllowEmptyCommand(bool allow)
+{
+ d->emptyCommandAllowed = allow;
+}
+
+bool IDevice::isAnyUnixDevice() const
+{
+ return d->osType == OsTypeLinux || d->osType == OsTypeMac || d->osType == OsTypeOtherUnix;
+}
+
+FilePath IDevice::mapToGlobalPath(const FilePath &pathOnDevice) const
+{
+ return pathOnDevice;
+}
+
+bool IDevice::handlesFile(const FilePath &filePath) const
+{
+ Q_UNUSED(filePath);
+ return false;
+}
+
+bool IDevice::isExecutableFile(const FilePath &filePath) const
+{
+ Q_UNUSED(filePath);
+ QTC_CHECK(false);
+ return false;
+}
+
+bool IDevice::isReadableFile(const FilePath &filePath) const
+{
+ Q_UNUSED(filePath);
+ QTC_CHECK(false);
+ return false;
+}
+
+bool IDevice::isReadableDirectory(const FilePath &filePath) const
+{
+ Q_UNUSED(filePath);
+ QTC_CHECK(false);
+ return false;
+}
+
+bool IDevice::isWritableDirectory(const FilePath &filePath) const
+{
+ Q_UNUSED(filePath);
+ QTC_CHECK(false);
+ return false;
+}
+
+bool IDevice::createDirectory(const Utils::FilePath &filePath) const
+{
+ Q_UNUSED(filePath);
+ QTC_CHECK(false);
+ return false;
+}
+
+QList<FilePath> IDevice::directoryEntries(const FilePath &filePath,
+ const QStringList &nameFilters,
+ QDir::Filters filters) const
+{
+ Q_UNUSED(filePath);
+ Q_UNUSED(nameFilters);
+ Q_UNUSED(filters);
+ QTC_CHECK(false);
+ return {};
+}
+
+QByteArray IDevice::fileContents(const FilePath &filePath, int limit) const
+{
+ Q_UNUSED(filePath);
+ Q_UNUSED(limit);
+ QTC_CHECK(false);
+ return {};
+}
+
+void IDevice::runProcess(QtcProcess &process) const
+{
+ Q_UNUSED(process);
+ QTC_CHECK(false);
+}
+
+Environment IDevice::systemEnvironment() const
+{
+ QTC_CHECK(false);
+ return Environment::systemEnvironment();
+}
+
IDevice::~IDevice() = default;
/*!
diff --git a/src/plugins/projectexplorer/devicesupport/idevice.h b/src/plugins/projectexplorer/devicesupport/idevice.h
index c3caaa617f..ba69c47f9c 100644
--- a/src/plugins/projectexplorer/devicesupport/idevice.h
+++ b/src/plugins/projectexplorer/devicesupport/idevice.h
@@ -32,6 +32,7 @@
#include <QAbstractSocket>
#include <QCoreApplication>
+#include <QDir>
#include <QList>
#include <QObject>
#include <QSharedPointer>
@@ -48,10 +49,13 @@ QT_END_NAMESPACE
namespace QSsh { class SshConnectionParameters; }
namespace Utils {
+class CommandLine;
class Environment;
+class FilePath;
class Icon;
class PortList;
class Port;
+class QtcProcess;
} // Utils
namespace ProjectExplorer {
@@ -221,6 +225,29 @@ public:
bool canOpenTerminal() const;
void openTerminal(const Utils::Environment &env, const QString &workingDir) const;
+ bool isEmptyCommandAllowed() const;
+ void setAllowEmptyCommand(bool allow);
+
+ bool isWindowsDevice() const { return osType() == Utils::OsTypeWindows; }
+ bool isLinuxDevice() const { return osType() == Utils::OsTypeLinux; }
+ bool isMacDevice() const { return osType() == Utils::OsTypeMac; }
+ bool isAnyUnixDevice() const;
+
+ virtual Utils::FilePath mapToGlobalPath(const Utils::FilePath &pathOnDevice) const;
+
+ virtual bool handlesFile(const Utils::FilePath &filePath) const;
+ virtual bool isExecutableFile(const Utils::FilePath &filePath) const;
+ virtual bool isReadableFile(const Utils::FilePath &filePath) const;
+ virtual bool isReadableDirectory(const Utils::FilePath &filePath) const;
+ virtual bool isWritableDirectory(const Utils::FilePath &filePath) const;
+ virtual bool createDirectory(const Utils::FilePath &filePath) const;
+ virtual QList<Utils::FilePath> directoryEntries(const Utils::FilePath &filePath,
+ const QStringList &nameFilters,
+ QDir::Filters filters) const;
+ virtual QByteArray fileContents(const Utils::FilePath &filePath, int limit) const;
+ virtual void runProcess(Utils::QtcProcess &process) const;
+ virtual Utils::Environment systemEnvironment() const;
+
protected:
IDevice();
diff --git a/src/plugins/projectexplorer/devicesupport/localprocesslist.cpp b/src/plugins/projectexplorer/devicesupport/localprocesslist.cpp
index 3b8c534c98..bab7615f7f 100644
--- a/src/plugins/projectexplorer/devicesupport/localprocesslist.cpp
+++ b/src/plugins/projectexplorer/devicesupport/localprocesslist.cpp
@@ -25,7 +25,7 @@
#include "localprocesslist.h"
-#include <utils/synchronousprocess.h>
+#include <utils/qtcprocess.h>
#include <QLibrary>
#include <QTimer>
@@ -156,12 +156,12 @@ static QList<DeviceProcessItem> getLocalProcessesUsingProc(const QDir &procDir)
static QMap<qint64, QString> getLocalProcessDataUsingPs(const QString &column)
{
QMap<qint64, QString> result;
- QProcess psProcess;
- const QStringList args{"-e", "-o", "pid," + column};
- psProcess.start("ps", args);
+ Utils::QtcProcess psProcess;
+ psProcess.setCommand({"ps", {"-e", "-o", "pid," + column}});
+ psProcess.start();
if (psProcess.waitForStarted()) {
QByteArray output;
- if (Utils::SynchronousProcess::readDataFromProcess(psProcess, 30000, &output, nullptr, false)) {
+ if (psProcess.readDataFromProcess(30000, &output, nullptr, false)) {
// Split "457 /Users/foo.app arg1 arg2"
const QStringList lines = QString::fromLocal8Bit(output).split(QLatin1Char('\n'));
const int lineCount = lines.size();
diff --git a/src/plugins/projectexplorer/environmentwidget.cpp b/src/plugins/projectexplorer/environmentwidget.cpp
index 948bba7d43..078eb2f2a5 100644
--- a/src/plugins/projectexplorer/environmentwidget.cpp
+++ b/src/plugins/projectexplorer/environmentwidget.cpp
@@ -437,38 +437,6 @@ 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;
- if (varName == "PKG_CONFIG_DIR")
- return true;
- if (Utils::HostOsInfo::isWindowsHost()
- && QStringList{"INCLUDE", "LIB", "LIBPATH"}.contains(varName)) {
- 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(), Qt::SkipEmptyParts);
- if (entries.length() < 2)
- return false;
- return Utils::anyOf(entries, [](const QString &d) { return QFileInfo(d).isDir(); });
-}
-
void EnvironmentWidget::updateButtons()
{
environmentCurrentIndexChanged(d->m_environmentView->currentIndex());
@@ -477,7 +445,9 @@ void EnvironmentWidget::updateButtons()
void EnvironmentWidget::editEnvironmentButtonClicked()
{
const QModelIndex current = d->m_environmentView->currentIndex();
- if (current.column() == 1 && d->m_type == TypeLocal && currentEntryIsPathList(current)) {
+ if (current.column() == 1
+ && d->m_type == TypeLocal
+ && d->m_model->currentEntryIsPathList(current)) {
PathListDialog dlg(d->m_model->indexToVariable(current),
d->m_model->data(current).toString(), this);
if (dlg.exec() == QDialog::Accepted)
@@ -562,8 +532,9 @@ void EnvironmentWidget::environmentCurrentIndexChanged(const QModelIndex &curren
d->m_toggleButton->setText(tr("Disable"));
}
if (d->m_appendPathButton) {
- d->m_appendPathButton->setEnabled(currentEntryIsPathList(current));
- d->m_prependPathButton->setEnabled(currentEntryIsPathList(current));
+ const bool isPathList = d->m_model->currentEntryIsPathList(current);
+ d->m_appendPathButton->setEnabled(isPathList);
+ d->m_prependPathButton->setEnabled(isPathList);
}
}
diff --git a/src/plugins/projectexplorer/environmentwidget.h b/src/plugins/projectexplorer/environmentwidget.h
index e59d84efbc..62a91b46ca 100644
--- a/src/plugins/projectexplorer/environmentwidget.h
+++ b/src/plugins/projectexplorer/environmentwidget.h
@@ -80,7 +80,6 @@ private:
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(Utils::NameValueItem::Operation op);
diff --git a/src/plugins/projectexplorer/extraabi.cpp b/src/plugins/projectexplorer/extraabi.cpp
index 855d4a9e9c..17c16b9efe 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(FilePath::fromString(Core::ICore::installerResourcePath() + "/abi.xml"));
+ setBaseFilePath(Core::ICore::installerResourcePath("abi.xml"));
addVersionUpgrader(std::make_unique<AbiFlavorUpgraderV0>());
}
diff --git a/src/plugins/projectexplorer/gccparser.cpp b/src/plugins/projectexplorer/gccparser.cpp
index 33f820a34f..96ac617beb 100644
--- a/src/plugins/projectexplorer/gccparser.cpp
+++ b/src/plugins/projectexplorer/gccparser.cpp
@@ -45,11 +45,11 @@ GccParser::GccParser()
{
setObjectName(QLatin1String("GCCParser"));
m_regExp.setPattern(QLatin1Char('^') + QLatin1String(FILE_PATTERN)
- + QLatin1String("(?:(?:(\\d+):(\\d+:)?)|\\(.*\\):)\\s+((fatal |#)?(warning|error|note):?\\s)?([^\\s].+)$"));
+ + QLatin1String("(?:(?:(\\d+):(?:(\\d+):)?)|\\(.*\\):)\\s+((fatal |#)?(warning|error|note):?\\s)?([^\\s].+)$"));
QTC_CHECK(m_regExp.isValid());
m_regExpScope.setPattern(QLatin1Char('^') + FILE_PATTERN
- + "(?:(\\d+):)?(\\d+:)?\\s+((?:In .*(?:function|constructor) .*|At global scope):)$");
+ + "(?:(\\d+):)?(\\d+:)?\\s+((?:In .*(?:function|constructor) .*|At global scope|At top level):)$");
QTC_CHECK(m_regExpScope.isValid());
m_regExpIncluded.setPattern(QString::fromLatin1("\\bfrom\\s") + QLatin1String(FILE_PATTERN)
@@ -90,13 +90,14 @@ void GccParser::createOrAmendTask(
bool forceAmend,
const FilePath &file,
int line,
+ int column,
const LinkSpecs &linkSpecs
)
{
const bool amend = !m_currentTask.isNull() && (forceAmend || isContinuation(originalLine));
if (!amend) {
flush();
- m_currentTask = CompileTask(type, description, file, line);
+ m_currentTask = CompileTask(type, description, file, line, column);
m_currentTask.details.append(originalLine);
m_linkSpecs = linkSpecs;
m_lines = 1;
@@ -119,6 +120,7 @@ void GccParser::createOrAmendTask(
if (!file.isEmpty()) {
m_currentTask.setFile(file);
m_currentTask.line = line;
+ m_currentTask.column = column;
}
}
++m_lines;
@@ -183,9 +185,10 @@ OutputLineParser::Result GccParser::handleLine(const QString &line, OutputFormat
if (match.hasMatch()) {
const FilePath filePath = absoluteFilePath(FilePath::fromUserInput(match.captured(1)));
const int lineNo = match.captured(3).toInt();
+ const int column = match.captured(4).toInt();
LinkSpecs linkSpecs;
addLinkSpecForAbsoluteFilePath(linkSpecs, filePath, lineNo, match, 1);
- createOrAmendTask(Task::Unknown, lne.trimmed(), lne, false, filePath, lineNo, linkSpecs);
+ createOrAmendTask(Task::Unknown, lne.trimmed(), lne, false, filePath, lineNo, column, linkSpecs);
return {Status::InProgress, linkSpecs};
}
@@ -196,7 +199,7 @@ OutputLineParser::Result GccParser::handleLine(const QString &line, OutputFormat
LinkSpecs linkSpecs;
if (!filePath.isEmpty())
addLinkSpecForAbsoluteFilePath(linkSpecs, filePath, -1, match, 3);
- createOrAmendTask(type, match.captured(2), lne, false, filePath, -1, linkSpecs);
+ createOrAmendTask(type, match.captured(2), lne, false, filePath, -1, 0, linkSpecs);
flush();
return {Status::Done, linkSpecs};
}
@@ -204,6 +207,7 @@ OutputLineParser::Result GccParser::handleLine(const QString &line, OutputFormat
match = m_regExp.match(lne);
if (match.hasMatch()) {
int lineno = match.captured(3).toInt();
+ int column = match.captured(4).toInt();
Task::TaskType type = Task::Unknown;
QString description = match.captured(8);
if (match.captured(7) == QLatin1String("warning"))
@@ -220,18 +224,19 @@ OutputLineParser::Result GccParser::handleLine(const QString &line, OutputFormat
const FilePath filePath = absoluteFilePath(FilePath::fromUserInput(match.captured(1)));
LinkSpecs linkSpecs;
addLinkSpecForAbsoluteFilePath(linkSpecs, filePath, lineno, match, 1);
- createOrAmendTask(type, description, lne, false, filePath, lineno, linkSpecs);
+ createOrAmendTask(type, description, lne, false, filePath, lineno, column, linkSpecs);
return {Status::InProgress, linkSpecs};
}
match = m_regExpScope.match(lne);
if (match.hasMatch()) {
const int lineno = match.captured(3).toInt();
+ const int column = match.captured(4).toInt();
const QString description = match.captured(5);
const FilePath filePath = absoluteFilePath(FilePath::fromUserInput(match.captured(1)));
LinkSpecs linkSpecs;
addLinkSpecForAbsoluteFilePath(linkSpecs, filePath, lineno, match, 1);
- createOrAmendTask(Task::Unknown, description, lne, false, filePath, lineno, linkSpecs);
+ createOrAmendTask(Task::Unknown, description, lne, false, filePath, lineno, column, linkSpecs);
return {Status::InProgress, linkSpecs};
}
@@ -275,9 +280,10 @@ void ProjectExplorerPlugin::testGccOutputParsers_data()
const QString &description,
const Utils::FilePath &file,
int line,
+ int column,
const QVector<QTextLayout::FormatRange> formats)
{
- CompileTask task(type, description, file, line);
+ CompileTask task(type, description, file, line, column);
task.formats = formats;
return task;
};
@@ -320,7 +326,7 @@ void ProjectExplorerPlugin::testGccOutputParsers_data()
"/temp/test/untitled8/main.cpp: In function `int main(int, char**)':\n"
"/temp/test/untitled8/main.cpp:9: error: `sfasdf' undeclared (first use this function)",
FilePath::fromUserInput("/temp/test/untitled8/main.cpp"),
- 9,
+ 9, 0,
QVector<QTextLayout::FormatRange>()
<< formatRange(46, 0)
<< formatRange(46, 29, "olpfile:///temp/test/untitled8/main.cpp::0::-1")
@@ -330,7 +336,7 @@ void ProjectExplorerPlugin::testGccOutputParsers_data()
<< CompileTask(Task::Error,
"(Each undeclared identifier is reported only once for each function it appears in.)",
FilePath::fromUserInput("/temp/test/untitled8/main.cpp"),
- 9))
+ 9, 0))
<< QString();
QTest::newRow("GCCE warning")
@@ -341,7 +347,7 @@ void ProjectExplorerPlugin::testGccOutputParsers_data()
<< CompileTask(Task::Warning,
"inline function `QDebug qDebug()' used but never defined",
FilePath::fromUserInput("/src/corelib/global/qglobal.h"),
- 1635))
+ 1635, 0))
<< QString();
QTest::newRow("warning")
@@ -352,7 +358,7 @@ void ProjectExplorerPlugin::testGccOutputParsers_data()
<< CompileTask(Task::Warning,
"Some warning",
FilePath::fromUserInput("main.cpp"),
- 7))
+ 7, 2))
<< QString();
QTest::newRow("GCCE #error")
@@ -363,7 +369,7 @@ void ProjectExplorerPlugin::testGccOutputParsers_data()
<< CompileTask(Task::Error,
"#error Symbian error",
FilePath::fromUserInput("C:\\temp\\test\\untitled8\\main.cpp"),
- 7))
+ 7, 0))
<< QString();
// Symbian reports #warning(s) twice (using different syntax).
@@ -375,7 +381,7 @@ void ProjectExplorerPlugin::testGccOutputParsers_data()
<< CompileTask(Task::Warning,
"#warning Symbian warning",
FilePath::fromUserInput("C:\\temp\\test\\untitled8\\main.cpp"),
- 8))
+ 8, 0))
<< QString();
QTest::newRow("GCCE #warning2")
@@ -386,7 +392,7 @@ void ProjectExplorerPlugin::testGccOutputParsers_data()
<< CompileTask(Task::Warning,
"#warning Symbian warning",
FilePath::fromUserInput("/temp/test/untitled8/main.cpp"),
- 8))
+ 8, 2))
<< QString();
QVector<QTextLayout::FormatRange> formatRanges;
@@ -409,7 +415,7 @@ void ProjectExplorerPlugin::testGccOutputParsers_data()
"main.o: In function `main':\n"
"C:\\temp\\test\\untitled8/main.cpp:8: undefined reference to `MainWindow::doSomething()'",
FilePath::fromUserInput("C:\\temp\\test\\untitled8/main.cpp"),
- 8,
+ 8, 0,
formatRanges)
<< CompileTask(Task::Error,
"collect2: ld returned 1 exit status"))
@@ -435,7 +441,7 @@ void ProjectExplorerPlugin::testGccOutputParsers_data()
"main.o: In function `main':\n"
"C:\\temp\\test\\untitled8/main.cpp:(.text+0x40): undefined reference to `MainWindow::doSomething()'",
FilePath::fromUserInput("C:\\temp\\test\\untitled8/main.cpp"),
- -1,
+ -1, 0,
formatRanges)
<< CompileTask(Task::Error,
"collect2: ld returned 1 exit status"))
@@ -472,13 +478,13 @@ void ProjectExplorerPlugin::testGccOutputParsers_data()
"../../../../master/src/plugins/debugger/gdb/gdbengine.cpp: In member function 'void Debugger::Internal::GdbEngine::handleBreakInsert2(const Debugger::Internal::GdbResponse&)':\n"
"../../../../master/src/plugins/debugger/gdb/gdbengine.cpp:2114: warning: unused variable 'index'",
FilePath::fromUserInput("../../../../master/src/plugins/debugger/gdb/gdbengine.cpp"),
- 2114,
+ 2114, 0,
QVector<QTextLayout::FormatRange>()
<< formatRange(24, 272))
<< CompileTask(Task::Warning,
"unused variable 'handler'",
FilePath::fromUserInput("../../../../master/src/plugins/debugger/gdb/gdbengine.cpp"),
- 2115))
+ 2115, 0))
<< QString();
QTest::newRow("gnumakeparser.cpp errors")
@@ -493,7 +499,7 @@ void ProjectExplorerPlugin::testGccOutputParsers_data()
"/home/code/src/creator/src/plugins/projectexplorer/gnumakeparser.cpp: In member function 'void ProjectExplorer::ProjectExplorerPlugin::testGnuMakeParserTaskMangling_data()':\n"
"/home/code/src/creator/src/plugins/projectexplorer/gnumakeparser.cpp:264: error: expected primary-expression before ':' token",
FilePath::fromUserInput("/home/code/src/creator/src/plugins/projectexplorer/gnumakeparser.cpp"),
- 264,
+ 264, 0,
QVector<QTextLayout::FormatRange>()
<< formatRange(45, 0)
<< formatRange(45, 68, "olpfile:///home/code/src/creator/src/plugins/projectexplorer/gnumakeparser.cpp::0::-1")
@@ -503,7 +509,7 @@ void ProjectExplorerPlugin::testGccOutputParsers_data()
<< CompileTask(Task::Error,
"expected ';' before ':' token",
FilePath::fromUserInput("/home/code/src/creator/src/plugins/projectexplorer/gnumakeparser.cpp"),
- 264))
+ 264, 0))
<< QString();
QTest::newRow("distcc error(QTCREATORBUG-904)")
@@ -562,7 +568,7 @@ void ProjectExplorerPlugin::testGccOutputParsers_data()
"/Qt/4.6.2-Symbian/s60sdk/epoc32/include/stdapis/stlport/stl/_tree.c: 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*&)':\n"
"/Qt/4.6.2-Symbian/s60sdk/epoc32/include/stdapis/stlport/stl/_tree.c:194: warning: suggest explicit braces to avoid ambiguous 'else'",
FilePath::fromUserInput("/Qt/4.6.2-Symbian/s60sdk/epoc32/include/stdapis/stlport/stl/_tree.c"),
- 194,
+ 194, 0,
QVector<QTextLayout::FormatRange>()
<< formatRange(50, 0)
<< formatRange(50, 67, "olpfile:///Qt/4.6.2-Symbian/s60sdk/epoc32/include/stdapis/stlport/stl/_tree.c::0::-1")
@@ -599,7 +605,7 @@ void ProjectExplorerPlugin::testGccOutputParsers_data()
"../../scriptbug/main.cpp: In function void foo(i) [with i = double]:\n"
"../../scriptbug/main.cpp:22: instantiated from here",
FilePath::fromUserInput("../../scriptbug/main.cpp"),
- -1,
+ -1, 0,
QVector<QTextLayout::FormatRange>()
<< formatRange(43, 120))
<< CompileTask(Task::Warning,
@@ -644,7 +650,7 @@ void ProjectExplorerPlugin::testGccOutputParsers_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]",
FilePath::fromUserInput("../../scriptbug/main.cpp"),
- -1,
+ -1, 0,
QVector<QTextLayout::FormatRange>()
<< formatRange(17, 195))
<< CompileTask(Task::Unknown,
@@ -665,7 +671,7 @@ void ProjectExplorerPlugin::testGccOutputParsers_data()
<< CompileTask(Task::Error,
"test.moc: No such file or directory",
FilePath::fromUserInput("/home/code/test.cpp"),
- 54))
+ 54, 38))
<< QString();
formatRanges.clear();
@@ -689,7 +695,7 @@ void ProjectExplorerPlugin::testGccOutputParsers_data()
"debug/qplotaxis.o: In function `QPlotAxis':\n"
"M:\\Development\\x64\\QtPlot/qplotaxis.cpp:26: undefined reference to `vtable for QPlotAxis'",
FilePath::fromUserInput("M:\\Development\\x64\\QtPlot/qplotaxis.cpp"),
- 26,
+ 26, 0,
formatRanges)
<< CompileTask(Task::Error,
"undefined reference to `vtable for QPlotAxis'",
@@ -713,7 +719,7 @@ void ProjectExplorerPlugin::testGccOutputParsers_data()
"../stl/main.cpp: In member function typename _Vector_base<_Tp, _Alloc>::_Tp_alloc_type::const_reference Vector<_Tp, _Alloc>::at(int) [with _Tp = Point, _Alloc = Allocator<Point>]:\n"
"../stl/main.cpp:38: instantiated from here",
FilePath::fromUserInput("../stl/main.cpp"),
- -1,
+ -1, 0,
QVector<QTextLayout::FormatRange>()
<< formatRange(163, 224))
<< CompileTask(Task::Warning,
@@ -724,7 +730,7 @@ void ProjectExplorerPlugin::testGccOutputParsers_data()
"../stl/main.cpp: At global scope:\n"
"../stl/main.cpp:31: warning: unused parameter index",
FilePath::fromUserInput("../stl/main.cpp"),
- 31,
+ 31, 0,
QVector<QTextLayout::FormatRange>()
<< formatRange(23, 85)))
<< QString();
@@ -757,7 +763,7 @@ void ProjectExplorerPlugin::testGccOutputParsers_data()
"C:/Symbian_SDK/epoc32/include/e32cmn.inl: In member function 'SSecureId::operator const TSecureId&() const':\n"
"C:/Symbian_SDK/epoc32/include/e32cmn.inl:7094: warning: returning reference to temporary",
FilePath::fromUserInput("C:/Symbian_SDK/epoc32/include/e32cmn.inl"),
- 7094,
+ 7094, 0,
formatRanges)}
<< QString();
QTest::newRow("In constructor 2")
@@ -774,7 +780,7 @@ void ProjectExplorerPlugin::testGccOutputParsers_data()
" 28 | memset(this, 0, sizeof(PerfEventAttributes));\n"
" | ^",
FilePath::fromUserInput("perfattributes.cpp"),
- 28,
+ 28, 48,
QVector<QTextLayout::FormatRange>()
<< formatRange(170, 400))}
<< QString();
@@ -801,7 +807,7 @@ void ProjectExplorerPlugin::testGccOutputParsers_data()
" from <command line>:26:\n"
"/Symbian/SDK/epoc32/include/variant/Symbian_OS.hrh:1134:26: warning: no newline at end of file",
FilePath::fromUserInput("/Symbian/SDK/epoc32/include/variant/Symbian_OS.hrh"),
- 1134,
+ 1134, 26,
QVector<QTextLayout::FormatRange>()
<< formatRange(26, 22)
<< formatRange(48, 39, "olpfile:///Symbian/SDK/EPOC32/INCLUDE/GCCE/GCCE.h::15::-1")
@@ -831,7 +837,7 @@ void ProjectExplorerPlugin::testGccOutputParsers_data()
"../../../src/shared/proparser/profileevaluator.cpp: In member function 'ProFileEvaluator::Private::VisitReturn ProFileEvaluator::Private::evaluateConditionalFunction(const ProString&, const ProStringList&)':\n"
"../../../src/shared/proparser/profileevaluator.cpp:2817:9: warning: case value '0' not in enumerated type 'ProFileEvaluator::Private::TestFunc'",
FilePath::fromUserInput("../../../src/shared/proparser/profileevaluator.cpp"),
- 2817,
+ 2817, 9,
QVector<QTextLayout::FormatRange>()
<< formatRange(76, 351)))
<< QString();
@@ -847,7 +853,7 @@ void ProjectExplorerPlugin::testGccOutputParsers_data()
"In file included from <command-line>:0:0:\n"
"./mw.h:4:0: warning: \"STUPID_DEFINE\" redefined",
FilePath::fromUserInput("./mw.h"),
- 4,
+ 4, 0,
QVector<QTextLayout::FormatRange>()
<< formatRange(26, 88))}
<< QString();
@@ -864,13 +870,13 @@ void ProjectExplorerPlugin::testGccOutputParsers_data()
"file.h: In function 'void UnitTest::CheckEqual(UnitTest::TestResults&, const Expected&, const Actual&, const UnitTest::TestDetails&) [with Expected = unsigned int, Actual = int]':\n"
"file.cpp:87:10: instantiated from here",
FilePath::fromUserInput("file.h"),
- -1,
+ -1, 0,
QVector<QTextLayout::FormatRange>()
<< formatRange(172, 218))
<< CompileTask(Task::Warning,
"comparison between signed and unsigned integer expressions [-Wsign-compare]",
FilePath::fromUserInput("file.h"),
- 21))
+ 21, 5))
<< QString();
QTest::newRow("linker error") // QTCREATORBUG-3107
@@ -883,16 +889,6 @@ void ProjectExplorerPlugin::testGccOutputParsers_data()
FilePath::fromUserInput("cns5k_ins_parser_tests.cpp")))
<< QString();
- QTest::newRow("uic warning")
- << QString::fromLatin1("mainwindow.ui: Warning: The name 'pushButton' (QPushButton) is already in use, defaulting to 'pushButton1'.")
- << OutputParserTester::STDERR
- << QString() << QString()
- << (Tasks()
- << CompileTask(Task::Warning,
- "The name 'pushButton' (QPushButton) is already in use, defaulting to 'pushButton1'.",
- FilePath::fromUserInput("mainwindow.ui")))
- << QString();
-
QTest::newRow("libimf warning")
<< QString::fromLatin1("libimf.so: warning: warning: feupdateenv is not implemented and will always fail")
<< OutputParserTester::STDERR
@@ -918,7 +914,7 @@ void ProjectExplorerPlugin::testGccOutputParsers_data()
" #include <QtGui/QAction>\n"
" ^",
FilePath::fromUserInput(".uic/ui_pluginerrorview.h"),
- 14,
+ 14, 25,
QVector<QTextLayout::FormatRange>()
<< formatRange(41, 22)
<< formatRange(63, 67, "olpfile:///home/code/src/creator/src/libs/extensionsystem/pluginerrorview.cpp::31::-1")
@@ -942,7 +938,7 @@ void ProjectExplorerPlugin::testGccOutputParsers_data()
"/usr/include/qt4/QtCore/qstring.h:597:5: error: 'QString::QString(const char*)' is private\n"
"main.cpp:7:22: error: within this context",
FilePath::fromUserInput("/usr/include/qt4/QtCore/qstring.h"),
- 597,
+ 597, 5,
QVector<QTextLayout::FormatRange>()
<< formatRange(43, 22)
<< formatRange(65, 31, "olpfile:///usr/include/qt4/QtCore/QString::1::-1")
@@ -966,7 +962,7 @@ void ProjectExplorerPlugin::testGccOutputParsers_data()
"foo.o: In function `foo()':\n"
"/home/user/test/foo.cpp:2: multiple definition of `foo()'",
FilePath::fromUserInput("/home/user/test/foo.cpp"),
- 2,
+ 2, 0,
QVector<QTextLayout::FormatRange>()
<< formatRange(31, 28)
<< formatRange(59, 23, "olpfile:///home/user/test/foo.cpp::2::-1")
@@ -1169,16 +1165,6 @@ void ProjectExplorerPlugin::testGccOutputParsers_data()
"file: lib/libtest.a(Test0.cpp.o) has no symbols"))
<< QString();
- QTest::newRow("moc note")
- << QString::fromLatin1("/home/qtwebkithelpviewer.h:0: Note: No relevant classes found. No output generated.")
- << OutputParserTester::STDERR
- << QString() << QString()
- << (Tasks()
- << CompileTask(Task::Unknown,
- "Note: No relevant classes found. No output generated.",
- FilePath::fromUserInput("/home/qtwebkithelpviewer.h")))
- << QString();
-
QTest::newRow("GCC 9 output")
<< QString("In file included from /usr/include/qt/QtCore/qlocale.h:43,\n"
" from /usr/include/qt/QtCore/qtextstream.h:46,\n"
@@ -1231,7 +1217,7 @@ void ProjectExplorerPlugin::testGccOutputParsers_data()
" 399 | inline Private(const Private &other) Q_DECL_NOTHROW\n"
" | ^~~~~~~)",
FilePath::fromUserInput("/usr/include/qt/QtCore/qvariant.h"),
- 273,
+ 273, 25,
QVector<QTextLayout::FormatRange>()
<< formatRange(140, 22)
<< formatRange(162, 32, "olpfile:///usr/include/qt/QtCore/qlocale.h::43::-1")
@@ -1259,7 +1245,7 @@ void ProjectExplorerPlugin::testGccOutputParsers_data()
" | |\n"
" | boxed_value<[...]>",
FilePath::fromUserInput("t.cc"),
- 15,
+ 15, 4,
QVector<QTextLayout::FormatRange>()
<< formatRange(93, 460)),
compileTask(Task::Error,
@@ -1271,7 +1257,7 @@ void ProjectExplorerPlugin::testGccOutputParsers_data()
" +++ |+#include <string>\n"
" 1 | std::string test(void)",
FilePath::fromUserInput("incomplete.c"),
- 1,
+ 1, 6,
QVector<QTextLayout::FormatRange>()
<< formatRange(49, 284)),
compileTask(Task::Warning,
@@ -1286,7 +1272,7 @@ void ProjectExplorerPlugin::testGccOutputParsers_data()
" 1 | extern int callee(int one, const char *two, float three);\n"
" | ~~~~~~~~~~~~^~~",
FilePath::fromUserInput("param-type-mismatch.c"),
- 5,
+ 5, 24,
QVector<QTextLayout::FormatRange>()
<< formatRange(92, 519))}
<< QString();
@@ -1319,7 +1305,7 @@ void ProjectExplorerPlugin::testGccOutputParsers_data()
" 465 | at(newSize) = 0;\n"
" | ~~~~~~~~~~~~^~~",
FilePath::fromUserInput("smallstring.h"),
- 465,
+ 465, 21,
QVector<QTextLayout::FormatRange>()
<< formatRange(62, 805))}
<< QString();
@@ -1361,7 +1347,7 @@ void ProjectExplorerPlugin::testGccOutputParsers_data()
" 110 | T value;\n"
" | ^~~~~",
FilePath::fromUserInput("qmap.h"),
- 110,
+ 110, 7,
QVector<QTextLayout::FormatRange>()
<< formatRange(46, 1458))}
<< QString();
diff --git a/src/plugins/projectexplorer/gccparser.h b/src/plugins/projectexplorer/gccparser.h
index 1625c947f1..8628d5d46f 100644
--- a/src/plugins/projectexplorer/gccparser.h
+++ b/src/plugins/projectexplorer/gccparser.h
@@ -52,6 +52,7 @@ protected:
bool forceAmend = false,
const Utils::FilePath &file = {},
int line = -1,
+ int column = 0,
const LinkSpecs &linkSpecs = {}
);
void flush() override;
diff --git a/src/plugins/projectexplorer/gcctoolchain.cpp b/src/plugins/projectexplorer/gcctoolchain.cpp
index 25dfd23e29..ba9a5b9fb9 100644
--- a/src/plugins/projectexplorer/gcctoolchain.cpp
+++ b/src/plugins/projectexplorer/gcctoolchain.cpp
@@ -37,11 +37,9 @@
#include <utils/algorithm.h>
#include <utils/environment.h>
#include <utils/hostosinfo.h>
-#include <utils/synchronousprocess.h>
#include <utils/pathchooser.h>
#include <utils/qtcassert.h>
#include <utils/qtcprocess.h>
-#include <utils/synchronousprocess.h>
#include <QBuffer>
#include <QComboBox>
@@ -78,33 +76,32 @@ 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 FilePath &gcc, const QStringList &arguments, const QStringList &env)
+static QByteArray runGcc(const FilePath &gcc, const QStringList &arguments, const Environment &env)
{
- if (gcc.isEmpty() || !gcc.toFileInfo().isExecutable())
+ if (!gcc.isExecutableFile())
return QByteArray();
SynchronousProcess cpp;
- QStringList environment(env);
- Utils::Environment::setupEnglishOutput(&environment);
+ Environment environment(env);
+ environment.setupEnglishOutput();
cpp.setEnvironment(environment);
cpp.setTimeoutS(10);
- CommandLine cmdLine(gcc, arguments);
- SynchronousProcessResponse response = cpp.runBlocking(cmdLine);
- if (response.result != SynchronousProcessResponse::Finished ||
- response.exitCode != 0) {
+ cpp.setCommand({gcc, arguments});
+ cpp.runBlocking();
+ if (cpp.result() != QtcProcess::Finished || cpp.exitCode() != 0) {
Core::MessageManager::writeFlashing({"Compiler feature detection failure!",
- response.exitMessage(cmdLine.toUserOutput(), 10),
- QString::fromUtf8(response.allRawOutput())});
+ cpp.exitMessage(),
+ QString::fromUtf8(cpp.allRawOutput())});
return QByteArray();
}
- return response.allOutput().toUtf8();
+ return cpp.allOutput().toUtf8();
}
static ProjectExplorer::Macros gccPredefinedMacros(const FilePath &gcc,
const QStringList &args,
- const QStringList &env)
+ const Environment &env)
{
QStringList arguments = args;
arguments << "-";
@@ -128,8 +125,9 @@ static ProjectExplorer::Macros gccPredefinedMacros(const FilePath &gcc,
return predefinedMacros;
}
-HeaderPaths GccToolChain::gccHeaderPaths(const FilePath &gcc, const QStringList &arguments,
- const QStringList &env)
+HeaderPaths GccToolChain::gccHeaderPaths(const FilePath &gcc,
+ const QStringList &arguments,
+ const Environment &env)
{
HeaderPaths builtInHeaderPaths;
QByteArray line;
@@ -211,9 +209,10 @@ static Abis guessGccAbi(const QString &m, const ProjectExplorer::Macros &macros)
}
-static GccToolChain::DetectedAbisResult guessGccAbi(const FilePath &path, const QStringList &env,
- const ProjectExplorer::Macros &macros,
- const QStringList &extraArgs = QStringList())
+static GccToolChain::DetectedAbisResult guessGccAbi(const FilePath &path,
+ const Environment &env,
+ const Macros &macros,
+ const QStringList &extraArgs = {})
{
if (path.isEmpty())
return GccToolChain::DetectedAbisResult();
@@ -230,7 +229,8 @@ static GccToolChain::DetectedAbisResult guessGccAbi(const FilePath &path, const
return GccToolChain::DetectedAbisResult(guessGccAbi(machine, macros), machine);
}
-static QString gccVersion(const FilePath &path, const QStringList &env,
+static QString gccVersion(const FilePath &path,
+ const Environment &env,
const QStringList &extraArgs)
{
QStringList arguments = extraArgs;
@@ -238,8 +238,9 @@ static QString gccVersion(const FilePath &path, const QStringList &env,
return QString::fromLocal8Bit(runGcc(path, arguments, env)).trimmed();
}
-static Utils::FilePath gccInstallDir(const FilePath &path, const QStringList &env,
- const QStringList &extraArgs = {})
+static FilePath gccInstallDir(const FilePath &path,
+ const Environment &env,
+ const QStringList &extraArgs = {})
{
QStringList arguments = extraArgs;
arguments << "-print-search-dirs";
@@ -254,7 +255,7 @@ static Utils::FilePath gccInstallDir(const FilePath &path, const QStringList &en
const QString line = QTextStream(&output).readLine();
if (!line.startsWith(prefix))
return {};
- return Utils::FilePath::fromString(QDir::cleanPath(line.mid(prefix.size())));
+ return FilePath::fromString(QDir::cleanPath(line.mid(prefix.size()))).onDevice(path);
}
// --------------------------------------------------------------------------
@@ -306,11 +307,11 @@ QString GccToolChain::defaultDisplayName() const
const Abi abi = targetAbi();
if (abi.architecture() == Abi::UnknownArchitecture || abi.wordWidth() == 0)
return type;
- return tr("%1 (%2, %3 %4 in %5)").arg(type,
+ return tr("%1 (%2, %3 %4 at %5)").arg(type,
ToolChainManager::displayNameOfLanguageId(language()),
Abi::toString(abi.architecture()),
Abi::toString(abi.wordWidth()),
- compilerCommand().parentDir().toUserOutput());
+ compilerCommand().toUserOutput());
}
LanguageExtensions GccToolChain::defaultLanguageExtensions() const
@@ -440,7 +441,7 @@ ToolChain::MacroInspectionRunner GccToolChain::createMacroInspectionRunner() con
const Macros macros = gccPredefinedMacros(findLocalCompiler(compilerCommand, env),
arguments,
- env.toStringList());
+ env);
const auto report = MacroInspectionReport{macros, languageVersion(lang, macros)};
macroCache->insert(arguments, report);
@@ -586,7 +587,7 @@ HeaderPaths GccToolChain::builtInHeaderPaths(const Utils::Environment &env,
HeaderPaths paths = gccHeaderPaths(findLocalCompiler(compilerCommand, env),
arguments,
- env.toStringList());
+ env);
extraHeaderPathsFunction(paths);
headerCache->insert(qMakePair(env, arguments), paths);
@@ -822,7 +823,7 @@ GccToolChain::DetectedAbisResult GccToolChain::detectSupportedAbis() const
addToEnvironment(env);
ProjectExplorer::Macros macros = createMacroInspectionRunner()({}).macros;
return guessGccAbi(findLocalCompiler(compilerCommand(), env),
- env.toStringList(),
+ env,
macros,
platformCodeGenFlags());
}
@@ -831,7 +832,7 @@ QString GccToolChain::detectVersion() const
{
Environment env = Environment::systemEnvironment();
addToEnvironment(env);
- return gccVersion(findLocalCompiler(compilerCommand(), env), env.toStringList(),
+ return gccVersion(findLocalCompiler(compilerCommand(), env), env,
filteredFlags(platformCodeGenFlags(), true));
}
@@ -839,7 +840,7 @@ Utils::FilePath GccToolChain::detectInstallDir() const
{
Environment env = Environment::systemEnvironment();
addToEnvironment(env);
- return gccInstallDir(findLocalCompiler(compilerCommand(), env), env.toStringList(),
+ return gccInstallDir(findLocalCompiler(compilerCommand(), env), env,
filteredFlags(platformCodeGenFlags(), true));
}
@@ -998,7 +999,8 @@ GccToolChainFactory::GccToolChainFactory()
setUserCreatable(true);
}
-QList<ToolChain *> GccToolChainFactory::autoDetect(const QList<ToolChain *> &alreadyKnown)
+QList<ToolChain *> GccToolChainFactory::autoDetect(const QList<ToolChain *> &alreadyKnown,
+ const IDevice::Ptr &device)
{
// GCC is almost never what you want on macOS, but it is by default found in /usr/bin
if (HostOsInfo::isMacHost())
@@ -1010,9 +1012,11 @@ QList<ToolChain *> GccToolChainFactory::autoDetect(const QList<ToolChain *> &alr
&& tc->compilerCommand().fileName() != "c99-gcc";
};
tcs.append(autoDetectToolchains("g++", DetectVariants::Yes, Constants::CXX_LANGUAGE_ID,
- Constants::GCC_TOOLCHAIN_TYPEID, alreadyKnown, tcChecker));
+ Constants::GCC_TOOLCHAIN_TYPEID, alreadyKnown,
+ device, tcChecker));
tcs.append(autoDetectToolchains("gcc", DetectVariants::Yes, Constants::C_LANGUAGE_ID,
- Constants::GCC_TOOLCHAIN_TYPEID, alreadyKnown, tcChecker));
+ Constants::GCC_TOOLCHAIN_TYPEID, alreadyKnown,
+ device, tcChecker));
return tcs;
}
@@ -1032,10 +1036,16 @@ QList<ToolChain *> GccToolChainFactory::detectForImport(const ToolChainDescripti
}
QList<ToolChain *> GccToolChainFactory::autoDetectToolchains(
- const QString &compilerName, DetectVariants detectVariants, Utils::Id language,
- const Utils::Id requiredTypeId, const QList<ToolChain *> &alreadyKnown,
+ const QString &compilerName,
+ DetectVariants detectVariants,
+ const Id language,
+ const Id requiredTypeId,
+ const QList<ToolChain *> &alreadyKnown,
+ const IDevice::Ptr &device,
const ToolchainChecker &checker)
{
+ Q_UNUSED(device)
+
FilePaths compilerPaths;
QFileInfo fi(compilerName);
if (fi.isAbsolute()) {
@@ -1123,8 +1133,8 @@ QList<ToolChain *> GccToolChainFactory::autoDetectToolchains(
}
}
if (!alreadyExists) {
- const QList<ToolChain *> newToolchains = autoDetectToolChain({compilerPath, language},
- checker);
+ const QList<ToolChain *> newToolchains
+ = autoDetectToolChain({compilerPath, language}, checker);
result << newToolchains;
existingCandidates << newToolchains;
}
@@ -1143,14 +1153,14 @@ QList<ToolChain *> GccToolChainFactory::autoDetectToolChain(const ToolChainDescr
const FilePath localCompilerPath = findLocalCompiler(tcd.compilerPath, systemEnvironment);
Macros macros
= gccPredefinedMacros(localCompilerPath, gccPredefinedMacrosOptions(tcd.language),
- systemEnvironment.toStringList());
+ systemEnvironment);
if (macros.isEmpty())
return result;
const GccToolChain::DetectedAbisResult detectedAbis = guessGccAbi(localCompilerPath,
- systemEnvironment.toStringList(),
+ systemEnvironment,
macros);
const Utils::FilePath installDir = gccInstallDir(localCompilerPath,
- systemEnvironment.toStringList());
+ systemEnvironment);
for (const Abi &abi : detectedAbis.supportedAbis) {
std::unique_ptr<GccToolChain> tc(dynamic_cast<GccToolChain *>(create()));
@@ -1192,10 +1202,10 @@ GccToolChainConfigWidget::GccToolChainConfigWidget(GccToolChain *tc) :
m_compilerCommand->setHistoryCompleter("PE.Gcc.Command.History");
m_mainLayout->addRow(tr("&Compiler path:"), m_compilerCommand);
m_platformCodeGenFlagsLineEdit = new QLineEdit(this);
- m_platformCodeGenFlagsLineEdit->setText(QtcProcess::joinArgs(tc->platformCodeGenFlags()));
+ m_platformCodeGenFlagsLineEdit->setText(ProcessArgs::joinArgs(tc->platformCodeGenFlags()));
m_mainLayout->addRow(tr("Platform codegen flags:"), m_platformCodeGenFlagsLineEdit);
m_platformLinkerFlagsLineEdit = new QLineEdit(this);
- m_platformLinkerFlagsLineEdit->setText(QtcProcess::joinArgs(tc->platformLinkerFlags()));
+ m_platformLinkerFlagsLineEdit->setText(ProcessArgs::joinArgs(tc->platformLinkerFlags()));
m_mainLayout->addRow(tr("Platform linker flags:"), m_platformLinkerFlagsLineEdit);
m_mainLayout->addRow(tr("&ABI:"), m_abiWidget);
@@ -1248,8 +1258,8 @@ void GccToolChainConfigWidget::setFromToolchain()
QSignalBlocker blocker(this);
auto tc = static_cast<GccToolChain *>(toolChain());
m_compilerCommand->setFilePath(tc->compilerCommand());
- m_platformCodeGenFlagsLineEdit->setText(QtcProcess::joinArgs(tc->platformCodeGenFlags()));
- m_platformLinkerFlagsLineEdit->setText(QtcProcess::joinArgs(tc->platformLinkerFlags()));
+ m_platformCodeGenFlagsLineEdit->setText(ProcessArgs::joinArgs(tc->platformCodeGenFlags()));
+ m_platformLinkerFlagsLineEdit->setText(ProcessArgs::joinArgs(tc->platformLinkerFlags()));
if (m_abiWidget) {
m_abiWidget->setAbis(tc->supportedAbis(), tc->targetAbi());
if (!m_isReadOnly && !m_compilerCommand->filePath().toString().isEmpty())
@@ -1263,9 +1273,9 @@ bool GccToolChainConfigWidget::isDirtyImpl() const
Q_ASSERT(tc);
return m_compilerCommand->filePath() != tc->compilerCommand()
|| m_platformCodeGenFlagsLineEdit->text()
- != QtcProcess::joinArgs(tc->platformCodeGenFlags())
+ != ProcessArgs::joinArgs(tc->platformCodeGenFlags())
|| m_platformLinkerFlagsLineEdit->text()
- != QtcProcess::joinArgs(tc->platformLinkerFlags())
+ != ProcessArgs::joinArgs(tc->platformLinkerFlags())
|| (m_abiWidget && m_abiWidget->currentAbi() != tc->targetAbi());
}
@@ -1300,8 +1310,8 @@ void GccToolChainConfigWidget::handleCompilerCommandChange()
QStringList args = gccPredefinedMacrosOptions(Constants::CXX_LANGUAGE_ID)
+ splitString(m_platformCodeGenFlagsLineEdit->text());
const FilePath localCompilerPath = findLocalCompiler(path, env);
- m_macros = gccPredefinedMacros(localCompilerPath, args, env.toStringList());
- abiList = guessGccAbi(localCompilerPath, env.toStringList(), m_macros,
+ m_macros = gccPredefinedMacros(localCompilerPath, args, env);
+ abiList = guessGccAbi(localCompilerPath, env, m_macros,
splitString(m_platformCodeGenFlagsLineEdit->text())).supportedAbis;
}
m_abiWidget->setEnabled(haveCompiler);
@@ -1318,7 +1328,7 @@ void GccToolChainConfigWidget::handleCompilerCommandChange()
void GccToolChainConfigWidget::handlePlatformCodeGenFlagsChange()
{
QString str1 = m_platformCodeGenFlagsLineEdit->text();
- QString str2 = QtcProcess::joinArgs(splitString(str1));
+ QString str2 = ProcessArgs::joinArgs(splitString(str1));
if (str1 != str2)
m_platformCodeGenFlagsLineEdit->setText(str2);
else
@@ -1328,7 +1338,7 @@ void GccToolChainConfigWidget::handlePlatformCodeGenFlagsChange()
void GccToolChainConfigWidget::handlePlatformLinkerFlagsChange()
{
QString str1 = m_platformLinkerFlagsLineEdit->text();
- QString str2 = QtcProcess::joinArgs(splitString(str1));
+ QString str2 = ProcessArgs::joinArgs(splitString(str1));
if (str1 != str2)
m_platformLinkerFlagsLineEdit->setText(str2);
else
@@ -1591,15 +1601,16 @@ ClangToolChainFactory::ClangToolChainFactory()
setToolchainConstructor([] { return new ClangToolChain; });
}
-QList<ToolChain *> ClangToolChainFactory::autoDetect(const QList<ToolChain *> &alreadyKnown)
+QList<ToolChain *> ClangToolChainFactory::autoDetect(const QList<ToolChain *> &alreadyKnown,
+ const IDevice::Ptr &device)
{
QList<ToolChain *> tcs;
QList<ToolChain *> known = alreadyKnown;
tcs.append(autoDetectToolchains("clang++", DetectVariants::Yes, Constants::CXX_LANGUAGE_ID,
- Constants::CLANG_TOOLCHAIN_TYPEID, alreadyKnown));
+ Constants::CLANG_TOOLCHAIN_TYPEID, alreadyKnown, device));
tcs.append(autoDetectToolchains("clang", DetectVariants::Yes, Constants::C_LANGUAGE_ID,
- Constants::CLANG_TOOLCHAIN_TYPEID, alreadyKnown));
+ Constants::CLANG_TOOLCHAIN_TYPEID, alreadyKnown, device));
known.append(tcs);
const FilePath compilerPath = FilePath::fromString(Core::ICore::clangExecutable(CLANG_BINDIR));
@@ -1608,7 +1619,7 @@ QList<ToolChain *> ClangToolChainFactory::autoDetect(const QList<ToolChain *> &a
HostOsInfo::withExecutableSuffix("clang"));
tcs.append(autoDetectToolchains(clang.toString(), DetectVariants::No,
Constants::C_LANGUAGE_ID, Constants::CLANG_TOOLCHAIN_TYPEID,
- tcs));
+ tcs, device));
}
return tcs;
@@ -1779,16 +1790,17 @@ MingwToolChainFactory::MingwToolChainFactory()
setToolchainConstructor([] { return new MingwToolChain; });
}
-QList<ToolChain *> MingwToolChainFactory::autoDetect(const QList<ToolChain *> &alreadyKnown)
+QList<ToolChain *> MingwToolChainFactory::autoDetect(const QList<ToolChain *> &alreadyKnown,
+ const IDevice::Ptr &device)
{
static const auto tcChecker = [](const ToolChain *tc) {
return tc->targetAbi().osFlavor() == Abi::WindowsMSysFlavor;
};
QList<ToolChain *> result = autoDetectToolchains(
"g++", DetectVariants::Yes, Constants::CXX_LANGUAGE_ID,
- Constants::MINGW_TOOLCHAIN_TYPEID, alreadyKnown, tcChecker);
+ Constants::MINGW_TOOLCHAIN_TYPEID, alreadyKnown, device, tcChecker);
result += autoDetectToolchains("gcc", DetectVariants::Yes, Constants::C_LANGUAGE_ID,
- Constants::MINGW_TOOLCHAIN_TYPEID, alreadyKnown, tcChecker);
+ Constants::MINGW_TOOLCHAIN_TYPEID, alreadyKnown, device, tcChecker);
return result;
}
@@ -1860,13 +1872,14 @@ LinuxIccToolChainFactory::LinuxIccToolChainFactory()
setToolchainConstructor([] { return new LinuxIccToolChain; });
}
-QList<ToolChain *> LinuxIccToolChainFactory::autoDetect(const QList<ToolChain *> &alreadyKnown)
+QList<ToolChain *> LinuxIccToolChainFactory::autoDetect(const QList<ToolChain *> &alreadyKnown,
+ const IDevice::Ptr &device)
{
QList<ToolChain *> result
= autoDetectToolchains("icpc", DetectVariants::No, Constants::CXX_LANGUAGE_ID,
- Constants::LINUXICC_TOOLCHAIN_TYPEID, alreadyKnown);
+ Constants::LINUXICC_TOOLCHAIN_TYPEID, alreadyKnown, device);
result += autoDetectToolchains("icc", DetectVariants::Yes, Constants::C_LANGUAGE_ID,
- Constants::LINUXICC_TOOLCHAIN_TYPEID, alreadyKnown);
+ Constants::LINUXICC_TOOLCHAIN_TYPEID, alreadyKnown, device);
return result;
}
diff --git a/src/plugins/projectexplorer/gcctoolchain.h b/src/plugins/projectexplorer/gcctoolchain.h
index 458b220a0b..11c53a070b 100644
--- a/src/plugins/projectexplorer/gcctoolchain.h
+++ b/src/plugins/projectexplorer/gcctoolchain.h
@@ -153,8 +153,9 @@ protected:
const QString &sysRoot,
const QString &originalTargetTriple);
- static HeaderPaths gccHeaderPaths(const Utils::FilePath &gcc, const QStringList &args,
- const QStringList &env);
+ static HeaderPaths gccHeaderPaths(const Utils::FilePath &gcc,
+ const QStringList &args,
+ const Utils::Environment &env);
class WarningFlagAdder
{
diff --git a/src/plugins/projectexplorer/gcctoolchainfactories.h b/src/plugins/projectexplorer/gcctoolchainfactories.h
index 8e3350e411..6308ba861c 100644
--- a/src/plugins/projectexplorer/gcctoolchainfactories.h
+++ b/src/plugins/projectexplorer/gcctoolchainfactories.h
@@ -52,15 +52,17 @@ class GccToolChainFactory : public ToolChainFactory
public:
GccToolChainFactory();
- QList<ToolChain *> autoDetect(const QList<ToolChain *> &alreadyKnown) override;
- QList<ToolChain *> detectForImport(const ProjectExplorer::ToolChainDescription &tcd) override;
+ QList<ToolChain *> autoDetect(const QList<ToolChain *> &alreadyKnown,
+ const IDevice::Ptr &device) override;
+ QList<ToolChain *> detectForImport(const ToolChainDescription &tcd) override;
protected:
enum class DetectVariants { Yes, No };
using ToolchainChecker = std::function<bool(const ToolChain *)>;
QList<ToolChain *> autoDetectToolchains(
- const QString &compilerName, DetectVariants detectVariants, Utils::Id language,
+ const QString &compilerName, DetectVariants detectVariants, const Utils::Id language,
const Utils::Id requiredTypeId, const QList<ToolChain *> &alreadyKnown,
+ const ProjectExplorer::IDevice::Ptr &device,
const ToolchainChecker &checker = {});
QList<ToolChain *> autoDetectToolChain(
const ToolChainDescription &tcd,
@@ -132,7 +134,8 @@ class ClangToolChainFactory : public GccToolChainFactory
public:
ClangToolChainFactory();
- QList<ToolChain *> autoDetect(const QList<ToolChain *> &alreadyKnown) override;
+ QList<ToolChain *> autoDetect(const QList<ToolChain *> &alreadyKnown,
+ const IDevice::Ptr &device) override;
QList<ToolChain *> detectForImport(const ToolChainDescription &tcd) final;
};
@@ -145,7 +148,8 @@ class MingwToolChainFactory : public GccToolChainFactory
public:
MingwToolChainFactory();
- QList<ToolChain *> autoDetect(const QList<ToolChain *> &alreadyKnown) override;
+ QList<ToolChain *> autoDetect(const QList<ToolChain *> &alreadyKnown,
+ const IDevice::Ptr &device) override;
QList<ToolChain *> detectForImport(const ToolChainDescription &tcd) final;
};
@@ -158,7 +162,7 @@ class LinuxIccToolChainFactory : public GccToolChainFactory
public:
LinuxIccToolChainFactory();
- QList<ToolChain *> autoDetect(const QList<ToolChain *> &alreadyKnown) override;
+ QList<ToolChain *> autoDetect(const QList<ToolChain *> &alreadyKnown, const IDevice::Ptr &) override;
QList<ToolChain *> detectForImport(const ToolChainDescription &tcd) final;
};
diff --git a/src/plugins/projectexplorer/jsonwizard/jsonwizard.cpp b/src/plugins/projectexplorer/jsonwizard/jsonwizard.cpp
index 85ec211594..5ea23a0522 100644
--- a/src/plugins/projectexplorer/jsonwizard/jsonwizard.cpp
+++ b/src/plugins/projectexplorer/jsonwizard/jsonwizard.cpp
@@ -514,7 +514,7 @@ void JsonWizard::openProjectForNode(Node *node)
Utils::optional<FilePath> projFilePath = projNode->visibleAfterAddFileAction();
- if (projFilePath && !Core::EditorManager::openEditor(projFilePath.value().toString())) {
+ if (projFilePath && !Core::EditorManager::openEditor(projFilePath.value())) {
auto errorMessage = QCoreApplication::translate("ProjectExplorer::JsonWizard",
"Failed to open an editor for \"%1\".")
.arg(QDir::toNativeSeparators(projFilePath.value().toString()));
diff --git a/src/plugins/projectexplorer/jsonwizard/jsonwizard_test.cpp b/src/plugins/projectexplorer/jsonwizard/jsonwizard_test.cpp
index 0669f9584b..d5783c9b21 100644
--- a/src/plugins/projectexplorer/jsonwizard/jsonwizard_test.cpp
+++ b/src/plugins/projectexplorer/jsonwizard/jsonwizard_test.cpp
@@ -257,7 +257,7 @@ void ProjectExplorer::ProjectExplorerPlugin::testJsonWizardsComboBox()
static QString iconInsideResource(const QString &relativePathToIcon)
{
- const QDir resourcePath(Core::ICore::resourcePath());
+ const QDir resourcePath(Core::ICore::resourcePath().toDir());
return resourcePath.filePath(relativePathToIcon);
}
diff --git a/src/plugins/projectexplorer/jsonwizard/jsonwizardfactory.cpp b/src/plugins/projectexplorer/jsonwizard/jsonwizardfactory.cpp
index 77aada4606..7a48be343b 100644
--- a/src/plugins/projectexplorer/jsonwizard/jsonwizardfactory.cpp
+++ b/src/plugins/projectexplorer/jsonwizard/jsonwizardfactory.cpp
@@ -336,11 +336,8 @@ static QStringList environmentTemplatesPaths()
Utils::FilePaths &JsonWizardFactory::searchPaths()
{
- static Utils::FilePaths m_searchPaths = Utils::FilePaths()
- << Utils::FilePath::fromString(Core::ICore::userResourcePath() + QLatin1Char('/') +
- QLatin1String(WIZARD_PATH))
- << Utils::FilePath::fromString(Core::ICore::resourcePath() + QLatin1Char('/') +
- QLatin1String(WIZARD_PATH));
+ static Utils::FilePaths m_searchPaths = {Core::ICore::userResourcePath(WIZARD_PATH),
+ Core::ICore::resourcePath(WIZARD_PATH)};
for (const QString &environmentTemplateDirName : environmentTemplatesPaths())
m_searchPaths << Utils::FilePath::fromString(environmentTemplateDirName);
diff --git a/src/plugins/projectexplorer/jsonwizard/jsonwizardfilegenerator.cpp b/src/plugins/projectexplorer/jsonwizard/jsonwizardfilegenerator.cpp
index 173e7a4b0d..982356adc7 100644
--- a/src/plugins/projectexplorer/jsonwizard/jsonwizardfilegenerator.cpp
+++ b/src/plugins/projectexplorer/jsonwizard/jsonwizardfilegenerator.cpp
@@ -99,7 +99,7 @@ Core::GeneratedFile JsonWizardFileGenerator::generateFile(const File &file,
QIODevice::ReadOnly : (QIODevice::ReadOnly|QIODevice::Text);
Utils::FileReader reader;
- if (!reader.fetch(file.source, openMode, errorMessage))
+ if (!reader.fetch(Utils::FilePath::fromString(file.source), openMode, errorMessage))
return Core::GeneratedFile();
// Generate file information:
diff --git a/src/plugins/projectexplorer/kit.cpp b/src/plugins/projectexplorer/kit.cpp
index 2fad1bf403..0791987c01 100644
--- a/src/plugins/projectexplorer/kit.cpp
+++ b/src/plugins/projectexplorer/kit.cpp
@@ -563,10 +563,30 @@ QVariantMap Kit::toMap() const
return data;
}
-void Kit::addToEnvironment(Environment &env) const
+void Kit::addToBuildEnvironment(Environment &env) const
{
for (KitAspect *aspect : KitManager::kitAspects())
- aspect->addToEnvironment(this, env);
+ aspect->addToBuildEnvironment(this, env);
+}
+
+void Kit::addToRunEnvironment(Environment &env) const
+{
+ for (KitAspect *aspect : KitManager::kitAspects())
+ aspect->addToRunEnvironment(this, env);
+}
+
+Environment Kit::buildEnvironment() const
+{
+ Environment env = Environment::systemEnvironment(); // FIXME: Use build device
+ addToBuildEnvironment(env);
+ return env;
+}
+
+Environment Kit::runEnvironment() const
+{
+ Environment env = Environment::systemEnvironment(); // FIXME: Use run device
+ addToRunEnvironment(env);
+ return env;
}
QList<OutputLineParser *> Kit::createOutputParsers() const
diff --git a/src/plugins/projectexplorer/kit.h b/src/plugins/projectexplorer/kit.h
index f7c75c5029..59948ceabc 100644
--- a/src/plugins/projectexplorer/kit.h
+++ b/src/plugins/projectexplorer/kit.h
@@ -115,7 +115,12 @@ public:
bool isDataEqual(const Kit *other) const;
bool isEqual(const Kit *other) const;
- void addToEnvironment(Utils::Environment &env) const;
+ void addToBuildEnvironment(Utils::Environment &env) const;
+ Utils::Environment buildEnvironment() const;
+
+ void addToRunEnvironment(Utils::Environment &env) const;
+ Utils::Environment runEnvironment() const;
+
QList<Utils::OutputLineParser *> createOutputParsers() const;
QString toHtml(const Tasks &additional = Tasks(), const QString &extraText = QString()) const;
diff --git a/src/plugins/projectexplorer/kitinformation.cpp b/src/plugins/projectexplorer/kitinformation.cpp
index d84a7b69ab..5b5f7ebade 100644
--- a/src/plugins/projectexplorer/kitinformation.cpp
+++ b/src/plugins/projectexplorer/kitinformation.cpp
@@ -35,12 +35,15 @@
#include "toolchain.h"
#include "toolchainmanager.h"
-#include <coreplugin/icore.h>
+#include <docker/dockerconstants.h>
+
#include <ssh/sshconnection.h>
+
#include <utils/algorithm.h>
#include <utils/elidinglabel.h>
#include <utils/environment.h>
#include <utils/environmentdialog.h>
+#include <utils/layoutbuilder.h>
#include <utils/macroexpander.h>
#include <utils/pathchooser.h>
#include <utils/qtcassert.h>
@@ -56,6 +59,8 @@
#include <QPushButton>
#include <QVBoxLayout>
+using namespace Utils;
+
namespace ProjectExplorer {
const char KITINFORMATION_ID_V1[] = "PE.Profile.ToolChain";
@@ -74,7 +79,7 @@ class SysRootKitAspectWidget : public KitAspectWidget
public:
SysRootKitAspectWidget(Kit *k, const KitAspect *ki) : KitAspectWidget(k, ki)
{
- m_chooser = new Utils::PathChooser;
+ m_chooser = createSubWidget<PathChooser>();
m_chooser->setExpectedKind(Utils::PathChooser::ExistingDirectory);
m_chooser->setHistoryCompleter(QLatin1String("PE.SysRoot.History"));
m_chooser->setFilePath(SysRootKitAspect::sysRoot(k));
@@ -86,8 +91,12 @@ public:
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 addToLayout(LayoutBuilder &builder) override
+ {
+ addMutableAction(m_chooser);
+ builder.addItem(Layouting::Span(2, m_chooser));
+ }
void refresh() override
{
@@ -214,7 +223,7 @@ class ToolChainKitAspectWidget final : public KitAspectWidget
public:
ToolChainKitAspectWidget(Kit *k, const KitAspect *ki) : KitAspectWidget(k, ki)
{
- m_mainWidget = new QWidget;
+ m_mainWidget = createSubWidget<QWidget>();
m_mainWidget->setContentsMargins(0, 0, 0, 0);
auto layout = new QGridLayout(m_mainWidget);
@@ -244,10 +253,7 @@ public:
refresh();
- m_manageButton = new QPushButton(KitAspectWidget::msgManage());
- m_manageButton->setContentsMargins(0, 0, 0, 0);
- connect(m_manageButton, &QAbstractButton::clicked,
- this, &ToolChainKitAspectWidget::manageToolChains);
+ m_manageButton = createManageButton(Constants::TOOLCHAIN_SETTINGS_PAGE_ID);
}
~ToolChainKitAspectWidget() override
@@ -257,8 +263,12 @@ public:
}
private:
- QWidget *mainWidget() const override { return m_mainWidget; }
- QWidget *buttonWidget() const override { return m_manageButton; }
+ void addToLayout(LayoutBuilder &builder) override
+ {
+ addMutableAction(m_mainWidget);
+ builder.addItem(m_mainWidget);
+ builder.addItem(m_manageButton);
+ }
void refresh() override
{
@@ -289,11 +299,6 @@ private:
}
}
- void manageToolChains()
- {
- Core::ICore::showOptionsDialog(Constants::TOOLCHAIN_SETTINGS_PAGE_ID, buttonWidget());
- }
-
void currentToolChainChanged(Utils::Id language, int idx)
{
if (m_ignoreChanges || idx < 0)
@@ -319,7 +324,7 @@ private:
}
QWidget *m_mainWidget = nullptr;
- QPushButton *m_manageButton = nullptr;
+ QWidget *m_manageButton = nullptr;
QHash<Utils::Id, QComboBox *> m_languageComboboxMap;
bool m_ignoreChanges = false;
bool m_isReadOnly = false;
@@ -521,7 +526,7 @@ KitAspect::ItemList ToolChainKitAspect::toUserOutput(const Kit *k) const
return {{tr("Compiler"), tc ? tc->displayName() : tr("None")}};
}
-void ToolChainKitAspect::addToEnvironment(const Kit *k, Utils::Environment &env) const
+void ToolChainKitAspect::addToBuildEnvironment(const Kit *k, Utils::Environment &env) const
{
ToolChain *tc = cxxToolChain(k);
if (tc)
@@ -760,7 +765,7 @@ class DeviceTypeKitAspectWidget final : public KitAspectWidget
public:
DeviceTypeKitAspectWidget(Kit *workingCopy, const KitAspect *ki)
- : KitAspectWidget(workingCopy, ki), m_comboBox(new QComboBox)
+ : KitAspectWidget(workingCopy, ki), m_comboBox(createSubWidget<QComboBox>())
{
for (IDeviceFactory *factory : IDeviceFactory::allDeviceFactories())
m_comboBox->addItem(factory->displayName(), factory->deviceType().toSetting());
@@ -773,7 +778,12 @@ public:
~DeviceTypeKitAspectWidget() override { delete m_comboBox; }
private:
- QWidget *mainWidget() const override { return m_comboBox; }
+ void addToLayout(LayoutBuilder &builder) override
+ {
+ addMutableAction(m_comboBox);
+ builder.addItem(m_comboBox);
+ }
+
void makeReadOnly() override { m_comboBox->setEnabled(false); }
void refresh() override
@@ -878,12 +888,13 @@ class DeviceKitAspectWidget final : public KitAspectWidget
public:
DeviceKitAspectWidget(Kit *workingCopy, const KitAspect *ki)
- : KitAspectWidget(workingCopy, ki), m_comboBox(new QComboBox),
+ : KitAspectWidget(workingCopy, ki),
+ m_comboBox(createSubWidget<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());
+ m_manageButton = createManageButton(Constants::DEVICE_SETTINGS_PAGE_ID);
refresh();
m_comboBox->setToolTip(ki->description());
@@ -893,8 +904,6 @@ public:
this, &DeviceKitAspectWidget::modelReset);
connect(m_comboBox, QOverload<int>::of(&QComboBox::currentIndexChanged),
this, &DeviceKitAspectWidget::currentDeviceChanged);
- connect(m_manageButton, &QAbstractButton::clicked,
- this, &DeviceKitAspectWidget::manageDevices);
}
~DeviceKitAspectWidget() override
@@ -905,8 +914,13 @@ public:
}
private:
- QWidget *mainWidget() const override { return m_comboBox; }
- QWidget *buttonWidget() const override { return m_manageButton; }
+ void addToLayout(LayoutBuilder &builder) override
+ {
+ addMutableAction(m_comboBox);
+ builder.addItem(m_comboBox);
+ builder.addItem(m_manageButton);
+ }
+
void makeReadOnly() override { m_comboBox->setEnabled(false); }
void refresh() override
@@ -915,11 +929,6 @@ private:
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());
@@ -941,7 +950,7 @@ private:
bool m_ignoreChange = false;
QComboBox *m_comboBox;
- QPushButton *m_manageButton;
+ QWidget *m_manageButton;
DeviceManagerModel *m_model;
Utils::Id m_selectedId;
};
@@ -1120,6 +1129,239 @@ void DeviceKitAspect::devicesChanged()
}
// --------------------------------------------------------------------------
+// BuildDeviceKitAspect:
+// --------------------------------------------------------------------------
+namespace Internal {
+class BuildDeviceKitAspectWidget final : public KitAspectWidget
+{
+ Q_DECLARE_TR_FUNCTIONS(ProjectExplorer::BuildDeviceKitAspect)
+
+public:
+ BuildDeviceKitAspectWidget(Kit *workingCopy, const KitAspect *ki)
+ : KitAspectWidget(workingCopy, ki),
+ m_comboBox(createSubWidget<QComboBox>()),
+ m_model(new DeviceManagerModel(DeviceManager::instance()))
+ {
+ m_comboBox->setSizePolicy(QSizePolicy::Ignored, m_comboBox->sizePolicy().verticalPolicy());
+ m_comboBox->setModel(m_model);
+ m_manageButton = createManageButton(Constants::DEVICE_SETTINGS_PAGE_ID);
+ refresh();
+ m_comboBox->setToolTip(ki->description());
+
+ connect(m_model, &QAbstractItemModel::modelAboutToBeReset,
+ this, &BuildDeviceKitAspectWidget::modelAboutToReset);
+ connect(m_model, &QAbstractItemModel::modelReset,
+ this, &BuildDeviceKitAspectWidget::modelReset);
+ connect(m_comboBox, QOverload<int>::of(&QComboBox::currentIndexChanged),
+ this, &BuildDeviceKitAspectWidget::currentDeviceChanged);
+ }
+
+ ~BuildDeviceKitAspectWidget() override
+ {
+ delete m_comboBox;
+ delete m_model;
+ delete m_manageButton;
+ }
+
+private:
+ void addToLayout(LayoutBuilder &builder) override
+ {
+ addMutableAction(m_comboBox);
+ builder.addItem(m_comboBox);
+ builder.addItem(m_manageButton);
+ }
+
+ void makeReadOnly() override { m_comboBox->setEnabled(false); }
+
+ void refresh() override
+ {
+ QList<Utils::Id> blackList;
+ const DeviceManager *dm = DeviceManager::instance();
+ for (int i = 0; i < dm->deviceCount(); ++i) {
+ IDevice::ConstPtr device = dm->deviceAt(i);
+ if (!(device->type() == Constants::DESKTOP_DEVICE_TYPE
+ || device->type() == Docker::Constants::DOCKER_DEVICE_TYPE))
+ blackList.append(device->id());
+ }
+
+ m_model->setFilter(blackList);
+ m_comboBox->setCurrentIndex(m_model->indexOf(BuildDeviceKitAspect::device(m_kit)));
+ }
+
+ 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;
+ BuildDeviceKitAspect::setDeviceId(m_kit, m_model->deviceId(m_comboBox->currentIndex()));
+ }
+
+ bool m_ignoreChange = false;
+ QComboBox *m_comboBox;
+ QWidget *m_manageButton;
+ DeviceManagerModel *m_model;
+ Utils::Id m_selectedId;
+};
+} // namespace Internal
+
+BuildDeviceKitAspect::BuildDeviceKitAspect()
+{
+ setObjectName("BuildDeviceInformation");
+ setId(BuildDeviceKitAspect::id());
+ setDisplayName(tr("Build device"));
+ setDescription(tr("The device used to build applications on."));
+ setPriority(31900);
+
+ connect(KitManager::instance(), &KitManager::kitsLoaded,
+ this, &BuildDeviceKitAspect::kitsWereLoaded);
+}
+
+QVariant BuildDeviceKitAspect::defaultValue(const Kit *k) const
+{
+ Q_UNUSED(k);
+ IDevice::ConstPtr defaultDevice =
+ DeviceManager::instance()->defaultDevice(Constants::DESKTOP_DEVICE_TYPE);
+ return defaultDevice->id().toString();
+}
+
+Tasks BuildDeviceKitAspect::validate(const Kit *k) const
+{
+ IDevice::ConstPtr dev = BuildDeviceKitAspect::device(k);
+ Tasks result;
+ if (dev.isNull())
+ result.append(BuildSystemTask(Task::Warning, tr("No build device set.")));
+
+ return result;
+}
+
+KitAspectWidget *BuildDeviceKitAspect::createConfigWidget(Kit *k) const
+{
+ QTC_ASSERT(k, return nullptr);
+ return new Internal::BuildDeviceKitAspectWidget(k, this);
+}
+
+QString BuildDeviceKitAspect::displayNamePostfix(const Kit *k) const
+{
+ IDevice::ConstPtr dev = device(k);
+ return dev.isNull() ? QString() : dev->displayName();
+}
+
+KitAspect::ItemList BuildDeviceKitAspect::toUserOutput(const Kit *k) const
+{
+ IDevice::ConstPtr dev = device(k);
+ return {{tr("Build device"), dev.isNull() ? tr("Unconfigured") : dev->displayName()}};
+}
+
+void BuildDeviceKitAspect::addToMacroExpander(Kit *kit, Utils::MacroExpander *expander) const
+{
+ QTC_ASSERT(kit, return);
+ expander->registerVariable("BuildDevice:HostAddress", tr("Build host address"),
+ [kit]() -> QString {
+ const IDevice::ConstPtr device = BuildDeviceKitAspect::device(kit);
+ return device ? device->sshParameters().host() : QString();
+ });
+ expander->registerVariable("BuildDevice:SshPort", tr("Build SSH port"),
+ [kit]() -> QString {
+ const IDevice::ConstPtr device = BuildDeviceKitAspect::device(kit);
+ return device ? QString::number(device->sshParameters().port()) : QString();
+ });
+ expander->registerVariable("BuildDevice:UserName", tr("Build user name"),
+ [kit]() -> QString {
+ const IDevice::ConstPtr device = BuildDeviceKitAspect::device(kit);
+ return device ? device->sshParameters().userName() : QString();
+ });
+ expander->registerVariable("BuildDevice:KeyFile", tr("Build private key file"),
+ [kit]() -> QString {
+ const IDevice::ConstPtr device = BuildDeviceKitAspect::device(kit);
+ return device ? device->sshParameters().privateKeyFile : QString();
+ });
+ expander->registerVariable("BuildDevice:Name", tr("Build device name"),
+ [kit]() -> QString {
+ const IDevice::ConstPtr device = BuildDeviceKitAspect::device(kit);
+ return device ? device->displayName() : QString();
+ });
+}
+
+Utils::Id BuildDeviceKitAspect::id()
+{
+ return "PE.Profile.BuildDevice";
+}
+
+IDevice::ConstPtr BuildDeviceKitAspect::device(const Kit *k)
+{
+ QTC_ASSERT(DeviceManager::instance()->isLoaded(), return IDevice::ConstPtr());
+ IDevice::ConstPtr dev = DeviceManager::instance()->find(deviceId(k));
+ // Use the "run" device as fallback if no build device is present.
+ // FIXME: Think about whether this shouldn't be the other way round.
+ if (!dev)
+ dev = DeviceKitAspect::device(k);
+ return dev;
+}
+
+Utils::Id BuildDeviceKitAspect::deviceId(const Kit *k)
+{
+ return k ? Utils::Id::fromSetting(k->value(BuildDeviceKitAspect::id())) : Utils::Id();
+}
+
+void BuildDeviceKitAspect::setDevice(Kit *k, IDevice::ConstPtr dev)
+{
+ setDeviceId(k, dev ? dev->id() : Utils::Id());
+}
+
+void BuildDeviceKitAspect::setDeviceId(Kit *k, Utils::Id id)
+{
+ QTC_ASSERT(k, return);
+ k->setValue(BuildDeviceKitAspect::id(), id.toSetting());
+}
+
+void BuildDeviceKitAspect::kitsWereLoaded()
+{
+ foreach (Kit *k, KitManager::kits())
+ fix(k);
+
+ DeviceManager *dm = DeviceManager::instance();
+ connect(dm, &DeviceManager::deviceListReplaced, this, &BuildDeviceKitAspect::devicesChanged);
+ connect(dm, &DeviceManager::deviceAdded, this, &BuildDeviceKitAspect::devicesChanged);
+ connect(dm, &DeviceManager::deviceRemoved, this, &BuildDeviceKitAspect::devicesChanged);
+ connect(dm, &DeviceManager::deviceUpdated, this, &BuildDeviceKitAspect::deviceUpdated);
+
+ connect(KitManager::instance(), &KitManager::kitUpdated,
+ this, &BuildDeviceKitAspect::kitUpdated);
+ connect(KitManager::instance(), &KitManager::unmanagedKitUpdated,
+ this, &BuildDeviceKitAspect::kitUpdated);
+}
+
+void BuildDeviceKitAspect::deviceUpdated(Utils::Id id)
+{
+ foreach (Kit *k, KitManager::kits()) {
+ if (deviceId(k) == id)
+ notifyAboutUpdate(k);
+ }
+}
+
+void BuildDeviceKitAspect::kitUpdated(Kit *k)
+{
+ setup(k); // Set default device if necessary
+}
+
+void BuildDeviceKitAspect::devicesChanged()
+{
+ foreach (Kit *k, KitManager::kits())
+ setup(k); // Set default device if necessary
+}
+
+// --------------------------------------------------------------------------
// EnvironmentKitAspect:
// --------------------------------------------------------------------------
namespace Internal {
@@ -1130,9 +1372,9 @@ class EnvironmentKitAspectWidget final : public KitAspectWidget
public:
EnvironmentKitAspectWidget(Kit *workingCopy, const KitAspect *ki)
: KitAspectWidget(workingCopy, ki),
- m_summaryLabel(new Utils::ElidingLabel),
- m_manageButton(new QPushButton),
- m_mainWidget(new QWidget)
+ m_summaryLabel(createSubWidget<Utils::ElidingLabel>()),
+ m_manageButton(createSubWidget<QPushButton>()),
+ m_mainWidget(createSubWidget<QWidget>())
{
auto *layout = new QVBoxLayout;
layout->setContentsMargins(0, 0, 0, 0);
@@ -1147,8 +1389,13 @@ public:
}
private:
- QWidget *mainWidget() const override { return m_mainWidget; }
- QWidget *buttonWidget() const override { return m_manageButton; }
+ void addToLayout(LayoutBuilder &builder) override
+ {
+ addMutableAction(m_mainWidget);
+ builder.addItem(m_mainWidget);
+ builder.addItem(m_manageButton);
+ }
+
void makeReadOnly() override { m_manageButton->setEnabled(false); }
void refresh() override
@@ -1254,7 +1501,7 @@ void EnvironmentKitAspect::fix(Kit *k)
}
}
-void EnvironmentKitAspect::addToEnvironment(const Kit *k, Utils::Environment &env) const
+void EnvironmentKitAspect::addToBuildEnvironment(const Kit *k, Environment &env) const
{
const QStringList values
= Utils::transform(Utils::EnvironmentItem::toStringList(environmentChanges(k)),
@@ -1262,6 +1509,11 @@ void EnvironmentKitAspect::addToEnvironment(const Kit *k, Utils::Environment &en
env.modify(Utils::EnvironmentItem::fromStringList(values));
}
+void EnvironmentKitAspect::addToRunEnvironment(const Kit *k, Environment &env) const
+{
+ addToBuildEnvironment(k, env);
+}
+
KitAspectWidget *EnvironmentKitAspect::createConfigWidget(Kit *k) const
{
QTC_ASSERT(k, return nullptr);
diff --git a/src/plugins/projectexplorer/kitinformation.h b/src/plugins/projectexplorer/kitinformation.h
index 4e5708eeca..6118bec9ae 100644
--- a/src/plugins/projectexplorer/kitinformation.h
+++ b/src/plugins/projectexplorer/kitinformation.h
@@ -83,7 +83,9 @@ public:
ItemList toUserOutput(const Kit *k) const override;
- void addToEnvironment(const Kit *k, Utils::Environment &env) const override;
+ void addToBuildEnvironment(const Kit *k, Utils::Environment &env) const override;
+ void addToRunEnvironment(const Kit *, Utils::Environment &) const override {}
+
void addToMacroExpander(Kit *kit, Utils::MacroExpander *expander) const override;
QList<Utils::OutputLineParser *> createOutputParsers(const Kit *k) const override;
QSet<Utils::Id> availableFeatures(const Kit *k) const override;
@@ -170,6 +172,42 @@ private:
};
// --------------------------------------------------------------------------
+// BuildDeviceInformation:
+// --------------------------------------------------------------------------
+
+class PROJECTEXPLORER_EXPORT BuildDeviceKitAspect : public KitAspect
+{
+ Q_OBJECT
+
+public:
+ BuildDeviceKitAspect();
+
+ Tasks validate(const Kit *k) const override;
+
+ KitAspectWidget *createConfigWidget(Kit *k) const override;
+
+ QString displayNamePostfix(const Kit *k) const override;
+
+ ItemList toUserOutput(const Kit *k) const override;
+
+ void addToMacroExpander(ProjectExplorer::Kit *kit, Utils::MacroExpander *expander) const override;
+
+ static Utils::Id id();
+ static IDevice::ConstPtr device(const Kit *k);
+ static Utils::Id deviceId(const Kit *k);
+ static void setDevice(Kit *k, IDevice::ConstPtr dev);
+ static void setDeviceId(Kit *k, Utils::Id dataId);
+
+private:
+ QVariant defaultValue(const Kit *k) const;
+
+ void kitsWereLoaded();
+ void deviceUpdated(Utils::Id dataId);
+ void devicesChanged();
+ void kitUpdated(ProjectExplorer::Kit *k);
+};
+
+// --------------------------------------------------------------------------
// EnvironmentKitAspect:
// --------------------------------------------------------------------------
@@ -183,7 +221,9 @@ public:
Tasks validate(const Kit *k) const override;
void fix(Kit *k) override;
- void addToEnvironment(const Kit *k, Utils::Environment &env) const override;
+ void addToBuildEnvironment(const Kit *k, Utils::Environment &env) const override;
+ void addToRunEnvironment(const Kit *, Utils::Environment &) const override;
+
KitAspectWidget *createConfigWidget(Kit *k) const override;
ItemList toUserOutput(const Kit *k) const override;
diff --git a/src/plugins/projectexplorer/kitmanager.cpp b/src/plugins/projectexplorer/kitmanager.cpp
index 9ddf264ed5..cfd4a56bda 100644
--- a/src/plugins/projectexplorer/kitmanager.cpp
+++ b/src/plugins/projectexplorer/kitmanager.cpp
@@ -50,8 +50,10 @@
#include <utils/qtcassert.h>
#include <utils/stringutils.h>
+#include <QAction>
#include <QHash>
#include <QLabel>
+#include <QPushButton>
#include <QSettings>
#include <QStyle>
@@ -77,11 +79,11 @@ 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";
+const char KIT_FILENAME[] = "profiles.xml";
static FilePath settingsFileName()
{
- return FilePath::fromString(ICore::userResourcePath() + KIT_FILENAME);
+ return ICore::userResourcePath(KIT_FILENAME);
}
// --------------------------------------------------------------------------
@@ -195,8 +197,7 @@ void KitManager::restoreKits()
// read all kits from SDK
{
- KitList system = restoreKitsHelper
- (FilePath::fromString(ICore::installerResourcePath() + KIT_FILENAME));
+ KitList system = restoreKitsHelper(ICore::installerResourcePath(KIT_FILENAME));
// SDK kits need to get updated with the user-provided extra settings:
for (auto &current : system.kits) {
@@ -681,7 +682,13 @@ int KitAspect::weight(const Kit *k) const
return k->value(id()).isValid() ? 1 : 0;
}
-void KitAspect::addToEnvironment(const Kit *k, Environment &env) const
+void KitAspect::addToBuildEnvironment(const Kit *k, Environment &env) const
+{
+ Q_UNUSED(k)
+ Q_UNUSED(env)
+}
+
+void KitAspect::addToRunEnvironment(const Kit *k, Environment &env) const
{
Q_UNUSED(k)
Q_UNUSED(env)
@@ -723,31 +730,50 @@ void KitAspect::notifyAboutUpdate(Kit *k)
k->kitUpdated();
}
-KitAspectWidget::KitAspectWidget(Kit *kit, const KitAspect *ki) : m_kit(kit),
- m_kitInformation(ki), m_isSticky(kit->isSticky(ki->id()))
-{ }
+KitAspectWidget::KitAspectWidget(Kit *kit, const KitAspect *ki)
+ : m_kit(kit), m_kitInformation(ki)
+{
+ const Id id = ki->id();
+ m_mutableAction = new QAction(tr("Mark as Mutable"));
+ m_mutableAction->setCheckable(true);
+ m_mutableAction->setChecked(m_kit->isMutable(id));
+ m_mutableAction->setEnabled(!m_kit->isSticky(id));
+ connect(m_mutableAction, &QAction::toggled, this, [this, id] {
+ m_kit->setMutable(id, m_mutableAction->isChecked());
+ });
+}
-Utils::Id KitAspectWidget::kitInformationId() const
+KitAspectWidget::~KitAspectWidget()
{
- return m_kitInformation->id();
+ delete m_mutableAction;
}
-void KitAspectWidget::addToLayout(LayoutBuilder &builder)
+void KitAspectWidget::addToLayoutWithLabel(QWidget *parent)
{
- QTC_ASSERT(!m_label, delete m_label);
- m_label = new QLabel(m_kitInformation->displayName() + ':');
- m_label->setToolTip(m_kitInformation->description());
+ QTC_ASSERT(parent, return);
+ auto label = createSubWidget<QLabel>(m_kitInformation->displayName() + ':');
+ label->setToolTip(m_kitInformation->description());
+
+ LayoutExtender builder(parent->layout());
+ builder.finishRow();
+ builder.addItem(label);
+ addToLayout(builder);
+}
- builder.addRow({{m_label, 1, LayoutBuilder::AlignAsFormLabel}, mainWidget(), buttonWidget()});
+void KitAspectWidget::addMutableAction(QWidget *child)
+{
+ QTC_ASSERT(child, return);
+ child->addAction(m_mutableAction);
+ child->setContextMenuPolicy(Qt::ActionsContextMenu);
}
-void KitAspectWidget::setVisible(bool visible)
+QWidget *KitAspectWidget::createManageButton(Id pageId)
{
- mainWidget()->setVisible(visible);
- if (buttonWidget())
- buttonWidget()->setVisible(visible);
- QTC_ASSERT(m_label, return);
- m_label->setVisible(visible);
+ auto button = createSubWidget<QPushButton>(msgManage());
+ connect(button, &QPushButton::clicked, this, [pageId] {
+ Core::ICore::showOptionsDialog(pageId);
+ });
+ return button;
}
QString KitAspectWidget::msgManage()
diff --git a/src/plugins/projectexplorer/kitmanager.h b/src/plugins/projectexplorer/kitmanager.h
index 99e9a40ac6..79747de8aa 100644
--- a/src/plugins/projectexplorer/kitmanager.h
+++ b/src/plugins/projectexplorer/kitmanager.h
@@ -31,6 +31,8 @@
#include <coreplugin/featureprovider.h>
+#include <utils/aspects.h>
+
#include <QObject>
#include <QPair>
#include <QSet>
@@ -94,7 +96,9 @@ public:
virtual KitAspectWidget *createConfigWidget(Kit *) const = 0;
- virtual void addToEnvironment(const Kit *k, Utils::Environment &env) const;
+ virtual void addToBuildEnvironment(const Kit *k, Utils::Environment &env) const;
+ virtual void addToRunEnvironment(const Kit *k, Utils::Environment &env) const;
+
virtual QList<Utils::OutputLineParser *> createOutputParsers(const Kit *k) const;
virtual QString displayNamePostfix(const Kit *k) const;
@@ -125,36 +129,31 @@ private:
bool m_essential = false;
};
-class PROJECTEXPLORER_EXPORT KitAspectWidget : public QObject
+class PROJECTEXPLORER_EXPORT KitAspectWidget : public Utils::BaseAspect
{
Q_OBJECT
public:
KitAspectWidget(Kit *kit, const KitAspect *ki);
-
- Utils::Id kitInformationId() const;
+ ~KitAspectWidget();
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; }
-
- void addToLayout(Utils::LayoutBuilder &builder);
- void setVisible(bool visible);
- bool isSticky() const { return m_isSticky; }
+ void addToLayoutWithLabel(QWidget *parent);
static QString msgManage();
Kit *kit() const { return m_kit; }
+ const KitAspect *kitInformation() const { return m_kitInformation; }
+ QAction *mutableAction() const { return m_mutableAction; }
+ void addMutableAction(QWidget *child);
+ QWidget *createManageButton(Utils::Id pageId);
protected:
Kit *m_kit;
const KitAspect *m_kitInformation;
- bool m_isSticky;
- QLabel *m_label = nullptr;
+ QAction *m_mutableAction = nullptr;
};
class PROJECTEXPLORER_EXPORT KitManager : public QObject
diff --git a/src/plugins/projectexplorer/kitmanagerconfigwidget.cpp b/src/plugins/projectexplorer/kitmanagerconfigwidget.cpp
index 3d40b510cb..884ab33307 100644
--- a/src/plugins/projectexplorer/kitmanagerconfigwidget.cpp
+++ b/src/plugins/projectexplorer/kitmanagerconfigwidget.cpp
@@ -68,10 +68,8 @@ KitManagerConfigWidget::KitManagerConfigWidget(Kit *k) :
{
setSizePolicy(QSizePolicy::Preferred, QSizePolicy::Preferred);
- LayoutBuilder builder(this, LayoutBuilder::GridLayout);
QLabel *label = new QLabel(tr("Name:"));
label->setToolTip(tr("Kit name and icon."));
- builder.addRow({{label, 1, LayoutBuilder::AlignAsFormLabel}, m_nameEdit, m_iconButton});
QString toolTip =
tr("<html><head/><body><p>The name of the kit suitable for generating "
@@ -85,10 +83,15 @@ KitManagerConfigWidget::KitManagerConfigWidget(Kit *k) :
label = new QLabel(tr("File system name:"));
label->setToolTip(toolTip);
- builder.addRow({{label, 1, LayoutBuilder::AlignAsFormLabel}, m_fileSystemFriendlyNameLineEdit});
connect(m_fileSystemFriendlyNameLineEdit, &QLineEdit::textChanged,
this, &KitManagerConfigWidget::setFileSystemFriendlyName);
+ using namespace Layouting;
+ Grid {
+ AlignAsFormLabel(label), m_nameEdit, m_iconButton, Break(),
+ AlignAsFormLabel(label), m_fileSystemFriendlyNameLineEdit
+ }.attachTo(this);
+
m_iconButton->setToolTip(tr("Kit icon."));
auto setIconAction = new QAction(tr("Select Icon..."), this);
m_iconButton->addAction(setIconAction);
@@ -130,8 +133,6 @@ KitManagerConfigWidget::~KitManagerConfigWidget()
{
qDeleteAll(m_widgets);
m_widgets.clear();
- qDeleteAll(m_actions);
- m_actions.clear();
// Make sure our workingCopy did not get registered somehow:
QTC_CHECK(!Utils::contains(KitManager::kits(),
@@ -216,23 +217,11 @@ void KitManagerConfigWidget::addAspectToWorkingCopy(KitAspect *aspect)
QTC_ASSERT(widget, return);
QTC_ASSERT(!m_widgets.contains(widget), return);
- auto action = new QAction(tr("Mark as Mutable"), nullptr);
- action->setCheckable(true);
- 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, aspect, action] {
- workingCopy()->setMutable(aspect->id(), action->isChecked());
- emit dirty();
- });
-
- m_actions << action;
-
- LayoutBuilder builder(layout());
- widget->addToLayout(builder);
+ widget->addToLayoutWithLabel(this);
m_widgets.append(widget);
+
+ connect(widget->mutableAction(), &QAction::toggled,
+ this, &KitManagerConfigWidget::dirty);
}
void KitManagerConfigWidget::updateVisibility()
@@ -240,9 +229,10 @@ void KitManagerConfigWidget::updateVisibility()
int count = m_widgets.count();
for (int i = 0; i < count; ++i) {
KitAspectWidget *widget = m_widgets.at(i);
- const bool visible = widget->visibleInKit()
- && !m_modifiedKit->irrelevantAspects().contains(widget->kitInformationId());
- widget->setVisible(visible);
+ const KitAspect *ki = widget->kitInformation();
+ const bool visibleInKit = ki->isApplicableToKit(m_modifiedKit.get());
+ const bool irrelevant = m_modifiedKit->irrelevantAspects().contains(ki->id());
+ widget->setVisible(visibleInKit && !irrelevant);
}
}
@@ -254,7 +244,7 @@ void KitManagerConfigWidget::setHasUniqueName(bool unique)
void KitManagerConfigWidget::makeStickySubWidgetsReadOnly()
{
foreach (KitAspectWidget *w, m_widgets) {
- if (w->isSticky())
+ if (w->kit()->isSticky(w->kitInformation()->id()))
w->makeReadOnly();
}
}
diff --git a/src/plugins/projectexplorer/kitmanagerconfigwidget.h b/src/plugins/projectexplorer/kitmanagerconfigwidget.h
index 89b74d7ee7..d2b315749e 100644
--- a/src/plugins/projectexplorer/kitmanagerconfigwidget.h
+++ b/src/plugins/projectexplorer/kitmanagerconfigwidget.h
@@ -100,7 +100,6 @@ private:
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/ldparser.cpp b/src/plugins/projectexplorer/ldparser.cpp
index afbdf985aa..33cf1b85ad 100644
--- a/src/plugins/projectexplorer/ldparser.cpp
+++ b/src/plugins/projectexplorer/ldparser.cpp
@@ -26,6 +26,7 @@
#include "ldparser.h"
#include "projectexplorerconstants.h"
+#include <utils/algorithm.h>
#include <utils/qtcassert.h>
using namespace ProjectExplorer;
@@ -133,21 +134,28 @@ Utils::OutputLineParser::Result LdParser::handleLine(const QString &line, Utils:
}
QString description = match.captured(8).trimmed();
Task::TaskType type = Task::Error;
- if (description.startsWith(QLatin1String("At global scope")) ||
- description.startsWith(QLatin1String("At top level")) ||
- description.startsWith(QLatin1String("instantiated from ")) ||
- description.startsWith(QLatin1String("In ")) ||
- description.startsWith(QLatin1String("first defined here")) ||
+ if (description.startsWith(QLatin1String("first defined here")) ||
description.startsWith(QLatin1String("note:"), Qt::CaseInsensitive)) {
type = Task::Unknown;
} else if (description.startsWith(QLatin1String("warning: "), Qt::CaseInsensitive)) {
type = Task::Warning;
description = description.mid(9);
}
- LinkSpecs linkSpecs;
- addLinkSpecForAbsoluteFilePath(linkSpecs, filename, lineno, match, capIndex);
- scheduleTask(CompileTask(type, description, filename, lineno), 1);
- return {Status::Done, linkSpecs};
+ static const QStringList keywords{
+ "File format not recognized",
+ "undefined reference",
+ "first defined here",
+ "feupdateenv is not implemented and will always fail", // yes, this is quite special ...
+ };
+ const auto descriptionContainsKeyword = [&description](const QString &keyword) {
+ return description.contains(keyword);
+ };
+ if (Utils::anyOf(keywords, descriptionContainsKeyword)) {
+ LinkSpecs linkSpecs;
+ addLinkSpecForAbsoluteFilePath(linkSpecs, filename, lineno, match, capIndex);
+ scheduleTask(CompileTask(type, description, filename, lineno), 1);
+ return {Status::Done, linkSpecs};
+ }
}
return Status::NotHandled;
diff --git a/src/plugins/projectexplorer/linuxiccparser.cpp b/src/plugins/projectexplorer/linuxiccparser.cpp
index 41d46a3522..dd1b295e34 100644
--- a/src/plugins/projectexplorer/linuxiccparser.cpp
+++ b/src/plugins/projectexplorer/linuxiccparser.cpp
@@ -217,16 +217,6 @@ void ProjectExplorerPlugin::testLinuxIccOutputParsers_data()
"use of \"=\" where \"==\" may have been intended\nwhile (a = true)",
FilePath::fromUserInput("main.cpp"), 41))
<< QString();
-
- QTest::newRow("moc note")
- << QString::fromLatin1("/home/qtwebkithelpviewer.h:0: Note: No relevant classes found. No output generated.")
- << OutputParserTester::STDERR
- << QString() << QString()
- << (Tasks()
- << CompileTask(Task::Unknown,
- "Note: No relevant classes found. No output generated.",
- FilePath::fromUserInput("/home/qtwebkithelpviewer.h"), -1))
- << QString();
}
void ProjectExplorerPlugin::testLinuxIccOutputParsers()
diff --git a/src/plugins/projectexplorer/localenvironmentaspect.cpp b/src/plugins/projectexplorer/localenvironmentaspect.cpp
index 92a0319e1f..f08efa7fd5 100644
--- a/src/plugins/projectexplorer/localenvironmentaspect.cpp
+++ b/src/plugins/projectexplorer/localenvironmentaspect.cpp
@@ -49,8 +49,7 @@ LocalEnvironmentAspect::LocalEnvironmentAspect(Target *target, bool includeBuild
if (BuildConfiguration *bc = target->activeBuildConfiguration()) {
env = bc->environment();
} else { // Fallback for targets without buildconfigurations:
- env = Environment::systemEnvironment();
- target->kit()->addToEnvironment(env);
+ env = target->kit()->buildEnvironment();
}
return env;
});
diff --git a/src/plugins/projectexplorer/makestep.cpp b/src/plugins/projectexplorer/makestep.cpp
index 7e171236fe..ad44e822fb 100644
--- a/src/plugins/projectexplorer/makestep.cpp
+++ b/src/plugins/projectexplorer/makestep.cpp
@@ -83,9 +83,7 @@ MakeStep::MakeStep(BuildStepList *parent, Id id)
m_userArgumentsAspect->setLabelText(tr("Make arguments:"));
m_userArgumentsAspect->setDisplayStyle(StringAspect::LineEditDisplay);
- m_jobCountContainer = addAspect<AspectContainer>();
-
- m_userJobCountAspect = m_jobCountContainer->addAspect<IntegerAspect>();
+ m_userJobCountAspect = addAspect<IntegerAspect>();
m_userJobCountAspect->setSettingsKey(id.withSuffix(JOBCOUNT_SUFFIX).toString());
m_userJobCountAspect->setLabel(tr("Parallel jobs:"));
m_userJobCountAspect->setRange(1, 999);
@@ -93,11 +91,11 @@ MakeStep::MakeStep(BuildStepList *parent, Id id)
m_userJobCountAspect->setDefaultValue(defaultJobCount());
const QString text = tr("Override MAKEFLAGS");
- m_overrideMakeflagsAspect = m_jobCountContainer->addAspect<BoolAspect>();
+ m_overrideMakeflagsAspect = addAspect<BoolAspect>();
m_overrideMakeflagsAspect->setSettingsKey(id.withSuffix(OVERRIDE_MAKEFLAGS_SUFFIX).toString());
m_overrideMakeflagsAspect->setLabel(text, BoolAspect::LabelPlacement::AtCheckBox);
- m_nonOverrideWarning = m_jobCountContainer->addAspect<TextDisplay>();
+ m_nonOverrideWarning = addAspect<TextDisplay>();
m_nonOverrideWarning->setToolTip("<html><body><p>" +
tr("<code>MAKEFLAGS</code> specifies parallel jobs. Check \"%1\" to override.")
.arg(text) + "</p></body></html>");
@@ -113,10 +111,10 @@ MakeStep::MakeStep(BuildStepList *parent, Id id)
m_buildTargetsAspect->setLabelText(tr("Targets:"));
const auto updateMakeLabel = [this] {
- const QString defaultMake = defaultMakeCommand().toString();
+ const FilePath defaultMake = defaultMakeCommand();
const QString labelText = defaultMake.isEmpty()
? tr("Make:")
- : tr("Override %1:").arg(QDir::toNativeSeparators(defaultMake));
+ : tr("Override %1:").arg(defaultMake.toUserOutput());
m_makeCommandAspect->setLabelText(labelText);
};
@@ -185,11 +183,11 @@ static const QList<ToolChain *> preferredToolChains(const Kit *kit)
FilePath MakeStep::defaultMakeCommand() const
{
- const Utils::Environment env = makeEnvironment();
+ const Environment env = makeEnvironment();
for (const ToolChain *tc : preferredToolChains(kit())) {
FilePath make = tc->makeCommand(env);
if (!make.isEmpty())
- return make;
+ return mapFromBuildDeviceToGlobalPath(make);
}
return {};
}
@@ -223,7 +221,7 @@ bool MakeStep::jobCountOverridesMakeflags() const
static Utils::optional<int> argsJobCount(const QString &str)
{
- const QStringList args = Utils::QtcProcess::splitArgs(str, Utils::HostOsInfo::hostOs());
+ const QStringList args = ProcessArgs::splitArgs(str, HostOsInfo::hostOs());
const int argIndex = Utils::indexOf(args, [](const QString &arg) { return arg.startsWith("-j"); });
if (argIndex == -1)
return Utils::nullopt;
@@ -275,7 +273,7 @@ bool MakeStep::userArgsContainsJobCount() const
Environment MakeStep::makeEnvironment() const
{
Environment env = buildEnvironment();
- Utils::Environment::setupEnglishOutput(&env);
+ env.setupEnglishOutput();
if (makeCommand().isEmpty()) {
// We also prepend "L" to the MAKEFLAGS, so that nmake / jom are less verbose
const QList<ToolChain *> tcs = preferredToolChains(target()->kit());
@@ -348,16 +346,16 @@ CommandLine MakeStep::effectiveMakeCommand(MakeCommandType type) const
QWidget *MakeStep::createConfigWidget()
{
- auto widget = new QWidget;
-
- LayoutBuilder builder(widget);
+ Layouting::Form builder;
builder.addRow(m_makeCommandAspect);
builder.addRow(m_userArgumentsAspect);
- builder.addRow(m_jobCountContainer);
+ builder.addRow({m_userJobCountAspect, m_overrideMakeflagsAspect, m_nonOverrideWarning});
if (m_disablingForSubDirsSupported)
builder.addRow(m_disabledForSubdirsAspect);
builder.addRow(m_buildTargetsAspect);
+ auto widget = builder.emerge(false);
+
VariableChooser::addSupportForChildWidgets(widget, macroExpander());
setSummaryUpdater([this] {
diff --git a/src/plugins/projectexplorer/makestep.h b/src/plugins/projectexplorer/makestep.h
index 464d62a900..0412864c6e 100644
--- a/src/plugins/projectexplorer/makestep.h
+++ b/src/plugins/projectexplorer/makestep.h
@@ -90,7 +90,9 @@ protected:
Utils::StringAspect *makeCommandAspect() const { return m_makeCommandAspect; }
Utils::MultiSelectionAspect *buildTargetsAspect() const { return m_buildTargetsAspect; }
Utils::StringAspect *userArgumentsAspect() const { return m_userArgumentsAspect; }
- Utils::AspectContainer *jobCountContainer() const { return m_jobCountContainer; }
+ Utils::BoolAspect *overrideMakeflagsAspect() const { return m_overrideMakeflagsAspect; }
+ Utils::TextDisplay *nonOverrideWarning() const { return m_nonOverrideWarning; }
+ Utils::IntegerAspect *jobCountAspect() const { return m_userJobCountAspect; }
Utils::BoolAspect *disabledForSubdirsAspect() const { return m_disabledForSubdirsAspect; }
@@ -102,7 +104,6 @@ private:
QStringList m_availableTargets; // FIXME: Unused, remove in 4.15.
Utils::StringAspect *m_makeCommandAspect = nullptr;
Utils::StringAspect *m_userArgumentsAspect = nullptr;
- Utils::AspectContainer *m_jobCountContainer = nullptr;
Utils::IntegerAspect *m_userJobCountAspect = nullptr;
Utils::BoolAspect *m_overrideMakeflagsAspect = nullptr;
Utils::BoolAspect *m_disabledForSubdirsAspect = nullptr;
diff --git a/src/plugins/projectexplorer/miniprojecttargetselector.cpp b/src/plugins/projectexplorer/miniprojecttargetselector.cpp
index f255c6bbf9..b73d12c578 100644
--- a/src/plugins/projectexplorer/miniprojecttargetselector.cpp
+++ b/src/plugins/projectexplorer/miniprojecttargetselector.cpp
@@ -39,6 +39,7 @@
#include <utils/algorithm.h>
#include <utils/itemviews.h>
+#include <utils/layoutbuilder.h>
#include <utils/stringutils.h>
#include <utils/styledbar.h>
#include <utils/stylehelper.h>
@@ -564,15 +565,14 @@ class KitAreaWidget : public QWidget
Q_OBJECT
public:
explicit KitAreaWidget(QWidget *parent = nullptr)
- : QWidget(parent), m_layout(new QGridLayout(this))
+ : QWidget(parent)
{
- m_layout->setContentsMargins(3, 3, 3, 3);
connect(KitManager::instance(), &KitManager::kitUpdated, this, &KitAreaWidget::updateKit);
}
~KitAreaWidget() override { setKit(nullptr); }
- void setKit(ProjectExplorer::Kit *k)
+ void setKit(Kit *k)
{
qDeleteAll(m_widgets);
m_widgets.clear();
@@ -580,25 +580,22 @@ public:
if (!k)
return;
- foreach (QLabel *l, m_labels)
- l->deleteLater();
- m_labels.clear();
+ delete layout();
- int row = 0;
+ LayoutBuilder builder(LayoutBuilder::GridLayout);
for (KitAspect *aspect : KitManager::kitAspects()) {
if (k && k->isMutable(aspect->id())) {
KitAspectWidget *widget = aspect->createConfigWidget(k);
m_widgets << widget;
QLabel *label = new QLabel(aspect->displayName());
- m_labels << label;
-
- m_layout->addWidget(label, row, 0);
- m_layout->addWidget(widget->mainWidget(), row, 1);
- m_layout->addWidget(widget->buttonWidget(), row, 2);
-
- ++row;
+ builder.addItem(label);
+ widget->addToLayout(builder);
+ builder.finishRow();
}
}
+ builder.attachTo(this);
+ layout()->setContentsMargins(3, 3, 3, 3);
+
m_kit = k;
setHidden(m_widgets.isEmpty());
@@ -611,16 +608,17 @@ private:
return;
bool addedMutables = false;
- QList<Utils::Id> knownIdList = Utils::transform(m_widgets, &KitAspectWidget::kitInformationId);
+ QList<const KitAspect *> knownList
+ = Utils::transform(m_widgets, &KitAspectWidget::kitInformation);
for (KitAspect *aspect : KitManager::kitAspects()) {
const Utils::Id currentId = aspect->id();
- if (m_kit->isMutable(currentId) && !knownIdList.removeOne(currentId)) {
+ if (m_kit->isMutable(currentId) && !knownList.removeOne(aspect)) {
addedMutables = true;
break;
}
}
- const bool removedMutables = !knownIdList.isEmpty();
+ const bool removedMutables = !knownList.isEmpty();
if (addedMutables || removedMutables) {
// Redo whole setup if the number of mutable settings did change
@@ -632,10 +630,8 @@ private:
}
}
- QGridLayout *m_layout;
Kit *m_kit = nullptr;
QList<KitAspectWidget *> m_widgets;
- QList<QLabel *> m_labels;
};
/////////
diff --git a/src/plugins/projectexplorer/msvctoolchain.cpp b/src/plugins/projectexplorer/msvctoolchain.cpp
index c57cf0e1d6..39d4b6dbcf 100644
--- a/src/plugins/projectexplorer/msvctoolchain.cpp
+++ b/src/plugins/projectexplorer/msvctoolchain.cpp
@@ -40,7 +40,6 @@
#include <utils/optional.h>
#include <utils/qtcassert.h>
#include <utils/qtcprocess.h>
-#include <utils/synchronousprocess.h>
#include <utils/runextensions.h>
#include <utils/temporarydirectory.h>
#include <utils/pathchooser.h>
@@ -104,7 +103,9 @@ const MsvcPlatform platforms[]
{MsvcToolChain::arm, "arm", "/bin/arm", "vcvarsarm.bat"},
{MsvcToolChain::x86_arm, "x86_arm", "/bin/x86_arm", "vcvarsx86_arm.bat"},
{MsvcToolChain::amd64_arm, "amd64_arm", "/bin/amd64_arm", "vcvarsamd64_arm.bat"},
- {MsvcToolChain::amd64_x86, "amd64_x86", "/bin/amd64_x86", "vcvarsamd64_x86.bat"}};
+ {MsvcToolChain::amd64_x86, "amd64_x86", "/bin/amd64_x86", "vcvarsamd64_x86.bat"},
+ {MsvcToolChain::x86_arm64, "x86_arm64", "/bin/x86_arm64", "vcvarsx86_arm64.bat"},
+ {MsvcToolChain::amd64_arm64, "amd64_arm64", "/bin/amd64_arm64", "vcvarsamd64_arm64.bat"}};
static QList<const MsvcToolChain *> g_availableMsvcToolchains;
@@ -129,12 +130,13 @@ static bool hostSupportsPlatform(MsvcToolChain::Platform platform)
switch (Utils::HostOsInfo::hostArchitecture()) {
case Utils::HostOsInfo::HostArchitectureAMD64:
if (platform == MsvcToolChain::amd64 || platform == MsvcToolChain::amd64_arm
- || platform == MsvcToolChain::amd64_x86)
+ || platform == MsvcToolChain::amd64_x86 || platform == MsvcToolChain::amd64_arm64)
return true;
Q_FALLTHROUGH(); // all x86 toolchains are also working on an amd64 host
case Utils::HostOsInfo::HostArchitectureX86:
return platform == MsvcToolChain::x86 || platform == MsvcToolChain::x86_amd64
- || platform == MsvcToolChain::x86_ia64 || platform == MsvcToolChain::x86_arm;
+ || platform == MsvcToolChain::x86_ia64 || platform == MsvcToolChain::x86_arm
+ || platform == MsvcToolChain::x86_arm64;
case Utils::HostOsInfo::HostArchitectureArm:
return platform == MsvcToolChain::arm;
case Utils::HostOsInfo::HostArchitectureItanium:
@@ -235,35 +237,35 @@ static Utils::optional<VisualStudioInstallation> detectCppBuildTools2017()
static QVector<VisualStudioInstallation> detectVisualStudioFromVsWhere(const QString &vswhere)
{
QVector<VisualStudioInstallation> installations;
- Utils::SynchronousProcess vsWhereProcess;
+ SynchronousProcess vsWhereProcess;
vsWhereProcess.setCodec(QTextCodec::codecForName("UTF-8"));
const int timeoutS = 5;
vsWhereProcess.setTimeoutS(timeoutS);
- const CommandLine cmd(vswhere,
- {"-products", "*", "-prerelease", "-legacy", "-format", "json", "-utf8"});
- Utils::SynchronousProcessResponse response = vsWhereProcess.runBlocking(cmd);
- switch (response.result) {
- case Utils::SynchronousProcessResponse::Finished:
+ vsWhereProcess.setCommand({vswhere,
+ {"-products", "*", "-prerelease", "-legacy", "-format", "json", "-utf8"}});
+ vsWhereProcess.runBlocking();
+ switch (vsWhereProcess.result()) {
+ case QtcProcess::Finished:
break;
- case Utils::SynchronousProcessResponse::StartFailed:
+ case QtcProcess::StartFailed:
qWarning().noquote() << QDir::toNativeSeparators(vswhere) << "could not be started.";
return installations;
- case Utils::SynchronousProcessResponse::FinishedError:
+ case QtcProcess::FinishedError:
qWarning().noquote().nospace() << QDir::toNativeSeparators(vswhere)
<< " finished with exit code "
- << response.exitCode << ".";
+ << vsWhereProcess.exitCode() << ".";
return installations;
- case Utils::SynchronousProcessResponse::TerminatedAbnormally:
+ case QtcProcess::TerminatedAbnormally:
qWarning().noquote().nospace()
- << QDir::toNativeSeparators(vswhere) << " crashed. Exit code: " << response.exitCode;
+ << QDir::toNativeSeparators(vswhere) << " crashed. Exit code: " << vsWhereProcess.exitCode();
return installations;
- case Utils::SynchronousProcessResponse::Hang:
+ case QtcProcess::Hang:
qWarning().noquote() << QDir::toNativeSeparators(vswhere) << "did not finish in" << timeoutS
<< "seconds.";
return installations;
}
- QByteArray output = response.stdOut().toUtf8();
+ QByteArray output = vsWhereProcess.stdOut().toUtf8();
QJsonParseError error;
const QJsonDocument doc = QJsonDocument::fromJson(output, &error);
if (error.error != QJsonParseError::NoError || doc.isNull()) {
@@ -365,6 +367,8 @@ static unsigned char wordWidthForPlatform(MsvcToolChain::Platform platform)
case ProjectExplorer::Internal::MsvcToolChain::x86_amd64:
case ProjectExplorer::Internal::MsvcToolChain::ia64:
case ProjectExplorer::Internal::MsvcToolChain::x86_ia64:
+ case ProjectExplorer::Internal::MsvcToolChain::amd64_arm64:
+ case ProjectExplorer::Internal::MsvcToolChain::x86_arm64:
return 64;
}
@@ -382,6 +386,8 @@ static Abi::Architecture archForPlatform(MsvcToolChain::Platform platform)
case ProjectExplorer::Internal::MsvcToolChain::arm:
case ProjectExplorer::Internal::MsvcToolChain::x86_arm:
case ProjectExplorer::Internal::MsvcToolChain::amd64_arm:
+ case ProjectExplorer::Internal::MsvcToolChain::x86_arm64:
+ case ProjectExplorer::Internal::MsvcToolChain::amd64_arm64:
return Abi::ArmArchitecture;
case ProjectExplorer::Internal::MsvcToolChain::ia64:
case ProjectExplorer::Internal::MsvcToolChain::x86_ia64:
@@ -610,7 +616,7 @@ Macros MsvcToolChain::msvcPredefinedMacros(const QStringList &cxxflags,
return predefinedMacros;
}
Utils::SynchronousProcess cpp;
- cpp.setEnvironment(env.toStringList());
+ cpp.setEnvironment(env);
cpp.setWorkingDirectory(Utils::TemporaryDirectory::masterDirectoryPath());
QStringList arguments;
const Utils::FilePath binary = env.searchInPath(QLatin1String("cl.exe"));
@@ -621,12 +627,13 @@ Macros MsvcToolChain::msvcPredefinedMacros(const QStringList &cxxflags,
if (language() == ProjectExplorer::Constants::C_LANGUAGE_ID)
arguments << QLatin1String("/TC");
- arguments << toProcess << QLatin1String("/EP") << QDir::toNativeSeparators(saver.fileName());
- SynchronousProcessResponse response = cpp.runBlocking({binary, arguments});
- if (response.result != Utils::SynchronousProcessResponse::Finished || response.exitCode != 0)
+ arguments << toProcess << QLatin1String("/EP") << saver.filePath().toUserOutput();
+ cpp.setCommand({binary, arguments});
+ cpp.runBlocking();
+ if (cpp.result() != QtcProcess::Finished || cpp.exitCode() != 0)
return predefinedMacros;
- const QStringList output = Utils::filtered(response.stdOut().split('\n'),
+ const QStringList output = Utils::filtered(cpp.stdOut().split('\n'),
[](const QString &s) { return s.startsWith('V'); });
for (const QString &line : output)
predefinedMacros.append(Macro::fromKeyValue(line.mid(1)));
@@ -899,6 +906,7 @@ QStringList MsvcToolChain::suggestedMkspecList() const
case Abi::WindowsMsvc2019Flavor:
return {"win32-msvc",
"win32-msvc2019",
+ "win32-arm64-msvc",
"winrt-arm-msvc2019",
"winrt-x86-msvc2019",
"winrt-x64-msvc2019"};
@@ -1138,8 +1146,8 @@ FilePath MsvcToolChain::makeCommand(const Environment &environment) const
FilePath command;
if (useJom) {
tmp = environment.searchInPath(jom,
- {Utils::FilePath::fromString(
- QCoreApplication::applicationDirPath())});
+ {Core::ICore::libexecPath(),
+ Core::ICore::libexecPath("jom")});
if (!tmp.isEmpty())
command = tmp;
}
@@ -1272,10 +1280,10 @@ MsvcToolChainConfigWidget::MsvcToolChainConfigWidget(ToolChain *tc)
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("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("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);
@@ -1496,13 +1504,13 @@ static const MsvcToolChain *findMsvcToolChain(const QString &displayedVarsBat)
static QVersionNumber clangClVersion(const QString &clangClPath)
{
SynchronousProcess clangClProcess;
- const SynchronousProcessResponse response
- = clangClProcess.runBlocking({clangClPath, {"--version"}});
- if (response.result != SynchronousProcessResponse::Finished || response.exitCode != 0)
+ clangClProcess.setCommand({clangClPath, {"--version"}});
+ clangClProcess.runBlocking();
+ if (clangClProcess.result() != QtcProcess::Finished || clangClProcess.exitCode() != 0)
return {};
const QRegularExpressionMatch match = QRegularExpression(
QStringLiteral("clang version (\\d+(\\.\\d+)+)"))
- .match(response.stdOut());
+ .match(clangClProcess.stdOut());
if (!match.hasMatch())
return {};
return QVersionNumber::fromString(match.captured(1));
@@ -1715,20 +1723,21 @@ Macros ClangClToolChain::msvcPredefinedMacros(const QStringList &cxxflags,
if (!cxxflags.contains("--driver-mode=g++"))
return MsvcToolChain::msvcPredefinedMacros(cxxflags, env);
- Utils::SynchronousProcess cpp;
- cpp.setEnvironment(env.toStringList());
+ SynchronousProcess cpp;
+ cpp.setEnvironment(env);
cpp.setWorkingDirectory(Utils::TemporaryDirectory::masterDirectoryPath());
QStringList arguments = cxxflags;
arguments.append(gccPredefinedMacrosOptions(language()));
arguments.append("-");
- Utils::SynchronousProcessResponse response = cpp.runBlocking({clangPath(), arguments});
- if (response.result != Utils::SynchronousProcessResponse::Finished || response.exitCode != 0) {
+ cpp.setCommand({compilerCommand(), arguments});
+ cpp.runBlocking();
+ if (cpp.result() != Utils::QtcProcess::Finished || cpp.exitCode() != 0) {
// Show the warning but still parse the output.
QTC_CHECK(false && "clang-cl exited with non-zero code.");
}
- return Macro::toMacros(response.allRawOutput());
+ return Macro::toMacros(cpp.allRawOutput());
}
Utils::LanguageVersion ClangClToolChain::msvcLanguageVersion(const QStringList &cxxflags,
@@ -1825,7 +1834,9 @@ static void detectCppBuildTools2015(QList<ToolChain *> *list)
const Entry entries[] = {{" (x86)", "x86", Abi::X86Architecture, Abi::PEFormat, 32},
{" (x64)", "amd64", Abi::X86Architecture, Abi::PEFormat, 64},
{" (x86_arm)", "x86_arm", Abi::ArmArchitecture, Abi::PEFormat, 32},
- {" (x64_arm)", "amd64_arm", Abi::ArmArchitecture, Abi::PEFormat, 64}};
+ {" (x64_arm)", "amd64_arm", Abi::ArmArchitecture, Abi::PEFormat, 32},
+ {" (x86_arm64)", "x86_arm64", Abi::ArmArchitecture, Abi::PEFormat, 64},
+ {" (x64_arm64)", "amd64_arm64", Abi::ArmArchitecture, Abi::PEFormat, 64}};
const QString name = "Microsoft Visual C++ Build Tools";
const QString vcVarsBat = windowsProgramFilesDir() + '/' + name + "/vcbuildtools.bat";
@@ -1848,8 +1859,11 @@ static void detectCppBuildTools2015(QList<ToolChain *> *list)
}
}
-QList<ToolChain *> MsvcToolChainFactory::autoDetect(const QList<ToolChain *> &alreadyKnown)
+QList<ToolChain *> MsvcToolChainFactory::autoDetect(const QList<ToolChain *> &alreadyKnown,
+ const IDevice::Ptr &device)
{
+ Q_UNUSED(device)
+
QList<ToolChain *> results;
// 1) Installed SDKs preferred over standalone Visual studio
@@ -1911,6 +1925,8 @@ QList<ToolChain *> MsvcToolChainFactory::autoDetect(const QList<ToolChain *> &al
MsvcToolChain::arm,
MsvcToolChain::x86_arm,
MsvcToolChain::amd64_arm,
+ MsvcToolChain::x86_arm64,
+ MsvcToolChain::amd64_arm64,
MsvcToolChain::ia64,
MsvcToolChain::x86_ia64};
@@ -1950,9 +1966,11 @@ bool ClangClToolChainFactory::canCreate() const
return !g_availableMsvcToolchains.isEmpty();
}
-QList<ToolChain *> ClangClToolChainFactory::autoDetect(const QList<ToolChain *> &alreadyKnown)
+QList<ToolChain *> ClangClToolChainFactory::autoDetect(const QList<ToolChain *> &alreadyKnown,
+ const IDevice::Ptr &device)
{
Q_UNUSED(alreadyKnown)
+ Q_UNUSED(device) // FIXME: Use it.
#ifdef Q_OS_WIN64
const char registryNode[] = "HKEY_LOCAL_MACHINE\\SOFTWARE\\WOW6432Node\\LLVM\\LLVM";
@@ -2019,7 +2037,7 @@ Utils::optional<QString> MsvcToolChain::generateEnvironmentSettings(const Utils:
Utils::TempFileSaver saver(Utils::TemporaryDirectory::masterDirectoryPath() + "/XXXXXX.bat");
QByteArray call = "call ";
- call += Utils::QtcProcess::quoteArg(batchFile).toLocal8Bit();
+ call += ProcessArgs::quoteArg(batchFile).toLocal8Bit();
if (!batchArgs.isEmpty()) {
call += ' ';
call += batchArgs.toLocal8Bit();
@@ -2043,24 +2061,23 @@ Utils::optional<QString> MsvcToolChain::generateEnvironmentSettings(const Utils:
// if Creator is launched within a session set up by setenv.cmd.
Utils::Environment runEnv = env;
runEnv.unset(QLatin1String("ORIGINALPATH"));
- run.setEnvironment(runEnv.toStringList());
+ run.setEnvironment(runEnv);
run.setTimeoutS(30);
Utils::FilePath cmdPath = Utils::FilePath::fromUserInput(
QString::fromLocal8Bit(qgetenv("COMSPEC")));
if (cmdPath.isEmpty())
cmdPath = env.searchInPath(QLatin1String("cmd.exe"));
// Windows SDK setup scripts require command line switches for environment expansion.
- CommandLine cmd(cmdPath, {"/E:ON", "/V:ON", "/c", QDir::toNativeSeparators(saver.fileName())});
+ CommandLine cmd(cmdPath, {"/E:ON", "/V:ON", "/c", saver.filePath().toUserOutput()});
if (debug)
qDebug() << "readEnvironmentSetting: " << call << cmd.toUserOutput()
<< " Env: " << runEnv.size();
run.setCodec(QTextCodec::codecForName("UTF-8"));
- Utils::SynchronousProcessResponse response = run.runBlocking(cmd);
+ run.setCommand(cmd);
+ run.runBlocking();
- if (response.result != Utils::SynchronousProcessResponse::Finished) {
- const QString message = !response.stdErr().isEmpty()
- ? response.stdErr()
- : response.exitMessage(cmdPath.toString(), 10);
+ if (run.result() != QtcProcess::Finished) {
+ const QString message = !run.stdErr().isEmpty() ? run.stdErr() : run.exitMessage();
qWarning().noquote() << message;
QString command = QDir::toNativeSeparators(batchFile);
if (!batchArgs.isEmpty())
@@ -2072,7 +2089,7 @@ Utils::optional<QString> MsvcToolChain::generateEnvironmentSettings(const Utils:
}
// The SDK/MSVC scripts do not return exit codes != 0. Check on stdout.
- const QString stdOut = response.stdOut();
+ const QString stdOut = run.stdOut();
//
// Now parse the file to get the environment settings
diff --git a/src/plugins/projectexplorer/msvctoolchain.h b/src/plugins/projectexplorer/msvctoolchain.h
index 339ebb50ae..b74d278d59 100644
--- a/src/plugins/projectexplorer/msvctoolchain.h
+++ b/src/plugins/projectexplorer/msvctoolchain.h
@@ -57,7 +57,8 @@ class MsvcToolChain : public ToolChain
public:
enum Type { WindowsSDK, VS };
- enum Platform { x86, amd64, x86_amd64, ia64, x86_ia64, arm, x86_arm, amd64_arm, amd64_x86 };
+ enum Platform { x86, amd64, x86_amd64, ia64, x86_ia64, arm, x86_arm, amd64_arm, amd64_x86,
+ x86_arm64, amd64_arm64 };
explicit MsvcToolChain(Utils::Id typeId);
~MsvcToolChain() override;
@@ -197,7 +198,8 @@ class MsvcToolChainFactory : public ToolChainFactory
public:
MsvcToolChainFactory();
- QList<ToolChain *> autoDetect(const QList<ToolChain *> &alreadyKnown) override;
+ QList<ToolChain *> autoDetect(const QList<ToolChain *> &alreadyKnown,
+ const IDevice::Ptr &device) override;
bool canCreate() const override;
@@ -211,7 +213,8 @@ class ClangClToolChainFactory : public ToolChainFactory
public:
ClangClToolChainFactory();
- QList<ToolChain *> autoDetect(const QList<ToolChain *> &alreadyKnown) override;
+ QList<ToolChain *> autoDetect(const QList<ToolChain *> &alreadyKnown,
+ const IDevice::Ptr &device) override;
bool canCreate() const override;
};
diff --git a/src/plugins/projectexplorer/outputparser_test.cpp b/src/plugins/projectexplorer/outputparser_test.cpp
index 18e3a7ae19..8cbfb4108a 100644
--- a/src/plugins/projectexplorer/outputparser_test.cpp
+++ b/src/plugins/projectexplorer/outputparser_test.cpp
@@ -91,6 +91,7 @@ void OutputParserTester::testParsing(const QString &lines,
QVERIFY2(m_receivedTasks.at(i).file == tasks.at(i).file,
msgFileComparisonFail(m_receivedTasks.at(i).file, tasks.at(i).file));
QCOMPARE(m_receivedTasks.at(i).line, tasks.at(i).line);
+ QCOMPARE(m_receivedTasks.at(i).column, tasks.at(i).column);
QCOMPARE(static_cast<int>(m_receivedTasks.at(i).type), static_cast<int>(tasks.at(i).type));
// Skip formats check if we haven't specified expected
if (tasks.at(i).formats.size() == 0)
diff --git a/src/plugins/projectexplorer/processparameters.cpp b/src/plugins/projectexplorer/processparameters.cpp
index 9f5047e57e..fdec5291db 100644
--- a/src/plugins/projectexplorer/processparameters.cpp
+++ b/src/plugins/projectexplorer/processparameters.cpp
@@ -161,10 +161,10 @@ QString ProcessParameters::prettyArguments() const
{
QString margs = effectiveArguments();
QString workDir = effectiveWorkingDirectory().toString();
- QtcProcess::SplitError err;
- QtcProcess::Arguments args =
- QtcProcess::prepareArgs(margs, &err, HostOsInfo::hostOs(), &m_environment, &workDir);
- if (err != QtcProcess::SplitOk)
+ ProcessArgs::SplitError err;
+ ProcessArgs args =
+ ProcessArgs::prepareArgs(margs, &err, HostOsInfo::hostOs(), &m_environment, &workDir);
+ if (err != ProcessArgs::SplitOk)
return margs; // Sorry, too complex - just fall back.
return args.toString();
}
@@ -184,7 +184,7 @@ QString ProcessParameters::summary(const QString &displayName) const
return QString::fromLatin1("<b>%1:</b> %2 %3")
.arg(displayName,
- QtcProcess::quoteArg(prettyCommand()),
+ ProcessArgs::quoteArg(prettyCommand()),
prettyArguments());
}
@@ -195,7 +195,7 @@ QString ProcessParameters::summaryInWorkdir(const QString &displayName) const
return QString::fromLatin1("<b>%1:</b> %2 %3 in %4")
.arg(displayName,
- QtcProcess::quoteArg(prettyCommand()),
+ ProcessArgs::quoteArg(prettyCommand()),
prettyArguments(),
QDir::toNativeSeparators(effectiveWorkingDirectory().toString()));
}
diff --git a/src/plugins/projectexplorer/processparameters.h b/src/plugins/projectexplorer/processparameters.h
index 94d1bd8883..08f2cf7e27 100644
--- a/src/plugins/projectexplorer/processparameters.h
+++ b/src/plugins/projectexplorer/processparameters.h
@@ -27,6 +27,7 @@
#include "projectexplorer_export.h"
+#include <utils/commandline.h>
#include <utils/environment.h>
#include <utils/fileutils.h>
diff --git a/src/plugins/projectexplorer/project.cpp b/src/plugins/projectexplorer/project.cpp
index bbf35c342a..39d7a6c46f 100644
--- a/src/plugins/projectexplorer/project.cpp
+++ b/src/plugins/projectexplorer/project.cpp
@@ -188,6 +188,7 @@ public:
bool m_hasMakeInstallEquivalent = false;
bool m_needsBuildConfigurations = true;
bool m_needsDeployConfigurations = true;
+ bool m_shuttingDown = false;
std::function<BuildSystem *(Target *)> m_buildSystemCreator;
@@ -247,6 +248,16 @@ Utils::Id Project::id() const
return d->m_id;
}
+void Project::markAsShuttingDown()
+{
+ d->m_shuttingDown = true;
+}
+
+bool Project::isShuttingDown() const
+{
+ return d->m_shuttingDown;
+}
+
QString Project::mimeType() const
{
return d->m_document->mimeType();
@@ -312,6 +323,7 @@ bool Project::removeTarget(Target *target)
if (BuildManager::isBuilding(target))
return false;
+ target->markAsShuttingDown();
emit aboutToRemoveTarget(target);
auto keep = Utils::take(d->m_targets, target);
if (target == d->m_activeTarget) {
@@ -1083,10 +1095,14 @@ bool Project::isModified() const
} // namespace ProjectExplorer
+#include <coreplugin/editormanager/editormanager.h>
#include <utils/hostosinfo.h>
+#include <utils/temporarydirectory.h>
-#include <QTest>
+#include <QEventLoop>
#include <QSignalSpy>
+#include <QTest>
+#include <QTimer>
namespace ProjectExplorer {
@@ -1283,6 +1299,60 @@ void ProjectExplorerPlugin::testProject_projectTree()
QVERIFY(!project.rootProjectNode());
}
+void ProjectExplorerPlugin::testProject_multipleBuildConfigs()
+{
+ // Find suitable kit.
+ Kit * const kit = Utils::findOr(KitManager::kits(), nullptr, [](const Kit *k) {
+ return k->isValid();
+ });
+ if (!kit)
+ QSKIP("The test requires at least one valid kit.");
+
+ // Copy project from qrc file and set it up.
+ using namespace Utils;
+ QTemporaryDir * const tempDir = TemporaryDirectory::masterTemporaryDirectory();
+ QVERIFY(tempDir->isValid());
+ QString error;
+ const FilePath projectDir = FilePath::fromString(tempDir->path() + "/generic-project");
+ FileUtils::copyRecursively(FilePath::fromString(":/projectexplorer/testdata/generic-project"),
+ projectDir, &error);
+ QVERIFY2(error.isEmpty(), qPrintable(error));
+ const QFileInfoList files = QDir(projectDir.toString()).entryInfoList(QDir::Files | QDir::Dirs);
+ for (const QFileInfo &f : files)
+ QFile(f.absoluteFilePath()).setPermissions(f.permissions() | QFile::WriteUser);
+ const auto theProject = openProject(projectDir.pathAppended("generic-project.creator")
+ .toString());
+ QVERIFY2(theProject, qPrintable(theProject.errorMessage()));
+ theProject.project()->configureAsExampleProject(kit);
+ QCOMPARE(theProject.project()->targets().size(), 1);
+ Target * const target = theProject.project()->activeTarget();
+ QVERIFY(target);
+ QCOMPARE(target->buildConfigurations().size(), 6);
+ SessionManager::setActiveBuildConfiguration(target, target->buildConfigurations().at(1),
+ SetActive::Cascade);
+ BuildSystem * const bs = theProject.project()->activeTarget()->buildSystem();
+ QVERIFY(bs);
+ QCOMPARE(bs, target->activeBuildConfiguration()->buildSystem());
+ if (bs->isWaitingForParse() || bs->isParsing()) {
+ QEventLoop loop;
+ QTimer t;
+ t.setSingleShot(true);
+ connect(&t, &QTimer::timeout, &loop, &QEventLoop::quit);
+ connect(bs, &BuildSystem::parsingFinished, &loop, &QEventLoop::quit);
+ t.start(10000);
+ QVERIFY(loop.exec());
+ QVERIFY(t.isActive());
+ }
+ QVERIFY(!bs->isWaitingForParse() && !bs->isParsing());
+
+ QCOMPARE(SessionManager::startupProject(), theProject.project());
+ QCOMPARE(ProjectTree::currentProject(), theProject.project());
+ QVERIFY(Core::EditorManager::openEditor(projectDir.pathAppended("main.cpp")));
+ QVERIFY(ProjectTree::currentNode());
+ ProjectTree::instance()->expandAll();
+ SessionManager::closeAllProjects(); // QTCREATORBUG-25655
+}
+
#endif // WITH_TESTS
} // namespace ProjectExplorer
diff --git a/src/plugins/projectexplorer/project.h b/src/plugins/projectexplorer/project.h
index 317d8bdc19..31cb6e12b9 100644
--- a/src/plugins/projectexplorer/project.h
+++ b/src/plugins/projectexplorer/project.h
@@ -80,6 +80,9 @@ public:
QString displayName() const;
Utils::Id id() const;
+ void markAsShuttingDown();
+ bool isShuttingDown() const;
+
QString mimeType() const;
bool canBuildProducts() const;
diff --git a/src/plugins/projectexplorer/projectconfiguration.cpp b/src/plugins/projectexplorer/projectconfiguration.cpp
index 10490df854..92e77dc89f 100644
--- a/src/plugins/projectexplorer/projectconfiguration.cpp
+++ b/src/plugins/projectexplorer/projectconfiguration.cpp
@@ -24,6 +24,8 @@
****************************************************************************/
#include "projectconfiguration.h"
+
+#include "kitinformation.h"
#include "target.h"
#include <utils/algorithm.h>
@@ -33,6 +35,7 @@
#include <QWidget>
using namespace ProjectExplorer;
+using namespace Utils;
const char CONFIGURATION_ID_KEY[] = "ProjectExplorer.ProjectConfiguration.Id";
const char DISPLAY_NAME_KEY[] = "ProjectExplorer.ProjectConfiguration.DisplayName";
@@ -43,6 +46,8 @@ ProjectConfiguration::ProjectConfiguration(QObject *parent, Utils::Id id)
: QObject(parent)
, m_id(id)
{
+ m_aspects.setOwnsSubAspects(true);
+
QTC_CHECK(parent);
QTC_CHECK(id.isValid());
setObjectName(id.toString());
@@ -140,6 +145,13 @@ void ProjectConfiguration::acquaintAspects()
aspect->acquaintSiblings(m_aspects);
}
+FilePath ProjectConfiguration::mapFromBuildDeviceToGlobalPath(const FilePath &path) const
+{
+ IDevice::ConstPtr dev = BuildDeviceKitAspect::device(kit());
+ QTC_ASSERT(dev, return path);
+ return dev->mapToGlobalPath(path);
+}
+
Utils::Id ProjectExplorer::idFromMap(const QVariantMap &map)
{
return Utils::Id::fromSetting(map.value(QLatin1String(CONFIGURATION_ID_KEY)));
diff --git a/src/plugins/projectexplorer/projectconfiguration.h b/src/plugins/projectexplorer/projectconfiguration.h
index eb4cc325a6..a6d1732973 100644
--- a/src/plugins/projectexplorer/projectconfiguration.h
+++ b/src/plugins/projectexplorer/projectconfiguration.h
@@ -82,19 +82,21 @@ public:
return m_aspects.addAspect<Aspect>(std::forward<Args>(args)...);
}
- const Utils::BaseAspects &aspects() const { return m_aspects; }
+ const Utils::AspectContainer &aspects() const { return m_aspects; }
Utils::BaseAspect *aspect(Utils::Id id) const;
template <typename T> T *aspect() const { return m_aspects.aspect<T>(); }
void acquaintAspects();
+ Utils::FilePath mapFromBuildDeviceToGlobalPath(const Utils::FilePath &path) const;
+
signals:
void displayNameChanged();
void toolTipChanged();
protected:
- Utils::BaseAspects m_aspects;
+ Utils::AspectContainer m_aspects;
private:
QPointer<Target> m_target;
diff --git a/src/plugins/projectexplorer/projectexplorer.cpp b/src/plugins/projectexplorer/projectexplorer.cpp
index 6c98f71675..75c9ce59eb 100644
--- a/src/plugins/projectexplorer/projectexplorer.cpp
+++ b/src/plugins/projectexplorer/projectexplorer.cpp
@@ -27,7 +27,6 @@
#include "appoutputpane.h"
#include "buildpropertiessettings.h"
-#include "buildpropertiessettingspage.h"
#include "buildsteplist.h"
#include "buildsystem.h"
#include "compileoutputwindow.h"
@@ -124,7 +123,9 @@
#include <coreplugin/imode.h>
#include <coreplugin/iversioncontrol.h>
#include <coreplugin/locator/directoryfilter.h>
+#include <coreplugin/minisplitter.h>
#include <coreplugin/modemanager.h>
+#include <coreplugin/outputpane.h>
#include <coreplugin/vcsmanager.h>
#include <extensionsystem/pluginmanager.h>
#include <extensionsystem/pluginspec.h>
@@ -256,10 +257,6 @@ const char RUNMENUCONTEXTMENU[] = "Project.RunMenu";
const char FOLDER_OPEN_LOCATIONS_CONTEXT_MENU[] = "Project.F.OpenLocation.CtxMenu";
const char PROJECT_OPEN_LOCATIONS_CONTEXT_MENU[] = "Project.P.OpenLocation.CtxMenu";
-// Default directories:
-const char DEFAULT_BUILD_DIRECTORY_TEMPLATE[] = "../%{JS: Util.asciify(\"build-%{Project:Name}-%{Kit:FileSystemName}-%{BuildConfig:Name}\")}";
-const char DEFAULT_BUILD_DIRECTORY_TEMPLATE_KEY_OLD[] = "Directories/BuildDirectory.Template"; // TODO: Remove in ~4.16
-const char DEFAULT_BUILD_DIRECTORY_TEMPLATE_KEY[] = "Directories/BuildDirectory.TemplateV2";
const char RECENTPROJECTS_FILE_NAMES_KEY[] = "ProjectExplorer/RecentProjects/FileNames";
const char RECENTPROJECTS_DISPLAY_NAMES_KEY[] = "ProjectExplorer/RecentProjects/DisplayNames";
@@ -284,10 +281,6 @@ const char ABORT_BUILD_ALL_ON_ERROR_SETTINGS_KEY[]
= "ProjectExplorer/Settings/AbortBuildAllOnError";
const char LOW_BUILD_PRIORITY_SETTINGS_KEY[] = "ProjectExplorer/Settings/LowBuildPriority";
-const char SEPARATE_DEBUG_INFO_SETTINGS_KEY[] = "ProjectExplorer/Settings/SeparateDebugInfo";
-const char QML_DEBUGGING_SETTINGS_KEY[] = "ProjectExplorer/Settings/QmlDebugging";
-const char QT_QUICK_COMPILER_SETTINGS_KEY[] = "ProjectExplorer/Settings/QtQuickCompiler";
-
const char CUSTOM_PARSER_COUNT_KEY[] = "ProjectExplorer/Settings/CustomParserCount";
const char CUSTOM_PARSER_PREFIX_KEY[] = "ProjectExplorer/Settings/CustomParser";
@@ -505,19 +498,19 @@ public:
QAction *m_buildSessionAction;
QAction *m_buildSessionForAllConfigsAction;
QAction *m_rebuildProjectOnlyAction;
- Utils::ParameterAction *m_rebuildAction;
- Utils::ParameterAction *m_rebuildProjectForAllConfigsAction;
+ QAction *m_rebuildAction;
+ QAction *m_rebuildProjectForAllConfigsAction;
QAction *m_rebuildActionContextMenu;
QAction *m_rebuildDependenciesActionContextMenu;
QAction *m_rebuildSessionAction;
QAction *m_rebuildSessionForAllConfigsAction;
QAction *m_cleanProjectOnlyAction;
QAction *m_deployProjectOnlyAction;
- Utils::ParameterAction *m_deployAction;
+ QAction *m_deployAction;
QAction *m_deployActionContextMenu;
QAction *m_deploySessionAction;
- Utils::ParameterAction *m_cleanAction;
- Utils::ParameterAction *m_cleanProjectForAllConfigsAction;
+ QAction *m_cleanAction;
+ QAction *m_cleanProjectForAllConfigsAction;
QAction *m_cleanActionContextMenu;
QAction *m_cleanDependenciesActionContextMenu;
QAction *m_cleanSessionAction;
@@ -648,7 +641,7 @@ public:
// Settings pages
ProjectExplorerSettingsPage m_projectExplorerSettingsPage;
- BuildPropertiesSettingsPage m_buildPropertiesSettingsPage;
+ BuildPropertiesSettingsPage m_buildPropertiesSettingsPage{&m_buildPropertiesSettings};
AppOutputSettingsPage m_appOutputSettingsPage;
CompileOutputSettingsPage m_compileOutputSettingsPage;
DeviceSettingsPage m_deviceSettingsPage;
@@ -662,7 +655,8 @@ public:
IDocumentFactory m_documentFactory;
DeviceTypeKitAspect deviceTypeKitAspect;
- DeviceKitAspect deviceeKitAspect;
+ DeviceKitAspect deviceKitAspect;
+ BuildDeviceKitAspect buildDeviceKitAspect;
ToolChainKitAspect toolChainKitAspect;
SysRootKitAspect sysRootKitAspect;
EnvironmentKitAspect environmentKitAspect;
@@ -804,7 +798,10 @@ bool ProjectExplorerPlugin::initialize(const QStringList &arguments, QString *er
Context projectTreeContext(Constants::C_PROJECT_TREE);
- dd->m_projectsMode.setWidget(dd->m_proWindow);
+ auto splitter = new MiniSplitter(Qt::Vertical);
+ splitter->addWidget(dd->m_proWindow);
+ splitter->addWidget(new OutputPanePlaceHolder(Constants::MODE_SESSION, splitter));
+ dd->m_projectsMode.setWidget(splitter);
dd->m_projectsMode.setEnabled(false);
ICore::addPreCloseListener([]() -> bool { return coreAboutToClose(); });
@@ -894,9 +891,13 @@ bool ProjectExplorerPlugin::initialize(const QStringList &arguments, QString *er
//
mbuild->appendGroup(Constants::G_BUILD_BUILD);
- mbuild->appendGroup(Constants::G_BUILD_DEPLOY);
- mbuild->appendGroup(Constants::G_BUILD_REBUILD);
- mbuild->appendGroup(Constants::G_BUILD_CLEAN);
+ mbuild->appendGroup(Constants::G_BUILD_ALLPROJECTS);
+ mbuild->appendGroup(Constants::G_BUILD_PROJECT);
+ mbuild->appendGroup(Constants::G_BUILD_PRODUCT);
+ mbuild->appendGroup(Constants::G_BUILD_SUBPROJECT);
+ mbuild->appendGroup(Constants::G_BUILD_FILE);
+ mbuild->appendGroup(Constants::G_BUILD_ALLPROJECTS_ALLCONFIGURATIONS);
+ mbuild->appendGroup(Constants::G_BUILD_PROJECT_ALLCONFIGURATIONS);
mbuild->appendGroup(Constants::G_BUILD_CANCEL);
mbuild->appendGroup(Constants::G_BUILD_RUN);
@@ -982,7 +983,14 @@ bool ProjectExplorerPlugin::initialize(const QStringList &arguments, QString *er
mprojectContextMenu->addSeparator(projectTreeContext, Constants::G_PROJECT_FILES);
msubProjectContextMenu->addSeparator(projectTreeContext, Constants::G_PROJECT_FILES);
mfile->addSeparator(Core::Constants::G_FILE_PROJECT);
- mbuild->addSeparator(Constants::G_BUILD_REBUILD);
+ mbuild->addSeparator(Constants::G_BUILD_BUILD);
+ mbuild->addSeparator(Constants::G_BUILD_ALLPROJECTS);
+ mbuild->addSeparator(Constants::G_BUILD_PROJECT);
+ mbuild->addSeparator(Constants::G_BUILD_PRODUCT);
+ mbuild->addSeparator(Constants::G_BUILD_SUBPROJECT);
+ mbuild->addSeparator(Constants::G_BUILD_FILE);
+ mbuild->addSeparator(Constants::G_BUILD_ALLPROJECTS_ALLCONFIGURATIONS);
+ mbuild->addSeparator(Constants::G_BUILD_PROJECT_ALLCONFIGURATIONS);
msessionContextMenu->addSeparator(Constants::G_SESSION_OTHER);
mbuild->addSeparator(Constants::G_BUILD_CANCEL);
mbuild->addSeparator(Constants::G_BUILD_RUN);
@@ -1119,49 +1127,49 @@ bool ProjectExplorerPlugin::initialize(const QStringList &arguments, QString *er
dd->m_buildSessionAction = new QAction(buildIcon, tr("Build All Projects"), this);
cmd = ActionManager::registerAction(dd->m_buildSessionAction, Constants::BUILDSESSION);
cmd->setDefaultKeySequence(QKeySequence(tr("Ctrl+Shift+B")));
- mbuild->addAction(cmd, Constants::G_BUILD_BUILD);
+ mbuild->addAction(cmd, Constants::G_BUILD_ALLPROJECTS);
msessionContextMenu->addAction(cmd, Constants::G_SESSION_BUILD);
dd->m_buildSessionForAllConfigsAction
= new QAction(buildIcon, tr("Build All Projects for All Configurations"), this);
cmd = ActionManager::registerAction(dd->m_buildSessionForAllConfigsAction,
Constants::BUILDSESSIONALLCONFIGS);
- mbuild->addAction(cmd, Constants::G_BUILD_BUILD);
+ mbuild->addAction(cmd, Constants::G_BUILD_ALLPROJECTS_ALLCONFIGURATIONS);
msessionContextMenu->addAction(cmd, Constants::G_SESSION_BUILD);
// deploy session
- dd->m_deploySessionAction = new QAction(tr("Deploy All Projects"), this);
+ dd->m_deploySessionAction = new QAction(tr("Deploy"), this);
cmd = ActionManager::registerAction(dd->m_deploySessionAction, Constants::DEPLOYSESSION);
- mbuild->addAction(cmd, Constants::G_BUILD_DEPLOY);
+ mbuild->addAction(cmd, Constants::G_BUILD_ALLPROJECTS);
msessionContextMenu->addAction(cmd, Constants::G_SESSION_BUILD);
// rebuild session action
- dd->m_rebuildSessionAction = new QAction(Icons::REBUILD.icon(), tr("Rebuild All Projects"),
+ dd->m_rebuildSessionAction = new QAction(Icons::REBUILD.icon(), tr("Rebuild"),
this);
cmd = ActionManager::registerAction(dd->m_rebuildSessionAction, Constants::REBUILDSESSION);
- mbuild->addAction(cmd, Constants::G_BUILD_REBUILD);
+ mbuild->addAction(cmd, Constants::G_BUILD_ALLPROJECTS);
msessionContextMenu->addAction(cmd, Constants::G_SESSION_REBUILD);
dd->m_rebuildSessionForAllConfigsAction
- = new QAction(Icons::REBUILD.icon(), tr("Rebuild All Projects for All Configurations"),
+ = new QAction(Icons::REBUILD.icon(), tr("Rebuild"),
this);
cmd = ActionManager::registerAction(dd->m_rebuildSessionForAllConfigsAction,
Constants::REBUILDSESSIONALLCONFIGS);
- mbuild->addAction(cmd, Constants::G_BUILD_REBUILD);
+ mbuild->addAction(cmd, Constants::G_BUILD_ALLPROJECTS_ALLCONFIGURATIONS);
msessionContextMenu->addAction(cmd, Constants::G_SESSION_REBUILD);
// clean session
- dd->m_cleanSessionAction = new QAction(Utils::Icons::CLEAN.icon(), tr("Clean All Projects"),
+ dd->m_cleanSessionAction = new QAction(Utils::Icons::CLEAN.icon(), tr("Clean"),
this);
cmd = ActionManager::registerAction(dd->m_cleanSessionAction, Constants::CLEANSESSION);
- mbuild->addAction(cmd, Constants::G_BUILD_CLEAN);
+ mbuild->addAction(cmd, Constants::G_BUILD_ALLPROJECTS);
msessionContextMenu->addAction(cmd, Constants::G_SESSION_REBUILD);
dd->m_cleanSessionForAllConfigsAction = new QAction(Utils::Icons::CLEAN.icon(),
- tr("Clean All Projects for All Configurations"), this);
+ tr("Clean"), this);
cmd = ActionManager::registerAction(dd->m_cleanSessionForAllConfigsAction,
Constants::CLEANSESSIONALLCONFIGS);
- mbuild->addAction(cmd, Constants::G_BUILD_CLEAN);
+ mbuild->addAction(cmd, Constants::G_BUILD_ALLPROJECTS_ALLCONFIGURATIONS);
msessionContextMenu->addAction(cmd, Constants::G_SESSION_REBUILD);
// build action
@@ -1172,7 +1180,7 @@ bool ProjectExplorerPlugin::initialize(const QStringList &arguments, QString *er
cmd->setAttribute(Command::CA_UpdateText);
cmd->setDescription(dd->m_buildAction->text());
cmd->setDefaultKeySequence(QKeySequence(tr("Ctrl+B")));
- mbuild->addAction(cmd, Constants::G_BUILD_BUILD);
+ mbuild->addAction(cmd, Constants::G_BUILD_PROJECT);
dd->m_buildProjectForAllConfigsAction
= new Utils::ParameterAction(tr("Build Project for All Configurations"),
@@ -1183,7 +1191,7 @@ bool ProjectExplorerPlugin::initialize(const QStringList &arguments, QString *er
Constants::BUILDALLCONFIGS);
cmd->setAttribute(Command::CA_UpdateText);
cmd->setDescription(dd->m_buildProjectForAllConfigsAction->text());
- mbuild->addAction(cmd, Constants::G_BUILD_BUILD);
+ mbuild->addAction(cmd, Constants::G_BUILD_PROJECT_ALLCONFIGURATIONS);
// Add to mode bar
dd->m_modeBarBuildAction = new Utils::ProxyAction(this);
@@ -1205,48 +1213,41 @@ bool ProjectExplorerPlugin::initialize(const QStringList &arguments, QString *er
mbuild->addAction(cmd, Constants::G_BUILD_BUILD);
// deploy action
- dd->m_deployAction = new Utils::ParameterAction(tr("Deploy Project"), tr("Deploy Project \"%1\""),
- Utils::ParameterAction::AlwaysEnabled, this);
+ dd->m_deployAction = new QAction(tr("Deploy"), this);
cmd = ActionManager::registerAction(dd->m_deployAction, Constants::DEPLOY);
cmd->setAttribute(Command::CA_UpdateText);
cmd->setDescription(dd->m_deployAction->text());
- mbuild->addAction(cmd, Constants::G_BUILD_DEPLOY);
+ mbuild->addAction(cmd, Constants::G_BUILD_PROJECT);
// rebuild action
- dd->m_rebuildAction = new Utils::ParameterAction(tr("Rebuild Project"), tr("Rebuild Project \"%1\""),
- Utils::ParameterAction::AlwaysEnabled, this);
+ dd->m_rebuildAction = new QAction(Icons::REBUILD.icon(), tr("Rebuild"), this);
cmd = ActionManager::registerAction(dd->m_rebuildAction, Constants::REBUILD);
cmd->setAttribute(Command::CA_UpdateText);
cmd->setDescription(dd->m_rebuildAction->text());
- mbuild->addAction(cmd, Constants::G_BUILD_REBUILD);
+ mbuild->addAction(cmd, Constants::G_BUILD_PROJECT);
dd->m_rebuildProjectForAllConfigsAction
- = new Utils::ParameterAction(tr("Rebuild Project for All Configurations"),
- tr("Rebuild Project \"%1\" for All Configurations"),
- Utils::ParameterAction::AlwaysEnabled, this);
+ = new QAction(Icons::REBUILD.icon(), tr("Rebuild"), this);
cmd = ActionManager::registerAction(dd->m_rebuildProjectForAllConfigsAction,
Constants::REBUILDALLCONFIGS);
cmd->setAttribute(Command::CA_UpdateText);
cmd->setDescription(dd->m_rebuildProjectForAllConfigsAction->text());
- mbuild->addAction(cmd, Constants::G_BUILD_REBUILD);
+ mbuild->addAction(cmd, Constants::G_BUILD_PROJECT_ALLCONFIGURATIONS);
// clean action
- dd->m_cleanAction = new Utils::ParameterAction(tr("Clean Project"), tr("Clean Project \"%1\""),
- Utils::ParameterAction::AlwaysEnabled, this);
+ dd->m_cleanAction = new QAction(Utils::Icons::CLEAN.icon(), tr("Clean"), this);
cmd = ActionManager::registerAction(dd->m_cleanAction, Constants::CLEAN);
cmd->setAttribute(Command::CA_UpdateText);
cmd->setDescription(dd->m_cleanAction->text());
- mbuild->addAction(cmd, Constants::G_BUILD_CLEAN);
+ mbuild->addAction(cmd, Constants::G_BUILD_PROJECT);
dd->m_cleanProjectForAllConfigsAction
- = new Utils::ParameterAction(tr("Clean Project for All Configurations"),
- tr("Clean Project \"%1\" for All Configurations"),
- Utils::ParameterAction::AlwaysEnabled, this);
+ = new QAction(Utils::Icons::CLEAN.icon(), tr("Clean"), this);
cmd = ActionManager::registerAction(dd->m_cleanProjectForAllConfigsAction,
Constants::CLEANALLCONFIGS);
cmd->setAttribute(Command::CA_UpdateText);
cmd->setDescription(dd->m_cleanProjectForAllConfigsAction->text());
- mbuild->addAction(cmd, Constants::G_BUILD_CLEAN);
+ mbuild->addAction(cmd, Constants::G_BUILD_PROJECT_ALLCONFIGURATIONS);
// cancel build action
dd->m_cancelBuildAction = new QAction(Utils::Icons::STOP_SMALL.icon(), tr("Cancel Build"), this);
@@ -1585,33 +1586,7 @@ bool ProjectExplorerPlugin::initialize(const QStringList &arguments, QString *er
= s->value(Constants::LOW_BUILD_PRIORITY_SETTINGS_KEY, defaultSettings.lowBuildPriority)
.toBool();
- dd->m_buildPropertiesSettings.buildDirectoryTemplateOld
- = s->value(Constants::DEFAULT_BUILD_DIRECTORY_TEMPLATE_KEY_OLD).toString();
- dd->m_buildPropertiesSettings.buildDirectoryTemplate
- = s->value(Constants::DEFAULT_BUILD_DIRECTORY_TEMPLATE_KEY).toString();
- if (dd->m_buildPropertiesSettings.buildDirectoryTemplate.isEmpty()) {
- dd->m_buildPropertiesSettings.buildDirectoryTemplate
- = dd->m_buildPropertiesSettings.buildDirectoryTemplateOld;
- }
- if (dd->m_buildPropertiesSettings.buildDirectoryTemplate.isEmpty())
- dd->m_buildPropertiesSettings.buildDirectoryTemplate = Constants::DEFAULT_BUILD_DIRECTORY_TEMPLATE;
- // TODO: Remove in ~4.16
- dd->m_buildPropertiesSettings.buildDirectoryTemplate.replace("%{CurrentProject:Name}",
- "%{Project:Name}");
- dd->m_buildPropertiesSettings.buildDirectoryTemplate.replace("%{CurrentKit:FileSystemName}",
- "%{Kit:FileSystemName}");
- dd->m_buildPropertiesSettings.buildDirectoryTemplate.replace("%{CurrentBuild:Name}",
- "%{BuildConfig:Name}");
-
- const auto loadTriStateValue = [&s](const QString &key) {
- return TriState::fromVariant(s->value(key, TriState::Default.toVariant()));
- };
- dd->m_buildPropertiesSettings.separateDebugInfo
- = loadTriStateValue(Constants::SEPARATE_DEBUG_INFO_SETTINGS_KEY);
- dd->m_buildPropertiesSettings.qmlDebugging
- = loadTriStateValue(Constants::QML_DEBUGGING_SETTINGS_KEY);
- dd->m_buildPropertiesSettings.qtQuickCompiler
- = loadTriStateValue(Constants::QT_QUICK_COMPILER_SETTINGS_KEY);
+ dd->m_buildPropertiesSettings.readSettings(s);
const int customParserCount = s->value(Constants::CUSTOM_PARSER_COUNT_KEY).toInt();
for (int i = 0; i < customParserCount; ++i) {
@@ -2096,8 +2071,7 @@ void ProjectExplorerPlugin::extensionsInitialized()
QSsh::SshSettings::loadSettings(Core::ICore::settings());
const auto searchPathRetriever = [] {
- Utils::FilePaths searchPaths;
- searchPaths << Utils::FilePath::fromString(Core::ICore::libexecPath());
+ Utils::FilePaths searchPaths = {Core::ICore::libexecPath()};
if (Utils::HostOsInfo::isWindowsHost()) {
const QString gitBinary = Core::ICore::settings()->value("Git/BinaryPath", "git")
.toString();
@@ -2301,27 +2275,7 @@ void ProjectExplorerPluginPrivate::savePersistentSettings()
int(dd->m_projectExplorerSettings.stopBeforeBuild),
int(defaultSettings.stopBeforeBuild));
- // Store this in the Core directory scope for backward compatibility!
- if (dd->m_buildPropertiesSettings.buildDirectoryTemplate
- == Constants::DEFAULT_BUILD_DIRECTORY_TEMPLATE) {
- s->remove(Constants::DEFAULT_BUILD_DIRECTORY_TEMPLATE_KEY_OLD);
- s->remove(Constants::DEFAULT_BUILD_DIRECTORY_TEMPLATE_KEY);
- } else {
- s->setValue(Constants::DEFAULT_BUILD_DIRECTORY_TEMPLATE_KEY_OLD,
- dd->m_buildPropertiesSettings.buildDirectoryTemplateOld);
- s->setValue(Constants::DEFAULT_BUILD_DIRECTORY_TEMPLATE_KEY,
- dd->m_buildPropertiesSettings.buildDirectoryTemplate);
- }
-
- s->setValueWithDefault(Constants::SEPARATE_DEBUG_INFO_SETTINGS_KEY,
- dd->m_buildPropertiesSettings.separateDebugInfo.toVariant(),
- TriState::Default.toVariant());
- s->setValueWithDefault(Constants::QML_DEBUGGING_SETTINGS_KEY,
- dd->m_buildPropertiesSettings.qmlDebugging.toVariant(),
- TriState::Default.toVariant());
- s->setValueWithDefault(Constants::QT_QUICK_COMPILER_SETTINGS_KEY,
- dd->m_buildPropertiesSettings.qtQuickCompiler.toVariant(),
- TriState::Default.toVariant());
+ dd->m_buildPropertiesSettings.writeSettings(s);
s->setValueWithDefault(Constants::CUSTOM_PARSER_COUNT_KEY, int(dd->m_customParsers.count()), 0);
for (int i = 0; i < dd->m_customParsers.count(); ++i) {
@@ -2730,10 +2684,6 @@ void ProjectExplorerPluginPrivate::updateActions()
m_buildProjectForAllConfigsAction->setParameter(projectName);
if (runConfig)
m_buildForRunConfigAction->setParameter(runConfig->displayName());
- m_rebuildAction->setParameter(projectName);
- m_rebuildProjectForAllConfigsAction->setParameter(projectName);
- m_cleanAction->setParameter(projectName);
- m_cleanProjectForAllConfigsAction->setParameter(projectName);
m_buildAction->setEnabled(buildActionState.first);
m_buildProjectForAllConfigsAction->setEnabled(buildActionState.first);
@@ -3104,7 +3054,6 @@ void ProjectExplorerPluginPrivate::updateDeployActions()
const QString projectName = project ? project->displayName() : QString();
bool hasProjects = SessionManager::hasProjects();
- m_deployAction->setParameter(projectName);
m_deployAction->setEnabled(enableDeployActions);
m_deployActionContextMenu->setEnabled(enableDeployActionsContextMenu);
@@ -3510,7 +3459,7 @@ void ProjectExplorerPluginPrivate::updateLocationSubMenus()
: tr("%1 in %2").arg(li.displayName).arg(li.path.toUserOutput());
auto *action = new QAction(displayName, nullptr);
connect(action, &QAction::triggered, this, [line, path]() {
- Core::EditorManager::openEditorAt(path.toString(), line);
+ Core::EditorManager::openEditorAt(Link(path, line));
});
projectMenu->addAction(action);
@@ -3690,7 +3639,7 @@ void ProjectExplorerPluginPrivate::openFile()
{
const Node *currentNode = ProjectTree::currentNode();
QTC_ASSERT(currentNode, return);
- EditorManager::openEditor(currentNode->filePath().toString());
+ EditorManager::openEditor(currentNode->filePath());
}
void ProjectExplorerPluginPrivate::searchOnFileSystem()
@@ -4022,19 +3971,14 @@ const AppOutputSettings &ProjectExplorerPlugin::appOutputSettings()
return dd->m_outputPane.settings();
}
-void ProjectExplorerPlugin::setBuildPropertiesSettings(const BuildPropertiesSettings &settings)
-{
- dd->m_buildPropertiesSettings = settings;
-}
-
-const BuildPropertiesSettings &ProjectExplorerPlugin::buildPropertiesSettings()
+BuildPropertiesSettings &ProjectExplorerPlugin::buildPropertiesSettings()
{
return dd->m_buildPropertiesSettings;
}
void ProjectExplorerPlugin::showQtSettings()
{
- dd->m_buildPropertiesSettings.showQtSettings = true;
+ dd->m_buildPropertiesSettings.showQtSettings.setValue(true);
}
void ProjectExplorerPlugin::setCustomParsers(const QList<CustomParserSettings> &settings)
@@ -4107,12 +4051,12 @@ void ProjectExplorerPlugin::openOpenProjectDialog()
*/
QString ProjectExplorerPlugin::buildDirectoryTemplate()
{
- return dd->m_buildPropertiesSettings.buildDirectoryTemplate;
+ return dd->m_buildPropertiesSettings.buildDirectoryTemplate.value();
}
QString ProjectExplorerPlugin::defaultBuildDirectoryTemplate()
{
- return QString(Constants::DEFAULT_BUILD_DIRECTORY_TEMPLATE);
+ return dd->m_buildPropertiesSettings.defaultBuildDirectoryTemplate();
}
void ProjectExplorerPlugin::updateActions()
diff --git a/src/plugins/projectexplorer/projectexplorer.h b/src/plugins/projectexplorer/projectexplorer.h
index 1255beb08e..2d6aaf9a51 100644
--- a/src/plugins/projectexplorer/projectexplorer.h
+++ b/src/plugins/projectexplorer/projectexplorer.h
@@ -137,8 +137,7 @@ public:
static void setAppOutputSettings(const Internal::AppOutputSettings &settings);
static const Internal::AppOutputSettings &appOutputSettings();
- static void setBuildPropertiesSettings(const BuildPropertiesSettings &settings);
- static const BuildPropertiesSettings &buildPropertiesSettings();
+ static BuildPropertiesSettings &buildPropertiesSettings();
static void showQtSettings();
static void setCustomParsers(const QList<CustomParserSettings> &settings);
@@ -274,6 +273,7 @@ private slots:
void testProject_parsingSuccess();
void testProject_parsingFail();
void testProject_projectTree();
+ void testProject_multipleBuildConfigs();
void testSessionSwitch();
#endif // WITH_TESTS
diff --git a/src/plugins/projectexplorer/projectexplorer.pro b/src/plugins/projectexplorer/projectexplorer.pro
index 89771190dd..07ecca97b8 100644
--- a/src/plugins/projectexplorer/projectexplorer.pro
+++ b/src/plugins/projectexplorer/projectexplorer.pro
@@ -14,7 +14,6 @@ HEADERS += projectexplorer.h \
buildaspects.h \
buildinfo.h \
buildpropertiessettings.h \
- buildpropertiessettingspage.h \
buildsystem.h \
buildtargettype.h \
clangparser.h \
@@ -173,7 +172,7 @@ SOURCES += projectexplorer.cpp \
addrunconfigdialog.cpp \
buildaspects.cpp \
buildinfo.cpp \
- buildpropertiessettingspage.cpp \
+ buildpropertiessettings.cpp \
buildsystem.cpp \
clangparser.cpp \
customparserssettingspage.cpp \
@@ -343,6 +342,10 @@ equals(TEST, 1) {
outputparser_test.cpp
HEADERS += \
outputparser_test.h
+ test_files.files = $$files(testdata/*, true)
+ test_files.base = $$PWD
+ test_files.prefix = /projectexplorer
+ RESOURCES += test_files
}
journald {
diff --git a/src/plugins/projectexplorer/projectexplorer.qbs b/src/plugins/projectexplorer/projectexplorer.qbs
index da3f283224..e6e64c98fa 100644
--- a/src/plugins/projectexplorer/projectexplorer.qbs
+++ b/src/plugins/projectexplorer/projectexplorer.qbs
@@ -16,6 +16,8 @@ Project {
Depends { name: "libclang"; required: false }
Depends { name: "clang_defines" }
+ pluginTestDepends: ["GenericProjectManager"]
+
Group {
name: "General"
files: [
@@ -33,8 +35,7 @@ Project {
"buildinfo.cpp", "buildinfo.h",
"buildmanager.cpp", "buildmanager.h",
"buildprogress.cpp", "buildprogress.h",
- "buildpropertiessettings.h",
- "buildpropertiessettingspage.cpp", "buildpropertiessettingspage.h",
+ "buildpropertiessettings.cpp", "buildpropertiessettings.h",
"buildsettingspropertiespage.cpp", "buildsettingspropertiespage.h",
"buildstep.cpp", "buildstep.h",
"buildsteplist.cpp", "buildsteplist.h",
@@ -253,6 +254,15 @@ Project {
files: ["outputparser_test.h", "outputparser_test.cpp"]
}
+ Group {
+ name: "Test resources"
+ condition: qtc.testsEnabled
+ files: ["testdata/**"]
+ fileTags: ["qt.core.resource_data"]
+ Qt.core.resourcePrefix: "/projectexplorer"
+ Qt.core.resourceSourceBase: path
+ }
+
Export {
Depends { name: "Qt.network" }
}
diff --git a/src/plugins/projectexplorer/projectexplorer_dependencies.pri b/src/plugins/projectexplorer/projectexplorer_dependencies.pri
index df12aea613..00fa9e9c05 100644
--- a/src/plugins/projectexplorer/projectexplorer_dependencies.pri
+++ b/src/plugins/projectexplorer/projectexplorer_dependencies.pri
@@ -8,3 +8,5 @@ QTC_PLUGIN_DEPENDS += \
coreplugin \
texteditor
QT *= network
+QTC_TEST_DEPENDS += \
+ genericprojectmanager
diff --git a/src/plugins/projectexplorer/projectexplorerconstants.h b/src/plugins/projectexplorer/projectexplorerconstants.h
index e0f7fa8045..c0a495af25 100644
--- a/src/plugins/projectexplorer/projectexplorerconstants.h
+++ b/src/plugins/projectexplorer/projectexplorerconstants.h
@@ -52,9 +52,13 @@ const char M_DEBUG_STARTDEBUGGING[] = "ProjectExplorer.Menu.Debug.StartDebugging
// Menu groups
const char G_BUILD_BUILD[] = "ProjectExplorer.Group.Build";
-const char G_BUILD_DEPLOY[] = "ProjectExplorer.Group.Deploy";
-const char G_BUILD_REBUILD[] = "ProjectExplorer.Group.Rebuild";
-const char G_BUILD_CLEAN[] = "ProjectExplorer.Group.Clean";
+const char G_BUILD_ALLPROJECTS[] = "ProjectExplorer.Group.AllProjects";
+const char G_BUILD_PROJECT[] = "ProjectExplorer.Group.Project";
+const char G_BUILD_PRODUCT[] = "ProjectExplorer.Group.Product";
+const char G_BUILD_SUBPROJECT[] = "ProjectExplorer.Group.SubProject";
+const char G_BUILD_FILE[] = "ProjectExplorer.Group.File";
+const char G_BUILD_ALLPROJECTS_ALLCONFIGURATIONS[] = "ProjectExplorer.Group.AllProjects.AllConfigurations";
+const char G_BUILD_PROJECT_ALLCONFIGURATIONS[] = "ProjectExplorer.Group.Project.AllConfigurations";
const char G_BUILD_RUN[] = "ProjectExplorer.Group.Run";
const char G_BUILD_CANCEL[] = "ProjectExplorer.Group.BuildCancel";
diff --git a/src/plugins/projectexplorer/projectnodes.cpp b/src/plugins/projectexplorer/projectnodes.cpp
index 93d8a412f5..8211882230 100644
--- a/src/plugins/projectexplorer/projectnodes.cpp
+++ b/src/plugins/projectexplorer/projectnodes.cpp
@@ -46,16 +46,19 @@
#include <utils/qtcassert.h>
#include <utils/stringutils.h>
-#include <QFileInfo>
#include <QDir>
+#include <QFileInfo>
#include <QIcon>
#include <QStyle>
+#include <QThread>
#include <QTimer>
#include <memory>
namespace ProjectExplorer {
+QHash<QString, QIcon> DirectoryIcon::m_cache;
+
static FolderNode *recursiveFindOrCreateFolderNode(FolderNode *folder,
const Utils::FilePath &directory,
const Utils::FilePath &overrideBaseDir,
@@ -481,16 +484,28 @@ QString FolderNode::displayName() const
}
/*!
- Contains the icon that should be used in a view. Default is the directory icon
- (QStyle::S_PDirIcon).
- s\a setIcon()
+ Contains the icon that should be used in a view. Default is the directory icon
+ (QStyle::S_PDirIcon). Calling this method is only safe in the UI thread.
+
+ \sa setIcon()
*/
QIcon FolderNode::icon() const
{
+ QTC_CHECK(QThread::currentThread() == QCoreApplication::instance()->thread());
+
// Instantiating the Icon provider is expensive.
- if (m_icon.isNull())
- m_icon = Core::FileIconProvider::icon(QFileIconProvider::Folder);
- return m_icon;
+ if (auto strPtr = Utils::get_if<QString>(&m_icon)) {
+ m_icon = QIcon(*strPtr);
+ } else if (auto directoryIconPtr = Utils::get_if<DirectoryIcon>(&m_icon)) {
+ m_icon = directoryIconPtr->icon();
+ } else if (auto creatorPtr = Utils::get_if<IconCreator>(&m_icon)) {
+ m_icon = (*creatorPtr)();
+ } else {
+ auto iconPtr = Utils::get_if<QIcon>(&m_icon);
+ if (!iconPtr || iconPtr->isNull())
+ m_icon = Core::FileIconProvider::icon(QFileIconProvider::Folder);
+ }
+ return Utils::get<QIcon>(m_icon);
}
Node *FolderNode::findNode(const std::function<bool(Node *)> &filter)
@@ -724,11 +739,38 @@ void FolderNode::setDisplayName(const QString &name)
m_displayName = name;
}
+/*!
+ Sets the \a icon for this node. Note that creating QIcon instances is only safe in the UI thread.
+*/
void FolderNode::setIcon(const QIcon &icon)
{
m_icon = icon;
}
+/*!
+ Sets the \a directoryIcon that is used to create the icon for this node on demand.
+*/
+void FolderNode::setIcon(const DirectoryIcon &directoryIcon)
+{
+ m_icon = directoryIcon;
+}
+
+/*!
+ Sets the \a path that is used to create the icon for this node on demand.
+*/
+void FolderNode::setIcon(const QString &path)
+{
+ m_icon = path;
+}
+
+/*!
+ Sets the \a iconCreator function that is used to create the icon for this node on demand.
+*/
+void FolderNode::setIcon(const IconCreator &iconCreator)
+{
+ m_icon = iconCreator;
+}
+
void FolderNode::setLocationInfo(const QVector<FolderNode::LocationInfo> &info)
{
m_locations = info;
@@ -1048,4 +1090,34 @@ void ContainerNode::handleSubTreeChanged(FolderNode *node)
m_project->handleSubTreeChanged(node);
}
+/*!
+ \class ProjectExplorer::DirectoryIcon
+
+ The DirectoryIcon class represents a directory icon with an overlay.
+
+ The QIcon is created on demand and globally cached, so other DirectoryIcon
+ instances with the same overlay share the same QIcon instance.
+*/
+
+/*!
+ Creates a DirectoryIcon for the specified \a overlay.
+*/
+DirectoryIcon::DirectoryIcon(const QString &overlay)
+ : m_overlay(overlay)
+{}
+
+/*!
+ Returns the icon for this DirectoryIcon. Calling this method is only safe in the UI thread.
+*/
+QIcon DirectoryIcon::icon() const
+{
+ QTC_CHECK(QThread::currentThread() == QCoreApplication::instance()->thread());
+ const auto it = m_cache.find(m_overlay);
+ if (it != m_cache.end())
+ return it.value();
+ const QIcon icon = Core::FileIconProvider::directoryIcon(m_overlay);
+ m_cache.insert(m_overlay, icon);
+ return icon;
+}
+
} // namespace ProjectExplorer
diff --git a/src/plugins/projectexplorer/projectnodes.h b/src/plugins/projectexplorer/projectnodes.h
index 0fd53414d1..beb609a3c4 100644
--- a/src/plugins/projectexplorer/projectnodes.h
+++ b/src/plugins/projectexplorer/projectnodes.h
@@ -34,6 +34,7 @@
#include <utils/fileutils.h>
#include <utils/id.h>
#include <utils/optional.h>
+#include <utils/variant.h>
#include <functional>
@@ -93,6 +94,20 @@ class FolderNode;
class ProjectNode;
class ContainerNode;
+class PROJECTEXPLORER_EXPORT DirectoryIcon
+{
+public:
+ explicit DirectoryIcon(const QString &overlay);
+
+ QIcon icon() const; // only safe in UI thread
+
+private:
+ QString m_overlay;
+ static QHash<QString, QIcon> m_cache;
+};
+
+using IconCreator = std::function<QIcon()>;
+
// Documentation inside.
class PROJECTEXPLORER_EXPORT Node
{
@@ -218,6 +233,7 @@ public:
explicit FolderNode(const Utils::FilePath &folderPath);
QString displayName() const override;
+ // only safe from UI thread
QIcon icon() const;
bool isFolderNodeType() const override { return true; }
@@ -253,7 +269,11 @@ public:
bool replaceSubtree(Node *oldNode, std::unique_ptr<Node> &&newNode);
void setDisplayName(const QString &name);
+ // you have to make sure the QIcon is created in the UI thread if you are calling setIcon(QIcon)
void setIcon(const QIcon &icon);
+ void setIcon(const DirectoryIcon &directoryIcon);
+ void setIcon(const QString &path);
+ void setIcon(const IconCreator &iconCreator);
class LocationInfo
{
@@ -328,7 +348,7 @@ private:
QString m_displayName;
QString m_addFileFilter;
- mutable QIcon m_icon;
+ mutable Utils::variant<QIcon, DirectoryIcon, QString, IconCreator> m_icon;
bool m_showWhenEmpty = false;
};
diff --git a/src/plugins/projectexplorer/projecttreewidget.cpp b/src/plugins/projectexplorer/projecttreewidget.cpp
index 2ee230f58d..dbaed8d983 100644
--- a/src/plugins/projectexplorer/projecttreewidget.cpp
+++ b/src/plugins/projectexplorer/projecttreewidget.cpp
@@ -289,13 +289,12 @@ ProjectTreeWidget::ProjectTreeWidget(QWidget *parent) : QWidget(parent)
connect(m_view, &QTreeView::collapsed,
m_model, &FlatModel::onCollapsed);
- m_toggleSync = new QToolButton(this);
+ m_toggleSync = new QAction(this);
m_toggleSync->setIcon(Icons::LINK_TOOLBAR.icon());
m_toggleSync->setCheckable(true);
m_toggleSync->setChecked(autoSynchronization());
m_toggleSync->setToolTip(tr("Synchronize with Editor"));
- connect(m_toggleSync, &QAbstractButton::clicked,
- this, &ProjectTreeWidget::toggleAutoSynchronization);
+ connect(m_toggleSync, &QAction::triggered, this, &ProjectTreeWidget::toggleAutoSynchronization);
setCurrentItem(ProjectTree::currentNode());
setAutoSynchronization(true);
@@ -381,11 +380,6 @@ Node *ProjectTreeWidget::nodeForFile(const FilePath &fileName)
return bestNode;
}
-QToolButton *ProjectTreeWidget::toggleSync()
-{
- return m_toggleSync;
-}
-
void ProjectTreeWidget::toggleAutoSynchronization()
{
setAutoSynchronization(!m_autoSync);
@@ -435,6 +429,27 @@ void ProjectTreeWidget::expandAll()
m_view->expandAll();
}
+QList<QToolButton *> ProjectTreeWidget::createToolButtons()
+{
+ auto filter = new QToolButton(this);
+ filter->setIcon(Icons::FILTER.icon());
+ filter->setToolTip(tr("Filter Tree"));
+ filter->setPopupMode(QToolButton::InstantPopup);
+ filter->setProperty("noArrow", true);
+
+ auto filterMenu = new QMenu(filter);
+ filterMenu->addAction(m_filterProjectsAction);
+ filterMenu->addAction(m_filterGeneratedFilesAction);
+ filterMenu->addAction(m_filterDisabledFilesAction);
+ filterMenu->addAction(m_trimEmptyDirectoriesAction);
+ filter->setMenu(filterMenu);
+
+ auto toggleSync = new QToolButton;
+ toggleSync->setDefaultAction(m_toggleSync);
+
+ return {filter, toggleSync};
+}
+
void ProjectTreeWidget::editCurrentItem()
{
m_delayedRename.clear();
@@ -542,7 +557,7 @@ void ProjectTreeWidget::openItem(const QModelIndex &mainIndex)
Node *node = m_model->nodeForIndex(mainIndex);
if (!node || !node->asFileNode())
return;
- IEditor *editor = EditorManager::openEditor(node->filePath().toString());
+ IEditor *editor = EditorManager::openEditor(node->filePath());
if (editor && node->line() >= 0)
editor->gotoLine(node->line());
}
@@ -602,24 +617,8 @@ ProjectTreeWidgetFactory::ProjectTreeWidgetFactory()
NavigationView ProjectTreeWidgetFactory::createWidget()
{
- NavigationView n;
auto ptw = new ProjectTreeWidget;
- n.widget = ptw;
-
- auto filter = new QToolButton(ptw);
- filter->setIcon(Icons::FILTER.icon());
- filter->setToolTip(tr("Filter Tree"));
- filter->setPopupMode(QToolButton::InstantPopup);
- filter->setProperty("noArrow", true);
- auto filterMenu = new QMenu(filter);
- filterMenu->addAction(ptw->m_filterProjectsAction);
- filterMenu->addAction(ptw->m_filterGeneratedFilesAction);
- filterMenu->addAction(ptw->m_filterDisabledFilesAction);
- filterMenu->addAction(ptw->m_trimEmptyDirectoriesAction);
- filter->setMenu(filterMenu);
-
- n.dockToolBarWidgets << filter << ptw->toggleSync();
- return n;
+ return {ptw, ptw->createToolButtons()};
}
const bool kProjectFilterDefault = false;
diff --git a/src/plugins/projectexplorer/projecttreewidget.h b/src/plugins/projectexplorer/projecttreewidget.h
index c9afb44fab..4909d0bbd8 100644
--- a/src/plugins/projectexplorer/projecttreewidget.h
+++ b/src/plugins/projectexplorer/projecttreewidget.h
@@ -58,7 +58,6 @@ public:
bool generatedFilesFilter();
bool disabledFilesFilter();
bool trimEmptyDirectoriesFilter();
- QToolButton *toggleSync();
Node *currentNode();
void sync(ProjectExplorer::Node *node);
void showMessage(ProjectExplorer::Node *node, const QString &message);
@@ -71,6 +70,8 @@ public:
void collapseAll();
void expandAll();
+ QList<QToolButton *> createToolButtons();
+
private:
void setProjectFilter(bool filter);
void setGeneratedFilesFilter(bool filter);
@@ -96,7 +97,7 @@ private:
QAction *m_filterGeneratedFilesAction = nullptr;
QAction *m_filterDisabledFilesAction = nullptr;
QAction *m_trimEmptyDirectoriesAction = nullptr;
- QToolButton *m_toggleSync = nullptr;
+ QAction *m_toggleSync = nullptr;
QString m_modelId;
bool m_autoSync = true;
diff --git a/src/plugins/projectexplorer/runconfiguration.cpp b/src/plugins/projectexplorer/runconfiguration.cpp
index 55c89d0932..542d0732fa 100644
--- a/src/plugins/projectexplorer/runconfiguration.cpp
+++ b/src/plugins/projectexplorer/runconfiguration.cpp
@@ -233,15 +233,14 @@ bool RunConfiguration::isEnabled() const
QWidget *RunConfiguration::createConfigurationWidget()
{
- auto widget = new QWidget;
- {
- LayoutBuilder builder(widget);
- for (BaseAspect *aspect : qAsConst(m_aspects)) {
- if (aspect->isVisible())
- aspect->addToLayout(builder.finishRow());
- }
+ Layouting::Form builder;
+ for (BaseAspect *aspect : qAsConst(m_aspects)) {
+ if (aspect->isVisible())
+ aspect->addToLayout(builder.finishRow());
}
+ auto widget = builder.emerge(false);
+
VariableChooser::addSupportForChildWidgets(widget, &m_expander);
auto detailsWidget = new Utils::DetailsWidget;
@@ -308,6 +307,11 @@ CommandLine RunConfiguration::commandLine() const
return m_commandLineGetter();
}
+void RunConfiguration::setRunnableModifier(const RunnableModifier &runnableModifier)
+{
+ m_runnableModifier = runnableModifier;
+}
+
void RunConfiguration::update()
{
if (m_updater)
@@ -399,6 +403,8 @@ Runnable RunConfiguration::runnable() const
r.workingDirectory = workingDirectoryAspect->workingDirectory(macroExpander()).toString();
if (auto environmentAspect = aspect<EnvironmentAspect>())
r.environment = environmentAspect->environment();
+ if (m_runnableModifier)
+ m_runnableModifier(r);
return r;
}
@@ -560,7 +566,7 @@ RunConfiguration *RunConfigurationFactory::create(Target *target) const
// Add the universal aspects.
for (const RunConfiguration::AspectFactory &factory : theAspectFactories)
- rc->m_aspects.append(factory(target));
+ rc->m_aspects.registerAspect(factory(target));
rc->acquaintAspects();
return rc;
diff --git a/src/plugins/projectexplorer/runconfiguration.h b/src/plugins/projectexplorer/runconfiguration.h
index 38f1170f6c..50652f30dd 100644
--- a/src/plugins/projectexplorer/runconfiguration.h
+++ b/src/plugins/projectexplorer/runconfiguration.h
@@ -61,7 +61,7 @@ class Target;
*
*/
-class PROJECTEXPLORER_EXPORT ISettingsAspect : public QObject
+class PROJECTEXPLORER_EXPORT ISettingsAspect : public Utils::AspectContainer
{
Q_OBJECT
@@ -76,10 +76,6 @@ protected:
void setConfigWidgetCreator(const ConfigWidgetCreator &configWidgetCreator);
friend class GlobalOrProjectAspect;
- /// Converts current object into map for storage.
- virtual void toMap(QVariantMap &map) const = 0;
- /// Read object state from @p map.
- virtual void fromMap(const QVariantMap &map) = 0;
ConfigWidgetCreator m_configWidgetCreator;
};
@@ -142,6 +138,9 @@ public:
void setCommandLineGetter(const CommandLineGetter &cmdGetter);
Utils::CommandLine commandLine() const;
+ using RunnableModifier = std::function<void(Runnable &)>;
+ void setRunnableModifier(const RunnableModifier &extraModifier);
+
virtual Runnable runnable() const;
// Return a handle to the build system target that created this run configuration.
@@ -198,6 +197,7 @@ private:
QString m_buildKey;
CommandLineGetter m_commandLineGetter;
+ RunnableModifier m_runnableModifier;
Updater m_updater;
Utils::MacroExpander m_expander;
};
diff --git a/src/plugins/projectexplorer/runconfigurationaspects.cpp b/src/plugins/projectexplorer/runconfigurationaspects.cpp
index 6aca37d98c..040cc54507 100644
--- a/src/plugins/projectexplorer/runconfigurationaspects.cpp
+++ b/src/plugins/projectexplorer/runconfigurationaspects.cpp
@@ -203,7 +203,7 @@ void WorkingDirectoryAspect::addToLayout(LayoutBuilder &builder)
builder.addItems({tr("Working directory:"), m_chooser.data(), m_resetButton.data()});
}
-void WorkingDirectoryAspect::acquaintSiblings(const BaseAspects &siblings)
+void WorkingDirectoryAspect::acquaintSiblings(const AspectContainer &siblings)
{
m_envAspect = siblings.aspect<EnvironmentAspect>();
}
@@ -235,8 +235,8 @@ void WorkingDirectoryAspect::toMap(QVariantMap &data) const
{
const QString wd = m_workingDirectory == m_defaultWorkingDirectory
? QString() : m_workingDirectory.toString();
- saveToMap(data, wd, QString());
- saveToMap(data, m_defaultWorkingDirectory.toString(), QString(), ".default");
+ saveToMap(data, wd, QString(), settingsKey());
+ saveToMap(data, m_defaultWorkingDirectory.toString(), QString(), settingsKey() + ".default");
}
/*!
@@ -392,7 +392,7 @@ void ArgumentsAspect::fromMap(const QVariantMap &map)
QVariant args = map.value(settingsKey());
// Until 3.7 a QStringList was stored for Remote Linux
if (args.type() == QVariant::StringList)
- m_arguments = QtcProcess::joinArgs(args.toStringList(), OsTypeLinux);
+ m_arguments = ProcessArgs::joinArgs(args.toStringList(), OsTypeLinux);
else
m_arguments = args.toString();
@@ -411,8 +411,8 @@ void ArgumentsAspect::fromMap(const QVariantMap &map)
*/
void ArgumentsAspect::toMap(QVariantMap &map) const
{
- saveToMap(map, m_arguments, QString());
- saveToMap(map, m_multiLine, false, ".multi");
+ saveToMap(map, m_arguments, QString(), settingsKey());
+ saveToMap(map, m_multiLine, false, settingsKey() + ".multi");
}
/*!
diff --git a/src/plugins/projectexplorer/runconfigurationaspects.h b/src/plugins/projectexplorer/runconfigurationaspects.h
index 508d308ef9..ca37d063ef 100644
--- a/src/plugins/projectexplorer/runconfigurationaspects.h
+++ b/src/plugins/projectexplorer/runconfigurationaspects.h
@@ -76,7 +76,7 @@ public:
WorkingDirectoryAspect();
void addToLayout(Utils::LayoutBuilder &builder) override;
- void acquaintSiblings(const Utils::BaseAspects &) override;
+ void acquaintSiblings(const Utils::AspectContainer &) override;
Utils::FilePath workingDirectory(const Utils::MacroExpander *expander) const;
Utils::FilePath defaultWorkingDirectory() const;
diff --git a/src/plugins/projectexplorer/runcontrol.cpp b/src/plugins/projectexplorer/runcontrol.cpp
index 7c6e50b515..bbde5b4f66 100644
--- a/src/plugins/projectexplorer/runcontrol.cpp
+++ b/src/plugins/projectexplorer/runcontrol.cpp
@@ -494,12 +494,11 @@ bool RunControl::createMainWorker()
bool RunControl::canRun(Utils::Id runMode, Utils::Id deviceType, Utils::Id runConfigId)
{
- const auto check = std::bind(&RunWorkerFactory::canRun,
- std::placeholders::_1,
- runMode,
- deviceType,
- runConfigId.toString());
- return Utils::contains(g_runWorkerFactories, check);
+ for (const RunWorkerFactory *factory : qAsConst(g_runWorkerFactories)) {
+ if (factory->canRun(runMode, deviceType, runConfigId.toString()))
+ return true;
+ }
+ return false;
}
void RunControlPrivate::initiateStart()
diff --git a/src/plugins/projectexplorer/session.cpp b/src/plugins/projectexplorer/session.cpp
index 1542cbe3cc..77c26714be 100644
--- a/src/plugins/projectexplorer/session.cpp
+++ b/src/plugins/projectexplorer/session.cpp
@@ -286,6 +286,9 @@ void SessionManager::setActiveTarget(Project *project, Target *target, SetActive
{
QTC_ASSERT(project, return);
+ if (project->isShuttingDown())
+ return;
+
project->setActiveTarget(target);
if (!target) // never cascade setting no target
@@ -307,6 +310,11 @@ void SessionManager::setActiveTarget(Project *project, Target *target, SetActive
void SessionManager::setActiveBuildConfiguration(Target *target, BuildConfiguration *bc, SetActive cascade)
{
QTC_ASSERT(target, return);
+ QTC_ASSERT(target->project(), return);
+
+ if (target->project()->isShuttingDown() || target->isShuttingDown())
+ return;
+
target->setActiveBuildConfiguration(bc);
if (!bc)
@@ -335,6 +343,11 @@ void SessionManager::setActiveBuildConfiguration(Target *target, BuildConfigurat
void SessionManager::setActiveDeployConfiguration(Target *target, DeployConfiguration *dc, SetActive cascade)
{
QTC_ASSERT(target, return);
+ QTC_ASSERT(target->project(), return);
+
+ if (target->project()->isShuttingDown() || target->isShuttingDown())
+ return;
+
target->setActiveDeployConfiguration(dc);
if (!dc)
@@ -724,6 +737,7 @@ void SessionManager::removeProjects(const QList<Project *> &remove)
// Delete projects
for (Project *pro : remove) {
pro->saveSettings();
+ pro->markAsShuttingDown();
// Remove the project node:
d->m_projects.removeOne(pro);
@@ -768,7 +782,7 @@ QStringList SessionManager::sessions()
{
if (d->m_sessions.isEmpty()) {
// We are not initialized yet, so do that now
- QDir sessionDir(ICore::userResourcePath());
+ QDir sessionDir(ICore::userResourcePath().toDir());
QFileInfoList sessionFiles = sessionDir.entryInfoList(QStringList() << QLatin1String("*.qws"), QDir::NoFilter, QDir::Time);
foreach (const QFileInfo &fileInfo, sessionFiles) {
const QString &name = fileInfo.completeBaseName();
@@ -788,7 +802,7 @@ QDateTime SessionManager::sessionDateTime(const QString &session)
FilePath SessionManager::sessionNameToFileName(const QString &session)
{
- return FilePath::fromString(ICore::userResourcePath() + QLatin1Char('/') + session + QLatin1String(".qws"));
+ return ICore::userResourcePath(session + ".qws");
}
/*!
diff --git a/src/plugins/projectexplorer/showineditortaskhandler.cpp b/src/plugins/projectexplorer/showineditortaskhandler.cpp
index 18ba24370f..e922501452 100644
--- a/src/plugins/projectexplorer/showineditortaskhandler.cpp
+++ b/src/plugins/projectexplorer/showineditortaskhandler.cpp
@@ -46,7 +46,8 @@ bool ShowInEditorTaskHandler::canHandle(const Task &task) const
void ShowInEditorTaskHandler::handle(const Task &task)
{
QFileInfo fi(task.file.toFileInfo());
- Core::EditorManager::openEditorAt(fi.filePath(), task.movedLine, {}, {},
+ const int column = task.column ? task.column - 1 : 0;
+ Core::EditorManager::openEditorAt(fi.filePath(), task.movedLine, column, {},
Core::EditorManager::SwitchSplitIfAlreadyVisible);
}
diff --git a/src/plugins/projectexplorer/target.cpp b/src/plugins/projectexplorer/target.cpp
index f2d79dec95..d44a294442 100644
--- a/src/plugins/projectexplorer/target.cpp
+++ b/src/plugins/projectexplorer/target.cpp
@@ -50,6 +50,7 @@
#include <coreplugin/coreconstants.h>
#include <utils/algorithm.h>
+#include <utils/commandline.h>
#include <utils/macroexpander.h>
#include <utils/qtcassert.h>
#include <utils/stringutils.h>
@@ -122,6 +123,8 @@ public:
ProjectConfigurationModel m_buildConfigurationModel;
ProjectConfigurationModel m_deployConfigurationModel;
ProjectConfigurationModel m_runConfigurationModel;
+
+ bool m_shuttingDown = false;
};
@@ -232,6 +235,16 @@ bool Target::isActive() const
return project()->activeTarget() == this;
}
+void Target::markAsShuttingDown()
+{
+ d->m_shuttingDown = true;
+}
+
+bool Target::isShuttingDown() const
+{
+ return d->m_shuttingDown;
+}
+
Project *Target::project() const
{
return static_cast<Project *>(parent());
@@ -511,6 +524,9 @@ RunConfiguration *Target::activeRunConfiguration() const
void Target::setActiveRunConfiguration(RunConfiguration *rc)
{
+ if (isShuttingDown())
+ return;
+
if ((!rc && d->m_runConfigurations.isEmpty()) ||
(rc && d->m_runConfigurations.contains(rc) &&
rc != d->m_activeRunConfiguration)) {
diff --git a/src/plugins/projectexplorer/target.h b/src/plugins/projectexplorer/target.h
index ce8440fa38..12cf80d01a 100644
--- a/src/plugins/projectexplorer/target.h
+++ b/src/plugins/projectexplorer/target.h
@@ -63,6 +63,9 @@ public:
bool isActive() const;
+ void markAsShuttingDown();
+ bool isShuttingDown() const;
+
Project *project() const;
Kit *kit() const;
BuildSystem *buildSystem() const;
diff --git a/src/plugins/projectexplorer/task.cpp b/src/plugins/projectexplorer/task.cpp
index 3ca1b969da..fe880442ba 100644
--- a/src/plugins/projectexplorer/task.cpp
+++ b/src/plugins/projectexplorer/task.cpp
@@ -206,9 +206,12 @@ bool containsType(const Tasks &issues, Task::TaskType type)
// CompilerTask
-CompileTask::CompileTask(TaskType type, const QString &desc, const FilePath &file, int line)
+CompileTask::CompileTask(TaskType type, const QString &desc,
+ const FilePath &file, int line, int column_)
: Task(type, desc, file, line, ProjectExplorer::Constants::TASK_CATEGORY_COMPILE)
-{}
+{
+ column = column_;
+}
// BuildSystemTask
diff --git a/src/plugins/projectexplorer/task.h b/src/plugins/projectexplorer/task.h
index 61aa31e4fc..a21332c708 100644
--- a/src/plugins/projectexplorer/task.h
+++ b/src/plugins/projectexplorer/task.h
@@ -85,6 +85,7 @@ public:
Utils::FilePaths fileCandidates;
int line = -1;
int movedLine = -1; // contains a line number if the line was moved in the editor
+ int column = 0;
Utils::Id category;
// Having a container of QTextLayout::FormatRange in Task isn't that great
@@ -113,7 +114,8 @@ public:
CompileTask(TaskType type,
const QString &description,
const Utils::FilePath &file = {},
- int line = -1);
+ int line = -1,
+ int column = 0);
};
class PROJECTEXPLORER_EXPORT BuildSystemTask : public Task
diff --git a/src/plugins/projectexplorer/taskwindow.cpp b/src/plugins/projectexplorer/taskwindow.cpp
index 26b147c0d3..eabe4c2e18 100644
--- a/src/plugins/projectexplorer/taskwindow.cpp
+++ b/src/plugins/projectexplorer/taskwindow.cpp
@@ -52,6 +52,8 @@
#include <QToolButton>
#include <QScrollBar>
+using namespace Utils;
+
namespace {
const int ELLIPSIS_GRADIENT_WIDTH = 16;
const char SESSION_FILTER_CATEGORIES[] = "TaskWindow.Categories";
@@ -86,13 +88,7 @@ private:
void mouseReleaseEvent(QMouseEvent *e) override;
void mouseMoveEvent(QMouseEvent *e) override;
- class Location {
- public:
- Utils::FilePath file;
- int line;
- int column;
- };
- Location locationForPos(const QPoint &pos);
+ Utils::Link locationForPos(const QPoint &pos);
bool m_linksActive = true;
Qt::MouseButton m_mouseButtonPressed = Qt::NoButton;
@@ -229,9 +225,9 @@ void TaskView::mousePressEvent(QMouseEvent *e)
void TaskView::mouseReleaseEvent(QMouseEvent *e)
{
if (m_linksActive && m_mouseButtonPressed == Qt::LeftButton) {
- const Location loc = locationForPos(e->pos());
- if (!loc.file.isEmpty()) {
- Core::EditorManager::openEditorAt(loc.file.toString(), loc.line, loc.column, {},
+ const Link loc = locationForPos(e->pos());
+ if (!loc.targetFilePath.isEmpty()) {
+ Core::EditorManager::openEditorAt(loc, {},
Core::EditorManager::SwitchSplitIfAlreadyVisible);
}
}
@@ -248,23 +244,20 @@ void TaskView::mouseMoveEvent(QMouseEvent *e)
if (m_mouseButtonPressed != Qt::NoButton)
m_linksActive = false;
- viewport()->setCursor(m_linksActive && !locationForPos(e->pos()).file.isEmpty()
+ viewport()->setCursor(m_linksActive && !locationForPos(e->pos()).targetFilePath.isEmpty()
? Qt::PointingHandCursor : Qt::ArrowCursor);
ListView::mouseMoveEvent(e);
}
-TaskView::Location TaskView::locationForPos(const QPoint &pos)
+Link TaskView::locationForPos(const QPoint &pos)
{
const auto delegate = qobject_cast<TaskDelegate *>(itemDelegate(indexAt(pos)));
if (!delegate)
return {};
- Utils::OutputFormatter formatter;
- Location loc;
- connect(&formatter, &Utils::OutputFormatter::openInEditorRequested, this,
- [&loc](const Utils::FilePath &fp, int line, int column) {
- loc.file = fp;
- loc.line = line;
- loc.column = column;
+ OutputFormatter formatter;
+ Link loc;
+ connect(&formatter, &OutputFormatter::openInEditorRequested, this, [&loc](const Link &link) {
+ loc = link;
});
const QString href = delegate->hrefForPos(pos);
diff --git a/src/plugins/projectexplorer/testdata/generic-project/generic-project.cflags b/src/plugins/projectexplorer/testdata/generic-project/generic-project.cflags
new file mode 100644
index 0000000000..e69de29bb2
--- /dev/null
+++ b/src/plugins/projectexplorer/testdata/generic-project/generic-project.cflags
diff --git a/src/plugins/projectexplorer/testdata/generic-project/generic-project.config b/src/plugins/projectexplorer/testdata/generic-project/generic-project.config
new file mode 100644
index 0000000000..e69de29bb2
--- /dev/null
+++ b/src/plugins/projectexplorer/testdata/generic-project/generic-project.config
diff --git a/src/plugins/projectexplorer/testdata/generic-project/generic-project.creator b/src/plugins/projectexplorer/testdata/generic-project/generic-project.creator
new file mode 100644
index 0000000000..e94cbbd302
--- /dev/null
+++ b/src/plugins/projectexplorer/testdata/generic-project/generic-project.creator
@@ -0,0 +1 @@
+[General]
diff --git a/src/plugins/projectexplorer/testdata/generic-project/generic-project.cxxflags b/src/plugins/projectexplorer/testdata/generic-project/generic-project.cxxflags
new file mode 100644
index 0000000000..e69de29bb2
--- /dev/null
+++ b/src/plugins/projectexplorer/testdata/generic-project/generic-project.cxxflags
diff --git a/src/plugins/projectexplorer/testdata/generic-project/generic-project.files b/src/plugins/projectexplorer/testdata/generic-project/generic-project.files
new file mode 100644
index 0000000000..f0ce4404d8
--- /dev/null
+++ b/src/plugins/projectexplorer/testdata/generic-project/generic-project.files
@@ -0,0 +1 @@
+main.cpp
diff --git a/src/plugins/projectexplorer/testdata/generic-project/generic-project.includes b/src/plugins/projectexplorer/testdata/generic-project/generic-project.includes
new file mode 100644
index 0000000000..e69de29bb2
--- /dev/null
+++ b/src/plugins/projectexplorer/testdata/generic-project/generic-project.includes
diff --git a/src/plugins/projectexplorer/testdata/generic-project/main.cpp b/src/plugins/projectexplorer/testdata/generic-project/main.cpp
new file mode 100644
index 0000000000..237c8ce181
--- /dev/null
+++ b/src/plugins/projectexplorer/testdata/generic-project/main.cpp
@@ -0,0 +1 @@
+int main() {}
diff --git a/src/plugins/projectexplorer/toolchain.cpp b/src/plugins/projectexplorer/toolchain.cpp
index 2427a2d4dd..98df39036a 100644
--- a/src/plugins/projectexplorer/toolchain.cpp
+++ b/src/plugins/projectexplorer/toolchain.cpp
@@ -197,8 +197,7 @@ bool ToolChain::isValid() const
{
if (compilerCommand().isEmpty())
return false;
- QFileInfo fi = compilerCommand().toFileInfo();
- return fi.isExecutable();
+ return compilerCommand().isExecutableFile();
}
QStringList ToolChain::includedFiles(const QStringList &flags, const QString &directory) const
@@ -266,7 +265,7 @@ QVariantMap ToolChain::toMap() const
if (!d->m_targetAbiKey.isEmpty())
result.insert(d->m_targetAbiKey, d->m_targetAbi.toString());
if (!d->m_compilerCommandKey.isEmpty())
- result.insert(d->m_compilerCommandKey, d->m_compilerCommand.toString());
+ result.insert(d->m_compilerCommandKey, d->m_compilerCommand.toVariant());
return result;
}
@@ -374,7 +373,7 @@ bool ToolChain::fromMap(const QVariantMap &data)
if (!d->m_targetAbiKey.isEmpty())
d->m_targetAbi = Abi::fromString(data.value(d->m_targetAbiKey).toString());
- d->m_compilerCommand = FilePath::fromString(data.value(d->m_compilerCommandKey).toString());
+ d->m_compilerCommand = FilePath::fromVariant(data.value(d->m_compilerCommandKey));
return true;
}
@@ -526,9 +525,11 @@ const QList<ToolChainFactory *> ToolChainFactory::allToolChainFactories()
return Internal::g_toolChainFactories;
}
-QList<ToolChain *> ToolChainFactory::autoDetect(const QList<ToolChain *> &alreadyKnown)
+QList<ToolChain *> ToolChainFactory::autoDetect(const QList<ToolChain *> &alreadyKnown,
+ const IDevice::Ptr &device)
{
Q_UNUSED(alreadyKnown)
+ Q_UNUSED(device)
return {};
}
diff --git a/src/plugins/projectexplorer/toolchain.h b/src/plugins/projectexplorer/toolchain.h
index 1a05ec326c..2c2a3c68b7 100644
--- a/src/plugins/projectexplorer/toolchain.h
+++ b/src/plugins/projectexplorer/toolchain.h
@@ -28,6 +28,7 @@
#include "projectexplorer_export.h"
#include "abi.h"
+#include "devicesupport/idevice.h"
#include "headerpath.h"
#include "projectmacro.h"
#include "task.h"
@@ -214,7 +215,8 @@ public:
QString displayName() const { return m_displayName; }
Utils::Id supportedToolChainType() const;
- virtual QList<ToolChain *> autoDetect(const QList<ToolChain *> &alreadyKnown);
+ virtual QList<ToolChain *> autoDetect(const QList<ToolChain *> &alreadyKnown,
+ const IDevice::Ptr &device);
virtual QList<ToolChain *> detectForImport(const ToolChainDescription &tcd);
virtual bool canCreate() const;
diff --git a/src/plugins/projectexplorer/toolchainconfigwidget.cpp b/src/plugins/projectexplorer/toolchainconfigwidget.cpp
index d38c6ea3bf..e0afdad212 100644
--- a/src/plugins/projectexplorer/toolchainconfigwidget.cpp
+++ b/src/plugins/projectexplorer/toolchainconfigwidget.cpp
@@ -38,6 +38,8 @@
#include <QScrollArea>
#include <QPainter>
+using namespace Utils;
+
namespace ProjectExplorer {
ToolChainConfigWidget::ToolChainConfigWidget(ToolChain *tc) :
@@ -128,15 +130,15 @@ void ToolChainConfigWidget::clearErrorMessage()
QStringList ToolChainConfigWidget::splitString(const QString &s)
{
- Utils::QtcProcess::SplitError splitError;
- const Utils::OsType osType = Utils::HostOsInfo::hostOs();
- QStringList res = Utils::QtcProcess::splitArgs(s, osType, false, &splitError);
- if (splitError != Utils::QtcProcess::SplitOk){
- res = Utils::QtcProcess::splitArgs(s + '\\', osType, false, &splitError);
- if (splitError != Utils::QtcProcess::SplitOk){
- res = Utils::QtcProcess::splitArgs(s + '"', osType, false, &splitError);
- if (splitError != Utils::QtcProcess::SplitOk)
- res = Utils::QtcProcess::splitArgs(s + '\'', osType, false, &splitError);
+ ProcessArgs::SplitError splitError;
+ const OsType osType = HostOsInfo::hostOs();
+ QStringList res = ProcessArgs::splitArgs(s, osType, false, &splitError);
+ if (splitError != ProcessArgs::SplitOk) {
+ res = ProcessArgs::splitArgs(s + '\\', osType, false, &splitError);
+ if (splitError != ProcessArgs::SplitOk) {
+ res = ProcessArgs::splitArgs(s + '"', osType, false, &splitError);
+ if (splitError != ProcessArgs::SplitOk)
+ res = ProcessArgs::splitArgs(s + '\'', osType, false, &splitError);
}
}
return res;
diff --git a/src/plugins/projectexplorer/toolchainoptionspage.cpp b/src/plugins/projectexplorer/toolchainoptionspage.cpp
index 470eaa02da..fc92b2e83b 100644
--- a/src/plugins/projectexplorer/toolchainoptionspage.cpp
+++ b/src/plugins/projectexplorer/toolchainoptionspage.cpp
@@ -413,7 +413,7 @@ void ToolChainOptionsWidget::redetectToolchains()
QList<ToolChain *> toAdd;
QSet<ToolChain *> toDelete;
for (ToolChainFactory *f : ToolChainFactory::allToolChainFactories()) {
- for (ToolChain * const tc : f->autoDetect(knownTcs)) {
+ for (ToolChain * const tc : f->autoDetect(knownTcs, {})) { // FIXME: Pass device.
if (knownTcs.contains(tc) || toDelete.contains(tc))
continue;
const auto matchItem = [tc](const ToolChainTreeItem *item) {
diff --git a/src/plugins/projectexplorer/toolchainsettingsaccessor.cpp b/src/plugins/projectexplorer/toolchainsettingsaccessor.cpp
index 7142ffdce9..021cd0992f 100644
--- a/src/plugins/projectexplorer/toolchainsettingsaccessor.cpp
+++ b/src/plugins/projectexplorer/toolchainsettingsaccessor.cpp
@@ -58,7 +58,7 @@ public:
static const char TOOLCHAIN_DATA_KEY[] = "ToolChain.";
static const char TOOLCHAIN_COUNT_KEY[] = "ToolChain.Count";
-static const char TOOLCHAIN_FILENAME[] = "/toolchains.xml";
+static const char TOOLCHAIN_FILENAME[] = "toolchains.xml";
struct ToolChainOperations
{
@@ -67,11 +67,12 @@ struct ToolChainOperations
QList<ToolChain *> toDelete;
};
-static QList<ToolChain *> autoDetectToolChains(const QList<ToolChain *> alreadyKnownTcs)
+static QList<ToolChain *> autoDetectToolChains(const QList<ToolChain *> alreadyKnownTcs,
+ const IDevice::Ptr &device)
{
QList<ToolChain *> result;
for (ToolChainFactory *f : ToolChainFactory::allToolChainFactories())
- result.append(f->autoDetect(alreadyKnownTcs));
+ result.append(f->autoDetect(alreadyKnownTcs, device));
// Remove invalid toolchains that might have sneaked in.
return Utils::filtered(result, [](const ToolChain *tc) { return tc->isValid(); });
@@ -184,7 +185,7 @@ ToolChainSettingsAccessor::ToolChainSettingsAccessor() :
QCoreApplication::translate("ProjectExplorer::ToolChainManager", "Tool Chains"),
Core::Constants::IDE_DISPLAY_NAME)
{
- setBaseFilePath(FilePath::fromString(Core::ICore::userResourcePath() + TOOLCHAIN_FILENAME));
+ setBaseFilePath(Core::ICore::userResourcePath(TOOLCHAIN_FILENAME));
addVersionUpgrader(std::make_unique<ToolChainSettingsUpgraderV0>());
}
@@ -192,9 +193,8 @@ ToolChainSettingsAccessor::ToolChainSettingsAccessor() :
QList<ToolChain *> ToolChainSettingsAccessor::restoreToolChains(QWidget *parent) const
{
// read all tool chains from SDK
- const QList<ToolChain *> systemFileTcs
- = toolChains(restoreSettings(FilePath::fromString(Core::ICore::installerResourcePath() + TOOLCHAIN_FILENAME),
- parent));
+ const QList<ToolChain *> systemFileTcs = toolChains(
+ restoreSettings(Core::ICore::installerResourcePath(TOOLCHAIN_FILENAME), parent));
for (ToolChain * const systemTc : systemFileTcs)
systemTc->setDetection(ToolChain::AutoDetectionFromSdk);
@@ -204,7 +204,8 @@ QList<ToolChain *> ToolChainSettingsAccessor::restoreToolChains(QWidget *parent)
// Autodetect: Pass autodetected toolchains from user file so the information can be reused:
const QList<ToolChain *> autodetectedUserFileTcs
= Utils::filtered(userFileTcs, &ToolChain::isAutoDetected);
- const QList<ToolChain *> autodetectedTcs = autoDetectToolChains(autodetectedUserFileTcs);
+ // FIXME: Use real device?
+ const QList<ToolChain *> autodetectedTcs = autoDetectToolChains(autodetectedUserFileTcs, {});
// merge tool chains and register those that we need to keep:
const ToolChainOperations ops = mergeToolChainLists(systemFileTcs, userFileTcs, autodetectedTcs);
diff --git a/src/plugins/python/pythonproject.cpp b/src/plugins/python/pythonproject.cpp
index 5c3f7dcdba..223812589c 100644
--- a/src/plugins/python/pythonproject.cpp
+++ b/src/plugins/python/pythonproject.cpp
@@ -295,7 +295,7 @@ bool PythonBuildSystem::saveRawList(const QStringList &rawList, const QString &f
// New project file
if (fileName.endsWith(".pyproject")) {
- FileSaver saver(fileName, QIODevice::ReadOnly | QIODevice::Text);
+ FileSaver saver(FilePath::fromString(fileName), QIODevice::ReadOnly | QIODevice::Text);
if (!saver.hasError()) {
QString content = QTextStream(saver.file()).readAll();
if (saver.finalize(ICore::dialogParent())) {
@@ -306,7 +306,7 @@ bool PythonBuildSystem::saveRawList(const QStringList &rawList, const QString &f
}
}
} else { // Old project file
- FileSaver saver(fileName, QIODevice::WriteOnly | QIODevice::Text);
+ FileSaver saver(FilePath::fromString(fileName), QIODevice::WriteOnly | QIODevice::Text);
if (!saver.hasError()) {
QTextStream stream(saver.file());
for (const QString &filePath : rawList)
diff --git a/src/plugins/python/pythonrunconfiguration.cpp b/src/plugins/python/pythonrunconfiguration.cpp
index 866116ff14..47af192c93 100644
--- a/src/plugins/python/pythonrunconfiguration.cpp
+++ b/src/plugins/python/pythonrunconfiguration.cpp
@@ -177,7 +177,7 @@ void InterpreterAspect::fromMap(const QVariantMap &map)
void InterpreterAspect::toMap(QVariantMap &map) const
{
- saveToMap(map, m_currentId, QString());
+ saveToMap(map, m_currentId, QString(), settingsKey());
}
void InterpreterAspect::addToLayout(LayoutBuilder &builder)
diff --git a/src/plugins/python/pythonsettings.cpp b/src/plugins/python/pythonsettings.cpp
index 01dcf671a1..9e665ee1e8 100644
--- a/src/plugins/python/pythonsettings.cpp
+++ b/src/plugins/python/pythonsettings.cpp
@@ -28,15 +28,16 @@
#include "pythonconstants.h"
#include <coreplugin/dialogs/ioptionspage.h>
-#include "coreplugin/icore.h"
+#include <coreplugin/icore.h>
#include <utils/algorithm.h>
#include <utils/qtcassert.h>
#include <utils/detailswidget.h>
#include <utils/environment.h>
#include <utils/listmodel.h>
+#include <utils/layoutbuilder.h>
#include <utils/pathchooser.h>
-#include <utils/synchronousprocess.h>
+#include <utils/qtcprocess.h>
#include <utils/treemodel.h>
#include <QDir>
@@ -46,13 +47,13 @@
#include <QSettings>
#include <QStackedWidget>
#include <QTreeView>
-#include <QVBoxLayout>
#include <QWidget>
namespace Python {
namespace Internal {
using namespace Utils;
+using namespace Layouting;
class InterpreterDetailsWidget : public QWidget
{
@@ -61,13 +62,12 @@ public:
: m_name(new QLineEdit)
, m_executable(new Utils::PathChooser())
{
- auto mainLayout = new QGridLayout();
- mainLayout->addWidget(new QLabel(PythonSettings::tr("Name:")), 0, 0);
- mainLayout->addWidget(m_name, 0, 1);
- mainLayout->addWidget(new QLabel(PythonSettings::tr("Executable")), 1, 0);
- mainLayout->addWidget(m_executable, 1, 1);
m_executable->setExpectedKind(Utils::PathChooser::ExistingCommand);
- setLayout(mainLayout);
+
+ Form {
+ PythonSettings::tr("Name:"), m_name, Break(),
+ PythonSettings::tr("Executable"), m_executable
+ }.attachTo(this, false);
}
void updateInterpreter(const Interpreter &interpreter)
@@ -125,8 +125,6 @@ InterpreterOptionsWidget::InterpreterOptionsWidget(const QList<Interpreter> &int
});
m_model.setAllData(interpreters);
- auto mainLayout = new QVBoxLayout();
- auto layout = new QHBoxLayout();
m_view.setModel(&m_model);
m_view.setHeaderHidden(true);
m_view.setSelectionMode(QAbstractItemView::SingleSelection);
@@ -135,25 +133,31 @@ InterpreterOptionsWidget::InterpreterOptionsWidget(const QList<Interpreter> &int
&QItemSelectionModel::currentChanged,
this,
&InterpreterOptionsWidget::currentChanged);
- auto buttonLayout = new QVBoxLayout();
+
auto addButton = new QPushButton(PythonSettings::tr("&Add"));
connect(addButton, &QPushButton::pressed, this, &InterpreterOptionsWidget::addItem);
+
m_deleteButton = new QPushButton(PythonSettings::tr("&Delete"));
m_deleteButton->setEnabled(false);
connect(m_deleteButton, &QPushButton::pressed, this, &InterpreterOptionsWidget::deleteItem);
+
m_makeDefaultButton = new QPushButton(PythonSettings::tr("&Make Default"));
m_makeDefaultButton->setEnabled(false);
connect(m_makeDefaultButton, &QPushButton::pressed, this, &InterpreterOptionsWidget::makeDefault);
- mainLayout->addLayout(layout);
- mainLayout->addWidget(m_detailsWidget);
+
m_detailsWidget->hide();
- setLayout(mainLayout);
- layout->addWidget(&m_view);
- layout->addLayout(buttonLayout);
- buttonLayout->addWidget(addButton);
- buttonLayout->addWidget(m_deleteButton);
- buttonLayout->addWidget(m_makeDefaultButton);
- buttonLayout->addStretch(10);
+
+ Column buttons {
+ addButton,
+ m_deleteButton,
+ m_makeDefaultButton,
+ Stretch()
+ };
+
+ Column {
+ Row { &m_view, buttons },
+ m_detailsWidget
+ }.attachTo(this);
}
void InterpreterOptionsWidget::apply()
@@ -277,10 +281,10 @@ Interpreter::Interpreter(const FilePath &python, const QString &defaultName, boo
SynchronousProcess pythonProcess;
pythonProcess.setProcessChannelMode(QProcess::MergedChannels);
pythonProcess.setTimeoutS(1);
- SynchronousProcessResponse response = pythonProcess.runBlocking(
- CommandLine(python, {"--version"}));
- if (response.result == SynchronousProcessResponse::Finished)
- name = response.stdOut().trimmed();
+ pythonProcess.setCommand({python, {"--version"}});
+ pythonProcess.runBlocking();
+ if (pythonProcess.result() == QtcProcess::Finished)
+ name = pythonProcess.stdOut().trimmed();
if (name.isEmpty())
name = defaultName;
if (windowedSuffix)
diff --git a/src/plugins/python/pythonutils.cpp b/src/plugins/python/pythonutils.cpp
index 56b2dbe6db..d693c2597b 100644
--- a/src/plugins/python/pythonutils.cpp
+++ b/src/plugins/python/pythonutils.cpp
@@ -46,8 +46,8 @@
#include <utils/infobar.h>
#include <utils/mimetypes/mimedatabase.h>
#include <utils/qtcassert.h>
+#include <utils/qtcprocess.h>
#include <utils/runextensions.h>
-#include <utils/synchronousprocess.h>
#include <QDir>
#include <QFutureWatcher>
@@ -86,11 +86,11 @@ static QString pythonName(const FilePath &pythonPath)
if (name.isEmpty()) {
SynchronousProcess pythonProcess;
pythonProcess.setTimeoutS(2);
- const CommandLine pythonVersionCommand(pythonPath, {"--version"});
- const SynchronousProcessResponse response = pythonProcess.runBlocking(pythonVersionCommand);
- if (response.result != SynchronousProcessResponse::Finished)
+ pythonProcess.setCommand({pythonPath, {"--version"}});
+ pythonProcess.runBlocking();
+ if (pythonProcess.result() != QtcProcess::Finished)
return {};
- name = response.allOutput().trimmed();
+ name = pythonProcess.allOutput().trimmed();
nameForPython[pythonPath] = name;
}
return name;
@@ -104,9 +104,13 @@ FilePath getPylsModulePath(CommandLine pylsCommand)
return modulePath;
pylsCommand.addArg("-h");
+
SynchronousProcess pythonProcess;
- pythonProcess.setEnvironment(pythonProcess.environment() + QStringList("PYTHONVERBOSE=x"));
- SynchronousProcessResponse response = pythonProcess.runBlocking(pylsCommand);
+ Environment env = pythonProcess.environment();
+ env.set("PYTHONVERBOSE", "x");
+ pythonProcess.setEnvironment(env);
+ pythonProcess.setCommand(pylsCommand);
+ pythonProcess.runBlocking();
static const QString pylsInitPattern = "(.*)"
+ QRegularExpression::escape(
@@ -117,7 +121,7 @@ FilePath getPylsModulePath(CommandLine pylsCommand)
static const QRegularExpression regexNotCached(" code object from " + pylsInitPattern,
QRegularExpression::MultilineOption);
- const QString &output = response.allOutput();
+ const QString output = pythonProcess.allOutput();
for (const auto &regex : {regexCached, regexNotCached}) {
const QRegularExpressionMatch result = regex.match(output);
if (result.hasMatch()) {
@@ -145,7 +149,6 @@ QList<const StdIOSettings *> configuredPythonLanguageServer()
static PythonLanguageServerState checkPythonLanguageServer(const FilePath &python)
{
using namespace LanguageClient;
- SynchronousProcess pythonProcess;
const CommandLine pythonLShelpCommand(python, {"-m", "pyls", "-h"});
const FilePath &modulePath = getPylsModulePath(pythonLShelpCommand);
for (const StdIOSettings *serverSetting : configuredPythonLanguageServer()) {
@@ -156,13 +159,15 @@ static PythonLanguageServerState checkPythonLanguageServer(const FilePath &pytho
}
}
- SynchronousProcessResponse response = pythonProcess.runBlocking(pythonLShelpCommand);
- if (response.allOutput().contains("Python Language Server"))
+ SynchronousProcess pythonProcess;
+ pythonProcess.setCommand(pythonLShelpCommand);
+ pythonProcess.runBlocking();
+ if (pythonProcess.allOutput().contains("Python Language Server"))
return {PythonLanguageServerState::AlreadyInstalled, modulePath};
- const CommandLine pythonPipVersionCommand(python, {"-m", "pip", "-V"});
- response = pythonProcess.runBlocking(pythonPipVersionCommand);
- if (response.allOutput().startsWith("pip "))
+ pythonProcess.setCommand({python, {"-m", "pip", "-V"}});
+ pythonProcess.runBlocking();
+ if (pythonProcess.allOutput().startsWith("pip "))
return {PythonLanguageServerState::CanBeInstalled, FilePath()};
else
return {PythonLanguageServerState::CanNotBeInstalled, FilePath()};
@@ -267,7 +272,8 @@ public:
if (!QDir(m_python.parentDir().toString()).exists("activate"))
arguments << "--user";
- m_process.start(m_python.toString(), arguments);
+ m_process.setCommand({m_python, arguments});
+ m_process.start();
Core::MessageManager::writeDisrupting(
tr("Running \"%1 %2\" to install Python language server")
@@ -280,7 +286,7 @@ public:
private:
void cancel()
{
- SynchronousProcess::stopProcess(m_process);
+ m_process.stopProcess();
Core::MessageManager::writeFlashing(
tr("The Python language server installation was canceled by %1.")
.arg(m_killTimer.isActive() ? tr("user") : tr("time out")));
@@ -315,7 +321,7 @@ private:
QFutureInterface<void> m_future;
QFutureWatcher<void> m_watcher;
- QProcess m_process;
+ QtcProcess m_process;
QTimer m_killTimer;
const FilePath m_python;
QPointer<TextEditor::TextDocument> m_document;
@@ -377,7 +383,6 @@ void PyLSConfigureAssistant::openDocumentWithPython(const FilePath &python,
using CheckPylsWatcher = QFutureWatcher<PythonLanguageServerState>;
QPointer<CheckPylsWatcher> watcher = new CheckPylsWatcher();
- watcher->setFuture(Utils::runAsync(&checkPythonLanguageServer, python));
// cancel and delete watcher after a 10 second timeout
QTimer::singleShot(10000, this, [watcher]() {
@@ -397,6 +402,7 @@ void PyLSConfigureAssistant::openDocumentWithPython(const FilePath &python,
handlePyLSState(python, watcher->result(), document);
watcher->deleteLater();
});
+ watcher->setFuture(Utils::runAsync(&checkPythonLanguageServer, python));
}
void PyLSConfigureAssistant::handlePyLSState(const FilePath &python,
diff --git a/src/plugins/qbsprojectmanager/qbsbuildstep.cpp b/src/plugins/qbsprojectmanager/qbsbuildstep.cpp
index 7c80399354..68d95f60e5 100644
--- a/src/plugins/qbsprojectmanager/qbsbuildstep.cpp
+++ b/src/plugins/qbsprojectmanager/qbsbuildstep.cpp
@@ -88,7 +88,7 @@ public:
bool isManagedByTarget() const { return m_isManagedByTarget; }
private:
- void setVisibleDynamic(bool visible) final;
+ void setVisibleDynamic(bool visible);
const ProjectExplorer::Kit *m_kit = nullptr;
QMap<QString, QString> m_abisToArchMap;
@@ -129,8 +129,8 @@ void ArchitecturesAspect::addToLayout(LayoutBuilder &builder)
setVisibleDynamic(true);
};
- connect(KitManager::instance(), &KitManager::kitsChanged, builder.layout(), changeHandler);
- connect(this, &ArchitecturesAspect::changed, builder.layout(), changeHandler);
+ connect(KitManager::instance(), &KitManager::kitsChanged, this, changeHandler);
+ connect(this, &ArchitecturesAspect::changed, this, changeHandler);
changeHandler();
}
@@ -146,7 +146,7 @@ QStringList ArchitecturesAspect::selectedArchitectures() const
void ArchitecturesAspect::setVisibleDynamic(bool visible)
{
- MultiSelectionAspect::setVisibleDynamic(visible);
+ MultiSelectionAspect::setVisible(visible);
m_isManagedByTarget = visible;
}
@@ -497,7 +497,7 @@ void QbsBuildStep::handleProcessResult(
if (success && !hasOutput)
return;
- emit addOutput(executable.toUserOutput() + ' ' + QtcProcess::joinArgs(arguments),
+ emit addOutput(executable.toUserOutput() + ' ' + ProcessArgs::joinArgs(arguments),
OutputFormat::Stdout);
for (const QString &line : stdErr)
emit addOutput(line, OutputFormat::Stderr);
@@ -668,7 +668,7 @@ QbsBuildStepConfigWidget::QbsBuildStepConfigWidget(QbsBuildStep *step) :
installDirChooser = new PathChooser(this);
installDirChooser->setExpectedKind(PathChooser::Directory);
- LayoutBuilder builder(this);
+ Layouting::Form builder;
builder.addRow(m_qbsStep->m_buildVariant);
builder.addRow(m_qbsStep->m_selectedAbis);
builder.addRow(m_qbsStep->m_maxJobCount);
@@ -686,6 +686,7 @@ QbsBuildStepConfigWidget::QbsBuildStepConfigWidget(QbsBuildStep *step) :
builder.addRow({tr("Installation directory:"), installDirChooser});
builder.addRow(m_qbsStep->m_commandLine);
+ builder.attachTo(this, false);
propertyEdit->setToolTip(tr("Properties to pass to the project."));
defaultInstallDirCheckBox->setText(tr("Use default location"));
@@ -773,7 +774,7 @@ void QbsBuildStepConfigWidget::updatePropertyEdit(const QVariantMap &data)
for (QVariantMap::const_iterator i = editable.constBegin(); i != editable.constEnd(); ++i)
propertyList.append(i.key() + ':' + i.value().toString());
- propertyEdit->setText(QtcProcess::joinArgs(propertyList));
+ propertyEdit->setText(ProcessArgs::joinArgs(propertyList));
}
void QbsBuildStep::changeBuildVariant()
@@ -850,10 +851,9 @@ QbsBuildStep *QbsBuildStepConfigWidget::qbsStep() const
bool QbsBuildStepConfigWidget::validateProperties(Utils::FancyLineEdit *edit, QString *errorMessage)
{
- Utils::QtcProcess::SplitError err;
- QStringList argList = Utils::QtcProcess::splitArgs(edit->text(), Utils::HostOsInfo::hostOs(),
- false, &err);
- if (err != Utils::QtcProcess::SplitOk) {
+ ProcessArgs::SplitError err;
+ QStringList argList = ProcessArgs::splitArgs(edit->text(), HostOsInfo::hostOs(), false, &err);
+ if (err != ProcessArgs::SplitOk) {
if (errorMessage)
*errorMessage = tr("Could not split properties.");
return false;
diff --git a/src/plugins/qbsprojectmanager/qbsinstallstep.cpp b/src/plugins/qbsprojectmanager/qbsinstallstep.cpp
index 19cf5c76f4..16a8ea2ac1 100644
--- a/src/plugins/qbsprojectmanager/qbsinstallstep.cpp
+++ b/src/plugins/qbsprojectmanager/qbsinstallstep.cpp
@@ -193,7 +193,7 @@ QWidget *QbsInstallStep::createConfigWidget()
commandLineTextEdit->setTextInteractionFlags(Qt::TextSelectableByKeyboard|Qt::TextSelectableByMouse);
commandLineTextEdit->setMinimumHeight(QFontMetrics(widget->font()).height() * 8);
- LayoutBuilder builder(widget);
+ Layouting::Form builder;
builder.addRow({tr("Install root:"), installRootValueLabel});
builder.addRow(tr("Flags:"));
m_dryRun->addToLayout(builder);
@@ -201,6 +201,7 @@ QWidget *QbsInstallStep::createConfigWidget()
m_cleanInstallRoot->addToLayout(builder);
builder.addRow({commandLineKeyLabel, commandLineTextEdit});
+ builder.attachTo(widget);
const auto updateState = [this, commandLineTextEdit, installRootValueLabel] {
installRootValueLabel->setText(installRoot());
diff --git a/src/plugins/qbsprojectmanager/qbskitinformation.cpp b/src/plugins/qbsprojectmanager/qbskitinformation.cpp
index 3167d77e74..d481d09d44 100644
--- a/src/plugins/qbsprojectmanager/qbskitinformation.cpp
+++ b/src/plugins/qbsprojectmanager/qbskitinformation.cpp
@@ -31,6 +31,7 @@
#include <projectexplorer/kitmanager.h>
#include <utils/elidinglabel.h>
+#include <utils/layoutbuilder.h>
#include <utils/qtcassert.h>
#include <QPushButton>
@@ -46,8 +47,8 @@ class AspectWidget final : public KitAspectWidget
public:
AspectWidget(Kit *kit, const KitAspect *kitInfo)
: KitAspectWidget(kit, kitInfo),
- m_contentLabel(new Utils::ElidingLabel),
- m_changeButton(new QPushButton(tr("Change...")))
+ m_contentLabel(createSubWidget<Utils::ElidingLabel>()),
+ m_changeButton(createSubWidget<QPushButton>(tr("Change...")))
{
connect(m_changeButton, &QPushButton::clicked, this, &AspectWidget::changeProperties);
}
@@ -55,8 +56,13 @@ public:
private:
void makeReadOnly() override { m_changeButton->setEnabled(false); }
void refresh() override { m_contentLabel->setText(QbsKitAspect::representation(kit())); }
- QWidget *mainWidget() const override { return m_contentLabel; }
- QWidget *buttonWidget() const override { return m_changeButton; }
+
+ void addToLayout(Utils::LayoutBuilder &builder) override
+ {
+ addMutableAction(m_contentLabel);
+ builder.addItem(m_contentLabel);
+ builder.addItem(m_changeButton);
+ }
void changeProperties()
{
diff --git a/src/plugins/qbsprojectmanager/qbsnodes.cpp b/src/plugins/qbsprojectmanager/qbsnodes.cpp
index 68731e30a1..1393583213 100644
--- a/src/plugins/qbsprojectmanager/qbsnodes.cpp
+++ b/src/plugins/qbsprojectmanager/qbsnodes.cpp
@@ -73,8 +73,7 @@ const QbsProductNode *parentQbsProductNode(const ProjectExplorer::Node *node)
QbsGroupNode::QbsGroupNode(const QJsonObject &grp) : ProjectNode(FilePath()), m_groupData(grp)
{
- static QIcon groupIcon = QIcon(QString(ProjectExplorer::Constants::FILEOVERLAY_GROUP));
- setIcon(groupIcon);
+ setIcon(ProjectExplorer::Constants::FILEOVERLAY_GROUP);
setDisplayName(grp.value("name").toString());
setEnabled(grp.value("is-enabled").toBool());
}
@@ -108,9 +107,7 @@ QVariant QbsGroupNode::data(Id role) const
QbsProductNode::QbsProductNode(const QJsonObject &prd) : ProjectNode(FilePath()), m_productData(prd)
{
- static QIcon productIcon = Core::FileIconProvider::directoryIcon(
- ProjectExplorer::Constants::FILEOVERLAY_PRODUCT);
- setIcon(productIcon);
+ setIcon(DirectoryIcon(ProjectExplorer::Constants::FILEOVERLAY_PRODUCT));
if (prd.value("is-runnable").toBool()) {
setProductType(ProductType::App);
} else {
@@ -265,9 +262,7 @@ QJsonObject QbsProductNode::mainGroup() const
QbsProjectNode::QbsProjectNode(const QJsonObject &projectData)
: ProjectNode(FilePath()), m_projectData(projectData)
{
- static QIcon projectIcon = Core::FileIconProvider::directoryIcon(
- ProjectExplorer::Constants::FILEOVERLAY_QT);
- setIcon(projectIcon);
+ setIcon(DirectoryIcon(ProjectExplorer::Constants::FILEOVERLAY_QT));
setDisplayName(projectData.value("name").toString());
}
diff --git a/src/plugins/qbsprojectmanager/qbsprojectmanagerplugin.cpp b/src/plugins/qbsprojectmanager/qbsprojectmanagerplugin.cpp
index 0fa4a8079b..cf46e0b544 100644
--- a/src/plugins/qbsprojectmanager/qbsprojectmanagerplugin.cpp
+++ b/src/plugins/qbsprojectmanager/qbsprojectmanagerplugin.cpp
@@ -52,6 +52,7 @@
#include <projectexplorer/project.h>
#include <projectexplorer/projectexplorer.h>
#include <projectexplorer/projectexplorerconstants.h>
+#include <projectexplorer/projectexplorericons.h>
#include <projectexplorer/projectmanager.h>
#include <projectexplorer/projecttree.h>
#include <projectexplorer/runcontrol.h>
@@ -63,6 +64,7 @@
#include <utils/fileutils.h>
#include <utils/qtcassert.h>
+#include <utils/utilsicons.h>
#include <QAction>
@@ -159,7 +161,7 @@ bool QbsProjectManagerPlugin::initialize(const QStringList &arguments, QString *
command->setAttribute(Core::Command::CA_UpdateText);
command->setDescription(m_buildFile->text());
command->setDefaultKeySequence(QKeySequence(tr("Ctrl+Alt+B")));
- mbuild->addAction(command, ProjectExplorer::Constants::G_BUILD_BUILD);
+ mbuild->addAction(command, ProjectExplorer::Constants::G_BUILD_FILE);
connect(m_buildFile, &QAction::triggered, this, &QbsProjectManagerPlugin::buildFile);
m_buildProductCtx = new QAction(tr("Build"), this);
@@ -176,7 +178,7 @@ bool QbsProjectManagerPlugin::initialize(const QStringList &arguments, QString *
command->setAttribute(Core::Command::CA_UpdateText);
command->setDescription(m_buildFile->text());
command->setDefaultKeySequence(QKeySequence(tr("Ctrl+Alt+Shift+B")));
- mbuild->addAction(command, ProjectExplorer::Constants::G_BUILD_BUILD);
+ mbuild->addAction(command, ProjectExplorer::Constants::G_BUILD_PRODUCT);
connect(m_buildProduct, &QAction::triggered, this, &QbsProjectManagerPlugin::buildProduct);
m_cleanProductCtx = new QAction(tr("Clean"), this);
@@ -187,12 +189,11 @@ bool QbsProjectManagerPlugin::initialize(const QStringList &arguments, QString *
connect(m_cleanProductCtx, &QAction::triggered,
this, &QbsProjectManagerPlugin::cleanProductContextMenu);
- m_cleanProduct = new Utils::ParameterAction(tr("Clean Product"), tr("Clean Product \"%1\""),
- Utils::ParameterAction::AlwaysEnabled, this);
+ m_cleanProduct = new QAction(Utils::Icons::CLEAN.icon(), tr("Clean"), this);
command = Core::ActionManager::registerAction(m_cleanProduct, Constants::ACTION_CLEAN_PRODUCT);
command->setAttribute(Core::Command::CA_Hide);
command->setAttribute(Core::Command::CA_UpdateText);
- mbuild->addAction(command, ProjectExplorer::Constants::G_BUILD_CLEAN);
+ mbuild->addAction(command, ProjectExplorer::Constants::G_BUILD_PRODUCT);
connect(m_cleanProduct, &QAction::triggered, this, &QbsProjectManagerPlugin::cleanProduct);
m_rebuildProductCtx = new QAction(tr("Rebuild"), this);
@@ -203,14 +204,12 @@ bool QbsProjectManagerPlugin::initialize(const QStringList &arguments, QString *
connect(m_rebuildProductCtx, &QAction::triggered,
this, &QbsProjectManagerPlugin::rebuildProductContextMenu);
- m_rebuildProduct = new Utils::ParameterAction(
- tr("Rebuild Product"), tr("Rebuild Product \"%1\""),
- Utils::ParameterAction::AlwaysEnabled, this);
+ m_rebuildProduct = new QAction(ProjectExplorer::Icons::REBUILD.icon(), tr("Rebuild"), this);
command = Core::ActionManager::registerAction(m_rebuildProduct,
Constants::ACTION_REBUILD_PRODUCT);
command->setAttribute(Core::Command::CA_Hide);
command->setAttribute(Core::Command::CA_UpdateText);
- mbuild->addAction(command, ProjectExplorer::Constants::G_BUILD_REBUILD);
+ mbuild->addAction(command, ProjectExplorer::Constants::G_BUILD_PRODUCT);
connect(m_rebuildProduct, &QAction::triggered, this, &QbsProjectManagerPlugin::rebuildProduct);
m_buildSubprojectCtx = new QAction(tr("Build"), this);
@@ -358,10 +357,8 @@ void QbsProjectManagerPlugin::updateBuildActions()
m_buildProduct->setParameter(productName);
m_cleanProduct->setEnabled(enabled);
m_cleanProduct->setVisible(productVisible);
- m_cleanProduct->setParameter(productName);
m_rebuildProduct->setEnabled(enabled);
m_rebuildProduct->setVisible(productVisible);
- m_rebuildProduct->setParameter(productName);
}
void QbsProjectManagerPlugin::projectChanged()
diff --git a/src/plugins/qbsprojectmanager/qbsprojectmanagerplugin.h b/src/plugins/qbsprojectmanager/qbsprojectmanagerplugin.h
index 02c2a52e0b..641bf5d01d 100644
--- a/src/plugins/qbsprojectmanager/qbsprojectmanagerplugin.h
+++ b/src/plugins/qbsprojectmanager/qbsprojectmanagerplugin.h
@@ -96,8 +96,8 @@ private:
QAction *m_rebuildSubprojectCtx = nullptr;
Utils::ParameterAction *m_buildFile = nullptr;
Utils::ParameterAction *m_buildProduct = nullptr;
- Utils::ParameterAction *m_cleanProduct = nullptr;
- Utils::ParameterAction *m_rebuildProduct = nullptr;
+ QAction *m_cleanProduct = nullptr;
+ QAction *m_rebuildProduct = nullptr;
};
} // namespace Internal
diff --git a/src/plugins/qbsprojectmanager/qbssettings.cpp b/src/plugins/qbsprojectmanager/qbssettings.cpp
index e3200a0ae0..de6b1ad9da 100644
--- a/src/plugins/qbsprojectmanager/qbssettings.cpp
+++ b/src/plugins/qbsprojectmanager/qbssettings.cpp
@@ -85,7 +85,7 @@ bool QbsSettings::useCreatorSettingsDirForQbs()
QString QbsSettings::qbsSettingsBaseDir()
{
- return useCreatorSettingsDirForQbs() ? Core::ICore::userResourcePath() : QString();
+ return useCreatorSettingsDirForQbs() ? Core::ICore::userResourcePath().toString() : QString();
}
QbsSettings &QbsSettings::instance()
diff --git a/src/plugins/qmakeprojectmanager/customwidgetwizard/plugingenerator.cpp b/src/plugins/qmakeprojectmanager/customwidgetwizard/plugingenerator.cpp
index 13f5441af8..6b4b7f28bc 100644
--- a/src/plugins/qmakeprojectmanager/customwidgetwizard/plugingenerator.cpp
+++ b/src/plugins/qmakeprojectmanager/customwidgetwizard/plugingenerator.cpp
@@ -55,7 +55,9 @@ struct ProjectContents {
};
// Create a binary icon file
-static inline Core::GeneratedFile generateIconFile(const QString &source, const QString &target, QString *errorMessage)
+static inline Core::GeneratedFile generateIconFile(const Utils::FilePath &source,
+ const QString &target,
+ QString *errorMessage)
{
// Read out source
Utils::FileReader reader;
@@ -270,7 +272,9 @@ QList<Core::GeneratedFile> PluginGenerator::generatePlugin(const GenerationPara
const QFileInfo qfi(icon);
if (qfi.dir() != slashLessBaseDir) {
const QString newIcon = baseDir + qfi.fileName();
- const Core::GeneratedFile iconFile = generateIconFile(icon, newIcon, errorMessage);
+ const Core::GeneratedFile iconFile = generateIconFile(Utils::FilePath::fromFileInfo(qfi),
+ newIcon,
+ errorMessage);
if (iconFile.path().isEmpty())
return QList<Core::GeneratedFile>();
rc.push_back(iconFile);
@@ -311,7 +315,7 @@ QString PluginGenerator::processTemplate(const QString &tmpl,
QString *errorMessage)
{
Utils::FileReader reader;
- if (!reader.fetch(tmpl, errorMessage))
+ if (!reader.fetch(Utils::FilePath::fromString(tmpl), errorMessage))
return QString();
diff --git a/src/plugins/qmakeprojectmanager/externaleditors.cpp b/src/plugins/qmakeprojectmanager/externaleditors.cpp
index 7db24b732e..fd7f6bc149 100644
--- a/src/plugins/qmakeprojectmanager/externaleditors.cpp
+++ b/src/plugins/qmakeprojectmanager/externaleditors.cpp
@@ -27,7 +27,7 @@
#include <utils/algorithm.h>
#include <utils/hostosinfo.h>
-#include <utils/synchronousprocess.h>
+#include <utils/qtcprocess.h>
#include <projectexplorer/project.h>
#include <projectexplorer/projectexplorer.h>
#include <projectexplorer/projectexplorerconstants.h>
@@ -156,7 +156,7 @@ static QString findFirstCommand(QVector<QtSupport::BaseQtVersion *> qtVersions,
return QString();
}
-bool ExternalQtEditor::getEditorLaunchData(const QString &fileName,
+bool ExternalQtEditor::getEditorLaunchData(const Utils::FilePath &filePath,
LaunchData *data,
QString *errorMessage) const
{
@@ -168,7 +168,7 @@ bool ExternalQtEditor::getEditorLaunchData(const QString &fileName,
// As fallback check PATH
data->workingDirectory.clear();
QVector<QtSupport::BaseQtVersion *> qtVersionsToCheck; // deduplicated after being filled
- if (const Project *project = SessionManager::projectForFile(Utils::FilePath::fromString(fileName))) {
+ if (const Project *project = SessionManager::projectForFile(filePath)) {
data->workingDirectory = project->projectDirectory().toString();
// active kit
if (const Target *target = project->activeTarget()) {
@@ -187,13 +187,13 @@ bool ExternalQtEditor::getEditorLaunchData(const QString &fileName,
data->binary = findFirstCommand(qtVersionsToCheck, m_commandForQtVersion);
// fallback
if (data->binary.isEmpty())
- data->binary = Utils::SynchronousProcess::locateBinary(m_commandForQtVersion(nullptr));
+ data->binary = Utils::QtcProcess::locateBinary(m_commandForQtVersion(nullptr));
if (data->binary.isEmpty()) {
*errorMessage = msgAppNotFound(id().toString());
return false;
}
// Setup binary + arguments, use Mac Open if appropriate
- data->arguments.push_back(fileName);
+ data->arguments.push_back(filePath.toString());
if (Utils::HostOsInfo::isMacHost())
*data = createMacOpenCommand(*data);
if (debug)
@@ -201,10 +201,10 @@ bool ExternalQtEditor::getEditorLaunchData(const QString &fileName,
return true;
}
-bool ExternalQtEditor::startEditor(const QString &fileName, QString *errorMessage)
+bool ExternalQtEditor::startEditor(const Utils::FilePath &filePath, QString *errorMessage)
{
LaunchData data;
- return getEditorLaunchData(fileName, &data, errorMessage)
+ return getEditorLaunchData(filePath, &data, errorMessage)
&& startEditorProcess(data, errorMessage);
}
@@ -244,11 +244,11 @@ void DesignerExternalEditor::processTerminated(const QString &binary)
socket->deleteLater();
}
-bool DesignerExternalEditor::startEditor(const QString &fileName, QString *errorMessage)
+bool DesignerExternalEditor::startEditor(const Utils::FilePath &filePath, QString *errorMessage)
{
LaunchData data;
// Find the editor binary
- if (!getEditorLaunchData(fileName, &data, errorMessage)) {
+ if (!getEditorLaunchData(filePath, &data, errorMessage)) {
return false;
}
// Known one?
@@ -256,9 +256,9 @@ bool DesignerExternalEditor::startEditor(const QString &fileName, QString *error
if (it != m_processCache.end()) {
// Process is known, write to its socket to cause it to open the file
if (debug)
- qDebug() << Q_FUNC_INFO << "\nWriting to socket:" << data.binary << fileName;
+ qDebug() << Q_FUNC_INFO << "\nWriting to socket:" << data.binary << filePath;
QTcpSocket *socket = it.value();
- if (!socket->write(fileName.toUtf8() + '\n')) {
+ if (!socket->write(filePath.toString().toUtf8() + '\n')) {
*errorMessage = tr("Qt Designer is not responding (%1).").arg(socket->errorString());
return false;
}
@@ -272,7 +272,7 @@ bool DesignerExternalEditor::startEditor(const QString &fileName, QString *error
}
const quint16 port = server.serverPort();
if (debug)
- qDebug() << Q_FUNC_INFO << "\nLaunching server:" << port << data.binary << fileName;
+ qDebug() << Q_FUNC_INFO << "\nLaunching server:" << port << data.binary << filePath;
// Start first one with file and socket as '-client port file'
// Wait for the socket listening
data.arguments.push_front(QString::number(port));
diff --git a/src/plugins/qmakeprojectmanager/externaleditors.h b/src/plugins/qmakeprojectmanager/externaleditors.h
index cea0b62a7f..8a750f6a2d 100644
--- a/src/plugins/qmakeprojectmanager/externaleditors.h
+++ b/src/plugins/qmakeprojectmanager/externaleditors.h
@@ -62,7 +62,7 @@ public:
Utils::Id id() const override;
QString displayName() const override;
- bool startEditor(const QString &fileName, QString *errorMessage) override;
+ bool startEditor(const Utils::FilePath &filePath, QString *errorMessage) override;
// Data required to launch the editor
struct LaunchData {
@@ -79,7 +79,7 @@ protected:
// Try to retrieve the binary of the editor from the Qt version,
// prepare arguments accordingly (Mac "open" if desired)
- bool getEditorLaunchData(const QString &fileName,
+ bool getEditorLaunchData(const Utils::FilePath &filePath,
LaunchData *data,
QString *errorMessage) const;
@@ -104,7 +104,7 @@ class DesignerExternalEditor : public ExternalQtEditor
public:
DesignerExternalEditor();
- bool startEditor(const QString &fileName, QString *errorMessage) override;
+ bool startEditor(const Utils::FilePath &filePath, QString *errorMessage) override;
private:
void processTerminated(const QString &binary);
diff --git a/src/plugins/qmakeprojectmanager/librarydetailscontroller.cpp b/src/plugins/qmakeprojectmanager/librarydetailscontroller.cpp
index 906796db9b..04f6e131bc 100644
--- a/src/plugins/qmakeprojectmanager/librarydetailscontroller.cpp
+++ b/src/plugins/qmakeprojectmanager/librarydetailscontroller.cpp
@@ -397,7 +397,7 @@ static QString smartQuote(const QString &aString)
{
// The OS type is not important in that case, but use always the same
// in order not to generate different quoting depending on host platform
- return Utils::QtcProcess::quoteArg(aString, Utils::OsTypeLinux);
+ return Utils::ProcessArgs::quoteArg(aString, Utils::OsTypeLinux);
}
static QString appendSeparator(const QString &aString)
diff --git a/src/plugins/qmakeprojectmanager/makefileparse.cpp b/src/plugins/qmakeprojectmanager/makefileparse.cpp
index 2beb5d899f..04048801b2 100644
--- a/src/plugins/qmakeprojectmanager/makefileparse.cpp
+++ b/src/plugins/qmakeprojectmanager/makefileparse.cpp
@@ -76,7 +76,7 @@ void MakeFileParse::parseArgs(const QString &args, const QString &project,
bool after = false;
bool ignoreNext = false;
m_unparsedArguments = args;
- QtcProcess::ArgIterator ait(&m_unparsedArguments);
+ ProcessArgs::ArgIterator ait(&m_unparsedArguments);
while (ait.next()) {
if (ignoreNext) {
// Ignoring
@@ -391,11 +391,11 @@ void MakeFileParse::parseCommandLine(const QString &command, const QString &proj
const QList<QMakeAssignment> &assignmentsToUse = m_mode == Mode::FilterKnownConfigValues
? filteredAssignments : assignments;
foreach (const QMakeAssignment &qa, assignmentsToUse)
- QtcProcess::addArg(&m_unparsedArguments, qa.variable + qa.op + qa.value);
+ ProcessArgs::addArg(&m_unparsedArguments, qa.variable + qa.op + qa.value);
if (!afterAssignments.isEmpty()) {
- QtcProcess::addArg(&m_unparsedArguments, QLatin1String("-after"));
+ ProcessArgs::addArg(&m_unparsedArguments, QLatin1String("-after"));
foreach (const QMakeAssignment &qa, afterAssignments)
- QtcProcess::addArg(&m_unparsedArguments, qa.variable + qa.op + qa.value);
+ ProcessArgs::addArg(&m_unparsedArguments, qa.variable + qa.op + qa.value);
}
}
@@ -527,8 +527,8 @@ void QmakeProjectManagerPlugin::testMakefileParser()
MakeFileParse parser("/tmp/something", MakeFileParse::Mode::FilterKnownConfigValues);
parser.parseCommandLine(command, project);
- QCOMPARE(Utils::QtcProcess::splitArgs(parser.unparsedArguments()),
- Utils::QtcProcess::splitArgs(unparsedArguments));
+ QCOMPARE(Utils::ProcessArgs::splitArgs(parser.unparsedArguments()),
+ Utils::ProcessArgs::splitArgs(unparsedArguments));
QCOMPARE(parser.effectiveBuildConfig({}), effectiveBuildConfig);
const QMakeStepConfig qmsc = parser.config();
diff --git a/src/plugins/qmakeprojectmanager/profileeditor.cpp b/src/plugins/qmakeprojectmanager/profileeditor.cpp
index 6443af2635..a3cc952834 100644
--- a/src/plugins/qmakeprojectmanager/profileeditor.cpp
+++ b/src/plugins/qmakeprojectmanager/profileeditor.cpp
@@ -238,11 +238,11 @@ void ProFileEditorWidget::findLinkAt(const QTextCursor &cursor,
else
return processLinkCallback(link);
}
- link.targetFileName = QDir::cleanPath(fileName);
+ link.targetFilePath = Utils::FilePath::fromString(QDir::cleanPath(fileName));
} else {
- link.targetFileName = checkForPrfFile(buffer);
+ link.targetFilePath = Utils::FilePath::fromString(checkForPrfFile(buffer));
}
- if (!link.targetFileName.isEmpty()) {
+ if (!link.targetFilePath.isEmpty()) {
link.linkTextStart = cursor.position() - positionInBlock + beginPos + 1;
link.linkTextEnd = cursor.position() - positionInBlock + endPos;
}
diff --git a/src/plugins/qmakeprojectmanager/qmakebuildconfiguration.cpp b/src/plugins/qmakeprojectmanager/qmakebuildconfiguration.cpp
index 3e0db04afd..9129a7b852 100644
--- a/src/plugins/qmakeprojectmanager/qmakebuildconfiguration.cpp
+++ b/src/plugins/qmakeprojectmanager/qmakebuildconfiguration.cpp
@@ -32,7 +32,6 @@
#include "qmakenodes.h"
#include "qmakesettings.h"
#include "qmakestep.h"
-#include "qmakemakestep.h"
#include "makefileparse.h"
#include "qmakebuildconfiguration.h"
@@ -47,6 +46,7 @@
#include <projectexplorer/buildpropertiessettings.h>
#include <projectexplorer/buildsteplist.h>
#include <projectexplorer/kit.h>
+#include <projectexplorer/makestep.h>
#include <projectexplorer/projectexplorer.h>
#include <projectexplorer/projectexplorerconstants.h>
#include <projectexplorer/projectmacroexpander.h>
@@ -89,9 +89,9 @@ public:
QmakeExtraBuildInfo::QmakeExtraBuildInfo()
{
const BuildPropertiesSettings &settings = ProjectExplorerPlugin::buildPropertiesSettings();
- config.separateDebugInfo = settings.separateDebugInfo;
- config.linkQmlDebuggingQQ2 = settings.qmlDebugging;
- config.useQtQuickCompiler = settings.qtQuickCompiler;
+ config.separateDebugInfo = settings.separateDebugInfo.value();
+ config.linkQmlDebuggingQQ2 = settings.qmlDebugging.value();
+ config.useQtQuickCompiler = settings.qtQuickCompiler.value();
}
// --------------------------------------------------------------------
@@ -491,12 +491,12 @@ QMakeStep *QmakeBuildConfiguration::qmakeStep() const
return nullptr;
}
-QmakeMakeStep *QmakeBuildConfiguration::makeStep() const
+MakeStep *QmakeBuildConfiguration::makeStep() const
{
- QmakeMakeStep *ms = nullptr;
+ MakeStep *ms = nullptr;
BuildStepList *bsl = buildSteps();
for (int i = 0; i < bsl->count(); ++i)
- if ((ms = qobject_cast<QmakeMakeStep *>(bsl->at(i))) != nullptr)
+ if ((ms = qobject_cast<MakeStep *>(bsl->at(i))) != nullptr)
return ms;
return nullptr;
}
@@ -646,7 +646,7 @@ QString QmakeBuildConfiguration::extractSpecFromArguments(QString *args,
bool ignoreNext = false;
bool nextIsSpec = false;
- for (QtcProcess::ArgIterator ait(args); ait.next(); ) {
+ for (ProcessArgs::ArgIterator ait(args); ait.next(); ) {
if (ignoreNext) {
ignoreNext = false;
ait.deleteArg();
@@ -725,7 +725,7 @@ static BuildInfo createBuildInfo(const Kit *k, const FilePath &projectPath,
info.displayName = BuildConfiguration::tr("Release");
//: Non-ASCII characters in directory suffix may cause build issues.
suffix = QmakeBuildConfiguration::tr("Release", "Shadow build directory suffix");
- if (settings.qtQuickCompiler == TriState::Default) {
+ if (settings.qtQuickCompiler.value() == TriState::Default) {
if (version && version->isQtQuickCompilerSupported())
extraInfo.config.useQtQuickCompiler = TriState::Enabled;
}
@@ -740,15 +740,15 @@ static BuildInfo createBuildInfo(const Kit *k, const FilePath &projectPath,
info.displayName = BuildConfiguration::tr("Profile");
//: Non-ASCII characters in directory suffix may cause build issues.
suffix = QmakeBuildConfiguration::tr("Profile", "Shadow build directory suffix");
- if (settings.separateDebugInfo == TriState::Default)
+ if (settings.separateDebugInfo.value() == TriState::Default)
extraInfo.config.separateDebugInfo = TriState::Enabled;
- if (settings.qtQuickCompiler == TriState::Default) {
+ if (settings.qtQuickCompiler.value() == TriState::Default) {
if (version && version->isQtQuickCompilerSupported())
extraInfo.config.useQtQuickCompiler = TriState::Enabled;
}
}
- if (settings.qmlDebugging == TriState::Default) {
+ if (settings.qmlDebugging.value() == TriState::Default) {
if (version && version->isQmlDebuggingSupported())
extraInfo.config.linkQmlDebuggingQQ2 = TriState::Enabled;
}
diff --git a/src/plugins/qmakeprojectmanager/qmakebuildconfiguration.h b/src/plugins/qmakeprojectmanager/qmakebuildconfiguration.h
index 4a452ee6d4..92b2bc13de 100644
--- a/src/plugins/qmakeprojectmanager/qmakebuildconfiguration.h
+++ b/src/plugins/qmakeprojectmanager/qmakebuildconfiguration.h
@@ -32,13 +32,15 @@
#include <utils/aspects.h>
-namespace ProjectExplorer { class FileNode; }
+namespace ProjectExplorer {
+class FileNode;
+class MakeStep;
+} // ProjectExplorer
namespace QmakeProjectManager {
class QMakeStep;
class QmakeBuildSystem;
-class QmakeMakeStep;
class QmakeProFileNode;
class QMAKEPROJECTMANAGER_EXPORT QmakeBuildConfiguration : public ProjectExplorer::BuildConfiguration
@@ -68,13 +70,12 @@ public:
QStringList configCommandLineArguments() const;
- // Those functions are used in a few places.
+ // This function is used in a few places.
// The drawback is that we shouldn't actually depend on them being always there
// That is generally the stuff that is asked should normally be transferred to
// QmakeProject *
// So that we can later enable people to build qmake the way they would like
QMakeStep *qmakeStep() const;
- QmakeMakeStep *makeStep() const;
QmakeBuildSystem *qmakeBuildSystem() const;
@@ -128,6 +129,8 @@ private:
void qtVersionsChanged(const QList<int> &, const QList<int> &, const QList<int> &changed);
void updateProblemLabel();
+ ProjectExplorer::MakeStep *makeStep() const;
+
class LastKitState
{
public:
diff --git a/src/plugins/qmakeprojectmanager/qmakekitinformation.cpp b/src/plugins/qmakeprojectmanager/qmakekitinformation.cpp
index 631f9ee3ee..dfd2b76a30 100644
--- a/src/plugins/qmakeprojectmanager/qmakekitinformation.cpp
+++ b/src/plugins/qmakeprojectmanager/qmakekitinformation.cpp
@@ -34,6 +34,7 @@
#include <qtsupport/qtkitinformation.h>
#include <utils/algorithm.h>
+#include <utils/layoutbuilder.h>
#include <utils/qtcassert.h>
#include <QDir>
@@ -51,7 +52,7 @@ class QmakeKitAspectWidget final : public KitAspectWidget
public:
QmakeKitAspectWidget(Kit *k, const KitAspect *ki)
- : KitAspectWidget(k, ki), m_lineEdit(new QLineEdit)
+ : KitAspectWidget(k, ki), m_lineEdit(createSubWidget<QLineEdit>())
{
refresh(); // set up everything according to kit
m_lineEdit->setToolTip(ki->description());
@@ -61,7 +62,12 @@ public:
~QmakeKitAspectWidget() override { delete m_lineEdit; }
private:
- QWidget *mainWidget() const override { return m_lineEdit; }
+ void addToLayout(LayoutBuilder &builder) override
+ {
+ addMutableAction(m_lineEdit);
+ builder.addItem(m_lineEdit);
+ }
+
void makeReadOnly() override { m_lineEdit->setEnabled(false); }
void refresh() override
diff --git a/src/plugins/qmakeprojectmanager/qmakemakestep.cpp b/src/plugins/qmakeprojectmanager/qmakemakestep.cpp
index 274e9632ea..418587b36c 100644
--- a/src/plugins/qmakeprojectmanager/qmakemakestep.cpp
+++ b/src/plugins/qmakeprojectmanager/qmakemakestep.cpp
@@ -50,10 +50,32 @@
#include <QFileInfo>
using namespace ProjectExplorer;
-using namespace QmakeProjectManager;
-using namespace QmakeProjectManager::Internal;
+using namespace Utils;
-QmakeMakeStep::QmakeMakeStep(BuildStepList *bsl, Utils::Id id)
+namespace QmakeProjectManager {
+namespace Internal {
+
+class QmakeMakeStep : public MakeStep
+{
+ Q_DECLARE_TR_FUNCTIONS(QmakeProjectManager::QmakeMakeStep)
+
+public:
+ QmakeMakeStep(BuildStepList *bsl, Id id);
+
+private:
+ void finish(bool success) override;
+ bool init() override;
+ void setupOutputFormatter(OutputFormatter *formatter) override;
+ void doRun() override;
+ QStringList displayArguments() const override;
+
+ bool m_scriptTarget = false;
+ QString m_makeFileToCheck;
+ bool m_unalignedBuildDir;
+ bool m_ignoredNonTopLevelBuild = false;
+};
+
+QmakeMakeStep::QmakeMakeStep(BuildStepList *bsl, Id id)
: MakeStep(bsl, id)
{
if (bsl->id() == ProjectExplorer::Constants::BUILDSTEPS_CLEAN) {
@@ -71,8 +93,8 @@ bool QmakeMakeStep::init()
const auto bc = static_cast<QmakeBuildConfiguration *>(buildConfiguration());
- const Utils::CommandLine unmodifiedMake = effectiveMakeCommand(Execution);
- const Utils::FilePath makeExecutable = unmodifiedMake.executable();
+ const CommandLine unmodifiedMake = effectiveMakeCommand(Execution);
+ const FilePath makeExecutable = unmodifiedMake.executable();
if (makeExecutable.isEmpty())
emit addTask(makeCommandMissingTask());
@@ -87,14 +109,14 @@ bool QmakeMakeStep::init()
ProcessParameters *pp = processParameters();
pp->setMacroExpander(bc->macroExpander());
- Utils::FilePath workingDirectory;
+ FilePath workingDirectory;
if (bc->subNodeBuild())
workingDirectory = bc->qmakeBuildSystem()->buildDir(bc->subNodeBuild()->filePath());
else
workingDirectory = bc->buildDirectory();
pp->setWorkingDirectory(workingDirectory);
- Utils::CommandLine makeCmd(makeExecutable);
+ CommandLine makeCmd(makeExecutable);
QmakeProjectManager::QmakeProFileNode *subProFile = bc->subNodeBuild();
if (subProFile) {
@@ -125,7 +147,7 @@ bool QmakeMakeStep::init()
}
}
- makeCmd.addArgs(unmodifiedMake.arguments(), Utils::CommandLine::Raw);
+ makeCmd.addArgs(unmodifiedMake.arguments(), CommandLine::Raw);
if (bc->fileNodeBuild() && subProFile) {
QString objectsDir = subProFile->objectsDirectory();
@@ -140,8 +162,8 @@ bool QmakeMakeStep::init()
}
if (subProFile->isObjectParallelToSource()) {
- const Utils::FilePath sourceFileDir = bc->fileNodeBuild()->filePath().parentDir();
- const Utils::FilePath proFileDir = subProFile->proFile()->sourceDir().canonicalPath();
+ const FilePath sourceFileDir = bc->fileNodeBuild()->filePath().parentDir();
+ const FilePath proFileDir = subProFile->proFile()->sourceDir().canonicalPath();
if (!objectsDir.endsWith('/'))
objectsDir += QLatin1Char('/');
objectsDir += sourceFileDir.relativeChildPath(proFileDir).toString();
@@ -179,22 +201,22 @@ bool QmakeMakeStep::init()
return true;
}
-void QmakeMakeStep::setupOutputFormatter(Utils::OutputFormatter *formatter)
+void QmakeMakeStep::setupOutputFormatter(OutputFormatter *formatter)
{
- formatter->addLineParser(new ProjectExplorer::GnuMakeParser());
+ formatter->addLineParser(new GnuMakeParser());
ToolChain *tc = ToolChainKitAspect::cxxToolChain(kit());
OutputTaskParser *xcodeBuildParser = nullptr;
if (tc && tc->targetAbi().os() == Abi::DarwinOS) {
xcodeBuildParser = new XcodebuildParser;
formatter->addLineParser(xcodeBuildParser);
}
- QList<Utils::OutputLineParser *> additionalParsers = kit()->createOutputParsers();
+ QList<OutputLineParser *> additionalParsers = kit()->createOutputParsers();
// make may cause qmake to be run, add last to make sure it has a low priority.
additionalParsers << new QMakeParser;
if (xcodeBuildParser) {
- for (Utils::OutputLineParser * const p : qAsConst(additionalParsers))
+ for (OutputLineParser * const p : qAsConst(additionalParsers))
p->setRedirectionDetector(xcodeBuildParser);
}
formatter->addLineParsers(additionalParsers);
@@ -250,3 +272,6 @@ QmakeMakeStepFactory::QmakeMakeStepFactory()
setSupportedProjectType(Constants::QMAKEPROJECT_ID);
setDisplayName(MakeStep::defaultDisplayName());
}
+
+} // Internal
+} // QmakeProjectManager
diff --git a/src/plugins/qmakeprojectmanager/qmakemakestep.h b/src/plugins/qmakeprojectmanager/qmakemakestep.h
index ae589ebe15..798f615022 100644
--- a/src/plugins/qmakeprojectmanager/qmakemakestep.h
+++ b/src/plugins/qmakeprojectmanager/qmakemakestep.h
@@ -38,28 +38,5 @@ public:
QmakeMakeStepFactory();
};
-} //namespace Internal
-
-class QmakeProject;
-
-class QMAKEPROJECTMANAGER_EXPORT QmakeMakeStep : public ProjectExplorer::MakeStep
-{
- Q_OBJECT
-
-public:
- QmakeMakeStep(ProjectExplorer::BuildStepList *bsl, Utils::Id id);
-
-private:
- void finish(bool success) override;
- bool init() override;
- void setupOutputFormatter(Utils::OutputFormatter *formatter) override;
- void doRun() override;
- QStringList displayArguments() const override;
-
- bool m_scriptTarget = false;
- QString m_makeFileToCheck;
- bool m_unalignedBuildDir;
- bool m_ignoredNonTopLevelBuild = false;
-};
-
+} // Internal
} // QmakeProjectManager
diff --git a/src/plugins/qmakeprojectmanager/qmakeparsernodes.cpp b/src/plugins/qmakeprojectmanager/qmakeparsernodes.cpp
index a61df84fc2..8d7866dd93 100644
--- a/src/plugins/qmakeprojectmanager/qmakeparsernodes.cpp
+++ b/src/plugins/qmakeprojectmanager/qmakeparsernodes.cpp
@@ -770,12 +770,12 @@ QPair<ProFile *, QStringList> QmakePriFile::readProFile()
QString contents;
{
QString errorMsg;
- if (TextFileFormat::readFile(
- filePath().toString(),
- Core::EditorManager::defaultTextCodec(),
- &contents,
- &m_textFormat,
- &errorMsg) != TextFileFormat::ReadSuccess) {
+ if (TextFileFormat::readFile(filePath(),
+ Core::EditorManager::defaultTextCodec(),
+ &contents,
+ &m_textFormat,
+ &errorMsg)
+ != TextFileFormat::ReadSuccess) {
QmakeBuildSystem::proFileParseError(errorMsg, filePath());
return qMakePair(includeFile, lines);
}
@@ -932,7 +932,7 @@ void QmakePriFile::save(const QStringList &lines)
QTC_ASSERT(m_textFormat.codec, return);
FileChangeBlocker changeGuard(filePath().toString());
QString errorMsg;
- if (!m_textFormat.writeFile(filePath().toString(), lines.join('\n'), &errorMsg)) {
+ if (!m_textFormat.writeFile(filePath(), lines.join('\n'), &errorMsg)) {
QMessageBox::critical(Core::ICore::dialogParent(), QCoreApplication::translate(
"QmakePriFile", "File Error"), errorMsg);
}
@@ -1140,9 +1140,9 @@ QByteArray QmakeProFile::cxxDefines() const
QByteArray result;
foreach (const QString &def, variableValue(Variable::Defines)) {
// 'def' is shell input, so interpret it.
- QtcProcess::SplitError error = QtcProcess::SplitOk;
- const QStringList args = QtcProcess::splitArgs(def, HostOsInfo::hostOs(), false, &error);
- if (error != QtcProcess::SplitOk || args.size() == 0)
+ ProcessArgs::SplitError error = ProcessArgs::SplitOk;
+ const QStringList args = ProcessArgs::splitArgs(def, HostOsInfo::hostOs(), false, &error);
+ if (error != ProcessArgs::SplitOk || args.size() == 0)
continue;
result += "#define ";
diff --git a/src/plugins/qmakeprojectmanager/qmakeprojectmanagerplugin.cpp b/src/plugins/qmakeprojectmanager/qmakeprojectmanagerplugin.cpp
index 2659b22e9e..bd62251e2d 100644
--- a/src/plugins/qmakeprojectmanager/qmakeprojectmanagerplugin.cpp
+++ b/src/plugins/qmakeprojectmanager/qmakeprojectmanagerplugin.cpp
@@ -56,6 +56,7 @@
#include <projectexplorer/session.h>
#include <projectexplorer/target.h>
#include <projectexplorer/projectexplorer.h>
+#include <projectexplorer/projectexplorericons.h>
#include <texteditor/texteditor.h>
#include <texteditor/texteditoractionhandler.h>
@@ -63,6 +64,7 @@
#include <utils/hostosinfo.h>
#include <utils/parameteraction.h>
+#include <utils/utilsicons.h>
#ifdef WITH_TESTS
# include <QTest>
@@ -118,8 +120,8 @@ public:
QAction *m_cleanSubProjectContextMenu = nullptr;
QAction *m_buildFileContextMenu = nullptr;
Utils::ParameterAction *m_buildSubProjectAction = nullptr;
- Utils::ParameterAction *m_rebuildSubProjectAction = nullptr;
- Utils::ParameterAction *m_cleanSubProjectAction = nullptr;
+ QAction *m_rebuildSubProjectAction = nullptr;
+ QAction *m_cleanSubProjectAction = nullptr;
Utils::ParameterAction *m_buildFileAction = nullptr;
QAction *m_addLibraryAction = nullptr;
QAction *m_addLibraryActionContextMenu = nullptr;
@@ -231,7 +233,7 @@ bool QmakeProjectManagerPlugin::initialize(const QStringList &arguments, QString
command->setAttribute(Command::CA_Hide);
command->setAttribute(Command::CA_UpdateText);
command->setDescription(d->m_buildSubProjectAction->text());
- mbuild->addAction(command, ProjectExplorer::Constants::G_BUILD_BUILD);
+ mbuild->addAction(command, ProjectExplorer::Constants::G_BUILD_SUBPROJECT);
connect(d->m_buildSubProjectAction, &QAction::triggered,
d, &QmakeProjectManagerPluginPrivate::buildSubDirContextMenu);
@@ -242,23 +244,22 @@ bool QmakeProjectManagerPlugin::initialize(const QStringList &arguments, QString
connect(d->m_runQMakeAction, &QAction::triggered,
d, &QmakeProjectManagerPluginPrivate::runQMake);
- d->m_rebuildSubProjectAction = new Utils::ParameterAction(tr("Rebuild Subproject"), tr("Rebuild Subproject \"%1\""),
- Utils::ParameterAction::AlwaysEnabled, this);
+ d->m_rebuildSubProjectAction = new QAction(Icons::REBUILD.icon(), tr("Rebuild"),
+ this);
command = ActionManager::registerAction(d->m_rebuildSubProjectAction, Constants::REBUILDSUBDIR, projectContext);
command->setAttribute(Command::CA_Hide);
command->setAttribute(Command::CA_UpdateText);
command->setDescription(d->m_rebuildSubProjectAction->text());
- mbuild->addAction(command, ProjectExplorer::Constants::G_BUILD_REBUILD);
+ mbuild->addAction(command, ProjectExplorer::Constants::G_BUILD_SUBPROJECT);
connect(d->m_rebuildSubProjectAction, &QAction::triggered,
d, &QmakeProjectManagerPluginPrivate::rebuildSubDirContextMenu);
- d->m_cleanSubProjectAction = new Utils::ParameterAction(tr("Clean Subproject"), tr("Clean Subproject \"%1\""),
- Utils::ParameterAction::AlwaysEnabled, this);
+ d->m_cleanSubProjectAction = new QAction(Utils::Icons::CLEAN.icon(),tr("Clean"), this);
command = ActionManager::registerAction(d->m_cleanSubProjectAction, Constants::CLEANSUBDIR, projectContext);
command->setAttribute(Command::CA_Hide);
command->setAttribute(Command::CA_UpdateText);
command->setDescription(d->m_cleanSubProjectAction->text());
- mbuild->addAction(command, ProjectExplorer::Constants::G_BUILD_CLEAN);
+ mbuild->addAction(command, ProjectExplorer::Constants::G_BUILD_SUBPROJECT);
connect(d->m_cleanSubProjectAction, &QAction::triggered,
d, &QmakeProjectManagerPluginPrivate::cleanSubDirContextMenu);
@@ -269,7 +270,7 @@ bool QmakeProjectManagerPlugin::initialize(const QStringList &arguments, QString
command->setAttribute(Command::CA_UpdateText);
command->setDescription(d->m_buildFileAction->text());
command->setDefaultKeySequence(QKeySequence(tr("Ctrl+Alt+B")));
- mbuild->addAction(command, ProjectExplorer::Constants::G_BUILD_BUILD);
+ mbuild->addAction(command, ProjectExplorer::Constants::G_BUILD_FILE);
connect(d->m_buildFileAction, &QAction::triggered,
d, &QmakeProjectManagerPluginPrivate::buildFile);
@@ -547,8 +548,6 @@ void QmakeProjectManagerPluginPrivate::updateContextActions()
subProjectName = subProjectNode->displayName();
m_buildSubProjectAction->setParameter(subProjectName);
- m_rebuildSubProjectAction->setParameter(subProjectName);
- m_cleanSubProjectAction->setParameter(subProjectName);
m_buildSubProjectContextMenu->setParameter(proFileNode ? proFileNode->displayName() : QString());
auto buildConfiguration = (qmakeProject && qmakeProject->activeTarget()) ?
diff --git a/src/plugins/qmakeprojectmanager/qmakesettings.cpp b/src/plugins/qmakeprojectmanager/qmakesettings.cpp
index cd77fcf3e2..12886c1486 100644
--- a/src/plugins/qmakeprojectmanager/qmakesettings.cpp
+++ b/src/plugins/qmakeprojectmanager/qmakesettings.cpp
@@ -26,44 +26,61 @@
#include "qmakesettings.h"
#include <coreplugin/icore.h>
+
#include <projectexplorer/projectexplorerconstants.h>
-#include <utils/hostosinfo.h>
-#include <QCheckBox>
-#include <QCoreApplication>
-#include <QVBoxLayout>
+#include <utils/layoutbuilder.h>
+
+using namespace Utils;
namespace QmakeProjectManager {
namespace Internal {
-const char BUILD_DIR_WARNING_KEY[] = "QmakeProjectManager/WarnAgainstUnalignedBuildDir";
-const char ALWAYS_RUN_QMAKE_KEY[] = "QmakeProjectManager/AlwaysRunQmake";
-const char RUN_SYSTEM_KEY[] = "QmakeProjectManager/RunSystemFunction";
-
-static bool operator==(const QmakeSettingsData &s1, const QmakeSettingsData &s2)
-{
- return s1.warnAgainstUnalignedBuildDir == s2.warnAgainstUnalignedBuildDir
- && s1.alwaysRunQmake == s2.alwaysRunQmake
- && s1.runSystemFunction == s2.runSystemFunction;
-}
-static bool operator!=(const QmakeSettingsData &s1, const QmakeSettingsData &s2)
+QmakeSettings::QmakeSettings()
{
- return !(s1 == s2);
+ setAutoApply(false);
+
+ registerAspect(&m_warnAgainstUnalignedBuildDir);
+ m_warnAgainstUnalignedBuildDir.setSettingsKey("QmakeProjectManager/WarnAgainstUnalignedBuildDir");
+ m_warnAgainstUnalignedBuildDir.setDefaultValue(HostOsInfo::isWindowsHost());
+ m_warnAgainstUnalignedBuildDir.setLabelText(tr("Warn if a project's source and "
+ "build directories are not at the same level"));
+ m_warnAgainstUnalignedBuildDir.setToolTip(tr("Qmake has subtle bugs that "
+ "can be triggered if source and build directory are not at the same level."));
+
+ registerAspect(&m_alwaysRunQmake);
+ m_alwaysRunQmake.setSettingsKey("QmakeProjectManager/AlwaysRunQmake");
+ m_alwaysRunQmake.setLabelText(tr("Run qmake on every build"));
+ m_alwaysRunQmake.setToolTip(tr("This option can help to prevent failures on "
+ "incremental builds, but might slow them down unnecessarily in the general case."));
+
+ registerAspect(&m_ignoreSystemFunction);
+ m_ignoreSystemFunction.setSettingsKey("QmakeProjectManager/RunSystemFunction");
+ m_ignoreSystemFunction.setLabelText(tr("Ignore qmake's system() function when parsing a project"));
+ m_ignoreSystemFunction.setToolTip(tr("Checking this option avoids unwanted side effects, "
+ "but may result in inexact parsing results."));
+ // The settings value has been stored with the opposite meaning for a while.
+ // Avoid changing the stored value, but flip it on read/write:
+ const auto invertBoolVariant = [](const QVariant &v) { return QVariant(!v.toBool()); };
+ m_ignoreSystemFunction.setFromSettingsTransformation(invertBoolVariant);
+ m_ignoreSystemFunction.setToSettingsTransformation(invertBoolVariant);
+
+ readSettings(Core::ICore::settings());
}
bool QmakeSettings::warnAgainstUnalignedBuildDir()
{
- return instance().m_settings.warnAgainstUnalignedBuildDir;
+ return instance().m_warnAgainstUnalignedBuildDir.value();
}
bool QmakeSettings::alwaysRunQmake()
{
- return instance().m_settings.alwaysRunQmake;
+ return instance().m_alwaysRunQmake.value();
}
bool QmakeSettings::runSystemFunction()
{
- return instance().m_settings.runSystemFunction;
+ return !instance().m_ignoreSystemFunction.value(); // Note: negated.
}
QmakeSettings &QmakeSettings::instance()
@@ -72,78 +89,31 @@ QmakeSettings &QmakeSettings::instance()
return theSettings;
}
-void QmakeSettings::setSettingsData(const QmakeSettingsData &settings)
-{
- if (instance().m_settings != settings) {
- instance().m_settings = settings;
- instance().storeSettings();
- emit instance().settingsChanged();
- }
-}
-
-QmakeSettings::QmakeSettings()
-{
- loadSettings();
-}
-
-void QmakeSettings::loadSettings()
-{
- QSettings * const s = Core::ICore::settings();
- m_settings.warnAgainstUnalignedBuildDir = s->value(
- BUILD_DIR_WARNING_KEY, Utils::HostOsInfo::isWindowsHost()).toBool();
- m_settings.alwaysRunQmake = s->value(ALWAYS_RUN_QMAKE_KEY, false).toBool();
- m_settings.runSystemFunction = s->value(RUN_SYSTEM_KEY, true).toBool();
-}
-
-void QmakeSettings::storeSettings() const
-{
- QSettings * const s = Core::ICore::settings();
- s->setValue(BUILD_DIR_WARNING_KEY, warnAgainstUnalignedBuildDir());
- s->setValue(ALWAYS_RUN_QMAKE_KEY, alwaysRunQmake());
- s->setValue(RUN_SYSTEM_KEY, runSystemFunction());
-}
-
-class QmakeSettingsPage::SettingsWidget : public QWidget
+class SettingsWidget final : public Core::IOptionsPageWidget
{
Q_DECLARE_TR_FUNCTIONS(QmakeProjectManager::Internal::QmakeSettingsPage)
+
public:
SettingsWidget()
{
- m_warnAgainstUnalignedBuildDirCheckbox.setText(tr("Warn if a project's source and "
- "build directories are not at the same level"));
- m_warnAgainstUnalignedBuildDirCheckbox.setToolTip(tr("Qmake has subtle bugs that "
- "can be triggered if source and build directory are not at the same level."));
- m_warnAgainstUnalignedBuildDirCheckbox.setChecked(
- QmakeSettings::warnAgainstUnalignedBuildDir());
- m_alwaysRunQmakeCheckbox.setText(tr("Run qmake on every build"));
- m_alwaysRunQmakeCheckbox.setToolTip(tr("This option can help to prevent failures on "
- "incremental builds, but might slow them down unnecessarily in the general case."));
- m_alwaysRunQmakeCheckbox.setChecked(QmakeSettings::alwaysRunQmake());
- m_ignoreSystemCheckbox.setText(tr("Ignore qmake's system() function "
- "when parsing a project"));
- m_ignoreSystemCheckbox.setToolTip(tr("Checking this option avoids unwanted side effects, "
- "but may result in inexact parsing results."));
- m_ignoreSystemCheckbox.setChecked(!QmakeSettings::runSystemFunction());
- const auto layout = new QVBoxLayout(this);
- layout->addWidget(&m_warnAgainstUnalignedBuildDirCheckbox);
- layout->addWidget(&m_alwaysRunQmakeCheckbox);
- layout->addWidget(&m_ignoreSystemCheckbox);
- layout->addStretch(1);
+ auto &s = QmakeSettings::instance();
+ using namespace Layouting;
+ Column {
+ s.m_warnAgainstUnalignedBuildDir,
+ s.m_alwaysRunQmake,
+ s.m_ignoreSystemFunction,
+ Stretch()
+ }.attachTo(this);
}
- void apply()
+ void apply() final
{
- QmakeSettingsData settings;
- settings.warnAgainstUnalignedBuildDir = m_warnAgainstUnalignedBuildDirCheckbox.isChecked();
- settings.alwaysRunQmake = m_alwaysRunQmakeCheckbox.isChecked();
- settings.runSystemFunction = !m_ignoreSystemCheckbox.isChecked();
- QmakeSettings::setSettingsData(settings);
+ auto &s = QmakeSettings::instance();
+ if (s.isDirty()) {
+ s.apply();
+ s.writeSettings(Core::ICore::settings());
+ }
}
-
-private:
- QCheckBox m_warnAgainstUnalignedBuildDirCheckbox;
- QCheckBox m_alwaysRunQmakeCheckbox;
- QCheckBox m_ignoreSystemCheckbox;
};
QmakeSettingsPage::QmakeSettingsPage()
@@ -151,25 +121,7 @@ QmakeSettingsPage::QmakeSettingsPage()
setId("K.QmakeProjectManager.QmakeSettings");
setDisplayName(SettingsWidget::tr("Qmake"));
setCategory(ProjectExplorer::Constants::BUILD_AND_RUN_SETTINGS_CATEGORY);
-}
-
-QWidget *QmakeSettingsPage::widget()
-{
- if (!m_widget)
- m_widget = new SettingsWidget;
- return m_widget;
-
-}
-
-void QmakeSettingsPage::apply()
-{
- if (m_widget)
- m_widget->apply();
-}
-
-void QmakeSettingsPage::finish()
-{
- delete m_widget;
+ setWidgetCreator([] { return new SettingsWidget; });
}
} // namespace Internal
diff --git a/src/plugins/qmakeprojectmanager/qmakesettings.h b/src/plugins/qmakeprojectmanager/qmakesettings.h
index b64bb5087c..6287dc5704 100644
--- a/src/plugins/qmakeprojectmanager/qmakesettings.h
+++ b/src/plugins/qmakeprojectmanager/qmakesettings.h
@@ -27,52 +27,37 @@
#include <coreplugin/dialogs/ioptionspage.h>
-#include <QObject>
-#include <QPointer>
+#include <utils/aspects.h>
namespace QmakeProjectManager {
namespace Internal {
-class QmakeSettingsData {
-public:
- bool warnAgainstUnalignedBuildDir = false;
- bool alwaysRunQmake = false;
- bool runSystemFunction = true;
-};
-
-class QmakeSettings : public QObject
+class QmakeSettings : public Utils::AspectContainer
{
Q_OBJECT
+
public:
static QmakeSettings &instance();
static bool warnAgainstUnalignedBuildDir();
static bool alwaysRunQmake();
static bool runSystemFunction();
- static void setSettingsData(const QmakeSettingsData &settings);
signals:
void settingsChanged();
private:
QmakeSettings();
- void loadSettings();
- void storeSettings() const;
+ friend class SettingsWidget;
- QmakeSettingsData m_settings;
+ Utils::BoolAspect m_warnAgainstUnalignedBuildDir;
+ Utils::BoolAspect m_alwaysRunQmake;
+ Utils::BoolAspect m_ignoreSystemFunction;
};
class QmakeSettingsPage final : public Core::IOptionsPage
{
public:
QmakeSettingsPage();
-
-private:
- QWidget *widget() override;
- void apply() override;
- void finish() override;
-
- class SettingsWidget;
- QPointer<SettingsWidget> m_widget;
};
} // namespace Internal
diff --git a/src/plugins/qmakeprojectmanager/qmakestep.cpp b/src/plugins/qmakeprojectmanager/qmakestep.cpp
index 3cd4ec54f9..e8c53d2315 100644
--- a/src/plugins/qmakeprojectmanager/qmakestep.cpp
+++ b/src/plugins/qmakeprojectmanager/qmakestep.cpp
@@ -76,7 +76,7 @@ const char QMAKE_ARGUMENTS_KEY[] = "QtProjectManager.QMakeBuildStep.QMakeArgumen
const char QMAKE_FORCED_KEY[] = "QtProjectManager.QMakeBuildStep.QMakeForced";
const char QMAKE_SELECTED_ABIS_KEY[] = "QtProjectManager.QMakeBuildStep.SelectedAbis";
-QMakeStep::QMakeStep(BuildStepList *bsl, Utils::Id id)
+QMakeStep::QMakeStep(BuildStepList *bsl, Id id)
: AbstractProcessStep(bsl, id)
{
setLowPriority();
@@ -142,7 +142,7 @@ QString QMakeStep::allArguments(const BaseQtVersion *v, ArgumentFlags flags) con
if (v->qtVersion() < QtVersionNumber(5, 0, 0))
arguments << "-r";
bool userProvidedMkspec = false;
- for (QtcProcess::ConstArgIterator ait(userArguments()); ait.next(); ) {
+ for (ProcessArgs::ConstArgIterator ait(userArguments()); ait.next(); ) {
if (ait.value() == "-spec") {
if (ait.next()) {
userProvidedMkspec = true;
@@ -159,11 +159,11 @@ QString QMakeStep::allArguments(const BaseQtVersion *v, ArgumentFlags flags) con
arguments << deducedArguments().toArguments();
- QString args = QtcProcess::joinArgs(arguments);
+ QString args = ProcessArgs::joinArgs(arguments);
// User arguments
- QtcProcess::addArgs(&args, userArguments());
- foreach (QString arg, m_extraArgs)
- QtcProcess::addArgs(&args, arg);
+ ProcessArgs::addArgs(&args, userArguments());
+ for (QString arg : qAsConst(m_extraArgs))
+ ProcessArgs::addArgs(&args, arg);
return (flags & ArgumentFlag::Expand) ? bc->macroExpander()->expand(args) : args;
}
@@ -263,7 +263,7 @@ bool QMakeStep::init()
if (!tasks.isEmpty()) {
bool canContinue = true;
- foreach (const ProjectExplorer::Task &t, tasks) {
+ for (const Task &t : qAsConst(tasks)) {
emit addTask(t);
if (t.type == Task::Error)
canContinue = false;
@@ -419,10 +419,10 @@ QString QMakeStep::makeArguments(const QString &makefile) const
{
QString args;
if (!makefile.isEmpty()) {
- Utils::QtcProcess::addArg(&args, "-f");
- Utils::QtcProcess::addArg(&args, makefile);
+ ProcessArgs::addArg(&args, "-f");
+ ProcessArgs::addArg(&args, makefile);
}
- Utils::QtcProcess::addArg(&args, "qmake_all");
+ ProcessArgs::addArg(&args, "qmake_all");
return args;
}
@@ -432,7 +432,7 @@ QString QMakeStep::effectiveQMakeCall() const
QString qmake = qtVersion ? qtVersion->qmakeCommand().toUserOutput() : QString();
if (qmake.isEmpty())
qmake = tr("<no Qt version>");
- QString make = makeCommand().toString();
+ QString make = makeCommand().toUserOutput();
if (make.isEmpty())
make = tr("<no Make step found>");
@@ -453,7 +453,7 @@ QStringList QMakeStep::parserArguments()
QStringList result = m_extraParserArgs;
BaseQtVersion *qt = QtKitAspect::qtVersion(kit());
QTC_ASSERT(qt, return QStringList());
- for (QtcProcess::ConstArgIterator ait(allArguments(qt, ArgumentFlag::Expand)); ait.next(); ) {
+ for (ProcessArgs::ConstArgIterator ait(allArguments(qt, ArgumentFlag::Expand)); ait.next(); ) {
if (ait.isSimple())
result << ait.value();
}
@@ -468,8 +468,8 @@ QString QMakeStep::userArguments() const
QString QMakeStep::mkspec() const
{
QString additionalArguments = userArguments();
- QtcProcess::addArgs(&additionalArguments, m_extraArgs);
- for (QtcProcess::ArgIterator ait(&additionalArguments); ait.next(); ) {
+ ProcessArgs::addArgs(&additionalArguments, m_extraArgs);
+ for (ProcessArgs::ArgIterator ait(&additionalArguments); ait.next(); ) {
if (ait.value() == "-spec") {
if (ait.next())
return FilePath::fromUserInput(ait.value()).toString();
@@ -511,18 +511,17 @@ bool QMakeStep::fromMap(const QVariantMap &map)
QWidget *QMakeStep::createConfigWidget()
{
- auto widget = new QWidget;
-
- abisLabel = new QLabel(tr("ABIs:"), widget);
+ abisLabel = new QLabel(tr("ABIs:"));
abisLabel->setAlignment(Qt::AlignLeading|Qt::AlignLeft|Qt::AlignTop);
- abisListWidget = new QListWidget(widget);
+ abisListWidget = new QListWidget;
- LayoutBuilder builder(widget);
+ Layouting::Form builder;
builder.addRow(m_buildType);
builder.addRow(m_userArgs);
builder.addRow(m_effectiveCall);
builder.addRow({abisLabel, abisListWidget});
+ auto widget = builder.emerge(false);
qmakeBuildConfigChanged();
@@ -750,39 +749,36 @@ QMakeStepFactory::QMakeStepFactory()
QMakeStepConfig::TargetArchConfig QMakeStepConfig::targetArchFor(const Abi &targetAbi, const BaseQtVersion *version)
{
- QMakeStepConfig::TargetArchConfig arch = QMakeStepConfig::NoArch;
+ TargetArchConfig arch = NoArch;
if (!version || version->type() != QtSupport::Constants::DESKTOPQT)
return arch;
- if ((targetAbi.os() == ProjectExplorer::Abi::DarwinOS)
- && (targetAbi.binaryFormat() == ProjectExplorer::Abi::MachOFormat)) {
- if (targetAbi.architecture() == ProjectExplorer::Abi::X86Architecture) {
+ if (targetAbi.os() == Abi::DarwinOS && targetAbi.binaryFormat() == Abi::MachOFormat) {
+ if (targetAbi.architecture() == Abi::X86Architecture) {
if (targetAbi.wordWidth() == 32)
- arch = QMakeStepConfig::X86;
+ arch = X86;
else if (targetAbi.wordWidth() == 64)
- arch = QMakeStepConfig::X86_64;
- } else if (targetAbi.architecture() == ProjectExplorer::Abi::PowerPCArchitecture) {
+ arch = X86_64;
+ } else if (targetAbi.architecture() == Abi::PowerPCArchitecture) {
if (targetAbi.wordWidth() == 32)
- arch = QMakeStepConfig::PowerPC;
+ arch = PowerPC;
else if (targetAbi.wordWidth() == 64)
- arch = QMakeStepConfig::PowerPC64;
+ arch = PowerPC64;
}
}
return arch;
}
-QMakeStepConfig::OsType QMakeStepConfig::osTypeFor(const ProjectExplorer::Abi &targetAbi, const BaseQtVersion *version)
+QMakeStepConfig::OsType QMakeStepConfig::osTypeFor(const Abi &targetAbi, const BaseQtVersion *version)
{
- QMakeStepConfig::OsType os = QMakeStepConfig::NoOsType;
+ OsType os = NoOsType;
const char IOSQT[] = "Qt4ProjectManager.QtVersion.Ios";
if (!version || version->type() != IOSQT)
return os;
- if ((targetAbi.os() == ProjectExplorer::Abi::DarwinOS)
- && (targetAbi.binaryFormat() == ProjectExplorer::Abi::MachOFormat)) {
- if (targetAbi.architecture() == ProjectExplorer::Abi::X86Architecture) {
- os = QMakeStepConfig::IphoneSimulator;
- } else if (targetAbi.architecture() == ProjectExplorer::Abi::ArmArchitecture) {
- os = QMakeStepConfig::IphoneOS;
- }
+ if (targetAbi.os() == Abi::DarwinOS && targetAbi.binaryFormat() == Abi::MachOFormat) {
+ if (targetAbi.architecture() == Abi::X86Architecture)
+ os = IphoneSimulator;
+ else if (targetAbi.architecture() == Abi::ArmArchitecture)
+ os = IphoneOS;
}
return os;
}
diff --git a/src/plugins/qmakeprojectmanager/qmakestep.h b/src/plugins/qmakeprojectmanager/qmakestep.h
index 3679186297..b439108436 100644
--- a/src/plugins/qmakeprojectmanager/qmakestep.h
+++ b/src/plugins/qmakeprojectmanager/qmakestep.h
@@ -30,7 +30,7 @@
#include <projectexplorer/abstractprocessstep.h>
#include <utils/aspects.h>
-#include <utils/fileutils.h>
+#include <utils/commandline.h>
#include <memory>
diff --git a/src/plugins/qmakeprojectmanager/wizards/qtwizard.cpp b/src/plugins/qmakeprojectmanager/wizards/qtwizard.cpp
index 70a489dd07..c4d2a1373c 100644
--- a/src/plugins/qmakeprojectmanager/wizards/qtwizard.cpp
+++ b/src/plugins/qmakeprojectmanager/wizards/qtwizard.cpp
@@ -102,9 +102,7 @@ bool QtWizard::qt4ProjectPostGenerateFiles(const QWizard *w,
QString QtWizard::templateDir()
{
- QString rc = Core::ICore::resourcePath();
- rc += QLatin1String("/templates/qt4project");
- return rc;
+ return Core::ICore::resourcePath("templates/qt4project").toString();
}
bool QtWizard::lowerCaseFiles()
diff --git a/src/plugins/qmldesigner/CMakeLists.txt b/src/plugins/qmldesigner/CMakeLists.txt
index e79c69ea6c..23fc187d99 100644
--- a/src/plugins/qmldesigner/CMakeLists.txt
+++ b/src/plugins/qmldesigner/CMakeLists.txt
@@ -210,6 +210,7 @@ extend_qtc_plugin(QmlDesigner
modelnodecontextmenu.cpp modelnodecontextmenu.h
modelnodecontextmenu_helper.cpp modelnodecontextmenu_helper.h
modelnodeoperations.cpp modelnodeoperations.h
+ formatoperation.cpp formatoperation.h
navigation2d.cpp navigation2d.h
gestures.cpp gestures.h
qmldesignericonprovider.cpp qmldesignericonprovider.h
@@ -309,12 +310,10 @@ extend_qtc_plugin(QmlDesigner
assetimportupdatetreeitemdelegate.cpp assetimportupdatetreeitemdelegate.h
assetimportupdatetreemodel.cpp assetimportupdatetreemodel.h
assetimportupdatetreeview.cpp assetimportupdatetreeview.h
- customfilesystemmodel.cpp customfilesystemmodel.h
itemlibrary.qrc
itemlibraryimageprovider.cpp itemlibraryimageprovider.h
itemlibraryitem.cpp itemlibraryitem.h
itemlibrarymodel.cpp itemlibrarymodel.h
- itemlibraryresourceview.cpp itemlibraryresourceview.h
itemlibrarycategory.cpp itemlibrarycategory.h
itemlibraryitemsmodel.cpp itemlibraryitemsmodel.h
itemlibraryview.cpp itemlibraryview.h
@@ -326,6 +325,11 @@ extend_qtc_plugin(QmlDesigner
itemlibraryimport.cpp itemlibraryimport.h
itemlibrarycategoriesmodel.cpp itemlibrarycategoriesmodel.h
itemlibraryaddimportmodel.cpp itemlibraryaddimportmodel.h
+ itemlibraryassetsmodel.cpp itemlibraryassetsmodel.h
+ itemlibraryassetsiconprovider.cpp itemlibraryassetsiconprovider.h
+ itemlibraryassetsdir.cpp itemlibraryassetsdir.h
+ itemlibraryassetsdirsmodel.cpp itemlibraryassetsdirsmodel.h
+ itemlibraryassetsfilesmodel.cpp itemlibraryassetsfilesmodel.h
)
extend_qtc_plugin(QmlDesigner
diff --git a/src/plugins/qmldesigner/assetexporterplugin/assetexporter.cpp b/src/plugins/qmldesigner/assetexporterplugin/assetexporter.cpp
index 7e0cf0d084..eedf64c9d8 100644
--- a/src/plugins/qmldesigner/assetexporterplugin/assetexporter.cpp
+++ b/src/plugins/qmldesigner/assetexporterplugin/assetexporter.cpp
@@ -276,9 +276,9 @@ void AssetExporter::preprocessQmlFile(const Utils::FilePath &path)
// Meanwhile cache the Component UUIDs as well
std::unique_ptr<Model> model(Model::create("Item", 2, 7));
Utils::FileReader reader;
- if (!reader.fetch(path.toString())) {
+ if (!reader.fetch(path)) {
ExportNotification::addError(tr("Cannot preprocess file: %1. Error %2")
- .arg(path.toString()).arg(reader.errorString()));
+ .arg(path.toUserOutput()).arg(reader.errorString()));
return;
}
@@ -301,11 +301,11 @@ void AssetExporter::preprocessQmlFile(const Utils::FilePath &path)
// Some UUIDs were assigned. Rewrite the file.
rewriterView->writeAuxiliaryData();
const QByteArray data = textEdit.toPlainText().toUtf8();
- Utils::FileSaver saver(path.toString(), QIODevice::Text);
+ Utils::FileSaver saver(path, QIODevice::Text);
saver.write(data);
if (!saver.finalize()) {
ExportNotification::addError(tr("Cannot update %1.\n%2")
- .arg(path.toString()).arg(saver.errorString()));
+ .arg(path.toUserOutput()).arg(saver.errorString()));
return;
}
@@ -414,7 +414,7 @@ void AssetExporter::writeMetadata() const
return;
}
- Utils::FileSaver saver(path.toString(), QIODevice::Text);
+ Utils::FileSaver saver(path, QIODevice::Text);
saver.write(doc.toJson(QJsonDocument::Indented));
if (!saver.finalize()) {
ExportNotification::addError(tr("Writing metadata failed. %1").
diff --git a/src/plugins/qmldesigner/assetexporterplugin/assetexporterview.cpp b/src/plugins/qmldesigner/assetexporterplugin/assetexporterview.cpp
index 6e5212818d..81dc1ce486 100644
--- a/src/plugins/qmldesigner/assetexporterplugin/assetexporterview.cpp
+++ b/src/plugins/qmldesigner/assetexporterplugin/assetexporterview.cpp
@@ -62,7 +62,7 @@ bool AssetExporterView::loadQmlFile(const Utils::FilePath &path, uint timeoutSec
setState(LoadState::Busy);
m_retryCount = std::max(MinRetry, static_cast<int>((timeoutSecs * 1000) / RetryIntervalMs));
- m_currentEditor = Core::EditorManager::openEditor(path.toString(), Utils::Id(),
+ m_currentEditor = Core::EditorManager::openEditor(path, Utils::Id(),
Core::EditorManager::DoNotMakeVisible);
Core::ModeManager::activateMode(Core::Constants::MODE_DESIGN);
Core::ModeManager::setFocusToCurrentMode();
diff --git a/src/plugins/qmldesigner/assetexporterplugin/componentexporter.h b/src/plugins/qmldesigner/assetexporterplugin/componentexporter.h
index d2f6c720c8..ef4760c2bd 100644
--- a/src/plugins/qmldesigner/assetexporterplugin/componentexporter.h
+++ b/src/plugins/qmldesigner/assetexporterplugin/componentexporter.h
@@ -50,7 +50,7 @@ public:
virtual ~NodeDumperCreatorBase() {}
protected:
virtual NodeDumper *instance(const QByteArrayList &, const ModelNode &) const = 0;
- friend class QmlDesigner::Component;
+ friend Component;
};
template<class T>
diff --git a/src/plugins/qmldesigner/components/componentcore/changestyleaction.cpp b/src/plugins/qmldesigner/components/componentcore/changestyleaction.cpp
index 0b73a1f39d..f98a32b969 100644
--- a/src/plugins/qmldesigner/components/componentcore/changestyleaction.cpp
+++ b/src/plugins/qmldesigner/components/componentcore/changestyleaction.cpp
@@ -98,11 +98,7 @@ QWidget *ChangeStyleWidgetAction::createWidget(QWidget *parent)
});
connect(comboBox,
- #if QT_VERSION < QT_VERSION_CHECK(5, 14, 0)
- QOverload<const QString &>::of(&QComboBox::activated),
- #else
&QComboBox::textActivated,
- #endif
this,
[this](const QString &style) {
diff --git a/src/plugins/qmldesigner/components/componentcore/componentcore.pri b/src/plugins/qmldesigner/components/componentcore/componentcore.pri
index 174ed0341a..a64f61ab46 100644
--- a/src/plugins/qmldesigner/components/componentcore/componentcore.pri
+++ b/src/plugins/qmldesigner/components/componentcore/componentcore.pri
@@ -15,6 +15,7 @@ SOURCES += modelnodecontextmenu_helper.cpp
SOURCES += selectioncontext.cpp
SOURCES += designeractionmanager.cpp
SOURCES += modelnodeoperations.cpp
+SOURCES += formatoperation.cpp
SOURCES += navigation2d.cpp
SOURCES += crumblebar.cpp
SOURCES += qmldesignericonprovider.cpp
@@ -37,6 +38,7 @@ HEADERS += selectioncontext.h
HEADERS += componentcore_constants.h
HEADERS += designeractionmanager.h
HEADERS += modelnodeoperations.h
+HEADERS += formatoperation.h
HEADERS += navigation2d.h
HEADERS += actioninterface.h
HEADERS += crumblebar.h
diff --git a/src/plugins/qmldesigner/components/componentcore/componentcore_constants.h b/src/plugins/qmldesigner/components/componentcore/componentcore_constants.h
index 69e4e39b55..9024b32776 100644
--- a/src/plugins/qmldesigner/components/componentcore/componentcore_constants.h
+++ b/src/plugins/qmldesigner/components/componentcore/componentcore_constants.h
@@ -55,6 +55,8 @@ const char resetZCommandId[] = "ResetZ";
const char reverseCommandId[] = "Reverse";
const char resetSizeCommandId[] = "ResetSize";
const char resetPositionCommandId[] = "ResetPosition";
+const char copyFormatCommandId[] = "CopyFormat";
+const char applyFormatCommandId[] = "ApplyFormat";
const char visiblityCommandId[] = "ToggleVisiblity";
const char anchorsFillCommandId[] = "AnchorsFill";
const char anchorsResetCommandId[] = "AnchorsReset";
@@ -123,6 +125,8 @@ const char visibilityDisplayName[] = QT_TRANSLATE_NOOP("QmlDesignerContextMenu",
const char resetSizeDisplayName[] = QT_TRANSLATE_NOOP("QmlDesignerContextMenu", "Reset Size");
const char resetPositionDisplayName[] = QT_TRANSLATE_NOOP("QmlDesignerContextMenu", "Reset Position");
+const char copyFormatDisplayName[] = QT_TRANSLATE_NOOP("QmlDesignerContextMenu", "Copy Formatting");
+const char applyFormatDisplayName[] = QT_TRANSLATE_NOOP("QmlDesignerContextMenu", "Apply Formatting");
const char goIntoComponentDisplayName[] = QT_TRANSLATE_NOOP("QmlDesignerContextMenu", "Go into Component");
const char mergeTemplateDisplayName[] = QT_TRANSLATE_NOOP("QmlDesignerContextMenu", "Merge File With Template");
@@ -176,6 +180,8 @@ const char lowerToolTip[] = QT_TRANSLATE_NOOP("QmlDesignerContextMenu", "Lower s
const char resetSizeToolTip[] = QT_TRANSLATE_NOOP("QmlDesignerContextMenu", "Reset size and use implicit size.");
const char resetPositionTooltip[] = QT_TRANSLATE_NOOP("QmlDesignerContextMenu", "Reset position and use implicit position.");
+const char copyFormatTooltip[] = QT_TRANSLATE_NOOP("QmlDesignerContextMenu", "Copy formatting.");
+const char applyFormatTooltip[] = QT_TRANSLATE_NOOP("QmlDesignerContextMenu", "Apply formatting.");
const char anchorsFillToolTip[] = QT_TRANSLATE_NOOP("QmlDesignerContextMenu", "Fill selected component to parent.");
const char anchorsResetToolTip[] = QT_TRANSLATE_NOOP("QmlDesignerContextMenu", "Reset anchors for selected component.");
diff --git a/src/plugins/qmldesigner/components/componentcore/crumblebar.cpp b/src/plugins/qmldesigner/components/componentcore/crumblebar.cpp
index 33f44af9dc..c729fd0751 100644
--- a/src/plugins/qmldesigner/components/componentcore/crumblebar.cpp
+++ b/src/plugins/qmldesigner/components/componentcore/crumblebar.cpp
@@ -178,7 +178,7 @@ void CrumbleBar::onCrumblePathElementClicked(const QVariant &data)
} else {
crumblePath()->popElement();
nextFileIsCalledInternally();
- Core::EditorManager::openEditor(clickedCrumbleBarInfo.fileName.toString(),
+ Core::EditorManager::openEditor(clickedCrumbleBarInfo.fileName,
Utils::Id(),
Core::EditorManager::DoNotMakeVisible);
if (clickedCrumbleBarInfo.modelNode.isValid()) {
diff --git a/src/plugins/qmldesigner/components/componentcore/designeractionmanager.cpp b/src/plugins/qmldesigner/components/componentcore/designeractionmanager.cpp
index 808882220e..dbfa2f82d0 100644
--- a/src/plugins/qmldesigner/components/componentcore/designeractionmanager.cpp
+++ b/src/plugins/qmldesigner/components/componentcore/designeractionmanager.cpp
@@ -28,6 +28,7 @@
#include "changestyleaction.h"
#include "designeractionmanagerview.h"
#include "modelnodecontextmenu_helper.h"
+#include "formatoperation.h"
#include "qmldesignerconstants.h"
#include "rewritingexception.h"
#include <bindingproperty.h>
@@ -909,11 +910,13 @@ bool anchorsMenuEnabled(const SelectionContext &context)
|| singleSelectionItemIsAnchored(context);
}
+
void DesignerActionManager::createDefaultDesignerActions()
{
using namespace SelectionContextFunctors;
using namespace ComponentCoreConstants;
using namespace ModelNodeOperations;
+ using namespace FormatOperation;
const Utils::Icon prevIcon({
{QLatin1String(":/utils/images/prev.png"), Utils::Theme::QmlDesigner_FormEditorForegroundColor}}, Utils::Icon::MenuTintedStyle);
@@ -1002,6 +1005,29 @@ void DesignerActionManager::createDefaultDesignerActions()
&selectionNotEmptyAndHasXorYProperty));
addDesignerAction(new ModelNodeAction(
+ copyFormatCommandId,
+ copyFormatDisplayName,
+ Utils::Icon({{":/qmldesigner/icon/designeractions/images/raise.png", Utils::Theme::IconsBaseColor}}).icon(),
+ copyFormatTooltip,
+ editCategory,
+ QKeySequence(),
+ 120,
+ &copyFormat,
+ &propertiesCopyable));
+
+ addDesignerAction(new ModelNodeAction(
+ applyFormatCommandId,
+ applyFormatDisplayName,
+ Utils::Icon({{":/qmldesigner/icon/designeractions/images/lower.png", Utils::Theme::IconsBaseColor}}).icon(),
+ applyFormatTooltip,
+ editCategory,
+ QKeySequence(),
+ 120,
+ &applyFormat,
+ &propertiesApplyable));
+
+
+ addDesignerAction(new ModelNodeAction(
resetSizeCommandId,
resetSizeDisplayName,
Utils::Icon({{":/utils/images/fittoview.png", Utils::Theme::IconsBaseColor},
diff --git a/src/plugins/qmldesigner/components/componentcore/designeractionmanagerview.cpp b/src/plugins/qmldesigner/components/componentcore/designeractionmanagerview.cpp
index 8a6c06fcdc..026596b876 100644
--- a/src/plugins/qmldesigner/components/componentcore/designeractionmanagerview.cpp
+++ b/src/plugins/qmldesigner/components/componentcore/designeractionmanagerview.cpp
@@ -112,7 +112,7 @@ void DesignerActionManagerView::selectedNodesChanged(const QList<ModelNode> &sel
emit selectionChanged(!selectedNodes.isEmpty(), singleSelectedModelNode().isRootNode());
}
-void DesignerActionManagerView::nodeOrderChanged(const NodeListProperty &, const ModelNode &, int)
+void DesignerActionManagerView::nodeOrderChanged(const NodeListProperty &)
{
setupContext(SelectionContext::UpdateMode::NodeHierachy);
}
diff --git a/src/plugins/qmldesigner/components/componentcore/designeractionmanagerview.h b/src/plugins/qmldesigner/components/componentcore/designeractionmanagerview.h
index a7a34271ea..f7777bcac1 100644
--- a/src/plugins/qmldesigner/components/componentcore/designeractionmanagerview.h
+++ b/src/plugins/qmldesigner/components/componentcore/designeractionmanagerview.h
@@ -58,7 +58,7 @@ public:
void currentStateChanged(const ModelNode &) override;
void selectedNodesChanged(const QList<ModelNode> &,
const QList<ModelNode> &) override;
- void nodeOrderChanged(const NodeListProperty &, const ModelNode &, int ) override;
+ void nodeOrderChanged(const NodeListProperty &) override;
void importsChanged(const QList<Import> &, const QList<Import> &) override;
void signalHandlerPropertiesChanged(const QVector<SignalHandlerProperty> &/*propertyList*/, PropertyChangeFlags /*propertyChange*/) override;
void variantPropertiesChanged(const QList<VariantProperty>& propertyList, PropertyChangeFlags propertyChangeFlag) override;
diff --git a/src/plugins/qmldesigner/components/componentcore/formatoperation.cpp b/src/plugins/qmldesigner/components/componentcore/formatoperation.cpp
new file mode 100644
index 0000000000..cfa3bf4f9e
--- /dev/null
+++ b/src/plugins/qmldesigner/components/componentcore/formatoperation.cpp
@@ -0,0 +1,212 @@
+/****************************************************************************
+**
+** 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 "formatoperation.h"
+#include "utils/fileutils.h"
+
+#include <coreplugin/icore.h>
+#include <qmlobjectnode.h>
+#include <nodemetainfo.h>
+#include <QJsonDocument>
+#include <QJsonObject>
+#include <QJsonArray>
+
+namespace QmlDesigner {
+namespace FormatOperation{
+
+void readFormatConfiguration(){
+
+ if (copyableProperties.isEmpty()){
+ QString source = "formatconfiguration.json";
+ Utils::FilePath path = Core::ICore::resourcePath() + "/qmldesigner/" + source;
+ QString errorString;
+ Utils::FileReader reader;
+
+ if (reader.fetch(path, &errorString)){
+ QJsonParseError jsonError;
+ QJsonDocument document = QJsonDocument::fromJson(reader.data(), &jsonError );
+
+ if (jsonError.error != QJsonParseError::NoError)
+ return;
+
+ QJsonObject jsonObject = document.object();
+ QVariantMap rootMap = jsonObject.toVariantMap();
+ QJsonArray jsonArray = rootMap["propertylist"].toJsonArray();
+
+ for (int i=0; i< jsonArray.count(); ++i){
+ auto item = jsonArray.at(i).toObject();
+ QVariantMap itemMap = item.toVariantMap();
+ StylePropertyStruct current;
+ current.id = itemMap["id"].toString();
+ QVariantList subclassVariantList = itemMap["subclasses"].toList();
+ QStringList subclassList;
+
+ for (auto subclass : subclassVariantList)
+ subclassList.append(subclass.toString());
+
+ current.subclasses = subclassList;
+
+ QVariantList propertyList = itemMap["properties"].toList();
+ QStringList propertyStringList;
+
+ for (auto property : propertyList)
+ propertyStringList.append(property.toString());
+
+ current.properties = propertyStringList;
+ copyableProperties.append(current);
+ }
+ }
+ }
+}
+
+bool propertiesCopyable(const SelectionContext &selectionState)
+{
+ if (!selectionState.singleNodeIsSelected())
+ return false;
+
+ readFormatConfiguration();
+
+ ModelNode modelNode = selectionState.currentSingleSelectedNode();
+
+ for (StylePropertyStruct copyable : copyableProperties)
+ for (QString copyableSubclass : copyable.subclasses)
+ if (modelNode.metaInfo().isSubclassOf(copyableSubclass.toUtf8()))
+ return true;
+
+ return false;
+}
+
+bool propertiesApplyable(const SelectionContext &selectionState)
+{
+ if (selectionState.selectedModelNodes().isEmpty())
+ return false;
+
+ if (chosenItem.subclasses.isEmpty())
+ return false;
+
+ const ModelNode firstSelectedNode = selectionState.firstSelectedModelNode();
+ bool found = false;
+
+ for (QString copyableSubclass : chosenItem.subclasses){
+ if (firstSelectedNode.metaInfo().isSubclassOf(copyableSubclass.toUtf8())){
+ found = true;
+ break;
+ }
+ }
+
+ if (!found)
+ return false;
+
+ for (const ModelNode &modelNode : selectionState.selectedModelNodes()){
+ found = false;
+
+ for (QString subclass : chosenItem.subclasses)
+ if (modelNode.metaInfo().isSubclassOf(subclass.toUtf8())){
+ found = true;
+ break;
+ }
+
+ if (found)
+ continue;
+
+ return false;
+ }
+
+ return true;
+}
+
+void copyFormat(const SelectionContext &selectionState)
+{
+ if (!selectionState.view())
+ return;
+
+ selectionState.view()->executeInTransaction("DesignerActionManager|copyFormat",[selectionState](){
+
+ applyableProperties.clear();
+
+ ModelNode node = selectionState.currentSingleSelectedNode();
+ QStringList propertyList;
+ for (StylePropertyStruct copyable : copyableProperties){
+ bool found = false;
+ for (QString copyableSubclass : copyable.subclasses)
+ if (node.metaInfo().isSubclassOf(copyableSubclass.toUtf8())){
+ propertyList = copyable.properties;
+ chosenItem = copyable;
+ found = true;
+ break;
+ }
+ if (found)
+ break;
+ }
+
+ QmlObjectNode qmlObjectNode(node);
+
+ for (auto propertyName : propertyList){
+ if (qmlObjectNode.propertyAffectedByCurrentState(propertyName.toUtf8())) {
+ StyleProperties property;
+ property.propertyName = propertyName.toUtf8();
+ property.value = qmlObjectNode.modelValue(propertyName.toUtf8());
+ applyableProperties.append(property);
+ }
+ }
+ });
+}
+
+void applyFormat(const SelectionContext &selectionState)
+{
+ if (!selectionState.view())
+ return;
+
+ selectionState.view()->executeInTransaction("DesignerActionManager|applyFormat",[selectionState](){
+
+ for (ModelNode node : selectionState.selectedModelNodes()) {
+ QmlObjectNode qmlObjectNode(node);
+ QStringList propertyList;
+
+ for (StylePropertyStruct copyable : copyableProperties){
+ bool found = false;
+ for (QString copyableSubclass : copyable.subclasses)
+ if (node.metaInfo().isSubclassOf(copyableSubclass.toUtf8())){
+ propertyList = copyable.properties;
+ found = true;
+ break;
+ }
+ if (found)
+ break;
+ }
+
+ for (auto propertyName : propertyList)
+ if (qmlObjectNode.propertyAffectedByCurrentState(propertyName.toUtf8()))
+ qmlObjectNode.removeProperty(propertyName.toUtf8());
+
+ for (StyleProperties currentProperty : applyableProperties)
+ if (node.metaInfo().hasProperty((currentProperty.propertyName)))
+ qmlObjectNode.setVariantProperty(currentProperty.propertyName, currentProperty.value);
+ }
+ });
+}
+
+} // namespace FormatOperation
+} // QmlDesigner
diff --git a/src/plugins/perforce/settingspage.h b/src/plugins/qmldesigner/components/componentcore/formatoperation.h
index a718c43ea6..c4aa94476b 100644
--- a/src/plugins/perforce/settingspage.h
+++ b/src/plugins/qmldesigner/components/componentcore/formatoperation.h
@@ -25,20 +25,33 @@
#pragma once
-#include <coreplugin/dialogs/ioptionspage.h>
+#include "selectioncontext.h"
-#include "ui_settingspage.h"
+namespace QmlDesigner {
+namespace FormatOperation {
-namespace Perforce {
-namespace Internal {
-
-class PerforceSettings;
+struct StylePropertyStruct
+{
+QString id;
+QStringList subclasses;
+QStringList properties;
+};
-class SettingsPage final : public Core::IOptionsPage
+struct StyleProperties
{
-public:
- SettingsPage(PerforceSettings *settings, const std::function<void()> &onApply);
+ QmlDesigner::PropertyName propertyName;
+ QVariant value;
};
-} // namespace Internal
-} // namespace Perforce
+static QList<StylePropertyStruct> copyableProperties = {};
+static QList<StyleProperties> applyableProperties = {};
+static StylePropertyStruct chosenItem = {};
+
+bool propertiesCopyable(const SelectionContext &selectionState);
+bool propertiesApplyable(const SelectionContext &selectionState);
+void copyFormat(const SelectionContext &selectionState);
+void applyFormat(const SelectionContext &selectionState);
+void readFormatConfiguration();
+
+} // namespace FormatOperation
+} // QmlDesigner
diff --git a/src/plugins/qmldesigner/components/componentcore/modelnodeoperations.cpp b/src/plugins/qmldesigner/components/componentcore/modelnodeoperations.cpp
index 3acfa1fce4..34c519e1bb 100644
--- a/src/plugins/qmldesigner/components/componentcore/modelnodeoperations.cpp
+++ b/src/plugins/qmldesigner/components/componentcore/modelnodeoperations.cpp
@@ -1458,7 +1458,7 @@ void styleMerge(const SelectionContext &selectionContext, const QString &templat
QPlainTextEdit textEditTemplate;
Utils::FileReader reader;
- QTC_ASSERT(reader.fetch(templateFile), return);
+ QTC_ASSERT(reader.fetch(Utils::FilePath::fromString(templateFile)), return);
QString qmlTemplateString = QString::fromUtf8(reader.data());
QString imports;
diff --git a/src/plugins/qmldesigner/components/componentcore/qmldesignericonprovider.cpp b/src/plugins/qmldesigner/components/componentcore/qmldesignericonprovider.cpp
index a1ca4a42dc..cbc19b4362 100644
--- a/src/plugins/qmldesigner/components/componentcore/qmldesignericonprovider.cpp
+++ b/src/plugins/qmldesigner/components/componentcore/qmldesignericonprovider.cpp
@@ -42,9 +42,10 @@ QmlDesignerIconProvider::QmlDesignerIconProvider()
}
-static QString iconPath()
+static Utils::FilePath iconPath()
{
- return Core::ICore::resourcePath() + QLatin1String("/qmldesigner/propertyEditorQmlSources/imports/HelperWidgets/images/");
+ return Core::ICore::resourcePath(
+ "qmldesigner/propertyEditorQmlSources/imports/HelperWidgets/images/");
}
QPixmap QmlDesignerIconProvider::requestPixmap(const QString &id, QSize *size, const QSize &requestedSize)
@@ -69,18 +70,15 @@ QPixmap QmlDesignerIconProvider::getPixmap(const QString &id)
else if (id == "plus")
result = Utils::Icons::PLUS_TOOLBAR.pixmap();
else if (id == "expression")
- result = Icon({
- { iconPath() + QLatin1String("expression.png"), Theme::QmlDesigner_HighlightColor}}).pixmap();
+ result = Icon({{iconPath() / "expression.png", Theme::QmlDesigner_HighlightColor}}).pixmap();
else if (id == "placeholder")
- result = Icon(iconPath() + "placeholder.png").pixmap();
+ result = Icon(iconPath() / "placeholder.png").pixmap();
else if (id == "submenu")
- result = Icon(iconPath() + "submenu.png").pixmap();
+ result = Icon(iconPath() / "submenu.png").pixmap();
else if (id == "up-arrow")
- result = Icon({
- { iconPath() + QLatin1String("up-arrow.png"), Theme::IconsBaseColor}}, Icon::Tint).pixmap();
+ result = Icon({{iconPath() / "up-arrow.png", Theme::IconsBaseColor}}, Icon::Tint).pixmap();
else if (id == "down-arrow")
- result = Icon({
- { iconPath() + QLatin1String("down-arrow.png"), Theme::IconsBaseColor}}, Icon::Tint).pixmap();
+ result = Icon({{iconPath() / "down-arrow.png", Theme::IconsBaseColor}}, Icon::Tint).pixmap();
else if (id == "checkbox-indicator")
result = Icon({
{ ":/qmldesigner/images/checkbox_indicator.png", Theme::IconsBaseColor}}, Icon::Tint).pixmap();
diff --git a/src/plugins/qmldesigner/components/componentcore/theme.cpp b/src/plugins/qmldesigner/components/componentcore/theme.cpp
index 2c31414db3..cb5cdb218e 100644
--- a/src/plugins/qmldesigner/components/componentcore/theme.cpp
+++ b/src/plugins/qmldesigner/components/componentcore/theme.cpp
@@ -49,8 +49,10 @@ Theme::Theme(Utils::Theme *originTheme, QObject *parent)
: Utils::Theme(originTheme, parent)
, m_constants(nullptr)
{
- QString constantsPath = Core::ICore::resourcePath() +
- QStringLiteral("/qmldesigner/propertyEditorQmlSources/imports/StudioTheme/InternalConstants.qml");
+ QString constantsPath
+ = Core::ICore::resourcePath(
+ "qmldesigner/propertyEditorQmlSources/imports/StudioTheme/InternalConstants.qml")
+ .toString();
QQmlEngine* engine = new QQmlEngine(this);
QQmlComponent component(engine, QUrl::fromLocalFile(constantsPath));
diff --git a/src/plugins/qmldesigner/components/componentcore/theme.h b/src/plugins/qmldesigner/components/componentcore/theme.h
index e2d26720ad..3d7ed9cd32 100644
--- a/src/plugins/qmldesigner/components/componentcore/theme.h
+++ b/src/plugins/qmldesigner/components/componentcore/theme.h
@@ -54,8 +54,8 @@ public:
adsClose,
adsDetach,
adsDropDown,
+ alias,
aliasAnimated,
- aliasProperty,
alignBottom,
alignCenterHorizontal,
alignCenterVertical,
@@ -73,9 +73,15 @@ public:
annotationBubble,
annotationDecal,
assign,
+ bevelAll,
+ bevelCorner,
centerHorizontal,
centerVertical,
closeCross,
+ copyStyle,
+ cornerA,
+ cornerB,
+ cornersAll,
curveDesigner,
curveEditor,
decisionNode,
@@ -96,22 +102,32 @@ public:
distributeSpacingVertical,
distributeTop,
edit,
+ eyeDropper,
flowAction,
flowTransition,
fontStyleBold,
fontStyleItalic,
fontStyleStrikethrough,
fontStyleUnderline,
+ gradient,
gridView,
idAliasOff,
idAliasOn,
+ keyframe,
+ linkTriangle,
+ linked,
listView,
lockOff,
lockOn,
mergeCells,
minus,
+ mirror,
+ paddingEdge,
+ paddingFrame,
+ pasteStyle,
pin,
plus,
+ promote,
redo,
rotationFill,
rotationOutline,
@@ -130,7 +146,9 @@ public:
textFullJustification,
textNumberedList,
tickIcon,
+ transparent,
triState,
+ unLinked,
undo,
unpin,
upDownIcon,
diff --git a/src/plugins/qmldesigner/components/curveeditor/detail/graphicsview.cpp b/src/plugins/qmldesigner/components/curveeditor/detail/graphicsview.cpp
index 8ed0653a11..092fd42358 100644
--- a/src/plugins/qmldesigner/components/curveeditor/detail/graphicsview.cpp
+++ b/src/plugins/qmldesigner/components/curveeditor/detail/graphicsview.cpp
@@ -88,8 +88,8 @@ GraphicsView::GraphicsView(CurveEditorModel *model, QWidget *parent)
applyZoom(m_zoomX, m_zoomY);
update();
- const QString css = Theme::replaceCssColors(QString::fromUtf8(
- Utils::FileReader::fetchQrc(QLatin1String(":/qmldesigner/scrollbar.css"))));
+ const QString css = Theme::replaceCssColors(
+ QString::fromUtf8(Utils::FileReader::fetchQrc(":/qmldesigner/scrollbar.css")));
horizontalScrollBar()->setStyleSheet(css);
verticalScrollBar()->setStyleSheet(css);
}
diff --git a/src/plugins/qmldesigner/components/curveeditor/detail/graphicsview.h b/src/plugins/qmldesigner/components/curveeditor/detail/graphicsview.h
index c2d2b0c714..22b474d1bb 100644
--- a/src/plugins/qmldesigner/components/curveeditor/detail/graphicsview.h
+++ b/src/plugins/qmldesigner/components/curveeditor/detail/graphicsview.h
@@ -44,7 +44,7 @@ class GraphicsView : public QGraphicsView
{
Q_OBJECT
- friend class Playhead;
+ friend Playhead;
signals:
void currentFrameChanged(int frame, bool notify);
diff --git a/src/plugins/qmldesigner/components/debugview/debugview.cpp b/src/plugins/qmldesigner/components/debugview/debugview.cpp
index c4dd86c44e..a8b0b34f10 100644
--- a/src/plugins/qmldesigner/components/debugview/debugview.cpp
+++ b/src/plugins/qmldesigner/components/debugview/debugview.cpp
@@ -513,16 +513,13 @@ void DebugView::currentStateChanged(const ModelNode &/*node*/)
}
-void DebugView::nodeOrderChanged(const NodeListProperty &listProperty, const ModelNode &movedNode, int oldIndex)
+void DebugView::nodeOrderChanged(const NodeListProperty &listProperty)
{
if (isDebugViewEnabled()) {
QTextStream message;
QString string;
message.setString(&string);
- message << movedNode << listProperty;
- message << oldIndex << "to" << listProperty.indexOf(movedNode);
-
log("::nodeSlide:", string);
}
}
diff --git a/src/plugins/qmldesigner/components/debugview/debugview.h b/src/plugins/qmldesigner/components/debugview/debugview.h
index ba6e053786..3e986917e1 100644
--- a/src/plugins/qmldesigner/components/debugview/debugview.h
+++ b/src/plugins/qmldesigner/components/debugview/debugview.h
@@ -88,7 +88,7 @@ public:
void nodeAboutToBeReparented(const ModelNode &node, const NodeAbstractProperty &newPropertyParent, const NodeAbstractProperty &oldPropertyParent, PropertyChangeFlags propertyChange) override;
void instancesToken(const QString &tokenName, int tokenNumber, const QVector<ModelNode> &nodeVector) override;
void currentStateChanged(const ModelNode &node) override;
- void nodeOrderChanged(const NodeListProperty &listProperty, const ModelNode &movedNode, int oldIndex) override;
+ void nodeOrderChanged(const NodeListProperty &listProperty) override;
protected:
void log(const QString &title, const QString &message, bool highlight = false);
diff --git a/src/plugins/qmldesigner/components/formeditor/abstractformeditortool.h b/src/plugins/qmldesigner/components/formeditor/abstractformeditortool.h
index 02cbc5a289..c1fe3c34d5 100644
--- a/src/plugins/qmldesigner/components/formeditor/abstractformeditortool.h
+++ b/src/plugins/qmldesigner/components/formeditor/abstractformeditortool.h
@@ -40,7 +40,8 @@ class FormEditorView;
class QMLDESIGNERCORE_EXPORT AbstractFormEditorTool
{
- friend class FormEditorView;
+ friend FormEditorView;
+
public:
AbstractFormEditorTool(FormEditorView* view);
diff --git a/src/plugins/qmldesigner/components/formeditor/formeditoritem.h b/src/plugins/qmldesigner/components/formeditor/formeditoritem.h
index 8304f1a36b..769488aa4a 100644
--- a/src/plugins/qmldesigner/components/formeditor/formeditoritem.h
+++ b/src/plugins/qmldesigner/components/formeditor/formeditoritem.h
@@ -49,7 +49,8 @@ namespace Internal {
class QMLDESIGNERCORE_EXPORT FormEditorItem : public QGraphicsItem
{
- friend class QmlDesigner::FormEditorScene;
+ friend FormEditorScene;
+
public:
~FormEditorItem() override;
@@ -156,7 +157,8 @@ private: // variables
class FormEditorFlowItem : public FormEditorItem
{
- friend class QmlDesigner::FormEditorScene;
+ friend FormEditorScene;
+
public:
void synchronizeOtherProperty(const QByteArray &propertyName) override;
void setDataModelPosition(const QPointF &position) override;
@@ -175,7 +177,8 @@ private:
class FormEditorFlowActionItem : public FormEditorItem
{
- friend class QmlDesigner::FormEditorScene;
+ friend FormEditorScene;
+
public:
void setDataModelPosition(const QPointF &position) override;
void setDataModelPositionInBaseState(const QPointF &position) override;
@@ -194,7 +197,8 @@ private:
class FormEditorTransitionItem : public FormEditorItem
{
- friend class QmlDesigner::FormEditorScene;
+ friend FormEditorScene;
+
public:
void synchronizeOtherProperty(const QByteArray &propertyName) override;
void setDataModelPosition(const QPointF &position) override;
@@ -220,7 +224,7 @@ private:
class FormEditorFlowDecisionItem : FormEditorFlowItem
{
- friend class QmlDesigner::FormEditorScene;
+ friend FormEditorScene;
public:
void updateGeometry() override;
@@ -243,7 +247,7 @@ protected:
class FormEditorFlowWildcardItem : FormEditorFlowDecisionItem
{
- friend class QmlDesigner::FormEditorScene;
+ friend FormEditorScene;
public:
void paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget = nullptr) override;
diff --git a/src/plugins/qmldesigner/components/formeditor/formeditorscene.h b/src/plugins/qmldesigner/components/formeditor/formeditorscene.h
index 6ac22f47f4..070d587776 100644
--- a/src/plugins/qmldesigner/components/formeditor/formeditorscene.h
+++ b/src/plugins/qmldesigner/components/formeditor/formeditorscene.h
@@ -47,8 +47,8 @@ class QMLDESIGNERCORE_EXPORT FormEditorScene : public QGraphicsScene
{
Q_OBJECT
- friend class QmlDesigner::FormEditorItem;
- friend class QmlDesigner::FormEditorView;
+ friend FormEditorItem;
+ friend FormEditorView;
public:
diff --git a/src/plugins/qmldesigner/components/formeditor/resizecontroller.h b/src/plugins/qmldesigner/components/formeditor/resizecontroller.h
index 334ce19c0c..c7846fd7c8 100644
--- a/src/plugins/qmldesigner/components/formeditor/resizecontroller.h
+++ b/src/plugins/qmldesigner/components/formeditor/resizecontroller.h
@@ -37,7 +37,8 @@ class WeakResizeController;
class ResizeController
{
- friend class WeakResizeController;
+ friend WeakResizeController;
+
public:
ResizeController();
ResizeController(LayerItem *layerItem, FormEditorItem *formEditorItem);
@@ -76,7 +77,8 @@ private: // variables
class WeakResizeController
{
- friend class ResizeController;
+ friend ResizeController;
+
public:
WeakResizeController();
WeakResizeController(const WeakResizeController &resizeController);
diff --git a/src/plugins/qmldesigner/components/formeditor/rotationcontroller.h b/src/plugins/qmldesigner/components/formeditor/rotationcontroller.h
index 52b5002387..ffca7bae5a 100644
--- a/src/plugins/qmldesigner/components/formeditor/rotationcontroller.h
+++ b/src/plugins/qmldesigner/components/formeditor/rotationcontroller.h
@@ -37,7 +37,8 @@ class WeakRotationController;
class RotationController
{
- friend class WeakRotationController;
+ friend WeakRotationController;
+
public:
RotationController();
RotationController(LayerItem *layerItem, FormEditorItem *formEditorItem);
@@ -74,7 +75,8 @@ private:
class WeakRotationController
{
- friend class RotationController;
+ friend RotationController;
+
public:
WeakRotationController();
WeakRotationController(const WeakRotationController &rotationController);
diff --git a/src/plugins/qmldesigner/components/itemlibrary/customfilesystemmodel.cpp b/src/plugins/qmldesigner/components/itemlibrary/customfilesystemmodel.cpp
deleted file mode 100644
index 9873963411..0000000000
--- a/src/plugins/qmldesigner/components/itemlibrary/customfilesystemmodel.cpp
+++ /dev/null
@@ -1,437 +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 "customfilesystemmodel.h"
-
-#include <synchronousimagecache.h>
-#include <theme.h>
-#include <hdrimage.h>
-
-#include <utils/filesystemwatcher.h>
-
-#include <QDir>
-#include <QDirIterator>
-#include <QFileIconProvider>
-#include <QFileSystemModel>
-#include <QFont>
-#include <QImageReader>
-#include <QPainter>
-#include <QRawFont>
-#include <qmath.h>
-#include <condition_variable>
-#include <mutex>
-
-namespace QmlDesigner {
-
-static const QStringList &supportedImageSuffixes()
-{
- static QStringList retList;
- if (retList.isEmpty()) {
- const QList<QByteArray> suffixes = QImageReader::supportedImageFormats();
- for (const QByteArray &suffix : suffixes)
- retList.append(QString::fromUtf8(suffix));
- }
- return retList;
-}
-
-static const QStringList &supportedFragmentShaderSuffixes()
-{
- static const QStringList retList {"frag", "glsl", "glslf", "fsh"};
- return retList;
-}
-
-static const QStringList &supportedShaderSuffixes()
-{
- static const QStringList retList {"frag", "vert",
- "glsl", "glslv", "glslf",
- "vsh", "fsh"};
- return retList;
-}
-
-static const QStringList &supportedFontSuffixes()
-{
- static const QStringList retList {"ttf", "otf"};
- return retList;
-}
-
-static const QStringList &supportedAudioSuffixes()
-{
- static const QStringList retList {"wav"};
- return retList;
-}
-
-static const QStringList &supportedTexture3DSuffixes()
-{
- // These are file types only supported by 3D textures
- static QStringList retList {"hdr"};
- return retList;
-}
-
-static QPixmap defaultPixmapForType(const QString &type, const QSize &size)
-{
- return QPixmap(QStringLiteral(":/ItemLibrary/images/asset_%1_%2.png").arg(type).arg(size.width()));
-}
-
-static QPixmap texturePixmap(const QString &fileName)
-{
- return HdrImage{fileName}.toPixmap();
-}
-
-QString fontFamily(const QFileInfo &info)
-{
- QRawFont font(info.absoluteFilePath(), 10);
- if (font.isValid())
- return font.familyName();
- return {};
-}
-
-class ItemLibraryFileIconProvider : public QFileIconProvider
-{
-public:
- ItemLibraryFileIconProvider(SynchronousImageCache &fontImageCache,
- QHash<QString, QPair<QDateTime, QIcon>> &iconCache)
- : QFileIconProvider()
- , m_fontImageCache(fontImageCache)
- , m_iconCache(iconCache)
- {
- }
-
- QIcon icon( const QFileInfo & info ) const override
- {
- const QString filePath = info.absoluteFilePath();
- QPair<QDateTime, QIcon> &cachedIcon = m_iconCache[filePath];
- if (!cachedIcon.second.isNull() && cachedIcon.first == info.lastModified())
- return cachedIcon.second;
-
- QIcon icon;
- const QString suffix = info.suffix().toLower();
-
- // Provide icon depending on suffix
- QPixmap origPixmap;
-
- if (supportedFontSuffixes().contains(suffix))
- return generateFontIcons(filePath);
- else if (supportedImageSuffixes().contains(suffix))
- origPixmap.load(filePath);
- else if (supportedTexture3DSuffixes().contains(suffix))
- origPixmap = texturePixmap(filePath);
-
- for (auto iconSize : iconSizes) {
- QPixmap pixmap = origPixmap;
- if (pixmap.isNull()) {
- if (supportedAudioSuffixes().contains(suffix))
- pixmap = defaultPixmapForType("sound", iconSize);
- else if (supportedShaderSuffixes().contains(suffix))
- pixmap = defaultPixmapForType("shader", iconSize);
- if (pixmap.isNull())
- return QFileIconProvider::icon(info);
- }
-
- if ((pixmap.width() > iconSize.width()) || (pixmap.height() > iconSize.height()))
- pixmap = pixmap.scaled(iconSize, Qt::KeepAspectRatio, Qt::SmoothTransformation);
-
- icon.addPixmap(pixmap);
- }
-
- cachedIcon.first = info.lastModified();
- cachedIcon.second = icon;
- return icon;
- }
-
- QIcon generateFontIcons(const QString &filePath) const
- {
- return m_fontImageCache.icon(
- filePath,
- {},
- ImageCache::FontCollectorSizesAuxiliaryData{Utils::span{iconSizes},
- Theme::getColor(Theme::DStextColor).name(),
- "Abc"});
- }
-
-private:
- // Generated icon sizes should contain all ItemLibraryResourceView needed icon sizes, and their
- // x2 versions for HDPI sceens
- std::vector<QSize> iconSizes = {{384, 384},
- {192, 192}, // Large
- {256, 256},
- {128, 128}, // Drag
- {96, 96}, // Medium
- {48, 48}, // Small
- {64, 64},
- {32, 32}}; // List
-
- SynchronousImageCache &m_fontImageCache;
- QHash<QString, QPair<QDateTime, QIcon>> &m_iconCache;
-};
-
-CustomFileSystemModel::CustomFileSystemModel(SynchronousImageCache &fontImageCache, QObject *parent)
- : QAbstractListModel(parent)
- , m_fileSystemModel(new QFileSystemModel(this))
- , m_fileSystemWatcher(new Utils::FileSystemWatcher(this))
- , m_fontImageCache(fontImageCache)
-{
- m_updatePathTimer.setInterval(200);
- m_updatePathTimer.setSingleShot(true);
- m_updatePathTimer.callOnTimeout([this]() {
- updatePath(m_fileSystemModel->rootPath());
- });
-
- // If project directory contents change, or one of the asset files is modified, we must
- // reconstruct the model to update the icons
- connect(m_fileSystemWatcher, &Utils::FileSystemWatcher::directoryChanged, [this] {
- m_updatePathTimer.start();
- });
- connect(m_fileSystemWatcher, &Utils::FileSystemWatcher::fileChanged, [this] {
- m_updatePathTimer.start();
- });
-}
-
-void CustomFileSystemModel::setFilter(QDir::Filters)
-{
-
-}
-
-bool filterMetaIcons(const QString &fileName)
-{
-
- QFileInfo info(fileName);
-
- if (info.dir().path().split("/").contains("designer")) {
-
- QDir currentDir = info.dir();
-
- int i = 0;
- while (!currentDir.isRoot() && i < 3) {
- if (currentDir.dirName() == "designer") {
- if (!currentDir.entryList({"*.metainfo"}).isEmpty())
- return false;
- }
-
- currentDir.cdUp();
- ++i;
- }
-
- if (info.dir().dirName() == "designer")
- return false;
- }
-
- return true;
-}
-
-QModelIndex CustomFileSystemModel::setRootPath(const QString &newPath)
-{
- if (m_fileSystemModel->rootPath() == newPath)
- return QAbstractListModel::index(0, 0);
-
- return updatePath(newPath);
-}
-
-QVariant CustomFileSystemModel::data(const QModelIndex &index, int role) const
-{
- if (role == Qt::ToolTipRole)
- return fileInfo(index).filePath();
-
- if (role == Qt::FontRole) {
- QFont font = m_fileSystemModel->data(fileSystemModelIndex(index), role).value<QFont>();
- font.setPixelSize(Theme::instance()->smallFontPixelSize());
- return font;
- }
-
-
- return m_fileSystemModel->data(fileSystemModelIndex(index), role);
-}
-
-int CustomFileSystemModel::rowCount(const QModelIndex &) const
-{
- return m_files.count();
-}
-
-int CustomFileSystemModel::columnCount(const QModelIndex &) const
-{
- return 1;
-}
-
-QModelIndex CustomFileSystemModel::indexForPath(const QString &path, int /*column*/) const
-{
- return QAbstractListModel::index(m_files.indexOf(path), 0);
-}
-
-QIcon CustomFileSystemModel::fileIcon(const QModelIndex &index) const
-{
- return m_fileSystemModel->fileIcon(fileSystemModelIndex(index));
-}
-
-QString CustomFileSystemModel::fileName(const QModelIndex &index) const
-{
- return m_fileSystemModel->fileName(fileSystemModelIndex(index));
-}
-
-QFileInfo CustomFileSystemModel::fileInfo(const QModelIndex &index) const
-{
- return m_fileSystemModel->fileInfo(fileSystemModelIndex(index));
-}
-
-Qt::ItemFlags CustomFileSystemModel::flags(const QModelIndex &index) const
-{
- return m_fileSystemModel->flags (fileSystemModelIndex(index));
-}
-
-void CustomFileSystemModel::setSearchFilter(const QString &nameFilterList)
-{
- m_searchFilter = nameFilterList;
- setRootPath(m_fileSystemModel->rootPath());
-}
-
-QPair<QString, QByteArray> CustomFileSystemModel::resourceTypeAndData(const QModelIndex &index) const
-{
- QFileInfo fi = fileInfo(index);
- QString suffix = fi.suffix().toLower();
- if (!suffix.isEmpty()) {
- if (supportedImageSuffixes().contains(suffix)) {
- // Data: Image format (suffix)
- return {"application/vnd.bauhaus.libraryresource.image", suffix.toUtf8()};
- } else if (supportedFontSuffixes().contains(suffix)) {
- // Data: Font family name
- return {"application/vnd.bauhaus.libraryresource.font", fontFamily(fi).toUtf8()};
- } else if (supportedShaderSuffixes().contains(suffix)) {
- // Data: shader type, frament (f) or vertex (v)
- return {"application/vnd.bauhaus.libraryresource.shader",
- supportedFragmentShaderSuffixes().contains(suffix) ? "f" : "v"};
- } else if (supportedAudioSuffixes().contains(suffix)) {
- // No extra data for sounds
- return {"application/vnd.bauhaus.libraryresource.sound", {}};
- } else if (supportedTexture3DSuffixes().contains(suffix)) {
- // Data: Image format (suffix)
- return {"application/vnd.bauhaus.libraryresource.texture3d", suffix.toUtf8()};
- }
- }
- return {};
-}
-
-const QSet<QString> &CustomFileSystemModel::supportedSuffixes() const
-{
- static QSet<QString> allSuffixes;
- if (allSuffixes.isEmpty()) {
- auto insertSuffixes = [](const QStringList &suffixes) {
- for (const auto &suffix : suffixes)
- allSuffixes.insert(suffix);
- };
- insertSuffixes(supportedImageSuffixes());
- insertSuffixes(supportedShaderSuffixes());
- insertSuffixes(supportedFontSuffixes());
- insertSuffixes(supportedAudioSuffixes());
- insertSuffixes(supportedTexture3DSuffixes());
- }
- return allSuffixes;
-}
-
-const QSet<QString> &CustomFileSystemModel::previewableSuffixes() const
-{
- static QSet<QString> previewableSuffixes;
- if (previewableSuffixes.isEmpty()) {
- auto insertSuffixes = [](const QStringList &suffixes) {
- for (const auto &suffix : suffixes)
- previewableSuffixes.insert(suffix);
- };
- insertSuffixes(supportedFontSuffixes());
- }
- return previewableSuffixes;
-
-}
-
-void CustomFileSystemModel::appendIfNotFiltered(const QString &file)
-{
- if (filterMetaIcons(file))
- m_files.append(file);
-}
-
-QModelIndex CustomFileSystemModel::updatePath(const QString &newPath)
-{
- beginResetModel();
-
- // We must recreate icon provider to ensure modified icons are recreated
- auto newProvider = new ItemLibraryFileIconProvider(m_fontImageCache, m_iconCache);
- m_fileSystemModel->setIconProvider(newProvider);
- delete m_fileIconProvider;
- m_fileIconProvider = newProvider;
-
- m_fileSystemModel->setRootPath(newPath);
-
- m_fileSystemWatcher->removeDirectories(m_fileSystemWatcher->directories());
- m_fileSystemWatcher->removeFiles(m_fileSystemWatcher->files());
-
- m_fileSystemWatcher->addDirectory(newPath, Utils::FileSystemWatcher::WatchAllChanges);
-
- QStringList nameFilterList;
-
- const QString searchFilter = m_searchFilter;
-
- if (searchFilter.contains(QLatin1Char('.'))) {
- nameFilterList.append(QString(QStringLiteral("*%1*")).arg(searchFilter));
- } else {
- const QString filterTemplate("*%1*.%2");
- auto appendFilters = [&](const QStringList &suffixes) {
- for (const QString &ext : suffixes) {
- nameFilterList.append(filterTemplate.arg(searchFilter, ext));
- nameFilterList.append(filterTemplate.arg(searchFilter, ext.toUpper()));
- }
- };
- appendFilters(supportedImageSuffixes());
- appendFilters(supportedShaderSuffixes());
- appendFilters(supportedFontSuffixes());
- appendFilters(supportedAudioSuffixes());
- appendFilters(supportedTexture3DSuffixes());
- }
-
- m_files.clear();
-
- QDirIterator fileIterator(newPath, nameFilterList, QDir::Files, QDirIterator::Subdirectories);
-
- while (fileIterator.hasNext())
- appendIfNotFiltered(fileIterator.next());
-
- QDirIterator dirIterator(newPath, {}, QDir::Files | QDir::Dirs | QDir::NoDotAndDotDot,
- QDirIterator::Subdirectories);
- while (dirIterator.hasNext()) {
- const QString entry = dirIterator.next();
- QFileInfo fi{entry};
- if (fi.isDir())
- m_fileSystemWatcher->addDirectory(entry, Utils::FileSystemWatcher::WatchAllChanges);
- else if (supportedSuffixes().contains(fi.suffix()))
- m_fileSystemWatcher->addFile(entry, Utils::FileSystemWatcher::WatchAllChanges);
- }
-
- endResetModel();
-
- return QAbstractListModel::index(0, 0);
-}
-
-QModelIndex CustomFileSystemModel::fileSystemModelIndex(const QModelIndex &index) const
-{
- const int row = index.row();
- return m_fileSystemModel->index(m_files.at(row));
-}
-
-} //QmlDesigner
diff --git a/src/plugins/qmldesigner/components/itemlibrary/itemlibrary.pri b/src/plugins/qmldesigner/components/itemlibrary/itemlibrary.pri
index 8099c87853..d1059d11d7 100644
--- a/src/plugins/qmldesigner/components/itemlibrary/itemlibrary.pri
+++ b/src/plugins/qmldesigner/components/itemlibrary/itemlibrary.pri
@@ -5,7 +5,6 @@ HEADERS += itemlibraryview.h \
$$PWD/itemlibraryiconimageprovider.h \
itemlibrarywidget.h \
itemlibrarymodel.h \
- itemlibraryresourceview.h \
itemlibraryimageprovider.h \
itemlibraryitem.h \
itemlibrarycategory.h \
@@ -15,7 +14,11 @@ HEADERS += itemlibraryview.h \
itemlibraryaddimportmodel.h \
itemlibraryassetimportdialog.h \
itemlibraryassetimporter.h \
- customfilesystemmodel.h \
+ itemlibraryassetsdir.h \
+ itemlibraryassetsdirsmodel.h \
+ itemlibraryassetsfilesmodel.h \
+ itemlibraryassetsiconprovider.h \
+ itemlibraryassetsmodel.h \
assetimportupdatedialog.h \
assetimportupdatetreeitem.h \
assetimportupdatetreeitemdelegate.h \
@@ -26,7 +29,6 @@ SOURCES += itemlibraryview.cpp \
$$PWD/itemlibraryiconimageprovider.cpp \
itemlibrarywidget.cpp \
itemlibrarymodel.cpp \
- itemlibraryresourceview.cpp \
itemlibraryimageprovider.cpp \
itemlibraryitem.cpp \
itemlibrarycategory.cpp \
@@ -36,7 +38,11 @@ SOURCES += itemlibraryview.cpp \
itemlibraryaddimportmodel.cpp \
itemlibraryassetimportdialog.cpp \
itemlibraryassetimporter.cpp \
- customfilesystemmodel.cpp \
+ itemlibraryassetsdir.cpp \
+ itemlibraryassetsdirsmodel.cpp \
+ itemlibraryassetsfilesmodel.cpp \
+ itemlibraryassetsiconprovider.cpp \
+ itemlibraryassetsmodel.cpp \
assetimportupdatedialog.cpp \
assetimportupdatetreeitem.cpp \
assetimportupdatetreeitemdelegate.cpp \
diff --git a/src/plugins/qmldesigner/components/itemlibrary/itemlibraryassetsdir.cpp b/src/plugins/qmldesigner/components/itemlibrary/itemlibraryassetsdir.cpp
new file mode 100644
index 0000000000..755752f4fc
--- /dev/null
+++ b/src/plugins/qmldesigner/components/itemlibrary/itemlibraryassetsdir.cpp
@@ -0,0 +1,89 @@
+/****************************************************************************
+**
+** Copyright (C) 2021 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of Qt Creator.
+**
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3 as published by the Free Software
+** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-3.0.html.
+**
+****************************************************************************/
+
+#include "itemlibraryassetsdir.h"
+#include "itemlibraryassetsdirsmodel.h"
+#include "itemlibraryassetsfilesmodel.h"
+
+namespace QmlDesigner {
+
+ItemLibraryAssetsDir::ItemLibraryAssetsDir(const QString &path, int depth, bool expanded, QObject *parent)
+ : QObject(parent)
+ , m_dirPath(path)
+ , m_dirDepth(depth)
+ , m_dirExpanded(expanded)
+{
+
+}
+
+QString ItemLibraryAssetsDir::dirName() const { return m_dirPath.split('/').last(); }
+QString ItemLibraryAssetsDir::dirPath() const { return m_dirPath; }
+int ItemLibraryAssetsDir::dirDepth() const { return m_dirDepth; }
+bool ItemLibraryAssetsDir::dirExpanded() const { return m_dirExpanded; }
+bool ItemLibraryAssetsDir::dirVisible() const { return m_dirVisible; }
+
+void ItemLibraryAssetsDir::setDirExpanded(bool expand)
+{
+ if (m_dirExpanded != expand) {
+ m_dirExpanded = expand;
+ emit dirExpandedChanged();
+ }
+}
+
+void ItemLibraryAssetsDir::setDirVisible(bool visible)
+{
+ if (m_dirVisible != visible) {
+ m_dirVisible = visible;
+ emit dirVisibleChanged();
+ }
+}
+
+QObject *ItemLibraryAssetsDir::filesModel() const
+{
+ return m_filesModel;
+}
+
+QObject *ItemLibraryAssetsDir::dirsModel() const
+{
+ return m_dirsModel;
+}
+
+void ItemLibraryAssetsDir::addDir(ItemLibraryAssetsDir *assetsDir)
+{
+ if (!m_dirsModel)
+ m_dirsModel = new ItemLibraryAssetsDirsModel(this);
+
+ m_dirsModel->addDir(assetsDir);
+}
+
+void ItemLibraryAssetsDir::addFile(const QString &filePath)
+{
+ if (!m_filesModel)
+ m_filesModel = new ItemLibraryAssetsFilesModel(this);
+
+ m_filesModel->addFile(filePath);
+}
+
+} // namespace QmlDesigner
diff --git a/src/plugins/qmldesigner/components/itemlibrary/itemlibraryassetsdir.h b/src/plugins/qmldesigner/components/itemlibrary/itemlibraryassetsdir.h
new file mode 100644
index 0000000000..4ef67ce63e
--- /dev/null
+++ b/src/plugins/qmldesigner/components/itemlibrary/itemlibraryassetsdir.h
@@ -0,0 +1,83 @@
+/****************************************************************************
+**
+** Copyright (C) 2021 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of Qt Creator.
+**
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3 as published by the Free Software
+** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-3.0.html.
+**
+****************************************************************************/
+
+#pragma once
+
+#include <QObject>
+
+namespace QmlDesigner {
+
+class ItemLibraryAssetsDirsModel;
+class ItemLibraryAssetsFilesModel;
+
+class ItemLibraryAssetsDir : public QObject
+{
+ Q_OBJECT
+
+ Q_PROPERTY(QString dirName READ dirName NOTIFY dirNameChanged)
+ Q_PROPERTY(QString dirPath READ dirPath NOTIFY dirPathChanged)
+ Q_PROPERTY(bool dirExpanded READ dirExpanded WRITE setDirExpanded NOTIFY dirExpandedChanged)
+ Q_PROPERTY(bool dirVisible READ dirVisible WRITE setDirVisible NOTIFY dirVisibleChanged)
+ Q_PROPERTY(int dirDepth READ dirDepth NOTIFY dirDepthChanged)
+ Q_PROPERTY(QObject *filesModel READ filesModel NOTIFY filesModelChanged)
+ Q_PROPERTY(QObject *dirsModel READ dirsModel NOTIFY dirsModelChanged)
+
+public:
+ ItemLibraryAssetsDir(const QString &path, int depth, bool expanded = true, QObject *parent = nullptr);
+
+ QString dirName() const;
+ QString dirPath() const;
+ int dirDepth() const;
+
+ bool dirExpanded() const;
+ bool dirVisible() const;
+ void setDirExpanded(bool expand);
+ void setDirVisible(bool visible);
+
+ QObject *filesModel() const;
+ QObject *dirsModel() const;
+
+ void addDir(ItemLibraryAssetsDir *assetsDir);
+ void addFile(const QString &filePath);
+
+signals:
+ void dirNameChanged();
+ void dirPathChanged();
+ void dirDepthChanged();
+ void dirExpandedChanged();
+ void dirVisibleChanged();
+ void filesModelChanged();
+ void dirsModelChanged();
+
+private:
+ QString m_dirPath;
+ int m_dirDepth = 0;
+ bool m_dirExpanded = true;
+ bool m_dirVisible = true;
+ ItemLibraryAssetsDirsModel *m_dirsModel = nullptr;
+ ItemLibraryAssetsFilesModel *m_filesModel = nullptr;
+};
+
+} // namespace QmlDesigner
diff --git a/src/plugins/qmldesigner/components/itemlibrary/itemlibraryassetsdirsmodel.cpp b/src/plugins/qmldesigner/components/itemlibrary/itemlibraryassetsdirsmodel.cpp
new file mode 100644
index 0000000000..4eae703002
--- /dev/null
+++ b/src/plugins/qmldesigner/components/itemlibrary/itemlibraryassetsdirsmodel.cpp
@@ -0,0 +1,90 @@
+/****************************************************************************
+**
+** Copyright (C) 2021 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of Qt Creator.
+**
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3 as published by the Free Software
+** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-3.0.html.
+**
+****************************************************************************/
+
+#include "itemlibraryassetsdirsmodel.h"
+#include "itemlibraryassetsmodel.h"
+
+#include <QDebug>
+#include <QMetaProperty>
+
+namespace QmlDesigner {
+
+ItemLibraryAssetsDirsModel::ItemLibraryAssetsDirsModel(QObject *parent)
+ : QAbstractListModel(parent)
+{
+ // add roles
+ const QMetaObject meta = ItemLibraryAssetsDir::staticMetaObject;
+ for (int i = meta.propertyOffset(); i < meta.propertyCount(); ++i)
+ m_roleNames.insert(i, meta.property(i).name());
+}
+
+QVariant ItemLibraryAssetsDirsModel::data(const QModelIndex &index, int role) const
+{
+ if (!index.isValid()) {
+ qWarning() << Q_FUNC_INFO << "Invalid index requested: " << QString::number(index.row());
+ return {};
+ }
+
+ if (m_roleNames.contains(role))
+ return m_dirs[index.row()]->property(m_roleNames[role]);
+
+ qWarning() << Q_FUNC_INFO << "Invalid role requested: " << QString::number(role);
+ return {};
+}
+
+bool ItemLibraryAssetsDirsModel::setData(const QModelIndex &index, const QVariant &value, int role)
+{
+ // currently only dirExpanded property is updatable
+ if (index.isValid() && m_roleNames.contains(role)) {
+ QVariant currValue = m_dirs.at(index.row())->property(m_roleNames.value(role));
+ if (currValue != value) {
+ m_dirs.at(index.row())->setProperty(m_roleNames.value(role), value);
+ if (m_roleNames.value(role) == "dirExpanded")
+ ItemLibraryAssetsModel::saveExpandedState(value.toBool(), m_dirs.at(index.row())->dirPath());
+ emit dataChanged(index, index, {role});
+ return true;
+ }
+ }
+ return false;
+}
+
+int ItemLibraryAssetsDirsModel::rowCount(const QModelIndex &parent) const
+{
+ Q_UNUSED(parent)
+
+ return m_dirs.size();
+}
+
+QHash<int, QByteArray> ItemLibraryAssetsDirsModel::roleNames() const
+{
+ return m_roleNames;
+}
+
+void ItemLibraryAssetsDirsModel::addDir(ItemLibraryAssetsDir *assetsDir)
+{
+ m_dirs.append(assetsDir);
+}
+
+} // namespace QmlDesigner
diff --git a/src/plugins/qmldesigner/components/itemlibrary/itemlibraryresourceview.h b/src/plugins/qmldesigner/components/itemlibrary/itemlibraryassetsdirsmodel.h
index fa22973c0c..06bc5a5839 100644
--- a/src/plugins/qmldesigner/components/itemlibrary/itemlibraryresourceview.h
+++ b/src/plugins/qmldesigner/components/itemlibrary/itemlibraryassetsdirsmodel.h
@@ -1,6 +1,6 @@
/****************************************************************************
**
-** Copyright (C) 2016 The Qt Company Ltd.
+** Copyright (C) 2021 The Qt Company Ltd.
** Contact: https://www.qt.io/licensing/
**
** This file is part of Qt Creator.
@@ -25,32 +25,28 @@
#pragma once
-#include <previewtooltip/previewtooltipbackend.h>
-
-#include <QListView>
-
-QT_BEGIN_NAMESPACE
-class QActionGroup;
-QT_END_NAMESPACE
+#include <QAbstractListModel>
+#include "itemlibraryassetsdir.h"
namespace QmlDesigner {
-class AsynchronousImageCache;
-
-class ItemLibraryResourceView : public QListView {
-
+class ItemLibraryAssetsDirsModel : public QAbstractListModel
+{
Q_OBJECT
+
public:
- explicit ItemLibraryResourceView(AsynchronousImageCache &fontImageCache,
- QWidget *parent = nullptr);
+ ItemLibraryAssetsDirsModel(QObject *parent = nullptr);
- void startDrag(Qt::DropActions supportedActions) override;
- bool viewportEvent(QEvent *event) override;
+ QVariant data(const QModelIndex & index, int role = Qt::DisplayRole) const override;
+ bool setData(const QModelIndex &index, const QVariant &value, int role) override;
+ int rowCount(const QModelIndex & parent = QModelIndex()) const override;
+ QHash<int, QByteArray> roleNames() const override;
-private:
- void addSizeAction(QActionGroup *group, const QString &text, int size, int iconSize);
+ void addDir(ItemLibraryAssetsDir *assetsDir);
- std::unique_ptr<PreviewTooltipBackend> m_fontPreviewTooltipBackend;
+private:
+ QList<ItemLibraryAssetsDir *> m_dirs;
+ QHash<int, QByteArray> m_roleNames;
};
} // namespace QmlDesigner
diff --git a/src/plugins/qmldesigner/components/itemlibrary/itemlibraryassetsfilesmodel.cpp b/src/plugins/qmldesigner/components/itemlibrary/itemlibraryassetsfilesmodel.cpp
new file mode 100644
index 0000000000..1140ba43d7
--- /dev/null
+++ b/src/plugins/qmldesigner/components/itemlibrary/itemlibraryassetsfilesmodel.cpp
@@ -0,0 +1,73 @@
+/****************************************************************************
+**
+** Copyright (C) 2021 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of Qt Creator.
+**
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3 as published by the Free Software
+** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-3.0.html.
+**
+****************************************************************************/
+#include "itemlibraryassetsfilesmodel.h"
+
+#include <QDebug>
+
+namespace QmlDesigner {
+
+ItemLibraryAssetsFilesModel::ItemLibraryAssetsFilesModel(QObject *parent)
+ : QAbstractListModel(parent)
+{
+ // add roles
+ m_roleNames.insert(FileNameRole, "fileName");
+ m_roleNames.insert(FilePathRole, "filePath");
+}
+
+QVariant ItemLibraryAssetsFilesModel::data(const QModelIndex &index, int role) const
+{
+ if (!index.isValid()) {
+ qWarning() << Q_FUNC_INFO << "Invalid index requested: " << QString::number(index.row());
+ return {};
+ }
+
+ if (role == FileNameRole)
+ return m_files[index.row()].split('/').last();
+
+ if (role == FilePathRole)
+ return m_files[index.row()];
+
+ qWarning() << Q_FUNC_INFO << "Invalid role requested: " << QString::number(role);
+ return {};
+}
+
+int ItemLibraryAssetsFilesModel::rowCount(const QModelIndex &parent) const
+{
+ Q_UNUSED(parent)
+
+ return m_files.size();
+}
+
+QHash<int, QByteArray> ItemLibraryAssetsFilesModel::roleNames() const
+{
+ return m_roleNames;
+}
+
+void ItemLibraryAssetsFilesModel::addFile(const QString &filePath)
+{
+ m_files.append(filePath);
+}
+
+} // namespace QmlDesigner
diff --git a/src/plugins/android/adbcommandswidget.h b/src/plugins/qmldesigner/components/itemlibrary/itemlibraryassetsfilesmodel.h
index 4650639cc2..25577dce51 100644
--- a/src/plugins/android/adbcommandswidget.h
+++ b/src/plugins/qmldesigner/components/itemlibrary/itemlibraryassetsfilesmodel.h
@@ -1,6 +1,6 @@
/****************************************************************************
**
-** Copyright (C) 2017 The Qt Company Ltd.
+** Copyright (C) 2021 The Qt Company Ltd.
** Contact: https://www.qt.io/licensing/
**
** This file is part of Qt Creator.
@@ -25,34 +25,29 @@
#pragma once
-#include <QGroupBox>
-#include <QStringList>
+#include <QAbstractListModel>
-#include <memory>
+namespace QmlDesigner {
-namespace Android {
-namespace Internal {
-
-class AdbCommandsWidgetPrivate;
-
-class AdbCommandsWidget : public QGroupBox
+class ItemLibraryAssetsFilesModel : public QAbstractListModel
{
Q_OBJECT
-public:
- AdbCommandsWidget();
- ~AdbCommandsWidget() override;
- QStringList commandsList() const;
- void setCommandList(const QStringList &commands);
+public:
+ ItemLibraryAssetsFilesModel(QObject *parent = nullptr);
- void setTitleText(const QString &title);
+ QVariant data(const QModelIndex & index, int role = Qt::DisplayRole) const override;
+ int rowCount(const QModelIndex & parent = QModelIndex()) const override;
+ QHash<int, QByteArray> roleNames() const override;
-signals:
- void commandsChanged();
+ void addFile(const QString &filePath);
private:
- std::unique_ptr<AdbCommandsWidgetPrivate> d;
+ enum Roles {FileNameRole = Qt::UserRole + 1,
+ FilePathRole};
+
+ QStringList m_files;
+ QHash<int, QByteArray> m_roleNames;
};
-} // Internal
-} // Android
+} // QmlDesigner
diff --git a/src/plugins/qmldesigner/components/itemlibrary/itemlibraryassetsiconprovider.cpp b/src/plugins/qmldesigner/components/itemlibrary/itemlibraryassetsiconprovider.cpp
new file mode 100644
index 0000000000..7382a175fc
--- /dev/null
+++ b/src/plugins/qmldesigner/components/itemlibrary/itemlibraryassetsiconprovider.cpp
@@ -0,0 +1,79 @@
+/****************************************************************************
+**
+** Copyright (C) 2021 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of Qt Creator.
+**
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3 as published by the Free Software
+** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-3.0.html.
+**
+****************************************************************************/
+
+#include "itemlibraryassetsiconprovider.h"
+#include "itemlibraryassetsmodel.h"
+
+#include <hdrimage.h>
+#include <theme.h>
+#include <utils/stylehelper.h>
+
+namespace QmlDesigner {
+
+ItemLibraryAssetsIconProvider::ItemLibraryAssetsIconProvider(SynchronousImageCache &fontImageCache)
+ : QQuickImageProvider(QQuickImageProvider::Pixmap)
+ , m_fontImageCache(fontImageCache)
+{
+}
+
+QPixmap ItemLibraryAssetsIconProvider::requestPixmap(const QString &id, QSize *size, const QSize &requestedSize)
+{
+ QPixmap pixmap;
+ const QString suffix = "*." + id.split('.').last();
+ if (ItemLibraryAssetsModel::supportedFontSuffixes().contains(suffix))
+ pixmap = generateFontIcons(id);
+ else if (ItemLibraryAssetsModel::supportedImageSuffixes().contains(suffix))
+ pixmap = Utils::StyleHelper::dpiSpecificImageFile(id);
+ else if (ItemLibraryAssetsModel::supportedTexture3DSuffixes().contains(suffix))
+ pixmap = HdrImage{id}.toPixmap();
+ else if (ItemLibraryAssetsModel::supportedAudioSuffixes().contains(suffix))
+ pixmap = QPixmap(Utils::StyleHelper::dpiSpecificImageFile(":/ItemLibrary/images/asset_sound_48.png"));
+
+ if (size) {
+ size->setWidth(pixmap.width());
+ size->setHeight(pixmap.height());
+ }
+
+ if (pixmap.isNull()) {
+ pixmap = QPixmap(Utils::StyleHelper::dpiSpecificImageFile(
+ QStringLiteral(":/ItemLibrary/images/item-default-icon.png")));
+ }
+
+ if (requestedSize.isValid())
+ return pixmap.scaled(requestedSize);
+
+ return pixmap;
+}
+
+QPixmap ItemLibraryAssetsIconProvider::generateFontIcons(const QString &filePath) const
+{
+ return m_fontImageCache.icon(filePath, {},
+ ImageCache::FontCollectorSizesAuxiliaryData{Utils::span{iconSizes},
+ Theme::getColor(Theme::DStextColor).name(),
+ "Abc"}).pixmap({48, 48});
+}
+
+} // namespace QmlDesigner
+
diff --git a/src/plugins/qmldesigner/components/itemlibrary/itemlibraryassetsiconprovider.h b/src/plugins/qmldesigner/components/itemlibrary/itemlibraryassetsiconprovider.h
new file mode 100644
index 0000000000..3c5bc4081e
--- /dev/null
+++ b/src/plugins/qmldesigner/components/itemlibrary/itemlibraryassetsiconprovider.h
@@ -0,0 +1,58 @@
+/****************************************************************************
+**
+** Copyright (C) 2021 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of Qt Creator.
+**
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3 as published by the Free Software
+** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-3.0.html.
+**
+****************************************************************************/
+
+#pragma once
+
+#include <synchronousimagecache.h>
+
+#include <QQuickImageProvider>
+
+namespace QmlDesigner {
+
+class ItemLibraryAssetsIconProvider : public QQuickImageProvider
+{
+public:
+ ItemLibraryAssetsIconProvider(SynchronousImageCache &fontImageCache);
+
+ QPixmap requestPixmap(const QString &id, QSize *size, const QSize &requestedSize) override;
+
+private:
+ QPixmap generateFontIcons(const QString &filePath) const;
+
+ SynchronousImageCache &m_fontImageCache;
+
+ // Generated icon sizes should contain all ItemLibraryResourceView needed icon sizes, and their
+ // x2 versions for HDPI sceens
+ std::vector<QSize> iconSizes = {{384, 384},
+ {192, 192}, // Large
+ {256, 256},
+ {128, 128}, // Drag
+ {96, 96}, // Medium
+ {48, 48}, // Small
+ {64, 64},
+ {32, 32}}; // List
+};
+
+} // namespace QmlDesigner
diff --git a/src/plugins/qmldesigner/components/itemlibrary/itemlibraryassetsmodel.cpp b/src/plugins/qmldesigner/components/itemlibrary/itemlibraryassetsmodel.cpp
new file mode 100644
index 0000000000..f96af59029
--- /dev/null
+++ b/src/plugins/qmldesigner/components/itemlibrary/itemlibraryassetsmodel.cpp
@@ -0,0 +1,252 @@
+/****************************************************************************
+**
+** Copyright (C) 2021 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of Qt Creator.
+**
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3 as published by the Free Software
+** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-3.0.html.
+**
+****************************************************************************/
+
+#include "itemlibraryassetsmodel.h"
+#include "itemlibraryassetsdirsmodel.h"
+#include "itemlibraryassetsfilesmodel.h"
+
+#include <synchronousimagecache.h>
+#include <theme.h>
+#include <hdrimage.h>
+
+#include <QDebug>
+#include <QDir>
+#include <QDirIterator>
+#include <QFont>
+#include <QImageReader>
+#include <QMetaProperty>
+#include <QPainter>
+#include <QRawFont>
+#include "qmldesignerplugin.h"
+#include <projectexplorer/project.h>
+#include <projectexplorer/session.h>
+#include <utils/stylehelper.h>
+#include <utils/filesystemwatcher.h>
+
+namespace QmlDesigner {
+
+void ItemLibraryAssetsModel::saveExpandedState(bool expanded, const QString &sectionName)
+{
+ m_expandedStateHash.insert(sectionName, expanded);
+}
+
+bool ItemLibraryAssetsModel::loadExpandedState(const QString &sectionName)
+{
+ return m_expandedStateHash.value(sectionName, true);
+}
+
+const QStringList &ItemLibraryAssetsModel::supportedImageSuffixes()
+{
+ static QStringList retList;
+ if (retList.isEmpty()) {
+ const QList<QByteArray> suffixes = QImageReader::supportedImageFormats();
+ for (const QByteArray &suffix : suffixes)
+ retList.append("*." + QString::fromUtf8(suffix));
+ }
+ return retList;
+}
+
+const QStringList &ItemLibraryAssetsModel::supportedFragmentShaderSuffixes()
+{
+ static const QStringList retList {"*.frag", "*.glsl", "*.glslf", "*.fsh"};
+ return retList;
+}
+
+const QStringList &ItemLibraryAssetsModel::supportedShaderSuffixes()
+{
+ static const QStringList retList {"*.frag", "*.vert",
+ "*.glsl", "*.glslv", "*.glslf",
+ "*.vsh", "*.fsh"};
+ return retList;
+}
+
+const QStringList &ItemLibraryAssetsModel::supportedFontSuffixes()
+{
+ static const QStringList retList {"*.ttf", "*.otf"};
+ return retList;
+}
+
+const QStringList &ItemLibraryAssetsModel::supportedAudioSuffixes()
+{
+ static const QStringList retList {"*.wav"};
+ return retList;
+}
+
+const QStringList &ItemLibraryAssetsModel::supportedTexture3DSuffixes()
+{
+ // These are file types only supported by 3D textures
+ static QStringList retList {"*.hdr"};
+ return retList;
+}
+
+ItemLibraryAssetsModel::ItemLibraryAssetsModel(SynchronousImageCache &fontImageCache,
+ Utils::FileSystemWatcher *fileSystemWatcher,
+ QObject *parent)
+ : QAbstractListModel(parent)
+ , m_fontImageCache(fontImageCache)
+ , m_fileSystemWatcher(fileSystemWatcher)
+{
+ // add role names
+ int role = 0;
+ const QMetaObject meta = ItemLibraryAssetsDir::staticMetaObject;
+ for (int i = meta.propertyOffset(); i < meta.propertyCount(); ++i)
+ m_roleNames.insert(role++, meta.property(i).name());
+}
+
+QVariant ItemLibraryAssetsModel::data(const QModelIndex &index, int role) const
+{
+ if (!index.isValid()) {
+ qWarning() << Q_FUNC_INFO << "Invalid index requested: " << QString::number(index.row());
+ return {};
+ }
+
+ if (m_assetsDir && m_roleNames.contains(role)) {
+ return m_assetsDir->property(m_roleNames.value(role));
+ }
+
+ qWarning() << Q_FUNC_INFO << "Invalid role requested: " << QString::number(role);
+ return {};
+}
+
+int ItemLibraryAssetsModel::rowCount(const QModelIndex &parent) const
+{
+ Q_UNUSED(parent)
+
+ return 1;
+}
+
+QHash<int, QByteArray> ItemLibraryAssetsModel::roleNames() const
+{
+ return m_roleNames;
+}
+
+// called when a directory is changed to refresh the model for this directory
+void ItemLibraryAssetsModel::refresh()
+{
+ setRootPath(m_assetsDir->dirPath());
+}
+
+void ItemLibraryAssetsModel::setRootPath(const QString &path)
+{
+ static const QStringList supportedTopLevelDirs {"images", "sounds", "fonts", "assets"};
+
+ m_fileSystemWatcher->removeDirectories(m_fileSystemWatcher->directories());
+ m_fileSystemWatcher->removeFiles(m_fileSystemWatcher->files());
+
+ DesignDocument *currDesignDoc = QmlDesignerPlugin::instance()->currentDesignDocument();
+ if (!currDesignDoc) // happens sometimes on QDS shutdown
+ return;
+ ProjectExplorer::Project *project = ProjectExplorer::SessionManager::projectForFile(currDesignDoc->fileName());
+ QString projectName = project ? project->displayName() : "";
+
+ std::function<bool(ItemLibraryAssetsDir *, int)> parseDirRecursive;
+ parseDirRecursive = [this, &parseDirRecursive, &projectName](ItemLibraryAssetsDir *currAssetsDir, int currDepth) {
+ m_fileSystemWatcher->addDirectory(currAssetsDir->dirPath(), Utils::FileSystemWatcher::WatchAllChanges);
+
+ QDir dir(currAssetsDir->dirPath());
+ dir.setNameFilters(supportedSuffixes().values());
+ dir.setFilter(QDir::Files);
+ QDirIterator itFiles(dir);
+ bool isEmpty = true;
+ while (itFiles.hasNext()) {
+ QString filePath = itFiles.next();
+ QString fileName = filePath.split('/').last();
+ if (m_searchText.isEmpty() || fileName.contains(m_searchText, Qt::CaseInsensitive)) {
+ currAssetsDir->addFile(filePath);
+ m_fileSystemWatcher->addFile(filePath, Utils::FileSystemWatcher::WatchAllChanges);
+ isEmpty = false;
+ }
+ }
+
+ dir.setNameFilters({});
+ dir.setFilter(QDir::Dirs | QDir::NoDotAndDotDot);
+ QDirIterator itDirs(dir);
+
+ while (itDirs.hasNext()) {
+ QDir subDir = itDirs.next();
+ if (subDir.isEmpty() || projectName == subDir.dirName()
+ || (currDepth == 1 && !supportedTopLevelDirs.contains(subDir.dirName()))) {
+ continue;
+ }
+
+ ItemLibraryAssetsDir *assetsDir = new ItemLibraryAssetsDir(subDir.path(), currDepth, loadExpandedState(subDir.path()), currAssetsDir);
+ currAssetsDir->addDir(assetsDir);
+ isEmpty &= parseDirRecursive(assetsDir, currDepth + 1);
+ }
+
+ if (isEmpty)
+ currAssetsDir->setDirVisible(false);
+
+ return isEmpty;
+ };
+
+ if (m_assetsDir)
+ delete m_assetsDir;
+
+ beginResetModel();
+ m_assetsDir = new ItemLibraryAssetsDir(path, 0, true, this);
+ parseDirRecursive(m_assetsDir, 1);
+ endResetModel();
+}
+
+void ItemLibraryAssetsModel::setSearchText(const QString &searchText)
+{
+ if (m_searchText != searchText) {
+ m_searchText = searchText;
+ refresh();
+ }
+}
+
+const QSet<QString> &ItemLibraryAssetsModel::supportedSuffixes() const
+{
+ static QSet<QString> allSuffixes;
+ if (allSuffixes.isEmpty()) {
+ auto insertSuffixes = [](const QStringList &suffixes) {
+ for (const auto &suffix : suffixes)
+ allSuffixes.insert(suffix);
+ };
+ insertSuffixes(supportedImageSuffixes());
+ insertSuffixes(supportedShaderSuffixes());
+ insertSuffixes(supportedFontSuffixes());
+ insertSuffixes(supportedAudioSuffixes());
+ insertSuffixes(supportedTexture3DSuffixes());
+ }
+ return allSuffixes;
+}
+
+const QSet<QString> &ItemLibraryAssetsModel::previewableSuffixes() const
+{
+ static QSet<QString> previewableSuffixes;
+ if (previewableSuffixes.isEmpty()) {
+ auto insertSuffixes = [](const QStringList &suffixes) {
+ for (const auto &suffix : suffixes)
+ previewableSuffixes.insert(suffix);
+ };
+ insertSuffixes(supportedFontSuffixes());
+ }
+ return previewableSuffixes;
+}
+
+} // namespace QmlDesigner
diff --git a/src/plugins/qmldesigner/components/itemlibrary/customfilesystemmodel.h b/src/plugins/qmldesigner/components/itemlibrary/itemlibraryassetsmodel.h
index eabd6c1e23..1a6535bdfe 100644
--- a/src/plugins/qmldesigner/components/itemlibrary/customfilesystemmodel.h
+++ b/src/plugins/qmldesigner/components/itemlibrary/itemlibraryassetsmodel.h
@@ -1,6 +1,6 @@
/****************************************************************************
**
-** Copyright (C) 2016 The Qt Company Ltd.
+** Copyright (C) 2021 The Qt Company Ltd.
** Contact: https://www.qt.io/licensing/
**
** This file is part of Qt Creator.
@@ -25,7 +25,7 @@
#pragma once
-#include <QAbstractTableModel>
+#include <QAbstractListModel>
#include <QDateTime>
#include <QDir>
#include <QHash>
@@ -34,59 +34,54 @@
#include <QSet>
#include <QTimer>
-QT_BEGIN_NAMESPACE
-class QFileIconProvider;
-class QFileSystemModel;
-QT_END_NAMESPACE
+#include "itemlibraryassetsdir.h"
namespace Utils { class FileSystemWatcher; }
namespace QmlDesigner {
class SynchronousImageCache;
-class ItemLibraryFileIconProvider;
-class CustomFileSystemModel : public QAbstractListModel
+class ItemLibraryAssetsModel : public QAbstractListModel
{
Q_OBJECT
-public:
- CustomFileSystemModel(QmlDesigner::SynchronousImageCache &fontImageCache,
- QObject *parent = nullptr);
- void setFilter(QDir::Filters filters);
- QString rootPath() const;
- QModelIndex setRootPath(const QString &newPath);
+public:
+ ItemLibraryAssetsModel(QmlDesigner::SynchronousImageCache &fontImageCache,
+ Utils::FileSystemWatcher *fileSystemWatcher,
+ QObject *parent = nullptr);
QVariant data(const QModelIndex & index, int role = Qt::DisplayRole) const override;
int rowCount(const QModelIndex & parent = QModelIndex()) const override;
- int columnCount(const QModelIndex & parent = QModelIndex()) const override;
-
- QModelIndex indexForPath(const QString & path, int column = 0) const;
+ QHash<int, QByteArray> roleNames() const override;
- QIcon fileIcon(const QModelIndex & index) const;
- QString fileName(const QModelIndex & index) const;
- QFileInfo fileInfo(const QModelIndex & index) const;
+ void refresh();
+ void setRootPath(const QString &path);
+ void setSearchText(const QString &searchText);
- Qt::ItemFlags flags(const QModelIndex &index) const override;
- void setSearchFilter(const QString &nameFilterList);
+ static const QStringList &supportedImageSuffixes();
+ static const QStringList &supportedFragmentShaderSuffixes();
+ static const QStringList &supportedShaderSuffixes();
+ static const QStringList &supportedFontSuffixes();
+ static const QStringList &supportedAudioSuffixes();
+ static const QStringList &supportedTexture3DSuffixes();
- QPair<QString, QByteArray> resourceTypeAndData(const QModelIndex &index) const;
const QSet<QString> &supportedSuffixes() const;
const QSet<QString> &previewableSuffixes() const;
+ static void saveExpandedState(bool expanded, const QString &sectionName);
+ static bool loadExpandedState(const QString &sectionName);
+
private:
- QModelIndex updatePath(const QString &newPath);
- QModelIndex fileSystemModelIndex(const QModelIndex &index) const;
- void appendIfNotFiltered(const QString &file);
-
- QFileSystemModel *m_fileSystemModel;
- QStringList m_files;
- QString m_searchFilter;
- Utils::FileSystemWatcher *m_fileSystemWatcher;
SynchronousImageCache &m_fontImageCache;
- ItemLibraryFileIconProvider *m_fileIconProvider = nullptr;
QHash<QString, QPair<QDateTime, QIcon>> m_iconCache;
- QTimer m_updatePathTimer;
+
+ QString m_searchText;
+ Utils::FileSystemWatcher *m_fileSystemWatcher = nullptr;
+ ItemLibraryAssetsDir *m_assetsDir = nullptr;
+
+ QHash<int, QByteArray> m_roleNames;
+ inline static QHash<QString, bool> m_expandedStateHash;
};
-} //QmlDesigner
+} // namespace QmlDesigner
diff --git a/src/plugins/qmldesigner/components/itemlibrary/itemlibraryresourceview.cpp b/src/plugins/qmldesigner/components/itemlibrary/itemlibraryresourceview.cpp
deleted file mode 100644
index 1eef27473d..0000000000
--- a/src/plugins/qmldesigner/components/itemlibrary/itemlibraryresourceview.cpp
+++ /dev/null
@@ -1,204 +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 "itemlibraryresourceview.h"
-
-#include "customfilesystemmodel.h"
-
-#include <theme.h>
-#include <asynchronousimagecache.h>
-
-#include <QAction>
-#include <QActionGroup>
-#include <QDebug>
-#include <QDrag>
-#include <QFileSystemModel>
-#include <QMimeData>
-#include <QPainter>
-#include <QPixmap>
-#include <QtGui/qevent.h>
-
-#include <QProxyStyle>
-
-#include <functional>
-
-enum { debug = 0 };
-
-namespace QmlDesigner {
-
-void ItemLibraryResourceView::addSizeAction(QActionGroup *group, const QString &text, int gridSize, int iconSize)
-{
- auto action = new QAction(text, group);
- group->addAction(action);
- action->setCheckable(true);
- QAction::connect(action, &QAction::triggered, this, [this, gridSize, iconSize]() {
- setViewMode(QListView::IconMode);
- setGridSize(QSize(gridSize, gridSize));
- setIconSize(QSize(iconSize, iconSize));
- setDragEnabled(true);
- setWrapping(true);
- });
-}
-
-ItemLibraryResourceView::ItemLibraryResourceView(AsynchronousImageCache &fontImageCache,
- QWidget *parent)
- : QListView(parent)
-{
- setVerticalScrollBarPolicy(Qt::ScrollBarAsNeeded);
- setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
- setAttribute(Qt::WA_MacShowFocusRect, false);
-
- setGridSize(QSize(128, 128));
- setIconSize(QSize(96, 96));
- setSpacing(4);
-
- setViewMode(QListView::IconMode);
- setMovement(QListView::Snap);
- setResizeMode(QListView::Adjust);
- setSelectionRectVisible(false);
- setWrapping(true);
- setWordWrap(true);
-
- setDragDropMode(QAbstractItemView::DragOnly);
-
- setContextMenuPolicy(Qt::ActionsContextMenu);
-
- auto actionGroup = new QActionGroup(this);
- actionGroup->setExclusive(true);
-
- addSizeAction(actionGroup, tr("Large Icons"), 256, 192);
- addSizeAction(actionGroup, tr("Medium Icons"), 128, 96);
- addSizeAction(actionGroup, tr("Small Icons"), 96, 48);
-
- QAction *action = new QAction(tr("List"), actionGroup);
- actionGroup->addAction(action);
- action->setCheckable(true);
- QAction::connect(action, &QAction::triggered, this, [this](){
- setViewMode(QListView::ListMode);
- setGridSize(QSize());
- setIconSize(QSize(32, 32));
- setDragEnabled(true);
- setWrapping(false);
- });
-
- QAction *defaultAction = actionGroup->actions().at(1);
- defaultAction->toggle();
-
- addActions(actionGroup->actions());
-
- viewport()->setAttribute(Qt::WA_Hover);
- m_fontPreviewTooltipBackend = std::make_unique<PreviewTooltipBackend>(fontImageCache);
- // Note: Though the text specified here appears in UI, it shouldn't be translated, as it's
- // a commonly used sentence to preview the font glyphs in latin fonts.
- // For fonts that do not have latin glyphs, the font family name will have to
- // suffice for preview. Font family name is inserted into %1 at render time.
- m_fontPreviewTooltipBackend->setAuxiliaryData(
- ImageCache::FontCollectorSizeAuxiliaryData{QSize{300, 300},
- Theme::getColor(Theme::DStextColor).name(),
- QStringLiteral("The quick brown fox jumps\n"
- "over the lazy dog\n"
- "1234567890")});
-}
-
-void ItemLibraryResourceView::startDrag(Qt::DropActions /* supportedActions */)
-{
- if (debug)
- qDebug() << Q_FUNC_INFO;
-
- const auto indexes = selectedIndexes();
- if (indexes.isEmpty())
- return;
-
- const QModelIndex &index = indexes.constFirst();
- if (!index.isValid())
- return;
-
- auto fileSystemModel = qobject_cast<CustomFileSystemModel*>(model());
- Q_ASSERT(fileSystemModel);
- QPair<QString, QByteArray> typeAndData = fileSystemModel->resourceTypeAndData(index);
-
- if (typeAndData.first.isEmpty())
- return;
-
- QFileInfo fileInfo = fileSystemModel->fileInfo(index);
-
- auto drag = new QDrag(this);
- drag->setPixmap(fileSystemModel->fileIcon(index).pixmap(128, 128));
- QMimeData *mimeData = new QMimeData;
- mimeData->setData(QLatin1String("application/vnd.bauhaus.libraryresource"),
- fileInfo.absoluteFilePath().toUtf8());
- mimeData->setData(typeAndData.first, typeAndData.second);
- drag->setMimeData(mimeData);
- drag->exec();
-}
-
-bool ItemLibraryResourceView::viewportEvent(QEvent *event)
-{
- if (event->type() == QEvent::ToolTip) {
- auto fileSystemModel = qobject_cast<CustomFileSystemModel *>(model());
- Q_ASSERT(fileSystemModel);
- QHelpEvent *helpEvent = static_cast<QHelpEvent *>(event);
- QModelIndex index = indexAt(helpEvent->pos());
- if (index.isValid()) {
- QFileInfo fi = fileSystemModel->fileInfo(index);
- if (fileSystemModel->previewableSuffixes().contains(fi.suffix())) {
- QString filePath = fi.absoluteFilePath();
- if (!filePath.isEmpty()) {
- if (!m_fontPreviewTooltipBackend->isVisible()
- || m_fontPreviewTooltipBackend->path() != filePath) {
- m_fontPreviewTooltipBackend->setPath(filePath);
- m_fontPreviewTooltipBackend->setName(fi.fileName());
- m_fontPreviewTooltipBackend->showTooltip();
- } else {
- m_fontPreviewTooltipBackend->reposition();
- }
- return true;
- }
- }
- }
- m_fontPreviewTooltipBackend->hideTooltip();
- } else if (event->type() == QEvent::Leave) {
- m_fontPreviewTooltipBackend->hideTooltip();
- } else if (event->type() == QEvent::HoverMove) {
- if (m_fontPreviewTooltipBackend->isVisible()) {
- auto fileSystemModel = qobject_cast<CustomFileSystemModel *>(model());
- Q_ASSERT(fileSystemModel);
- auto *he = static_cast<QHoverEvent *>(event);
- QModelIndex index = indexAt(he->pos());
- if (index.isValid()) {
- QFileInfo fi = fileSystemModel->fileInfo(index);
- if (fi.absoluteFilePath() != m_fontPreviewTooltipBackend->path())
- m_fontPreviewTooltipBackend->hideTooltip();
- else
- m_fontPreviewTooltipBackend->reposition();
- }
- }
- }
-
- return QListView::viewportEvent(event);
-}
-
-} // namespace QmlDesigner
-
diff --git a/src/plugins/qmldesigner/components/itemlibrary/itemlibraryview.cpp b/src/plugins/qmldesigner/components/itemlibrary/itemlibraryview.cpp
index 151e6c5a59..b7f89ec96e 100644
--- a/src/plugins/qmldesigner/components/itemlibrary/itemlibraryview.cpp
+++ b/src/plugins/qmldesigner/components/itemlibrary/itemlibraryview.cpp
@@ -65,8 +65,8 @@ ProjectExplorer::Target *activeTarget(ProjectExplorer::Project *project)
class ImageCacheData
{
public:
- Sqlite::Database database{
- Utils::PathString{Core::ICore::cacheResourcePath() + "/imagecache-v2.db"}};
+ Sqlite::Database database{Utils::PathString{
+ Core::ICore::cacheResourcePath("imagecache-v2.db").toString()}};
ImageCacheStorage<Sqlite::Database> storage{database};
ImageCacheConnectionManager connectionManager;
ImageCacheCollector collector{connectionManager};
diff --git a/src/plugins/qmldesigner/components/itemlibrary/itemlibrarywidget.cpp b/src/plugins/qmldesigner/components/itemlibrary/itemlibrarywidget.cpp
index 290611e2e0..27e9fa3d51 100644
--- a/src/plugins/qmldesigner/components/itemlibrary/itemlibrarywidget.cpp
+++ b/src/plugins/qmldesigner/components/itemlibrary/itemlibrarywidget.cpp
@@ -25,7 +25,7 @@
#include "itemlibrarywidget.h"
-#include "customfilesystemmodel.h"
+#include "itemlibraryassetsmodel.h"
#include "itemlibraryiconimageprovider.h"
#include "itemlibraryimport.h"
@@ -37,6 +37,7 @@
#include <itemlibraryinfo.h>
#include <itemlibrarymodel.h>
#include <itemlibraryaddimportmodel.h>
+#include "itemlibraryassetsiconprovider.h"
#include <metainfo.h>
#include <model.h>
#include <rewritingexception.h>
@@ -46,6 +47,7 @@
#include <utils/algorithm.h>
#include <utils/flowlayout.h>
#include <utils/fileutils.h>
+#include <utils/filesystemwatcher.h>
#include <utils/stylehelper.h>
#include <utils/qtcassert.h>
#include <utils/utilsicons.h>
@@ -75,8 +77,9 @@
namespace QmlDesigner {
-static QString propertyEditorResourcesPath() {
- return Core::ICore::resourcePath() + QStringLiteral("/qmldesigner/propertyEditorQmlSources");
+static QString propertyEditorResourcesPath()
+{
+ return Core::ICore::resourcePath("qmldesigner/propertyEditorQmlSources").toString();
}
bool ItemLibraryWidget::eventFilter(QObject *obj, QEvent *event)
@@ -124,13 +127,16 @@ ItemLibraryWidget::ItemLibraryWidget(AsynchronousImageCache &imageCache,
AsynchronousImageCache &asynchronousFontImageCache,
SynchronousImageCache &synchronousFontImageCache)
: m_itemIconSize(24, 24)
+ , m_fontImageCache(synchronousFontImageCache)
, m_itemLibraryModel(new ItemLibraryModel(this))
, m_itemLibraryAddImportModel(new ItemLibraryAddImportModel(this))
- , m_resourcesFileSystemModel{new CustomFileSystemModel(synchronousFontImageCache, this)}
+ , m_assetsIconProvider(new ItemLibraryAssetsIconProvider(synchronousFontImageCache))
+ , m_fileSystemWatcher(new Utils::FileSystemWatcher(this))
+ , m_assetsModel(new ItemLibraryAssetsModel(synchronousFontImageCache, m_fileSystemWatcher, this))
, m_headerWidget(new QQuickWidget(this))
, m_addImportWidget(new QQuickWidget(this))
, m_itemViewQuickWidget(new QQuickWidget(this))
- , m_resourcesView(new ItemLibraryResourceView(asynchronousFontImageCache, this))
+ , m_assetsWidget(new QQuickWidget(this))
, m_imageCache{imageCache}
{
m_compressionTimer.setInterval(200);
@@ -142,6 +148,8 @@ ItemLibraryWidget::ItemLibraryWidget(AsynchronousImageCache &imageCache,
// create header widget
m_headerWidget->setResizeMode(QQuickWidget::SizeRootObjectToView);
+ m_headerWidget->setMinimumHeight(75);
+ m_headerWidget->setMinimumWidth(100);
Theme::setupTheme(m_headerWidget->engine());
m_headerWidget->engine()->addImportPath(propertyEditorResourcesPath() + "/imports");
m_headerWidget->setClearColor(Theme::getColor(Theme::Color::DSpanelBackground));
@@ -179,12 +187,47 @@ ItemLibraryWidget::ItemLibraryWidget(AsynchronousImageCache &imageCache,
Theme::setupTheme(m_itemViewQuickWidget->engine());
m_itemViewQuickWidget->installEventFilter(this);
- // connect Resources view and its model
- m_resourcesView->setModel(m_resourcesFileSystemModel.data());
+ m_fontPreviewTooltipBackend = std::make_unique<PreviewTooltipBackend>(asynchronousFontImageCache);
+ // Note: Though the text specified here appears in UI, it shouldn't be translated, as it's
+ // a commonly used sentence to preview the font glyphs in latin fonts.
+ // For fonts that do not have latin glyphs, the font family name will have to suffice for preview.
+ m_fontPreviewTooltipBackend->setAuxiliaryData(
+ ImageCache::FontCollectorSizeAuxiliaryData{QSize{300, 300},
+ Theme::getColor(Theme::DStextColor).name(),
+ QStringLiteral("The quick brown fox jumps\n"
+ "over the lazy dog\n"
+ "1234567890")});
+ // create assets widget
+ m_assetsWidget->setResizeMode(QQuickWidget::SizeRootObjectToView);
+ Theme::setupTheme(m_assetsWidget->engine());
+ m_assetsWidget->engine()->addImportPath(propertyEditorResourcesPath() + "/imports");
+ m_assetsWidget->setClearColor(Theme::getColor(Theme::Color::QmlDesigner_BackgroundColorDarkAlternate));
+ m_assetsWidget->engine()->addImageProvider("qmldesigner_assets", m_assetsIconProvider);
+ m_assetsWidget->rootContext()->setContextProperties(QVector<QQmlContext::PropertyPair>{
+ {{"assetsModel"}, QVariant::fromValue(m_assetsModel.data())},
+ {{"rootView"}, QVariant::fromValue(this)},
+ {{"tooltipBackend"}, QVariant::fromValue(m_fontPreviewTooltipBackend.get())}
+ });
+
+ // If project directory contents change, or one of the asset files is modified, we must
+ // reconstruct the model to update the icons
+ connect(m_fileSystemWatcher, &Utils::FileSystemWatcher::directoryChanged, [this](const QString & changedDirPath) {
+ Q_UNUSED(changedDirPath)
+ // TODO: find a clever way to only refresh the changed directory part of the model
+
+ m_assetsModel->refresh();
+
+ // reload assets qml so that an overridden file's image shows the new image
+ QTimer::singleShot(100, [this] {
+ const QString assetsQmlPath = qmlSourcesPath() + "/Assets.qml";
+ m_assetsWidget->engine()->clearComponentCache();
+ m_assetsWidget->setSource(QUrl::fromLocalFile(assetsQmlPath));
+ });
+ });
m_stackedWidget = new QStackedWidget(this);
m_stackedWidget->addWidget(m_itemViewQuickWidget.data());
- m_stackedWidget->addWidget(m_resourcesView.data());
+ m_stackedWidget->addWidget(m_assetsWidget.data());
m_stackedWidget->addWidget(m_addImportWidget.data());
m_stackedWidget->setMinimumHeight(30);
m_stackedWidget->setSizePolicy(QSizePolicy::Ignored, QSizePolicy::Ignored);
@@ -198,34 +241,14 @@ ItemLibraryWidget::ItemLibraryWidget(AsynchronousImageCache &imageCache,
updateSearch();
/* style sheets */
- setStyleSheet(Theme::replaceCssColors(QString::fromUtf8(Utils::FileReader::fetchQrc(QLatin1String(":/qmldesigner/stylesheet.css")))));
- m_resourcesView->setStyleSheet(Theme::replaceCssColors(QString::fromUtf8(Utils::FileReader::fetchQrc(QLatin1String(":/qmldesigner/scrollbar.css")))));
+ setStyleSheet(Theme::replaceCssColors(
+ QString::fromUtf8(Utils::FileReader::fetchQrc(":/qmldesigner/stylesheet.css"))));
m_qmlSourceUpdateShortcut = new QShortcut(QKeySequence(Qt::CTRL + Qt::Key_F5), this);
connect(m_qmlSourceUpdateShortcut, &QShortcut::activated, this, &ItemLibraryWidget::reloadQmlSource);
connect(&m_compressionTimer, &QTimer::timeout, this, &ItemLibraryWidget::updateModel);
- const auto dropSupport = new Utils::DropSupport(
- m_resourcesView.data(), [this](QDropEvent *event, Utils::DropSupport *) {
- // Accept supported file types
- if (event->type() == QDropEvent::DragEnter && !Utils::DropSupport::isFileDrop(event))
- return false; // do not accept drops without files
- bool accept = false;
- const QSet<QString> &suffixes = m_resourcesFileSystemModel->supportedSuffixes();
- const QList<QUrl> urls = event->mimeData()->urls();
- for (const QUrl &url : urls) {
- QFileInfo fi(url.toLocalFile());
- if (suffixes.contains(fi.suffix().toLower())) {
- accept = true;
- break;
- }
- }
- return accept;
- });
- connect(dropSupport, &Utils::DropSupport::filesDropped,
- this, &ItemLibraryWidget::importDroppedFiles);
-
m_itemViewQuickWidget->engine()->addImageProvider("itemlibrary_preview",
new ItemLibraryIconImageProvider{m_imageCache});
@@ -298,6 +321,16 @@ void ItemLibraryWidget::handleAddImport(int index)
updateSearch();
}
+bool ItemLibraryWidget::isSearchActive() const
+{
+ return !m_filterText.isEmpty();
+}
+
+void ItemLibraryWidget::handleFilesDrop(const QStringList &filesPaths)
+{
+ addResources(filesPaths);
+}
+
void ItemLibraryWidget::delayedUpdateModel()
{
static bool disableTimer = DesignerSettings::getValue(DesignerSettingsKey::DISABLE_ITEM_LIBRARY_UPDATE_TIMER).toBool();
@@ -324,7 +357,7 @@ void ItemLibraryWidget::handleTabChanged(int index)
QString ItemLibraryWidget::qmlSourcesPath()
{
- return Core::ICore::resourcePath() + QStringLiteral("/qmldesigner/itemLibraryQmlSources");
+ return Core::ICore::resourcePath("qmldesigner/itemLibraryQmlSources").toString();
}
void ItemLibraryWidget::clearSearchFilter()
@@ -348,6 +381,11 @@ void ItemLibraryWidget::reloadQmlSource()
QTC_ASSERT(QFileInfo::exists(itemLibraryQmlPath), return);
m_itemViewQuickWidget->engine()->clearComponentCache();
m_itemViewQuickWidget->setSource(QUrl::fromLocalFile(itemLibraryQmlPath));
+
+ const QString assetsQmlPath = qmlSourcesPath() + "/Assets.qml";
+ QTC_ASSERT(QFileInfo::exists(assetsQmlPath), return);
+ m_assetsWidget->engine()->clearComponentCache();
+ m_assetsWidget->setSource(QUrl::fromLocalFile(assetsQmlPath));
}
void ItemLibraryWidget::updateModel()
@@ -387,9 +425,7 @@ void ItemLibraryWidget::updateSearch()
m_itemLibraryModel->setSearchText(m_filterText);
m_itemViewQuickWidget->update();
} else if (m_stackedWidget->currentIndex() == 1) { // Assets tab selected
- m_resourcesFileSystemModel->setSearchFilter(m_filterText);
- m_resourcesFileSystemModel->setFilter(QDir::AllDirs | QDir::Files | QDir::NoDotAndDotDot);
- m_resourcesView->scrollToTop();
+ m_assetsModel->setSearchText(m_filterText);
} else if (m_stackedWidget->currentIndex() == 2) { // QML imports tab selected
m_itemLibraryAddImportModel->setSearchText(m_filterText);
}
@@ -405,10 +441,7 @@ void ItemLibraryWidget::handlePriorityImportsChanged()
void ItemLibraryWidget::setResourcePath(const QString &resourcePath)
{
- if (m_resourcesView->model() == m_resourcesFileSystemModel.data()) {
- m_resourcesFileSystemModel->setRootPath(resourcePath);
- m_resourcesView->setRootIndex(m_resourcesFileSystemModel->indexForPath(resourcePath));
- }
+ m_assetsModel->setRootPath(resourcePath);
updateSearch();
}
@@ -421,6 +454,51 @@ void ItemLibraryWidget::startDragAndDrop(const QVariant &itemLibEntry, const QPo
m_dragStartPoint = mousePos.toPoint();
}
+void ItemLibraryWidget::startDragAsset(const QString &assetPath)
+{
+ QFileInfo fileInfo(assetPath);
+ QPair<QString, QByteArray> typeAndData = getAssetTypeAndData(fileInfo);
+
+ if (typeAndData.first.isEmpty())
+ return;
+
+ auto drag = new QDrag(this);
+ drag->setPixmap(m_assetsIconProvider->requestPixmap(assetPath, nullptr, {128, 128}));
+ QMimeData *mimeData = new QMimeData;
+ mimeData->setData(QLatin1String("application/vnd.bauhaus.libraryresource"),
+ fileInfo.absoluteFilePath().toUtf8());
+ mimeData->setData(typeAndData.first, typeAndData.second);
+ drag->setMimeData(mimeData);
+ drag->exec();
+}
+
+QPair<QString, QByteArray> ItemLibraryWidget::getAssetTypeAndData(const QFileInfo &fi) const
+{
+ QString suffix = "*." + fi.suffix().toLower();
+ if (!suffix.isEmpty()) {
+ if (ItemLibraryAssetsModel::supportedImageSuffixes().contains(suffix)) {
+ // Data: Image format (suffix)
+ return {"application/vnd.bauhaus.libraryresource.image", suffix.toUtf8()};
+ } else if (ItemLibraryAssetsModel::supportedFontSuffixes().contains(suffix)) {
+ // Data: Font family name
+ QRawFont font(fi.absoluteFilePath(), 10);
+ QString fontFamily = font.isValid() ? font.familyName() : "";
+ return {"application/vnd.bauhaus.libraryresource.font", fontFamily.toUtf8()};
+ } else if (ItemLibraryAssetsModel::supportedShaderSuffixes().contains(suffix)) {
+ // Data: shader type, frament (f) or vertex (v)
+ return {"application/vnd.bauhaus.libraryresource.shader",
+ ItemLibraryAssetsModel::supportedFragmentShaderSuffixes().contains(suffix) ? "f" : "v"};
+ } else if (ItemLibraryAssetsModel::supportedAudioSuffixes().contains(suffix)) {
+ // No extra data for sounds
+ return {"application/vnd.bauhaus.libraryresource.sound", {}};
+ } else if (ItemLibraryAssetsModel::supportedTexture3DSuffixes().contains(suffix)) {
+ // Data: Image format (suffix)
+ return {"application/vnd.bauhaus.libraryresource.texture3d", suffix.toUtf8()};
+ }
+ }
+ return {};
+}
+
void ItemLibraryWidget::setFlowMode(bool b)
{
m_itemLibraryModel->setFlowMode(b);
@@ -525,15 +603,4 @@ void ItemLibraryWidget::addResources(const QStringList &files)
}
}
-void ItemLibraryWidget::importDroppedFiles(const QList<Utils::DropSupport::FileSpec> &files)
-{
- QStringList fileNames;
- for (const auto &file : files) {
- QFileInfo fi(file.filePath);
- if (m_resourcesFileSystemModel->supportedSuffixes().contains(fi.suffix().toLower()))
- fileNames.append(fi.absoluteFilePath());
- }
- if (!fileNames.isEmpty())
- addResources(fileNames);
-}
} // namespace QmlDesigner
diff --git a/src/plugins/qmldesigner/components/itemlibrary/itemlibrarywidget.h b/src/plugins/qmldesigner/components/itemlibrary/itemlibrarywidget.h
index 2883cebb63..122e67eacd 100644
--- a/src/plugins/qmldesigner/components/itemlibrary/itemlibrarywidget.h
+++ b/src/plugins/qmldesigner/components/itemlibrary/itemlibrarywidget.h
@@ -26,12 +26,12 @@
#pragma once
#include "itemlibraryinfo.h"
-#include "itemlibraryresourceview.h"
#include "import.h"
#include <utils/fancylineedit.h>
#include <utils/dropsupport.h>
#include <previewtooltip/previewtooltipbackend.h>
+#include "itemlibraryassetsmodel.h"
#include <QFrame>
#include <QToolButton>
@@ -48,6 +48,8 @@ class QStackedWidget;
class QShortcut;
QT_END_NAMESPACE
+namespace Utils { class FileSystemWatcher; }
+
namespace QmlDesigner {
class MetaInfo;
@@ -55,8 +57,9 @@ class ItemLibraryEntry;
class Model;
class CustomFileSystemModel;
-
class ItemLibraryModel;
+class ItemLibraryAssetsIconProvider;
+class ItemLibraryAssetsModel;
class ItemLibraryAddImportModel;
class ItemLibraryResourceView;
class SynchronousImageCache;
@@ -87,8 +90,10 @@ public:
void setResourcePath(const QString &resourcePath);
void setModel(Model *model);
void setFlowMode(bool b);
+ QPair<QString, QByteArray> getAssetTypeAndData(const QFileInfo &fi) const;
Q_INVOKABLE void startDragAndDrop(const QVariant &itemLibEntry, const QPointF &mousePos);
+ Q_INVOKABLE void startDragAsset(const QString &assetPath);
Q_INVOKABLE void removeImport(const QString &importUrl);
Q_INVOKABLE void addImportForItem(const QString &importUrl);
Q_INVOKABLE void handleTabChanged(int index);
@@ -96,6 +101,9 @@ public:
Q_INVOKABLE void handleAddAsset();
Q_INVOKABLE void handleSearchfilterChanged(const QString &filterText);
Q_INVOKABLE void handleAddImport(int index);
+ Q_INVOKABLE bool isSearchActive() const;
+ Q_INVOKABLE void handleFilesDrop(const QStringList &filesPaths);
+ Q_INVOKABLE QSet<QString> supportedSuffixes() const { return m_assetsModel->supportedSuffixes(); };
signals:
void itemActivated(const QString& itemName);
@@ -107,26 +115,29 @@ private:
void reloadQmlSource();
void addResources(const QStringList &files);
- void importDroppedFiles(const QList<Utils::DropSupport::FileSpec> &files);
void updateSearch();
void handlePriorityImportsChanged();
QTimer m_compressionTimer;
QSize m_itemIconSize;
+ SynchronousImageCache &m_fontImageCache;
QPointer<ItemLibraryInfo> m_itemLibraryInfo;
QPointer<ItemLibraryModel> m_itemLibraryModel;
QPointer<ItemLibraryAddImportModel> m_itemLibraryAddImportModel;
- QPointer<CustomFileSystemModel> m_resourcesFileSystemModel;
+ ItemLibraryAssetsIconProvider *m_assetsIconProvider = nullptr;
+ Utils::FileSystemWatcher *m_fileSystemWatcher = nullptr;
+ QPointer<ItemLibraryAssetsModel> m_assetsModel;
QPointer<QStackedWidget> m_stackedWidget;
QScopedPointer<QQuickWidget> m_headerWidget;
QScopedPointer<QQuickWidget> m_addImportWidget;
QScopedPointer<QQuickWidget> m_itemViewQuickWidget;
- QScopedPointer<ItemLibraryResourceView> m_resourcesView;
+ QScopedPointer<QQuickWidget> m_assetsWidget;
std::unique_ptr<PreviewTooltipBackend> m_previewTooltipBackend;
+ std::unique_ptr<PreviewTooltipBackend> m_fontPreviewTooltipBackend;
QShortcut *m_qmlSourceUpdateShortcut;
AsynchronousImageCache &m_imageCache;
diff --git a/src/plugins/qmldesigner/components/navigator/navigatorview.cpp b/src/plugins/qmldesigner/components/navigator/navigatorview.cpp
index b344077788..2ba7941b3d 100644
--- a/src/plugins/qmldesigner/components/navigator/navigatorview.cpp
+++ b/src/plugins/qmldesigner/components/navigator/navigatorview.cpp
@@ -346,9 +346,7 @@ void NavigatorView::instanceErrorChanged(const QVector<ModelNode> &errorNodeList
m_currentModelInterface->notifyDataChanged(modelNode);
}
-void NavigatorView::nodeOrderChanged(const NodeListProperty &listProperty,
- const ModelNode &/*node*/,
- int /*oldIndex*/)
+void NavigatorView::nodeOrderChanged(const NodeListProperty &listProperty)
{
m_currentModelInterface->notifyModelNodesMoved(listProperty.directSubNodes());
diff --git a/src/plugins/qmldesigner/components/navigator/navigatorview.h b/src/plugins/qmldesigner/components/navigator/navigatorview.h
index b78c9e612a..7e811ca39f 100644
--- a/src/plugins/qmldesigner/components/navigator/navigatorview.h
+++ b/src/plugins/qmldesigner/components/navigator/navigatorview.h
@@ -75,7 +75,7 @@ public:
void nodeAboutToBeRemoved(const ModelNode &removedNode) override;
void nodeRemoved(const ModelNode &removedNode, const NodeAbstractProperty &parentProperty, PropertyChangeFlags propertyChange) override;
- void nodeOrderChanged(const NodeListProperty &listProperty, const ModelNode &movedNode, int oldIndex) override;
+ void nodeOrderChanged(const NodeListProperty &listProperty) override;
void nodeReparented(const ModelNode &node, const NodeAbstractProperty &newPropertyParent, const NodeAbstractProperty &oldPropertyParent, AbstractView::PropertyChangeFlags propertyChange) override;
void rootNodeTypeChanged(const QString &type, int majorVersion, int minorVersion) override;
@@ -133,8 +133,6 @@ private:
QHash<QUrl, QHash<QString, bool>> m_expandMap;
NavigatorModelInterface *m_currentModelInterface = nullptr;
-
- friend class TestNavigator;
};
}
diff --git a/src/plugins/qmldesigner/components/pathtool/pathitem.h b/src/plugins/qmldesigner/components/pathtool/pathitem.h
index 17981283a6..aa75a0aff0 100644
--- a/src/plugins/qmldesigner/components/pathtool/pathitem.h
+++ b/src/plugins/qmldesigner/components/pathtool/pathitem.h
@@ -65,7 +65,8 @@ private:
class PathItem : public QGraphicsObject
{
Q_OBJECT
- friend class PathUpdateDisabler;
+ friend PathUpdateDisabler;
+
public:
enum
{
diff --git a/src/plugins/qmldesigner/components/propertyeditor/gradientpresetcustomlistmodel.cpp b/src/plugins/qmldesigner/components/propertyeditor/gradientpresetcustomlistmodel.cpp
index 64008fade5..7396b32b41 100644
--- a/src/plugins/qmldesigner/components/propertyeditor/gradientpresetcustomlistmodel.cpp
+++ b/src/plugins/qmldesigner/components/propertyeditor/gradientpresetcustomlistmodel.cpp
@@ -39,14 +39,14 @@
namespace Internal {
static const char settingsKey[] = "GradientPresetCustomList";
-static const char settingsFileName[] = "/GradientPresets.ini";
+static const char settingsFileName[] = "GradientPresets.ini";
QString settingsFullFilePath(const QSettings::Scope &scope)
{
if (scope == QSettings::SystemScope)
- return Core::ICore::installerResourcePath() + settingsFileName;
+ return Core::ICore::installerResourcePath(settingsFileName).toString();
- return Core::ICore::userResourcePath() + settingsFileName;
+ return Core::ICore::userResourcePath(settingsFileName).toString();
}
} // namespace Internal
diff --git a/src/plugins/qmldesigner/components/propertyeditor/gradientpresetitem.cpp b/src/plugins/qmldesigner/components/propertyeditor/gradientpresetitem.cpp
index fbead98717..6afa715f4d 100644
--- a/src/plugins/qmldesigner/components/propertyeditor/gradientpresetitem.cpp
+++ b/src/plugins/qmldesigner/components/propertyeditor/gradientpresetitem.cpp
@@ -167,12 +167,7 @@ QString GradientPresetItem::getNameByPreset(Preset value)
QGradient GradientPresetItem::createGradientFromPreset(Preset value)
{
-#if QT_VERSION >= QT_VERSION_CHECK(5, 12, 0)
return QGradient(value);
-#else
- Q_UNUSED(value)
- return {};
-#endif
}
QDebug &operator<<(QDebug &stream, const GradientPresetItem &gradient)
diff --git a/src/plugins/qmldesigner/components/propertyeditor/gradientpresetitem.h b/src/plugins/qmldesigner/components/propertyeditor/gradientpresetitem.h
index cec45bb4af..ba5f2903e5 100644
--- a/src/plugins/qmldesigner/components/propertyeditor/gradientpresetitem.h
+++ b/src/plugins/qmldesigner/components/propertyeditor/gradientpresetitem.h
@@ -39,17 +39,8 @@ class GradientPresetItem
Q_PROPERTY(int presetID READ presetID FINAL)
public:
-#if QT_VERSION >= QT_VERSION_CHECK(5, 12, 0)
using Preset = QGradient::Preset;
-#else
- enum Preset {};
-#endif
-
-#if QT_VERSION >= QT_VERSION_CHECK(5, 14, 0)
static const int numPresets = Preset::NumPresets;
-#else
- static const int numPresets = 181;
-#endif
explicit GradientPresetItem();
explicit GradientPresetItem(const QGradient &value, const QString &name = QString());
diff --git a/src/plugins/qmldesigner/components/propertyeditor/propertyeditorcontextobject.cpp b/src/plugins/qmldesigner/components/propertyeditor/propertyeditorcontextobject.cpp
index 967f5cbd4c..09a2d2b058 100644
--- a/src/plugins/qmldesigner/components/propertyeditor/propertyeditorcontextobject.cpp
+++ b/src/plugins/qmldesigner/components/propertyeditor/propertyeditorcontextobject.cpp
@@ -28,10 +28,11 @@
#include <abstractview.h>
#include <nodemetainfo.h>
+#include <rewritingexception.h>
#include <qmldesignerplugin.h>
-#include <qmlobjectnode.h>
#include <qmlmodelnodeproxy.h>
-#include <rewritingexception.h>
+#include <qmlobjectnode.h>
+#include <qmltimeline.h>
#include <coreplugin/messagebox.h>
#include <utils/algorithm.h>
@@ -302,6 +303,9 @@ void PropertyEditorContextObject::insertKeyframe(const QString &propertyName)
{
QTC_ASSERT(m_model && m_model->rewriterView(), return);
+ if (isBlocked(propertyName))
+ return;
+
/* Ideally we should not missuse the rewriterView
* If we add more code here we have to forward the property editor view */
RewriterView *rewriterView = m_model->rewriterView();
@@ -310,9 +314,12 @@ void PropertyEditorContextObject::insertKeyframe(const QString &propertyName)
ModelNode selectedNode = rewriterView->selectedModelNodes().constFirst();
- rewriterView->emitCustomNotification("INSERT_KEYFRAME",
- { selectedNode },
- { propertyName });
+ QmlTimeline timeline = rewriterView->currentTimeline();
+
+ QTC_ASSERT(timeline.isValid(), return );
+ QTC_ASSERT(selectedNode.isValid(), return );
+
+ timeline.insertKeyframe(selectedNode, propertyName.toUtf8());
}
int PropertyEditorContextObject::majorVersion() const
@@ -553,6 +560,20 @@ QStringList PropertyEditorContextObject::allStatesForId(const QString &id)
return {};
}
+bool PropertyEditorContextObject::isBlocked(const QString &propName) const
+{
+ if (m_model && m_model->rewriterView()) {
+ const QList<ModelNode> nodes = m_model->rewriterView()->selectedModelNodes();
+ QScopedPointer<QmlObjectNode> objNode;
+ for (const auto &node : nodes) {
+ objNode.reset(QmlObjectNode::getQmlObjectNodeOfCorrectType(node));
+ if (objNode->isBlocked(propName.toUtf8()))
+ return true;
+ }
+ }
+ return false;
+}
+
void EasingCurveEditor::registerDeclarativeType()
{
qmlRegisterType<EasingCurveEditor>("HelperWidgets", 2, 0, "EasingCurveEditor");
diff --git a/src/plugins/qmldesigner/components/propertyeditor/propertyeditorcontextobject.h b/src/plugins/qmldesigner/components/propertyeditor/propertyeditorcontextobject.h
index 04d5d074bb..8b7947bd52 100644
--- a/src/plugins/qmldesigner/components/propertyeditor/propertyeditorcontextobject.h
+++ b/src/plugins/qmldesigner/components/propertyeditor/propertyeditorcontextobject.h
@@ -99,6 +99,8 @@ public:
Q_INVOKABLE QStringList allStatesForId(const QString &id);
+ Q_INVOKABLE bool isBlocked(const QString &propName) const;
+
int majorVersion() const;
int majorQtQuickVersion() const;
int minorQtQuickVersion() const;
diff --git a/src/plugins/qmldesigner/components/propertyeditor/propertyeditorqmlbackend.cpp b/src/plugins/qmldesigner/components/propertyeditor/propertyeditorqmlbackend.cpp
index e498d20156..ebaf1da7b6 100644
--- a/src/plugins/qmldesigner/components/propertyeditor/propertyeditorqmlbackend.cpp
+++ b/src/plugins/qmldesigner/components/propertyeditor/propertyeditorqmlbackend.cpp
@@ -530,8 +530,9 @@ void PropertyEditorQmlBackend::initialSetup(const TypeName &typeName, const QUrl
contextObject()->setGlobalBaseUrl(QUrl());
}
-QString PropertyEditorQmlBackend::propertyEditorResourcesPath() {
- return Core::ICore::resourcePath() + QStringLiteral("/qmldesigner/propertyEditorQmlSources");
+QString PropertyEditorQmlBackend::propertyEditorResourcesPath()
+{
+ return Core::ICore::resourcePath("qmldesigner/propertyEditorQmlSources").toString();
}
inline bool dotPropertyHeuristic(const QmlObjectNode &node, const NodeMetaInfo &type, const PropertyName &name)
diff --git a/src/plugins/qmldesigner/components/propertyeditor/propertyeditorvalue.cpp b/src/plugins/qmldesigner/components/propertyeditor/propertyeditorvalue.cpp
index ec78ed97af..684a1746e0 100644
--- a/src/plugins/qmldesigner/components/propertyeditor/propertyeditorvalue.cpp
+++ b/src/plugins/qmldesigner/components/propertyeditor/propertyeditorvalue.cpp
@@ -39,6 +39,7 @@
#include <QRegularExpression>
#include <QUrl>
+#include <QScopedPointer>
//using namespace QmlDesigner;
@@ -610,14 +611,15 @@ void PropertyEditorNodeWrapper::changeValue(const QString &propertyName)
if (name.isNull())
return;
if (m_modelNode.isValid()) {
- QmlDesigner::QmlObjectNode qmlObjectNode(m_modelNode);
+ QScopedPointer<QmlDesigner::QmlObjectNode> qmlObjectNode{
+ QmlDesigner::QmlObjectNode::getQmlObjectNodeOfCorrectType(m_modelNode)};
auto valueObject = qvariant_cast<PropertyEditorValue *>(m_valuesPropertyMap.value(QString::fromLatin1(name)));
if (valueObject->value().isValid())
- qmlObjectNode.setVariantProperty(name, valueObject->value());
+ qmlObjectNode->setVariantProperty(name, valueObject->value());
else
- qmlObjectNode.removeProperty(name);
+ qmlObjectNode->removeProperty(name);
}
}
diff --git a/src/plugins/qmldesigner/components/propertyeditor/propertyeditorview.cpp b/src/plugins/qmldesigner/components/propertyeditor/propertyeditorview.cpp
index 873d7ba6a8..abdfc2ebd4 100644
--- a/src/plugins/qmldesigner/components/propertyeditor/propertyeditorview.cpp
+++ b/src/plugins/qmldesigner/components/propertyeditor/propertyeditorview.cpp
@@ -56,6 +56,7 @@
#include <QTimer>
#include <QShortcut>
#include <QApplication>
+#include <QScopedPointer>
enum {
debug = false
@@ -88,7 +89,7 @@ PropertyEditorView::PropertyEditorView(QWidget *parent) :
connect(m_updateShortcut, &QShortcut::activated, this, &PropertyEditorView::reloadQml);
m_stackedWidget->setStyleSheet(Theme::replaceCssColors(
- QString::fromUtf8(Utils::FileReader::fetchQrc(QStringLiteral(":/qmldesigner/stylesheet.css")))));
+ QString::fromUtf8(Utils::FileReader::fetchQrc(":/qmldesigner/stylesheet.css"))));
m_stackedWidget->setMinimumWidth(340);
m_stackedWidget->move(0, 0);
connect(m_stackedWidget, &PropertyEditorWidget::resized, this, &PropertyEditorView::updateSize);
@@ -251,7 +252,7 @@ void PropertyEditorView::changeExpression(const QString &propertyName)
PropertyName underscoreName(name);
underscoreName.replace('.', '_');
- QmlObjectNode qmlObjectNode(m_selectedNode);
+ QScopedPointer<QmlObjectNode> qmlObjectNode {QmlObjectNode::getQmlObjectNodeOfCorrectType(m_selectedNode)};
PropertyEditorValue *value = m_qmlBackEndForCurrentType->propertyValueForName(QString::fromLatin1(underscoreName));
if (!value) {
@@ -259,33 +260,33 @@ void PropertyEditorView::changeExpression(const QString &propertyName)
return;
}
- if (qmlObjectNode.modelNode().metaInfo().isValid() && qmlObjectNode.modelNode().metaInfo().hasProperty(name)) {
- if (qmlObjectNode.modelNode().metaInfo().propertyTypeName(name) == "QColor") {
+ if (qmlObjectNode->modelNode().metaInfo().isValid() && qmlObjectNode->modelNode().metaInfo().hasProperty(name)) {
+ if (qmlObjectNode->modelNode().metaInfo().propertyTypeName(name) == "QColor") {
if (QColor(value->expression().remove('"')).isValid()) {
- qmlObjectNode.setVariantProperty(name, QColor(value->expression().remove('"')));
+ qmlObjectNode->setVariantProperty(name, QColor(value->expression().remove('"')));
return;
}
- } else if (qmlObjectNode.modelNode().metaInfo().propertyTypeName(name) == "bool") {
+ } else if (qmlObjectNode->modelNode().metaInfo().propertyTypeName(name) == "bool") {
if (value->expression().compare(QLatin1String("false"), Qt::CaseInsensitive) == 0
|| value->expression().compare(QLatin1String("true"), Qt::CaseInsensitive) == 0) {
if (value->expression().compare(QLatin1String("true"), Qt::CaseInsensitive) == 0)
- qmlObjectNode.setVariantProperty(name, true);
+ qmlObjectNode->setVariantProperty(name, true);
else
- qmlObjectNode.setVariantProperty(name, false);
+ qmlObjectNode->setVariantProperty(name, false);
return;
}
- } else if (qmlObjectNode.modelNode().metaInfo().propertyTypeName(name) == "int") {
+ } else if (qmlObjectNode->modelNode().metaInfo().propertyTypeName(name) == "int") {
bool ok;
int intValue = value->expression().toInt(&ok);
if (ok) {
- qmlObjectNode.setVariantProperty(name, intValue);
+ qmlObjectNode->setVariantProperty(name, intValue);
return;
}
- } else if (qmlObjectNode.modelNode().metaInfo().propertyTypeName(name) == "qreal") {
+ } else if (qmlObjectNode->modelNode().metaInfo().propertyTypeName(name) == "qreal") {
bool ok;
qreal realValue = value->expression().toDouble(&ok);
if (ok) {
- qmlObjectNode.setVariantProperty(name, realValue);
+ qmlObjectNode->setVariantProperty(name, realValue);
return;
}
}
@@ -296,8 +297,8 @@ void PropertyEditorView::changeExpression(const QString &propertyName)
return;
}
- if (qmlObjectNode.expression(name) != value->expression() || !qmlObjectNode.propertyAffectedByCurrentState(name))
- qmlObjectNode.setBindingProperty(name, value->expression());
+ if (qmlObjectNode->expression(name) != value->expression() || !qmlObjectNode->propertyAffectedByCurrentState(name))
+ qmlObjectNode->setBindingProperty(name, value->expression());
}); /* end of transaction */
}
@@ -465,11 +466,13 @@ void PropertyEditorView::setupQmlBackend()
m_stackedWidget->addWidget(currentQmlBackend->widget());
m_qmlBackendHash.insert(qmlFile.toString(), currentQmlBackend);
- QmlObjectNode qmlObjectNode;
+ QScopedPointer<QmlObjectNode> qmlObjectNode;
if (m_selectedNode.isValid()) {
- qmlObjectNode = QmlObjectNode(m_selectedNode);
- Q_ASSERT(qmlObjectNode.isValid());
- currentQmlBackend->setup(qmlObjectNode, currentStateName, qmlSpecificsFile, this);
+ qmlObjectNode.reset(QmlObjectNode::getQmlObjectNodeOfCorrectType(m_selectedNode));
+ Q_ASSERT(qmlObjectNode->isValid());
+ currentQmlBackend->setup(*qmlObjectNode, currentStateName, qmlSpecificsFile, this);
+ } else {
+ qmlObjectNode.reset(new QmlObjectNode);
}
currentQmlBackend->context()->setContextProperty("finishedNotify", QVariant(false));
if (specificQmlData.isEmpty())
@@ -480,14 +483,16 @@ void PropertyEditorView::setupQmlBackend()
currentQmlBackend->setSource(qmlFile);
currentQmlBackend->context()->setContextProperty("finishedNotify", QVariant(true));
} else {
- QmlObjectNode qmlObjectNode;
+ QScopedPointer<QmlObjectNode> qmlObjectNode;
if (m_selectedNode.isValid())
- qmlObjectNode = QmlObjectNode(m_selectedNode);
+ qmlObjectNode.reset(QmlObjectNode::getQmlObjectNodeOfCorrectType(m_selectedNode));
+ else
+ qmlObjectNode.reset(new QmlObjectNode);
currentQmlBackend->context()->setContextProperty("finishedNotify", QVariant(false));
if (specificQmlData.isEmpty())
currentQmlBackend->contextObject()->setSpecificQmlData(specificQmlData);
- currentQmlBackend->setup(qmlObjectNode, currentStateName, qmlSpecificsFile, this);
+ currentQmlBackend->setup(*qmlObjectNode, currentStateName, qmlSpecificsFile, this);
currentQmlBackend->contextObject()->setGlobalBaseUrl(qmlFile);
currentQmlBackend->contextObject()->setSpecificQmlData(specificQmlData);
}
@@ -509,8 +514,10 @@ void PropertyEditorView::commitVariantValueToModel(const PropertyName &propertyN
RewriterTransaction transaction = beginRewriterTransaction("PropertyEditorView::commitVariantValueToMode");
for (const ModelNode &node : m_selectedNode.view()->selectedModelNodes()) {
- if (QmlObjectNode::isValidQmlObjectNode(node))
- QmlObjectNode(node).setVariantProperty(propertyName, value);
+ if (QmlObjectNode::isValidQmlObjectNode(node)) {
+ QScopedPointer<QmlObjectNode>{QmlObjectNode::getQmlObjectNodeOfCorrectType(node)}
+ ->setVariantProperty(propertyName, value);
+ }
}
transaction.commit();
}
diff --git a/src/plugins/qmldesigner/components/richtexteditor/richtexteditor.cpp b/src/plugins/qmldesigner/components/richtexteditor/richtexteditor.cpp
index 1cce16b26c..5121de7685 100644
--- a/src/plugins/qmldesigner/components/richtexteditor/richtexteditor.cpp
+++ b/src/plugins/qmldesigner/components/richtexteditor/richtexteditor.cpp
@@ -587,11 +587,7 @@ void RichTextEditor::setupTableActions()
tableFormat.setCellSpacing(2.0);
tableFormat.setCellPadding(2.0);
tableFormat.setBorder(1.0);
-
-#if (QT_VERSION >= QT_VERSION_CHECK(5, 14, 0))
tableFormat.setBorderCollapse(true);
-#endif
-
cursor.insertTable(1, 1, tableFormat);
//move cursor into the first cell of the table:
diff --git a/src/plugins/qmldesigner/components/stateseditor/stateseditorview.cpp b/src/plugins/qmldesigner/components/stateseditor/stateseditorview.cpp
index a25cb385d3..12fff40c79 100644
--- a/src/plugins/qmldesigner/components/stateseditor/stateseditorview.cpp
+++ b/src/plugins/qmldesigner/components/stateseditor/stateseditorview.cpp
@@ -211,9 +211,9 @@ void StatesEditorView::resetModel()
if (m_statesEditorWidget) {
if (currentState().isBaseState())
- m_statesEditorWidget->setCurrentStateInternalId(currentState().modelNode().internalId());
- else
m_statesEditorWidget->setCurrentStateInternalId(0);
+ else
+ m_statesEditorWidget->setCurrentStateInternalId(currentState().modelNode().internalId());
}
}
@@ -526,7 +526,7 @@ void StatesEditorView::nodeReparented(const ModelNode &node, const NodeAbstractP
}
}
-void StatesEditorView::nodeOrderChanged(const NodeListProperty &listProperty, const ModelNode & /*movedNode*/, int /*oldIndex*/)
+void StatesEditorView::nodeOrderChanged(const NodeListProperty &listProperty)
{
if (listProperty.isValid() && listProperty.parentModelNode().isRootNode() && listProperty.name() == "states")
resetModel();
diff --git a/src/plugins/qmldesigner/components/stateseditor/stateseditorview.h b/src/plugins/qmldesigner/components/stateseditor/stateseditorview.h
index 44b4a3a380..1ac7a6f39f 100644
--- a/src/plugins/qmldesigner/components/stateseditor/stateseditorview.h
+++ b/src/plugins/qmldesigner/components/stateseditor/stateseditorview.h
@@ -73,7 +73,7 @@ public:
const NodeAbstractProperty &newPropertyParent,
const NodeAbstractProperty &oldPropertyParent,
AbstractView::PropertyChangeFlags propertyChange) override;
- void nodeOrderChanged(const NodeListProperty &listProperty, const ModelNode &movedNode, int oldIndex) override;
+ void nodeOrderChanged(const NodeListProperty &listProperty) override;
void bindingPropertiesChanged(const QList<BindingProperty>& propertyList, PropertyChangeFlags propertyChange) override;
void variantPropertiesChanged(const QList<VariantProperty>& propertyList, PropertyChangeFlags propertyChange) override;
diff --git a/src/plugins/qmldesigner/components/stateseditor/stateseditorwidget.cpp b/src/plugins/qmldesigner/components/stateseditor/stateseditorwidget.cpp
index b6b301b855..6b13b890d4 100644
--- a/src/plugins/qmldesigner/components/stateseditor/stateseditorwidget.cpp
+++ b/src/plugins/qmldesigner/components/stateseditor/stateseditorwidget.cpp
@@ -56,8 +56,9 @@ enum {
namespace QmlDesigner {
-static QString propertyEditorResourcesPath() {
- return Core::ICore::resourcePath() + QStringLiteral("/qmldesigner/propertyEditorQmlSources");
+static QString propertyEditorResourcesPath()
+{
+ return Core::ICore::resourcePath("qmldesigner/propertyEditorQmlSources").toString();
}
int StatesEditorWidget::currentStateInternalId() const
@@ -119,8 +120,9 @@ StatesEditorWidget::StatesEditorWidget(StatesEditorView *statesEditorView, State
StatesEditorWidget::~StatesEditorWidget() = default;
-QString StatesEditorWidget::qmlSourcesPath() {
- return Core::ICore::resourcePath() + QStringLiteral("/qmldesigner/statesEditorQmlSources");
+QString StatesEditorWidget::qmlSourcesPath()
+{
+ return Core::ICore::resourcePath("qmldesigner/statesEditorQmlSources").toString();
}
void StatesEditorWidget::toggleStatesViewExpanded()
diff --git a/src/plugins/qmldesigner/components/texteditor/texteditorwidget.cpp b/src/plugins/qmldesigner/components/texteditor/texteditorwidget.cpp
index a1e2cb6fc1..b8747f7102 100644
--- a/src/plugins/qmldesigner/components/texteditor/texteditorwidget.cpp
+++ b/src/plugins/qmldesigner/components/texteditor/texteditorwidget.cpp
@@ -85,7 +85,9 @@ void TextEditorWidget::setTextEditor(TextEditor::BaseTextEditor *textEditor)
});
textEditor->editorWidget()->installEventFilter(this);
- static QString styleSheet = Theme::replaceCssColors(QString::fromUtf8(Utils::FileReader::fetchQrc(QLatin1String(":/qmldesigner/scrollbar.css"))));
+ static QString styleSheet = Theme::replaceCssColors(
+ QString::fromUtf8(Utils::FileReader::fetchQrc(
+ ":/qmldesigner/scrollbar.css")));
textEditor->editorWidget()->verticalScrollBar()->setStyleSheet(styleSheet);
textEditor->editorWidget()->horizontalScrollBar()->setStyleSheet(styleSheet);
}
diff --git a/src/plugins/qmldesigner/components/timelineeditor/preseteditor.cpp b/src/plugins/qmldesigner/components/timelineeditor/preseteditor.cpp
index fd17b10d9a..d57caf0e1a 100644
--- a/src/plugins/qmldesigner/components/timelineeditor/preseteditor.cpp
+++ b/src/plugins/qmldesigner/components/timelineeditor/preseteditor.cpp
@@ -141,14 +141,14 @@ QIcon paintPreview(const EasingCurve &curve, const QColor& background, const QCo
namespace Internal {
static const char settingsKey[] = "EasingCurveList";
-static const char settingsFileName[] = "/EasingCurves.ini";
+static const char settingsFileName[] = "EasingCurves.ini";
QString settingsFullFilePath(const QSettings::Scope &scope)
{
if (scope == QSettings::SystemScope)
- return Core::ICore::installerResourcePath() + settingsFileName;
+ return Core::ICore::installerResourcePath(settingsFileName).toString();
- return Core::ICore::userResourcePath() + settingsFileName;
+ return Core::ICore::userResourcePath(settingsFileName).toString();
}
} // namespace Internal
diff --git a/src/plugins/qmldesigner/components/timelineeditor/timelinecontrols.cpp b/src/plugins/qmldesigner/components/timelineeditor/timelinecontrols.cpp
index 21f5af9eff..185b12ea42 100644
--- a/src/plugins/qmldesigner/components/timelineeditor/timelinecontrols.cpp
+++ b/src/plugins/qmldesigner/components/timelineeditor/timelinecontrols.cpp
@@ -56,9 +56,7 @@ FloatControl::FloatControl()
setValue(0.0);
setButtonSymbols(QAbstractSpinBox::NoButtons);
setFrame(false);
-#if QT_VERSION >= QT_VERSION_CHECK(5, 12, 0)
setStepType(QAbstractSpinBox::AdaptiveDecimalStepType);
-#endif
setMinimum(std::numeric_limits<float>::lowest());
setMaximum(std::numeric_limits<float>::max());
diff --git a/src/plugins/qmldesigner/components/timelineeditor/timelinegraphicsscene.cpp b/src/plugins/qmldesigner/components/timelineeditor/timelinegraphicsscene.cpp
index c86d3fffdb..0b67542fc6 100644
--- a/src/plugins/qmldesigner/components/timelineeditor/timelinegraphicsscene.cpp
+++ b/src/plugins/qmldesigner/components/timelineeditor/timelinegraphicsscene.cpp
@@ -511,7 +511,11 @@ QGraphicsView *AbstractScrollGraphicsScene::rulerView() const
QmlTimeline TimelineGraphicsScene::currentTimeline() const
{
- return QmlTimeline(timelineModelNode());
+ QmlTimeline timeline(timelineModelNode());
+ if (timeline.isValid()) {
+ QTC_ASSERT(timeline == timelineView()->currentTimeline(), ;);
+ }
+ return timelineView()->currentTimeline();
}
QRectF AbstractScrollGraphicsScene::selectionBounds() const
diff --git a/src/plugins/qmldesigner/components/timelineeditor/timelinepropertyitem.cpp b/src/plugins/qmldesigner/components/timelineeditor/timelinepropertyitem.cpp
index fa1d258c28..77f0bbf34c 100644
--- a/src/plugins/qmldesigner/components/timelineeditor/timelinepropertyitem.cpp
+++ b/src/plugins/qmldesigner/components/timelineeditor/timelinepropertyitem.cpp
@@ -56,6 +56,7 @@
#include <QLineEdit>
#include <QMenu>
#include <QPainter>
+#include <QScopedPointer>
#include <algorithm>
@@ -354,8 +355,9 @@ void TimelinePropertyItem::changePropertyValue(const QVariant &value)
QTimer::singleShot(0, deferredFunc);
} else {
- QmlObjectNode objectNode(m_frames.target());
- objectNode.setVariantProperty(m_frames.propertyName(), value);
+ QScopedPointer<QmlObjectNode> objectNode {
+ QmlObjectNode::getQmlObjectNodeOfCorrectType(m_frames.target())};
+ objectNode->setVariantProperty(m_frames.propertyName(), value);
}
}
diff --git a/src/plugins/qmldesigner/components/timelineeditor/timelineview.cpp b/src/plugins/qmldesigner/components/timelineeditor/timelineview.cpp
index 9f87a33c00..ed35459ded 100644
--- a/src/plugins/qmldesigner/components/timelineeditor/timelineview.cpp
+++ b/src/plugins/qmldesigner/components/timelineeditor/timelineview.cpp
@@ -378,6 +378,7 @@ void TimelineView::addNewTimelineDialog()
{
auto timeline = addNewTimeline();
addAnimation(timeline);
+ setCurrentTimeline(timeline);
openSettingsDialog();
}
@@ -404,13 +405,13 @@ void TimelineView::openSettingsDialog()
void TimelineView::setTimelineRecording(bool value)
{
- ModelNode node = widget()->graphicsScene()->currentTimeline();
+ const ModelNode node = timelineForState(currentState()).modelNode();
if (value && node.isValid()) {
activateTimelineRecording(node);
} else {
deactivateTimelineRecording();
- activateTimeline(node);
+ setCurrentTimeline(node);
}
}
@@ -423,30 +424,16 @@ void TimelineView::customNotification(const AbstractView * /*view*/,
QmlTimeline timeline = widget()->graphicsScene()->currentTimeline();
if (timeline.isValid())
timeline.modelNode().removeAuxiliaryData("currentFrame@NodeInstance");
- } else if (identifier == "INSERT_KEYFRAME" && !nodeList.isEmpty() && !data.isEmpty()) {
- insertKeyframe(nodeList.constFirst(), data.constFirst().toString().toUtf8());
}
}
void TimelineView::insertKeyframe(const ModelNode &target, const PropertyName &propertyName)
{
- QmlTimeline timeline = widget()->graphicsScene()->currentTimeline();
- ModelNode targetNode = target;
- if (timeline.isValid() && targetNode.isValid()
- && QmlObjectNode::isValidQmlObjectNode(targetNode)) {
- executeInTransaction("TimelineView::insertKeyframe", [=, &timeline, &targetNode]() {
- targetNode.validId();
-
- QmlTimelineKeyframeGroup timelineFrames(
- timeline.keyframeGroup(targetNode, propertyName));
-
- QTC_ASSERT(timelineFrames.isValid(), return );
-
- const qreal frame
- = timeline.modelNode().auxiliaryData("currentFrame@NodeInstance").toReal();
- const QVariant value = QmlObjectNode(targetNode).instanceValue(propertyName);
+ QmlTimeline timeline = currentTimeline();
- timelineFrames.setValue(value, frame);
+ if (timeline.isValid() && target.isValid() && QmlObjectNode::isValidQmlObjectNode(target)) {
+ executeInTransaction("TimelineView::insertKeyframe", [=, &timeline, &target]() {
+ timeline.insertKeyframe(target, propertyName);
});
}
}
diff --git a/src/plugins/qmldesigner/components/timelineeditor/timelinewidget.cpp b/src/plugins/qmldesigner/components/timelineeditor/timelinewidget.cpp
index 00af769a63..b71173d4a1 100644
--- a/src/plugins/qmldesigner/components/timelineeditor/timelinewidget.cpp
+++ b/src/plugins/qmldesigner/components/timelineeditor/timelinewidget.cpp
@@ -128,7 +128,7 @@ TimelineWidget::TimelineWidget(TimelineView *view)
setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding);
const QString css = Theme::replaceCssColors(QString::fromUtf8(
- Utils::FileReader::fetchQrc(QLatin1String(":/qmldesigner/scrollbar.css"))));
+ Utils::FileReader::fetchQrc(":/qmldesigner/scrollbar.css")));
m_scrollbar->setStyleSheet(css);
m_scrollbar->setOrientation(Qt::Horizontal);
@@ -391,7 +391,7 @@ void TimelineWidget::setTimelineRecording(bool value)
timelineView()->activateTimelineRecording(node);
} else {
timelineView()->deactivateTimelineRecording();
- timelineView()->activateTimeline(node);
+ timelineView()->setCurrentTimeline(node);
}
graphicsScene()->invalidateRecordButtonsStatus();
@@ -417,7 +417,7 @@ void TimelineWidget::init()
m_statusBar->clear();
}
- invalidateTimelineDuration(m_graphicsScene->currentTimeline());
+ invalidateTimelineDuration(currentTimeline);
m_graphicsScene->setWidth(m_graphicsView->viewport()->width());
@@ -446,7 +446,7 @@ TimelineToolBar *TimelineWidget::toolBar() const
void TimelineWidget::invalidateTimelineDuration(const QmlTimeline &timeline)
{
if (timelineView() && timelineView()->model()) {
- QmlTimeline currentTimeline = graphicsScene()->currentTimeline();
+ QmlTimeline currentTimeline = timelineView()->currentTimeline();
if (currentTimeline.isValid() && currentTimeline == timeline) {
m_toolbar->setStartFrame(timeline.startKeyframe());
m_toolbar->setEndFrame(timeline.endKeyframe());
@@ -470,7 +470,7 @@ void TimelineWidget::invalidateTimelineDuration(const QmlTimeline &timeline)
void TimelineWidget::invalidateTimelinePosition(const QmlTimeline &timeline)
{
if (timelineView() && timelineView()->model()) {
- QmlTimeline currentTimeline = graphicsScene()->currentTimeline();
+ QmlTimeline currentTimeline = timelineView()->currentTimeline();
if (currentTimeline.isValid() && currentTimeline == timeline) {
qreal frame = getcurrentFrame(timeline);
m_toolbar->setCurrentFrame(frame);
@@ -519,6 +519,7 @@ void TimelineWidget::setTimelineActive(bool b)
m_graphicsView->setVisible(false);
m_rulerView->setVisible(false);
m_scrollbar->setVisible(false);
+ m_statusBar->clear();
m_addButton->setVisible(true);
m_onboardingContainer->setVisible(true);
}
diff --git a/src/plugins/qmldesigner/components/transitioneditor/transitioneditorwidget.cpp b/src/plugins/qmldesigner/components/transitioneditor/transitioneditorwidget.cpp
index a981537a4f..1c8c042fdc 100644
--- a/src/plugins/qmldesigner/components/transitioneditor/transitioneditorwidget.cpp
+++ b/src/plugins/qmldesigner/components/transitioneditor/transitioneditorwidget.cpp
@@ -100,8 +100,8 @@ TransitionEditorWidget::TransitionEditorWidget(TransitionEditorView *view)
setWindowTitle(tr("Transition", "Title of transition view"));
setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding);
- const QString css = Theme::replaceCssColors(QString::fromUtf8(
- Utils::FileReader::fetchQrc(QLatin1String(":/qmldesigner/scrollbar.css"))));
+ const QString css = Theme::replaceCssColors(
+ QString::fromUtf8(Utils::FileReader::fetchQrc(":/qmldesigner/scrollbar.css")));
m_scrollbar->setStyleSheet(css);
m_scrollbar->setOrientation(Qt::Horizontal);
diff --git a/src/plugins/qmldesigner/designercore/filemanager/qmlrewriter.cpp b/src/plugins/qmldesigner/designercore/filemanager/qmlrewriter.cpp
index 25a72134b2..43e23f3fec 100644
--- a/src/plugins/qmldesigner/designercore/filemanager/qmlrewriter.cpp
+++ b/src/plugins/qmldesigner/designercore/filemanager/qmlrewriter.cpp
@@ -33,7 +33,6 @@
#include <typeinfo>
-
static Q_LOGGING_CATEGORY(qmlRewriter, "qtc.rewriter.qmlrewriter", QtWarningMsg)
using namespace QmlDesigner::Internal;
@@ -73,24 +72,18 @@ QString QMLRewriter::textAt(const QmlJS::SourceLocation &location) const
return m_textModifier->text().mid(location.offset, location.length);
}
+int QMLRewriter::indentDepth() const
+{
+ return textModifier()->tabSettings().m_indentSize;
+}
+
unsigned QMLRewriter::calculateIndentDepth(const QmlJS::SourceLocation &position) const
{
QTextDocument *doc = m_textModifier->textDocument();
QTextCursor tc(doc);
tc.setPosition(position.offset);
- const int lineOffset = tc.block().position();
- unsigned indentDepth = 0;
-
- forever {
- const QChar ch = doc->characterAt(lineOffset + indentDepth);
-
- if (ch.isNull() || !ch.isSpace())
- break;
- else
- ++indentDepth;
- }
- return indentDepth;
+ return textModifier()->tabSettings().indentationColumn(tc.block().text());
}
QString QMLRewriter::addIndentation(const QString &text, unsigned depth)
@@ -98,56 +91,24 @@ QString QMLRewriter::addIndentation(const QString &text, unsigned depth)
if (depth == 0)
return text;
- const QString indentation(depth, QLatin1Char(' '));
-
- if (text.isEmpty())
- return indentation;
-
- const QLatin1Char lineSep('\n');
- const QStringList lines = text.split(lineSep);
+ TextEditor::TabSettings tabSettings = textModifier()->tabSettings();
QString result;
-
- for (int i = 0; i < lines.size(); ++i) {
- if (i > 0)
+ bool addLineSep = false;
+ constexpr char lineSep('\n');
+ const QStringList lines = text.split(lineSep);
+ for (const QString &line : lines) {
+ if (addLineSep)
result += lineSep;
- const QString &line = lines.at(i);
- if (!line.isEmpty()) {
- result += indentation;
- result += line;
- }
- }
- return result;
-}
+ addLineSep = true;
+ if (line.isEmpty())
+ continue;
-QString QMLRewriter::removeIndentationFromLine(const QString &text, int depth)
-{
- int charsToRemove = 0;
- for (int i = 0; i < depth && i < text.length(); ++i) {
- if (text.at(i).isSpace())
- charsToRemove++;
- else
- break;
+ const int firstNoneSpace = TextEditor::TabSettings::firstNonSpace(line);
+ const int lineIndentColumn = tabSettings.indentationColumn(line) + int(depth);
+ result.append(tabSettings.indentationString(0, lineIndentColumn, 0));
+ result.append(line.mid(firstNoneSpace));
}
-
- if (charsToRemove == 0)
- return text;
- else
- return text.mid(charsToRemove);
-}
-
-QString QMLRewriter::removeIndentation(const QString &text, unsigned depth)
-{
- const QLatin1Char lineSep('\n');
- const QStringList lines = text.split(lineSep);
- QString result;
-
- for (int i = 0; i < lines.size(); ++i) {
- if (i > 0)
- result += lineSep;
- result += removeIndentationFromLine(lines.at(i), depth);
- }
-
return result;
}
diff --git a/src/plugins/qmldesigner/designercore/filemanager/qmlrewriter.h b/src/plugins/qmldesigner/designercore/filemanager/qmlrewriter.h
index c773de35be..9a081a8b29 100644
--- a/src/plugins/qmldesigner/designercore/filemanager/qmlrewriter.h
+++ b/src/plugins/qmldesigner/designercore/filemanager/qmlrewriter.h
@@ -59,12 +59,9 @@ protected:
QString textBetween(int startPosition, int endPosition) const;
QString textAt(const QmlJS::SourceLocation &location) const;
- int indentDepth() const
- { return textModifier()->indentDepth(); }
+ int indentDepth() const;
unsigned calculateIndentDepth(const QmlJS::SourceLocation &position) const;
- static QString addIndentation(const QString &text, unsigned depth);
- static QString removeIndentation(const QString &text, unsigned depth);
- static QString removeIndentationFromLine(const QString &text, int depth);
+ QString addIndentation(const QString &text, unsigned depth);
static QmlJS::SourceLocation calculateLocation(QmlJS::AST::UiQualifiedId *id);
static bool isMissingSemicolon(QmlJS::AST::UiObjectMember *member);
diff --git a/src/plugins/qmldesigner/designercore/include/abstractproperty.h b/src/plugins/qmldesigner/designercore/include/abstractproperty.h
index 2a74a12539..7f6671be5e 100644
--- a/src/plugins/qmldesigner/designercore/include/abstractproperty.h
+++ b/src/plugins/qmldesigner/designercore/include/abstractproperty.h
@@ -61,8 +61,8 @@ namespace Internal {
class QMLDESIGNERCORE_EXPORT AbstractProperty
{
- friend class QmlDesigner::ModelNode;
- friend class QmlDesigner::Internal::ModelPrivate;
+ friend ModelNode;
+ friend Internal::ModelPrivate;
friend QMLDESIGNERCORE_EXPORT bool operator ==(const AbstractProperty &property1, const AbstractProperty &property2);
friend QMLDESIGNERCORE_EXPORT bool operator !=(const AbstractProperty &property1, const AbstractProperty &property2);
diff --git a/src/plugins/qmldesigner/designercore/include/abstractview.h b/src/plugins/qmldesigner/designercore/include/abstractview.h
index 95bf66949f..3908844dea 100644
--- a/src/plugins/qmldesigner/designercore/include/abstractview.h
+++ b/src/plugins/qmldesigner/designercore/include/abstractview.h
@@ -232,7 +232,10 @@ public:
virtual void fileUrlChanged(const QUrl &oldUrl, const QUrl &newUrl);
- virtual void nodeOrderChanged(const NodeListProperty &listProperty, const ModelNode &movedNode, int oldIndex);
+ virtual void nodeOrderChanged(const NodeListProperty &listProperty);
+ virtual void nodeOrderChanged(const NodeListProperty &listProperty,
+ const ModelNode &movedNode,
+ int oldIndex);
virtual void importsChanged(const QList<Import> &addedImports, const QList<Import> &removedImports);
virtual void possibleImportsChanged(const QList<Import> &possibleImports);
@@ -277,7 +280,7 @@ public:
virtual void contextHelp(const Core::IContext::HelpCallback &callback) const;
- void activateTimeline(const ModelNode &timeline);
+ void setCurrentTimeline(const ModelNode &timeline);
void activateTimelineRecording(const ModelNode &timeline);
void deactivateTimelineRecording();
diff --git a/src/plugins/qmldesigner/designercore/include/basetexteditmodifier.h b/src/plugins/qmldesigner/designercore/include/basetexteditmodifier.h
index 640ff367bc..2e3ff68903 100644
--- a/src/plugins/qmldesigner/designercore/include/basetexteditmodifier.h
+++ b/src/plugins/qmldesigner/designercore/include/basetexteditmodifier.h
@@ -44,7 +44,7 @@ public:
void indentLines(int startLine, int endLine) override;
void indent(int offset, int length) override;
- int indentDepth() const override;
+ TextEditor::TabSettings tabSettings() const override;
bool renameId(const QString &oldId, const QString &newId) override;
bool moveToComponent(int nodeOffset) override;
diff --git a/src/plugins/qmldesigner/designercore/include/bindingproperty.h b/src/plugins/qmldesigner/designercore/include/bindingproperty.h
index c0442a678d..761d93b892 100644
--- a/src/plugins/qmldesigner/designercore/include/bindingproperty.h
+++ b/src/plugins/qmldesigner/designercore/include/bindingproperty.h
@@ -32,9 +32,9 @@ namespace QmlDesigner {
class QMLDESIGNERCORE_EXPORT BindingProperty : public QmlDesigner::AbstractProperty
{
- friend class QmlDesigner::ModelNode;
- friend class QmlDesigner::Internal::ModelPrivate;
- friend class QmlDesigner::AbstractProperty;
+ friend ModelNode;
+ friend Internal::ModelPrivate;
+ friend AbstractProperty;
public:
void setExpression(const QString &expression);
diff --git a/src/plugins/qmldesigner/designercore/include/componenttextmodifier.h b/src/plugins/qmldesigner/designercore/include/componenttextmodifier.h
index 8cc2c235f7..d870f29622 100644
--- a/src/plugins/qmldesigner/designercore/include/componenttextmodifier.h
+++ b/src/plugins/qmldesigner/designercore/include/componenttextmodifier.h
@@ -41,7 +41,7 @@ public:
void indent(int offset, int length) override;
void indentLines(int startLine, int endLine) override;
- int indentDepth() const override;
+ TextEditor::TabSettings tabSettings() const override;
void startGroup() override;
void flushGroup() override;
diff --git a/src/plugins/qmldesigner/designercore/include/forwardview.h b/src/plugins/qmldesigner/designercore/include/forwardview.h
index 8d4406b6d2..5b46204091 100644
--- a/src/plugins/qmldesigner/designercore/include/forwardview.h
+++ b/src/plugins/qmldesigner/designercore/include/forwardview.h
@@ -65,7 +65,7 @@ public:
void fileUrlChanged(const QUrl &oldUrl, const QUrl &newUrl) override;
- void nodeOrderChanged(const NodeListProperty &listProperty, const ModelNode &movedNode, int oldIndex) override;
+ void nodeOrderChanged(const NodeListProperty &listProperty) override;
void importsChanged(const QList<Import> &addedImports, const QList<Import> &removedImports) override;
void auxiliaryDataChanged(const ModelNode &node, const PropertyName &name, const QVariant &data) override;
@@ -211,12 +211,11 @@ void ForwardView<ViewType>::fileUrlChanged(const QUrl &oldUrl, const QUrl &newUr
view->fileUrlChanged(oldUrl, newUrl);
}
-template <class ViewType>
-void ForwardView<ViewType>::nodeOrderChanged(const NodeListProperty &listProperty, const ModelNode &movedNode, int oldIndex)
+template<class ViewType>
+void ForwardView<ViewType>::nodeOrderChanged(const NodeListProperty &listProperty)
{
foreach (const ViewTypePointer &view, m_targetViewList)
- view->nodeOrderChanged(NodeListProperty(listProperty, view.data()),
- ModelNode(movedNode, view.data()), oldIndex);
+ view->nodeOrderChanged(NodeListProperty(listProperty, view.data()));
}
template <class ViewType>
diff --git a/src/plugins/qmldesigner/designercore/include/itemlibraryinfo.h b/src/plugins/qmldesigner/designercore/include/itemlibraryinfo.h
index b31b3d916c..c44467f002 100644
--- a/src/plugins/qmldesigner/designercore/include/itemlibraryinfo.h
+++ b/src/plugins/qmldesigner/designercore/include/itemlibraryinfo.h
@@ -48,8 +48,6 @@ QMLDESIGNERCORE_EXPORT QDebug operator<<(QDebug debug, const ItemLibraryEntry &i
class QMLDESIGNERCORE_EXPORT ItemLibraryEntry
{
- //friend class QmlDesigner::MetaInfo;
- //friend class QmlDesigner::Internal::MetaInfoParser;
friend QMLDESIGNERCORE_EXPORT QDataStream& operator<<(QDataStream& stream, const ItemLibraryEntry &itemLibraryEntry);
friend QMLDESIGNERCORE_EXPORT QDataStream& operator>>(QDataStream& stream, ItemLibraryEntry &itemLibraryEntry);
friend QMLDESIGNERCORE_EXPORT QDebug operator<<(QDebug debug, const ItemLibraryEntry &itemLibraryEntry);
diff --git a/src/plugins/qmldesigner/designercore/include/metainfo.h b/src/plugins/qmldesigner/designercore/include/metainfo.h
index cc4e8c1ed0..eb17139b8e 100644
--- a/src/plugins/qmldesigner/designercore/include/metainfo.h
+++ b/src/plugins/qmldesigner/designercore/include/metainfo.h
@@ -52,10 +52,10 @@ QMLDESIGNERCORE_EXPORT bool operator!=(const MetaInfo &first, const MetaInfo &se
class QMLDESIGNERCORE_EXPORT MetaInfo
{
- friend class QmlDesigner::Internal::MetaInfoPrivate;
- friend class QmlDesigner::Internal::ModelPrivate;
- friend class QmlDesigner::Internal::MetaInfoReader;
- friend class QmlDesigner::Internal::SubComponentManagerPrivate;
+ friend Internal::MetaInfoPrivate;
+ friend Internal::ModelPrivate;
+ friend Internal::MetaInfoReader;
+ friend Internal::SubComponentManagerPrivate;
friend QMLDESIGNERCORE_EXPORT bool operator==(const MetaInfo &, const MetaInfo &);
public:
diff --git a/src/plugins/qmldesigner/designercore/include/model.h b/src/plugins/qmldesigner/designercore/include/model.h
index 966e30c0c1..7b47dd67bd 100644
--- a/src/plugins/qmldesigner/designercore/include/model.h
+++ b/src/plugins/qmldesigner/designercore/include/model.h
@@ -64,12 +64,12 @@ using PropertyListType = QList<QPair<PropertyName, QVariant> >;
class QMLDESIGNERCORE_EXPORT Model : public QObject
{
- friend class QmlDesigner::ModelNode;
- friend class QmlDesigner::AbstractProperty;
- friend class QmlDesigner::AbstractView;
- friend class Internal::ModelPrivate;
- friend class Internal::WriteLocker;
- friend class QmlDesigner::Internal::NodeMetaInfoPrivate;
+ friend ModelNode;
+ friend AbstractProperty;
+ friend AbstractView;
+ friend Internal::ModelPrivate;
+ friend Internal::WriteLocker;
+ friend Internal::NodeMetaInfoPrivate;
Q_OBJECT
diff --git a/src/plugins/qmldesigner/designercore/include/modelnode.h b/src/plugins/qmldesigner/designercore/include/modelnode.h
index a7ad989728..e9c47ccae4 100644
--- a/src/plugins/qmldesigner/designercore/include/modelnode.h
+++ b/src/plugins/qmldesigner/designercore/include/modelnode.h
@@ -75,12 +75,12 @@ class QMLDESIGNERCORE_EXPORT ModelNode
friend QMLDESIGNERCORE_EXPORT QDebug operator<<(QDebug debug, const ModelNode &modelNode);
friend QMLDESIGNERCORE_EXPORT bool operator <(const ModelNode &firstNode, const ModelNode &secondNode);
friend QMLDESIGNERCORE_EXPORT QList<Internal::InternalNodePointer> toInternalNodeList(const QList<ModelNode> &nodeList);
- friend class QmlDesigner::Model;
- friend class QmlDesigner::AbstractView;
- friend class QmlDesigner::NodeListProperty;
- friend class QmlDesigner::Internal::ModelPrivate;
- friend class QmlDesigner::NodeAbstractProperty;
- friend class QmlDesigner::NodeProperty;
+ friend Model;
+ friend AbstractView;
+ friend NodeListProperty;
+ friend Internal::ModelPrivate;
+ friend NodeAbstractProperty;
+ friend NodeProperty;
public:
enum NodeSourceType {
@@ -236,7 +236,7 @@ public:
bool isSubclassOf(const TypeName &typeName, int majorVersion = -1, int minorVersion = -1) const;
QIcon typeIcon() const;
- friend void swap(ModelNode &first, ModelNode &second)
+ friend void swap(ModelNode &first, ModelNode &second) noexcept
{
using std::swap;
diff --git a/src/plugins/qmldesigner/designercore/include/nodeabstractproperty.h b/src/plugins/qmldesigner/designercore/include/nodeabstractproperty.h
index ae9e070d6e..8c2f67e6ad 100644
--- a/src/plugins/qmldesigner/designercore/include/nodeabstractproperty.h
+++ b/src/plugins/qmldesigner/designercore/include/nodeabstractproperty.h
@@ -36,9 +36,9 @@ namespace Internal {
class QMLDESIGNERCORE_EXPORT NodeAbstractProperty : public AbstractProperty
{
- friend class QmlDesigner::ModelNode;
- friend class QmlDesigner::Internal::ModelPrivate;
- friend class QmlDesigner::AbstractProperty;
+ friend ModelNode;
+ friend Internal::ModelPrivate;
+ friend AbstractProperty;
friend QMLDESIGNERCORE_EXPORT bool operator ==(const NodeAbstractProperty &property1, const NodeAbstractProperty &property2);
friend QMLDESIGNERCORE_EXPORT bool operator !=(const NodeAbstractProperty &property1, const NodeAbstractProperty &property2);
diff --git a/src/plugins/qmldesigner/designercore/include/nodeinstance.h b/src/plugins/qmldesigner/designercore/include/nodeinstance.h
index 56b8141bde..d008375175 100644
--- a/src/plugins/qmldesigner/designercore/include/nodeinstance.h
+++ b/src/plugins/qmldesigner/designercore/include/nodeinstance.h
@@ -42,7 +42,8 @@ class ProxyNodeInstanceData;
class NodeInstance
{
- friend class NodeInstanceView;
+ friend NodeInstanceView;
+
public:
static NodeInstance create(const ModelNode &node);
NodeInstance();
diff --git a/src/plugins/qmldesigner/designercore/include/nodeinstanceview.h b/src/plugins/qmldesigner/designercore/include/nodeinstanceview.h
index 2027fc10bb..f237bcf0d4 100644
--- a/src/plugins/qmldesigner/designercore/include/nodeinstanceview.h
+++ b/src/plugins/qmldesigner/designercore/include/nodeinstanceview.h
@@ -73,7 +73,7 @@ class QMLDESIGNERCORE_EXPORT NodeInstanceView : public AbstractView, public Node
{
Q_OBJECT
- friend class NodeInstance;
+ friend NodeInstance;
public:
using Pointer = QWeakPointer<NodeInstanceView>;
@@ -95,7 +95,7 @@ public:
void nodeTypeChanged(const ModelNode& node, const TypeName &type, int majorVersion, int minorVersion) override;
void fileUrlChanged(const QUrl &oldUrl, const QUrl &newUrl) override;
void nodeIdChanged(const ModelNode& node, const QString& newId, const QString& oldId) override;
- void nodeOrderChanged(const NodeListProperty &listProperty, const ModelNode &movedNode, int oldIndex) override;
+ void nodeOrderChanged(const NodeListProperty &listProperty) override;
void importsChanged(const QList<Import> &addedImports, const QList<Import> &removedImports) override;
void auxiliaryDataChanged(const ModelNode &node, const PropertyName &name, const QVariant &data) override;
void customNotification(const AbstractView *view, const QString &identifier, const QList<ModelNode> &nodeList, const QList<QVariant> &data) override;
@@ -224,6 +224,8 @@ private: // functions
void updateWatcher(const QString &path);
+ void updateRotationBlocks();
+
private:
QHash<QString, ModelNodePreviewImageData> m_imageDataMap;
@@ -251,6 +253,7 @@ private:
QTimer m_resetTimer;
QTimer m_updateWatcherTimer;
QSet<QString> m_pendingUpdateDirs;
+ QTimer m_rotBlockTimer;
};
} // namespace ProxyNodeInstanceView
diff --git a/src/plugins/qmldesigner/designercore/include/nodelistproperty.h b/src/plugins/qmldesigner/designercore/include/nodelistproperty.h
index 806ecde6b3..8bc8590cc3 100644
--- a/src/plugins/qmldesigner/designercore/include/nodelistproperty.h
+++ b/src/plugins/qmldesigner/designercore/include/nodelistproperty.h
@@ -25,27 +25,168 @@
#pragma once
-
-#include "qmldesignercorelib_global.h"
+#include "modelnode.h"
#include "nodeabstractproperty.h"
+#include "qmldesignercorelib_global.h"
+
#include <QList>
+#include <iterator>
namespace QmlDesigner {
namespace Internal {
- class ModelPrivate;
- class InternalNodeListProperty;
- using InternalNodeListPropertyPointer = QSharedPointer<InternalNodeListProperty>;
-}
+class ModelPrivate;
+class InternalNodeListProperty;
+using InternalNodeListPropertyPointer = QSharedPointer<InternalNodeListProperty>;
+
+class NodeListPropertyIterator
+{
+ friend NodeListProperty;
+
+public:
+ using iterator_category = std::random_access_iterator_tag;
+ using difference_type = qsizetype;
+ using value_type = ModelNode;
+ using pointer = InternalNodeListPropertyPointer;
+ using reference = ModelNode;
+
+ NodeListPropertyIterator() = default;
+ NodeListPropertyIterator(difference_type currentIndex,
+ class InternalNodeListProperty *nodeListProperty,
+ Model *model,
+ AbstractView *view)
+ : m_nodeListProperty{nodeListProperty}
+ , m_model{model}
+ , m_view{view}
+ , m_currentIndex{currentIndex}
+ {}
+
+ NodeListPropertyIterator &operator++()
+ {
+ ++m_currentIndex;
+ return *this;
+ }
+
+ NodeListPropertyIterator operator++(int)
+ {
+ auto tmp = *this;
+ ++m_currentIndex;
+ return tmp;
+ }
+
+ NodeListPropertyIterator &operator--()
+ {
+ --m_currentIndex;
+ return *this;
+ }
+
+ NodeListPropertyIterator operator--(int)
+ {
+ auto tmp = *this;
+ --m_currentIndex;
+ return tmp;
+ }
+
+ NodeListPropertyIterator &operator+=(difference_type index)
+ {
+ m_currentIndex += index;
+ return *this;
+ }
+
+ NodeListPropertyIterator &operator-=(difference_type index)
+ {
+ m_currentIndex -= index;
+ return *this;
+ }
+
+ NodeListPropertyIterator operator[](difference_type index) const
+ {
+ return {index, m_nodeListProperty, m_model, m_view};
+ }
+
+ friend NodeListPropertyIterator operator+(const NodeListPropertyIterator &first,
+ difference_type index)
+ {
+ return {first.m_currentIndex + index, first.m_nodeListProperty, first.m_model, first.m_view};
+ }
+ friend NodeListPropertyIterator operator+(difference_type index,
+ const NodeListPropertyIterator &second)
+ {
+ return second + index;
+ }
+
+ friend NodeListPropertyIterator operator-(const NodeListPropertyIterator &first,
+ difference_type index)
+ {
+ return first + (-index);
+ }
+
+ friend difference_type operator-(const NodeListPropertyIterator &first,
+ const NodeListPropertyIterator &second)
+ {
+ return first.m_currentIndex - second.m_currentIndex;
+ }
+
+ friend bool operator==(const NodeListPropertyIterator &first,
+ const NodeListPropertyIterator &second)
+ {
+ return first.m_currentIndex == second.m_currentIndex;
+ }
+
+ friend bool operator!=(const NodeListPropertyIterator &first,
+ const NodeListPropertyIterator &second)
+ {
+ return !(first == second);
+ }
+
+ friend bool operator<(const NodeListPropertyIterator &first, const NodeListPropertyIterator &second)
+ {
+ return first.m_currentIndex < second.m_currentIndex;
+ }
+
+ friend bool operator<=(const NodeListPropertyIterator &first,
+ const NodeListPropertyIterator &second)
+ {
+ return first.m_currentIndex <= second.m_currentIndex;
+ }
+ friend bool operator>(const NodeListPropertyIterator &first, const NodeListPropertyIterator &second)
+ {
+ return first.m_currentIndex > second.m_currentIndex;
+ }
+
+ friend bool operator>=(const NodeListPropertyIterator &first,
+ const NodeListPropertyIterator &second)
+ {
+ return first.m_currentIndex >= second.m_currentIndex;
+ }
+
+ value_type operator*() const;
+
+private:
+ InternalNodeListProperty *m_nodeListProperty{};
+ Model *m_model{};
+ AbstractView *m_view{};
+ difference_type m_currentIndex = -1;
+};
+
+} // namespace Internal
class QMLDESIGNERCORE_EXPORT NodeListProperty : public NodeAbstractProperty
{
- friend class QmlDesigner::ModelNode;
- friend class QmlDesigner::AbstractProperty;
- friend class QmlDesigner::Internal::ModelPrivate;
+ friend ModelNode;
+ friend AbstractProperty;
+ friend Internal::ModelPrivate;
+
public:
+ using value_type = ModelNode;
+ using iterator = Internal::NodeListPropertyIterator;
+ using const_iterator = iterator;
+ using size_type = int;
+ using difference_type = int;
+ using reference = ModelNode;
+
NodeListProperty();
NodeListProperty(const NodeListProperty &nodeListProperty, AbstractView *view);
QList<ModelNode> toModelNodeList() const;
@@ -54,11 +195,37 @@ public:
void swap(int, int) const;
void reparentHere(const ModelNode &modelNode);
ModelNode at(int index) const;
+ void iterSwap(iterator &first, iterator &second);
+ iterator rotate(iterator first, iterator newFirst, iterator last);
+ template<typename Range>
+ iterator rotate(Range &range, iterator newFirst)
+ {
+ return rotate(range.begin(), newFirst, range.end());
+ }
+ void reverse(iterator first, iterator last);
+ template<typename Range>
+ void reverse(Range &range)
+ {
+ reverse(range.begin(), range.end());
+ }
static void reverseModelNodes(const QList<ModelNode> &nodes);
+ iterator begin();
+ iterator end();
+
+ const_iterator begin() const;
+ const_iterator end() const;
+
protected:
NodeListProperty(const PropertyName &propertyName, const Internal::InternalNodePointer &internalNode, Model* model, AbstractView *view);
- NodeListProperty(const Internal::InternalNodeListPropertyPointer &internalNodeListProperty, Model* model, AbstractView *view);
+ NodeListProperty(const Internal::InternalNodeListPropertyPointer &internalNodeListProperty,
+ Model *model,
+ AbstractView *view);
+
+ Internal::InternalNodeListPropertyPointer &internalNodeListProperty() const;
+
+private:
+ mutable Internal::InternalNodeListPropertyPointer m_internalNodeListProperty{};
};
}
diff --git a/src/plugins/qmldesigner/designercore/include/nodemetainfo.h b/src/plugins/qmldesigner/designercore/include/nodemetainfo.h
index 869d327f5f..3cafe30e7c 100644
--- a/src/plugins/qmldesigner/designercore/include/nodemetainfo.h
+++ b/src/plugins/qmldesigner/designercore/include/nodemetainfo.h
@@ -76,7 +76,6 @@ public:
bool propertyIsEnumType(const PropertyName &propertyName) const;
bool propertyIsPrivate(const PropertyName &propertyName) const;
bool propertyIsPointer(const PropertyName &propertyName) const;
- QString propertyEnumScope(const PropertyName &propertyName) const;
QStringList propertyKeysForEnum(const PropertyName &propertyName) const;
QVariant propertyCastedValue(const PropertyName &propertyName, const QVariant &value) const;
@@ -91,11 +90,8 @@ public:
int majorVersion() const;
int minorVersion() const;
- QString componentSource() const;
QString componentFileName() const;
- bool hasCustomParser() const;
-
bool availableInVersion(int majorVersion, int minorVersion) const;
bool isSubclassOf(const TypeName &type, int majorVersion = -1, int minorVersion = -1) const;
diff --git a/src/plugins/qmldesigner/designercore/include/nodeproperty.h b/src/plugins/qmldesigner/designercore/include/nodeproperty.h
index 40a5e2ec78..64cacb5a71 100644
--- a/src/plugins/qmldesigner/designercore/include/nodeproperty.h
+++ b/src/plugins/qmldesigner/designercore/include/nodeproperty.h
@@ -34,9 +34,9 @@ namespace Internal { class ModelPrivate; }
class QMLDESIGNERCORE_EXPORT NodeProperty : public NodeAbstractProperty
{
- friend class QmlDesigner::ModelNode;
- friend class QmlDesigner::Internal::ModelPrivate;
- friend class QmlDesigner::AbstractProperty;
+ friend ModelNode;
+ friend Internal::ModelPrivate;
+ friend AbstractProperty;
public:
void setModelNode(const ModelNode &modelNode);
diff --git a/src/plugins/qmldesigner/designercore/include/plaintexteditmodifier.h b/src/plugins/qmldesigner/designercore/include/plaintexteditmodifier.h
index c18b4d8cfb..3ef3a996a9 100644
--- a/src/plugins/qmldesigner/designercore/include/plaintexteditmodifier.h
+++ b/src/plugins/qmldesigner/designercore/include/plaintexteditmodifier.h
@@ -59,8 +59,6 @@ public:
void indent(int offset, int length) override = 0;
void indentLines(int startLine, int endLine) override = 0;
- int indentDepth() const override = 0;
-
void startGroup() override;
void flushGroup() override;
void commitGroup() override;
@@ -95,19 +93,28 @@ class QMLDESIGNERCORE_EXPORT NotIndentingTextEditModifier: public PlainTextEditM
public:
NotIndentingTextEditModifier(QPlainTextEdit *textEdit)
: PlainTextEditModifier(textEdit)
- {}
+ {
+ m_tabSettings.m_tabSize = 0;
+ m_tabSettings.m_indentSize = 0;
+ }
NotIndentingTextEditModifier(QTextDocument *document, const QTextCursor &textCursor)
: PlainTextEditModifier{document, textCursor}
- {}
+ {
+ m_tabSettings.m_tabSize = 0;
+ m_tabSettings.m_indentSize = 0;
+ }
void indent(int /*offset*/, int /*length*/) override
{}
void indentLines(int /*offset*/, int /*length*/) override
{}
- int indentDepth() const override
- { return 0; }
+ TextEditor::TabSettings tabSettings() const override
+ { return m_tabSettings; }
+
+private:
+ TextEditor::TabSettings m_tabSettings;
};
}
diff --git a/src/plugins/qmldesigner/designercore/include/qml3dnode.h b/src/plugins/qmldesigner/designercore/include/qml3dnode.h
index d487666ae1..e2e7688979 100644
--- a/src/plugins/qmldesigner/designercore/include/qml3dnode.h
+++ b/src/plugins/qmldesigner/designercore/include/qml3dnode.h
@@ -49,6 +49,14 @@ public:
Qml3DNode(const ModelNode &modelNode) : QmlVisualNode(modelNode) {}
bool isValid() const override;
static bool isValidQml3DNode(const ModelNode &modelNode);
+
+ // From QmlObjectNode
+ void setVariantProperty(const PropertyName &name, const QVariant &value) override;
+ void setBindingProperty(const PropertyName &name, const QString &expression) override;
+ bool isBlocked(const PropertyName &propName) const override;
+
+private:
+ void handleEulerRotationSet();
};
QMLDESIGNERCORE_EXPORT uint qHash(const Qml3DNode &node);
diff --git a/src/plugins/qmldesigner/designercore/include/qmlconnections.h b/src/plugins/qmldesigner/designercore/include/qmlconnections.h
index d84f0017a9..23267738e5 100644
--- a/src/plugins/qmldesigner/designercore/include/qmlconnections.h
+++ b/src/plugins/qmldesigner/designercore/include/qmlconnections.h
@@ -32,9 +32,11 @@
namespace QmlDesigner {
+class StatesEditorView;
+
class QMLDESIGNERCORE_EXPORT QmlConnections : public QmlModelNodeFacade
{
- friend class StatesEditorView;
+ friend StatesEditorView;
public:
QmlConnections();
diff --git a/src/plugins/qmldesigner/designercore/include/qmlitemnode.h b/src/plugins/qmldesigner/designercore/include/qmlitemnode.h
index 2aa4b8d4bb..38b5f24c77 100644
--- a/src/plugins/qmldesigner/designercore/include/qmlitemnode.h
+++ b/src/plugins/qmldesigner/designercore/include/qmlitemnode.h
@@ -44,7 +44,8 @@ class ItemLibraryEntry;
class QMLDESIGNERCORE_EXPORT QmlItemNode : public QmlVisualNode
{
- friend class QmlAnchors;
+ friend QmlAnchors;
+
public:
QmlItemNode() : QmlVisualNode() {}
QmlItemNode(const ModelNode &modelNode) : QmlVisualNode(modelNode) {}
diff --git a/src/plugins/qmldesigner/designercore/include/qmlobjectnode.h b/src/plugins/qmldesigner/designercore/include/qmlobjectnode.h
index 48b7c1ac00..43f975e5cf 100644
--- a/src/plugins/qmldesigner/designercore/include/qmlobjectnode.h
+++ b/src/plugins/qmldesigner/designercore/include/qmlobjectnode.h
@@ -42,8 +42,9 @@ class QmlVisualNode;
class QMLDESIGNERCORE_EXPORT QmlObjectNode : public QmlModelNodeFacade
{
- friend class QmlItemNode;
- friend class MoveManipulator;
+ friend QmlItemNode;
+ friend MoveManipulator;
+
public:
QmlObjectNode();
QmlObjectNode(const ModelNode &modelNode);
@@ -68,8 +69,8 @@ public:
QmlModelState currentState() const;
QmlTimeline currentTimeline() const;
- void setVariantProperty(const PropertyName &name, const QVariant &value);
- void setBindingProperty(const PropertyName &name, const QString &expression);
+ virtual void setVariantProperty(const PropertyName &name, const QVariant &value);
+ virtual void setBindingProperty(const PropertyName &name, const QString &expression);
NodeAbstractProperty nodeAbstractProperty(const PropertyName &name) const;
NodeAbstractProperty defaultNodeAbstractProperty() const;
NodeProperty nodeProperty(const PropertyName &name) const;
@@ -122,6 +123,10 @@ public:
QStringList allStateNames() const;
+ static QmlObjectNode *getQmlObjectNodeOfCorrectType(const ModelNode &modelNode);
+
+ virtual bool isBlocked(const PropertyName &propName) const;
+
protected:
NodeInstance nodeInstance() const;
QmlObjectNode nodeForInstance(const NodeInstance &instance) const;
diff --git a/src/plugins/qmldesigner/designercore/include/qmlstate.h b/src/plugins/qmldesigner/designercore/include/qmlstate.h
index 7c43ac8776..bd0aad854b 100644
--- a/src/plugins/qmldesigner/designercore/include/qmlstate.h
+++ b/src/plugins/qmldesigner/designercore/include/qmlstate.h
@@ -36,10 +36,11 @@ class QmlObjectNode;
class QmlModelStateGroup;
class Annotation;
class AnnotationEditor;
+class StatesEditorView;
class QMLDESIGNERCORE_EXPORT QmlModelState : public QmlModelNodeFacade
{
- friend class StatesEditorView;
+ friend StatesEditorView;
public:
QmlModelState();
diff --git a/src/plugins/qmldesigner/designercore/include/qmltimeline.h b/src/plugins/qmldesigner/designercore/include/qmltimeline.h
index 59342bcb04..1d9bb4b718 100644
--- a/src/plugins/qmldesigner/designercore/include/qmltimeline.h
+++ b/src/plugins/qmldesigner/designercore/include/qmltimeline.h
@@ -74,6 +74,8 @@ public:
bool hasKeyframeGroup(const ModelNode &node, const PropertyName &propertyName) const;
bool hasKeyframeGroupForTarget(const ModelNode &node) const;
+ void insertKeyframe(const ModelNode &target, const PropertyName &propertyName);
+
private:
void addKeyframeGroupIfNotExists(const ModelNode &node, const PropertyName &propertyName);
QList<QmlTimelineKeyframeGroup> allKeyframeGroups() const;
diff --git a/src/plugins/qmldesigner/designercore/include/rewriterview.h b/src/plugins/qmldesigner/designercore/include/rewriterview.h
index c867b9a67d..ac251ef064 100644
--- a/src/plugins/qmldesigner/designercore/include/rewriterview.h
+++ b/src/plugins/qmldesigner/designercore/include/rewriterview.h
@@ -91,7 +91,10 @@ public:
const NodeAbstractProperty &oldPropertyParent,
AbstractView::PropertyChangeFlags propertyChange) override;
void nodeIdChanged(const ModelNode& node, const QString& newId, const QString& oldId) override;
- void nodeOrderChanged(const NodeListProperty &listProperty, const ModelNode &movedNode, int oldIndex) override;
+ void nodeOrderChanged(const NodeListProperty &listProperty,
+ const ModelNode &movedNode,
+ int /*oldIndex*/) override;
+ void nodeOrderChanged(const NodeListProperty &listProperty) override;
void rootNodeTypeChanged(const QString &type, int majorVersion, int minorVersion) override;
void nodeTypeChanged(const ModelNode& node, const TypeName &type, int majorVersion, int minorVersion) override;
void customNotification(const AbstractView *view, const QString &identifier,
diff --git a/src/plugins/qmldesigner/designercore/include/signalhandlerproperty.h b/src/plugins/qmldesigner/designercore/include/signalhandlerproperty.h
index f28fd7feda..07e48decad 100644
--- a/src/plugins/qmldesigner/designercore/include/signalhandlerproperty.h
+++ b/src/plugins/qmldesigner/designercore/include/signalhandlerproperty.h
@@ -32,9 +32,9 @@ namespace QmlDesigner {
class QMLDESIGNERCORE_EXPORT SignalHandlerProperty : public QmlDesigner::AbstractProperty
{
- friend class QmlDesigner::ModelNode;
- friend class QmlDesigner::Internal::ModelPrivate;
- friend class QmlDesigner::AbstractProperty;
+ friend ModelNode;
+ friend Internal::ModelPrivate;
+ friend AbstractProperty;
public:
void setSource(const QString &source);
diff --git a/src/plugins/qmldesigner/designercore/include/textmodifier.h b/src/plugins/qmldesigner/designercore/include/textmodifier.h
index 617d0b9b7b..648f9e15c4 100644
--- a/src/plugins/qmldesigner/designercore/include/textmodifier.h
+++ b/src/plugins/qmldesigner/designercore/include/textmodifier.h
@@ -28,11 +28,15 @@
#include "qmldesignercorelib_global.h"
#include <qmljs/qmljsdocument.h>
+#include <texteditor/tabsettings.h>
+#include <utils/optional.h>
#include <QObject>
#include <QTextCursor>
#include <QTextDocument>
+namespace TextEditor { class TabSettings; }
+
namespace QmlDesigner {
class QMLDESIGNERCORE_EXPORT TextModifier: public QObject
@@ -66,7 +70,7 @@ public:
virtual void indent(int offset, int length) = 0;
virtual void indentLines(int startLine, int endLine) = 0;
- virtual int indentDepth() const = 0;
+ virtual TextEditor::TabSettings tabSettings() const = 0;
virtual void startGroup() = 0;
virtual void flushGroup() = 0;
diff --git a/src/plugins/qmldesigner/designercore/include/variantproperty.h b/src/plugins/qmldesigner/designercore/include/variantproperty.h
index 8f25ab3109..7e59b87e19 100644
--- a/src/plugins/qmldesigner/designercore/include/variantproperty.h
+++ b/src/plugins/qmldesigner/designercore/include/variantproperty.h
@@ -42,9 +42,9 @@ namespace Internal { class ModelPrivate; }
class QMLDESIGNERCORE_EXPORT VariantProperty : public AbstractProperty
{
- friend class QmlDesigner::ModelNode;
- friend class QmlDesigner::Internal::ModelPrivate;
- friend class QmlDesigner::AbstractProperty;
+ friend ModelNode;
+ friend Internal::ModelPrivate;
+ friend AbstractProperty;
public:
void setValue(const QVariant &value);
diff --git a/src/plugins/qmldesigner/designercore/instances/nodeinstanceserverproxy.h b/src/plugins/qmldesigner/designercore/instances/nodeinstanceserverproxy.h
index e4edeb6725..f87f15432c 100644
--- a/src/plugins/qmldesigner/designercore/instances/nodeinstanceserverproxy.h
+++ b/src/plugins/qmldesigner/designercore/instances/nodeinstanceserverproxy.h
@@ -48,13 +48,15 @@ namespace QmlDesigner {
class NodeInstanceClientInterface;
class NodeInstanceView;
class NodeInstanceClientProxy;
+class BaseConnectionManager;
class ConnectionManagerInterface;
class NodeInstanceServerProxy : public NodeInstanceServerInterface
{
- friend class BaseConnectionManager;
Q_OBJECT
+ friend BaseConnectionManager;
+
public:
explicit NodeInstanceServerProxy(NodeInstanceView *nodeInstanceView,
ProjectExplorer::Target *target,
diff --git a/src/plugins/qmldesigner/designercore/instances/nodeinstanceview.cpp b/src/plugins/qmldesigner/designercore/instances/nodeinstanceview.cpp
index 4216dbb6ac..74d2770c88 100644
--- a/src/plugins/qmldesigner/designercore/instances/nodeinstanceview.cpp
+++ b/src/plugins/qmldesigner/designercore/instances/nodeinstanceview.cpp
@@ -54,6 +54,7 @@
#include "nodeproperty.h"
#include "pixmapchangedcommand.h"
#include "puppettocreatorcommand.h"
+#include "qml3dnode.h"
#include "qmlchangeset.h"
#include "qmldesignerconstants.h"
#include "qmlstate.h"
@@ -103,6 +104,7 @@
#include <QPainter>
#include <QDirIterator>
#include <QFileSystemWatcher>
+#include <QScopedPointer>
enum {
debug = false
@@ -176,6 +178,10 @@ NodeInstanceView::NodeInstanceView(ConnectionManagerInterface &connectionManager
connect(m_fileSystemWatcher, &QFileSystemWatcher::fileChanged, [this] {
m_resetTimer.start();
});
+
+ m_rotBlockTimer.setSingleShot(true);
+ m_rotBlockTimer.setInterval(0);
+ QObject::connect(&m_rotBlockTimer, &QTimer::timeout, this, &NodeInstanceView::updateRotationBlocks);
}
@@ -562,8 +568,7 @@ void NodeInstanceView::nodeIdChanged(const ModelNode& node, const QString& /*new
}
}
-void NodeInstanceView::nodeOrderChanged(const NodeListProperty & listProperty,
- const ModelNode & /*movedNode*/, int /*oldIndex*/)
+void NodeInstanceView::nodeOrderChanged(const NodeListProperty &listProperty)
{
QTC_ASSERT(m_nodeInstanceServer, return);
QVector<ReparentContainer> containerList;
@@ -595,11 +600,12 @@ void NodeInstanceView::auxiliaryDataChanged(const ModelNode &node,
const QVariant &value)
{
QTC_ASSERT(m_nodeInstanceServer, return);
- if (((node.isRootNode() && (name == "width" || name == "height")) || name == "invisible" || name == "locked")
+ const bool forceAuxChange = name == "invisible" || name == "locked" || name == "rotBlocked@internal";
+ if (((node.isRootNode() && (name == "width" || name == "height")) || forceAuxChange)
|| name.endsWith(PropertyName("@NodeInstance"))) {
if (hasInstanceForModelNode(node)) {
NodeInstance instance = instanceForModelNode(node);
- if (value.isValid() || name == "invisible" || name == "locked") {
+ if (value.isValid() || forceAuxChange) {
PropertyValueContainer container{instance.instanceId(), name, value, TypeName()};
m_nodeInstanceServer->changeAuxiliaryValues({{container}});
} else {
@@ -1342,10 +1348,10 @@ void NodeInstanceView::valuesModified(const ValuesModifiedCommand &command)
if (hasInstanceForId(container.instanceId())) {
NodeInstance instance = instanceForId(container.instanceId());
if (instance.isValid()) {
- // QmlVisualNode is needed so timeline and state are updated
- QmlVisualNode node = instance.modelNode();
- if (node.modelValue(container.name()) != container.value())
- node.setVariantProperty(container.name(), container.value());
+ QScopedPointer<QmlObjectNode> node {
+ QmlObjectNode::getQmlObjectNodeOfCorrectType(instance.modelNode())};
+ if (node->modelValue(container.name()) != container.value())
+ node->setVariantProperty(container.name(), container.value());
}
}
}
@@ -1594,6 +1600,7 @@ void NodeInstanceView::selectedNodesChanged(const QList<ModelNode> &selectedNode
const QList<ModelNode> & /*lastSelectedNodeList*/)
{
m_nodeInstanceServer->changeSelection(createChangeSelectionCommand(selectedNodeList));
+ m_rotBlockTimer.start();
}
void NodeInstanceView::sendInputEvent(QInputEvent *e) const
@@ -1851,4 +1858,46 @@ void NodeInstanceView::updateWatcher(const QString &path)
}
}
+void NodeInstanceView::updateRotationBlocks()
+{
+ QList<ModelNode> qml3DNodes;
+ QSet<ModelNode> rotationKeyframeTargets;
+ bool groupsResolved = false;
+ const PropertyName targetPropName {"target"};
+ const PropertyName propertyPropName {"property"};
+ const PropertyName rotationPropName {"rotation"};
+ const QList<ModelNode> selectedNodes = selectedModelNodes();
+ for (const auto &node : selectedNodes) {
+ if (Qml3DNode::isValidQml3DNode(node)) {
+ if (!groupsResolved) {
+ const QList<ModelNode> keyframeGroups = allModelNodesOfType("KeyframeGroup");
+ for (const auto &kfgNode : keyframeGroups) {
+ if (kfgNode.isValid()) {
+ VariantProperty varProp = kfgNode.variantProperty(propertyPropName);
+ if (varProp.isValid() && varProp.value().value<PropertyName>() == rotationPropName) {
+ BindingProperty bindProp = kfgNode.bindingProperty(targetPropName);
+ if (bindProp.isValid()) {
+ ModelNode targetNode = bindProp.resolveToModelNode();
+ if (Qml3DNode::isValidQml3DNode(targetNode))
+ rotationKeyframeTargets.insert(targetNode);
+ }
+ }
+ }
+ }
+ groupsResolved = true;
+ }
+ qml3DNodes.append(node);
+ }
+ }
+ if (!qml3DNodes.isEmpty()) {
+ const PropertyName auxDataProp {"rotBlocked@internal"};
+ for (const auto &node : qAsConst(qml3DNodes)) {
+ if (rotationKeyframeTargets.contains(node))
+ node.setAuxiliaryData(auxDataProp, true);
+ else
+ node.setAuxiliaryData(auxDataProp, false);
+ }
+ }
+}
+
}
diff --git a/src/plugins/qmldesigner/designercore/instances/puppetcreator.cpp b/src/plugins/qmldesigner/designercore/instances/puppetcreator.cpp
index 8295a0346c..7203a959ab 100644
--- a/src/plugins/qmldesigner/designercore/instances/puppetcreator.cpp
+++ b/src/plugins/qmldesigner/designercore/instances/puppetcreator.cpp
@@ -392,7 +392,7 @@ void PuppetCreator::createQml2PuppetExecutableIfMissing()
QString PuppetCreator::defaultPuppetToplevelBuildDirectory()
{
- return Core::ICore::userResourcePath() + "/qmlpuppet/";
+ return Core::ICore::userResourcePath("qmlpuppet/").toString();
}
QString PuppetCreator::qmlPuppetToplevelBuildDirectory() const
@@ -424,9 +424,9 @@ QString PuppetCreator::qmlPuppetDirectory(PuppetType puppetType) const
QString PuppetCreator::defaultPuppetFallbackDirectory()
{
if (Utils::HostOsInfo::isMacHost())
- return Core::ICore::libexecPath() + "/qmldesigner";
+ return Core::ICore::libexecPath("qmldesigner").toString();
else
- return Core::ICore::libexecPath();
+ return Core::ICore::libexecPath().toString();
}
QString PuppetCreator::qmlPuppetFallbackDirectory(const DesignerSettings &settings)
@@ -462,7 +462,7 @@ QProcessEnvironment PuppetCreator::processEnvironment() const
Utils::Environment environment = Utils::Environment::systemEnvironment();
if (QTC_GUARD(m_target)) {
if (!useOnlyFallbackPuppet())
- m_target->kit()->addToEnvironment(environment);
+ m_target->kit()->addToBuildEnvironment(environment);
const QtSupport::BaseQtVersion *qt = QtSupport::QtKitAspect::qtVersion(m_target->kit());
if (QTC_GUARD(qt)) { // Kits without a Qt version should not have a puppet!
// Update PATH to include QT_HOST_BINS
@@ -561,8 +561,7 @@ QProcessEnvironment PuppetCreator::processEnvironment() const
QString PuppetCreator::buildCommand() const
{
- Utils::Environment environment = Utils::Environment::systemEnvironment();
- m_target->kit()->addToEnvironment(environment);
+ const Utils::Environment environment = m_target->kit()->buildEnvironment();
if (ToolChain *toolChain = ToolChainKitAspect::cxxToolChain(m_target->kit()))
return toolChain->makeCommand(environment).toString();
@@ -632,7 +631,7 @@ bool PuppetCreator::startBuildProcess(const QString &buildDirectoryPath,
QString PuppetCreator::puppetSourceDirectoryPath()
{
- return Core::ICore::resourcePath() + "/qml/qmlpuppet";
+ return Core::ICore::resourcePath("qml/qmlpuppet").toString();
}
QString PuppetCreator::qml2PuppetProjectFile()
diff --git a/src/plugins/qmldesigner/designercore/metainfo/itemlibraryinfo.cpp b/src/plugins/qmldesigner/designercore/metainfo/itemlibraryinfo.cpp
index 5bdb5530f6..806d37c99b 100644
--- a/src/plugins/qmldesigner/designercore/metainfo/itemlibraryinfo.cpp
+++ b/src/plugins/qmldesigner/designercore/metainfo/itemlibraryinfo.cpp
@@ -167,7 +167,7 @@ static QByteArray getSourceForUrl(const QString &fileURl)
{
Utils::FileReader fileReader;
- if (fileReader.fetch(fileURl))
+ if (fileReader.fetch(Utils::FilePath::fromString(fileURl)))
return fileReader.data();
else
return Utils::FileReader::fetchQrc(fileURl);
diff --git a/src/plugins/qmldesigner/designercore/metainfo/nodemetainfo.cpp b/src/plugins/qmldesigner/designercore/metainfo/nodemetainfo.cpp
index dc7fcc816b..7eacf17197 100644
--- a/src/plugins/qmldesigner/designercore/metainfo/nodemetainfo.cpp
+++ b/src/plugins/qmldesigner/designercore/metainfo/nodemetainfo.cpp
@@ -603,7 +603,6 @@ public:
bool isPropertyPointer(const PropertyName &propertyName) const;
bool isPropertyList(const PropertyName &propertyName) const;
bool isPropertyEnum(const PropertyName &propertyName) const;
- QString propertyEnumScope(const PropertyName &propertyName) const;
QStringList keysForEnum(const QString &enumName) const;
bool cleverCheckType(const TypeName &otherType) const;
QVariant::Type variantTypeId(const PropertyName &properyName) const;
@@ -615,7 +614,6 @@ public:
QByteArray cppPackageName() const;
- QString componentSource() const;
QString componentFileName() const;
QString importDirectoryPath() const;
@@ -998,55 +996,6 @@ bool NodeMetaInfoPrivate::isPropertyEnum(const PropertyName &propertyName) const
return qmlObjectValue->getEnum(QString::fromUtf8(propertyType(propertyName))).isValid();
}
-QString NodeMetaInfoPrivate::propertyEnumScope(const PropertyName &propertyName) const
-{
- if (!isValid())
- return QString();
-
- ensureProperties();
-
- if (propertyType(propertyName).contains("Qt::"))
- return QStringLiteral("Qt");
-
- if (propertyName.contains('.')) {
- const PropertyNameList parts = propertyName.split('.');
- const PropertyName &objectName = parts.constFirst();
- const PropertyName &rawPropertyName = parts.constLast();
- const TypeName objectType = propertyType(objectName);
-
- if (isValueType(objectType))
- return QString();
-
- QSharedPointer<NodeMetaInfoPrivate> objectInfo(create(m_model, objectType));
- if (objectInfo->isValid())
- return objectInfo->propertyEnumScope(rawPropertyName);
- else
- return QString();
- }
-
- const CppComponentValue *qmlObjectValue = getNearestCppComponentValue();
- if (!qmlObjectValue)
- return QString();
- const CppComponentValue *definedIn = nullptr;
- qmlObjectValue->getEnum(QString::fromUtf8(propertyType(propertyName)), &definedIn);
- if (definedIn) {
- QString nonCppPackage;
- foreach (const LanguageUtils::FakeMetaObject::Export &qmlExport, definedIn->metaObject()->exports()) {
- if (qmlExport.package != QStringLiteral("<cpp>"))
- nonCppPackage = qmlExport.package;
- }
-
- const LanguageUtils::FakeMetaObject::Export qmlExport =
- definedIn->metaObject()->exportInPackage(nonCppPackage);
- if (qmlExport.isValid())
- return qmlExport.type;
-
- return definedIn->className();
- }
-
- return QString();
-}
-
static QByteArray getUnqualifiedName(const QByteArray &name)
{
const QList<QByteArray> nameComponents = name.split('.');
@@ -1186,17 +1135,6 @@ QByteArray NodeMetaInfoPrivate::cppPackageName() const
return QByteArray();
}
-QString NodeMetaInfoPrivate::componentSource() const
-{
- if (isFileComponent()) {
- const ASTObjectValue * astObjectValue = value_cast<ASTObjectValue>(getObjectValue());
- if (astObjectValue)
- return astObjectValue->document()->source().mid(astObjectValue->typeName()->identifierToken.begin(),
- astObjectValue->initializer()->rbraceToken.end());
- }
- return QString();
-}
-
QString NodeMetaInfoPrivate::componentFileName() const
{
if (isFileComponent()) {
@@ -1505,11 +1443,6 @@ bool NodeMetaInfo::propertyIsPointer(const PropertyName &propertyName) const
return m_privateData->isPropertyPointer(propertyName);
}
-QString NodeMetaInfo::propertyEnumScope(const PropertyName &propertyName) const
-{
- return m_privateData->propertyEnumScope(propertyName);
-}
-
QStringList NodeMetaInfo::propertyKeysForEnum(const PropertyName &propertyName) const
{
return m_privateData->keysForEnum(QString::fromUtf8(propertyTypeName(propertyName)));
@@ -1604,11 +1537,6 @@ int NodeMetaInfo::minorVersion() const
return m_privateData->minorVersion();
}
-QString NodeMetaInfo::componentSource() const
-{
- return m_privateData->componentSource();
-}
-
QString NodeMetaInfo::componentFileName() const
{
return m_privateData->componentFileName();
@@ -1619,11 +1547,6 @@ QString NodeMetaInfo::importDirectoryPath() const
return m_privateData->importDirectoryPath();
}
-bool NodeMetaInfo::hasCustomParser() const
-{
- return false;
-}
-
bool NodeMetaInfo::availableInVersion(int majorVersion, int minorVersion) const
{
if (majorVersion == -1 && minorVersion == -1)
diff --git a/src/plugins/qmldesigner/designercore/metainfo/storagecache.h b/src/plugins/qmldesigner/designercore/metainfo/storagecache.h
new file mode 100644
index 0000000000..55759c69f5
--- /dev/null
+++ b/src/plugins/qmldesigner/designercore/metainfo/storagecache.h
@@ -0,0 +1,335 @@
+/****************************************************************************
+**
+** Copyright (C) 2021 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of Qt Creator.
+**
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3 as published by the Free Software
+** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-3.0.html.
+**
+****************************************************************************/
+
+#pragma once
+
+#include "storagecacheentry.h"
+#include "storagecachefwd.h"
+
+#include <utils/algorithm.h>
+#include <utils/optional.h>
+#include <utils/set_algorithm.h>
+#include <utils/smallstringfwd.h>
+
+#include <algorithm>
+#include <shared_mutex>
+#include <vector>
+
+namespace QmlDesigner {
+
+class StorageCacheException : public std::exception
+{
+ const char *what() const noexcept override
+ {
+ return "StorageCache entries are in invalid state.";
+ }
+};
+
+class NonLockingMutex
+{
+public:
+ constexpr NonLockingMutex() noexcept {}
+ NonLockingMutex(const NonLockingMutex&) = delete;
+ NonLockingMutex& operator=(const NonLockingMutex&) = delete;
+ void lock() {}
+ void unlock() {}
+ void lock_shared() {}
+ void unlock_shared() {}
+};
+
+template<typename Type,
+ typename ViewType,
+ typename IndexType,
+ typename Storage,
+ typename Mutex,
+ bool (*compare)(Utils::SmallStringView, Utils::SmallStringView),
+ class CacheEntry = StorageCacheEntry<Type, ViewType, IndexType>>
+class StorageCache
+{
+ friend StorageCache;
+
+ using ResultType = std::conditional_t<std::is_base_of<NonLockingMutex, Mutex>::value, ViewType, Type>;
+
+public:
+ using MutexType = Mutex;
+ using CacheEntries = std::vector<CacheEntry>;
+ using const_iterator = typename CacheEntries::const_iterator;
+
+ StorageCache(Storage storage, std::size_t reserveSize = 1024)
+ : m_storage{std::move(storage)}
+ {
+ m_entries.reserve(reserveSize);
+ m_indices.reserve(reserveSize);
+ }
+
+ StorageCache(const StorageCache &other)
+ : m_entries(other.m_entries)
+ , m_indices(other.m_indices)
+ {}
+
+ template<typename Cache>
+ Cache clone()
+ {
+ Cache cache;
+ cache.m_entries = m_entries;
+ cache.m_indices = m_indices;
+
+ return cache;
+ }
+
+ StorageCache(StorageCache &&other)
+ : m_entries(std::move(other.m_entries))
+ , m_indices(std::move(other.m_indices))
+ {}
+
+ StorageCache &operator=(StorageCache &&other)
+ {
+ m_entries = std::move(other.m_entries);
+ m_indices = std::move(other.m_indices);
+
+ return *this;
+ }
+
+ void populate(CacheEntries &&entries)
+ {
+ uncheckedPopulate(std::move(entries));
+
+ checkEntries();
+ }
+
+ void uncheckedPopulate(CacheEntries &&entries)
+ {
+ std::sort(entries.begin(), entries.end(), [](ViewType first, ViewType second) {
+ return compare(first, second);
+ });
+
+ m_entries = std::move(entries);
+
+ int max_id = 0;
+
+ auto found = std::max_element(m_entries.begin(),
+ m_entries.end(),
+ [](const auto &first, const auto &second) {
+ return first.id < second.id;
+ });
+
+ if (found != m_entries.end())
+ max_id = found->id + 1;
+
+ m_indices.resize(max_id, -1);
+
+ updateIndices();
+ }
+
+ void add(std::vector<ViewType> &&views)
+ {
+ auto less = [](ViewType first, ViewType second) { return compare(first, second); };
+
+ std::sort(views.begin(), views.end(), less);
+
+ views.erase(std::unique(views.begin(), views.end()), views.end());
+
+ CacheEntries newCacheEntries;
+ newCacheEntries.reserve(views.size());
+
+ std::set_difference(views.begin(),
+ views.end(),
+ m_entries.begin(),
+ m_entries.end(),
+ Utils::make_iterator([&](ViewType newView) {
+ IndexType index = m_storage.fetchId(newView);
+ newCacheEntries.emplace_back(newView, index);
+ }),
+ less);
+
+ if (newCacheEntries.size()) {
+ auto found = std::max_element(newCacheEntries.begin(),
+ newCacheEntries.end(),
+ [](const auto &first, const auto &second) {
+ return first.id < second.id;
+ });
+
+ int max_id = found->id + 1;
+
+ if (max_id > int(m_indices.size()))
+ m_indices.resize(max_id, -1);
+
+ CacheEntries mergedCacheEntries;
+ mergedCacheEntries.reserve(newCacheEntries.size() + m_entries.size());
+
+ std::merge(std::make_move_iterator(m_entries.begin()),
+ std::make_move_iterator(m_entries.end()),
+ std::make_move_iterator(newCacheEntries.begin()),
+ std::make_move_iterator(newCacheEntries.end()),
+ std::back_inserter(mergedCacheEntries),
+ less);
+
+ m_entries = std::move(mergedCacheEntries);
+
+ updateIndices();
+ }
+ }
+
+ IndexType id(ViewType view)
+ {
+ std::shared_lock<Mutex> sharedLock(m_mutex);
+
+ auto found = find(view);
+
+ if (found != m_entries.end())
+ return found->id;
+
+ sharedLock.unlock();
+ std::lock_guard<Mutex> exclusiveLock(m_mutex);
+
+ if (!std::is_base_of<NonLockingMutex, Mutex>::value)
+ found = find(view);
+ if (found == m_entries.end())
+ found = insertEntry(found, view, m_storage.fetchId(view));
+
+ return found->id;
+ }
+
+ template<typename Container>
+ std::vector<IndexType> ids(const Container &values)
+ {
+ std::vector<IndexType> ids;
+ ids.reserve(values.size());
+
+ std::transform(values.begin(), values.end(), std::back_inserter(ids), [&](const auto &values) {
+ return this->id(values);
+ });
+
+ return ids;
+ }
+
+ std::vector<IndexType> ids(std::initializer_list<Type> values)
+ {
+ return ids<std::initializer_list<Type>>(values);
+ }
+
+ ResultType value(IndexType id)
+ {
+ std::shared_lock<Mutex> sharedLock(m_mutex);
+
+ if (IndexType(m_indices.size()) > id && m_indices.at(id) >= 0)
+ return m_entries.at(m_indices.at(id)).value;
+
+ sharedLock.unlock();
+ std::lock_guard<Mutex> exclusiveLock(m_mutex);
+
+ Type value{m_storage.fetchValue(id)};
+ auto interator = insertEntry(find(value), value, id);
+
+ return interator->value;
+ }
+
+ std::vector<ResultType> values(const std::vector<IndexType> &ids) const
+ {
+ std::shared_lock<Mutex> sharedLock(m_mutex);
+
+ std::vector<ResultType> values;
+ values.reserve(ids.size());
+
+ for (IndexType id : ids)
+ values.emplace_back(m_entries.at(m_indices.at(id)).value);
+
+ return values;
+ }
+
+ bool isEmpty() const { return m_entries.empty() && m_indices.empty(); }
+
+ Mutex &mutex() const
+ {
+ return m_mutex;
+ }
+
+private:
+ void updateIndices()
+ {
+ auto begin = m_entries.cbegin();
+ for (auto current = begin; current != m_entries.cend(); ++current)
+ m_indices[current->id] = std::distance(begin, current);
+ }
+
+ auto find(ViewType view)
+ {
+ auto found = std::lower_bound(m_entries.begin(), m_entries.end(), view, compare);
+
+ if (found == m_entries.end())
+ return m_entries.end();
+
+ if (*found == view)
+ return found;
+
+ return m_entries.end();
+ }
+
+ void incrementLargerOrEqualIndicesByOne(IndexType newIndex)
+ {
+ std::transform(m_indices.begin(),
+ m_indices.end(),
+ m_indices.begin(),
+ [&] (IndexType index) {
+ return index >= newIndex ? ++index : index;
+ });
+ }
+
+ void ensureSize(IndexType id)
+ {
+ if (m_indices.size() <= std::size_t(id))
+ m_indices.resize(id + 1, -1);
+ }
+
+ auto insertEntry(const_iterator beforeIterator, ViewType view, IndexType id)
+ {
+ auto inserted = m_entries.emplace(beforeIterator, view, id);
+
+ auto newIndex = IndexType(std::distance(m_entries.begin(), inserted));
+
+ incrementLargerOrEqualIndicesByOne(newIndex);
+
+ ensureSize(id);
+ m_indices.at(id) = newIndex;
+
+ return inserted;
+ }
+
+ void checkEntries()
+ {
+ for (const auto &entry : m_entries) {
+ if (entry.value != value(entry.id) || entry.id != id(entry.value))
+ throw StorageCacheException();
+ }
+ }
+
+private:
+ CacheEntries m_entries;
+ std::vector<IndexType> m_indices;
+ mutable Mutex m_mutex;
+ Storage m_storage;
+};
+
+} // namespace QmlDesigner
diff --git a/src/plugins/autotest/gtest/gtestsettingspage.h b/src/plugins/qmldesigner/designercore/metainfo/storagecacheentry.h
index acb3b3513c..f121c6df2f 100644
--- a/src/plugins/autotest/gtest/gtestsettingspage.h
+++ b/src/plugins/qmldesigner/designercore/metainfo/storagecacheentry.h
@@ -1,6 +1,6 @@
/****************************************************************************
**
-** Copyright (C) 2016 The Qt Company Ltd.
+** Copyright (C) 2021 The Qt Company Ltd.
** Contact: https://www.qt.io/licensing/
**
** This file is part of Qt Creator.
@@ -25,18 +25,26 @@
#pragma once
-#include <coreplugin/dialogs/ioptionspage.h>
+namespace QmlDesigner {
-namespace Autotest {
-namespace Internal {
+template<typename Type, typename ViewType, typename IndexType>
+class StorageCacheEntry
+{
+public:
+ StorageCacheEntry(ViewType value, IndexType id)
+ : value(value)
+ , id(id)
+ {}
-class GTestSettings;
+ operator ViewType() const { return value; }
+ friend bool operator==(const StorageCacheEntry &first, const StorageCacheEntry &second)
+ {
+ return first.id == second.id && first.value == second.value;
+ }
-class GTestSettingsPage final : public Core::IOptionsPage
-{
public:
- GTestSettingsPage(GTestSettings *settings, Utils::Id settingsId);
+ Type value;
+ IndexType id;
};
-} // namespace Internal
-} // namespace Autotest
+} // namespace QmlDesigner
diff --git a/src/plugins/autotest/qtest/qttestsettingspage.h b/src/plugins/qmldesigner/designercore/metainfo/storagecachefwd.h
index dbd8850a69..3c5df91391 100644
--- a/src/plugins/autotest/qtest/qttestsettingspage.h
+++ b/src/plugins/qmldesigner/designercore/metainfo/storagecachefwd.h
@@ -1,6 +1,6 @@
/****************************************************************************
**
-** Copyright (C) 2016 The Qt Company Ltd.
+** Copyright (C) 2021 The Qt Company Ltd.
** Contact: https://www.qt.io/licensing/
**
** This file is part of Qt Creator.
@@ -25,18 +25,18 @@
#pragma once
-#include <coreplugin/dialogs/ioptionspage.h>
+#include <utils/smallstringfwd.h>
-namespace Autotest {
-namespace Internal {
+namespace QmlDesigner {
-class QtTestSettings;
+class NonLockingMutex;
-class QtTestSettingsPage final : public Core::IOptionsPage
-{
-public:
- QtTestSettingsPage(QtTestSettings *settings, Utils::Id settingsId);
-};
-
-} // namespace Internal
-} // namespace Autotest
+template<typename Type,
+ typename ViewType,
+ typename IndexType,
+ typename Storage,
+ typename Mutex,
+ bool (*compare)(Utils::SmallStringView, Utils::SmallStringView),
+ typename CacheEntry>
+class StorageCache;
+} // namespace QmlDesigner
diff --git a/src/plugins/qmldesigner/designercore/model/abstractview.cpp b/src/plugins/qmldesigner/designercore/model/abstractview.cpp
index fa36ea447d..6ef3c6d5d6 100644
--- a/src/plugins/qmldesigner/designercore/model/abstractview.cpp
+++ b/src/plugins/qmldesigner/designercore/model/abstractview.cpp
@@ -270,8 +270,11 @@ void AbstractView::fileUrlChanged(const QUrl &/*oldUrl*/, const QUrl &/*newUrl*/
{
}
-void AbstractView::nodeOrderChanged(const NodeListProperty &/*listProperty*/, const ModelNode &/*movedNode*/, int /*oldIndex*/)
+void AbstractView::nodeOrderChanged(const NodeListProperty & /*listProperty*/) {}
+
+void AbstractView::nodeOrderChanged(const NodeListProperty &listProperty, const ModelNode &, int)
{
+ nodeOrderChanged(listProperty);
}
/*!
@@ -636,7 +639,7 @@ void AbstractView::contextHelp(const Core::IContext::HelpCallback &callback) con
#endif
}
-void AbstractView::activateTimeline(const ModelNode &timeline)
+void AbstractView::setCurrentTimeline(const ModelNode &timeline)
{
if (currentTimeline().isValid())
currentTimeline().toogleRecording(false);
diff --git a/src/plugins/qmldesigner/designercore/model/basetexteditmodifier.cpp b/src/plugins/qmldesigner/designercore/model/basetexteditmodifier.cpp
index 8113e62846..4639fd101c 100644
--- a/src/plugins/qmldesigner/designercore/model/basetexteditmodifier.cpp
+++ b/src/plugins/qmldesigner/designercore/model/basetexteditmodifier.cpp
@@ -31,7 +31,9 @@
#include <qmljseditor/qmljseditordocument.h>
#include <qmljseditor/qmljscomponentfromobjectdef.h>
#include <qmljseditor/qmljscompletionassist.h>
+#include <qmljstools/qmljstoolssettings.h>
#include <texteditor/tabsettings.h>
+#include <texteditor/simplecodestylepreferences.h>
#include <utils/changeset.h>
#include <typeinfo>
@@ -80,12 +82,11 @@ void BaseTextEditModifier::indent(int offset, int length)
indentLines(startLine, endLine);
}
-int BaseTextEditModifier::indentDepth() const
+TextEditor::TabSettings BaseTextEditModifier::tabSettings() const
{
if (m_textEdit)
- return m_textEdit->textDocument()->tabSettings().m_indentSize;
- else
- return 0;
+ return m_textEdit->textDocument()->tabSettings();
+ return QmlJSTools::QmlJSToolsSettings::globalCodeStyle()->tabSettings();
}
bool BaseTextEditModifier::renameId(const QString &oldId, const QString &newId)
diff --git a/src/plugins/qmldesigner/designercore/model/componenttextmodifier.cpp b/src/plugins/qmldesigner/designercore/model/componenttextmodifier.cpp
index 1d500b8496..5f984a1f34 100644
--- a/src/plugins/qmldesigner/designercore/model/componenttextmodifier.cpp
+++ b/src/plugins/qmldesigner/designercore/model/componenttextmodifier.cpp
@@ -83,9 +83,9 @@ void ComponentTextModifier::indentLines(int startLine, int endLine)
m_originalModifier->indentLines(startLine, endLine);
}
-int ComponentTextModifier::indentDepth() const
+TextEditor::TabSettings ComponentTextModifier::tabSettings() const
{
- return m_originalModifier->indentDepth();
+ return m_originalModifier->tabSettings();
}
void ComponentTextModifier::startGroup()
diff --git a/src/plugins/qmldesigner/designercore/model/internalnode_p.h b/src/plugins/qmldesigner/designercore/model/internalnode_p.h
index a5f3c6dfca..8770763b4e 100644
--- a/src/plugins/qmldesigner/designercore/model/internalnode_p.h
+++ b/src/plugins/qmldesigner/designercore/model/internalnode_p.h
@@ -52,7 +52,8 @@ using InternalPropertyPointer = QSharedPointer<InternalProperty>;
class InternalNode
{
- friend class InternalProperty;
+ friend InternalProperty;
+
public:
using Pointer = QSharedPointer<InternalNode>;
using WeakPointer = QWeakPointer<InternalNode>;
diff --git a/src/plugins/qmldesigner/designercore/model/internalnodeabstractproperty.h b/src/plugins/qmldesigner/designercore/model/internalnodeabstractproperty.h
index ee80cc42da..2254788e77 100644
--- a/src/plugins/qmldesigner/designercore/model/internalnodeabstractproperty.h
+++ b/src/plugins/qmldesigner/designercore/model/internalnodeabstractproperty.h
@@ -33,7 +33,7 @@ namespace Internal {
class InternalNodeAbstractProperty : public InternalProperty
{
- friend class InternalNode;
+ friend InternalNode;
public:
using Pointer = QSharedPointer<InternalNodeAbstractProperty>;
diff --git a/src/plugins/qmldesigner/designercore/model/internalnodelistproperty.cpp b/src/plugins/qmldesigner/designercore/model/internalnodelistproperty.cpp
index 51f6b3421b..97c191e35c 100644
--- a/src/plugins/qmldesigner/designercore/model/internalnodelistproperty.cpp
+++ b/src/plugins/qmldesigner/designercore/model/internalnodelistproperty.cpp
@@ -68,12 +68,6 @@ int InternalNodeListProperty::indexOf(const InternalNode::Pointer &node) const
return m_nodeList.indexOf(node);
}
-InternalNode::Pointer InternalNodeListProperty::at(int index) const
-{
- Q_ASSERT(index >=0 || index < m_nodeList.count());
- return InternalNode::Pointer(m_nodeList.at(index));
-}
-
bool InternalNodeListProperty::isNodeListProperty() const
{
return true;
diff --git a/src/plugins/qmldesigner/designercore/model/internalnodelistproperty.h b/src/plugins/qmldesigner/designercore/model/internalnodelistproperty.h
index b50a144491..a0ba6d07eb 100644
--- a/src/plugins/qmldesigner/designercore/model/internalnodelistproperty.h
+++ b/src/plugins/qmldesigner/designercore/model/internalnodelistproperty.h
@@ -33,7 +33,7 @@ namespace QmlDesigner {
namespace Internal {
-class InternalNodeListProperty : public InternalNodeAbstractProperty
+class InternalNodeListProperty final : public InternalNodeAbstractProperty
{
public:
using Pointer = QSharedPointer<InternalNodeListProperty>;
@@ -43,9 +43,27 @@ public:
bool isValid() const override;
bool isEmpty() const override;
+ int size() const { return m_nodeList.size(); }
int count() const override;
int indexOf(const InternalNodePointer &node) const override;
- InternalNodePointer at(int index) const;
+ const InternalNodePointer &at(int index) const
+ {
+ Q_ASSERT(index >= 0 && index < m_nodeList.count());
+ return m_nodeList[index];
+ }
+
+ InternalNodePointer &at(int index)
+ {
+ Q_ASSERT(index >= 0 && index < m_nodeList.count());
+ return m_nodeList[index];
+ }
+
+ InternalNodePointer &find(InternalNodePointer node)
+ {
+ auto found = std::find(m_nodeList.begin(), m_nodeList.end(), node);
+
+ return *found;
+ }
bool isNodeListProperty() const override;
@@ -54,6 +72,9 @@ public:
const QList<InternalNodePointer> &nodeList() const;
void slide(int from, int to);
+ QList<InternalNodePointer>::iterator begin() { return m_nodeList.begin(); }
+ QList<InternalNodePointer>::iterator end() { return m_nodeList.end(); }
+
protected:
InternalNodeListProperty(const PropertyName &name, const InternalNodePointer &propertyOwner);
void add(const InternalNodePointer &node) override;
diff --git a/src/plugins/qmldesigner/designercore/model/model.cpp b/src/plugins/qmldesigner/designercore/model/model.cpp
index d695be92ef..ef21c1ef45 100644
--- a/src/plugins/qmldesigner/designercore/model/model.cpp
+++ b/src/plugins/qmldesigner/designercore/model/model.cpp
@@ -880,12 +880,20 @@ void ModelPrivate::notifyNodeReparent(const InternalNodePointer &node,
}
void ModelPrivate::notifyNodeOrderChanged(const InternalNodeListPropertyPointer &internalListProperty,
- const InternalNodePointer &node, int oldIndex)
+ const InternalNodePointer &node,
+ int oldIndex)
{
notifyNodeInstanceViewLast([&](AbstractView *view) {
- view->nodeOrderChanged(NodeListProperty(internalListProperty, m_model, view),
- ModelNode(node, m_model, view),
- oldIndex);
+ NodeListProperty nodeListProperty(internalListProperty, m_model, view);
+ view->nodeOrderChanged(nodeListProperty, ModelNode(node, m_model, view), oldIndex);
+ });
+}
+
+void ModelPrivate::notifyNodeOrderChanged(const InternalNodeListPropertyPointer &internalListProperty)
+{
+ notifyNodeInstanceViewLast([&](AbstractView *view) {
+ NodeListProperty nodeListProperty(internalListProperty, m_model, view);
+ view->nodeOrderChanged(nodeListProperty);
});
}
diff --git a/src/plugins/qmldesigner/designercore/model/model_p.h b/src/plugins/qmldesigner/designercore/model/model_p.h
index cc15226265..43a8585809 100644
--- a/src/plugins/qmldesigner/designercore/model/model_p.h
+++ b/src/plugins/qmldesigner/designercore/model/model_p.h
@@ -83,9 +83,9 @@ class ModelPrivate : public QObject {
Q_OBJECT
Q_DISABLE_COPY(ModelPrivate)
- friend class QmlDesigner::Model;
- friend class QmlDesigner::Internal::WriteLocker;
- friend class QmlDesigner::Internal::NodeMetaInfoPrivate;
+ friend Model;
+ friend Internal::WriteLocker;
+ friend Internal::NodeMetaInfoPrivate;
public:
ModelPrivate(Model *model);
@@ -156,7 +156,10 @@ public:
void notifyVariantPropertiesChanged(const InternalNodePointer &node, const PropertyNameList &propertyNameList, AbstractView::PropertyChangeFlags propertyChange);
void notifyScriptFunctionsChanged(const InternalNodePointer &node, const QStringList &scriptFunctionList);
- void notifyNodeOrderChanged(const InternalNodeListPropertyPointer &internalListProperty, const InternalNodePointer &node, int oldIndex);
+ void notifyNodeOrderChanged(const InternalNodeListPropertyPointer &internalListProperty,
+ const InternalNodePointer &node,
+ int oldIndex);
+ void notifyNodeOrderChanged(const InternalNodeListPropertyPointer &internalListProperty);
void notifyAuxiliaryDataChanged(const InternalNodePointer &node, const PropertyName &name, const QVariant &data);
void notifyNodeSourceChanged(const InternalNodePointer &node, const QString &newNodeSource);
diff --git a/src/plugins/qmldesigner/designercore/model/modeltotextmerger.cpp b/src/plugins/qmldesigner/designercore/model/modeltotextmerger.cpp
index 1f8c23048d..b2f36b5456 100644
--- a/src/plugins/qmldesigner/designercore/model/modeltotextmerger.cpp
+++ b/src/plugins/qmldesigner/designercore/model/modeltotextmerger.cpp
@@ -81,12 +81,13 @@ void ModelToTextMerger::propertiesRemoved(const QList<AbstractProperty>& propert
void ModelToTextMerger::propertiesChanged(const QList<AbstractProperty>& propertyList, PropertyChangeFlags propertyChange)
{
+ const TextEditor::TabSettings tabSettings = m_rewriterView->textModifier()->tabSettings();
foreach (const AbstractProperty &property, propertyList) {
ModelNode containedModelNode;
- const int indentDepth = m_rewriterView->textModifier()->indentDepth();
const QString propertyTextValue = QmlTextGenerator(propertyOrder(),
- indentDepth)(property);
+ tabSettings,
+ tabSettings.m_indentSize)(property);
switch (propertyChange) {
case AbstractView::PropertiesAdded:
@@ -162,14 +163,18 @@ void ModelToTextMerger::nodeReparented(const ModelNode &node, const NodeAbstract
switch (propertyChange) {
case AbstractView::PropertiesAdded:
schedule(new AddPropertyRewriteAction(newPropertyParent,
- QmlTextGenerator(propertyOrder())(node),
+ QmlTextGenerator(propertyOrder(),
+ m_rewriterView->textModifier()
+ ->tabSettings())(node),
propertyType(newPropertyParent),
node));
break;
case AbstractView::NoAdditionalChanges:
schedule(new ChangePropertyRewriteAction(newPropertyParent,
- QmlTextGenerator(propertyOrder())(node),
+ QmlTextGenerator(propertyOrder(),
+ m_rewriterView->textModifier()
+ ->tabSettings())(node),
propertyType(newPropertyParent),
node));
break;
@@ -213,7 +218,7 @@ void ModelToTextMerger::applyChanges()
dumpRewriteActions(QStringLiteral("Before compression"));
RewriteActionCompressor compress(propertyOrder());
- compress(m_rewriteActions);
+ compress(m_rewriteActions, m_rewriterView->textModifier()->tabSettings());
dumpRewriteActions(QStringLiteral("After compression"));
if (m_rewriteActions.isEmpty())
diff --git a/src/plugins/qmldesigner/designercore/model/nodelistproperty.cpp b/src/plugins/qmldesigner/designercore/model/nodelistproperty.cpp
index 2fa462c85a..512f37722a 100644
--- a/src/plugins/qmldesigner/designercore/model/nodelistproperty.cpp
+++ b/src/plugins/qmldesigner/designercore/model/nodelistproperty.cpp
@@ -36,6 +36,11 @@
namespace QmlDesigner {
+Internal::NodeListPropertyIterator::value_type Internal::NodeListPropertyIterator::operator*() const
+{
+ return {m_nodeListProperty->at(m_currentIndex), m_model, m_view};
+}
+
NodeListProperty::NodeListProperty() = default;
NodeListProperty::NodeListProperty(const NodeListProperty &property, AbstractView *view)
@@ -54,6 +59,20 @@ NodeListProperty::NodeListProperty(const Internal::InternalNodeListProperty::Poi
{
}
+Internal::InternalNodeListPropertyPointer &NodeListProperty::internalNodeListProperty() const
+{
+ if (m_internalNodeListProperty)
+ return m_internalNodeListProperty;
+
+ if (internalNode()->hasProperty(name())) {
+ Internal::InternalProperty::Pointer internalProperty = internalNode()->property(name());
+ if (internalProperty->isNodeListProperty())
+ m_internalNodeListProperty = internalProperty->toNodeListProperty();
+ }
+
+ return m_internalNodeListProperty;
+}
+
static QList<ModelNode> internalNodesToModelNodes(const QList<Internal::InternalNode::Pointer> &inputList, Model* model, AbstractView *view)
{
QList<ModelNode> modelNodeList;
@@ -68,11 +87,10 @@ QList<ModelNode> NodeListProperty::toModelNodeList() const
if (!isValid())
throw InvalidPropertyException(__LINE__, __FUNCTION__, __FILE__, "<invalid node list property>");
- if (internalNode()->hasProperty(name())) {
- Internal::InternalProperty::Pointer internalProperty = internalNode()->property(name());
- if (internalProperty->isNodeListProperty())
- return internalNodesToModelNodes(internalProperty->toNodeListProperty()->nodeList(), model(), view());
- }
+ if (internalNodeListProperty())
+ return internalNodesToModelNodes(m_internalNodeListProperty->toNodeListProperty()->nodeList(),
+ model(),
+ view());
return QList<ModelNode>();
}
@@ -129,14 +147,51 @@ ModelNode NodeListProperty::at(int index) const
if (!isValid())
throw InvalidPropertyException(__LINE__, __FUNCTION__, __FILE__, "<invalid node list property>");
- Internal::InternalNodeListProperty::Pointer internalProperty = internalNode()->nodeListProperty(name());
- if (internalProperty)
- return ModelNode(internalProperty->at(index), model(), view());
-
+ if (internalNodeListProperty())
+ return ModelNode(m_internalNodeListProperty->at(index), model(), view());
return ModelNode();
}
+void NodeListProperty::iterSwap(NodeListProperty::iterator &first, NodeListProperty::iterator &second)
+{
+ if (!internalNodeListProperty())
+ return;
+
+ std::swap(m_internalNodeListProperty->at(first.m_currentIndex),
+ m_internalNodeListProperty->at(second.m_currentIndex));
+}
+
+NodeListProperty::iterator NodeListProperty::rotate(NodeListProperty::iterator first,
+ NodeListProperty::iterator newFirst,
+ NodeListProperty::iterator last)
+{
+ if (!internalNodeListProperty())
+ return {};
+
+ auto begin = m_internalNodeListProperty->begin();
+
+ auto iter = std::rotate(std::next(begin, first.m_currentIndex),
+ std::next(begin, newFirst.m_currentIndex),
+ std::next(begin, last.m_currentIndex));
+
+ privateModel()->notifyNodeOrderChanged(m_internalNodeListProperty);
+
+ return {iter - begin, internalNodeListProperty().data(), model(), view()};
+}
+
+void NodeListProperty::reverse(NodeListProperty::iterator first, NodeListProperty::iterator last)
+{
+ if (!internalNodeListProperty())
+ return;
+
+ auto begin = m_internalNodeListProperty->begin();
+
+ std::reverse(std::next(begin, first.m_currentIndex), std::next(begin, last.m_currentIndex));
+
+ privateModel()->notifyNodeOrderChanged(m_internalNodeListProperty);
+}
+
void NodeListProperty::reverseModelNodes(const QList<ModelNode> &nodes)
{
ModelNode firstNode = nodes.first();
@@ -157,4 +212,27 @@ void NodeListProperty::reverseModelNodes(const QList<ModelNode> &nodes)
parentProperty.swap(selectedNodeIndices[i], selectedNodeIndices[selectedNodeIndices.size() - 1 - i]);
}
+Internal::NodeListPropertyIterator NodeListProperty::begin()
+{
+ return const_cast<const NodeListProperty *>(this)->begin();
+}
+
+Internal::NodeListPropertyIterator NodeListProperty::end()
+{
+ return const_cast<const NodeListProperty *>(this)->end();
+}
+
+Internal::NodeListPropertyIterator NodeListProperty::begin() const
+{
+ return {0, internalNodeListProperty().data(), model(), view()};
+}
+
+Internal::NodeListPropertyIterator NodeListProperty::end() const
+{
+ auto nodeListProperty = internalNodeListProperty();
+ auto size = nodeListProperty ? nodeListProperty->size() : 0;
+
+ return {size, nodeListProperty.data(), model(), view()};
+}
+
} // namespace QmlDesigner
diff --git a/src/plugins/qmldesigner/designercore/model/qml3dnode.cpp b/src/plugins/qmldesigner/designercore/model/qml3dnode.cpp
index d05048fe31..cb9e2b8bb1 100644
--- a/src/plugins/qmldesigner/designercore/model/qml3dnode.cpp
+++ b/src/plugins/qmldesigner/designercore/model/qml3dnode.cpp
@@ -58,6 +58,68 @@ bool Qml3DNode::isValidQml3DNode(const ModelNode &modelNode)
&& (modelNode.metaInfo().isSubclassOf("QtQuick3D.Node"));
}
+void Qml3DNode::setVariantProperty(const PropertyName &name, const QVariant &value)
+{
+ if (isBlocked(name))
+ return;
+
+ if (name.startsWith("eulerRotation"))
+ handleEulerRotationSet();
+
+ QmlObjectNode::setVariantProperty(name, value);
+}
+
+void Qml3DNode::setBindingProperty(const PropertyName &name, const QString &expression)
+{
+ if (isBlocked(name))
+ return;
+
+ if (name.startsWith("eulerRotation"))
+ handleEulerRotationSet();
+
+ QmlObjectNode::setBindingProperty(name, expression);
+}
+
+bool Qml3DNode::isBlocked(const PropertyName &propName) const
+{
+ if (modelNode().isValid() && propName.startsWith("eulerRotation"))
+ return modelNode().auxiliaryData("rotBlocked@internal").toBool();
+
+ return false;
+}
+
+void Qml3DNode::handleEulerRotationSet()
+{
+ ModelNode node = modelNode();
+ // The rotation property is quaternion, which is difficult to deal with for users, so QDS
+ // only supports eulerRotation. Since having both on the same object isn't supported,
+ // remove the rotation property if eulerRotation is set.
+ if (node.isValid() && node.isSubclassOf("QtQuick3D.Node")) {
+ if (!isInBaseState()) {
+ QmlPropertyChanges changeSet(currentState().propertyChanges(node));
+ Q_ASSERT(changeSet.isValid());
+ node = changeSet.modelNode();
+ }
+
+ if (node.hasProperty("rotation")) {
+ // We need to reset the eulerRotation values as removing rotation will zero them,
+ // which is not desirable if the change only targets one of the xyz subproperties.
+ // Get the eulerRotation value from instance, as they are not available in model.
+ QVector3D eulerVec = instanceValue("eulerRotation").value<QVector3D>();
+ node.removeProperty("rotation");
+ if (qIsNaN(eulerVec.x()))
+ eulerVec.setX(0.);
+ if (qIsNaN(eulerVec.y()))
+ eulerVec.setY(0.);
+ if (qIsNaN(eulerVec.z()))
+ eulerVec.setZ(0.);
+ node.variantProperty("eulerRotation.x").setValue(eulerVec.x());
+ node.variantProperty("eulerRotation.y").setValue(eulerVec.y());
+ node.variantProperty("eulerRotation.z").setValue(eulerVec.z());
+ }
+ }
+}
+
QList<ModelNode> toModelNodeList(const QList<Qml3DNode> &qmlVisualNodeList)
{
QList<ModelNode> modelNodeList;
diff --git a/src/plugins/qmldesigner/designercore/model/qmlobjectnode.cpp b/src/plugins/qmldesigner/designercore/model/qmlobjectnode.cpp
index cebe171295..6c9acc4b6e 100644
--- a/src/plugins/qmldesigner/designercore/model/qmlobjectnode.cpp
+++ b/src/plugins/qmldesigner/designercore/model/qmlobjectnode.cpp
@@ -28,6 +28,7 @@
#include "qmlstate.h"
#include "qmltimelinekeyframegroup.h"
#include "qmlvisualnode.h"
+#include "qml3dnode.h"
#include "variantproperty.h"
#include "nodeproperty.h"
#include <invalidmodelnodeexception.h>
@@ -738,4 +739,19 @@ QStringList QmlObjectNode::allStateNames() const
return nodeInstance().allStateNames();
}
+QmlObjectNode *QmlObjectNode::getQmlObjectNodeOfCorrectType(const ModelNode &modelNode)
+{
+ // Create QmlObjectNode of correct type for the modelNode
+ // Note: Currently we are only interested in differentiating 3D nodes, so no check for
+ // visual nodes is done for efficiency reasons
+ if (modelNode.isValid() && modelNode.isSubclassOf("QtQuick3D.Node"))
+ return new Qml3DNode(modelNode);
+ return new QmlObjectNode(modelNode);
+}
+
+bool QmlObjectNode::isBlocked(const PropertyName &propName) const
+{
+ return false;
+}
+
} //QmlDesigner
diff --git a/src/plugins/qmldesigner/designercore/model/qmltextgenerator.cpp b/src/plugins/qmldesigner/designercore/model/qmltextgenerator.cpp
index 3349a5df54..0a22c352b2 100644
--- a/src/plugins/qmldesigner/designercore/model/qmltextgenerator.cpp
+++ b/src/plugins/qmldesigner/designercore/model/qmltextgenerator.cpp
@@ -85,9 +85,12 @@ static QString unicodeEscape(const QString &stringValue)
return stringValue;
}
-QmlTextGenerator::QmlTextGenerator(const PropertyNameList &propertyOrder, int indentDepth):
- m_propertyOrder(propertyOrder),
- m_indentDepth(indentDepth)
+QmlTextGenerator::QmlTextGenerator(const PropertyNameList &propertyOrder,
+ const TextEditor::TabSettings &tabSettings,
+ const int startIndentDepth)
+ : m_propertyOrder(propertyOrder)
+ , m_tabSettings(tabSettings)
+ , m_startIndentDepth(startIndentDepth)
{
}
@@ -106,13 +109,13 @@ QString QmlTextGenerator::toQml(const AbstractProperty &property, int indentDept
for (int i = 0; i < nodes.length(); ++i) {
if (i > 0)
result += QStringLiteral("\n\n");
- result += QString(indentDepth, QLatin1Char(' '));
+ result += m_tabSettings.indentationString(0, indentDepth, 0);
result += toQml(nodes.at(i), indentDepth);
}
return result;
} else {
QString result = QStringLiteral("[");
- const int arrayContentDepth = indentDepth + 4;
+ const int arrayContentDepth = indentDepth + m_tabSettings.m_indentSize;
const QString arrayContentIndentation(arrayContentDepth, QLatin1Char(' '));
for (int i = 0; i < nodes.length(); ++i) {
if (i > 0)
@@ -208,11 +211,12 @@ QString QmlTextGenerator::toQml(const ModelNode &node, int indentDepth) const
result += type;
result += QStringLiteral(" {\n");
- const int propertyIndentDepth = indentDepth + 4;
+ const int propertyIndentDepth = indentDepth + m_tabSettings.m_indentSize;
const QString properties = propertiesToQml(node, propertyIndentDepth);
- return result + properties + QString(indentDepth, QLatin1Char(' ')) + QLatin1Char('}');
+ return result + properties + m_tabSettings.indentationString(0, indentDepth, 0)
+ + QLatin1Char('}');
}
QString QmlTextGenerator::propertiesToQml(const ModelNode &node, int indentDepth) const
@@ -227,7 +231,7 @@ QString QmlTextGenerator::propertiesToQml(const ModelNode &node, int indentDepth
if (propertyName == "id") {
// the model handles the id property special, so:
if (!node.id().isEmpty()) {
- QString idLine(indentDepth, QLatin1Char(' '));
+ QString idLine = m_tabSettings.indentationString(0, indentDepth, 0);
idLine += QStringLiteral("id: ");
idLine += node.id();
idLine += QLatin1Char('\n');
@@ -264,7 +268,7 @@ QString QmlTextGenerator::propertyToQml(const AbstractProperty &property, int in
result = toQml(property, indentDepth);
} else {
if (property.isDynamic()) {
- result = QString(indentDepth, QLatin1Char(' '))
+ result = m_tabSettings.indentationString(0, indentDepth, 0)
+ QStringLiteral("property ")
+ QString::fromUtf8(property.dynamicTypeName())
+ QStringLiteral(" ")
@@ -272,7 +276,7 @@ QString QmlTextGenerator::propertyToQml(const AbstractProperty &property, int in
+ QStringLiteral(": ")
+ toQml(property, indentDepth);
} else {
- result = QString(indentDepth, QLatin1Char(' '))
+ result = m_tabSettings.indentationString(0, indentDepth, 0)
+ QString::fromUtf8(property.name())
+ QStringLiteral(": ")
+ toQml(property, indentDepth);
diff --git a/src/plugins/qmldesigner/designercore/model/qmltextgenerator.h b/src/plugins/qmldesigner/designercore/model/qmltextgenerator.h
index 5c2823573e..0138dd149a 100644
--- a/src/plugins/qmldesigner/designercore/model/qmltextgenerator.h
+++ b/src/plugins/qmldesigner/designercore/model/qmltextgenerator.h
@@ -27,6 +27,8 @@
#include <QString>
+#include <texteditor/tabsettings.h>
+
#include "abstractproperty.h"
#include "modelnode.h"
@@ -36,13 +38,15 @@ namespace Internal {
class QmlTextGenerator
{
public:
- explicit QmlTextGenerator(const PropertyNameList &propertyOrder, int indentDepth = 0);
+ explicit QmlTextGenerator(const PropertyNameList &propertyOrder,
+ const TextEditor::TabSettings &tabSettings,
+ const int startIndentDepth = 0);
QString operator()(const AbstractProperty &property) const
- { return toQml(property, m_indentDepth); }
+ { return toQml(property, m_startIndentDepth); }
QString operator()(const ModelNode &modelNode) const
- { return toQml(modelNode, m_indentDepth); }
+ { return toQml(modelNode, m_startIndentDepth); }
private:
QString toQml(const AbstractProperty &property, int indentDepth) const;
@@ -54,7 +58,8 @@ private:
private:
PropertyNameList m_propertyOrder;
- int m_indentDepth;
+ TextEditor::TabSettings m_tabSettings;
+ const int m_startIndentDepth;
};
} // namespace Internal
diff --git a/src/plugins/qmldesigner/designercore/model/qmltimeline.cpp b/src/plugins/qmldesigner/designercore/model/qmltimeline.cpp
index 68738b06de..d84f338741 100644
--- a/src/plugins/qmldesigner/designercore/model/qmltimeline.cpp
+++ b/src/plugins/qmldesigner/designercore/model/qmltimeline.cpp
@@ -294,6 +294,19 @@ bool QmlTimeline::hasKeyframeGroupForTarget(const ModelNode &node) const
return false;
}
+void QmlTimeline::insertKeyframe(const ModelNode &target, const PropertyName &propertyName)
+{
+ ModelNode targetNode = target;
+ QmlTimelineKeyframeGroup timelineFrames(keyframeGroup(targetNode, propertyName));
+
+ QTC_ASSERT(timelineFrames.isValid(), return );
+
+ const qreal frame = modelNode().auxiliaryData("currentFrame@NodeInstance").toReal();
+ const QVariant value = QmlObjectNode(targetNode).instanceValue(propertyName);
+
+ timelineFrames.setValue(value, frame);
+}
+
QList<QmlTimelineKeyframeGroup> QmlTimeline::allKeyframeGroups() const
{
QList<QmlTimelineKeyframeGroup> returnList;
diff --git a/src/plugins/qmldesigner/designercore/model/rewriteactioncompressor.cpp b/src/plugins/qmldesigner/designercore/model/rewriteactioncompressor.cpp
index d84b088db8..24342002b3 100644
--- a/src/plugins/qmldesigner/designercore/model/rewriteactioncompressor.cpp
+++ b/src/plugins/qmldesigner/designercore/model/rewriteactioncompressor.cpp
@@ -50,14 +50,15 @@ static bool nodeOrParentInSet(const ModelNode &modelNode, const QSet<ModelNode>
return false;
}
-void RewriteActionCompressor::operator()(QList<RewriteAction *> &actions) const
+void RewriteActionCompressor::operator()(QList<RewriteAction *> &actions,
+ const TextEditor::TabSettings &tabSettings) const
{
compressImports(actions);
compressRereparentActions(actions);
compressReparentIntoSamePropertyActions(actions);
compressPropertyActions(actions);
compressAddEditRemoveNodeActions(actions);
- compressAddEditActions(actions);
+ compressAddEditActions(actions, tabSettings);
compressAddReparentActions(actions);
}
@@ -256,7 +257,8 @@ void RewriteActionCompressor::compressPropertyActions(QList<RewriteAction *> &ac
}
}
-void RewriteActionCompressor::compressAddEditActions(QList<RewriteAction *> &actions) const
+void RewriteActionCompressor::compressAddEditActions(
+ QList<RewriteAction *> &actions, const TextEditor::TabSettings &tabSettings) const
{
QList<RewriteAction *> actionsToRemove;
QSet<ModelNode> addedNodes;
@@ -303,7 +305,7 @@ void RewriteActionCompressor::compressAddEditActions(QList<RewriteAction *> &act
delete action;
}
- QmlTextGenerator gen(m_propertyOrder);
+ QmlTextGenerator gen(m_propertyOrder, tabSettings);
foreach (RewriteAction *action, dirtyActions) {
RewriteAction *newAction = nullptr;
if (AddPropertyRewriteAction *addAction = action->asAddPropertyRewriteAction()) {
diff --git a/src/plugins/qmldesigner/designercore/model/rewriteactioncompressor.h b/src/plugins/qmldesigner/designercore/model/rewriteactioncompressor.h
index 2702ab0d60..57139f9811 100644
--- a/src/plugins/qmldesigner/designercore/model/rewriteactioncompressor.h
+++ b/src/plugins/qmldesigner/designercore/model/rewriteactioncompressor.h
@@ -35,7 +35,7 @@ class RewriteActionCompressor
public:
RewriteActionCompressor(const PropertyNameList &propertyOrder): m_propertyOrder(propertyOrder) {}
- void operator()(QList<RewriteAction *> &actions) const;
+ void operator()(QList<RewriteAction *> &actions, const TextEditor::TabSettings &tabSettings) const;
private:
void compressImports(QList<RewriteAction *> &actions) const;
@@ -44,7 +44,7 @@ private:
void compressReparentIntoSamePropertyActions(QList<RewriteAction *> &actions) const;
void compressAddEditRemoveNodeActions(QList<RewriteAction *> &actions) const;
void compressPropertyActions(QList<RewriteAction *> &actions) const;
- void compressAddEditActions(QList<RewriteAction *> &actions) const;
+ void compressAddEditActions(QList<RewriteAction *> &actions, const TextEditor::TabSettings &tabSettings) const;
void compressAddReparentActions(QList<RewriteAction *> &actions) const;
private:
diff --git a/src/plugins/qmldesigner/designercore/model/rewriterview.cpp b/src/plugins/qmldesigner/designercore/model/rewriterview.cpp
index 04ec87e077..a110750453 100644
--- a/src/plugins/qmldesigner/designercore/model/rewriterview.cpp
+++ b/src/plugins/qmldesigner/designercore/model/rewriterview.cpp
@@ -310,7 +310,9 @@ void RewriterView::nodeIdChanged(const ModelNode& node, const QString& newId, co
applyChanges();
}
-void RewriterView::nodeOrderChanged(const NodeListProperty &listProperty, const ModelNode &movedNode, int /*oldIndex*/)
+void RewriterView::nodeOrderChanged(const NodeListProperty &listProperty,
+ const ModelNode &movedNode,
+ int /*oldIndex*/)
{
Q_ASSERT(textModifier());
if (textToModelMerger()->isActive())
@@ -326,6 +328,21 @@ void RewriterView::nodeOrderChanged(const NodeListProperty &listProperty, const
applyChanges();
}
+void RewriterView::nodeOrderChanged(const NodeListProperty &listProperty)
+{
+ Q_ASSERT(textModifier());
+ if (textToModelMerger()->isActive())
+ return;
+
+ auto modelNodes = listProperty.directSubNodes();
+
+ for (const ModelNode &movedNode : modelNodes)
+ modelToTextMerger()->nodeSlidAround(movedNode, ModelNode{});
+
+ if (!isModificationGroupActive())
+ applyChanges();
+}
+
void RewriterView::rootNodeTypeChanged(const QString &type, int majorVersion, int minorVersion)
{
Q_ASSERT(textModifier());
diff --git a/src/plugins/qmldesigner/designercore/model/variantproperty.cpp b/src/plugins/qmldesigner/designercore/model/variantproperty.cpp
index 498faea6ec..d2a7dc1870 100644
--- a/src/plugins/qmldesigner/designercore/model/variantproperty.cpp
+++ b/src/plugins/qmldesigner/designercore/model/variantproperty.cpp
@@ -57,8 +57,7 @@ void VariantProperty::setValue(const QVariant &value)
if (isDynamic())
qWarning() << "Calling VariantProperty::setValue on dynamic property.";
- // QVector*D(0, 0, 0) detects as null variant though it is valid value
- if (value.isNull() && (value.type() != QVariant::Vector3D && value.type() != QVariant::Vector2D))
+ if (!value.isValid())
throw InvalidArgumentException(__LINE__, __FUNCTION__, __FILE__, name());
if (internalNode()->hasProperty(name())) { //check if oldValue != value
diff --git a/src/plugins/qmldesigner/designermcumanager.cpp b/src/plugins/qmldesigner/designermcumanager.cpp
index d173ab6766..b7b9ef2fad 100644
--- a/src/plugins/qmldesigner/designermcumanager.cpp
+++ b/src/plugins/qmldesigner/designermcumanager.cpp
@@ -64,7 +64,7 @@ DesignerMcuManager &DesignerMcuManager::instance()
QString DesignerMcuManager::mcuResourcesPath()
{
- return Core::ICore::resourcePath() + QStringLiteral("/qmldesigner/qt4mcu");
+ return Core::ICore::resourcePath("qmldesigner/qt4mcu").toString();
}
bool DesignerMcuManager::isMCUProject() const
@@ -186,22 +186,12 @@ void DesignerMcuManager::readVersionData(const DesignerMcuManager::Version &vers
//handling banned properties:
const QStringList bannedProperties = readPropertyList("bannedProperties", child);
-#if QT_VERSION >= QT_VERSION_CHECK(5, 14, 0)
m_bannedProperties.unite(QSet<QString>(bannedProperties.begin(), bannedProperties.end()));
-#elif
- m_bannedProperties.unite(QSet<QString>::fromList(bannedProperties));
-#endif
-
}
const QList<QString> bannedItems = readPropertyList("bannedItems", versionData);
-#if QT_VERSION >= QT_VERSION_CHECK(5, 14, 0)
- m_bannedItems = QSet<QString>(bannedItems.begin(), bannedItems.end());
-#elif
- m_bannedItems = QSet<QString>::fromList(bannedItems);
-#endif
-
+ m_bannedItems = QSet<QString>(bannedItems.begin(), bannedItems.end());
m_allowedImports = readPropertyList("allowedImports", versionData);
m_bannedImports = readPropertyList("bannedImports", versionData);
m_currentVersion = version;
diff --git a/src/plugins/qmldesigner/designersettings.cpp b/src/plugins/qmldesigner/designersettings.cpp
index ed12230ff9..a08f5cae62 100644
--- a/src/plugins/qmldesigner/designersettings.cpp
+++ b/src/plugins/qmldesigner/designersettings.cpp
@@ -76,13 +76,7 @@ void DesignerSettings::fromSettings(QSettings *settings)
restoreValue(settings, DesignerSettingsKey::NAVIGATOR_SHOW_ONLY_VISIBLE_ITEMS, true);
restoreValue(settings, DesignerSettingsKey::NAVIGATOR_REVERSE_ITEM_ORDER, false);
restoreValue(settings, DesignerSettingsKey::STANDALONE_MODE, false);
- restoreValue(settings, DesignerSettingsKey::ENABLE_TIMELINEVIEW,
-#if (QT_VERSION < QT_VERSION_CHECK(5, 14, 0))
- false
-#else
- true
-#endif
- );
+ restoreValue(settings, DesignerSettingsKey::ENABLE_TIMELINEVIEW, true);
restoreValue(settings, DesignerSettingsKey::SIMPLE_COLOR_PALETTE_CONTENT, QStringList());
restoreValue(settings, DesignerSettingsKey::ALWAYS_DESIGN_MODE, true);
restoreValue(settings, DesignerSettingsKey::DISABLE_ITEM_LIBRARY_UPDATE_TIMER, true);
diff --git a/src/plugins/qmldesigner/designmodewidget.cpp b/src/plugins/qmldesigner/designmodewidget.cpp
index 4c485c02b3..19baf68f8e 100644
--- a/src/plugins/qmldesigner/designmodewidget.cpp
+++ b/src/plugins/qmldesigner/designmodewidget.cpp
@@ -234,7 +234,8 @@ void DesignModeWidget::setup()
ADS::DockManager::setConfigFlag(ADS::DockManager::AllTabsHaveCloseButton, true);
m_dockManager = new ADS::DockManager(this);
m_dockManager->setSettings(settings);
- m_dockManager->setWorkspacePresetsPath(Core::ICore::resourcePath() + QLatin1String("/qmldesigner/workspacePresets/"));
+ m_dockManager->setWorkspacePresetsPath(
+ Core::ICore::resourcePath("qmldesigner/workspacePresets/").toString());
QString sheet = QString::fromUtf8(Utils::FileReader::fetchQrc(":/qmldesigner/dockwidgets.css"));
m_dockManager->setStyleSheet(Theme::replaceCssColors(sheet));
diff --git a/src/plugins/qmldesigner/documentmanager.cpp b/src/plugins/qmldesigner/documentmanager.cpp
index 7cd0b2d14c..d8a8048aaf 100644
--- a/src/plugins/qmldesigner/documentmanager.cpp
+++ b/src/plugins/qmldesigner/documentmanager.cpp
@@ -302,7 +302,7 @@ bool DocumentManager::createFile(const QString &filePath, const QString &content
textFileFormat.codec = Core::EditorManager::defaultTextCodec();
QString errorMessage;
- return textFileFormat.writeFile(filePath, contents, &errorMessage);
+ return textFileFormat.writeFile(Utils::FilePath::fromString(filePath), contents, &errorMessage);
}
void DocumentManager::addFileToVersionControl(const QString &directoryPath, const QString &newFilePath)
diff --git a/src/plugins/qmldesigner/generateresource.cpp b/src/plugins/qmldesigner/generateresource.cpp
index d9e3447c3f..6925092b53 100644
--- a/src/plugins/qmldesigner/generateresource.cpp
+++ b/src/plugins/qmldesigner/generateresource.cpp
@@ -44,7 +44,7 @@
#include <utils/fileutils.h>
#include <utils/qtcassert.h>
#include <utils/utilsicons.h>
-#include <utils/synchronousprocess.h>
+#include <utils/qtcprocess.h>
#include <QAction>
#include <QTemporaryFile>
@@ -103,14 +103,15 @@ void GenerateResource::generateMenuEntry()
currentProject->activeTarget()->kit());
QString rccBinary = qtVersion->rccCommand();
- QProcess rccProcess;
+ Utils::QtcProcess rccProcess;
rccProcess.setWorkingDirectory(projectPath);
const QStringList arguments1 = {"--project", "--output", temp.fileName()};
const QStringList arguments2 = {"--binary", "--output", resourceFileName, temp.fileName()};
for (const auto &arguments : {arguments1, arguments2}) {
- rccProcess.start(rccBinary, arguments);
+ rccProcess.setCommand({rccBinary, arguments});
+ rccProcess.start();
if (!rccProcess.waitForStarted()) {
Core::MessageManager::writeDisrupting(
QCoreApplication::translate("QmlDesigner::GenerateResource",
@@ -120,8 +121,8 @@ void GenerateResource::generateMenuEntry()
}
QByteArray stdOut;
QByteArray stdErr;
- if (!Utils::SynchronousProcess::readDataFromProcess(rccProcess, 30, &stdOut, &stdErr, true)) {
- Utils::SynchronousProcess::stopProcess(rccProcess);
+ if (!rccProcess.readDataFromProcess(30, &stdOut, &stdErr, true)) {
+ rccProcess.stopProcess();
Core::MessageManager::writeDisrupting(
QCoreApplication::translate("QmlDesigner::GenerateResource",
"A timeout occurred running \"%1\"")
diff --git a/src/plugins/qmldesigner/qmldesignerplugin.cpp b/src/plugins/qmldesigner/qmldesignerplugin.cpp
index 489d7951c1..c35539942b 100644
--- a/src/plugins/qmldesigner/qmldesignerplugin.cpp
+++ b/src/plugins/qmldesigner/qmldesignerplugin.cpp
@@ -213,8 +213,7 @@ QmlDesignerPlugin::~QmlDesignerPlugin()
bool QmlDesignerPlugin::initialize(const QStringList & /*arguments*/, QString *errorMessage/* = 0*/)
{
Sqlite::LibraryInitializer::initialize();
-
- QDir{}.mkpath(Core::ICore::cacheResourcePath());
+ QDir{}.mkpath(Core::ICore::cacheResourcePath().toString());
if (!Utils::HostOsInfo::canCreateOpenGLContext(errorMessage))
return false;
@@ -222,8 +221,10 @@ bool QmlDesignerPlugin::initialize(const QStringList & /*arguments*/, QString *e
if (DesignerSettings::getValue(DesignerSettingsKey::STANDALONE_MODE).toBool())
GenerateResource::generateMenuEntry();
- QString fontPath = Core::ICore::resourcePath() +
- QStringLiteral("/qmldesigner/propertyEditorQmlSources/imports/StudioTheme/icons.ttf");
+ const QString fontPath
+ = Core::ICore::resourcePath(
+ "qmldesigner/propertyEditorQmlSources/imports/StudioTheme/icons.ttf")
+ .toString();
if (QFontDatabase::addApplicationFont(fontPath) < 0)
qCWarning(qmldesignerLog) << "Could not add font " << fontPath << "to font database";
diff --git a/src/plugins/qmldesigner/qmldesignerplugin.qbs b/src/plugins/qmldesigner/qmldesignerplugin.qbs
index 9f9124691f..ff972573dd 100644
--- a/src/plugins/qmldesigner/qmldesignerplugin.qbs
+++ b/src/plugins/qmldesigner/qmldesignerplugin.qbs
@@ -69,13 +69,13 @@ Project {
Export {
Depends { name: "QmlJS" }
cpp.includePaths: base.concat([
- product.sourceDirectory,
- product.sourceDirectory + "/components/componentcore",
- product.sourceDirectory + "/components/edit3d",
- product.sourceDirectory + "/components/formeditor",
- product.sourceDirectory + "/components/integration",
- product.sourceDirectory + "/designercore",
- product.sourceDirectory + "/designercore/include",
+ exportingProduct.sourceDirectory,
+ exportingProduct.sourceDirectory + "/components/componentcore",
+ exportingProduct.sourceDirectory + "/components/edit3d",
+ exportingProduct.sourceDirectory + "/components/formeditor",
+ exportingProduct.sourceDirectory + "/components/integration",
+ exportingProduct.sourceDirectory + "/designercore",
+ exportingProduct.sourceDirectory + "/designercore/include",
qtc.export_data_base + "/qml/qmlpuppet/interfaces",
])
}
@@ -458,6 +458,8 @@ Project {
"componentcore/designeractionmanagerview.h",
"componentcore/findimplementation.cpp",
"componentcore/findimplementation.h",
+ "componentcore/formatoperation.cpp",
+ "componentcore/formatoperation.h",
"componentcore/gestures.cpp",
"componentcore/gestures.h",
"componentcore/layoutingridlayout.cpp",
@@ -623,6 +625,16 @@ Project {
"itemlibrary/itemlibraryassetimportdialog.ui",
"itemlibrary/itemlibraryassetimporter.cpp",
"itemlibrary/itemlibraryassetimporter.h",
+ "itemlibrary/itemlibraryassetsdir.cpp",
+ "itemlibrary/itemlibraryassetsdir.h",
+ "itemlibrary/itemlibraryassetsdirsmodel.cpp",
+ "itemlibrary/itemlibraryassetsdirsmodel.h",
+ "itemlibrary/itemlibraryassetsfilesmodel.cpp",
+ "itemlibrary/itemlibraryassetsfilesmodel.h",
+ "itemlibrary/itemlibraryassetsiconprovider.cpp",
+ "itemlibrary/itemlibraryassetsiconprovider.h",
+ "itemlibrary/itemlibraryassetsmodel.cpp",
+ "itemlibrary/itemlibraryassetsmodel.h",
"itemlibrary/itemlibrarycategoriesmodel.cpp",
"itemlibrary/itemlibrarycategoriesmodel.h",
"itemlibrary/itemlibrarycategory.cpp",
@@ -637,14 +649,10 @@ Project {
"itemlibrary/itemlibraryitemsmodel.h",
"itemlibrary/itemlibrarymodel.cpp",
"itemlibrary/itemlibrarymodel.h",
- "itemlibrary/itemlibraryresourceview.cpp",
- "itemlibrary/itemlibraryresourceview.h",
"itemlibrary/itemlibraryview.cpp",
"itemlibrary/itemlibraryview.h",
"itemlibrary/itemlibrarywidget.cpp",
"itemlibrary/itemlibrarywidget.h",
- "itemlibrary/customfilesystemmodel.cpp",
- "itemlibrary/customfilesystemmodel.h",
"itemlibrary/itemlibraryiconimageprovider.cpp",
"itemlibrary/itemlibraryiconimageprovider.h",
"navigator/iconcheckboxitemdelegate.cpp",
diff --git a/src/plugins/qmldesigner/qmldesignerunittestfiles.pri b/src/plugins/qmldesigner/qmldesignerunittestfiles.pri
index a50be7f644..e8a4eaf358 100644
--- a/src/plugins/qmldesigner/qmldesignerunittestfiles.pri
+++ b/src/plugins/qmldesigner/qmldesignerunittestfiles.pri
@@ -53,6 +53,9 @@ HEADERS += \
$$PWD/designercore/include/import.h \
$$PWD/designercore/include/abstractproperty.h \
$$PWD/designercore/include/abstractview.h \
+ $$PWD/designercore/metainfo/storagecache.h \
+ $$PWD/designercore/metainfo/storagecacheentry.h \
+ $$PWD/designercore/metainfo/storagecachefwd.h \
$$PWD/designercore/model/model_p.h \
$$PWD/designercore/include/qmldesignercorelib_global.h \
$$PWD/designercore/model/internalbindingproperty.h \
diff --git a/src/plugins/qmljseditor/qmljseditor.cpp b/src/plugins/qmljseditor/qmljseditor.cpp
index e7c26c8a05..39105a0406 100644
--- a/src/plugins/qmljseditor/qmljseditor.cpp
+++ b/src/plugins/qmljseditor/qmljseditor.cpp
@@ -772,7 +772,7 @@ void QmlJSEditorWidget::findLinkAt(const QTextCursor &cursor,
// if it's a file import, link to the file
foreach (const ImportInfo &import, semanticInfo.document->bind()->imports()) {
if (import.ast() == importAst && import.type() == ImportType::File) {
- Utils::Link link(import.path());
+ Utils::Link link(Utils::FilePath::fromString(import.path()));
link.linkTextStart = importAst->firstSourceLocation().begin();
link.linkTextEnd = importAst->lastSourceLocation().end();
processLinkCallback(Utils::Link());
@@ -790,7 +790,7 @@ void QmlJSEditorWidget::findLinkAt(const QTextCursor &cursor,
link.linkTextStart = literal->literalToken.begin();
link.linkTextEnd = literal->literalToken.end();
if (semanticInfo.snapshot.document(text)) {
- link.targetFileName = text;
+ link.targetFilePath = Utils::FilePath::fromString(text);
processLinkCallback(link);
return;
}
@@ -798,7 +798,7 @@ void QmlJSEditorWidget::findLinkAt(const QTextCursor &cursor,
semanticInfo.document->path(),
text);
if (QFileInfo::exists(relative)) {
- link.targetFileName = relative;
+ link.targetFilePath = Utils::FilePath::fromString(relative);
processLinkCallback(link);
return;
}
@@ -815,7 +815,7 @@ void QmlJSEditorWidget::findLinkAt(const QTextCursor &cursor,
return processLinkCallback(Utils::Link());
Utils::Link link;
- link.targetFileName = fileName;
+ link.targetFilePath = Utils::FilePath::fromString(fileName);
link.targetLine = line;
link.targetColumn = column - 1; // adjust the column
diff --git a/src/plugins/qmljseditor/qmljseditorplugin.cpp b/src/plugins/qmljseditor/qmljseditorplugin.cpp
index 7414a1a972..e0d5703102 100644
--- a/src/plugins/qmljseditor/qmljseditorplugin.cpp
+++ b/src/plugins/qmljseditor/qmljseditorplugin.cpp
@@ -92,8 +92,9 @@ public:
QPointer<QmlJSEditorDocument> m_currentDocument;
- Utils::JsonSchemaManager m_jsonManager{{ICore::userResourcePath() + "/json/",
- ICore::resourcePath() + "/json/"}};
+ Utils::JsonSchemaManager m_jsonManager{
+ {ICore::userResourcePath("json/").toString(),
+ ICore::resourcePath("json/").toString()}};
QmlJSEditorFactory m_qmlJSEditorFactory;
QmlJSOutlineWidgetFactory m_qmlJSOutlineWidgetFactory;
QuickToolBar m_quickToolBar;
diff --git a/src/plugins/qmljseditor/qmljsfindreferences.cpp b/src/plugins/qmljseditor/qmljsfindreferences.cpp
index a251e82306..06afc62d8a 100644
--- a/src/plugins/qmljseditor/qmljsfindreferences.cpp
+++ b/src/plugins/qmljseditor/qmljsfindreferences.cpp
@@ -815,6 +815,7 @@ FindReferences::FindReferences(QObject *parent)
m_watcher.setPendingResultsLimit(1);
connect(&m_watcher, &QFutureWatcherBase::resultsReadyAt, this, &FindReferences::displayResults);
connect(&m_watcher, &QFutureWatcherBase::finished, this, &FindReferences::searchFinished);
+ m_synchronizer.setCancelOnWait(true);
}
FindReferences::~FindReferences() = default;
@@ -922,6 +923,7 @@ void FindReferences::findUsages(const QString &fileName, quint32 offset)
QFuture<Usage> result = Utils::runAsync(&find_helper, ModelManagerInterface::workingCopy(),
modelManager->snapshot(), fileName, offset, QString());
m_watcher.setFuture(result);
+ m_synchronizer.addFuture(result);
}
void FindReferences::renameUsages(const QString &fileName, quint32 offset,
@@ -937,6 +939,7 @@ void FindReferences::renameUsages(const QString &fileName, quint32 offset,
QFuture<Usage> result = Utils::runAsync(&find_helper, ModelManagerInterface::workingCopy(),
modelManager->snapshot(), fileName, offset, newName);
m_watcher.setFuture(result);
+ m_synchronizer.addFuture(result);
}
QList<FindReferences::Usage> FindReferences::findUsageOfType(const QString &fileName, const QString &typeName)
diff --git a/src/plugins/qmljseditor/qmljsfindreferences.h b/src/plugins/qmljseditor/qmljsfindreferences.h
index ebfdad5a23..30c120503d 100644
--- a/src/plugins/qmljseditor/qmljsfindreferences.h
+++ b/src/plugins/qmljseditor/qmljsfindreferences.h
@@ -27,6 +27,8 @@
#include "qmljseditor_global.h"
+#include <utils/futuresynchronizer.h>
+
#include <QObject>
#include <QFutureWatcher>
#include <QPointer>
@@ -81,6 +83,7 @@ private:
QPointer<Core::SearchResult> m_currentSearch;
QFutureWatcher<Usage> m_watcher;
+ Utils::FutureSynchronizer m_synchronizer;
};
} // namespace QmlJSEditor
diff --git a/src/plugins/qmljseditor/qmljssemantichighlighter.cpp b/src/plugins/qmljseditor/qmljssemantichighlighter.cpp
index b7e98ad0b7..9db93925a3 100644
--- a/src/plugins/qmljseditor/qmljssemantichighlighter.cpp
+++ b/src/plugins/qmljseditor/qmljssemantichighlighter.cpp
@@ -224,12 +224,16 @@ public:
protected:
void accept(Node *ast)
{
+ if (m_futureInterface.isCanceled())
+ return;
if (ast)
ast->accept(this);
}
void scopedAccept(Node *ast, Node *child)
{
+ if (m_futureInterface.isCanceled())
+ return;
m_scopeBuilder.push(ast);
accept(child);
m_scopeBuilder.pop();
@@ -553,6 +557,7 @@ SemanticHighlighter::SemanticHighlighter(QmlJSEditorDocument *document)
this, &SemanticHighlighter::applyResults);
connect(&m_watcher, &QFutureWatcherBase::finished,
this, &SemanticHighlighter::finished);
+ m_futureSynchronizer.setCancelOnWait(true);
}
void SemanticHighlighter::rerun(const QmlJSTools::SemanticInfo &semanticInfo)
@@ -560,8 +565,10 @@ void SemanticHighlighter::rerun(const QmlJSTools::SemanticInfo &semanticInfo)
m_watcher.cancel();
m_startRevision = m_document->document()->revision();
- m_watcher.setFuture(Utils::runAsync(QThread::LowestPriority,
- &SemanticHighlighter::run, this, semanticInfo));
+ auto future = Utils::runAsync(QThread::LowestPriority, &SemanticHighlighter::run,
+ this, semanticInfo);
+ m_watcher.setFuture(future);
+ m_futureSynchronizer.addFuture(future);
}
void SemanticHighlighter::cancel()
diff --git a/src/plugins/qmljseditor/qmljssemantichighlighter.h b/src/plugins/qmljseditor/qmljssemantichighlighter.h
index 77ea2a7c12..f36b9b5518 100644
--- a/src/plugins/qmljseditor/qmljssemantichighlighter.h
+++ b/src/plugins/qmljseditor/qmljssemantichighlighter.h
@@ -27,6 +27,7 @@
#include <qmljseditor/qmljseditor_global.h>
#include <texteditor/semantichighlighter.h>
+#include <utils/futuresynchronizer.h>
#include <QFutureWatcher>
#include <QTextLayout>
#include <QVector>
@@ -89,6 +90,7 @@ private:
QHash<int, QTextCharFormat> m_formats;
QHash<int, QTextCharFormat> m_extraFormats;
QVector<QTextLayout::FormatRange> m_diagnosticRanges;
+ Utils::FutureSynchronizer m_futureSynchronizer;
};
} // namespace QmlJSEditor
diff --git a/src/plugins/qmljseditor/qmloutlinemodel.cpp b/src/plugins/qmljseditor/qmloutlinemodel.cpp
index 8110110809..80ca3c0804 100644
--- a/src/plugins/qmljseditor/qmloutlinemodel.cpp
+++ b/src/plugins/qmljseditor/qmloutlinemodel.cpp
@@ -328,8 +328,7 @@ QmlOutlineModel::QmlOutlineModel(QmlJSEditorDocument *document) :
m_editorDocument(document)
{
m_icons = Icons::instance();
- const QString resourcePath = Core::ICore::resourcePath();
- Icons::instance()->setIconFilesPath(resourcePath + QLatin1String("/qmlicons"));
+ Icons::instance()->setIconFilesPath(Core::ICore::resourcePath("qmlicons").toString());
setItemPrototype(new QmlOutlineItem(this));
}
diff --git a/src/plugins/qmljstools/qmljsbundleprovider.cpp b/src/plugins/qmljstools/qmljsbundleprovider.cpp
index 176d66b33d..2f4e5d1e79 100644
--- a/src/plugins/qmljstools/qmljsbundleprovider.cpp
+++ b/src/plugins/qmljstools/qmljsbundleprovider.cpp
@@ -51,16 +51,15 @@ QmlBundle BasicBundleProvider::defaultBundle(const QString &bundleInfoName)
{
static bool wroteErrors = false;
QmlBundle res;
- QString defaultBundlePath = Core::ICore::resourcePath()
- + QLatin1String("/qml-type-descriptions/")
- + bundleInfoName;
- if (!QFileInfo::exists(defaultBundlePath)) {
+ const Utils::FilePath defaultBundlePath = Core::ICore::resourcePath("qml-type-descriptions")
+ / bundleInfoName;
+ if (!defaultBundlePath.exists()) {
qWarning() << "BasicBundleProvider: ERROR " << defaultBundlePath
<< " not found";
return res;
}
QStringList errors;
- if (!res.readFrom(defaultBundlePath, &errors) && ! wroteErrors) {
+ if (!res.readFrom(defaultBundlePath.toString(), &errors) && !wroteErrors) {
qWarning() << "BasicBundleProvider: ERROR reading " << defaultBundlePath
<< " : " << errors;
wroteErrors = true;
diff --git a/src/plugins/qmljstools/qmljsmodelmanager.cpp b/src/plugins/qmljstools/qmljsmodelmanager.cpp
index c41d55b996..3a95852254 100644
--- a/src/plugins/qmljstools/qmljsmodelmanager.cpp
+++ b/src/plugins/qmljstools/qmljsmodelmanager.cpp
@@ -220,15 +220,15 @@ void ModelManager::delayedInitialization()
ViewerContext qbsVContext;
qbsVContext.language = Dialect::QmlQbs;
- qbsVContext.paths.append(ICore::resourcePath() + QLatin1String("/qbs"));
+ qbsVContext.paths.append(ICore::resourcePath("qbs").toString());
setDefaultVContext(qbsVContext);
}
void ModelManager::loadDefaultQmlTypeDescriptions()
{
if (ICore::instance()) {
- loadQmlTypeDescriptionsInternal(ICore::resourcePath());
- loadQmlTypeDescriptionsInternal(ICore::userResourcePath());
+ loadQmlTypeDescriptionsInternal(ICore::resourcePath().toString());
+ loadQmlTypeDescriptionsInternal(ICore::userResourcePath().toString());
}
}
diff --git a/src/plugins/qmljstools/qmljstools_test.cpp b/src/plugins/qmljstools/qmljstools_test.cpp
index a2c35efa00..1daf28f7b6 100644
--- a/src/plugins/qmljstools/qmljstools_test.cpp
+++ b/src/plugins/qmljstools/qmljstools_test.cpp
@@ -43,7 +43,9 @@ void QmlJSToolsPlugin::test_basic()
{
ModelManagerInterface *modelManager = ModelManagerInterface::instance();
- const QString qmlFilePath = Core::ICore::resourcePath() + QLatin1String("/qmldesigner/itemLibraryQmlSources/ItemDelegate.qml");
+ const QString qmlFilePath = Core::ICore::resourcePath(
+ "qmldesigner/itemLibraryQmlSources/ItemDelegate.qml")
+ .toString();
modelManager->updateSourceFiles(QStringList(qmlFilePath), false);
modelManager->test_joinAllThreads();
diff --git a/src/plugins/qmlpreview/qmlpreviewruncontrol.cpp b/src/plugins/qmlpreview/qmlpreviewruncontrol.cpp
index fd1d3bde3d..f9528c8e0e 100644
--- a/src/plugins/qmlpreview/qmlpreviewruncontrol.cpp
+++ b/src/plugins/qmlpreview/qmlpreviewruncontrol.cpp
@@ -148,7 +148,7 @@ LocalQmlPreviewSupport::LocalQmlPreviewSupport(ProjectExplorer::RunControl *runC
}
}
- Utils::QtcProcess::addArg(&runnable.commandLineArguments,
+ Utils::ProcessArgs::addArg(&runnable.commandLineArguments,
QmlDebug::qmlDebugLocalArguments(QmlDebug::QmlPreviewServices,
serverUrl.path()));
doStart(runnable, {});
diff --git a/src/plugins/qmlprofiler/CMakeLists.txt b/src/plugins/qmlprofiler/CMakeLists.txt
index 016e874e03..304c69dd35 100644
--- a/src/plugins/qmlprofiler/CMakeLists.txt
+++ b/src/plugins/qmlprofiler/CMakeLists.txt
@@ -17,17 +17,15 @@ add_qtc_plugin(QmlProfiler
qmlprofiler_global.h
qmlprofileractions.cpp qmlprofileractions.h
qmlprofileranimationsmodel.cpp qmlprofileranimationsmodel.h
- qmlprofilerattachdialog.cpp qmlprofilerattachdialog.h qmlprofilerattachdialog.ui
+ qmlprofilerattachdialog.cpp qmlprofilerattachdialog.h
qmlprofilerbindingloopsrenderpass.cpp qmlprofilerbindingloopsrenderpass.h
qmlprofilerclientmanager.cpp qmlprofilerclientmanager.h
- qmlprofilerconfigwidget.cpp qmlprofilerconfigwidget.h qmlprofilerconfigwidget.ui
qmlprofilerconstants.h
qmlprofilerdetailsrewriter.cpp qmlprofilerdetailsrewriter.h
qmlprofilereventsview.h
qmlprofilereventtypes.h
qmlprofilermodelmanager.cpp qmlprofilermodelmanager.h
qmlprofilernotesmodel.cpp qmlprofilernotesmodel.h
- qmlprofileroptionspage.cpp qmlprofileroptionspage.h
qmlprofilerplugin.cpp qmlprofilerplugin.h
qmlprofilerrangemodel.cpp qmlprofilerrangemodel.h
qmlprofilerrunconfigurationaspect.cpp qmlprofilerrunconfigurationaspect.h
@@ -67,7 +65,6 @@ extend_qtc_plugin(QmlProfiler
tests/qmlprofilerattachdialog_test.cpp tests/qmlprofilerattachdialog_test.h
tests/qmlprofilerbindingloopsrenderpass_test.cpp tests/qmlprofilerbindingloopsrenderpass_test.h
tests/qmlprofilerclientmanager_test.cpp tests/qmlprofilerclientmanager_test.h
- tests/qmlprofilerconfigwidget_test.cpp tests/qmlprofilerconfigwidget_test.h
tests/qmlprofilerdetailsrewriter_test.cpp tests/qmlprofilerdetailsrewriter_test.h
tests/qmlprofilertool_test.cpp tests/qmlprofilertool_test.h
tests/qmlprofilertraceclient_test.cpp tests/qmlprofilertraceclient_test.h
diff --git a/src/plugins/qmlprofiler/qmlprofiler.pro b/src/plugins/qmlprofiler/qmlprofiler.pro
index 884a63e24d..be6db89a7f 100644
--- a/src/plugins/qmlprofiler/qmlprofiler.pro
+++ b/src/plugins/qmlprofiler/qmlprofiler.pro
@@ -20,11 +20,9 @@ SOURCES += \
qmlprofilerattachdialog.cpp \
qmlprofilerbindingloopsrenderpass.cpp \
qmlprofilerclientmanager.cpp \
- qmlprofilerconfigwidget.cpp \
qmlprofilerdetailsrewriter.cpp \
qmlprofilermodelmanager.cpp \
qmlprofilernotesmodel.cpp \
- qmlprofileroptionspage.cpp \
qmlprofilerplugin.cpp \
qmlprofilerrangemodel.cpp \
qmlprofilerrunconfigurationaspect.cpp \
@@ -61,14 +59,12 @@ HEADERS += \
qmlprofilerattachdialog.h \
qmlprofilerbindingloopsrenderpass.h \
qmlprofilerclientmanager.h \
- qmlprofilerconfigwidget.h \
qmlprofilerconstants.h \
qmlprofilerdetailsrewriter.h \
qmlprofilereventsview.h \
qmlprofilereventtypes.h \
qmlprofilermodelmanager.h \
qmlprofilernotesmodel.h \
- qmlprofileroptionspage.h \
qmlprofilerplugin.h \
qmlprofilerrangemodel.h \
qmlprofilerrunconfigurationaspect.h \
@@ -91,9 +87,6 @@ HEADERS += \
RESOURCES += \
qml/qmlprofiler.qrc
-FORMS += \
- qmlprofilerconfigwidget.ui
-
equals(TEST, 1) {
include(tests/tests.pri)
}
diff --git a/src/plugins/qmlprofiler/qmlprofiler.qbs b/src/plugins/qmlprofiler/qmlprofiler.qbs
index 44103450c1..d6b445c9c3 100644
--- a/src/plugins/qmlprofiler/qmlprofiler.qbs
+++ b/src/plugins/qmlprofiler/qmlprofiler.qbs
@@ -36,14 +36,12 @@ QtcPlugin {
"qmlprofilerattachdialog.cpp", "qmlprofilerattachdialog.h",
"qmlprofilerbindingloopsrenderpass.cpp","qmlprofilerbindingloopsrenderpass.h",
"qmlprofilerclientmanager.cpp", "qmlprofilerclientmanager.h",
- "qmlprofilerconfigwidget.cpp", "qmlprofilerconfigwidget.h",
- "qmlprofilerconfigwidget.ui", "qmlprofilerconstants.h",
+ "qmlprofilerconstants.h",
"qmlprofilerdetailsrewriter.cpp", "qmlprofilerdetailsrewriter.h",
"qmlprofilereventsview.h",
"qmlprofilereventtypes.h",
"qmlprofilermodelmanager.cpp", "qmlprofilermodelmanager.h",
"qmlprofilernotesmodel.cpp", "qmlprofilernotesmodel.h",
- "qmlprofileroptionspage.cpp", "qmlprofileroptionspage.h",
"qmlprofilerplugin.cpp", "qmlprofilerplugin.h",
"qmlprofilerrunconfigurationaspect.cpp", "qmlprofilerrunconfigurationaspect.h",
"qmlprofilerrangemodel.cpp", "qmlprofilerrangemodel.h",
@@ -93,7 +91,6 @@ QtcPlugin {
"qmlprofilerbindingloopsrenderpass_test.cpp",
"qmlprofilerbindingloopsrenderpass_test.h",
"qmlprofilerclientmanager_test.cpp", "qmlprofilerclientmanager_test.h",
- "qmlprofilerconfigwidget_test.cpp", "qmlprofilerconfigwidget_test.h",
"qmlprofilerdetailsrewriter_test.cpp", "qmlprofilerdetailsrewriter_test.h",
"qmlprofilertool_test.cpp", "qmlprofilertool_test.h",
"qmlprofilertraceclient_test.cpp", "qmlprofilertraceclient_test.h",
diff --git a/src/plugins/qmlprofiler/qmlprofilerattachdialog.ui b/src/plugins/qmlprofiler/qmlprofilerattachdialog.ui
deleted file mode 100644
index c920c4d160..0000000000
--- a/src/plugins/qmlprofiler/qmlprofilerattachdialog.ui
+++ /dev/null
@@ -1,129 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<ui version="4.0">
- <class>QmlProfiler::Internal::QmlProfilerAttachDialog</class>
- <widget class="QDialog" name="QmlProfiler::Internal::QmlProfilerAttachDialog">
- <property name="geometry">
- <rect>
- <x>0</x>
- <y>0</y>
- <width>203</width>
- <height>136</height>
- </rect>
- </property>
- <property name="windowTitle">
- <string>QML Profiler</string>
- </property>
- <layout class="QVBoxLayout" name="verticalLayout">
- <item>
- <layout class="QFormLayout" name="formLayout">
- <item row="0" column="0">
- <widget class="QLabel" name="addressLabel">
- <property name="text">
- <string>&amp;Host:</string>
- </property>
- <property name="buddy">
- <cstring>addressLineEdit</cstring>
- </property>
- </widget>
- </item>
- <item row="0" column="1">
- <widget class="QLineEdit" name="addressLineEdit">
- <property name="text">
- <string>localhost</string>
- </property>
- </widget>
- </item>
- <item row="1" column="0">
- <widget class="QLabel" name="portLabel">
- <property name="text">
- <string>&amp;Port:</string>
- </property>
- <property name="buddy">
- <cstring>portSpinBox</cstring>
- </property>
- </widget>
- </item>
- <item row="1" column="1">
- <widget class="QSpinBox" name="portSpinBox">
- <property name="minimum">
- <number>1</number>
- </property>
- <property name="maximum">
- <number>65535</number>
- </property>
- <property name="value">
- <number>3768</number>
- </property>
- </widget>
- </item>
- <item row="2" column="0">
- <widget class="QLabel" name="label">
- <property name="text">
- <string>Sys&amp;root:</string>
- </property>
- <property name="buddy">
- <cstring>sysrootChooser</cstring>
- </property>
- </widget>
- </item>
- <item row="2" column="1">
- <widget class="Utils::PathChooser" name="sysrootChooser" native="true"/>
- </item>
- </layout>
- </item>
- <item>
- <widget class="QDialogButtonBox" name="buttonBox">
- <property name="orientation">
- <enum>Qt::Horizontal</enum>
- </property>
- <property name="standardButtons">
- <set>QDialogButtonBox::Cancel|QDialogButtonBox::Ok</set>
- </property>
- </widget>
- </item>
- </layout>
- </widget>
- <customwidgets>
- <customwidget>
- <class>Utils::PathChooser</class>
- <extends>QWidget</extends>
- <header location="global">utils/pathchooser.h</header>
- <container>1</container>
- </customwidget>
- </customwidgets>
- <resources/>
- <connections>
- <connection>
- <sender>buttonBox</sender>
- <signal>accepted()</signal>
- <receiver>QmlProfiler::Internal::QmlProfilerAttachDialog</receiver>
- <slot>accept()</slot>
- <hints>
- <hint type="sourcelabel">
- <x>248</x>
- <y>254</y>
- </hint>
- <hint type="destinationlabel">
- <x>157</x>
- <y>274</y>
- </hint>
- </hints>
- </connection>
- <connection>
- <sender>buttonBox</sender>
- <signal>rejected()</signal>
- <receiver>QmlProfiler::Internal::QmlProfilerAttachDialog</receiver>
- <slot>reject()</slot>
- <hints>
- <hint type="sourcelabel">
- <x>316</x>
- <y>260</y>
- </hint>
- <hint type="destinationlabel">
- <x>286</x>
- <y>274</y>
- </hint>
- </hints>
- </connection>
- </connections>
-</ui>
diff --git a/src/plugins/qmlprofiler/qmlprofilerconfigwidget.cpp b/src/plugins/qmlprofiler/qmlprofilerconfigwidget.cpp
deleted file mode 100644
index 3eea277525..0000000000
--- a/src/plugins/qmlprofiler/qmlprofilerconfigwidget.cpp
+++ /dev/null
@@ -1,64 +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 "qmlprofilerconfigwidget.h"
-#include "ui_qmlprofilerconfigwidget.h"
-
-namespace QmlProfiler {
-namespace Internal {
-
-QmlProfilerConfigWidget::QmlProfilerConfigWidget(QmlProfilerSettings *settings) :
- m_ui(new Ui::QmlProfilerConfigWidget), m_settings(settings)
-{
- m_ui->setupUi(this);
- updateUi();
-
- connect(m_ui->flushEnabled, &QCheckBox::toggled,
- m_settings, &QmlProfilerSettings::setFlushEnabled);
-
- connect(m_ui->flushInterval, QOverload<int>::of(&QSpinBox::valueChanged),
- m_settings, &QmlProfilerSettings::setFlushInterval);
-
- connect(m_ui->aggregateTraces, &QCheckBox::toggled,
- m_settings, &QmlProfilerSettings::setAggregateTraces);
-
- connect(m_settings, &QmlProfilerSettings::changed, this, &QmlProfilerConfigWidget::updateUi);
-}
-
-QmlProfilerConfigWidget::~QmlProfilerConfigWidget()
-{
- delete m_ui;
-}
-
-void QmlProfilerConfigWidget::updateUi()
-{
- m_ui->flushEnabled->setChecked(m_settings->flushEnabled());
- m_ui->flushInterval->setEnabled(m_settings->flushEnabled());
- m_ui->flushInterval->setValue(m_settings->flushInterval());
- m_ui->aggregateTraces->setChecked(m_settings->aggregateTraces());
-}
-
-} // Internal
-} // QmlProfiler
diff --git a/src/plugins/qmlprofiler/qmlprofilerconfigwidget.ui b/src/plugins/qmlprofiler/qmlprofilerconfigwidget.ui
deleted file mode 100644
index df66e67b80..0000000000
--- a/src/plugins/qmlprofiler/qmlprofilerconfigwidget.ui
+++ /dev/null
@@ -1,71 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<ui version="4.0">
- <class>QmlProfiler::Internal::QmlProfilerConfigWidget</class>
- <widget class="QWidget" name="QmlProfiler::Internal::QmlProfilerConfigWidget">
- <property name="geometry">
- <rect>
- <x>0</x>
- <y>0</y>
- <width>320</width>
- <height>100</height>
- </rect>
- </property>
- <layout class="QFormLayout" name="formLayout">
- <item row="0" column="0">
- <widget class="QLabel" name="flushEnabledLabel">
- <property name="text">
- <string>Flush data while profiling:</string>
- </property>
- </widget>
- </item>
- <item row="0" column="1">
- <widget class="QCheckBox" name="flushEnabled">
- <property name="toolTip">
- <string>Periodically flush pending data to the profiler. This reduces the delay when loading the
-data and the memory usage in the application. It distorts the profile as the flushing
-itself takes time.</string>
- </property>
- </widget>
- </item>
- <item row="1" column="0">
- <widget class="QLabel" name="flushIntervalLabel">
- <property name="text">
- <string>Flush interval (ms):</string>
- </property>
- </widget>
- </item>
- <item row="1" column="1">
- <widget class="QSpinBox" name="flushInterval">
- <property name="minimum">
- <number>1</number>
- </property>
- <property name="maximum">
- <number>10000000</number>
- </property>
- <property name="value">
- <number>1000</number>
- </property>
- </widget>
- </item>
- <item row="2" column="0">
- <widget class="QLabel" name="aggregateTracesLabel">
- <property name="text">
- <string>Process data only when process ends:</string>
- </property>
- </widget>
- </item>
- <item row="2" column="1">
- <widget class="QCheckBox" name="aggregateTraces">
- <property name="toolTip">
- <string>Only process data when the process being profiled ends, not when the current recording
-session ends. This way multiple recording sessions can be aggregated in a single trace,
-for example if multiple QML engines start and stop sequentially during a single run of
-the program.</string>
- </property>
- </widget>
- </item>
- </layout>
- </widget>
- <resources/>
- <connections/>
-</ui>
diff --git a/src/plugins/qmlprofiler/qmlprofilerconstants.h b/src/plugins/qmlprofiler/qmlprofilerconstants.h
index 183e8e779b..0645cd3f06 100644
--- a/src/plugins/qmlprofiler/qmlprofilerconstants.h
+++ b/src/plugins/qmlprofiler/qmlprofilerconstants.h
@@ -30,10 +30,6 @@ namespace Constants {
const char TASK_LOAD[] = "QmlProfiler.TaskLoad";
const char TASK_SAVE[] = "QmlProfiler.TaskSave";
-const char FLUSH_ENABLED[] = "Analyzer.QmlProfiler.FlushEnabled";
-const char FLUSH_INTERVAL[] = "Analyzer.QmlProfiler.FlushInterval";
-const char LAST_TRACE_FILE[] = "Analyzer.QmlProfiler.LastTraceFile";
-const char AGGREGATE_TRACES[] = "Analyzer.QmlProfiler.AggregateTraces";
const char SETTINGS[] = "Analyzer.QmlProfiler.Settings";
const char ANALYZER[] = "Analyzer";
const char TEXT_MARK_CATEGORY[] = "Analyzer.QmlProfiler.TextMark";
diff --git a/src/plugins/qmlprofiler/qmlprofilerplugin.cpp b/src/plugins/qmlprofiler/qmlprofilerplugin.cpp
index f53c604285..f6592de524 100644
--- a/src/plugins/qmlprofiler/qmlprofilerplugin.cpp
+++ b/src/plugins/qmlprofiler/qmlprofilerplugin.cpp
@@ -25,7 +25,6 @@
#include "qmlprofilerplugin.h"
#include "qmlprofilerrunconfigurationaspect.h"
-#include "qmlprofileroptionspage.h"
#include "qmlprofilerruncontrol.h"
#include "qmlprofilersettings.h"
#include "qmlprofilertool.h"
@@ -49,7 +48,6 @@
#include "tests/qmlprofilerattachdialog_test.h"
#include "tests/qmlprofilerbindingloopsrenderpass_test.h"
#include "tests/qmlprofilerclientmanager_test.h"
-#include "tests/qmlprofilerconfigwidget_test.h"
#include "tests/qmlprofilerdetailsrewriter_test.h"
#include "tests/qmlprofilertool_test.h"
#include "tests/qmlprofilertraceclient_test.h"
@@ -154,7 +152,6 @@ QVector<QObject *> QmlProfiler::Internal::QmlProfilerPlugin::createTestObjects()
tests << new QmlProfilerAttachDialogTest;
tests << new QmlProfilerBindingLoopsRenderPassTest;
tests << new QmlProfilerClientManagerTest;
- tests << new QmlProfilerConfigWidgetTest;
tests << new QmlProfilerDetailsRewriterTest;
tests << new QmlProfilerToolTest;
tests << new QmlProfilerTraceClientTest;
diff --git a/src/plugins/qmlprofiler/qmlprofilerruncontrol.cpp b/src/plugins/qmlprofiler/qmlprofilerruncontrol.cpp
index 5d51540d3f..5dd244cba4 100644
--- a/src/plugins/qmlprofiler/qmlprofilerruncontrol.cpp
+++ b/src/plugins/qmlprofiler/qmlprofilerruncontrol.cpp
@@ -51,7 +51,6 @@
using namespace Core;
using namespace ProjectExplorer;
-using namespace QmlProfiler::Internal;
namespace QmlProfiler {
namespace Internal {
@@ -249,7 +248,7 @@ LocalQmlProfilerSupport::LocalQmlProfilerSupport(RunControl *runControl, const Q
else
QTC_CHECK(false);
- QString arguments = Utils::QtcProcess::quoteArg(
+ QString arguments = Utils::ProcessArgs::quoteArg(
QmlDebug::qmlDebugCommandLineArguments(QmlDebug::QmlProfilerServices, code, true));
if (!debuggee.commandLineArguments.isEmpty())
diff --git a/src/plugins/qmlprofiler/qmlprofilersettings.cpp b/src/plugins/qmlprofiler/qmlprofilersettings.cpp
index ded460bead..ecc3442fc4 100644
--- a/src/plugins/qmlprofiler/qmlprofilersettings.cpp
+++ b/src/plugins/qmlprofiler/qmlprofilersettings.cpp
@@ -24,115 +24,106 @@
****************************************************************************/
#include "qmlprofilersettings.h"
+
#include "qmlprofilerconstants.h"
-#include "qmlprofilerconfigwidget.h"
+#include "qmlprofilerplugin.h"
#include <coreplugin/icore.h>
-#include <QSettings>
+#include <debugger/analyzer/analyzericons.h>
-namespace QmlProfiler {
-namespace Internal {
-
-QmlProfilerSettings::QmlProfilerSettings()
-{
- setConfigWidgetCreator([this] { return new QmlProfilerConfigWidget(this); });
+#include <utils/layoutbuilder.h>
- QVariantMap defaults;
- defaults.insert(QLatin1String(Constants::FLUSH_INTERVAL), 1000);
- defaults.insert(QLatin1String(Constants::FLUSH_ENABLED), false);
- defaults.insert(QLatin1String(Constants::LAST_TRACE_FILE), QString());
- defaults.insert(QLatin1String(Constants::AGGREGATE_TRACES), false);
-
- // Read stored values
- QSettings *settings = Core::ICore::settings();
- settings->beginGroup(QLatin1String(Constants::ANALYZER));
- QVariantMap map = defaults;
- for (QVariantMap::ConstIterator it = defaults.constBegin(); it != defaults.constEnd(); ++it)
- map.insert(it.key(), settings->value(it.key(), it.value()));
- settings->endGroup();
-
- fromMap(map);
-}
+#include <QSettings>
-bool QmlProfilerSettings::flushEnabled() const
-{
- return m_flushEnabled;
-}
+using namespace Utils;
-void QmlProfilerSettings::setFlushEnabled(bool flushEnabled)
-{
- if (m_flushEnabled != flushEnabled) {
- m_flushEnabled = flushEnabled;
- emit changed();
- }
-}
+namespace QmlProfiler {
+namespace Internal {
-quint32 QmlProfilerSettings::flushInterval() const
+static QWidget *createQmlConfigWidget(QmlProfilerSettings *settings)
{
- return m_flushInterval;
+ QmlProfilerSettings &s = *settings;
+ using namespace Layouting;
+
+ return Form {
+ s.flushEnabled,
+ s.flushInterval,
+ s.aggregateTraces
+ }.emerge();
}
-void QmlProfilerSettings::setFlushInterval(quint32 flushInterval)
+QmlProfilerSettings::QmlProfilerSettings()
{
- if (m_flushInterval != flushInterval) {
- m_flushInterval = flushInterval;
- emit changed();
- }
-}
+ setConfigWidgetCreator([this] { return createQmlConfigWidget(this); });
+
+ setSettingsGroup(Constants::ANALYZER);
+
+ registerAspect(&flushEnabled);
+ flushEnabled.setSettingsKey("Analyzer.QmlProfiler.FlushEnabled");
+ flushEnabled.setLabelPlacement(BoolAspect::LabelPlacement::InExtraLabel);
+ flushEnabled.setLabelText(tr("Flush data while profiling:"));
+ flushEnabled.setToolTip(tr(
+ "Periodically flush pending data to the profiler. This reduces the delay when loading the\n"
+ "data and the memory usage in the application. It distorts the profile as the flushing\n"
+ "itself takes time."));
+
+ registerAspect(&flushInterval);
+ flushInterval.setSettingsKey("Analyzer.QmlProfiler.FlushInterval");
+ flushInterval.setRange(1, 10000000);
+ flushInterval.setDefaultValue(1000);
+ flushInterval.setLabelText(tr("Flush interval (ms):"));
+ flushInterval.setEnabler(&flushEnabled);
+
+ registerAspect(&lastTraceFile);
+ lastTraceFile.setSettingsKey("Analyzer.QmlProfiler.LastTraceFile");
+
+ registerAspect(&aggregateTraces);
+ aggregateTraces.setSettingsKey("Analyzer.QmlProfiler.AggregateTraces");
+ aggregateTraces.setLabelPlacement(BoolAspect::LabelPlacement::InExtraLabel);
+ aggregateTraces.setLabelText(tr("Process data only when process ends:"));
+ aggregateTraces.setToolTip(tr(
+ "Only process data when the process being profiled ends, not when the current recording\n"
+ "session ends. This way multiple recording sessions can be aggregated in a single trace,\n"
+ "for example if multiple QML engines start and stop sequentially during a single run of\n"
+ "the program."));
-QString QmlProfilerSettings::lastTraceFile() const
-{
- return m_lastTraceFile;
+ // Read stored values
+ readSettings(Core::ICore::settings());
}
-void QmlProfilerSettings::setLastTraceFile(const QString &lastTracePath)
+void QmlProfilerSettings::writeGlobalSettings() const
{
- if (m_lastTraceFile != lastTracePath) {
- m_lastTraceFile = lastTracePath;
- emit changed();
- }
+ writeSettings(Core::ICore::settings());
}
-bool QmlProfilerSettings::aggregateTraces() const
-{
- return m_aggregateTraces;
-}
+// QmlProfilerOptionsPage
-void QmlProfilerSettings::setAggregateTraces(bool aggregateTraces)
+QmlProfilerOptionsPage::QmlProfilerOptionsPage()
{
- if (m_aggregateTraces != aggregateTraces) {
- m_aggregateTraces = aggregateTraces;
- emit changed();
- }
+ setId(Constants::SETTINGS);
+ setDisplayName(QmlProfilerSettings::tr("QML Profiler"));
+ setCategory("T.Analyzer");
+ setDisplayCategory(QmlProfilerSettings::tr("Analyzer"));
+ setCategoryIconPath(Analyzer::Icons::SETTINGSCATEGORY_ANALYZER);
}
-void QmlProfilerSettings::writeGlobalSettings() const
+QWidget *QmlProfilerOptionsPage::widget()
{
- QSettings *settings = Core::ICore::settings();
- settings->beginGroup(QLatin1String(Constants::ANALYZER));
- QVariantMap map;
- toMap(map);
- for (QVariantMap::ConstIterator it = map.constBegin(); it != map.constEnd(); ++it)
- settings->setValue(it.key(), it.value());
- settings->endGroup();
+ // We cannot parent the widget to the options page as it expects a QWidget as parent
+ if (!m_widget)
+ m_widget = createQmlConfigWidget(QmlProfilerPlugin::globalSettings());
+ return m_widget;
}
-void QmlProfilerSettings::toMap(QVariantMap &map) const
+void QmlProfilerOptionsPage::apply()
{
- map[QLatin1String(Constants::FLUSH_INTERVAL)] = m_flushInterval;
- map[QLatin1String(Constants::FLUSH_ENABLED)] = m_flushEnabled;
- map[QLatin1String(Constants::LAST_TRACE_FILE)] = m_lastTraceFile;
- map[QLatin1String(Constants::AGGREGATE_TRACES)] = m_aggregateTraces;
+ QmlProfilerPlugin::globalSettings()->writeGlobalSettings();
}
-void QmlProfilerSettings::fromMap(const QVariantMap &map)
+void QmlProfilerOptionsPage::finish()
{
- m_flushEnabled = map.value(QLatin1String(Constants::FLUSH_ENABLED)).toBool();
- m_flushInterval = map.value(QLatin1String(Constants::FLUSH_INTERVAL)).toUInt();
- m_lastTraceFile = map.value(QLatin1String(Constants::LAST_TRACE_FILE)).toString();
- m_aggregateTraces = map.value(QLatin1String(Constants::AGGREGATE_TRACES)).toBool();
- emit changed();
+ delete m_widget;
}
} // Internal
diff --git a/src/plugins/qmlprofiler/qmlprofilersettings.h b/src/plugins/qmlprofiler/qmlprofilersettings.h
index 6af1b65de9..fa65e73a52 100644
--- a/src/plugins/qmlprofiler/qmlprofilersettings.h
+++ b/src/plugins/qmlprofiler/qmlprofilersettings.h
@@ -25,43 +25,41 @@
#pragma once
+#include <coreplugin/dialogs/ioptionspage.h>
+
#include <projectexplorer/runconfiguration.h>
+#include <QPointer>
+
namespace QmlProfiler {
namespace Internal {
class QmlProfilerSettings : public ProjectExplorer::ISettingsAspect
{
Q_OBJECT
+
public:
QmlProfilerSettings();
- bool flushEnabled() const;
- void setFlushEnabled(bool flushEnabled);
-
- quint32 flushInterval() const;
- void setFlushInterval(quint32 flushInterval);
-
- QString lastTraceFile() const;
- void setLastTraceFile(const QString &lastTraceFile);
-
- bool aggregateTraces() const;
- void setAggregateTraces(bool aggregateTraces);
-
void writeGlobalSettings() const;
-signals:
- void changed();
+ Utils::BoolAspect flushEnabled;
+ Utils::IntegerAspect flushInterval;
+ Utils::StringAspect lastTraceFile;
+ Utils::BoolAspect aggregateTraces;
+};
+
+class QmlProfilerOptionsPage final : public Core::IOptionsPage
+{
+public:
+ QmlProfilerOptionsPage();
-protected:
- void toMap(QVariantMap &map) const override;
- void fromMap(const QVariantMap &map) override;
+ QWidget *widget() override;
+ void apply() override;
+ void finish() override;
private:
- bool m_flushEnabled;
- quint32 m_flushInterval;
- QString m_lastTraceFile;
- bool m_aggregateTraces;
+ QPointer<QWidget> m_widget;
};
} // Internal
diff --git a/src/plugins/qmlprofiler/qmlprofilertool.cpp b/src/plugins/qmlprofiler/qmlprofilertool.cpp
index c41076ede9..3d49dbd59d 100644
--- a/src/plugins/qmlprofiler/qmlprofilertool.cpp
+++ b/src/plugins/qmlprofiler/qmlprofilertool.cpp
@@ -314,9 +314,9 @@ void QmlProfilerTool::finalizeRunControl(QmlProfilerRunner *runWorker)
if (auto aspect = static_cast<QmlProfilerRunConfigurationAspect *>(
runControl->aspect(Constants::SETTINGS))) {
if (auto settings = static_cast<const QmlProfilerSettings *>(aspect->currentSettings())) {
- d->m_profilerConnections->setFlushInterval(settings->flushEnabled() ?
- settings->flushInterval() : 0);
- d->m_profilerModelManager->setAggregateTraces(settings->aggregateTraces());
+ d->m_profilerConnections->setFlushInterval(settings->flushEnabled.value() ?
+ settings->flushInterval.value() : 0);
+ d->m_profilerModelManager->setAggregateTraces(settings->aggregateTraces.value());
}
}
@@ -589,8 +589,8 @@ void QmlProfilerTool::showErrorDialog(const QString &error)
void saveLastTraceFile(const QString &filename)
{
QmlProfilerSettings *settings = QmlProfilerPlugin::globalSettings();
- if (filename != settings->lastTraceFile()) {
- settings->setLastTraceFile(filename);
+ if (filename != settings->lastTraceFile.value()) {
+ settings->lastTraceFile.setValue(filename);
settings->writeGlobalSettings();
}
}
@@ -601,7 +601,7 @@ void QmlProfilerTool::showSaveDialog()
QLatin1String zFile(QztFileExtension);
QString filename = QFileDialog::getSaveFileName(
ICore::dialogParent(), tr("Save QML Trace"),
- QmlProfilerPlugin::globalSettings()->lastTraceFile(),
+ QmlProfilerPlugin::globalSettings()->lastTraceFile.value(),
tr("QML traces (*%1 *%2)").arg(zFile).arg(tFile));
if (!filename.isEmpty()) {
if (!filename.endsWith(zFile) && !filename.endsWith(tFile))
@@ -625,7 +625,7 @@ void QmlProfilerTool::showLoadDialog()
QLatin1String zFile(QztFileExtension);
QString filename = QFileDialog::getOpenFileName(
ICore::dialogParent(), tr("Load QML Trace"),
- QmlProfilerPlugin::globalSettings()->lastTraceFile(),
+ QmlProfilerPlugin::globalSettings()->lastTraceFile.value(),
tr("QML traces (*%1 *%2)").arg(zFile).arg(tFile));
if (!filename.isEmpty()) {
diff --git a/src/plugins/qmlprofiler/tests/qmlprofilerconfigwidget_test.cpp b/src/plugins/qmlprofiler/tests/qmlprofilerconfigwidget_test.cpp
deleted file mode 100644
index e291c15f5d..0000000000
--- a/src/plugins/qmlprofiler/tests/qmlprofilerconfigwidget_test.cpp
+++ /dev/null
@@ -1,96 +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 "qmlprofilerconfigwidget_test.h"
-#include <QtTest>
-
-namespace QmlProfiler {
-namespace Internal {
-
-QmlProfilerConfigWidgetTest::QmlProfilerConfigWidgetTest(QObject *parent) :
- QObject(parent), widget(&settings)
-{
- widget.show();
- flushEnabled = widget.findChild<QCheckBox*>("flushEnabled");
- QVERIFY(flushEnabled);
- flushInterval = widget.findChild<QSpinBox*>("flushInterval");
- QVERIFY(flushInterval);
- aggregateTraces = widget.findChild<QCheckBox*>("aggregateTraces");
- QVERIFY(aggregateTraces);
-}
-
-void QmlProfilerConfigWidgetTest::testUpdateFromSettings()
-{
- QSignalSpy flushes(flushEnabled, SIGNAL(stateChanged(int)));
- QCOMPARE(flushEnabled->checkState(), Qt::Unchecked);
- settings.setFlushEnabled(true);
- QCOMPARE(flushEnabled->checkState(), Qt::Checked);
- settings.setFlushEnabled(false);
- QCOMPARE(flushEnabled->checkState(), Qt::Unchecked);
- QCOMPARE(flushes.count(), 2);
-
-
- QSignalSpy intervals(flushInterval, SIGNAL(valueChanged(int)));
- QCOMPARE(flushInterval->value(), 1000);
- settings.setFlushInterval(200);
- QCOMPARE(flushInterval->value(), 200);
- settings.setFlushInterval(1000);
- QCOMPARE(flushInterval->value(), 1000);
- QCOMPARE(intervals.count(), 2);
-
- QSignalSpy aggregates(aggregateTraces, SIGNAL(stateChanged(int)));
- QCOMPARE(aggregateTraces->checkState(), Qt::Unchecked);
- settings.setAggregateTraces(true);
- QCOMPARE(aggregateTraces->checkState(), Qt::Checked);
- settings.setAggregateTraces(false);
- QCOMPARE(aggregateTraces->checkState(), Qt::Unchecked);
- QCOMPARE(aggregates.count(), 2);
-}
-
-void QmlProfilerConfigWidgetTest::testChangeWidget()
-{
- QCOMPARE(flushEnabled->checkState(), Qt::Unchecked);
- QVERIFY(!settings.flushEnabled());
- flushEnabled->setCheckState(Qt::Checked);
- QVERIFY(settings.flushEnabled());
- flushEnabled->setCheckState(Qt::Unchecked);
- QVERIFY(!settings.flushEnabled());
-
- QCOMPARE(flushInterval->value(), 1000);
- QCOMPARE(settings.flushInterval(), 1000u);
- flushInterval->setValue(200);
- QCOMPARE(settings.flushInterval(), 200u);
- flushInterval->setValue(1000);
- QCOMPARE(settings.flushInterval(), 1000u);
-
- QCOMPARE(aggregateTraces->checkState(), Qt::Unchecked);
- QVERIFY(!settings.aggregateTraces());
- aggregateTraces->setCheckState(Qt::Checked);
- QVERIFY(settings.aggregateTraces());
- aggregateTraces->setCheckState(Qt::Unchecked);
- QVERIFY(!settings.aggregateTraces());
-}
-
-} // namespace Internal
-} // namespace QmlProfiler
diff --git a/src/plugins/qmlprofiler/tests/tests.pri b/src/plugins/qmlprofiler/tests/tests.pri
index eee511e93f..166f606a76 100644
--- a/src/plugins/qmlprofiler/tests/tests.pri
+++ b/src/plugins/qmlprofiler/tests/tests.pri
@@ -15,7 +15,6 @@ SOURCES += \
$$PWD/qmlprofilerattachdialog_test.cpp \
$$PWD/qmlprofilerbindingloopsrenderpass_test.cpp \
$$PWD/qmlprofilerclientmanager_test.cpp \
- $$PWD/qmlprofilerconfigwidget_test.cpp \
$$PWD/qmlprofilerdetailsrewriter_test.cpp \
$$PWD/qmlprofilertool_test.cpp \
$$PWD/qmlprofilertraceclient_test.cpp \
@@ -38,7 +37,6 @@ HEADERS += \
$$PWD/qmlprofilerattachdialog_test.h \
$$PWD/qmlprofilerbindingloopsrenderpass_test.h \
$$PWD/qmlprofilerclientmanager_test.h \
- $$PWD/qmlprofilerconfigwidget_test.h \
$$PWD/qmlprofilerdetailsrewriter_test.h \
$$PWD/qmlprofilertool_test.h \
$$PWD/qmlprofilertraceclient_test.h \
diff --git a/src/plugins/qmlprojectmanager/qmlproject.cpp b/src/plugins/qmlprojectmanager/qmlproject.cpp
index 3469a44c23..c89b88a450 100644
--- a/src/plugins/qmlprojectmanager/qmlproject.cpp
+++ b/src/plugins/qmlprojectmanager/qmlproject.cpp
@@ -215,7 +215,7 @@ void QmlBuildSystem::parseProject(RefreshOptions options)
= QDir(canonicalProjectDir().toString()).absoluteFilePath(mainFilePath);
Utils::FileReader reader;
QString errorMessage;
- if (!reader.fetch(mainFilePath, &errorMessage)) {
+ if (!reader.fetch(Utils::FilePath::fromString(mainFilePath), &errorMessage)) {
MessageManager::writeFlashing(tr("Warning while loading project file %1.")
.arg(projectFilePath().toUserOutput()));
MessageManager::writeSilently(errorMessage);
@@ -543,7 +543,7 @@ bool QmlBuildSystem::renameFile(Node * context, const QString &filePath, const Q
QString error;
Utils::TextFileFormat textFileFormat;
const QTextCodec *codec = QTextCodec::codecForName("UTF-8"); // qml files are defined to be utf-8
- if (Utils::TextFileFormat::readFile(qmlProjectFilePath.toString(), codec, &fileContent, &textFileFormat, &error)
+ if (Utils::TextFileFormat::readFile(qmlProjectFilePath, codec, &fileContent, &textFileFormat, &error)
!= Utils::TextFileFormat::ReadSuccess) {
qWarning() << "Failed to read file" << qmlProjectFilePath << ":" << error;
}
@@ -556,7 +556,7 @@ bool QmlBuildSystem::renameFile(Node * context, const QString &filePath, const Q
fileContent.replace(match.capturedStart(1), match.capturedLength(1), QFileInfo(newFilePath).fileName());
- if (!textFileFormat.writeFile(qmlProjectFilePath.toString(), fileContent, &error))
+ if (!textFileFormat.writeFile(qmlProjectFilePath, fileContent, &error))
qWarning() << "Failed to write file" << qmlProjectFilePath << ":" << error;
refresh(Everything);
diff --git a/src/plugins/qmlprojectmanager/qmlprojectnodes.cpp b/src/plugins/qmlprojectmanager/qmlprojectnodes.cpp
index cfa6c5e74e..fe35539314 100644
--- a/src/plugins/qmlprojectmanager/qmlprojectnodes.cpp
+++ b/src/plugins/qmlprojectmanager/qmlprojectnodes.cpp
@@ -40,8 +40,7 @@ QmlProjectNode::QmlProjectNode(Project *project)
{
setDisplayName(project->projectFilePath().toFileInfo().completeBaseName());
- static QIcon qmlProjectIcon = Core::FileIconProvider::directoryIcon(":/projectexplorer/images/fileoverlay_qml.png");
- setIcon(qmlProjectIcon);
+ setIcon(DirectoryIcon(":/projectexplorer/images/fileoverlay_qml.png"));
}
} // namespace Internal
diff --git a/src/plugins/qmlprojectmanager/qmlprojectrunconfiguration.cpp b/src/plugins/qmlprojectmanager/qmlprojectrunconfiguration.cpp
index 999f34e426..3f5c6e3ebd 100644
--- a/src/plugins/qmlprojectmanager/qmlprojectrunconfiguration.cpp
+++ b/src/plugins/qmlprojectmanager/qmlprojectrunconfiguration.cpp
@@ -69,15 +69,14 @@ class QmlProjectRunConfiguration final : public RunConfiguration
Q_DECLARE_TR_FUNCTIONS(QmlProjectManager::QmlProjectRunConfiguration)
public:
- QmlProjectRunConfiguration(Target *target, Utils::Id id);
+ QmlProjectRunConfiguration(Target *target, Id id);
private:
- Runnable runnable() const final;
QString disabledReason() const final;
bool isEnabled() const final;
QString mainScript() const;
- Utils::FilePath qmlScenePath() const;
+ FilePath qmlScenePath() const;
QString commandLineArguments() const;
StringAspect *m_qmlViewerAspect = nullptr;
@@ -137,20 +136,15 @@ QmlProjectRunConfiguration::QmlProjectRunConfiguration(Target *target, Id id)
return envModifier(environment);
});
+ setRunnableModifier([this](Runnable &r) {
+ const QmlBuildSystem *bs = static_cast<QmlBuildSystem *>(activeBuildSystem());
+ r.workingDirectory = bs->targetDirectory().toString();
+ });
+
setDisplayName(tr("QML Scene", "QMLRunConfiguration display name."));
update();
}
-Runnable QmlProjectRunConfiguration::runnable() const
-{
- Runnable r;
- r.setCommandLine(commandLine());
- r.environment = aspect<EnvironmentAspect>()->environment();
- const QmlBuildSystem *bs = static_cast<QmlBuildSystem *>(activeBuildSystem());
- r.workingDirectory = bs->targetDirectory().toString();
- return r;
-}
-
QString QmlProjectRunConfiguration::disabledReason() const
{
if (mainScript().isEmpty())
@@ -205,26 +199,26 @@ QString QmlProjectRunConfiguration::commandLineArguments() const
const QmlBuildSystem *bs = qobject_cast<QmlBuildSystem *>(target()->buildSystem());
foreach (const QString &importPath,
QmlBuildSystem::makeAbsolute(bs->targetDirectory(), bs->customImportPaths())) {
- QtcProcess::addArg(&args, "-I", osType);
- QtcProcess::addArg(&args, importPath, osType);
+ ProcessArgs::addArg(&args, "-I", osType);
+ ProcessArgs::addArg(&args, importPath, osType);
}
for (const QString &fileSelector : bs->customFileSelectors()) {
- QtcProcess::addArg(&args, "-S", osType);
- QtcProcess::addArg(&args, fileSelector, osType);
+ ProcessArgs::addArg(&args, "-S", osType);
+ ProcessArgs::addArg(&args, fileSelector, osType);
}
- if (Utils::HostOsInfo::isWindowsHost() && bs->forceFreeType()) {
- Utils::QtcProcess::addArg(&args, "-platform", osType);
- Utils::QtcProcess::addArg(&args, "windows:fontengine=freetype", osType);
+ if (HostOsInfo::isWindowsHost() && bs->forceFreeType()) {
+ ProcessArgs::addArg(&args, "-platform", osType);
+ ProcessArgs::addArg(&args, "windows:fontengine=freetype", osType);
}
const QString main = bs->targetFile(FilePath::fromString(mainScript())).toString();
if (!main.isEmpty())
- QtcProcess::addArg(&args, main, osType);
+ ProcessArgs::addArg(&args, main, osType);
if (m_multiLanguageAspect && m_multiLanguageAspect->value())
- QtcProcess::addArg(&args, "-qmljsdebugger=file:unused_if_debugger_arguments_added,services:DebugTranslation", osType);
+ ProcessArgs::addArg(&args, "-qmljsdebugger=file:unused_if_debugger_arguments_added,services:DebugTranslation", osType);
return args;
}
diff --git a/src/plugins/qnx/qnxanalyzesupport.cpp b/src/plugins/qnx/qnxanalyzesupport.cpp
index bba9401fe9..59236e60f5 100644
--- a/src/plugins/qnx/qnxanalyzesupport.cpp
+++ b/src/plugins/qnx/qnxanalyzesupport.cpp
@@ -61,7 +61,7 @@ QnxQmlProfilerSupport::QnxQmlProfilerSupport(RunControl *runControl)
profiler->recordData("QmlServerUrl", serverUrl);
Runnable r = runControl->runnable();
- QtcProcess::addArg(&r.commandLineArguments,
+ ProcessArgs::addArg(&r.commandLineArguments,
QmlDebug::qmlDebugTcpArguments(QmlDebug::QmlProfilerServices, serverUrl),
Utils::OsTypeOtherUnix);
diff --git a/src/plugins/qnx/qnxconfiguration.cpp b/src/plugins/qnx/qnxconfiguration.cpp
index 48071784fa..4a55f7118f 100644
--- a/src/plugins/qnx/qnxconfiguration.cpp
+++ b/src/plugins/qnx/qnxconfiguration.cpp
@@ -67,6 +67,10 @@ const QLatin1String QNXVersionKey("QNXVersion");
// For backward compatibility
const QLatin1String SdpEnvFileKey("NDKEnvFile");
+const QLatin1String QNXConfiguration("QNX_CONFIGURATION");
+const QLatin1String QNXTarget("QNX_TARGET");
+const QLatin1String QNXHost("QNX_HOST");
+
QnxConfiguration::QnxConfiguration() = default;
QnxConfiguration::QnxConfiguration(const FilePath &sdpEnvFile)
@@ -244,16 +248,18 @@ QList<ToolChain *> QnxConfiguration::autoDetect(const QList<ToolChain *> &alread
void QnxConfiguration::createTools(const Target &target)
{
- QnxToolChain *tc = createToolChain(target);
+ QnxToolChainMap toolchainMap = createToolChain(target);
QVariant debuggerId = createDebugger(target);
- createKit(target, tc, debuggerId);
+ createKit(target, toolchainMap, debuggerId);
}
QVariant QnxConfiguration::createDebugger(const Target &target)
{
+ Utils::Environment sysEnv = Utils::Environment::systemEnvironment();
+ sysEnv.modify(qnxEnvironmentItems());
Debugger::DebuggerItem debugger;
debugger.setCommand(target.m_debuggerPath);
- debugger.reinitializeFromFile();
+ debugger.reinitializeFromFile(sysEnv);
debugger.setAutoDetected(true);
debugger.setUnexpandedDisplayName(
QCoreApplication::translate(
@@ -264,23 +270,31 @@ QVariant QnxConfiguration::createDebugger(const Target &target)
return Debugger::DebuggerItemManager::registerDebugger(debugger);
}
-QnxToolChain *QnxConfiguration::createToolChain(const Target &target)
+QnxConfiguration::QnxToolChainMap QnxConfiguration::createToolChain(const Target &target)
{
- auto toolChain = new QnxToolChain;
- toolChain->setDetection(ToolChain::AutoDetection);
- toolChain->setLanguage(ProjectExplorer::Constants::CXX_LANGUAGE_ID);
- toolChain->setTargetAbi(target.m_abi);
- toolChain->setDisplayName(
- QCoreApplication::translate(
- "Qnx::Internal::QnxConfiguration",
- "QCC for %1 (%2)")
- .arg(displayName())
- .arg(target.shortDescription()));
- toolChain->setSdpPath(sdpPath().toString());
- toolChain->setCpuDir(target.cpuDir());
- toolChain->resetToolChain(qccCompilerPath());
- ToolChainManager::registerToolChain(toolChain);
- return toolChain;
+ QnxToolChainMap toolChainMap;
+
+ for (auto language : { ProjectExplorer::Constants::C_LANGUAGE_ID,
+ ProjectExplorer::Constants::CXX_LANGUAGE_ID}) {
+ auto toolChain = new QnxToolChain;
+ toolChain->setDetection(ToolChain::AutoDetection);
+ toolChain->setLanguage(language);
+ toolChain->setTargetAbi(target.m_abi);
+ toolChain->setDisplayName(
+ QCoreApplication::translate(
+ "Qnx::Internal::QnxConfiguration",
+ "QCC for %1 (%2)")
+ .arg(displayName())
+ .arg(target.shortDescription()));
+ toolChain->setSdpPath(sdpPath().toString());
+ toolChain->setCpuDir(target.cpuDir());
+ toolChain->resetToolChain(qccCompilerPath());
+ ToolChainManager::registerToolChain(toolChain);
+
+ toolChainMap.insert(std::make_pair(language, toolChain));
+ }
+
+ return toolChainMap;
}
QList<ToolChain *> QnxConfiguration::findToolChain(const QList<ToolChain *> &alreadyKnown,
@@ -293,7 +307,7 @@ QList<ToolChain *> QnxConfiguration::findToolChain(const QList<ToolChain *> &alr
});
}
-void QnxConfiguration::createKit(const Target &target, QnxToolChain *toolChain,
+void QnxConfiguration::createKit(const Target &target, const QnxToolChainMap &toolChainMap,
const QVariant &debugger)
{
QnxQtVersion *qnxQt = qnxQtVersion(target);
@@ -303,8 +317,8 @@ void QnxConfiguration::createKit(const Target &target, QnxToolChain *toolChain,
const auto init = [&](Kit *k) {
QtKitAspect::setQtVersion(k, qnxQt);
- ToolChainKitAspect::setToolChain(k, toolChain);
- ToolChainKitAspect::clearToolChain(k, ProjectExplorer::Constants::C_LANGUAGE_ID);
+ ToolChainKitAspect::setToolChain(k, toolChainMap.at(ProjectExplorer::Constants::C_LANGUAGE_ID));
+ ToolChainKitAspect::setToolChain(k, toolChainMap.at(ProjectExplorer::Constants::CXX_LANGUAGE_ID));
if (debugger.isValid())
DebuggerKitAspect::setDebugger(k, debugger);
@@ -328,6 +342,8 @@ void QnxConfiguration::createKit(const Target &target, QnxToolChain *toolChain,
k->setSticky(SysRootKitAspect::id(), true);
k->setSticky(DebuggerKitAspect::id(), true);
k->setSticky(QmakeProjectManager::Constants::KIT_INFORMATION_ID, true);
+
+ EnvironmentKitAspect::setEnvironmentChanges(k, qnxEnvironmentItems());
};
// add kit with device and qt version not sticky
@@ -361,8 +377,8 @@ void QnxConfiguration::readInformation()
return;
foreach (const ConfigInstallInformation &info, installInfoList) {
- if (m_qnxHost == FilePath::fromString(info.host)
- && m_qnxTarget == FilePath::fromString(info.target)) {
+ if (m_qnxHost == FilePath::fromString(info.host).canonicalPath()
+ && m_qnxTarget == FilePath::fromString(info.target).canonicalPath()) {
m_configName = info.name;
setVersion(QnxVersionNumber(info.version));
break;
@@ -376,12 +392,12 @@ void QnxConfiguration::setDefaultConfiguration(const Utils::FilePath &envScript)
m_envFile = envScript;
m_qnxEnv = QnxUtils::qnxEnvironmentFromEnvFile(m_envFile.toString());
foreach (const EnvironmentItem &item, m_qnxEnv) {
- if (item.name == QLatin1String("QNX_CONFIGURATION"))
- m_qnxConfiguration = FilePath::fromString(item.value);
- else if (item.name == QLatin1String("QNX_TARGET"))
- m_qnxTarget = FilePath::fromString(item.value);
- else if (item.name == QLatin1String("QNX_HOST"))
- m_qnxHost = FilePath::fromString(item.value);
+ if (item.name == QNXConfiguration)
+ m_qnxConfiguration = FilePath::fromString(item.value).canonicalPath();
+ else if (item.name == QNXTarget)
+ m_qnxTarget = FilePath::fromString(item.value).canonicalPath();
+ else if (item.name == QNXHost)
+ m_qnxHost = FilePath::fromString(item.value).canonicalPath();
}
FilePath qccPath = FilePath::fromString(HostOsInfo::withExecutableSuffix(
@@ -401,6 +417,16 @@ void QnxConfiguration::setDefaultConfiguration(const Utils::FilePath &envScript)
});
}
+EnvironmentItems QnxConfiguration::qnxEnvironmentItems() const
+{
+ Utils::EnvironmentItems envList;
+ envList.push_back(EnvironmentItem(QNXConfiguration, m_qnxConfiguration.toString()));
+ envList.push_back(EnvironmentItem(QNXTarget, m_qnxTarget.toString()));
+ envList.push_back(EnvironmentItem(QNXHost, m_qnxHost.toString()));
+
+ return envList;
+}
+
const QnxConfiguration::Target *QnxConfiguration::findTargetByDebuggerPath(
const FilePath &path) const
{
@@ -423,12 +449,14 @@ void QnxConfiguration::assignDebuggersToTargets()
QStringList debuggerNames = hostUsrBinDir.entryList(
QStringList(HostOsInfo::withExecutableSuffix(QLatin1String("nto*-gdb"))),
QDir::Files);
+ Utils::Environment sysEnv = Utils::Environment::systemEnvironment();
+ sysEnv.modify(qnxEnvironmentItems());
foreach (const QString &debuggerName, debuggerNames) {
const FilePath debuggerPath = FilePath::fromString(hostUsrBinDir.path())
.pathAppended(debuggerName);
DebuggerItem item;
item.setCommand(debuggerPath);
- item.reinitializeFromFile();
+ item.reinitializeFromFile(sysEnv);
bool found = false;
foreach (const Abi &abi, item.abis()) {
for (Target &target : m_targets) {
diff --git a/src/plugins/qnx/qnxconfiguration.h b/src/plugins/qnx/qnxconfiguration.h
index 41649ce6bf..a9b9d7a9e7 100644
--- a/src/plugins/qnx/qnxconfiguration.h
+++ b/src/plugins/qnx/qnxconfiguration.h
@@ -90,6 +90,8 @@ private:
void setDefaultConfiguration(const Utils::FilePath &envScript);
+ Utils::EnvironmentItems qnxEnvironmentItems() const;
+
QString m_configName;
Utils::FilePath m_envFile;
@@ -122,8 +124,11 @@ private:
void createTools(const Target &target);
QVariant createDebugger(const Target &target);
- QnxToolChain *createToolChain(const Target &target);
- void createKit(const Target &target, QnxToolChain *toolChain, const QVariant &debugger);
+
+ using QnxToolChainMap = std::map<const char*, QnxToolChain*>;
+
+ QnxToolChainMap createToolChain(const Target &target);
+ void createKit(const Target &target, const QnxToolChainMap &toolChain, const QVariant &debugger);
const Target *findTargetByDebuggerPath(const Utils::FilePath &path) const;
diff --git a/src/plugins/qnx/qnxconfigurationmanager.cpp b/src/plugins/qnx/qnxconfigurationmanager.cpp
index a6046c4120..bfb9f90110 100644
--- a/src/plugins/qnx/qnxconfigurationmanager.cpp
+++ b/src/plugins/qnx/qnxconfigurationmanager.cpp
@@ -40,7 +40,7 @@ const QLatin1String QNXConfigsFileVersionKey("Version");
static FilePath qnxConfigSettingsFileName()
{
- return FilePath::fromString(Core::ICore::userResourcePath() + "/qnx/qnxconfigurations.xml");
+ return Core::ICore::userResourcePath("qnx/qnxconfigurations.xml");
}
static QnxConfigurationManager *m_instance = nullptr;
diff --git a/src/plugins/qnx/qnxdebugsupport.cpp b/src/plugins/qnx/qnxdebugsupport.cpp
index 4eeb0e25b8..d2a44e73f6 100644
--- a/src/plugins/qnx/qnxdebugsupport.cpp
+++ b/src/plugins/qnx/qnxdebugsupport.cpp
@@ -116,8 +116,8 @@ public:
arguments.append(QmlDebug::qmlDebugTcpArguments(QmlDebug::QmlDebuggerServices,
portsGatherer->qmlServer()));
}
- arguments.append(QtcProcess::splitArgs(r.commandLineArguments));
- r.commandLineArguments = QtcProcess::joinArgs(arguments);
+ arguments.append(ProcessArgs::splitArgs(r.commandLineArguments));
+ r.commandLineArguments = ProcessArgs::joinArgs(arguments);
doStart(r, runControl->device());
});
diff --git a/src/plugins/qnx/qnxdeviceprocess.cpp b/src/plugins/qnx/qnxdeviceprocess.cpp
index 2b6a0c85c4..42dd90cd7e 100644
--- a/src/plugins/qnx/qnxdeviceprocess.cpp
+++ b/src/plugins/qnx/qnxdeviceprocess.cpp
@@ -46,17 +46,16 @@ QnxDeviceProcess::QnxDeviceProcess(const QSharedPointer<const IDevice> &device,
QString QnxDeviceProcess::fullCommandLine(const Runnable &runnable) const
{
- QStringList args = QtcProcess::splitArgs(runnable.commandLineArguments);
+ QStringList args = ProcessArgs::splitArgs(runnable.commandLineArguments);
args.prepend(runnable.executable.toString());
- QString cmd = QtcProcess::Arguments::createUnixArgs(args).toString();
+ QString cmd = ProcessArgs::createUnixArgs(args).toString();
- QString fullCommandLine = QLatin1String(
+ QString fullCommandLine =
"test -f /etc/profile && . /etc/profile ; "
- "test -f $HOME/profile && . $HOME/profile ; "
- );
+ "test -f $HOME/profile && . $HOME/profile ; ";
if (!runnable.workingDirectory.isEmpty())
- fullCommandLine += QString::fromLatin1("cd %1 ; ").arg(QtcProcess::quoteArg(runnable.workingDirectory));
+ fullCommandLine += QString::fromLatin1("cd %1 ; ").arg(ProcessArgs::quoteArg(runnable.workingDirectory));
const Environment env = runnable.environment;
for (auto it = env.constBegin(); it != env.constEnd(); ++it) {
diff --git a/src/plugins/qnx/qnxdeviceprocesslist.cpp b/src/plugins/qnx/qnxdeviceprocesslist.cpp
index efd1bdb9d7..81b2fb531b 100644
--- a/src/plugins/qnx/qnxdeviceprocesslist.cpp
+++ b/src/plugins/qnx/qnxdeviceprocesslist.cpp
@@ -41,7 +41,7 @@ QnxDeviceProcessList::QnxDeviceProcessList(
QString QnxDeviceProcessList::listProcessesCommandLine() const
{
- return QLatin1String("pidin -F \"%a %A '/%n'\"");
+ return QLatin1String("pidin -F '%a %A {/%n}'");
}
QList<ProjectExplorer::DeviceProcessItem> QnxDeviceProcessList::buildProcessList(
@@ -53,7 +53,7 @@ QList<ProjectExplorer::DeviceProcessItem> QnxDeviceProcessList::buildProcessList
return processes;
lines.pop_front(); // drop headers
- const QRegularExpression re("\\s*(\\d+)\\s+(.*)'(.*)'");
+ const QRegularExpression re("\\s*(\\d+)\\s+(.*){(.*)}");
for (const QString &line : qAsConst(lines)) {
const QRegularExpressionMatch match = re.match(line);
diff --git a/src/plugins/qnx/qnxdevicetester.cpp b/src/plugins/qnx/qnxdevicetester.cpp
index 51cd8d5b33..f4a88b62b6 100644
--- a/src/plugins/qnx/qnxdevicetester.cpp
+++ b/src/plugins/qnx/qnxdevicetester.cpp
@@ -62,7 +62,7 @@ QnxDeviceTester::QnxDeviceTester(QObject *parent)
<< QLatin1String("mkdir")
<< QLatin1String("print")
<< QLatin1String("printf")
- << QLatin1String("ps")
+ << QLatin1String("pidin")
<< QLatin1String("read")
<< QLatin1String("rm")
<< QLatin1String("sed")
diff --git a/src/plugins/qnx/qnxqtversion.cpp b/src/plugins/qnx/qnxqtversion.cpp
index 2265bd2f1a..02dceac4a4 100644
--- a/src/plugins/qnx/qnxqtversion.cpp
+++ b/src/plugins/qnx/qnxqtversion.cpp
@@ -134,15 +134,12 @@ void QnxQtVersion::addToEnvironment(const Kit *k, Environment &env) const
env.prependOrSetLibrarySearchPath(libraryPath().toString());
}
-Environment QnxQtVersion::qmakeRunEnvironment() const
+void QnxQtVersion::setupQmakeRunEnvironment(Utils::Environment &env) const
{
if (!sdpPath().isEmpty())
updateEnvironment();
- Environment env = Environment::systemEnvironment();
env.modify(m_qnxEnv);
-
- return env;
}
QtSupport::QtConfigWidget *QnxQtVersion::createConfigurationWidget() const
diff --git a/src/plugins/qnx/qnxqtversion.h b/src/plugins/qnx/qnxqtversion.h
index 55d5522cc5..bd8876def2 100644
--- a/src/plugins/qnx/qnxqtversion.h
+++ b/src/plugins/qnx/qnxqtversion.h
@@ -56,7 +56,7 @@ public:
ProjectExplorer::Abis detectQtAbis() const override;
void addToEnvironment(const ProjectExplorer::Kit *k, Utils::Environment &env) const override;
- Utils::Environment qmakeRunEnvironment() const override;
+ void setupQmakeRunEnvironment(Utils::Environment &env) const override;
QtSupport::QtConfigWidget *createConfigurationWidget() const override;
diff --git a/src/plugins/qnx/qnxrunconfiguration.cpp b/src/plugins/qnx/qnxrunconfiguration.cpp
index c8735c177b..02f61894b7 100644
--- a/src/plugins/qnx/qnxrunconfiguration.cpp
+++ b/src/plugins/qnx/qnxrunconfiguration.cpp
@@ -64,7 +64,7 @@ QnxRunConfiguration::QnxRunConfiguration(Target *target, Utils::Id id)
addAspect<TerminalAspect>();
addAspect<RemoteLinuxEnvironmentAspect>(target);
- auto libAspect = addAspect<QtLibPathAspect>();
+ auto libAspect = addAspect<StringAspect>();
libAspect->setSettingsKey("Qt4ProjectManager.QnxRunConfiguration.QtLibPath");
libAspect->setLabelText(tr("Path to Qt libraries on device"));
libAspect->setDisplayStyle(StringAspect::LineEditDisplay);
@@ -78,21 +78,18 @@ QnxRunConfiguration::QnxRunConfiguration(Target *target, Utils::Id id)
symbolsAspect->setFilePath(localExecutable);
});
- connect(target, &Target::buildSystemUpdated, this, &RunConfiguration::update);
-}
+ setRunnableModifier([libAspect](Runnable &r) {
+ QString libPath = libAspect->value();
+ if (!libPath.isEmpty()) {
+ r.environment.appendOrSet("LD_LIBRARY_PATH", libPath + "/lib:$LD_LIBRARY_PATH");
+ r.environment.appendOrSet("QML_IMPORT_PATH", libPath + "/imports:$QML_IMPORT_PATH");
+ r.environment.appendOrSet("QML2_IMPORT_PATH", libPath + "/qml:$QML2_IMPORT_PATH");
+ r.environment.appendOrSet("QT_PLUGIN_PATH", libPath + "/plugins:$QT_PLUGIN_PATH");
+ r.environment.set("QT_QPA_FONTDIR", libPath + "/lib/fonts");
+ }
+ });
-Runnable QnxRunConfiguration::runnable() const
-{
- Runnable r = RunConfiguration::runnable();
- QString libPath = aspect<QtLibPathAspect>()->value();
- if (!libPath.isEmpty()) {
- r.environment.appendOrSet("LD_LIBRARY_PATH", libPath + "/lib:$LD_LIBRARY_PATH");
- r.environment.appendOrSet("QML_IMPORT_PATH", libPath + "/imports:$QML_IMPORT_PATH");
- r.environment.appendOrSet("QML2_IMPORT_PATH", libPath + "/qml:$QML2_IMPORT_PATH");
- r.environment.appendOrSet("QT_PLUGIN_PATH", libPath + "/plugins:$QT_PLUGIN_PATH");
- r.environment.set("QT_QPA_FONTDIR", libPath + "/lib/fonts");
- }
- return r;
+ connect(target, &Target::buildSystemUpdated, this, &RunConfiguration::update);
}
// QnxRunConfigurationFactory
diff --git a/src/plugins/qnx/qnxrunconfiguration.h b/src/plugins/qnx/qnxrunconfiguration.h
index e56d00fe34..2f52bc930d 100644
--- a/src/plugins/qnx/qnxrunconfiguration.h
+++ b/src/plugins/qnx/qnxrunconfiguration.h
@@ -31,23 +31,12 @@
namespace Qnx {
namespace Internal {
-class QtLibPathAspect : public Utils::StringAspect
-{
- Q_OBJECT
-
-public:
- QtLibPathAspect() = default;
-};
-
class QnxRunConfiguration final : public ProjectExplorer::RunConfiguration
{
Q_OBJECT
public:
QnxRunConfiguration(ProjectExplorer::Target *target, Utils::Id id);
-
-private:
- ProjectExplorer::Runnable runnable() const override;
};
class QnxRunConfigurationFactory final : public ProjectExplorer::RunConfigurationFactory
diff --git a/src/plugins/qnx/qnxtoolchain.cpp b/src/plugins/qnx/qnxtoolchain.cpp
index 88ac04bde3..0fc060f51e 100644
--- a/src/plugins/qnx/qnxtoolchain.cpp
+++ b/src/plugins/qnx/qnxtoolchain.cpp
@@ -213,8 +213,11 @@ QnxToolChainFactory::QnxToolChainFactory()
}
QList<ProjectExplorer::ToolChain *> QnxToolChainFactory::autoDetect(
- const QList<ProjectExplorer::ToolChain *> &alreadyKnown)
+ const QList<ProjectExplorer::ToolChain *> &alreadyKnown,
+ const IDevice::Ptr &device)
{
+ Q_UNUSED(device);
+
QList<ToolChain *> tcs;
QList<QnxConfiguration *> configurations =
QnxConfigurationManager::instance()->configurations();
diff --git a/src/plugins/qnx/qnxtoolchain.h b/src/plugins/qnx/qnxtoolchain.h
index 3f38f2c555..428cc5202d 100644
--- a/src/plugins/qnx/qnxtoolchain.h
+++ b/src/plugins/qnx/qnxtoolchain.h
@@ -71,7 +71,8 @@ public:
QnxToolChainFactory();
QList<ProjectExplorer::ToolChain *> autoDetect(
- const QList<ProjectExplorer::ToolChain *> &alreadyKnown) override;
+ const QList<ProjectExplorer::ToolChain *> &alreadyKnown,
+ const ProjectExplorer::IDevice::Ptr &device) final;
};
//----------------------------------------------------------------------------
diff --git a/src/plugins/qnx/qnxutils.cpp b/src/plugins/qnx/qnxutils.cpp
index 510553fcf7..5e5d762432 100644
--- a/src/plugins/qnx/qnxutils.cpp
+++ b/src/plugins/qnx/qnxutils.cpp
@@ -29,27 +29,26 @@
#include <utils/algorithm.h>
#include <utils/fileutils.h>
#include <utils/hostosinfo.h>
-#include <utils/synchronousprocess.h>
+#include <utils/qtcprocess.h>
#include <utils/temporaryfile.h>
#include <QDebug>
#include <QDir>
#include <QDirIterator>
#include <QDomDocument>
-#include <QProcess>
#include <QStandardPaths>
#include <QApplication>
using namespace ProjectExplorer;
-using namespace Qnx;
-using namespace Qnx::Internal;
+using namespace Utils;
+
+namespace Qnx {
+namespace Internal {
-namespace {
const char *EVAL_ENV_VARS[] = {
"QNX_TARGET", "QNX_HOST", "QNX_CONFIGURATION", "QNX_CONFIGURATION_EXCLUSIVE",
"MAKEFLAGS", "LD_LIBRARY_PATH", "PATH", "QDE", "CPUVARDIR", "PYTHONPATH"
};
-}
QString QnxUtils::cpuDirFromAbi(const Abi &abi)
{
@@ -79,18 +78,17 @@ QString QnxUtils::cpuDirShortDescription(const QString &cpuDir)
return cpuDir;
}
-Utils::EnvironmentItems QnxUtils::qnxEnvironmentFromEnvFile(const QString &fileName)
+EnvironmentItems QnxUtils::qnxEnvironmentFromEnvFile(const QString &fileName)
{
- Utils::EnvironmentItems items;
+ EnvironmentItems items;
if (!QFileInfo::exists(fileName))
return items;
- const bool isWindows = Utils::HostOsInfo::isWindowsHost();
+ const bool isWindows = HostOsInfo::isWindowsHost();
// locking creating sdp-env file wrapper script
- Utils::TemporaryFile tmpFile(QString::fromLatin1("sdp-env-eval-XXXXXX")
- + QString::fromLatin1(isWindows ? ".bat" : ".sh"));
+ TemporaryFile tmpFile("sdp-env-eval-XXXXXX" + QString::fromLatin1(isWindows ? ".bat" : ".sh"));
if (!tmpFile.open())
return items;
tmpFile.setTextModeEnabled(true);
@@ -98,31 +96,30 @@ Utils::EnvironmentItems QnxUtils::qnxEnvironmentFromEnvFile(const QString &fileN
// writing content to wrapper script
QTextStream fileContent(&tmpFile);
if (isWindows)
- fileContent << QLatin1String("@echo off\n")
- << QLatin1String("call ") << fileName << QLatin1Char('\n');
+ fileContent << "@echo off\n"
+ << "call " << fileName << '\n';
else
- fileContent << QLatin1String("#!/bin/bash\n")
- << QLatin1String(". ") << fileName << QLatin1Char('\n');
+ fileContent << "#!/bin/bash\n"
+ << ". " << fileName << '\n';
QString linePattern = QString::fromLatin1(isWindows ? "echo %1=%%1%" : "echo %1=$%1");
for (int i = 0, len = sizeof(EVAL_ENV_VARS) / sizeof(const char *); i < len; ++i)
fileContent << linePattern.arg(QLatin1String(EVAL_ENV_VARS[i])) << QLatin1Char('\n');
tmpFile.close();
// running wrapper script
- QProcess process;
+ QtcProcess process;
if (isWindows)
- process.start(QLatin1String("cmd.exe"),
- QStringList() << QLatin1String("/C") << tmpFile.fileName());
+ process.setCommand({"cmd.exe", {"/C", tmpFile.fileName()}});
else
- process.start(QLatin1String("/bin/bash"),
- QStringList() << tmpFile.fileName());
+ process.setCommand({"/bin/bash", {tmpFile.fileName()}});
+ process.start();
// waiting for finish
QApplication::setOverrideCursor(Qt::BusyCursor);
bool waitResult = process.waitForFinished(10000);
QApplication::restoreOverrideCursor();
if (!waitResult) {
- Utils::SynchronousProcess::stopProcess(process);
+ process.stopProcess();
return items;
}
@@ -138,7 +135,7 @@ Utils::EnvironmentItems QnxUtils::qnxEnvironmentFromEnvFile(const QString &fileN
continue;
QString var = line.left(equalIndex);
QString value = line.mid(equalIndex + 1);
- items.append(Utils::EnvironmentItem(var, value));
+ items.append(EnvironmentItem(var, value));
}
return items;
@@ -148,7 +145,7 @@ QString QnxUtils::envFilePath(const QString &sdpPath)
{
QDir sdp(sdpPath);
QStringList entries;
- if (Utils::HostOsInfo::isWindowsHost())
+ if (HostOsInfo::isWindowsHost())
entries = sdp.entryList(QStringList(QLatin1String("*-env.bat")));
else
entries = sdp.entryList(QStringList(QLatin1String("*-env.sh")));
@@ -162,7 +159,7 @@ QString QnxUtils::envFilePath(const QString &sdpPath)
QString QnxUtils::defaultTargetVersion(const QString &sdpPath)
{
foreach (const ConfigInstallInformation &sdpInfo, installedConfigs()) {
- if (!sdpInfo.path.compare(sdpPath, Utils::HostOsInfo::fileNameCaseSensitivity()))
+ if (!sdpInfo.path.compare(sdpPath, HostOsInfo::fileNameCaseSensitivity()))
return sdpInfo.version;
}
@@ -212,14 +209,13 @@ QList<ConfigInstallInformation> QnxUtils::installedConfigs(const QString &config
return sdpList;
}
-Utils::EnvironmentItems QnxUtils::qnxEnvironment(const QString &sdpPath)
+EnvironmentItems QnxUtils::qnxEnvironment(const QString &sdpPath)
{
return qnxEnvironmentFromEnvFile(envFilePath(sdpPath));
}
-QList<QnxTarget> QnxUtils::findTargets(const Utils::FilePath &basePath)
+QList<QnxTarget> QnxUtils::findTargets(const FilePath &basePath)
{
- using namespace Utils;
QList<QnxTarget> result;
QDirIterator iterator(basePath.toString());
@@ -261,3 +257,6 @@ Abis QnxUtils::convertAbis(const Abis &abis)
{
return Utils::transform(abis, &QnxUtils::convertAbi);
}
+
+} // Internal
+} // Qnx
diff --git a/src/plugins/qtsupport/baseqtversion.cpp b/src/plugins/qtsupport/baseqtversion.cpp
index e9feec7f2a..85d71a9e0e 100644
--- a/src/plugins/qtsupport/baseqtversion.cpp
+++ b/src/plugins/qtsupport/baseqtversion.cpp
@@ -53,9 +53,9 @@
#include <utils/hostosinfo.h>
#include <utils/macroexpander.h>
#include <utils/qtcassert.h>
+#include <utils/qtcprocess.h>
#include <utils/runextensions.h>
#include <utils/stringutils.h>
-#include <utils/synchronousprocess.h>
#include <utils/winutils.h>
#include <resourceeditor/resourcenode.h>
@@ -196,8 +196,10 @@ public:
static QString qmakeProperty(const QHash<ProKey, ProString> &versionInfo,
const QByteArray &name,
PropertyVariant variant = PropertyVariantGet);
- static FilePath mkspecDirectoryFromVersionInfo(const QHash<ProKey,ProString> &versionInfo);
- static FilePath mkspecFromVersionInfo(const QHash<ProKey,ProString> &versionInfo);
+ static FilePath mkspecDirectoryFromVersionInfo(const QHash<ProKey, ProString> &versionInfo,
+ const FilePath &qmakeCommand);
+ static FilePath mkspecFromVersionInfo(const QHash<ProKey,ProString> &versionInfo,
+ const FilePath &qmakeCommand);
static FilePath sourcePath(const QHash<ProKey,ProString> &versionInfo);
void setId(int id); // used by the qtversionmanager for legacy restore
// and by the qtoptionspage to replace Qt versions
@@ -495,6 +497,10 @@ QSet<Id> BaseQtVersion::availableFeatures() const
if (qtVersion().matches(5, 15))
return features;
+ // Qt 6 uses versionless imports
+ features.unite(versionedIds(Constants::FEATURE_QT_QUICK_PREFIX, 6, -1));
+ features.unite(versionedIds(Constants::FEATURE_QT_QUICK_CONTROLS_2_PREFIX, 6, -1));
+
return features;
}
@@ -718,11 +724,24 @@ void BaseQtVersion::fromMap(const QVariantMap &map)
d->m_isAutodetected = map.value(QTVERSIONAUTODETECTED).toBool();
d->m_autodetectionSource = map.value(QTVERSIONAUTODETECTIONSOURCE).toString();
d->m_overrideFeatures = Utils::Id::fromStringList(map.value(QTVERSION_OVERRIDE_FEATURES).toStringList());
- QString string = map.value(QTVERSIONQMAKEPATH).toString();
+ d->m_qmakeCommand = FilePath::fromVariant(map.value(QTVERSIONQMAKEPATH));
+
+ QString string = d->m_qmakeCommand.toString();
if (string.startsWith('~'))
string.remove(0, 1).prepend(QDir::homePath());
+ if (!d->m_qmakeCommand.needsDevice()) {
+ // FIXME: generalize for all devices.
+ QFileInfo fi(string);
+ if (BuildableHelperLibrary::isQtChooser(fi)) {
+ // we don't want to treat qtchooser as a normal qmake
+ // see e.g. QTCREATORBUG-9841, also this lead to users changing what
+ // qtchooser forwards too behind our backs, which will inadvertly lead to bugs
+ string = BuildableHelperLibrary::qtChooserToQmakePath(fi.symLinkTarget());
+ d->m_qmakeCommand = FilePath::fromString(string);
+ }
+ }
- d->m_data.qtSources = FilePath::fromUserInput(map.value(QTVERSIONSOURCEPATH).toString());
+ d->m_data.qtSources = FilePath::fromVariant(map.value(QTVERSIONSOURCEPATH));
// Handle ABIs provided by the SDKTool:
// Note: Creator does not write these settings itself, so it has to come from the SDKTool!
@@ -731,15 +750,6 @@ void BaseQtVersion::fromMap(const QVariantMap &map)
d->m_data.qtAbis = Utils::filtered(d->m_data.qtAbis, &Abi::isValid);
d->m_data.hasQtAbis = !d->m_data.qtAbis.isEmpty();
- QFileInfo fi(string);
- if (BuildableHelperLibrary::isQtChooser(fi)) {
- // we don't want to treat qtchooser as a normal qmake
- // see e.g. QTCREATORBUG-9841, also this lead to users changing what
- // qtchooser forwards too behind our backs, which will inadvertly lead to bugs
- string = BuildableHelperLibrary::qtChooserToQmakePath(fi.symLinkTarget());
- }
-
- d->m_qmakeCommand = FilePath::fromString(string);
updateDefaultDisplayName();
// Clear the cached qmlscene command, it might not match the restored path anymore.
@@ -751,12 +761,13 @@ QVariantMap BaseQtVersion::toMap() const
QVariantMap result;
result.insert(Constants::QTVERSIONID, uniqueId());
d->m_data.unexpandedDisplayName.toMap(result, Constants::QTVERSIONNAME);
+
result.insert(QTVERSIONAUTODETECTED, isAutodetected());
result.insert(QTVERSIONAUTODETECTIONSOURCE, autodetectionSource());
if (!d->m_overrideFeatures.isEmpty())
result.insert(QTVERSION_OVERRIDE_FEATURES, Utils::Id::toStringList(d->m_overrideFeatures));
- result.insert(QTVERSIONQMAKEPATH, qmakeCommand().toString());
+ result.insert(QTVERSIONQMAKEPATH, qmakeCommand().toVariant());
return result;
}
@@ -1138,13 +1149,13 @@ void BaseQtVersionPrivate::updateMkspec()
return;
m_mkspecUpToDate = true;
- m_mkspecFullPath = mkspecFromVersionInfo(versionInfo());
+ m_mkspecFullPath = mkspecFromVersionInfo(versionInfo(), m_qmakeCommand);
m_mkspec = m_mkspecFullPath;
if (m_mkspecFullPath.isEmpty())
return;
- FilePath baseMkspecDir = mkspecDirectoryFromVersionInfo(versionInfo());
+ FilePath baseMkspecDir = mkspecDirectoryFromVersionInfo(versionInfo(), m_qmakeCommand);
if (m_mkspec.isChildOf(baseMkspecDir)) {
m_mkspec = m_mkspec.relativeChildPath(baseMkspecDir);
@@ -1171,7 +1182,9 @@ void BaseQtVersion::ensureMkSpecParsed() const
QMakeVfs vfs;
QMakeGlobals option;
applyProperties(&option);
- option.environment = qmakeRunEnvironment().toProcessEnvironment();
+ Environment env = Environment::systemEnvironment(); // FIXME: Use build device
+ setupQmakeRunEnvironment(env);
+ option.environment = env.toProcessEnvironment();
ProMessageHandler msgHandler(true);
ProFileCacheManager::instance()->incRefCount();
QMakeParser parser(ProFileCacheManager::instance()->cache(), &vfs, &msgHandler);
@@ -1299,60 +1312,49 @@ void BaseQtVersionPrivate::updateVersionInfo()
}
m_qmakeIsExecutable = true;
- m_data.prefix = FilePath::fromUserInput(qmakeProperty("QT_INSTALL_PREFIX"));
-
- m_data.binPath = FilePath::fromUserInput(qmakeProperty("QT_INSTALL_BINS"));
- m_data.libExecPath = FilePath::fromUserInput(qmakeProperty("QT_INSTALL_LIBEXECS"));
- m_data.configurationPath = FilePath::fromUserInput(qmakeProperty("QT_INSTALL_CONFIGURATION"));
- m_data.dataPath = FilePath::fromUserInput(qmakeProperty("QT_INSTALL_DATA"));
- m_data.demosPath = FilePath::fromString(
- QFileInfo(qmakeProperty("QT_INSTALL_DEMOS")).canonicalFilePath());
- m_data.docsPath = FilePath::fromUserInput(qmakeProperty("QT_INSTALL_DOCS"));
- m_data.examplesPath = FilePath::fromString(
- QFileInfo(qmakeProperty("QT_INSTALL_EXAMPLES")).canonicalFilePath());
- m_data.headerPath = FilePath::fromUserInput(qmakeProperty("QT_INSTALL_HEADERS"));
- m_data.importsPath = FilePath::fromUserInput(qmakeProperty("QT_INSTALL_IMPORTS"));
- m_data.libraryPath = FilePath::fromUserInput(qmakeProperty("QT_INSTALL_LIBS"));
- m_data.pluginPath = FilePath::fromUserInput(qmakeProperty("QT_INSTALL_PLUGINS"));
- m_data.qmlPath = FilePath::fromUserInput(qmakeProperty("QT_INSTALL_QML"));
- m_data.translationsPath = FilePath::fromUserInput(qmakeProperty("QT_INSTALL_TRANSLATIONS"));
-
- m_data.hostBinPath = FilePath::fromUserInput(qmakeProperty("QT_HOST_BINS"));
- m_data.hostLibexecPath = FilePath::fromUserInput(qmakeProperty("QT_HOST_LIBEXECS"));
- m_data.hostDataPath = FilePath::fromUserInput(qmakeProperty("QT_HOST_DATA"));
- m_data.hostPrefixPath = FilePath::fromUserInput(qmakeProperty("QT_HOST_PREFIX"));
-
- const QString qtHeaderData = q->headerPath().toString();
+ auto fileProperty = [this](const QByteArray &name) {
+ return FilePath::fromUserInput(qmakeProperty(name)).onDevice(m_qmakeCommand);
+ };
+
+ m_data.prefix = fileProperty("QT_INSTALL_PREFIX");
+ m_data.binPath = fileProperty("QT_INSTALL_BINS");
+ m_data.libExecPath = fileProperty("QT_INSTALL_LIBEXECS");
+ m_data.configurationPath = fileProperty("QT_INSTALL_CONFIGURATION");
+ m_data.dataPath = fileProperty("QT_INSTALL_DATA");
+ m_data.demosPath = fileProperty("QT_INSTALL_DEMOS");
+ m_data.docsPath = fileProperty("QT_INSTALL_DOCS");
+ m_data.examplesPath = fileProperty("QT_INSTALL_EXAMPLES");
+ m_data.headerPath = fileProperty("QT_INSTALL_HEADERS");
+ m_data.importsPath = fileProperty("QT_INSTALL_IMPORTS");
+ m_data.libraryPath = fileProperty("QT_INSTALL_LIBS");
+ m_data.pluginPath = fileProperty("QT_INSTALL_PLUGINS");
+ m_data.qmlPath = fileProperty("QT_INSTALL_QML");
+ m_data.translationsPath = fileProperty("QT_INSTALL_TRANSLATIONS");
+ m_data.hostBinPath = fileProperty("QT_HOST_BINS");
+ m_data.hostLibexecPath = fileProperty("QT_HOST_LIBEXECS");
+ m_data.hostDataPath = fileProperty("QT_HOST_DATA");
+ m_data.hostPrefixPath = fileProperty("QT_HOST_PREFIX");
// Now check for a qt that is configured with a prefix but not installed
- QString installDir = q->hostBinPath().toString();
- if (!installDir.isNull()) {
- if (!QFileInfo::exists(installDir))
- m_data.installed = false;
- }
+ if (!m_data.hostBinPath.isReadableDir())
+ m_data.installed = false;
+
// Framework builds for Qt 4.8 don't use QT_INSTALL_HEADERS
// so we don't check on mac
if (!HostOsInfo::isMacHost()) {
- if (!qtHeaderData.isNull()) {
- if (!QFileInfo::exists(qtHeaderData))
- m_data.installed = false;
- }
- }
- const QString qtInstallDocs = q->docsPath().toString();
- if (!qtInstallDocs.isEmpty()) {
- if (QFileInfo::exists(qtInstallDocs))
- m_data.hasDocumentation = true;
- }
- const QString qtInstallExamples = q->examplesPath().toString();
- if (!qtInstallExamples.isEmpty()) {
- if (QFileInfo::exists(qtInstallExamples))
- m_data.hasExamples = true;
- }
- const QString qtInstallDemos = q->demosPath().toString();
- if (!qtInstallDemos.isEmpty()) {
- if (QFileInfo::exists(qtInstallDemos))
- m_data.hasDemos = true;
+ if (!m_data.headerPath.isReadableDir())
+ m_data.installed = false;
}
+
+ if (m_data.docsPath.isReadableDir())
+ m_data.hasDocumentation = true;
+
+ if (m_data.examplesPath.isReadableDir())
+ m_data.hasExamples = true;
+
+ if (m_data.demosPath.isReadableDir())
+ m_data.hasDemos = true;
+
m_data.qtVersionString = qmakeProperty("QT_VERSION");
m_isUpdating = false;
@@ -1706,9 +1708,17 @@ void BaseQtVersion::addToEnvironment(const Kit *k, Environment &env) const
// One such example is Blackberry which for some reason decided to always use the same
// qmake and use environment variables embedded in their mkspecs to make that point to
// the different Qt installations.
+
Environment BaseQtVersion::qmakeRunEnvironment() const
{
- return Environment::systemEnvironment();
+ Environment env = Environment::systemEnvironment(); // FIXME: Use build environment
+ setupQmakeRunEnvironment(env);
+ return env;
+}
+
+void BaseQtVersion::setupQmakeRunEnvironment(Environment &env) const
+{
+ Q_UNUSED(env);
}
bool BaseQtVersion::hasQmlDumpWithRelocatableFlag() const
@@ -1729,12 +1739,11 @@ Tasks BaseQtVersion::reportIssuesImpl(const QString &proFile, const QString &bui
results.append(BuildSystemTask(Task::Error, msg));
}
- QFileInfo qmakeInfo = qmakeCommand().toFileInfo();
- if (!qmakeInfo.exists() ||
- !qmakeInfo.isExecutable()) {
+ FilePath qmake = qmakeCommand();
+ if (!qmake.isExecutableFile()) {
//: %1: Path to qmake executable
const QString msg = QCoreApplication::translate("QmakeProjectManager::QtVersion",
- "The qmake command \"%1\" was not found or is not executable.").arg(qmakeCommand().toUserOutput());
+ "The qmake command \"%1\" was not found or is not executable.").arg(qmake.toUserOutput());
results.append(BuildSystemTask(Task::Error, msg));
}
@@ -1758,8 +1767,7 @@ QtConfigWidget *BaseQtVersion::createConfigurationWidget() const
return nullptr;
}
-static QByteArray runQmakeQuery(const FilePath &binary, const Environment &env,
- QString *error)
+static QByteArray runQmakeQuery(const FilePath &binary, const Environment &env, QString *error)
{
QTC_ASSERT(error, return QByteArray());
@@ -1768,16 +1776,18 @@ static QByteArray runQmakeQuery(const FilePath &binary, const Environment &env,
// Prevent e.g. qmake 4.x on MinGW to show annoying errors about missing dll's.
WindowsCrashDialogBlocker crashDialogBlocker;
- QProcess process;
- process.setEnvironment(env.toStringList());
- process.start(binary.toString(), QStringList("-query"), QIODevice::ReadOnly);
+ QtcProcess process;
+ process.setEnvironment(env);
+ process.setOpenMode(QIODevice::ReadOnly);
+ process.setCommand({binary, {"-query"}});
+ process.start();
if (!process.waitForStarted()) {
*error = QCoreApplication::translate("QtVersion", "Cannot start \"%1\": %2").arg(binary.toUserOutput()).arg(process.errorString());
return QByteArray();
}
if (!process.waitForFinished(timeOutMS)) {
- SynchronousProcess::stopProcess(process);
+ process.stopProcess();
*error = QCoreApplication::translate("QtVersion", "Timeout running \"%1\" (%2 ms).").arg(binary.toUserOutput()).arg(timeOutMS);
return QByteArray();
}
@@ -1797,8 +1807,7 @@ bool BaseQtVersionPrivate::queryQMakeVariables(const FilePath &binary, const Env
if (!error)
error = &tmp;
- const QFileInfo qmake = binary.toFileInfo();
- if (!qmake.exists() || !qmake.isExecutable() || qmake.isDir()) {
+ if (!binary.isExecutableFile()) {
*error = QCoreApplication::translate("QtVersion", "qmake \"%1\" is not an executable.").arg(binary.toUserOutput());
return false;
}
@@ -1839,17 +1848,19 @@ QString BaseQtVersionPrivate::qmakeProperty(const QByteArray &name,
return qmakeProperty(m_versionInfo, name, variant);
}
-FilePath BaseQtVersionPrivate::mkspecDirectoryFromVersionInfo(const QHash<ProKey, ProString> &versionInfo)
+FilePath BaseQtVersionPrivate::mkspecDirectoryFromVersionInfo(const QHash<ProKey, ProString> &versionInfo,
+ const FilePath &qmakeCommand)
{
QString dataDir = qmakeProperty(versionInfo, "QT_HOST_DATA", PropertyVariantSrc);
if (dataDir.isEmpty())
return FilePath();
- return FilePath::fromUserInput(dataDir + "/mkspecs");
+ return FilePath::fromUserInput(dataDir + "/mkspecs").onDevice(qmakeCommand);
}
-FilePath BaseQtVersionPrivate::mkspecFromVersionInfo(const QHash<ProKey, ProString> &versionInfo)
+FilePath BaseQtVersionPrivate::mkspecFromVersionInfo(const QHash<ProKey, ProString> &versionInfo,
+ const FilePath &qmakeCommand)
{
- FilePath baseMkspecDir = mkspecDirectoryFromVersionInfo(versionInfo);
+ FilePath baseMkspecDir = mkspecDirectoryFromVersionInfo(versionInfo, qmakeCommand);
if (baseMkspecDir.isEmpty())
return FilePath();
@@ -2056,35 +2067,24 @@ FilePaths BaseQtVersionPrivate::qtCorePaths()
updateVersionInfo();
const QString versionString = m_data.qtVersionString;
- const QString installLibsDir = q->libraryPath().toString();
- const QString installBinDir = q->binPath().toString();
-
const QDir::Filters filters = QDir::Files | QDir::Dirs | QDir::NoDotAndDotDot;
- const QFileInfoList entryInfoList = [&]() {
- QFileInfoList result;
- if (!installLibsDir.isEmpty())
- result += QDir(installLibsDir).entryInfoList(filters);
- if (!installBinDir.isEmpty())
- result += QDir(installBinDir).entryInfoList(filters);
- return result;
- }();
+ const FilePaths entries = m_data.libraryPath.dirEntries(filters)
+ + m_data.binPath.dirEntries(filters);
+
FilePaths staticLibs;
FilePaths dynamicLibs;
- for (const QFileInfo &info : entryInfoList) {
- const QString file = info.fileName();
- if (info.isDir()
- && file.startsWith("QtCore")
- && file.endsWith(".framework")) {
+ for (const FilePath &entry : entries) {
+ const QString file = entry.fileName();
+ if (file.startsWith("QtCore") && file.endsWith(".framework") && entry.isReadableDir()) {
// handle Framework
- const FilePath lib = FilePath::fromFileInfo(info);
- dynamicLibs.append(lib.pathAppended(file.left(file.lastIndexOf('.'))));
- } else if (info.isReadable()) {
- if (file.startsWith("libQtCore") || file.startsWith("QtCore")
+ dynamicLibs.append(entry.pathAppended(file.left(file.lastIndexOf('.'))));
+ } else if (file.startsWith("libQtCore") || file.startsWith("QtCore")
|| file.startsWith("libQt5Core") || file.startsWith("Qt5Core")
|| file.startsWith("libQt6Core") || file.startsWith("Qt6Core")) {
+ if (entry.isReadableFile()) {
if (file.endsWith(".a") || file.endsWith(".lib"))
- staticLibs.append(FilePath::fromFileInfo(info));
+ staticLibs.append(entry);
else if (file.endsWith(".dll")
|| file.endsWith(QString::fromLatin1(".so.") + versionString)
|| file.endsWith(".so")
@@ -2092,7 +2092,7 @@ FilePaths BaseQtVersionPrivate::qtCorePaths()
|| file.contains(QRegularExpression("\\.so\\.[0-9]+\\.[0-9]+$")) // QTCREATORBUG-23818
#endif
|| file.endsWith(QLatin1Char('.') + versionString + ".dylib"))
- dynamicLibs.append(FilePath::fromFileInfo(info));
+ dynamicLibs.append(entry);
}
}
}
@@ -2298,7 +2298,7 @@ BaseQtVersion *QtVersionFactory::createQtVersionFromQMakePath
QHash<ProKey, ProString> versionInfo;
if (!BaseQtVersionPrivate::queryQMakeVariables(qmakePath, Environment::systemEnvironment(), &versionInfo, error))
return nullptr;
- FilePath mkspec = BaseQtVersionPrivate::mkspecFromVersionInfo(versionInfo);
+ FilePath mkspec = BaseQtVersionPrivate::mkspecFromVersionInfo(versionInfo, qmakePath);
QMakeVfs vfs;
QMakeGlobals globals;
@@ -2307,15 +2307,14 @@ BaseQtVersion *QtVersionFactory::createQtVersionFromQMakePath
ProFileCacheManager::instance()->incRefCount();
QMakeParser parser(ProFileCacheManager::instance()->cache(), &vfs, &msgHandler);
ProFileEvaluator evaluator(&globals, &parser, &vfs, &msgHandler);
- evaluator.loadNamedSpec(mkspec.toString(), false);
+ evaluator.loadNamedSpec(mkspec.path(), false);
QList<QtVersionFactory *> factories = g_qtVersionFactories;
Utils::sort(factories, [](const QtVersionFactory *l, const QtVersionFactory *r) {
return l->m_priority > r->m_priority;
});
- QFileInfo fi = qmakePath.toFileInfo();
- if (!fi.exists() || !fi.isExecutable() || !fi.isFile())
+ if (!qmakePath.isExecutableFile())
return nullptr;
QtVersionFactory::SetupData setup;
diff --git a/src/plugins/qtsupport/baseqtversion.h b/src/plugins/qtsupport/baseqtversion.h
index fde110da62..65cf7669d6 100644
--- a/src/plugins/qtsupport/baseqtversion.h
+++ b/src/plugins/qtsupport/baseqtversion.h
@@ -122,7 +122,7 @@ public:
void applyProperties(QMakeGlobals *qmakeGlobals) const;
virtual void addToEnvironment(const ProjectExplorer::Kit *k, Utils::Environment &env) const;
- virtual Utils::Environment qmakeRunEnvironment() const;
+ Utils::Environment qmakeRunEnvironment() const;
// source path defined by qmake property QT_INSTALL_PREFIX/src or by qmake.stash QT_SOURCE_TREE
Utils::FilePath sourcePath() const;
@@ -253,6 +253,7 @@ protected:
void ensureMkSpecParsed() const;
virtual void parseMkSpec(ProFileEvaluator *) const;
+ virtual void setupQmakeRunEnvironment(Utils::Environment &env) const;
private:
void updateDefaultDisplayName();
diff --git a/src/plugins/qtsupport/exampleslistmodel.cpp b/src/plugins/qtsupport/exampleslistmodel.cpp
index a983752838..6753dc3ad8 100644
--- a/src/plugins/qtsupport/exampleslistmodel.cpp
+++ b/src/plugins/qtsupport/exampleslistmodel.cpp
@@ -449,7 +449,7 @@ void ExamplesListModel::parseTutorials(QXmlStreamReader *reader, const QString &
static QString resourcePath()
{
// normalize paths so QML doesn't freak out if it's wrongly capitalized on Windows
- return Utils::FileUtils::normalizePathName(Core::ICore::resourcePath());
+ return Utils::FileUtils::normalizePathName(Core::ICore::resourcePath().toString());
}
void ExamplesListModel::updateExamples()
diff --git a/src/plugins/qtsupport/profilereader.h b/src/plugins/qtsupport/profilereader.h
index cf7da8c876..e16572be3c 100644
--- a/src/plugins/qtsupport/profilereader.h
+++ b/src/plugins/qtsupport/profilereader.h
@@ -61,10 +61,8 @@ private:
QStringList m_messages;
};
-class QTSUPPORT_EXPORT ProFileReader : public QObject, public ProMessageHandler, public QMakeParser, public ProFileEvaluator
+class QTSUPPORT_EXPORT ProFileReader : public ProMessageHandler, public QMakeParser, public ProFileEvaluator
{
- Q_OBJECT
-
public:
ProFileReader(QMakeGlobals *option, QMakeVfs *vfs);
~ProFileReader() override;
diff --git a/src/plugins/qtsupport/qtbuildaspects.cpp b/src/plugins/qtsupport/qtbuildaspects.cpp
index d1dab4c943..2afc339b60 100644
--- a/src/plugins/qtsupport/qtbuildaspects.cpp
+++ b/src/plugins/qtsupport/qtbuildaspects.cpp
@@ -46,13 +46,13 @@ QmlDebuggingAspect::QmlDebuggingAspect()
{
setSettingsKey("EnableQmlDebugging");
setDisplayName(tr("QML debugging and profiling:"));
- setValue(ProjectExplorerPlugin::buildPropertiesSettings().qmlDebugging);
+ setValue(ProjectExplorerPlugin::buildPropertiesSettings().qmlDebugging.value());
}
void QmlDebuggingAspect::addToLayout(LayoutBuilder &builder)
{
SelectionAspect::addToLayout(builder);
- const auto warningLabel = new Utils::InfoLabel({}, Utils::InfoLabel::Warning);
+ const auto warningLabel = createSubWidget<InfoLabel>(QString(), InfoLabel::Warning);
warningLabel->setElideMode(Qt::ElideNone);
builder.addRow({{}, warningLabel});
const auto changeHandler = [this, warningLabel] {
@@ -65,12 +65,13 @@ void QmlDebuggingAspect::addToLayout(LayoutBuilder &builder)
"Only use in a safe environment.");
}
warningLabel->setText(warningText);
- setVisibleDynamic(supported);
+ setVisible(supported);
const bool warningLabelsVisible = supported && !warningText.isEmpty();
- warningLabel->setVisible(warningLabelsVisible);
+ if (warningLabel->parentWidget())
+ warningLabel->setVisible(warningLabelsVisible);
};
- connect(KitManager::instance(), &KitManager::kitsChanged, builder.layout(), changeHandler);
- connect(this, &QmlDebuggingAspect::changed, builder.layout(), changeHandler);
+ connect(KitManager::instance(), &KitManager::kitsChanged, warningLabel, changeHandler);
+ connect(this, &QmlDebuggingAspect::changed, warningLabel, changeHandler);
changeHandler();
}
@@ -78,14 +79,15 @@ QtQuickCompilerAspect::QtQuickCompilerAspect()
{
setSettingsKey("QtQuickCompiler");
setDisplayName(tr("Qt Quick Compiler:"));
- setValue(ProjectExplorerPlugin::buildPropertiesSettings().qtQuickCompiler);
+ setValue(ProjectExplorerPlugin::buildPropertiesSettings().qtQuickCompiler.value());
}
void QtQuickCompilerAspect::addToLayout(LayoutBuilder &builder)
{
SelectionAspect::addToLayout(builder);
- const auto warningLabel = new Utils::InfoLabel({}, Utils::InfoLabel::Warning);
+ const auto warningLabel = createSubWidget<InfoLabel>(QString(), InfoLabel::Warning);
warningLabel->setElideMode(Qt::ElideNone);
+ warningLabel->setVisible(false);
builder.addRow({{}, warningLabel});
const auto changeHandler = [this, warningLabel] {
QString warningText;
@@ -98,21 +100,20 @@ void QtQuickCompilerAspect::addToLayout(LayoutBuilder &builder)
warningText = tr("Disables QML debugging. QML profiling will still work.");
}
warningLabel->setText(warningText);
- setVisibleDynamic(supported);
+ setVisible(supported);
const bool warningLabelsVisible = supported && !warningText.isEmpty();
- warningLabel->setVisible(warningLabelsVisible);
+ if (warningLabel->parentWidget())
+ warningLabel->setVisible(warningLabelsVisible);
};
- connect(KitManager::instance(), &KitManager::kitsChanged, builder.layout(), changeHandler);
- connect(this, &QmlDebuggingAspect::changed, builder.layout(), changeHandler);
- connect(this, &QtQuickCompilerAspect::changed, builder.layout(), changeHandler);
- if (m_qmlDebuggingAspect) {
- connect(m_qmlDebuggingAspect, &QmlDebuggingAspect::changed, builder.layout(),
- changeHandler);
- }
+ connect(KitManager::instance(), &KitManager::kitsChanged, warningLabel, changeHandler);
+ connect(this, &QmlDebuggingAspect::changed, warningLabel, changeHandler);
+ connect(this, &QtQuickCompilerAspect::changed, warningLabel, changeHandler);
+ if (m_qmlDebuggingAspect)
+ connect(m_qmlDebuggingAspect, &QmlDebuggingAspect::changed, warningLabel, changeHandler);
changeHandler();
}
-void QtQuickCompilerAspect::acquaintSiblings(const BaseAspects &siblings)
+void QtQuickCompilerAspect::acquaintSiblings(const AspectContainer &siblings)
{
m_qmlDebuggingAspect = siblings.aspect<QmlDebuggingAspect>();
}
diff --git a/src/plugins/qtsupport/qtbuildaspects.h b/src/plugins/qtsupport/qtbuildaspects.h
index c9f8a12c1d..428f9dc811 100644
--- a/src/plugins/qtsupport/qtbuildaspects.h
+++ b/src/plugins/qtsupport/qtbuildaspects.h
@@ -56,7 +56,7 @@ public:
private:
void addToLayout(Utils::LayoutBuilder &builder) override;
- void acquaintSiblings(const Utils::BaseAspects &siblings) override;
+ void acquaintSiblings(const Utils::AspectContainer &siblings) override;
const ProjectExplorer::Kit *m_kit = nullptr;
const QmlDebuggingAspect *m_qmlDebuggingAspect = nullptr;
diff --git a/src/plugins/qtsupport/qtkitinformation.cpp b/src/plugins/qtsupport/qtkitinformation.cpp
index 153f43ac0f..d88f4df59b 100644
--- a/src/plugins/qtsupport/qtkitinformation.cpp
+++ b/src/plugins/qtsupport/qtkitinformation.cpp
@@ -30,18 +30,18 @@
#include "qtparser.h"
#include "qttestparser.h"
-#include <coreplugin/icore.h>
#include <projectexplorer/projectexplorerconstants.h>
#include <projectexplorer/task.h>
#include <projectexplorer/toolchain.h>
#include <projectexplorer/toolchainmanager.h>
+
#include <utils/algorithm.h>
#include <utils/buildablehelperlibrary.h>
+#include <utils/layoutbuilder.h>
#include <utils/macroexpander.h>
#include <utils/qtcassert.h>
#include <QComboBox>
-#include <QPushButton>
using namespace ProjectExplorer;
using namespace Utils;
@@ -55,14 +55,14 @@ class QtKitAspectWidget final : public KitAspectWidget
public:
QtKitAspectWidget(Kit *k, const KitAspect *ki) : KitAspectWidget(k, ki)
{
- m_combo = new QComboBox;
+ m_combo = createSubWidget<QComboBox>();
m_combo->setSizePolicy(QSizePolicy::Ignored, m_combo->sizePolicy().verticalPolicy());
m_combo->addItem(tr("None"), -1);
QList<int> versionIds = Utils::transform(QtVersionManager::versions(), &BaseQtVersion::uniqueId);
versionsChanged(versionIds, QList<int>(), QList<int>());
- m_manageButton = new QPushButton(KitAspectWidget::msgManage());
+ m_manageButton = createManageButton(Constants::QTVERSION_SETTINGS_PAGE_ID);
refresh();
m_combo->setToolTip(ki->description());
@@ -72,8 +72,6 @@ public:
connect(QtVersionManager::instance(), &QtVersionManager::qtVersionsChanged,
this, &QtKitAspectWidget::versionsChanged);
-
- connect(m_manageButton, &QAbstractButton::clicked, this, &QtKitAspectWidget::manageQtVersions);
}
~QtKitAspectWidget() final
@@ -84,8 +82,13 @@ public:
private:
void makeReadOnly() final { m_combo->setEnabled(false); }
- QWidget *mainWidget() const final { return m_combo; }
- QWidget *buttonWidget() const final { return m_manageButton; }
+
+ void addToLayout(LayoutBuilder &builder)
+ {
+ addMutableAction(m_combo);
+ builder.addItem(m_combo);
+ builder.addItem(m_manageButton);
+ }
void refresh() final
{
@@ -123,11 +126,6 @@ private:
}
}
- void manageQtVersions()
- {
- Core::ICore::showOptionsDialog(Constants::QTVERSION_SETTINGS_PAGE_ID, buttonWidget());
- }
-
void currentWasChanged(int idx)
{
QtKitAspect::setQtVersionId(m_kit, m_combo->itemData(idx).toInt());
@@ -143,7 +141,7 @@ private:
}
QComboBox *m_combo;
- QPushButton *m_manageButton;
+ QWidget *m_manageButton;
};
} // namespace Internal
@@ -279,7 +277,7 @@ KitAspect::ItemList QtKitAspect::toUserOutput(const Kit *k) const
return {{tr("Qt version"), version ? version->displayName() : tr("None")}};
}
-void QtKitAspect::addToEnvironment(const Kit *k, Environment &env) const
+void QtKitAspect::addToBuildEnvironment(const Kit *k, Environment &env) const
{
BaseQtVersion *version = qtVersion(k);
if (version)
@@ -471,4 +469,14 @@ Id SuppliesQtQuickImportPath::id()
return QtSupport::Constants::FLAGS_SUPPLIES_QTQUICK_IMPORT_PATH;
}
+Id KitQmlImportPath::id()
+{
+ return QtSupport::Constants::KIT_QML_IMPORT_PATH;
+}
+
+Id KitHasMergedHeaderPathsWithQmlImportPaths::id()
+{
+ return QtSupport::Constants::KIT_HAS_MERGED_HEADER_PATHS_WITH_QML_IMPORT_PATHS;
+}
+
} // namespace QtSupport
diff --git a/src/plugins/qtsupport/qtkitinformation.h b/src/plugins/qtsupport/qtkitinformation.h
index 23427df87b..0aa5a93c48 100644
--- a/src/plugins/qtsupport/qtkitinformation.h
+++ b/src/plugins/qtsupport/qtkitinformation.h
@@ -53,7 +53,7 @@ public:
ItemList toUserOutput(const ProjectExplorer::Kit *k) const override;
- void addToEnvironment(const ProjectExplorer::Kit *k, Utils::Environment &env) const override;
+ void addToBuildEnvironment(const ProjectExplorer::Kit *k, Utils::Environment &env) const override;
QList<Utils::OutputLineParser *> createOutputParsers(const ProjectExplorer::Kit *k) const override;
void addToMacroExpander(ProjectExplorer::Kit *kit, Utils::MacroExpander *expander) const override;
@@ -89,4 +89,16 @@ public:
static Utils::Id id();
};
+class QTSUPPORT_EXPORT KitQmlImportPath
+{
+public:
+ static Utils::Id id();
+};
+
+class QTSUPPORT_EXPORT KitHasMergedHeaderPathsWithQmlImportPaths
+{
+public:
+ static Utils::Id id();
+};
+
} // namespace QtSupport
diff --git a/src/plugins/qtsupport/qtoptionspage.cpp b/src/plugins/qtsupport/qtoptionspage.cpp
index 9c9974964c..54009c47ca 100644
--- a/src/plugins/qtsupport/qtoptionspage.cpp
+++ b/src/plugins/qtsupport/qtoptionspage.cpp
@@ -266,7 +266,7 @@ QtOptionsPageWidget::QtOptionsPageWidget()
m_manualItem = new StaticTreeItem(ProjectExplorer::Constants::msgManual());
m_model = new TreeModel<TreeItem, TreeItem, QtVersionItem>();
- m_model->setHeader({tr("Name"), tr("qmake Location")});
+ m_model->setHeader({tr("Name"), tr("qmake Path")});
m_model->rootItem()->appendChild(m_autoItem);
m_model->rootItem()->appendChild(m_manualItem);
@@ -805,7 +805,7 @@ static QString qtVersionsFile(const QString &baseDir)
static Utils::optional<QString> currentlyLinkedQtDir(bool *hasInstallSettings)
{
- const QString installSettingsFilePath = settingsFile(Core::ICore::resourcePath());
+ const QString installSettingsFilePath = settingsFile(Core::ICore::resourcePath().toString());
const bool installSettingsExist = QFile::exists(installSettingsFilePath);
if (hasInstallSettings)
*hasInstallSettings = installSettingsExist;
@@ -834,7 +834,7 @@ static bool canLinkWithQt(QString *toolTip)
&installSettingsExist);
QStringList tip;
tip << linkingPurposeText();
- if (!FilePath::fromString(Core::ICore::resourcePath()).isWritablePath()) {
+ if (!Core::ICore::resourcePath().isWritablePath()) {
canLink = false;
tip << QtOptionsPageWidget::tr("%1's resource directory is not writable.")
.arg(Core::Constants::IDE_DISPLAY_NAME);
@@ -997,7 +997,7 @@ void QtOptionsPageWidget::linkWithQt()
unlinkButton->setEnabled(currentLink.has_value());
connect(unlinkButton, &QPushButton::clicked, &dialog, [&dialog, &askForRestart] {
bool removeSettingsFile = false;
- const QString filePath = settingsFile(Core::ICore::resourcePath());
+ const QString filePath = settingsFile(Core::ICore::resourcePath().toString());
{
QSettings installSettings(filePath, QSettings::IniFormat);
installSettings.remove(kInstallSettingsKey);
@@ -1016,7 +1016,7 @@ void QtOptionsPageWidget::linkWithQt()
if (dialog.result() == QDialog::Accepted) {
const Utils::optional<QString> settingsDir = settingsDirForQtDir(pathInput->rawPath());
if (QTC_GUARD(settingsDir)) {
- QSettings(settingsFile(Core::ICore::resourcePath()), QSettings::IniFormat)
+ QSettings(settingsFile(Core::ICore::resourcePath().toString()), QSettings::IniFormat)
.setValue(kInstallSettingsKey, *settingsDir);
askForRestart = true;
}
diff --git a/src/plugins/qtsupport/qtparser.cpp b/src/plugins/qtsupport/qtparser.cpp
index 7265f45c64..5fb0d4d73c 100644
--- a/src/plugins/qtsupport/qtparser.cpp
+++ b/src/plugins/qtsupport/qtparser.cpp
@@ -45,6 +45,7 @@ namespace QtSupport {
QtParser::QtParser() :
m_mocRegExp(QLatin1String(FILE_PATTERN"[:\\(](\\d+?)\\)?:\\s([Ww]arning|[Ee]rror|[Nn]ote):\\s(.+?)$")),
+ m_uicRegExp(QLatin1String(FILE_PATTERN": Warning:\\s(?<msg>.+?)$")),
m_translationRegExp(QLatin1String("^([Ww]arning|[Ee]rror):\\s+(.*?) in '(.*?)'$"))
{
setObjectName(QLatin1String("QtParser"));
@@ -76,6 +77,26 @@ Utils::OutputLineParser::Result QtParser::handleLine(const QString &line, Utils:
scheduleTask(task, 1);
return {Status::Done, linkSpecs};
}
+ match = m_uicRegExp.match(lne);
+ if (match.hasMatch()) {
+ const QString fileName = match.captured(1);
+ QString message = match.captured("msg").trimmed();
+ Utils::FilePath filePath;
+ LinkSpecs linkSpecs;
+ bool isUicMessage = true;
+ if (fileName == "uic" || fileName == "stdin") {
+ message.prepend(": ").prepend(fileName);
+ } else if (fileName.endsWith(".ui")) {
+ filePath = absoluteFilePath(Utils::FilePath::fromUserInput(fileName));
+ addLinkSpecForAbsoluteFilePath(linkSpecs, filePath, -1, match, 1);
+ } else {
+ isUicMessage = false;
+ }
+ if (isUicMessage) {
+ scheduleTask(CompileTask(Task::Warning, message, filePath), 1);
+ return {Status::Done, linkSpecs};
+ }
+ }
match = m_translationRegExp.match(line);
if (match.hasMatch()) {
Task::TaskType type = Task::Warning;
@@ -172,6 +193,15 @@ void QtSupportPlugin::testQtOutputParser_data()
QLatin1String("Undefined interface"),
Utils::FilePath::fromUserInput(QLatin1String("E:/sandbox/creator/loaden/src/libs/utils/iwelcomepage.h")), 54))
<< QString();
+ QTest::newRow("uic warning")
+ << QString::fromLatin1("mainwindow.ui: Warning: The name 'pushButton' (QPushButton) is already in use, defaulting to 'pushButton1'.")
+ << OutputParserTester::STDERR
+ << QString() << QString()
+ << (Tasks()
+ << CompileTask(Task::Warning,
+ "The name 'pushButton' (QPushButton) is already in use, defaulting to 'pushButton1'.",
+ Utils::FilePath::fromUserInput("mainwindow.ui")))
+ << QString();
QTest::newRow("translation")
<< QString::fromLatin1("Warning: dropping duplicate messages in '/some/place/qtcreator_fr.qm'")
<< OutputParserTester::STDERR
diff --git a/src/plugins/qtsupport/qtparser.h b/src/plugins/qtsupport/qtparser.h
index ad6c9d5d35..8e47b6b66e 100644
--- a/src/plugins/qtsupport/qtparser.h
+++ b/src/plugins/qtsupport/qtparser.h
@@ -45,6 +45,7 @@ private:
Result handleLine(const QString &line, Utils::OutputFormat type) override;
QRegularExpression m_mocRegExp;
+ QRegularExpression m_uicRegExp;
QRegularExpression m_translationRegExp;
};
diff --git a/src/plugins/qtsupport/qtsupportconstants.h b/src/plugins/qtsupport/qtsupportconstants.h
index ea921295d6..da0f01ba1e 100644
--- a/src/plugins/qtsupport/qtsupportconstants.h
+++ b/src/plugins/qtsupport/qtsupportconstants.h
@@ -57,6 +57,9 @@ const char FEATURE_DESKTOP[] = "QtSupport.Wizards.FeatureDesktop";
// Kit flags
const char FLAGS_SUPPLIES_QTQUICK_IMPORT_PATH[] = "QtSupport.SuppliesQtQuickImportPath";
+const char KIT_QML_IMPORT_PATH[] = "QtSupport.KitQmlImportPath";
+const char KIT_HAS_MERGED_HEADER_PATHS_WITH_QML_IMPORT_PATHS[] =
+ "QtSupport.KitHasMergedHeaderPathsWithQmlImportPaths";
} // namepsace Constants
} // namepsace QtSupport
diff --git a/src/plugins/qtsupport/qtversioninfo.ui b/src/plugins/qtsupport/qtversioninfo.ui
index 221316e18e..467e898a20 100644
--- a/src/plugins/qtsupport/qtversioninfo.ui
+++ b/src/plugins/qtsupport/qtversioninfo.ui
@@ -29,7 +29,7 @@
<item row="0" column="0">
<widget class="QLabel" name="versionNameLabel">
<property name="text">
- <string>Version name:</string>
+ <string>Name:</string>
</property>
</widget>
</item>
@@ -39,7 +39,7 @@
<item row="1" column="0">
<widget class="QLabel" name="pathLabel">
<property name="text">
- <string>qmake location:</string>
+ <string>qmake path:</string>
</property>
</widget>
</item>
diff --git a/src/plugins/qtsupport/qtversionmanager.cpp b/src/plugins/qtsupport/qtversionmanager.cpp
index d362e53020..149a30a187 100644
--- a/src/plugins/qtsupport/qtversionmanager.cpp
+++ b/src/plugins/qtsupport/qtversionmanager.cpp
@@ -65,7 +65,7 @@ using namespace Internal;
const char QTVERSION_DATA_KEY[] = "QtVersion.";
const char QTVERSION_TYPE_KEY[] = "QtVersion.Type";
const char QTVERSION_FILE_VERSION_KEY[] = "Version";
-const char QTVERSION_FILENAME[] = "/qtversion.xml";
+const char QTVERSION_FILENAME[] = "qtversion.xml";
using VersionMap = QMap<int, BaseQtVersion *>;
static VersionMap m_versions;
@@ -84,12 +84,12 @@ static Q_LOGGING_CATEGORY(log, "qtc.qt.versions", QtWarningMsg);
static FilePath globalSettingsFileName()
{
- return FilePath::fromString(Core::ICore::installerResourcePath() + QTVERSION_FILENAME);
+ return Core::ICore::installerResourcePath(QTVERSION_FILENAME);
}
static FilePath settingsFileName(const QString &path)
{
- return FilePath::fromString(Core::ICore::userResourcePath() + path);
+ return Core::ICore::userResourcePath(path);
}
diff --git a/src/plugins/remotelinux/genericdirectuploadservice.cpp b/src/plugins/remotelinux/genericdirectuploadservice.cpp
index cc7db8561a..d8996568a4 100644
--- a/src/plugins/remotelinux/genericdirectuploadservice.cpp
+++ b/src/plugins/remotelinux/genericdirectuploadservice.cpp
@@ -198,7 +198,7 @@ void GenericDirectUploadService::stopDeployment()
void GenericDirectUploadService::runStat(const DeployableFile &file)
{
// We'd like to use --format=%Y, but it's not supported by busybox.
- const QString statCmd = "stat -t " + Utils::QtcProcess::quoteArgUnix(file.remoteFilePath());
+ const QString statCmd = "stat -t " + Utils::ProcessArgs::quoteArgUnix(file.remoteFilePath());
SshRemoteProcess * const statProc = connection()->createRemoteProcess(statCmd).release();
statProc->setParent(this);
connect(statProc, &SshRemoteProcess::done, this,
@@ -344,7 +344,7 @@ void GenericDirectUploadService::chmod()
if (!f.isExecutable())
continue;
const QString command = QLatin1String("chmod a+x ")
- + Utils::QtcProcess::quoteArgUnix(f.remoteFilePath());
+ + Utils::ProcessArgs::quoteArgUnix(f.remoteFilePath());
SshRemoteProcess * const chmodProc
= connection()->createRemoteProcess(command).release();
chmodProc->setParent(this);
diff --git a/src/plugins/remotelinux/makeinstallstep.cpp b/src/plugins/remotelinux/makeinstallstep.cpp
index d7f970b9e2..7f3a880c4e 100644
--- a/src/plugins/remotelinux/makeinstallstep.cpp
+++ b/src/plugins/remotelinux/makeinstallstep.cpp
@@ -61,7 +61,9 @@ MakeInstallStep::MakeInstallStep(BuildStepList *parent, Utils::Id id) : MakeStep
makeCommandAspect()->setVisible(false);
buildTargetsAspect()->setVisible(false);
userArgumentsAspect()->setVisible(false);
- jobCountContainer()->setVisible(false);
+ overrideMakeflagsAspect()->setVisible(false);
+ nonOverrideWarning()->setVisible(false);
+ jobCountAspect()->setVisible(false);
disabledForSubdirsAspect()->setVisible(false);
const auto makeAspect = addAspect<ExecutableAspect>();
@@ -239,7 +241,7 @@ void MakeInstallStep::updateArgsFromAspect()
{
if (customCommandLineAspect()->isChecked())
return;
- setUserArguments(QtcProcess::joinArgs(target()->makeInstallCommand(
+ setUserArguments(ProcessArgs::joinArgs(target()->makeInstallCommand(
static_cast<StringAspect *>(aspect(InstallRootAspectId))->filePath().toString())
.arguments));
updateFullCommandLine();
@@ -250,7 +252,7 @@ void MakeInstallStep::updateFullCommandLine()
// FIXME: Only executable?
static_cast<StringAspect *>(aspect(FullCommandLineAspectId))->setValue(
QDir::toNativeSeparators(
- QtcProcess::quoteArg(makeExecutable().toString()))
+ ProcessArgs::quoteArg(makeExecutable().toString()))
+ ' ' + userArguments());
}
@@ -259,9 +261,9 @@ void MakeInstallStep::updateFromCustomCommandLineAspect()
const StringAspect * const aspect = customCommandLineAspect();
if (!aspect->isChecked())
return;
- const QStringList tokens = QtcProcess::splitArgs(aspect->value());
+ const QStringList tokens = ProcessArgs::splitArgs(aspect->value());
setMakeCommand(tokens.isEmpty() ? FilePath() : FilePath::fromString(tokens.first()));
- setUserArguments(QtcProcess::joinArgs(tokens.mid(1)));
+ setUserArguments(ProcessArgs::joinArgs(tokens.mid(1)));
}
StringAspect *MakeInstallStep::customCommandLineAspect() const
diff --git a/src/plugins/remotelinux/remotelinuxcustomrunconfiguration.cpp b/src/plugins/remotelinux/remotelinuxcustomrunconfiguration.cpp
index 7588dcc580..b3604332d1 100644
--- a/src/plugins/remotelinux/remotelinuxcustomrunconfiguration.cpp
+++ b/src/plugins/remotelinux/remotelinuxcustomrunconfiguration.cpp
@@ -41,7 +41,20 @@ using namespace Utils;
namespace RemoteLinux {
namespace Internal {
-RemoteLinuxCustomRunConfiguration::RemoteLinuxCustomRunConfiguration(Target *target, Utils::Id id)
+class RemoteLinuxCustomRunConfiguration : public RunConfiguration
+{
+ Q_DECLARE_TR_FUNCTIONS(RemoteLinux::Internal::RemoteLinuxCustomRunConfiguration)
+
+public:
+ RemoteLinuxCustomRunConfiguration(Target *target, Id id);
+
+ QString runConfigDefaultDisplayName();
+
+private:
+ Tasks checkForIssues() const override;
+};
+
+RemoteLinuxCustomRunConfiguration::RemoteLinuxCustomRunConfiguration(Target *target, Id id)
: RunConfiguration(target, id)
{
auto exeAspect = addAspect<ExecutableAspect>();
@@ -62,9 +75,14 @@ RemoteLinuxCustomRunConfiguration::RemoteLinuxCustomRunConfiguration(Target *tar
if (HostOsInfo::isAnyUnixHost())
addAspect<TerminalAspect>();
addAspect<RemoteLinuxEnvironmentAspect>(target);
- if (Utils::HostOsInfo::isAnyUnixHost())
+ if (HostOsInfo::isAnyUnixHost())
addAspect<X11ForwardingAspect>();
+ setRunnableModifier([this](Runnable &r) {
+ if (const auto * const forwardingAspect = aspect<X11ForwardingAspect>())
+ r.extraData.insert("Ssh.X11ForwardToDisplay", forwardingAspect->display(macroExpander()));
+ });
+
setDefaultDisplayName(runConfigDefaultDisplayName());
}
@@ -76,14 +94,6 @@ QString RemoteLinuxCustomRunConfiguration::runConfigDefaultDisplayName()
return RunConfigurationFactory::decoratedTargetName(display, target());
}
-Runnable RemoteLinuxCustomRunConfiguration::runnable() const
-{
- ProjectExplorer::Runnable r = RunConfiguration::runnable();
- if (const auto * const forwardingAspect = aspect<X11ForwardingAspect>())
- r.extraData.insert("Ssh.X11ForwardToDisplay", forwardingAspect->display(macroExpander()));
- return r;
-}
-
Tasks RemoteLinuxCustomRunConfiguration::checkForIssues() const
{
Tasks tasks;
diff --git a/src/plugins/remotelinux/remotelinuxcustomrunconfiguration.h b/src/plugins/remotelinux/remotelinuxcustomrunconfiguration.h
index 9cd0385b31..aeed4c55df 100644
--- a/src/plugins/remotelinux/remotelinuxcustomrunconfiguration.h
+++ b/src/plugins/remotelinux/remotelinuxcustomrunconfiguration.h
@@ -30,20 +30,6 @@
namespace RemoteLinux {
namespace Internal {
-class RemoteLinuxCustomRunConfiguration : public ProjectExplorer::RunConfiguration
-{
- Q_OBJECT
-
-public:
- RemoteLinuxCustomRunConfiguration(ProjectExplorer::Target *target, Utils::Id id);
-
- QString runConfigDefaultDisplayName();
-
-private:
- ProjectExplorer::Runnable runnable() const override;
- ProjectExplorer::Tasks checkForIssues() const override;
-};
-
class RemoteLinuxCustomRunConfigurationFactory
: public ProjectExplorer::FixedRunConfigurationFactory
{
diff --git a/src/plugins/remotelinux/remotelinuxqmltoolingsupport.cpp b/src/plugins/remotelinux/remotelinuxqmltoolingsupport.cpp
index 2dd5214617..9b983587c0 100644
--- a/src/plugins/remotelinux/remotelinuxqmltoolingsupport.cpp
+++ b/src/plugins/remotelinux/remotelinuxqmltoolingsupport.cpp
@@ -58,7 +58,7 @@ RemoteLinuxQmlToolingSupport::RemoteLinuxQmlToolingSupport(RunControl *runContro
QmlDebug::QmlDebugServicesPreset services = QmlDebug::servicesForRunMode(runControl->runMode());
Runnable r = runControl->runnable();
- QtcProcess::addArg(&r.commandLineArguments,
+ ProcessArgs::addArg(&r.commandLineArguments,
QmlDebug::qmlDebugTcpArguments(services, serverUrl),
OsTypeLinux);
diff --git a/src/plugins/remotelinux/remotelinuxrunconfiguration.cpp b/src/plugins/remotelinux/remotelinuxrunconfiguration.cpp
index 9b1773d56a..c964d235cc 100644
--- a/src/plugins/remotelinux/remotelinuxrunconfiguration.cpp
+++ b/src/plugins/remotelinux/remotelinuxrunconfiguration.cpp
@@ -46,7 +46,15 @@ using namespace Utils;
namespace RemoteLinux {
namespace Internal {
-RemoteLinuxRunConfiguration::RemoteLinuxRunConfiguration(Target *target, Utils::Id id)
+class RemoteLinuxRunConfiguration final : public RunConfiguration
+{
+ Q_DECLARE_TR_FUNCTIONS(RemoteLinux::Internal::RemoteLinuxRunConfiguration)
+
+public:
+ RemoteLinuxRunConfiguration(Target *target, Id id);
+};
+
+RemoteLinuxRunConfiguration::RemoteLinuxRunConfiguration(Target *target, Id id)
: RunConfiguration(target, id)
{
auto exeAspect = addAspect<ExecutableAspect>();
@@ -78,20 +86,16 @@ RemoteLinuxRunConfiguration::RemoteLinuxRunConfiguration(Target *target, Utils::
symbolsAspect->setFilePath(localExecutable);
});
+ setRunnableModifier([this](Runnable &r) {
+ if (const auto * const forwardingAspect = aspect<X11ForwardingAspect>())
+ r.extraData.insert("Ssh.X11ForwardToDisplay", forwardingAspect->display(macroExpander()));
+ });
+
connect(target, &Target::buildSystemUpdated, this, &RunConfiguration::update);
connect(target, &Target::deploymentDataChanged, this, &RunConfiguration::update);
connect(target, &Target::kitChanged, this, &RunConfiguration::update);
}
-Runnable RemoteLinuxRunConfiguration::runnable() const
-{
- Runnable r = RunConfiguration::runnable();
- const auto * const forwardingAspect = aspect<X11ForwardingAspect>();
- if (forwardingAspect)
- r.extraData.insert("Ssh.X11ForwardToDisplay", forwardingAspect->display(macroExpander()));
- return r;
-}
-
// RemoteLinuxRunConfigurationFactory
RemoteLinuxRunConfigurationFactory::RemoteLinuxRunConfigurationFactory()
diff --git a/src/plugins/remotelinux/remotelinuxrunconfiguration.h b/src/plugins/remotelinux/remotelinuxrunconfiguration.h
index 4cd0a5f976..59951dbe45 100644
--- a/src/plugins/remotelinux/remotelinuxrunconfiguration.h
+++ b/src/plugins/remotelinux/remotelinuxrunconfiguration.h
@@ -32,17 +32,6 @@
namespace RemoteLinux {
namespace Internal {
-class RemoteLinuxRunConfiguration final : public ProjectExplorer::RunConfiguration
-{
- Q_OBJECT
-
-public:
- RemoteLinuxRunConfiguration(ProjectExplorer::Target *target, Utils::Id id);
-
-private:
- ProjectExplorer::Runnable runnable() const override;
-};
-
class RemoteLinuxRunConfigurationFactory final : public ProjectExplorer::RunConfigurationFactory
{
public:
diff --git a/src/plugins/remotelinux/remotelinuxx11forwardingaspect.cpp b/src/plugins/remotelinux/remotelinuxx11forwardingaspect.cpp
index 7db97f5dbb..739a470321 100644
--- a/src/plugins/remotelinux/remotelinuxx11forwardingaspect.cpp
+++ b/src/plugins/remotelinux/remotelinuxx11forwardingaspect.cpp
@@ -36,7 +36,7 @@ static QString defaultDisplay() { return QLatin1String(qgetenv("DISPLAY")); }
X11ForwardingAspect::X11ForwardingAspect()
{
- setDisplayName(tr("X11 Forwarding"));
+ setLabelText(tr("X11 Forwarding:"));
setDisplayStyle(LineEditDisplay);
setId("X11ForwardingAspect");
setSettingsKey("RunConfiguration.X11Forwarding");
diff --git a/src/plugins/remotelinux/rsyncdeploystep.cpp b/src/plugins/remotelinux/rsyncdeploystep.cpp
index 65ffce4030..7005d77e9a 100644
--- a/src/plugins/remotelinux/rsyncdeploystep.cpp
+++ b/src/plugins/remotelinux/rsyncdeploystep.cpp
@@ -103,8 +103,8 @@ void RsyncDeployService::createRemoteDirectories()
remoteDirs << f.remoteDirectory();
remoteDirs.sort();
remoteDirs.removeDuplicates();
- m_mkdir = connection()->createRemoteProcess("mkdir -p " + QtcProcess::Arguments
- ::createUnixArgs(remoteDirs).toString());
+ m_mkdir = connection()->createRemoteProcess("mkdir -p " +
+ ProcessArgs::createUnixArgs(remoteDirs).toString());
connect(m_mkdir.get(), &SshRemoteProcess::done, this, [this](const QString &error) {
QString userError;
if (!error.isEmpty())
@@ -237,7 +237,7 @@ QString RsyncDeployStep::defaultFlags()
RsyncCommandLine RsyncDeployStep::rsyncCommand(const SshConnection &sshConnection,
const QString &flags)
{
- const QString sshCmdLine = QtcProcess::joinArgs(
+ const QString sshCmdLine = ProcessArgs::joinArgs(
QStringList{SshSettings::sshFilePath().toUserOutput()}
<< sshConnection.connectionOptions(SshSettings::sshFilePath()), OsTypeLinux);
const SshConnectionParameters sshParams = sshConnection.connectionParameters();
diff --git a/src/plugins/remotelinux/sshkeydeployer.cpp b/src/plugins/remotelinux/sshkeydeployer.cpp
index ff6b0d3bf0..cb55102a1e 100644
--- a/src/plugins/remotelinux/sshkeydeployer.cpp
+++ b/src/plugins/remotelinux/sshkeydeployer.cpp
@@ -58,7 +58,7 @@ void SshKeyDeployer::deployPublicKey(const SshConnectionParameters &sshParams,
cleanup();
Utils::FileReader reader;
- if (!reader.fetch(keyFilePath)) {
+ if (!reader.fetch(Utils::FilePath::fromString(keyFilePath))) {
emit error(tr("Public key error: %1").arg(reader.errorString()));
return;
}
diff --git a/src/plugins/resourceeditor/qrceditor/qrceditor.cpp b/src/plugins/resourceeditor/qrceditor/qrceditor.cpp
index 8384ab0a34..e17de86b44 100644
--- a/src/plugins/resourceeditor/qrceditor/qrceditor.cpp
+++ b/src/plugins/resourceeditor/qrceditor/qrceditor.cpp
@@ -391,6 +391,8 @@ void QrcEditor::onAddPrefix()
QUndoCommand * const addEmptyPrefixCommand = new AddEmptyPrefixCommand(m_treeview);
m_history.push(addEmptyPrefixCommand);
updateHistoryControls();
+ m_ui.prefixText->selectAll();
+ m_ui.prefixText->setFocus();
}
// Slot for 'Undo' button
diff --git a/src/plugins/resourceeditor/qrceditor/resourcefile.cpp b/src/plugins/resourceeditor/qrceditor/resourcefile.cpp
index 88b86ff9b4..9cb8dd1e79 100644
--- a/src/plugins/resourceeditor/qrceditor/resourcefile.cpp
+++ b/src/plugins/resourceeditor/qrceditor/resourcefile.cpp
@@ -245,7 +245,9 @@ bool ResourceFile::save()
return false;
}
- return m_textFileFormat.writeFile(m_file_name, contents(), &m_error_message);
+ return m_textFileFormat.writeFile(Utils::FilePath::fromString(m_file_name),
+ contents(),
+ &m_error_message);
}
void ResourceFile::refresh()
diff --git a/src/plugins/resourceeditor/resourceeditorw.cpp b/src/plugins/resourceeditor/resourceeditorw.cpp
index 726ef54ddc..d782ae7d5f 100644
--- a/src/plugins/resourceeditor/resourceeditorw.cpp
+++ b/src/plugins/resourceeditor/resourceeditorw.cpp
@@ -120,15 +120,15 @@ ResourceEditorW::~ResourceEditorW()
}
Core::IDocument::OpenResult ResourceEditorDocument::open(QString *errorString,
- const QString &fileName,
- const QString &realFileName)
+ const Utils::FilePath &filePath,
+ const Utils::FilePath &realFilePath)
{
if (debugResourceEditorW)
- qDebug() << "ResourceEditorW::open: " << fileName;
+ qDebug() << "ResourceEditorW::open: " << filePath;
setBlockDirtyChanged(true);
- m_model->setFileName(realFileName);
+ m_model->setFileName(realFilePath.toString());
OpenResult openResult = m_model->reload();
if (openResult != OpenResult::Success) {
@@ -138,22 +138,21 @@ Core::IDocument::OpenResult ResourceEditorDocument::open(QString *errorString,
return openResult;
}
- setFilePath(FilePath::fromString(fileName));
+ setFilePath(filePath);
setBlockDirtyChanged(false);
- m_model->setDirty(fileName != realFileName);
+ m_model->setDirty(filePath != realFilePath);
m_shouldAutoSave = false;
emit loaded(true);
return OpenResult::Success;
}
-bool ResourceEditorDocument::save(QString *errorString, const QString &name, bool autoSave)
+bool ResourceEditorDocument::save(QString *errorString, const FilePath &filePath, bool autoSave)
{
if (debugResourceEditorW)
- qDebug(">ResourceEditorW::save: %s", qPrintable(name));
+ qDebug() << ">ResourceEditorW::save: " << filePath;
- const FilePath oldFileName = filePath();
- const FilePath actualName = name.isEmpty() ? oldFileName : FilePath::fromString(name);
+ const FilePath &actualName = filePath.isEmpty() ? this->filePath() : filePath;
if (actualName.isEmpty())
return false;
@@ -161,14 +160,14 @@ bool ResourceEditorDocument::save(QString *errorString, const QString &name, boo
m_model->setFileName(actualName.toString());
if (!m_model->save()) {
*errorString = m_model->errorMessage();
- m_model->setFileName(oldFileName.toString());
+ m_model->setFileName(this->filePath().toString());
m_blockDirtyChanged = false;
return false;
}
m_shouldAutoSave = false;
if (autoSave) {
- m_model->setFileName(oldFileName.toString());
+ m_model->setFileName(this->filePath().toString());
m_model->setDirty(true);
m_blockDirtyChanged = false;
return true;
@@ -199,12 +198,12 @@ bool ResourceEditorDocument::setContents(const QByteArray &contents)
return false;
const QString originalFileName = m_model->fileName();
- m_model->setFileName(saver.fileName());
+ m_model->setFileName(saver.filePath().toString());
const bool success = (m_model->reload() == OpenResult::Success);
m_model->setFileName(originalFileName);
m_shouldAutoSave = false;
if (debugResourceEditorW)
- qDebug() << "ResourceEditorW::createNew: " << contents << " (" << saver.fileName() << ") returns " << success;
+ qDebug() << "ResourceEditorW::createNew: " << contents << " (" << saver.filePath() << ") returns " << success;
emit loaded(success);
return success;
}
@@ -272,8 +271,7 @@ bool ResourceEditorDocument::reload(QString *errorString, ReloadFlag flag, Chang
if (flag == FlagIgnore)
return true;
emit aboutToReload();
- QString fn = filePath().toString();
- const bool success = (open(errorString, fn, fn) == OpenResult::Success);
+ const bool success = (open(errorString, filePath(), filePath()) == OpenResult::Success);
emit reloadFinished(success);
return success;
}
diff --git a/src/plugins/resourceeditor/resourceeditorw.h b/src/plugins/resourceeditor/resourceeditorw.h
index 55fd3bfab5..628c6b138e 100644
--- a/src/plugins/resourceeditor/resourceeditorw.h
+++ b/src/plugins/resourceeditor/resourceeditorw.h
@@ -51,9 +51,9 @@ public:
ResourceEditorDocument(QObject *parent = nullptr);
//IDocument
- OpenResult open(QString *errorString, const QString &fileName,
- const QString &realFileName) override;
- bool save(QString *errorString, const QString &fileName, bool autoSave) override;
+ OpenResult open(QString *errorString, const Utils::FilePath &filePath,
+ const Utils::FilePath &realFilePath) override;
+ bool save(QString *errorString, const Utils::FilePath &filePath, bool autoSave) override;
QString plainText() const;
QByteArray contents() const override;
bool setContents(const QByteArray &contents) override;
diff --git a/src/plugins/resourceeditor/resourcenode.cpp b/src/plugins/resourceeditor/resourcenode.cpp
index 88c04bbfc2..7b57a6eabf 100644
--- a/src/plugins/resourceeditor/resourcenode.cpp
+++ b/src/plugins/resourceeditor/resourcenode.cpp
@@ -243,7 +243,7 @@ ResourceTopLevelNode::ResourceTopLevelNode(const FilePath &filePath,
const QString &contents)
: FolderNode(filePath)
{
- setIcon(FileIconProvider::icon(filePath.toFileInfo()));
+ setIcon([filePath] { return FileIconProvider::icon(filePath.toFileInfo()); });
setPriority(Node::DefaultFilePriority);
setListInProject(true);
setAddFileFilter("*.png; *.jpg; *.gif; *.svg; *.ico; *.qml; *.qml.ui");
diff --git a/src/plugins/scxmleditor/common/navigatorgraphicsview.cpp b/src/plugins/scxmleditor/common/navigatorgraphicsview.cpp
index e49aaaefca..654d6695d9 100644
--- a/src/plugins/scxmleditor/common/navigatorgraphicsview.cpp
+++ b/src/plugins/scxmleditor/common/navigatorgraphicsview.cpp
@@ -80,11 +80,7 @@ void NavigatorGraphicsView::wheelEvent(QWheelEvent *event)
else
emit zoomOut();
-#if QT_VERSION < QT_VERSION_CHECK(5, 14, 0)
- emit moveMainViewTo(mapToScene(event->pos()));
-#else
emit moveMainViewTo(mapToScene(event->position().toPoint()));
-#endif
} else
QGraphicsView::wheelEvent(event);
}
diff --git a/src/plugins/scxmleditor/plugin_interface/sceneutils.cpp b/src/plugins/scxmleditor/plugin_interface/sceneutils.cpp
index d90dbabe95..97fd56c7f6 100644
--- a/src/plugins/scxmleditor/plugin_interface/sceneutils.cpp
+++ b/src/plugins/scxmleditor/plugin_interface/sceneutils.cpp
@@ -225,11 +225,7 @@ void layout(const QList<QGraphicsItem*> &items)
firstItem = initialItem->outputTransitions().constFirst()->connectedItem(initialItem);
int index = childItems.indexOf(firstItem);
if (index > 0)
-#if QT_VERSION < QT_VERSION_CHECK(5, 13, 0)
- childItems.swap(index, 0);
-#else
childItems.swapItemsAt(index, 0);
-#endif
}
// Search final-item
diff --git a/src/plugins/scxmleditor/plugin_interface/transitionitem.cpp b/src/plugins/scxmleditor/plugin_interface/transitionitem.cpp
index 307af62f6f..84c3d66683 100644
--- a/src/plugins/scxmleditor/plugin_interface/transitionitem.cpp
+++ b/src/plugins/scxmleditor/plugin_interface/transitionitem.cpp
@@ -306,19 +306,11 @@ void TransitionItem::mousePressEvent(QGraphicsSceneMouseEvent *event)
QPointF intersPoint;
QLineF line2(p, p + QPointF(SELECTION_DISTANCE, SELECTION_DISTANCE));
line2.setAngle(line.angle() + 90);
-#if QT_VERSION < QT_VERSION_CHECK(5, 14, 0)
- if (line.intersect(line2, &intersPoint) == QLineF::BoundedIntersection)
-#else
- if (line.intersects(line2, &intersPoint) == QLineF::BoundedIntersection)
-#endif
+ if (line.intersects(line2, &intersPoint) == QLineF::BoundedIntersection) {
sel = true;
- else {
+ } else {
line2.setAngle(line.angle() - 90);
-#if QT_VERSION < QT_VERSION_CHECK(5, 14, 0)
- sel = line.intersect(line2, &intersPoint) == QLineF::BoundedIntersection;
-#else
sel = line.intersects(line2, &intersPoint) == QLineF::BoundedIntersection;
-#endif
}
if (sel)
@@ -805,11 +797,7 @@ QPointF TransitionItem::findIntersectionPoint(ConnectableItem *item, const QLine
for (int i = 1; i < itemPolygon.count(); ++i) {
p2 = itemPolygon.at(i) + item->scenePos();
checkLine = QLineF(p1, p2);
-#if QT_VERSION < QT_VERSION_CHECK(5, 14, 0)
- if (checkLine.intersect(line, &intersectPoint) == QLineF::BoundedIntersection)
-#else
if (checkLine.intersects(line, &intersectPoint) == QLineF::BoundedIntersection)
-#endif
return intersectPoint;
p1 = p2;
}
@@ -1096,19 +1084,11 @@ bool TransitionItem::containsScenePoint(const QPointF &p) const
QPointF intersPoint;
QLineF line2(pp, pp + QPointF(SELECTION_DISTANCE, SELECTION_DISTANCE));
line2.setAngle(line.angle() + 90);
-#if QT_VERSION < QT_VERSION_CHECK(5, 14, 0)
- if (line.intersect(line2, &intersPoint) == QLineF::BoundedIntersection) {
-#else
if (line.intersects(line2, &intersPoint) == QLineF::BoundedIntersection) {
-#endif
return true;
} else {
line2.setAngle(line.angle() - 90);
-#if QT_VERSION < QT_VERSION_CHECK(5, 14, 0)
- if (line.intersect(line2, &intersPoint) == QLineF::BoundedIntersection)
-#else
if (line.intersects(line2, &intersPoint) == QLineF::BoundedIntersection)
-#endif
return true;
}
}
diff --git a/src/plugins/scxmleditor/scxmleditordocument.cpp b/src/plugins/scxmleditor/scxmleditordocument.cpp
index 10acfe24c5..22cf828589 100644
--- a/src/plugins/scxmleditor/scxmleditordocument.cpp
+++ b/src/plugins/scxmleditor/scxmleditordocument.cpp
@@ -57,32 +57,33 @@ ScxmlEditorDocument::ScxmlEditorDocument(MainWidget *designWidget, QObject *pare
});
}
-Core::IDocument::OpenResult ScxmlEditorDocument::open(QString *errorString, const QString &fileName, const QString &realFileName)
+Core::IDocument::OpenResult ScxmlEditorDocument::open(QString *errorString,
+ const Utils::FilePath &filePath,
+ const Utils::FilePath &realFilePath)
{
- Q_UNUSED(realFileName)
+ Q_UNUSED(realFilePath)
- if (fileName.isEmpty())
+ if (filePath.isEmpty())
return OpenResult::ReadError;
if (!m_designWidget)
return OpenResult::ReadError;
- const QFileInfo fi(fileName);
- const QString absfileName = fi.absoluteFilePath();
- if (!m_designWidget->load(absfileName)) {
+ const FilePath &absoluteFilePath = filePath.absoluteFilePath();
+ if (!m_designWidget->load(absoluteFilePath.toString())) {
*errorString = m_designWidget->errorMessage();
return OpenResult::ReadError;
}
- setFilePath(Utils::FilePath::fromString(absfileName));
+ setFilePath(absoluteFilePath);
return OpenResult::Success;
}
-bool ScxmlEditorDocument::save(QString *errorString, const QString &name, bool autoSave)
+bool ScxmlEditorDocument::save(QString *errorString, const FilePath &filePath, bool autoSave)
{
- const FilePath oldFileName = filePath();
- const FilePath actualName = name.isEmpty() ? oldFileName : FilePath::fromString(name);
+ const FilePath oldFileName = this->filePath();
+ const FilePath actualName = filePath.isEmpty() ? oldFileName : filePath;
if (actualName.isEmpty())
return false;
bool dirty = m_designWidget->isDirty();
diff --git a/src/plugins/scxmleditor/scxmleditordocument.h b/src/plugins/scxmleditor/scxmleditordocument.h
index 537c7eb027..587343a70b 100644
--- a/src/plugins/scxmleditor/scxmleditordocument.h
+++ b/src/plugins/scxmleditor/scxmleditordocument.h
@@ -49,8 +49,10 @@ public:
explicit ScxmlEditorDocument(Common::MainWidget *designWidget, QObject *parent = nullptr);
// IDocument
- OpenResult open(QString *errorString, const QString &fileName, const QString &realFileName) override;
- bool save(QString *errorString, const QString &fileName, bool autoSave) override;
+ OpenResult open(QString *errorString,
+ const Utils::FilePath &filePath,
+ const Utils::FilePath &realFilePath) override;
+ bool save(QString *errorString, const Utils::FilePath &filePath, bool autoSave) override;
bool shouldAutoSave() const override;
bool isSaveAsAllowed() const override;
bool isModified() const override;
diff --git a/src/plugins/studiowelcome/examplecheckout.cpp b/src/plugins/studiowelcome/examplecheckout.cpp
index c7180155d8..17cc306b36 100644
--- a/src/plugins/studiowelcome/examplecheckout.cpp
+++ b/src/plugins/studiowelcome/examplecheckout.cpp
@@ -65,8 +65,8 @@ void ExampleCheckout::checkoutExample(const QUrl &url)
layout->addWidget(widget);
widget->engine()->addImportPath("qrc:/studiofonts");
- widget->engine()->addImportPath(Core::ICore::resourcePath()
- + "/qmldesigner/propertyEditorQmlSources/imports");
+ widget->engine()->addImportPath(
+ Core::ICore::resourcePath("/qmldesigner/propertyEditorQmlSources/imports").toString());
widget->setSource(QUrl("qrc:/qml/downloaddialog/main.qml"));
diff --git a/src/plugins/studiowelcome/studiowelcomeplugin.cpp b/src/plugins/studiowelcome/studiowelcomeplugin.cpp
index 0129b0e226..55400a3a01 100644
--- a/src/plugins/studiowelcome/studiowelcomeplugin.cpp
+++ b/src/plugins/studiowelcome/studiowelcomeplugin.cpp
@@ -207,12 +207,11 @@ public:
return;
}
- const QString projectFile = Core::ICore::resourcePath() + "/examples/" + example + "/"
- + example + ".qmlproject";
-
- ProjectExplorer::ProjectExplorerPlugin::openProjectWelcomePage(projectFile);
- const QString qmlFile = Core::ICore::resourcePath() + "/examples/" + example + "/"
- + formFile;
+ const Utils::FilePath projectFile = Core::ICore::resourcePath("examples")
+ / example / example + ".qmlproject";
+ ProjectExplorer::ProjectExplorerPlugin::openProjectWelcomePage(projectFile.toString());
+ const Utils::FilePath qmlFile = Core::ICore::resourcePath("examples")
+ / example / formFile;
Core::EditorManager::openEditor(qmlFile);
}
diff --git a/src/plugins/subversion/CMakeLists.txt b/src/plugins/subversion/CMakeLists.txt
index 4d225e5782..816d0089e9 100644
--- a/src/plugins/subversion/CMakeLists.txt
+++ b/src/plugins/subversion/CMakeLists.txt
@@ -2,7 +2,6 @@ add_qtc_plugin(Subversion
PLUGIN_DEPENDS Core DiffEditor TextEditor VcsBase
SOURCES
annotationhighlighter.cpp annotationhighlighter.h
- settingspage.cpp settingspage.h settingspage.ui
subversionclient.cpp subversionclient.h
subversionconstants.h
subversioneditor.cpp subversioneditor.h
diff --git a/src/plugins/subversion/settingspage.cpp b/src/plugins/subversion/settingspage.cpp
deleted file mode 100644
index 2ee4aaad5c..0000000000
--- a/src/plugins/subversion/settingspage.cpp
+++ /dev/null
@@ -1,114 +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 "settingspage.h"
-
-#include "subversionclient.h"
-#include "subversionplugin.h"
-#include "subversionsettings.h"
-
-#include "ui_settingspage.h"
-
-#include <coreplugin/icore.h>
-#include <extensionsystem/pluginmanager.h>
-#include <vcsbase/vcsbaseconstants.h>
-#include <utils/pathchooser.h>
-
-#include <QCoreApplication>
-
-using namespace Utils;
-using namespace VcsBase;
-
-namespace Subversion {
-namespace Internal {
-
-class SubversionSettingsPageWidget final : public Core::IOptionsPageWidget
-{
- Q_DECLARE_TR_FUNCTIONS(Subversion::Internal::SettingsPageWidget)
-
-public:
- SubversionSettingsPageWidget(const std::function<void()> &onApply, SubversionSettings *settings);
-
- void apply() final;
-
-private:
- Ui::SettingsPage m_ui;
- std::function<void()> m_onApply;
- SubversionSettings *m_settings;
-};
-
-SubversionSettingsPageWidget::SubversionSettingsPageWidget(const std::function<void()> &onApply,
- SubversionSettings *settings)
- : m_onApply(onApply), m_settings(settings)
-{
- m_ui.setupUi(this);
- m_ui.pathChooser->setExpectedKind(PathChooser::ExistingCommand);
- m_ui.pathChooser->setHistoryCompleter(QLatin1String("Subversion.Command.History"));
- m_ui.pathChooser->setPromptDialogTitle(tr("Subversion Command"));
-
- SubversionSettings &s = *m_settings;
- m_ui.pathChooser->setFilePath(s.binaryPath());
- m_ui.usernameLineEdit->setText(s.stringValue(SubversionSettings::userKey));
- m_ui.passwordLineEdit->setText(s.stringValue(SubversionSettings::passwordKey));
- m_ui.userGroupBox->setChecked(s.boolValue(SubversionSettings::useAuthenticationKey));
- m_ui.timeOutSpinBox->setValue(s.intValue(SubversionSettings::timeoutKey));
- m_ui.promptToSubmitCheckBox->setChecked(s.boolValue(SubversionSettings::promptOnSubmitKey));
- m_ui.spaceIgnorantAnnotationCheckBox->setChecked(
- s.boolValue(SubversionSettings::spaceIgnorantAnnotationKey));
- m_ui.logCountSpinBox->setValue(s.intValue(SubversionSettings::logCountKey));
-}
-
-void SubversionSettingsPageWidget::apply()
-{
- SubversionSettings rc = *m_settings;
- rc.setValue(SubversionSettings::binaryPathKey, m_ui.pathChooser->rawPath());
- rc.setValue(SubversionSettings::useAuthenticationKey, m_ui.userGroupBox->isChecked());
- rc.setValue(SubversionSettings::userKey, m_ui.usernameLineEdit->text());
- rc.setValue(SubversionSettings::passwordKey, m_ui.passwordLineEdit->text());
- rc.setValue(SubversionSettings::timeoutKey, m_ui.timeOutSpinBox->value());
- if (rc.stringValue(SubversionSettings::userKey).isEmpty())
- rc.setValue(SubversionSettings::useAuthenticationKey, false);
- rc.setValue(SubversionSettings::promptOnSubmitKey, m_ui.promptToSubmitCheckBox->isChecked());
- rc.setValue(SubversionSettings::spaceIgnorantAnnotationKey,
- m_ui.spaceIgnorantAnnotationCheckBox->isChecked());
- rc.setValue(SubversionSettings::logCountKey, m_ui.logCountSpinBox->value());
-
- if (rc == *m_settings)
- return;
-
- *m_settings = rc;
- m_onApply();
-}
-
-SubversionSettingsPage::SubversionSettingsPage(const std::function<void()> &onApply, SubversionSettings *settings)
-{
- setId(VcsBase::Constants::VCS_ID_SUBVERSION);
- setDisplayName(SubversionSettingsPageWidget::tr("Subversion"));
- setCategory(VcsBase::Constants::VCS_SETTINGS_CATEGORY);
- setWidgetCreator([onApply, settings] { return new SubversionSettingsPageWidget(onApply, settings); });
-}
-
-} // Internal
-} // Subversion
diff --git a/src/plugins/subversion/settingspage.h b/src/plugins/subversion/settingspage.h
deleted file mode 100644
index 9778dfb2c4..0000000000
--- a/src/plugins/subversion/settingspage.h
+++ /dev/null
@@ -1,42 +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 <coreplugin/dialogs/ioptionspage.h>
-
-namespace Subversion {
-namespace Internal {
-
-class SubversionSettings;
-
-class SubversionSettingsPage final : public Core::IOptionsPage
-{
-public:
- SubversionSettingsPage(const std::function<void()> &onApply, SubversionSettings *settings);
-};
-
-} // namespace Subversion
-} // namespace Internal
diff --git a/src/plugins/subversion/settingspage.ui b/src/plugins/subversion/settingspage.ui
deleted file mode 100644
index f2a9bc0691..0000000000
--- a/src/plugins/subversion/settingspage.ui
+++ /dev/null
@@ -1,180 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<ui version="4.0">
- <class>Subversion::Internal::SettingsPage</class>
- <widget class="QWidget" name="Subversion::Internal::SettingsPage">
- <property name="geometry">
- <rect>
- <x>0</x>
- <y>0</y>
- <width>665</width>
- <height>359</height>
- </rect>
- </property>
- <layout class="QVBoxLayout" name="verticalLayout">
- <item>
- <widget class="QGroupBox" name="generalGroupBox">
- <property name="title">
- <string>Configuration</string>
- </property>
- <layout class="QFormLayout" name="formLayout_3">
- <property name="fieldGrowthPolicy">
- <enum>QFormLayout::ExpandingFieldsGrow</enum>
- </property>
- <item row="0" column="0">
- <widget class="QLabel" name="commandLabel">
- <property name="text">
- <string>Subversion command:</string>
- </property>
- </widget>
- </item>
- <item row="0" column="1">
- <widget class="Utils::PathChooser" name="pathChooser" native="true"/>
- </item>
- </layout>
- </widget>
- </item>
- <item>
- <widget class="QGroupBox" name="userGroupBox">
- <property name="title">
- <string>Authentication</string>
- </property>
- <property name="checkable">
- <bool>true</bool>
- </property>
- <layout class="QFormLayout" name="formLayout">
- <property name="fieldGrowthPolicy">
- <enum>QFormLayout::ExpandingFieldsGrow</enum>
- </property>
- <item row="0" column="0">
- <widget class="QLabel" name="usernameLabel">
- <property name="text">
- <string>Username:</string>
- </property>
- </widget>
- </item>
- <item row="0" column="1">
- <widget class="QLineEdit" name="usernameLineEdit"/>
- </item>
- <item row="1" column="0">
- <widget class="QLabel" name="passwordLabel">
- <property name="text">
- <string>Password:</string>
- </property>
- </widget>
- </item>
- <item row="1" column="1">
- <widget class="QLineEdit" name="passwordLineEdit">
- <property name="echoMode">
- <enum>QLineEdit::Password</enum>
- </property>
- </widget>
- </item>
- </layout>
- </widget>
- </item>
- <item>
- <widget class="QGroupBox" name="miscGroupBox">
- <property name="title">
- <string>Miscellaneous</string>
- </property>
- <layout class="QGridLayout" name="gridLayout">
- <item row="0" column="0">
- <widget class="QLabel" name="logCountLabel">
- <property name="text">
- <string>Log count:</string>
- </property>
- </widget>
- </item>
- <item row="0" column="1">
- <widget class="QSpinBox" name="logCountSpinBox">
- <property name="maximum">
- <number>10000</number>
- </property>
- <property name="value">
- <number>1000</number>
- </property>
- </widget>
- </item>
- <item row="0" column="2">
- <widget class="QLabel" name="timeOutLabel">
- <property name="text">
- <string>Timeout:</string>
- </property>
- </widget>
- </item>
- <item row="0" column="3">
- <widget class="QSpinBox" name="timeOutSpinBox">
- <property name="suffix">
- <string>s</string>
- </property>
- <property name="minimum">
- <number>1</number>
- </property>
- <property name="maximum">
- <number>360</number>
- </property>
- <property name="value">
- <number>30</number>
- </property>
- </widget>
- </item>
- <item row="0" column="4">
- <spacer name="horizontalSpacer">
- <property name="orientation">
- <enum>Qt::Horizontal</enum>
- </property>
- <property name="sizeHint" stdset="0">
- <size>
- <width>127</width>
- <height>20</height>
- </size>
- </property>
- </spacer>
- </item>
- <item row="1" column="0" colspan="2">
- <widget class="QCheckBox" name="promptToSubmitCheckBox">
- <property name="text">
- <string>Prompt on submit</string>
- </property>
- </widget>
- </item>
- <item row="2" column="0" colspan="4">
- <widget class="QCheckBox" name="spaceIgnorantAnnotationCheckBox">
- <property name="text">
- <string>Ignore whitespace changes in annotation</string>
- </property>
- </widget>
- </item>
- </layout>
- </widget>
- </item>
- <item>
- <spacer name="verticalSpacer">
- <property name="orientation">
- <enum>Qt::Vertical</enum>
- </property>
- <property name="sizeHint" stdset="0">
- <size>
- <width>20</width>
- <height>40</height>
- </size>
- </property>
- </spacer>
- </item>
- </layout>
- </widget>
- <customwidgets>
- <customwidget>
- <class>Utils::PathChooser</class>
- <extends>QWidget</extends>
- <header location="global">utils/pathchooser.h</header>
- <container>1</container>
- <slots>
- <signal>editingFinished()</signal>
- <signal>browsingFinished()</signal>
- </slots>
- </customwidget>
- </customwidgets>
- <resources/>
- <connections/>
-</ui>
diff --git a/src/plugins/subversion/subversion.pro b/src/plugins/subversion/subversion.pro
index b24824e43e..4bc77a5ba6 100644
--- a/src/plugins/subversion/subversion.pro
+++ b/src/plugins/subversion/subversion.pro
@@ -3,7 +3,6 @@ include(../../qtcreatorplugin.pri)
HEADERS += annotationhighlighter.h \
subversionplugin.h \
subversionclient.h \
- settingspage.h \
subversioneditor.h \
subversionsubmiteditor.h \
subversionsettings.h \
@@ -12,9 +11,6 @@ HEADERS += annotationhighlighter.h \
SOURCES += annotationhighlighter.cpp \
subversionplugin.cpp \
subversionclient.cpp \
- settingspage.cpp \
subversioneditor.cpp \
subversionsubmiteditor.cpp \
subversionsettings.cpp
-
-FORMS += settingspage.ui
diff --git a/src/plugins/subversion/subversion.qbs b/src/plugins/subversion/subversion.qbs
index 4ae10db96b..3c36fa8bcc 100644
--- a/src/plugins/subversion/subversion.qbs
+++ b/src/plugins/subversion/subversion.qbs
@@ -14,9 +14,6 @@ QtcPlugin {
files: [
"annotationhighlighter.cpp",
"annotationhighlighter.h",
- "settingspage.cpp",
- "settingspage.h",
- "settingspage.ui",
"subversionclient.cpp",
"subversionclient.h",
"subversionconstants.h",
diff --git a/src/plugins/subversion/subversionclient.cpp b/src/plugins/subversion/subversionclient.cpp
index a8c0428e1a..e7dc99f001 100644
--- a/src/plugins/subversion/subversionclient.cpp
+++ b/src/plugins/subversion/subversionclient.cpp
@@ -28,20 +28,22 @@
#include "subversionplugin.h"
#include "subversionsettings.h"
+#include <coreplugin/editormanager/editormanager.h>
+
#include <vcsbase/vcscommand.h>
#include <vcsbase/vcsbaseconstants.h>
#include <vcsbase/vcsbasediffeditorcontroller.h>
#include <vcsbase/vcsbaseeditor.h>
#include <vcsbase/vcsbaseeditorconfig.h>
#include <vcsbase/vcsbaseplugin.h>
-#include <utils/qtcassert.h>
-#include <utils/synchronousprocess.h>
+
#include <diffeditor/diffeditorcontroller.h>
#include <diffeditor/diffutils.h>
-#include <coreplugin/editormanager/editormanager.h>
#include <utils/algorithm.h>
#include <utils/hostosinfo.h>
+#include <utils/qtcassert.h>
+#include <utils/qtcprocess.h>
#include <QDir>
#include <QFileInfo>
@@ -60,12 +62,12 @@ class SubversionLogConfig : public VcsBaseEditorConfig
{
Q_OBJECT
public:
- SubversionLogConfig(VcsBaseClientSettings &settings, QToolBar *toolBar) :
+ SubversionLogConfig(SubversionSettings &settings, QToolBar *toolBar) :
VcsBaseEditorConfig(toolBar)
{
- mapSetting(addToggleButton(QLatin1String("--verbose"), tr("Verbose"),
+ mapSetting(addToggleButton("--verbose", tr("Verbose"),
tr("Show files changed in each revision")),
- settings.boolPointer(SubversionSettings::logVerboseKey));
+ &settings.logVerbose);
}
};
@@ -83,16 +85,16 @@ bool SubversionClient::doCommit(const QString &repositoryRoot,
{
const QStringList svnExtraOptions =
QStringList(extraOptions)
- << SubversionClient::addAuthenticationOptions(settings())
+ << SubversionClient::addAuthenticationOptions(static_cast<SubversionSettings &>(settings()))
<< QLatin1String(Constants::NON_INTERACTIVE_OPTION)
<< QLatin1String("--encoding") << QLatin1String("UTF-8")
<< QLatin1String("--file") << commitMessageFile;
QStringList args(vcsCommandString(CommitCommand));
- SynchronousProcessResponse resp =
- vcsSynchronousExec(repositoryRoot, args << svnExtraOptions << escapeFiles(files),
- VcsCommand::ShowStdOut | VcsCommand::NoFullySync);
- return resp.result == SynchronousProcessResponse::Finished;
+ SynchronousProcess proc;
+ vcsSynchronousExec(proc, repositoryRoot, args << svnExtraOptions << escapeFiles(files),
+ VcsCommand::ShowStdOut | VcsCommand::NoFullySync);
+ return proc.result() == QtcProcess::Finished;
}
void SubversionClient::commit(const QString &repositoryRoot,
@@ -117,13 +119,13 @@ Id SubversionClient::vcsEditorKind(VcsCommandTag cmd) const
}
// Add authorization options to the command line arguments.
-QStringList SubversionClient::addAuthenticationOptions(const VcsBaseClientSettings &settings)
+QStringList SubversionClient::addAuthenticationOptions(const SubversionSettings &settings)
{
- if (!static_cast<const SubversionSettings &>(settings).hasAuthentication())
+ if (!settings.hasAuthentication())
return QStringList();
- const QString userName = settings.stringValue(SubversionSettings::userKey);
- const QString password = settings.stringValue(SubversionSettings::passwordKey);
+ const QString userName = settings.userName.value();
+ const QString password = settings.password.value();
if (userName.isEmpty())
return QStringList();
@@ -149,12 +151,12 @@ QString SubversionClient::synchronousTopic(const QString &repository) const
else
svnVersionBinary = svnVersionBinary.left(pos + 1);
svnVersionBinary.append(HostOsInfo::withExecutableSuffix("svnversion"));
- const SynchronousProcessResponse result
- = vcsFullySynchronousExec(repository, {svnVersionBinary, args});
- if (result.result != SynchronousProcessResponse::Finished)
+ SynchronousProcess proc;
+ vcsFullySynchronousExec(proc, repository, {svnVersionBinary, args});
+ if (proc.result() != QtcProcess::Finished)
return QString();
- return result.stdOut().trimmed();
+ return proc.stdOut().trimmed();
}
QString SubversionClient::escapeFile(const QString &file)
@@ -260,13 +262,14 @@ SubversionDiffEditorController *SubversionClient::findOrCreateDiffEditor(const Q
const QString &title,
const QString &workingDirectory)
{
+ auto &settings = static_cast<SubversionSettings &>(this->settings());
IDocument *document = DiffEditorController::findOrCreateDocument(documentId, title);
auto controller = qobject_cast<SubversionDiffEditorController *>(
DiffEditorController::controller(document));
if (!controller) {
- controller = new SubversionDiffEditorController(document, addAuthenticationOptions(settings()));
- controller->setVcsBinary(settings().binaryPath());
- controller->setVcsTimeoutS(settings().vcsTimeoutS());
+ controller = new SubversionDiffEditorController(document, addAuthenticationOptions(settings));
+ controller->setVcsBinary(settings.binaryPath.filePath());
+ controller->setVcsTimeoutS(settings.timeout.value());
controller->setProcessEnvironment(processEnvironment());
controller->setWorkingDirectory(workingDirectory);
}
@@ -295,10 +298,10 @@ void SubversionClient::log(const QString &workingDir,
const QStringList &extraOptions,
bool enableAnnotationContextMenu)
{
- const auto logCount = settings().intValue(SubversionSettings::logCountKey);
- QStringList svnExtraOptions =
- QStringList(extraOptions)
- << SubversionClient::addAuthenticationOptions(settings());
+ auto &settings = static_cast<SubversionSettings &>(this->settings());
+ const int logCount = settings.logCount.value();
+ QStringList svnExtraOptions = extraOptions;
+ svnExtraOptions.append(SubversionClient::addAuthenticationOptions(settings));
if (logCount > 0)
svnExtraOptions << QLatin1String("-l") << QString::number(logCount);
diff --git a/src/plugins/subversion/subversionclient.h b/src/plugins/subversion/subversionclient.h
index 705efbc273..7d7ec85b36 100644
--- a/src/plugins/subversion/subversionclient.h
+++ b/src/plugins/subversion/subversionclient.h
@@ -64,7 +64,7 @@ public:
void describe(const QString &workingDirectory, int changeNumber, const QString &title);
// Add authorization options to the command line arguments.
- static QStringList addAuthenticationOptions(const VcsBase::VcsBaseClientSettings &settings);
+ static QStringList addAuthenticationOptions(const SubversionSettings &settings);
QString synchronousTopic(const QString &repository) const;
diff --git a/src/plugins/subversion/subversionplugin.cpp b/src/plugins/subversion/subversionplugin.cpp
index 3beb8d28fc..e662fc7ec2 100644
--- a/src/plugins/subversion/subversionplugin.cpp
+++ b/src/plugins/subversion/subversionplugin.cpp
@@ -25,7 +25,6 @@
#include "subversionplugin.h"
-#include "settingspage.h"
#include "subversioneditor.h"
#include "subversionsubmiteditor.h"
@@ -58,8 +57,8 @@
#include <utils/hostosinfo.h>
#include <utils/parameteraction.h>
#include <utils/qtcassert.h>
+#include <utils/qtcprocess.h>
#include <utils/stringutils.h>
-#include <utils/synchronousprocess.h>
#include <QDebug>
#include <QDir>
@@ -322,7 +321,7 @@ private:
QAction *m_menuAction = nullptr;
bool m_submitActionTriggered = false;
- SubversionSettingsPage m_settingsPage{[this] { configurationChanged(); }, &m_settings};
+ SubversionSettingsPage m_settingsPage{&m_settings};
public:
VcsSubmitEditorFactory submitEditorFactory {
@@ -403,6 +402,7 @@ SubversionPluginPrivate::SubversionPluginPrivate()
const QString prefix = QLatin1String("svn");
m_commandLocator = new CommandLocator("Subversion", prefix, prefix, this);
+ m_commandLocator->setDescription(tr("Triggers a Subversion version control operation."));
// Register actions
ActionContainer *toolsContainer = ActionManager::actionContainer(M_TOOLS);
@@ -557,6 +557,8 @@ SubversionPluginPrivate::SubversionPluginPrivate()
connect(m_revertRepositoryAction, &QAction::triggered, this, &SubversionPluginPrivate::revertAll);
subversionMenu->addAction(command);
m_commandLocator->appendCommand(command);
+
+ connect(&m_settings, &AspectContainer::applied, this, &IVersionControl::configurationChanged);
}
bool SubversionPluginPrivate::isVcsDirectory(const FilePath &fileName) const
@@ -592,8 +594,7 @@ bool SubversionPluginPrivate::submitEditorAboutToClose()
// Prompt user. Force a prompt unless submit was actually invoked (that
// is, the editor was closed or shutdown).
const VcsBaseSubmitEditor::PromptSubmitResult answer = editor->promptSubmit(
- this, m_settings.boolPointer(SubversionSettings::promptOnSubmitKey),
- !m_submitActionTriggered);
+ this, nullptr, !m_submitActionTriggered, true, &m_settings.promptOnSubmit);
m_submitActionTriggered = false;
switch (answer) {
case VcsBaseSubmitEditor::SubmitCanceled:
@@ -691,7 +692,7 @@ void SubversionPluginPrivate::revertAll()
args << SubversionClient::addAuthenticationOptions(m_settings);
args << QLatin1String("--recursive") << state.topLevel();
const SubversionResponse revertResponse
- = runSvn(state.topLevel(), args, m_settings.vcsTimeoutS(),
+ = runSvn(state.topLevel(), args, m_settings.timeout.value(),
VcsCommand::SshPasswordPrompt | VcsCommand::ShowStdOut);
if (revertResponse.error)
QMessageBox::warning(ICore::dialogParent(), title,
@@ -710,7 +711,7 @@ void SubversionPluginPrivate::revertCurrentFile()
args.push_back(SubversionClient::escapeFile(state.relativeCurrentFile()));
const SubversionResponse diffResponse
- = runSvn(state.currentFileTopLevel(), args, m_settings.vcsTimeoutS(), 0);
+ = runSvn(state.currentFileTopLevel(), args, m_settings.timeout.value(), 0);
if (diffResponse.error)
return;
@@ -731,7 +732,7 @@ void SubversionPluginPrivate::revertCurrentFile()
args << SubversionClient::escapeFile(state.relativeCurrentFile());
const SubversionResponse revertResponse
- = runSvn(state.currentFileTopLevel(), args, m_settings.vcsTimeoutS(),
+ = runSvn(state.currentFileTopLevel(), args, m_settings.timeout.value(),
VcsCommand::SshPasswordPrompt | VcsCommand::ShowStdOut);
if (!revertResponse.error)
@@ -797,7 +798,7 @@ void SubversionPluginPrivate::startCommit(const QString &workingDir, const QStri
args += SubversionClient::escapeFiles(files);
const SubversionResponse response
- = runSvn(workingDir, args, m_settings.vcsTimeoutS(), 0);
+ = runSvn(workingDir, args, m_settings.timeout.value(), 0);
if (response.error)
return;
@@ -819,7 +820,7 @@ void SubversionPluginPrivate::startCommit(const QString &workingDir, const QStri
VcsOutputWindow::appendError(saver.errorString());
return;
}
- m_commitMessageFileName = saver.fileName();
+ m_commitMessageFileName = saver.filePath().toString();
// Create a submit editor and set file list
SubversionSubmitEditor *editor = openSubversionSubmitEditor(m_commitMessageFileName);
QTC_ASSERT(editor, return);
@@ -877,7 +878,7 @@ void SubversionPluginPrivate::svnStatus(const QString &workingDir, const QString
if (!relativePath.isEmpty())
args.append(SubversionClient::escapeFile(relativePath));
VcsOutputWindow::setRepository(workingDir);
- runSvn(workingDir, args, m_settings.vcsTimeoutS(),
+ runSvn(workingDir, args, m_settings.timeout.value(),
VcsCommand::ShowStdOut | VcsCommand::ShowSuccessMessage);
VcsOutputWindow::clearRepository();
}
@@ -904,7 +905,7 @@ void SubversionPluginPrivate::svnUpdate(const QString &workingDir, const QString
if (!relativePath.isEmpty())
args.append(relativePath);
const SubversionResponse response
- = runSvn(workingDir, args, 10 * m_settings.vcsTimeoutS(),
+ = runSvn(workingDir, args, 10 * m_settings.timeout.value(),
VcsCommand::SshPasswordPrompt | VcsCommand::ShowStdOut);
if (!response.error)
emit repositoryChanged(workingDir);
@@ -926,7 +927,7 @@ void SubversionPluginPrivate::vcsAnnotateHelper(const QString &workingDir, const
QStringList args(QLatin1String("annotate"));
args << SubversionClient::addAuthenticationOptions(m_settings);
- if (m_settings.boolValue(SubversionSettings::spaceIgnorantAnnotationKey))
+ if (m_settings.spaceIgnorantAnnotation.value())
args << QLatin1String("-x") << QLatin1String("-uw");
if (!revision.isEmpty())
args << QLatin1String("-r") << revision;
@@ -934,7 +935,7 @@ void SubversionPluginPrivate::vcsAnnotateHelper(const QString &workingDir, const
args.append(QDir::toNativeSeparators(SubversionClient::escapeFile(file)));
const SubversionResponse response
- = runSvn(workingDir, args, m_settings.vcsTimeoutS(),
+ = runSvn(workingDir, args, m_settings.timeout.value(),
VcsCommand::SshPasswordPrompt | VcsCommand::ForceCLocale, codec);
if (response.error)
return;
@@ -1019,20 +1020,20 @@ SubversionResponse SubversionPluginPrivate::runSvn(const QString &workingDir,
QTextCodec *outputCodec) const
{
SubversionResponse response;
- if (m_settings.binaryPath().isEmpty()) {
+ if (m_settings.binaryPath.value().isEmpty()) {
response.error = true;
response.message =tr("No subversion executable specified.");
return response;
}
- const SynchronousProcessResponse sp_resp
- = m_client->vcsFullySynchronousExec(workingDir, arguments, flags, timeOutS, outputCodec);
+ SynchronousProcess proc;
+ m_client->vcsFullySynchronousExec(proc, workingDir, arguments, flags, timeOutS, outputCodec);
- response.error = sp_resp.result != SynchronousProcessResponse::Finished;
+ response.error = proc.result() != QtcProcess::Finished;
if (response.error)
- response.message = sp_resp.exitMessage(m_settings.binaryPath().toString(), timeOutS);
- response.stdErr = sp_resp.stdErr();
- response.stdOut = sp_resp.stdOut();
+ response.message = proc.exitMessage();
+ response.stdErr = proc.stdErr();
+ response.stdOut = proc.stdOut();
return response;
}
@@ -1093,7 +1094,7 @@ bool SubversionPluginPrivate::vcsAdd(const QString &workingDir, const QString &r
<< SubversionClient::addAuthenticationOptions(m_settings)
<< QLatin1String("--parents") << file;
const SubversionResponse response
- = runSvn(workingDir, args, m_settings.vcsTimeoutS(),
+ = runSvn(workingDir, args, m_settings.timeout.value(),
VcsCommand::SshPasswordPrompt | VcsCommand::ShowStdOut);
return !response.error;
}
@@ -1108,7 +1109,7 @@ bool SubversionPluginPrivate::vcsDelete(const QString &workingDir, const QString
<< QLatin1String("--force") << file;
const SubversionResponse response
- = runSvn(workingDir, args, m_settings.vcsTimeoutS(),
+ = runSvn(workingDir, args, m_settings.timeout.value(),
VcsCommand::SshPasswordPrompt | VcsCommand::ShowStdOut);
return !response.error;
}
@@ -1120,7 +1121,7 @@ bool SubversionPluginPrivate::vcsMove(const QString &workingDir, const QString &
args << QDir::toNativeSeparators(SubversionClient::escapeFile(from))
<< QDir::toNativeSeparators(SubversionClient::escapeFile(to));
const SubversionResponse response
- = runSvn(workingDir, args, m_settings.vcsTimeoutS(),
+ = runSvn(workingDir, args, m_settings.timeout.value(),
VcsCommand::SshPasswordPrompt | VcsCommand::ShowStdOut
| VcsCommand::FullySynchronously);
return !response.error;
@@ -1149,7 +1150,7 @@ bool SubversionPluginPrivate::vcsCheckout(const QString &directory, const QByteA
args << QLatin1String(tempUrl.toEncoded()) << directory;
const SubversionResponse response
- = runSvn(directory, args, 10 * m_settings.vcsTimeoutS(), VcsCommand::SshPasswordPrompt);
+ = runSvn(directory, args, 10 * m_settings.timeout.value(), VcsCommand::SshPasswordPrompt);
return !response.error;
}
@@ -1184,7 +1185,7 @@ bool SubversionPluginPrivate::managesFile(const QString &workingDirectory, const
args << SubversionClient::addAuthenticationOptions(m_settings)
<< QDir::toNativeSeparators(SubversionClient::escapeFile(fileName));
SubversionResponse response
- = runSvn(workingDirectory, args, m_settings.vcsTimeoutS(), 0);
+ = runSvn(workingDirectory, args, m_settings.timeout.value(), 0);
return response.stdOut.isEmpty() || response.stdOut.at(0) != QLatin1Char('?');
}
@@ -1220,7 +1221,7 @@ bool SubversionPluginPrivate::isVcsFileOrDirectory(const Utils::FilePath &fileNa
bool SubversionPluginPrivate::isConfigured() const
{
- const Utils::FilePath binary = m_settings.binaryPath();
+ const FilePath binary = m_settings.binaryPath.filePath();
if (binary.isEmpty())
return false;
QFileInfo fi = binary.toFileInfo();
@@ -1293,7 +1294,7 @@ Core::ShellCommand *SubversionPluginPrivate::createInitialCheckoutCommand(const
args << extraArgs << url << localName;
auto command = new VcsBase::VcsCommand(baseDirectory.toString(), m_client->processEnvironment());
- command->addJob({m_settings.binaryPath(), args}, -1);
+ command->addJob({m_settings.binaryPath.filePath(), args}, -1);
return command;
}
diff --git a/src/plugins/subversion/subversionsettings.cpp b/src/plugins/subversion/subversionsettings.cpp
index 18c47e61d9..b720dfd5aa 100644
--- a/src/plugins/subversion/subversionsettings.cpp
+++ b/src/plugins/subversion/subversionsettings.cpp
@@ -25,38 +25,125 @@
#include "subversionsettings.h"
+#include "subversionclient.h"
+#include "subversionplugin.h"
+
+#include <coreplugin/icore.h>
+#include <coreplugin/dialogs/ioptionspage.h>
+
#include <utils/environment.h>
#include <utils/hostosinfo.h>
+#include <utils/layoutbuilder.h>
+#include <utils/pathchooser.h>
+
+#include <vcsbase/vcsbaseconstants.h>
#include <QSettings>
+using namespace Utils;
+using namespace VcsBase;
+
namespace Subversion {
namespace Internal {
-const QLatin1String SubversionSettings::useAuthenticationKey("Authentication");
-const QLatin1String SubversionSettings::userKey("User");
-const QLatin1String SubversionSettings::passwordKey("Password");
-const QLatin1String SubversionSettings::spaceIgnorantAnnotationKey("SpaceIgnorantAnnotation");
-const QLatin1String SubversionSettings::diffIgnoreWhiteSpaceKey("DiffIgnoreWhiteSpace");
-const QLatin1String SubversionSettings::logVerboseKey("LogVerbose");
+// SubversionSettings
SubversionSettings::SubversionSettings()
{
- setSettingsGroup(QLatin1String("Subversion"));
- declareKey(binaryPathKey, QLatin1String("svn" QTC_HOST_EXE_SUFFIX));
- declareKey(logCountKey, 1000);
- declareKey(useAuthenticationKey, false);
- declareKey(userKey, QString());
- declareKey(passwordKey, QString());
- declareKey(spaceIgnorantAnnotationKey, true);
- declareKey(diffIgnoreWhiteSpaceKey, false);
- declareKey(logVerboseKey, false);
+ setAutoApply(false);
+ setSettingsGroup("Subversion");
+
+ registerAspect(&binaryPath);
+ binaryPath.setDisplayStyle(StringAspect::PathChooserDisplay);
+ binaryPath.setExpectedKind(PathChooser::ExistingCommand);
+ binaryPath.setHistoryCompleter("Subversion.Command.History");
+ binaryPath.setDefaultValue("svn" QTC_HOST_EXE_SUFFIX);
+ binaryPath.setDisplayName(tr("Subversion Command"));
+ binaryPath.setLabelText(tr("Subversion command:"));
+
+ registerAspect(&useAuthentication);
+ useAuthentication.setSettingsKey("Authentication");
+ useAuthentication.setLabelPlacement(BoolAspect::LabelPlacement::AtCheckBoxWithoutDummyLabel);
+
+ registerAspect(&userName);
+ userName.setSettingsKey("User");
+ userName.setDisplayStyle(StringAspect::LineEditDisplay);
+ userName.setLabelText(tr("Username:"));
+
+ registerAspect(&password);
+ password.setSettingsKey("Password");
+ password.setDisplayStyle(StringAspect::LineEditDisplay);
+ password.setLabelText(tr("Password:"));
+
+ registerAspect(&spaceIgnorantAnnotation);
+ spaceIgnorantAnnotation.setSettingsKey("SpaceIgnorantAnnotation");
+ spaceIgnorantAnnotation.setDefaultValue(true);
+ spaceIgnorantAnnotation.setLabelText(tr("Ignore whitespace changes in annotation"));
+
+ registerAspect(&diffIgnoreWhiteSpace);
+ diffIgnoreWhiteSpace.setSettingsKey("DiffIgnoreWhiteSpace");
+
+ registerAspect(&logVerbose);
+ logVerbose.setSettingsKey("LogVerbose");
+
+ registerAspect(&logCount);
+ logCount.setDefaultValue(1000);
+ logCount.setLabelText(tr("Log count:"));
+
+ registerAspect(&timeout);
+ timeout.setLabelText(tr("Timeout:"));
+ timeout.setSuffix(tr("s"));
+
+ registerAspect(&promptOnSubmit);
+ promptOnSubmit.setLabelText(tr("Prompt on submit"));
+
+ QObject::connect(&useAuthentication, &BaseAspect::changed, [this] {
+ userName.setEnabled(useAuthentication.value());
+ password.setEnabled(useAuthentication.value());
+ });
}
bool SubversionSettings::hasAuthentication() const
{
- return boolValue(useAuthenticationKey) && !stringValue(userKey).isEmpty();
+ return useAuthentication.value() && !userName.value().isEmpty();
+}
+
+SubversionSettingsPage::SubversionSettingsPage(SubversionSettings *settings)
+{
+ setId(VcsBase::Constants::VCS_ID_SUBVERSION);
+ setDisplayName(SubversionSettings::tr("Subversion"));
+ setCategory(VcsBase::Constants::VCS_SETTINGS_CATEGORY);
+ setSettings(settings);
+
+ setLayouter([settings](QWidget *widget) {
+ SubversionSettings &s = *settings;
+ using namespace Layouting;
+
+ Column {
+ Group {
+ Title(SubversionSettings::tr("Configuration")),
+ s.binaryPath
+ },
+
+ Group {
+ Title(SubversionSettings::tr("Authentication"), &s.useAuthentication),
+ Form {
+ s.userName,
+ s.password,
+ }
+ },
+
+ Group {
+ Title(SubversionSettings::tr("Miscellaneous")),
+ Row { s.logCount, s.timeout, Stretch() },
+ s.promptOnSubmit,
+ s.spaceIgnorantAnnotation,
+ },
+
+ Stretch()
+ }.attachTo(widget);
+ });
}
-} // namespace Internal
-} // namespace Subversion
+} // Internal
+} // Subversion
diff --git a/src/plugins/subversion/subversionsettings.h b/src/plugins/subversion/subversionsettings.h
index 6b54c24c00..9e5c902435 100644
--- a/src/plugins/subversion/subversionsettings.h
+++ b/src/plugins/subversion/subversionsettings.h
@@ -25,23 +25,32 @@
#pragma once
+#include <coreplugin/dialogs/ioptionspage.h>
#include <vcsbase/vcsbaseclientsettings.h>
namespace Subversion {
namespace Internal {
-class SubversionSettings : public VcsBase::VcsBaseClientSettings
+class SubversionSettings : public VcsBase::VcsBaseSettings
{
-public:
- static const QLatin1String useAuthenticationKey;
- static const QLatin1String userKey;
- static const QLatin1String passwordKey;
- static const QLatin1String spaceIgnorantAnnotationKey;
- static const QLatin1String diffIgnoreWhiteSpaceKey;
- static const QLatin1String logVerboseKey;
+ Q_DECLARE_TR_FUNCTIONS(Subversion::Internal::SubversionSettings)
+public:
SubversionSettings();
+
bool hasAuthentication() const;
+
+ Utils::BoolAspect useAuthentication;
+ Utils::StringAspect password;
+ Utils::BoolAspect spaceIgnorantAnnotation;
+ Utils::BoolAspect diffIgnoreWhiteSpace;
+ Utils::BoolAspect logVerbose;
+};
+
+class SubversionSettingsPage final : public Core::IOptionsPage
+{
+public:
+ explicit SubversionSettingsPage(SubversionSettings *settings);
};
} // namespace Internal
diff --git a/src/plugins/texteditor/CMakeLists.txt b/src/plugins/texteditor/CMakeLists.txt
index 93d773ddb5..caaa4846b7 100644
--- a/src/plugins/texteditor/CMakeLists.txt
+++ b/src/plugins/texteditor/CMakeLists.txt
@@ -81,6 +81,8 @@ add_qtc_plugin(TextEditor
snippets/snippet.cpp snippets/snippet.h
snippets/snippetassistcollector.cpp snippets/snippetassistcollector.h
snippets/snippeteditor.cpp snippets/snippeteditor.h
+ snippets/snippetoverlay.cpp snippets/snippetoverlay.h
+ snippets/snippetparser.cpp snippets/snippetparser.h
snippets/snippetprovider.cpp snippets/snippetprovider.h
snippets/snippetscollection.cpp snippets/snippetscollection.h
snippets/snippetssettings.cpp snippets/snippetssettings.h
diff --git a/src/plugins/texteditor/codeassist/assistproposalitem.cpp b/src/plugins/texteditor/codeassist/assistproposalitem.cpp
index cf9cbe6e38..6542c1580a 100644
--- a/src/plugins/texteditor/codeassist/assistproposalitem.cpp
+++ b/src/plugins/texteditor/codeassist/assistproposalitem.cpp
@@ -25,8 +25,9 @@
#include "assistproposalitem.h"
-#include <texteditor/texteditor.h>
#include <texteditor/quickfix.h>
+#include <texteditor/snippets/snippet.h>
+#include <texteditor/texteditor.h>
#include <QTextCursor>
@@ -147,7 +148,7 @@ void AssistProposalItem::applyContextualContent(TextDocumentManipulatorInterface
void AssistProposalItem::applySnippet(TextDocumentManipulatorInterface &manipulator, int basePosition) const
{
- manipulator.insertCodeSnippet(basePosition, data().toString());
+ manipulator.insertCodeSnippet(basePosition, data().toString(), &Snippet::parse);
}
void AssistProposalItem::applyQuickFix(TextDocumentManipulatorInterface &manipulator, int basePosition) const
diff --git a/src/plugins/texteditor/codeassist/textdocumentmanipulator.cpp b/src/plugins/texteditor/codeassist/textdocumentmanipulator.cpp
index 0eee5793db..268d9494a0 100644
--- a/src/plugins/texteditor/codeassist/textdocumentmanipulator.cpp
+++ b/src/plugins/texteditor/codeassist/textdocumentmanipulator.cpp
@@ -85,11 +85,13 @@ bool TextDocumentManipulator::replace(int position, int length, const QString &t
return textWillBeReplaced;
}
-void TextDocumentManipulator::insertCodeSnippet(int position, const QString &text)
+void TextDocumentManipulator::insertCodeSnippet(int position,
+ const QString &text,
+ const SnippetParser &parse)
{
auto cursor = m_textEditorWidget->textCursor();
cursor.setPosition(position, QTextCursor::KeepAnchor);
- m_textEditorWidget->insertCodeSnippet(cursor, text);
+ m_textEditorWidget->insertCodeSnippet(cursor, text, parse);
}
void TextDocumentManipulator::paste()
diff --git a/src/plugins/texteditor/codeassist/textdocumentmanipulator.h b/src/plugins/texteditor/codeassist/textdocumentmanipulator.h
index 46aa99f29d..23c7186d60 100644
--- a/src/plugins/texteditor/codeassist/textdocumentmanipulator.h
+++ b/src/plugins/texteditor/codeassist/textdocumentmanipulator.h
@@ -45,7 +45,7 @@ public:
void setCursorPosition(int position) final;
void setAutoCompleteSkipPosition(int position) final;
bool replace(int position, int length, const QString &text) final;
- void insertCodeSnippet(int position, const QString &text) final;
+ void insertCodeSnippet(int position, const QString &text, const SnippetParser &parse) final;
void paste() final;
void encourageApply() final;
void autoIndent(int position, int length) override;
diff --git a/src/plugins/texteditor/codeassist/textdocumentmanipulatorinterface.h b/src/plugins/texteditor/codeassist/textdocumentmanipulatorinterface.h
index ae803260c7..88404713ef 100644
--- a/src/plugins/texteditor/codeassist/textdocumentmanipulatorinterface.h
+++ b/src/plugins/texteditor/codeassist/textdocumentmanipulatorinterface.h
@@ -25,6 +25,7 @@
#pragma once
+#include <texteditor/snippets/snippetparser.h>
#include <texteditor/texteditor_global.h>
QT_BEGIN_NAMESPACE
@@ -49,7 +50,9 @@ public:
virtual void setCursorPosition(int position) = 0;
virtual void setAutoCompleteSkipPosition(int position) = 0;
virtual bool replace(int position, int length, const QString &text) = 0;
- virtual void insertCodeSnippet(int position, const QString &text) = 0;
+ virtual void insertCodeSnippet(int position,
+ const QString &text,
+ const SnippetParser &parse) = 0;
virtual void paste() = 0;
virtual void encourageApply() = 0;
virtual void autoIndent(int position, int length) = 0;
diff --git a/src/plugins/texteditor/codestylepool.cpp b/src/plugins/texteditor/codestylepool.cpp
index 55377eceae..e92592b348 100644
--- a/src/plugins/texteditor/codestylepool.cpp
+++ b/src/plugins/texteditor/codestylepool.cpp
@@ -94,9 +94,7 @@ QByteArray CodeStylePoolPrivate::generateUniqueId(const QByteArray &id) const
static QString customCodeStylesPath()
{
- QString path = Core::ICore::userResourcePath();
- path.append(QLatin1String("/codestyles/"));
- return path;
+ return Core::ICore::userResourcePath("codestyles").toString();
}
CodeStylePool::CodeStylePool(ICodeStylePreferencesFactory *factory, QObject *parent)
diff --git a/src/plugins/texteditor/colorscheme.cpp b/src/plugins/texteditor/colorscheme.cpp
index d032f3e37b..69d8349734 100644
--- a/src/plugins/texteditor/colorscheme.cpp
+++ b/src/plugins/texteditor/colorscheme.cpp
@@ -238,7 +238,7 @@ void ColorScheme::clear()
bool ColorScheme::save(const QString &fileName, QWidget *parent) const
{
- Utils::FileSaver saver(fileName);
+ Utils::FileSaver saver(Utils::FilePath::fromString(fileName));
if (!saver.hasError()) {
QXmlStreamWriter w(saver.file());
w.setAutoFormatting(true);
diff --git a/src/plugins/texteditor/fontsettings.cpp b/src/plugins/texteditor/fontsettings.cpp
index d74a13b2cc..e35ed5c3b2 100644
--- a/src/plugins/texteditor/fontsettings.cpp
+++ b/src/plugins/texteditor/fontsettings.cpp
@@ -504,20 +504,19 @@ int FontSettings::defaultFontSize()
*/
QString FontSettings::defaultSchemeFileName(const QString &fileName)
{
- QString defaultScheme = Core::ICore::resourcePath();
- defaultScheme += QLatin1String("/styles/");
+ Utils::FilePath defaultScheme = Core::ICore::resourcePath("styles");
- if (!fileName.isEmpty() && QFile::exists(defaultScheme + fileName)) {
- defaultScheme += fileName;
+ if (!fileName.isEmpty() && (defaultScheme / fileName).exists()) {
+ defaultScheme = defaultScheme / fileName;
} else {
const QString themeScheme = Utils::creatorTheme()->defaultTextEditorColorScheme();
- if (!themeScheme.isEmpty() && QFile::exists(defaultScheme + themeScheme))
- defaultScheme += themeScheme;
+ if (!themeScheme.isEmpty() && (defaultScheme / themeScheme).exists())
+ defaultScheme = defaultScheme / themeScheme;
else
- defaultScheme += QLatin1String("default.xml");
+ defaultScheme = defaultScheme / "default.xml";
}
- return defaultScheme;
+ return defaultScheme.toString();
}
} // namespace TextEditor
diff --git a/src/plugins/texteditor/fontsettingspage.cpp b/src/plugins/texteditor/fontsettingspage.cpp
index 42c14549c4..2487e31fff 100644
--- a/src/plugins/texteditor/fontsettingspage.cpp
+++ b/src/plugins/texteditor/fontsettingspage.cpp
@@ -191,9 +191,7 @@ public:
static QString customStylesPath()
{
- QString path = Core::ICore::userResourcePath();
- path.append(QLatin1String("/styles/"));
- return path;
+ return Core::ICore::userResourcePath("styles").toString();
}
static QString createColorSchemeFileName(const QString &pattern)
@@ -558,8 +556,7 @@ void FontSettingsPageWidget::refreshColorSchemeList()
{
QList<ColorSchemeEntry> colorSchemes;
- QString resourcePath = Core::ICore::resourcePath();
- QDir styleDir(resourcePath + QLatin1String("/styles"));
+ QDir styleDir(Core::ICore::resourcePath("styles").toDir());
styleDir.setNameFilters(QStringList() << QLatin1String("*.xml"));
styleDir.setFilter(QDir::Files);
diff --git a/src/plugins/texteditor/formattexteditor.cpp b/src/plugins/texteditor/formattexteditor.cpp
index 54655de390..57b30d39f2 100644
--- a/src/plugins/texteditor/formattexteditor.cpp
+++ b/src/plugins/texteditor/formattexteditor.cpp
@@ -32,11 +32,11 @@
#include <coreplugin/messagemanager.h>
#include <utils/differ.h>
+#include <utils/qtcassert.h>
+#include <utils/qtcprocess.h>
#include <utils/runextensions.h>
-#include <utils/synchronousprocess.h>
#include <utils/temporarydirectory.h>
#include <utils/textutils.h>
-#include <utils/qtcassert.h>
#include <QFileInfo>
#include <QFutureWatcher>
@@ -81,30 +81,31 @@ static FormatTask format(FormatTask task)
if (!sourceFile.finalize()) {
task.error = QString(QT_TRANSLATE_NOOP("TextEditor",
"Cannot create temporary file \"%1\": %2."))
- .arg(sourceFile.fileName(), sourceFile.errorString());
+ .arg(sourceFile.filePath().toUserOutput(), sourceFile.errorString());
return task;
}
// Format temporary file
QStringList options = task.command.options();
- options.replaceInStrings(QLatin1String("%file"), sourceFile.fileName());
- Utils::SynchronousProcess process;
+ options.replaceInStrings(QLatin1String("%file"), sourceFile.filePath().toString());
+ SynchronousProcess process;
process.setTimeoutS(5);
- Utils::SynchronousProcessResponse response = process.runBlocking({executable, options});
- if (response.result != Utils::SynchronousProcessResponse::Finished) {
+ process.setCommand({executable, options});
+ process.runBlocking();
+ if (process.result() != QtcProcess::Finished) {
task.error = QString(QT_TRANSLATE_NOOP("TextEditor", "Failed to format: %1."))
- .arg(response.exitMessage(executable, 5));
+ .arg(process.exitMessage());
return task;
}
- const QString output = response.stdErr();
+ const QString output = process.stdErr();
if (!output.isEmpty())
task.error = executable + QLatin1String(": ") + output;
// Read text back
Utils::FileReader reader;
- if (!reader.fetch(sourceFile.fileName(), QIODevice::Text)) {
+ if (!reader.fetch(sourceFile.filePath(), QIODevice::Text)) {
task.error = QString(QT_TRANSLATE_NOOP("TextEditor", "Cannot read file \"%1\": %2."))
- .arg(sourceFile.fileName(), reader.errorString());
+ .arg(sourceFile.filePath().toUserOutput(), reader.errorString());
return task;
}
task.formattedData = QString::fromUtf8(reader.data());
diff --git a/src/plugins/texteditor/highlighter.cpp b/src/plugins/texteditor/highlighter.cpp
index 51e1a307f1..2a940b3f73 100644
--- a/src/plugins/texteditor/highlighter.cpp
+++ b/src/plugins/texteditor/highlighter.cpp
@@ -59,7 +59,7 @@ KSyntaxHighlighting::Repository *highlightRepository()
if (!repository) {
repository = new KSyntaxHighlighting::Repository();
repository->addCustomSearchPath(TextEditorSettings::highlighterSettings().definitionFilesPath());
- QDir dir(Core::ICore::resourcePath() + QLatin1String("/generic-highlighter/syntax"));
+ QDir dir(Core::ICore::resourcePath("generic-highlighter/syntax").toDir());
if (dir.exists() && dir.cdUp())
repository->addCustomSearchPath(dir.path());
}
diff --git a/src/plugins/texteditor/highlightersettings.cpp b/src/plugins/texteditor/highlightersettings.cpp
index bb224f6345..f954be4996 100644
--- a/src/plugins/texteditor/highlightersettings.cpp
+++ b/src/plugins/texteditor/highlightersettings.cpp
@@ -31,8 +31,8 @@
#include <utils/fileutils.h>
#include <utils/hostosinfo.h>
+#include <utils/qtcprocess.h>
#include <utils/stringutils.h>
-#include <utils/synchronousprocess.h>
#include <QSettings>
#include <QLatin1String>
@@ -74,10 +74,10 @@ QString findFallbackDefinitionsLocation()
for (auto &program : programs) {
Utils::SynchronousProcess process;
process.setTimeoutS(5);
- Utils::SynchronousProcessResponse response
- = process.runBlocking({program, {"--prefix"}});
- if (response.result == Utils::SynchronousProcessResponse::Finished) {
- QString output = response.stdOut();
+ process.setCommand({program, {"--prefix"}});
+ process.runBlocking();
+ if (process.result() == Utils::QtcProcess::Finished) {
+ QString output = process.stdOut();
output.remove(QLatin1Char('\n'));
for (auto &kateSyntaxPath : kateSyntaxPaths) {
dir.setPath(output + kateSyntaxPath);
@@ -88,7 +88,7 @@ QString findFallbackDefinitionsLocation()
}
}
- dir.setPath(Core::ICore::resourcePath() + QLatin1String("/generic-highlighter"));
+ dir.setPath(Core::ICore::resourcePath("generic-highlighter").toString());
if (dir.exists() && !dir.entryInfoList().isEmpty())
return dir.path();
@@ -165,8 +165,7 @@ void HighlighterSettings::assignDefaultIgnoredPatterns()
void HighlighterSettings::assignDefaultDefinitionsPath()
{
- const QString &path =
- Core::ICore::userResourcePath() + QLatin1String("/generic-highlighter");
+ const QString path = Core::ICore::userResourcePath("generic-highlighter").toString();
if (QFile::exists(path) || QDir().mkpath(path))
m_definitionFilesPath = path;
}
diff --git a/src/plugins/texteditor/linenumberfilter.cpp b/src/plugins/texteditor/linenumberfilter.cpp
index dc1f6298c2..7695bbd39d 100644
--- a/src/plugins/texteditor/linenumberfilter.cpp
+++ b/src/plugins/texteditor/linenumberfilter.cpp
@@ -48,6 +48,7 @@ LineNumberFilter::LineNumberFilter(QObject *parent)
{
setId("Line in current document");
setDisplayName(tr("Line in Current Document"));
+ setDescription(tr("Jumps to the given line in the current document."));
setPriority(High);
setDefaultShortcutString("l");
setDefaultIncludedByDefault(true);
diff --git a/src/plugins/texteditor/outlinefactory.cpp b/src/plugins/texteditor/outlinefactory.cpp
index 7c7e644b18..421479ab7a 100644
--- a/src/plugins/texteditor/outlinefactory.cpp
+++ b/src/plugins/texteditor/outlinefactory.cpp
@@ -110,27 +110,17 @@ OutlineWidgetStack::OutlineWidgetStack(OutlineFactory *factory) :
updateCurrentEditor();
}
-OutlineWidgetStack::~OutlineWidgetStack() = default;
-
-QToolButton *OutlineWidgetStack::toggleSyncButton()
-{
- return m_toggleSync;
-}
-
-QToolButton *OutlineWidgetStack::filterButton()
+QList<QToolButton *> OutlineWidgetStack::toolButtons()
{
- return m_filterButton;
+ return {m_filterButton, m_toggleSort, m_toggleSync};
}
-QToolButton *OutlineWidgetStack::sortButton()
-{
- return m_toggleSort;
-}
+OutlineWidgetStack::~OutlineWidgetStack() = default;
void OutlineWidgetStack::saveSettings(QSettings *settings, int position)
{
const QString baseKey = QStringLiteral("Outline.%1.").arg(position);
- settings->setValue(baseKey + QLatin1String("SyncWithEditor"), toggleSyncButton()->isChecked());
+ settings->setValue(baseKey + QLatin1String("SyncWithEditor"), m_toggleSync->isChecked());
for (auto iter = m_widgetSettings.constBegin(); iter != m_widgetSettings.constEnd(); ++iter)
settings->setValue(baseKey + iter.key(), iter.value());
}
@@ -154,7 +144,7 @@ void OutlineWidgetStack::restoreSettings(QSettings *settings, int position)
m_widgetSettings.insert(key, settings->value(longKey));
}
- toggleSyncButton()->setChecked(syncWithEditor);
+ m_toggleSync->setChecked(syncWithEditor);
if (auto outlineWidget = qobject_cast<IOutlineWidget*>(currentWidget()))
outlineWidget->restoreSettings(m_widgetSettings);
}
@@ -241,13 +231,8 @@ OutlineFactory::OutlineFactory()
Core::NavigationView OutlineFactory::createWidget()
{
- Core::NavigationView n;
auto placeHolder = new OutlineWidgetStack(this);
- n.widget = placeHolder;
- n.dockToolBarWidgets.append(placeHolder->filterButton());
- n.dockToolBarWidgets.append(placeHolder->sortButton());
- n.dockToolBarWidgets.append(placeHolder->toggleSyncButton());
- return n;
+ return {placeHolder, placeHolder->toolButtons()};
}
void OutlineFactory::saveSettings(Utils::QtcSettings *settings, int position, QWidget *widget)
diff --git a/src/plugins/texteditor/outlinefactory.h b/src/plugins/texteditor/outlinefactory.h
index 0f72bcf6e5..d231b700de 100644
--- a/src/plugins/texteditor/outlinefactory.h
+++ b/src/plugins/texteditor/outlinefactory.h
@@ -44,9 +44,7 @@ public:
OutlineWidgetStack(OutlineFactory *factory);
~OutlineWidgetStack() override;
- QToolButton *toggleSyncButton();
- QToolButton *filterButton();
- QToolButton *sortButton();
+ QList<QToolButton *> toolButtons();
void saveSettings(QSettings *settings, int position);
void restoreSettings(QSettings *settings, int position);
diff --git a/src/plugins/texteditor/refactoringchanges.cpp b/src/plugins/texteditor/refactoringchanges.cpp
index 9732972b01..b936066b1a 100644
--- a/src/plugins/texteditor/refactoringchanges.cpp
+++ b/src/plugins/texteditor/refactoringchanges.cpp
@@ -98,7 +98,7 @@ bool RefactoringChanges::createFile(const QString &fileName, const QString &cont
TextFileFormat format;
format.codec = EditorManager::defaultTextCodec();
QString error;
- bool saveOk = format.writeFile(fileName, document->toPlainText(), &error);
+ bool saveOk = format.writeFile(Utils::FilePath::fromString(fileName), document->toPlainText(), &error);
delete document;
if (!saveOk)
return false;
@@ -198,10 +198,12 @@ QTextDocument *RefactoringFile::mutableDocument() const
if (!m_fileName.isEmpty()) {
QString error;
QTextCodec *defaultCodec = EditorManager::defaultTextCodec();
- TextFileFormat::ReadResult result = TextFileFormat::readFile(
- m_fileName, defaultCodec,
- &fileContents, &m_textFileFormat,
- &error);
+ TextFileFormat::ReadResult result = TextFileFormat::readFile(FilePath::fromString(
+ m_fileName),
+ defaultCodec,
+ &fileContents,
+ &m_textFileFormat,
+ &error);
if (result != TextFileFormat::ReadSuccess) {
qWarning() << "Could not read " << m_fileName << ". Error: " << error;
m_textFileFormat.codec = nullptr;
@@ -372,7 +374,9 @@ bool RefactoringFile::apply()
QString error;
// suppress "file has changed" warnings if the file is open in a read-only editor
Core::FileChangeBlocker block(m_fileName);
- if (!m_textFileFormat.writeFile(m_fileName, doc->toPlainText(), &error)) {
+ if (!m_textFileFormat.writeFile(FilePath::fromString(m_fileName),
+ doc->toPlainText(),
+ &error)) {
qWarning() << "Could not apply changes to" << m_fileName << ". Error: " << error;
result = false;
}
diff --git a/src/plugins/texteditor/snippets/snippet.cpp b/src/plugins/texteditor/snippets/snippet.cpp
index 986655ba4e..38b481b16f 100644
--- a/src/plugins/texteditor/snippets/snippet.cpp
+++ b/src/plugins/texteditor/snippets/snippet.cpp
@@ -154,34 +154,10 @@ bool Snippet::isModified() const
return m_isModified;
}
-struct SnippetReplacement
-{
- QString text;
- int posDelta = 0;
-};
-
-static SnippetReplacement replacementAt(int pos, Snippet::ParsedSnippet &parsedSnippet)
+static QString tipPart(const ParsedSnippet::Part &part)
{
static const char kOpenBold[] = "<b>";
static const char kCloseBold[] = "</b>";
-
- auto mangledText = [](const QString &text, const Snippet::ParsedSnippet::Range &range) {
- if (range.length == 0)
- return QString("...");
- if (NameMangler *mangler = range.mangler)
- return mangler->mangle(text.mid(range.start, range.length));
- return text.mid(range.start, range.length);
- };
-
- if (!parsedSnippet.ranges.isEmpty() && parsedSnippet.ranges.first().start == pos) {
- Snippet::ParsedSnippet::Range range = parsedSnippet.ranges.takeFirst();
- return {kOpenBold + mangledText(parsedSnippet.text, range) + kCloseBold, range.length};
- }
- return {};
-}
-
-QString Snippet::generateTip() const
-{
static const QHash<QChar, QString> replacements = {{'\n', "<br>"},
{' ', "&nbsp;"},
{'"', "&quot;"},
@@ -189,116 +165,128 @@ QString Snippet::generateTip() const
{'<', "&lt;"},
{'>', "&gt;"}};
- ParsedSnippet parsedSnippet = Snippet::parse(m_content);
+ QString text;
+ text.reserve(part.text.size());
- QString tip("<nobr>");
- int pos = 0;
- for (int end = parsedSnippet.text.count(); pos < end;) {
- const SnippetReplacement &replacement = replacementAt(pos, parsedSnippet);
- if (!replacement.text.isEmpty()) {
- tip += replacement.text;
- pos += replacement.posDelta;
- } else {
- const QChar &currentChar = parsedSnippet.text.at(pos);
- tip += replacements.value(currentChar, currentChar);
- ++pos;
- }
- }
- SnippetReplacement replacement = replacementAt(pos, parsedSnippet);
- while (!replacement.text.isEmpty()) {
- tip += replacement.text;
- pos += replacement.posDelta;
- replacement = replacementAt(pos, parsedSnippet);
- }
+ for (const QChar &c : part.text)
+ text.append(replacements.value(c, c));
+
+ if (part.variableIndex >= 0)
+ text = kOpenBold + (text.isEmpty() ? QString("...") : part.text) + kCloseBold;
+
+ return text;
+}
+
+QString Snippet::generateTip() const
+{
+ SnippetParseResult result = Snippet::parse(m_content);
+
+ if (Utils::holds_alternative<SnippetParseError>(result))
+ return Utils::get<SnippetParseError>(result).htmlMessage();
+ QTC_ASSERT(Utils::holds_alternative<ParsedSnippet>(result), return {});
+ const ParsedSnippet parsedSnippet = Utils::get<ParsedSnippet>(result);
- QTC_CHECK(parsedSnippet.ranges.isEmpty());
+ QString tip("<nobr>");
+ for (const ParsedSnippet::Part &part : parsedSnippet.parts)
+ tip.append(tipPart(part));
return tip;
}
-Snippet::ParsedSnippet Snippet::parse(const QString &snippet)
+SnippetParseResult Snippet::parse(const QString &snippet)
{
static UppercaseMangler ucMangler;
static LowercaseMangler lcMangler;
static TitlecaseMangler tcMangler;
- Snippet::ParsedSnippet result;
+ ParsedSnippet result;
QString errorMessage;
QString preprocessedSnippet
= Utils::TemplateEngine::processText(Utils::globalMacroExpander(), snippet,
&errorMessage);
- result.success = errorMessage.isEmpty();
- if (!result.success) {
- result.text = snippet;
- result.errorMessage = errorMessage;
- return result;
- }
+ if (!errorMessage.isEmpty())
+ return {SnippetParseError{errorMessage, {}, -1}};
const int count = preprocessedSnippet.count();
- bool success = true;
- int start = -1;
NameMangler *mangler = nullptr;
- result.text.reserve(count);
+ QMap<QString, int> variableIndexes;
+ bool inVar = false;
+
+ ParsedSnippet::Part currentPart;
for (int i = 0; i < count; ++i) {
QChar current = preprocessedSnippet.at(i);
- QChar next = (i + 1) < count ? preprocessedSnippet.at(i + 1) : QChar();
if (current == Snippet::kVariableDelimiter) {
- if (start < 0) {
- // start delimiter:
- start = result.text.count();
- } else {
- int length = result.text.count() - start;
- result.ranges << ParsedSnippet::Range(start, length, mangler);
+ if (inVar) {
+ const QString variable = currentPart.text;
+ const int index = variableIndexes.value(currentPart.text, result.variables.size());
+ if (index == result.variables.size()) {
+ variableIndexes[variable] = index;
+ result.variables.append(QList<int>());
+ }
+ currentPart.variableIndex = index;
+ currentPart.mangler = mangler;
mangler = nullptr;
- start = -1;
+ result.variables[index] << result.parts.size() - 1;
+ } else if (currentPart.text.isEmpty()) {
+ inVar = !inVar;
+ continue;
}
+ result.parts << currentPart;
+ currentPart = ParsedSnippet::Part();
+ inVar = !inVar;
continue;
}
if (mangler) {
- success = false;
- break;
+ return SnippetParseResult{SnippetParseError{tr("Expected delimiter after mangler id"),
+ preprocessedSnippet,
+ i}};
}
- if (current == QLatin1Char(':') && start >= 0) {
- if (next == QLatin1Char('l')) {
+ if (current == ':' && inVar) {
+ QChar next = (i + 1) < count ? preprocessedSnippet.at(i + 1) : QChar();
+ if (next == 'l') {
mangler = &lcMangler;
- } else if (next == QLatin1Char('u')) {
+ } else if (next == 'u') {
mangler = &ucMangler;
- } else if (next == QLatin1Char('c')) {
+ } else if (next == 'c') {
mangler = &tcMangler;
} else {
- success = false;
- break;
+ return SnippetParseResult{
+ SnippetParseError{tr("Expected mangler id 'l'(lowercase), 'u'(uppercase), "
+ "or 'c'(titlecase) after colon"),
+ preprocessedSnippet,
+ i}};
}
++i;
continue;
}
- if (current == kEscapeChar && (next == kEscapeChar || next == kVariableDelimiter)) {
- result.text.append(next);
- ++i;
- continue;
+ if (current == kEscapeChar){
+ QChar next = (i + 1) < count ? preprocessedSnippet.at(i + 1) : QChar();
+ if (next == kEscapeChar || next == kVariableDelimiter) {
+ currentPart.text.append(next);
+ ++i;
+ continue;
+ }
}
- result.text.append(current);
+ currentPart.text.append(current);
}
- if (start >= 0)
- success = false;
-
- result.success = success;
-
- if (!success) {
- result.ranges.clear();
- result.text = preprocessedSnippet;
+ if (inVar) {
+ return SnippetParseResult{
+ SnippetParseError{tr("Missing closing variable delimiter for:"), currentPart.text, 0}};
}
- return result;
+ if (!currentPart.text.isEmpty())
+ result.parts << currentPart;
+
+ return SnippetParseResult(result);
}
#ifdef WITH_TESTS
@@ -308,129 +296,130 @@ Snippet::ParsedSnippet Snippet::parse(const QString &snippet)
const char NOMANGLER_ID[] = "TextEditor::NoMangler";
+struct SnippetPart
+{
+ SnippetPart() = default;
+ explicit SnippetPart(const QString &text,
+ int index = -1,
+ const Utils::Id &manglerId = NOMANGLER_ID)
+ : text(text)
+ , variableIndex(index)
+ , manglerId(manglerId)
+ {}
+ QString text;
+ int variableIndex = -1; // if variable index is >= 0 the text is interpreted as a variable
+ Utils::Id manglerId;
+};
+Q_DECLARE_METATYPE(SnippetPart);
+
+using Parts = QList<SnippetPart>;
+
void Internal::TextEditorPlugin::testSnippetParsing_data()
{
QTest::addColumn<QString>("input");
- QTest::addColumn<QString>("text");
QTest::addColumn<bool>("success");
- QTest::addColumn<QList<int> >("ranges_start");
- QTest::addColumn<QList<int> >("ranges_length");
- QTest::addColumn<QList<Utils::Id> >("ranges_mangler");
-
- QTest::newRow("no input")
- << QString() << QString() << true
- << (QList<int>()) << (QList<int>()) << (QList<Utils::Id>());
- QTest::newRow("empty input")
- << QString::fromLatin1("") << QString::fromLatin1("") << true
- << (QList<int>()) << (QList<int>()) << (QList<Utils::Id>());
- QTest::newRow("newline only")
- << QString::fromLatin1("\n") << QString::fromLatin1("\n") << true
- << (QList<int>()) << (QList<int>()) << (QList<Utils::Id>());
+ QTest::addColumn<Parts>("parts");
+
+ QTest::newRow("no input") << QString() << true << Parts();
+ QTest::newRow("empty input") << QString("") << true << Parts();
+ QTest::newRow("newline only") << QString("\n") << true << Parts{SnippetPart("\n")};
QTest::newRow("simple identifier")
- << QString::fromLatin1("$tESt$") << QString::fromLatin1("tESt") << true
- << (QList<int>() << 0) << (QList<int>() << 4)
- << (QList<Utils::Id>() << NOMANGLER_ID);
+ << QString("$tESt$") << true << Parts{SnippetPart("tESt", 0)};
QTest::newRow("simple identifier with lc")
- << QString::fromLatin1("$tESt:l$") << QString::fromLatin1("tESt") << true
- << (QList<int>() << 0) << (QList<int>() << 4)
- << (QList<Utils::Id>() << LCMANGLER_ID);
+ << QString("$tESt:l$") << true << Parts{SnippetPart("tESt", 0, LCMANGLER_ID)};
QTest::newRow("simple identifier with uc")
- << QString::fromLatin1("$tESt:u$") << QString::fromLatin1("tESt") << true
- << (QList<int>() << 0) << (QList<int>() << 4)
- << (QList<Utils::Id>() << UCMANGLER_ID);
+ << QString("$tESt:u$") << true << Parts{SnippetPart("tESt", 0, UCMANGLER_ID)};
QTest::newRow("simple identifier with tc")
- << QString::fromLatin1("$tESt:c$") << QString::fromLatin1("tESt") << true
- << (QList<int>() << 0) << (QList<int>() << 4)
- << (QList<Utils::Id>() << TCMANGLER_ID);
+ << QString("$tESt:c$") << true << Parts{SnippetPart("tESt", 0, TCMANGLER_ID)};
QTest::newRow("escaped string")
- << QString::fromLatin1("\\\\$test\\\\$") << QString::fromLatin1("$test$") << true
- << (QList<int>()) << (QList<int>())
- << (QList<Utils::Id>());
- QTest::newRow("escaped escape")
- << QString::fromLatin1("\\\\\\\\$test$\\\\\\\\") << QString::fromLatin1("\\test\\") << true
- << (QList<int>() << 1) << (QList<int>() << 4)
- << (QList<Utils::Id>() << NOMANGLER_ID);
+ << QString("\\\\$test\\\\$") << true << Parts{SnippetPart("$test$")};
+ QTest::newRow("escaped escape") << QString("\\\\\\\\$test$\\\\\\\\") << true
+ << Parts{
+ SnippetPart("\\"),
+ SnippetPart("test", 0),
+ SnippetPart("\\"),
+ };
QTest::newRow("broken escape")
- << QString::fromLatin1("\\\\$test\\\\\\\\$\\\\") << QString::fromLatin1("\\$test\\\\$\\") << false
- << (QList<int>()) << (QList<int>())
- << (QList<Utils::Id>());
-
- QTest::newRow("Q_PROPERTY")
- << QString::fromLatin1("Q_PROPERTY($type$ $name$ READ $name$ WRITE set$name:c$ NOTIFY $name$Changed)")
- << QString::fromLatin1("Q_PROPERTY(type name READ name WRITE setname NOTIFY nameChanged)") << true
- << (QList<int>() << 11 << 16 << 26 << 40 << 52)
- << (QList<int>() << 4 << 4 << 4 << 4 << 4)
- << (QList<Utils::Id>() << NOMANGLER_ID << NOMANGLER_ID << NOMANGLER_ID << TCMANGLER_ID << NOMANGLER_ID);
-
- QTest::newRow("open identifier")
- << QString::fromLatin1("$test") << QString::fromLatin1("$test") << false
- << (QList<int>()) << (QList<int>())
- << (QList<Utils::Id>());
- QTest::newRow("wrong mangler")
- << QString::fromLatin1("$test:X$") << QString::fromLatin1("$test:X$") << false
- << (QList<int>()) << (QList<int>())
- << (QList<Utils::Id>());
-
- QTest::newRow("multiline with :")
- << QString::fromLatin1("class $name$\n"
- "{\n"
- "public:\n"
- " $name$() {}\n"
- "};")
- << QString::fromLatin1("class name\n"
- "{\n"
- "public:\n"
- " name() {}\n"
- "};")
- << true
- << (QList<int>() << 6 << 25)
- << (QList<int>() << 4 << 4)
- << (QList<Utils::Id>() << NOMANGLER_ID << NOMANGLER_ID);
-
- QTest::newRow("escape sequences")
- << QString::fromLatin1("class $name$\\n"
- "{\\n"
- "public\\\\:\\n"
- "\\t$name$() {}\\n"
- "};")
- << QString::fromLatin1("class name\n"
- "{\n"
- "public\\:\n"
- "\tname() {}\n"
- "};")
- << true
- << (QList<int>() << 6 << 23)
- << (QList<int>() << 4 << 4)
- << (QList<Utils::Id>() << NOMANGLER_ID << NOMANGLER_ID);
-
+ << QString::fromLatin1("\\\\$test\\\\\\\\$\\\\") << false << Parts();
+
+ QTest::newRow("Q_PROPERTY") << QString(
+ "Q_PROPERTY($type$ $name$ READ $name$ WRITE set$name:c$ NOTIFY $name$Changed)")
+ << true
+ << Parts{SnippetPart("Q_PROPERTY("),
+ SnippetPart("type", 0),
+ SnippetPart(" "),
+ SnippetPart("name", 1),
+ SnippetPart(" READ "),
+ SnippetPart("name", 1),
+ SnippetPart(" WRITE set"),
+ SnippetPart("name", 1, TCMANGLER_ID),
+ SnippetPart(" NOTIFY "),
+ SnippetPart("name", 1),
+ SnippetPart("Changed)")};
+
+ QTest::newRow("open identifier") << QString("$test") << false << Parts();
+ QTest::newRow("wrong mangler") << QString("$test:X$") << false << Parts();
+
+ QTest::newRow("multiline with :") << QString("class $name$\n"
+ "{\n"
+ "public:\n"
+ " $name$() {}\n"
+ "};")
+ << true
+ << Parts{
+ SnippetPart("class "),
+ SnippetPart("name", 0),
+ SnippetPart("\n"
+ "{\n"
+ "public:\n"
+ " "),
+ SnippetPart("name", 0),
+ SnippetPart("() {}\n"
+ "};"),
+ };
+
+ QTest::newRow("escape sequences") << QString("class $name$\\n"
+ "{\\n"
+ "public\\\\:\\n"
+ "\\t$name$() {}\\n"
+ "};")
+ << true
+ << Parts{
+ SnippetPart("class "),
+ SnippetPart("name", 0),
+ SnippetPart("\n"
+ "{\n"
+ "public\\:\n"
+ "\t"),
+ SnippetPart("name", 0),
+ SnippetPart("() {}\n"
+ "};"),
+ };
}
void Internal::TextEditorPlugin::testSnippetParsing()
{
QFETCH(QString, input);
- QFETCH(QString, text);
QFETCH(bool, success);
- QFETCH(QList<int>, ranges_start);
- QFETCH(QList<int>, ranges_length);
- QFETCH(QList<Utils::Id>, ranges_mangler);
- Q_ASSERT(ranges_start.count() == ranges_length.count()); // sanity check for the test data
- Q_ASSERT(ranges_start.count() == ranges_mangler.count()); // sanity check for the test data
-
- Snippet::ParsedSnippet result = Snippet::parse(input);
-
- QCOMPARE(result.text, text);
- QCOMPARE(result.success, success);
- QCOMPARE(result.ranges.count(), ranges_start.count());
- for (int i = 0; i < ranges_start.count(); ++i) {
- QCOMPARE(result.ranges.at(i).start, ranges_start.at(i));
- QCOMPARE(result.ranges.at(i).length, ranges_length.at(i));
- Utils::Id id = NOMANGLER_ID;
- if (result.ranges.at(i).mangler)
- id = result.ranges.at(i).mangler->id();
- QCOMPARE(id, ranges_mangler.at(i));
- }
+ QFETCH(Parts, parts);
+
+ SnippetParseResult result = Snippet::parse(input);
+ QCOMPARE(Utils::holds_alternative<ParsedSnippet>(result), success);
+ if (!success)
+ return;
+
+ ParsedSnippet snippet = Utils::get<ParsedSnippet>(result);
+
+ auto rangesCompare = [&](const ParsedSnippet::Part &actual, const SnippetPart &expected) {
+ QCOMPARE(actual.text, expected.text);
+ QCOMPARE(actual.variableIndex, expected.variableIndex);
+ auto manglerId = actual.mangler ? actual.mangler->id() : NOMANGLER_ID;
+ QCOMPARE(manglerId, expected.manglerId);
+ };
+
+ for (int i = 0; i < parts.count(); ++i)
+ rangesCompare(snippet.parts.at(i), parts.at(i));
}
#endif
-
diff --git a/src/plugins/texteditor/snippets/snippet.h b/src/plugins/texteditor/snippets/snippet.h
index 4689f6af52..a75b3a297e 100644
--- a/src/plugins/texteditor/snippets/snippet.h
+++ b/src/plugins/texteditor/snippets/snippet.h
@@ -27,25 +27,18 @@
#include <texteditor/texteditor_global.h>
-#include <utils/id.h>
+#include "snippetparser.h"
#include <QChar>
+#include <QCoreApplication>
#include <QList>
#include <QString>
namespace TextEditor {
-class TEXTEDITOR_EXPORT NameMangler
-{
-public:
- virtual ~NameMangler();
-
- virtual Utils::Id id() const = 0;
- virtual QString mangle(const QString &unmangled) const = 0;
-};
-
class TEXTEDITOR_EXPORT Snippet
{
+ Q_DECLARE_TR_FUNCTIONS(Snippet)
public:
explicit Snippet(const QString &groupId = QString(), const QString &id = QString());
~Snippet();
@@ -76,21 +69,7 @@ public:
static const QChar kVariableDelimiter;
static const QChar kEscapeChar;
- class ParsedSnippet {
- public:
- QString text;
- QString errorMessage;
- bool success;
- struct Range {
- Range(int s, int l, NameMangler *m) : start(s), length(l), mangler(m) { }
- int start;
- int length;
- NameMangler *mangler;
- };
- QList<Range> ranges;
- };
-
- static ParsedSnippet parse(const QString &snippet);
+ static SnippetParseResult parse(const QString &snippet);
private:
bool m_isRemoved = false;
diff --git a/src/plugins/texteditor/snippets/snippetoverlay.cpp b/src/plugins/texteditor/snippets/snippetoverlay.cpp
new file mode 100644
index 0000000000..b773acfee1
--- /dev/null
+++ b/src/plugins/texteditor/snippets/snippetoverlay.cpp
@@ -0,0 +1,181 @@
+/****************************************************************************
+**
+** Copyright (C) 2021 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of Qt Creator.
+**
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3 as published by the Free Software
+** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-3.0.html.
+**
+****************************************************************************/
+
+#include "snippetoverlay.h"
+
+#include <utils/algorithm.h>
+#include <utils/qtcassert.h>
+
+namespace TextEditor {
+namespace Internal {
+
+void SnippetOverlay::clear()
+{
+ TextEditorOverlay::clear();
+ m_selections.clear();
+ m_variables.clear();
+}
+
+void SnippetOverlay::addSnippetSelection(const QTextCursor &cursor,
+ const QColor &color,
+ NameMangler *mangler,
+ int variableIndex)
+{
+ m_variables[variableIndex] << selections().size();
+ SnippetSelection selection;
+ selection.variableIndex = variableIndex;
+ selection.mangler = mangler;
+ m_selections << selection;
+ addOverlaySelection(cursor, color, color, TextEditorOverlay::ExpandBegin);
+}
+
+void SnippetOverlay::setFinalSelection(const QTextCursor &cursor, const QColor &color)
+{
+ m_finalSelectionIndex = selections().size();
+ addOverlaySelection(cursor, color, color, TextEditorOverlay::ExpandBegin);
+}
+
+void SnippetOverlay::updateEquivalentSelections(const QTextCursor &cursor)
+{
+ const int &currentIndex = indexForCursor(cursor);
+ if (currentIndex < 0)
+ return;
+ const QString &currentText = cursorForIndex(currentIndex).selectedText();
+ const QList<int> &equivalents = m_variables.value(m_selections[currentIndex].variableIndex);
+ for (int i : equivalents) {
+ if (i == currentIndex)
+ continue;
+ QTextCursor cursor = cursorForIndex(i);
+ const QString &equivalentText = cursor.selectedText();
+ if (currentText != equivalentText) {
+ cursor.joinPreviousEditBlock();
+ cursor.insertText(currentText);
+ cursor.endEditBlock();
+ }
+ }
+}
+
+void SnippetOverlay::mangle()
+{
+ for (int i = 0; i < m_selections.size(); ++i) {
+ if (NameMangler *mangler = m_selections[i].mangler) {
+ QTextCursor cursor = cursorForIndex(i);
+ const QString current = cursor.selectedText();
+ const QString result = mangler->mangle(current);
+ if (result != current) {
+ cursor.joinPreviousEditBlock();
+ cursor.insertText(result);
+ cursor.endEditBlock();
+ }
+ }
+ }
+}
+
+bool SnippetOverlay::hasCursorInSelection(const QTextCursor &cursor) const
+{
+ return indexForCursor(cursor) >= 0;
+}
+
+QTextCursor SnippetOverlay::firstSelectionCursor() const
+{
+ const QList<OverlaySelection> selections = TextEditorOverlay::selections();
+ return selections.isEmpty() ? QTextCursor() : cursorForSelection(selections.first());
+}
+
+QTextCursor SnippetOverlay::nextSelectionCursor(const QTextCursor &cursor) const
+{
+ const QList<OverlaySelection> selections = TextEditorOverlay::selections();
+ if (selections.isEmpty())
+ return {};
+ const SnippetSelection &currentSelection = selectionForCursor(cursor);
+ if (currentSelection.variableIndex >= 0) {
+ int nextVariableIndex = currentSelection.variableIndex + 1;
+ if (nextVariableIndex >= m_variables.size()) {
+ if (m_finalSelectionIndex >= 0)
+ return cursorForIndex(m_finalSelectionIndex);
+ nextVariableIndex = 0;
+ }
+
+ for (int selectionIndex : m_variables[nextVariableIndex]) {
+ if (selections[selectionIndex].m_cursor_begin.position() > cursor.position())
+ return cursorForIndex(selectionIndex);
+ }
+ return cursorForIndex(m_variables[nextVariableIndex].first());
+ }
+ // currently not over a variable simply select the next available one
+ for (const OverlaySelection &candidate : selections) {
+ if (candidate.m_cursor_begin.position() > cursor.position())
+ return cursorForSelection(candidate);
+ }
+ return cursorForSelection(selections.first());
+}
+
+QTextCursor SnippetOverlay::previousSelectionCursor(const QTextCursor &cursor) const
+{
+ const QList<OverlaySelection> selections = TextEditorOverlay::selections();
+ if (selections.isEmpty())
+ return {};
+ const SnippetSelection &currentSelection = selectionForCursor(cursor);
+ if (currentSelection.variableIndex >= 0) {
+ int previousVariableIndex = currentSelection.variableIndex - 1;
+ if (previousVariableIndex < 0)
+ previousVariableIndex = m_variables.size() - 1;
+
+ const QList<int> &equivalents = m_variables[previousVariableIndex];
+ for (int i = equivalents.size() - 1; i >= 0; --i) {
+ if (selections.at(equivalents.at(i)).m_cursor_end.position() < cursor.position())
+ return cursorForIndex(equivalents.at(i));
+ }
+ return cursorForIndex(m_variables[previousVariableIndex].last());
+ }
+ // currently not over a variable simply select the previous available one
+ for (int i = selections.size() - 1; i >= 0; --i) {
+ if (selections.at(i).m_cursor_end.position() < cursor.position())
+ return cursorForIndex(i);
+ }
+ return cursorForSelection(selections.last());
+}
+
+bool SnippetOverlay::isFinalSelection(const QTextCursor &cursor) const
+{
+ return m_finalSelectionIndex >= 0 ? cursor == cursorForIndex(m_finalSelectionIndex) : false;
+}
+
+int SnippetOverlay::indexForCursor(const QTextCursor &cursor) const
+{
+ return Utils::indexOf(selections(),
+ [pos = cursor.position()](const OverlaySelection &selection) {
+ return selection.m_cursor_begin.position() <= pos
+ && selection.m_cursor_end.position() >= pos;
+ });
+}
+
+SnippetOverlay::SnippetSelection SnippetOverlay::selectionForCursor(const QTextCursor &cursor) const
+{
+ return m_selections.value(indexForCursor(cursor));
+}
+
+} // namespace Internal
+} // namespace TextEditor
diff --git a/src/plugins/texteditor/snippets/snippetoverlay.h b/src/plugins/texteditor/snippets/snippetoverlay.h
new file mode 100644
index 0000000000..9bf80524d6
--- /dev/null
+++ b/src/plugins/texteditor/snippets/snippetoverlay.h
@@ -0,0 +1,78 @@
+/****************************************************************************
+**
+** Copyright (C) 2021 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of Qt Creator.
+**
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3 as published by the Free Software
+** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-3.0.html.
+**
+****************************************************************************/
+
+#pragma once
+
+#include "snippet.h"
+#include "texteditor/texteditoroverlay.h"
+
+#include <QTextEdit>
+
+namespace TextEditor {
+class NameMangler;
+
+namespace Internal {
+
+class SnippetOverlay : public TextEditorOverlay
+{
+public:
+ using TextEditorOverlay::TextEditorOverlay;
+
+ void clear() override;
+
+ void addSnippetSelection(const QTextCursor &cursor,
+ const QColor &color,
+ NameMangler *mangler,
+ int variableGoup);
+ void setFinalSelection(const QTextCursor &cursor, const QColor &color);
+
+ void updateEquivalentSelections(const QTextCursor &cursor);
+ void mangle();
+
+ bool hasCursorInSelection(const QTextCursor &cursor) const;
+
+ QTextCursor firstSelectionCursor() const;
+ QTextCursor nextSelectionCursor(const QTextCursor &cursor) const;
+ QTextCursor previousSelectionCursor(const QTextCursor &cursor) const;
+ bool isFinalSelection(const QTextCursor &cursor) const;
+
+private:
+ struct SnippetSelection
+ {
+ int variableIndex = -1;
+ NameMangler *mangler;
+ };
+
+ int indexForCursor(const QTextCursor &cursor) const;
+ SnippetSelection selectionForCursor(const QTextCursor &cursor) const;
+
+ QList<SnippetSelection> m_selections;
+ int m_finalSelectionIndex = -1;
+ QMap<int, QList<int>> m_variables;
+};
+
+} // namespace Internal
+} // namespace TextEditor
+
diff --git a/src/plugins/qmlprofiler/qmlprofilerconfigwidget.h b/src/plugins/texteditor/snippets/snippetparser.cpp
index cc80849f85..366489120d 100644
--- a/src/plugins/qmlprofiler/qmlprofilerconfigwidget.h
+++ b/src/plugins/texteditor/snippets/snippetparser.cpp
@@ -1,6 +1,6 @@
/****************************************************************************
**
-** Copyright (C) 2016 The Qt Company Ltd.
+** Copyright (C) 2021 The Qt Company Ltd.
** Contact: https://www.qt.io/licensing/
**
** This file is part of Qt Creator.
@@ -23,33 +23,24 @@
**
****************************************************************************/
-#pragma once
+#include "snippetparser.h"
-#include "qmlprofilersettings.h"
-#include <QWidget>
+namespace TextEditor {
-namespace QmlProfiler {
-namespace Internal {
-
-namespace Ui {
-class QmlProfilerConfigWidget;
-}
-
-
-class QmlProfilerConfigWidget : public QWidget
+QString SnippetParseError::htmlMessage() const
{
- Q_OBJECT
-
-public:
- explicit QmlProfilerConfigWidget(QmlProfilerSettings *settings);
- ~QmlProfilerConfigWidget() override;
-
-private:
- void updateUi();
-
- Ui::QmlProfilerConfigWidget *m_ui;
- QmlProfilerSettings *m_settings;
-};
+ QString message = errorMessage;
+ if (pos < 0 || pos > 50)
+ return message;
+ QString detail = text.left(50);
+ if (detail != text)
+ detail.append("...");
+ detail.replace(QChar::Space, "&nbsp;");
+ message.append("<br><code>" + detail + "<br>");
+ for (int i = 0; i < pos; ++i)
+ message.append("&nbsp;");
+ message.append("^</code>");
+ return message;
+}
-} // Internal
-} // QmlProfiler
+} // namespace TextEditor
diff --git a/src/plugins/texteditor/snippets/snippetparser.h b/src/plugins/texteditor/snippets/snippetparser.h
new file mode 100644
index 0000000000..67d0560d02
--- /dev/null
+++ b/src/plugins/texteditor/snippets/snippetparser.h
@@ -0,0 +1,73 @@
+/****************************************************************************
+**
+** Copyright (C) 2021 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of Qt Creator.
+**
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3 as published by the Free Software
+** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-3.0.html.
+**
+****************************************************************************/
+
+#pragma once
+
+#include <texteditor/texteditor_global.h>
+
+#include <utils/id.h>
+#include <utils/variant.h>
+
+namespace TextEditor {
+
+class TEXTEDITOR_EXPORT NameMangler
+{
+public:
+ virtual ~NameMangler();
+
+ virtual Utils::Id id() const = 0;
+ virtual QString mangle(const QString &unmangled) const = 0;
+};
+
+class TEXTEDITOR_EXPORT ParsedSnippet
+{
+public:
+ class Part {
+ public:
+ Part() = default;
+ explicit Part(const QString &text) : text(text) {}
+ QString text;
+ int variableIndex = -1; // if variable index is >= 0 the text is interpreted as a variable
+ NameMangler *mangler = nullptr;
+ bool finalPart = false;
+ };
+ QList<Part> parts;
+ QList<QList<int>> variables;
+};
+
+class TEXTEDITOR_EXPORT SnippetParseError
+{
+public:
+ QString errorMessage;
+ QString text;
+ int pos;
+
+ QString htmlMessage() const;
+};
+
+using SnippetParseResult = Utils::variant<ParsedSnippet, SnippetParseError>;
+using SnippetParser = std::function<SnippetParseResult (const QString &)>;
+
+} // namespace TextEditor
diff --git a/src/plugins/texteditor/snippets/snippetscollection.cpp b/src/plugins/texteditor/snippets/snippetscollection.cpp
index afb6c28eda..e814607a12 100644
--- a/src/plugins/texteditor/snippets/snippetscollection.cpp
+++ b/src/plugins/texteditor/snippets/snippetscollection.cpp
@@ -94,11 +94,11 @@ SnippetsCollection *SnippetsCollection::instance()
}
// SnippetsCollection
-SnippetsCollection::SnippetsCollection() :
- m_userSnippetsPath(Core::ICore::userResourcePath() + QLatin1String("/snippets/")),
- m_userSnippetsFile(QLatin1String("snippets.xml"))
+SnippetsCollection::SnippetsCollection()
+ : m_userSnippetsPath(Core::ICore::userResourcePath().pathAppended("snippets/").toString())
+ , m_userSnippetsFile(QLatin1String("snippets.xml"))
{
- QDir dir(Core::ICore::resourcePath() + QLatin1String("/snippets/"));
+ QDir dir = Core::ICore::resourcePath("snippets").toDir();
dir.setNameFilters(QStringList(QLatin1String("*.xml")));
foreach (const QFileInfo &fi, dir.entryInfoList())
m_builtInSnippetsFiles.append(fi.absoluteFilePath());
@@ -306,7 +306,7 @@ bool SnippetsCollection::synchronize(QString *errorString)
QDir::toNativeSeparators(m_userSnippetsPath));
return false;
}
- Utils::FileSaver saver(m_userSnippetsPath + m_userSnippetsFile);
+ Utils::FileSaver saver(Utils::FilePath::fromString(m_userSnippetsPath + m_userSnippetsFile));
if (!saver.hasError()) {
using GroupIndexByIdConstIt = QHash<QString, int>::ConstIterator;
diff --git a/src/plugins/texteditor/textdocument.cpp b/src/plugins/texteditor/textdocument.cpp
index eb6ae5b0dd..2a52c42575 100644
--- a/src/plugins/texteditor/textdocument.cpp
+++ b/src/plugins/texteditor/textdocument.cpp
@@ -600,7 +600,7 @@ SyntaxHighlighter *TextDocument::syntaxHighlighter() const
* If \a autoSave is true, the cursor will be restored and some signals suppressed
* and we do not clean up the text file (cleanWhitespace(), ensureFinalNewLine()).
*/
-bool TextDocument::save(QString *errorString, const QString &saveFileName, bool autoSave)
+bool TextDocument::save(QString *errorString, const FilePath &filePath, bool autoSave)
{
QTextCursor cursor(&d->m_document);
@@ -638,11 +638,9 @@ bool TextDocument::save(QString *errorString, const QString &saveFileName, bool
if (d->m_storageSettings.m_addFinalNewLine)
ensureFinalNewLine(cursor);
cursor.endEditBlock();
- }
+ }
- QString fName = filePath().toString();
- if (!saveFileName.isEmpty())
- fName = saveFileName;
+ const Utils::FilePath &savePath = filePath.isEmpty() ? this->filePath() : filePath;
// check if UTF8-BOM has to be added or removed
Utils::TextFileFormat saveFormat = format();
@@ -659,7 +657,7 @@ bool TextDocument::save(QString *errorString, const QString &saveFileName, bool
}
}
- const bool ok = write(fName, saveFormat, d->m_document.toPlainText(), errorString);
+ const bool ok = write(savePath, saveFormat, d->m_document.toPlainText(), errorString);
// restore text cursor and scroll bar positions
if (autoSave && undos < d->m_document.availableUndoSteps()) {
@@ -681,9 +679,8 @@ bool TextDocument::save(QString *errorString, const QString &saveFileName, bool
return true;
// inform about the new filename
- const QFileInfo fi(fName);
d->m_document.setModified(false); // also triggers update of the block revisions
- setFilePath(Utils::FilePath::fromUserInput(fi.absoluteFilePath()));
+ setFilePath(savePath.absoluteFilePath());
emit changed();
return true;
}
@@ -715,33 +712,35 @@ bool TextDocument::isModified() const
return d->m_document.isModified();
}
-Core::IDocument::OpenResult TextDocument::open(QString *errorString, const QString &fileName,
- const QString &realFileName)
+Core::IDocument::OpenResult TextDocument::open(QString *errorString,
+ const Utils::FilePath &filePath,
+ const Utils::FilePath &realFilePath)
{
- emit aboutToOpen(fileName, realFileName);
- OpenResult success = openImpl(errorString, fileName, realFileName, /*reload =*/ false);
+ emit aboutToOpen(filePath, realFilePath);
+ OpenResult success = openImpl(errorString, filePath, realFilePath, /*reload =*/ false);
if (success == OpenResult::Success) {
- setMimeType(Utils::mimeTypeForFile(fileName).name());
+ setMimeType(Utils::mimeTypeForFile(filePath.toString()).name());
emit openFinishedSuccessfully();
}
return success;
}
-Core::IDocument::OpenResult TextDocument::openImpl(QString *errorString, const QString &fileName,
- const QString &realFileName, bool reload)
+Core::IDocument::OpenResult TextDocument::openImpl(QString *errorString,
+ const Utils::FilePath &filePath,
+ const Utils::FilePath &realFilePath,
+ bool reload)
{
QStringList content;
ReadResult readResult = Utils::TextFileFormat::ReadIOError;
- if (!fileName.isEmpty()) {
- const QFileInfo fi(fileName);
- readResult = read(realFileName, &content, errorString);
+ if (!filePath.isEmpty()) {
+ readResult = read(realFilePath, &content, errorString);
const int chunks = content.size();
// Don't call setUndoRedoEnabled(true) when reload is true and filenames are different,
// since it will reset the undo's clear index
- if (!reload || fileName == realFileName)
+ if (!reload || filePath == realFilePath)
d->m_document.setUndoRedoEnabled(reload);
QTextCursor c(&d->m_document);
@@ -775,7 +774,7 @@ Core::IDocument::OpenResult TextDocument::openImpl(QString *errorString, const Q
// Don't call setUndoRedoEnabled(true) when reload is true and filenames are different,
// since it will reset the undo's clear index
- if (!reload || fileName == realFileName)
+ if (!reload || filePath == realFilePath)
d->m_document.setUndoRedoEnabled(true);
auto documentLayout =
@@ -783,8 +782,8 @@ Core::IDocument::OpenResult TextDocument::openImpl(QString *errorString, const Q
QTC_ASSERT(documentLayout, return OpenResult::CannotHandle);
documentLayout->lastSaveRevision = d->m_autoSaveRevision = d->m_document.revision();
d->updateRevisions();
- d->m_document.setModified(fileName != realFileName);
- setFilePath(Utils::FilePath::fromUserInput(fi.absoluteFilePath()));
+ d->m_document.setModified(filePath != realFilePath);
+ setFilePath(filePath);
}
if (readResult == Utils::TextFileFormat::ReadIOError)
return OpenResult::ReadError;
@@ -800,10 +799,10 @@ bool TextDocument::reload(QString *errorString, QTextCodec *codec)
bool TextDocument::reload(QString *errorString)
{
- return reload(errorString, filePath().toString());
+ return reload(errorString, filePath());
}
-bool TextDocument::reload(QString *errorString, const QString &realFileName)
+bool TextDocument::reload(QString *errorString, const FilePath &realFilePath)
{
emit aboutToReload();
auto documentLayout =
@@ -812,8 +811,8 @@ bool TextDocument::reload(QString *errorString, const QString &realFileName)
if (documentLayout)
marks = documentLayout->documentClosing(); // removes text marks non-permanently
- const QString &file = filePath().toString();
- bool success = openImpl(errorString, file, realFileName, /*reload =*/ true) == OpenResult::Success;
+ bool success = openImpl(errorString, filePath(), realFilePath, /*reload =*/true)
+ == OpenResult::Success;
if (documentLayout)
documentLayout->documentReloaded(marks, this); // re-adds text marks
diff --git a/src/plugins/texteditor/textdocument.h b/src/plugins/texteditor/textdocument.h
index f67b55fa6e..98e6546045 100644
--- a/src/plugins/texteditor/textdocument.h
+++ b/src/plugins/texteditor/textdocument.h
@@ -112,7 +112,7 @@ public:
void removeMarkFromMarksCache(TextMark *mark);
// IDocument implementation.
- bool save(QString *errorString, const QString &fileName, bool autoSave) override;
+ bool save(QString *errorString, const Utils::FilePath &filePath, bool autoSave) override;
QByteArray contents() const override;
bool setContents(const QByteArray &contents) override;
bool shouldAutoSave() const override;
@@ -127,10 +127,10 @@ public:
void setFallbackSaveAsPath(const QString &fallbackSaveAsPath);
void setFallbackSaveAsFileName(const QString &fallbackSaveAsFileName);
- OpenResult open(QString *errorString, const QString &fileName,
- const QString &realFileName) override;
+ OpenResult open(QString *errorString, const Utils::FilePath &filePath,
+ const Utils::FilePath &realFilePath) override;
virtual bool reload(QString *errorString);
- bool reload(QString *errorString, const QString &realFileName);
+ bool reload(QString *errorString, const Utils::FilePath &realFilePath);
bool setPlainText(const QString &text);
QTextDocument *document() const;
@@ -156,7 +156,7 @@ public:
const std::function<Utils::FilePath()> &filePath);
signals:
- void aboutToOpen(const QString &fileName, const QString &realFileName);
+ void aboutToOpen(const Utils::FilePath &filePath, const Utils::FilePath &realFilePath);
void openFinishedSuccessfully();
void contentsChangedWithPosition(int position, int charsRemoved, int charsAdded);
void tabSettingsChanged();
@@ -167,7 +167,9 @@ protected:
virtual void applyFontSettings();
private:
- OpenResult openImpl(QString *errorString, const QString &fileName, const QString &realFileName,
+ OpenResult openImpl(QString *errorString,
+ const Utils::FilePath &filePath,
+ const Utils::FilePath &realFileName,
bool reload);
void cleanWhitespace(QTextCursor &cursor, bool inEntireDocument, bool cleanIndentation);
void ensureFinalNewLine(QTextCursor &cursor);
diff --git a/src/plugins/texteditor/texteditor.cpp b/src/plugins/texteditor/texteditor.cpp
index e9f64c5b3f..033dd2a58a 100644
--- a/src/plugins/texteditor/texteditor.cpp
+++ b/src/plugins/texteditor/texteditor.cpp
@@ -42,6 +42,7 @@
#include "icodestylepreferences.h"
#include "refactoroverlay.h"
#include "snippets/snippet.h"
+#include "snippets/snippetoverlay.h"
#include "storagesettings.h"
#include "syntaxhighlighter.h"
#include "tabsettings.h"
@@ -665,7 +666,7 @@ public:
int extraAreaPreviousMarkTooltipRequestedLine = -1;
TextEditorOverlay *m_overlay = nullptr;
- TextEditorOverlay *m_snippetOverlay = nullptr;
+ SnippetOverlay *m_snippetOverlay = nullptr;
TextEditorOverlay *m_searchResultOverlay = nullptr;
bool snippetCheckCursor(const QTextCursor &cursor);
void snippetTabOrBacktab(bool forward);
@@ -1004,7 +1005,7 @@ void TextEditorWidgetPrivate::ctor(const QSharedPointer<TextDocument> &doc)
q->setVerticalScrollBarPolicy(Qt::ScrollBarAlwaysOn);
m_overlay = new TextEditorOverlay(q);
- m_snippetOverlay = new TextEditorOverlay(q);
+ m_snippetOverlay = new SnippetOverlay(q);
m_searchResultOverlay = new TextEditorOverlay(q);
m_refactorOverlay = new RefactorOverlay(q);
@@ -1214,11 +1215,7 @@ void TextEditorWidgetPrivate::print(QPrinter *printer)
QAbstractTextDocumentLayout *layout = doc->documentLayout();
layout->setPaintDevice(p.device());
-#if QT_VERSION < QT_VERSION_CHECK(5, 14, 0)
- int dpiy = p.device()->logicalDpiY();
-#else
int dpiy = qRound(QGuiApplication::primaryScreen()->logicalDotsPerInchY());
-#endif
int margin = int((2/2.54)*dpiy); // 2 cm margins
QTextFrameFormat fmt = doc->rootFrame()->frameFormat();
@@ -1467,10 +1464,10 @@ TextDocument *TextEditorWidget::textDocument() const
return d->m_document.data();
}
-void TextEditorWidget::aboutToOpen(const QString &fileName, const QString &realFileName)
+void TextEditorWidget::aboutToOpen(const Utils::FilePath &filePath, const Utils::FilePath &realFilePath)
{
- Q_UNUSED(fileName)
- Q_UNUSED(realFileName)
+ Q_UNUSED(filePath)
+ Q_UNUSED(realFilePath)
}
void TextEditorWidget::openFinishedSuccessfully()
@@ -2702,61 +2699,97 @@ void TextEditorWidget::keyPressEvent(QKeyEvent *e)
d->m_codeAssistant.process();
}
-void TextEditorWidget::insertCodeSnippet(const QTextCursor &cursor_arg, const QString &snippet)
+class PositionedPart : public ParsedSnippet::Part
+{
+public:
+ explicit PositionedPart(const ParsedSnippet::Part &part) : ParsedSnippet::Part(part) {}
+ int start;
+ int end;
+};
+
+class CursorPart : public ParsedSnippet::Part
{
- Snippet::ParsedSnippet data = Snippet::parse(snippet);
+public:
+ CursorPart(const PositionedPart &part, QTextDocument *doc)
+ : ParsedSnippet::Part(part)
+ , cursor(doc)
+ {
+ cursor.setPosition(part.start);
+ cursor.setPosition(part.end, QTextCursor::KeepAnchor);
+ }
+ QTextCursor cursor;
+};
- if (!data.success) {
- QString message = QString::fromLatin1("Cannot parse snippet \"%1\".").arg(snippet);
- if (!data.errorMessage.isEmpty())
- message += QLatin1String("\nParse error: ") + data.errorMessage;
- QMessageBox::warning(this, QLatin1String("Snippet Parse Error"), message);
+void TextEditorWidget::insertCodeSnippet(const QTextCursor &cursor_arg,
+ const QString &snippet,
+ const SnippetParser &parse)
+{
+ SnippetParseResult result = parse(snippet);
+ if (Utils::holds_alternative<SnippetParseError>(result)) {
+ const auto &error = Utils::get<SnippetParseError>(result);
+ QMessageBox::warning(this, tr("Snippet Parse Error"), error.htmlMessage());
return;
}
+ QTC_ASSERT(Utils::holds_alternative<ParsedSnippet>(result), return);
+ ParsedSnippet data = Utils::get<ParsedSnippet>(result);
QTextCursor cursor = cursor_arg;
cursor.beginEditBlock();
cursor.removeSelectedText();
const int startCursorPosition = cursor.position();
- cursor.insertText(data.text);
- QList<QTextEdit::ExtraSelection> selections;
-
- QList<NameMangler *> manglers;
- for (int i = 0; i < data.ranges.count(); ++i) {
- int position = data.ranges.at(i).start + startCursorPosition;
- int length = data.ranges.at(i).length;
-
- QTextCursor tc(document());
- tc.setPosition(position);
- tc.setPosition(position + length, QTextCursor::KeepAnchor);
- QTextEdit::ExtraSelection selection;
- selection.cursor = tc;
- selection.format = (length
- ? textDocument()->fontSettings().toTextCharFormat(C_OCCURRENCES)
- : textDocument()->fontSettings().toTextCharFormat(C_OCCURRENCES_RENAME));
- selections.append(selection);
- manglers << data.ranges.at(i).mangler;
+ d->m_snippetOverlay->mangle();
+ d->m_snippetOverlay->clear();
+
+ QList<PositionedPart> positionedParts;
+ for (const ParsedSnippet::Part &part : qAsConst(data.parts)) {
+ if (part.variableIndex >= 0) {
+ PositionedPart posPart(part);
+ posPart.start = cursor.position();
+ cursor.insertText(part.text);
+ posPart.end = cursor.position();
+ positionedParts << posPart;
+ } else {
+ cursor.insertText(part.text);
+ }
}
+ QList<CursorPart> cursorParts = Utils::transform(positionedParts,
+ [doc = document()](const PositionedPart &part) {
+ return CursorPart(part, doc);
+ });
+
cursor.setPosition(startCursorPosition, QTextCursor::KeepAnchor);
d->m_document->autoIndent(cursor);
cursor.endEditBlock();
- setExtraSelections(TextEditorWidget::SnippetPlaceholderSelection, selections);
- d->m_snippetOverlay->setNameMangler(manglers);
+ const QColor &occurrencesColor
+ = textDocument()->fontSettings().toTextCharFormat(C_OCCURRENCES).background().color();
+ const QColor &renameColor
+ = textDocument()->fontSettings().toTextCharFormat(C_OCCURRENCES_RENAME).background().color();
- if (!selections.isEmpty()) {
- const QTextEdit::ExtraSelection &selection = selections.first();
-
- cursor = textCursor();
- if (selection.cursor.hasSelection()) {
- cursor.setPosition(selection.cursor.selectionStart());
- cursor.setPosition(selection.cursor.selectionEnd(), QTextCursor::KeepAnchor);
+ for (const CursorPart &part : cursorParts) {
+ const QColor &color = part.cursor.hasSelection() ? occurrencesColor : renameColor;
+ if (part.finalPart) {
+ d->m_snippetOverlay->setFinalSelection(part.cursor, color);
} else {
- cursor.setPosition(selection.cursor.position());
+ d->m_snippetOverlay->addSnippetSelection(part.cursor,
+ color,
+ part.mangler,
+ part.variableIndex);
}
+ }
+
+ cursor = d->m_snippetOverlay->firstSelectionCursor();
+ if (!cursor.isNull()) {
setTextCursor(cursor);
+ if (d->m_snippetOverlay->isFinalSelection(cursor)) {
+ d->m_snippetOverlay->mangle();
+ d->m_snippetOverlay->clear();
+ d->m_snippetOverlay->setVisible(false);
+ } else {
+ d->m_snippetOverlay->setVisible(true);
+ }
}
}
@@ -3464,37 +3497,14 @@ void TextEditorWidgetPrivate::snippetTabOrBacktab(bool forward)
{
if (!m_snippetOverlay->isVisible() || m_snippetOverlay->isEmpty())
return;
- QTextCursor cursor = q->textCursor();
- OverlaySelection final;
- if (forward) {
- for (int i = 0; i < m_snippetOverlay->selections().count(); ++i){
- const OverlaySelection &selection = m_snippetOverlay->selections().at(i);
- if (selection.m_cursor_begin.position() >= cursor.position()
- && selection.m_cursor_end.position() > cursor.position()) {
- final = selection;
- break;
- }
- }
- } else {
- for (int i = m_snippetOverlay->selections().count()-1; i >= 0; --i){
- const OverlaySelection &selection = m_snippetOverlay->selections().at(i);
- if (selection.m_cursor_end.position() < cursor.position()) {
- final = selection;
- break;
- }
- }
-
- }
- if (final.m_cursor_begin.isNull())
- final = forward ? m_snippetOverlay->selections().first() : m_snippetOverlay->selections().last();
-
- if (final.m_cursor_begin.position() == final.m_cursor_end.position()) { // empty tab stop
- cursor.setPosition(final.m_cursor_end.position());
- } else {
- cursor.setPosition(final.m_cursor_begin.position());
- cursor.setPosition(final.m_cursor_end.position(), QTextCursor::KeepAnchor);
- }
+ QTextCursor cursor = forward ? m_snippetOverlay->nextSelectionCursor(q->textCursor())
+ : m_snippetOverlay->previousSelectionCursor(q->textCursor());
q->setTextCursor(cursor);
+ if (m_snippetOverlay->isFinalSelection(cursor)) {
+ m_snippetOverlay->setVisible(false);
+ m_snippetOverlay->mangle();
+ m_snippetOverlay->clear();
+ }
}
// Calculate global position for a tooltip considering the left extra area.
@@ -6250,7 +6260,7 @@ bool TextEditorWidget::openLink(const Utils::Link &link, bool inNextSplit)
if (!link.hasValidTarget())
return false;
- if (!inNextSplit && textDocument()->filePath().toString() == link.targetFileName) {
+ if (!inNextSplit && textDocument()->filePath() == link.targetFilePath) {
EditorManager::addCurrentPositionToNavigationHistory();
gotoLine(link.targetLine, link.targetColumn, true, true);
setFocus();
@@ -6260,8 +6270,7 @@ bool TextEditorWidget::openLink(const Utils::Link &link, bool inNextSplit)
if (inNextSplit)
flags |= EditorManager::OpenInOtherSplit;
- return EditorManager::openEditorAt(link.targetFileName, link.targetLine, link.targetColumn,
- Id(), flags);
+ return EditorManager::openEditorAt(link, Id(), flags);
}
bool TextEditorWidgetPrivate::isMouseNavigationEvent(QMouseEvent *e) const
@@ -7086,17 +7095,6 @@ void TextEditorWidgetPrivate::setExtraSelections(Id kind, const QList<QTextEdit:
TextEditorOverlay::LockSize);
}
m_overlay->setVisible(!m_overlay->isEmpty());
- } else if (kind == TextEditorWidget::SnippetPlaceholderSelection) {
- m_snippetOverlay->mangle();
- m_snippetOverlay->clear();
- foreach (const QTextEdit::ExtraSelection &selection, m_extraSelections[kind]) {
- m_snippetOverlay->addOverlaySelection(selection.cursor,
- selection.format.background().color(),
- selection.format.background().color(),
- TextEditorOverlay::ExpandBegin);
- }
- m_snippetOverlay->mapEquivalentSelections();
- m_snippetOverlay->setVisible(!m_snippetOverlay->isEmpty());
} else {
QList<QTextEdit::ExtraSelection> all;
for (auto i = m_extraSelections.constBegin(); i != m_extraSelections.constEnd(); ++i) {
@@ -8687,7 +8685,7 @@ void TextEditorLinkLabel::mouseMoveEvent(QMouseEvent *event)
return;
auto data = new DropMimeData;
- data->addFile(m_link.targetFileName, m_link.targetLine, m_link.targetColumn);
+ data->addFile(m_link.targetFilePath.toString(), m_link.targetLine, m_link.targetColumn);
auto drag = new QDrag(this);
drag->setMimeData(data);
drag->exec(Qt::CopyAction);
@@ -8699,7 +8697,9 @@ void TextEditorLinkLabel::mouseReleaseEvent(QMouseEvent *event)
if (!m_link.hasValidTarget())
return;
- EditorManager::openEditorAt(m_link.targetFileName, m_link.targetLine, m_link.targetColumn);
+ EditorManager::openEditorAt(m_link.targetFilePath.toString(),
+ m_link.targetLine,
+ m_link.targetColumn);
}
//
diff --git a/src/plugins/texteditor/texteditor.h b/src/plugins/texteditor/texteditor.h
index b48c7b3ee3..ceab8fbb53 100644
--- a/src/plugins/texteditor/texteditor.h
+++ b/src/plugins/texteditor/texteditor.h
@@ -26,10 +26,12 @@
#pragma once
#include "texteditor_global.h"
+
#include "blockrange.h"
#include "codeassist/assistenums.h"
#include "indenter.h"
#include "refactoroverlay.h"
+#include "snippets/snippetparser.h"
#include <coreplugin/editormanager/editormanager.h>
#include <coreplugin/editormanager/ieditor.h>
@@ -186,7 +188,7 @@ public:
TextDocument *textDocument() const;
QSharedPointer<TextDocument> textDocumentPtr() const;
- virtual void aboutToOpen(const QString &fileName, const QString &realFileName);
+ virtual void aboutToOpen(const Utils::FilePath &filePath, const Utils::FilePath &realFilePath);
virtual void openFinishedSuccessfully();
// IEditor
QByteArray saveState() const;
@@ -265,7 +267,9 @@ public:
void setReadOnly(bool b);
- void insertCodeSnippet(const QTextCursor &cursor, const QString &snippet);
+ void insertCodeSnippet(const QTextCursor &cursor,
+ const QString &snippet,
+ const SnippetParser &parse);
void setBlockSelection(bool on);
void setBlockSelection(int positionBlock, int positionColumn, int anchhorBlock,
diff --git a/src/plugins/texteditor/texteditor.pro b/src/plugins/texteditor/texteditor.pro
index bbf536459e..c22ed59c59 100644
--- a/src/plugins/texteditor/texteditor.pro
+++ b/src/plugins/texteditor/texteditor.pro
@@ -97,7 +97,9 @@ SOURCES += texteditorplugin.cpp \
commentssettings.cpp \
marginsettings.cpp \
formattexteditor.cpp \
- command.cpp
+ command.cpp \
+ snippets/snippetoverlay.cpp \
+ snippets/snippetparser.cpp
HEADERS += texteditorplugin.h \
plaintexteditorfactory.h \
@@ -192,7 +194,9 @@ HEADERS += texteditorplugin.h \
formattexteditor.h \
command.h \
indenter.h \
- formatter.h
+ formatter.h \
+ snippets/snippetoverlay.h \
+ snippets/snippetparser.h
FORMS += \
displaysettingspage.ui \
diff --git a/src/plugins/texteditor/texteditor.qbs b/src/plugins/texteditor/texteditor.qbs
index 5b36e0c76c..896c9d515e 100644
--- a/src/plugins/texteditor/texteditor.qbs
+++ b/src/plugins/texteditor/texteditor.qbs
@@ -205,8 +205,6 @@ Project {
name: "Snippets"
prefix: "snippets/"
files: [
- "snippetprovider.cpp",
- "snippetprovider.h",
"reuse.h",
"snippet.cpp",
"snippet.h",
@@ -214,6 +212,12 @@ Project {
"snippetassistcollector.h",
"snippeteditor.cpp",
"snippeteditor.h",
+ "snippetoverlay.cpp",
+ "snippetoverlay.h",
+ "snippetparser.cpp",
+ "snippetparser.h",
+ "snippetprovider.cpp",
+ "snippetprovider.h",
"snippetscollection.cpp",
"snippetscollection.h",
"snippetssettings.cpp",
diff --git a/src/plugins/texteditor/texteditorconstants.cpp b/src/plugins/texteditor/texteditorconstants.cpp
index 3902c13665..6063b1c5e8 100644
--- a/src/plugins/texteditor/texteditorconstants.cpp
+++ b/src/plugins/texteditor/texteditorconstants.cpp
@@ -55,6 +55,7 @@ const char *nameForStyle(TextStyle style)
case C_STRING: return "String";
case C_TYPE: return "Type";
case C_LOCAL: return "Local";
+ case C_PARAMETER: return "Parameter";
case C_GLOBAL: return "Global";
case C_FIELD: return "Field";
// TODO: Rename "Static" to "Enumeration" in next major update,
diff --git a/src/plugins/texteditor/texteditorconstants.h b/src/plugins/texteditor/texteditorconstants.h
index 22b602074d..abab979b61 100644
--- a/src/plugins/texteditor/texteditorconstants.h
+++ b/src/plugins/texteditor/texteditorconstants.h
@@ -55,6 +55,7 @@ enum TextStyle : quint8 {
C_STRING,
C_TYPE,
C_LOCAL,
+ C_PARAMETER,
C_GLOBAL,
C_FIELD,
C_ENUMERATION,
diff --git a/src/plugins/texteditor/texteditoroverlay.cpp b/src/plugins/texteditor/texteditoroverlay.cpp
index 863db175c9..4fb7de00a2 100644
--- a/src/plugins/texteditor/texteditoroverlay.cpp
+++ b/src/plugins/texteditor/texteditoroverlay.cpp
@@ -25,7 +25,6 @@
#include "texteditoroverlay.h"
#include "texteditor.h"
-#include "snippets/snippet.h"
#include <QDebug>
#include <QMap>
@@ -34,6 +33,7 @@
#include <QTextBlock>
#include <algorithm>
+#include <utils/qtcassert.h>
using namespace TextEditor;
using namespace TextEditor::Internal;
@@ -72,8 +72,6 @@ void TextEditorOverlay::clear()
return;
m_selections.clear();
m_firstSelectionOriginalBegin = -1;
- m_equivalentSelections.clear();
- m_manglers.clear();
update();
}
@@ -419,6 +417,21 @@ void TextEditorOverlay::paint(QPainter *painter, const QRect &clip)
}
}
+QTextCursor TextEditorOverlay::cursorForSelection(const OverlaySelection &selection) const
+{
+ QTextCursor cursor = selection.m_cursor_begin;
+ cursor.setPosition(selection.m_cursor_begin.position());
+ cursor.setKeepPositionOnInsert(false);
+ if (!cursor.isNull())
+ cursor.setPosition(selection.m_cursor_end.position(), QTextCursor::KeepAnchor);
+ return cursor;
+}
+
+QTextCursor TextEditorOverlay::cursorForIndex(int selectionIndex) const
+{
+ return cursorForSelection(m_selections.value(selectionIndex));
+}
+
void TextEditorOverlay::fill(QPainter *painter, const QColor &color, const QRect &clip)
{
Q_UNUSED(clip)
@@ -446,111 +459,6 @@ void TextEditorOverlay::fill(QPainter *painter, const QColor &color, const QRect
}
}
-/*! \returns true if any selection contains \a cursor, where a cursor on the
- start or end of a selection is counted as contained.
-*/
-bool TextEditorOverlay::hasCursorInSelection(const QTextCursor &cursor) const
-{
- if (selectionIndexForCursor(cursor) != -1)
- return true;
- return false;
-}
-
-int TextEditorOverlay::selectionIndexForCursor(const QTextCursor &cursor) const
-{
- for (int i = 0; i < m_selections.size(); ++i) {
- const OverlaySelection &selection = m_selections.at(i);
- if (cursor.position() >= selection.m_cursor_begin.position()
- && cursor.position() <= selection.m_cursor_end.position())
- return i;
- }
- return -1;
-}
-
-QString TextEditorOverlay::selectionText(int selectionIndex) const
-{
- return assembleCursorForSelection(selectionIndex).selectedText();
-}
-
-QTextCursor TextEditorOverlay::assembleCursorForSelection(int selectionIndex) const
-{
- const OverlaySelection &selection = m_selections.at(selectionIndex);
- QTextCursor cursor(m_editor->document());
- cursor.setPosition(selection.m_cursor_begin.position());
- cursor.setPosition(selection.m_cursor_end.position(), QTextCursor::KeepAnchor);
- return cursor;
-}
-
-void TextEditorOverlay::mapEquivalentSelections()
-{
- m_equivalentSelections.clear();
- m_equivalentSelections.resize(m_selections.size());
-
- QMultiMap<QString, int> all;
- for (int i = 0; i < m_selections.size(); ++i)
- all.insert(selectionText(i).toLower(), i);
-
- const QList<QString> &uniqueKeys = all.uniqueKeys();
- foreach (const QString &key, uniqueKeys) {
- QList<int> indexes;
- const auto cAll = all;
- QMultiMap<QString, int>::const_iterator lbit = cAll.lowerBound(key);
- QMultiMap<QString, int>::const_iterator ubit = cAll.upperBound(key);
- while (lbit != ubit) {
- indexes.append(lbit.value());
- ++lbit;
- }
-
- foreach (int index, indexes)
- m_equivalentSelections[index] = indexes;
- }
-}
-
-void TextEditorOverlay::updateEquivalentSelections(const QTextCursor &cursor)
-{
- int selectionIndex = selectionIndexForCursor(cursor);
- if (selectionIndex == -1)
- return;
-
- const QString &currentText = selectionText(selectionIndex);
- const QList<int> &equivalents = m_equivalentSelections.at(selectionIndex);
- foreach (int i, equivalents) {
- if (i == selectionIndex)
- continue;
- const QString &equivalentText = selectionText(i);
- if (currentText != equivalentText) {
- QTextCursor selectionCursor = assembleCursorForSelection(i);
- selectionCursor.joinPreviousEditBlock();
- selectionCursor.removeSelectedText();
- selectionCursor.insertText(currentText);
- selectionCursor.endEditBlock();
- }
- }
-}
-
-void TextEditorOverlay::setNameMangler(const QList<NameMangler *> &manglers)
-{
- m_manglers = manglers;
-}
-
-void TextEditorOverlay::mangle()
-{
- for (int i = 0; i < m_manglers.count(); ++i) {
- if (!m_manglers.at(i))
- continue;
-
- const QString current = selectionText(i);
- const QString result = m_manglers.at(i)->mangle(current);
- if (result != current) {
- QTextCursor selectionCursor = assembleCursorForSelection(i);
- selectionCursor.joinPreviousEditBlock();
- selectionCursor.removeSelectedText();
- selectionCursor.insertText(result);
- selectionCursor.endEditBlock();
- }
- }
-}
-
bool TextEditorOverlay::hasFirstSelectionBeginMoved() const
{
if (m_firstSelectionOriginalBegin == -1 || m_selections.isEmpty())
diff --git a/src/plugins/texteditor/texteditoroverlay.h b/src/plugins/texteditor/texteditoroverlay.h
index 374bc0ea1e..d87a0fe7aa 100644
--- a/src/plugins/texteditor/texteditoroverlay.h
+++ b/src/plugins/texteditor/texteditoroverlay.h
@@ -35,7 +35,6 @@ QT_FORWARD_DECLARE_CLASS(QWidget)
QT_FORWARD_DECLARE_CLASS(QPainterPath)
namespace TextEditor {
-class NameMangler;
class TextEditorWidget;
namespace Internal {
@@ -74,7 +73,7 @@ public:
void setAlpha(bool enabled) { m_alpha = enabled; }
- void clear();
+ virtual void clear();
enum OverlaySelectionFlags {
LockSize = 1,
@@ -93,22 +92,16 @@ public:
inline int dropShadowWidth() const { return m_dropShadowWidth; }
- bool hasCursorInSelection(const QTextCursor &cursor) const;
-
- void mapEquivalentSelections();
- void updateEquivalentSelections(const QTextCursor &cursor);
- void setNameMangler(const QList<NameMangler *> &manglers);
- void mangle();
-
bool hasFirstSelectionBeginMoved() const;
+protected:
+ QTextCursor cursorForSelection(const OverlaySelection &selection) const;
+ QTextCursor cursorForIndex(int selectionIndex) const;
+
private:
QPainterPath createSelectionPath(const QTextCursor &begin, const QTextCursor &end, const QRect& clip);
void paintSelection(QPainter *painter, const OverlaySelection &selection);
void fillSelection(QPainter *painter, const OverlaySelection &selection, const QColor &color);
- int selectionIndexForCursor(const QTextCursor &cursor) const;
- QString selectionText(int selectionIndex) const;
- QTextCursor assembleCursorForSelection(int selectionIndex) const;
bool m_visible;
bool m_alpha;
@@ -118,8 +111,6 @@ private:
TextEditorWidget *m_editor;
QWidget *m_viewport;
QList<OverlaySelection> m_selections;
- QVector<QList<int> > m_equivalentSelections;
- QList<NameMangler *> m_manglers;
};
} // namespace Internal
diff --git a/src/plugins/texteditor/texteditorsettings.cpp b/src/plugins/texteditor/texteditorsettings.cpp
index 2c72606dea..724e3efedc 100644
--- a/src/plugins/texteditor/texteditorsettings.cpp
+++ b/src/plugins/texteditor/texteditorsettings.cpp
@@ -162,6 +162,8 @@ FormatDescriptions TextEditorSettingsPrivate::initialFormats()
Qt::darkMagenta);
formatDescr.emplace_back(C_LOCAL, tr("Local"),
tr("Local variables."), QColor(9, 46, 100));
+ formatDescr.emplace_back(C_PARAMETER, tr("Parameter"),
+ tr("Function or method parameters."), QColor(9, 46, 100));
formatDescr.emplace_back(C_FIELD, tr("Field"),
tr("Class' data members."), Qt::darkRed);
formatDescr.emplace_back(C_GLOBAL, tr("Global"),
diff --git a/src/plugins/todo/todoplugin.cpp b/src/plugins/todo/todoplugin.cpp
index fc7e47c614..edc8b70cd9 100644
--- a/src/plugins/todo/todoplugin.cpp
+++ b/src/plugins/todo/todoplugin.cpp
@@ -37,6 +37,7 @@
#include <coreplugin/editormanager/ieditor.h>
#include <projectexplorer/projectpanelfactory.h>
+#include <utils/link.h>
#include <QFileInfo>
#include <QSettings>
@@ -103,7 +104,7 @@ void TodoPluginPrivate::scanningScopeChanged(ScanningScope scanningScope)
void TodoPluginPrivate::todoItemClicked(const TodoItem &item)
{
if (item.file.exists())
- Core::EditorManager::openEditorAt(item.file.toString(), item.line);
+ Core::EditorManager::openEditorAt(Utils::Link(item.file, item.line));
}
void TodoPluginPrivate::createItemsProvider()
diff --git a/src/plugins/updateinfo/updateinfoplugin.cpp b/src/plugins/updateinfo/updateinfoplugin.cpp
index 814e0559f6..99fc625f3f 100644
--- a/src/plugins/updateinfo/updateinfoplugin.cpp
+++ b/src/plugins/updateinfo/updateinfoplugin.cpp
@@ -35,7 +35,8 @@
#include <utils/algorithm.h>
#include <utils/fileutils.h>
#include <utils/infobar.h>
-#include <utils/synchronousprocess.h>
+#include <utils/qtcassert.h>
+#include <utils/qtcprocess.h>
#include <QDate>
#include <QDomDocument>
@@ -73,8 +74,12 @@ public:
QString m_collectedOutput;
QTimer *m_checkUpdatesTimer = nullptr;
- bool m_automaticCheck = true;
- UpdateInfoPlugin::CheckUpdateInterval m_checkInterval = UpdateInfoPlugin::WeeklyCheck;
+ struct Settings
+ {
+ bool automaticCheck = true;
+ UpdateInfoPlugin::CheckUpdateInterval checkInterval = UpdateInfoPlugin::WeeklyCheck;
+ };
+ Settings m_settings;
QDate m_lastCheckDate;
};
@@ -124,8 +129,8 @@ void UpdateInfoPlugin::startCheckForUpdates()
{
stopCheckForUpdates();
- QProcessEnvironment env = QProcessEnvironment::systemEnvironment();
- env.insert(QLatin1String("QT_LOGGING_RULES"), QLatin1String("*=false"));
+ Utils::Environment env = Utils::Environment::systemEnvironment();
+ env.set("QT_LOGGING_RULES", "*=false");
d->m_checkUpdatesCommand = new ShellCommand(QString(), env);
d->m_checkUpdatesCommand->setDisplayName(tr("Checking for Updates"));
connect(d->m_checkUpdatesCommand, &ShellCommand::stdOutText, this, &UpdateInfoPlugin::collectCheckForUpdatesOutput);
@@ -133,7 +138,7 @@ void UpdateInfoPlugin::startCheckForUpdates()
d->m_checkUpdatesCommand->addJob({Utils::FilePath::fromString(d->m_maintenanceTool), {"--checkupdates"}},
60 * 3, // 3 minutes timeout
/*workingDirectory=*/QString(),
- [](int /*exitCode*/) { return Utils::SynchronousProcessResponse::Finished; });
+ [](int /*exitCode*/) { return Utils::QtcProcess::Finished; });
d->m_checkUpdatesCommand->execute();
d->m_progress = d->m_checkUpdatesCommand->futureProgress();
if (d->m_progress) {
@@ -273,49 +278,59 @@ bool UpdateInfoPlugin::initialize(const QStringList & /* arguments */, QString *
void UpdateInfoPlugin::loadSettings() const
{
+ UpdateInfoPluginPrivate::Settings def;
QSettings *settings = ICore::settings();
- const QString updaterKey = QLatin1String(UpdaterGroup) + QLatin1Char('/');
- d->m_maintenanceTool = settings->value(updaterKey + QLatin1String(MaintenanceToolKey)).toString();
- d->m_lastCheckDate = settings->value(updaterKey + QLatin1String(LastCheckDateKey), QDate()).toDate();
- d->m_automaticCheck = settings->value(updaterKey + QLatin1String(AutomaticCheckKey), true).toBool();
- const QString checkInterval = settings->value(updaterKey + QLatin1String(CheckIntervalKey)).toString();
+ const QString updaterKey = QLatin1String(UpdaterGroup) + '/';
+ d->m_maintenanceTool = settings->value(updaterKey + MaintenanceToolKey).toString();
+ d->m_lastCheckDate = settings->value(updaterKey + LastCheckDateKey, QDate()).toDate();
+ d->m_settings.automaticCheck
+ = settings->value(updaterKey + AutomaticCheckKey, def.automaticCheck).toBool();
const QMetaObject *mo = metaObject();
const QMetaEnum me = mo->enumerator(mo->indexOfEnumerator(CheckIntervalKey));
- if (me.isValid()) {
+ if (QTC_GUARD(me.isValid())) {
+ const QString checkInterval = settings
+ ->value(updaterKey + CheckIntervalKey,
+ me.valueToKey(def.checkInterval))
+ .toString();
bool ok = false;
const int newValue = me.keyToValue(checkInterval.toUtf8(), &ok);
if (ok)
- d->m_checkInterval = static_cast<CheckUpdateInterval>(newValue);
+ d->m_settings.checkInterval = static_cast<CheckUpdateInterval>(newValue);
}
}
void UpdateInfoPlugin::saveSettings()
{
- QSettings *settings = ICore::settings();
- settings->beginGroup(QLatin1String(UpdaterGroup));
- settings->setValue(QLatin1String(LastCheckDateKey), d->m_lastCheckDate);
- settings->setValue(QLatin1String(AutomaticCheckKey), d->m_automaticCheck);
+ UpdateInfoPluginPrivate::Settings def;
+ Utils::QtcSettings *settings = ICore::settings();
+ settings->beginGroup(UpdaterGroup);
+ settings->setValueWithDefault(LastCheckDateKey, d->m_lastCheckDate, QDate());
+ settings->setValueWithDefault(AutomaticCheckKey,
+ d->m_settings.automaticCheck,
+ def.automaticCheck);
// Note: don't save MaintenanceToolKey on purpose! This setting may be set only by installer.
// If creator is run not from installed SDK, the setting can be manually created here:
// [CREATOR_INSTALLATION_LOCATION]/share/qtcreator/QtProject/QtCreator.ini or
// [CREATOR_INSTALLATION_LOCATION]/Qt Creator.app/Contents/Resources/QtProject/QtCreator.ini on OS X
const QMetaObject *mo = metaObject();
const QMetaEnum me = mo->enumerator(mo->indexOfEnumerator(CheckIntervalKey));
- settings->setValue(QLatin1String(CheckIntervalKey), QLatin1String(me.valueToKey(d->m_checkInterval)));
+ settings->setValueWithDefault(CheckIntervalKey,
+ QString::fromUtf8(me.valueToKey(d->m_settings.checkInterval)),
+ QString::fromUtf8(me.valueToKey(def.checkInterval)));
settings->endGroup();
}
bool UpdateInfoPlugin::isAutomaticCheck() const
{
- return d->m_automaticCheck;
+ return d->m_settings.automaticCheck;
}
void UpdateInfoPlugin::setAutomaticCheck(bool on)
{
- if (d->m_automaticCheck == on)
+ if (d->m_settings.automaticCheck == on)
return;
- d->m_automaticCheck = on;
+ d->m_settings.automaticCheck = on;
if (on)
startAutoCheckForUpdates();
else
@@ -324,15 +339,15 @@ void UpdateInfoPlugin::setAutomaticCheck(bool on)
UpdateInfoPlugin::CheckUpdateInterval UpdateInfoPlugin::checkUpdateInterval() const
{
- return d->m_checkInterval;
+ return d->m_settings.checkInterval;
}
void UpdateInfoPlugin::setCheckUpdateInterval(UpdateInfoPlugin::CheckUpdateInterval interval)
{
- if (d->m_checkInterval == interval)
+ if (d->m_settings.checkInterval == interval)
return;
- d->m_checkInterval = interval;
+ d->m_settings.checkInterval = interval;
}
QDate UpdateInfoPlugin::lastCheckDate() const
@@ -351,7 +366,7 @@ void UpdateInfoPlugin::setLastCheckDate(const QDate &date)
QDate UpdateInfoPlugin::nextCheckDate() const
{
- return nextCheckDate(d->m_checkInterval);
+ return nextCheckDate(d->m_settings.checkInterval);
}
QDate UpdateInfoPlugin::nextCheckDate(CheckUpdateInterval interval) const
diff --git a/src/plugins/valgrind/CMakeLists.txt b/src/plugins/valgrind/CMakeLists.txt
index 797f3011bb..83720cb2c0 100644
--- a/src/plugins/valgrind/CMakeLists.txt
+++ b/src/plugins/valgrind/CMakeLists.txt
@@ -27,7 +27,7 @@ add_qtc_plugin(Valgrind
memchecktool.cpp memchecktool.h
suppressiondialog.cpp suppressiondialog.h
valgrind.qrc
- valgrindconfigwidget.cpp valgrindconfigwidget.h valgrindconfigwidget.ui
+ valgrindconfigwidget.cpp valgrindconfigwidget.h
valgrindengine.cpp valgrindengine.h
valgrindplugin.cpp valgrindplugin.h
valgrindrunner.cpp valgrindrunner.h
diff --git a/src/plugins/valgrind/callgrindengine.cpp b/src/plugins/valgrind/callgrindengine.cpp
index 2bf80550fb..aba8997a2f 100644
--- a/src/plugins/valgrind/callgrindengine.cpp
+++ b/src/plugins/valgrind/callgrindengine.cpp
@@ -78,16 +78,16 @@ QStringList CallgrindToolRunner::toolArguments() const
{
QStringList arguments = {"--tool=callgrind"};
- if (m_settings.enableCacheSim())
+ if (m_settings.enableCacheSim.value())
arguments << "--cache-sim=yes";
- if (m_settings.enableBranchSim())
+ if (m_settings.enableBranchSim.value())
arguments << "--branch-sim=yes";
- if (m_settings.collectBusEvents())
+ if (m_settings.collectBusEvents.value())
arguments << "--collect-bus=yes";
- if (m_settings.collectSystime())
+ if (m_settings.collectSystime.value())
arguments << "--collect-systime=yes";
if (m_markAsPaused)
@@ -97,7 +97,7 @@ QStringList CallgrindToolRunner::toolArguments() const
if (!m_argumentForToggleCollect.isEmpty())
arguments << m_argumentForToggleCollect;
- arguments << Utils::QtcProcess::splitArgs(m_settings.callgrindArguments());
+ arguments << Utils::ProcessArgs::splitArgs(m_settings.callgrindArguments.value());
return arguments;
}
diff --git a/src/plugins/valgrind/callgrindtool.cpp b/src/plugins/valgrind/callgrindtool.cpp
index 5a392a6511..c19b80414a 100644
--- a/src/plugins/valgrind/callgrindtool.cpp
+++ b/src/plugins/valgrind/callgrindtool.cpp
@@ -133,8 +133,6 @@ public:
void selectFunction(const Function *);
void setCostFormat(CostDelegate::CostFormat format);
- void enableCycleDetection(bool enabled);
- void shortenTemplates(bool enabled);
void setCostEvent(int index);
/// This function will add custom text marks to the editor
@@ -198,8 +196,6 @@ public:
QAction *m_costAbsolute = nullptr;
QAction *m_costRelative = nullptr;
QAction *m_costRelativeToParent = nullptr;
- QAction *m_cycleDetection = nullptr;
- QAction *m_shortenTemplates = nullptr;
QComboBox *m_eventCombo = nullptr;
QTimer m_updateTimer;
@@ -382,7 +378,7 @@ CallgrindToolPrivate::CallgrindToolPrivate()
action->setIcon(kCachegrindIcon.icon());
action->setToolTip(CallgrindTool::tr("Open results in KCachegrind."));
connect(action, &QAction::triggered, this, [this, settings] {
- QProcess::startDetached(settings->kcachegrindExecutable(), { m_lastFileName });
+ QProcess::startDetached(settings->kcachegrindExecutable.value(), { m_lastFileName });
});
// dump action
@@ -488,40 +484,20 @@ CallgrindToolPrivate::CallgrindToolPrivate()
m_perspective.addToolBarWidget(button);
}
- // Cycle detection
- //action = new QAction("Cycle Detection", this); ///FIXME: icon
- action = m_cycleDetection = new QAction("O", this); ///FIXME: icon
- action->setToolTip(CallgrindTool::tr("Enable cycle detection to properly handle recursive or circular function calls."));
- action->setCheckable(true);
- connect(action, &QAction::toggled, &m_dataModel, &DataModel::enableCycleDetection);
- connect(action, &QAction::toggled, settings, &ValgrindGlobalSettings::setDetectCycles);
-
- // Shorter template signature
- action = m_shortenTemplates = new QAction("<>", this);
- action->setToolTip(CallgrindTool::tr("Remove template parameter lists when displaying function names."));
- action->setCheckable(true);
- connect(action, &QAction::toggled, &m_dataModel, &DataModel::setShortenTemplates);
- connect(action, &QAction::toggled, settings, &ValgrindGlobalSettings::setShortenTemplates);
-
// Filtering
- action = m_filterProjectCosts = new QAction(CallgrindTool::tr("Show Project Costs Only"), this);
- action->setIcon(Utils::Icons::FILTER.icon());
- action->setToolTip(CallgrindTool::tr("Show only profiling info that originated from this project source."));
- action->setCheckable(true);
+ action = m_filterProjectCosts = settings->filterExternalIssues.action();
connect(action, &QAction::toggled, this, &CallgrindToolPrivate::handleFilterProjectCosts);
// Filter
- ///FIXME: find workaround for https://bugreports.qt.io/browse/QTCREATORBUG-3247
m_searchFilter = new QLineEdit;
m_searchFilter->setPlaceholderText(CallgrindTool::tr("Filter..."));
connect(m_searchFilter, &QLineEdit::textChanged,
&m_updateTimer, QOverload<>::of(&QTimer::start));
- setCostFormat(settings->costFormat());
- enableCycleDetection(settings->detectCycles());
+ setCostFormat(CostDelegate::CostFormat(settings->costFormat.value()));
- m_perspective.addToolBarAction(m_cycleDetection);
- m_perspective.addToolBarAction(m_shortenTemplates);
+ m_perspective.addToolBarAction(settings->detectCycles.action());
+ m_perspective.addToolBarAction(settings->shortenTemplates.action());
m_perspective.addToolBarAction(m_filterProjectCosts);
m_perspective.addToolBarWidget(m_searchFilter);
@@ -640,16 +616,6 @@ void CallgrindToolPrivate::setCostEvent(int index)
m_callersModel.setCostEvent(index);
}
-void CallgrindToolPrivate::enableCycleDetection(bool enabled)
-{
- m_cycleDetection->setChecked(enabled);
-}
-
-void CallgrindToolPrivate::shortenTemplates(bool enabled)
-{
- m_shortenTemplates->setChecked(enabled);
-}
-
// Following functions can be called with actions=0 or widgets=0
// depending on initialization sequence (whether callgrind was current).
CostDelegate::CostFormat CallgrindToolPrivate::costFormat() const
@@ -671,7 +637,7 @@ void CallgrindToolPrivate::updateCostFormat()
m_callersView->setCostFormat(format);
}
if (ValgrindGlobalSettings *settings = ValgrindGlobalSettings::instance())
- settings->setCostFormat(format);
+ settings->costFormat.setValue(format);
}
void CallgrindToolPrivate::handleFilterProjectCosts()
@@ -789,9 +755,9 @@ void CallgrindToolPrivate::setupRunner(CallgrindToolRunner *toolRunner)
// apply project settings
ValgrindProjectSettings settings;
settings.fromMap(runControl->settingsData(ANALYZER_VALGRIND_SETTINGS));
- m_visualization->setMinimumInclusiveCostRatio(settings.visualisationMinimumInclusiveCostRatio() / 100.0);
- m_proxyModel.setMinimumInclusiveCostRatio(settings.minimumInclusiveCostRatio() / 100.0);
- m_dataModel.setVerboseToolTipsEnabled(settings.enableEventToolTips());
+ m_visualization->setMinimumInclusiveCostRatio(settings.visualizationMinimumInclusiveCostRatio.value() / 100.0);
+ m_proxyModel.setMinimumInclusiveCostRatio(settings.minimumInclusiveCostRatio.value() / 100.0);
+ m_dataModel.setVerboseToolTipsEnabled(settings.enableEventToolTips.value());
m_toolBusy = true;
updateRunActions();
@@ -949,7 +915,8 @@ void CallgrindToolPrivate::takeParserData(ParseData *data)
doClear(true);
setParseData(data);
- const QString kcachegrindExecutable = ValgrindGlobalSettings::instance()->kcachegrindExecutable();
+ const QString kcachegrindExecutable =
+ ValgrindGlobalSettings::instance()->kcachegrindExecutable.value();
const bool kcachegrindExists = !Utils::Environment::systemEnvironment().searchInPath(
kcachegrindExecutable).isEmpty();
m_startKCachegrind->setEnabled(kcachegrindExists && !m_lastFileName.isEmpty());
diff --git a/src/plugins/valgrind/memchecktool.cpp b/src/plugins/valgrind/memchecktool.cpp
index 418728e642..6b105111b5 100644
--- a/src/plugins/valgrind/memchecktool.cpp
+++ b/src/plugins/valgrind/memchecktool.cpp
@@ -128,7 +128,7 @@ public:
void start() override;
void stop() override;
- QStringList suppressionFiles() const;
+ const QStringList suppressionFiles() const;
signals:
void internalParserError(const QString &errorString);
@@ -191,14 +191,14 @@ QStringList MemcheckToolRunner::toolArguments() const
{
QStringList arguments = {"--tool=memcheck", "--gen-suppressions=all"};
- if (m_settings.trackOrigins())
+ if (m_settings.trackOrigins.value())
arguments << "--track-origins=yes";
- if (m_settings.showReachable())
+ if (m_settings.showReachable.value())
arguments << "--show-reachable=yes";
QString leakCheckValue;
- switch (m_settings.leakCheckOnFinish()) {
+ switch (m_settings.leakCheckOnFinish.value()) {
case ValgrindBaseSettings::LeakCheckOnFinishNo:
leakCheckValue = "no";
break;
@@ -212,22 +212,22 @@ QStringList MemcheckToolRunner::toolArguments() const
}
arguments << "--leak-check=" + leakCheckValue;
- foreach (const QString &file, m_settings.suppressionFiles())
+ for (const QString &file : m_settings.suppressions.value())
arguments << QString("--suppressions=%1").arg(file);
- arguments << QString("--num-callers=%1").arg(m_settings.numCallers());
+ arguments << QString("--num-callers=%1").arg(m_settings.numCallers.value());
if (m_withGdb)
arguments << "--vgdb=yes" << "--vgdb-error=0";
- arguments << Utils::QtcProcess::splitArgs(m_settings.memcheckArguments());
+ arguments << Utils::ProcessArgs::splitArgs(m_settings.memcheckArguments.value());
return arguments;
}
-QStringList MemcheckToolRunner::suppressionFiles() const
+const QStringList MemcheckToolRunner::suppressionFiles() const
{
- return m_settings.suppressionFiles();
+ return m_settings.suppressions.value();
}
void MemcheckToolRunner::startDebugger(qint64 valgrindPid)
@@ -916,22 +916,22 @@ void MemcheckToolPrivate::updateFromSettings()
foreach (const QVariant &v, action->data().toList()) {
bool ok;
int kind = v.toInt(&ok);
- if (ok && !m_settings->visibleErrorKinds().contains(kind))
+ if (ok && !m_settings->visibleErrorKinds.value().contains(kind))
contained = false;
}
action->setChecked(contained);
}
- m_filterProjectAction->setChecked(!m_settings->filterExternalIssues());
+ m_filterProjectAction->setChecked(!m_settings->filterExternalIssues.value());
m_errorView->settingsChanged(m_settings);
- connect(m_settings, &ValgrindBaseSettings::visibleErrorKindsChanged,
+ connect(&m_settings->visibleErrorKinds, &IntegersAspect::valueChanged,
&m_errorProxyModel, &MemcheckErrorFilterProxyModel::setAcceptedKinds);
- m_errorProxyModel.setAcceptedKinds(m_settings->visibleErrorKinds());
+ m_errorProxyModel.setAcceptedKinds(m_settings->visibleErrorKinds.value());
- connect(m_settings, &ValgrindBaseSettings::filterExternalIssuesChanged,
+ connect(&m_settings->filterExternalIssues, &BoolAspect::valueChanged,
&m_errorProxyModel, &MemcheckErrorFilterProxyModel::setFilterExternalIssues);
- m_errorProxyModel.setFilterExternalIssues(m_settings->filterExternalIssues());
+ m_errorProxyModel.setFilterExternalIssues(m_settings->filterExternalIssues.value());
}
void MemcheckToolPrivate::maybeActiveRunConfigurationChanged()
@@ -1006,7 +1006,7 @@ void MemcheckToolPrivate::setupRunner(MemcheckToolRunner *runTool)
void MemcheckToolPrivate::loadShowXmlLogFile(const QString &filePath, const QString &exitMsg)
{
clearErrorView();
- m_settings->setFilterExternalIssues(false);
+ m_settings->filterExternalIssues.setValue(false);
m_filterProjectAction->setChecked(true);
m_perspective.select();
Core::ModeManager::activateMode(Debugger::Constants::MODE_DEBUG);
@@ -1092,7 +1092,7 @@ void MemcheckToolPrivate::updateErrorFilter()
QTC_ASSERT(m_errorView, return);
QTC_ASSERT(m_settings, return);
- m_settings->setFilterExternalIssues(!m_filterProjectAction->isChecked());
+ m_settings->filterExternalIssues.setValue(!m_filterProjectAction->isChecked());
QList<int> errorKinds;
foreach (QAction *a, m_errorFilterActions) {
@@ -1105,7 +1105,7 @@ void MemcheckToolPrivate::updateErrorFilter()
errorKinds << kind;
}
}
- m_settings->setVisibleErrorKinds(errorKinds);
+ m_settings->visibleErrorKinds.setValue(errorKinds);
}
int MemcheckToolPrivate::updateUiAfterFinishedHelper()
diff --git a/src/plugins/valgrind/suppressiondialog.cpp b/src/plugins/valgrind/suppressiondialog.cpp
index 695aa42b02..21683db3eb 100644
--- a/src/plugins/valgrind/suppressiondialog.cpp
+++ b/src/plugins/valgrind/suppressiondialog.cpp
@@ -44,13 +44,12 @@
#include <utils/fileutils.h>
#include <utils/qtcassert.h>
-#include <QFile>
-
#include <QDialogButtonBox>
+#include <QFile>
#include <QFormLayout>
-#include <QPushButton>
#include <QLabel>
#include <QPlainTextEdit>
+#include <QPushButton>
using namespace Valgrind::XmlProtocol;
@@ -194,7 +193,7 @@ void SuppressionDialog::maybeShow(MemcheckErrorView *view)
void SuppressionDialog::accept()
{
- const QString path = m_fileChooser->filePath().toString();
+ const Utils::FilePath path = m_fileChooser->filePath();
QTC_ASSERT(!path.isEmpty(), return);
QTC_ASSERT(!m_suppressionEdit->toPlainText().trimmed().isEmpty(), return);
@@ -208,16 +207,16 @@ void SuppressionDialog::accept()
return;
// Add file to project if there is a project containing this file on the file system.
- if (!ProjectExplorer::SessionManager::projectForFile(Utils::FilePath::fromString(path))) {
+ if (!ProjectExplorer::SessionManager::projectForFile(path)) {
for (ProjectExplorer::Project *p : ProjectExplorer::SessionManager::projects()) {
if (path.startsWith(p->projectDirectory().toString())) {
- p->rootProjectNode()->addFiles(QStringList() << path);
+ p->rootProjectNode()->addFiles({path.toString()});
break;
}
}
}
- m_settings->addSuppressionFiles(QStringList(path));
+ m_settings->suppressions.addSuppressionFile(path.toString());
QModelIndexList indices = m_view->selectionModel()->selectedRows();
Utils::sort(indices, [](const QModelIndex &l, const QModelIndex &r) {
diff --git a/src/plugins/valgrind/valgrind.pro b/src/plugins/valgrind/valgrind.pro
index 34b48f76c7..f67290e76d 100644
--- a/src/plugins/valgrind/valgrind.pro
+++ b/src/plugins/valgrind/valgrind.pro
@@ -41,9 +41,6 @@ SOURCES += \
memcheckerrorview.cpp \
suppressiondialog.cpp
-FORMS += \
- valgrindconfigwidget.ui
-
RESOURCES += \
valgrind.qrc
diff --git a/src/plugins/valgrind/valgrind.qbs b/src/plugins/valgrind/valgrind.qbs
index 5714d22261..65573c3141 100644
--- a/src/plugins/valgrind/valgrind.qbs
+++ b/src/plugins/valgrind/valgrind.qbs
@@ -31,7 +31,7 @@ QtcPlugin {
"memchecktool.cpp", "memchecktool.h",
"suppressiondialog.cpp", "suppressiondialog.h",
"valgrind.qrc",
- "valgrindconfigwidget.cpp", "valgrindconfigwidget.h", "valgrindconfigwidget.ui",
+ "valgrindconfigwidget.cpp", "valgrindconfigwidget.h",
"valgrindengine.cpp", "valgrindengine.h",
"valgrindplugin.cpp", "valgrindplugin.h",
"valgrindrunner.cpp", "valgrindrunner.h",
diff --git a/src/plugins/valgrind/valgrindconfigwidget.cpp b/src/plugins/valgrind/valgrindconfigwidget.cpp
index b3f9831a90..980b04fc73 100644
--- a/src/plugins/valgrind/valgrindconfigwidget.cpp
+++ b/src/plugins/valgrind/valgrindconfigwidget.cpp
@@ -28,296 +28,83 @@
#include "valgrindsettings.h"
#include "valgrindplugin.h"
-#include "ui_valgrindconfigwidget.h"
-
#include <debugger/analyzer/analyzericons.h>
+#include <coreplugin/icore.h>
+
#include <utils/algorithm.h>
-#include <utils/hostosinfo.h>
+#include <utils/layoutbuilder.h>
#include <utils/qtcassert.h>
-#include <QDebug>
-#include <QStandardItemModel>
-#include <QFileDialog>
-
-#include <functional>
+using namespace Utils;
namespace Valgrind {
namespace Internal {
-class ValgrindBaseSettings;
-
class ValgrindConfigWidget : public Core::IOptionsPageWidget
{
Q_DECLARE_TR_FUNCTIONS(Valgrind::Internal::ValgrindConfigWidget)
public:
explicit ValgrindConfigWidget(ValgrindBaseSettings *settings);
- ~ValgrindConfigWidget() override;
void apply() final
{
+ ValgrindGlobalSettings::instance()->apply();
ValgrindGlobalSettings::instance()->writeSettings();
}
- void setSuppressions(const QStringList &files);
- QStringList suppressions() const;
-
- void slotAddSuppression();
- void slotRemoveSuppression();
- void slotSuppressionsRemoved(const QStringList &files);
- void slotSuppressionsAdded(const QStringList &files);
- void slotSuppressionSelectionChanged();
-
-private:
- void updateUi();
-
- ValgrindBaseSettings *m_settings;
- Ui::ValgrindConfigWidget *m_ui;
- QStandardItemModel *m_model;
+ void finish() final
+ {
+ ValgrindGlobalSettings::instance()->finish();
+ }
};
ValgrindConfigWidget::ValgrindConfigWidget(ValgrindBaseSettings *settings)
- : m_settings(settings),
- m_ui(new Ui::ValgrindConfigWidget)
{
- m_ui->setupUi(this);
- m_model = new QStandardItemModel(this);
-
- m_ui->valgrindExeChooser->setExpectedKind(Utils::PathChooser::ExistingCommand);
- m_ui->valgrindExeChooser->setHistoryCompleter("Valgrind.Command.History");
- m_ui->valgrindExeChooser->setPromptDialogTitle(tr("Valgrind Command"));
-
- updateUi();
- connect(m_settings, &ValgrindBaseSettings::changed, this, &ValgrindConfigWidget::updateUi);
-
- connect(m_ui->valgrindExeChooser, &Utils::PathChooser::rawPathChanged,
- m_settings, &ValgrindBaseSettings::setValgrindExecutable);
-
- connect(m_ui->valgrindArgumentsLineEdit, &QLineEdit::textChanged,
- m_settings, &ValgrindBaseSettings::setValgrindArguments);
- connect(m_settings, &ValgrindBaseSettings::valgrindArgumentsChanged,
- m_ui->valgrindArgumentsLineEdit, &QLineEdit::setText);
-
- connect(m_ui->smcDetectionComboBox, QOverload<int>::of(&QComboBox::currentIndexChanged),
- m_settings, &ValgrindBaseSettings::setSelfModifyingCodeDetection);
-
- if (Utils::HostOsInfo::isWindowsHost()) {
- // FIXME: On Window we know that we don't have a local valgrind
- // executable, so having the "Browse" button in the path chooser
- // (which is needed for the remote executable) is confusing.
- m_ui->valgrindExeChooser->buttonAtIndex(0)->hide();
- }
-
- //
- // Callgrind
- //
- m_ui->kcachegrindExeChooser->setExpectedKind(Utils::PathChooser::ExistingCommand);
- m_ui->kcachegrindExeChooser->setPromptDialogTitle(tr("KCachegrind Command"));
- connect(m_ui->callgrindArgumentsLineEdit, &QLineEdit::textChanged,
- m_settings, &ValgrindBaseSettings::setCallgrindArguments);
- connect(m_settings, &ValgrindBaseSettings::callgrindArgumentsChanged,
- m_ui->callgrindArgumentsLineEdit, &QLineEdit::setText);
-
- connect(m_ui->kcachegrindExeChooser, &Utils::PathChooser::rawPathChanged,
- m_settings, &ValgrindBaseSettings::setKCachegrindExecutable);
- connect(m_ui->enableCacheSim, &QCheckBox::toggled,
- m_settings, &ValgrindBaseSettings::setEnableCacheSim);
- connect(m_settings, &ValgrindBaseSettings::enableCacheSimChanged,
- m_ui->enableCacheSim, &QAbstractButton::setChecked);
-
- connect(m_ui->enableBranchSim, &QCheckBox::toggled,
- m_settings, &ValgrindBaseSettings::setEnableBranchSim);
- connect(m_settings, &ValgrindBaseSettings::enableBranchSimChanged,
- m_ui->enableBranchSim, &QAbstractButton::setChecked);
-
- connect(m_ui->collectSystime, &QCheckBox::toggled,
- m_settings, &ValgrindBaseSettings::setCollectSystime);
- connect(m_settings, &ValgrindBaseSettings::collectSystimeChanged,
- m_ui->collectSystime, &QAbstractButton::setChecked);
-
- connect(m_ui->collectBusEvents, &QCheckBox::toggled,
- m_settings, &ValgrindBaseSettings::setCollectBusEvents);
- connect(m_settings, &ValgrindBaseSettings::collectBusEventsChanged,
- m_ui->collectBusEvents, &QAbstractButton::setChecked);
-
- connect(m_ui->enableEventToolTips, &QGroupBox::toggled,
- m_settings, &ValgrindBaseSettings::setEnableEventToolTips);
- connect(m_settings, &ValgrindBaseSettings::enableEventToolTipsChanged,
- m_ui->enableEventToolTips, &QGroupBox::setChecked);
-
- connect(m_ui->minimumInclusiveCostRatio, QOverload<double>::of(&QDoubleSpinBox::valueChanged),
- m_settings, &ValgrindBaseSettings::setMinimumInclusiveCostRatio);
- connect(m_settings, &ValgrindBaseSettings::minimumInclusiveCostRatioChanged,
- m_ui->minimumInclusiveCostRatio, &QDoubleSpinBox::setValue);
-
- connect(m_ui->visualisationMinimumInclusiveCostRatio, QOverload<double>::of(&QDoubleSpinBox::valueChanged),
- m_settings, &ValgrindBaseSettings::setVisualisationMinimumInclusiveCostRatio);
- connect(m_settings, &ValgrindBaseSettings::visualisationMinimumInclusiveCostRatioChanged,
- m_ui->visualisationMinimumInclusiveCostRatio, &QDoubleSpinBox::setValue);
-
- //
- // Memcheck
- //
- m_ui->suppressionList->setModel(m_model);
- m_ui->suppressionList->setSelectionMode(QAbstractItemView::MultiSelection);
-
- connect(m_ui->memcheckArgumentsLineEdit, &QLineEdit::textChanged,
- m_settings, &ValgrindBaseSettings::setMemcheckArguments);
- connect(m_settings, &ValgrindBaseSettings::memcheckArgumentsChanged,
- m_ui->memcheckArgumentsLineEdit, &QLineEdit::setText);
-
- connect(m_ui->addSuppression, &QPushButton::clicked, this, &ValgrindConfigWidget::slotAddSuppression);
- connect(m_ui->removeSuppression, &QPushButton::clicked, this, &ValgrindConfigWidget::slotRemoveSuppression);
-
- connect(m_ui->numCallers, QOverload<int>::of(&QSpinBox::valueChanged),
- m_settings, &ValgrindBaseSettings::setNumCallers);
- connect(m_settings, &ValgrindBaseSettings::numCallersChanged,
- m_ui->numCallers, &QSpinBox::setValue);
-
- connect(m_ui->leakCheckOnFinish, QOverload<int>::of(&QComboBox::currentIndexChanged),
- m_settings, &ValgrindBaseSettings::setLeakCheckOnFinish);
- connect(m_settings, &ValgrindBaseSettings::leakCheckOnFinishChanged,
- m_ui->leakCheckOnFinish, &QComboBox::setCurrentIndex);
-
- connect(m_ui->showReachable, &QCheckBox::toggled,
- m_settings, &ValgrindBaseSettings::setShowReachable);
- connect(m_settings, &ValgrindBaseSettings::showReachableChanged,
- m_ui->showReachable, &QAbstractButton::setChecked);
-
- connect(m_ui->trackOrigins, &QCheckBox::toggled, m_settings, &ValgrindBaseSettings::setTrackOrigins);
- connect(m_settings, &ValgrindBaseSettings::trackOriginsChanged,
- m_ui->trackOrigins, &QAbstractButton::setChecked);
-
- connect(m_settings, &ValgrindBaseSettings::suppressionFilesRemoved,
- this, &ValgrindConfigWidget::slotSuppressionsRemoved);
- connect(m_settings, &ValgrindBaseSettings::suppressionFilesAdded,
- this, &ValgrindConfigWidget::slotSuppressionsAdded);
-
- connect(m_ui->suppressionList->selectionModel(), &QItemSelectionModel::selectionChanged,
- this, &ValgrindConfigWidget::slotSuppressionSelectionChanged);
- slotSuppressionSelectionChanged();
-
- if (settings != ValgrindGlobalSettings::instance()) {
- // In project settings we want a flat vertical list.
- auto l = new QVBoxLayout;
- while (layout()->count()) {
- QLayoutItem *item = layout()->takeAt(0);
- if (QWidget *w = item->widget())
- l->addWidget(w);
- delete item;
+ using namespace Layouting;
+ const Break nl;
+ ValgrindBaseSettings &s = *settings;
+
+ Grid generic {
+ s.valgrindExecutable, nl,
+ s.valgrindArguments, nl,
+ s.selfModifyingCodeDetection, nl
+ };
+
+ Grid memcheck {
+ s.memcheckArguments, nl,
+ s.trackOrigins, nl,
+ s.showReachable, nl,
+ s.leakCheckOnFinish, nl,
+ s.numCallers, nl,
+ s.filterExternalIssues, nl,
+ s.suppressions
+ };
+
+ Grid callgrind {
+ s.callgrindArguments, nl,
+ s.kcachegrindExecutable, nl,
+ s.minimumInclusiveCostRatio, nl,
+ s.visualizationMinimumInclusiveCostRatio, nl,
+ s.enableEventToolTips, nl,
+ Span {
+ 2,
+ Group {
+ s.enableCacheSim,
+ s.enableBranchSim,
+ s.collectSystime,
+ s.collectBusEvents,
+ }
}
- delete layout();
- setLayout(l);
- }
-}
-
-ValgrindConfigWidget::~ValgrindConfigWidget()
-{
- delete m_ui;
-}
-
-void ValgrindConfigWidget::updateUi()
-{
- m_ui->valgrindExeChooser->setPath(m_settings->valgrindExecutable());
- m_ui->valgrindArgumentsLineEdit->setText(m_settings->valgrindArguments());
- m_ui->memcheckArgumentsLineEdit->setText(m_settings->memcheckArguments());
- m_ui->callgrindArgumentsLineEdit->setText(m_settings->callgrindArguments());
- m_ui->smcDetectionComboBox->setCurrentIndex(m_settings->selfModifyingCodeDetection());
- m_ui->kcachegrindExeChooser->setPath(m_settings->kcachegrindExecutable());
- m_ui->enableCacheSim->setChecked(m_settings->enableCacheSim());
- m_ui->enableBranchSim->setChecked(m_settings->enableBranchSim());
- m_ui->collectSystime->setChecked(m_settings->collectSystime());
- m_ui->collectBusEvents->setChecked(m_settings->collectBusEvents());
- m_ui->enableEventToolTips->setChecked(m_settings->enableEventToolTips());
- m_ui->minimumInclusiveCostRatio->setValue(m_settings->minimumInclusiveCostRatio());
- m_ui->visualisationMinimumInclusiveCostRatio->setValue(m_settings->visualisationMinimumInclusiveCostRatio());
- m_ui->numCallers->setValue(m_settings->numCallers());
- m_ui->leakCheckOnFinish->setCurrentIndex(m_settings->leakCheckOnFinish());
- m_ui->showReachable->setChecked(m_settings->showReachable());
- m_ui->trackOrigins->setChecked(m_settings->trackOrigins());
- m_model->clear();
- foreach (const QString &file, m_settings->suppressionFiles())
- m_model->appendRow(new QStandardItem(file));
-}
-
-void ValgrindConfigWidget::slotAddSuppression()
-{
- ValgrindGlobalSettings *conf = ValgrindGlobalSettings::instance();
- QTC_ASSERT(conf, return);
- QStringList files = QFileDialog::getOpenFileNames(this,
- tr("Valgrind Suppression Files"),
- conf->lastSuppressionDialogDirectory(),
- tr("Valgrind Suppression File (*.supp);;All Files (*)"));
- //dialog.setHistory(conf->lastSuppressionDialogHistory());
- if (!files.isEmpty()) {
- foreach (const QString &file, files)
- m_model->appendRow(new QStandardItem(file));
- m_settings->addSuppressionFiles(files);
- conf->setLastSuppressionDialogDirectory(QFileInfo(files.at(0)).absolutePath());
- //conf->setLastSuppressionDialogHistory(dialog.history());
- }
-}
-
-void ValgrindConfigWidget::slotSuppressionsAdded(const QStringList &files)
-{
- QStringList filesToAdd = files;
- for (int i = 0, c = m_model->rowCount(); i < c; ++i)
- filesToAdd.removeAll(m_model->item(i)->text());
-
- foreach (const QString &file, filesToAdd)
- m_model->appendRow(new QStandardItem(file));
-}
-
-void ValgrindConfigWidget::slotRemoveSuppression()
-{
- // remove from end so no rows get invalidated
- QList<int> rows;
-
- QStringList removed;
- foreach (const QModelIndex &index, m_ui->suppressionList->selectionModel()->selectedIndexes()) {
- rows << index.row();
- removed << index.data().toString();
- }
-
- Utils::sort(rows, std::greater<int>());
-
- foreach (int row, rows)
- m_model->removeRow(row);
-
- m_settings->removeSuppressionFiles(removed);
-}
-
-void ValgrindConfigWidget::slotSuppressionsRemoved(const QStringList &files)
-{
- for (int i = 0; i < m_model->rowCount(); ++i) {
- if (files.contains(m_model->item(i)->text())) {
- m_model->removeRow(i);
- --i;
- }
- }
-}
-
-void ValgrindConfigWidget::setSuppressions(const QStringList &files)
-{
- m_model->clear();
- foreach (const QString &file, files)
- m_model->appendRow(new QStandardItem(file));
-}
-
-QStringList ValgrindConfigWidget::suppressions() const
-{
- QStringList ret;
-
- for (int i = 0; i < m_model->rowCount(); ++i)
- ret << m_model->item(i)->text();
-
- return ret;
-}
-
-void ValgrindConfigWidget::slotSuppressionSelectionChanged()
-{
- m_ui->removeSuppression->setEnabled(m_ui->suppressionList->selectionModel()->hasSelection());
+ };
+
+ Column {
+ Group { Title(tr("Valgrind Generic Settings")), generic },
+ Group { Title(tr("MemCheck Memory Analysis Options")), memcheck },
+ Group { Title(tr("CallGrind Profiling Options")), callgrind },
+ Stretch(),
+ }.attachTo(this);
}
// ValgrindOptionsPage
diff --git a/src/plugins/valgrind/valgrindconfigwidget.ui b/src/plugins/valgrind/valgrindconfigwidget.ui
deleted file mode 100644
index 474cde1861..0000000000
--- a/src/plugins/valgrind/valgrindconfigwidget.ui
+++ /dev/null
@@ -1,503 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<ui version="4.0">
- <class>Valgrind::Internal::ValgrindConfigWidget</class>
- <widget class="QWidget" name="Valgrind::Internal::ValgrindConfigWidget">
- <property name="geometry">
- <rect>
- <x>0</x>
- <y>0</y>
- <width>727</width>
- <height>658</height>
- </rect>
- </property>
- <layout class="QGridLayout" name="gridLayout">
- <item row="0" column="0" colspan="2">
- <widget class="QGroupBox" name="commonValgrindOptions">
- <property name="sizePolicy">
- <sizepolicy hsizetype="Preferred" vsizetype="Expanding">
- <horstretch>0</horstretch>
- <verstretch>0</verstretch>
- </sizepolicy>
- </property>
- <property name="title">
- <string>Valgrind Generic Settings</string>
- </property>
- <layout class="QGridLayout" name="gridLayout_2">
- <item row="2" column="1">
- <layout class="QHBoxLayout" name="horizontalLayout_2">
- <item>
- <widget class="QComboBox" name="smcDetectionComboBox">
- <property name="currentIndex">
- <number>1</number>
- </property>
- <item>
- <property name="text">
- <string>No</string>
- </property>
- </item>
- <item>
- <property name="text">
- <string>Only on Stack</string>
- </property>
- </item>
- <item>
- <property name="text">
- <string>Everywhere</string>
- </property>
- </item>
- <item>
- <property name="text">
- <string>Everywhere Except in File-backend Mappings</string>
- </property>
- </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>
- </item>
- </layout>
- </item>
- <item row="0" column="0">
- <widget class="QLabel" name="valgrindExeLabel">
- <property name="text">
- <string>Valgrind executable:</string>
- </property>
- </widget>
- </item>
- <item row="0" column="1">
- <widget class="Utils::PathChooser" name="valgrindExeChooser" native="true">
- <property name="sizePolicy">
- <sizepolicy hsizetype="Preferred" vsizetype="Preferred">
- <horstretch>1</horstretch>
- <verstretch>0</verstretch>
- </sizepolicy>
- </property>
- </widget>
- </item>
- <item row="2" column="0">
- <widget class="QLabel" name="smcDetectionLabel">
- <property name="text">
- <string>Detect self-modifying code:</string>
- </property>
- </widget>
- </item>
- <item row="1" column="0">
- <widget class="QLabel" name="valgrindArgumentsLabel">
- <property name="text">
- <string>Valgrind arguments:</string>
- </property>
- </widget>
- </item>
- <item row="1" column="1">
- <widget class="QLineEdit" name="valgrindArgumentsLineEdit"/>
- </item>
- </layout>
- </widget>
- </item>
- <item row="3" column="0">
- <spacer name="verticalSpacer">
- <property name="orientation">
- <enum>Qt::Vertical</enum>
- </property>
- <property name="sizeType">
- <enum>QSizePolicy::Expanding</enum>
- </property>
- <property name="sizeHint" stdset="0">
- <size>
- <width>1</width>
- <height>500</height>
- </size>
- </property>
- </spacer>
- </item>
- <item row="1" column="0">
- <widget class="QGroupBox" name="memcheckOptions">
- <property name="sizePolicy">
- <sizepolicy hsizetype="Preferred" vsizetype="Preferred">
- <horstretch>0</horstretch>
- <verstretch>0</verstretch>
- </sizepolicy>
- </property>
- <property name="title">
- <string>MemCheck Memory Analysis Options</string>
- </property>
- <layout class="QFormLayout" name="formLayout">
- <item row="1" column="0" colspan="2">
- <widget class="QCheckBox" name="trackOrigins">
- <property name="text">
- <string>Track origins of uninitialized memory</string>
- </property>
- <property name="checked">
- <bool>true</bool>
- </property>
- </widget>
- </item>
- <item row="2" column="0" colspan="2">
- <widget class="QCheckBox" name="showReachable">
- <property name="text">
- <string>Show reachable and indirectly lost blocks</string>
- </property>
- </widget>
- </item>
- <item row="3" column="0">
- <widget class="QLabel" name="leakCheckOnFinishLabel">
- <property name="text">
- <string>Check for leaks on finish:</string>
- </property>
- </widget>
- </item>
- <item row="3" column="1">
- <layout class="QHBoxLayout" name="horizontalLayout_3">
- <item>
- <widget class="QComboBox" name="leakCheckOnFinish">
- <property name="currentIndex">
- <number>0</number>
- </property>
- <item>
- <property name="text">
- <string>No</string>
- </property>
- </item>
- <item>
- <property name="text">
- <string>Summary Only</string>
- </property>
- </item>
- <item>
- <property name="text">
- <string>Full</string>
- </property>
- </item>
- </widget>
- </item>
- <item>
- <spacer name="horizontalSpacer_2">
- <property name="orientation">
- <enum>Qt::Horizontal</enum>
- </property>
- <property name="sizeHint" stdset="0">
- <size>
- <width>40</width>
- <height>20</height>
- </size>
- </property>
- </spacer>
- </item>
- </layout>
- </item>
- <item row="4" column="0">
- <widget class="QLabel" name="numCallersLabel">
- <property name="text">
- <string>Backtrace frame count:</string>
- </property>
- <property name="buddy">
- <cstring>numCallers</cstring>
- </property>
- </widget>
- </item>
- <item row="4" column="1">
- <layout class="QHBoxLayout" name="horizontalLayout_4">
- <item>
- <widget class="QSpinBox" name="numCallers">
- <property name="minimum">
- <number>5</number>
- </property>
- <property name="maximum">
- <number>50</number>
- </property>
- <property name="value">
- <number>12</number>
- </property>
- </widget>
- </item>
- <item>
- <spacer name="horizontalSpacer_3">
- <property name="orientation">
- <enum>Qt::Horizontal</enum>
- </property>
- <property name="sizeHint" stdset="0">
- <size>
- <width>40</width>
- <height>20</height>
- </size>
- </property>
- </spacer>
- </item>
- </layout>
- </item>
- <item row="5" column="0">
- <widget class="QLabel" name="label">
- <property name="text">
- <string>Suppression files:</string>
- </property>
- <property name="buddy">
- <cstring>suppressionList</cstring>
- </property>
- </widget>
- </item>
- <item row="6" column="0" colspan="2">
- <layout class="QHBoxLayout" name="horizontalLayout">
- <item>
- <widget class="QListView" name="suppressionList">
- <property name="sizePolicy">
- <sizepolicy hsizetype="Expanding" vsizetype="Expanding">
- <horstretch>0</horstretch>
- <verstretch>1</verstretch>
- </sizepolicy>
- </property>
- </widget>
- </item>
- <item>
- <layout class="QVBoxLayout" name="verticalLayout_2" stretch="0,0,1">
- <property name="sizeConstraint">
- <enum>QLayout::SetMinimumSize</enum>
- </property>
- <item>
- <widget class="QPushButton" name="addSuppression">
- <property name="text">
- <string>Add...</string>
- </property>
- </widget>
- </item>
- <item>
- <widget class="QPushButton" name="removeSuppression">
- <property name="text">
- <string>Remove</string>
- </property>
- <property name="flat">
- <bool>false</bool>
- </property>
- </widget>
- </item>
- <item>
- <spacer name="verticalSpacer_2">
- <property name="orientation">
- <enum>Qt::Vertical</enum>
- </property>
- <property name="sizeHint" stdset="0">
- <size>
- <width>20</width>
- <height>40</height>
- </size>
- </property>
- </spacer>
- </item>
- </layout>
- </item>
- </layout>
- </item>
- <item row="0" column="0">
- <widget class="QLabel" name="memcheckArgumentsLabel">
- <property name="text">
- <string>Extra MemCheck arguments:</string>
- </property>
- </widget>
- </item>
- <item row="0" column="1">
- <widget class="QLineEdit" name="memcheckArgumentsLineEdit"/>
- </item>
- </layout>
- </widget>
- </item>
- <item row="2" column="0">
- <widget class="QGroupBox" name="memcheckOptions_2">
- <property name="sizePolicy">
- <sizepolicy hsizetype="Preferred" vsizetype="Preferred">
- <horstretch>0</horstretch>
- <verstretch>0</verstretch>
- </sizepolicy>
- </property>
- <property name="title">
- <string>CallGrind Profiling Options</string>
- </property>
- <layout class="QFormLayout" name="formLayout_2">
- <item row="2" column="0">
- <widget class="QLabel" name="minimumInclusiveCostRatioLabel">
- <property name="toolTip">
- <string>Limits the amount of results the profiler gives you. A lower limit will likely increase performance.</string>
- </property>
- <property name="text">
- <string>Result view: Minimum event cost:</string>
- </property>
- <property name="buddy">
- <cstring>minimumInclusiveCostRatio</cstring>
- </property>
- </widget>
- </item>
- <item row="2" column="1">
- <widget class="QDoubleSpinBox" name="minimumInclusiveCostRatio">
- <property name="suffix">
- <string>%</string>
- </property>
- <property name="decimals">
- <number>2</number>
- </property>
- <property name="maximum">
- <double>10.000000000000000</double>
- </property>
- <property name="singleStep">
- <double>0.100000000000000</double>
- </property>
- </widget>
- </item>
- <item row="4" column="0" colspan="2">
- <widget class="QGroupBox" name="enableEventToolTips">
- <property name="title">
- <string>Show additional information for events in tooltips</string>
- </property>
- <property name="checkable">
- <bool>true</bool>
- </property>
- <layout class="QGridLayout" name="gridLayout_3">
- <item row="0" column="0">
- <widget class="QCheckBox" name="enableCacheSim">
- <property name="toolTip">
- <string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;
-&lt;p&gt;Does full cache simulation.&lt;/p&gt;
-&lt;p&gt;By default, only instruction read accesses will be counted (&quot;Ir&quot;).&lt;/p&gt;
-&lt;p&gt;
-With cache simulation, further event counters are enabled:
-&lt;ul&gt;&lt;li&gt;Cache misses on instruction reads (&quot;I1mr&quot;/&quot;I2mr&quot;).&lt;/li&gt;
-&lt;li&gt;Data read accesses (&quot;Dr&quot;) and related cache misses (&quot;D1mr&quot;/&quot;D2mr&quot;).&lt;/li&gt;
-&lt;li&gt;Data write accesses (&quot;Dw&quot;) and related cache misses (&quot;D1mw&quot;/&quot;D2mw&quot;).&lt;/li&gt;&lt;/ul&gt;
-&lt;/p&gt;
-
-&lt;/body&gt;&lt;/html&gt;</string>
- </property>
- <property name="text">
- <string>Enable cache simulation</string>
- </property>
- </widget>
- </item>
- <item row="1" column="0">
- <widget class="QCheckBox" name="enableBranchSim">
- <property name="toolTip">
- <string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;
-&lt;p&gt;Does branch prediction simulation.&lt;/p&gt;
-&lt;p&gt;Further event counters are enabled: &lt;/p&gt;
-&lt;ul&gt;&lt;li&gt;Number of executed conditional branches and related predictor misses (
-&quot;Bc&quot;/&quot;Bcm&quot;).&lt;/li&gt;
-&lt;li&gt;Executed indirect jumps and related misses of the jump address predictor (
-&quot;Bi&quot;/&quot;Bim&quot;).&lt;/li&gt;&lt;/ul&gt;&lt;/body&gt;&lt;/html&gt;</string>
- </property>
- <property name="text">
- <string>Enable branch prediction simulation</string>
- </property>
- </widget>
- </item>
- <item row="2" column="0">
- <widget class="QCheckBox" name="collectSystime">
- <property name="toolTip">
- <string>Collects information for system call times.</string>
- </property>
- <property name="text">
- <string>Collect system call time</string>
- </property>
- </widget>
- </item>
- <item row="3" column="0">
- <widget class="QCheckBox" name="collectBusEvents">
- <property name="toolTip">
- <string>Collect the number of global bus events that are executed. The event type &quot;Ge&quot; is used for these events.</string>
- </property>
- <property name="text">
- <string>Collect global bus events</string>
- </property>
- </widget>
- </item>
- </layout>
- </widget>
- </item>
- <item row="3" column="0">
- <widget class="QLabel" name="visualisationMinimumInclusiveCostRatioLabel">
- <property name="text">
- <string>Visualization: Minimum event cost:</string>
- </property>
- </widget>
- </item>
- <item row="3" column="1">
- <widget class="QDoubleSpinBox" name="visualisationMinimumInclusiveCostRatio">
- <property name="prefix">
- <string/>
- </property>
- <property name="suffix">
- <string>%</string>
- </property>
- <property name="minimum">
- <double>0.000000000000000</double>
- </property>
- <property name="maximum">
- <double>50.000000000000000</double>
- </property>
- </widget>
- </item>
- <item row="1" column="0">
- <widget class="QLabel" name="kcachgrindExeLabel">
- <property name="text">
- <string>KCachegrind executable:</string>
- </property>
- </widget>
- </item>
- <item row="1" column="1">
- <widget class="Utils::PathChooser" name="kcachegrindExeChooser" native="true">
- <property name="sizePolicy">
- <sizepolicy hsizetype="Preferred" vsizetype="Preferred">
- <horstretch>1</horstretch>
- <verstretch>0</verstretch>
- </sizepolicy>
- </property>
- </widget>
- </item>
- <item row="0" column="0">
- <widget class="QLabel" name="callgrindArgumentsLabel">
- <property name="text">
- <string>Extra CallGrind arguments:</string>
- </property>
- </widget>
- </item>
- <item row="0" column="1">
- <widget class="QLineEdit" name="callgrindArgumentsLineEdit"/>
- </item>
- </layout>
- </widget>
- </item>
- </layout>
- </widget>
- <customwidgets>
- <customwidget>
- <class>Utils::PathChooser</class>
- <extends>QWidget</extends>
- <header location="global">utils/pathchooser.h</header>
- <container>1</container>
- </customwidget>
- </customwidgets>
- <tabstops>
- <tabstop>smcDetectionComboBox</tabstop>
- <tabstop>trackOrigins</tabstop>
- <tabstop>showReachable</tabstop>
- <tabstop>leakCheckOnFinish</tabstop>
- <tabstop>numCallers</tabstop>
- <tabstop>suppressionList</tabstop>
- <tabstop>addSuppression</tabstop>
- <tabstop>removeSuppression</tabstop>
- <tabstop>minimumInclusiveCostRatio</tabstop>
- <tabstop>visualisationMinimumInclusiveCostRatio</tabstop>
- <tabstop>enableEventToolTips</tabstop>
- <tabstop>enableCacheSim</tabstop>
- <tabstop>enableBranchSim</tabstop>
- <tabstop>collectSystime</tabstop>
- <tabstop>collectBusEvents</tabstop>
- </tabstops>
- <resources/>
- <connections/>
-</ui>
diff --git a/src/plugins/valgrind/valgrindengine.cpp b/src/plugins/valgrind/valgrindengine.cpp
index 5b6e378a0f..0e7fc99d90 100644
--- a/src/plugins/valgrind/valgrindengine.cpp
+++ b/src/plugins/valgrind/valgrindengine.cpp
@@ -77,8 +77,8 @@ void ValgrindToolRunner::start()
emit outputReceived(tr("Command line arguments: %1").arg(runnable().debuggeeArgs), LogMessageFormat);
#endif
- CommandLine valgrind{m_settings.valgrindExecutable()};
- valgrind.addArgs(m_settings.valgrindArguments(), CommandLine::Raw);
+ CommandLine valgrind{m_settings.valgrindExecutable.value()};
+ valgrind.addArgs(m_settings.valgrindArguments.value(), CommandLine::Raw);
valgrind.addArgs(genericToolArguments());
valgrind.addArgs(toolArguments());
@@ -124,7 +124,7 @@ QStringList ValgrindToolRunner::genericToolArguments() const
{
QString smcCheckValue;
- switch (m_settings.selfModifyingCodeDetection()) {
+ switch (m_settings.selfModifyingCodeDetection.value()) {
case ValgrindBaseSettings::DetectSmcNo:
smcCheckValue = "none";
break;
@@ -175,7 +175,7 @@ void ValgrindToolRunner::receiveProcessOutput(const QString &output, OutputForma
void ValgrindToolRunner::receiveProcessError(const QString &message, QProcess::ProcessError error)
{
if (error == QProcess::FailedToStart) {
- const QString valgrind = m_settings.valgrindExecutable();
+ const QString valgrind = m_settings.valgrindExecutable.value();
if (!valgrind.isEmpty())
appendMessage(tr("Error: \"%1\" could not be started: %2").arg(valgrind, message), ErrorMessageFormat);
else
diff --git a/src/plugins/valgrind/valgrindsettings.cpp b/src/plugins/valgrind/valgrindsettings.cpp
index f6cfcc224b..8d5bcb573a 100644
--- a/src/plugins/valgrind/valgrindsettings.cpp
+++ b/src/plugins/valgrind/valgrindsettings.cpp
@@ -29,300 +29,426 @@
#include "valgrindconfigwidget.h"
#include <coreplugin/icore.h>
+
+#include <utils/layoutbuilder.h>
#include <utils/qtcassert.h>
+#include <utils/treemodel.h>
+#include <utils/utilsicons.h>
+
#include <valgrind/xmlprotocol/error.h>
-#include <QSettings>
#include <QDebug>
+#include <QFileDialog>
+#include <QListView>
+#include <QPushButton>
+#include <QSettings>
+#include <QStandardItemModel>
-const char numCallersC[] = "Analyzer.Valgrind.NumCallers";
-const char leakCheckOnFinishC[] = "Analyzer.Valgrind.LeakCheckOnFinish";
-const char showReachableC[] = "Analyzer.Valgrind.ShowReachable";
-const char trackOriginsC[] = "Analyzer.Valgrind.TrackOrigins";
-const char selfModifyingCodeDetectionC[] = "Analyzer.Valgrind.SelfModifyingCodeDetection";
-const char suppressionFilesC[] = "Analyzer.Valgrind.SupressionFiles";
-const char removedSuppressionFilesC[] = "Analyzer.Valgrind.RemovedSuppressionFiles";
-const char addedSuppressionFilesC[] = "Analyzer.Valgrind.AddedSuppressionFiles";
-const char filterExternalIssuesC[] = "Analyzer.Valgrind.FilterExternalIssues";
-const char visibleErrorKindsC[] = "Analyzer.Valgrind.VisibleErrorKinds";
-const char memcheckArgumentsC[] = "Analyzer.Valgrind.Memcheck.Arguments";
-
-const char lastSuppressionDirectoryC[] = "Analyzer.Valgrind.LastSuppressionDirectory";
-const char lastSuppressionHistoryC[] = "Analyzer.Valgrind.LastSuppressionHistory";
-
-const char kcachegrindExeC[] = "Analyzer.Valgrind.KCachegrindExecutable";
-const char callgrindEnableCacheSimC[] = "Analyzer.Valgrind.Callgrind.EnableCacheSim";
-const char callgrindEnableBranchSimC[] = "Analyzer.Valgrind.Callgrind.EnableBranchSim";
-const char callgrindCollectSystimeC[] = "Analyzer.Valgrind.Callgrind.CollectSystime";
-const char callgrindCollectBusEventsC[] = "Analyzer.Valgrind.Callgrind.CollectBusEvents";
-const char callgrindEnableEventToolTipsC[] = "Analyzer.Valgrind.Callgrind.EnableEventToolTips";
-const char callgrindMinimumCostRatioC[] = "Analyzer.Valgrind.Callgrind.MinimumCostRatio";
-const char callgrindVisualisationMinimumCostRatioC[] = "Analyzer.Valgrind.Callgrind.VisualisationMinimumCostRatio";
-
-const char callgrindCycleDetectionC[] = "Analyzer.Valgrind.Callgrind.CycleDetection";
-const char callgrindShortenTemplates[] = "Analyzer.Valgrind.Callgrind.ShortenTemplates";
-const char callgrindCostFormatC[] = "Analyzer.Valgrind.Callgrind.CostFormat";
-const char callgrindArgumentsC[] = "Analyzer.Valgrind.Callgrind.Arguments";
-
-const char valgrindExeC[] = "Analyzer.Valgrind.ValgrindExecutable";
-const char valgrindArgumentsC[] = "Analyzer.Valgrind.ValgrindArguments";
+using namespace Utils;
namespace Valgrind {
namespace Internal {
-//////////////////////////////////////////////////////////////////
//
-// ValgrindBaseSettings
+// SuppressionAspect
//
-//////////////////////////////////////////////////////////////////
-/**
- * Utility function to set @p val if @p key is present in @p map.
- */
-template <typename T> void setIfPresent(const QVariantMap &map, const QString &key, T *val)
-{
- if (map.contains(key))
- *val = map.value(key).template value<T>();
-}
+// This is somewhat unusual, as it looks the same in Global Settings and Project
+// settings, but behaves differently (Project only stores a diff) depending on
+// context.
-ValgrindBaseSettings::ValgrindBaseSettings() = default;
+const char globalSuppressionKey[] = "Analyzer.Valgrind.SupressionFiles";
+const char removedProjectSuppressionKey[] = "Analyzer.Valgrind.RemovedSuppressionFiles";
+const char addedProjectSuppressionKey[] = "Analyzer.Valgrind.AddedSuppressionFiles";
-void ValgrindBaseSettings::fromMap(const QVariantMap &map)
+class SuppressionAspectPrivate : public QObject
{
- // General
- setIfPresent(map, valgrindExeC, &m_valgrindExecutable);
- setIfPresent(map, valgrindArgumentsC, &m_valgrindArguments);
- setIfPresent(map, selfModifyingCodeDetectionC,
- (int*) &m_selfModifyingCodeDetection);
+ Q_DECLARE_TR_FUNCTIONS(Valgrind::Internal::ValgrindConfigWidget)
- // Memcheck
- setIfPresent(map, numCallersC, &m_numCallers);
- setIfPresent(map, memcheckArgumentsC, &m_memcheckArguments);
- setIfPresent(map, leakCheckOnFinishC, (int*) &m_leakCheckOnFinish);
- setIfPresent(map, showReachableC, &m_showReachable);
- setIfPresent(map, trackOriginsC, &m_trackOrigins);
- setIfPresent(map, filterExternalIssuesC, &m_filterExternalIssues);
- if (map.contains(visibleErrorKindsC)) {
- m_visibleErrorKinds.clear();
- foreach (const QVariant &val, map.value(visibleErrorKindsC).toList())
- m_visibleErrorKinds << val.toInt();
- }
+public:
+ SuppressionAspectPrivate(SuppressionAspect *q, bool global) : q(q), isGlobal(global) {}
- // Callgrind
- setIfPresent(map, callgrindArgumentsC, &m_callgrindArguments);
- setIfPresent(map, kcachegrindExeC, &m_kcachegrindExecutable);
- setIfPresent(map, callgrindEnableCacheSimC, &m_enableCacheSim);
- setIfPresent(map, callgrindEnableBranchSimC, &m_enableBranchSim);
- setIfPresent(map, callgrindCollectSystimeC, &m_collectSystime);
- setIfPresent(map, callgrindCollectBusEventsC, &m_collectBusEvents);
- setIfPresent(map, callgrindEnableEventToolTipsC, &m_enableEventToolTips);
- setIfPresent(map, callgrindMinimumCostRatioC, &m_minimumInclusiveCostRatio);
- setIfPresent(map, callgrindVisualisationMinimumCostRatioC,
- &m_visualisationMinimumInclusiveCostRatio);
-
- emit changed();
-}
+ void slotAddSuppression();
+ void slotRemoveSuppression();
+ void slotSuppressionSelectionChanged();
-void ValgrindBaseSettings::toMap(QVariantMap &map) const
-{
- // General
- map.insert(valgrindExeC, m_valgrindExecutable);
- map.insert(valgrindArgumentsC, m_valgrindArguments);
- map.insert(selfModifyingCodeDetectionC, m_selfModifyingCodeDetection);
+ SuppressionAspect *q;
+ const bool isGlobal;
- // Memcheck
- map.insert(memcheckArgumentsC, m_memcheckArguments);
- map.insert(numCallersC, m_numCallers);
- map.insert(leakCheckOnFinishC, m_leakCheckOnFinish);
- map.insert(showReachableC, m_showReachable);
- map.insert(trackOriginsC, m_trackOrigins);
- map.insert(filterExternalIssuesC, m_filterExternalIssues);
- QVariantList errorKinds;
- foreach (int i, m_visibleErrorKinds)
- errorKinds << i;
- map.insert(visibleErrorKindsC, errorKinds);
+ QPointer<QPushButton> addEntry;
+ QPointer<QPushButton> removeEntry;
+ QPointer<QListView> entryList;
- // Callgrind
- map.insert(callgrindArgumentsC, m_callgrindArguments);
- map.insert(kcachegrindExeC, m_kcachegrindExecutable);
- map.insert(callgrindEnableCacheSimC, m_enableCacheSim);
- map.insert(callgrindEnableBranchSimC, m_enableBranchSim);
- map.insert(callgrindCollectSystimeC, m_collectSystime);
- map.insert(callgrindCollectBusEventsC, m_collectBusEvents);
- map.insert(callgrindEnableEventToolTipsC, m_enableEventToolTips);
- map.insert(callgrindMinimumCostRatioC, m_minimumInclusiveCostRatio);
- map.insert(callgrindVisualisationMinimumCostRatioC,
- m_visualisationMinimumInclusiveCostRatio);
-}
+ QStandardItemModel m_model; // The volatile value of this aspect.
-void ValgrindBaseSettings::setValgrindExecutable(const QString &valgrindExecutable)
-{
- m_valgrindExecutable = valgrindExecutable;
-}
+ QStringList globalSuppressionFiles; // Real value, only used for global settings
-void ValgrindBaseSettings::setValgrindArguments(const QString &arguments)
-{
- if (m_valgrindArguments != arguments) {
- m_valgrindArguments = arguments;
- emit valgrindArgumentsChanged(arguments);
- }
-}
+ QStringList removedProjectSuppressionFiles; // Part of real value for project settings
+ QStringList addedProjectSuppressionFiles; // Part of real value for project settings
+};
-void ValgrindBaseSettings::setSelfModifyingCodeDetection(int smcDetection)
+void SuppressionAspect::addSuppressionFile(const QString &suppression)
{
- if (m_selfModifyingCodeDetection != smcDetection) {
- m_selfModifyingCodeDetection = (SelfModifyingCodeDetection) smcDetection;
- emit selfModifyingCodeDetectionChanged(smcDetection);
+ if (d->isGlobal) {
+ d->globalSuppressionFiles.append(suppression);
+ } else {
+ const QStringList globalSuppressions = ValgrindGlobalSettings::instance()->suppressions.value();
+ if (!d->addedProjectSuppressionFiles.contains(suppression))
+ d->addedProjectSuppressionFiles.append(suppression);
+ d->removedProjectSuppressionFiles.removeAll(suppression);
+ }
+ setVolatileValue(value());
+}
+
+void SuppressionAspectPrivate::slotAddSuppression()
+{
+ ValgrindGlobalSettings *conf = ValgrindGlobalSettings::instance();
+ QTC_ASSERT(conf, return);
+ const QStringList files =
+ QFileDialog::getOpenFileNames(Core::ICore::dialogParent(),
+ tr("Valgrind Suppression Files"),
+ conf->lastSuppressionDirectory.value(),
+ tr("Valgrind Suppression File (*.supp);;All Files (*)"));
+ //dialog.setHistory(conf->lastSuppressionDialogHistory());
+ if (!files.isEmpty()) {
+ for (const QString &file : files)
+ m_model.appendRow(new QStandardItem(file));
+ conf->lastSuppressionDirectory.setValue(QFileInfo(files.at(0)).absolutePath());
+ //conf->setLastSuppressionDialogHistory(dialog.history());
+ if (!isGlobal)
+ q->apply();
}
}
-void ValgrindBaseSettings::setMemcheckArguments(const QString &arguments)
+void SuppressionAspectPrivate::slotRemoveSuppression()
{
- if (m_memcheckArguments != arguments) {
- m_memcheckArguments = arguments;
- emit memcheckArgumentsChanged(arguments);
+ // remove from end so no rows get invalidated
+ QList<int> rows;
+
+ QStringList removed;
+ const QModelIndexList selected = entryList->selectionModel()->selectedIndexes();
+ for (const QModelIndex &index : selected) {
+ rows << index.row();
+ removed << index.data().toString();
}
-}
-QString ValgrindBaseSettings::valgrindExecutable() const
-{
- return m_valgrindExecutable;
+ Utils::sort(rows, std::greater<int>());
+
+ for (int row : qAsConst(rows))
+ m_model.removeRow(row);
+
+ if (!isGlobal)
+ q->apply();
}
-ValgrindBaseSettings::SelfModifyingCodeDetection ValgrindBaseSettings::selfModifyingCodeDetection() const
+void SuppressionAspectPrivate::slotSuppressionSelectionChanged()
{
- return m_selfModifyingCodeDetection;
+ removeEntry->setEnabled(entryList->selectionModel()->hasSelection());
}
-void ValgrindBaseSettings::setNumCallers(int numCallers)
+//
+// SuppressionAspect
+//
+
+SuppressionAspect::SuppressionAspect(bool global)
{
- if (m_numCallers != numCallers) {
- m_numCallers = numCallers;
- emit numCallersChanged(numCallers);
- }
+ d = new SuppressionAspectPrivate(this, global);
}
-void ValgrindBaseSettings::setLeakCheckOnFinish(int leakCheckOnFinish)
+SuppressionAspect::~SuppressionAspect()
{
- if (m_leakCheckOnFinish != leakCheckOnFinish) {
- m_leakCheckOnFinish = (LeakCheckOnFinish) leakCheckOnFinish;
- emit leakCheckOnFinishChanged(leakCheckOnFinish);
- }
+ delete d;
}
-void ValgrindBaseSettings::setShowReachable(bool showReachable)
+QStringList SuppressionAspect::value() const
{
- if (m_showReachable != showReachable) {
- m_showReachable = showReachable;
- emit showReachableChanged(showReachable);
- }
+ // Note: BaseAspect::d->value is /not/ used.
+ if (d->isGlobal)
+ return d->globalSuppressionFiles;
+
+ QStringList ret = ValgrindGlobalSettings::instance()->suppressions.value();
+ for (const QString &s : d->removedProjectSuppressionFiles)
+ ret.removeAll(s);
+ ret.append(d->addedProjectSuppressionFiles);
+ return ret;
}
-void ValgrindBaseSettings::setTrackOrigins(bool trackOrigins)
-{
- if (m_trackOrigins != trackOrigins) {
- m_trackOrigins = trackOrigins;
- emit trackOriginsChanged(trackOrigins);
+void SuppressionAspect::setValue(const QStringList &val)
+{
+ if (d->isGlobal) {
+ d->globalSuppressionFiles = val;
+ } else {
+ const QStringList globals = ValgrindGlobalSettings::instance()->suppressions.value();
+ d->addedProjectSuppressionFiles.clear();
+ for (const QString &s : val) {
+ if (!globals.contains(s))
+ d->addedProjectSuppressionFiles.append(s);
+ }
+ d->removedProjectSuppressionFiles.clear();
+ for (const QString &s : globals) {
+ if (!val.contains(s))
+ d->removedProjectSuppressionFiles.append(s);
+ }
}
}
-void ValgrindBaseSettings::setFilterExternalIssues(bool filterExternalIssues)
+void SuppressionAspect::addToLayout(LayoutBuilder &builder)
{
- if (m_filterExternalIssues != filterExternalIssues) {
- m_filterExternalIssues = filterExternalIssues;
- emit filterExternalIssuesChanged(filterExternalIssues);
- }
+ QTC_CHECK(!d->addEntry);
+ QTC_CHECK(!d->removeEntry);
+ QTC_CHECK(!d->entryList);
+
+ using namespace Layouting;
+
+ d->addEntry = new QPushButton(tr("Add..."));
+ d->removeEntry = new QPushButton(tr("Remove"));
+
+ d->entryList = new QListView;
+ d->entryList->setModel(&d->m_model);
+ d->entryList->setSelectionMode(QAbstractItemView::MultiSelection);
+
+ connect(d->addEntry, &QPushButton::clicked,
+ d, &SuppressionAspectPrivate::slotAddSuppression);
+ connect(d->removeEntry, &QPushButton::clicked,
+ d, &SuppressionAspectPrivate::slotRemoveSuppression);
+ connect(d->entryList->selectionModel(), &QItemSelectionModel::selectionChanged,
+ d, &SuppressionAspectPrivate::slotSuppressionSelectionChanged);
+
+ builder.addItem(tr("Suppression files:"));
+ Row group {
+ d->entryList.data(),
+ Column { d->addEntry.data(), d->removeEntry.data(), Stretch() }
+ };
+ builder.addItem(Span { 2, group });
}
-void ValgrindBaseSettings::setVisibleErrorKinds(const QList<int> &visibleErrorKinds)
+void SuppressionAspect::fromMap(const QVariantMap &map)
{
- if (m_visibleErrorKinds != visibleErrorKinds) {
- m_visibleErrorKinds = visibleErrorKinds;
- emit visibleErrorKindsChanged(visibleErrorKinds);
+ if (d->isGlobal) {
+ d->globalSuppressionFiles = map.value(globalSuppressionKey).toStringList();
+ } else {
+ d->addedProjectSuppressionFiles = map.value(addedProjectSuppressionKey).toStringList();
+ d->removedProjectSuppressionFiles = map.value(removedProjectSuppressionKey).toStringList();
}
+ setVolatileValue(value());
}
-QString ValgrindBaseSettings::kcachegrindExecutable() const
+void SuppressionAspect::toMap(QVariantMap &map) const
{
- return m_kcachegrindExecutable;
-}
+ auto save = [&map](const QStringList &data, const QString &key) {
+ if (data.isEmpty())
+ map.remove(key);
+ else
+ map.insert(key, data);
+ };
-void ValgrindBaseSettings::setCallgrindArguments(const QString &arguments)
-{
- if (m_callgrindArguments != arguments) {
- m_callgrindArguments = arguments;
- emit callgrindArgumentsChanged(arguments);
+ if (d->isGlobal) {
+ save(d->globalSuppressionFiles, globalSuppressionKey);
+ } else {
+ save(d->addedProjectSuppressionFiles, addedProjectSuppressionKey);
+ save(d->removedProjectSuppressionFiles, removedProjectSuppressionKey);
}
}
-void ValgrindBaseSettings::setKCachegrindExecutable(const QString &exec)
+QVariant SuppressionAspect::volatileValue() const
{
- m_kcachegrindExecutable = exec;
-}
+ QStringList ret;
-void ValgrindBaseSettings::setEnableCacheSim(bool enable)
-{
- if (m_enableCacheSim == enable)
- return;
+ for (int i = 0; i < d->m_model.rowCount(); ++i)
+ ret << d->m_model.item(i)->text();
- m_enableCacheSim = enable;
- emit enableCacheSimChanged(enable);
+ return ret;
}
-void ValgrindBaseSettings::setEnableBranchSim(bool enable)
+void SuppressionAspect::setVolatileValue(const QVariant &val)
{
- if (m_enableBranchSim == enable)
- return;
-
- m_enableBranchSim = enable;
- emit enableBranchSimChanged(enable);
+ const QStringList files = val.toStringList();
+ d->m_model.clear();
+ for (const QString &file : files)
+ d->m_model.appendRow(new QStandardItem(file));
}
-void ValgrindBaseSettings::setCollectSystime(bool collect)
+void SuppressionAspect::cancel()
{
- if (m_collectSystime == collect)
- return;
-
- m_collectSystime = collect;
- emit collectSystimeChanged(collect);
+ setVolatileValue(value());
}
-void ValgrindBaseSettings::setCollectBusEvents(bool collect)
+void SuppressionAspect::apply()
{
- if (m_collectBusEvents == collect)
- return;
-
- m_collectBusEvents = collect;
- emit collectBusEventsChanged(collect);
+ setValue(volatileValue().toStringList());
}
-void ValgrindBaseSettings::setEnableEventToolTips(bool enable)
+void SuppressionAspect::finish()
{
- if (m_enableEventToolTips == enable)
- return;
-
- m_enableEventToolTips = enable;
- emit enableEventToolTipsChanged(enable);
+ setVolatileValue(value()); // Clean up m_model content
}
-void ValgrindBaseSettings::setMinimumInclusiveCostRatio(
- double minimumInclusiveCostRatio)
-{
- if (m_minimumInclusiveCostRatio == minimumInclusiveCostRatio)
- return;
+//////////////////////////////////////////////////////////////////
+//
+// ValgrindBaseSettings
+//
+//////////////////////////////////////////////////////////////////
- m_minimumInclusiveCostRatio = qBound(0.0, minimumInclusiveCostRatio, 100.0);
- emit minimumInclusiveCostRatioChanged(minimumInclusiveCostRatio);
-}
+ValgrindBaseSettings::ValgrindBaseSettings(bool global)
+ : suppressions(global)
+{
+ // Note that this is used twice, once for project settings in the .user files
+ // and once for global settings in QtCreator.ini. This uses intentionally
+ // the same key to facilitate copying using fromMap/toMap.
+ QString base = "Analyzer.Valgrind.";
+
+ registerAspect(&suppressions);
+
+ registerAspect(&valgrindExecutable);
+ valgrindExecutable.setSettingsKey(base + "ValgrindExecutable");
+ valgrindExecutable.setDefaultValue("valgrind");
+ valgrindExecutable.setDisplayStyle(StringAspect::PathChooserDisplay);
+ valgrindExecutable.setExpectedKind(PathChooser::Command);
+ valgrindExecutable.setHistoryCompleter("Valgrind.Command.History");
+ valgrindExecutable.setDisplayName(tr("Valgrind Command"));
+ valgrindExecutable.setLabelText(tr("Valgrind executable:"));
+ if (Utils::HostOsInfo::isWindowsHost()) {
+ // On Window we know that we don't have a local valgrind
+ // executable, so having the "Browse" button in the path chooser
+ // (which is needed for the remote executable) is confusing.
+ // FIXME: not deadly, still...
+ //valgrindExecutable. ... buttonAtIndex(0)->hide();
+ }
-void ValgrindBaseSettings::setVisualisationMinimumInclusiveCostRatio(
- double minimumInclusiveCostRatio)
-{
- if (m_visualisationMinimumInclusiveCostRatio == minimumInclusiveCostRatio)
- return;
+ registerAspect(&valgrindArguments);
+ valgrindArguments.setSettingsKey(base + "ValgrindArguments");
+ valgrindArguments.setDisplayStyle(StringAspect::LineEditDisplay);
+ valgrindArguments.setLabelText(tr("Valgrind arguments:"));
+
+ registerAspect(&selfModifyingCodeDetection);
+ selfModifyingCodeDetection.setSettingsKey(base + "SelfModifyingCodeDetection");
+ selfModifyingCodeDetection.setDefaultValue(DetectSmcStackOnly);
+ selfModifyingCodeDetection.setDisplayStyle(SelectionAspect::DisplayStyle::ComboBox);
+ selfModifyingCodeDetection.addOption("No");
+ selfModifyingCodeDetection.addOption("Only on Stack");
+ selfModifyingCodeDetection.addOption("Everywhere");
+ selfModifyingCodeDetection.addOption("Everywhere Except in File-backend Mappings");
+ selfModifyingCodeDetection.setLabelText(tr("Detect self-modifying code:"));
- m_visualisationMinimumInclusiveCostRatio = qBound(0.0, minimumInclusiveCostRatio, 100.0);
- emit visualisationMinimumInclusiveCostRatioChanged(minimumInclusiveCostRatio);
+ // Memcheck
+ registerAspect(&memcheckArguments);
+ memcheckArguments.setSettingsKey(base + "Memcheck.Arguments");
+ memcheckArguments.setDisplayStyle(StringAspect::LineEditDisplay);
+ memcheckArguments.setLabelText(tr("Extra MemCheck arguments:"));
+
+ registerAspect(&filterExternalIssues);
+ filterExternalIssues.setSettingsKey(base + "FilterExternalIssues");
+ filterExternalIssues.setDefaultValue(true);
+ filterExternalIssues.setIcon(Icons::FILTER.icon());
+ filterExternalIssues.setLabelPlacement(BoolAspect::LabelPlacement::AtCheckBoxWithoutDummyLabel);
+ filterExternalIssues.setLabelText(tr("Show Project Costs Only"));
+ filterExternalIssues.setToolTip(tr("Show only profiling info that originated from this project source."));
+
+ registerAspect(&trackOrigins);
+ trackOrigins.setSettingsKey(base + "TrackOrigins");
+ trackOrigins.setDefaultValue(true);
+ trackOrigins.setLabelPlacement(BoolAspect::LabelPlacement::AtCheckBoxWithoutDummyLabel);
+ trackOrigins.setLabelText(tr("Track origins of uninitialized memory"));
+
+ registerAspect(&showReachable);
+ showReachable.setSettingsKey(base + "ShowReachable");
+ showReachable.setLabelPlacement(BoolAspect::LabelPlacement::AtCheckBoxWithoutDummyLabel);
+ showReachable.setLabelText(tr("Show reachable and indirectly lost blocks"));
+
+ registerAspect(&leakCheckOnFinish);
+ leakCheckOnFinish.setSettingsKey(base + "LeakCheckOnFinish");
+ leakCheckOnFinish.setDefaultValue(LeakCheckOnFinishSummaryOnly);
+ leakCheckOnFinish.setDisplayStyle(SelectionAspect::DisplayStyle::ComboBox);
+ leakCheckOnFinish.addOption(tr("No"));
+ leakCheckOnFinish.addOption(tr("Summary Only"));
+ leakCheckOnFinish.addOption(tr("Full"));
+ leakCheckOnFinish.setLabelText(tr("Check for leaks on finish:"));
+
+ registerAspect(&numCallers);
+ numCallers.setSettingsKey(base + "NumCallers");
+ numCallers.setDefaultValue(25);
+ numCallers.setLabelText(tr("Backtrace frame count:"));
+
+ // Callgrind
+
+ registerAspect(&kcachegrindExecutable);
+ kcachegrindExecutable.setSettingsKey(base + "KCachegrindExecutable");
+ kcachegrindExecutable.setDefaultValue("kcachegrind");
+ kcachegrindExecutable.setDisplayStyle(StringAspect::PathChooserDisplay);
+ kcachegrindExecutable.setLabelText(tr("KCachegrind executable:"));
+ kcachegrindExecutable.setExpectedKind(Utils::PathChooser::Command);
+ kcachegrindExecutable.setDisplayName(tr("KCachegrind Command"));
+
+ registerAspect(&callgrindArguments);
+ callgrindArguments.setSettingsKey(base + "Callgrind.Arguments");
+ callgrindArguments.setDisplayStyle(StringAspect::LineEditDisplay);
+ callgrindArguments.setLabelText(tr("Extra CallGrind arguments:"));
+
+ registerAspect(&enableEventToolTips);
+ enableEventToolTips.setDefaultValue(true);
+ enableEventToolTips.setSettingsKey(base + "Callgrind.EnableEventToolTips");
+ enableEventToolTips.setLabelPlacement(BoolAspect::LabelPlacement::AtCheckBoxWithoutDummyLabel);
+ enableEventToolTips.setLabelText(tr("Show additional information for events in tooltips"));
+
+ registerAspect(&enableCacheSim);
+ enableCacheSim.setSettingsKey(base + "Callgrind.EnableCacheSim");
+ enableCacheSim.setLabelPlacement(BoolAspect::LabelPlacement::AtCheckBoxWithoutDummyLabel);
+ enableCacheSim.setLabelText(tr("Enable cache simulation"));
+ enableCacheSim.setToolTip("<html><head/><body>" + tr(
+ "<p>Does full cache simulation.</p>\n"
+ "<p>By default, only instruction read accesses will be counted (\"Ir\").</p>\n"
+ "<p>\n"
+ "With cache simulation, further event counters are enabled:\n"
+ "<ul><li>Cache misses on instruction reads (\"I1mr\"/\"I2mr\").</li>\n"
+ "<li>Data read accesses (\"Dr\") and related cache misses (\"D1mr\"/\"D2mr\").</li>\n"
+ "<li>Data write accesses (\"Dw\") and related cache misses (\"D1mw\"/\"D2mw\").</li></ul>\n"
+ "</p>") + "</body></html>");
+
+ registerAspect(&enableBranchSim);
+ enableBranchSim.setSettingsKey(base + "Callgrind.EnableBranchSim");
+ enableBranchSim.setLabelPlacement(BoolAspect::LabelPlacement::AtCheckBoxWithoutDummyLabel);
+ enableBranchSim.setLabelText(tr("Enable branch prediction simulation"));
+ enableBranchSim.setToolTip("<html><head/><body>\n" + tr(
+ "<p>Does branch prediction simulation.</p>\n"
+ "<p>Further event counters are enabled: </p>\n"
+ "<ul><li>Number of executed conditional branches and related predictor misses (\n"
+ "\"Bc\"/\"Bcm\").</li>\n"
+ "<li>Executed indirect jumps and related misses of the jump address predictor (\n"
+ "\"Bi\"/\"Bim\").)</li></ul>") + "</body></html>");
+
+ registerAspect(&collectSystime);
+ collectSystime.setSettingsKey(base + "Callgrind.CollectSystime");
+ collectSystime.setLabelPlacement(BoolAspect::LabelPlacement::AtCheckBoxWithoutDummyLabel);
+ collectSystime.setLabelText(tr("Collect system call time"));
+ collectSystime.setToolTip(tr("Collects information for system call times."));
+
+ registerAspect(&collectBusEvents);
+ collectBusEvents.setLabelPlacement(BoolAspect::LabelPlacement::AtCheckBoxWithoutDummyLabel);
+ collectBusEvents.setSettingsKey(base + "Callgrind.CollectBusEvents");
+ collectBusEvents.setLabelText(tr("Collect global bus events"));
+ collectBusEvents.setToolTip(tr("Collect the number of global bus events that are executed. "
+ "The event type \"Ge\" is used for these events."));
+
+ registerAspect(&minimumInclusiveCostRatio);
+ minimumInclusiveCostRatio.setSettingsKey(base + "Callgrind.MinimumCostRatio");
+ minimumInclusiveCostRatio.setDefaultValue(0.01);
+ minimumInclusiveCostRatio.setSuffix(tr("%"));
+ minimumInclusiveCostRatio.setLabelText(tr("Result view: Minimum event cost:"));
+ minimumInclusiveCostRatio.setToolTip(tr("Limits the amount of results the profiler gives you. "
+ "A lower limit will likely increase performance."));
+
+ registerAspect(&visualizationMinimumInclusiveCostRatio);
+ visualizationMinimumInclusiveCostRatio.setSettingsKey(base + "Callgrind.VisualisationMinimumCostRatio");
+ visualizationMinimumInclusiveCostRatio.setDefaultValue(10.0);
+ visualizationMinimumInclusiveCostRatio.setLabelText(tr("Visualization: Minimum event cost:"));
+ visualizationMinimumInclusiveCostRatio.setSuffix(tr("%"));
+
+ registerAspect(&visibleErrorKinds);
+ visibleErrorKinds.setSettingsKey(base + "VisibleErrorKinds");
+ QList<int> defaultErrorKinds;
+ for (int i = 0; i < Valgrind::XmlProtocol::MemcheckErrorKindCount; ++i)
+ defaultErrorKinds << i;
+ visibleErrorKinds.setDefaultValue(defaultErrorKinds);
}
@@ -335,147 +461,71 @@ void ValgrindBaseSettings::setVisualisationMinimumInclusiveCostRatio(
static ValgrindGlobalSettings *theGlobalSettings = nullptr;
ValgrindGlobalSettings::ValgrindGlobalSettings()
+ : ValgrindBaseSettings(true)
{
theGlobalSettings = this;
- setConfigWidgetCreator([this] { return ValgrindOptionsPage::createSettingsWidget(this); });
- readSettings();
-}
-
-ValgrindGlobalSettings *ValgrindGlobalSettings::instance()
-{
- return theGlobalSettings;
-}
-
-void ValgrindGlobalSettings::fromMap(const QVariantMap &map)
-{
- ValgrindBaseSettings::fromMap(map);
-
- // Memcheck
- m_suppressionFiles = map.value(suppressionFilesC).toStringList();
- m_lastSuppressionDirectory = map.value(lastSuppressionDirectoryC).toString();
- m_lastSuppressionHistory = map.value(lastSuppressionHistoryC).toStringList();
-
- // Callgrind
- // special code as the default one does not cope with the enum properly
- if (map.contains(callgrindCostFormatC))
- m_costFormat = static_cast<CostDelegate::CostFormat>(map.value(callgrindCostFormatC).toInt());
- setIfPresent(map, callgrindCycleDetectionC, &m_detectCycles);
- setIfPresent(map, callgrindShortenTemplates, &m_shortenTemplates);
-}
-
-void ValgrindGlobalSettings::toMap(QVariantMap &map) const
-{
- ValgrindBaseSettings::toMap(map);
-
- // Memcheck
- map.insert(suppressionFilesC, m_suppressionFiles);
- map.insert(lastSuppressionDirectoryC, m_lastSuppressionDirectory);
- map.insert(lastSuppressionHistoryC, m_lastSuppressionHistory);
+ const QString base = "Analyzer.Valgrind";
- // Callgrind
- map.insert(callgrindCostFormatC, m_costFormat);
- map.insert(callgrindCycleDetectionC, m_detectCycles);
- map.insert(callgrindShortenTemplates, m_shortenTemplates);
-}
+ registerAspect(&lastSuppressionDirectory);
+ lastSuppressionDirectory.setSettingsKey(base + "LastSuppressionDirectory");
-//
-// Memcheck
-//
-QStringList ValgrindGlobalSettings::suppressionFiles() const
-{
- return m_suppressionFiles;
-}
-
-void ValgrindGlobalSettings::addSuppressionFiles(const QStringList &suppressions)
-{
- foreach (const QString &s, suppressions)
- if (!m_suppressionFiles.contains(s))
- m_suppressionFiles.append(s);
-}
+ registerAspect(&lastSuppressionHistory);
+ lastSuppressionHistory.setSettingsKey(base + "LastSuppressionHistory");
+ registerAspect(&detectCycles);
+ detectCycles.setSettingsKey(base + "Callgrind.CycleDetection");
+ detectCycles.setDefaultValue(true);
+ detectCycles.setLabelText("O"); // FIXME: Create a real icon
+ detectCycles.setToolTip(tr("Enable cycle detection to properly handle recursive "
+ "or circular function calls."));
-void ValgrindGlobalSettings::removeSuppressionFiles(const QStringList &suppressions)
-{
- foreach (const QString &s, suppressions)
- m_suppressionFiles.removeAll(s);
-}
+ registerAspect(&costFormat);
+ costFormat.setSettingsKey(base + "Callgrind.CostFormat");
+ costFormat.setDefaultValue(CostDelegate::FormatRelative);
+ costFormat.setDisplayStyle(SelectionAspect::DisplayStyle::ComboBox);
-QString ValgrindGlobalSettings::lastSuppressionDialogDirectory() const
-{
- return m_lastSuppressionDirectory;
-}
+ registerAspect(&shortenTemplates);
+ shortenTemplates.setSettingsKey(base + "Callgrind.ShortenTemplates");
+ shortenTemplates.setDefaultValue(true);
+ shortenTemplates.setLabelText("<>"); // FIXME: Create a real icon
+ shortenTemplates.setToolTip(tr("Remove template parameter lists when displaying function names."));
-void ValgrindGlobalSettings::setLastSuppressionDialogDirectory(const QString &directory)
-{
- m_lastSuppressionDirectory = directory;
-}
+ setConfigWidgetCreator([this] { return ValgrindOptionsPage::createSettingsWidget(this); });
+ readSettings();
-QStringList ValgrindGlobalSettings::lastSuppressionDialogHistory() const
-{
- return m_lastSuppressionHistory;
+ setAutoApply(false);
}
-void ValgrindGlobalSettings::setLastSuppressionDialogHistory(const QStringList &history)
+ValgrindGlobalSettings *ValgrindGlobalSettings::instance()
{
- m_lastSuppressionHistory = history;
+ return theGlobalSettings;
}
-static const char groupC[] = "Analyzer";
+//
+// Memcheck
+//
-static QVariantMap defaultSettings()
+QVariantMap ValgrindBaseSettings::defaultSettings() const
{
QVariantMap defaults;
-
- // General
- defaults.insert(valgrindExeC, "valgrind");
- defaults.insert(valgrindArgumentsC, QString());
- defaults.insert(selfModifyingCodeDetectionC, ValgrindBaseSettings::DetectSmcStackOnly);
-
- // Memcheck
- defaults.insert(memcheckArgumentsC, QString());
- defaults.insert(numCallersC, 25);
- defaults.insert(leakCheckOnFinishC, ValgrindBaseSettings::LeakCheckOnFinishSummaryOnly);
- defaults.insert(showReachableC, false);
- defaults.insert(trackOriginsC, true);
- defaults.insert(filterExternalIssuesC, true);
- QVariantList defaultErrorKinds;
- for (int i = 0; i < Valgrind::XmlProtocol::MemcheckErrorKindCount; ++i)
- defaultErrorKinds << i;
- defaults.insert(visibleErrorKindsC, defaultErrorKinds);
-
- defaults.insert(suppressionFilesC, QStringList());
- defaults.insert(lastSuppressionDirectoryC, QString());
- defaults.insert(lastSuppressionHistoryC, QStringList());
-
- // Callgrind
- defaults.insert(callgrindArgumentsC, QString());
- defaults.insert(kcachegrindExeC, "kcachegrind");
- defaults.insert(callgrindEnableCacheSimC, false);
- defaults.insert(callgrindEnableBranchSimC, false);
- defaults.insert(callgrindCollectSystimeC, false);
- defaults.insert(callgrindCollectBusEventsC, false);
- defaults.insert(callgrindEnableEventToolTipsC, true);
- defaults.insert(callgrindMinimumCostRatioC, 0.01);
- defaults.insert(callgrindVisualisationMinimumCostRatioC, 10.0);
-
- defaults.insert(callgrindCostFormatC, CostDelegate::FormatRelative);
- defaults.insert(callgrindCycleDetectionC, true);
- defaults.insert(callgrindShortenTemplates, true);
-
+ forEachAspect([&defaults](BaseAspect *aspect) {
+ defaults.insert(aspect->settingsKey(), aspect->defaultValue());
+ });
return defaults;
}
+static const char groupC[] = "Analyzer";
+
void ValgrindGlobalSettings::readSettings()
{
- QVariantMap defaults = defaultSettings();
-
// Read stored values
QSettings *settings = Core::ICore::settings();
settings->beginGroup(groupC);
- QVariantMap map = defaults;
- for (QVariantMap::ConstIterator it = defaults.constBegin(); it != defaults.constEnd(); ++it)
- map.insert(it.key(), settings->value(it.key(), it.value()));
+ QVariantMap map;
+ const QStringList childKey = settings->childKeys();
+ for (const QString &key : childKey)
+ map.insert(key, settings->value(key));
settings->endGroup();
fromMap(map);
@@ -494,43 +544,6 @@ void ValgrindGlobalSettings::writeSettings() const
settings->endGroup();
}
-//
-// Callgrind
-//
-CostDelegate::CostFormat ValgrindGlobalSettings::costFormat() const
-{
- return m_costFormat;
-}
-
-void ValgrindGlobalSettings::setCostFormat(CostDelegate::CostFormat format)
-{
- m_costFormat = format;
- writeSettings();
-}
-
-bool ValgrindGlobalSettings::detectCycles() const
-{
- return m_detectCycles;
-}
-
-void ValgrindGlobalSettings::setDetectCycles(bool on)
-{
- m_detectCycles = on;
- writeSettings();
-}
-
-bool ValgrindGlobalSettings::shortenTemplates() const
-{
- return m_shortenTemplates;
-}
-
-void ValgrindGlobalSettings::setShortenTemplates(bool on)
-{
- m_shortenTemplates = on;
- writeSettings();
-}
-
-
//////////////////////////////////////////////////////////////////
//
// ValgrindProjectSettings
@@ -538,61 +551,18 @@ void ValgrindGlobalSettings::setShortenTemplates(bool on)
//////////////////////////////////////////////////////////////////
ValgrindProjectSettings::ValgrindProjectSettings()
+ : ValgrindBaseSettings(false)
{
setConfigWidgetCreator([this] { return ValgrindOptionsPage::createSettingsWidget(this); });
-}
-
-void ValgrindProjectSettings::fromMap(const QVariantMap &map)
-{
- ValgrindBaseSettings::fromMap(map);
- // Memcheck
- setIfPresent(map, addedSuppressionFilesC, &m_addedSuppressionFiles);
- setIfPresent(map, removedSuppressionFilesC, &m_disabledGlobalSuppressionFiles);
-}
-
-void ValgrindProjectSettings::toMap(QVariantMap &map) const
-{
- ValgrindBaseSettings::toMap(map);
-
- // Memcheck
- map.insert(addedSuppressionFilesC, m_addedSuppressionFiles);
- map.insert(removedSuppressionFilesC, m_disabledGlobalSuppressionFiles);
-}
-
-//
-// Memcheck
-//
-
-void ValgrindProjectSettings::addSuppressionFiles(const QStringList &suppressions)
-{
- const QStringList globalSuppressions = ValgrindGlobalSettings::instance()->suppressionFiles();
- for (const QString &s : suppressions) {
- if (m_addedSuppressionFiles.contains(s))
- continue;
- m_disabledGlobalSuppressionFiles.removeAll(s);
- if (!globalSuppressions.contains(s))
- m_addedSuppressionFiles.append(s);
- }
-}
-
-void ValgrindProjectSettings::removeSuppressionFiles(const QStringList &suppressions)
-{
- const QStringList globalSuppressions = ValgrindGlobalSettings::instance()->suppressionFiles();
- for (const QString &s : suppressions) {
- m_addedSuppressionFiles.removeAll(s);
- if (globalSuppressions.contains(s))
- m_disabledGlobalSuppressionFiles.append(s);
- }
-}
-
-QStringList ValgrindProjectSettings::suppressionFiles() const
-{
- QStringList ret = ValgrindGlobalSettings::instance()->suppressionFiles();
- for (const QString &s : m_disabledGlobalSuppressionFiles)
- ret.removeAll(s);
- ret.append(m_addedSuppressionFiles);
- return ret;
+ connect(this, &AspectContainer::fromMapFinished, [this] {
+ // FIXME: Update project page e.g. on "Restore Global", aspects
+ // there are 'autoapply', and Aspect::cancel() is normally part of
+ // the 'manual apply' machinery.
+ setAutoApply(false);
+ cancel();
+ setAutoApply(true);
+ });
}
} // namespace Internal
diff --git a/src/plugins/valgrind/valgrindsettings.h b/src/plugins/valgrind/valgrindsettings.h
index 1f119b7669..f5011587bb 100644
--- a/src/plugins/valgrind/valgrindsettings.h
+++ b/src/plugins/valgrind/valgrindsettings.h
@@ -27,17 +27,45 @@
#pragma once
#include "callgrindcostdelegate.h"
-#include <projectexplorer/runconfiguration.h>
-#include <QObject>
-#include <QString>
-#include <QVariant>
+#include <projectexplorer/runconfiguration.h>
+#include <projectexplorer/runconfigurationaspects.h>
namespace Valgrind {
namespace Internal {
const char ANALYZER_VALGRIND_SETTINGS[] = "Analyzer.Valgrind.Settings";
+class SuppressionAspectPrivate;
+
+class SuppressionAspect final : public Utils::BaseAspect
+{
+public:
+ explicit SuppressionAspect(bool global);
+ ~SuppressionAspect() final;
+
+ QStringList value() const;
+ void setValue(const QStringList &val);
+
+ void addToLayout(Utils::LayoutBuilder &builder) final;
+
+ void fromMap(const QVariantMap &map) final;
+ void toMap(QVariantMap &map) const final;
+
+ QVariant volatileValue() const final;
+ void setVolatileValue(const QVariant &val) final;
+
+ void cancel() final;
+ void apply() final;
+ void finish() final;
+
+ void addSuppressionFile(const QString &suppressionFile);
+
+private:
+ friend class ValgrindBaseSettings;
+ SuppressionAspectPrivate *d = nullptr;
+};
+
/**
* Valgrind settings shared for global and per-project.
*/
@@ -46,6 +74,8 @@ class ValgrindBaseSettings : public ProjectExplorer::ISettingsAspect
Q_OBJECT
public:
+ explicit ValgrindBaseSettings(bool global);
+
enum SelfModifyingCodeDetection {
DetectSmcNo,
DetectSmcStackOnly,
@@ -59,11 +89,6 @@ public:
LeakCheckOnFinishYes
};
- ValgrindBaseSettings();
-
- void toMap(QVariantMap &map) const override;
- void fromMap(const QVariantMap &map) override;
-
signals:
void changed(); // sent when multiple values have changed simulatenously (e.g. fromMap)
@@ -71,121 +96,42 @@ signals:
* Base valgrind settings
*/
public:
- QString valgrindExecutable() const;
- QString valgrindArguments() const { return m_valgrindArguments; }
- SelfModifyingCodeDetection selfModifyingCodeDetection() const;
-
- void setValgrindExecutable(const QString &);
- void setValgrindArguments(const QString &arguments);
- void setSelfModifyingCodeDetection(int);
-
-signals:
- void valgrindArgumentsChanged(const QString &arguments);
- void selfModifyingCodeDetectionChanged(int);
-
-private:
- QString m_valgrindExecutable;
- QString m_valgrindArguments;
- SelfModifyingCodeDetection m_selfModifyingCodeDetection;
+ Utils::StringAspect valgrindExecutable;
+ Utils::StringAspect valgrindArguments;
+ Utils::SelectionAspect selfModifyingCodeDetection;
+ SuppressionAspect suppressions;
/**
* Base memcheck settings
*/
public:
- QString memcheckArguments() const { return m_memcheckArguments; }
- int numCallers() const { return m_numCallers; }
- LeakCheckOnFinish leakCheckOnFinish() const { return m_leakCheckOnFinish; }
- bool showReachable() const { return m_showReachable; }
- bool trackOrigins() const { return m_trackOrigins; }
- bool filterExternalIssues() const { return m_filterExternalIssues; }
- QList<int> visibleErrorKinds() const { return m_visibleErrorKinds; }
-
- virtual QStringList suppressionFiles() const = 0;
- virtual void addSuppressionFiles(const QStringList &) = 0;
- virtual void removeSuppressionFiles(const QStringList &) = 0;
-
- void setMemcheckArguments(const QString &arguments);
- void setNumCallers(int);
- void setLeakCheckOnFinish(int);
- void setShowReachable(bool);
- void setTrackOrigins(bool);
- void setFilterExternalIssues(bool);
- void setVisibleErrorKinds(const QList<int> &);
+ Utils::StringAspect memcheckArguments;
+ Utils::IntegerAspect numCallers;
+ Utils::SelectionAspect leakCheckOnFinish;
+ Utils::BoolAspect showReachable;
+ Utils::BoolAspect trackOrigins;
+ Utils::BoolAspect filterExternalIssues;
+ Utils::IntegersAspect visibleErrorKinds;
-signals:
- void memcheckArgumentsChanged(const QString &arguments);
- void numCallersChanged(int);
- void leakCheckOnFinishChanged(int);
- void showReachableChanged(bool);
- void trackOriginsChanged(bool);
- void filterExternalIssuesChanged(bool);
- void visibleErrorKindsChanged(const QList<int> &);
- void suppressionFilesRemoved(const QStringList &);
- void suppressionFilesAdded(const QStringList &);
-
-protected:
- QString m_memcheckArguments;
- int m_numCallers;
- LeakCheckOnFinish m_leakCheckOnFinish;
- bool m_showReachable;
- bool m_trackOrigins;
- bool m_filterExternalIssues;
- QList<int> m_visibleErrorKinds;
+ void setVisibleErrorKinds(const QList<int> &);
/**
* Base callgrind settings
*/
public:
- QString callgrindArguments() const { return m_callgrindArguments;}
- QString kcachegrindExecutable() const;
-
- bool enableCacheSim() const { return m_enableCacheSim; }
- bool enableBranchSim() const { return m_enableBranchSim; }
- bool collectSystime() const { return m_collectSystime; }
- bool collectBusEvents() const { return m_collectBusEvents; }
- bool enableEventToolTips() const { return m_enableEventToolTips; }
-
- /// \return Minimum cost ratio, range [0.0..100.0]
- double minimumInclusiveCostRatio() const { return m_minimumInclusiveCostRatio; }
-
- /// \return Minimum cost ratio, range [0.0..100.0]
- double visualisationMinimumInclusiveCostRatio() const { return m_visualisationMinimumInclusiveCostRatio; }
-
- void setCallgrindArguments(const QString &arguments);
- void setKCachegrindExecutable(const QString &exec);
- void setEnableCacheSim(bool enable);
- void setEnableBranchSim(bool enable);
- void setCollectSystime(bool collect);
- void setCollectBusEvents(bool collect);
- void setEnableEventToolTips(bool enable);
-
- /// \param minimumInclusiveCostRatio Minimum inclusive cost ratio, valid values are [0.0..100.0]
- void setMinimumInclusiveCostRatio(double minimumInclusiveCostRatio);
-
- /// \param minimumInclusiveCostRatio Minimum inclusive cost ratio, valid values are [0.0..100.0]
- void setVisualisationMinimumInclusiveCostRatio(double minimumInclusiveCostRatio);
-
-signals:
- void callgrindArgumentsChanged(const QString &argumnts);
- void enableCacheSimChanged(bool);
- void enableBranchSimChanged(bool);
- void collectSystimeChanged(bool);
- void collectBusEventsChanged(bool);
- void enableEventToolTipsChanged(bool);
- void minimumInclusiveCostRatioChanged(double);
- void visualisationMinimumInclusiveCostRatioChanged(double);
-
-private:
- QString m_callgrindArguments;
- QString m_kcachegrindExecutable;
- bool m_enableCacheSim;
- bool m_collectSystime;
- bool m_collectBusEvents;
- bool m_enableBranchSim;
- bool m_enableEventToolTips;
- double m_minimumInclusiveCostRatio;
- double m_visualisationMinimumInclusiveCostRatio;
+ Utils::StringAspect callgrindArguments;
+ Utils::StringAspect kcachegrindExecutable;
+
+ Utils::BoolAspect enableCacheSim;
+ Utils::BoolAspect enableBranchSim;
+ Utils::BoolAspect collectSystime;
+ Utils::BoolAspect collectBusEvents;
+ Utils::BoolAspect enableEventToolTips;
+ Utils::DoubleAspect minimumInclusiveCostRatio;
+ Utils::DoubleAspect visualizationMinimumInclusiveCostRatio;
+
+ QVariantMap defaultSettings() const;
};
@@ -201,50 +147,23 @@ public:
static ValgrindGlobalSettings *instance();
- void toMap(QVariantMap &map) const override;
- void fromMap(const QVariantMap &map) override;
-
- /*
+ /**
* Global memcheck settings
*/
-public:
- QStringList suppressionFiles() const override;
- // in the global settings we change the internal list directly
- void addSuppressionFiles(const QStringList &) override;
- void removeSuppressionFiles(const QStringList &) override;
-
- // internal settings which don't require any UI
- void setLastSuppressionDialogDirectory(const QString &directory);
- QString lastSuppressionDialogDirectory() const;
-
- void setLastSuppressionDialogHistory(const QStringList &history);
- QStringList lastSuppressionDialogHistory() const;
void writeSettings() const;
void readSettings();
-private:
- QStringList m_suppressionFiles;
- QString m_lastSuppressionDirectory;
- QStringList m_lastSuppressionHistory;
+ Utils::StringAspect lastSuppressionDirectory;
+ Utils::StringAspect lastSuppressionHistory;
/**
* Global callgrind settings
*/
-public:
- CostDelegate::CostFormat costFormat() const;
- bool detectCycles() const;
- bool shortenTemplates() const;
-
- void setCostFormat(Valgrind::Internal::CostDelegate::CostFormat format);
- void setDetectCycles(bool on);
- void setShortenTemplates(bool on);
-
-private:
- CostDelegate::CostFormat m_costFormat;
- bool m_detectCycles;
- bool m_shortenTemplates;
+ Utils::SelectionAspect costFormat;
+ Utils::BoolAspect detectCycles;
+ Utils::BoolAspect shortenTemplates;
};
@@ -257,27 +176,6 @@ class ValgrindProjectSettings : public ValgrindBaseSettings
public:
ValgrindProjectSettings();
-
- void toMap(QVariantMap &map) const override;
- void fromMap(const QVariantMap &map) override;
-
- /**
- * Per-project memcheck settings, saves a diff to the global suppression files list
- */
-public:
- QStringList suppressionFiles() const override;
- // in the project-specific settings we store a diff to the global list
- void addSuppressionFiles(const QStringList &suppressions) override;
- void removeSuppressionFiles(const QStringList &suppressions) override;
-
-private:
- QStringList m_disabledGlobalSuppressionFiles;
- QStringList m_addedSuppressionFiles;
-
-
- /**
- * Per-project callgrind settings, saves a diff to the global suppression files list
- */
};
} // namespace Internal
diff --git a/src/plugins/vcsbase/CMakeLists.txt b/src/plugins/vcsbase/CMakeLists.txt
index c26bf04ef2..1e25ff911a 100644
--- a/src/plugins/vcsbase/CMakeLists.txt
+++ b/src/plugins/vcsbase/CMakeLists.txt
@@ -6,7 +6,6 @@ add_qtc_plugin(VcsBase
basevcseditorfactory.cpp basevcseditorfactory.h
basevcssubmiteditorfactory.cpp basevcssubmiteditorfactory.h
cleandialog.cpp cleandialog.h cleandialog.ui
- commonsettingspage.cpp commonsettingspage.h commonsettingspage.ui
commonvcssettings.cpp commonvcssettings.h
diffandloghighlighter.cpp diffandloghighlighter.h
nicknamedialog.cpp nicknamedialog.h nicknamedialog.ui
diff --git a/src/plugins/vcsbase/commonsettingspage.cpp b/src/plugins/vcsbase/commonsettingspage.cpp
deleted file mode 100644
index f1f2a73f7e..0000000000
--- a/src/plugins/vcsbase/commonsettingspage.cpp
+++ /dev/null
@@ -1,144 +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 "commonsettingspage.h"
-#include "vcsbaseconstants.h"
-
-#include "ui_commonsettingspage.h"
-
-#include <coreplugin/icore.h>
-#include <coreplugin/iversioncontrol.h>
-#include <coreplugin/vcsmanager.h>
-
-#include <utils/environment.h>
-#include <utils/hostosinfo.h>
-
-#include <QCoreApplication>
-
-using namespace Utils;
-
-namespace VcsBase {
-namespace Internal {
-
-// ------------------ VcsBaseSettingsWidget
-
-CommonSettingsWidget::CommonSettingsWidget(QWidget *parent) :
- QWidget(parent),
- m_ui(new Ui::CommonSettingsPage)
-{
- m_ui->setupUi(this);
- m_ui->submitMessageCheckScriptChooser->setExpectedKind(PathChooser::ExistingCommand);
- m_ui->submitMessageCheckScriptChooser->setHistoryCompleter(QLatin1String("Vcs.MessageCheckScript.History"));
- m_ui->nickNameFieldsFileChooser->setExpectedKind(PathChooser::File);
- m_ui->nickNameFieldsFileChooser->setHistoryCompleter(QLatin1String("Vcs.NickFields.History"));
- m_ui->nickNameMailMapChooser->setExpectedKind(PathChooser::File);
- m_ui->nickNameMailMapChooser->setHistoryCompleter(QLatin1String("Vcs.NickMap.History"));
- m_ui->sshPromptChooser->setExpectedKind(PathChooser::ExistingCommand);
- m_ui->sshPromptChooser->setHistoryCompleter(QLatin1String("Vcs.SshPrompt.History"));
-
- updatePath();
-
- connect(Core::VcsManager::instance(), &Core::VcsManager::configurationChanged,
- this, &CommonSettingsWidget::updatePath);
- connect(m_ui->cacheResetButton, &QPushButton::clicked,
- Core::VcsManager::instance(), &Core::VcsManager::clearVersionControlCache);
-}
-
-CommonSettingsWidget::~CommonSettingsWidget()
-{
- delete m_ui;
-}
-
-CommonVcsSettings CommonSettingsWidget::settings() const
-{
- CommonVcsSettings rc;
- rc.nickNameMailMap = m_ui->nickNameMailMapChooser->filePath().toString();
- rc.nickNameFieldListFile = m_ui->nickNameFieldsFileChooser->filePath().toString();
- rc.submitMessageCheckScript = m_ui->submitMessageCheckScriptChooser->filePath().toString();
- rc.lineWrap= m_ui->lineWrapCheckBox->isChecked();
- rc.lineWrapWidth = m_ui->lineWrapSpinBox->value();
- rc.sshPasswordPrompt = m_ui->sshPromptChooser->filePath().toString();
- return rc;
-}
-
-void CommonSettingsWidget::setSettings(const CommonVcsSettings &s)
-{
- m_ui->nickNameMailMapChooser->setPath(s.nickNameMailMap);
- m_ui->nickNameFieldsFileChooser->setPath(s.nickNameFieldListFile);
- m_ui->submitMessageCheckScriptChooser->setPath(s.submitMessageCheckScript);
- m_ui->lineWrapCheckBox->setChecked(s.lineWrap);
- m_ui->lineWrapSpinBox->setValue(s.lineWrapWidth);
- m_ui->sshPromptChooser->setPath(s.sshPasswordPrompt);
-}
-
-void CommonSettingsWidget::updatePath()
-{
- Environment env = Environment::systemEnvironment();
- QStringList toAdd = Core::VcsManager::additionalToolsPath();
- env.appendOrSetPath(toAdd.join(HostOsInfo::pathListSeparator()));
- m_ui->sshPromptChooser->setEnvironment(env);
-}
-
-// --------------- VcsBaseSettingsPage
-CommonOptionsPage::CommonOptionsPage()
-{
- m_settings.fromSettings(Core::ICore::settings());
-
- setId(Constants::VCS_COMMON_SETTINGS_ID);
- setDisplayName(QCoreApplication::translate("VcsBase", Constants::VCS_COMMON_SETTINGS_NAME));
- setCategory(Constants::VCS_SETTINGS_CATEGORY);
- // The following act as blueprint for other pages in the same category:
- setDisplayCategory(QCoreApplication::translate("VcsBase", "Version Control"));
- setCategoryIconPath(":/vcsbase/images/settingscategory_vcs.png");
-}
-
-QWidget *CommonOptionsPage::widget()
-{
- if (!m_widget) {
- m_widget = new CommonSettingsWidget;
- m_widget->setSettings(m_settings);
- }
- return m_widget;
-}
-
-void CommonOptionsPage::apply()
-{
- if (m_widget) {
- const CommonVcsSettings newSettings = m_widget->settings();
- if (newSettings != m_settings) {
- m_settings = newSettings;
- m_settings.toSettings(Core::ICore::settings());
- emit settingsChanged(m_settings);
- }
- }
-}
-
-void CommonOptionsPage::finish()
-{
- delete m_widget;
-}
-
-} // namespace Internal
-} // namespace VcsBase
diff --git a/src/plugins/vcsbase/commonsettingspage.ui b/src/plugins/vcsbase/commonsettingspage.ui
deleted file mode 100644
index 0368510cff..0000000000
--- a/src/plugins/vcsbase/commonsettingspage.ui
+++ /dev/null
@@ -1,181 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<ui version="4.0">
- <class>VcsBase::Internal::CommonSettingsPage</class>
- <widget class="QWidget" name="VcsBase::Internal::CommonSettingsPage">
- <property name="geometry">
- <rect>
- <x>0</x>
- <y>0</y>
- <width>350</width>
- <height>212</height>
- </rect>
- </property>
- <layout class="QFormLayout" name="formLayout">
- <property name="fieldGrowthPolicy">
- <enum>QFormLayout::ExpandingFieldsGrow</enum>
- </property>
- <item row="0" column="0">
- <widget class="QCheckBox" name="lineWrapCheckBox">
- <property name="text">
- <string>Wrap submit message at:</string>
- </property>
- </widget>
- </item>
- <item row="0" column="1">
- <widget class="QSpinBox" name="lineWrapSpinBox">
- <property name="enabled">
- <bool>false</bool>
- </property>
- <property name="suffix">
- <string> characters</string>
- </property>
- <property name="minimum">
- <number>40</number>
- </property>
- <property name="maximum">
- <number>200</number>
- </property>
- <property name="value">
- <number>72</number>
- </property>
- </widget>
- </item>
- <item row="1" column="1">
- <spacer name="horizontalSpacer">
- <property name="orientation">
- <enum>Qt::Horizontal</enum>
- </property>
- <property name="sizeHint" stdset="0">
- <size>
- <width>40</width>
- <height>20</height>
- </size>
- </property>
- </spacer>
- </item>
- <item row="2" column="0">
- <widget class="QLabel" name="submitMessageCheckScriptLabel">
- <property name="toolTip">
- <string>An executable which is called with the submit message in a temporary file as first argument. It should return with an exit != 0 and a message on standard error to indicate failure.</string>
- </property>
- <property name="text">
- <string>Submit message &amp;check script:</string>
- </property>
- <property name="buddy">
- <cstring>submitMessageCheckScriptChooser</cstring>
- </property>
- </widget>
- </item>
- <item row="2" column="1">
- <widget class="Utils::PathChooser" name="submitMessageCheckScriptChooser" native="true"/>
- </item>
- <item row="3" column="0">
- <widget class="QLabel" name="nickNameMailMapLabel">
- <property name="toolTip">
- <string>A file listing nicknames in a 4-column mailmap format:
-'name &lt;email&gt; alias &lt;email&gt;'.</string>
- </property>
- <property name="text">
- <string>User/&amp;alias configuration file:</string>
- </property>
- <property name="buddy">
- <cstring>nickNameMailMapChooser</cstring>
- </property>
- </widget>
- </item>
- <item row="3" column="1">
- <widget class="Utils::PathChooser" name="nickNameMailMapChooser" native="true"/>
- </item>
- <item row="4" column="0">
- <widget class="QLabel" name="nickNameFieldsFileLabel">
- <property name="toolTip">
- <string>A simple file containing lines with field names like &quot;Reviewed-By:&quot; which will be added below the submit editor.</string>
- </property>
- <property name="text">
- <string>User &amp;fields configuration file:</string>
- </property>
- <property name="buddy">
- <cstring>nickNameFieldsFileChooser</cstring>
- </property>
- </widget>
- </item>
- <item row="4" column="1">
- <widget class="Utils::PathChooser" name="nickNameFieldsFileChooser" native="true"/>
- </item>
- <item row="5" column="0">
- <widget class="QLabel" name="sshPromptLabel">
- <property name="toolTip">
- <string>Specifies a command that is executed to graphically prompt for a password,
-should a repository require SSH-authentication (see documentation on SSH and the environment variable SSH_ASKPASS).</string>
- </property>
- <property name="text">
- <string>&amp;SSH prompt command:</string>
- </property>
- <property name="buddy">
- <cstring>sshPromptChooser</cstring>
- </property>
- </widget>
- </item>
- <item row="5" column="1">
- <widget class="Utils::PathChooser" name="sshPromptChooser" native="true"/>
- </item>
- <item row="6" column="0">
- <spacer name="verticalSpacer">
- <property name="orientation">
- <enum>Qt::Vertical</enum>
- </property>
- <property name="sizeType">
- <enum>QSizePolicy::Fixed</enum>
- </property>
- <property name="sizeHint" stdset="0">
- <size>
- <width>20</width>
- <height>20</height>
- </size>
- </property>
- </spacer>
- </item>
- <item row="7" column="1">
- <widget class="QPushButton" name="cacheResetButton">
- <property name="toolTip">
- <string>Reset information about which version control system handles which directory.</string>
- </property>
- <property name="text">
- <string>Reset VCS Cache</string>
- </property>
- </widget>
- </item>
- </layout>
- </widget>
- <customwidgets>
- <customwidget>
- <class>Utils::PathChooser</class>
- <extends>QWidget</extends>
- <header location="global">utils/pathchooser.h</header>
- <container>1</container>
- <slots>
- <signal>editingFinished()</signal>
- <signal>browsingFinished()</signal>
- </slots>
- </customwidget>
- </customwidgets>
- <resources/>
- <connections>
- <connection>
- <sender>lineWrapCheckBox</sender>
- <signal>toggled(bool)</signal>
- <receiver>lineWrapSpinBox</receiver>
- <slot>setEnabled(bool)</slot>
- <hints>
- <hint type="sourcelabel">
- <x>175</x>
- <y>21</y>
- </hint>
- <hint type="destinationlabel">
- <x>216</x>
- <y>21</y>
- </hint>
- </hints>
- </connection>
- </connections>
-</ui>
diff --git a/src/plugins/vcsbase/commonvcssettings.cpp b/src/plugins/vcsbase/commonvcssettings.cpp
index b9be1d343a..e927c22552 100644
--- a/src/plugins/vcsbase/commonvcssettings.cpp
+++ b/src/plugins/vcsbase/commonvcssettings.cpp
@@ -25,87 +25,165 @@
#include "commonvcssettings.h"
+#include "vcsbaseconstants.h"
+
+#include <coreplugin/icore.h>
+#include <coreplugin/iversioncontrol.h>
+#include <coreplugin/vcsmanager.h>
+
+#include <utils/environment.h>
#include <utils/hostosinfo.h>
+#include <utils/layoutbuilder.h>
-#include <QSettings>
#include <QDebug>
+#include <QPushButton>
-static const char settingsGroupC[] = "VCS";
-static const char nickNameMailMapKeyC[] = "NickNameMailMap";
-static const char nickNameFieldListFileKeyC[] = "NickNameFieldListFile";
-static const char submitMessageCheckScriptKeyC[] = "SubmitMessageCheckScript";
-static const char lineWrapKeyC[] = "LineWrap";
-static const char lineWrapWidthKeyC[] = "LineWrapWidth";
-static const char sshPasswordPromptKeyC[] = "SshPasswordPrompt";
+using namespace Utils;
-static const int lineWrapWidthDefault = 72;
-static const bool lineWrapDefault = true;
+namespace VcsBase {
+namespace Internal {
// Return default for the ssh-askpass command (default to environment)
-static inline QString sshPasswordPromptDefault()
+static QString sshPasswordPromptDefault()
{
const QByteArray envSetting = qgetenv("SSH_ASKPASS");
if (!envSetting.isEmpty())
return QString::fromLocal8Bit(envSetting);
- if (Utils::HostOsInfo::isWindowsHost())
+ if (HostOsInfo::isWindowsHost())
return QLatin1String("win-ssh-askpass");
return QLatin1String("ssh-askpass");
}
-namespace VcsBase {
-namespace Internal {
-
-CommonVcsSettings::CommonVcsSettings() :
- sshPasswordPrompt(sshPasswordPromptDefault()),
- lineWrap(lineWrapDefault),
- lineWrapWidth(lineWrapWidthDefault)
+CommonVcsSettings::CommonVcsSettings()
{
+ setSettingsGroup("VCS");
+ setAutoApply(false);
+
+ registerAspect(&nickNameMailMap);
+ nickNameMailMap.setSettingsKey("NickNameMailMap");
+ nickNameMailMap.setDisplayStyle(StringAspect::PathChooserDisplay);
+ nickNameMailMap.setExpectedKind(PathChooser::File);
+ nickNameMailMap.setHistoryCompleter("Vcs.NickMap.History");
+ nickNameMailMap.setLabelText(tr("User/&alias configuration file:"));
+ nickNameMailMap.setToolTip(tr("A file listing nicknames in a 4-column mailmap format:\n"
+ "'name <email> alias <email>'."));
+
+ registerAspect(&nickNameFieldListFile);
+ nickNameFieldListFile.setSettingsKey("NickNameFieldListFile");
+ nickNameFieldListFile.setDisplayStyle(StringAspect::PathChooserDisplay);
+ nickNameFieldListFile.setExpectedKind(PathChooser::File);
+ nickNameFieldListFile.setHistoryCompleter("Vcs.NickFields.History");
+ nickNameFieldListFile.setLabelText(tr("User &fields configuration file:"));
+ nickNameFieldListFile.setToolTip(tr("A simple file containing lines with field names like "
+ "\"Reviewed-By:\" which will be added below the submit editor."));
+
+ registerAspect(&submitMessageCheckScript);
+ submitMessageCheckScript.setSettingsKey("SubmitMessageCheckScript");
+ submitMessageCheckScript.setDisplayStyle(StringAspect::PathChooserDisplay);
+ submitMessageCheckScript.setExpectedKind(PathChooser::ExistingCommand);
+ submitMessageCheckScript.setHistoryCompleter("Vcs.MessageCheckScript.History");
+ submitMessageCheckScript.setLabelText(tr("Submit message &check script:"));
+ submitMessageCheckScript.setToolTip(tr("An executable which is called with the submit message "
+ "in a temporary file as first argument. It should return with an exit != 0 and a message "
+ "on standard error to indicate failure."));
+
+ registerAspect(&sshPasswordPrompt);
+ sshPasswordPrompt.setSettingsKey("SshPasswordPrompt");
+ sshPasswordPrompt.setDisplayStyle(StringAspect::PathChooserDisplay);
+ sshPasswordPrompt.setExpectedKind(PathChooser::ExistingCommand);
+ sshPasswordPrompt.setHistoryCompleter("Vcs.SshPrompt.History");
+ sshPasswordPrompt.setDefaultValue(sshPasswordPromptDefault());
+ sshPasswordPrompt.setLabelText(tr("&SSH prompt command:"));
+ sshPasswordPrompt.setToolTip(tr("Specifies a command that is executed to graphically prompt "
+ "for a password,\nshould a repository require SSH-authentication "
+ "(see documentation on SSH and the environment variable SSH_ASKPASS)."));
+
+ registerAspect(&lineWrap);
+ lineWrap.setSettingsKey("LineWrap");
+ lineWrap.setDefaultValue(true);
+ lineWrap.setLabelText(tr("Wrap submit message at:"));
+
+ registerAspect(&lineWrapWidth);
+ lineWrapWidth.setSettingsKey("LineWrapWidth");
+ lineWrapWidth.setSuffix(tr(" characters"));
+ lineWrapWidth.setDefaultValue(72);
}
-void CommonVcsSettings::toSettings(Utils::QtcSettings *s) const
+// CommonSettingsWidget
+
+class CommonSettingsWidget final : public Core::IOptionsPageWidget
+{
+public:
+ CommonSettingsWidget(CommonOptionsPage *page);
+
+ void apply() final;
+
+private:
+ void updatePath();
+ CommonOptionsPage *m_page;
+};
+
+
+CommonSettingsWidget::CommonSettingsWidget(CommonOptionsPage *page)
+ : m_page(page)
{
- s->beginGroup(settingsGroupC);
- s->setValueWithDefault(nickNameMailMapKeyC, nickNameMailMap);
- s->setValueWithDefault(nickNameFieldListFileKeyC, nickNameFieldListFile);
- s->setValueWithDefault(submitMessageCheckScriptKeyC, submitMessageCheckScript);
- s->setValueWithDefault(lineWrapKeyC, lineWrap, lineWrapDefault);
- s->setValueWithDefault(lineWrapWidthKeyC, lineWrapWidth, lineWrapWidthDefault);
- s->setValueWithDefault(sshPasswordPromptKeyC, sshPasswordPrompt, sshPasswordPromptDefault());
- s->endGroup();
+ CommonVcsSettings &s = m_page->settings();
+
+ auto cacheResetButton = new QPushButton(CommonVcsSettings::tr("Reset VCS Cache"));
+ cacheResetButton->setToolTip(CommonVcsSettings::tr("Reset information about which "
+ "version control system handles which directory."));
+
+ updatePath();
+
+ using namespace Layouting;
+ Column {
+ Row { s.lineWrap, s.lineWrapWidth, Stretch() },
+ Form {
+ s.submitMessageCheckScript,
+ s.nickNameMailMap,
+ s.nickNameFieldListFile,
+ s.sshPasswordPrompt,
+ {}, cacheResetButton
+ }
+ }.attachTo(this);
+
+ connect(Core::VcsManager::instance(), &Core::VcsManager::configurationChanged,
+ this, &CommonSettingsWidget::updatePath);
+ connect(cacheResetButton, &QPushButton::clicked,
+ Core::VcsManager::instance(), &Core::VcsManager::clearVersionControlCache);
}
-void CommonVcsSettings::fromSettings(QSettings *s)
+void CommonSettingsWidget::updatePath()
{
- s->beginGroup(QLatin1String(settingsGroupC));
- nickNameMailMap = s->value(QLatin1String(nickNameMailMapKeyC), QString()).toString();
- nickNameFieldListFile = s->value(QLatin1String(nickNameFieldListFileKeyC), QString()).toString();
- submitMessageCheckScript = s->value(QLatin1String(submitMessageCheckScriptKeyC), QString()).toString();
- lineWrap = s->value(QLatin1String(lineWrapKeyC), lineWrapDefault).toBool();
- lineWrapWidth = s->value(QLatin1String(lineWrapWidthKeyC), lineWrapWidthDefault).toInt();
- sshPasswordPrompt = s->value(QLatin1String(sshPasswordPromptKeyC), sshPasswordPromptDefault()).toString();
- s->endGroup();
+ Environment env = Environment::systemEnvironment();
+ QStringList toAdd = Core::VcsManager::additionalToolsPath();
+ env.appendOrSetPath(toAdd.join(HostOsInfo::pathListSeparator()));
+ m_page->settings().sshPasswordPrompt.setEnvironment(env);
}
-bool CommonVcsSettings::equals(const CommonVcsSettings &rhs) const
+void CommonSettingsWidget::apply()
{
- return lineWrap == rhs.lineWrap
- && lineWrapWidth == rhs.lineWrapWidth
- && nickNameMailMap == rhs.nickNameMailMap
- && nickNameFieldListFile == rhs.nickNameFieldListFile
- && submitMessageCheckScript == rhs.submitMessageCheckScript
- && sshPasswordPrompt == rhs.sshPasswordPrompt;
+ CommonVcsSettings &s = m_page->settings();
+ if (s.isDirty()) {
+ s.apply();
+ s.writeSettings(Core::ICore::settings());
+ emit m_page->settingsChanged();
+ }
}
-QDebug operator<<(QDebug d,const CommonVcsSettings& s)
+// CommonOptionsPage
+
+CommonOptionsPage::CommonOptionsPage()
{
- d.nospace() << " lineWrap=" << s.lineWrap
- << " lineWrapWidth=" << s.lineWrapWidth
- << " nickNameMailMap='" << s.nickNameMailMap
- << "' nickNameFieldListFile='" << s.nickNameFieldListFile
- << "'submitMessageCheckScript='" << s.submitMessageCheckScript
- << "'sshPasswordPrompt='" << s.sshPasswordPrompt
- << "'\n";
- return d;
+ m_settings.readSettings(Core::ICore::settings());
+
+ setId(Constants::VCS_COMMON_SETTINGS_ID);
+ setDisplayName(QCoreApplication::translate("VcsBase", Constants::VCS_COMMON_SETTINGS_NAME));
+ setCategory(Constants::VCS_SETTINGS_CATEGORY);
+ // The following act as blueprint for other pages in the same category:
+ setDisplayCategory(QCoreApplication::translate("VcsBase", "Version Control"));
+ setCategoryIconPath(":/vcsbase/images/settingscategory_vcs.png");
+ setWidgetCreator([this] { return new CommonSettingsWidget(this); });
}
} // namespace Internal
diff --git a/src/plugins/vcsbase/commonvcssettings.h b/src/plugins/vcsbase/commonvcssettings.h
index 9ecc10a286..fdcafb0f49 100644
--- a/src/plugins/vcsbase/commonvcssettings.h
+++ b/src/plugins/vcsbase/commonvcssettings.h
@@ -25,44 +25,51 @@
#pragma once
-#include <utils/qtcsettings.h>
-
-#include <QString>
+#include <coreplugin/dialogs/ioptionspage.h>
-QT_BEGIN_NAMESPACE
-class QDebug;
-QT_END_NAMESPACE
+#include <utils/aspects.h>
+#include <utils/qtcsettings.h>
namespace VcsBase {
namespace Internal {
-// Common VCS settings, message check script and user nick names.
-class CommonVcsSettings
+class CommonVcsSettings : public Utils::AspectContainer
{
+ Q_DECLARE_TR_FUNCTIONS(VcsBase::Internal::CommonVcsSettings)
+
public:
CommonVcsSettings();
- QString nickNameMailMap;
- QString nickNameFieldListFile;
+ Utils::StringAspect nickNameMailMap;
+ Utils::StringAspect nickNameFieldListFile;
- QString submitMessageCheckScript;
+ Utils::StringAspect submitMessageCheckScript;
// Executable run to graphically prompt for a SSH-password.
- QString sshPasswordPrompt;
+ Utils::StringAspect sshPasswordPrompt;
- bool lineWrap;
- int lineWrapWidth;
-
- void toSettings(Utils::QtcSettings *) const;
- void fromSettings(QSettings *);
-
- bool equals(const CommonVcsSettings &rhs) const;
+ Utils::BoolAspect lineWrap;
+ Utils::IntegerAspect lineWrapWidth;
};
-inline bool operator==(const CommonVcsSettings &s1, const CommonVcsSettings &s2) { return s1.equals(s2); }
-inline bool operator!=(const CommonVcsSettings &s1, const CommonVcsSettings &s2) { return !s1.equals(s2); }
QDebug operator<<(QDebug, const CommonVcsSettings &);
+class CommonOptionsPage final : public Core::IOptionsPage
+{
+ Q_OBJECT
+
+public:
+ explicit CommonOptionsPage();
+
+ CommonVcsSettings &settings() { return m_settings; }
+
+signals:
+ void settingsChanged();
+
+private:
+ CommonVcsSettings m_settings;
+};
+
} // namespace Internal
} // namespace VcsBase
diff --git a/src/plugins/vcsbase/nicknamedialog.cpp b/src/plugins/vcsbase/nicknamedialog.cpp
index 799ef29faf..e0bd5a8a57 100644
--- a/src/plugins/vcsbase/nicknamedialog.cpp
+++ b/src/plugins/vcsbase/nicknamedialog.cpp
@@ -244,7 +244,7 @@ bool NickNameDialog::populateModelFromMailCapFile(const QString &fileName,
if (fileName.isEmpty())
return true;
FileReader reader;
- if (!reader.fetch(fileName, QIODevice::Text, errorMessage))
+ if (!reader.fetch(Utils::FilePath::fromString(fileName), QIODevice::Text, errorMessage))
return false;
// Split into lines and read
NickNameEntry entry;
diff --git a/src/plugins/vcsbase/submiteditorfile.cpp b/src/plugins/vcsbase/submiteditorfile.cpp
index 2ea545c047..7cda09855e 100644
--- a/src/plugins/vcsbase/submiteditorfile.cpp
+++ b/src/plugins/vcsbase/submiteditorfile.cpp
@@ -51,22 +51,23 @@ SubmitEditorFile::SubmitEditorFile(VcsBaseSubmitEditor *editor) :
this, &Core::IDocument::contentsChanged);
}
-Core::IDocument::OpenResult SubmitEditorFile::open(QString *errorString, const QString &fileName,
- const QString &realFileName)
+Core::IDocument::OpenResult SubmitEditorFile::open(QString *errorString,
+ const Utils::FilePath &filePath,
+ const Utils::FilePath &realFilePath)
{
- if (fileName.isEmpty())
+ if (filePath.isEmpty())
return OpenResult::ReadError;
FileReader reader;
- if (!reader.fetch(realFileName, QIODevice::Text, errorString))
+ if (!reader.fetch(realFilePath, QIODevice::Text, errorString))
return OpenResult::ReadError;
const QString text = QString::fromLocal8Bit(reader.data());
if (!m_editor->setFileContents(text.toUtf8()))
return OpenResult::CannotHandle;
- setFilePath(FilePath::fromString(fileName));
- setModified(fileName != realFileName);
+ setFilePath(filePath.absoluteFilePath());
+ setModified(filePath != realFilePath);
return OpenResult::Success;
}
@@ -88,17 +89,16 @@ void SubmitEditorFile::setModified(bool modified)
emit changed();
}
-bool SubmitEditorFile::save(QString *errorString, const QString &fileName, bool autoSave)
+bool SubmitEditorFile::save(QString *errorString, const FilePath &filePath, bool autoSave)
{
- const FilePath fName = fileName.isEmpty() ? filePath() : FilePath::fromString(fileName);
- FileSaver saver(fName.toString(),
- QIODevice::WriteOnly | QIODevice::Truncate | QIODevice::Text);
+ const FilePath &fName = filePath.isEmpty() ? this->filePath() : filePath;
+ FileSaver saver(fName, QIODevice::WriteOnly | QIODevice::Truncate | QIODevice::Text);
saver.write(m_editor->fileContents());
if (!saver.finalize(errorString))
return false;
if (autoSave)
return true;
- setFilePath(FilePath::fromUserInput(fName.toFileInfo().absoluteFilePath()));
+ setFilePath(fName.absoluteFilePath());
setModified(false);
if (!errorString->isEmpty())
return false;
diff --git a/src/plugins/vcsbase/submiteditorfile.h b/src/plugins/vcsbase/submiteditorfile.h
index de326c6101..cbc5f22dea 100644
--- a/src/plugins/vcsbase/submiteditorfile.h
+++ b/src/plugins/vcsbase/submiteditorfile.h
@@ -39,13 +39,13 @@ class SubmitEditorFile : public Core::IDocument
public:
explicit SubmitEditorFile(VcsBaseSubmitEditor *editor);
- OpenResult open(QString *errorString, const QString &fileName,
- const QString &realFileName) override;
+ OpenResult open(QString *errorString, const Utils::FilePath &filePath,
+ const Utils::FilePath &realFilePath) override;
QByteArray contents() const override;
bool setContents(const QByteArray &contents) override;
bool isModified() const override { return m_modified; }
- bool save(QString *errorString, const QString &fileName, bool autoSave) override;
+ bool save(QString *errorString, const Utils::FilePath &filePath, bool autoSave) override;
ReloadBehavior reloadBehavior(ChangeTrigger state, ChangeType type) const override;
void setModified(bool modified = true);
diff --git a/src/plugins/vcsbase/vcsbase.pro b/src/plugins/vcsbase/vcsbase.pro
index db33e93240..7b1d8f2e35 100644
--- a/src/plugins/vcsbase/vcsbase.pro
+++ b/src/plugins/vcsbase/vcsbase.pro
@@ -17,7 +17,6 @@ HEADERS += vcsbase_global.h \
basevcssubmiteditorfactory.h \
submitfilemodel.h \
commonvcssettings.h \
- commonsettingspage.h \
nicknamedialog.h \
vcsoutputwindow.h \
cleandialog.h \
@@ -44,7 +43,6 @@ SOURCES += vcsplugin.cpp \
basevcssubmiteditorfactory.cpp \
submitfilemodel.cpp \
commonvcssettings.cpp \
- commonsettingspage.cpp \
nicknamedialog.cpp \
vcsoutputwindow.cpp \
cleandialog.cpp \
@@ -58,7 +56,7 @@ SOURCES += vcsplugin.cpp \
RESOURCES += vcsbase.qrc
-FORMS += commonsettingspage.ui \
+FORMS += \
nicknamedialog.ui \
cleandialog.ui \
submiteditorwidget.ui
diff --git a/src/plugins/vcsbase/vcsbase.qbs b/src/plugins/vcsbase/vcsbase.qbs
index ac629c450d..ecbad61f1b 100644
--- a/src/plugins/vcsbase/vcsbase.qbs
+++ b/src/plugins/vcsbase/vcsbase.qbs
@@ -28,9 +28,6 @@ QtcPlugin {
"cleandialog.cpp",
"cleandialog.h",
"cleandialog.ui",
- "commonsettingspage.cpp",
- "commonsettingspage.h",
- "commonsettingspage.ui",
"commonvcssettings.cpp",
"commonvcssettings.h",
"diffandloghighlighter.cpp",
diff --git a/src/plugins/vcsbase/vcsbaseclient.cpp b/src/plugins/vcsbase/vcsbaseclient.cpp
index 86fc118cbb..26acb2161c 100644
--- a/src/plugins/vcsbase/vcsbaseclient.cpp
+++ b/src/plugins/vcsbase/vcsbaseclient.cpp
@@ -35,7 +35,8 @@
#include <coreplugin/idocument.h>
#include <utils/qtcassert.h>
-#include <utils/synchronousprocess.h>
+#include <utils/qtcprocess.h>
+
#include <vcsbase/vcsbaseeditor.h>
#include <vcsbase/vcsoutputwindow.h>
#include <vcsbase/vcsbaseplugin.h>
@@ -73,23 +74,22 @@ static Core::IEditor *locateEditor(const char *property, const QString &entry)
namespace VcsBase {
-VcsBaseClientImpl::VcsBaseClientImpl(VcsBaseClientSettings *settings) :
- m_clientSettings(settings)
+VcsBaseClientImpl::VcsBaseClientImpl(VcsBaseSettings *baseSettings)
+ : m_baseSettings(baseSettings)
{
- m_defaultSettings = *m_clientSettings;
- m_clientSettings->readSettings(Core::ICore::settings());
+ m_baseSettings->readSettings(Core::ICore::settings());
connect(Core::ICore::instance(), &Core::ICore::saveSettingsRequested,
this, &VcsBaseClientImpl::saveSettings);
}
-VcsBaseClientSettings &VcsBaseClientImpl::settings() const
+VcsBaseSettings &VcsBaseClientImpl::settings() const
{
- return *m_clientSettings;
+ return *m_baseSettings;
}
FilePath VcsBaseClientImpl::vcsBinary() const
{
- return settings().binaryPath();
+ return m_baseSettings->binaryPath.filePath();
}
VcsCommand *VcsBaseClientImpl::createCommand(const QString &workingDirectory,
@@ -119,16 +119,16 @@ void VcsBaseClientImpl::enqueueJob(VcsCommand *cmd, const QStringList &args,
cmd->execute();
}
-QProcessEnvironment VcsBaseClientImpl::processEnvironment() const
+Environment VcsBaseClientImpl::processEnvironment() const
{
- QProcessEnvironment environment = QProcessEnvironment::systemEnvironment();
+ Environment environment = Environment::systemEnvironment();
VcsBase::setProcessEnvironment(&environment, false);
return environment;
}
QString VcsBaseClientImpl::commandOutputFromLocal8Bit(const QByteArray &a)
{
- return SynchronousProcess::normalizeNewlines(QString::fromLocal8Bit(a));
+ return QtcProcess::normalizeNewlines(QString::fromLocal8Bit(a));
}
QStringList VcsBaseClientImpl::commandOutputLinesFromLocal8Bit(const QByteArray &a)
@@ -154,15 +154,16 @@ QString VcsBaseClientImpl::stripLastNewline(const QString &in)
return in;
}
-SynchronousProcessResponse
-VcsBaseClientImpl::vcsFullySynchronousExec(const QString &workingDir, const CommandLine &cmdLine,
- unsigned flags, int timeoutS, QTextCodec *codec) const
+void VcsBaseClientImpl::vcsFullySynchronousExec(SynchronousProcess &proc,
+ const QString &workingDir, const CommandLine &cmdLine,
+ unsigned flags, int timeoutS, QTextCodec *codec) const
{
VcsCommand command(workingDir, processEnvironment());
command.addFlags(flags);
if (codec)
command.setCodec(codec);
- return command.runCommand(cmdLine, (timeoutS > 0) ? timeoutS : vcsTimeoutS());
+ proc.setTimeoutS(timeoutS > 0 ? timeoutS : vcsTimeoutS());
+ command.runCommand(proc, cmdLine);
}
void VcsBaseClientImpl::resetCachedVcsInfo(const QString &workingDir)
@@ -183,11 +184,11 @@ void VcsBaseClientImpl::annotateRevisionRequested(const QString &workingDirector
annotate(workingDirectory, file, changeCopy, line);
}
-SynchronousProcessResponse
-VcsBaseClientImpl::vcsFullySynchronousExec(const QString &workingDir, const QStringList &args,
- unsigned flags, int timeoutS, QTextCodec *codec) const
+void VcsBaseClientImpl::vcsFullySynchronousExec(SynchronousProcess &proc,
+ const QString &workingDir, const QStringList &args,
+ unsigned flags, int timeoutS, QTextCodec *codec) const
{
- return vcsFullySynchronousExec(workingDir, {vcsBinary(), args}, flags, timeoutS, codec);
+ vcsFullySynchronousExec(proc, workingDir, {vcsBinary(), args}, flags, timeoutS, codec);
}
VcsCommand *VcsBaseClientImpl::vcsExec(const QString &workingDirectory, const QStringList &arguments,
@@ -204,18 +205,22 @@ VcsCommand *VcsBaseClientImpl::vcsExec(const QString &workingDirectory, const QS
return command;
}
-SynchronousProcessResponse VcsBaseClientImpl::vcsSynchronousExec(const QString &workingDir,
- const QStringList &args,
- unsigned flags,
- QTextCodec *outputCodec) const
+void VcsBaseClientImpl::vcsSynchronousExec(SynchronousProcess &proc, const QString &workingDir,
+ const QStringList &args,
+ unsigned flags,
+ QTextCodec *outputCodec) const
{
- return VcsBase::runVcs(workingDir, {vcsBinary(), args}, vcsTimeoutS(), flags,
- outputCodec, processEnvironment());
+ Environment env = processEnvironment();
+ VcsCommand command(workingDir, env.size() == 0 ? Environment::systemEnvironment() : env);
+ proc.setTimeoutS(vcsTimeoutS());
+ command.addFlags(flags);
+ command.setCodec(outputCodec);
+ command.runCommand(proc, {vcsBinary(), args});
}
int VcsBaseClientImpl::vcsTimeoutS() const
{
- return m_clientSettings->vcsTimeoutS();
+ return m_baseSettings->timeout.value();
}
VcsBaseEditorWidget *VcsBaseClientImpl::createVcsEditor(Utils::Id kind, QString title,
@@ -250,11 +255,11 @@ VcsBaseEditorWidget *VcsBaseClientImpl::createVcsEditor(Utils::Id kind, QString
void VcsBaseClientImpl::saveSettings()
{
- settings().writeSettings(Core::ICore::settings(), m_defaultSettings);
+ m_baseSettings->writeSettings(Core::ICore::settings());
}
-VcsBaseClient::VcsBaseClient(VcsBaseClientSettings *settings) :
- VcsBaseClientImpl(settings)
+VcsBaseClient::VcsBaseClient(VcsBaseSettings *baseSettings)
+ : VcsBaseClientImpl(baseSettings)
{
qRegisterMetaType<QVariant>();
}
@@ -264,10 +269,11 @@ bool VcsBaseClient::synchronousCreateRepository(const QString &workingDirectory,
{
QStringList args(vcsCommandString(CreateRepositoryCommand));
args << extraOptions;
- SynchronousProcessResponse result = vcsFullySynchronousExec(workingDirectory, args);
- if (result.result != SynchronousProcessResponse::Finished)
+ SynchronousProcess proc;
+ vcsFullySynchronousExec(proc, workingDirectory, args);
+ if (proc.result() != QtcProcess::Finished)
return false;
- VcsOutputWindow::append(result.stdOut());
+ VcsOutputWindow::append(proc.stdOut());
resetCachedVcsInfo(workingDirectory);
@@ -283,9 +289,10 @@ bool VcsBaseClient::synchronousClone(const QString &workingDir,
args << vcsCommandString(CloneCommand)
<< extraOptions << srcLocation << dstLocation;
- SynchronousProcessResponse result = vcsFullySynchronousExec(workingDir, args);
+ SynchronousProcess proc;
+ vcsFullySynchronousExec(proc, workingDir, args);
resetCachedVcsInfo(workingDir);
- return result.result == SynchronousProcessResponse::Finished;
+ return proc.result() == QtcProcess::Finished;
}
bool VcsBaseClient::synchronousAdd(const QString &workingDir, const QString &filename,
@@ -293,7 +300,9 @@ bool VcsBaseClient::synchronousAdd(const QString &workingDir, const QString &fil
{
QStringList args;
args << vcsCommandString(AddCommand) << extraOptions << filename;
- return vcsFullySynchronousExec(workingDir, args).result == SynchronousProcessResponse::Finished;
+ SynchronousProcess proc;
+ vcsFullySynchronousExec(proc, workingDir, args);
+ return proc.result() == QtcProcess::Finished;
}
bool VcsBaseClient::synchronousRemove(const QString &workingDir, const QString &filename,
@@ -301,7 +310,9 @@ bool VcsBaseClient::synchronousRemove(const QString &workingDir, const QString &
{
QStringList args;
args << vcsCommandString(RemoveCommand) << extraOptions << filename;
- return vcsFullySynchronousExec(workingDir, args).result == SynchronousProcessResponse::Finished;
+ SynchronousProcess proc;
+ vcsFullySynchronousExec(proc, workingDir, args);
+ return proc.result() == QtcProcess::Finished;
}
bool VcsBaseClient::synchronousMove(const QString &workingDir,
@@ -310,7 +321,9 @@ bool VcsBaseClient::synchronousMove(const QString &workingDir,
{
QStringList args;
args << vcsCommandString(MoveCommand) << extraOptions << from << to;
- return vcsFullySynchronousExec(workingDir, args).result == SynchronousProcessResponse::Finished;
+ SynchronousProcess proc;
+ vcsFullySynchronousExec(proc, workingDir, args);
+ return proc.result() == QtcProcess::Finished;
}
bool VcsBaseClient::synchronousPull(const QString &workingDir,
@@ -324,8 +337,9 @@ bool VcsBaseClient::synchronousPull(const QString &workingDir,
VcsCommand::SshPasswordPrompt
| VcsCommand::ShowStdOut
| VcsCommand::ShowSuccessMessage;
- const SynchronousProcessResponse resp = vcsSynchronousExec(workingDir, args, flags);
- const bool ok = resp.result == SynchronousProcessResponse::Finished;
+ SynchronousProcess proc;
+ vcsSynchronousExec(proc, workingDir, args, flags);
+ const bool ok = proc.result() == QtcProcess::Finished;
if (ok)
emit changed(QVariant(workingDir));
return ok;
@@ -342,8 +356,9 @@ bool VcsBaseClient::synchronousPush(const QString &workingDir,
VcsCommand::SshPasswordPrompt
| VcsCommand::ShowStdOut
| VcsCommand::ShowSuccessMessage;
- const SynchronousProcessResponse resp = vcsSynchronousExec(workingDir, args, flags);
- return resp.result == SynchronousProcessResponse::Finished;
+ SynchronousProcess proc;
+ vcsSynchronousExec(proc, workingDir, args, flags);
+ return proc.result() == QtcProcess::Finished;
}
VcsBaseEditorWidget *VcsBaseClient::annotate(
@@ -518,7 +533,7 @@ QString VcsBaseClient::vcsCommandString(VcsCommandTag cmd) const
ExitCodeInterpreter VcsBaseClient::exitCodeInterpreter(VcsCommandTag cmd) const
{
Q_UNUSED(cmd)
- return Utils::defaultExitCodeInterpreter;
+ return {};
}
void VcsBaseClient::setDiffConfigCreator(ConfigCreator creator)
diff --git a/src/plugins/vcsbase/vcsbaseclient.h b/src/plugins/vcsbase/vcsbaseclient.h
index 7d47ed0374..cc0317ea23 100644
--- a/src/plugins/vcsbase/vcsbaseclient.h
+++ b/src/plugins/vcsbase/vcsbaseclient.h
@@ -31,7 +31,7 @@
#include <utils/fileutils.h>
#include <utils/id.h>
-#include <utils/synchronousprocess.h>
+#include <utils/qtcprocess.h>
#include <QObject>
#include <QStringList>
@@ -41,7 +41,6 @@
QT_BEGIN_NAMESPACE
class QFileInfo;
-class QProcessEnvironment;
class QToolBar;
QT_END_NAMESPACE
@@ -58,10 +57,10 @@ class VCSBASE_EXPORT VcsBaseClientImpl : public QObject
Q_OBJECT
public:
- explicit VcsBaseClientImpl(VcsBaseClientSettings *settings);
+ explicit VcsBaseClientImpl(VcsBaseSettings *baseSettings);
~VcsBaseClientImpl() override = default;
- VcsBaseClientSettings &settings() const;
+ VcsBaseSettings &settings() const;
virtual Utils::FilePath vcsBinary() const;
int vcsTimeoutS() const;
@@ -82,9 +81,9 @@ public:
void enqueueJob(VcsCommand *cmd, const QStringList &args,
const QString &workingDirectory = QString(),
- const Utils::ExitCodeInterpreter &interpreter = Utils::defaultExitCodeInterpreter) const;
+ const Utils::ExitCodeInterpreter &interpreter = {}) const;
- virtual QProcessEnvironment processEnvironment() const;
+ virtual Utils::Environment processEnvironment() const;
// VCS functionality:
virtual VcsBaseEditorWidget *annotate(
@@ -100,12 +99,12 @@ public:
static QString stripLastNewline(const QString &in);
// Fully synchronous VCS execution (QProcess-based)
- Utils::SynchronousProcessResponse
- vcsFullySynchronousExec(const QString &workingDir, const QStringList &args,
- unsigned flags = 0, int timeoutS = -1, QTextCodec *codec = nullptr) const;
- Utils::SynchronousProcessResponse
- vcsFullySynchronousExec(const QString &workingDir, const Utils::CommandLine &cmdLine,
- unsigned flags = 0, int timeoutS = -1, QTextCodec *codec = nullptr) const;
+ void vcsFullySynchronousExec(Utils::SynchronousProcess &process,
+ const QString &workingDir, const QStringList &args,
+ unsigned flags = 0, int timeoutS = -1, QTextCodec *codec = nullptr) const;
+ void vcsFullySynchronousExec(Utils::SynchronousProcess &process,
+ const QString &workingDir, const Utils::CommandLine &cmdLine,
+ unsigned flags = 0, int timeoutS = -1, QTextCodec *codec = nullptr) const;
// Simple helper to execute a single command using createCommand and enqueueJob.
@@ -120,16 +119,16 @@ protected:
// Synchronous VCS execution using Utils::SynchronousProcess, with
// log windows updating (using VcsBasePlugin::runVcs with flags)
- Utils::SynchronousProcessResponse vcsSynchronousExec(const QString &workingDir,
- const QStringList &args,
- unsigned flags = 0,
- QTextCodec *outputCodec = nullptr) const;
+ void vcsSynchronousExec(Utils::SynchronousProcess &proc,
+ const QString &workingDir,
+ const QStringList &args,
+ unsigned flags = 0,
+ QTextCodec *outputCodec = nullptr) const;
private:
void saveSettings();
- VcsBaseClientSettings *m_clientSettings;
- VcsBaseClientSettings m_defaultSettings;
+ VcsBaseSettings *m_baseSettings = nullptr; // Aspect based.
};
class VCSBASE_EXPORT VcsBaseClient : public VcsBaseClientImpl
@@ -145,7 +144,7 @@ public:
QString file;
};
- explicit VcsBaseClient(VcsBaseClientSettings *settings);
+ explicit VcsBaseClient(VcsBaseSettings *baseSettings);
virtual bool synchronousCreateRepository(const QString &workingDir,
const QStringList &extraOptions = QStringList());
diff --git a/src/plugins/vcsbase/vcsbaseclientsettings.cpp b/src/plugins/vcsbase/vcsbaseclientsettings.cpp
index 42760f77af..fe51a44ecd 100644
--- a/src/plugins/vcsbase/vcsbaseclientsettings.cpp
+++ b/src/plugins/vcsbase/vcsbaseclientsettings.cpp
@@ -38,363 +38,46 @@
using namespace Utils;
-namespace {
-
-class SettingValue
-{
-public:
- union Composite
- {
- QString *strPtr; // Union can't store class objects ...
- int intValue;
- bool boolValue;
- };
-
- SettingValue() = default;
-
- explicit SettingValue(const QVariant &v) :
- m_type(v.type())
- {
- switch (v.type()) {
- case QVariant::UInt:
- m_type = QVariant::Int;
- Q_FALLTHROUGH();
- case QVariant::Int:
- m_comp.intValue = v.toInt();
- break;
- case QVariant::Bool:
- m_comp.boolValue = v.toBool();
- break;
- case QVariant::String:
- m_comp.strPtr = new QString(v.toString());
- break;
- default:
- m_type = QVariant::Invalid;
- break;
- }
- }
-
- SettingValue(const SettingValue &other) :
- m_comp(other.m_comp),
- m_type(other.type())
- {
- copyInternalString(other);
- }
-
- ~SettingValue()
- {
- deleteInternalString();
- }
-
- SettingValue &operator=(const SettingValue &other)
- {
- if (this != &other) {
- deleteInternalString();
- m_type = other.type();
- m_comp = other.m_comp;
- copyInternalString(other);
- }
- return *this;
- }
-
- QString stringValue(const QString &defaultString = QString()) const
- {
- if (type() == QVariant::String && m_comp.strPtr != nullptr)
- return *(m_comp.strPtr);
- return defaultString;
- }
-
- QVariant::Type type() const
- {
- return m_type;
- }
-
- static bool isUsableVariantType(QVariant::Type varType)
- {
- return varType == QVariant::UInt || varType == QVariant::Int ||
- varType == QVariant::Bool || varType == QVariant::String;
- }
-
- Composite m_comp;
-
-private:
- void deleteInternalString()
- {
- if (m_type == QVariant::String && m_comp.strPtr != nullptr) {
- delete m_comp.strPtr;
- m_comp.strPtr = nullptr;
- }
- }
-
- void copyInternalString(const SettingValue &other)
- {
- if (type() == QVariant::String) {
- const QString *otherString = other.m_comp.strPtr;
- m_comp.strPtr = new QString(otherString != nullptr ? *otherString : QString());
- }
- }
-
- QVariant::Type m_type = QVariant::Invalid;
-};
-
-bool operator==(const SettingValue &lhs, const SettingValue &rhs)
-{
- if (lhs.type() == rhs.type()) {
- switch (lhs.type()) {
- case QVariant::Int:
- return lhs.m_comp.intValue == rhs.m_comp.intValue;
- case QVariant::Bool:
- return lhs.m_comp.boolValue == rhs.m_comp.boolValue;
- case QVariant::String:
- return lhs.stringValue() == rhs.stringValue();
- default:
- return false;
- }
- }
- return false;
-}
-
-} // Anonymous namespace
-
namespace VcsBase {
-namespace Internal {
-
-class VcsBaseClientSettingsPrivate : public QSharedData
-{
-public:
- VcsBaseClientSettingsPrivate() {}
-
- VcsBaseClientSettingsPrivate(const VcsBaseClientSettingsPrivate &other) :
- QSharedData(other),
- m_valueHash(other.m_valueHash),
- m_defaultValueHash(other.m_defaultValueHash),
- m_settingsGroup(other.m_settingsGroup),
- m_binaryFullPath(other.m_binaryFullPath)
- {
- }
-
- QHash<QString, SettingValue> m_valueHash;
- QVariantHash m_defaultValueHash;
- QString m_settingsGroup;
- mutable FilePath m_binaryFullPath;
-};
-
-} // namespace Internal
-
-/*!
- \class VcsBase::VcsBaseClientSettings
-
- \brief The VcsBaseClientSettings class contains settings used in
- VcsBaseClient.
-
- \sa VcsBase::VcsBaseClient
-*/
-
-const QLatin1String VcsBaseClientSettings::binaryPathKey("BinaryPath");
-const QLatin1String VcsBaseClientSettings::userNameKey("Username");
-const QLatin1String VcsBaseClientSettings::userEmailKey("UserEmail");
-const QLatin1String VcsBaseClientSettings::logCountKey("LogCount");
-const QLatin1String VcsBaseClientSettings::promptOnSubmitKey("PromptOnSubmit");
-const QLatin1String VcsBaseClientSettings::timeoutKey("Timeout");
-const QLatin1String VcsBaseClientSettings::pathKey("Path");
-
-VcsBaseClientSettings::VcsBaseClientSettings() :
- d(new Internal::VcsBaseClientSettingsPrivate)
-{
- declareKey(binaryPathKey, QString());
- declareKey(userNameKey, QString());
- declareKey(userEmailKey, QString());
- declareKey(logCountKey, 100);
- declareKey(promptOnSubmitKey, true);
- declareKey(timeoutKey, 30);
- declareKey(pathKey, QString());
-}
-
-VcsBaseClientSettings::VcsBaseClientSettings(const VcsBaseClientSettings &other) :
- d(other.d)
-{
-}
-
-VcsBaseClientSettings &VcsBaseClientSettings::operator=(const VcsBaseClientSettings &other)
-{
- if (this != &other)
- d = other.d;
- return *this;
-}
-
-VcsBaseClientSettings::~VcsBaseClientSettings()
-{
-}
-
-void VcsBaseClientSettings::writeSettings(QSettings *settings,
- const VcsBaseClientSettings &defaultSettings) const
-{
- QTC_ASSERT(!settingsGroup().isEmpty(), return);
-
- settings->remove(settingsGroup());
- settings->beginGroup(settingsGroup());
- foreach (const QString &key, keys())
- QtcSettings::setValueWithDefault(settings, key, value(key), defaultSettings.value(key));
- settings->endGroup();
-}
-
-void VcsBaseClientSettings::readSettings(const QSettings *settings)
-{
- const QString keyRoot = settingsGroup() + QLatin1Char('/');
- foreach (const QString &key, keys()) {
- const QVariant value = settings->value(keyRoot + key, keyDefaultValue(key));
- // For some reason QSettings always return QVariant(QString) when the
- // key exists. The type is explicited to avoid wrong conversions
- switch (valueType(key)) {
- case QVariant::Int:
- setValue(key, value.toInt());
- break;
- case QVariant::Bool:
- setValue(key, value.toBool());
- break;
- case QVariant::String:
- setValue(key, value.toString());
- break;
- default:
- break;
- }
- }
-}
-
-bool VcsBaseClientSettings::equals(const VcsBaseClientSettings &rhs) const
-{
- if (this == &rhs)
- return true;
- return d->m_valueHash == rhs.d->m_valueHash;
-}
-
-QStringList VcsBaseClientSettings::keys() const
-{
- return d->m_valueHash.keys();
-}
-
-bool VcsBaseClientSettings::hasKey(const QString &key) const
-{
- return d->m_valueHash.contains(key);
-}
-
-int *VcsBaseClientSettings::intPointer(const QString &key)
-{
- if (hasKey(key))
- return &(d->m_valueHash[key].m_comp.intValue);
- return nullptr;
-}
-
-bool *VcsBaseClientSettings::boolPointer(const QString &key)
-{
- if (hasKey(key))
- return &(d->m_valueHash[key].m_comp.boolValue);
- return nullptr;
-}
-
-QString *VcsBaseClientSettings::stringPointer(const QString &key)
-{
- if (hasKey(key) && valueType(key) == QVariant::String)
- return d->m_valueHash[key].m_comp.strPtr;
- return nullptr;
-}
-
-int VcsBaseClientSettings::intValue(const QString &key, int defaultValue) const
-{
- if (hasKey(key) && valueType(key) == QVariant::Int)
- return d->m_valueHash[key].m_comp.intValue;
- return defaultValue;
-}
-
-bool VcsBaseClientSettings::boolValue(const QString &key, bool defaultValue) const
+VcsBaseSettings::VcsBaseSettings()
{
- if (hasKey(key) && valueType(key) == QVariant::Bool)
- return d->m_valueHash[key].m_comp.boolValue;
- return defaultValue;
-}
+ setAutoApply(false);
-QString VcsBaseClientSettings::stringValue(const QString &key, const QString &defaultValue) const
-{
- if (hasKey(key))
- return d->m_valueHash[key].stringValue(defaultValue);
- return defaultValue;
-}
+ registerAspect(&binaryPath);
+ binaryPath.setSettingsKey("BinaryPath");
-QVariant VcsBaseClientSettings::value(const QString &key) const
-{
- switch (valueType(key)) {
- case QVariant::Int:
- return intValue(key);
- case QVariant::Bool:
- return boolValue(key);
- case QVariant::String:
- return stringValue(key);
- case QVariant::Invalid:
- return QVariant();
- default:
- return QVariant();
- }
-}
+ registerAspect(&userName);
+ userName.setSettingsKey("Username");
-void VcsBaseClientSettings::setValue(const QString &key, const QVariant &v)
-{
- if (SettingValue::isUsableVariantType(valueType(key))) {
- d->m_valueHash.insert(key, SettingValue(v));
- d->m_binaryFullPath.clear();
- }
-}
+ registerAspect(&userEmail);
+ userEmail.setSettingsKey("UserEmail");
-QVariant::Type VcsBaseClientSettings::valueType(const QString &key) const
-{
- if (hasKey(key))
- return d->m_valueHash[key].type();
- return QVariant::Invalid;
-}
+ registerAspect(&logCount);
+ logCount.setSettingsKey("LogCount");
+ logCount.setRange(0, 1000 * 1000);
+ logCount.setDefaultValue(100);
+ logCount.setLabelText(tr("Log count:"));
-FilePath VcsBaseClientSettings::binaryPath() const
-{
- if (d->m_binaryFullPath.isEmpty()) {
- const FilePaths searchPaths = Utils::transform(searchPathList(), &FilePath::fromString);
- d->m_binaryFullPath = Environment::systemEnvironment().searchInPath(
- stringValue(binaryPathKey), searchPaths);
- }
- return d->m_binaryFullPath;
-}
+ registerAspect(&path);
+ path.setSettingsKey("Path");
-int VcsBaseClientSettings::vcsTimeoutS() const
-{
- return intValue(VcsBaseClientSettings::timeoutKey);
-}
-
-QStringList VcsBaseClientSettings::searchPathList() const
-{
- return stringValue(pathKey).split(HostOsInfo::pathListSeparator(), Qt::SkipEmptyParts);
-}
+ registerAspect(&promptOnSubmit);
+ promptOnSubmit.setSettingsKey("PromptOnSubmit");
+ promptOnSubmit.setDefaultValue(true);
+ promptOnSubmit.setLabelText(tr("Prompt on submit"));
-QString VcsBaseClientSettings::settingsGroup() const
-{
- return d->m_settingsGroup;
-}
-
-void VcsBaseClientSettings::setSettingsGroup(const QString &group)
-{
- d->m_settingsGroup = group;
-}
-
-void VcsBaseClientSettings::declareKey(const QString &key, const QVariant &defaultValue)
-{
- if (SettingValue::isUsableVariantType(defaultValue.type())) {
- d->m_valueHash.insert(key, SettingValue(defaultValue));
- d->m_defaultValueHash.insert(key, defaultValue);
- }
+ registerAspect(&timeout);
+ timeout.setSettingsKey("Timeout");
+ timeout.setRange(0, 3600 * 24 * 365);
+ timeout.setDefaultValue(30);
+ timeout.setLabelText(tr("Timeout:"));
+ timeout.setSuffix(tr("s"));
}
-QVariant VcsBaseClientSettings::keyDefaultValue(const QString &key) const
+QStringList VcsBaseSettings::searchPathList() const
{
- if (d->m_defaultValueHash.contains(key))
- return d->m_defaultValueHash.value(key);
- return QVariant(valueType(key));
+ return path.value().split(HostOsInfo::pathListSeparator(), Qt::SkipEmptyParts);
}
} // namespace VcsBase
diff --git a/src/plugins/vcsbase/vcsbaseclientsettings.h b/src/plugins/vcsbase/vcsbaseclientsettings.h
index 494e726597..91dae89874 100644
--- a/src/plugins/vcsbase/vcsbaseclientsettings.h
+++ b/src/plugins/vcsbase/vcsbaseclientsettings.h
@@ -27,77 +27,29 @@
#include "vcsbase_global.h"
-#include <QStringList>
-#include <QVariant>
-#include <QSharedDataPointer>
+#include <utils/aspects.h>
-QT_BEGIN_NAMESPACE
-class QSettings;
-QT_END_NAMESPACE
-
-namespace Utils { class FilePath; }
namespace VcsBase {
-namespace Internal { class VcsBaseClientSettingsPrivate; }
-
-class VCSBASE_EXPORT VcsBaseClientSettings
+class VCSBASE_EXPORT VcsBaseSettings : public Utils::AspectContainer
{
-public:
- static const QLatin1String binaryPathKey;
- static const QLatin1String userNameKey;
- static const QLatin1String userEmailKey;
- static const QLatin1String logCountKey;
- static const QLatin1String promptOnSubmitKey;
- static const QLatin1String timeoutKey; // Seconds
- static const QLatin1String pathKey;
-
- VcsBaseClientSettings();
- VcsBaseClientSettings(const VcsBaseClientSettings &other);
- VcsBaseClientSettings &operator=(const VcsBaseClientSettings &other);
- virtual ~VcsBaseClientSettings();
-
- void writeSettings(QSettings *settings, const VcsBaseClientSettings &defaultSettings) const;
- void readSettings(const QSettings *settings);
-
- bool equals(const VcsBaseClientSettings &rhs) const;
-
- QStringList keys() const;
- bool hasKey(const QString &key) const;
+ Q_DECLARE_TR_FUNCTIONS(VcsBase::VcsBaseSettings)
- int *intPointer(const QString &key);
- int intValue(const QString &key, int defaultValue = 0) const;
-
- bool *boolPointer(const QString &key);
- bool boolValue(const QString &key, bool defaultValue = false) const;
-
- QString *stringPointer(const QString &key);
- QString stringValue(const QString &key, const QString &defaultValue = QString()) const;
-
- QVariant value(const QString &key) const;
- void setValue(const QString &key, const QVariant &v);
- QVariant::Type valueType(const QString &key) const;
+public:
+ VcsBaseSettings();
- Utils::FilePath binaryPath() const;
+ Utils::StringAspect binaryPath;
+ Utils::StringAspect userName;
+ Utils::StringAspect userEmail;
+ Utils::IntegerAspect logCount;
+ Utils::BoolAspect promptOnSubmit;
+ Utils::IntegerAspect timeout; // Seconds
+ Utils::StringAspect path;
QStringList searchPathList() const;
- int vcsTimeoutS() const;
-
-protected:
- QString settingsGroup() const;
- void setSettingsGroup(const QString &group);
-
- void declareKey(const QString &key, const QVariant &defaultValue);
- QVariant keyDefaultValue(const QString &key) const;
private:
- friend bool equals(const VcsBaseClientSettings &rhs);
- friend class VcsBaseClientSettingsPrivate;
- QSharedDataPointer<Internal::VcsBaseClientSettingsPrivate> d;
+ QString m_settingsGroup;
};
-inline bool operator==(const VcsBaseClientSettings &s1, const VcsBaseClientSettings &s2)
-{ return s1.equals(s2); }
-inline bool operator!=(const VcsBaseClientSettings &s1, const VcsBaseClientSettings &s2)
-{ return !s1.equals(s2); }
-
} // namespace VcsBase
diff --git a/src/plugins/vcsbase/vcsbasediffeditorcontroller.cpp b/src/plugins/vcsbase/vcsbasediffeditorcontroller.cpp
index 93e75a6dd9..aad270f569 100644
--- a/src/plugins/vcsbase/vcsbasediffeditorcontroller.cpp
+++ b/src/plugins/vcsbase/vcsbasediffeditorcontroller.cpp
@@ -30,6 +30,8 @@
#include <coreplugin/editormanager/editormanager.h>
#include <coreplugin/progressmanager/progressmanager.h>
#include <diffeditor/diffutils.h>
+
+#include <utils/environment.h>
#include <utils/qtcassert.h>
#include <utils/runextensions.h>
@@ -37,6 +39,7 @@
using namespace DiffEditor;
using namespace Core;
+using namespace Utils;
namespace VcsBase {
@@ -93,7 +96,7 @@ public:
VcsBaseDiffEditorController *q;
QString m_directory;
- QProcessEnvironment m_processEnvironment;
+ Environment m_processEnvironment;
Utils::FilePath m_vcsBinary;
int m_vscTimeoutS;
QString m_startupFile;
@@ -294,7 +297,7 @@ void VcsBaseDiffEditorController::setVcsBinary(const Utils::FilePath &path)
d->m_vcsBinary = path;
}
-void VcsBaseDiffEditorController::setProcessEnvironment(const QProcessEnvironment &value)
+void VcsBaseDiffEditorController::setProcessEnvironment(const Environment &value)
{
d->m_processEnvironment = value;
}
diff --git a/src/plugins/vcsbase/vcsbasediffeditorcontroller.h b/src/plugins/vcsbase/vcsbasediffeditorcontroller.h
index ffe4f7cc43..7ccf05fd41 100644
--- a/src/plugins/vcsbase/vcsbasediffeditorcontroller.h
+++ b/src/plugins/vcsbase/vcsbasediffeditorcontroller.h
@@ -29,14 +29,16 @@
#include <diffeditor/diffeditorcontroller.h>
-#include <QProcessEnvironment>
-
QT_BEGIN_NAMESPACE
class QTextCodec;
QT_END_NAMESPACE
namespace Core { class IDocument; }
-namespace Utils { class FilePath; }
+
+namespace Utils {
+class Environment;
+class FilePath;
+} // Utils
namespace VcsBase {
@@ -50,7 +52,7 @@ public:
explicit VcsBaseDiffEditorController(Core::IDocument *document);
~VcsBaseDiffEditorController() override;
- void setProcessEnvironment(const QProcessEnvironment &value);
+ void setProcessEnvironment(const Utils::Environment &value);
void setVcsBinary(const Utils::FilePath &path);
void setVcsTimeoutS(int value);
void setWorkingDirectory(const QString &workingDir);
diff --git a/src/plugins/vcsbase/vcsbaseeditorconfig.cpp b/src/plugins/vcsbase/vcsbaseeditorconfig.cpp
index 95a08f72ae..f4b704b6e9 100644
--- a/src/plugins/vcsbase/vcsbaseeditorconfig.cpp
+++ b/src/plugins/vcsbase/vcsbaseeditorconfig.cpp
@@ -25,6 +25,7 @@
#include "vcsbaseeditorconfig.h"
+#include <utils/aspects.h>
#include <utils/utilsicons.h>
#include <QComboBox>
@@ -34,8 +35,9 @@
#include <QStringList>
#include <QDebug>
-namespace VcsBase {
+using namespace Utils;
+namespace VcsBase {
namespace Internal {
class SettingMappingData
@@ -46,7 +48,10 @@ public:
Invalid,
Bool,
String,
- Int
+ Int,
+ AspectBool,
+ AspectString,
+ AspectInt
};
SettingMappingData() : boolSetting(nullptr)
@@ -61,6 +66,15 @@ public:
SettingMappingData(int *setting) : intSetting(setting), m_type(Int)
{ }
+ SettingMappingData(BoolAspect *setting) : boolAspectSetting(setting), m_type(AspectBool)
+ { }
+
+ SettingMappingData(StringAspect *setting) : stringAspectSetting(setting), m_type(AspectString)
+ { }
+
+ SettingMappingData(IntegerAspect *setting) : intAspectSetting(setting), m_type(AspectInt)
+ { }
+
Type type() const
{
return m_type;
@@ -70,6 +84,9 @@ public:
bool *boolSetting;
QString *stringSetting;
int *intSetting;
+ BoolAspect *boolAspectSetting;
+ StringAspect *stringAspectSetting;
+ IntegerAspect *intAspectSetting;
};
private:
@@ -197,6 +214,17 @@ void VcsBaseEditorConfig::mapSetting(QAction *button, bool *setting)
}
}
+void VcsBaseEditorConfig::mapSetting(QAction *button, BoolAspect *setting)
+{
+ if (!d->m_settingMapping.contains(button) && button) {
+ d->m_settingMapping.insert(button, Internal::SettingMappingData(setting));
+ if (setting) {
+ QSignalBlocker blocker(button);
+ button->setChecked(setting->value());
+ }
+ }
+}
+
void VcsBaseEditorConfig::mapSetting(QComboBox *comboBox, QString *setting)
{
if (!d->m_settingMapping.contains(comboBox) && comboBox) {
@@ -210,6 +238,19 @@ void VcsBaseEditorConfig::mapSetting(QComboBox *comboBox, QString *setting)
}
}
+void VcsBaseEditorConfig::mapSetting(QComboBox *comboBox, StringAspect *setting)
+{
+ if (!d->m_settingMapping.contains(comboBox) && comboBox) {
+ d->m_settingMapping.insert(comboBox, Internal::SettingMappingData(setting));
+ if (setting) {
+ QSignalBlocker blocker(comboBox);
+ const int itemIndex = comboBox->findData(setting->value());
+ if (itemIndex != -1)
+ comboBox->setCurrentIndex(itemIndex);
+ }
+ }
+}
+
void VcsBaseEditorConfig::mapSetting(QComboBox *comboBox, int *setting)
{
if (d->m_settingMapping.contains(comboBox) || !comboBox)
@@ -224,6 +265,20 @@ void VcsBaseEditorConfig::mapSetting(QComboBox *comboBox, int *setting)
comboBox->setCurrentIndex(*setting);
}
+void VcsBaseEditorConfig::mapSetting(QComboBox *comboBox, IntegerAspect *setting)
+{
+ if (d->m_settingMapping.contains(comboBox) || !comboBox)
+ return;
+
+ d->m_settingMapping.insert(comboBox, Internal::SettingMappingData(setting));
+
+ if (!setting || setting->value() < 0 || setting->value() >= comboBox->count())
+ return;
+
+ QSignalBlocker blocker(comboBox);
+ comboBox->setCurrentIndex(setting->value());
+}
+
void VcsBaseEditorConfig::handleArgumentsChanged()
{
updateMappedSettings();
@@ -287,6 +342,12 @@ void VcsBaseEditorConfig::updateMappedSettings()
*settingData.boolSetting = action->isChecked();
break;
}
+ case Internal::SettingMappingData::AspectBool :
+ {
+ if (auto action = qobject_cast<const QAction *>(optMapping.object))
+ settingData.boolAspectSetting->setValue(action->isChecked());
+ break;
+ }
case Internal::SettingMappingData::String :
{
auto cb = qobject_cast<const QComboBox *>(optMapping.object);
@@ -294,6 +355,13 @@ void VcsBaseEditorConfig::updateMappedSettings()
*settingData.stringSetting = cb->itemData(cb->currentIndex()).toString();
break;
}
+ case Internal::SettingMappingData::AspectString :
+ {
+ auto cb = qobject_cast<const QComboBox *>(optMapping.object);
+ if (cb && cb->currentIndex() != -1)
+ settingData.stringAspectSetting->setValue(cb->itemData(cb->currentIndex()).toString());
+ break;
+ }
case Internal::SettingMappingData::Int:
{
auto cb = qobject_cast<const QComboBox *>(optMapping.object);
@@ -301,6 +369,13 @@ void VcsBaseEditorConfig::updateMappedSettings()
*settingData.intSetting = cb->currentIndex();
break;
}
+ case Internal::SettingMappingData::AspectInt:
+ {
+ auto cb = qobject_cast<const QComboBox *>(optMapping.object);
+ if (cb && cb->currentIndex() != -1)
+ settingData.intAspectSetting->setValue(cb->currentIndex());
+ break;
+ }
case Internal::SettingMappingData::Invalid : break;
} // end switch ()
}
diff --git a/src/plugins/vcsbase/vcsbaseeditorconfig.h b/src/plugins/vcsbase/vcsbaseeditorconfig.h
index 8f1ebaee19..494988eb7c 100644
--- a/src/plugins/vcsbase/vcsbaseeditorconfig.h
+++ b/src/plugins/vcsbase/vcsbaseeditorconfig.h
@@ -35,6 +35,12 @@ class QComboBox;
class QToolButton;
QT_END_NAMESPACE
+namespace Utils {
+class BoolAspect;
+class IntegerAspect;
+class StringAspect;
+} // Utils
+
namespace VcsBase {
class VcsBaseEditorWidget;
@@ -75,6 +81,10 @@ public:
void mapSetting(QComboBox *comboBox, QString *setting);
void mapSetting(QComboBox *comboBox, int *setting);
+ void mapSetting(QAction *button, Utils::BoolAspect *setting);
+ void mapSetting(QComboBox *comboBox, Utils::StringAspect *setting);
+ void mapSetting(QComboBox *comboBox, Utils::IntegerAspect *setting);
+
// Return the effective arguments according to setting.
virtual QStringList arguments() const;
diff --git a/src/plugins/vcsbase/vcsbaseplugin.cpp b/src/plugins/vcsbase/vcsbaseplugin.cpp
index 9ff8a0b997..05e3557e21 100644
--- a/src/plugins/vcsbase/vcsbaseplugin.cpp
+++ b/src/plugins/vcsbase/vcsbaseplugin.cpp
@@ -38,7 +38,7 @@
#include <projectexplorer/project.h>
#include <projectexplorer/session.h>
#include <utils/qtcassert.h>
-#include <utils/synchronousprocess.h>
+#include <utils/qtcprocess.h>
#include <QDebug>
#include <QDir>
@@ -721,7 +721,7 @@ QString findRepositoryForDirectory(const QString &dirS, const QString &checkFile
// Is SSH prompt configured?
QString sshPrompt()
{
- return Internal::VcsPlugin::instance()->settings().sshPasswordPrompt;
+ return Internal::VcsPlugin::instance()->settings().sshPasswordPrompt.value();
}
bool isSshPromptConfigured()
@@ -742,31 +742,14 @@ QString source(IDocument *document)
return document->property(SOURCE_PROPERTY).toString();
}
-void setProcessEnvironment(QProcessEnvironment *e,
- bool forceCLocale,
- const QString &sshPromptBinary)
+void setProcessEnvironment(Environment *e, bool forceCLocale, const QString &sshPromptBinary)
{
if (forceCLocale) {
- e->insert("LANG", "C");
- e->insert("LANGUAGE", "C");
+ e->set("LANG", "C");
+ e->set("LANGUAGE", "C");
}
if (!sshPromptBinary.isEmpty())
- e->insert("SSH_ASKPASS", sshPromptBinary);
-}
-
-// Run a process synchronously, returning Utils::SynchronousProcessResponse
-// response struct and using the VcsBasePlugin flags as applicable
-SynchronousProcessResponse runVcs(const QString &workingDir,
- const CommandLine &cmd,
- int timeOutS,
- unsigned flags,
- QTextCodec *outputCodec,
- const QProcessEnvironment &env)
-{
- VcsCommand command(workingDir, env.isEmpty() ? QProcessEnvironment::systemEnvironment() : env);
- command.addFlags(flags);
- command.setCodec(outputCodec);
- return command.runCommand(cmd, timeOutS);
+ e->set("SSH_ASKPASS", sshPromptBinary);
}
} // namespace VcsBase
diff --git a/src/plugins/vcsbase/vcsbaseplugin.h b/src/plugins/vcsbase/vcsbaseplugin.h
index d1fc51bae5..9afc4c109f 100644
--- a/src/plugins/vcsbase/vcsbaseplugin.h
+++ b/src/plugins/vcsbase/vcsbaseplugin.h
@@ -30,10 +30,9 @@
#include <coreplugin/icontext.h>
#include <coreplugin/iversioncontrol.h>
#include <coreplugin/vcsmanager.h>
+
#include <extensionsystem/iplugin.h>
-#include <QList>
-#include <QProcessEnvironment>
#include <QSharedDataPointer>
QT_BEGIN_NAMESPACE
@@ -42,8 +41,7 @@ class QTextCodec;
QT_END_NAMESPACE
namespace Utils {
-class CommandLine;
-class SynchronousProcessResponse;
+class Environment;
} // namespace Utils
namespace Core {
@@ -138,7 +136,7 @@ VCSBASE_EXPORT bool isSshPromptConfigured();
// Sets up SSH graphical password prompting (note that the latter
// requires a terminal-less process) and sets LANG to 'C' to force English
// (suppress LOCALE warnings/parse commands output) if desired.
-VCSBASE_EXPORT void setProcessEnvironment(QProcessEnvironment *e,
+VCSBASE_EXPORT void setProcessEnvironment(Utils::Environment *e,
bool forceCLocale,
const QString &sshPasswordPrompt = sshPrompt());
// Sets the source of editor contents, can be directory or file.
@@ -146,13 +144,6 @@ VCSBASE_EXPORT void setSource(Core::IDocument *document, const QString &source);
// Returns the source of editor contents.
VCSBASE_EXPORT QString source(Core::IDocument *document);
-VCSBASE_EXPORT Utils::SynchronousProcessResponse runVcs(const QString &workingDir,
- const Utils::CommandLine &cmd,
- int timeOutS,
- unsigned flags = 0,
- QTextCodec *outputCodec = nullptr,
- const QProcessEnvironment &env = {});
-
class VCSBASE_EXPORT VcsBasePluginPrivate : public Core::IVersionControl
{
Q_OBJECT
diff --git a/src/plugins/vcsbase/vcsbasesubmiteditor.cpp b/src/plugins/vcsbase/vcsbasesubmiteditor.cpp
index e4feb29ca0..229a18b4b2 100644
--- a/src/plugins/vcsbase/vcsbasesubmiteditor.cpp
+++ b/src/plugins/vcsbase/vcsbasesubmiteditor.cpp
@@ -50,7 +50,7 @@
#include <utils/fileutils.h>
#include <utils/icon.h>
#include <utils/qtcassert.h>
-#include <utils/synchronousprocess.h>
+#include <utils/qtcprocess.h>
#include <utils/temporarydirectory.h>
#include <utils/theme/theme.h>
@@ -128,7 +128,7 @@ using namespace Utils;
static inline QString submitMessageCheckScript()
{
- return VcsPlugin::instance()->settings().submitMessageCheckScript;
+ return VcsPlugin::instance()->settings().submitMessageCheckScript.value();
}
class VcsBaseSubmitEditorPrivate
@@ -199,32 +199,33 @@ void VcsBaseSubmitEditor::setParameters(const VcsBaseSubmitEditorParameters &par
connect(descriptionEdit, &QTextEdit::textChanged,
this, &VcsBaseSubmitEditor::fileContentsChanged);
- const CommonVcsSettings settings = VcsPlugin::instance()->settings();
+ const CommonVcsSettings &settings = VcsPlugin::instance()->settings();
// Add additional context menu settings
- if (!settings.submitMessageCheckScript.isEmpty() || !settings.nickNameMailMap.isEmpty()) {
+ if (!settings.submitMessageCheckScript.value().isEmpty()
+ || !settings.nickNameMailMap.value().isEmpty()) {
auto sep = new QAction(this);
sep->setSeparator(true);
d->m_widget->addDescriptionEditContextMenuAction(sep);
// Run check action
- if (!settings.submitMessageCheckScript.isEmpty()) {
+ if (!settings.submitMessageCheckScript.value().isEmpty()) {
auto checkAction = new QAction(tr("Check Message"), this);
connect(checkAction, &QAction::triggered,
this, &VcsBaseSubmitEditor::slotCheckSubmitMessage);
d->m_widget->addDescriptionEditContextMenuAction(checkAction);
}
// Insert nick
- if (!settings.nickNameMailMap.isEmpty()) {
+ if (!settings.nickNameMailMap.value().isEmpty()) {
auto insertAction = new QAction(tr("Insert Name..."), this);
connect(insertAction, &QAction::triggered, this, &VcsBaseSubmitEditor::slotInsertNickName);
d->m_widget->addDescriptionEditContextMenuAction(insertAction);
}
}
// Do we have user fields?
- if (!settings.nickNameFieldListFile.isEmpty())
- createUserFields(settings.nickNameFieldListFile);
+ if (!settings.nickNameFieldListFile.value().isEmpty())
+ createUserFields(settings.nickNameFieldListFile.value());
// wrapping. etc
- slotUpdateEditorSettings(settings);
+ slotUpdateEditorSettings();
connect(VcsPlugin::instance(), &VcsPlugin::settingsChanged,
this, &VcsBaseSubmitEditor::slotUpdateEditorSettings);
connect(Core::EditorManager::instance(), &Core::EditorManager::currentEditorChanged,
@@ -250,10 +251,11 @@ VcsBaseSubmitEditor::~VcsBaseSubmitEditor()
delete d;
}
-void VcsBaseSubmitEditor::slotUpdateEditorSettings(const CommonVcsSettings &s)
+void VcsBaseSubmitEditor::slotUpdateEditorSettings()
{
- setLineWrapWidth(s.lineWrapWidth);
- setLineWrap(s.lineWrap);
+ const CommonVcsSettings &s = VcsPlugin::instance()->settings();
+ setLineWrapWidth(s.lineWrapWidth.value());
+ setLineWrap(s.lineWrap.value());
}
// Return a trimmed list of non-empty field texts
@@ -272,8 +274,11 @@ static inline QStringList fieldTexts(const QString &fileContents)
void VcsBaseSubmitEditor::createUserFields(const QString &fieldConfigFile)
{
FileReader reader;
- if (!reader.fetch(fieldConfigFile, QIODevice::Text, Core::ICore::dialogParent()))
+ if (!reader.fetch(FilePath::fromString(fieldConfigFile),
+ QIODevice::Text,
+ Core::ICore::dialogParent())) {
return;
+ }
// Parse into fields
const QStringList fields = fieldTexts(QString::fromUtf8(reader.data()));
if (fields.empty())
@@ -514,12 +519,13 @@ static QString withUnusedMnemonic(QString string, const QList<QPushButton *> &ot
VcsBaseSubmitEditor::PromptSubmitResult
VcsBaseSubmitEditor::promptSubmit(VcsBasePluginPrivate *plugin,
- bool *promptSetting,
+ bool *promptSettingOld,
bool forcePrompt,
- bool canCommitOnFailure)
+ bool canCommitOnFailure,
+ BoolAspect *promptSetting)
{
- bool dummySetting = false;
- if (!promptSetting)
+ BoolAspect dummySetting;
+ if (!promptSetting && !promptSettingOld)
promptSetting = &dummySetting;
auto submitWidget = static_cast<SubmitEditorWidget *>(this->widget());
@@ -530,7 +536,8 @@ VcsBaseSubmitEditor::PromptSubmitResult
QString errorMessage;
- const bool prompt = forcePrompt || *promptSetting;
+ const bool value = promptSettingOld ? *promptSettingOld : promptSetting->value();
+ const bool prompt = forcePrompt || value;
// Pop up a message depending on whether the check succeeded and the
// user wants to be prompted
@@ -552,9 +559,9 @@ VcsBaseSubmitEditor::PromptSubmitResult
}
mb.setText(message);
mb.setCheckBoxText(tr("Prompt to %1").arg(commitName.toLower()));
- mb.setChecked(*promptSetting);
+ mb.setChecked(value);
// Provide check box to turn off prompt ONLY if it was not forced
- mb.setCheckBoxVisible(*promptSetting && !forcePrompt);
+ mb.setCheckBoxVisible(value && !forcePrompt);
QDialogButtonBox::StandardButtons buttons = QDialogButtonBox::Close | QDialogButtonBox::Cancel;
if (canCommit || canCommitOnFailure)
buttons |= QDialogButtonBox::Ok;
@@ -570,8 +577,12 @@ VcsBaseSubmitEditor::PromptSubmitResult
commitButton->setText(withUnusedMnemonic(commitName,
{cancelButton, mb.button(QDialogButtonBox::Close)}));
}
- if (mb.exec() == QDialog::Accepted)
- *promptSetting = mb.isChecked();
+ if (mb.exec() == QDialog::Accepted) {
+ if (promptSettingOld)
+ *promptSettingOld = mb.isChecked();
+ else
+ promptSetting->setValue(mb.isChecked());
+ }
QAbstractButton *chosen = mb.clickedButton();
if (!chosen || chosen == cancelButton)
return SubmitCanceled;
@@ -646,10 +657,11 @@ bool VcsBaseSubmitEditor::runSubmitMessageCheckScript(const QString &checkScript
// Run check process
VcsOutputWindow::appendShellCommandLine(msgCheckScript(d->m_checkScriptWorkingDirectory,
checkScript));
- QProcess checkProcess;
+ QtcProcess checkProcess;
if (!d->m_checkScriptWorkingDirectory.isEmpty())
checkProcess.setWorkingDirectory(d->m_checkScriptWorkingDirectory);
- checkProcess.start(checkScript, QStringList(saver.fileName()));
+ checkProcess.setCommand({checkScript, {saver.filePath().toString()}});
+ checkProcess.start();
checkProcess.closeWriteChannel();
if (!checkProcess.waitForStarted()) {
*errorMessage = tr("The check script \"%1\" could not be started: %2").arg(checkScript, checkProcess.errorString());
@@ -657,8 +669,8 @@ bool VcsBaseSubmitEditor::runSubmitMessageCheckScript(const QString &checkScript
}
QByteArray stdOutData;
QByteArray stdErrData;
- if (!SynchronousProcess::readDataFromProcess(checkProcess, 30, &stdOutData, &stdErrData, false)) {
- SynchronousProcess::stopProcess(checkProcess);
+ if (!checkProcess.readDataFromProcess(30, &stdOutData, &stdErrData, false)) {
+ checkProcess.stopProcess();
*errorMessage = tr("The check script \"%1\" timed out.").
arg(QDir::toNativeSeparators(checkScript));
return false;
diff --git a/src/plugins/vcsbase/vcsbasesubmiteditor.h b/src/plugins/vcsbase/vcsbasesubmiteditor.h
index 8e60e39ff7..73b4209b6e 100644
--- a/src/plugins/vcsbase/vcsbasesubmiteditor.h
+++ b/src/plugins/vcsbase/vcsbasesubmiteditor.h
@@ -29,6 +29,8 @@
#include <coreplugin/editormanager/ieditor.h>
+#include <utils/aspects.h>
+
#include <QAbstractItemView>
QT_BEGIN_NAMESPACE
@@ -85,9 +87,10 @@ public:
// prompt setting. The user can uncheck it from the message box.
enum PromptSubmitResult { SubmitConfirmed, SubmitCanceled, SubmitDiscarded };
PromptSubmitResult promptSubmit(VcsBasePluginPrivate *plugin,
- bool *promptSetting,
+ bool *promptSettingOld,
bool forcePrompt = false,
- bool canCommitOnFailure = true);
+ bool canCommitOnFailure = true,
+ Utils::BoolAspect *promptSetting = nullptr);
QAbstractItemView::SelectionMode fileListSelectionMode() const;
void setFileListSelectionMode(QAbstractItemView::SelectionMode sm);
@@ -150,7 +153,7 @@ private:
void slotCheckSubmitMessage();
void slotInsertNickName();
void slotSetFieldNickName(int);
- void slotUpdateEditorSettings(const VcsBase::Internal::CommonVcsSettings &);
+ void slotUpdateEditorSettings();
void createUserFields(const QString &fieldConfigFile);
bool checkSubmitMessage(QString *errorMessage) const;
diff --git a/src/plugins/vcsbase/vcscommand.cpp b/src/plugins/vcsbase/vcscommand.cpp
index 3b1697c136..deb12aecc1 100644
--- a/src/plugins/vcsbase/vcscommand.cpp
+++ b/src/plugins/vcsbase/vcscommand.cpp
@@ -30,20 +30,18 @@
#include <coreplugin/documentmanager.h>
#include <coreplugin/vcsmanager.h>
#include <utils/globalfilechangeblocker.h>
-#include <utils/synchronousprocess.h>
-
-#include <QProcessEnvironment>
+#include <utils/qtcprocess.h>
using namespace Utils;
namespace VcsBase {
-VcsCommand::VcsCommand(const QString &workingDirectory,
- const QProcessEnvironment &environment) :
+VcsCommand::VcsCommand(const QString &workingDirectory, const Environment &environment) :
Core::ShellCommand(workingDirectory, environment),
m_preventRepositoryChanged(false)
{
VcsOutputWindow::setRepository(workingDirectory);
+ setDisableUnixTerminal();
setOutputProxyFactory([this] {
auto proxy = new OutputProxy;
VcsOutputWindow *outputWindow = VcsOutputWindow::instance();
@@ -71,21 +69,19 @@ VcsCommand::VcsCommand(const QString &workingDirectory,
});
}
-const QProcessEnvironment VcsCommand::processEnvironment() const
+const Environment VcsCommand::processEnvironment() const
{
- QProcessEnvironment env = Core::ShellCommand::processEnvironment();
+ Environment env = Core::ShellCommand::processEnvironment();
VcsBase::setProcessEnvironment(&env, flags() & ForceCLocale, VcsBase::sshPrompt());
return env;
}
-SynchronousProcessResponse VcsCommand::runCommand(const CommandLine &command, int timeoutS,
- const QString &workingDirectory,
- const ExitCodeInterpreter &interpreter)
+void VcsCommand::runCommand(SynchronousProcess &proc,
+ const CommandLine &command,
+ const QString &workingDirectory)
{
- SynchronousProcessResponse response
- = Core::ShellCommand::runCommand(command, timeoutS, workingDirectory, interpreter);
+ ShellCommand::runCommand(proc, command, workingDirectory);
emitRepositoryChanged(workingDirectory);
- return response;
}
void VcsCommand::emitRepositoryChanged(const QString &workingDirectory)
@@ -97,14 +93,6 @@ void VcsCommand::emitRepositoryChanged(const QString &workingDirectory)
Core::VcsManager::emitRepositoryChanged(workDirectory(workingDirectory));
}
-unsigned VcsCommand::processFlags() const
-{
- unsigned processFlags = 0;
- if (!VcsBase::sshPrompt().isEmpty() && (flags() & SshPasswordPrompt))
- processFlags |= SynchronousProcess::UnixTerminalDisabled;
- return processFlags;
-}
-
void VcsCommand::coreAboutToClose()
{
m_preventRepositoryChanged = true;
diff --git a/src/plugins/vcsbase/vcscommand.h b/src/plugins/vcsbase/vcscommand.h
index e092b25177..37fc6f23b3 100644
--- a/src/plugins/vcsbase/vcscommand.h
+++ b/src/plugins/vcsbase/vcscommand.h
@@ -41,17 +41,15 @@ public:
ExpectRepoChanges = 0x2000, // Expect changes in repository by the command
};
- VcsCommand(const QString &defaultWorkingDirectory, const QProcessEnvironment &environment);
+ VcsCommand(const QString &defaultWorkingDirectory, const Utils::Environment &environment);
- const QProcessEnvironment processEnvironment() const override;
+ const Utils::Environment processEnvironment() const override;
- Utils::SynchronousProcessResponse runCommand(const Utils::CommandLine &command,
- int timeoutS,
- const QString &workDirectory = QString(),
- const Utils::ExitCodeInterpreter &interpreter = Utils::defaultExitCodeInterpreter) override;
+ void runCommand(Utils::SynchronousProcess &process,
+ const Utils::CommandLine &command,
+ const QString &workDirectory = {}) override;
private:
- unsigned processFlags() const override;
void emitRepositoryChanged(const QString &workingDirectory);
void coreAboutToClose() override;
diff --git a/src/plugins/vcsbase/vcsoutputwindow.cpp b/src/plugins/vcsbase/vcsoutputwindow.cpp
index dcc144f0fa..1069a3fa7d 100644
--- a/src/plugins/vcsbase/vcsoutputwindow.cpp
+++ b/src/plugins/vcsbase/vcsoutputwindow.cpp
@@ -448,12 +448,12 @@ static inline QString formatArguments(const QStringList &args)
if (i)
str << ' ';
if (arg.startsWith(QString::fromLatin1(passwordOptionC) + '=')) {
- str << QtcProcess::quoteArg("--password=********");
+ str << ProcessArgs::quoteArg("--password=********");
continue;
}
- str << QtcProcess::quoteArg(arg);
+ str << ProcessArgs::quoteArg(arg);
if (arg == passwordOptionC) {
- str << ' ' << QtcProcess::quoteArg("********");
+ str << ' ' << ProcessArgs::quoteArg("********");
i++;
}
}
@@ -463,7 +463,7 @@ static inline QString formatArguments(const QStringList &args)
QString VcsOutputWindow::msgExecutionLogEntry(const QString &workingDir, const CommandLine &command)
{
const QString args = formatArguments(command.splitArguments());
- const QString nativeExecutable = QtcProcess::quoteArg(command.executable().toUserOutput());
+ const QString nativeExecutable = ProcessArgs::quoteArg(command.executable().toUserOutput());
if (workingDir.isEmpty())
return tr("Running: %1 %2").arg(nativeExecutable, args) + '\n';
return tr("Running in %1: %2 %3").
diff --git a/src/plugins/vcsbase/vcsplugin.cpp b/src/plugins/vcsbase/vcsplugin.cpp
index 43d17145de..4ac28c46c2 100644
--- a/src/plugins/vcsbase/vcsplugin.cpp
+++ b/src/plugins/vcsbase/vcsplugin.cpp
@@ -28,7 +28,7 @@
#include "vcsbaseconstants.h"
#include "vcsbasesubmiteditor.h"
-#include "commonsettingspage.h"
+#include "commonvcssettings.h"
#include "nicknamedialog.h"
#include "vcsoutputwindow.h"
#include "wizard/vcscommandpage.h"
@@ -140,7 +140,7 @@ VcsPlugin *VcsPlugin::instance()
return m_instance;
}
-CommonVcsSettings VcsPlugin::settings() const
+CommonVcsSettings &VcsPlugin::settings() const
{
return d->m_settingsPage.settings();
}
@@ -158,7 +158,7 @@ QStandardItemModel *VcsPlugin::nickNameModel()
void VcsPlugin::populateNickNameModel()
{
QString errorMessage;
- if (!NickNameDialog::populateModelFromMailCapFile(settings().nickNameMailMap,
+ if (!NickNameDialog::populateModelFromMailCapFile(settings().nickNameMailMap.value(),
d->m_nickNameModel,
&errorMessage)) {
qWarning("%s", qPrintable(errorMessage));
diff --git a/src/plugins/vcsbase/vcsplugin.h b/src/plugins/vcsbase/vcsplugin.h
index 516a9f57fb..f236a39048 100644
--- a/src/plugins/vcsbase/vcsplugin.h
+++ b/src/plugins/vcsbase/vcsplugin.h
@@ -52,7 +52,7 @@ public:
static VcsPlugin *instance();
- CommonVcsSettings settings() const;
+ CommonVcsSettings &settings() const;
// Model of user nick names used for the submit
// editor. Stored centrally here to achieve delayed
@@ -60,7 +60,7 @@ public:
QStandardItemModel *nickNameModel();
signals:
- void settingsChanged(const VcsBase::Internal::CommonVcsSettings &s);
+ void settingsChanged();
void submitEditorAboutToClose(VcsBase::VcsBaseSubmitEditor *e, bool *result);
private:
diff --git a/src/plugins/webassembly/webassemblytoolchain.cpp b/src/plugins/webassembly/webassemblytoolchain.cpp
index c01c4aa06e..f83189efce 100644
--- a/src/plugins/webassembly/webassemblytoolchain.cpp
+++ b/src/plugins/webassembly/webassemblytoolchain.cpp
@@ -128,7 +128,7 @@ void WebAssemblyToolChain::registerToolChains()
return f->supportedToolChainType() == Constants::WEBASSEMBLY_TOOLCHAIN_TYPEID;
});
QTC_ASSERT(factory, return);
- for (auto toolChain : factory->autoDetect({}))
+ for (auto toolChain : factory->autoDetect({}, {}))
ToolChainManager::registerToolChain(toolChain);
// Let kits pick up the new toolchains
@@ -158,9 +158,11 @@ WebAssemblyToolChainFactory::WebAssemblyToolChainFactory()
}
QList<ToolChain *> WebAssemblyToolChainFactory::autoDetect(
- const QList<ToolChain *> &alreadyKnown)
+ const QList<ToolChain *> &alreadyKnown,
+ const IDevice::Ptr &device)
{
Q_UNUSED(alreadyKnown)
+ Q_UNUSED(device)
const FilePath sdk = WebAssemblyEmSdk::registeredEmSdk();
if (!WebAssemblyEmSdk::isValid(sdk))
diff --git a/src/plugins/webassembly/webassemblytoolchain.h b/src/plugins/webassembly/webassemblytoolchain.h
index efabcafdb4..453a395ada 100644
--- a/src/plugins/webassembly/webassemblytoolchain.h
+++ b/src/plugins/webassembly/webassemblytoolchain.h
@@ -58,7 +58,8 @@ public:
WebAssemblyToolChainFactory();
QList<ProjectExplorer::ToolChain *> autoDetect(
- const QList<ProjectExplorer::ToolChain *> &alreadyKnown) override;
+ const QList<ProjectExplorer::ToolChain *> &alreadyKnown,
+ const ProjectExplorer::IDevice::Ptr &device) override;
};
} // namespace Internal
diff --git a/src/plugins/winrt/winrtpackagedeploymentstep.cpp b/src/plugins/winrt/winrtpackagedeploymentstep.cpp
index 3cfd60f86b..a84ba3a5e8 100644
--- a/src/plugins/winrt/winrtpackagedeploymentstep.cpp
+++ b/src/plugins/winrt/winrtpackagedeploymentstep.cpp
@@ -346,8 +346,8 @@ void WinRtPackageDeploymentStep::stdOutput(const QString &line)
QString WinRtPackageDeploymentStep::defaultWinDeployQtArguments() const
{
QString args;
- QtcProcess::addArg(&args, QStringLiteral("--qmldir"));
- QtcProcess::addArg(&args, project()->projectDirectory().toUserOutput());
+ ProcessArgs::addArg(&args, QStringLiteral("--qmldir"));
+ ProcessArgs::addArg(&args, project()->projectDirectory().toUserOutput());
return args;
}
diff --git a/src/qtcreatorplugin.pri b/src/qtcreatorplugin.pri
index 806ed6f865..4bb8e89853 100644
--- a/src/qtcreatorplugin.pri
+++ b/src/qtcreatorplugin.pri
@@ -1,3 +1,5 @@
+include(../qtcreator_testvars.pri)
+
depfile = $$replace(_PRO_FILE_PWD_, ([^/]+$), \\1/\\1_dependencies.pri)
exists($$depfile) {
include($$depfile)
diff --git a/src/shared/json/json.qbs b/src/shared/json/json.qbs
index df11ab293a..99726f7d68 100644
--- a/src/shared/json/json.qbs
+++ b/src/shared/json/json.qbs
@@ -11,6 +11,6 @@ StaticLibrary {
]
Export {
Depends { name: "cpp" }
- cpp.includePaths: [product.sourceDirectory]
+ cpp.includePaths: [exportingProduct.sourceDirectory]
}
}
diff --git a/src/shared/proparser/proparser.qbs b/src/shared/proparser/proparser.qbs
index dc9de24c36..dd9ce7cc64 100644
--- a/src/shared/proparser/proparser.qbs
+++ b/src/shared/proparser/proparser.qbs
@@ -13,6 +13,6 @@ Product {
"PROEVALUATOR_CUMULATIVE",
"PROEVALUATOR_SETENV",
])
- cpp.includePaths: base.concat([product.sourceDirectory + "/.."])
+ cpp.includePaths: base.concat([exportingProduct.sourceDirectory + "/.."])
}
}
diff --git a/src/shared/qtcreator_gui_pch.h b/src/shared/qtcreator_gui_pch.h
index b25dbf67b7..af57b87ba7 100644
--- a/src/shared/qtcreator_gui_pch.h
+++ b/src/shared/qtcreator_gui_pch.h
@@ -27,6 +27,8 @@
* This is a precompiled header file for use in Xcode / Mac GCC /
* GCC >= 3.4 / VC to greatly speed the building of Qt Creator.
*/
+#ifndef QTCREATOR_GUI_PCH_H
+#define QTCREATOR_GUI_PCH_H
#include "qtcreator_pch.h"
@@ -45,3 +47,5 @@
#include <QWidget>
#endif
+
+#endif // QTCREATOR_GUI_PCH_H
diff --git a/src/shared/qtcreator_pch.h b/src/shared/qtcreator_pch.h
index 3106ca5ba3..75e15967c5 100644
--- a/src/shared/qtcreator_pch.h
+++ b/src/shared/qtcreator_pch.h
@@ -26,8 +26,13 @@
/*
* This is a precompiled header file for use in Xcode / Mac GCC /
* GCC >= 3.4 / VC to greatly speed the building of Qt Creator.
+ *
+ * The define below is checked in source code. Do not replace with #pragma once!
*/
+#ifndef QTCREATOR_PCH_H
+#define QTCREATOR_PCH_H
+
#if defined __cplusplus
#include <QtGlobal>
@@ -50,6 +55,9 @@
#undef ERROR
#undef ABSOLUTE
+// LLVM 12 comes with CALLBACK as a template argument
+#undef CALLBACK
+
#define _POSIX_
#include <limits.h>
#undef _POSIX_
@@ -82,3 +90,5 @@ using Qt::noforcesign;
#include <stdlib.h>
#endif
+
+#endif // QTCREATOR_PCH_H
diff --git a/src/tools/clangbackend/source/clangjobs.cpp b/src/tools/clangbackend/source/clangjobs.cpp
index f1df7dcd49..51b875f65f 100644
--- a/src/tools/clangbackend/source/clangjobs.cpp
+++ b/src/tools/clangbackend/source/clangjobs.cpp
@@ -29,10 +29,10 @@
#include "clangiasyncjob.h"
#include <QDebug>
-#include <QFutureSynchronizer>
#include <QLoggingCategory>
#include <utils/algorithm.h>
+#include <utils/futuresynchronizer.h>
#include <utils/qtcassert.h>
namespace ClangBackEnd {
@@ -63,7 +63,7 @@ Jobs::~Jobs()
foreach (IAsyncJob *asyncJob, m_running.keys())
asyncJob->preventFinalization();
- QFutureSynchronizer<void> waitForFinishedJobs;
+ Utils::FutureSynchronizer waitForFinishedJobs;
foreach (const RunningJob &runningJob, m_running.values())
waitForFinishedJobs.addFuture(runningJob.future);
@@ -114,7 +114,7 @@ JobRequests Jobs::stop()
queue().clear();
// Wait until currently running jobs finish.
- QFutureSynchronizer<void> waitForFinishedJobs;
+ Utils::FutureSynchronizer waitForFinishedJobs;
foreach (const RunningJob &runningJob, m_running.values())
waitForFinishedJobs.addFuture(runningJob.future);
diff --git a/src/tools/clangbackend/source/clangtooltipinfocollector.cpp b/src/tools/clangbackend/source/clangtooltipinfocollector.cpp
index 06bc98203b..03a328915e 100644
--- a/src/tools/clangbackend/source/clangtooltipinfocollector.cpp
+++ b/src/tools/clangbackend/source/clangtooltipinfocollector.cpp
@@ -34,9 +34,10 @@
#include "unsavedfile.h"
#include <clangsupport/sourcerangecontainer.h>
+#include <utils/fileutils.h>
#include <utils/qtcassert.h>
-#include <utils/textfileformat.h>
#include <utils/qtcassert.h>
+#include <utils/textfileformat.h>
#include <utf8string.h>
@@ -487,7 +488,10 @@ UnsavedFile ToolTipInfoCollector::unsavedFile(const Utf8String &filePath) const
QString errorString;
using namespace Utils;
const TextFileFormat::ReadResult readResult
- = TextFileFormat::readFileUTF8(filePath.toString(), codec, &fileContent, &errorString);
+ = TextFileFormat::readFileUTF8(Utils::FilePath::fromString(filePath),
+ codec,
+ &fileContent,
+ &errorString);
if (readResult != TextFileFormat::ReadSuccess) {
qWarning() << "Failed to read file" << filePath << ":" << errorString;
return UnsavedFile();
diff --git a/src/tools/clangbackend/source/commandlinearguments.cpp b/src/tools/clangbackend/source/commandlinearguments.cpp
index 97c1982a58..cde7329525 100644
--- a/src/tools/clangbackend/source/commandlinearguments.cpp
+++ b/src/tools/clangbackend/source/commandlinearguments.cpp
@@ -37,7 +37,7 @@
static QList<QByteArray> splitArgs(QString &argsString)
{
QList<QByteArray> result;
- Utils::QtcProcess::ArgIterator it(&argsString);
+ Utils::ProcessArgs::ArgIterator it(&argsString);
while (it.next())
result.append(it.value().toUtf8());
return result;
@@ -112,7 +112,7 @@ const char *CommandLineArguments::at(int position) const
static Utf8String maybeQuoted(const char *argumentAsCString)
{
const QString argumentAsQString = QString::fromUtf8(argumentAsCString);
- const QString quotedArgument = Utils::QtcProcess::quoteArg(argumentAsQString);
+ const QString quotedArgument = Utils::ProcessArgs::quoteArg(argumentAsQString);
return Utf8String::fromString(quotedArgument);
}
diff --git a/src/tools/clangbackend/source/cursor.cpp b/src/tools/clangbackend/source/cursor.cpp
index e8092186be..be84a64331 100644
--- a/src/tools/clangbackend/source/cursor.cpp
+++ b/src/tools/clangbackend/source/cursor.cpp
@@ -110,6 +110,11 @@ bool Cursor::isInvalidDeclaration() const
return clang_isInvalidDeclaration(m_cxCursor);
}
+bool Cursor::isParameter() const
+{
+ return kind() == CXCursor_ParmDecl;
+}
+
bool Cursor::isLocalVariable() const
{
switch (semanticParent().kind()) {
diff --git a/src/tools/clangbackend/source/cursor.h b/src/tools/clangbackend/source/cursor.h
index c748db4725..fe9641ecfe 100644
--- a/src/tools/clangbackend/source/cursor.h
+++ b/src/tools/clangbackend/source/cursor.h
@@ -62,6 +62,7 @@ public:
bool isCompoundType() const;
bool isDeclaration() const;
bool isInvalidDeclaration() const;
+ bool isParameter() const;
bool isLocalVariable() const;
bool isReference() const;
bool isExpression() const;
diff --git a/src/tools/clangbackend/source/tokeninfo.cpp b/src/tools/clangbackend/source/tokeninfo.cpp
index 76f6595a66..e8ece9c06d 100644
--- a/src/tools/clangbackend/source/tokeninfo.cpp
+++ b/src/tools/clangbackend/source/tokeninfo.cpp
@@ -49,7 +49,9 @@ TokenInfo::TokenInfo(const Cursor &cursor,
m_line = start.line();
m_column = start.column();
m_offset = start.offset();
- m_length = end.offset() - start.offset();
+ m_length = token->spelling().operator Utf8String().toString().size();
+ if (m_length == 0)
+ m_length = end.offset() - start.offset(); // Just for safety.
}
bool TokenInfo::hasInvalidMainType() const
@@ -142,7 +144,9 @@ void TokenInfo::overloadedDeclRefKind(const Cursor &cursor)
void TokenInfo::variableKind(const Cursor &cursor)
{
- if (cursor.isLocalVariable())
+ if (cursor.isParameter())
+ m_types.mainHighlightingType = HighlightingType::Parameter;
+ else if (cursor.isLocalVariable())
m_types.mainHighlightingType = HighlightingType::LocalVariable;
else
m_types.mainHighlightingType = HighlightingType::GlobalVariable;
diff --git a/src/tools/qml2puppet/qml2puppet.qbs b/src/tools/qml2puppet/qml2puppet.qbs
index 08d947d14d..8d7e3edfd4 100644
--- a/src/tools/qml2puppet/qml2puppet.qbs
+++ b/src/tools/qml2puppet/qml2puppet.qbs
@@ -19,8 +19,6 @@ QtcTool {
property bool useQuick3d: Utilities.versionCompare(Qt.core.version, "5.15") >= 0
&& Qt["quick3d-private"].present
- property bool useQt5Compat: Utilities.versionCompare(Qt.core.version, "6.0") >= 0
-
cpp.defines: {
var defines = base.filter(function(d) { return d != "QT_CREATOR"; });
if (useQuick3d)
@@ -265,13 +263,13 @@ QtcTool {
Group {
name: "puppet2 Qt 5 compatibility sources"
- condition: product.useQt5Compat
+ condition: product.usesQt6
files: ["editor3d/qt5compat/qquick3darealight.cpp"]
}
Group {
name: "puppet2 Qt 5 compatibility headers"
- condition: product.useQt5Compat
+ condition: product.usesQt6
files: ["editor3d/qt5compat/qquick3darealight_p.h"]
fileTags: product.useQuick3d ? [] : ["unmocable"]
overrideTags: false
diff --git a/src/tools/sdktool/CMakeLists.txt b/src/tools/sdktool/CMakeLists.txt
index 76040f4ba0..dc2320a92c 100644
--- a/src/tools/sdktool/CMakeLists.txt
+++ b/src/tools/sdktool/CMakeLists.txt
@@ -86,7 +86,6 @@ extend_qtc_executable(sdktool
persistentsettings.cpp persistentsettings.h
porting.h
qtcassert.cpp qtcassert.h
- qtcprocess.cpp qtcprocess.h
savefile.cpp savefile.h
stringutils.cpp stringutils.h
)
diff --git a/src/tools/sdktool/main.cpp b/src/tools/sdktool/main.cpp
index 0a07b1157c..1997604270 100644
--- a/src/tools/sdktool/main.cpp
+++ b/src/tools/sdktool/main.cpp
@@ -73,6 +73,7 @@ const QString tabular(const std::unique_ptr<Operation> &o)
void printHelp(const std::vector<std::unique_ptr<Operation>> &operations)
{
std::cout << Core::Constants::IDE_DISPLAY_NAME << "SDK setup tool." << std::endl;
+ std::cout << "Based on Qt " << qVersion() << std::endl;
std::cout << " Usage: " << qPrintable(QCoreApplication::arguments().at(0))
<< " <ARGS> <OPERATION> <OPERATION_ARGS>" << std::endl << std::endl;
std::cout << "ARGS:" << std::endl;
diff --git a/src/tools/sdktool/sdktool.pro b/src/tools/sdktool/sdktool.pro
index 207a120a1f..0b58755a1e 100644
--- a/src/tools/sdktool/sdktool.pro
+++ b/src/tools/sdktool/sdktool.pro
@@ -38,7 +38,7 @@ SOURCES += \
$$UTILS/namevalueitem.cpp \
$$UTILS/persistentsettings.cpp \
$$UTILS/qtcassert.cpp \
- $$UTILS/qtcprocess.cpp \
+ $$UTILS/commandline.cpp \
$$UTILS/savefile.cpp \
$$UTILS/stringutils.cpp
@@ -71,7 +71,7 @@ HEADERS += \
$$UTILS/namevalueitem.h \
$$UTILS/persistentsettings.h \
$$UTILS/qtcassert.h \
- $$UTILS/qtcprocess.h \
+ $$UTILS/commandline.h \
$$UTILS/savefile.h \
$$UTILS/porting.h
diff --git a/src/tools/sdktool/sdktool.qbs b/src/tools/sdktool/sdktool.qbs
index 3d60c130fc..a6fd9ed8b8 100644
--- a/src/tools/sdktool/sdktool.qbs
+++ b/src/tools/sdktool/sdktool.qbs
@@ -68,6 +68,7 @@ QtcTool {
name: "Utils"
prefix: libsDir + "/utils/"
files: [
+ "commandline.cpp", "commandline.h",
"environment.cpp", "environment.h",
"fileutils.cpp", "fileutils.h",
"hostosinfo.cpp", "hostosinfo.h",
@@ -76,7 +77,6 @@ QtcTool {
"persistentsettings.cpp", "persistentsettings.h",
"porting.h",
"qtcassert.cpp", "qtcassert.h",
- "qtcprocess.cpp", "qtcprocess.h",
"savefile.cpp", "savefile.h",
"stringutils.cpp"
]
diff --git a/tests/auto/CMakeLists.txt b/tests/auto/CMakeLists.txt
index 6e5d03b0e4..dcf51ff0a2 100644
--- a/tests/auto/CMakeLists.txt
+++ b/tests/auto/CMakeLists.txt
@@ -1,5 +1,6 @@
add_subdirectory(aggregation)
add_subdirectory(algorithm)
+add_subdirectory(android)
add_subdirectory(changeset)
add_subdirectory(cplusplus)
add_subdirectory(debugger)
@@ -14,7 +15,6 @@ add_subdirectory(mapreduce)
add_subdirectory(pointeralgorithm)
add_subdirectory(profilewriter)
add_subdirectory(qml)
-add_subdirectory(qtcprocess)
add_subdirectory(runextensions)
add_subdirectory(sdktool)
add_subdirectory(ssh)
diff --git a/tests/auto/android/CMakeLists.txt b/tests/auto/android/CMakeLists.txt
new file mode 100644
index 0000000000..8f328fe98e
--- /dev/null
+++ b/tests/auto/android/CMakeLists.txt
@@ -0,0 +1,18 @@
+add_qtc_test(tst_avdmanageroutputparser
+ DEPENDS Utils
+ INCLUDES
+ "${PROJECT_SOURCE_DIR}/src/plugins"
+ "${PROJECT_SOURCE_DIR}/src/plugins/android"
+ SOURCES
+ tst_avdmanageroutputparser.cpp
+ "${PROJECT_SOURCE_DIR}/src/plugins/android/avdmanageroutputparser.cpp"
+ "${PROJECT_SOURCE_DIR}/src/plugins/android/avdmanageroutputparser.h"
+ "${PROJECT_SOURCE_DIR}/src/plugins/android/androiddeviceinfo.cpp"
+ "${PROJECT_SOURCE_DIR}/src/plugins/android/androiddeviceinfo.h"
+)
+
+qtc_add_resources(tst_avdmanageroutputparser tst_avdmanageroutputparser_rcc
+ FILES
+ Test.avd/config.ini
+ TestTablet.avd/config.ini
+)
diff --git a/tests/auto/android/Test.avd/config.ini b/tests/auto/android/Test.avd/config.ini
new file mode 100644
index 0000000000..f48d6df0c4
--- /dev/null
+++ b/tests/auto/android/Test.avd/config.ini
@@ -0,0 +1,119 @@
+PlayStore.enabled=no
+abi.type=x86
+avd.id=<build>
+avd.ini.encoding=UTF-8
+avd.name=<build>
+disk.cachePartition=yes
+disk.cachePartition.size=66MB
+disk.dataPartition.path=<temp>
+disk.dataPartition.size=800M
+disk.systemPartition.size=0
+disk.vendorPartition.size=0
+fastboot.forceChosenSnapshotBoot=no
+fastboot.forceColdBoot=no
+fastboot.forceFastBoot=yes
+hw.accelerometer=yes
+hw.arc=no
+hw.arc.autologin=no
+hw.audioInput=yes
+hw.audioOutput=yes
+hw.battery=yes
+hw.camera.back=emulated
+hw.camera.front=none
+hw.cpu.arch=x86
+hw.cpu.ncore=4
+hw.dPad=no
+hw.device.hash2=MD5:5c288d27461585ecc73a535555e7cf61
+hw.device.manufacturer=Google
+hw.device.name=Galaxy Nexus
+hw.display1.density=0
+hw.display1.flag=0
+hw.display1.height=0
+hw.display1.width=0
+hw.display1.xOffset=-1
+hw.display1.yOffset=-1
+hw.display2.density=0
+hw.display2.flag=0
+hw.display2.height=0
+hw.display2.width=0
+hw.display2.xOffset=-1
+hw.display2.yOffset=-1
+hw.display3.density=0
+hw.display3.flag=0
+hw.display3.height=0
+hw.display3.width=0
+hw.display3.xOffset=-1
+hw.display3.yOffset=-1
+hw.displayRegion.0.1.height=0
+hw.displayRegion.0.1.width=0
+hw.displayRegion.0.1.xOffset=-1
+hw.displayRegion.0.1.yOffset=-1
+hw.displayRegion.0.2.height=0
+hw.displayRegion.0.2.width=0
+hw.displayRegion.0.2.xOffset=-1
+hw.displayRegion.0.2.yOffset=-1
+hw.displayRegion.0.3.height=0
+hw.displayRegion.0.3.width=0
+hw.displayRegion.0.3.xOffset=-1
+hw.displayRegion.0.3.yOffset=-1
+hw.gltransport=pipe
+hw.gltransport.asg.dataRingSize=32768
+hw.gltransport.asg.writeBufferSize=1048576
+hw.gltransport.asg.writeStepSize=4096
+hw.gltransport.drawFlushInterval=800
+hw.gps=yes
+hw.gpu.enabled=no
+hw.gpu.mode=auto
+hw.gsmModem=yes
+hw.gyroscope=yes
+hw.initialOrientation=portrait
+hw.keyboard=no
+hw.keyboard.charmap=qwerty2
+hw.keyboard.lid=yes
+hw.lcd.backlight=yes
+hw.lcd.density=320
+hw.lcd.depth=16
+hw.lcd.height=1280
+hw.lcd.vsync=60
+hw.lcd.width=720
+hw.mainKeys=no
+hw.ramSize=1024
+hw.rotaryInput=no
+hw.screen=multi-touch
+hw.sdCard=no
+hw.sensor.hinge=yes
+hw.sensor.hinge.count=0
+hw.sensor.hinge.fold_to_displayRegion.0.1_at_posture=1
+hw.sensor.hinge.sub_type=0
+hw.sensor.hinge.type=0
+hw.sensor.roll=no
+hw.sensor.roll.count=0
+hw.sensor.roll.resize_to_displayRegion.0.1_at_posture=6
+hw.sensor.roll.resize_to_displayRegion.0.2_at_posture=6
+hw.sensor.roll.resize_to_displayRegion.0.3_at_posture=6
+hw.sensors.gyroscope_uncalibrated=yes
+hw.sensors.heart_rate=no
+hw.sensors.humidity=yes
+hw.sensors.light=yes
+hw.sensors.magnetic_field=yes
+hw.sensors.magnetic_field_uncalibrated=yes
+hw.sensors.orientation=yes
+hw.sensors.pressure=yes
+hw.sensors.proximity=yes
+hw.sensors.temperature=yes
+hw.trackBall=no
+hw.useext4=yes
+image.sysdir.1=system-images/android-30/google_apis/x86/
+kernel.newDeviceNaming=autodetect
+kernel.supportsYaffs2=autodetect
+runtime.network.latency=None
+runtime.network.speed=Full
+sdcard.size=512 MB
+showDeviceFrame=yes
+skin.path=_no_skin
+tag.display=Google APIs
+tag.id=google_apis
+test.delayAdbTillBootComplete=0
+test.monitorAdb=0
+test.quitAfterBootTimeOut=-1
+vm.heapSize=112M
diff --git a/tests/auto/android/TestTablet.avd/config.ini b/tests/auto/android/TestTablet.avd/config.ini
new file mode 100644
index 0000000000..241c721ff6
--- /dev/null
+++ b/tests/auto/android/TestTablet.avd/config.ini
@@ -0,0 +1,119 @@
+PlayStore.enabled=no
+abi.type=x86
+avd.id=<build>
+avd.ini.encoding=UTF-8
+avd.name=<build>
+disk.cachePartition=yes
+disk.cachePartition.size=66MB
+disk.dataPartition.path=<temp>
+disk.dataPartition.size=800M
+disk.systemPartition.size=0
+disk.vendorPartition.size=0
+fastboot.forceChosenSnapshotBoot=no
+fastboot.forceColdBoot=no
+fastboot.forceFastBoot=yes
+hw.accelerometer=yes
+hw.arc=no
+hw.arc.autologin=no
+hw.audioInput=yes
+hw.audioOutput=yes
+hw.battery=yes
+hw.camera.back=emulated
+hw.camera.front=none
+hw.cpu.arch=x86
+hw.cpu.ncore=4
+hw.dPad=no
+hw.device.hash2=MD5:6f5876a1c548aef127b373f80cac4953
+hw.device.manufacturer=Generic
+hw.device.name=7in WSVGA (Tablet)
+hw.display1.density=0
+hw.display1.flag=0
+hw.display1.height=0
+hw.display1.width=0
+hw.display1.xOffset=-1
+hw.display1.yOffset=-1
+hw.display2.density=0
+hw.display2.flag=0
+hw.display2.height=0
+hw.display2.width=0
+hw.display2.xOffset=-1
+hw.display2.yOffset=-1
+hw.display3.density=0
+hw.display3.flag=0
+hw.display3.height=0
+hw.display3.width=0
+hw.display3.xOffset=-1
+hw.display3.yOffset=-1
+hw.displayRegion.0.1.height=0
+hw.displayRegion.0.1.width=0
+hw.displayRegion.0.1.xOffset=-1
+hw.displayRegion.0.1.yOffset=-1
+hw.displayRegion.0.2.height=0
+hw.displayRegion.0.2.width=0
+hw.displayRegion.0.2.xOffset=-1
+hw.displayRegion.0.2.yOffset=-1
+hw.displayRegion.0.3.height=0
+hw.displayRegion.0.3.width=0
+hw.displayRegion.0.3.xOffset=-1
+hw.displayRegion.0.3.yOffset=-1
+hw.gltransport=pipe
+hw.gltransport.asg.dataRingSize=32768
+hw.gltransport.asg.writeBufferSize=1048576
+hw.gltransport.asg.writeStepSize=4096
+hw.gltransport.drawFlushInterval=800
+hw.gps=yes
+hw.gpu.enabled=no
+hw.gpu.mode=auto
+hw.gsmModem=yes
+hw.gyroscope=yes
+hw.initialOrientation=portrait
+hw.keyboard=no
+hw.keyboard.charmap=qwerty2
+hw.keyboard.lid=yes
+hw.lcd.backlight=yes
+hw.lcd.density=160
+hw.lcd.depth=16
+hw.lcd.height=600
+hw.lcd.vsync=60
+hw.lcd.width=1024
+hw.mainKeys=no
+hw.ramSize=512
+hw.rotaryInput=no
+hw.screen=multi-touch
+hw.sdCard=no
+hw.sensor.hinge=yes
+hw.sensor.hinge.count=0
+hw.sensor.hinge.fold_to_displayRegion.0.1_at_posture=1
+hw.sensor.hinge.sub_type=0
+hw.sensor.hinge.type=0
+hw.sensor.roll=no
+hw.sensor.roll.count=0
+hw.sensor.roll.resize_to_displayRegion.0.1_at_posture=6
+hw.sensor.roll.resize_to_displayRegion.0.2_at_posture=6
+hw.sensor.roll.resize_to_displayRegion.0.3_at_posture=6
+hw.sensors.gyroscope_uncalibrated=yes
+hw.sensors.heart_rate=no
+hw.sensors.humidity=yes
+hw.sensors.light=yes
+hw.sensors.magnetic_field=yes
+hw.sensors.magnetic_field_uncalibrated=yes
+hw.sensors.orientation=yes
+hw.sensors.pressure=yes
+hw.sensors.proximity=yes
+hw.sensors.temperature=yes
+hw.trackBall=no
+hw.useext4=yes
+image.sysdir.1=system-images/android-30/google_apis/x86/
+kernel.newDeviceNaming=autodetect
+kernel.supportsYaffs2=autodetect
+runtime.network.latency=None
+runtime.network.speed=Full
+sdcard.size=512 MB
+showDeviceFrame=yes
+skin.path=_no_skin
+tag.display=Google APIs
+tag.id=google_apis
+test.delayAdbTillBootComplete=0
+test.monitorAdb=0
+test.quitAfterBootTimeOut=-1
+vm.heapSize=112M
diff --git a/tests/auto/android/tst_avdmanageroutputparser.cpp b/tests/auto/android/tst_avdmanageroutputparser.cpp
new file mode 100644
index 0000000000..004ec1b6a6
--- /dev/null
+++ b/tests/auto/android/tst_avdmanageroutputparser.cpp
@@ -0,0 +1,124 @@
+/****************************************************************************
+**
+** Copyright (C) 2021 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of Qt Creator.
+**
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3 as published by the Free Software
+** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-3.0.html.
+**
+****************************************************************************/
+
+#include "avdmanageroutputparser.h"
+
+#include <QtTest>
+
+using namespace Android;
+using namespace Android::Internal;
+
+class tst_AvdManagerOutputParser : public QObject
+{
+ Q_OBJECT
+
+private slots:
+ void parse_data();
+ void parse();
+};
+
+void tst_AvdManagerOutputParser::parse_data()
+{
+ QTest::addColumn<QString>("input");
+ QTest::addColumn<AndroidDeviceInfoList>("output");
+ QTest::addColumn<QStringList>("errorPaths");
+
+ QTest::newRow("none") << "Available Android Virtual Devices:\n"
+ << AndroidDeviceInfoList() << QStringList();
+
+ QTest::newRow("one") << "Available Android Virtual Devices:\n"
+ " Name: Test\n"
+ " Device: Galaxy Nexus (Google)\n"
+ " Path: :Test.avd\n"
+ " Target: Google APIs (Google Inc.)\n"
+ " Based on: Android API 30 Tag/ABI: google_apis/x86\n"
+ " Sdcard: 512 MB\n"
+ << AndroidDeviceInfoList({{"",
+ "Test",
+ {"x86"},
+ "Google APIs (Google Inc.)",
+ "Galaxy Nexus (Google)",
+ "",
+ "512 MB",
+ -1,
+ AndroidDeviceInfo::OkState,
+ false,
+ AndroidDeviceInfo::Emulator}})
+ << QStringList();
+
+ QTest::newRow("two") << "Available Android Virtual Devices:\n"
+ " Name: Test\n"
+ " Device: Galaxy Nexus (Google)\n"
+ " Path: :Test.avd\n"
+ " Target: Google APIs (Google Inc.)\n"
+ " Based on: Android API 30 Tag/ABI: google_apis/x86\n"
+ " Sdcard: 512 MB\n"
+ "---------\n"
+ " Name: TestTablet\n"
+ " Device: 7in WSVGA (Tablet) (Generic)\n"
+ " Path: :TestTablet.avd\n"
+ " Target: Google APIs (Google Inc.)\n"
+ " Based on: Android API 30 Tag/ABI: google_apis/x86\n"
+ " Sdcard: 256 MB\n"
+ << AndroidDeviceInfoList({{"",
+ "Test",
+ {"x86"},
+ "Google APIs (Google Inc.)",
+ "Galaxy Nexus (Google)",
+ "",
+ "512 MB",
+ -1,
+ AndroidDeviceInfo::OkState,
+ false,
+ AndroidDeviceInfo::Emulator},
+ {"",
+ "TestTablet",
+ {"x86"},
+ "Google APIs (Google Inc.)",
+ "7in WSVGA (Tablet) (Generic)",
+ "",
+ "256 MB",
+ -1,
+ AndroidDeviceInfo::OkState,
+ false,
+ AndroidDeviceInfo::Emulator}})
+ << QStringList();
+}
+
+void tst_AvdManagerOutputParser::parse()
+{
+ QFETCH(QString, input);
+ QFETCH(AndroidDeviceInfoList, output);
+ QFETCH(QStringList, errorPaths);
+
+ QStringList avdErrorPaths;
+ const auto result = parseAvdList(input, &avdErrorPaths);
+ QCOMPARE(result, output);
+ QCOMPARE(avdErrorPaths, errorPaths);
+}
+
+QTEST_MAIN(tst_AvdManagerOutputParser)
+
+#include "tst_avdmanageroutputparser.moc"
diff --git a/tests/auto/auto.pro b/tests/auto/auto.pro
index d68d3ed43f..c5020a5e6d 100644
--- a/tests/auto/auto.pro
+++ b/tests/auto/auto.pro
@@ -15,7 +15,6 @@ SUBDIRS += \
ssh \
treeviewfind \
toolchaincache \
- qtcprocess \
json \
utils \
filesearch \
diff --git a/tests/auto/auto.qbs b/tests/auto/auto.qbs
index 895f7d8da8..c82d1df094 100644
--- a/tests/auto/auto.qbs
+++ b/tests/auto/auto.qbs
@@ -18,7 +18,6 @@ Project {
"languageserverprotocol/languageserverprotocol.qbs",
"profilewriter/profilewriter.qbs",
"qml/qml.qbs",
- "qtcprocess/qtcprocess.qbs",
"runextensions/runextensions.qbs",
"sdktool/sdktool.qbs",
"ssh/ssh.qbs",
diff --git a/tests/auto/debugger/dumpers.pro b/tests/auto/debugger/dumpers.pro
index e5ca224b28..f7b279226b 100644
--- a/tests/auto/debugger/dumpers.pro
+++ b/tests/auto/debugger/dumpers.pro
@@ -16,6 +16,7 @@ msvc {
} else {
SOURCES += \
+ $$IDE_SOURCE_TREE/src/libs/utils/commandline.cpp \
$$IDE_SOURCE_TREE/src/libs/utils/environment.cpp \
$$IDE_SOURCE_TREE/src/libs/utils/fileutils.cpp \
$$IDE_SOURCE_TREE/src/libs/utils/hostosinfo.cpp \
@@ -28,6 +29,7 @@ msvc {
$$IDE_SOURCE_TREE/src/libs/utils/savefile.cpp
HEADERS += \
+ $$IDE_SOURCE_TREE/src/libs/utils/commandline.h \
$$IDE_SOURCE_TREE/src/libs/utils/environment.h \
$$IDE_SOURCE_TREE/src/libs/utils/fileutils.h \
$$IDE_SOURCE_TREE/src/libs/utils/hostosinfo.h \
diff --git a/tests/auto/debugger/gdb.pro b/tests/auto/debugger/gdb.pro
index 1d025d67f4..d09e1a7674 100644
--- a/tests/auto/debugger/gdb.pro
+++ b/tests/auto/debugger/gdb.pro
@@ -17,6 +17,7 @@ HEADERS += \
!msvc {
SOURCES += \
+ $$UTILSDIR/commandline.cpp \
$$UTILSDIR/environment.cpp \
$$UTILSDIR/fileutils.cpp \
$$UTILSDIR/hostosinfo.cpp \
@@ -28,6 +29,7 @@ HEADERS += \
$$UTILSDIR/savefile.cpp \
HEADERS += \
+ $$UTILSDIR/commandline.h \
$$UTILSDIR/environment.h \
$$UTILSDIR/fileutils.h \
$$UTILSDIR/hostosinfo.h \
diff --git a/tests/auto/debugger/protocol.pro b/tests/auto/debugger/protocol.pro
index 1008ba3d93..0119d25867 100644
--- a/tests/auto/debugger/protocol.pro
+++ b/tests/auto/debugger/protocol.pro
@@ -17,6 +17,7 @@ HEADERS += \
!msvc {
SOURCES += \
+ $$UTILSDIR/commandline.cpp \
$$UTILSDIR/environment.cpp \
$$UTILSDIR/fileutils.cpp \
$$UTILSDIR/hostosinfo.cpp \
@@ -28,6 +29,7 @@ HEADERS += \
$$UTILSDIR/savefile.cpp \
HEADERS += \
+ $$UTILSDIR/commandline.h \
$$UTILSDIR/environment.h \
$$UTILSDIR/fileutils.h \
$$UTILSDIR/hostosinfo.h \
diff --git a/tests/auto/debugger/tst_dumpers.cpp b/tests/auto/debugger/tst_dumpers.cpp
index 0336436926..a0026745be 100644
--- a/tests/auto/debugger/tst_dumpers.cpp
+++ b/tests/auto/debugger/tst_dumpers.cpp
@@ -29,17 +29,16 @@
#include "watchutils.h"
#include <utils/fileutils.h>
-#ifdef Q_OS_WIN
#include <utils/environment.h>
-#ifdef Q_CC_MSVC
#include <utils/qtcprocess.h>
-#include <utils/synchronousprocess.h>
-#endif // Q_CC_MSVC
-#endif // Q_OS_WIN
#include <QtTest>
#include <math.h>
+#ifndef CDBEXT_PATH
+#define CDBEXT_PATH ""
+#endif
+
#define MSKIP_SINGLE(x) do { disarm(); QSKIP(x); } while (0)
using namespace Debugger;
@@ -61,8 +60,6 @@ enum class Language
Fortran90
};
-#ifdef Q_CC_MSVC
-
// Copied from msvctoolchain.cpp to avoid plugin dependency.
static bool generateEnvironmentSettings(Utils::Environment &env,
const QString &batchFile,
@@ -85,14 +82,14 @@ static bool generateEnvironmentSettings(Utils::Environment &env,
Utils::TempFileSaver saver(QDir::tempPath() + "/XXXXXX.bat");
QByteArray call = "call ";
- call += Utils::QtcProcess::quoteArg(batchFile).toLocal8Bit();
+ call += Utils::ProcessArgs::quoteArg(batchFile).toLocal8Bit();
if (!batchArgs.isEmpty()) {
call += ' ';
call += batchArgs.toLocal8Bit();
}
saver.write(call + "\r\n");
- const QByteArray redirect = "set > " + Utils::QtcProcess::quoteArg(
+ const QByteArray redirect = "set > " + Utils::ProcessArgs::quoteArg(
QDir::toNativeSeparators(tempOutFile)).toLocal8Bit() + "\r\n";
saver.write(redirect);
if (!saver.finalize()) {
@@ -109,7 +106,7 @@ static bool generateEnvironmentSettings(Utils::Environment &env,
const Utils::FilePath cmdPath
= Utils::FilePath::fromString(QString::fromLocal8Bit(qgetenv("COMSPEC")));
// Windows SDK setup scripts require command line switches for environment expansion.
- QString cmdArguments = " /E:ON /V:ON /c \"" + QDir::toNativeSeparators(saver.fileName()) + '"';
+ QString cmdArguments = " /E:ON /V:ON /c \"" + saver.filePath().toUserOutput() + '"';
run.setCommand(Utils::CommandLine(cmdPath, cmdArguments, Utils::CommandLine::Raw));
run.start();
@@ -120,7 +117,7 @@ static bool generateEnvironmentSettings(Utils::Environment &env,
}
if (!run.waitForFinished()) {
qWarning("%s: Timeout running '%s'", Q_FUNC_INFO, qPrintable(batchFile));
- Utils::SynchronousProcess::stopProcess(run);
+ run.stopProcess();
return false;
}
// The SDK/MSVC scripts do not return exit codes != 0. Check on stdout.
@@ -155,12 +152,6 @@ static bool generateEnvironmentSettings(Utils::Environment &env,
}
-#ifndef CDBEXT_PATH
-#define CDBEXT_PATH ""
-#endif
-
-#endif // Q_CC_MSVC
-
struct VersionBase
{
// Minimum and maximum are inclusive.
@@ -1245,7 +1236,6 @@ void tst_Dumpers::initTestCase()
qDebug() << "Make path : " << m_makeBinary;
qDebug() << "Gdb version : " << m_debuggerVersion;
} else if (m_debuggerEngine == CdbEngine) {
-#ifdef Q_CC_MSVC
QByteArray envBat = qgetenv("QTC_MSVC_ENV_BAT");
QMap <QString, QString> envPairs;
Utils::Environment env = Utils::Environment::systemEnvironment();
@@ -1273,7 +1263,6 @@ void tst_Dumpers::initTestCase()
QRegularExpressionMatch match = reg.match(output);
if (match.matchType() != QRegularExpression::NoMatch)
m_msvcVersion = QString(match.captured(1) + match.captured(2)).toInt();
-#endif //Q_CC_MSVC
} else if (m_debuggerEngine == LldbEngine) {
qDebug() << "Dumper dir : " << DUMPERDIR;
QProcess debugger;
diff --git a/tests/auto/languageserverprotocol/tst_languageserverprotocol.cpp b/tests/auto/languageserverprotocol/tst_languageserverprotocol.cpp
index 137d5f6327..c5d7ffbd11 100644
--- a/tests/auto/languageserverprotocol/tst_languageserverprotocol.cpp
+++ b/tests/auto/languageserverprotocol/tst_languageserverprotocol.cpp
@@ -60,8 +60,6 @@ private slots:
void jsonMessageToBaseMessage_data();
void jsonMessageToBaseMessage();
- void jsonObject();
-
void documentUri_data();
void documentUri();
@@ -478,127 +476,6 @@ void tst_LanguageServerProtocol::jsonMessageToBaseMessage()
QCOMPARE(jsonMessage.toBaseMessage(), baseMessage);
}
-class JsonTestObject : public JsonObject
-{
-public:
- using JsonObject::JsonObject;
- using JsonObject::insert;
- using JsonObject::value;
- using JsonObject::contains;
- using JsonObject::find;
- using JsonObject::end;
- using JsonObject::remove;
- using JsonObject::keys;
- using JsonObject::typedValue;
- using JsonObject::optionalValue;
- using JsonObject::clientValue;
- using JsonObject::optionalClientValue;
- using JsonObject::array;
- using JsonObject::optionalArray;
- using JsonObject::clientArray;
- using JsonObject::optionalClientArray;
- using JsonObject::insertArray;
- using JsonObject::checkKey;
- using JsonObject::valueTypeString;
- using JsonObject::check;
- using JsonObject::checkType;
- using JsonObject::checkVal;
- using JsonObject::checkArray;
- using JsonObject::checkOptional;
- using JsonObject::checkOptionalArray;
- using JsonObject::errorString;
- using JsonObject::operator==;
-};
-
-void tst_LanguageServerProtocol::jsonObject()
-{
- JsonTestObject obj;
-
- obj.insert("integer", 42);
- obj.insert("double", 42.42);
- obj.insert("bool", false);
- obj.insert("null", QJsonValue::Null);
- obj.insert("string", "foobar");
- obj.insertArray("strings", QStringList{"foo", "bar"});
- const JsonTestObject innerObj(obj);
- obj.insert("object", innerObj);
-
- QCOMPARE(obj.value("integer"), QJsonValue(42));
- QCOMPARE(obj.value("double"), QJsonValue(42.42));
- QCOMPARE(obj.value("bool"), QJsonValue(false));
- QCOMPARE(obj.value("null"), QJsonValue(QJsonValue::Null));
- QCOMPARE(obj.value("string"), QJsonValue("foobar"));
- QCOMPARE(obj.value("strings"), QJsonValue(QJsonArray({"foo", "bar"})));
- QCOMPARE(obj.value("object"), QJsonValue(QJsonObject(innerObj)));
-
- QCOMPARE(obj.typedValue<int>("integer"), 42);
- QCOMPARE(obj.typedValue<double>("double"), 42.42);
- QCOMPARE(obj.typedValue<bool>("bool"), false);
- QCOMPARE(obj.typedValue<QString>("string"), QString("foobar"));
- QCOMPARE(obj.typedValue<JsonTestObject>("object"), innerObj);
-
- QVERIFY(!obj.optionalValue<int>("doesNotExist").has_value());
- QVERIFY(obj.optionalValue<int>("integer").has_value());
- QCOMPARE(obj.optionalValue<int>("integer").value_or(0), 42);
-
- QVERIFY(obj.clientValue<int>("null").isNull());
- QVERIFY(!obj.clientValue<int>("integer").isNull());
- QCOMPARE(obj.clientValue<int>("integer").value(), 42);
-
- QVERIFY(!obj.optionalClientValue<int>("doesNotExist").has_value());
- QVERIFY(obj.optionalClientValue<int>("null").has_value());
- QVERIFY(obj.optionalClientValue<int>("null").value().isNull());
- QVERIFY(obj.optionalClientValue<int>("integer").has_value());
- QVERIFY(!obj.optionalClientValue<int>("integer").value().isNull());
- QCOMPARE(obj.optionalClientValue<int>("integer").value().value(0), 42);
-
- QCOMPARE(obj.array<QString>("strings"), QList<QString>({"foo", "bar"}));
-
- QVERIFY(!obj.optionalArray<QString>("doesNotExist").has_value());
- QVERIFY(obj.optionalArray<QString>("strings").has_value());
- QCOMPARE(obj.optionalArray<QString>("strings").value_or(QList<QString>()),
- QList<QString>({"foo", "bar"}));
-
- QVERIFY(obj.clientArray<QString>("null").isNull());
- QVERIFY(!obj.clientArray<QString>("strings").isNull());
- QCOMPARE(obj.clientArray<QString>("strings").toList(), QList<QString>({"foo", "bar"}));
-
- QVERIFY(!obj.optionalClientArray<QString>("doesNotExist").has_value());
- QVERIFY(obj.optionalClientArray<QString>("null").has_value());
- QVERIFY(obj.optionalClientArray<QString>("null").value().isNull());
- QVERIFY(obj.optionalClientArray<QString>("strings").has_value());
- QVERIFY(!obj.optionalClientArray<QString>("strings").value().isNull());
- QCOMPARE(obj.optionalClientArray<QString>("strings").value().toList(),
- QList<QString>({"foo", "bar"}));
-
- ErrorHierarchy errorHierarchy;
- QVERIFY(!obj.check<int>(&errorHierarchy, "doesNotExist"));
- ErrorHierarchy errorDoesNotExists;
- errorDoesNotExists.setError(
- JsonTestObject::errorString(QJsonValue::Double, QJsonValue::Undefined));
- errorDoesNotExists.prependMember("doesNotExist");
- QCOMPARE(errorHierarchy, errorDoesNotExists);
- errorHierarchy.clear();
-
- QVERIFY(!obj.check<int>(&errorHierarchy, "bool"));
- ErrorHierarchy errorWrongType;
- errorWrongType.setError(JsonTestObject::errorString(QJsonValue::Double, QJsonValue::Bool));
- errorWrongType.prependMember("bool");
- QCOMPARE(errorHierarchy, errorWrongType);
- errorHierarchy.clear();
-
- QVERIFY(obj.check<int>(&errorHierarchy, "integer"));
- QVERIFY(errorHierarchy.isEmpty());
- QVERIFY(obj.check<double>(&errorHierarchy, "double"));
- QVERIFY(errorHierarchy.isEmpty());
- QVERIFY(obj.check<bool>(&errorHierarchy, "bool"));
- QVERIFY(errorHierarchy.isEmpty());
- QVERIFY(obj.check<std::nullptr_t>(&errorHierarchy, "null"));
- QVERIFY(errorHierarchy.isEmpty());
- QVERIFY(obj.check<QString>(&errorHierarchy, "string"));
- QVERIFY(errorHierarchy.isEmpty());
-}
-
void tst_LanguageServerProtocol::documentUri_data()
{
QTest::addColumn<DocumentUri>("uri");
diff --git a/tests/auto/qml/codemodel/check/SmurfNonRecursive.qml b/tests/auto/qml/codemodel/check/SmurfNonRecursive.qml
new file mode 100644
index 0000000000..9e09492bcc
--- /dev/null
+++ b/tests/auto/qml/codemodel/check/SmurfNonRecursive.qml
@@ -0,0 +1,6 @@
+import QtQuick 2.0
+import QtQuickControls 2.0 as Controls
+
+Controls.SmurfNonRecursive {
+
+}
diff --git a/tests/auto/qml/codemodel/check/SmurfRecursive.qml b/tests/auto/qml/codemodel/check/SmurfRecursive.qml
new file mode 100644
index 0000000000..5a729ba24b
--- /dev/null
+++ b/tests/auto/qml/codemodel/check/SmurfRecursive.qml
@@ -0,0 +1,5 @@
+import QtQuick 2.0
+
+SmurfRecursive { // 129 1 14 // 303 1 14
+
+}
diff --git a/tests/auto/qml/codemodel/check/tst_check.cpp b/tests/auto/qml/codemodel/check/tst_check.cpp
index 0df1bca5b6..35e49392dd 100644
--- a/tests/auto/qml/codemodel/check/tst_check.cpp
+++ b/tests/auto/qml/codemodel/check/tst_check.cpp
@@ -153,30 +153,40 @@ void tst_Check::test()
QList<Message> messages = checker();
std::sort(messages.begin(), messages.end(), &offsetComparator);
+ /*
+ * expected message are marked inside the respective qml file on the line of their occurrence
+ * with a comment stating error number, start column, and end column with optional state to mark
+ * e.g. false positives
+ * if more than 1 message at a line is expected these can be specified by adding further
+ * line comments in the same line
+ */
const QRegularExpression messagePattern(" (-?\\d+) (\\d+) (\\d+)\\s*(# false positive|# wrong warning.*)?");
QList<Message> expectedMessages;
QHash<int, QString> xfails;
for (const SourceLocation &comment : doc->engine()->comments()) {
- const QString text = doc->source().mid(comment.begin(), comment.end() - comment.begin());
- const QRegularExpressionMatch match = messagePattern.match(text);
- if (!match.hasMatch())
- continue;
- const int type = match.captured(1).toInt();
- const int columnStart = match.captured(2).toInt();
- const int columnEnd = match.captured(3).toInt() + 1;
-
- Message message;
- message.location = SourceLocation(
- comment.offset - comment.startColumn + columnStart,
- columnEnd - columnStart,
- comment.startLine,
- columnStart),
- message.type = static_cast<QmlJS::StaticAnalysis::Type>(type);
- expectedMessages += message;
-
- if (messagePattern.captureCount() == 4 && !match.captured(4).isEmpty())
- xfails.insert(expectedMessages.size() - 1, match.captured(4));
+ const QString fullComment = doc->source().mid(comment.begin(), comment.end() - comment.begin());
+ const QStringList splittedComment = fullComment.split("//");
+ for (const QString &text : splittedComment) {
+ const QRegularExpressionMatch match = messagePattern.match(text);
+ if (!match.hasMatch())
+ continue;
+ const int type = match.captured(1).toInt();
+ const int columnStart = match.captured(2).toInt();
+ const int columnEnd = match.captured(3).toInt() + 1;
+
+ Message message;
+ message.location = SourceLocation(
+ comment.offset - comment.startColumn + columnStart,
+ columnEnd - columnStart,
+ comment.startLine,
+ columnStart),
+ message.type = static_cast<QmlJS::StaticAnalysis::Type>(type);
+ expectedMessages += message;
+
+ if (messagePattern.captureCount() == 4 && !match.captured(4).isEmpty())
+ xfails.insert(expectedMessages.size() - 1, match.captured(4));
+ }
}
for (int i = 0; i < messages.size(); ++i) {
diff --git a/tests/auto/qml/codemodel/importscheck/moduleMapping/MyControls/Oblong.qml b/tests/auto/qml/codemodel/importscheck/moduleMapping/MyControls/Oblong.qml
new file mode 100644
index 0000000000..48aa963b30
--- /dev/null
+++ b/tests/auto/qml/codemodel/importscheck/moduleMapping/MyControls/Oblong.qml
@@ -0,0 +1,4 @@
+import QtQuick 2.15
+
+Item {
+}
diff --git a/tests/auto/qml/codemodel/importscheck/moduleMapping/MyControls/qmldir b/tests/auto/qml/codemodel/importscheck/moduleMapping/MyControls/qmldir
new file mode 100644
index 0000000000..fb93ddae5f
--- /dev/null
+++ b/tests/auto/qml/codemodel/importscheck/moduleMapping/MyControls/qmldir
@@ -0,0 +1,3 @@
+module MyControls
+import QtQuick
+Oblong 1.0 Oblong.qml
diff --git a/tests/auto/qml/codemodel/importscheck/moduleMapping/QtQuick/Controls/Button.qml b/tests/auto/qml/codemodel/importscheck/moduleMapping/QtQuick/Controls/Button.qml
new file mode 100644
index 0000000000..ceea3cbd28
--- /dev/null
+++ b/tests/auto/qml/codemodel/importscheck/moduleMapping/QtQuick/Controls/Button.qml
@@ -0,0 +1,4 @@
+import QtQuick 2.15
+
+Rect {
+}
diff --git a/tests/auto/qml/codemodel/importscheck/moduleMapping/QtQuick/Controls/qmldir b/tests/auto/qml/codemodel/importscheck/moduleMapping/QtQuick/Controls/qmldir
new file mode 100644
index 0000000000..e18a13a334
--- /dev/null
+++ b/tests/auto/qml/codemodel/importscheck/moduleMapping/QtQuick/Controls/qmldir
@@ -0,0 +1,3 @@
+module QtQuick.Controls
+import QtQuick
+Button 1.0 Button.qml
diff --git a/tests/auto/qml/codemodel/importscheck/moduleMapping/importQtQuick.qml b/tests/auto/qml/codemodel/importscheck/moduleMapping/importQtQuick.qml
new file mode 100644
index 0000000000..3bfee86997
--- /dev/null
+++ b/tests/auto/qml/codemodel/importscheck/moduleMapping/importQtQuick.qml
@@ -0,0 +1,5 @@
+import QtQuick 2.15
+import QtQuick.Controls 2.15
+
+Item {
+}
diff --git a/tests/auto/qml/codemodel/importscheck/tst_importscheck.cpp b/tests/auto/qml/codemodel/importscheck/tst_importscheck.cpp
index 6d7579daa8..f325338e4d 100644
--- a/tests/auto/qml/codemodel/importscheck/tst_importscheck.cpp
+++ b/tests/auto/qml/codemodel/importscheck/tst_importscheck.cpp
@@ -61,18 +61,22 @@ private slots:
void importTypes_data();
void importTypes();
+ void moduleMapping_data();
+ void moduleMapping();
+
void initTestCase();
private:
QStringList m_basePaths;
};
-void scanDir(const QString &dir)
+void scanDirectory(const QString &dir)
{
QFutureInterface<void> result;
PathsAndLanguages paths;
paths.maybeInsert(Utils::FilePath::fromString(dir), Dialect::Qml);
ModelManagerInterface::importScan(result, ModelManagerInterface::workingCopy(), paths,
ModelManagerInterface::instance(), false);
+ QCoreApplication::processEvents();
ModelManagerInterface::instance()->test_joinAllThreads();
ViewerContext vCtx;
vCtx.paths.append(dir);
@@ -269,6 +273,7 @@ void tst_ImportCheck::importTypes()
modelManager->activateScan();
modelManager->updateSourceFiles(QStringList(qmlFile), false);
+ QCoreApplication::processEvents();
modelManager->test_joinAllThreads();
Snapshot snapshot = modelManager->newestSnapshot();
@@ -283,6 +288,7 @@ void tst_ImportCheck::importTypes()
return link();
};
getContext();
+ QCoreApplication::processEvents();
modelManager->test_joinAllThreads();
snapshot = modelManager->newestSnapshot();
doc = snapshot.document(qmlFile);
@@ -299,6 +305,102 @@ void tst_ImportCheck::importTypes()
QVERIFY(allFound);
}
+typedef QHash<QString, QString> StrStrHash;
+
+void tst_ImportCheck::moduleMapping_data()
+{
+ QTest::addColumn<QString>("qmlFile");
+ QTest::addColumn<QString>("importPath");
+ QTest::addColumn<StrStrHash>("moduleMappings");
+ QTest::addColumn<QStringList>("expectedTypes");
+ QTest::addColumn<bool>("expectedResult");
+
+ QTest::newRow("check for plain QtQuick/Controls")
+ << QString(TESTSRCDIR "/moduleMapping/importQtQuick.qml")
+ << QString(TESTSRCDIR "/moduleMapping")
+ << StrStrHash()
+ << QStringList({ "Item", "Button" })
+ << true;
+ QTest::newRow("check that MyControls is not imported")
+ << QString(TESTSRCDIR "/moduleMapping/importQtQuick.qml")
+ << QString(TESTSRCDIR "/moduleMapping")
+ << StrStrHash()
+ << QStringList({ "Item", "Oblong" })
+ << false;
+ QTest::newRow("check that QtQuick controls cannot be found with a mapping")
+ << QString(TESTSRCDIR "/moduleMapping/importQtQuick.qml")
+ << QString(TESTSRCDIR "/moduleMapping")
+ << StrStrHash({ std::make_pair(QStringLiteral("QtQuick.Controls"), QStringLiteral("MyControls")) })
+ << QStringList({ "Item", "Button" })
+ << false;
+ QTest::newRow("check that custom controls can be found with a mapping")
+ << QString(TESTSRCDIR "/moduleMapping/importQtQuick.qml")
+ << QString(TESTSRCDIR "/moduleMapping")
+ << StrStrHash({ std::make_pair(QStringLiteral("QtQuick.Controls"), QStringLiteral("MyControls")) })
+ << QStringList({ "Item", "Oblong" }) // item is in QtQuick, and should still be found, as only
+ // the QtQuick.Controls are redirected
+ << true;
+}
+
+void tst_ImportCheck::moduleMapping()
+{
+ QFETCH(QString, qmlFile);
+ QFETCH(QString, importPath);
+ QFETCH(StrStrHash, moduleMappings);
+ QFETCH(QStringList, expectedTypes);
+ QFETCH(bool, expectedResult);
+
+ // full reset
+ delete ModelManagerInterface::instance();
+ MyModelManager *modelManager = new MyModelManager;
+
+ ModelManagerInterface::ProjectInfo defaultProject;
+ defaultProject.importPaths = PathsAndLanguages();
+ QString qtQuickImportPath = QString(TESTSRCDIR "/importTypes/imports-QtQuick-qmldir-import");
+ defaultProject.importPaths.maybeInsert(Utils::FilePath::fromString(qtQuickImportPath), Dialect::Qml);
+ defaultProject.importPaths.maybeInsert(Utils::FilePath::fromString(importPath), Dialect::Qml);
+ defaultProject.moduleMappings = moduleMappings;
+ modelManager->setDefaultProject(defaultProject, nullptr);
+ modelManager->activateScan();
+
+ scanDirectory(importPath);
+ scanDirectory(qtQuickImportPath);
+
+ modelManager->updateSourceFiles(QStringList(qmlFile), false);
+ QCoreApplication::processEvents();
+ modelManager->test_joinAllThreads();
+
+ Snapshot snapshot = modelManager->newestSnapshot();
+ Document::Ptr doc = snapshot.document(qmlFile);
+ QVERIFY(!doc.isNull());
+
+ // It's unfortunate, but nowadays linking can trigger async module loads,
+ // so do it once to start the process, then do it again for real once the
+ // dependencies are available.
+ const auto getContext = [&]() {
+ Link link(snapshot, modelManager->completeVContext(modelManager->projectVContext(doc->language(), doc),doc),
+ modelManager->builtins(doc));
+ return link();
+ };
+ getContext();
+ QCoreApplication::processEvents();
+ modelManager->test_joinAllThreads();
+ snapshot = modelManager->newestSnapshot();
+ doc = snapshot.document(qmlFile);
+
+ ContextPtr context = getContext();
+
+ bool allFound = true;
+ for (const auto &expected : expectedTypes) {
+ if (!context->lookupType(doc.data(), QStringList(expected))) {
+ allFound = false;
+ qWarning() << "Type '" << expected << "' not found";
+ }
+ }
+ QVERIFY(allFound == expectedResult);
+ delete ModelManagerInterface::instance();
+}
+
#ifdef MANUAL_IMPORT_SCANNER
int main(int argc, char *argv[])
diff --git a/tests/auto/qml/qmldesigner/coretests/tst_testcore.cpp b/tests/auto/qml/qmldesigner/coretests/tst_testcore.cpp
index dd528efa71..95fb9612f1 100644
--- a/tests/auto/qml/qmldesigner/coretests/tst_testcore.cpp
+++ b/tests/auto/qml/qmldesigner/coretests/tst_testcore.cpp
@@ -4709,7 +4709,6 @@ void tst_TestCore::testImplicitComponents()
void tst_TestCore::testRevisionedProperties()
{
-#if QT_VERSION > QT_VERSION_CHECK(5, 11, 0)
const char* qmlString
= "import QtQuick 2.12\n"
"import QtQuick.Controls 2.0\n"
@@ -4761,8 +4760,6 @@ void tst_TestCore::testRevisionedProperties()
QVERIFY(metaInfo12.hasProperty("orientation"));
QVERIFY(metaInfoU.hasProperty("orientation"));
-
-#endif
}
void tst_TestCore::testStatesRewriter()
diff --git a/tests/auto/qml/qmldesigner/testview.cpp b/tests/auto/qml/qmldesigner/testview.cpp
index 23c50599c7..6c9237aa26 100644
--- a/tests/auto/qml/qmldesigner/testview.cpp
+++ b/tests/auto/qml/qmldesigner/testview.cpp
@@ -161,10 +161,10 @@ void TestView::selectedNodesChanged(const QList<QmlDesigner::ModelNode> &selecte
m_methodCalls += MethodCall("selectedNodesChanged", QStringList() << selectedNodes.join(", ") << lastSelectedNodes.join(", "));
}
-
-void TestView::nodeOrderChanged(const QmlDesigner::NodeListProperty &listProperty, const QmlDesigner::ModelNode &movedNode, int oldIndex)
+void TestView::nodeOrderChanged(const QmlDesigner::NodeListProperty &listProperty)
{
- m_methodCalls += MethodCall("nodeOrderChanged", QStringList() << QString::fromUtf8(listProperty.name()) << movedNode.id() << QString::number(oldIndex));
+ m_methodCalls += MethodCall("nodeOrderChanged",
+ QStringList() << QString::fromUtf8(listProperty.name()));
}
void TestView::instancePropertyChanged(const QList<QPair<QmlDesigner::ModelNode, QmlDesigner::PropertyName> > &)
diff --git a/tests/auto/qml/qmldesigner/testview.h b/tests/auto/qml/qmldesigner/testview.h
index 9a78611488..6fb835e038 100644
--- a/tests/auto/qml/qmldesigner/testview.h
+++ b/tests/auto/qml/qmldesigner/testview.h
@@ -73,8 +73,7 @@ public:
void selectedNodesChanged(const QList<QmlDesigner::ModelNode> &selectedNodeList,
const QList<QmlDesigner::ModelNode> &lastSelectedNodeList);
- void nodeOrderChanged(const QmlDesigner::NodeListProperty &listProperty, const QmlDesigner::ModelNode &movedNode, int oldIndex);
-
+ void nodeOrderChanged(const QmlDesigner::NodeListProperty &listProperty);
virtual void instancePropertyChanged(const QList<QPair<QmlDesigner::ModelNode, QmlDesigner::PropertyName> > &propertyList);
virtual void instancesCompleted(const QVector<QmlDesigner::ModelNode> &completedNodeList);
diff --git a/tests/auto/qml/reformatter/inline.qml b/tests/auto/qml/reformatter/inline.qml
new file mode 100644
index 0000000000..41eae25b1b
--- /dev/null
+++ b/tests/auto/qml/reformatter/inline.qml
@@ -0,0 +1,8 @@
+import QtQuick 2.15
+
+Item {
+ component CustomText: Text {
+ color: "red"
+ text: "Test Text"
+ }
+}
diff --git a/tests/auto/qml/reformatter/jssyntax.js b/tests/auto/qml/reformatter/jssyntax.js
index b6c2a9e905..34166825aa 100644
--- a/tests/auto/qml/reformatter/jssyntax.js
+++ b/tests/auto/qml/reformatter/jssyntax.js
@@ -5,12 +5,17 @@ var a_var = 1
let a_let = 2
const a_const = 3
+const tmpl = `template` + `t${i + 6}` + `t${i + `nested${i}`}` + `t${function () {
+ return 5
+}()}` + `t\${i}
+${i + 2}`
+
function foo(a, b) {
x = 15
x += 4
}
-var foo = function (a, b) {}
+var foo = function (a, b = 0) {}
function spread() {
iterableObj = [1, 2]
diff --git a/tests/auto/qml/reformatter/qmlreadonly.qml b/tests/auto/qml/reformatter/qmlreadonly.qml
index f8a937586a..0f68ccd32c 100644
--- a/tests/auto/qml/reformatter/qmlreadonly.qml
+++ b/tests/auto/qml/reformatter/qmlreadonly.qml
@@ -2,4 +2,13 @@ import QtQuick 2.0
Item {
readonly property int horse: 40
+ required property Item theItem
+ required data
+
+ function foo() {
+ theItem.foo("The issue is exacerbated if the object literal is wrapped onto the next line like so:",
+ {
+ "foo": theFoo
+ })
+ }
}
diff --git a/tests/auto/toolchaincache/CMakeLists.txt b/tests/auto/toolchaincache/CMakeLists.txt
index 01edb5d5d4..a07ba77574 100644
--- a/tests/auto/toolchaincache/CMakeLists.txt
+++ b/tests/auto/toolchaincache/CMakeLists.txt
@@ -1,5 +1,5 @@
add_qtc_test(tst_toolchaincache
- DEPENDS ProjectExplorer Qt5::Widgets
+ DEPENDS ProjectExplorer Utils
INCLUDES "${PROJECT_SOURCE_DIR}/src/libs"
SOURCES tst_toolchaincache.cpp
)
diff --git a/tests/auto/toolchaincache/toolchaincache.pro b/tests/auto/toolchaincache/toolchaincache.pro
index cdb1ca0bb7..8b04cc317f 100644
--- a/tests/auto/toolchaincache/toolchaincache.pro
+++ b/tests/auto/toolchaincache/toolchaincache.pro
@@ -1,4 +1,6 @@
include(../qttest.pri)
+QT += network
+
SOURCES += \
tst_toolchaincache.cpp
diff --git a/tests/auto/utils/CMakeLists.txt b/tests/auto/utils/CMakeLists.txt
index 1b96a980f0..4b341d6b3c 100644
--- a/tests/auto/utils/CMakeLists.txt
+++ b/tests/auto/utils/CMakeLists.txt
@@ -2,6 +2,7 @@ add_subdirectory(ansiescapecodehandler)
add_subdirectory(fileutils)
add_subdirectory(fuzzymatcher)
add_subdirectory(persistentsettings)
+add_subdirectory(qtcprocess)
add_subdirectory(settings)
add_subdirectory(stringutils)
add_subdirectory(templateengine)
diff --git a/tests/auto/utils/fileutils/tst_fileutils.cpp b/tests/auto/utils/fileutils/tst_fileutils.cpp
index b6eab1655b..a995887910 100644
--- a/tests/auto/utils/fileutils/tst_fileutils.cpp
+++ b/tests/auto/utils/fileutils/tst_fileutils.cpp
@@ -27,6 +27,7 @@
#include <QDebug>
#include <utils/fileutils.h>
+#include <utils/link.h>
//TESTED_COMPONENT=src/libs/utils
using namespace Utils;
@@ -38,14 +39,53 @@ class tst_fileutils : public QObject
public:
private slots:
+ void initTestCase();
void parentDir_data();
void parentDir();
void isChildOf_data();
void isChildOf();
void fileName_data();
void fileName();
+ void calcRelativePath_data();
+ void calcRelativePath();
+ void relativePath_specials();
+ void relativePath_data();
+ void relativePath();
+ void fromToString_data();
+ void fromToString();
+ void comparison_data();
+ void comparison();
+ void linkFromString_data();
+ void linkFromString();
+
+private:
+ QTemporaryDir tempDir;
+ QString rootPath;
};
+static void touch(const QDir &dir, const QString &filename)
+{
+ QFile file(dir.absoluteFilePath(filename));
+ file.open(QIODevice::WriteOnly);
+ file.close();
+}
+
+void tst_fileutils::initTestCase()
+{
+ // initialize test for tst_fileutiles::relativePath*()
+ QVERIFY(tempDir.isValid());
+ rootPath = tempDir.path();
+ QDir dir(rootPath);
+ dir.mkpath("a/b/c/d");
+ dir.mkpath("a/x/y/z");
+ dir.mkpath("a/b/x/y/z");
+ dir.mkpath("x/y/z");
+ touch(dir, "a/b/c/d/file1.txt");
+ touch(dir, "a/x/y/z/file2.txt");
+ touch(dir, "a/file3.txt");
+ touch(dir, "x/y/file4.txt");
+}
+
void tst_fileutils::parentDir_data()
{
QTest::addColumn<QString>("path");
@@ -164,5 +204,241 @@ void tst_fileutils::fileName()
QCOMPARE(FilePath::fromString(path).fileNameWithPathComponents(components), result);
}
+void tst_fileutils::calcRelativePath_data()
+{
+ QTest::addColumn<QString>("absolutePath");
+ QTest::addColumn<QString>("anchorPath");
+ QTest::addColumn<QString>("result");
+
+ QTest::newRow("empty") << "" << "" << "";
+ QTest::newRow("leftempty") << "" << "/" << "";
+ QTest::newRow("rightempty") << "/" << "" << "";
+ QTest::newRow("root") << "/" << "/" << "";
+ QTest::newRow("simple1") << "/a" << "/" << "a";
+ QTest::newRow("simple2") << "/" << "/a" << "..";
+ QTest::newRow("simple3") << "/a" << "/a" << "";
+ QTest::newRow("extraslash1") << "/a/b/c" << "/a/b/c" << "";
+ QTest::newRow("extraslash2") << "/a/b/c" << "/a/b/c/" << "";
+ QTest::newRow("extraslash3") << "/a/b/c/" << "/a/b/c" << "";
+ QTest::newRow("normal1") << "/a/b/c" << "/a/x" << "../b/c";
+ QTest::newRow("normal2") << "/a/b/c" << "/a/x/y" << "../../b/c";
+ QTest::newRow("normal3") << "/a/b/c" << "/x/y" << "../../a/b/c";
+}
+
+void tst_fileutils::calcRelativePath()
+{
+ QFETCH(QString, absolutePath);
+ QFETCH(QString, anchorPath);
+ QFETCH(QString, result);
+ QString relativePath = Utils::FilePath::calcRelativePath(absolutePath, anchorPath);
+ QCOMPARE(relativePath, result);
+}
+
+void tst_fileutils::relativePath_specials()
+{
+ QString path = FilePath::fromString("").relativePath(FilePath::fromString("")).toString();
+ QCOMPARE(path, "");
+}
+
+void tst_fileutils::relativePath_data()
+{
+ QTest::addColumn<QString>("relative");
+ QTest::addColumn<QString>("anchor");
+ QTest::addColumn<QString>("result");
+
+ QTest::newRow("samedir") << "/" << "/" << "";
+ QTest::newRow("dir2dir_1") << "a/b/c/d" << "a/x/y/z" << "../../../b/c/d";
+ QTest::newRow("dir2dir_2") << "a/b" <<"a/b/c" << "..";
+ QTest::newRow("file2file_1") << "a/b/c/d/file1.txt" << "a/file3.txt" << "b/c/d/file1.txt";
+ QTest::newRow("dir2file_1") << "a/b/c" << "a/x/y/z/file2.txt" << "../../../b/c";
+ QTest::newRow("file2dir_1") << "a/b/c/d/file1.txt" << "x/y" << "../../a/b/c/d/file1.txt";
+}
+
+void tst_fileutils::relativePath()
+{
+ QFETCH(QString, relative);
+ QFETCH(QString, anchor);
+ QFETCH(QString, result);
+ FilePath actualPath = FilePath::fromString(rootPath + "/" + relative)
+ .relativePath(FilePath::fromString(rootPath + "/" + anchor));
+ QCOMPARE(actualPath.toString(), result);
+}
+
+void tst_fileutils::fromToString_data()
+{
+ QTest::addColumn<QString>("scheme");
+ QTest::addColumn<QString>("host");
+ QTest::addColumn<QString>("path");
+ QTest::addColumn<QString>("full");
+
+ QTest::newRow("s0") << "" << "" << "" << "";
+ QTest::newRow("s1") << "" << "" << "/" << "/";
+ QTest::newRow("s2") << "" << "" << "a/b/c/d" << "a/b/c/d";
+ QTest::newRow("s3") << "" << "" << "/a/b" << "/a/b";
+
+ QTest::newRow("s4")
+ << "docker" << "1234abcdef" << "/bin/ls" << "docker://1234abcdef/bin/ls";
+
+ QTest::newRow("s5")
+ << "docker" << "1234" << "/bin/ls" << "docker://1234/bin/ls";
+
+ // This is not a proper URL.
+ QTest::newRow("s6")
+ << "docker" << "1234" << "somefile" << "docker://1234/./somefile";
+
+ // Local Windows paths:
+ QTest::newRow("w1") << "" << "" << "C:/data" << "C:/data";
+ QTest::newRow("w2") << "" << "" << "C:/" << "C:/";
+ QTest::newRow("w3") << "" << "" << "//./com1" << "//./com1";
+ QTest::newRow("w4") << "" << "" << "//?/path" << "//?/path";
+ QTest::newRow("w5") << "" << "" << "/Global?\?/UNC/host" << "/Global?\?/UNC/host";
+ QTest::newRow("w6") << "" << "" << "//server/dir/file" << "//server/dir/file";
+ QTest::newRow("w7") << "" << "" << "//server/dir" << "//server/dir";
+ QTest::newRow("w8") << "" << "" << "//server" << "//server";
+
+ // Not supported yet: "Remote" windows. Would require use of e.g.
+ // FileUtils::isRelativePath with support from the remote device
+ // identifying itself as Windows.
+
+ // Actual (filePath.path()): "/C:/data"
+ // Expected (path) : "C:/data"
+
+ //QTest::newRow("w9") << "scheme" << "server" << "C:/data"
+ // << "scheme://server/C:/data";
+}
+
+void tst_fileutils::fromToString()
+{
+ QFETCH(QString, full);
+ QFETCH(QString, scheme);
+ QFETCH(QString, host);
+ QFETCH(QString, path);
+
+ FilePath filePath = FilePath::fromString(full);
+
+ QCOMPARE(filePath.toString(), full);
+
+ QCOMPARE(filePath.scheme(), scheme);
+ QCOMPARE(filePath.host(), host);
+ QCOMPARE(filePath.path(), path);
+
+
+ FilePath copy = filePath;
+ copy.setHost(host);
+ QCOMPARE(copy.toString(), full);
+
+ copy.setScheme(scheme);
+ QCOMPARE(copy.toString(), full);
+
+ copy.setPath(path);
+ QCOMPARE(copy.toString(), full);
+}
+
+void tst_fileutils::comparison()
+{
+ QFETCH(QString, left);
+ QFETCH(QString, right);
+ QFETCH(bool, hostSensitive);
+ QFETCH(bool, expected);
+
+ HostOsInfo::setOverrideFileNameCaseSensitivity(
+ hostSensitive ? Qt::CaseSensitive : Qt::CaseInsensitive);
+
+ FilePath l = FilePath::fromString(left);
+ FilePath r = FilePath::fromString(right);
+ QCOMPARE(l == r, expected);
+}
+
+void tst_fileutils::comparison_data()
+{
+ QTest::addColumn<QString>("left");
+ QTest::addColumn<QString>("right");
+ QTest::addColumn<bool>("hostSensitive");
+ QTest::addColumn<bool>("expected");
+
+ QTest::newRow("r1") << "Abc" << "abc" << true << false;
+ QTest::newRow("r2") << "Abc" << "abc" << false << true;
+ QTest::newRow("r3") << "x://y/Abc" << "x://y/abc" << true << false;
+ QTest::newRow("r4") << "x://y/Abc" << "x://y/abc" << false << false;
+
+ QTest::newRow("s1") << "abc" << "abc" << true << true;
+ QTest::newRow("s2") << "abc" << "abc" << false << true;
+ QTest::newRow("s3") << "x://y/abc" << "x://y/abc" << true << true;
+ QTest::newRow("s4") << "x://y/abc" << "x://y/abc" << false << true;
+}
+
+void tst_fileutils::linkFromString()
+{
+ QFETCH(QString, testFile);
+ QFETCH(Utils::FilePath, filePath);
+ QFETCH(QString, postfix);
+ QFETCH(int, line);
+ QFETCH(int, column);
+ QString extractedPostfix;
+ Link link = Link::fromString(testFile, true, &extractedPostfix);
+ QCOMPARE(link.targetFilePath, filePath);
+ QCOMPARE(extractedPostfix, postfix);
+ QCOMPARE(link.targetLine, line);
+ QCOMPARE(link.targetColumn, column);
+}
+
+void tst_fileutils::linkFromString_data()
+{
+ QTest::addColumn<QString>("testFile");
+ QTest::addColumn<Utils::FilePath>("filePath");
+ QTest::addColumn<QString>("postfix");
+ QTest::addColumn<int>("line");
+ QTest::addColumn<int>("column");
+
+ QTest::newRow("no-line-no-column")
+ << QString::fromLatin1("someFile.txt") << Utils::FilePath::fromString("someFile.txt")
+ << QString() << -1 << -1;
+ QTest::newRow(": at end") << QString::fromLatin1("someFile.txt:")
+ << Utils::FilePath::fromString("someFile.txt")
+ << QString::fromLatin1(":") << 0 << -1;
+ QTest::newRow("+ at end") << QString::fromLatin1("someFile.txt+")
+ << Utils::FilePath::fromString("someFile.txt")
+ << QString::fromLatin1("+") << 0 << -1;
+ QTest::newRow(": for column") << QString::fromLatin1("someFile.txt:10:")
+ << Utils::FilePath::fromString("someFile.txt")
+ << QString::fromLatin1(":10:") << 10 << -1;
+ QTest::newRow("+ for column") << QString::fromLatin1("someFile.txt:10+")
+ << Utils::FilePath::fromString("someFile.txt")
+ << QString::fromLatin1(":10+") << 10 << -1;
+ QTest::newRow(": and + at end")
+ << QString::fromLatin1("someFile.txt:+") << Utils::FilePath::fromString("someFile.txt")
+ << QString::fromLatin1(":+") << 0 << -1;
+ QTest::newRow("empty line") << QString::fromLatin1("someFile.txt:+10")
+ << Utils::FilePath::fromString("someFile.txt")
+ << QString::fromLatin1(":+10") << 0 << 9;
+ QTest::newRow(":line-no-column") << QString::fromLatin1("/some/path/file.txt:42")
+ << Utils::FilePath::fromString("/some/path/file.txt")
+ << QString::fromLatin1(":42") << 42 << -1;
+ QTest::newRow("+line-no-column") << QString::fromLatin1("/some/path/file.txt+42")
+ << Utils::FilePath::fromString("/some/path/file.txt")
+ << QString::fromLatin1("+42") << 42 << -1;
+ QTest::newRow(":line-:column") << QString::fromLatin1("/some/path/file.txt:42:3")
+ << Utils::FilePath::fromString("/some/path/file.txt")
+ << QString::fromLatin1(":42:3") << 42 << 2;
+ QTest::newRow(":line-+column") << QString::fromLatin1("/some/path/file.txt:42+33")
+ << Utils::FilePath::fromString("/some/path/file.txt")
+ << QString::fromLatin1(":42+33") << 42 << 32;
+ QTest::newRow("+line-:column") << QString::fromLatin1("/some/path/file.txt+142:30")
+ << Utils::FilePath::fromString("/some/path/file.txt")
+ << QString::fromLatin1("+142:30") << 142 << 29;
+ QTest::newRow("+line-+column") << QString::fromLatin1("/some/path/file.txt+142+33")
+ << Utils::FilePath::fromString("/some/path/file.txt")
+ << QString::fromLatin1("+142+33") << 142 << 32;
+ QTest::newRow("( at end") << QString::fromLatin1("/some/path/file.txt(")
+ << Utils::FilePath::fromString("/some/path/file.txt")
+ << QString::fromLatin1("(") << -1 << -1;
+ QTest::newRow("(42 at end") << QString::fromLatin1("/some/path/file.txt(42")
+ << Utils::FilePath::fromString("/some/path/file.txt")
+ << QString::fromLatin1("(42") << 42 << -1;
+ QTest::newRow("(42) at end") << QString::fromLatin1("/some/path/file.txt(42)")
+ << Utils::FilePath::fromString("/some/path/file.txt")
+ << QString::fromLatin1("(42)") << 42 << -1;
+}
+
QTEST_APPLESS_MAIN(tst_fileutils)
#include "tst_fileutils.moc"
diff --git a/tests/auto/qtcprocess/CMakeLists.txt b/tests/auto/utils/qtcprocess/CMakeLists.txt
index 16b9f4a9fa..16b9f4a9fa 100644
--- a/tests/auto/qtcprocess/CMakeLists.txt
+++ b/tests/auto/utils/qtcprocess/CMakeLists.txt
diff --git a/tests/auto/qtcprocess/qtcprocess.pro b/tests/auto/utils/qtcprocess/qtcprocess.pro
index 8b7db5493e..ed61fd10d0 100644
--- a/tests/auto/qtcprocess/qtcprocess.pro
+++ b/tests/auto/utils/qtcprocess/qtcprocess.pro
@@ -1,5 +1,5 @@
QTC_LIB_DEPENDS += utils
-include(../qttest.pri)
+include(../../qttest.pri)
win32:DEFINES += _CRT_SECURE_NO_WARNINGS
diff --git a/tests/auto/qtcprocess/qtcprocess.qbs b/tests/auto/utils/qtcprocess/qtcprocess.qbs
index 53f5dcfd2f..53f5dcfd2f 100644
--- a/tests/auto/qtcprocess/qtcprocess.qbs
+++ b/tests/auto/utils/qtcprocess/qtcprocess.qbs
diff --git a/tests/auto/qtcprocess/tst_qtcprocess.cpp b/tests/auto/utils/qtcprocess/tst_qtcprocess.cpp
index b4df669441..af5bc3cd3e 100644
--- a/tests/auto/qtcprocess/tst_qtcprocess.cpp
+++ b/tests/auto/utils/qtcprocess/tst_qtcprocess.cpp
@@ -30,8 +30,33 @@
#include <QtTest>
+#include <iostream>
+
using namespace Utils;
+const char kExitCodeSubProcessCode[] = "QTC_TST_QTCPROCESS_EXITCODE_CODE";
+const char kRunBlockingStdOutSubProcessMagicWord[] = "42";
+const char kRunBlockingStdOutSubProcessWithEndl[] = "QTC_TST_QTCPROCESS_RUNBLOCKINGSTDOUT_WITHENDL";
+
+static void exitCodeSubProcessMain()
+{
+ const int exitCode = qEnvironmentVariableIntValue(kExitCodeSubProcessCode);
+ std::cout << "Exiting with code:" << exitCode << std::endl;
+ exit(exitCode);
+}
+
+static void blockingStdOutSubProcessMain()
+{
+ std::cout << "Wait for the Answer to the Ultimate Question of Life, "
+ "The Universe, and Everything..." << std::endl;
+ QThread::msleep(300);
+ std::cout << kRunBlockingStdOutSubProcessMagicWord << "...Now wait for the question...";
+ if (qEnvironmentVariable(kRunBlockingStdOutSubProcessWithEndl) == "true")
+ std::cout << std::endl;
+ QThread::msleep(5000);
+ exit(0);
+}
+
class MacroMapExpander : public AbstractMacroExpander {
public:
virtual bool resolveMacro(const QString &name, QString *ret, QSet<AbstractMacroExpander*> &seen)
@@ -73,6 +98,10 @@ private slots:
void iterations();
void iteratorEditsWindows();
void iteratorEditsLinux();
+ void exitCode_data();
+ void exitCode();
+ void runBlockingStdOut_data();
+ void runBlockingStdOut();
private:
void iteratorEditsHelper(OsType osType);
@@ -88,6 +117,11 @@ private:
void tst_QtcProcess::initTestCase()
{
+ if (qEnvironmentVariableIsSet(kExitCodeSubProcessCode))
+ exitCodeSubProcessMain();
+ if (qEnvironmentVariableIsSet(kRunBlockingStdOutSubProcessWithEndl))
+ blockingStdOutSubProcessMain();
+
homeStr = QLatin1String("@HOME@");
home = QDir::homePath();
@@ -130,55 +164,55 @@ void tst_QtcProcess::initTestCase()
}
-Q_DECLARE_METATYPE(QtcProcess::SplitError)
+Q_DECLARE_METATYPE(ProcessArgs::SplitError)
Q_DECLARE_METATYPE(Utils::OsType)
void tst_QtcProcess::splitArgs_data()
{
QTest::addColumn<QString>("in");
QTest::addColumn<QString>("out");
- QTest::addColumn<QtcProcess::SplitError>("err");
+ QTest::addColumn<ProcessArgs::SplitError>("err");
QTest::addColumn<Utils::OsType>("os");
static const struct {
const char * const in;
const char * const out;
- const QtcProcess::SplitError err;
+ const ProcessArgs::SplitError err;
const OsType os;
} vals[] = {
- {"", "", QtcProcess::SplitOk, OsTypeWindows},
- {" ", "", QtcProcess::SplitOk, OsTypeWindows},
- {"hi", "hi", QtcProcess::SplitOk, OsTypeWindows},
- {"hi ho", "hi ho", QtcProcess::SplitOk, OsTypeWindows},
- {" hi ho ", "hi ho", QtcProcess::SplitOk, OsTypeWindows},
- {"\"hi ho\" \"hi\" ho ", "\"hi ho\" hi ho", QtcProcess::SplitOk, OsTypeWindows},
- {"\\", "\\", QtcProcess::SplitOk, OsTypeWindows},
- {"\\\"", "\"\"\\^\"\"\"", QtcProcess::SplitOk, OsTypeWindows},
- {"\"hi\"\"\"ho\"", "\"hi\"\\^\"\"ho\"", QtcProcess::SplitOk, OsTypeWindows},
- {"\\\\\\\"", "\"\"\\\\\\^\"\"\"", QtcProcess::SplitOk, OsTypeWindows},
- {" ^^ ", "\"^^\"", QtcProcess::SplitOk, OsTypeWindows},
- {"hi\"", "", QtcProcess::BadQuoting, OsTypeWindows},
- {"hi\"dood", "", QtcProcess::BadQuoting, OsTypeWindows},
- {"%var%", "%var%", QtcProcess::SplitOk, OsTypeWindows},
-
- {"", "", QtcProcess::SplitOk, OsTypeLinux},
- {" ", "", QtcProcess::SplitOk, OsTypeLinux},
- {"hi", "hi", QtcProcess::SplitOk, OsTypeLinux},
- {"hi ho", "hi ho", QtcProcess::SplitOk, OsTypeLinux},
- {" hi ho ", "hi ho", QtcProcess::SplitOk, OsTypeLinux},
- {"'hi ho' \"hi\" ho ", "'hi ho' hi ho", QtcProcess::SplitOk, OsTypeLinux},
- {" \\ ", "' '", QtcProcess::SplitOk, OsTypeLinux},
- {" \\\" ", "'\"'", QtcProcess::SplitOk, OsTypeLinux},
- {" '\"' ", "'\"'", QtcProcess::SplitOk, OsTypeLinux},
- {" \"\\\"\" ", "'\"'", QtcProcess::SplitOk, OsTypeLinux},
- {"hi'", "", QtcProcess::BadQuoting, OsTypeLinux},
- {"hi\"dood", "", QtcProcess::BadQuoting, OsTypeLinux},
- {"$var", "'$var'", QtcProcess::SplitOk, OsTypeLinux},
- {"~", "@HOME@", QtcProcess::SplitOk, OsTypeLinux},
- {"~ foo", "@HOME@ foo", QtcProcess::SplitOk, OsTypeLinux},
- {"foo ~", "foo @HOME@", QtcProcess::SplitOk, OsTypeLinux},
- {"~/foo", "@HOME@/foo", QtcProcess::SplitOk, OsTypeLinux},
- {"~foo", "'~foo'", QtcProcess::SplitOk, OsTypeLinux}
+ {"", "", ProcessArgs::SplitOk, OsTypeWindows},
+ {" ", "", ProcessArgs::SplitOk, OsTypeWindows},
+ {"hi", "hi", ProcessArgs::SplitOk, OsTypeWindows},
+ {"hi ho", "hi ho", ProcessArgs::SplitOk, OsTypeWindows},
+ {" hi ho ", "hi ho", ProcessArgs::SplitOk, OsTypeWindows},
+ {"\"hi ho\" \"hi\" ho ", "\"hi ho\" hi ho", ProcessArgs::SplitOk, OsTypeWindows},
+ {"\\", "\\", ProcessArgs::SplitOk, OsTypeWindows},
+ {"\\\"", "\"\"\\^\"\"\"", ProcessArgs::SplitOk, OsTypeWindows},
+ {"\"hi\"\"\"ho\"", "\"hi\"\\^\"\"ho\"", ProcessArgs::SplitOk, OsTypeWindows},
+ {"\\\\\\\"", "\"\"\\\\\\^\"\"\"", ProcessArgs::SplitOk, OsTypeWindows},
+ {" ^^ ", "\"^^\"", ProcessArgs::SplitOk, OsTypeWindows},
+ {"hi\"", "", ProcessArgs::BadQuoting, OsTypeWindows},
+ {"hi\"dood", "", ProcessArgs::BadQuoting, OsTypeWindows},
+ {"%var%", "%var%", ProcessArgs::SplitOk, OsTypeWindows},
+
+ {"", "", ProcessArgs::SplitOk, OsTypeLinux},
+ {" ", "", ProcessArgs::SplitOk, OsTypeLinux},
+ {"hi", "hi", ProcessArgs::SplitOk, OsTypeLinux},
+ {"hi ho", "hi ho", ProcessArgs::SplitOk, OsTypeLinux},
+ {" hi ho ", "hi ho", ProcessArgs::SplitOk, OsTypeLinux},
+ {"'hi ho' \"hi\" ho ", "'hi ho' hi ho", ProcessArgs::SplitOk, OsTypeLinux},
+ {" \\ ", "' '", ProcessArgs::SplitOk, OsTypeLinux},
+ {" \\\" ", "'\"'", ProcessArgs::SplitOk, OsTypeLinux},
+ {" '\"' ", "'\"'", ProcessArgs::SplitOk, OsTypeLinux},
+ {" \"\\\"\" ", "'\"'", ProcessArgs::SplitOk, OsTypeLinux},
+ {"hi'", "", ProcessArgs::BadQuoting, OsTypeLinux},
+ {"hi\"dood", "", ProcessArgs::BadQuoting, OsTypeLinux},
+ {"$var", "'$var'", ProcessArgs::SplitOk, OsTypeLinux},
+ {"~", "@HOME@", ProcessArgs::SplitOk, OsTypeLinux},
+ {"~ foo", "@HOME@ foo", ProcessArgs::SplitOk, OsTypeLinux},
+ {"foo ~", "foo @HOME@", ProcessArgs::SplitOk, OsTypeLinux},
+ {"~/foo", "@HOME@/foo", ProcessArgs::SplitOk, OsTypeLinux},
+ {"~foo", "'~foo'", ProcessArgs::SplitOk, OsTypeLinux}
};
for (unsigned i = 0; i < sizeof(vals)/sizeof(vals[0]); i++) {
@@ -194,13 +228,13 @@ void tst_QtcProcess::splitArgs()
{
QFETCH(QString, in);
QFETCH(QString, out);
- QFETCH(QtcProcess::SplitError, err);
+ QFETCH(ProcessArgs::SplitError, err);
QFETCH(Utils::OsType, os);
- QtcProcess::SplitError outerr;
- QString outstr = QtcProcess::joinArgs(QtcProcess::splitArgs(in, os, false, &outerr), os);
+ ProcessArgs::SplitError outerr;
+ QString outstr = ProcessArgs::joinArgs(ProcessArgs::splitArgs(in, os, false, &outerr), os);
QCOMPARE(outerr, err);
- if (err == QtcProcess::SplitOk)
+ if (err == ProcessArgs::SplitOk)
QCOMPARE(outstr, out);
}
@@ -208,45 +242,45 @@ void tst_QtcProcess::prepareArgs_data()
{
QTest::addColumn<QString>("in");
QTest::addColumn<QString>("out");
- QTest::addColumn<QtcProcess::SplitError>("err");
+ QTest::addColumn<ProcessArgs::SplitError>("err");
QTest::addColumn<OsType>("os");
static const struct {
const char * const in;
const char * const out;
- const QtcProcess::SplitError err;
+ const ProcessArgs::SplitError err;
const OsType os;
} vals[] = {
- {" ", " ", QtcProcess::SplitOk, OsTypeWindows},
- {"", "", QtcProcess::SplitOk, OsTypeWindows},
- {"hi", "hi", QtcProcess::SplitOk, OsTypeWindows},
- {"hi ho", "hi ho", QtcProcess::SplitOk, OsTypeWindows},
- {" hi ho ", " hi ho ", QtcProcess::SplitOk, OsTypeWindows},
- {"\"hi ho\" \"hi\" ho ", "\"hi ho\" \"hi\" ho ", QtcProcess::SplitOk, OsTypeWindows},
- {"\\", "\\", QtcProcess::SplitOk, OsTypeWindows},
- {"\\\"", "\\\"", QtcProcess::SplitOk, OsTypeWindows},
- {"\"hi\"\"ho\"", "\"hi\"\"ho\"", QtcProcess::SplitOk, OsTypeWindows},
- {"\\\\\\\"", "\\\\\\\"", QtcProcess::SplitOk, OsTypeWindows},
- {"^^", "^", QtcProcess::SplitOk, OsTypeWindows},
- {"hi\"", "hi\"", QtcProcess::SplitOk, OsTypeWindows},
- {"hi\"dood", "hi\"dood", QtcProcess::SplitOk, OsTypeWindows},
- {"%var%", "", QtcProcess::FoundMeta, OsTypeWindows},
- {"echo hi > file", "", QtcProcess::FoundMeta, OsTypeWindows},
-
- {"", "", QtcProcess::SplitOk, OsTypeLinux},
- {" ", "", QtcProcess::SplitOk, OsTypeLinux},
- {"hi", "hi", QtcProcess::SplitOk, OsTypeLinux},
- {"hi ho", "hi ho", QtcProcess::SplitOk, OsTypeLinux},
- {" hi ho ", "hi ho", QtcProcess::SplitOk, OsTypeLinux},
- {"'hi ho' \"hi\" ho ", "'hi ho' hi ho", QtcProcess::SplitOk, OsTypeLinux},
- {" \\ ", "' '", QtcProcess::SplitOk, OsTypeLinux},
- {"hi'", "", QtcProcess::BadQuoting, OsTypeLinux},
- {"hi\"dood", "", QtcProcess::BadQuoting, OsTypeLinux},
- {"$var", "", QtcProcess::FoundMeta, OsTypeLinux},
- {"~", "@HOME@", QtcProcess::SplitOk, OsTypeLinux},
- {"~ foo", "@HOME@ foo", QtcProcess::SplitOk, OsTypeLinux},
- {"~/foo", "@HOME@/foo", QtcProcess::SplitOk, OsTypeLinux},
- {"~foo", "", QtcProcess::FoundMeta, OsTypeLinux}
+ {" ", " ", ProcessArgs::SplitOk, OsTypeWindows},
+ {"", "", ProcessArgs::SplitOk, OsTypeWindows},
+ {"hi", "hi", ProcessArgs::SplitOk, OsTypeWindows},
+ {"hi ho", "hi ho", ProcessArgs::SplitOk, OsTypeWindows},
+ {" hi ho ", " hi ho ", ProcessArgs::SplitOk, OsTypeWindows},
+ {"\"hi ho\" \"hi\" ho ", "\"hi ho\" \"hi\" ho ", ProcessArgs::SplitOk, OsTypeWindows},
+ {"\\", "\\", ProcessArgs::SplitOk, OsTypeWindows},
+ {"\\\"", "\\\"", ProcessArgs::SplitOk, OsTypeWindows},
+ {"\"hi\"\"ho\"", "\"hi\"\"ho\"", ProcessArgs::SplitOk, OsTypeWindows},
+ {"\\\\\\\"", "\\\\\\\"", ProcessArgs::SplitOk, OsTypeWindows},
+ {"^^", "^", ProcessArgs::SplitOk, OsTypeWindows},
+ {"hi\"", "hi\"", ProcessArgs::SplitOk, OsTypeWindows},
+ {"hi\"dood", "hi\"dood", ProcessArgs::SplitOk, OsTypeWindows},
+ {"%var%", "", ProcessArgs::FoundMeta, OsTypeWindows},
+ {"echo hi > file", "", ProcessArgs::FoundMeta, OsTypeWindows},
+
+ {"", "", ProcessArgs::SplitOk, OsTypeLinux},
+ {" ", "", ProcessArgs::SplitOk, OsTypeLinux},
+ {"hi", "hi", ProcessArgs::SplitOk, OsTypeLinux},
+ {"hi ho", "hi ho", ProcessArgs::SplitOk, OsTypeLinux},
+ {" hi ho ", "hi ho", ProcessArgs::SplitOk, OsTypeLinux},
+ {"'hi ho' \"hi\" ho ", "'hi ho' hi ho", ProcessArgs::SplitOk, OsTypeLinux},
+ {" \\ ", "' '", ProcessArgs::SplitOk, OsTypeLinux},
+ {"hi'", "", ProcessArgs::BadQuoting, OsTypeLinux},
+ {"hi\"dood", "", ProcessArgs::BadQuoting, OsTypeLinux},
+ {"$var", "", ProcessArgs::FoundMeta, OsTypeLinux},
+ {"~", "@HOME@", ProcessArgs::SplitOk, OsTypeLinux},
+ {"~ foo", "@HOME@ foo", ProcessArgs::SplitOk, OsTypeLinux},
+ {"~/foo", "@HOME@/foo", ProcessArgs::SplitOk, OsTypeLinux},
+ {"~foo", "", ProcessArgs::FoundMeta, OsTypeLinux}
};
for (unsigned i = 0; i < sizeof(vals)/sizeof(vals[0]); i++) {
@@ -262,15 +296,15 @@ void tst_QtcProcess::prepareArgs()
{
QFETCH(QString, in);
QFETCH(QString, out);
- QFETCH(QtcProcess::SplitError, err);
+ QFETCH(ProcessArgs::SplitError, err);
QFETCH(OsType, os);
- QtcProcess::SplitError outerr;
- QtcProcess::Arguments args = QtcProcess::prepareArgs(in, &outerr, os);
+ ProcessArgs::SplitError outerr;
+ ProcessArgs args = ProcessArgs::prepareArgs(in, &outerr, os);
QString outstr = args.toString();
QCOMPARE(outerr, err);
- if (err == QtcProcess::SplitOk)
+ if (err == ProcessArgs::SplitOk)
QCOMPARE(outstr, out);
}
@@ -278,65 +312,65 @@ void tst_QtcProcess::prepareArgsEnv_data()
{
QTest::addColumn<QString>("in");
QTest::addColumn<QString>("out");
- QTest::addColumn<QtcProcess::SplitError>("err");
+ QTest::addColumn<ProcessArgs::SplitError>("err");
QTest::addColumn<OsType>("os");
static const struct {
const char * const in;
const char * const out;
- const QtcProcess::SplitError err;
+ const ProcessArgs::SplitError err;
const OsType os;
} vals[] = {
- {" ", " ", QtcProcess::SplitOk, OsTypeWindows},
- {"", "", QtcProcess::SplitOk, OsTypeWindows},
- {"hi", "hi", QtcProcess::SplitOk, OsTypeWindows},
- {"hi ho", "hi ho", QtcProcess::SplitOk, OsTypeWindows},
- {" hi ho ", " hi ho ", QtcProcess::SplitOk, OsTypeWindows},
- {"\"hi ho\" \"hi\" ho ", "\"hi ho\" \"hi\" ho ", QtcProcess::SplitOk, OsTypeWindows},
- {"\\", "\\", QtcProcess::SplitOk, OsTypeWindows},
- {"\\\"", "\\\"", QtcProcess::SplitOk, OsTypeWindows},
- {"\"hi\"\"ho\"", "\"hi\"\"ho\"", QtcProcess::SplitOk, OsTypeWindows},
- {"\\\\\\\"", "\\\\\\\"", QtcProcess::SplitOk, OsTypeWindows},
- {"^^", "^", QtcProcess::SplitOk, OsTypeWindows},
- {"hi\"", "hi\"", QtcProcess::SplitOk, OsTypeWindows},
- {"hi\"dood", "hi\"dood", QtcProcess::SplitOk, OsTypeWindows},
- {"%empty%", "%empty%", QtcProcess::SplitOk, OsTypeWindows}, // Yep, no empty variables on Windows.
- {"%word%", "hi", QtcProcess::SplitOk, OsTypeWindows},
- {" %word% ", " hi ", QtcProcess::SplitOk, OsTypeWindows},
- {"%words%", "hi ho", QtcProcess::SplitOk, OsTypeWindows},
- {"%nonsense%words%", "%nonsensehi ho", QtcProcess::SplitOk, OsTypeWindows},
- {"fail%nonsense%words%", "fail%nonsensehi ho", QtcProcess::SplitOk, OsTypeWindows},
- {"%words%words%", "hi howords%", QtcProcess::SplitOk, OsTypeWindows},
- {"%words%%words%", "hi hohi ho", QtcProcess::SplitOk, OsTypeWindows},
- {"echo hi > file", "", QtcProcess::FoundMeta, OsTypeWindows},
-
- {"", "", QtcProcess::SplitOk, OsTypeLinux},
- {" ", "", QtcProcess::SplitOk, OsTypeLinux},
- {"hi", "hi", QtcProcess::SplitOk, OsTypeLinux},
- {"hi ho", "hi ho", QtcProcess::SplitOk, OsTypeLinux},
- {" hi ho ", "hi ho", QtcProcess::SplitOk, OsTypeLinux},
- {"'hi ho' \"hi\" ho ", "'hi ho' hi ho", QtcProcess::SplitOk, OsTypeLinux},
- {" \\ ", "' '", QtcProcess::SplitOk, OsTypeLinux},
- {"hi'", "", QtcProcess::BadQuoting, OsTypeLinux},
- {"hi\"dood", "", QtcProcess::BadQuoting, OsTypeLinux},
- {"$empty", "", QtcProcess::SplitOk, OsTypeLinux},
- {"$word", "hi", QtcProcess::SplitOk, OsTypeLinux},
- {" $word ", "hi", QtcProcess::SplitOk, OsTypeLinux},
- {"${word}", "hi", QtcProcess::SplitOk, OsTypeLinux},
- {" ${word} ", "hi", QtcProcess::SplitOk, OsTypeLinux},
- {"$words", "hi ho", QtcProcess::SplitOk, OsTypeLinux},
- {"$spacedwords", "hi ho sucker", QtcProcess::SplitOk, OsTypeLinux},
- {"hi${empty}ho", "hiho", QtcProcess::SplitOk, OsTypeLinux},
- {"hi${words}ho", "hihi hoho", QtcProcess::SplitOk, OsTypeLinux},
- {"hi${spacedwords}ho", "hi hi ho sucker ho", QtcProcess::SplitOk, OsTypeLinux},
- {"${", "", QtcProcess::BadQuoting, OsTypeLinux},
- {"${var", "", QtcProcess::BadQuoting, OsTypeLinux},
- {"${var ", "", QtcProcess::FoundMeta, OsTypeLinux},
- {"\"hi${words}ho\"", "'hihi hoho'", QtcProcess::SplitOk, OsTypeLinux},
- {"\"hi${spacedwords}ho\"", "'hi hi ho sucker ho'", QtcProcess::SplitOk, OsTypeLinux},
- {"\"${", "", QtcProcess::BadQuoting, OsTypeLinux},
- {"\"${var", "", QtcProcess::BadQuoting, OsTypeLinux},
- {"\"${var ", "", QtcProcess::FoundMeta, OsTypeLinux},
+ {" ", " ", ProcessArgs::SplitOk, OsTypeWindows},
+ {"", "", ProcessArgs::SplitOk, OsTypeWindows},
+ {"hi", "hi", ProcessArgs::SplitOk, OsTypeWindows},
+ {"hi ho", "hi ho", ProcessArgs::SplitOk, OsTypeWindows},
+ {" hi ho ", " hi ho ", ProcessArgs::SplitOk, OsTypeWindows},
+ {"\"hi ho\" \"hi\" ho ", "\"hi ho\" \"hi\" ho ", ProcessArgs::SplitOk, OsTypeWindows},
+ {"\\", "\\", ProcessArgs::SplitOk, OsTypeWindows},
+ {"\\\"", "\\\"", ProcessArgs::SplitOk, OsTypeWindows},
+ {"\"hi\"\"ho\"", "\"hi\"\"ho\"", ProcessArgs::SplitOk, OsTypeWindows},
+ {"\\\\\\\"", "\\\\\\\"", ProcessArgs::SplitOk, OsTypeWindows},
+ {"^^", "^", ProcessArgs::SplitOk, OsTypeWindows},
+ {"hi\"", "hi\"", ProcessArgs::SplitOk, OsTypeWindows},
+ {"hi\"dood", "hi\"dood", ProcessArgs::SplitOk, OsTypeWindows},
+ {"%empty%", "%empty%", ProcessArgs::SplitOk, OsTypeWindows}, // Yep, no empty variables on Windows.
+ {"%word%", "hi", ProcessArgs::SplitOk, OsTypeWindows},
+ {" %word% ", " hi ", ProcessArgs::SplitOk, OsTypeWindows},
+ {"%words%", "hi ho", ProcessArgs::SplitOk, OsTypeWindows},
+ {"%nonsense%words%", "%nonsensehi ho", ProcessArgs::SplitOk, OsTypeWindows},
+ {"fail%nonsense%words%", "fail%nonsensehi ho", ProcessArgs::SplitOk, OsTypeWindows},
+ {"%words%words%", "hi howords%", ProcessArgs::SplitOk, OsTypeWindows},
+ {"%words%%words%", "hi hohi ho", ProcessArgs::SplitOk, OsTypeWindows},
+ {"echo hi > file", "", ProcessArgs::FoundMeta, OsTypeWindows},
+
+ {"", "", ProcessArgs::SplitOk, OsTypeLinux},
+ {" ", "", ProcessArgs::SplitOk, OsTypeLinux},
+ {"hi", "hi", ProcessArgs::SplitOk, OsTypeLinux},
+ {"hi ho", "hi ho", ProcessArgs::SplitOk, OsTypeLinux},
+ {" hi ho ", "hi ho", ProcessArgs::SplitOk, OsTypeLinux},
+ {"'hi ho' \"hi\" ho ", "'hi ho' hi ho", ProcessArgs::SplitOk, OsTypeLinux},
+ {" \\ ", "' '", ProcessArgs::SplitOk, OsTypeLinux},
+ {"hi'", "", ProcessArgs::BadQuoting, OsTypeLinux},
+ {"hi\"dood", "", ProcessArgs::BadQuoting, OsTypeLinux},
+ {"$empty", "", ProcessArgs::SplitOk, OsTypeLinux},
+ {"$word", "hi", ProcessArgs::SplitOk, OsTypeLinux},
+ {" $word ", "hi", ProcessArgs::SplitOk, OsTypeLinux},
+ {"${word}", "hi", ProcessArgs::SplitOk, OsTypeLinux},
+ {" ${word} ", "hi", ProcessArgs::SplitOk, OsTypeLinux},
+ {"$words", "hi ho", ProcessArgs::SplitOk, OsTypeLinux},
+ {"$spacedwords", "hi ho sucker", ProcessArgs::SplitOk, OsTypeLinux},
+ {"hi${empty}ho", "hiho", ProcessArgs::SplitOk, OsTypeLinux},
+ {"hi${words}ho", "hihi hoho", ProcessArgs::SplitOk, OsTypeLinux},
+ {"hi${spacedwords}ho", "hi hi ho sucker ho", ProcessArgs::SplitOk, OsTypeLinux},
+ {"${", "", ProcessArgs::BadQuoting, OsTypeLinux},
+ {"${var", "", ProcessArgs::BadQuoting, OsTypeLinux},
+ {"${var ", "", ProcessArgs::FoundMeta, OsTypeLinux},
+ {"\"hi${words}ho\"", "'hihi hoho'", ProcessArgs::SplitOk, OsTypeLinux},
+ {"\"hi${spacedwords}ho\"", "'hi hi ho sucker ho'", ProcessArgs::SplitOk, OsTypeLinux},
+ {"\"${", "", ProcessArgs::BadQuoting, OsTypeLinux},
+ {"\"${var", "", ProcessArgs::BadQuoting, OsTypeLinux},
+ {"\"${var ", "", ProcessArgs::FoundMeta, OsTypeLinux},
};
for (unsigned i = 0; i < sizeof(vals)/sizeof(vals[0]); i++) {
@@ -352,15 +386,15 @@ void tst_QtcProcess::prepareArgsEnv()
{
QFETCH(QString, in);
QFETCH(QString, out);
- QFETCH(QtcProcess::SplitError, err);
+ QFETCH(ProcessArgs::SplitError, err);
QFETCH(OsType, os);
- QtcProcess::SplitError outerr;
- QtcProcess::Arguments args = QtcProcess::prepareArgs(in, &outerr, os, os == OsTypeLinux ? &envLinux : &envWindows);
+ ProcessArgs::SplitError outerr;
+ ProcessArgs args = ProcessArgs::prepareArgs(in, &outerr, os, os == OsTypeLinux ? &envLinux : &envWindows);
QString outstr = args.toString();
QCOMPARE(outerr, err);
- if (err == QtcProcess::SplitOk)
+ if (err == ProcessArgs::SplitOk)
QCOMPARE(outstr, out);
}
@@ -605,9 +639,9 @@ void tst_QtcProcess::expandMacros()
QFETCH(OsType, os);
if (os == OsTypeWindows)
- QtcProcess::expandMacros(&in, &mxWin, os);
+ ProcessArgs::expandMacros(&in, &mxWin, os);
else
- QtcProcess::expandMacros(&in, &mxUnix, os);
+ ProcessArgs::expandMacros(&in, &mxUnix, os);
QCOMPARE(in, out);
}
@@ -673,11 +707,11 @@ void tst_QtcProcess::iterations()
QFETCH(OsType, os);
QString outstr;
- for (QtcProcess::ArgIterator ait(&in, os); ait.next(); ) {
+ for (ProcessArgs::ArgIterator ait(&in, os); ait.next(); ) {
if (ait.isSimple())
- QtcProcess::addArg(&outstr, ait.value(), os);
+ ProcessArgs::addArg(&outstr, ait.value(), os);
else
- QtcProcess::addArgs(&outstr, "{}");
+ ProcessArgs::addArgs(&outstr, "{}");
}
QCOMPARE(outstr, out);
}
@@ -686,7 +720,7 @@ void tst_QtcProcess::iteratorEditsHelper(OsType osType)
{
QString in1 = "one two three", in2 = in1, in3 = in1, in4 = in1, in5 = in1;
- QtcProcess::ArgIterator ait1(&in1, osType);
+ ProcessArgs::ArgIterator ait1(&in1, osType);
QVERIFY(ait1.next());
ait1.deleteArg();
QVERIFY(ait1.next());
@@ -696,7 +730,7 @@ void tst_QtcProcess::iteratorEditsHelper(OsType osType)
ait1.appendArg("four");
QCOMPARE(in1, QString::fromLatin1("two three four"));
- QtcProcess::ArgIterator ait2(&in2, osType);
+ ProcessArgs::ArgIterator ait2(&in2, osType);
QVERIFY(ait2.next());
QVERIFY(ait2.next());
ait2.deleteArg();
@@ -705,7 +739,7 @@ void tst_QtcProcess::iteratorEditsHelper(OsType osType)
QVERIFY(!ait2.next());
QCOMPARE(in2, QString::fromLatin1("one three four"));
- QtcProcess::ArgIterator ait3(&in3, osType);
+ ProcessArgs::ArgIterator ait3(&in3, osType);
QVERIFY(ait3.next());
ait3.appendArg("one-b");
QVERIFY(ait3.next());
@@ -714,7 +748,7 @@ void tst_QtcProcess::iteratorEditsHelper(OsType osType)
QVERIFY(!ait3.next());
QCOMPARE(in3, QString::fromLatin1("one one-b two"));
- QtcProcess::ArgIterator ait4(&in4, osType);
+ ProcessArgs::ArgIterator ait4(&in4, osType);
ait4.appendArg("pre-one");
QVERIFY(ait4.next());
QVERIFY(ait4.next());
@@ -723,7 +757,7 @@ void tst_QtcProcess::iteratorEditsHelper(OsType osType)
QVERIFY(!ait4.next());
QCOMPARE(in4, QString::fromLatin1("pre-one one two"));
- QtcProcess::ArgIterator ait5(&in5, osType);
+ ProcessArgs::ArgIterator ait5(&in5, osType);
QVERIFY(ait5.next());
QVERIFY(ait5.next());
QVERIFY(ait5.next());
@@ -743,6 +777,98 @@ void tst_QtcProcess::iteratorEditsLinux()
iteratorEditsHelper(OsTypeLinux);
}
+void tst_QtcProcess::exitCode_data()
+{
+ QTest::addColumn<int>("exitCode");
+
+ static const auto exitCodes = {
+#ifdef Q_OS_WIN
+ "99999999", "-255", "-1",
+#endif // Q_OS_WIN
+ "0", "1", "255"
+ };
+ for (auto exitCode : exitCodes)
+ QTest::newRow(exitCode) << QString::fromLatin1(exitCode).toInt();
+}
+
+void tst_QtcProcess::exitCode()
+{
+ QFETCH(int, exitCode);
+
+ Environment env = Environment::systemEnvironment();
+ env.set(kExitCodeSubProcessCode, QString::number(exitCode));
+ QStringList args = QCoreApplication::arguments();
+ const QString binary = args.takeFirst();
+ const CommandLine command(binary, args);
+
+ {
+ QtcProcess qtcP;
+ qtcP.setCommand(command);
+ qtcP.setEnvironment(env);
+ qtcP.start();
+ const bool finished = qtcP.waitForFinished();
+
+ QVERIFY(finished);
+ QCOMPARE(qtcP.exitCode(), exitCode);
+ }
+ {
+ SynchronousProcess sP;
+ sP.setCommand(command);
+ sP.setEnvironment(env);
+ sP.runBlocking();
+
+ QCOMPARE(sP.exitCode(), exitCode);
+ }
+}
+
+void tst_QtcProcess::runBlockingStdOut_data()
+{
+ QTest::addColumn<bool>("withEndl");
+ QTest::addColumn<int>("timeOutS");
+
+ QTest::newRow("Terminated stdout delivered instantly")
+ << true
+ << 2;
+ QTest::newRow("Unterminated stdout lost: early timeout")
+ << false
+ << 2;
+ QTest::newRow("Unterminated stdout lost: hanging")
+ << false
+ << 20;
+}
+
+void tst_QtcProcess::runBlockingStdOut()
+{
+ QFETCH(bool, withEndl);
+ QFETCH(int, timeOutS);
+
+ SynchronousProcess sp;
+ QStringList args = QCoreApplication::arguments();
+ const QString binary = args.takeFirst();
+ sp.setCommand(CommandLine(binary, args));
+ Environment env = Environment::systemEnvironment();
+ env.set(kRunBlockingStdOutSubProcessWithEndl, withEndl ? "true" : "false");
+ sp.setEnvironment(env);
+ sp.setTimeoutS(timeOutS);
+ bool readLastLine = false;
+ sp.setStdOutCallback([&readLastLine, &sp](const QString &out) {
+ if (out.startsWith(kRunBlockingStdOutSubProcessMagicWord)) {
+ readLastLine = true;
+ sp.kill();
+ }
+ });
+ sp.runBlocking();
+
+ // See also QTCREATORBUG-25667 for why it is a bad idea to use SynchronousProcess::runBlocking
+ // with interactive cli tools.
+ QEXPECT_FAIL("Unterminated stdout lost: early timeout", "", Continue);
+ QVERIFY2(sp.result() != QtcProcess::Hang, "Process run did not time out.");
+
+ QEXPECT_FAIL("Unterminated stdout lost: early timeout", "", Continue);
+ QEXPECT_FAIL("Unterminated stdout lost: hanging", "", Continue);
+ QVERIFY2(readLastLine, "Last line was read.");
+}
+
QTEST_MAIN(tst_QtcProcess)
#include "tst_qtcprocess.moc"
diff --git a/tests/auto/utils/utils.pro b/tests/auto/utils/utils.pro
index 1a96edbfa0..2e15c4379e 100644
--- a/tests/auto/utils/utils.pro
+++ b/tests/auto/utils/utils.pro
@@ -5,6 +5,7 @@ SUBDIRS = \
ansiescapecodehandler \
fuzzymatcher \
persistentsettings \
+ qtcprocess \
settings \
stringutils \
templateengine \
diff --git a/tests/auto/utils/utils.qbs b/tests/auto/utils/utils.qbs
index e3e136305a..5b11f46e7b 100644
--- a/tests/auto/utils/utils.qbs
+++ b/tests/auto/utils/utils.qbs
@@ -7,6 +7,7 @@ Project {
"ansiescapecodehandler/ansiescapecodehandler.qbs",
"fuzzymatcher/fuzzymatcher.qbs",
"persistentsettings/persistentsettings.qbs",
+ "qtcprocess/qtcprocess.qbs",
"settings/settings.qbs",
"stringutils/stringutils.qbs",
"templateengine/templateengine.qbs",
diff --git a/tests/manual/docker/Dockerfile b/tests/manual/docker/Dockerfile
new file mode 100644
index 0000000000..169e5a6793
--- /dev/null
+++ b/tests/manual/docker/Dockerfile
@@ -0,0 +1,21 @@
+
+FROM ubuntu:20.04
+
+RUN apt-get update \
+ && DEBIAN_FRONTEND=noninteractive apt-get install -y \
+ git \
+ openssh-client \
+ sudo \
+ vim \
+ wget \
+ cmake \
+ qtbase5-dev \
+ libqt5core5a \
+ libqt5widgets5 \
+ libqt5quick5 \
+ libqt5quickcontrols2-5 \
+ qt5-qmake \
+ g++ \
+ gdb \
+ && apt-get clean \
+ && rm -rf /var/lib/apt/lists/*
diff --git a/tests/manual/docker/build.sh b/tests/manual/docker/build.sh
new file mode 100755
index 0000000000..234c18463f
--- /dev/null
+++ b/tests/manual/docker/build.sh
@@ -0,0 +1,2 @@
+#!/bin/sh
+docker build -t qt-5-ubuntu-20.04 .
diff --git a/tests/manual/process/main.cpp b/tests/manual/process/main.cpp
index 8c1dc67db6..df4f6fa963 100644
--- a/tests/manual/process/main.cpp
+++ b/tests/manual/process/main.cpp
@@ -25,7 +25,8 @@
#include "mainwindow.h"
-#include <utils/synchronousprocess.h>
+#include <utils/qtcprocess.h>
+
#include <QApplication>
#include <QDebug>
#include <QTimer>
@@ -47,15 +48,16 @@ static int testSynchronous(const QString &cmd, const QStringList &args)
{
std::fprintf(stdout, "testSynchronous %s %s\n", qPrintable(cmd),
qPrintable(args.join(QLatin1Char(' '))));
- QProcess p;
- p.start(cmd, args);
+ Utils::QtcProcess p;
+ p.setCommand({cmd, args});
+ p.start();
if (!p.waitForStarted())
return -2;
p.closeWriteChannel();
QByteArray stdOut;
QByteArray stdErr;
- if (!Utils::SynchronousProcess::readDataFromProcess(p, 2, &stdOut, &stdErr)) {
+ if (!p.readDataFromProcess(2, &stdOut, &stdErr, false)) {
std::fputs("Timeout", stderr);
return -3;
}
diff --git a/tests/manual/process/mainwindow.cpp b/tests/manual/process/mainwindow.cpp
index 85a7b2ef9f..cbe2aa03ac 100644
--- a/tests/manual/process/mainwindow.cpp
+++ b/tests/manual/process/mainwindow.cpp
@@ -26,7 +26,7 @@
#include "mainwindow.h"
#include <utils/fileutils.h>
-#include <utils/synchronousprocess.h>
+#include <utils/qtcprocess.h>
#include <QPlainTextEdit>
#include <QApplication>
@@ -55,8 +55,8 @@ void MainWindow::test()
Utils::SynchronousProcess process;
process.setTimeoutS(2);
qDebug() << "Async: " << cmd << args;
- connect(&process, &Utils::SynchronousProcess::stdOutBuffered, this, &MainWindow::append);
- connect(&process, &Utils::SynchronousProcess::stdErrBuffered, this, &MainWindow::append);
- const Utils::SynchronousProcessResponse resp = process.run({Utils::FilePath::fromString(cmd), args});
- qDebug() << resp;
+ process.setStdOutCallback([this](const QString &s) { append(s); });
+ process.setStdErrCallback([this](const QString &s) { append(s); });
+ process.run({cmd, args});
+ qDebug() << process;
}
diff --git a/tests/manual/qml/testprojects/modulemapping/CMakeLists.txt b/tests/manual/qml/testprojects/modulemapping/CMakeLists.txt
new file mode 100644
index 0000000000..a138dd3f98
--- /dev/null
+++ b/tests/manual/qml/testprojects/modulemapping/CMakeLists.txt
@@ -0,0 +1,7 @@
+cmake_minimum_required(VERSION 3.13)
+project(test_project)
+
+add_executable(test_exe test.cc test.qml)
+
+file(GENERATE OUTPUT "${CMAKE_BINARY_DIR}/qml_module_mappings/test_exe" CONTENT "QtQuick.Controls=MyControls\n")
+
diff --git a/tests/manual/qml/testprojects/modulemapping/MyControls/Button.qml b/tests/manual/qml/testprojects/modulemapping/MyControls/Button.qml
new file mode 100644
index 0000000000..1ca99665a5
--- /dev/null
+++ b/tests/manual/qml/testprojects/modulemapping/MyControls/Button.qml
@@ -0,0 +1,5 @@
+import QtQuick 2.0
+
+Item {
+ property int myproperty
+}
diff --git a/tests/manual/qml/testprojects/modulemapping/MyControls/qmldir b/tests/manual/qml/testprojects/modulemapping/MyControls/qmldir
new file mode 100644
index 0000000000..8ec6772e59
--- /dev/null
+++ b/tests/manual/qml/testprojects/modulemapping/MyControls/qmldir
@@ -0,0 +1,3 @@
+module MyControls
+import QtQuick
+Button 1.0 Button.qml
diff --git a/tests/manual/qml/testprojects/modulemapping/README.txt b/tests/manual/qml/testprojects/modulemapping/README.txt
new file mode 100644
index 0000000000..50c8585bfd
--- /dev/null
+++ b/tests/manual/qml/testprojects/modulemapping/README.txt
@@ -0,0 +1,9 @@
+This is a test for the module mapping feature used by Qt for MCUs.
+
+Please add this source directory to the QML_IMPORT_PATH! A Qt for MCUs kit will do this automatically, but other kits
+won't.
+
+You can check that it works by going to test.qml, and "myproperty" should not be underligned as error. Without mapping,
+the use of Button would resolve to QtQuick.Control's Button, which doesn't have that property. With the mapping, it
+redirects to MyControls's Button which does have the property. You can verify this by control/command-clicking on the
+property. This should take you to MyControls/Button.qml.
diff --git a/tests/manual/qml/testprojects/modulemapping/test.cc b/tests/manual/qml/testprojects/modulemapping/test.cc
new file mode 100644
index 0000000000..237c8ce181
--- /dev/null
+++ b/tests/manual/qml/testprojects/modulemapping/test.cc
@@ -0,0 +1 @@
+int main() {}
diff --git a/tests/manual/qml/testprojects/modulemapping/test.qml b/tests/manual/qml/testprojects/modulemapping/test.qml
new file mode 100644
index 0000000000..e30e0846ba
--- /dev/null
+++ b/tests/manual/qml/testprojects/modulemapping/test.qml
@@ -0,0 +1,8 @@
+import QtQuick 2.0
+import QtQuick.Controls 2.12
+
+Item {
+ Button {
+ myproperty: 1
+ }
+}
diff --git a/tests/manual/widgets/CMakeLists.txt b/tests/manual/widgets/CMakeLists.txt
index c7ce793d3e..9e5a48eb20 100644
--- a/tests/manual/widgets/CMakeLists.txt
+++ b/tests/manual/widgets/CMakeLists.txt
@@ -1,3 +1,4 @@
add_subdirectory(crumblepath)
add_subdirectory(infolabel)
add_subdirectory(manhattanstyle)
+add_subdirectory(tracing)
diff --git a/tests/manual/widgets/common/themeselector.cpp b/tests/manual/widgets/common/themeselector.cpp
index bf1a5b3a02..809f64acc5 100644
--- a/tests/manual/widgets/common/themeselector.cpp
+++ b/tests/manual/widgets/common/themeselector.cpp
@@ -35,9 +35,11 @@
#include <QDir>
#include <QSettings>
+namespace ManualTest {
+
static const char themeNameKey[] = "ThemeName";
-static void setTheme(const QString &themeFile)
+void ThemeSelector::setTheme(const QString &themeFile)
{
using namespace Utils;
@@ -50,7 +52,7 @@ static void setTheme(const QString &themeFile)
QApplication::setPalette(theme.palette());
}
-ManualTest::ThemeSelector::ThemeSelector(QWidget *parent)
+ThemeSelector::ThemeSelector(QWidget *parent)
: QComboBox(parent)
{
QCoreApplication::setOrganizationName("QtProject");
@@ -71,3 +73,5 @@ ManualTest::ThemeSelector::ThemeSelector(QWidget *parent)
appSettings.setValue(themeNameKey, currentText());
});
}
+
+} // namespace ManualTest
diff --git a/tests/manual/widgets/common/themeselector.h b/tests/manual/widgets/common/themeselector.h
index 0989390373..2a8375fa83 100644
--- a/tests/manual/widgets/common/themeselector.h
+++ b/tests/manual/widgets/common/themeselector.h
@@ -32,6 +32,8 @@ namespace ManualTest {
class ThemeSelector : public QComboBox {
public:
ThemeSelector(QWidget *parent = nullptr);
+
+ static void setTheme(const QString &themeFile);
};
-}
+} // namespace ManualTest
diff --git a/tests/manual/widgets/tracing/CMakeLists.txt b/tests/manual/widgets/tracing/CMakeLists.txt
new file mode 100644
index 0000000000..0de9edb7e0
--- /dev/null
+++ b/tests/manual/widgets/tracing/CMakeLists.txt
@@ -0,0 +1,9 @@
+add_qtc_executable(tst_manual_widgets_tracing
+ CONDITION TARGET Tracing
+ DEPENDS Tracing Utils Core Qt5::Gui Qt5::Quick
+ SOURCES
+ tst_manual_widgets_tracing.cpp
+ ../common/themeselector.cpp ../common/themeselector.h
+ ../common/themes.qrc
+ PROPERTIES RUNTIME_OUTPUT_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}
+)
diff --git a/tests/manual/widgets/tracing/tracing.qbs b/tests/manual/widgets/tracing/tracing.qbs
new file mode 100644
index 0000000000..06bbc4edd4
--- /dev/null
+++ b/tests/manual/widgets/tracing/tracing.qbs
@@ -0,0 +1,16 @@
+import "../common/common.qbs" as Common
+
+CppApplication {
+ name: "Manual Test Tracing"
+
+ Depends { name: "Qt.quick" }
+ Depends { name: "Tracing" }
+ Depends { name: "Utils" }
+ Depends { name: "Core" }
+
+ files: [
+ "tst_manual_widgets_tracing.cpp",
+ ]
+
+ Common {}
+}
diff --git a/tests/manual/widgets/tracing/tst_manual_widgets_tracing.cpp b/tests/manual/widgets/tracing/tst_manual_widgets_tracing.cpp
new file mode 100644
index 0000000000..baa879dc3a
--- /dev/null
+++ b/tests/manual/widgets/tracing/tst_manual_widgets_tracing.cpp
@@ -0,0 +1,175 @@
+/****************************************************************************
+**
+** Copyright (C) 2021 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of Qt Creator.
+**
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3 as published by the Free Software
+** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-3.0.html.
+**
+****************************************************************************/
+
+#include <QApplication>
+#include <QQuickView>
+#include <QQmlContext>
+
+#include <tracing/timelinerenderer.h>
+#include <tracing/timelineoverviewrenderer.h>
+#include <tracing/timelinemodelaggregator.h>
+#include <tracing/timelinetheme.h>
+#include <tracing/timelineformattime.h>
+#include <tracing/timelinezoomcontrol.h>
+
+#include "../common/themeselector.h"
+
+using namespace Timeline;
+
+static const qint64 oneMs = 1000 * 1000; // in nanoseconds
+
+class DummyModel : public Timeline::TimelineModel
+{
+public:
+ DummyModel(TimelineModelAggregator *parent)
+ : TimelineModel(parent)
+ {
+ setDisplayName("Dummy Category");
+ setCollapsedRowCount(1);
+ setExpandedRowCount(3);
+ setTooltip("This is a tool tip"); // Tooltip on the title on the left
+ setCategoryColor(Qt::yellow);
+ }
+
+ QRgb color(int index) const override
+ {
+ return QColor::fromHsl(index * 20, 96, 128).rgb(); // Red to green
+ }
+
+ // Called when a range gets selected, requests index of row which a range belongs to
+ int expandedRow(int index) const override
+ {
+ return selectionId(index) % expandedRowCount(); // Distribute selections among rows
+ }
+
+ // Called when the category gets expanded
+ QVariantList labels() const override
+ {
+ QVariantList result;
+
+ QVariantMap element;
+ element.insert(QLatin1String("description"), QVariant("Dummy sub category 1"));
+ element.insert(QLatin1String("id"), 0);
+ result << element;
+
+ element.clear();
+ element.insert(QLatin1String("description"), QVariant("Dummy sub category 2"));
+ element.insert(QLatin1String("id"), 1);
+ result << element;
+
+ return result;
+ }
+
+ // Called when a range (or track) is selected
+ QVariantMap details(int index) const override
+ {
+ QVariantMap result;
+ result.insert(QLatin1String("displayName"),
+ QString::fromLatin1("Details for range %1").arg(index));
+ result.insert(QLatin1String("Foo A"), QString::fromLatin1("Bar %1a").arg(index));
+ result.insert(QLatin1String("Foo B"), QString::fromLatin1("Bar %1b").arg(index));
+ return result;
+ }
+
+ float relativeHeight(int index) const override
+ {
+ return 1.0 - (index / 10.0); // Shrink over time
+ }
+
+ void populateData()
+ {
+ // One region per selection
+ insert(oneMs * 20, oneMs * 20, 0);
+ insert(oneMs * 100, oneMs * 30, 1);
+
+ // Two regions in the same selection
+ insert(oneMs * 40, oneMs * 20, 2);
+ insert(oneMs * 120, oneMs * 30, 2);
+
+ // Three regions in the same selection
+ insert(oneMs * 60, oneMs * 30, 3);
+ insert(oneMs * 140, oneMs * 20, 3);
+ insert(oneMs * 170, oneMs * 20, 3);
+
+ emit contentChanged();
+ }
+};
+
+class TraceView : public QQuickView
+{
+public:
+ TraceView(QWindow *parent = 0)
+ : QQuickView(parent)
+ {
+ setResizeMode(QQuickView::SizeRootObjectToView);
+
+ qmlRegisterType<TimelineRenderer>("TimelineRenderer", 1, 0, "TimelineRenderer");
+ qmlRegisterType<TimelineOverviewRenderer>(
+ "TimelineOverviewRenderer", 1, 0, "TimelineOverviewRenderer");
+ qmlRegisterAnonymousType<TimelineZoomControl>("TimelineZoomControl", 1);
+ qmlRegisterAnonymousType<TimelineModel>("TimelineModel", 1);
+ qmlRegisterAnonymousType<TimelineNotesModel>("TimelineNotesModel", 1);
+
+ TimelineTheme::setupTheme(engine());
+ TimeFormatter::setupTimeFormatter();
+
+ m_modelAggregator = new TimelineModelAggregator(this);
+ m_model = new DummyModel(m_modelAggregator);
+ m_model->populateData();
+ m_modelAggregator->setModels({QVariant::fromValue(m_model)});
+ rootContext()->setContextProperty(QLatin1String("timelineModelAggregator"),
+ m_modelAggregator);
+
+ m_zoomControl = new TimelineZoomControl(this);
+ m_zoomControl->setTrace(0, oneMs * 1000); // Total timeline length
+ rootContext()->setContextProperty("zoomControl", m_zoomControl);
+ setSource(QUrl(QLatin1String("qrc:/tracing/MainView.qml")));
+
+ // Zoom onto first timeline third. Needs to be done after loading setSource.
+ m_zoomControl->setRange(0, oneMs * 1000 / 3.0);
+ }
+
+ ~TraceView() override = default;
+
+ DummyModel *m_model;
+ TimelineModelAggregator *m_modelAggregator;
+ TimelineZoomControl *m_zoomControl;
+};
+
+int main(int argc, char *argv[])
+{
+ QApplication::setAttribute(Qt::AA_EnableHighDpiScaling);
+ QApplication::setAttribute(Qt::AA_UseHighDpiPixmaps);
+
+ QApplication app(argc, argv);
+
+ ManualTest::ThemeSelector::setTheme(":/themes/flat.creatortheme");
+
+ auto view = new TraceView;
+ view->resize(700, 300);
+ view->show();
+
+ return app.exec();
+}
diff --git a/tests/manual/widgets/widgets.qbs b/tests/manual/widgets/widgets.qbs
index fff0c158c0..2d55a7c347 100644
--- a/tests/manual/widgets/widgets.qbs
+++ b/tests/manual/widgets/widgets.qbs
@@ -9,5 +9,6 @@ Project {
"crumblepath/crumblepath.qbs",
"infolabel/infolabel.qbs",
"manhattanstyle/manhattanstyle.qbs",
+ "tracing/tracing.qbs",
]
}
diff --git a/tests/unit/mockup/coreplugin/icore.h b/tests/unit/mockup/coreplugin/icore.h
index 8cf88f7037..239085d56d 100644
--- a/tests/unit/mockup/coreplugin/icore.h
+++ b/tests/unit/mockup/coreplugin/icore.h
@@ -1,20 +1,23 @@
+#include "utils/fileutils.h"
+
#include <QDir>
+
namespace Core {
namespace ICore {
-inline static QString userResourcePath()
+inline static Utils::FilePath userResourcePath()
{
- return QDir::tempPath();
+ return Utils::FilePath::fromString(QDir::tempPath());
}
-inline static QString cacheResourcePath()
+inline static Utils::FilePath cacheResourcePath(const QString & /*rel*/ = {})
{
- return QDir::tempPath();
+ return Utils::FilePath::fromString(QDir::tempPath());
}
-inline static QString resourcePath()
+inline static Utils::FilePath resourcePath()
{
- return QDir::tempPath();
+ return Utils::FilePath::fromString(QDir::tempPath());
}
} // namespace ICore
diff --git a/tests/unit/mockup/qmldesigner/designercore/include/nodeinstanceview.h b/tests/unit/mockup/qmldesigner/designercore/include/nodeinstanceview.h
index 50dcf529b6..2cdcc0ac21 100644
--- a/tests/unit/mockup/qmldesigner/designercore/include/nodeinstanceview.h
+++ b/tests/unit/mockup/qmldesigner/designercore/include/nodeinstanceview.h
@@ -67,10 +67,7 @@ public:
{}
void nodeIdChanged(const ModelNode &node, const QString &newId, const QString &oldId) override
{}
- void nodeOrderChanged(const NodeListProperty &listProperty,
- const ModelNode &movedNode,
- int oldIndex) override
- {}
+ void nodeOrderChanged(const NodeListProperty &listProperty) override {}
void rootNodeTypeChanged(const QString &type, int majorVersion, int minorVersion) override {}
void nodeTypeChanged(const ModelNode &node,
const TypeName &type,
diff --git a/tests/unit/mockup/qmldesigner/designercore/include/rewriterview.h b/tests/unit/mockup/qmldesigner/designercore/include/rewriterview.h
index 87be6d8006..c055f7d252 100644
--- a/tests/unit/mockup/qmldesigner/designercore/include/rewriterview.h
+++ b/tests/unit/mockup/qmldesigner/designercore/include/rewriterview.h
@@ -87,7 +87,7 @@ public:
AbstractView::PropertyChangeFlags) override
{}
void nodeIdChanged(const ModelNode &, const QString &, const QString &) override {}
- void nodeOrderChanged(const NodeListProperty &, const ModelNode &, int) override {}
+ void nodeOrderChanged(const NodeListProperty &) override {}
void rootNodeTypeChanged(const QString &, int, int) override {}
void nodeTypeChanged(const ModelNode &, const TypeName &, int, int) override {}
void customNotification(const AbstractView *,
diff --git a/tests/unit/unittest/CMakeLists.txt b/tests/unit/unittest/CMakeLists.txt
index 0fdb966d3b..49050ae2f3 100644
--- a/tests/unit/unittest/CMakeLists.txt
+++ b/tests/unit/unittest/CMakeLists.txt
@@ -36,6 +36,7 @@ add_qtc_test(unittest GTEST
ECHOSERVER="$<TARGET_FILE_DIR:echo>/echo"
CPPTOOLS_JSON="${CMAKE_CURRENT_BINARY_DIR}/CppTools.json"
SOURCES
+ abstractviewmock.h
builddependenciesprovider-test.cpp
builddependenciesstorage-test.cpp
clangindexingsettingsmanager-test.cpp
@@ -123,6 +124,7 @@ add_qtc_test(unittest GTEST
modifiedtimechecker-test.cpp
nativefilepath-test.cpp
nativefilepathview-test.cpp
+ nodelistproperty-test.cpp
pchmanagerclientserverinprocess-test.cpp
pchmanagerclient-test.cpp
pchmanagerserver-test.cpp
diff --git a/src/plugins/autotest/catch/catchtestsettingspage.h b/tests/unit/unittest/abstractviewmock.h
index b2f9fe7969..d2bdbb79fe 100644
--- a/src/plugins/autotest/catch/catchtestsettingspage.h
+++ b/tests/unit/unittest/abstractviewmock.h
@@ -25,18 +25,12 @@
#pragma once
-#include <coreplugin/dialogs/ioptionspage.h>
+#include <googletest.h>
-namespace Autotest {
-namespace Internal {
+#include <qmldesigner/designercore/include/abstractview.h>
-class CatchTestSettings;
-
-class CatchTestSettingsPage : public Core::IOptionsPage
+class AbstractViewMock : public QmlDesigner::AbstractView
{
public:
- CatchTestSettingsPage(CatchTestSettings *settings, Utils::Id settingsId);
+ MOCK_METHOD(void, nodeOrderChanged, (const QmlDesigner::NodeListProperty &listProperty), (override));
};
-
-} // namespace Internal
-} // namespace Autotest
diff --git a/tests/unit/unittest/clangformat-test.cpp b/tests/unit/unittest/clangformat-test.cpp
index 822f4b76d2..2ce3eba24a 100644
--- a/tests/unit/unittest/clangformat-test.cpp
+++ b/tests/unit/unittest/clangformat-test.cpp
@@ -198,14 +198,7 @@ TEST_F(ClangFormat, IndentLambdaWithReturnType)
"}"));
}
-#ifndef KEEP_LINE_BREAKS_FOR_NON_EMPTY_LINES_BACKPORTED
-# define DISABLED_FOR_VANILLA_CLANG(x) DISABLED_##x
-#else
-# define DISABLED_FOR_VANILLA_CLANG(x) x
-#endif
-
-// This test requires the custom clang patch https://code.qt.io/cgit/clang/llvm-project.git/commit/?h=release_100-based&id=9b992a0f7f160dd6c75f20a4dcfcf7c60a4894df
-TEST_F(ClangFormat, DISABLED_FOR_VANILLA_CLANG(IndentFunctionArgumentLambdaWithNextLineScope))
+TEST_F(ClangFormat, ClangFormatIndentFunctionArgumentLambdaWithNextLineScope)
{
insertLines({"foo([]()",
"{",
@@ -954,6 +947,16 @@ TEST_F(ClangFormat, SortIncludes)
"#include <aa.h>",
"#include <bb.h>"));
}
+
+TEST_F(ClangFormat, ChainedMemberFunctionCalls)
+{
+ insertLines({"S().func().func()",
+ ".func();"});
+ indenter.indent(cursor, QChar::Null, TextEditor::TabSettings());
+ ASSERT_THAT(documentLines(), ElementsAre("S().func().func()",
+ " .func();"));
+}
+
// clang-format on
} // namespace
diff --git a/tests/unit/unittest/data/highlightingmarks.cpp b/tests/unit/unittest/data/highlightingmarks.cpp
index 79bca7d40d..7631534d35 100644
--- a/tests/unit/unittest/data/highlightingmarks.cpp
+++ b/tests/unit/unittest/data/highlightingmarks.cpp
@@ -789,6 +789,8 @@ static inline constexpr vecn<T, S> operator<(vecn<T, S> a, vecn<T, S> b)
return x;
}
+const char *cyrillic = "б";
+
struct foo {
#define blubb
};
diff --git a/tests/unit/unittest/gtest-creator-printing.cpp b/tests/unit/unittest/gtest-creator-printing.cpp
index 7f9d0030d9..bbe9e64b17 100644
--- a/tests/unit/unittest/gtest-creator-printing.cpp
+++ b/tests/unit/unittest/gtest-creator-printing.cpp
@@ -189,8 +189,8 @@ std::ostream &operator<<(std::ostream &out, const LineColumn &lineColumn)
std::ostream &operator<<(std::ostream &out, const Link &link)
{
- return out << "(" << link.targetFileName << ", " << link.targetLine << ", " << link.targetColumn
- << ", " << link.linkTextStart << ", " << link.linkTextEnd << ")";
+ return out << "(" << link.targetFilePath.toString() << ", " << link.targetLine << ", "
+ << link.targetColumn << ", " << link.linkTextStart << ", " << link.linkTextEnd << ")";
}
const char * toText(Utils::Language language)
@@ -835,6 +835,7 @@ static const char *highlightingTypeToCStringLiteral(HighlightingType type)
RETURN_TEXT_FOR_CASE(VirtualFunction);
RETURN_TEXT_FOR_CASE(Type);
RETURN_TEXT_FOR_CASE(LocalVariable);
+ RETURN_TEXT_FOR_CASE(Parameter);
RETURN_TEXT_FOR_CASE(GlobalVariable);
RETURN_TEXT_FOR_CASE(Field);
RETURN_TEXT_FOR_CASE(Enumeration);
diff --git a/tests/unit/unittest/gtest-creator-printing.h b/tests/unit/unittest/gtest-creator-printing.h
index 9bc90c75a6..28329c3a2a 100644
--- a/tests/unit/unittest/gtest-creator-printing.h
+++ b/tests/unit/unittest/gtest-creator-printing.h
@@ -110,7 +110,7 @@ std::ostream &operator<<(std::ostream &out, const HeaderPath &headerPath);
namespace Utils {
class LineColumn;
class SmallStringView;
-struct Link;
+class Link;
std::ostream &operator<<(std::ostream &out, const LineColumn &lineColumn);
std::ostream &operator<<(std::ostream &out, const Utils::Language &language);
diff --git a/tests/unit/unittest/mocksqlitestatement.h b/tests/unit/unittest/mocksqlitestatement.h
index ff556a9a4d..1f0da729d2 100644
--- a/tests/unit/unittest/mocksqlitestatement.h
+++ b/tests/unit/unittest/mocksqlitestatement.h
@@ -25,7 +25,8 @@
#pragma once
-#include <googletest.h>
+#include "googletest.h"
+#include "sqlitedatabasemock.h"
#include <sqlitebasestatement.h>
@@ -33,7 +34,12 @@
class BaseMockSqliteStatement
{
public:
- MOCK_METHOD0(next, bool ());
+ BaseMockSqliteStatement() = default;
+ BaseMockSqliteStatement(SqliteDatabaseMock &databaseMock)
+ : m_databaseMock{&databaseMock}
+ {}
+
+ MOCK_METHOD0(next, bool());
MOCK_METHOD0(step, void ());
MOCK_METHOD0(reset, void ());
@@ -60,6 +66,11 @@ public:
MOCK_METHOD1(checkColumnCount, void(int));
MOCK_CONST_METHOD0(isReadOnlyStatement, bool());
+
+ SqliteDatabaseMock &database() { return *m_databaseMock; }
+
+private:
+ SqliteDatabaseMock *m_databaseMock = nullptr;
};
template<>
@@ -102,8 +113,13 @@ template<int ResultCount = 1>
class MockSqliteStatement
: public Sqlite::StatementImplementation<NiceMock<BaseMockSqliteStatement>, ResultCount>
{
+ using Base = Sqlite::StatementImplementation<NiceMock<BaseMockSqliteStatement>, ResultCount>;
+
public:
explicit MockSqliteStatement() {}
+ explicit MockSqliteStatement(SqliteDatabaseMock &databaseMock)
+ : Base{databaseMock}
+ {}
protected:
void checkIsWritableStatement();
diff --git a/tests/unit/unittest/nodelistproperty-test.cpp b/tests/unit/unittest/nodelistproperty-test.cpp
new file mode 100644
index 0000000000..5d053388dc
--- /dev/null
+++ b/tests/unit/unittest/nodelistproperty-test.cpp
@@ -0,0 +1,520 @@
+/****************************************************************************
+**
+** Copyright (C) 2021 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of Qt Creator.
+**
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3 as published by the Free Software
+** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-3.0.html.
+**
+****************************************************************************/
+
+#include "abstractviewmock.h"
+#include "googletest.h"
+
+#include <model.h>
+#include <modelnode.h>
+#include <nodelistproperty.h>
+
+namespace {
+
+using QmlDesigner::ModelNode;
+
+class NodeListProperty : public testing::Test
+{
+protected:
+ using iterator = QmlDesigner::NodeListProperty::iterator;
+ NodeListProperty()
+ {
+ model->attachView(&abstractViewMock);
+ nodeListProperty = abstractViewMock.rootModelNode().nodeListProperty("foo");
+
+ node1 = abstractViewMock.createModelNode("QtQick.Item1", -1, -1);
+ node2 = abstractViewMock.createModelNode("QtQick.Item2", -1, -1);
+ node3 = abstractViewMock.createModelNode("QtQick.Item3", -1, -1);
+ node4 = abstractViewMock.createModelNode("QtQick.Item4", -1, -1);
+ node5 = abstractViewMock.createModelNode("QtQick.Item5", -1, -1);
+
+ nodeListProperty.reparentHere(node1);
+ nodeListProperty.reparentHere(node2);
+ nodeListProperty.reparentHere(node3);
+ nodeListProperty.reparentHere(node4);
+ nodeListProperty.reparentHere(node5);
+ }
+
+ ~NodeListProperty() { model->detachView(&abstractViewMock); }
+
+ std::vector<ModelNode> nodes() const
+ {
+ return std::vector<ModelNode>{nodeListProperty.begin(), nodeListProperty.end()};
+ }
+
+ static std::vector<ModelNode> nodes(iterator begin, iterator end)
+ {
+ return std::vector<ModelNode>{begin, end};
+ }
+
+protected:
+ std::unique_ptr<QmlDesigner::Model> model{QmlDesigner::Model::create("QtQuick.Item")};
+ NiceMock<AbstractViewMock> abstractViewMock;
+ QmlDesigner::NodeListProperty nodeListProperty;
+ ModelNode node1;
+ ModelNode node2;
+ ModelNode node3;
+ ModelNode node4;
+ ModelNode node5;
+};
+
+TEST_F(NodeListProperty, BeginAndEndItertors)
+{
+ std::vector<ModelNode> nodes{nodeListProperty.begin(), nodeListProperty.end()};
+
+ ASSERT_THAT(nodes, ElementsAre(node1, node2, node3, node4, node5));
+}
+
+TEST_F(NodeListProperty, LoopOverRange)
+{
+ std::vector<ModelNode> nodes;
+
+ for (const ModelNode &node : nodeListProperty)
+ nodes.push_back(node);
+
+ ASSERT_THAT(nodes, ElementsAre(node1, node2, node3, node4, node5));
+}
+
+TEST_F(NodeListProperty, NextIterator)
+{
+ auto begin = nodeListProperty.begin();
+
+ auto nextIterator = std::next(begin);
+
+ ASSERT_THAT(nodes(nextIterator, nodeListProperty.end()), ElementsAre(node2, node3, node4, node5));
+}
+
+TEST_F(NodeListProperty, PreviousIterator)
+{
+ auto end = nodeListProperty.end();
+
+ auto previousIterator = std::prev(end);
+
+ ASSERT_THAT(nodes(nodeListProperty.begin(), previousIterator),
+ ElementsAre(node1, node2, node3, node4));
+}
+
+TEST_F(NodeListProperty, IncrementIterator)
+{
+ auto incrementIterator = nodeListProperty.begin();
+
+ ++incrementIterator;
+
+ ASSERT_THAT(nodes(incrementIterator, nodeListProperty.end()),
+ ElementsAre(node2, node3, node4, node5));
+}
+
+TEST_F(NodeListProperty, IncrementIteratorReturnsIterator)
+{
+ auto begin = nodeListProperty.begin();
+
+ auto incrementIterator = ++begin;
+
+ ASSERT_THAT(nodes(incrementIterator, nodeListProperty.end()),
+ ElementsAre(node2, node3, node4, node5));
+}
+
+TEST_F(NodeListProperty, PostIncrementIterator)
+{
+ auto postIncrementIterator = nodeListProperty.begin();
+
+ postIncrementIterator++;
+
+ ASSERT_THAT(nodes(postIncrementIterator, nodeListProperty.end()),
+ ElementsAre(node2, node3, node4, node5));
+}
+
+TEST_F(NodeListProperty, PostIncrementIteratorReturnsPreincrementIterator)
+{
+ auto begin = nodeListProperty.begin();
+
+ auto postIncrementIterator = begin++;
+
+ ASSERT_THAT(nodes(postIncrementIterator, nodeListProperty.end()),
+ ElementsAre(node1, node2, node3, node4, node5));
+}
+
+TEST_F(NodeListProperty, DecrementIterator)
+{
+ auto decrementIterator = nodeListProperty.end();
+
+ --decrementIterator;
+
+ ASSERT_THAT(nodes(nodeListProperty.begin(), decrementIterator),
+ ElementsAre(node1, node2, node3, node4));
+}
+
+TEST_F(NodeListProperty, DerementIteratorReturnsIterator)
+{
+ auto end = nodeListProperty.end();
+
+ auto decrementIterator = --end;
+
+ ASSERT_THAT(nodes(nodeListProperty.begin(), decrementIterator),
+ ElementsAre(node1, node2, node3, node4));
+}
+
+TEST_F(NodeListProperty, PostDecrementIterator)
+{
+ auto postDecrementIterator = nodeListProperty.end();
+
+ postDecrementIterator--;
+
+ ASSERT_THAT(nodes(nodeListProperty.begin(), postDecrementIterator),
+ ElementsAre(node1, node2, node3, node4));
+}
+
+TEST_F(NodeListProperty, PostDecrementIteratorReturnsPredecrementIterator)
+{
+ auto end = nodeListProperty.end();
+
+ auto postDecrementIterator = end--;
+
+ ASSERT_THAT(nodes(nodeListProperty.begin(), postDecrementIterator),
+ ElementsAre(node1, node2, node3, node4, node5));
+}
+
+TEST_F(NodeListProperty, IncrementIteratorByTwo)
+{
+ auto incrementIterator = nodeListProperty.begin();
+
+ incrementIterator += 2;
+
+ ASSERT_THAT(nodes(incrementIterator, nodeListProperty.end()), ElementsAre(node3, node4, node5));
+}
+
+TEST_F(NodeListProperty, IncrementIteratorByTwoReturnsIterator)
+{
+ auto begin = nodeListProperty.begin();
+
+ auto incrementIterator = begin += 2;
+
+ ASSERT_THAT(nodes(incrementIterator, nodeListProperty.end()), ElementsAre(node3, node4, node5));
+}
+
+TEST_F(NodeListProperty, DecrementIteratorByTwo)
+{
+ auto decrementIterator = nodeListProperty.end();
+
+ decrementIterator -= 2;
+
+ ASSERT_THAT(nodes(nodeListProperty.begin(), decrementIterator), ElementsAre(node1, node2, node3));
+}
+
+TEST_F(NodeListProperty, DecrementIteratorByTwoReturnsIterator)
+{
+ auto end = nodeListProperty.end();
+
+ auto decrementIterator = end -= 2;
+
+ ASSERT_THAT(nodes(nodeListProperty.begin(), decrementIterator), ElementsAre(node1, node2, node3));
+}
+
+TEST_F(NodeListProperty, AccessIterator)
+{
+ auto iterator = std::next(nodeListProperty.begin(), 3);
+
+ auto accessIterator = iterator[2];
+
+ ASSERT_THAT(nodes(accessIterator, nodeListProperty.end()), ElementsAre(node3, node4, node5));
+}
+
+TEST_F(NodeListProperty, AddIteratorByIndexSecondOperand)
+{
+ auto begin = nodeListProperty.begin();
+
+ auto addedIterator = begin + 2;
+
+ ASSERT_THAT(nodes(addedIterator, nodeListProperty.end()), ElementsAre(node3, node4, node5));
+}
+
+TEST_F(NodeListProperty, AddIteratorByIndexFirstOperand)
+{
+ auto begin = nodeListProperty.begin();
+
+ auto addedIterator = 2 + begin;
+
+ ASSERT_THAT(nodes(addedIterator, nodeListProperty.end()), ElementsAre(node3, node4, node5));
+}
+
+TEST_F(NodeListProperty, SubtractIterator)
+{
+ auto end = nodeListProperty.end();
+
+ auto subtractedIterator = end - 3;
+
+ ASSERT_THAT(nodes(subtractedIterator, nodeListProperty.end()), ElementsAre(node3, node4, node5));
+}
+
+TEST_F(NodeListProperty, CompareEqualIteratorAreEqual)
+{
+ auto first = nodeListProperty.begin();
+ auto second = nodeListProperty.begin();
+
+ auto isEqual = first == second;
+
+ ASSERT_TRUE(isEqual);
+}
+
+TEST_F(NodeListProperty, CompareEqualIteratorAreNotEqual)
+{
+ auto first = nodeListProperty.begin();
+ auto second = std::next(nodeListProperty.begin());
+
+ auto isEqual = first == second;
+
+ ASSERT_FALSE(isEqual);
+}
+
+TEST_F(NodeListProperty, CompareUnqualIteratorAreEqual)
+{
+ auto first = nodeListProperty.begin();
+ auto second = nodeListProperty.begin();
+
+ auto isUnequal = first != second;
+
+ ASSERT_FALSE(isUnequal);
+}
+
+TEST_F(NodeListProperty, CompareUnequalIteratorAreNotEqual)
+{
+ auto first = nodeListProperty.begin();
+ auto second = std::next(nodeListProperty.begin());
+
+ auto isUnequal = first != second;
+
+ ASSERT_TRUE(isUnequal);
+}
+
+TEST_F(NodeListProperty, CompareLessIteratorAreNotLessIfEqual)
+{
+ auto first = nodeListProperty.begin();
+ auto second = nodeListProperty.begin();
+
+ auto isLess = first < second;
+
+ ASSERT_FALSE(isLess);
+}
+
+TEST_F(NodeListProperty, CompareLessIteratorAreNotLessIfGreater)
+{
+ auto first = std::next(nodeListProperty.begin());
+ auto second = nodeListProperty.begin();
+
+ auto isLess = first < second;
+
+ ASSERT_FALSE(isLess);
+}
+
+TEST_F(NodeListProperty, CompareLessIteratorAreLessIfLess)
+{
+ auto first = nodeListProperty.begin();
+ auto second = std::next(nodeListProperty.begin());
+
+ auto isLess = first < second;
+
+ ASSERT_TRUE(isLess);
+}
+
+TEST_F(NodeListProperty, CompareLessEqualIteratorAreLessEqualIfEqual)
+{
+ auto first = nodeListProperty.begin();
+ auto second = nodeListProperty.begin();
+
+ auto isLessEqual = first <= second;
+
+ ASSERT_TRUE(isLessEqual);
+}
+
+TEST_F(NodeListProperty, CompareLessEqualIteratorAreNotLessEqualIfGreater)
+{
+ auto first = std::next(nodeListProperty.begin());
+ auto second = nodeListProperty.begin();
+
+ auto isLessEqual = first <= second;
+
+ ASSERT_FALSE(isLessEqual);
+}
+
+TEST_F(NodeListProperty, CompareLessEqualIteratorAreLessEqualIfLess)
+{
+ auto first = nodeListProperty.begin();
+ auto second = std::next(nodeListProperty.begin());
+
+ auto isLessEqual = first <= second;
+
+ ASSERT_TRUE(isLessEqual);
+}
+
+TEST_F(NodeListProperty, CompareGreaterIteratorAreGreaterIfEqual)
+{
+ auto first = nodeListProperty.begin();
+ auto second = nodeListProperty.begin();
+
+ auto isGreater = first > second;
+
+ ASSERT_FALSE(isGreater);
+}
+
+TEST_F(NodeListProperty, CompareGreaterIteratorAreGreaterIfGreater)
+{
+ auto first = std::next(nodeListProperty.begin());
+ auto second = nodeListProperty.begin();
+
+ auto isGreater = first > second;
+
+ ASSERT_TRUE(isGreater);
+}
+
+TEST_F(NodeListProperty, CompareGreaterIteratorAreNotGreaterIfLess)
+{
+ auto first = nodeListProperty.begin();
+ auto second = std::next(nodeListProperty.begin());
+
+ auto isGreater = first > second;
+
+ ASSERT_FALSE(isGreater);
+}
+
+TEST_F(NodeListProperty, CompareGreaterEqualIteratorAreGreaterEqualIfEqual)
+{
+ auto first = nodeListProperty.begin();
+ auto second = nodeListProperty.begin();
+
+ auto isGreaterEqual = first >= second;
+
+ ASSERT_TRUE(isGreaterEqual);
+}
+
+TEST_F(NodeListProperty, CompareGreaterEqualIteratorAreGreaterEqualIfGreater)
+{
+ auto first = std::next(nodeListProperty.begin());
+ auto second = nodeListProperty.begin();
+
+ auto isGreaterEqual = first >= second;
+
+ ASSERT_TRUE(isGreaterEqual);
+}
+
+TEST_F(NodeListProperty, CompareGreaterEqualIteratorAreNotGreaterEqualIfLess)
+{
+ auto first = nodeListProperty.begin();
+ auto second = std::next(nodeListProperty.begin());
+
+ auto isGreaterEqual = first >= second;
+
+ ASSERT_FALSE(isGreaterEqual);
+}
+
+TEST_F(NodeListProperty, DereferenceIterator)
+{
+ auto iterator = std::next(nodeListProperty.begin());
+
+ auto node = *iterator;
+
+ ASSERT_THAT(node, Eq(node2));
+}
+
+TEST_F(NodeListProperty, IterSwap)
+{
+ auto first = std::next(nodeListProperty.begin(), 2);
+ auto second = nodeListProperty.begin();
+
+ nodeListProperty.iterSwap(first, second);
+
+ ASSERT_THAT(nodes(), ElementsAre(node3, node2, node1, node4, node5));
+}
+
+TEST_F(NodeListProperty, Rotate)
+{
+ auto first = std::next(nodeListProperty.begin());
+ auto newFirst = std::next(nodeListProperty.begin(), 2);
+ auto last = std::prev(nodeListProperty.end());
+
+ nodeListProperty.rotate(first, newFirst, last);
+
+ ASSERT_THAT(nodes(), ElementsAre(node1, node3, node4, node2, node5));
+}
+
+TEST_F(NodeListProperty, RotateCallsNodeOrderedChanged)
+{
+ auto first = std::next(nodeListProperty.begin());
+ auto newFirst = std::next(nodeListProperty.begin(), 2);
+ auto last = std::prev(nodeListProperty.end());
+
+ EXPECT_CALL(abstractViewMock, nodeOrderChanged(ElementsAre(node1, node3, node4, node2, node5)));
+
+ nodeListProperty.rotate(first, newFirst, last);
+}
+
+TEST_F(NodeListProperty, RotateRange)
+{
+ auto newFirst = std::prev(nodeListProperty.end(), 2);
+
+ nodeListProperty.rotate(nodeListProperty, newFirst);
+
+ ASSERT_THAT(nodes(), ElementsAre(node4, node5, node1, node2, node3));
+}
+
+TEST_F(NodeListProperty, RotateReturnsIterator)
+{
+ auto first = std::next(nodeListProperty.begin());
+ auto newFirst = std::next(nodeListProperty.begin(), 2);
+ auto last = std::prev(nodeListProperty.end());
+
+ auto iterator = nodeListProperty.rotate(first, newFirst, last);
+
+ ASSERT_THAT(iterator, Eq(first + (last - newFirst)));
+}
+
+TEST_F(NodeListProperty, RotateRangeReturnsIterator)
+{
+ auto newFirst = std::prev(nodeListProperty.end(), 2);
+
+ auto iterator = nodeListProperty.rotate(nodeListProperty, newFirst);
+
+ ASSERT_THAT(iterator, Eq(nodeListProperty.begin() + (nodeListProperty.end() - newFirst)));
+}
+
+TEST_F(NodeListProperty, Reverse)
+{
+ auto first = std::next(nodeListProperty.begin());
+ auto last = std::prev(nodeListProperty.end());
+
+ nodeListProperty.reverse(first, last);
+
+ ASSERT_THAT(nodes(), ElementsAre(node1, node4, node3, node2, node5));
+}
+
+TEST_F(NodeListProperty, ReverseCallsNodeOrderedChanged)
+{
+ auto first = std::next(nodeListProperty.begin());
+ auto last = std::prev(nodeListProperty.end());
+
+ EXPECT_CALL(abstractViewMock, nodeOrderChanged(ElementsAre(node1, node4, node3, node2, node5)));
+
+ nodeListProperty.reverse(first, last);
+}
+
+} // namespace
diff --git a/tests/unit/unittest/readexporteddiagnostics-test.cpp b/tests/unit/unittest/readexporteddiagnostics-test.cpp
index a3bdef3a6f..c4fe4572ae 100644
--- a/tests/unit/unittest/readexporteddiagnostics-test.cpp
+++ b/tests/unit/unittest/readexporteddiagnostics-test.cpp
@@ -52,11 +52,13 @@ protected:
const QString newFileName = temporaryDir.filePath(QFileInfo(yamlFilePath).fileName());
Utils::FileReader reader;
- if (QTC_GUARD(reader.fetch(yamlFilePath, QIODevice::ReadOnly | QIODevice::Text))) {
+ if (QTC_GUARD(reader.fetch(Utils::FilePath::fromString(yamlFilePath),
+ QIODevice::ReadOnly | QIODevice::Text))) {
QByteArray contents = reader.data();
contents.replace("FILE_PATH", filePathToInject.toLocal8Bit());
- Utils::FileSaver fileSaver(newFileName, QIODevice::WriteOnly | QIODevice::Text);
+ Utils::FileSaver fileSaver(Utils::FilePath::fromString(newFileName),
+ QIODevice::WriteOnly | QIODevice::Text);
QTC_CHECK(fileSaver.write(contents));
QTC_CHECK(fileSaver.finalize());
}
diff --git a/tests/unit/unittest/refactoringengine-test.cpp b/tests/unit/unittest/refactoringengine-test.cpp
index 0648cca8e0..37cfde0d76 100644
--- a/tests/unit/unittest/refactoringengine-test.cpp
+++ b/tests/unit/unittest/refactoringengine-test.cpp
@@ -155,7 +155,7 @@ TEST_F(RefactoringEngine, InGlobalFollowSymbol)
ON_CALL(mockSymbolQuery, declarationsAt(Eq(12), 2, 5)).WillByDefault(Return(usages));
EXPECT_CALL(mockCallback,
- Call(AllOf(Field(&Link::targetFileName, Eq("/path1")),
+ Call(AllOf(Field(&Link::targetFilePath, Eq(Utils::FilePath::fromString("/path1"))),
Field(&Link::targetLine, Eq(1)),
Field(&Link::targetColumn, Eq(2)))));
@@ -171,7 +171,7 @@ TEST_F(RefactoringEngine, InGlobalFollowSymbolSkipCurrentFile)
ON_CALL(mockSymbolQuery, declarationsAt(Eq(12), 2, 5)).WillByDefault(Return(usages));
EXPECT_CALL(mockCallback,
- Call(AllOf(Field(&Link::targetFileName, Eq("/path2")),
+ Call(AllOf(Field(&Link::targetFilePath, Eq(Utils::FilePath::fromString("/path2"))),
Field(&Link::targetLine, Eq(4)),
Field(&Link::targetColumn, Eq(4)))));
diff --git a/tests/unit/unittest/sqlitedatabasemock.h b/tests/unit/unittest/sqlitedatabasemock.h
index d65dd3f0fa..28c373f4c4 100644
--- a/tests/unit/unittest/sqlitedatabasemock.h
+++ b/tests/unit/unittest/sqlitedatabasemock.h
@@ -70,4 +70,3 @@ public:
MOCK_METHOD(void, setAttachedTables, (const Utils::SmallStringVector &tables), (override));
};
-
diff --git a/tests/unit/unittest/sqlitestatement-test.cpp b/tests/unit/unittest/sqlitestatement-test.cpp
index c526cc3d4b..10e5c609ae 100644
--- a/tests/unit/unittest/sqlitestatement-test.cpp
+++ b/tests/unit/unittest/sqlitestatement-test.cpp
@@ -25,6 +25,7 @@
#include "googletest.h"
#include "mocksqlitestatement.h"
+#include "sqlitedatabasemock.h"
#include "sqliteteststatement.h"
#include <sqliteblob.h>
@@ -38,6 +39,7 @@
#include <QDir>
#include <deque>
+#include <type_traits>
#include <vector>
namespace {
@@ -50,6 +52,21 @@ using Sqlite::ReadWriteStatement;
using Sqlite::Value;
using Sqlite::WriteStatement;
+template<typename Type>
+bool compareValue(SqliteTestStatement &statement, Type value, int column)
+{
+ if constexpr (std::is_convertible_v<Type, long long> && !std::is_same_v<Type, double>)
+ return statement.fetchLongLongValue(column) == value;
+ else if constexpr (std::is_convertible_v<Type, double>)
+ return statement.fetchDoubleValue(column) == value;
+ else if constexpr (std::is_convertible_v<Type, Utils::SmallStringView>)
+ return statement.fetchSmallStringViewValue(column) == value;
+ else if constexpr (std::is_convertible_v<Type, Sqlite::BlobView>)
+ return statement.fetchBlobValue(column) == value;
+
+ return false;
+}
+
MATCHER_P3(HasValues, value1, value2, rowid,
std::string(negation ? "isn't" : "is")
+ PrintToString(value1)
@@ -64,8 +81,7 @@ MATCHER_P3(HasValues, value1, value2, rowid,
statement.next();
- return statement.fetchSmallStringViewValue(0) == value1
- && statement.fetchSmallStringViewValue(1) == value2;
+ return compareValue(statement, value1, 0) && compareValue(statement, value2, 1);
}
MATCHER_P(HasNullValues, rowid, std::string(negation ? "isn't null" : "is null"))
@@ -490,13 +506,98 @@ TEST_F(SqliteStatement, WriteNullValues)
ASSERT_THAT(statement, HasNullValues(1));
}
-TEST_F(SqliteStatement, WriteSqliteValues)
+TEST_F(SqliteStatement, WriteSqliteIntegerValue)
{
WriteStatement statement("UPDATE test SET name=?, number=? WHERE rowid=?", database);
+ statement.write(1, 1, 1);
- statement.write(Value{"see"}, Value{7.23}, Value{1});
+ statement.write("see", Sqlite::Value{33}, 1);
- ASSERT_THAT(statement, HasValues("see", "7.23", 1));
+ ASSERT_THAT(statement, HasValues("see", 33, 1));
+}
+
+TEST_F(SqliteStatement, WriteSqliteDoubeValue)
+{
+ WriteStatement statement("UPDATE test SET name=?, number=? WHERE rowid=?", database);
+
+ statement.write("see", Value{7.23}, Value{1});
+
+ ASSERT_THAT(statement, HasValues("see", 7.23, 1));
+}
+
+TEST_F(SqliteStatement, WriteSqliteStringValue)
+{
+ WriteStatement statement("UPDATE test SET name=?, number=? WHERE rowid=?", database);
+
+ statement.write("see", Value{"foo"}, Value{1});
+
+ ASSERT_THAT(statement, HasValues("see", "foo", 1));
+}
+
+TEST_F(SqliteStatement, WriteSqliteBlobValue)
+{
+ SqliteTestStatement statement("INSERT INTO test VALUES ('blob', 40, ?)", database);
+ SqliteTestStatement readStatement("SELECT value FROM test WHERE name = 'blob'", database);
+ const unsigned char chars[] = "aaafdfdlll";
+ auto bytePointer = reinterpret_cast<const std::byte *>(chars);
+ Sqlite::BlobView bytes{bytePointer, sizeof(chars) - 1};
+
+ statement.write(Sqlite::Value{bytes});
+
+ ASSERT_THAT(readStatement.template value<Sqlite::Blob>(),
+ Optional(Field(&Sqlite::Blob::bytes, Eq(bytes))));
+}
+
+TEST_F(SqliteStatement, WriteNullValueView)
+{
+ WriteStatement statement("UPDATE test SET name=?, number=? WHERE rowid=?", database);
+ statement.write(1, 1, 1);
+
+ statement.write(Sqlite::NullValue{}, Sqlite::ValueView::create(Sqlite::NullValue{}), 1);
+
+ ASSERT_THAT(statement, HasNullValues(1));
+}
+
+TEST_F(SqliteStatement, WriteSqliteIntegerValueView)
+{
+ WriteStatement statement("UPDATE test SET name=?, number=? WHERE rowid=?", database);
+ statement.write(1, 1, 1);
+
+ statement.write("see", Sqlite::ValueView::create(33), 1);
+
+ ASSERT_THAT(statement, HasValues("see", 33, 1));
+}
+
+TEST_F(SqliteStatement, WriteSqliteDoubeValueView)
+{
+ WriteStatement statement("UPDATE test SET name=?, number=? WHERE rowid=?", database);
+
+ statement.write("see", Sqlite::ValueView::create(7.23), 1);
+
+ ASSERT_THAT(statement, HasValues("see", 7.23, 1));
+}
+
+TEST_F(SqliteStatement, WriteSqliteStringValueView)
+{
+ WriteStatement statement("UPDATE test SET name=?, number=? WHERE rowid=?", database);
+
+ statement.write("see", Sqlite::ValueView::create("foo"), 1);
+
+ ASSERT_THAT(statement, HasValues("see", "foo", 1));
+}
+
+TEST_F(SqliteStatement, WriteSqliteBlobValueView)
+{
+ SqliteTestStatement statement("INSERT INTO test VALUES ('blob', 40, ?)", database);
+ SqliteTestStatement readStatement("SELECT value FROM test WHERE name = 'blob'", database);
+ const unsigned char chars[] = "aaafdfdlll";
+ auto bytePointer = reinterpret_cast<const std::byte *>(chars);
+ Sqlite::BlobView bytes{bytePointer, sizeof(chars) - 1};
+
+ statement.write(Sqlite::ValueView::create(bytes));
+
+ ASSERT_THAT(readStatement.template value<Sqlite::Blob>(),
+ Optional(Field(&Sqlite::Blob::bytes, Eq(bytes))));
}
TEST_F(SqliteStatement, WriteEmptyBlobs)
@@ -562,6 +663,116 @@ TEST_F(SqliteStatement, GetTupleValuesWithoutArguments)
UnorderedElementsAre(Tuple{"bar", 0, 1}, Tuple{"foo", 23.3, 2}, Tuple{"poo", 40.0, 3}));
}
+TEST_F(SqliteStatement, GetTupleRangeWithoutArguments)
+{
+ using Tuple = std::tuple<Utils::SmallString, double, int>;
+ ReadStatement<3> statement("SELECT name, number, value FROM test", database);
+
+ auto range = statement.range<Tuple>();
+ std::vector<Tuple> values{range.begin(), range.end()};
+
+ ASSERT_THAT(values,
+ UnorderedElementsAre(Tuple{"bar", 0, 1}, Tuple{"foo", 23.3, 2}, Tuple{"poo", 40.0, 3}));
+}
+
+TEST_F(SqliteStatement, GetTupleRangeWithTransactionWithoutArguments)
+{
+ using Tuple = std::tuple<Utils::SmallString, double, int>;
+ ReadStatement<3> statement("SELECT name, number, value FROM test", database);
+
+ auto range = statement.rangeWithTransaction<Tuple>();
+ std::vector<Tuple> values{range.begin(), range.end()};
+
+ ASSERT_THAT(values,
+ UnorderedElementsAre(Tuple{"bar", 0, 1}, Tuple{"foo", 23.3, 2}, Tuple{"poo", 40.0, 3}));
+}
+
+TEST_F(SqliteStatement, GetTupleRangeInForRangeLoop)
+{
+ using Tuple = std::tuple<Utils::SmallString, double, int>;
+ ReadStatement<3> statement("SELECT name, number, value FROM test", database);
+ std::vector<Tuple> values;
+
+ for (auto value : statement.range<Tuple>())
+ values.push_back(value);
+
+ ASSERT_THAT(values,
+ UnorderedElementsAre(Tuple{"bar", 0, 1}, Tuple{"foo", 23.3, 2}, Tuple{"poo", 40.0, 3}));
+}
+
+TEST_F(SqliteStatement, GetTupleRangeWithTransactionInForRangeLoop)
+{
+ using Tuple = std::tuple<Utils::SmallString, double, int>;
+ ReadStatement<3> statement("SELECT name, number, value FROM test", database);
+ std::vector<Tuple> values;
+
+ for (auto value : statement.rangeWithTransaction<Tuple>())
+ values.push_back(value);
+
+ ASSERT_THAT(values,
+ UnorderedElementsAre(Tuple{"bar", 0, 1}, Tuple{"foo", 23.3, 2}, Tuple{"poo", 40.0, 3}));
+}
+
+TEST_F(SqliteStatement, GetTupleRangeInForRangeLoopWithBreak)
+{
+ using Tuple = std::tuple<Utils::SmallString, double, int>;
+ ReadStatement<3> statement("SELECT name, number, value FROM test ORDER BY name", database);
+ std::vector<Tuple> values;
+
+ for (auto value : statement.range<Tuple>()) {
+ values.push_back(value);
+ if (value == Tuple{"foo", 23.3, 2})
+ break;
+ }
+
+ ASSERT_THAT(values, UnorderedElementsAre(Tuple{"bar", 0, 1}, Tuple{"foo", 23.3, 2}));
+}
+
+TEST_F(SqliteStatement, GetTupleRangeWithTransactionInForRangeLoopWithBreak)
+{
+ using Tuple = std::tuple<Utils::SmallString, double, int>;
+ ReadStatement<3> statement("SELECT name, number, value FROM test ORDER BY name", database);
+ std::vector<Tuple> values;
+
+ for (auto value : statement.rangeWithTransaction<Tuple>()) {
+ values.push_back(value);
+ if (value == Tuple{"foo", 23.3, 2})
+ break;
+ }
+
+ ASSERT_THAT(values, UnorderedElementsAre(Tuple{"bar", 0, 1}, Tuple{"foo", 23.3, 2}));
+}
+
+TEST_F(SqliteStatement, GetTupleRangeInForRangeLoopWithContinue)
+{
+ using Tuple = std::tuple<Utils::SmallString, double, int>;
+ ReadStatement<3> statement("SELECT name, number, value FROM test ORDER BY name", database);
+ std::vector<Tuple> values;
+
+ for (auto value : statement.range<Tuple>()) {
+ if (value == Tuple{"foo", 23.3, 2})
+ continue;
+ values.push_back(value);
+ }
+
+ ASSERT_THAT(values, UnorderedElementsAre(Tuple{"bar", 0, 1}, Tuple{"poo", 40.0, 3}));
+}
+
+TEST_F(SqliteStatement, GetTupleRangeWithTransactionInForRangeLoopWithContinue)
+{
+ using Tuple = std::tuple<Utils::SmallString, double, int>;
+ ReadStatement<3> statement("SELECT name, number, value FROM test ORDER BY name", database);
+ std::vector<Tuple> values;
+
+ for (auto value : statement.rangeWithTransaction<Tuple>()) {
+ if (value == Tuple{"foo", 23.3, 2})
+ continue;
+ values.push_back(value);
+ }
+
+ ASSERT_THAT(values, UnorderedElementsAre(Tuple{"bar", 0, 1}, Tuple{"poo", 40.0, 3}));
+}
+
TEST_F(SqliteStatement, GetSingleValuesWithoutArguments)
{
ReadStatement<1> statement("SELECT name FROM test", database);
@@ -571,6 +782,26 @@ TEST_F(SqliteStatement, GetSingleValuesWithoutArguments)
ASSERT_THAT(values, UnorderedElementsAre("bar", "foo", "poo"));
}
+TEST_F(SqliteStatement, GetSingleRangeWithoutArguments)
+{
+ ReadStatement<1> statement("SELECT name FROM test", database);
+
+ auto range = statement.range<Utils::SmallStringView>();
+ std::vector<Utils::SmallString> values{range.begin(), range.end()};
+
+ ASSERT_THAT(values, UnorderedElementsAre("bar", "foo", "poo"));
+}
+
+TEST_F(SqliteStatement, GetSingleRangeWithTransactionWithoutArguments)
+{
+ ReadStatement<1> statement("SELECT name FROM test", database);
+
+ auto range = statement.rangeWithTransaction<Utils::SmallStringView>();
+ std::vector<Utils::SmallString> values{range.begin(), range.end()};
+
+ ASSERT_THAT(values, UnorderedElementsAre("bar", "foo", "poo"));
+}
+
class FooValue
{
public:
@@ -597,6 +828,28 @@ TEST_F(SqliteStatement, GetSingleSqliteValuesWithoutArguments)
ASSERT_THAT(values, UnorderedElementsAre(Eq("blah"), Eq(23.3), Eq(40), IsNull()));
}
+TEST_F(SqliteStatement, GetSingleSqliteRangeWithoutArguments)
+{
+ ReadStatement<1> statement("SELECT number FROM test", database);
+ database.execute("INSERT INTO test VALUES (NULL, NULL, NULL)");
+
+ auto range = statement.range<FooValue>();
+ std::vector<FooValue> values{range.begin(), range.end()};
+
+ ASSERT_THAT(values, UnorderedElementsAre(Eq("blah"), Eq(23.3), Eq(40), IsNull()));
+}
+
+TEST_F(SqliteStatement, GetSingleSqliteRangeWithTransactionWithoutArguments)
+{
+ ReadStatement<1> statement("SELECT number FROM test", database);
+ database.execute("INSERT INTO test VALUES (NULL, NULL, NULL)");
+
+ auto range = statement.rangeWithTransaction<FooValue>();
+ std::vector<FooValue> values{range.begin(), range.end()};
+
+ ASSERT_THAT(values, UnorderedElementsAre(Eq("blah"), Eq(23.3), Eq(40), IsNull()));
+}
+
TEST_F(SqliteStatement, GetStructValuesWithoutArguments)
{
ReadStatement<3> statement("SELECT name, number, value FROM test", database);
@@ -609,6 +862,32 @@ TEST_F(SqliteStatement, GetStructValuesWithoutArguments)
Output{"poo", "40", 3}));
}
+TEST_F(SqliteStatement, GetStructRangeWithoutArguments)
+{
+ ReadStatement<3> statement("SELECT name, number, value FROM test", database);
+
+ auto range = statement.range<Output>();
+ std::vector<Output> values{range.begin(), range.end()};
+
+ ASSERT_THAT(values,
+ UnorderedElementsAre(Output{"bar", "blah", 1},
+ Output{"foo", "23.3", 2},
+ Output{"poo", "40", 3}));
+}
+
+TEST_F(SqliteStatement, GetStructRangeWithTransactionWithoutArguments)
+{
+ ReadStatement<3> statement("SELECT name, number, value FROM test", database);
+
+ auto range = statement.rangeWithTransaction<Output>();
+ std::vector<Output> values{range.begin(), range.end()};
+
+ ASSERT_THAT(values,
+ UnorderedElementsAre(Output{"bar", "blah", 1},
+ Output{"foo", "23.3", 2},
+ Output{"poo", "40", 3}));
+}
+
TEST_F(SqliteStatement, GetValuesForSingleOutputWithBindingMultipleTimes)
{
ReadStatement<1> statement("SELECT name FROM test WHERE number=?", database);
@@ -619,6 +898,28 @@ TEST_F(SqliteStatement, GetValuesForSingleOutputWithBindingMultipleTimes)
ASSERT_THAT(values, ElementsAre("poo"));
}
+TEST_F(SqliteStatement, GetRangeForSingleOutputWithBindingMultipleTimes)
+{
+ ReadStatement<1> statement("SELECT name FROM test WHERE number=?", database);
+ statement.values<Utils::SmallString>(3, 40);
+
+ auto range = statement.range<Utils::SmallStringView>(40);
+ std::vector<Utils::SmallString> values{range.begin(), range.end()};
+
+ ASSERT_THAT(values, ElementsAre("poo"));
+}
+
+TEST_F(SqliteStatement, GetRangeWithTransactionForSingleOutputWithBindingMultipleTimes)
+{
+ ReadStatement<1> statement("SELECT name FROM test WHERE number=?", database);
+ statement.values<Utils::SmallString>(3, 40);
+
+ auto range = statement.rangeWithTransaction<Utils::SmallStringView>(40);
+ std::vector<Utils::SmallString> values{range.begin(), range.end()};
+
+ ASSERT_THAT(values, ElementsAre("poo"));
+}
+
TEST_F(SqliteStatement, GetValuesForMultipleOutputValuesAndMultipleQueryValue)
{
using Tuple = std::tuple<Utils::SmallString, Utils::SmallString, long long>;
@@ -630,6 +931,30 @@ TEST_F(SqliteStatement, GetValuesForMultipleOutputValuesAndMultipleQueryValue)
ASSERT_THAT(values, ElementsAre(Tuple{"bar", "blah", 1}));
}
+TEST_F(SqliteStatement, GetRangeForMultipleOutputValuesAndMultipleQueryValue)
+{
+ using Tuple = std::tuple<Utils::SmallString, Utils::SmallString, long long>;
+ ReadStatement<3> statement(
+ "SELECT name, number, value FROM test WHERE name=? AND number=? AND value=?", database);
+
+ auto range = statement.range<Tuple>("bar", "blah", 1);
+ std::vector<Tuple> values{range.begin(), range.end()};
+
+ ASSERT_THAT(values, ElementsAre(Tuple{"bar", "blah", 1}));
+}
+
+TEST_F(SqliteStatement, GetRangeWithTransactionForMultipleOutputValuesAndMultipleQueryValue)
+{
+ using Tuple = std::tuple<Utils::SmallString, Utils::SmallString, long long>;
+ ReadStatement<3> statement(
+ "SELECT name, number, value FROM test WHERE name=? AND number=? AND value=?", database);
+
+ auto range = statement.rangeWithTransaction<Tuple>("bar", "blah", 1);
+ std::vector<Tuple> values{range.begin(), range.end()};
+
+ ASSERT_THAT(values, ElementsAre(Tuple{"bar", "blah", 1}));
+}
+
TEST_F(SqliteStatement, CallGetValuesForMultipleOutputValuesAndMultipleQueryValueMultipleTimes)
{
using Tuple = std::tuple<Utils::SmallString, Utils::SmallString, long long>;
@@ -642,6 +967,39 @@ TEST_F(SqliteStatement, CallGetValuesForMultipleOutputValuesAndMultipleQueryValu
ASSERT_THAT(values, ElementsAre(Tuple{"bar", "blah", 1}));
}
+TEST_F(SqliteStatement, CallGetRangeForMultipleOutputValuesAndMultipleQueryValueMultipleTimes)
+{
+ using Tuple = std::tuple<Utils::SmallString, Utils::SmallString, long long>;
+ ReadStatement<3> statement("SELECT name, number, value FROM test WHERE name=? AND number=?",
+ database);
+ {
+ auto range = statement.range<Tuple>("bar", "blah");
+ std::vector<Tuple> values1{range.begin(), range.end()};
+ }
+
+ auto range2 = statement.range<Tuple>("bar", "blah");
+ std::vector<Tuple> values{range2.begin(), range2.end()};
+
+ ASSERT_THAT(values, ElementsAre(Tuple{"bar", "blah", 1}));
+}
+
+TEST_F(SqliteStatement,
+ CallGetRangeWithTransactionForMultipleOutputValuesAndMultipleQueryValueMultipleTimes)
+{
+ using Tuple = std::tuple<Utils::SmallString, Utils::SmallString, long long>;
+ ReadStatement<3> statement("SELECT name, number, value FROM test WHERE name=? AND number=?",
+ database);
+ {
+ auto range = statement.rangeWithTransaction<Tuple>("bar", "blah");
+ std::vector<Tuple> values1{range.begin(), range.end()};
+ }
+
+ auto range2 = statement.rangeWithTransaction<Tuple>("bar", "blah");
+ std::vector<Tuple> values{range2.begin(), range2.end()};
+
+ ASSERT_THAT(values, ElementsAre(Tuple{"bar", "blah", 1}));
+}
+
TEST_F(SqliteStatement, GetStructOutputValuesAndMultipleQueryValue)
{
ReadStatement<3> statement(
@@ -751,6 +1109,30 @@ TEST_F(SqliteStatement, GetValuesWithoutArgumentsCallsReset)
mockStatement.values<int>(3);
}
+TEST_F(SqliteStatement, GetRangeWithoutArgumentsCallsReset)
+{
+ MockSqliteStatement mockStatement;
+
+ EXPECT_CALL(mockStatement, reset());
+
+ mockStatement.range<int>();
+}
+
+TEST_F(SqliteStatement, GetRangeWithTransactionWithoutArgumentsCalls)
+{
+ InSequence s;
+ SqliteDatabaseMock databaseMock;
+ MockSqliteStatement mockStatement{databaseMock};
+
+ EXPECT_CALL(databaseMock, lock());
+ EXPECT_CALL(databaseMock, deferredBegin());
+ EXPECT_CALL(mockStatement, reset());
+ EXPECT_CALL(databaseMock, commit());
+ EXPECT_CALL(databaseMock, unlock());
+
+ mockStatement.rangeWithTransaction<int>();
+}
+
TEST_F(SqliteStatement, GetValuesWithoutArgumentsCallsResetIfExceptionIsThrown)
{
MockSqliteStatement mockStatement;
@@ -761,6 +1143,38 @@ TEST_F(SqliteStatement, GetValuesWithoutArgumentsCallsResetIfExceptionIsThrown)
EXPECT_THROW(mockStatement.values<int>(3), Sqlite::StatementHasError);
}
+TEST_F(SqliteStatement, GetRangeWithoutArgumentsCallsResetIfExceptionIsThrown)
+{
+ MockSqliteStatement mockStatement;
+ ON_CALL(mockStatement, next()).WillByDefault(Throw(Sqlite::StatementHasError("")));
+ auto range = mockStatement.range<int>();
+
+ EXPECT_CALL(mockStatement, reset());
+
+ EXPECT_THROW(range.begin(), Sqlite::StatementHasError);
+}
+
+TEST_F(SqliteStatement, GetRangeWithTransactionWithoutArgumentsCallsResetIfExceptionIsThrown)
+{
+ InSequence s;
+ SqliteDatabaseMock databaseMock;
+ MockSqliteStatement mockStatement{databaseMock};
+ ON_CALL(mockStatement, next()).WillByDefault(Throw(Sqlite::StatementHasError("")));
+
+ EXPECT_CALL(databaseMock, lock());
+ EXPECT_CALL(databaseMock, deferredBegin());
+ EXPECT_CALL(mockStatement, reset());
+ EXPECT_CALL(databaseMock, rollback());
+ EXPECT_CALL(databaseMock, unlock());
+
+ EXPECT_THROW(
+ {
+ auto range = mockStatement.rangeWithTransaction<int>();
+ range.begin();
+ },
+ Sqlite::StatementHasError);
+}
+
TEST_F(SqliteStatement, GetValuesWithSimpleArgumentsCallsReset)
{
MockSqliteStatement mockStatement;
@@ -897,7 +1311,7 @@ TEST_F(SqliteStatement, ReadToContainer)
std::deque<FooValue> values;
ReadStatement<1> statement("SELECT number FROM test", database);
- statement.readTo<1>(values);
+ statement.readTo(values);
ASSERT_THAT(values, UnorderedElementsAre(Eq("blah"), Eq(23.3), Eq(40)));
}
diff --git a/tests/unit/unittest/sqlitevalue-test.cpp b/tests/unit/unittest/sqlitevalue-test.cpp
index 682e8087ab..b36b23e732 100644
--- a/tests/unit/unittest/sqlitevalue-test.cpp
+++ b/tests/unit/unittest/sqlitevalue-test.cpp
@@ -445,7 +445,7 @@ TEST(SqliteValue, BlobValueAndValueViewEquals)
{
Utils::span<const std::byte> bytes{reinterpret_cast<const std::byte *>("abcd"), 4};
- bool isEqual = Sqlite::ValueView::create(bytes) == Sqlite::Value{bytes};
+ bool isEqual = Sqlite::ValueView::create(Sqlite::BlobView{bytes}) == Sqlite::Value{bytes};
ASSERT_TRUE(isEqual);
}
@@ -489,7 +489,7 @@ TEST(SqliteValue, ConvertFloatValueViewIntoValue)
TEST(SqliteValue, ConvertBlobValueViewIntoValue)
{
Utils::span<const std::byte> bytes{reinterpret_cast<const std::byte *>("abcd"), 4};
- auto view = Sqlite::ValueView::create(bytes);
+ auto view = Sqlite::ValueView::create(Sqlite::BlobView{bytes});
Sqlite::Value value{view};
diff --git a/tests/unit/unittest/storagecache-test.cpp b/tests/unit/unittest/storagecache-test.cpp
new file mode 100644
index 0000000000..4ffb5caa8f
--- /dev/null
+++ b/tests/unit/unittest/storagecache-test.cpp
@@ -0,0 +1,521 @@
+/****************************************************************************
+**
+** Copyright (C) 2021 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of Qt Creator.
+**
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3 as published by the Free Software
+** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-3.0.html.
+**
+****************************************************************************/
+
+#include "googletest.h"
+
+#include "mockfilepathstorage.h"
+#include "mockmutex.h"
+#include "sqlitedatabasemock.h"
+
+#include <metainfo/storagecache.h>
+
+#include <utils/smallstringio.h>
+
+namespace {
+
+using QmlDesigner::StorageCacheException;
+
+using uint64 = unsigned long long;
+
+using Utils::compare;
+using Utils::reverseCompare;
+
+class StorageAdapter
+{
+public:
+ auto fetchId(Utils::SmallStringView view) { return storage.fetchDirectoryId(view); }
+
+ auto fetchValue(int id) { return storage.fetchDirectoryPath(id); }
+
+ MockFilePathStorage &storage;
+};
+
+auto less(Utils::SmallStringView first, Utils::SmallStringView second) -> bool
+{
+ return Utils::reverseCompare(first, second) < 0;
+};
+
+using CacheWithMockLocking = QmlDesigner::
+ StorageCache<Utils::PathString, Utils::SmallStringView, int, StorageAdapter, NiceMock<MockMutex>, less>;
+
+using CacheWithoutLocking = QmlDesigner::
+ StorageCache<Utils::PathString, Utils::SmallStringView, int, StorageAdapter, NiceMock<MockMutexNonLocking>, less>;
+
+template<typename Cache>
+class StorageCache : public testing::Test
+{
+protected:
+ void SetUp()
+ {
+ std::sort(filePaths.begin(), filePaths.end(), [](auto &f, auto &l) {
+ return compare(f, l) < 0;
+ });
+ std::sort(reverseFilePaths.begin(), reverseFilePaths.end(), [](auto &f, auto &l) {
+ return reverseCompare(f, l) < 0;
+ });
+
+ ON_CALL(this->mockStorage, fetchDirectoryId(Eq("foo"))).WillByDefault(Return(42));
+ ON_CALL(this->mockStorage, fetchDirectoryId(Eq("bar"))).WillByDefault(Return(43));
+ ON_CALL(this->mockStorage, fetchDirectoryId(Eq("poo"))).WillByDefault(Return(44));
+ ON_CALL(this->mockStorage, fetchDirectoryId(Eq("taa"))).WillByDefault(Return(45));
+ ON_CALL(this->mockStorage, fetchDirectoryPath(41)).WillByDefault(Return(Utils::PathString("bar")));
+ ON_CALL(this->mockStorage, fetchDirectoryId(Eq(filePath1))).WillByDefault(Return(0));
+ ON_CALL(this->mockStorage, fetchDirectoryId(Eq(filePath2))).WillByDefault(Return(1));
+ ON_CALL(this->mockStorage, fetchDirectoryId(Eq(filePath3))).WillByDefault(Return(2));
+ ON_CALL(this->mockStorage, fetchDirectoryId(Eq(filePath4))).WillByDefault(Return(3));
+ ON_CALL(this->mockStorage, fetchDirectoryId(Eq(filePath5))).WillByDefault(Return(4));
+ }
+
+protected:
+ NiceMock<SqliteDatabaseMock> databaseMock;
+ NiceMock<MockFilePathStorage> mockStorage{databaseMock};
+ StorageAdapter storageAdapter{mockStorage};
+ Cache cache{storageAdapter};
+ typename Cache::MutexType &mockMutex = cache.mutex();
+ Utils::PathString filePath1{"/file/pathOne"};
+ Utils::PathString filePath2{"/file/pathTwo"};
+ Utils::PathString filePath3{"/file/pathThree"};
+ Utils::PathString filePath4{"/file/pathFour"};
+ Utils::PathString filePath5{"/file/pathFife"};
+ Utils::PathStringVector filePaths{filePath1,
+ filePath2,
+ filePath3,
+ filePath4,
+ filePath5};
+ Utils::PathStringVector reverseFilePaths{filePath1,
+ filePath2,
+ filePath3,
+ filePath4,
+ filePath5};
+};
+
+using CacheTypes = ::testing::Types<CacheWithMockLocking, CacheWithoutLocking>;
+TYPED_TEST_SUITE(StorageCache, CacheTypes);
+
+TYPED_TEST(StorageCache, AddFilePath)
+{
+ auto id = this->cache.id(this->filePath1);
+
+ ASSERT_THAT(id, 0);
+}
+
+TYPED_TEST(StorageCache, AddSecondFilePath)
+{
+ this->cache.id(this->filePath1);
+
+ auto id = this->cache.id(this->filePath2);
+
+ ASSERT_THAT(id, 1);
+}
+
+TYPED_TEST(StorageCache, AddDuplicateFilePath)
+{
+ this->cache.id(this->filePath1);
+
+ auto id = this->cache.id(this->filePath1);
+
+ ASSERT_THAT(id, 0);
+}
+
+TYPED_TEST(StorageCache, AddDuplicateFilePathBetweenOtherEntries)
+{
+ this->cache.id(this->filePath1);
+ this->cache.id(this->filePath2);
+ this->cache.id(this->filePath3);
+ this->cache.id(this->filePath4);
+
+ auto id = this->cache.id(this->filePath3);
+
+ ASSERT_THAT(id, 2);
+}
+
+TYPED_TEST(StorageCache, GetFilePathForIdWithOneEntry)
+{
+ this->cache.id(this->filePath1);
+
+ auto filePath = this->cache.value(0);
+
+ ASSERT_THAT(filePath, this->filePath1);
+}
+
+TYPED_TEST(StorageCache, GetFilePathForIdWithSomeEntries)
+{
+ this->cache.id(this->filePath1);
+ this->cache.id(this->filePath2);
+ this->cache.id(this->filePath3);
+ this->cache.id(this->filePath4);
+
+ auto filePath = this->cache.value(2);
+
+ ASSERT_THAT(filePath, this->filePath3);
+}
+
+TYPED_TEST(StorageCache, GetAllFilePaths)
+{
+ this->cache.id(this->filePath1);
+ this->cache.id(this->filePath2);
+ this->cache.id(this->filePath3);
+ this->cache.id(this->filePath4);
+
+ auto filePaths = this->cache.values({0, 1, 2, 3});
+
+ ASSERT_THAT(filePaths,
+ ElementsAre(this->filePath1, this->filePath2, this->filePath3, this->filePath4));
+}
+
+TYPED_TEST(StorageCache, AddFilePaths)
+{
+ auto ids = this->cache.ids({this->filePath1, this->filePath2, this->filePath3, this->filePath4});
+
+ ASSERT_THAT(ids, ElementsAre(0, 1, 2, 3));
+}
+
+TYPED_TEST(StorageCache, AddFilePathsWithStorageFunction)
+{
+ auto ids = this->cache.ids({"foo", "taa", "poo", "bar"});
+
+ ASSERT_THAT(ids, UnorderedElementsAre(42, 43, 44, 45));
+}
+
+TYPED_TEST(StorageCache, IsEmpty)
+{
+ auto isEmpty = this->cache.isEmpty();
+
+ ASSERT_TRUE(isEmpty);
+}
+
+TYPED_TEST(StorageCache, IsNotEmpty)
+{
+ this->cache.id(this->filePath1);
+
+ auto isEmpty = this->cache.isEmpty();
+
+ ASSERT_FALSE(isEmpty);
+}
+
+TYPED_TEST(StorageCache, PopulateWithEmptyVector)
+{
+ typename TypeParam::CacheEntries entries;
+
+ this->cache.uncheckedPopulate(std::move(entries));
+
+ ASSERT_TRUE(this->cache.isEmpty());
+}
+
+TYPED_TEST(StorageCache, IsNotEmptyAfterPopulateWithSomeEntries)
+{
+ typename TypeParam::CacheEntries entries{{this->filePath1.clone(), 0},
+ {this->filePath2.clone(), 3},
+ {this->filePath3.clone(), 2},
+ {this->filePath4.clone(), 5}};
+
+ this->cache.uncheckedPopulate(std::move(entries));
+
+ ASSERT_TRUE(!this->cache.isEmpty());
+}
+
+TYPED_TEST(StorageCache, GetEntryAfterPopulateWithSomeEntries)
+{
+ typename TypeParam::CacheEntries entries{{this->filePath1.clone(), 0},
+ {this->filePath2.clone(), 1},
+ {this->filePath3.clone(), 7},
+ {this->filePath4.clone(), 3}};
+ this->cache.uncheckedPopulate(std::move(entries));
+
+ auto value = this->cache.value(7);
+
+ ASSERT_THAT(value, this->filePath3);
+}
+
+TYPED_TEST(StorageCache, EntriesHaveUniqueIds)
+{
+ typename TypeParam::CacheEntries entries{{this->filePath1.clone(), 0},
+ {this->filePath2.clone(), 1},
+ {this->filePath3.clone(), 2},
+ {this->filePath4.clone(), 2}};
+
+ ASSERT_THROW(this->cache.populate(std::move(entries)), StorageCacheException);
+}
+
+TYPED_TEST(StorageCache, MultipleEntries)
+{
+ typename TypeParam::CacheEntries entries{{this->filePath1.clone(), 0},
+ {this->filePath1.clone(), 1},
+ {this->filePath3.clone(), 2},
+ {this->filePath4.clone(), 3}};
+
+ ASSERT_THROW(this->cache.populate(std::move(entries)), StorageCacheException);
+}
+
+TYPED_TEST(StorageCache, IdIsReadAndWriteLockedForUnknownEntry)
+{
+ InSequence s;
+
+ EXPECT_CALL(this->mockMutex, lock_shared());
+ EXPECT_CALL(this->mockMutex, unlock_shared());
+ EXPECT_CALL(this->mockMutex, lock());
+ EXPECT_CALL(this->mockMutex, unlock());
+
+ this->cache.id("foo");
+}
+
+TYPED_TEST(StorageCache, IdWithStorageFunctionIsReadAndWriteLockedForUnknownEntry)
+{
+ InSequence s;
+
+ EXPECT_CALL(this->mockMutex, lock_shared());
+ EXPECT_CALL(this->mockMutex, unlock_shared());
+ EXPECT_CALL(this->mockMutex, lock());
+ EXPECT_CALL(this->mockStorage, fetchDirectoryId(Eq("foo")));
+ EXPECT_CALL(this->mockMutex, unlock());
+
+ this->cache.id("foo");
+}
+
+TYPED_TEST(StorageCache, IdWithStorageFunctionIsReadLockedForKnownEntry)
+{
+ InSequence s;
+ this->cache.id("foo");
+
+ EXPECT_CALL(this->mockMutex, lock_shared());
+ EXPECT_CALL(this->mockMutex, unlock_shared());
+ EXPECT_CALL(this->mockMutex, lock()).Times(0);
+ EXPECT_CALL(this->mockStorage, fetchDirectoryId(Eq("foo"))).Times(0);
+ EXPECT_CALL(this->mockMutex, unlock()).Times(0);
+
+ this->cache.id("foo");
+}
+
+TYPED_TEST(StorageCache, IdIsReadLockedForKnownEntry)
+{
+ this->cache.id("foo");
+
+ EXPECT_CALL(this->mockMutex, lock_shared());
+ EXPECT_CALL(this->mockMutex, unlock_shared());
+ EXPECT_CALL(this->mockMutex, lock()).Times(0);
+ EXPECT_CALL(this->mockMutex, unlock()).Times(0);
+
+ this->cache.id("foo");
+}
+
+TYPED_TEST(StorageCache, IdsIsLocked)
+{
+ EXPECT_CALL(this->mockMutex, lock_shared());
+ EXPECT_CALL(this->mockMutex, unlock_shared());
+
+ this->cache.ids({"foo"});
+}
+
+TYPED_TEST(StorageCache, IdsWithStorageIsLocked)
+{
+ EXPECT_CALL(this->mockMutex, lock_shared());
+ EXPECT_CALL(this->mockMutex, unlock_shared());
+
+ this->cache.ids({"foo"});
+}
+
+TYPED_TEST(StorageCache, ValueIsLocked)
+{
+ auto id = this->cache.id("foo");
+
+ EXPECT_CALL(this->mockMutex, lock_shared());
+ EXPECT_CALL(this->mockMutex, unlock_shared());
+
+ this->cache.value(id);
+}
+
+TYPED_TEST(StorageCache, ValuesIsLocked)
+{
+ auto ids = this->cache.ids({"foo", "bar"});
+
+ EXPECT_CALL(this->mockMutex, lock_shared());
+ EXPECT_CALL(this->mockMutex, unlock_shared());
+
+ this->cache.values(ids);
+}
+
+TYPED_TEST(StorageCache, ValueWithStorageFunctionIsReadAndWriteLockedForUnknownId)
+{
+ InSequence s;
+
+ EXPECT_CALL(this->mockMutex, lock_shared());
+ EXPECT_CALL(this->mockMutex, unlock_shared());
+ EXPECT_CALL(this->mockMutex, lock());
+ EXPECT_CALL(this->mockStorage, fetchDirectoryPath(Eq(41)));
+ EXPECT_CALL(this->mockMutex, unlock());
+
+ this->cache.value(41);
+}
+
+TYPED_TEST(StorageCache, ValueWithStorageFunctionIsReadLockedForKnownId)
+{
+ InSequence s;
+ this->cache.value(41);
+
+ EXPECT_CALL(this->mockMutex, lock_shared());
+ EXPECT_CALL(this->mockMutex, unlock_shared());
+ EXPECT_CALL(this->mockMutex, lock()).Times(0);
+ EXPECT_CALL(this->mockStorage, fetchDirectoryPath(Eq(41))).Times(0);
+ EXPECT_CALL(this->mockMutex, unlock()).Times(0);
+
+ this->cache.value(41);
+}
+
+TYPED_TEST(StorageCache, IdWithStorageFunctionWhichHasNoEntryIsCallingStorageFunction)
+{
+ EXPECT_CALL(this->mockStorage, fetchDirectoryId(Eq("foo")));
+
+ this->cache.id("foo");
+}
+
+TYPED_TEST(StorageCache, IdWithStorageFunctionWhichHasEntryIsNotCallingStorageFunction)
+{
+ this->cache.id("foo");
+
+ EXPECT_CALL(this->mockStorage, fetchDirectoryId(Eq("foo"))).Times(0);
+
+ this->cache.id("foo");
+}
+
+TYPED_TEST(StorageCache, IndexOfIdWithStorageFunctionWhichHasEntry)
+{
+ this->cache.id("foo");
+
+ auto index = this->cache.id("foo");
+
+ ASSERT_THAT(index, 42);
+}
+
+TYPED_TEST(StorageCache, IndexOfIdWithStorageFunctionWhichHasNoEntry)
+{
+ auto index = this->cache.id("foo");
+
+ ASSERT_THAT(index, 42);
+}
+
+TYPED_TEST(StorageCache, GetEntryByIndexAfterInsertingByCustomIndex)
+{
+ auto index = this->cache.id("foo");
+
+ auto value = this->cache.value(index);
+
+ ASSERT_THAT(value, Eq("foo"));
+}
+
+TYPED_TEST(StorageCache, CallFetchDirectoryPathForLowerIndex)
+{
+ auto index = this->cache.id("foo");
+
+ EXPECT_CALL(this->mockStorage, fetchDirectoryPath(Eq(index - 1)));
+
+ this->cache.value(index - 1);
+}
+
+TYPED_TEST(StorageCache, CallFetchDirectoryPathForUnknownIndex)
+{
+ EXPECT_CALL(this->mockStorage, fetchDirectoryPath(Eq(0)));
+
+ this->cache.value(0);
+}
+
+TYPED_TEST(StorageCache, FetchDirectoryPathForUnknownIndex)
+{
+ auto value = this->cache.value(41);
+
+ ASSERT_THAT(value, Eq("bar"));
+}
+
+TYPED_TEST(StorageCache, AddCalls)
+{
+ EXPECT_CALL(this->mockStorage, fetchDirectoryId(Eq("foo")));
+ EXPECT_CALL(this->mockStorage, fetchDirectoryId(Eq("bar")));
+ EXPECT_CALL(this->mockStorage, fetchDirectoryId(Eq("poo")));
+
+ this->cache.add({"foo", "bar", "poo"});
+}
+
+TYPED_TEST(StorageCache, AddCallsOnlyForNewValues)
+{
+ this->cache.add({"foo", "poo"});
+
+ EXPECT_CALL(this->mockStorage, fetchDirectoryId(Eq("taa")));
+ EXPECT_CALL(this->mockStorage, fetchDirectoryId(Eq("bar")));
+
+ this->cache.add({"foo", "bar", "poo", "taa"});
+}
+
+TYPED_TEST(StorageCache, GetIdAfterAddingValues)
+{
+ this->cache.add({"foo", "bar", "poo", "taa"});
+
+ ASSERT_THAT(this->cache.value(this->cache.id("taa")), Eq("taa"));
+}
+
+TYPED_TEST(StorageCache, GetValueAfterAddingValues)
+{
+ this->cache.add({"foo", "bar", "poo", "taa"});
+
+ ASSERT_THAT(this->cache.value(this->cache.id("taa")), Eq("taa"));
+}
+
+TYPED_TEST(StorageCache, GetIdAfterAddingValuesMultipleTimes)
+{
+ this->cache.add({"foo", "taa"});
+
+ this->cache.add({"foo", "bar", "poo", "taa"});
+
+ ASSERT_THAT(this->cache.value(this->cache.id("taa")), Eq("taa"));
+}
+
+TYPED_TEST(StorageCache, GetIdAfterAddingTheSameValuesMultipleTimes)
+{
+ this->cache.add({"foo", "taa", "poo", "taa", "bar", "taa"});
+
+ ASSERT_THAT(this->cache.value(this->cache.id("taa")), Eq("taa"));
+}
+
+TYPED_TEST(StorageCache, AddingEmptyValues)
+{
+ this->cache.add({});
+}
+
+TYPED_TEST(StorageCache, FetchIdsFromStorageCalls)
+{
+ InSequence s;
+
+ EXPECT_CALL(this->mockMutex, lock_shared());
+ EXPECT_CALL(this->mockMutex, unlock_shared());
+ EXPECT_CALL(this->mockMutex, lock());
+ EXPECT_CALL(this->mockStorage, fetchDirectoryId(Eq("foo")));
+ EXPECT_CALL(this->mockMutex, unlock());
+ EXPECT_CALL(this->mockMutex, lock_shared());
+ EXPECT_CALL(this->mockMutex, unlock_shared());
+ EXPECT_CALL(this->mockMutex, lock());
+ EXPECT_CALL(this->mockStorage, fetchDirectoryId(Eq("bar")));
+ EXPECT_CALL(this->mockMutex, unlock());
+
+ this->cache.ids({"foo", "bar"});
+}
+} // namespace
diff --git a/tests/unit/unittest/tokenprocessor-test.cpp b/tests/unit/unittest/tokenprocessor-test.cpp
index b6acb918ab..ade12cb1fc 100644
--- a/tests/unit/unittest/tokenprocessor-test.cpp
+++ b/tests/unit/unittest/tokenprocessor-test.cpp
@@ -350,18 +350,18 @@ TEST_F(TokenProcessor, LocalVariableReference)
ASSERT_THAT(infos[0], IsHighlightingMark(81u, 5u, 3u, HighlightingType::LocalVariable));
}
-TEST_F(TokenProcessor, LocalVariableFunctionArgumentDeclaration)
+TEST_F(TokenProcessor, ParameterFunctionArgumentDeclaration)
{
const auto infos = translationUnit.tokenInfosInRange(sourceRange(84, 45));
- ASSERT_THAT(infos[5], IsHighlightingMark(84u, 41u, 3u, HighlightingType::LocalVariable));
+ ASSERT_THAT(infos[5], IsHighlightingMark(84u, 41u, 3u, HighlightingType::Parameter));
}
-TEST_F(TokenProcessor, LocalVariableFunctionArgumentReference)
+TEST_F(TokenProcessor, ParameterFunctionArgumentReference)
{
const auto infos = translationUnit.tokenInfosInRange(sourceRange(86, 26));
- ASSERT_THAT(infos[0], IsHighlightingMark(86u, 5u, 3u, HighlightingType::LocalVariable));
+ ASSERT_THAT(infos[0], IsHighlightingMark(86u, 5u, 3u, HighlightingType::Parameter));
}
TEST_F(TokenProcessor, ClassVariableDeclaration)
@@ -1208,7 +1208,7 @@ TEST_F(TokenProcessor, FriendArgumentDeclaration)
{
const auto infos = translationUnit.tokenInfosInRange(sourceRange(351, 65));
- ASSERT_THAT(infos[8], HasOnlyType(HighlightingType::LocalVariable));
+ ASSERT_THAT(infos[8], HasOnlyType(HighlightingType::Parameter));
}
TEST_F(TokenProcessor, FieldInitialization)
@@ -1396,7 +1396,7 @@ TEST_F(TokenProcessor, NonConstReferenceArgumentFromFunctionParameter)
infos[1];
ASSERT_THAT(infos[2],
- HasTwoTypes(HighlightingType::LocalVariable, HighlightingType::OutputArgument));
+ HasTwoTypes(HighlightingType::Parameter, HighlightingType::OutputArgument));
}
TEST_F(TokenProcessor, NonConstPointerArgumentAsExpression)
@@ -1497,7 +1497,7 @@ TEST_F(TokenProcessor, VariableInOperatorFunctionCall)
{
const auto infos = translationUnit.tokenInfosInRange(sourceRange(566, 12));
- ASSERT_THAT(infos[2], HasOnlyType(HighlightingType::LocalVariable));
+ ASSERT_THAT(infos[2], HasOnlyType(HighlightingType::Parameter));
}
TEST_F(TokenProcessor, UsingTemplateFunction)
@@ -1807,9 +1807,15 @@ TEST_F(TokenProcessor, OperatorInTemplate)
ASSERT_THAT(infos[9], HasOnlyType(HighlightingType::Punctuation));
}
+TEST_F(TokenProcessor, CyrillicString)
+{
+ const auto infos = translationUnit.tokenInfosInRange(sourceRange(792, 28));
+ ASSERT_THAT(infos[5], IsHighlightingMark(792u, 24u, 3u, HighlightingType::StringLiteral));
+}
+
TEST_F(TokenProcessor, PreProcessorInStruct)
{
- const auto infos = translationUnit.tokenInfosInRange(sourceRange(793, 14));
+ const auto infos = translationUnit.tokenInfosInRange(sourceRange(795, 14));
ASSERT_THAT(infos[1], HasOnlyType(HighlightingType::Preprocessor));
}
diff --git a/tests/unit/unittest/unittest.pro b/tests/unit/unittest/unittest.pro
index d6195d2160..d00920fdb5 100644
--- a/tests/unit/unittest/unittest.pro
+++ b/tests/unit/unittest/unittest.pro
@@ -70,6 +70,8 @@ SOURCES += \
gtest-creator-printing.cpp \
gtest-qt-printing.cpp \
asynchronousimagecache-test.cpp \
+ nodelistproperty-test.cpp \
+ storagecache-test.cpp \
synchronousimagecache-test.cpp \
imagecachegenerator-test.cpp \
imagecachestorage-test.cpp \
@@ -236,6 +238,7 @@ SOURCES += \
}
HEADERS += \
+ abstractviewmock.h \
compare-operators.h \
conditionally-disabled-tests.h \
dummyclangipcclient.h \