summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--.gitignore5
-rw-r--r--dist/changes-4.3.0.md3
-rw-r--r--doc/api/qtcreator-dev-wizards.qdoc4
-rw-r--r--doc/src/projects/creator-projects-build-run-tutorial.qdoc9
-rw-r--r--qtcreator.pro15
-rwxr-xr-xscripts/deployqtHelper_mac.sh4
-rw-r--r--share/qtcreator/debugger/cdbbridge.py9
-rw-r--r--share/qtcreator/debugger/dumper.py28
-rw-r--r--share/qtcreator/debugger/lldbbridge.py5
-rw-r--r--share/qtcreator/debugger/qttypes.py28
-rw-r--r--share/qtcreator/qml/qmlpuppet/qml2puppet/instances/objectnodeinstance.cpp6
-rw-r--r--share/qtcreator/qml/qmlpuppet/qmlprivategate/qmlprivategate.cpp4
-rw-r--r--share/qtcreator/qml/qmlpuppet/qmlprivategate/qmlprivategate_56.cpp4
-rw-r--r--src/libs/cplusplus/OverviewModel.cpp1
-rw-r--r--src/libs/extensionsystem/pluginmanager.cpp2
-rw-r--r--src/libs/flamegraph/flamegraph.cpp4
-rw-r--r--src/libs/modelinglib/qmt/diagram_scene/items/stereotypedisplayvisitor.cpp2
-rw-r--r--src/libs/modelinglib/qmt/model_widgets_ui/propertiesviewmview.cpp2
-rw-r--r--src/libs/qmldebug/baseenginedebugclient.cpp1
-rw-r--r--src/libs/qmleditorwidgets/contextpanewidgetimage.cpp16
-rw-r--r--src/libs/qmljs/parser/qmljsast_p.h2
-rw-r--r--src/libs/qmljs/qmljscheck.cpp5
-rw-r--r--src/libs/qmljs/qmljsconstants.h11
-rw-r--r--src/libs/qmljs/qmljsdescribevalue.cpp26
-rw-r--r--src/libs/qmljs/qmljslink.cpp5
-rw-r--r--src/libs/qmljs/qmljsmodelmanagerinterface.cpp3
-rw-r--r--src/libs/qmljs/qmljsreformatter.cpp8
-rw-r--r--src/libs/qmljs/qmljstypedescriptionreader.cpp4
-rw-r--r--src/libs/qtcreatorcdbext/pycdbextmodule.cpp35
-rw-r--r--src/libs/qtcreatorcdbext/pycdbextmodule.h2
-rw-r--r--src/libs/qtcreatorcdbext/qtcreatorcdbextension.cpp14
-rw-r--r--src/libs/qtcreatorcdbext/symbolgroup.cpp7
-rw-r--r--src/libs/qtcreatorcdbext/symbolgroupvalue.cpp6
-rw-r--r--src/libs/qtcreatorcdbext/symbolgroupvalue.h2
-rw-r--r--src/libs/timeline/qml/MainView.qml2
-rw-r--r--src/libs/utils/appmainwindow.cpp6
-rw-r--r--src/libs/utils/completinglineedit.cpp2
-rw-r--r--src/libs/utils/consoleprocess_unix.cpp5
-rw-r--r--src/libs/utils/crumblepath.cpp1
-rw-r--r--src/libs/utils/pathchooser.cpp2
-rw-r--r--src/libs/utils/theme/theme.cpp9
-rw-r--r--src/libs/utils/theme/theme_p.h1
-rw-r--r--src/libs/utils/treemodel.cpp8
-rw-r--r--src/libs/utils/treemodel.h2
-rw-r--r--src/libs/utils/unixutils.cpp2
-rw-r--r--src/plugins/android/android.pro10
-rw-r--r--src/plugins/android/android.qbs6
-rw-r--r--src/plugins/android/androidavdmanager.cpp441
-rw-r--r--src/plugins/android/androidavdmanager.h66
-rw-r--r--src/plugins/android/androidbuildapkstep.cpp21
-rw-r--r--src/plugins/android/androidbuildapkstep.h6
-rw-r--r--src/plugins/android/androidbuildapkwidget.cpp13
-rw-r--r--src/plugins/android/androidbuildapkwidget.ui86
-rw-r--r--src/plugins/android/androidconfigurations.cpp432
-rw-r--r--src/plugins/android/androidconfigurations.h60
-rw-r--r--src/plugins/android/androiddebugsupport.cpp10
-rw-r--r--src/plugins/android/androiddeployqtstep.cpp8
-rw-r--r--src/plugins/android/androiddevicedialog.cpp12
-rw-r--r--src/plugins/android/androiddevicedialog.h6
-rw-r--r--src/plugins/android/androidmanager.cpp30
-rw-r--r--src/plugins/android/androidmanager.h1
-rw-r--r--src/plugins/android/androidrunconfiguration.cpp191
-rw-r--r--src/plugins/android/androidrunconfiguration.h66
-rw-r--r--src/plugins/android/androidruncontrol.cpp7
-rw-r--r--src/plugins/android/androidrunner.cpp291
-rw-r--r--src/plugins/android/androidrunner.h3
-rw-r--r--src/plugins/android/androidsdkmanager.cpp337
-rw-r--r--src/plugins/android/androidsdkmanager.h51
-rw-r--r--src/plugins/android/androidsettingswidget.cpp48
-rw-r--r--src/plugins/android/androidsettingswidget.h12
-rw-r--r--src/plugins/android/androidsettingswidget.ui94
-rw-r--r--src/plugins/android/androidtoolmanager.cpp346
-rw-r--r--src/plugins/android/androidtoolmanager.h72
-rw-r--r--src/plugins/android/avddialog.cpp29
-rw-r--r--src/plugins/android/avddialog.h3
-rw-r--r--src/plugins/autotest/testconfiguration.cpp6
-rw-r--r--src/plugins/autotest/testconfiguration.h6
-rw-r--r--src/plugins/autotest/testrunner.cpp44
-rw-r--r--src/plugins/autotoolsprojectmanager/autotoolsproject.cpp6
-rw-r--r--src/plugins/autotoolsprojectmanager/autotoolsproject.h1
-rw-r--r--src/plugins/autotoolsprojectmanager/autotoolsprojectnode.cpp6
-rw-r--r--src/plugins/autotoolsprojectmanager/autotoolsprojectnode.h1
-rw-r--r--src/plugins/beautifier/beautifierplugin.cpp2
-rw-r--r--src/plugins/beautifier/beautifierplugin.h3
-rw-r--r--src/plugins/beautifier/generaloptionspage.cpp6
-rw-r--r--src/plugins/beautifier/generaloptionspage.h13
-rw-r--r--src/plugins/classview/classviewparser.cpp98
-rw-r--r--src/plugins/classview/classviewparser.h10
-rw-r--r--src/plugins/clearcase/clearcaseplugin.cpp4
-rw-r--r--src/plugins/clearcase/clearcasesync.cpp2
-rw-r--r--src/plugins/cmakeprojectmanager/cmakebuildconfiguration.cpp5
-rw-r--r--src/plugins/cmakeprojectmanager/cmakebuildsettingswidget.cpp2
-rw-r--r--src/plugins/cmakeprojectmanager/cmakebuildstep.cpp21
-rw-r--r--src/plugins/cmakeprojectmanager/cmakecbpparser.cpp9
-rw-r--r--src/plugins/cmakeprojectmanager/cmakeproject.cpp11
-rw-r--r--src/plugins/cmakeprojectmanager/cmakeproject.h2
-rw-r--r--src/plugins/cmakeprojectmanager/cmakeprojectmanager.cpp2
-rw-r--r--src/plugins/cmakeprojectmanager/cmakeprojectnodes.cpp24
-rw-r--r--src/plugins/cmakeprojectmanager/cmakeprojectnodes.h6
-rw-r--r--src/plugins/cmakeprojectmanager/servermodereader.cpp30
-rw-r--r--src/plugins/cmakeprojectmanager/servermodereader.h4
-rw-r--r--src/plugins/coreplugin/dialogs/saveitemsdialog.cpp2
-rw-r--r--src/plugins/coreplugin/editormanager/documentmodel.cpp2
-rw-r--r--src/plugins/coreplugin/editormanager/editormanager.cpp1
-rw-r--r--src/plugins/coreplugin/editormanager/editorview.cpp2
-rw-r--r--src/plugins/coreplugin/find/itemviewfind.cpp7
-rw-r--r--src/plugins/coreplugin/find/searchresultwidget.cpp2
-rw-r--r--src/plugins/coreplugin/icore.cpp8
-rw-r--r--src/plugins/coreplugin/mainwindow.cpp2
-rw-r--r--src/plugins/coreplugin/manhattanstyle.cpp16
-rw-r--r--src/plugins/coreplugin/plugindialog.cpp2
-rw-r--r--src/plugins/coreplugin/statusbarmanager.cpp2
-rw-r--r--src/plugins/coreplugin/themechooser.cpp12
-rw-r--r--src/plugins/coreplugin/variablechooser.cpp2
-rw-r--r--src/plugins/cpaster/authenticationdialog.cpp64
-rw-r--r--src/plugins/cpaster/authenticationdialog.h51
-rw-r--r--src/plugins/cpaster/cpaster.pro8
-rw-r--r--src/plugins/cpaster/cpaster.qbs2
-rw-r--r--src/plugins/cpaster/kdepasteprotocol.cpp126
-rw-r--r--src/plugins/cpaster/kdepasteprotocol.h27
-rw-r--r--src/plugins/cpaster/pastebindotcaprotocol.cpp73
-rw-r--r--src/plugins/cpaster/pastebindotcomprotocol.cpp2
-rw-r--r--src/plugins/cpaster/protocol.cpp19
-rw-r--r--src/plugins/cpaster/protocol.h5
-rw-r--r--src/plugins/cppeditor/cppautocompleter.cpp2
-rw-r--r--src/plugins/cpptools/modelmanagertesthelper.cpp5
-rw-r--r--src/plugins/cpptools/modelmanagertesthelper.h3
-rw-r--r--src/plugins/debugger/breakhandler.cpp26
-rw-r--r--src/plugins/debugger/cdb/cdbengine.cpp46
-rw-r--r--src/plugins/debugger/cdb/cdbengine.h1
-rw-r--r--src/plugins/debugger/commonoptionspage.cpp6
-rw-r--r--src/plugins/debugger/debuggerengine.cpp2
-rw-r--r--src/plugins/debugger/debuggerplugin.cpp13
-rw-r--r--src/plugins/debugger/debuggerruncontrol.cpp1
-rw-r--r--src/plugins/debugger/gdb/gdbengine.cpp20
-rw-r--r--src/plugins/debugger/gdb/termgdbadapter.cpp1
-rw-r--r--src/plugins/diffeditor/differ.cpp1
-rw-r--r--src/plugins/genericprojectmanager/genericproject.cpp14
-rw-r--r--src/plugins/genericprojectmanager/genericproject.h2
-rw-r--r--src/plugins/git/gitclient.cpp2
-rw-r--r--src/plugins/git/gitplugin.cpp121
-rw-r--r--src/plugins/git/gitplugin.h10
-rw-r--r--src/plugins/nim/project/nimproject.cpp10
-rw-r--r--src/plugins/nim/project/nimproject.h1
-rw-r--r--src/plugins/nim/project/nimprojectnode.cpp18
-rw-r--r--src/plugins/nim/project/nimprojectnode.h2
-rw-r--r--src/plugins/projectexplorer/abi.cpp44
-rw-r--r--src/plugins/projectexplorer/abi.h1
-rw-r--r--src/plugins/projectexplorer/abiwidget.cpp1
-rw-r--r--src/plugins/projectexplorer/devicesupport/devicemanager.cpp2
-rw-r--r--src/plugins/projectexplorer/gcctoolchain.cpp8
-rw-r--r--src/plugins/projectexplorer/jsonwizard/jsonwizard.cpp2
-rw-r--r--src/plugins/projectexplorer/msvcparser.cpp459
-rw-r--r--src/plugins/projectexplorer/processstep.cpp2
-rw-r--r--src/plugins/projectexplorer/project.cpp24
-rw-r--r--src/plugins/projectexplorer/project.h4
-rw-r--r--src/plugins/projectexplorer/projectexplorer.cpp64
-rw-r--r--src/plugins/projectexplorer/projectmodels.cpp104
-rw-r--r--src/plugins/projectexplorer/projectmodels.h5
-rw-r--r--src/plugins/projectexplorer/projectnodes.cpp37
-rw-r--r--src/plugins/projectexplorer/projectnodes.h9
-rw-r--r--src/plugins/projectexplorer/projectwelcomepage.cpp7
-rw-r--r--src/plugins/projectexplorer/projectwindow.cpp2
-rw-r--r--src/plugins/projectexplorer/projectwizardpage.cpp6
-rw-r--r--src/plugins/projectexplorer/session.cpp2
-rw-r--r--src/plugins/projectexplorer/sessiondialog.cpp1
-rw-r--r--src/plugins/projectexplorer/sessionview.cpp6
-rw-r--r--src/plugins/projectexplorer/sessionview.h5
-rw-r--r--src/plugins/projectexplorer/targetsettingspanel.cpp2
-rw-r--r--src/plugins/pythoneditor/pythoneditorplugin.cpp19
-rw-r--r--src/plugins/qbsprojectmanager/defaultpropertyprovider.cpp9
-rw-r--r--src/plugins/qbsprojectmanager/qbsnodes.cpp49
-rw-r--r--src/plugins/qbsprojectmanager/qbsnodes.h10
-rw-r--r--src/plugins/qbsprojectmanager/qbsnodetreebuilder.cpp24
-rw-r--r--src/plugins/qbsprojectmanager/qbsproject.cpp17
-rw-r--r--src/plugins/qbsprojectmanager/qbsproject.h1
-rw-r--r--src/plugins/qmakeandroidsupport/createandroidmanifestwizard.cpp9
-rw-r--r--src/plugins/qmakeandroidsupport/qmakeandroidbuildapkstep.cpp16
-rw-r--r--src/plugins/qmakeprojectmanager/desktopqmakerunconfiguration.cpp49
-rw-r--r--src/plugins/qmakeprojectmanager/desktopqmakerunconfiguration.h4
-rw-r--r--src/plugins/qmakeprojectmanager/qmakenodes.cpp43
-rw-r--r--src/plugins/qmakeprojectmanager/qmakenodes.h2
-rw-r--r--src/plugins/qmakeprojectmanager/qmakeproject.cpp28
-rw-r--r--src/plugins/qmakeprojectmanager/qmakeproject.h2
-rw-r--r--src/plugins/qmldesigner/components/componentcore/componentcore_constants.h2
-rw-r--r--src/plugins/qmldesigner/components/componentcore/modelnodeoperations.cpp2
-rw-r--r--src/plugins/qmldesigner/components/importmanager/importmanagercombobox.cpp4
-rw-r--r--src/plugins/qmldesigner/components/navigator/navigatortreemodel.cpp1
-rw-r--r--src/plugins/qmldesigner/components/texteditor/texteditorwidget.cpp5
-rw-r--r--src/plugins/qmldesigner/designercore/include/rewriterview.h3
-rw-r--r--src/plugins/qmldesigner/designercore/instances/nodeinstanceview.cpp4
-rw-r--r--src/plugins/qmldesigner/designercore/model/qmlitemnode.cpp3
-rw-r--r--src/plugins/qmldesigner/designercore/model/rewriterview.cpp15
-rw-r--r--src/plugins/qmldesigner/designercore/model/texttomodelmerger.cpp4
-rw-r--r--src/plugins/qmldesigner/designmodewidget.cpp4
-rw-r--r--src/plugins/qmldesigner/documentmanager.cpp2
-rw-r--r--src/plugins/qmldesigner/qmldesignerplugin.cpp1
-rw-r--r--src/plugins/qmldesigner/switchsplittabwidget.cpp5
-rw-r--r--src/plugins/qmljseditor/qmljseditor.cpp27
-rw-r--r--src/plugins/qmljseditor/qmljseditor.h14
-rw-r--r--src/plugins/qmljseditor/qmljseditordocument.cpp9
-rw-r--r--src/plugins/qmljseditor/qmljseditordocument_p.h12
-rw-r--r--src/plugins/qmljseditor/qmljsoutline.cpp83
-rw-r--r--src/plugins/qmljseditor/qmljsoutline.h25
-rw-r--r--src/plugins/qmljseditor/qmljssemantichighlighter.cpp4
-rw-r--r--src/plugins/qmlprofiler/tests/flamegraphview_test.cpp34
-rw-r--r--src/plugins/qmlprojectmanager/qmlproject.cpp6
-rw-r--r--src/plugins/qmlprojectmanager/qmlproject.h2
-rw-r--r--src/plugins/qmlprojectmanager/qmlprojectnodes.cpp14
-rw-r--r--src/plugins/qmlprojectmanager/qmlprojectnodes.h12
-rw-r--r--src/plugins/qnx/qnxconfiguration.cpp1
-rw-r--r--src/plugins/qnx/qnxtoolchain.cpp26
-rw-r--r--src/plugins/qnx/qnxtoolchain.h5
-rw-r--r--src/plugins/resourceeditor/resourceeditorplugin.cpp4
-rw-r--r--src/plugins/resourceeditor/resourcenode.cpp67
-rw-r--r--src/plugins/resourceeditor/resourcenode.h6
-rw-r--r--src/plugins/scxmleditor/common/colorthemes.cpp2
-rw-r--r--src/plugins/scxmleditor/plugin_interface/idwarningitem.cpp2
-rw-r--r--src/plugins/scxmleditor/plugin_interface/initialwarningitem.cpp4
-rw-r--r--src/plugins/scxmleditor/plugin_interface/scxmldocument.cpp14
-rw-r--r--src/plugins/scxmleditor/plugin_interface/stateitem.cpp2
-rw-r--r--src/plugins/scxmleditor/scxmleditorconstants.h2
-rw-r--r--src/plugins/texteditor/circularclipboardassist.cpp1
-rw-r--r--src/plugins/texteditor/textdocumentlayout.cpp2
-rw-r--r--src/plugins/valgrind/callgrind/callgrindproxymodel.cpp7
m---------src/shared/qbs0
-rw-r--r--tests/auto/debugger/tst_dumpers.cpp40
-rw-r--r--tests/auto/extensionsystem/pluginspec/tst_pluginspec.cpp2
-rw-r--r--tests/auto/qml/qmldesigner/coretests/tst_testcore.cpp2
-rw-r--r--tests/auto/qml/reformatter/comments.qml10
-rw-r--r--tests/system/shared/debugger.py1
-rw-r--r--tests/system/suite_tools/tst_codepasting/test.py1
232 files changed, 3907 insertions, 1818 deletions
diff --git a/.gitignore b/.gitignore
index f8851e46b8..3e0ccac715 100644
--- a/.gitignore
+++ b/.gitignore
@@ -110,9 +110,8 @@ phony.c
/dist/gdb/qtcreator-*/
/dist/gdb/source/
/dist/gdb/staging/
-/doc/api/html/
-/doc/html-dev/
-/doc/html/
+/doc/qtcreator/
+/doc/qtcreator-dev/
/doc/pluginhowto/html/
/lib/
/lib64/
diff --git a/dist/changes-4.3.0.md b/dist/changes-4.3.0.md
index 79e4574c5c..b133f9f557 100644
--- a/dist/changes-4.3.0.md
+++ b/dist/changes-4.3.0.md
@@ -21,7 +21,8 @@ Editing
All Projects
* Added support for `.qrc` files in project tree for all projects
-* Added Qt Creator variable `CurrentRun:Runnable:FilePath`
+* Added Qt Creator variable `CurrentRun:Executable` (QTCREATORBUG-12201,
+ QTCREATORBUG-16830)
* Added choice of build system to most project wizards (QTCREATORBUG-17308)
QMake Projects
diff --git a/doc/api/qtcreator-dev-wizards.qdoc b/doc/api/qtcreator-dev-wizards.qdoc
index 096d3a8320..ddb11119ea 100644
--- a/doc/api/qtcreator-dev-wizards.qdoc
+++ b/doc/api/qtcreator-dev-wizards.qdoc
@@ -34,8 +34,8 @@
is not sufficient for your case, you can write wizards in code.
A wizard in \QC is an instance of a class implementing
- the Core::IWizardFactory interface that is registered with
- ExtensionSystem::PluginManager.
+ the Core::IWizardFactory interface that has a creator function registered
+ with IWizardFactory::registerFactoryCreator.
Implementing wizards requires:
\list
diff --git a/doc/src/projects/creator-projects-build-run-tutorial.qdoc b/doc/src/projects/creator-projects-build-run-tutorial.qdoc
index 226bc4e5b6..4cdc509070 100644
--- a/doc/src/projects/creator-projects-build-run-tutorial.qdoc
+++ b/doc/src/projects/creator-projects-build-run-tutorial.qdoc
@@ -58,10 +58,13 @@
\image qtcreator-gs-build-example-open.png "Selecting an example"
+ If no examples are listed, check that a \l{Adding Qt Versions}
+ {Qt version} is installed and configured.
+
\li Select an example in the list of examples.
You can also search for examples. Enter the \uicontrol android or
- \uicontrol iOS keyword in the search field (2) to list all the
+ \uicontrol ios keyword in the search field (2) to list all the
examples tested for Android or iOS. To list examples that you can
run on embedded devices, enter the \uicontrol Boot2Qt keyword in the
search field (commercial only).
@@ -83,8 +86,8 @@
\li To see the compilation progress, press \key{Alt+4} to open the
\uicontrol {Compile Output} pane.
- If build errors occur, check that a \l{Adding Qt Versions}
- {Qt version} and \l{Adding Compilers}{compiler} are installed and
+ If build errors occur, check that a Qt version and
+ \l{Adding Compilers}{compiler} are installed and
configured and that the necessary kits are configured. If you are
building for an \l{Connecting Android Devices}{Android device} or
\l{Connecting iOS Devices}{iOS device}, check that the development
diff --git a/qtcreator.pro b/qtcreator.pro
index 460ecd3301..e25e8cc7f6 100644
--- a/qtcreator.pro
+++ b/qtcreator.pro
@@ -79,15 +79,16 @@ exists(src/shared/qbs/qbs.pro) {
}
# Create qbs documentation targets.
- QBS_DOCS_BUILD_DIR=$$IDE_DOC_PATH
- QBS_HTML_DOC_PATH=$$OUT_PWD/doc/html-qbs
- QBS_DOCS_INSTALL_DIR=$$INSTALL_DOC_PATH
- QDOC_BIN = $$QDOC
- HELPGENERATOR = $$QHELPGENERATOR
- include(src/shared/qbs/qbs_version.pri)
+ DOC_FILES =
+ DOC_TARGET_PREFIX = qbs_
+ include(src/shared/qbs/doc/doc_shared.pri)
include(src/shared/qbs/doc/doc_targets.pri)
docs.depends += qbs_docs
- install_docs.depends += install_inst_qbs_qch_docs
+ !build_online_docs {
+ install_docs.depends += install_qbs_docs
+ }
+ unset(DOC_FILES)
+ unset(DOC_TARGET_PREFIX)
}
contains(QT_ARCH, i386): ARCHITECTURE = x86
diff --git a/scripts/deployqtHelper_mac.sh b/scripts/deployqtHelper_mac.sh
index 5039c89e82..2ee40242f5 100755
--- a/scripts/deployqtHelper_mac.sh
+++ b/scripts/deployqtHelper_mac.sh
@@ -134,9 +134,9 @@ if [ ! -d "$app_path/Contents/Frameworks/QtCore.framework" ]; then
qbsapp="$app_path/Contents/MacOS/qbs"
- echo "- Running macdeployqt ($(which macdeployqt))"
+ echo "- Running macdeployqt ($bin_src/macdeployqt)"
- macdeployqt "$app_path" \
+ "$bin_src/macdeployqt" "$app_path" \
"-executable=$app_path/Contents/MacOS/qtdiag" \
"-executable=$resource_path/qtpromaker" \
"-executable=$resource_path/sdktool" \
diff --git a/share/qtcreator/debugger/cdbbridge.py b/share/qtcreator/debugger/cdbbridge.py
index fd8c65dd95..e34b8ed48e 100644
--- a/share/qtcreator/debugger/cdbbridge.py
+++ b/share/qtcreator/debugger/cdbbridge.py
@@ -125,7 +125,6 @@ class Dumper(DumperBase):
pass
val.isBaseClass = val.name == val.type.name
val.nativeValue = nativeValue
- val.lIsInScope = True
val.laddress = nativeValue.address()
return val
@@ -405,12 +404,12 @@ class Dumper(DumperBase):
return cdbext.lookupType(name, module)
def reportResult(self, result, args):
- self.report('result={%s}' % (result))
+ cdbext.reportResult('result={%s}' % result)
def readRawMemory(self, address, size):
mem = cdbext.readRawMemory(address, size)
if len(mem) != size:
- raise Exception("Invalid memory request")
+ raise Exception("Invalid memory request: %d bytes from 0x%x" % (size, address))
return mem
def findStaticMetaObject(self, type):
@@ -440,7 +439,9 @@ class Dumper(DumperBase):
variables = []
for val in cdbext.listOfLocals(self.partialVariable):
- variables.append(self.fromNativeValue(val))
+ dumperVal = self.fromNativeValue(val)
+ dumperVal.lIsInScope = not dumperVal.name in self.uninitialized
+ variables.append(dumperVal)
self.handleLocals(variables)
self.handleWatches(args)
diff --git a/share/qtcreator/debugger/dumper.py b/share/qtcreator/debugger/dumper.py
index 9a019f87c3..2d814e76f4 100644
--- a/share/qtcreator/debugger/dumper.py
+++ b/share/qtcreator/debugger/dumper.py
@@ -317,6 +317,8 @@ class DumperBase:
self.nativeMixed = int(args.get('nativemixed', '0'))
self.autoDerefPointers = int(args.get('autoderef', '0'))
self.partialVariable = args.get('partialvar', '')
+ self.uninitialized = args.get('uninitialized', [])
+ self.uninitialized = list(map(lambda x: self.hexdecode(x), self.uninitialized))
self.partialUpdate = int(args.get('partial', '0'))
self.fallbackQtVersion = 0x50200
#warn('NAMESPACE: "%s"' % self.qtNamespace())
@@ -1497,7 +1499,10 @@ class DumperBase:
def getJumpAddress_x86(dumper, address):
relativeJumpCode = 0xe9
jumpCode = 0xff
- data = dumper.readRawMemory(address, 6)
+ try:
+ data = dumper.readRawMemory(address, 6)
+ except:
+ return 0
primaryOpcode = data[0]
if primaryOpcode == relativeJumpCode:
# relative jump on 32 and 64 bit with a 32bit offset
@@ -3467,27 +3472,6 @@ class DumperBase:
def target(self):
return self.typeData().ltarget
-
- def field(self, value, name, bitoffset = 0):
- #warn('GETTING FIELD %s FOR: %s' % (name, self.name))
- for f in self.fields(value):
- #warn('EXAMINING MEMBER %s' % f.name)
- if f.name == name:
- ff = copy.copy(f)
- if ff.lbitpos is None:
- ff.lbitpos = bitoffset
- else:
- ff.lbitpos += bitoffset
- #warn('FOUND: %s' % ff)
- return ff
- if f.isBaseClass:
- #warn('EXAMINING BASE %s' % f.type)
- res = f.type.field(name, bitoffset + f.bitpos())
- if res is not None:
- return res
- #warn('FIELD %s NOT FOUND IN %s' % (name, self))
- return None
-
def stripTypedefs(self):
if isinstance(self, self.dumper.Type) and self.code != TypeCodeTypedef:
#warn('NO TYPEDEF: %s' % self)
diff --git a/share/qtcreator/debugger/lldbbridge.py b/share/qtcreator/debugger/lldbbridge.py
index 47f1243b46..2d45838eaf 100644
--- a/share/qtcreator/debugger/lldbbridge.py
+++ b/share/qtcreator/debugger/lldbbridge.py
@@ -811,7 +811,10 @@ class Dumper(DumperBase):
self.nativeMixed = int(args.get('nativemixed', 0))
self.workingDirectory_ = args.get('workingdirectory', '')
if self.workingDirectory_ == '':
- self.workingDirectory_ = os.getcwd()
+ try:
+ self.workingDirectory_ = os.getcwd()
+ except: # Could have been deleted in the mean time.
+ pass
self.ignoreStops = 0
self.silentStops = 0
diff --git a/share/qtcreator/debugger/qttypes.py b/share/qtcreator/debugger/qttypes.py
index ce7cda3f52..b43ebb4b6c 100644
--- a/share/qtcreator/debugger/qttypes.py
+++ b/share/qtcreator/debugger/qttypes.py
@@ -642,10 +642,10 @@ def qdump__QFiniteStack(d, value):
def qdump__QFlags(d, value):
i = value.split('{int}')[0]
enumType = value.type[0]
- if d.isLldb:
- d.putValue(i.cast(enumType.name).display())
- else:
+ if d.isGdb:
d.putValue(i.cast('enum ' + enumType.name).display())
+ else:
+ d.putValue(i.cast(enumType.name).display())
d.putNumChild(0)
@@ -2758,3 +2758,25 @@ def qdump__QSqlField(d, value):
qdump__QVariant(d, val)
d.putBetterType(d.currentType.value.replace('QVariant', 'QSqlField'))
d.putPlainChildren(value)
+
+
+def qdump__qfloat16(d, value):
+ h = value.split('H')[0]
+ # Stole^H^H^HHeavily inspired by J.F. Sebastian at
+ # http://math.stackexchange.com/questions/1128204/how-to-convert-
+ # from-floating-point-binary-to-decimal-in-half-precision16-bits
+ sign = h >> 15
+ exp = (h >> 10) & 0b011111
+ fraction = h & (2**10 - 1)
+ if exp == 0:
+ if fraction == 0:
+ res = -0.0 if sign else 0.0
+ else:
+ res = (-1)**sign * fraction / 2**10 * 2**(-14) # subnormal
+ elif exp == 0b11111:
+ res = ('-inf' if sign else 'inf') if fraction == 0 else 'nan'
+ else:
+ res = (-1)**sign * (1 + fraction / 2**10) * 2**(exp - 15)
+ d.putValue(res)
+ d.putNumChild(1)
+ d.putPlainChildren(value)
diff --git a/share/qtcreator/qml/qmlpuppet/qml2puppet/instances/objectnodeinstance.cpp b/share/qtcreator/qml/qmlpuppet/qml2puppet/instances/objectnodeinstance.cpp
index 8cd156345d..cea0946105 100644
--- a/share/qtcreator/qml/qmlpuppet/qml2puppet/instances/objectnodeinstance.cpp
+++ b/share/qtcreator/qml/qmlpuppet/qml2puppet/instances/objectnodeinstance.cpp
@@ -420,7 +420,7 @@ void ObjectNodeInstance::setPropertyVariant(const PropertyName &name, const QVar
if (oldValue.type() == QVariant::Url) {
QUrl url = oldValue.toUrl();
QString path = url.toLocalFile();
- if (QFileInfo(path).exists() && nodeInstanceServer() && !path.isEmpty())
+ if (QFileInfo::exists(path) && nodeInstanceServer() && !path.isEmpty())
nodeInstanceServer()->removeFilePropertyFromFileSystemWatcher(object(), name, path);
}
@@ -437,7 +437,7 @@ void ObjectNodeInstance::setPropertyVariant(const PropertyName &name, const QVar
if (newValue.type() == QVariant::Url) {
QUrl url = newValue.toUrl();
QString path = url.toLocalFile();
- if (QFileInfo(path).exists() && nodeInstanceServer() && !path.isEmpty())
+ if (QFileInfo::exists(path) && nodeInstanceServer() && !path.isEmpty())
nodeInstanceServer()->addFilePropertyToFileSystemWatcher(object(), name, path);
}
}
@@ -678,7 +678,7 @@ static inline QString fixComponentPathForIncompatibleQt(const QString &component
const QString relativeImportPath = componentPath.right(componentPath.length() - index);
QString fixedComponentPath = QLibraryInfo::location(QLibraryInfo::ImportsPath) + relativeImportPath;
fixedComponentPath.replace(QLatin1Char('\\'), QLatin1Char('/'));
- if (QFileInfo(fixedComponentPath).exists())
+ if (QFileInfo::exists(fixedComponentPath))
return fixedComponentPath;
QString fixedPath = QFileInfo(fixedComponentPath).path();
if (fixedPath.endsWith(QLatin1String(".1.0"))) {
diff --git a/share/qtcreator/qml/qmlpuppet/qmlprivategate/qmlprivategate.cpp b/share/qtcreator/qml/qmlpuppet/qmlprivategate/qmlprivategate.cpp
index b55374220d..3243db8fc0 100644
--- a/share/qtcreator/qml/qmlpuppet/qmlprivategate/qmlprivategate.cpp
+++ b/share/qtcreator/qml/qmlpuppet/qmlprivategate/qmlprivategate.cpp
@@ -389,7 +389,7 @@ QVariant fixResourcePaths(const QVariant &value)
if (qrcDefintion.count() == 2) {
QString fixedPath = path;
fixedPath.replace(QLatin1String("qrc:") + qrcDefintion.first(), qrcDefintion.last() + QLatin1Char('/'));
- if (QFileInfo(fixedPath).exists()) {
+ if (QFileInfo::exists(fixedPath)) {
fixedPath.replace(QLatin1String("//"), QLatin1String("/"));
fixedPath.replace(QLatin1Char('\\'), QLatin1Char('/'));
return QUrl::fromLocalFile(fixedPath);
@@ -410,7 +410,7 @@ QVariant fixResourcePaths(const QVariant &value)
if (qrcDefintion.count() == 2) {
QString fixedPath = str;
fixedPath.replace(QLatin1String("qrc:") + qrcDefintion.first(), qrcDefintion.last() + QLatin1Char('/'));
- if (QFileInfo(fixedPath).exists()) {
+ if (QFileInfo::exists(fixedPath)) {
fixedPath.replace(QLatin1String("//"), QLatin1String("/"));
fixedPath.replace(QLatin1Char('\\'), QLatin1Char('/'));
return fixedPath;
diff --git a/share/qtcreator/qml/qmlpuppet/qmlprivategate/qmlprivategate_56.cpp b/share/qtcreator/qml/qmlpuppet/qmlprivategate/qmlprivategate_56.cpp
index 15d2aa5daf..cbc4e54fb1 100644
--- a/share/qtcreator/qml/qmlpuppet/qmlprivategate/qmlprivategate_56.cpp
+++ b/share/qtcreator/qml/qmlpuppet/qmlprivategate/qmlprivategate_56.cpp
@@ -102,7 +102,7 @@ QVariant fixResourcePaths(const QVariant &value)
if (qrcDefintion.count() == 2) {
QString fixedPath = path;
fixedPath.replace(QLatin1String("qrc:") + qrcDefintion.first(), qrcDefintion.last() + QLatin1Char('/'));
- if (QFileInfo(fixedPath).exists()) {
+ if (QFileInfo::exists(fixedPath)) {
fixedPath.replace(QLatin1String("//"), QLatin1String("/"));
fixedPath.replace(QLatin1Char('\\'), QLatin1Char('/'));
return QUrl::fromLocalFile(fixedPath);
@@ -123,7 +123,7 @@ QVariant fixResourcePaths(const QVariant &value)
if (qrcDefintion.count() == 2) {
QString fixedPath = str;
fixedPath.replace(QLatin1String("qrc:") + qrcDefintion.first(), qrcDefintion.last() + QLatin1Char('/'));
- if (QFileInfo(fixedPath).exists()) {
+ if (QFileInfo::exists(fixedPath)) {
fixedPath.replace(QLatin1String("//"), QLatin1String("/"));
fixedPath.replace(QLatin1Char('\\'), QLatin1Char('/'));
return QUrl::fromLocalFile(fixedPath);
diff --git a/src/libs/cplusplus/OverviewModel.cpp b/src/libs/cplusplus/OverviewModel.cpp
index 3b42204be3..7b3649ed03 100644
--- a/src/libs/cplusplus/OverviewModel.cpp
+++ b/src/libs/cplusplus/OverviewModel.cpp
@@ -181,6 +181,7 @@ QVariant OverviewModel::data(const QModelIndex &index, int role) const
if (Template *t = symbol->asTemplate())
if (Symbol *templateDeclaration = t->declaration()) {
QStringList parameters;
+ parameters.reserve(t->templateParameterCount());
for (unsigned i = 0; i < t->templateParameterCount(); ++i)
parameters.append(_overview.prettyName(t->templateParameterAt(i)->name()));
name += QLatin1Char('<') + parameters.join(QLatin1String(", ")) + QLatin1Char('>');
diff --git a/src/libs/extensionsystem/pluginmanager.cpp b/src/libs/extensionsystem/pluginmanager.cpp
index 6998e7bbc4..ad1109ff0f 100644
--- a/src/libs/extensionsystem/pluginmanager.cpp
+++ b/src/libs/extensionsystem/pluginmanager.cpp
@@ -361,7 +361,7 @@ QReadWriteLock *PluginManager::listLock()
*/
void PluginManager::loadPlugins()
{
- return d->loadPlugins();
+ d->loadPlugins();
}
/*!
diff --git a/src/libs/flamegraph/flamegraph.cpp b/src/libs/flamegraph/flamegraph.cpp
index 79627c2dc5..eb7431d179 100644
--- a/src/libs/flamegraph/flamegraph.cpp
+++ b/src/libs/flamegraph/flamegraph.cpp
@@ -155,6 +155,10 @@ int FlameGraph::buildNode(const QModelIndex &parentIndex, QObject *parentObject,
}
}
+ // Root object: attribute all remaining width to "others"
+ if (!parentIndex.isValid())
+ skipped = parentSize - position;
+
if (skipped > 0) {
appendChild(parentObject, parentItem, context, QModelIndex(), position / parentSize,
skipped / parentSize);
diff --git a/src/libs/modelinglib/qmt/diagram_scene/items/stereotypedisplayvisitor.cpp b/src/libs/modelinglib/qmt/diagram_scene/items/stereotypedisplayvisitor.cpp
index c4c01a93fb..b5130477ad 100644
--- a/src/libs/modelinglib/qmt/diagram_scene/items/stereotypedisplayvisitor.cpp
+++ b/src/libs/modelinglib/qmt/diagram_scene/items/stereotypedisplayvisitor.cpp
@@ -147,7 +147,7 @@ void StereotypeDisplayVisitor::visitDItem(const DItem *item)
m_stereotypeSmartDisplay = DObject::StereotypeIcon;
visitDObject(item);
if (m_stereotypeIconId.isEmpty() && !item->shape().isEmpty())
- m_shapeIconId = m_stereotypeController->findStereotypeIconId(StereotypeIcon::ElementItem, QStringList(item->shape()));
+ m_stereotypeIconId = m_stereotypeController->findStereotypeIconId(StereotypeIcon::ElementItem, QStringList(item->shape()));
if (m_shapeIconId.isEmpty() && !item->variety().isEmpty())
m_shapeIconId = m_stereotypeController->findStereotypeIconId(StereotypeIcon::ElementItem, QStringList(item->variety()));
}
diff --git a/src/libs/modelinglib/qmt/model_widgets_ui/propertiesviewmview.cpp b/src/libs/modelinglib/qmt/model_widgets_ui/propertiesviewmview.cpp
index 01f3286ff9..62ceaad1a3 100644
--- a/src/libs/modelinglib/qmt/model_widgets_ui/propertiesviewmview.cpp
+++ b/src/libs/modelinglib/qmt/model_widgets_ui/propertiesviewmview.cpp
@@ -768,7 +768,7 @@ void PropertiesView::MView::visitMAssociation(const MAssociation *association)
this, &PropertiesView::MView::onAssociationEndBKindChanged);
}
if (isSingleSelection) {
- if ((!isValidAssociationKindIndex(m_endAKind->currentIndex())
+ if ((!isValidAssociationKindIndex(m_endBKind->currentIndex())
|| association->endB().kind() != translateIndexToAssociationKind(m_endBKind->currentIndex()))
&& !m_endBKind->hasFocus()) {
m_endBKind->setCurrentIndex(translateAssociationKindToIndex(association->endB().kind()));
diff --git a/src/libs/qmldebug/baseenginedebugclient.cpp b/src/libs/qmldebug/baseenginedebugclient.cpp
index 7f9df78d84..f3e5271e32 100644
--- a/src/libs/qmldebug/baseenginedebugclient.cpp
+++ b/src/libs/qmldebug/baseenginedebugclient.cpp
@@ -193,6 +193,7 @@ void BaseEngineDebugClient::messageReceived(const QByteArray &data)
int count;
ds >> count;
QList<EngineReference> engines;
+ engines.reserve(count);
for (int ii = 0; ii < count; ++ii) {
EngineReference eng;
ds >> eng.m_name;
diff --git a/src/libs/qmleditorwidgets/contextpanewidgetimage.cpp b/src/libs/qmleditorwidgets/contextpanewidgetimage.cpp
index e914bdcbc9..188e19ae7d 100644
--- a/src/libs/qmleditorwidgets/contextpanewidgetimage.cpp
+++ b/src/libs/qmleditorwidgets/contextpanewidgetimage.cpp
@@ -482,7 +482,7 @@ void ContextPaneWidgetImage::setPixmap(const QString &fileName)
if (m_borderImage) {
QString localFileName(fileName);
- if (QFile(fileName).exists()) {
+ if (QFileInfo::exists(fileName)) {
if (fileName.endsWith(QLatin1String("sci"))) {
QString pixmapFileName;
int left = 0;
@@ -527,7 +527,7 @@ void ContextPaneWidgetImage::setPixmap(const QString &fileName)
}
uiBorderImage->label->setPixmap(pix);
} else {
- if (QFile(fileName).exists()) {
+ if (QFileInfo::exists(fileName)) {
QPixmap source(fileName);
previewDialog()->setPixmap(source, 1);
ui->sizeLabel->setText(QString::number(source.width()) + QLatin1Char('x') + QString::number(source.height()));
@@ -703,8 +703,10 @@ static inline bool rangeCheck(int target, int pos)
void PreviewLabel::mousePressEvent(QMouseEvent * event)
{
- if (!m_borderImage)
- return QLabel::mouseMoveEvent(event);
+ if (!m_borderImage) {
+ QLabel::mouseMoveEvent(event);
+ return;
+ }
bool bottom = false;
@@ -790,8 +792,10 @@ static inline int limitPositive(int i)
void PreviewLabel::mouseMoveEvent(QMouseEvent * event)
{
- if (!m_borderImage)
- return QLabel::mouseMoveEvent(event);
+ if (!m_borderImage) {
+ QLabel::mouseMoveEvent(event);
+ return;
+ }
QPoint p = event->pos();
bool bottom = false;
diff --git a/src/libs/qmljs/parser/qmljsast_p.h b/src/libs/qmljs/parser/qmljsast_p.h
index 0a06dace61..0d2b338057 100644
--- a/src/libs/qmljs/parser/qmljsast_p.h
+++ b/src/libs/qmljs/parser/qmljsast_p.h
@@ -223,7 +223,7 @@ public:
static void accept(Node *node, Visitor *visitor);
inline static void acceptChild(Node *node, Visitor *visitor)
- { return accept(node, visitor); } // ### remove
+ { accept(node, visitor); } // ### remove
virtual void accept0(Visitor *visitor) = 0;
virtual SourceLocation firstSourceLocation() const = 0;
diff --git a/src/libs/qmljs/qmljscheck.cpp b/src/libs/qmljs/qmljscheck.cpp
index 66774a43f3..c88e57549e 100644
--- a/src/libs/qmljs/qmljscheck.cpp
+++ b/src/libs/qmljs/qmljscheck.cpp
@@ -124,7 +124,7 @@ public:
fileName.prepend(QLatin1Char('/'));
fileName.prepend(_doc->path());
}
- if (!QFileInfo(fileName).exists())
+ if (!QFileInfo::exists(fileName))
setMessage(WarnFileOrDirectoryDoesNotExist);
}
}
@@ -556,8 +556,7 @@ public:
"Scale",
"Translate",
"Package",
- "Particles",
- "Dialog"})
+ "Particles"})
{
}
diff --git a/src/libs/qmljs/qmljsconstants.h b/src/libs/qmljs/qmljsconstants.h
index 532b74697d..9cbf9fb19b 100644
--- a/src/libs/qmljs/qmljsconstants.h
+++ b/src/libs/qmljs/qmljsconstants.h
@@ -56,11 +56,12 @@ enum Enum {
namespace Severity {
enum Enum
{
- Hint, // cosmetic or convention
- MaybeWarning, // possibly a warning, insufficient information
- Warning, // could cause unintended behavior
- MaybeError, // possibly an error, insufficient information
- Error // definitely an error
+ Hint, // cosmetic or convention
+ MaybeWarning, // possibly a warning, insufficient information
+ Warning, // could cause unintended behavior
+ ReadingTypeInfoWarning, // currently dumping type information
+ MaybeError, // possibly an error, insufficient information
+ Error // definitely an error
};
}
diff --git a/src/libs/qmljs/qmljsdescribevalue.cpp b/src/libs/qmljs/qmljsdescribevalue.cpp
index ad9b2c1337..268266ffcc 100644
--- a/src/libs/qmljs/qmljsdescribevalue.cpp
+++ b/src/libs/qmljs/qmljsdescribevalue.cpp
@@ -325,20 +325,18 @@ void DescribeValueVisitor::visit(const ObjectValue *value)
basicDump("ObjectValue", value, printDetail);
}
if (printDetail) {
- if (value) {
- dumpNewline();
- dump("className:");
- dump(value->className());
- dumpNewline();
- dump("members:");
- openContext("[");
- PrintMembers printMembers(*this);
- value->processMembers(&printMembers);
- closeContext("]");
- dumpNewline();
- dump("prototype:");
- (*this)(value->prototype());
- }
+ dumpNewline();
+ dump("className:");
+ dump(value->className());
+ dumpNewline();
+ dump("members:");
+ openContext("[");
+ PrintMembers printMembers(*this);
+ value->processMembers(&printMembers);
+ closeContext("]");
+ dumpNewline();
+ dump("prototype:");
+ (*this)(value->prototype());
closeContext();
}
--m_depth;
diff --git a/src/libs/qmljs/qmljslink.cpp b/src/libs/qmljs/qmljslink.cpp
index 1f436160c0..eeceb6a786 100644
--- a/src/libs/qmljs/qmljslink.cpp
+++ b/src/libs/qmljs/qmljslink.cpp
@@ -453,8 +453,9 @@ bool LinkPrivate::importLibrary(Document::Ptr doc,
}
}
if (errorLoc.isValid()) {
- warning(doc, errorLoc,
- Link::tr("QML module contains C++ plugins, currently reading type information..."));
+ appendDiagnostic(doc, DiagnosticMessage(Severity::ReadingTypeInfoWarning,
+ errorLoc,
+ Link::tr("QML module contains C++ plugins, currently reading type information...")));
import->valid = false;
}
} else if (libraryInfo.pluginTypeInfoStatus() == LibraryInfo::DumpError
diff --git a/src/libs/qmljs/qmljsmodelmanagerinterface.cpp b/src/libs/qmljs/qmljsmodelmanagerinterface.cpp
index d88b1c261e..65a47b2bd9 100644
--- a/src/libs/qmljs/qmljsmodelmanagerinterface.cpp
+++ b/src/libs/qmljs/qmljsmodelmanagerinterface.cpp
@@ -782,7 +782,8 @@ static bool findNewQmlLibraryInPath(const QString &path,
}
// found a new library!
- qmldirFile.open(QFile::ReadOnly);
+ if (!qmldirFile.open(QFile::ReadOnly))
+ return false;
QString qmldirData = QString::fromUtf8(qmldirFile.readAll());
QmlDirParser qmldirParser;
diff --git a/src/libs/qmljs/qmljsreformatter.cpp b/src/libs/qmljs/qmljsreformatter.cpp
index ab43c03706..6c4befa0f8 100644
--- a/src/libs/qmljs/qmljsreformatter.cpp
+++ b/src/libs/qmljs/qmljsreformatter.cpp
@@ -150,8 +150,12 @@ protected:
void outCommentText(const QString &str)
{
QStringList lines = str.split(QLatin1Char('\n'));
+ bool multiline = lines.length() > 1;
for (int i = 0; i < lines.size(); ++i) {
- _line = lines.at(i); // multiline comments don't keep track of previos lines
+ if (multiline)
+ _line = lines.at(i); // multiline comments don't keep track of previos lines
+ else
+ _line += lines.at(i);
if (i != lines.size() - 1)
newLine();
}
@@ -582,7 +586,7 @@ protected:
out(ast->identifierToken);
}
} else { // signal
- out("signal ");
+ out("signal ", ast->identifierToken);
out(ast->identifierToken);
if (ast->parameters) {
out("(");
diff --git a/src/libs/qmljs/qmljstypedescriptionreader.cpp b/src/libs/qmljs/qmljstypedescriptionreader.cpp
index 4a7f30afc4..8c90b416d7 100644
--- a/src/libs/qmljs/qmljstypedescriptionreader.cpp
+++ b/src/libs/qmljs/qmljstypedescriptionreader.cpp
@@ -641,7 +641,9 @@ void TypeDescriptionReader::readMetaObjectRevisions(UiScriptBinding *ast, FakeMe
void TypeDescriptionReader::readEnumValues(AST::UiScriptBinding *ast, LanguageUtils::FakeMetaEnum *fme)
{
- if (!ast || !ast->statement) {
+ if (!ast)
+ return;
+ if (!ast->statement) {
addError(ast->colonToken, tr("Expected object literal after colon."));
return;
}
diff --git a/src/libs/qtcreatorcdbext/pycdbextmodule.cpp b/src/libs/qtcreatorcdbext/pycdbextmodule.cpp
index 4ca11a777d..2b807d18ac 100644
--- a/src/libs/qtcreatorcdbext/pycdbextmodule.cpp
+++ b/src/libs/qtcreatorcdbext/pycdbextmodule.cpp
@@ -40,6 +40,7 @@
#include <iterator>
static CurrentSymbolGroup currentSymbolGroup;
+static std::string results;
CurrentSymbolGroup::~CurrentSymbolGroup()
{
@@ -338,6 +339,16 @@ static PyObject *cdbext_call(PyObject *, PyObject *args)
return createPythonObject(PyValue(index, symbolGroup));
}
+static PyObject *cdbext_reportResult(PyObject *, PyObject *args)
+{
+ char *result;
+ if (!PyArg_ParseTuple(args, "s", &result))
+ Py_RETURN_NONE;
+
+ results += result;
+ Py_RETURN_NONE;
+}
+
static PyMethodDef cdbextMethods[] = {
{"parseAndEvaluate", cdbext_parseAndEvaluate, METH_VARARGS,
"Returns value of expression or None if the expression can not be resolved"},
@@ -361,6 +372,8 @@ static PyMethodDef cdbextMethods[] = {
"Creates a value with the given type at the given address"},
{"call", cdbext_call, METH_VARARGS,
"Call a function and return a cdbext.Value representing the return value of that function."},
+ {"reportResult", cdbext_reportResult, METH_VARARGS,
+ "Adds a result"},
{NULL, NULL, 0,
NULL} /* Sentinel */
};
@@ -420,3 +433,25 @@ int pointerSize()
{
return ExtensionCommandContext::instance()->control()->IsPointer64Bit() == S_OK ? 8 : 4;
}
+
+std::string collectOutput()
+{
+ // construct a gdbmi output string with two children: messages and result
+ std::stringstream ret;
+ ret << "output=[msg=[";
+ std::istringstream pyStdout(getPyStdout());
+ std::string line;
+ // Add a child to messages for every line.
+ while (std::getline(pyStdout, line)) {
+ // there are two kinds of messages we want to handle here:
+ if (line.find("bridgemessage=") == 0) { // preformatted gdmi bridgemessages from warn()
+ ret << line << ',';
+ } else { // and a line of "normal" python output
+ replace(line, '"', '$'); // otherwise creators gdbmi parser would fail
+ ret << "line=\"" << line << "\",";
+ }
+ }
+ ret << "]," << results << "]";
+ results.clear();
+ return ret.str();
+}
diff --git a/src/libs/qtcreatorcdbext/pycdbextmodule.h b/src/libs/qtcreatorcdbext/pycdbextmodule.h
index f1bc7d4c63..91c05bf12d 100644
--- a/src/libs/qtcreatorcdbext/pycdbextmodule.h
+++ b/src/libs/qtcreatorcdbext/pycdbextmodule.h
@@ -27,11 +27,13 @@
#include <Python.h>
#include <vector>
+#include <string>
#include "dbgeng.h"
void initCdbextPythonModule();
int pointerSize();
+std::string collectOutput();
constexpr bool debugPyCdbextModule = false;
using Bytes = std::vector<char>;
diff --git a/src/libs/qtcreatorcdbext/qtcreatorcdbextension.cpp b/src/libs/qtcreatorcdbext/qtcreatorcdbextension.cpp
index 63e79777fd..f98205db72 100644
--- a/src/libs/qtcreatorcdbext/qtcreatorcdbextension.cpp
+++ b/src/libs/qtcreatorcdbext/qtcreatorcdbextension.cpp
@@ -34,6 +34,7 @@
#ifdef WITH_PYTHON
#include <Python.h>
#include "pystdoutredirect.h"
+#include "pycdbextmodule.h"
#endif
#include <cstdio>
@@ -588,7 +589,7 @@ extern "C" HRESULT CALLBACK script(CIDebugClient *client, PCSTR argsIn)
const char result = (PyRun_SimpleString(command.str().c_str()) == 0) ? 'R' : 'N';
if (PyErr_Occurred())
PyErr_Print();
- ExtensionContext::instance().reportLong(result, token, "script", getPyStdout().c_str());
+ ExtensionContext::instance().reportLong(result, token, "script", collectOutput().c_str());
endCapturePyStdout();
PyErr_Restore(ptype, pvalue, ptraceback);
#else
@@ -849,10 +850,15 @@ extern "C" HRESULT CALLBACK assign(CIDebugClient *client, PCSTR argsIn)
const std::string iname = tokens.front().substr(0, equalsPos);
const std::string value = tokens.front().substr(equalsPos + 1, tokens.front().size() - equalsPos - 1);
// get the symbolgroup
- const int currentFrame = ExtensionContext::instance().symbolGroupFrame();
+ int currentFrame = ExtensionContext::instance().symbolGroupFrame();
if (currentFrame < 0) {
- errorMessage = "No current frame.";
- break;
+ CIDebugControl *control = ExtensionCommandContext::instance()->control();
+ DEBUG_STACK_FRAME frame;
+ if (FAILED(control->GetStackTrace(0, 0, 0, &frame, 1, NULL))) {
+ errorMessage = "No current frame.";
+ break;
+ }
+ currentFrame = frame.FrameNumber;
}
SymbolGroup *symGroup = ExtensionContext::instance().symbolGroup(exc.symbols(), exc.threadId(), currentFrame, &errorMessage);
if (!symGroup)
diff --git a/src/libs/qtcreatorcdbext/symbolgroup.cpp b/src/libs/qtcreatorcdbext/symbolgroup.cpp
index ed9cb0f248..5ea3e8930e 100644
--- a/src/libs/qtcreatorcdbext/symbolgroup.cpp
+++ b/src/libs/qtcreatorcdbext/symbolgroup.cpp
@@ -465,8 +465,11 @@ bool SymbolGroup::assign(const std::string &nodeName,
return false;
}
- return (node->dumperType() & KT_Editable) ? // Edit complex types
- assignType(node, valueEncoding, value, ctx, errorMessage) :
+ int kt = node->dumperType();
+ if (kt < 0)
+ kt = knownType(node->type(), KnownTypeAutoStripPointer | KnownTypeHasClassPrefix);
+ return (kt & KT_Editable) ? // Edit complex types
+ assignType(node, kt, valueEncoding, value, ctx, errorMessage) :
node->assign(value, errorMessage);
}
diff --git a/src/libs/qtcreatorcdbext/symbolgroupvalue.cpp b/src/libs/qtcreatorcdbext/symbolgroupvalue.cpp
index 9c5ff7bc25..d27e6bdf1f 100644
--- a/src/libs/qtcreatorcdbext/symbolgroupvalue.cpp
+++ b/src/libs/qtcreatorcdbext/symbolgroupvalue.cpp
@@ -3552,17 +3552,17 @@ static inline bool assignStdString(SymbolGroupNode *n,
return true;
}
-bool assignType(SymbolGroupNode *n, int valueEncoding, const std::string &value,
+bool assignType(SymbolGroupNode *n, int knownType, int valueEncoding, const std::string &value,
const SymbolGroupValueContext &ctx, std::string *errorMessage)
{
- switch (n->dumperType()) {
+ switch (knownType) {
case KT_QString:
return assignQString(n, valueEncoding, value, ctx, errorMessage);
case KT_QByteArray:
return assignQByteArray(n, valueEncoding, value, ctx, errorMessage);
case KT_StdString:
case KT_StdWString:
- return assignStdString(n, n->dumperType(), valueEncoding, value, ctx, errorMessage);
+ return assignStdString(n, knownType, valueEncoding, value, ctx, errorMessage);
default:
break;
}
diff --git a/src/libs/qtcreatorcdbext/symbolgroupvalue.h b/src/libs/qtcreatorcdbext/symbolgroupvalue.h
index 61c5a67523..b2c89cba47 100644
--- a/src/libs/qtcreatorcdbext/symbolgroupvalue.h
+++ b/src/libs/qtcreatorcdbext/symbolgroupvalue.h
@@ -286,7 +286,7 @@ enum AssignEncoding
AssignHexEncodedUtf16
};
-bool assignType(SymbolGroupNode *n, int valueEncoding, const std::string &value,
+bool assignType(SymbolGroupNode *n, int knownType, int valueEncoding, const std::string &value,
const SymbolGroupValueContext &ctx,
std::string *errorMessage);
diff --git a/src/libs/timeline/qml/MainView.qml b/src/libs/timeline/qml/MainView.qml
index 5a7acac4d0..e6aa2bb15e 100644
--- a/src/libs/timeline/qml/MainView.qml
+++ b/src/libs/timeline/qml/MainView.qml
@@ -92,7 +92,7 @@ Rectangle {
// This is called from outside to synchronize the timeline to other views
function selectByTypeId(typeId)
{
- if (lockItemSelection || typeId === -1)
+ if (lockItemSelection || typeId === -1 || content.typeId === typeId)
return;
var itemIndex = -1;
diff --git a/src/libs/utils/appmainwindow.cpp b/src/libs/utils/appmainwindow.cpp
index 7c9a8afe1f..bdeb3a4cbf 100644
--- a/src/libs/utils/appmainwindow.cpp
+++ b/src/libs/utils/appmainwindow.cpp
@@ -24,6 +24,7 @@
****************************************************************************/
#include "appmainwindow.h"
+#include "theme/theme_p.h"
#ifdef Q_OS_WIN
#include <windows.h>
@@ -60,11 +61,14 @@ void AppMainWindow::raiseWindow()
#ifdef Q_OS_WIN
bool AppMainWindow::event(QEvent *event)
{
- if (event->type() == m_deviceEventId) {
+ const QEvent::Type type = event->type();
+ if (type == m_deviceEventId) {
event->accept();
emit deviceChange();
return true;
}
+ if (type == QEvent::ThemeChange)
+ setThemeApplicationPalette();
return QMainWindow::event(event);
}
diff --git a/src/libs/utils/completinglineedit.cpp b/src/libs/utils/completinglineedit.cpp
index 52d2c5d7f1..5ae7448288 100644
--- a/src/libs/utils/completinglineedit.cpp
+++ b/src/libs/utils/completinglineedit.cpp
@@ -62,7 +62,7 @@ void CompletingLineEdit::keyPressEvent(QKeyEvent *e)
comp->complete();
}
}
- return QLineEdit::keyPressEvent(e);
+ QLineEdit::keyPressEvent(e);
}
} // namespace Utils
diff --git a/src/libs/utils/consoleprocess_unix.cpp b/src/libs/utils/consoleprocess_unix.cpp
index 192f340940..29e3d1845c 100644
--- a/src/libs/utils/consoleprocess_unix.cpp
+++ b/src/libs/utils/consoleprocess_unix.cpp
@@ -31,6 +31,7 @@
#include <utils/qtcassert.h>
#include <QCoreApplication>
+#include <QFileInfo>
#include <QSettings>
#include <QTimer>
@@ -359,7 +360,7 @@ QString ConsoleProcess::defaultTerminalEmulator()
{
if (HostOsInfo::isMacHost()) {
QString termCmd = QCoreApplication::applicationDirPath() + QLatin1String("/../Resources/scripts/openTerminal.command");
- if (QFile(termCmd).exists())
+ if (QFileInfo::exists(termCmd))
return termCmd.replace(QLatin1Char(' '), QLatin1String("\\ "));
return QLatin1String("/usr/X11/bin/xterm");
}
@@ -407,7 +408,7 @@ QString ConsoleProcess::terminalEmulator(const QSettings *settings, bool nonEmpt
void ConsoleProcess::setTerminalEmulator(QSettings *settings, const QString &term)
{
- return settings->setValue(QLatin1String("General/TerminalEmulator"), term);
+ settings->setValue(QLatin1String("General/TerminalEmulator"), term);
}
bool ConsoleProcess::startTerminalEmulator(QSettings *settings, const QString &workingDir)
diff --git a/src/libs/utils/crumblepath.cpp b/src/libs/utils/crumblepath.cpp
index 2d3e7bbb78..e32e344b96 100644
--- a/src/libs/utils/crumblepath.cpp
+++ b/src/libs/utils/crumblepath.cpp
@@ -365,6 +365,7 @@ void CrumblePath::resizeButtons()
// compute relative sizes
QList<int> sizes;
int totalSize = 0;
+ sizes.reserve(m_buttons.length());
for (int i = 0; i < m_buttons.length() ; ++i) {
CrumblePathButton *button = m_buttons.at(i);
diff --git a/src/libs/utils/pathchooser.cpp b/src/libs/utils/pathchooser.cpp
index bc20f85efc..bb79efe8db 100644
--- a/src/libs/utils/pathchooser.cpp
+++ b/src/libs/utils/pathchooser.cpp
@@ -56,7 +56,7 @@ static QString appBundleExpandedPath(const QString &path)
QFileInfo info(path);
if (info.isDir()) {
QString exePath = path + QLatin1String("/Contents/MacOS/") + info.completeBaseName();
- if (QFileInfo(exePath).exists())
+ if (QFileInfo::exists(exePath))
return exePath;
}
}
diff --git a/src/libs/utils/theme/theme.cpp b/src/libs/utils/theme/theme.cpp
index b8147de046..061ff335cc 100644
--- a/src/libs/utils/theme/theme.cpp
+++ b/src/libs/utils/theme/theme.cpp
@@ -57,14 +57,19 @@ Theme *proxyTheme()
return new Theme(m_creatorTheme);
}
+void setThemeApplicationPalette()
+{
+ if (m_creatorTheme && m_creatorTheme->flag(Theme::ApplyThemePaletteGlobally))
+ QApplication::setPalette(m_creatorTheme->palette());
+}
+
void setCreatorTheme(Theme *theme)
{
if (m_creatorTheme == theme)
return;
delete m_creatorTheme;
m_creatorTheme = theme;
- if (theme && theme->flag(Theme::ApplyThemePaletteGlobally))
- QApplication::setPalette(theme->palette());
+ setThemeApplicationPalette();
}
Theme::Theme(const QString &id, QObject *parent)
diff --git a/src/libs/utils/theme/theme_p.h b/src/libs/utils/theme/theme_p.h
index 4170ec7cd9..1feeeda4e2 100644
--- a/src/libs/utils/theme/theme_p.h
+++ b/src/libs/utils/theme/theme_p.h
@@ -51,5 +51,6 @@ public:
};
QTCREATOR_UTILS_EXPORT void setCreatorTheme(Theme *theme);
+QTCREATOR_UTILS_EXPORT void setThemeApplicationPalette();
} // namespace Utils
diff --git a/src/libs/utils/treemodel.cpp b/src/libs/utils/treemodel.cpp
index 5281ab33f5..db8923e372 100644
--- a/src/libs/utils/treemodel.cpp
+++ b/src/libs/utils/treemodel.cpp
@@ -919,11 +919,9 @@ QModelIndex BaseTreeModel::parent(const QModelIndex &idx) const
if (!grandparent)
return QModelIndex();
- for (int i = 0, n = grandparent->childCount(); i < n; ++i)
- if (grandparent->childAt(i) == parent)
- return createIndex(i, 0, static_cast<void*>(parent));
-
- return QModelIndex();
+ // This is on the performance-critical path for ItemViewFind.
+ const int i = grandparent->m_children.indexOf(parent);
+ return createIndex(i, 0, static_cast<void*>(parent));
}
int BaseTreeModel::rowCount(const QModelIndex &idx) const
diff --git a/src/libs/utils/treemodel.h b/src/libs/utils/treemodel.h
index 8782d7b37d..60db234d3b 100644
--- a/src/libs/utils/treemodel.h
+++ b/src/libs/utils/treemodel.h
@@ -66,7 +66,7 @@ public:
using const_iterator = QVector<TreeItem *>::const_iterator;
using value_type = TreeItem *;
- int childCount() const { return end() - begin(); }
+ int childCount() const { return m_children.size(); }
int indexInParent() const;
TreeItem *childAt(int index) const;
int indexOf(const TreeItem *item) const;
diff --git a/src/libs/utils/unixutils.cpp b/src/libs/utils/unixutils.cpp
index f08ee196c8..7db05c22ea 100644
--- a/src/libs/utils/unixutils.cpp
+++ b/src/libs/utils/unixutils.cpp
@@ -47,7 +47,7 @@ QString UnixUtils::fileBrowser(const QSettings *settings)
void UnixUtils::setFileBrowser(QSettings *settings, const QString &term)
{
- return settings->setValue(QLatin1String("General/FileBrowser"), term);
+ settings->setValue(QLatin1String("General/FileBrowser"), term);
}
diff --git a/src/plugins/android/android.pro b/src/plugins/android/android.pro
index 0df9a4a4ae..3d63124af5 100644
--- a/src/plugins/android/android.pro
+++ b/src/plugins/android/android.pro
@@ -47,7 +47,10 @@ HEADERS += \
android_global.h \
androidbuildapkstep.h \
androidbuildapkwidget.h \
- androidrunnable.h
+ androidrunnable.h \
+ androidtoolmanager.h \
+ androidsdkmanager.h \
+ androidavdmanager.h
SOURCES += \
androidconfigurations.cpp \
@@ -88,7 +91,10 @@ SOURCES += \
androidbuildapkstep.cpp \
androidbuildapkwidget.cpp \
androidqtsupport.cpp \
- androidrunnable.cpp
+ androidrunnable.cpp \
+ androidtoolmanager.cpp \
+ androidsdkmanager.cpp \
+ androidavdmanager.cpp
FORMS += \
androidsettingswidget.ui \
diff --git a/src/plugins/android/android.qbs b/src/plugins/android/android.qbs
index 1bb3296453..c3a2551bae 100644
--- a/src/plugins/android/android.qbs
+++ b/src/plugins/android/android.qbs
@@ -22,6 +22,8 @@ Project {
"android.qrc",
"androidanalyzesupport.cpp",
"androidanalyzesupport.h",
+ "androidavdmanager.cpp",
+ "androidavdmanager.h",
"androidconfigurations.cpp",
"androidconfigurations.h",
"androidconstants.h",
@@ -84,6 +86,8 @@ Project {
"androidrunnable.h",
"androidrunner.cpp",
"androidrunner.h",
+ "androidsdkmanager.cpp",
+ "androidsdkmanager.h",
"androidsettingspage.cpp",
"androidsettingspage.h",
"androidsettingswidget.cpp",
@@ -93,6 +97,8 @@ Project {
"androidsignaloperation.h",
"androidtoolchain.cpp",
"androidtoolchain.h",
+ "androidtoolmanager.cpp",
+ "androidtoolmanager.h",
"avddialog.cpp",
"avddialog.h",
"certificatesmodel.cpp",
diff --git a/src/plugins/android/androidavdmanager.cpp b/src/plugins/android/androidavdmanager.cpp
new file mode 100644
index 0000000000..028fe2c797
--- /dev/null
+++ b/src/plugins/android/androidavdmanager.cpp
@@ -0,0 +1,441 @@
+/****************************************************************************
+**
+** 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 "androidavdmanager.h"
+
+#include "androidtoolmanager.h"
+
+#include "utils/algorithm.h"
+#include "utils/qtcassert.h"
+#include "utils/runextensions.h"
+#include "utils/synchronousprocess.h"
+
+#include <QApplication>
+#include <QFileInfo>
+#include <QLoggingCategory>
+#include <QSettings>
+
+#include <chrono>
+
+namespace {
+Q_LOGGING_CATEGORY(avdManagerLog, "qtc.android.avdManager")
+}
+
+namespace Android {
+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 QVersionNumber avdManagerIntroVersion(25, 3 ,0);
+
+const int avdCreateTimeoutMs = 30000;
+
+/*!
+ Runs the \c avdmanager tool specific to configuration \a config with arguments \a args. Returns
+ \c true if the command is successfully executed. Output is copied into \a output. The function
+ blocks the calling thread.
+ */
+static bool avdManagerCommand(const AndroidConfig config, const QStringList &args, QString *output)
+{
+ QString avdManagerToolPath = config.avdManagerToolPath().toString();
+ Utils::SynchronousProcess proc;
+ Utils::SynchronousProcessResponse response = proc.runBlocking(avdManagerToolPath, args);
+ if (response.result == Utils::SynchronousProcessResponse::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();
+ return true;
+ }
+ return false;
+}
+
+static bool checkForTimeout(const chrono::steady_clock::time_point &start,
+ int msecs = 3000)
+{
+ bool timedOut = false;
+ auto end = chrono::steady_clock::now();
+ if (chrono::duration_cast<chrono::milliseconds>(end-start).count() > msecs)
+ timedOut = true;
+ return timedOut;
+}
+
+static AndroidConfig::CreateAvdInfo createAvdCommand(const AndroidConfig config,
+ const AndroidConfig::CreateAvdInfo &info)
+{
+ AndroidConfig::CreateAvdInfo result = info;
+
+ if (!result.isValid()) {
+ qCDebug(avdManagerLog) << "AVD Create failed. Invalid CreateAvdInfo" << result.name
+ << result.target.name << result.target.apiLevel;
+ result.error = QApplication::translate("AndroidAvdManager",
+ "Cannot create AVD. Invalid input.");
+ return result;
+ }
+
+ QStringList arguments({"create", "avd", "-k", result.target.package, "-n", result.name});
+
+ if (!result.abi.isEmpty()) {
+ SystemImage image = Utils::findOrDefault(result.target.systemImages,
+ Utils::equal(&SystemImage::abiName, result.abi));
+ if (image.isValid()) {
+ arguments << "-k" << image.package;
+ } else {
+ qCDebug(avdManagerLog) << "AVD Create failed. Cannot find system image for the platform"
+ << result.abi << result.target.name;
+ result.error = QApplication::translate("AndroidAvdManager",
+ "Cannot create AVD. Cannot find system image for "
+ "the ABI %1(%2).").arg(result.abi).arg(result.target.name);
+ return result;
+ }
+
+ } else {
+ arguments << "-k" << result.target.package;
+ }
+
+ if (result.sdcardSize > 0)
+ arguments << "-c" << QString::fromLatin1("%1M").arg(result.sdcardSize);
+
+ QProcess proc;
+ proc.start(config.avdManagerToolPath().toString(), arguments);
+ if (!proc.waitForStarted()) {
+ result.error = QApplication::translate("AndroidAvdManager",
+ "Could not start process \"%1 %2\"")
+ .arg(config.avdManagerToolPath().toString(), arguments.join(' '));
+ return result;
+ }
+ QTC_CHECK(proc.state() == QProcess::Running);
+ proc.write(QByteArray("yes\n")); // yes to "Do you wish to create a custom hardware profile"
+
+ auto start = chrono::steady_clock::now();
+ QString errorOutput;
+ QByteArray question;
+ while (errorOutput.isEmpty()) {
+ proc.waitForReadyRead(500);
+ question += proc.readAllStandardOutput();
+ if (question.endsWith(QByteArray("]:"))) {
+ // truncate to last line
+ int index = question.lastIndexOf(QByteArray("\n"));
+ if (index != -1)
+ question = question.mid(index);
+ if (question.contains("hw.gpu.enabled"))
+ proc.write(QByteArray("yes\n"));
+ else
+ proc.write(QByteArray("\n"));
+ question.clear();
+ }
+ // The exit code is always 0, so we need to check stderr
+ // For now assume that any output at all indicates a error
+ errorOutput = QString::fromLocal8Bit(proc.readAllStandardError());
+ if (proc.state() != QProcess::Running)
+ break;
+
+ // For a sane input and command, process should finish before timeout.
+ if (checkForTimeout(start, avdCreateTimeoutMs)) {
+ result.error = QApplication::translate("AndroidAvdManager",
+ "Cannot create AVD. Command timed out.");
+ }
+ }
+
+ // Kill the running process.
+ if (proc.state() != QProcess::NotRunning) {
+ proc.terminate();
+ if (!proc.waitForFinished(3000))
+ proc.kill();
+ }
+
+ QTC_CHECK(proc.state() == QProcess::NotRunning);
+ result.error = errorOutput;
+ return result;
+}
+
+/*!
+ \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_androidTool(new AndroidToolManager(m_config)),
+ m_parser(new AvdManagerOutputParser)
+{
+
+}
+
+AndroidAvdManager::~AndroidAvdManager()
+{
+
+}
+
+bool AndroidAvdManager::avdManagerUiToolAvailable() const
+{
+ return m_config.sdkToolsVersion() < avdManagerIntroVersion;
+}
+
+void AndroidAvdManager::launchAvdManagerUiTool() const
+{
+ if (avdManagerUiToolAvailable()) {
+ m_androidTool->launchAvdManager();
+ } else {
+ qCDebug(avdManagerLog) << "AVD Ui tool launch failed. UI tool not available"
+ << m_config.sdkToolsVersion();
+ }
+}
+
+QFuture<AndroidConfig::CreateAvdInfo>
+AndroidAvdManager::createAvd(AndroidConfig::CreateAvdInfo info) const
+{
+ if (m_config.sdkToolsVersion() < avdManagerIntroVersion)
+ return m_androidTool->createAvd(info);
+
+ return Utils::runAsync(&createAvdCommand, m_config, info);
+}
+
+bool AndroidAvdManager::removeAvd(const QString &name) const
+{
+ if (m_config.sdkToolsVersion() < avdManagerIntroVersion)
+ return m_androidTool->removeAvd(name);
+
+ Utils::SynchronousProcess proc;
+ proc.setTimeoutS(5);
+ Utils::SynchronousProcessResponse response
+ = proc.runBlocking(m_config.avdManagerToolPath().toString(),
+ QStringList({"delete", "avd", "-n", name}));
+ return response.result == Utils::SynchronousProcessResponse::Finished && response.exitCode == 0;
+}
+
+QFuture<AndroidDeviceInfoList> AndroidAvdManager::avdList() const
+{
+ if (m_config.sdkToolsVersion() < avdManagerIntroVersion)
+ return m_androidTool->androidVirtualDevicesFuture();
+
+ return Utils::runAsync(&AvdManagerOutputParser::listVirtualDevices, m_parser.get(), m_config);
+}
+
+QString AndroidAvdManager::startAvd(const QString &name) const
+{
+ if (!findAvd(name).isEmpty() || startAvdAsync(name))
+ return waitForAvd(name);
+ return QString();
+}
+
+bool AndroidAvdManager::startAvdAsync(const QString &avdName) const
+{
+ QProcess *avdProcess = new QProcess();
+ QObject::connect(avdProcess, static_cast<void (QProcess::*)(int)>(&QProcess::finished),
+ avdProcess, &QObject::deleteLater);
+
+ // start the emulator
+ QStringList arguments;
+ if (AndroidConfigurations::force32bitEmulator())
+ arguments << "-force-32bit";
+
+ arguments << "-partition-size" << QString::number(m_config.partitionSize())
+ << "-avd" << avdName;
+ avdProcess->start(m_config.emulatorToolPath().toString(), arguments);
+ if (!avdProcess->waitForStarted(-1)) {
+ delete avdProcess;
+ return false;
+ }
+ return true;
+}
+
+QString AndroidAvdManager::findAvd(const QString &avdName) const
+{
+ QVector<AndroidDeviceInfo> devices = m_config.connectedDevices();
+ foreach (AndroidDeviceInfo device, devices) {
+ if (device.type != AndroidDeviceInfo::Emulator)
+ continue;
+ if (device.avdname == avdName)
+ return device.serialNumber;
+ }
+ return QString();
+}
+
+QString AndroidAvdManager::waitForAvd(const QString &avdName, const QFutureInterface<bool> &fi) const
+{
+ // we cannot use adb -e wait-for-device, since that doesn't work if a emulator is already running
+ // 60 rounds of 2s sleeping, two minutes for the avd to start
+ QString serialNumber;
+ for (int i = 0; i < 60; ++i) {
+ if (fi.isCanceled())
+ return QString();
+ serialNumber = findAvd(avdName);
+ if (!serialNumber.isEmpty())
+ return waitForBooted(serialNumber, fi) ? serialNumber : QString();
+ QThread::sleep(2);
+ }
+ return QString();
+}
+
+bool AndroidAvdManager::isAvdBooted(const QString &device) const
+{
+ QStringList arguments = AndroidDeviceInfo::adbSelector(device);
+ arguments << "shell" << "getprop" << "init.svc.bootanim";
+
+ Utils::SynchronousProcess adbProc;
+ adbProc.setTimeoutS(10);
+ Utils::SynchronousProcessResponse response =
+ adbProc.runBlocking(m_config.adbToolPath().toString(), arguments);
+ if (response.result != Utils::SynchronousProcessResponse::Finished)
+ return false;
+ QString value = response.allOutput().trimmed();
+ return value == "stopped";
+}
+
+bool AndroidAvdManager::waitForBooted(const QString &serialNumber, const QFutureInterface<bool> &fi) const
+{
+ // found a serial number, now wait until it's done booting...
+ for (int i = 0; i < 60; ++i) {
+ if (fi.isCanceled())
+ return false;
+ if (isAvdBooted(serialNumber)) {
+ return true;
+ } else {
+ QThread::sleep(2);
+ if (!m_config.isConnected(serialNumber)) // device was disconnected
+ return false;
+ }
+ }
+ return false;
+}
+
+AndroidDeviceInfoList AvdManagerOutputParser::listVirtualDevices(const AndroidConfig &config)
+{
+ QString output;
+ if (!avdManagerCommand(config, QStringList({"list", "avd"}), &output)) {
+ qCDebug(avdManagerLog) << "Avd list command failed" << output << config.sdkToolsVersion();
+ return {};
+ }
+ return parseAvdList(output);
+}
+
+AndroidDeviceInfoList AvdManagerOutputParser::parseAvdList(const QString &output)
+{
+ AndroidDeviceInfoList avdList;
+ QStringList avdInfo;
+ auto parseAvdInfo = [&avdInfo, &avdList, this] () {
+ AndroidDeviceInfo avd;
+ if (parseAvd(avdInfo, &avd)) {
+ // armeabi-v7a devices can also run armeabi code
+ if (avd.cpuAbi.contains("armeabi-v7a"))
+ avd.cpuAbi << "armeabi";
+ avd.state = AndroidDeviceInfo::OkState;
+ avd.type = AndroidDeviceInfo::Emulator;
+ avdList << avd;
+ } else {
+ qCDebug(avdManagerLog) << "Avd Parsing: Parsing failed: " << avdInfo;
+ }
+ avdInfo.clear();
+ };
+
+ foreach (QString line, output.split('\n')) {
+ if (line.startsWith("---------") || line.isEmpty()) {
+ parseAvdInfo();
+ } else {
+ avdInfo << line;
+ }
+ }
+
+ if (!avdInfo.isEmpty())
+ parseAvdInfo();
+
+ Utils::sort(avdList);
+
+ return avdList;
+}
+
+bool AvdManagerOutputParser::parseAvd(const QStringList &deviceInfo, AndroidDeviceInfo *avd)
+{
+ QTC_ASSERT(avd, return false);
+ foreach (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::FileName avdPath = Utils::FileName::fromString(value);
+ if (avdPath.exists())
+ {
+ // Get ABI.
+ Utils::FileName configFile = avdPath;
+ configFile.appendPath("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
+ Utils::FileName avdInfoFile = avdPath.parentDir();
+ QString avdInfoFileName = avdPath.toFileInfo().baseName() + ".ini";
+ avdInfoFile.appendPath(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();
+ }
+ }
+ }
+ return true;
+}
+
+} // namespace Internal
+} // namespace Android
diff --git a/src/plugins/android/androidavdmanager.h b/src/plugins/android/androidavdmanager.h
new file mode 100644
index 0000000000..4e8633efda
--- /dev/null
+++ b/src/plugins/android/androidavdmanager.h
@@ -0,0 +1,66 @@
+/****************************************************************************
+**
+** 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 "androidconfigurations.h"
+
+#include <memory>
+
+namespace Android {
+namespace Internal {
+
+class AndroidToolManager;
+class AvdManagerOutputParser;
+
+class AndroidAvdManager
+{
+public:
+ AndroidAvdManager(const AndroidConfig& config = AndroidConfigurations::currentConfig());
+ ~AndroidAvdManager();
+
+ bool avdManagerUiToolAvailable() const;
+ void launchAvdManagerUiTool() const;
+ QFuture<AndroidConfig::CreateAvdInfo> createAvd(AndroidConfig::CreateAvdInfo info) const;
+ bool removeAvd(const QString &name) const;
+ QFuture<AndroidDeviceInfoList> avdList() const;
+
+ QString startAvd(const QString &name) const;
+ bool startAvdAsync(const QString &avdName) const;
+ QString findAvd(const QString &avdName) const;
+ QString waitForAvd(const QString &avdName,
+ const QFutureInterface<bool> &fi = QFutureInterface<bool>()) const;
+ bool isAvdBooted(const QString &device) const;
+
+private:
+ bool waitForBooted(const QString &serialNumber, const QFutureInterface<bool> &fi) const;
+
+private:
+ const AndroidConfig &m_config;
+ std::unique_ptr<AndroidToolManager> m_androidTool;
+ std::unique_ptr<AvdManagerOutputParser> m_parser;
+};
+
+} // namespace Internal
+} // namespace Android
diff --git a/src/plugins/android/androidbuildapkstep.cpp b/src/plugins/android/androidbuildapkstep.cpp
index 0ff998809f..9966b21faf 100644
--- a/src/plugins/android/androidbuildapkstep.cpp
+++ b/src/plugins/android/androidbuildapkstep.cpp
@@ -60,6 +60,8 @@
namespace Android {
using namespace Internal;
+const QVersionNumber gradleScriptRevokedSdkVersion(25, 3, 0);
+const QVersionNumber gradleScriptsContainedQtVersion(5, 9, 0);
const QLatin1String DeployActionKey("Qt4ProjectManager.AndroidDeployQtStep.DeployQtAction");
const QLatin1String KeystoreLocationKey("KeystoreLocation");
const QLatin1String BuildTargetSdkKey("BuildTargetSdk");
@@ -140,6 +142,15 @@ bool AndroidBuildApkStep::init(QList<const BuildStep *> &earlierSteps)
if (!version)
return false;
+ if (AndroidConfigurations::currentConfig().sdkToolsVersion() >= gradleScriptRevokedSdkVersion &&
+ QVersionNumber::fromString(version->qtVersionString()) < gradleScriptsContainedQtVersion) {
+ emit addOutput(tr("The installed SDK tools version (%1) does not include Gradle scripts. The "
+ "minimum Qt version required for Gradle build to work is %2")
+ .arg(gradleScriptRevokedSdkVersion.toString())
+ .arg(gradleScriptsContainedQtVersion.toString()), OutputFormat::Stderr);
+ return false;
+ }
+
int minSDKForKit = AndroidManager::minimumSDK(target()->kit());
if (AndroidManager::minimumSDK(target()) < minSDKForKit) {
emit addOutput(tr("The API level set for the APK is less than the minimum required by the kit."
@@ -342,6 +353,16 @@ void AndroidBuildApkStep::setUseGradle(bool b)
}
}
+bool AndroidBuildApkStep::addDebugger() const
+{
+ return m_addDebugger;
+}
+
+void AndroidBuildApkStep::setAddDebugger(bool debug)
+{
+ m_addDebugger = debug;
+}
+
bool AndroidBuildApkStep::verboseOutput() const
{
return m_verbose;
diff --git a/src/plugins/android/androidbuildapkstep.h b/src/plugins/android/androidbuildapkstep.h
index 0d044c0ccc..eae827eb15 100644
--- a/src/plugins/android/androidbuildapkstep.h
+++ b/src/plugins/android/androidbuildapkstep.h
@@ -73,6 +73,9 @@ public:
bool useGradle() const;
void setUseGradle(bool b);
+ bool addDebugger() const;
+ void setAddDebugger(bool debug);
+
QString buildTargetSdk() const;
void setBuildTargetSdk(const QString &sdk);
@@ -99,9 +102,10 @@ protected:
AndroidDeployAction m_deployAction = BundleLibrariesDeployment;
bool m_signPackage = false;
bool m_verbose = false;
- bool m_useGradle = false;
+ bool m_useGradle = true; // Ant builds are deprecated.
bool m_openPackageLocation = false;
bool m_openPackageLocationForRun = false;
+ bool m_addDebugger = true;
QString m_buildTargetSdk;
Utils::FileName m_keystorePath;
diff --git a/src/plugins/android/androidbuildapkwidget.cpp b/src/plugins/android/androidbuildapkwidget.cpp
index 2e85c243fc..97dd4695bd 100644
--- a/src/plugins/android/androidbuildapkwidget.cpp
+++ b/src/plugins/android/androidbuildapkwidget.cpp
@@ -54,9 +54,12 @@ AndroidBuildApkWidget::AndroidBuildApkWidget(AndroidBuildApkStep *step)
{
m_ui->setupUi(this);
+ m_ui->deprecatedInfoIconLabel->setPixmap(Utils::Icons::INFO.pixmap());
+
// Target sdk combobox
int minApiLevel = 9;
- QStringList targets = AndroidConfig::apiLevelNamesFor(AndroidConfigurations::currentConfig().sdkTargets(minApiLevel));
+ const AndroidConfig &config = AndroidConfigurations::currentConfig();
+ QStringList targets = AndroidConfig::apiLevelNamesFor(config.sdkTargets(minApiLevel));
targets.removeDuplicates();
m_ui->targetSDKComboBox->addItems(targets);
m_ui->targetSDKComboBox->setCurrentIndex(targets.indexOf(AndroidManager::buildTargetSDK(step->target())));
@@ -91,9 +94,12 @@ AndroidBuildApkWidget::AndroidBuildApkWidget(AndroidBuildApkStep *step)
m_ui->signingDebugDeployErrorIcon->setPixmap(Utils::Icons::CRITICAL.pixmap());
signPackageCheckBoxToggled(m_step->signPackage());
- m_ui->useGradleCheckBox->setChecked(m_step->useGradle());
+ m_ui->useGradleCheckBox->setEnabled(config.antScriptsAvailable());
+ m_ui->useGradleCheckBox->setChecked(!config.antScriptsAvailable() ||
+ m_step->useGradle());
m_ui->verboseOutputCheckBox->setChecked(m_step->verboseOutput());
m_ui->openPackageLocationCheckBox->setChecked(m_step->openPackageLocation());
+ m_ui->addDebuggerCheckBox->setChecked(m_step->addDebugger());
// target sdk
connect(m_ui->targetSDKComboBox,
@@ -120,6 +126,8 @@ AndroidBuildApkWidget::AndroidBuildApkWidget(AndroidBuildApkStep *step)
this, &AndroidBuildApkWidget::openPackageLocationCheckBoxToggled);
connect(m_ui->verboseOutputCheckBox, &QAbstractButton::toggled,
this, &AndroidBuildApkWidget::verboseOutputCheckBoxToggled);
+ connect(m_ui->addDebuggerCheckBox, &QAbstractButton::toggled,
+ m_step, &AndroidBuildApkStep::setAddDebugger);
//signing
connect(m_ui->signPackageCheckBox, &QAbstractButton::toggled,
@@ -185,6 +193,7 @@ void AndroidBuildApkWidget::signPackageCheckBoxToggled(bool checked)
{
m_ui->certificatesAliasComboBox->setEnabled(checked);
m_step->setSignPackage(checked);
+ m_ui->addDebuggerCheckBox->setChecked(!checked);
updateSigningWarning();
if (!checked)
return;
diff --git a/src/plugins/android/androidbuildapkwidget.ui b/src/plugins/android/androidbuildapkwidget.ui
index e5565873af..fa3c1ef3d6 100644
--- a/src/plugins/android/androidbuildapkwidget.ui
+++ b/src/plugins/android/androidbuildapkwidget.ui
@@ -7,7 +7,7 @@
<x>0</x>
<y>0</y>
<width>819</width>
- <height>390</height>
+ <height>478</height>
</rect>
</property>
<property name="windowTitle">
@@ -176,24 +176,75 @@ Deploying local Qt libraries is incompatible with Android 5.</string>
<string>Advanced Actions</string>
</property>
<layout class="QGridLayout" name="gridLayout">
- <item row="2" column="0">
- <widget class="QCheckBox" name="verboseOutputCheckBox">
+ <item row="0" column="0">
+ <widget class="QCheckBox" name="useGradleCheckBox">
+ <property name="sizePolicy">
+ <sizepolicy hsizetype="Maximum" vsizetype="Fixed">
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
<property name="text">
- <string>Verbose output</string>
+ <string>Use Gradle (Ant builds are deprecated)</string>
+ </property>
+ </widget>
+ </item>
+ <item row="0" column="1">
+ <widget class="QLabel" name="deprecatedInfoIconLabel">
+ <property name="sizePolicy">
+ <sizepolicy hsizetype="Fixed" vsizetype="Fixed">
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ <property name="toolTip">
+ <string>Gradle builds are forced from Android SDK tools version 25.3.0 onwards as Ant scripts are no longer available.</string>
+ </property>
+ <property name="text">
+ <string/>
</property>
</widget>
</item>
- <item row="1" column="0">
+ <item row="0" column="2">
+ <spacer name="horizontalSpacer">
+ <property name="orientation">
+ <enum>Qt::Horizontal</enum>
+ </property>
+ <property name="sizeType">
+ <enum>QSizePolicy::Preferred</enum>
+ </property>
+ <property name="sizeHint" stdset="0">
+ <size>
+ <width>0</width>
+ <height>0</height>
+ </size>
+ </property>
+ </spacer>
+ </item>
+ <item row="1" column="0" colspan="3">
<widget class="QCheckBox" name="openPackageLocationCheckBox">
<property name="text">
<string>Open package location after build</string>
</property>
</widget>
</item>
- <item row="0" column="0">
- <widget class="QCheckBox" name="useGradleCheckBox">
+ <item row="2" column="0" colspan="3">
+ <widget class="QCheckBox" name="verboseOutputCheckBox">
+ <property name="text">
+ <string>Verbose output</string>
+ </property>
+ </widget>
+ </item>
+ <item row="3" column="0" colspan="3">
+ <widget class="QCheckBox" name="addDebuggerCheckBox">
+ <property name="enabled">
+ <bool>false</bool>
+ </property>
+ <property name="toolTip">
+ <string>Packages debug server with the APK to enable debugging. For the signed APK this option is unchecked by default.</string>
+ </property>
<property name="text">
- <string>Use Gradle</string>
+ <string>Add debug server</string>
</property>
</widget>
</item>
@@ -254,5 +305,22 @@ The APK will not be usable on any other device.</string>
</customwidget>
</customwidgets>
<resources/>
- <connections/>
+ <connections>
+ <connection>
+ <sender>signPackageCheckBox</sender>
+ <signal>clicked(bool)</signal>
+ <receiver>addDebuggerCheckBox</receiver>
+ <slot>setEnabled(bool)</slot>
+ <hints>
+ <hint type="sourcelabel">
+ <x>113</x>
+ <y>178</y>
+ </hint>
+ <hint type="destinationlabel">
+ <x>510</x>
+ <y>452</y>
+ </hint>
+ </hints>
+ </connection>
+ </connections>
</ui>
diff --git a/src/plugins/android/androidconfigurations.cpp b/src/plugins/android/androidconfigurations.cpp
index 851b0f2350..42027743b8 100644
--- a/src/plugins/android/androidconfigurations.cpp
+++ b/src/plugins/android/androidconfigurations.cpp
@@ -28,8 +28,11 @@
#include "androidtoolchain.h"
#include "androiddevice.h"
#include "androidgdbserverkitinformation.h"
+#include "androidmanager.h"
#include "androidqtversion.h"
#include "androiddevicedialog.h"
+#include "androidsdkmanager.h"
+#include "androidtoolmanager.h"
#include "avddialog.h"
#include <coreplugin/icore.h>
@@ -73,6 +76,9 @@ namespace Android {
using namespace Internal;
namespace {
+
+ const QVersionNumber sdkToolsAntMissingVersion(25, 3, 0);
+
const QLatin1String SettingsGroup("AndroidConfigurations");
const QLatin1String SDKLocationKey("SDKLocation");
const QLatin1String NDKLocationKey("NDKLocation");
@@ -107,39 +113,14 @@ namespace {
const QLatin1String keytoolName("keytool");
const QLatin1String changeTimeStamp("ChangeTimeStamp");
+ const QLatin1String sdkToolsVersionKey("Pkg.Revision");
+
static QString sdkSettingsFileName()
{
return QFileInfo(Core::ICore::settings(QSettings::SystemScope)->fileName()).absolutePath()
+ QLatin1String("/qtcreator/android.xml");
}
- bool androidDevicesLessThan(const AndroidDeviceInfo &dev1, const AndroidDeviceInfo &dev2)
- {
- if (dev1.serialNumber.contains(QLatin1String("????")) != dev2.serialNumber.contains(QLatin1String("????")))
- return !dev1.serialNumber.contains(QLatin1String("????"));
- if (dev1.type != dev2.type)
- return dev1.type == AndroidDeviceInfo::Hardware;
- if (dev1.sdk != dev2.sdk)
- return dev1.sdk < dev2.sdk;
- if (dev1.avdname != dev2.avdname)
- return dev1.avdname < dev2.avdname;
-
- return dev1.serialNumber < dev2.serialNumber;
- }
-
- static QStringList cleanAndroidABIs(const QStringList &abis)
- {
- QStringList res;
- foreach (const QString &abi, abis) {
- int index = abi.lastIndexOf(QLatin1Char('/'));
- if (index == -1)
- res << abi;
- else
- res << abi.mid(index + 1);
- }
- return res;
- }
-
static bool is32BitUserSpace()
{
// Do the exact same check as android's emulator is doing:
@@ -162,25 +143,6 @@ namespace {
}
return false;
}
-
- // Some preview sdks use a non integer version
- int apiLevelFromAndroidList(const QString &string)
- {
- bool ok;
- int result = string.toInt(&ok);
- if (ok)
- return result;
- Utils::FileName sdkLocation = AndroidConfigurations::currentConfig().sdkLocation();
- sdkLocation.appendPath(QLatin1String("/platforms/android-") + string + QLatin1String("/source.properties"));
- result = QSettings(sdkLocation.toString(), QSettings::IniFormat).value(QLatin1String("AndroidVersion.ApiLevel")).toInt(&ok);
- if (ok)
- return result;
- if (string == QLatin1String("L"))
- return 21;
- if (string == QLatin1String("MNC"))
- return 22;
- return 23; // At least
- }
}
//////////////////////////////////
@@ -359,61 +321,14 @@ void AndroidConfig::updateNdkInformation() const
m_NdkInformationUpToDate = true;
}
-bool AndroidConfig::sortSdkPlatformByApiLevel(const SdkPlatform &a, const SdkPlatform &b)
-{
- if (a.apiLevel != b.apiLevel)
- return a.apiLevel > b.apiLevel;
- if (a.name != b.name)
- return a.name < b.name;
- return false;
-}
-
void AndroidConfig::updateAvailableSdkPlatforms() const
{
if (m_availableSdkPlatformsUpToDate)
return;
- m_availableSdkPlatforms.clear();
-
- SynchronousProcess proc;
- proc.setProcessEnvironment(androidToolEnvironment().toProcessEnvironment());
- SynchronousProcessResponse response
- = proc.runBlocking(androidToolPath().toString(),
- QStringList({"list", "target"})); // list available AVDs
- if (response.result != SynchronousProcessResponse::Finished)
- return;
-
- SdkPlatform platform;
- foreach (const QString &l, response.allOutput().split('\n')) {
- const QString line = l.trimmed();
- if (line.startsWith(QLatin1String("id:")) && line.contains(QLatin1String("android-"))) {
- int index = line.indexOf(QLatin1String("\"android-"));
- if (index == -1)
- continue;
- QString androidTarget = line.mid(index + 1, line.length() - index - 2);
- const QString tmp = androidTarget.mid(androidTarget.lastIndexOf(QLatin1Char('-')) + 1);
- platform.apiLevel = apiLevelFromAndroidList(tmp);
- } else if (line.startsWith(QLatin1String("Name:"))) {
- platform.name = line.mid(6);
- } else if (line.startsWith(QLatin1String("Tag/ABIs :"))) {
- platform.abis = cleanAndroidABIs(line.mid(10).trimmed().split(QLatin1String(", ")));
- } else if (line.startsWith(QLatin1String("ABIs"))) {
- platform.abis = cleanAndroidABIs(line.mid(6).trimmed().split(QLatin1String(", ")));
- } else if (line.startsWith(QLatin1String("---")) || line.startsWith(QLatin1String("==="))) {
- if (platform.apiLevel == -1)
- continue;
- auto it = std::lower_bound(m_availableSdkPlatforms.begin(), m_availableSdkPlatforms.end(),
- platform, sortSdkPlatformByApiLevel);
- m_availableSdkPlatforms.insert(it, platform);
- platform = SdkPlatform();
- }
- }
-
- if (platform.apiLevel != -1) {
- auto it = std::lower_bound(m_availableSdkPlatforms.begin(), m_availableSdkPlatforms.end(),
- platform, sortSdkPlatformByApiLevel);
- m_availableSdkPlatforms.insert(it, platform);
- }
+ m_availableSdkPlatforms.clear();
+ AndroidSdkManager sdkManager(*this);
+ m_availableSdkPlatforms = sdkManager.availableSdkPlatforms();
m_availableSdkPlatformsUpToDate = true;
}
@@ -446,18 +361,6 @@ FileName AndroidConfig::adbToolPath() const
return path.appendPath(QLatin1String("platform-tools/adb" QTC_HOST_EXE_SUFFIX));
}
-Environment AndroidConfig::androidToolEnvironment() const
-{
- Environment env = Environment::systemEnvironment();
- if (!m_openJDKLocation.isEmpty()) {
- env.set(QLatin1String("JAVA_HOME"), m_openJDKLocation.toUserOutput());
- Utils::FileName binPath = m_openJDKLocation;
- binPath.appendPath(QLatin1String("bin"));
- env.prependOrSetPath(binPath.toUserOutput());
- }
- return env;
-}
-
FileName AndroidConfig::androidToolPath() const
{
if (HostOsInfo::isWindowsHost()) {
@@ -486,7 +389,10 @@ FileName AndroidConfig::antToolPath() const
FileName AndroidConfig::emulatorToolPath() const
{
FileName path = m_sdkLocation;
- return path.appendPath(QLatin1String("tools/emulator" QTC_HOST_EXE_SUFFIX));
+ QString relativePath = "emulator/emulator";
+ if (sdkToolsVersion() < QVersionNumber(25, 3, 0))
+ relativePath = "tools/emulator";
+ return path.appendPath(relativePath + QTC_HOST_EXE_SUFFIX);
}
FileName AndroidConfig::toolPath(const Abi &abi, const QString &ndkToolChainVersion) const
@@ -499,6 +405,26 @@ FileName AndroidConfig::toolPath(const Abi &abi, const QString &ndkToolChainVers
.arg(toolsPrefix(abi)));
}
+FileName AndroidConfig::sdkManagerToolPath() const
+{
+ FileName sdkPath = m_sdkLocation;
+ QString toolPath = "tools/bin/sdkmanager";
+ if (HostOsInfo::isWindowsHost())
+ toolPath += ANDROID_BAT_SUFFIX;
+ sdkPath = sdkPath.appendPath(toolPath);
+ return sdkPath;
+}
+
+FileName AndroidConfig::avdManagerToolPath() const
+{
+ FileName avdManagerPath = m_sdkLocation;
+ QString toolPath = "tools/bin/avdmanager";
+ if (HostOsInfo::isWindowsHost())
+ toolPath += ANDROID_BAT_SUFFIX;
+ avdManagerPath = avdManagerPath.appendPath(toolPath);
+ return avdManagerPath;
+}
+
FileName AndroidConfig::gccPath(const Abi &abi, Core::Id lang,
const QString &ndkToolChainVersion) const
{
@@ -583,7 +509,7 @@ QVector<AndroidDeviceInfo> AndroidConfig::connectedDevices(const QString &adbToo
devices.push_back(dev);
}
- Utils::sort(devices, androidDevicesLessThan);
+ Utils::sort(devices);
if (devices.isEmpty() && error)
*error = QApplication::translate("AndroidConfiguration",
"No devices found in output of: %1")
@@ -605,197 +531,6 @@ AndroidConfig::CreateAvdInfo AndroidConfig::gatherCreateAVDInfo(QWidget *parent,
return result;
}
-QFuture<AndroidConfig::CreateAvdInfo> AndroidConfig::createAVD(CreateAvdInfo info) const
-{
- return Utils::runAsync(&AndroidConfig::createAVDImpl, info,
- androidToolPath(), androidToolEnvironment());
-}
-
-AndroidConfig::CreateAvdInfo AndroidConfig::createAVDImpl(CreateAvdInfo info, FileName androidToolPath, Environment env)
-{
- QProcess proc;
- proc.setProcessEnvironment(env.toProcessEnvironment());
- QStringList arguments;
- arguments << QLatin1String("create") << QLatin1String("avd")
- << QLatin1String("-t") << info.target
- << QLatin1String("-n") << info.name
- << QLatin1String("-b") << info.abi;
- if (info.sdcardSize > 0)
- arguments << QLatin1String("-c") << QString::fromLatin1("%1M").arg(info.sdcardSize);
- proc.start(androidToolPath.toString(), arguments);
- if (!proc.waitForStarted()) {
- info.error = QApplication::translate("AndroidConfig", "Could not start process \"%1 %2\"")
- .arg(androidToolPath.toString(), arguments.join(QLatin1Char(' ')));
- return info;
- }
- QTC_CHECK(proc.state() == QProcess::Running);
- proc.write(QByteArray("yes\n")); // yes to "Do you wish to create a custom hardware profile"
-
- QByteArray question;
- while (true) {
- proc.waitForReadyRead(500);
- question += proc.readAllStandardOutput();
- if (question.endsWith(QByteArray("]:"))) {
- // truncate to last line
- int index = question.lastIndexOf(QByteArray("\n"));
- if (index != -1)
- question = question.mid(index);
- if (question.contains("hw.gpu.enabled"))
- proc.write(QByteArray("yes\n"));
- else
- proc.write(QByteArray("\n"));
- question.clear();
- }
-
- if (proc.state() != QProcess::Running)
- break;
- }
- QTC_CHECK(proc.state() == QProcess::NotRunning);
-
- QString errorOutput = QString::fromLocal8Bit(proc.readAllStandardError());
- // The exit code is always 0, so we need to check stderr
- // For now assume that any output at all indicates a error
- if (!errorOutput.isEmpty()) {
- info.error = errorOutput;
- }
-
- return info;
-}
-
-bool AndroidConfig::removeAVD(const QString &name) const
-{
- SynchronousProcess proc;
- proc.setTimeoutS(5);
- proc.setProcessEnvironment(androidToolEnvironment().toProcessEnvironment());
- SynchronousProcessResponse response
- = proc.runBlocking(androidToolPath().toString(), QStringList({"delete", "avd", "-n", name}));
- return response.result == SynchronousProcessResponse::Finished && response.exitCode == 0;
-}
-
-QFuture<QVector<AndroidDeviceInfo>> AndroidConfig::androidVirtualDevicesFuture() const
-{
- return Utils::runAsync(&AndroidConfig::androidVirtualDevices,
- androidToolPath().toString(), androidToolEnvironment());
-}
-
-QVector<AndroidDeviceInfo> AndroidConfig::androidVirtualDevices(const QString &androidTool, const Environment &environment)
-{
- QVector<AndroidDeviceInfo> devices;
- SynchronousProcess proc;
- proc.setTimeoutS(20);
- proc.setProcessEnvironment(environment.toProcessEnvironment());
- SynchronousProcessResponse response = proc.run(androidTool, {"list", "avd"}); // list available AVDs
- if (response.result != SynchronousProcessResponse::Finished)
- return devices;
-
- QStringList avds = response.allOutput().split('\n');
- if (avds.empty())
- return devices;
-
- while (avds.first().startsWith(QLatin1String("* daemon")))
- avds.removeFirst(); // remove the daemon logs
- avds.removeFirst(); // remove "List of devices attached" header line
-
- bool nextLineIsTargetLine = false;
-
- AndroidDeviceInfo dev;
- for (int i = 0; i < avds.size(); i++) {
- QString line = avds.at(i);
- if (!line.contains(QLatin1String("Name:")))
- continue;
-
- int index = line.indexOf(QLatin1Char(':')) + 2;
- if (index >= line.size())
- break;
- dev.avdname = line.mid(index).trimmed();
- dev.sdk = -1;
- dev.cpuAbi.clear();
- ++i;
- for (; i < avds.size(); ++i) {
- line = avds.at(i);
- if (line.contains(QLatin1String("---------")))
- break;
-
- if (line.contains(QLatin1String("Target:")) || nextLineIsTargetLine) {
- if (line.contains(QLatin1String("Google APIs"))) {
- nextLineIsTargetLine = true;
- continue;
- }
-
- nextLineIsTargetLine = false;
-
- int lastIndex = line.lastIndexOf(QLatin1Char(' '));
- if (lastIndex == -1) // skip line
- break;
- QString tmp = line.mid(lastIndex).remove(QLatin1Char(')')).trimmed();
- dev.sdk = apiLevelFromAndroidList(tmp);
- }
- if (line.contains(QLatin1String("Tag/ABI:"))) {
- int lastIndex = line.lastIndexOf(QLatin1Char('/')) + 1;
- if (lastIndex >= line.size())
- break;
- dev.cpuAbi = QStringList(line.mid(lastIndex));
- } else if (line.contains(QLatin1String("ABI:"))) {
- int lastIndex = line.lastIndexOf(QLatin1Char(' ')) + 1;
- if (lastIndex >= line.size())
- break;
- dev.cpuAbi = QStringList(line.mid(lastIndex).trimmed());
- }
- }
- // armeabi-v7a devices can also run armeabi code
- if (dev.cpuAbi == QStringList("armeabi-v7a"))
- dev.cpuAbi << QLatin1String("armeabi");
- dev.state = AndroidDeviceInfo::OkState;
- dev.type = AndroidDeviceInfo::Emulator;
- if (dev.cpuAbi.isEmpty() || dev.sdk == -1)
- continue;
- devices.push_back(dev);
- }
- Utils::sort(devices, androidDevicesLessThan);
-
- return devices;
-}
-
-QString AndroidConfig::startAVD(const QString &name) const
-{
- if (!findAvd(name).isEmpty() || startAVDAsync(name))
- return waitForAvd(name);
- return QString();
-}
-
-bool AndroidConfig::startAVDAsync(const QString &avdName) const
-{
- QProcess *avdProcess = new QProcess();
- QObject::connect(avdProcess, static_cast<void (QProcess::*)(int)>(&QProcess::finished),
- avdProcess, &QObject::deleteLater);
-
- // start the emulator
- QStringList arguments;
- if (AndroidConfigurations::force32bitEmulator())
- arguments << QLatin1String("-force-32bit");
-
- arguments << QLatin1String("-partition-size") << QString::number(partitionSize())
- << QLatin1String("-avd") << avdName;
- avdProcess->start(emulatorToolPath().toString(), arguments);
- if (!avdProcess->waitForStarted(-1)) {
- delete avdProcess;
- return false;
- }
- return true;
-}
-
-QString AndroidConfig::findAvd(const QString &avdName) const
-{
- QVector<AndroidDeviceInfo> devices = connectedDevices();
- foreach (AndroidDeviceInfo device, devices) {
- if (device.type != AndroidDeviceInfo::Emulator)
- continue;
- if (device.avdname == avdName)
- return device.serialNumber;
- }
- return QString();
-}
-
bool AndroidConfig::isConnected(const QString &serialNumber) const
{
QVector<AndroidDeviceInfo> devices = connectedDevices();
@@ -806,39 +541,6 @@ bool AndroidConfig::isConnected(const QString &serialNumber) const
return false;
}
-bool AndroidConfig::waitForBooted(const QString &serialNumber, const QFutureInterface<bool> &fi) const
-{
- // found a serial number, now wait until it's done booting...
- for (int i = 0; i < 60; ++i) {
- if (fi.isCanceled())
- return false;
- if (hasFinishedBooting(serialNumber)) {
- return true;
- } else {
- QThread::sleep(2);
- if (!isConnected(serialNumber)) // device was disconnected
- return false;
- }
- }
- return false;
-}
-
-QString AndroidConfig::waitForAvd(const QString &avdName, const QFutureInterface<bool> &fi) const
-{
- // we cannot use adb -e wait-for-device, since that doesn't work if a emulator is already running
- // 60 rounds of 2s sleeping, two minutes for the avd to start
- QString serialNumber;
- for (int i = 0; i < 60; ++i) {
- if (fi.isCanceled())
- return QString();
- serialNumber = findAvd(avdName);
- if (!serialNumber.isEmpty())
- return waitForBooted(serialNumber, fi) ? serialNumber : QString();
- QThread::sleep(2);
- }
- return QString();
-}
-
bool AndroidConfig::isBootToQt(const QString &device) const
{
return isBootToQt(adbToolPath().toString(), device);
@@ -961,21 +663,6 @@ QString AndroidConfig::getProductModel(const QString &device) const
return model;
}
-bool AndroidConfig::hasFinishedBooting(const QString &device) const
-{
- QStringList arguments = AndroidDeviceInfo::adbSelector(device);
- arguments << QLatin1String("shell") << QLatin1String("getprop")
- << QLatin1String("init.svc.bootanim");
-
- SynchronousProcess adbProc;
- adbProc.setTimeoutS(10);
- SynchronousProcessResponse response = adbProc.runBlocking(adbToolPath().toString(), arguments);
- if (response.result != SynchronousProcessResponse::Finished)
- return false;
- QString value = response.allOutput().trimmed();
- return value == QLatin1String("stopped");
-}
-
QStringList AndroidConfig::getAbis(const QString &device) const
{
return getAbis(adbToolPath().toString(), device);
@@ -1053,6 +740,19 @@ void AndroidConfig::setSdkLocation(const FileName &sdkLocation)
m_availableSdkPlatformsUpToDate = false;
}
+QVersionNumber AndroidConfig::sdkToolsVersion() const
+{
+ QVersionNumber version;
+ if (m_sdkLocation.exists()) {
+ Utils::FileName sdkToolsPropertiesPath(m_sdkLocation);
+ sdkToolsPropertiesPath.appendPath("tools/source.properties");
+ QSettings settings(sdkToolsPropertiesPath.toString(), QSettings::IniFormat);
+ auto versionStr = settings.value(sdkToolsVersionKey).toString();
+ version = QVersionNumber::fromString(versionStr);
+ }
+ return version;
+}
+
FileName AndroidConfig::ndkLocation() const
{
return m_ndkLocation;
@@ -1126,9 +826,18 @@ void AndroidConfig::setAutomaticKitCreation(bool b)
m_automaticKitCreation = b;
}
+bool AndroidConfig::antScriptsAvailable() const
+{
+ return sdkToolsVersion() < sdkToolsAntMissingVersion;
+}
+
bool AndroidConfig::useGrandle() const
{
- return m_useGradle;
+ if (antScriptsAvailable()) {
+ return m_useGradle;
+ }
+ // Force gradle builds.
+ return true;
}
void AndroidConfig::setUseGradle(bool b)
@@ -1353,6 +1062,20 @@ QStringList AndroidDeviceInfo::adbSelector(const QString &serialNumber)
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;
+}
+
const AndroidConfig &AndroidConfigurations::currentConfig()
{
return m_instance->m_config; // ensure that m_instance is initialized
@@ -1494,4 +1217,13 @@ void AndroidConfigurations::updateAndroidDevice()
AndroidConfigurations *AndroidConfigurations::m_instance = 0;
+bool SdkPlatform::operator <(const SdkPlatform &other) const
+{
+ if (apiLevel != other.apiLevel)
+ return apiLevel > other.apiLevel;
+ if (name != other.name)
+ return name < other.name;
+ return false;
+}
+
} // namespace Android
diff --git a/src/plugins/android/androidconfigurations.h b/src/plugins/android/androidconfigurations.h
index 751e68d113..9107680810 100644
--- a/src/plugins/android/androidconfigurations.h
+++ b/src/plugins/android/androidconfigurations.h
@@ -36,6 +36,7 @@
#include <QHash>
#include <QMap>
#include <QFutureInterface>
+#include <QVersionNumber>
#include <utils/fileutils.h>
@@ -68,19 +69,36 @@ public:
static QStringList adbSelector(const QString &serialNumber);
- bool isValid() { return !serialNumber.isEmpty() || !avdname.isEmpty(); }
+ bool isValid() const { return !serialNumber.isEmpty() || !avdname.isEmpty(); }
+ bool operator<(const AndroidDeviceInfo &other) const;
};
+using AndroidDeviceInfoList = QList<AndroidDeviceInfo>;
+
+//! Defines an Android system image.
+class SystemImage
+{
+public:
+ bool isValid() const { return (apiLevel != -1) && !abiName.isEmpty(); }
+ int apiLevel = -1;
+ QString abiName;
+ QString package;
+ Utils::FileName installedLocation;
+};
+using SystemImageList = QList<SystemImage>;
+
class SdkPlatform
{
public:
- SdkPlatform()
- : apiLevel(-1)
- {}
- int apiLevel;
+ bool isValid() const { return !name.isEmpty() && apiLevel != -1; }
+ bool operator <(const SdkPlatform &other) const;
+ int apiLevel = -1;
QString name;
- QStringList abis;
+ QString package;
+ Utils::FileName installedLocation;
+ SystemImageList systemImages;
};
+using SdkPlatformList = QList<SdkPlatform>;
class ANDROID_EXPORT AndroidConfig
{
@@ -94,6 +112,7 @@ public:
Utils::FileName sdkLocation() const;
void setSdkLocation(const Utils::FileName &sdkLocation);
+ QVersionNumber sdkToolsVersion() const;
Utils::FileName ndkLocation() const;
void setNdkLocation(const Utils::FileName &ndkLocation);
@@ -116,18 +135,21 @@ public:
bool automaticKitCreation() const;
void setAutomaticKitCreation(bool b);
+ bool antScriptsAvailable() const;
+
bool useGrandle() const;
void setUseGradle(bool b);
Utils::FileName adbToolPath() const;
Utils::FileName androidToolPath() const;
- Utils::Environment androidToolEnvironment() const;
Utils::FileName antToolPath() const;
Utils::FileName emulatorToolPath() const;
-
+ Utils::FileName sdkManagerToolPath() const;
+ Utils::FileName avdManagerToolPath() const;
Utils::FileName gccPath(const ProjectExplorer::Abi &abi, Core::Id lang,
const QString &ndkToolChainVersion) const;
+
Utils::FileName gdbPath(const ProjectExplorer::Abi &abi, const QString &ndkToolChainVersion) const;
Utils::FileName keytoolPath() const;
@@ -135,7 +157,8 @@ public:
class CreateAvdInfo
{
public:
- QString target;
+ bool isValid() const { return target.isValid() && !name.isEmpty(); }
+ SdkPlatform target;
QString name;
QString abi;
int sdcardSize = 0;
@@ -143,19 +166,10 @@ public:
};
CreateAvdInfo gatherCreateAVDInfo(QWidget *parent, int minApiLevel = 0, QString targetArch = QString()) const;
- QFuture<CreateAvdInfo> createAVD(CreateAvdInfo info) const;
- bool removeAVD(const QString &name) const;
QVector<AndroidDeviceInfo> connectedDevices(QString *error = 0) const;
static QVector<AndroidDeviceInfo> connectedDevices(const QString &adbToolPath, QString *error = 0);
- QFuture<QVector<AndroidDeviceInfo> > androidVirtualDevicesFuture() const;
- static QVector<AndroidDeviceInfo> androidVirtualDevices(const QString &androidTool, const Utils::Environment &environment);
-
- QString startAVD(const QString &name) const;
- bool startAVDAsync(const QString &avdName) const;
- QString findAvd(const QString &avdName) const;
- QString waitForAvd(const QString &avdName, const QFutureInterface<bool> &fi = QFutureInterface<bool>()) const;
QString bestNdkPlatformMatch(int target) const;
static ProjectExplorer::Abi abiForToolChainPrefix(const QString &toolchainPrefix);
@@ -166,13 +180,10 @@ public:
QString getProductModel(const QString &device) const;
enum class OpenGl { Enabled, Disabled, Unknown };
OpenGl getOpenGLEnabled(const QString &emulator) const;
- bool hasFinishedBooting(const QString &device) const;
- bool waitForBooted(const QString &serialNumber, const QFutureInterface<bool> &fi) const;
bool isConnected(const QString &serialNumber) const;
SdkPlatform highestAndroidSdk() const;
private:
- static CreateAvdInfo createAVDImpl(CreateAvdInfo info, Utils::FileName androidToolPath, Utils::Environment env);
static QString getDeviceProperty(const QString &adbToolPath, const QString &device, const QString &property);
Utils::FileName toolPath(const ProjectExplorer::Abi &abi, const QString &ndkToolChainVersion) const;
@@ -196,12 +207,11 @@ private:
QStringList m_makeExtraSearchDirectories;
unsigned m_partitionSize = 1024;
bool m_automaticKitCreation = true;
- bool m_useGradle = false;
+ bool m_useGradle = true; // Ant builds are deprecated.
//caches
mutable bool m_availableSdkPlatformsUpToDate = false;
- mutable QVector<SdkPlatform> m_availableSdkPlatforms;
- static bool sortSdkPlatformByApiLevel(const SdkPlatform &a, const SdkPlatform &b);
+ mutable SdkPlatformList m_availableSdkPlatforms;
mutable bool m_NdkInformationUpToDate = false;
mutable QString m_toolchainHost;
@@ -247,3 +257,5 @@ private:
};
} // namespace Android
+Q_DECLARE_METATYPE(Android::SdkPlatform)
+
diff --git a/src/plugins/android/androiddebugsupport.cpp b/src/plugins/android/androiddebugsupport.cpp
index 76a3493c7e..aaffde81d4 100644
--- a/src/plugins/android/androiddebugsupport.cpp
+++ b/src/plugins/android/androiddebugsupport.cpp
@@ -180,6 +180,16 @@ AndroidDebugSupport::AndroidDebugSupport(RunControl *runControl)
[this](const QString &output) {
this->runControl()->showMessage(output, AppOutput);
});
+
+ QTC_ASSERT(runControl, return);
+ auto formatter = qobject_cast<AndroidOutputFormatter*>(runControl->outputFormatter());
+ QTC_ASSERT(formatter, return);
+ connect(m_runner, &AndroidRunner::pidFound, formatter, &AndroidOutputFormatter::appendPid);
+ connect(m_runner, &AndroidRunner::pidLost, formatter, &AndroidOutputFormatter::removePid);
+ connect(m_runner, &AndroidRunner::remoteProcessFinished, formatter,
+ [formatter] {
+ formatter->removePid(-1);
+ });
}
void AndroidDebugSupport::handleRemoteProcessStarted(Utils::Port gdbServerPort, Utils::Port qmlPort)
diff --git a/src/plugins/android/androiddeployqtstep.cpp b/src/plugins/android/androiddeployqtstep.cpp
index 98efc64ffe..b4bfbc7bc1 100644
--- a/src/plugins/android/androiddeployqtstep.cpp
+++ b/src/plugins/android/androiddeployqtstep.cpp
@@ -33,6 +33,7 @@
#include "androidmanager.h"
#include "androidconstants.h"
#include "androidglobal.h"
+#include "androidavdmanager.h"
#include <coreplugin/fileutils.h>
#include <coreplugin/icore.h>
@@ -262,8 +263,9 @@ bool AndroidDeployQtStep::init(QList<const BuildStep *> &earlierSteps)
m_adbPath = AndroidConfigurations::currentConfig().adbToolPath().toString();
- if (AndroidConfigurations::currentConfig().findAvd(m_avdName).isEmpty())
- AndroidConfigurations::currentConfig().startAVDAsync(m_avdName);
+ AndroidAvdManager avdManager;
+ if (avdManager.findAvd(m_avdName).isEmpty())
+ avdManager.startAvdAsync(m_avdName);
return true;
}
@@ -414,7 +416,7 @@ void AndroidDeployQtStep::slotSetSerialNumber(const QString &serialNumber)
void AndroidDeployQtStep::run(QFutureInterface<bool> &fi)
{
if (!m_avdName.isEmpty()) {
- QString serialNumber = AndroidConfigurations::currentConfig().waitForAvd(m_avdName, fi);
+ QString serialNumber = AndroidAvdManager().waitForAvd(m_avdName, fi);
if (serialNumber.isEmpty()) {
reportRunResult(fi, false);
return;
diff --git a/src/plugins/android/androiddevicedialog.cpp b/src/plugins/android/androiddevicedialog.cpp
index 519f125f45..451abf2dc5 100644
--- a/src/plugins/android/androiddevicedialog.cpp
+++ b/src/plugins/android/androiddevicedialog.cpp
@@ -25,6 +25,7 @@
#include "androiddevicedialog.h"
#include "androidmanager.h"
+#include "androidavdmanager.h"
#include "ui_androiddevicedialog.h"
#include <utils/environment.h>
@@ -423,7 +424,8 @@ AndroidDeviceDialog::AndroidDeviceDialog(int apiLevel, const QString &abi, Andro
m_ui(new Ui::AndroidDeviceDialog),
m_apiLevel(apiLevel),
m_abi(abi),
- m_defaultDevice(serialNumber)
+ m_defaultDevice(serialNumber),
+ m_avdManager(new AndroidAvdManager)
{
m_ui->setupUi(this);
m_ui->deviceView->setModel(m_model);
@@ -515,7 +517,7 @@ void AndroidDeviceDialog::refreshDeviceList()
m_ui->refreshDevicesButton->setEnabled(false);
m_progressIndicator->show();
m_connectedDevices = AndroidConfig::connectedDevices(AndroidConfigurations::currentConfig().adbToolPath().toString());
- m_futureWatcherRefreshDevices.setFuture(AndroidConfigurations::currentConfig().androidVirtualDevicesFuture());
+ m_futureWatcherRefreshDevices.setFuture(m_avdManager->avdList());
}
void AndroidDeviceDialog::devicesRefreshed()
@@ -530,7 +532,7 @@ void AndroidDeviceDialog::devicesRefreshed()
serialNumber = deviceType == AndroidDeviceInfo::Hardware ? info.serialNumber : info.avdname;
}
- QVector<AndroidDeviceInfo> devices = m_futureWatcherRefreshDevices.result();
+ AndroidDeviceInfoList devices = m_futureWatcherRefreshDevices.result();
QSet<QString> startedAvds = Utils::transform<QSet>(m_connectedDevices,
[] (const AndroidDeviceInfo &info) {
return info.avdname;
@@ -583,12 +585,12 @@ void AndroidDeviceDialog::createAvd()
m_ui->createAVDButton->setEnabled(false);
AndroidConfig::CreateAvdInfo info = AndroidConfigurations::currentConfig().gatherCreateAVDInfo(this, m_apiLevel, m_abi);
- if (info.target.isEmpty()) {
+ if (!info.target.isValid()) {
m_ui->createAVDButton->setEnabled(true);
return;
}
- m_futureWatcherAddDevice.setFuture(AndroidConfigurations::currentConfig().createAVD(info));
+ m_futureWatcherAddDevice.setFuture(m_avdManager->createAvd(info));
}
void AndroidDeviceDialog::avdAdded()
diff --git a/src/plugins/android/androiddevicedialog.h b/src/plugins/android/androiddevicedialog.h
index b4d7940048..8f957aa0b2 100644
--- a/src/plugins/android/androiddevicedialog.h
+++ b/src/plugins/android/androiddevicedialog.h
@@ -32,6 +32,8 @@
#include <QFutureWatcher>
#include <QTime>
+#include <memory>
+
QT_BEGIN_NAMESPACE
class QModelIndex;
QT_END_NAMESPACE
@@ -41,6 +43,7 @@ namespace Utils { class ProgressIndicator; }
namespace Android {
namespace Internal {
+class AndroidAvdManager;
class AndroidDeviceModel;
namespace Ui { class AndroidDeviceDialog; }
@@ -74,9 +77,10 @@ private:
QString m_abi;
QString m_avdNameFromAdd;
QString m_defaultDevice;
+ std::unique_ptr<AndroidAvdManager> m_avdManager;
QVector<AndroidDeviceInfo> m_connectedDevices;
QFutureWatcher<AndroidConfig::CreateAvdInfo> m_futureWatcherAddDevice;
- QFutureWatcher<QVector<AndroidDeviceInfo>> m_futureWatcherRefreshDevices;
+ QFutureWatcher<AndroidDeviceInfoList> m_futureWatcherRefreshDevices;
};
}
diff --git a/src/plugins/android/androidmanager.cpp b/src/plugins/android/androidmanager.cpp
index 0459355b04..ee57399060 100644
--- a/src/plugins/android/androidmanager.cpp
+++ b/src/plugins/android/androidmanager.cpp
@@ -34,6 +34,7 @@
#include "androidqtsupport.h"
#include "androidqtversion.h"
#include "androidbuildapkstep.h"
+#include "androidavdmanager.h"
#include <coreplugin/documentmanager.h>
#include <coreplugin/messagemanager.h>
@@ -60,11 +61,13 @@
#include <QMessageBox>
#include <QApplication>
#include <QDomDocument>
+#include <QVersionNumber>
namespace {
const QLatin1String AndroidManifestName("AndroidManifest.xml");
const QLatin1String AndroidDefaultPropertiesName("project.properties");
const QLatin1String AndroidDeviceSn("AndroidDeviceSerialNumber");
+ const QLatin1String ApiLevelKey("AndroidVersion.ApiLevel");
} // anonymous namespace
@@ -343,7 +346,7 @@ void AndroidManager::cleanLibsOnDevice(ProjectExplorer::Target *target)
QString deviceSerialNumber = info.serialNumber;
if (info.type == AndroidDeviceInfo::Emulator) {
- deviceSerialNumber = AndroidConfigurations::currentConfig().startAVD(info.avdname);
+ deviceSerialNumber = AndroidAvdManager().startAvd(info.avdname);
if (deviceSerialNumber.isEmpty())
Core::MessageManager::write(tr("Starting Android virtual device failed."));
}
@@ -372,7 +375,7 @@ void AndroidManager::installQASIPackage(ProjectExplorer::Target *target, const Q
QString deviceSerialNumber = info.serialNumber;
if (info.type == AndroidDeviceInfo::Emulator) {
- deviceSerialNumber = AndroidConfigurations::currentConfig().startAVD(info.avdname);
+ deviceSerialNumber = AndroidAvdManager().startAvd(info.avdname);
if (deviceSerialNumber.isEmpty())
Core::MessageManager::write(tr("Starting Android virtual device failed."));
}
@@ -565,18 +568,33 @@ bool AndroidManager::updateGradleProperties(ProjectExplorer::Target *target)
gradleProperties["buildDir"] = ".build";
gradleProperties["androidCompileSdkVersion"] = buildTargetSDK(target).split(QLatin1Char('-')).last().toLocal8Bit();
if (gradleProperties["androidBuildToolsVersion"].isEmpty()) {
- QString maxVersion;
+ QVersionNumber maxVersion;
QDir buildToolsDir(AndroidConfigurations::currentConfig().sdkLocation().appendPath(QLatin1String("build-tools")).toString());
foreach (const QFileInfo &file, buildToolsDir.entryList(QDir::Dirs|QDir::NoDotAndDotDot)) {
- QString ver(file.fileName());
+ QVersionNumber ver = QVersionNumber::fromString(file.fileName());
if (maxVersion < ver)
maxVersion = ver;
}
- if (maxVersion.isEmpty())
+ if (maxVersion.isNull())
return false;
- gradleProperties["androidBuildToolsVersion"] = maxVersion.toLocal8Bit();
+ gradleProperties["androidBuildToolsVersion"] = maxVersion.toString().toLocal8Bit();
}
return mergeGradleProperties(gradlePropertiesPath, gradleProperties);
}
+int AndroidManager::findApiLevel(const Utils::FileName &platformPath)
+{
+ int apiLevel = -1;
+ Utils::FileName propertiesPath = platformPath;
+ propertiesPath.appendPath("/source.properties");
+ if (propertiesPath.exists()) {
+ QSettings sdkProperties(propertiesPath.toString(), QSettings::IniFormat);
+ bool validInt = false;
+ apiLevel = sdkProperties.value(ApiLevelKey).toInt(&validInt);
+ if (!validInt)
+ apiLevel = -1;
+ }
+ return apiLevel;
+}
+
} // namespace Android
diff --git a/src/plugins/android/androidmanager.h b/src/plugins/android/androidmanager.h
index 2b79cb4c6a..ad50f45529 100644
--- a/src/plugins/android/androidmanager.h
+++ b/src/plugins/android/androidmanager.h
@@ -89,6 +89,7 @@ public:
static AndroidQtSupport *androidQtSupport(ProjectExplorer::Target *target);
static bool useGradle(ProjectExplorer::Target *target);
static bool updateGradleProperties(ProjectExplorer::Target *target);
+ static int findApiLevel(const Utils::FileName &platformPath);
};
} // namespace Android
diff --git a/src/plugins/android/androidrunconfiguration.cpp b/src/plugins/android/androidrunconfiguration.cpp
index d2d7844e5c..54f6449753 100644
--- a/src/plugins/android/androidrunconfiguration.cpp
+++ b/src/plugins/android/androidrunconfiguration.cpp
@@ -29,16 +29,205 @@
#include "androidmanager.h"
#include <projectexplorer/kitinformation.h>
+#include <projectexplorer/projectexplorer.h>
+#include <projectexplorer/projectexplorersettings.h>
#include <projectexplorer/target.h>
#include <qtsupport/qtoutputformatter.h>
#include <qtsupport/qtkitinformation.h>
+#include <QPlainTextEdit>
+#include <QRegularExpression>
+#include <QToolButton>
#include <utils/qtcassert.h>
+#include <utils/utilsicons.h>
using namespace ProjectExplorer;
namespace Android {
+static QRegularExpression logCatRegExp("([0-9\\-]*\\s+[0-9\\-:.]*)" // 1. time
+ "\\s*"
+ "([DEIVWF])" // 2. log level
+ "\\/"
+ "(.*)" // 3. TAG
+ "\\(\\s*"
+ "(\\d+)" // 4. PID
+ "\\)\\:\\s"
+ "(.*)"); // 5. Message
+
+AndroidOutputFormatter::AndroidOutputFormatter(Project *project)
+ : QtSupport::QtOutputFormatter(project)
+ , m_filtersButton(new QToolButton)
+{
+ auto filtersMenu = new QMenu(m_filtersButton.data());
+
+ m_filtersButton->setToolTip(tr("Filters"));
+ m_filtersButton->setIcon(Utils::Icons::FILTER.icon());
+ m_filtersButton->setProperty("noArrow", true);
+ m_filtersButton->setAutoRaise(true);
+ m_filtersButton->setPopupMode(QToolButton::InstantPopup);
+ m_filtersButton->setMenu(filtersMenu);
+
+ auto logsMenu = filtersMenu->addMenu(tr("Log Level"));
+ addLogAction(All, logsMenu, tr("All"));
+ addLogAction(Verbose, logsMenu, tr("Verbose"));
+ addLogAction(Info, logsMenu, tr("Info"));
+ addLogAction(Debug, logsMenu, tr("Debug"));
+ addLogAction(Warning, logsMenu, tr("Warning"));
+ addLogAction(Error, logsMenu, tr("Error"));
+ addLogAction(Fatal, logsMenu, tr("Fatal"));
+ updateLogMenu();
+ m_appsMenu = filtersMenu->addMenu(tr("Applications"));
+ appendPid(-1, tr("All"));
+}
+
+AndroidOutputFormatter::~AndroidOutputFormatter()
+{}
+
+QList<QWidget *> AndroidOutputFormatter::toolbarWidgets() const
+{
+ return QList<QWidget *>{m_filtersButton.data()};
+}
+
+void AndroidOutputFormatter::appendMessage(const QString &text, Utils::OutputFormat format)
+{
+ if (text.isEmpty())
+ return;
+
+ CachedLine line;
+ line.content = text;
+
+ if (format < Utils::StdOutFormat) {
+ line.level = SkipFiltering;
+ line.pid = -1;
+ } else {
+ QRegularExpressionMatch match = logCatRegExp.match(text);
+ if (!match.hasMatch())
+ return;
+ line.level = None;
+
+ switch (match.captured(2).toLatin1()[0]) {
+ case 'D': line.level = Debug; break;
+ case 'I': line.level = Info; break;
+ case 'V': line.level = Verbose; break;
+ case 'W': line.level = Warning; break;
+ case 'E': line.level = Error; break;
+ case 'F': line.level = Fatal; break;
+ default: return;
+ }
+ line.pid = match.captured(4).toLongLong();
+ }
+
+ m_cachedLines.append(line);
+ if (m_cachedLines.size() > ProjectExplorerPlugin::projectExplorerSettings().maxAppOutputLines)
+ m_cachedLines.pop_front();
+
+ filterMessage(line);
+}
+
+void AndroidOutputFormatter::clear()
+{
+ m_cachedLines.clear();
+}
+
+void AndroidOutputFormatter::appendPid(qint64 pid, const QString &name)
+{
+ if (m_pids.contains(pid))
+ return;
+
+ auto action = m_appsMenu->addAction(name);
+ m_pids[pid] = action;
+ action->setCheckable(true);
+ action->setChecked(pid != -1);
+ connect(action, &QAction::triggered, this, &AndroidOutputFormatter::applyFilter);
+ applyFilter();
+}
+
+void AndroidOutputFormatter::removePid(qint64 pid)
+{
+ if (pid == -1) {
+ for (auto action : m_pids)
+ m_appsMenu->removeAction(action);
+ m_pids.clear();
+ } else {
+ m_appsMenu->removeAction(m_pids[pid]);
+ m_pids.remove(pid);
+ }
+}
+
+void AndroidOutputFormatter::updateLogMenu(LogLevel set, LogLevel reset)
+{
+ m_logLevelFlags |= set;
+ m_logLevelFlags &= ~reset;
+ for (const auto & pair : m_logLevels)
+ pair.second->setChecked((m_logLevelFlags & pair.first) == pair.first);
+
+ applyFilter();
+}
+
+void AndroidOutputFormatter::filterMessage(const CachedLine &line)
+{
+ if (line.level == SkipFiltering || m_pids[-1]->isChecked()) {
+ QtOutputFormatter::appendMessage(line.content, Utils::NormalMessageFormat);
+ } else {
+ // Filter Log Level
+ if (!(m_logLevelFlags & line.level))
+ return;
+
+ // Filter PIDs
+ if (!m_pids[-1]->isChecked()) {
+ auto it = m_pids.find(line.pid);
+ if (it == m_pids.end() || !(*it)->isChecked())
+ return;
+ }
+
+ Utils::OutputFormat format = Utils::NormalMessageFormat;
+ switch (line.level) {
+ case Debug:
+ format = Utils::DebugFormat;
+ break;
+ case Info:
+ case Verbose:
+ format = Utils::StdOutFormat;
+ break;
+
+ case Warning:
+ case Error:
+ case Fatal:
+ format = Utils::StdErrFormat;
+ break;
+ default:
+ return;
+ }
+
+ Utils::OutputFormatter::appendMessage(line.content, format);
+ }
+}
+
+void AndroidOutputFormatter::applyFilter()
+{
+ if (!plainTextEdit())
+ return;
+
+ plainTextEdit()->clear();
+ if (!m_pids[-1]->isChecked()) {
+ bool allOn = true;
+ for (auto action : m_pids) {
+ if (!action->isChecked()) {
+ allOn = false;
+ break;
+ }
+ }
+ m_pids[-1]->setChecked(allOn);
+ } else {
+ for (auto action : m_pids)
+ action->setChecked(true);
+ }
+
+ for (const auto &line : m_cachedLines)
+ filterMessage(line);
+}
+
AndroidRunConfiguration::AndroidRunConfiguration(Target *parent, Core::Id id)
: RunConfiguration(parent, id)
{
@@ -56,7 +245,7 @@ QWidget *AndroidRunConfiguration::createConfigurationWidget()
Utils::OutputFormatter *AndroidRunConfiguration::createOutputFormatter() const
{
- return new QtSupport::QtOutputFormatter(target()->project());
+ return new AndroidOutputFormatter(target()->project());
}
const QString AndroidRunConfiguration::remoteChannel() const
diff --git a/src/plugins/android/androidrunconfiguration.h b/src/plugins/android/androidrunconfiguration.h
index cfa54312d9..9ec42e3d78 100644
--- a/src/plugins/android/androidrunconfiguration.h
+++ b/src/plugins/android/androidrunconfiguration.h
@@ -28,9 +28,75 @@
#include "android_global.h"
#include <projectexplorer/runconfiguration.h>
+#include <qtsupport/qtoutputformatter.h>
+
+#include <QMenu>
+
+QT_BEGIN_NAMESPACE
+class QToolButton;
+QT_END_NAMESPACE
namespace Android {
+class AndroidOutputFormatter : public QtSupport::QtOutputFormatter
+{
+ Q_OBJECT
+public:
+ enum LogLevel {
+ None = 0,
+ Verbose = 1,
+ Info = 1 << 1,
+ Debug = 1 << 2,
+ Warning = 1 << 3,
+ Error = 1 << 4,
+ Fatal = 1 << 5,
+ All = Verbose | Info | Debug | Warning | Error | Fatal,
+ SkipFiltering = ~All
+ };
+
+public:
+ explicit AndroidOutputFormatter(ProjectExplorer::Project *project);
+ ~AndroidOutputFormatter();
+
+ // OutputFormatter interface
+ QList<QWidget*> toolbarWidgets() const override;
+ void appendMessage(const QString &text, Utils::OutputFormat format) override;
+ void clear() override;
+
+public slots:
+ void appendPid(qint64 pid, const QString &name);
+ void removePid(qint64 pid);
+
+private:
+ struct CachedLine {
+ qint64 pid;
+ LogLevel level;
+ QString content;
+ };
+
+private:
+ void updateLogMenu(LogLevel set = None, LogLevel reset = None);
+ void filterMessage(const CachedLine &line);
+
+ void applyFilter();
+ void addLogAction(LogLevel level, QMenu *logsMenu, const QString &name) {
+ auto action = logsMenu->addAction(name);
+ m_logLevels.push_back(qMakePair(level, action));
+ action->setCheckable(true);
+ connect(action, &QAction::triggered, this, [level, this](bool checked) {
+ updateLogMenu(checked ? level : None , checked ? None : level);
+ });
+ }
+
+private:
+ int m_logLevelFlags = All;
+ QVector<QPair<LogLevel, QAction*>> m_logLevels;
+ QHash<qint64, QAction*> m_pids;
+ QScopedPointer<QToolButton> m_filtersButton;
+ QMenu *m_appsMenu;
+ QList<CachedLine> m_cachedLines;
+};
+
class ANDROID_EXPORT AndroidRunConfiguration : public ProjectExplorer::RunConfiguration
{
Q_OBJECT
diff --git a/src/plugins/android/androidruncontrol.cpp b/src/plugins/android/androidruncontrol.cpp
index 2ac929a0b1..d2a4bb1ea6 100644
--- a/src/plugins/android/androidruncontrol.cpp
+++ b/src/plugins/android/androidruncontrol.cpp
@@ -62,6 +62,13 @@ void AndroidRunControl::start()
this, &AndroidRunControl::handleRemoteOutput);
connect(m_runner, &AndroidRunner::remoteProcessFinished,
this, &AndroidRunControl::handleRemoteProcessFinished);
+
+ auto formatter = static_cast<AndroidOutputFormatter *>(outputFormatter());
+ connect(m_runner, &AndroidRunner::pidFound,
+ formatter, &AndroidOutputFormatter::appendPid);
+ connect(m_runner, &AndroidRunner::pidLost,
+ formatter, &AndroidOutputFormatter::removePid);
+
appendMessage(tr("Starting remote process."), Utils::NormalMessageFormat);
m_runner->setRunnable(runnable().as<AndroidRunnable>());
m_runner->start();
diff --git a/src/plugins/android/androidrunner.cpp b/src/plugins/android/androidrunner.cpp
index 778d348b68..9208e69953 100644
--- a/src/plugins/android/androidrunner.cpp
+++ b/src/plugins/android/androidrunner.cpp
@@ -31,6 +31,7 @@
#include "androidglobal.h"
#include "androidrunconfiguration.h"
#include "androidmanager.h"
+#include "androidavdmanager.h"
#include <debugger/debuggerrunconfigurationaspect.h>
#include <projectexplorer/projectexplorer.h>
@@ -51,6 +52,7 @@
#include <QTime>
#include <QTcpServer>
#include <QTcpSocket>
+#include <QRegularExpression>
using namespace std;
using namespace std::placeholders;
@@ -125,10 +127,10 @@ namespace Internal {
const int MIN_SOCKET_HANDSHAKE_PORT = 20001;
const int MAX_SOCKET_HANDSHAKE_PORT = 20999;
-static const QString pidScript = QStringLiteral("for p in /proc/[0-9]*; "
- "do cat <$p/cmdline && echo :${p##*/}; done");
-static const QString pidPollingScript = QStringLiteral("while true; do sleep 1; "
- "cat /proc/%1/cmdline > /dev/null; done");
+static const QString pidScript = QStringLiteral("input keyevent KEYCODE_WAKEUP; "
+ "while true; do sleep 1; echo \"=\"; "
+ "for p in /proc/[0-9]*; "
+ "do cat <$p/cmdline && echo :${p##*/}; done; done");
static const QString regExpLogcat = QStringLiteral("[0-9\\-]*" // date
"\\s+"
@@ -146,55 +148,26 @@ static const QString regExpLogcat = QStringLiteral("[0-9\\-]*" // date
);
static int APP_START_TIMEOUT = 45000;
-static bool isTimedOut(const chrono::high_resolution_clock::time_point &start,
- int msecs = APP_START_TIMEOUT)
-{
- bool timedOut = false;
- auto end = chrono::high_resolution_clock::now();
- if (chrono::duration_cast<chrono::milliseconds>(end-start).count() > msecs)
- timedOut = true;
- return timedOut;
-}
-
-static qint64 extractPID(const QByteArray &output, const QString &packageName)
-{
- qint64 pid = -1;
- foreach (auto tuple, output.split('\n')) {
- tuple = tuple.simplified();
- if (!tuple.isEmpty()) {
- auto parts = tuple.split(':');
- QString commandName = QString::fromLocal8Bit(parts.first());
- if (parts.length() == 2 && commandName == packageName) {
- pid = parts.last().toLongLong();
- break;
- }
- }
- }
- return pid;
-}
+enum class PidStatus {
+ Found,
+ Lost
+};
-void findProcessPID(QFutureInterface<qint64> &fi, const QString &adbPath,
- QStringList selector, const QString &packageName)
+struct PidInfo
{
- if (packageName.isEmpty())
- return;
-
- qint64 processPID = -1;
- chrono::high_resolution_clock::time_point start = chrono::high_resolution_clock::now();
- do {
- QThread::msleep(200);
- const QByteArray out = Utils::SynchronousProcess()
- .runBlocking(adbPath, selector << QStringLiteral("shell") << pidScript)
- .allRawOutput();
- processPID = extractPID(out, packageName);
- } while (processPID == -1 && !isTimedOut(start) && !fi.isCanceled());
-
- if (!fi.isCanceled())
- fi.reportResult(processPID);
-}
+ PidInfo(qint64 pid = -1, PidStatus status = PidStatus::Lost, QString name = {})
+ : pid(pid)
+ , status(status)
+ , name(name)
+ {}
+ qint64 pid;
+ PidStatus status;
+ QString name;
+};
static void deleter(QProcess *p)
{
+ p->disconnect();
p->kill();
p->waitForFinished();
// Might get deleted from its own signal handler.
@@ -228,29 +201,31 @@ signals:
void remoteOutput(const QString &output);
void remoteErrorOutput(const QString &output);
+ void pidFound(qint64, const QString &name);
+ void pidLost(qint64);
private:
- void onProcessIdChanged(qint64 pid);
+ void findProcessPids();
+ void onProcessIdChanged(PidInfo pidInfo);
void logcatReadStandardError();
void logcatReadStandardOutput();
void adbKill(qint64 pid);
QStringList selector() const { return m_selector; }
void forceStop();
- void findPs();
void logcatProcess(const QByteArray &text, QByteArray &buffer, bool onlyError);
bool adbShellAmNeedsQuotes();
bool runAdb(const QStringList &args, QString *exitMessage = nullptr, int timeoutS = 10);
+ int deviceSdkVersion();
// Create the processes and timer in the worker thread, for correct thread affinity
std::unique_ptr<QProcess, decltype(&deleter)> m_adbLogcatProcess;
- std::unique_ptr<QProcess, decltype(&deleter)> m_psIsAlive;
+ std::unique_ptr<QProcess, decltype(&deleter)> m_pidsFinderProcess;
QScopedPointer<QTcpSocket> m_socket;
QByteArray m_stdoutBuffer;
QByteArray m_stderrBuffer;
- QFuture<qint64> m_pidFinder;
- qint64 m_processPID = -1;
+ QSet<qint64> m_processPids;
bool m_useCppDebugger = false;
QmlDebug::QmlDebugServicesPreset m_qmlDebugServices;
Utils::Port m_localGdbServerPort; // Local end of forwarded debug socket.
@@ -261,20 +236,20 @@ private:
QString m_gdbserverSocket;
QString m_adb;
QStringList m_selector;
- QRegExp m_logCatRegExp;
DebugHandShakeType m_handShakeMethod = SocketHandShake;
bool m_customPort = false;
QString m_packageName;
int m_socketHandShakePort = MIN_SOCKET_HANDSHAKE_PORT;
+ QByteArray m_pidsBuffer;
+ QScopedPointer<QTimer> m_timeoutTimer;
};
AndroidRunnerWorker::AndroidRunnerWorker(AndroidRunConfiguration *runConfig, Core::Id runMode,
const QString &packageName, const QStringList &selector)
: m_adbLogcatProcess(nullptr, deleter)
- , m_psIsAlive(nullptr, deleter)
+ , m_pidsFinderProcess(nullptr, deleter)
, m_selector(selector)
- , m_logCatRegExp(regExpLogcat)
, m_packageName(packageName)
{
Debugger::DebuggerRunConfigurationAspect *aspect
@@ -338,23 +313,18 @@ AndroidRunnerWorker::AndroidRunnerWorker(AndroidRunConfiguration *runConfig, Cor
AndroidRunnerWorker::~AndroidRunnerWorker()
{
- if (!m_pidFinder.isFinished())
- m_pidFinder.cancel();
}
void AndroidRunnerWorker::forceStop()
{
runAdb(selector() << "shell" << "am" << "force-stop" << m_packageName, nullptr, 30);
- // try killing it via kill -9
- const QByteArray out = Utils::SynchronousProcess()
- .runBlocking(m_adb, selector() << QStringLiteral("shell") << pidScript)
- .allRawOutput();
-
- qint64 pid = extractPID(out.simplified(), m_packageName);
- if (pid != -1) {
- adbKill(pid);
+ for (auto it = m_processPids.constBegin(); it != m_processPids.constEnd(); ++it) {
+ emit pidLost(*it);
+ adbKill(*it);
}
+ m_processPids.clear();
+ m_pidsBuffer.clear();
}
void AndroidRunnerWorker::asyncStart(const QString &intentName,
@@ -368,8 +338,12 @@ void AndroidRunnerWorker::asyncStart(const QString &intentName,
this, &AndroidRunnerWorker::logcatReadStandardOutput);
connect(logcatProcess.get(), &QProcess::readyReadStandardError,
this, &AndroidRunnerWorker::logcatReadStandardError);
+
// Its assumed that the device or avd returned by selector() is online.
- logcatProcess->start(m_adb, selector() << "logcat");
+ QStringList logcatArgs = selector() << "logcat" << "-v" << "time";
+ if (deviceSdkVersion() > 20)
+ logcatArgs << "-T" << "0";
+ logcatProcess->start(m_adb, logcatArgs);
QString errorMessage;
@@ -507,9 +481,20 @@ void AndroidRunnerWorker::asyncStart(const QString &intentName,
QTC_ASSERT(!m_adbLogcatProcess, /**/);
m_adbLogcatProcess = std::move(logcatProcess);
- m_pidFinder = Utils::onResultReady(Utils::runAsync(&findProcessPID, m_adb, selector(),
- m_packageName),
- bind(&AndroidRunnerWorker::onProcessIdChanged, this, _1));
+
+ m_timeoutTimer.reset(new QTimer);
+ m_timeoutTimer->setSingleShot(true);
+ connect(m_timeoutTimer.data(), &QTimer::timeout,
+ this,[this] { onProcessIdChanged(PidInfo{}); });
+ m_timeoutTimer->start(APP_START_TIMEOUT);
+
+ m_pidsFinderProcess.reset(new QProcess);
+ m_pidsFinderProcess->setProcessChannelMode(QProcess::MergedChannels);
+ connect(m_pidsFinderProcess.get(), &QProcess::readyRead, this, &AndroidRunnerWorker::findProcessPids);
+ connect(m_pidsFinderProcess.get(),
+ static_cast<void(QProcess::*)(int, QProcess::ExitStatus)>(&QProcess::finished),
+ this, [this] { onProcessIdChanged(PidInfo{}); });
+ m_pidsFinderProcess->start(m_adb, selector() << "shell" << pidScript);
}
bool AndroidRunnerWorker::adbShellAmNeedsQuotes()
@@ -545,6 +530,19 @@ bool AndroidRunnerWorker::runAdb(const QStringList &args, QString *exitMessage,
return response.result == Utils::SynchronousProcessResponse::Finished;
}
+int AndroidRunnerWorker::deviceSdkVersion()
+{
+ Utils::SynchronousProcess adb;
+ adb.setTimeoutS(10);
+ Utils::SynchronousProcessResponse response
+ = adb.run(m_adb, selector() << "shell" << "getprop" << "ro.build.version.sdk");
+ if (response.result == Utils::SynchronousProcessResponse::StartFailed
+ || response.result != Utils::SynchronousProcessResponse::Finished)
+ return -1;
+
+ return response.allOutput().trimmed().toInt();
+}
+
void AndroidRunnerWorker::handleRemoteDebuggerRunning()
{
if (m_useCppDebugger) {
@@ -558,21 +556,79 @@ void AndroidRunnerWorker::handleRemoteDebuggerRunning()
runAdb(selector() << "push" << tmp.fileName() << m_pongFile);
}
- QTC_CHECK(m_processPID != -1);
+ QTC_CHECK(!m_processPids.isEmpty());
}
emit remoteProcessStarted(m_localGdbServerPort, m_qmlPort);
}
-void AndroidRunnerWorker::asyncStop(const QVector<QStringList> &adbCommands)
+void AndroidRunnerWorker::findProcessPids()
{
- if (!m_pidFinder.isFinished())
- m_pidFinder.cancel();
+ static QMap<qint64, QByteArray> extractedPids;
+ static auto oldPids = m_processPids;
- if (m_processPID != -1) {
- forceStop();
+ m_pidsBuffer += m_pidsFinderProcess->readAll();
+ while (!m_pidsBuffer.isEmpty()) {
+ const int to = m_pidsBuffer.indexOf('\n');
+ if (to < 0)
+ break;
+
+ if (to == 0) {
+ m_pidsBuffer = m_pidsBuffer.mid(1);
+ continue;
+ }
+
+ // = is used to delimit ps outputs
+ // is needed to know when an existins PID is killed
+ if (m_pidsBuffer[0] != '=') {
+ QByteArray tuple = m_pidsBuffer.left(to + 1).simplified();
+ QList<QByteArray> parts = tuple.split(':');
+ QByteArray commandName = parts.takeFirst();
+ if (QString::fromLocal8Bit(commandName) == m_packageName) {
+ auto pid = parts.last().toLongLong();
+ if (!m_processPids.contains(pid)) {
+ extractedPids[pid] = commandName + (parts.length() == 2
+ ? ":" + parts.first() : QByteArray{});
+ } else {
+ oldPids.remove(pid);
+ }
+ }
+ } else {
+ // Add new PIDs
+ for (auto it = extractedPids.constBegin(); it != extractedPids.constEnd(); ++it) {
+ onProcessIdChanged(PidInfo(it.key(), PidStatus::Found,
+ QString::fromLocal8Bit(it.value())));
+ }
+ extractedPids.clear();
+
+ // Remove the dead ones
+ for (auto it = oldPids.constBegin(); it != oldPids.constEnd(); ++it)
+ onProcessIdChanged(PidInfo(*it, PidStatus::Lost));
+
+ // Save the current non dead PIDs
+ oldPids = m_processPids;
+ if (m_processPids.isEmpty()) {
+ extractedPids.clear();
+ m_pidsBuffer.clear();
+ break;
+ }
+ }
+ m_pidsBuffer = m_pidsBuffer.mid(to + 1);
}
+}
+
+void AndroidRunnerWorker::asyncStop(const QVector<QStringList> &adbCommands)
+{
+ m_timeoutTimer.reset();
+ m_pidsFinderProcess.reset();
+ if (!m_processPids.isEmpty())
+ forceStop();
+
foreach (const QStringList &entry, adbCommands)
runAdb(selector() << entry);
+
+ m_adbLogcatProcess.reset();
+ emit remoteProcessFinished(QLatin1String("\n\n") +
+ tr("\"%1\" terminated.").arg(m_packageName));
}
void AndroidRunnerWorker::setAdbParameters(const QString &packageName, const QStringList &selector)
@@ -594,58 +650,48 @@ void AndroidRunnerWorker::logcatProcess(const QByteArray &text, QByteArray &buff
buffer.clear();
}
- QString pidString = QString::number(m_processPID);
foreach (const QByteArray &msg, lines) {
- const QString line = QString::fromUtf8(msg).trimmed() + QLatin1Char('\n');
- if (!line.contains(pidString))
- continue;
- if (m_logCatRegExp.exactMatch(line)) {
- // Android M
- if (m_logCatRegExp.cap(1) == pidString) {
- const QString &messagetype = m_logCatRegExp.cap(2);
- QString output = line.mid(m_logCatRegExp.pos(2));
-
- if (onlyError
- || messagetype == QLatin1String("F")
- || messagetype == QLatin1String("E")
- || messagetype == QLatin1String("W"))
- emit remoteErrorOutput(output);
- else
- emit remoteOutput(output);
- }
- } else {
- if (onlyError || line.startsWith("F/")
- || line.startsWith("E/")
- || line.startsWith("W/"))
- emit remoteErrorOutput(line);
- else
- emit remoteOutput(line);
- }
+ const QString line = QString::fromUtf8(msg.trimmed());
+ if (onlyError)
+ emit remoteErrorOutput(line);
+ else
+ emit remoteOutput(line);
}
}
-void AndroidRunnerWorker::onProcessIdChanged(qint64 pid)
+void AndroidRunnerWorker::onProcessIdChanged(PidInfo pidInfo)
{
// Don't write to m_psProc from a different thread
QTC_ASSERT(QThread::currentThread() == thread(), return);
- m_processPID = pid;
- if (m_processPID == -1) {
+
+ auto isFirst = m_processPids.isEmpty();
+ if (pidInfo.status == PidStatus::Lost) {
+ m_processPids.remove(pidInfo.pid);
+ emit pidLost(pidInfo.pid);
+ } else {
+ m_processPids.insert(pidInfo.pid);
+ emit pidFound(pidInfo.pid, pidInfo.name);
+ }
+
+ if (m_processPids.isEmpty() || pidInfo.pid == -1) {
emit remoteProcessFinished(QLatin1String("\n\n") + tr("\"%1\" died.")
.arg(m_packageName));
// App died/killed. Reset log and monitor processes.
+ forceStop();
m_adbLogcatProcess.reset();
- m_psIsAlive.reset();
- } else {
+ m_timeoutTimer.reset();
+ } else if (isFirst) {
+ m_timeoutTimer.reset();
if (m_useCppDebugger) {
// This will be funneled to the engine to actually start and attach
// gdb. Afterwards this ends up in handleRemoteDebuggerRunning() below.
QByteArray serverChannel = ':' + QByteArray::number(m_localGdbServerPort.number());
- emit remoteServerRunning(serverChannel, m_processPID);
+ emit remoteServerRunning(serverChannel, pidInfo.pid);
} else if (m_qmlDebugServices == QmlDebug::QmlDebuggerServices) {
// This will be funneled to the engine to actually start and attach
// gdb. Afterwards this ends up in handleRemoteDebuggerRunning() below.
QByteArray serverChannel = QByteArray::number(m_qmlPort.number());
- emit remoteServerRunning(serverChannel, m_processPID);
+ emit remoteServerRunning(serverChannel, pidInfo.pid);
} else if (m_qmlDebugServices == QmlDebug::QmlProfilerServices) {
emit remoteProcessStarted(Utils::Port(), m_qmlPort);
} else {
@@ -653,27 +699,18 @@ void AndroidRunnerWorker::onProcessIdChanged(qint64 pid)
emit remoteProcessStarted(Utils::Port(), Utils::Port());
}
logcatReadStandardOutput();
- QTC_ASSERT(!m_psIsAlive, /**/);
- m_psIsAlive.reset(new QProcess);
- m_psIsAlive->setProcessChannelMode(QProcess::MergedChannels);
- connect(m_psIsAlive.get(), &QProcess::readyRead, [this](){
- if (!m_psIsAlive->readAll().simplified().isEmpty())
- onProcessIdChanged(-1);
- });
- m_psIsAlive->start(m_adb, selector() << QStringLiteral("shell")
- << pidPollingScript.arg(m_processPID));
}
}
void AndroidRunnerWorker::logcatReadStandardError()
{
- if (m_processPID != -1)
+ if (!m_processPids.isEmpty() && m_adbLogcatProcess)
logcatProcess(m_adbLogcatProcess->readAllStandardError(), m_stderrBuffer, true);
}
void AndroidRunnerWorker::logcatReadStandardOutput()
{
- if (m_processPID != -1)
+ if (!m_processPids.isEmpty() && m_adbLogcatProcess)
logcatProcess(m_adbLogcatProcess->readAllStandardOutput(), m_stdoutBuffer, false);
}
@@ -724,6 +761,10 @@ AndroidRunner::AndroidRunner(QObject *parent, RunConfiguration *runConfig, Core:
this, &AndroidRunner::remoteOutput);
connect(m_worker.data(), &AndroidRunnerWorker::remoteErrorOutput,
this, &AndroidRunner::remoteErrorOutput);
+ connect(m_worker.data(), &AndroidRunnerWorker::pidFound,
+ this, &AndroidRunner::pidFound);
+ connect(m_worker.data(), &AndroidRunnerWorker::pidLost,
+ this, &AndroidRunner::pidLost);
m_thread.start();
}
@@ -791,8 +832,9 @@ void AndroidRunner::launchAVD()
emit adbParametersChanged(m_androidRunnable.packageName,
AndroidDeviceInfo::adbSelector(info.serialNumber));
if (info.isValid()) {
- if (AndroidConfigurations::currentConfig().findAvd(info.avdname).isEmpty()) {
- bool launched = AndroidConfigurations::currentConfig().startAVDAsync(info.avdname);
+ AndroidAvdManager avdManager;
+ if (avdManager.findAvd(info.avdname).isEmpty()) {
+ bool launched = avdManager.startAvdAsync(info.avdname);
m_launchedAVDName = launched ? info.avdname:"";
} else {
m_launchedAVDName.clear();
@@ -803,11 +845,12 @@ void AndroidRunner::launchAVD()
void AndroidRunner::checkAVD()
{
const AndroidConfig &config = AndroidConfigurations::currentConfig();
- QString serialNumber = config.findAvd(m_launchedAVDName);
+ AndroidAvdManager avdManager(config);
+ QString serialNumber = avdManager.findAvd(m_launchedAVDName);
if (!serialNumber.isEmpty())
return; // try again on next timer hit
- if (config.hasFinishedBooting(serialNumber)) {
+ if (avdManager.isAvdBooted(serialNumber)) {
m_checkAVDTimer.stop();
AndroidManager::setDeviceSerialNumber(m_runConfig->target(), serialNumber);
emit asyncStart(m_androidRunnable.intentName, m_androidRunnable.beforeStartADBCommands);
diff --git a/src/plugins/android/androidrunner.h b/src/plugins/android/androidrunner.h
index dd35534bd6..f30dc4754b 100644
--- a/src/plugins/android/androidrunner.h
+++ b/src/plugins/android/androidrunner.h
@@ -75,6 +75,9 @@ signals:
void adbParametersChanged(const QString &packageName, const QStringList &selector);
void avdDetected();
+ void pidFound(qint64, const QString &name);
+ void pidLost(qint64);
+
private:
void checkAVD();
void launchAVD();
diff --git a/src/plugins/android/androidsdkmanager.cpp b/src/plugins/android/androidsdkmanager.cpp
new file mode 100644
index 0000000000..0ed23660a6
--- /dev/null
+++ b/src/plugins/android/androidsdkmanager.cpp
@@ -0,0 +1,337 @@
+/****************************************************************************
+**
+** 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 "androidsdkmanager.h"
+
+#include "androidmanager.h"
+#include "androidtoolmanager.h"
+
+#include "utils/algorithm.h"
+#include "utils/qtcassert.h"
+#include "utils/synchronousprocess.h"
+#include "utils/environment.h"
+
+#include <QLoggingCategory>
+#include <QSettings>
+
+namespace {
+Q_LOGGING_CATEGORY(sdkManagerLog, "qtc.android.sdkManager")
+}
+
+namespace Android {
+namespace Internal {
+
+// Though sdk manager is introduced in 25.2.3 but the verbose mode is avaialble in 25.3.0
+// and android tool is supported in 25.2.3
+const QVersionNumber sdkManagerIntroVersion(25, 3 ,0);
+
+const char installLocationKey[] = "Installed Location:";
+const char apiLevelPropertyKey[] = "AndroidVersion.ApiLevel";
+const char abiPropertyKey[] = "SystemImage.Abi";
+
+using namespace Utils;
+
+/*!
+ Parses the \a line for a [spaces]key[spaces]value[spaces] pattern and returns
+ \c true if \a key is found, false otherwise. Result 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;
+}
+
+/*!
+ Runs the \c sdkmanger tool specific to configuration \a config with arguments \a args. Returns
+ \c true if the command is successfully executed. Output is copied into \a output. The function
+ blocks the calling thread.
+ */
+static bool sdkManagerCommand(const AndroidConfig config, const QStringList &args, QString *output)
+{
+ QString sdkManagerToolPath = config.sdkManagerToolPath().toString();
+ SynchronousProcess proc;
+ SynchronousProcessResponse response = proc.runBlocking(sdkManagerToolPath, args);
+ if (response.result == SynchronousProcessResponse::Finished) {
+ if (output)
+ *output = response.allOutput();
+ return true;
+ }
+ return false;
+}
+
+/*!
+ \class SdkManagerOutputParser
+ \brief The SdkManagerOutputParser class is a helper class to parse the output of the \c sdkmanager
+ commands.
+ */
+class SdkManagerOutputParser
+{
+public:
+ enum MarkerTag
+ {
+ None = 0x01,
+ InstalledPackagesMarker = 0x02,
+ AvailablePackagesMarkers = 0x04,
+ AvailableUpdatesMarker = 0x08,
+ EmptyMarker = 0x10,
+ PlatformMarker = 0x20,
+ SystemImageMarker = 0x40,
+ SectionMarkers = InstalledPackagesMarker | AvailablePackagesMarkers | AvailableUpdatesMarker
+ };
+
+ void parsePackageListing(const QString &output);
+
+ SdkPlatformList m_installedPlatforms;
+
+private:
+ void compileData();
+ void parsePackageData(MarkerTag packageMarker, const QStringList &data);
+ bool parsePlatform(const QStringList &data, SdkPlatform *platform) const;
+ bool parseSystemImage(const QStringList &data, SystemImage *image);
+ MarkerTag parseMarkers(const QString &line);
+
+ MarkerTag m_currentSection = MarkerTag::None;
+ SystemImageList m_installedSystemImages;
+};
+
+const std::map<SdkManagerOutputParser::MarkerTag, const char *> markerTags {
+ {SdkManagerOutputParser::MarkerTag::InstalledPackagesMarker, "Installed packages:"},
+ {SdkManagerOutputParser::MarkerTag::AvailablePackagesMarkers, "Available Packages:"},
+ {SdkManagerOutputParser::MarkerTag::AvailablePackagesMarkers, "Available Updates:"},
+ {SdkManagerOutputParser::MarkerTag::PlatformMarker, "platforms"},
+ {SdkManagerOutputParser::MarkerTag::SystemImageMarker, "system-images"}
+};
+
+AndroidSdkManager::AndroidSdkManager(const AndroidConfig &config):
+ m_config(config),
+ m_parser(new SdkManagerOutputParser)
+{
+ QString packageListing;
+ if (sdkManagerCommand(config, QStringList({"--list", "--verbose"}), &packageListing)) {
+ m_parser->parsePackageListing(packageListing);
+ }
+}
+
+AndroidSdkManager::~AndroidSdkManager()
+{
+
+}
+
+SdkPlatformList AndroidSdkManager::availableSdkPlatforms()
+{
+ if (m_config.sdkToolsVersion() < sdkManagerIntroVersion) {
+ AndroidToolManager toolManager(m_config);
+ return toolManager.availableSdkPlatforms();
+ }
+
+ return m_parser->m_installedPlatforms;
+}
+
+void SdkManagerOutputParser::parsePackageListing(const QString &output)
+{
+ QStringList packageData;
+ bool collectingPackageData = false;
+ MarkerTag currentPackageMarker = MarkerTag::None;
+
+ auto processCurrentPackage = [&]() {
+ if (collectingPackageData) {
+ collectingPackageData = false;
+ parsePackageData(currentPackageMarker, packageData);
+ packageData.clear();
+ }
+ };
+
+ foreach (QString outputLine, output.split('\n')) {
+ MarkerTag marker = parseMarkers(outputLine);
+
+ if (marker & SectionMarkers) {
+ // Section marker found. Update the current section being parsed.
+ m_currentSection = marker;
+ processCurrentPackage();
+ continue;
+ }
+
+ if (m_currentSection == None
+ || m_currentSection == AvailablePackagesMarkers // At this point. Not interested in
+ || m_currentSection == AvailableUpdatesMarker) { // available or update packages.
+ // Let go of verbose output utill a valid section starts.
+ continue;
+ }
+
+ if (marker == EmptyMarker) {
+ // Empty marker. Occurs at the end of a package details.
+ // Process the collected package data, if any.
+ processCurrentPackage();
+ continue;
+ }
+
+ if (marker == None) {
+ if (collectingPackageData)
+ packageData << outputLine; // Collect data until next marker.
+ else
+ continue;
+ } else {
+ // Package marker found.
+ processCurrentPackage(); // New package starts. Process the collected package data, if any.
+ currentPackageMarker = marker;
+ collectingPackageData = true;
+ packageData << outputLine;
+ }
+ }
+ compileData();
+ Utils::sort(m_installedPlatforms);
+}
+
+void SdkManagerOutputParser::compileData()
+{
+ // Associate the system images with sdk platforms.
+ for (auto &image : m_installedSystemImages) {
+ auto findPlatfom = [image](const SdkPlatform &platform) {
+ return platform.apiLevel == image.apiLevel;
+ };
+ auto itr = std::find_if(m_installedPlatforms.begin(), m_installedPlatforms.end(), findPlatfom);
+ if (itr != m_installedPlatforms.end())
+ itr->systemImages.append(image);
+ }
+}
+
+void SdkManagerOutputParser::parsePackageData(MarkerTag packageMarker, const QStringList &data)
+{
+ QTC_ASSERT(!data.isEmpty() && packageMarker != None, return);
+
+ if (m_currentSection != MarkerTag::InstalledPackagesMarker)
+ return; // For now, only interested in installed packages.
+
+ switch (packageMarker) {
+ case MarkerTag::PlatformMarker:
+ {
+ SdkPlatform platform;
+ if (parsePlatform(data, &platform))
+ m_installedPlatforms.append(platform);
+ else
+ qCDebug(sdkManagerLog) << "Platform: Parsing failed: " << data;
+ }
+ break;
+
+ case MarkerTag::SystemImageMarker:
+ {
+ SystemImage image;
+ if (parseSystemImage(data, &image))
+ m_installedSystemImages.append(image);
+ else
+ qCDebug(sdkManagerLog) << "System Image: Parsing failed: " << data;
+ }
+ break;
+
+ default:
+ qCDebug(sdkManagerLog) << "Unhandled package: " << markerTags.at(packageMarker);
+ break;
+ }
+}
+
+bool SdkManagerOutputParser::parsePlatform(const QStringList &data, SdkPlatform *platform) const
+{
+ QTC_ASSERT(platform && !data.isEmpty(), return false);
+
+ QStringList parts = data.at(0).split(';');
+ if (parts.count() < 2) {
+ qCDebug(sdkManagerLog) << "Platform: Unexpected header: "<< data;
+ return false;
+ }
+ platform->name = parts[1];
+ platform->package = data.at(0);
+
+ foreach (QString line, data) {
+ QString value;
+ if (valueForKey(installLocationKey, line, &value))
+ platform->installedLocation = Utils::FileName::fromString(value);
+ }
+
+ int apiLevel = AndroidManager::findApiLevel(platform->installedLocation);
+ if (apiLevel != -1)
+ platform->apiLevel = apiLevel;
+ else
+ qCDebug(sdkManagerLog) << "Platform: Can not parse api level: "<< data;
+
+ return apiLevel != -1;
+}
+
+bool SdkManagerOutputParser::parseSystemImage(const QStringList &data, SystemImage *image)
+{
+ QTC_ASSERT(image && !data.isEmpty(), return false);
+
+ QStringList parts = data.at(0).split(';');
+ QTC_ASSERT(!data.isEmpty() && parts.count() >= 4,
+ qCDebug(sdkManagerLog) << "System Image: Unexpected header: " << data);
+
+ image->package = data.at(0);
+ foreach (QString line, data) {
+ QString value;
+ if (valueForKey(installLocationKey, line, &value))
+ image->installedLocation = Utils::FileName::fromString(value);
+ }
+
+ Utils::FileName propertiesPath = image->installedLocation;
+ propertiesPath.appendPath("/source.properties");
+ if (propertiesPath.exists()) {
+ // Installed System Image.
+ QSettings imageProperties(propertiesPath.toString(), QSettings::IniFormat);
+ bool validApiLevel = false;
+ image->apiLevel = imageProperties.value(apiLevelPropertyKey).toInt(&validApiLevel);
+ if (!validApiLevel) {
+ qCDebug(sdkManagerLog) << "System Image: Can not parse api level: "<< data;
+ return false;
+ }
+ image->abiName = imageProperties.value(abiPropertyKey).toString();
+ } else if (parts.count() >= 4){
+ image->apiLevel = parts[1].section('-', 1, 1).toInt();
+ image->abiName = parts[3];
+ } else {
+ qCDebug(sdkManagerLog) << "System Image: Can not parse: "<< data;
+ return false;
+ }
+
+ return true;
+}
+
+SdkManagerOutputParser::MarkerTag SdkManagerOutputParser::parseMarkers(const QString &line)
+{
+ if (line.isEmpty())
+ return EmptyMarker;
+
+ for (auto pair: markerTags) {
+ if (line.startsWith(QLatin1String(pair.second)))
+ return pair.first;
+ }
+
+ return None;
+}
+
+} // namespace Internal
+} // namespace Android
diff --git a/src/plugins/android/androidsdkmanager.h b/src/plugins/android/androidsdkmanager.h
new file mode 100644
index 0000000000..2c11148072
--- /dev/null
+++ b/src/plugins/android/androidsdkmanager.h
@@ -0,0 +1,51 @@
+/****************************************************************************
+**
+** 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/fileutils.h"
+#include "androidconfigurations.h"
+
+#include <memory>
+
+namespace Android {
+namespace Internal {
+
+class SdkManagerOutputParser;
+
+class AndroidSdkManager
+{
+public:
+ AndroidSdkManager(const AndroidConfig &config);
+ ~AndroidSdkManager();
+
+ SdkPlatformList availableSdkPlatforms();
+
+private:
+ const AndroidConfig &m_config;
+ std::unique_ptr<SdkManagerOutputParser> m_parser;
+};
+
+} // namespace Internal
+} // namespace Android
diff --git a/src/plugins/android/androidsettingswidget.cpp b/src/plugins/android/androidsettingswidget.cpp
index 5cdf42cdf3..a0a24ea087 100644
--- a/src/plugins/android/androidsettingswidget.cpp
+++ b/src/plugins/android/androidsettingswidget.cpp
@@ -30,6 +30,7 @@
#include "androidconfigurations.h"
#include "androidconstants.h"
#include "androidtoolchain.h"
+#include "androidavdmanager.h"
#include <utils/environment.h>
#include <utils/hostosinfo.h>
@@ -58,7 +59,7 @@
namespace Android {
namespace Internal {
-void AvdModel::setAvdList(const QVector<AndroidDeviceInfo> &list)
+void AvdModel::setAvdList(const AndroidDeviceInfoList &list)
{
beginResetModel();
m_list = list;
@@ -128,10 +129,13 @@ AndroidSettingsWidget::AndroidSettingsWidget(QWidget *parent)
m_ndkState(NotSet),
m_javaState(NotSet),
m_ui(new Ui_AndroidSettingsWidget),
- m_androidConfig(AndroidConfigurations::currentConfig())
+ m_androidConfig(AndroidConfigurations::currentConfig()),
+ m_avdManager(new AndroidAvdManager(m_androidConfig))
{
m_ui->setupUi(this);
+ m_ui->deprecatedInfoIconLabel->setPixmap(Utils::Icons::INFO.pixmap());
+
connect(&m_checkGdbWatcher, &QFutureWatcherBase::finished,
this, &AndroidSettingsWidget::checkGdbFinished);
@@ -158,7 +162,8 @@ AndroidSettingsWidget::AndroidSettingsWidget(QWidget *parent)
m_ui->AntLocationPathChooser->setPromptDialogTitle(tr("Select ant Script"));
m_ui->AntLocationPathChooser->setInitialBrowsePathBackup(dir);
m_ui->AntLocationPathChooser->setPromptDialogFilter(filter);
- m_ui->UseGradleCheckBox->setChecked(m_androidConfig.useGrandle());
+
+ updateGradleBuildUi();
m_ui->OpenJDKLocationPathChooser->setFileName(m_androidConfig.openJDKLocation());
m_ui->OpenJDKLocationPathChooser->setPromptDialogTitle(tr("Select JDK Path"));
@@ -463,7 +468,7 @@ void AndroidSettingsWidget::enableAvdControls()
void AndroidSettingsWidget::startUpdateAvd()
{
disableAvdControls();
- m_virtualDevicesWatcher.setFuture(m_androidConfig.androidVirtualDevicesFuture());
+ m_virtualDevicesWatcher.setFuture(m_avdManager->avdList());
}
void AndroidSettingsWidget::updateAvds()
@@ -476,6 +481,13 @@ void AndroidSettingsWidget::updateAvds()
enableAvdControls();
}
+void AndroidSettingsWidget::updateGradleBuildUi()
+{
+ m_ui->UseGradleCheckBox->setEnabled(m_androidConfig.antScriptsAvailable());
+ m_ui->UseGradleCheckBox->setChecked(!m_androidConfig.antScriptsAvailable() ||
+ m_androidConfig.useGrandle());
+}
+
bool AndroidSettingsWidget::sdkLocationIsValid() const
{
Utils::FileName androidExe = m_androidConfig.sdkLocation();
@@ -505,6 +517,7 @@ void AndroidSettingsWidget::saveSettings()
void AndroidSettingsWidget::sdkLocationEditingFinished()
{
m_androidConfig.setSdkLocation(Utils::FileName::fromUserInput(m_ui->SDKLocationPathChooser->rawPath()));
+ updateGradleBuildUi();
check(Sdk);
@@ -587,12 +600,12 @@ void AndroidSettingsWidget::addAVD()
disableAvdControls();
AndroidConfig::CreateAvdInfo info = m_androidConfig.gatherCreateAVDInfo(this);
- if (info.target.isEmpty()) {
+ if (!info.target.isValid()) {
enableAvdControls();
return;
}
- m_futureWatcher.setFuture(m_androidConfig.createAVD(info));
+ m_futureWatcher.setFuture(m_avdManager->createAvd(info));
}
void AndroidSettingsWidget::avdAdded()
@@ -620,13 +633,13 @@ void AndroidSettingsWidget::removeAVD()
return;
}
- m_androidConfig.removeAVD(avdName);
+ m_avdManager->removeAvd(avdName);
startUpdateAvd();
}
void AndroidSettingsWidget::startAVD()
{
- m_androidConfig.startAVDAsync(m_AVDModel.avdName(m_ui->AVDTableView->currentIndex()));
+ m_avdManager->startAvdAsync(m_AVDModel.avdName(m_ui->AVDTableView->currentIndex()));
}
void AndroidSettingsWidget::avdActivated(const QModelIndex &index)
@@ -671,16 +684,15 @@ void AndroidSettingsWidget::showGdbWarningDialog()
void AndroidSettingsWidget::manageAVD()
{
- QProcess *avdProcess = new QProcess();
- connect(this, &QObject::destroyed, avdProcess, &QObject::deleteLater);
- connect(avdProcess, static_cast<void (QProcess::*)(int)>(&QProcess::finished),
- avdProcess, &QObject::deleteLater);
-
- avdProcess->setProcessEnvironment(m_androidConfig.androidToolEnvironment().toProcessEnvironment());
- QString executable = m_androidConfig.androidToolPath().toString();
- QStringList arguments = QStringList("avd");
-
- avdProcess->start(executable, arguments);
+ if (m_avdManager->avdManagerUiToolAvailable()) {
+ m_avdManager->launchAvdManagerUiTool();
+ } else {
+ QMessageBox::warning(this, tr("AVD Manager Not Available"),
+ tr("AVD manager UI tool is not available in the installed SDK tools"
+ "(version %1). Use the command line tool \"avdmanager\" for "
+ "advanced AVD management.")
+ .arg(m_androidConfig.sdkToolsVersion().toString()));
+ }
}
diff --git a/src/plugins/android/androidsettingswidget.h b/src/plugins/android/androidsettingswidget.h
index 3572ffef1a..50be7c1049 100644
--- a/src/plugins/android/androidsettingswidget.h
+++ b/src/plugins/android/androidsettingswidget.h
@@ -33,6 +33,8 @@
#include <QAbstractTableModel>
#include <QFutureWatcher>
+#include <memory>
+
QT_BEGIN_NAMESPACE
class Ui_AndroidSettingsWidget;
QT_END_NAMESPACE
@@ -40,11 +42,13 @@ QT_END_NAMESPACE
namespace Android {
namespace Internal {
+class AndroidAvdManager;
+
class AvdModel: public QAbstractTableModel
{
Q_OBJECT
public:
- void setAvdList(const QVector<AndroidDeviceInfo> &list);
+ void setAvdList(const AndroidDeviceInfoList &list);
QString avdName(const QModelIndex &index) const;
QModelIndex indexForAvdName(const QString &avdName) const;
@@ -55,7 +59,7 @@ protected:
int columnCount(const QModelIndex &parent = QModelIndex()) const;
private:
- QVector<AndroidDeviceInfo> m_list;
+ AndroidDeviceInfoList m_list;
};
class AndroidSettingsWidget : public QWidget
@@ -91,6 +95,7 @@ private:
void checkGdbFinished();
void showGdbWarningDialog();
void updateAvds();
+ void updateGradleBuildUi();
private:
enum Mode { Sdk = 1, Ndk = 2, Java = 4, All = Sdk | Ndk | Java };
@@ -117,8 +122,9 @@ private:
QFutureWatcher<QPair<QStringList, bool>> m_checkGdbWatcher;
QStringList m_gdbCheckPaths;
- QFutureWatcher<QVector<AndroidDeviceInfo>> m_virtualDevicesWatcher;
+ QFutureWatcher<AndroidDeviceInfoList> m_virtualDevicesWatcher;
QString m_lastAddedAvd;
+ std::unique_ptr<AndroidAvdManager> m_avdManager;
};
} // namespace Internal
diff --git a/src/plugins/android/androidsettingswidget.ui b/src/plugins/android/androidsettingswidget.ui
index 952dc444cc..338c73da04 100644
--- a/src/plugins/android/androidsettingswidget.ui
+++ b/src/plugins/android/androidsettingswidget.ui
@@ -237,20 +237,30 @@
</layout>
</item>
<item row="8" column="1">
- <widget class="QCheckBox" name="CreateKitCheckBox">
- <property name="sizePolicy">
- <sizepolicy hsizetype="Expanding" vsizetype="Fixed">
- <horstretch>0</horstretch>
- <verstretch>0</verstretch>
- </sizepolicy>
- </property>
- <property name="text">
- <string>Automatically create kits for Android tool chains</string>
+ <layout class="QHBoxLayout" name="horizontalLayout_8">
+ <property name="spacing">
+ <number>2</number>
</property>
- <property name="checked">
- <bool>true</bool>
+ <property name="leftMargin">
+ <number>0</number>
</property>
- </widget>
+ <item>
+ <widget class="QCheckBox" name="CreateKitCheckBox">
+ <property name="sizePolicy">
+ <sizepolicy hsizetype="Expanding" vsizetype="Fixed">
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ <property name="text">
+ <string>Automatically create kits for Android tool chains</string>
+ </property>
+ <property name="checked">
+ <bool>true</bool>
+ </property>
+ </widget>
+ </item>
+ </layout>
</item>
<item row="9" column="1">
<layout class="QHBoxLayout" name="horizontalLayout_2">
@@ -289,17 +299,59 @@
</layout>
</item>
<item row="10" column="1">
- <widget class="QCheckBox" name="UseGradleCheckBox">
- <property name="sizePolicy">
- <sizepolicy hsizetype="Expanding" vsizetype="Fixed">
- <horstretch>0</horstretch>
- <verstretch>0</verstretch>
- </sizepolicy>
+ <layout class="QHBoxLayout" name="horizontalLayout_7">
+ <property name="spacing">
+ <number>4</number>
</property>
- <property name="text">
- <string>Use Gradle instead of Ant</string>
+ <property name="leftMargin">
+ <number>0</number>
</property>
- </widget>
+ <item>
+ <widget class="QCheckBox" name="UseGradleCheckBox">
+ <property name="sizePolicy">
+ <sizepolicy hsizetype="Preferred" vsizetype="Fixed">
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ <property name="text">
+ <string>Use Gradle instead of Ant (Ant builds are deprecated)</string>
+ </property>
+ <property name="checked">
+ <bool>true</bool>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <widget class="QLabel" name="deprecatedInfoIconLabel">
+ <property name="sizePolicy">
+ <sizepolicy hsizetype="Fixed" vsizetype="Fixed">
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ <property name="toolTip">
+ <string>Gradle builds are forced from Android SDK tools version 25.3.0 onwards as Ant scripts are no longer available.</string>
+ </property>
+ <property name="text">
+ <string/>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <spacer name="horizontalSpacer_2">
+ <property name="orientation">
+ <enum>Qt::Horizontal</enum>
+ </property>
+ <property name="sizeHint" stdset="0">
+ <size>
+ <width>0</width>
+ <height>0</height>
+ </size>
+ </property>
+ </spacer>
+ </item>
+ </layout>
</item>
<item row="11" column="0">
<widget class="QLabel" name="AntLocationLabel">
diff --git a/src/plugins/android/androidtoolmanager.cpp b/src/plugins/android/androidtoolmanager.cpp
new file mode 100644
index 0000000000..a6e61d96d9
--- /dev/null
+++ b/src/plugins/android/androidtoolmanager.cpp
@@ -0,0 +1,346 @@
+/****************************************************************************
+**
+** 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 "androidtoolmanager.h"
+
+#include "androidmanager.h"
+
+#include "utils/algorithm.h"
+#include "utils/environment.h"
+#include "utils/qtcassert.h"
+#include "utils/runextensions.h"
+#include "utils/synchronousprocess.h"
+
+#include <QLoggingCategory>
+
+namespace {
+Q_LOGGING_CATEGORY(androidToolLog, "qtc.android.sdkManager")
+}
+
+namespace Android {
+namespace Internal {
+
+using namespace Utils;
+
+class AndroidToolOutputParser
+{
+public:
+ void parseTargetListing(const QString &output, const FileName &sdkLocation,
+ SdkPlatformList *platformList);
+
+ QList<SdkPlatform> m_installedPlatforms;
+};
+
+/*!
+ Runs the \c android tool located at \a toolPath with arguments \a args and environment \a
+ environment. Returns \c true for successful execution. Command's output is copied to \a
+ output.
+ */
+static bool androidToolCommand(Utils::FileName toolPath, const QStringList &args,
+ const Environment &environment, QString *output)
+{
+ QString androidToolPath = toolPath.toString();
+ SynchronousProcess proc;
+ proc.setProcessEnvironment(environment.toProcessEnvironment());
+ SynchronousProcessResponse response = proc.runBlocking(androidToolPath, args);
+ if (response.result == SynchronousProcessResponse::Finished) {
+ if (output)
+ *output = response.allOutput();
+ return true;
+ }
+ return false;
+}
+
+static QStringList cleanAndroidABIs(const QStringList &abis)
+{
+ QStringList res;
+ foreach (const QString &abi, abis) {
+ int index = abi.lastIndexOf(QLatin1Char('/'));
+ if (index == -1)
+ res << abi;
+ else
+ res << abi.mid(index + 1);
+ }
+ return res;
+}
+
+AndroidToolManager::AndroidToolManager(const AndroidConfig &config) :
+ m_config(config),
+ m_parser(new AndroidToolOutputParser)
+{
+
+}
+
+AndroidToolManager::~AndroidToolManager()
+{
+
+}
+
+SdkPlatformList AndroidToolManager::availableSdkPlatforms() const
+{
+ SdkPlatformList list;
+ QString targetListing;
+ if (androidToolCommand(m_config.androidToolPath(), QStringList({"list", "target"}),
+ androidToolEnvironment(), &targetListing)) {
+ m_parser->parseTargetListing(targetListing, m_config.sdkLocation(), &list);
+ } else {
+ qCDebug(androidToolLog) << "Android tool target listing failed";
+ }
+ return list;
+}
+
+void AndroidToolManager::launchAvdManager() const
+{
+ QProcess::startDetached(m_config.androidToolPath().toString(), QStringList("avd"));
+}
+
+QFuture<AndroidConfig::CreateAvdInfo>
+AndroidToolManager::createAvd(AndroidConfig::CreateAvdInfo info) const
+{
+ return Utils::runAsync(&AndroidToolManager::createAvdImpl, info,
+ m_config.androidToolPath(), androidToolEnvironment());
+}
+
+bool AndroidToolManager::removeAvd(const QString &name) const
+{
+ SynchronousProcess proc;
+ proc.setTimeoutS(5);
+ proc.setProcessEnvironment(androidToolEnvironment().toProcessEnvironment());
+ SynchronousProcessResponse response
+ = proc.runBlocking(m_config.androidToolPath().toString(),
+ QStringList({"delete", "avd", "-n", name}));
+ return response.result == SynchronousProcessResponse::Finished && response.exitCode == 0;
+}
+
+QFuture<AndroidDeviceInfoList> AndroidToolManager::androidVirtualDevicesFuture() const
+{
+ return Utils::runAsync(&AndroidToolManager::androidVirtualDevices,
+ m_config.androidToolPath(), m_config.sdkLocation(),
+ androidToolEnvironment());
+}
+
+Environment AndroidToolManager::androidToolEnvironment() const
+{
+ Environment env = Environment::systemEnvironment();
+ Utils::FileName jdkLocation = m_config.openJDKLocation();
+ if (!jdkLocation.isEmpty()) {
+ env.set(QLatin1String("JAVA_HOME"), jdkLocation.toUserOutput());
+ Utils::FileName binPath = jdkLocation;
+ binPath.appendPath(QLatin1String("bin"));
+ env.prependOrSetPath(binPath.toUserOutput());
+ }
+ return env;
+}
+
+AndroidConfig::CreateAvdInfo AndroidToolManager::createAvdImpl(AndroidConfig::CreateAvdInfo info,
+ FileName androidToolPath,
+ Environment env)
+{
+ QProcess proc;
+ proc.setProcessEnvironment(env.toProcessEnvironment());
+ QStringList arguments;
+ arguments << QLatin1String("create") << QLatin1String("avd")
+ << QLatin1String("-t") << info.target.name
+ << QLatin1String("-n") << info.name
+ << QLatin1String("-b") << info.abi;
+ if (info.sdcardSize > 0)
+ arguments << QLatin1String("-c") << QString::fromLatin1("%1M").arg(info.sdcardSize);
+ proc.start(androidToolPath.toString(), arguments);
+ if (!proc.waitForStarted()) {
+ info.error = tr("Could not start process \"%1 %2\"")
+ .arg(androidToolPath.toString(), arguments.join(QLatin1Char(' ')));
+ return info;
+ }
+ QTC_CHECK(proc.state() == QProcess::Running);
+ proc.write(QByteArray("yes\n")); // yes to "Do you wish to create a custom hardware profile"
+
+ QByteArray question;
+ while (true) {
+ proc.waitForReadyRead(500);
+ question += proc.readAllStandardOutput();
+ if (question.endsWith(QByteArray("]:"))) {
+ // truncate to last line
+ int index = question.lastIndexOf(QByteArray("\n"));
+ if (index != -1)
+ question = question.mid(index);
+ if (question.contains("hw.gpu.enabled"))
+ proc.write(QByteArray("yes\n"));
+ else
+ proc.write(QByteArray("\n"));
+ question.clear();
+ }
+
+ if (proc.state() != QProcess::Running)
+ break;
+ }
+ QTC_CHECK(proc.state() == QProcess::NotRunning);
+
+ QString errorOutput = QString::fromLocal8Bit(proc.readAllStandardError());
+ // The exit code is always 0, so we need to check stderr
+ // For now assume that any output at all indicates a error
+ if (!errorOutput.isEmpty()) {
+ info.error = errorOutput;
+ }
+
+ return info;
+}
+
+AndroidDeviceInfoList AndroidToolManager::androidVirtualDevices(const Utils::FileName &androidTool,
+ const FileName &sdkLocationPath,
+ const Environment &environment)
+{
+ AndroidDeviceInfoList devices;
+ QString output;
+ if (!androidToolCommand(androidTool, QStringList({"list", "avd"}), environment, &output))
+ return devices;
+
+ QStringList avds = output.split('\n');
+ if (avds.empty())
+ return devices;
+
+ while (avds.first().startsWith(QLatin1String("* daemon")))
+ avds.removeFirst(); // remove the daemon logs
+ avds.removeFirst(); // remove "List of devices attached" header line
+
+ bool nextLineIsTargetLine = false;
+
+ AndroidDeviceInfo dev;
+ for (int i = 0; i < avds.size(); i++) {
+ QString line = avds.at(i);
+ if (!line.contains(QLatin1String("Name:")))
+ continue;
+
+ int index = line.indexOf(QLatin1Char(':')) + 2;
+ if (index >= line.size())
+ break;
+ dev.avdname = line.mid(index).trimmed();
+ dev.sdk = -1;
+ dev.cpuAbi.clear();
+ ++i;
+ for (; i < avds.size(); ++i) {
+ line = avds.at(i);
+ if (line.contains(QLatin1String("---------")))
+ break;
+
+ if (line.contains(QLatin1String("Target:")) || nextLineIsTargetLine) {
+ if (line.contains(QLatin1String("Google APIs"))) {
+ nextLineIsTargetLine = true;
+ continue;
+ }
+
+ nextLineIsTargetLine = false;
+
+ int lastIndex = line.lastIndexOf(QLatin1Char(' '));
+ if (lastIndex == -1) // skip line
+ break;
+ QString tmp = line.mid(lastIndex).remove(QLatin1Char(')')).trimmed();
+ Utils::FileName platformPath = sdkLocationPath;
+ platformPath.appendPath(QString("/platforms/android-%1").arg(tmp));
+ dev.sdk = AndroidManager::findApiLevel(platformPath);
+ }
+ if (line.contains(QLatin1String("Tag/ABI:"))) {
+ int lastIndex = line.lastIndexOf(QLatin1Char('/')) + 1;
+ if (lastIndex >= line.size())
+ break;
+ dev.cpuAbi = QStringList(line.mid(lastIndex));
+ } else if (line.contains(QLatin1String("ABI:"))) {
+ int lastIndex = line.lastIndexOf(QLatin1Char(' ')) + 1;
+ if (lastIndex >= line.size())
+ break;
+ dev.cpuAbi = QStringList(line.mid(lastIndex).trimmed());
+ }
+ }
+ // armeabi-v7a devices can also run armeabi code
+ if (dev.cpuAbi == QStringList("armeabi-v7a"))
+ dev.cpuAbi << QLatin1String("armeabi");
+ dev.state = AndroidDeviceInfo::OkState;
+ dev.type = AndroidDeviceInfo::Emulator;
+ if (dev.cpuAbi.isEmpty() || dev.sdk == -1)
+ continue;
+ devices.push_back(dev);
+ }
+ Utils::sort(devices);
+
+ return devices;
+}
+
+void AndroidToolOutputParser::parseTargetListing(const QString &output,
+ const Utils::FileName &sdkLocation,
+ SdkPlatformList *platformList)
+{
+ if (!platformList)
+ return;
+
+ auto addSystemImage = [](const QStringList& abiList, SdkPlatform &platform) {
+ foreach (auto imageAbi, abiList) {
+ SystemImage image;
+ image.abiName = imageAbi;
+ image.apiLevel = platform.apiLevel;
+ platform.systemImages.append(image);
+ }
+ };
+
+ SdkPlatform platform;
+ QStringList abiList;
+ foreach (const QString &l, output.split('\n')) {
+ const QString line = l.trimmed();
+ if (line.startsWith(QLatin1String("id:")) && line.contains(QLatin1String("android-"))) {
+ int index = line.indexOf(QLatin1String("\"android-"));
+ if (index == -1)
+ continue;
+ QString androidTarget = line.mid(index + 1, line.length() - index - 2);
+ const QString tmp = androidTarget.mid(androidTarget.lastIndexOf(QLatin1Char('-')) + 1);
+ Utils::FileName platformPath = sdkLocation;
+ platformPath.appendPath(QString("/platforms/android-%1").arg(tmp));
+ platform.installedLocation = platformPath;
+ platform.apiLevel = AndroidManager::findApiLevel(platformPath);
+ } else if (line.startsWith(QLatin1String("Name:"))) {
+ platform.name = line.mid(6);
+ } else if (line.startsWith(QLatin1String("Tag/ABIs :"))) {
+ abiList = cleanAndroidABIs(line.mid(10).trimmed().split(QLatin1String(", ")));
+ } else if (line.startsWith(QLatin1String("ABIs"))) {
+ abiList = cleanAndroidABIs(line.mid(6).trimmed().split(QLatin1String(", ")));
+ } else if (line.startsWith(QLatin1String("---")) || line.startsWith(QLatin1String("==="))) {
+ if (platform.apiLevel == -1)
+ continue;
+
+ addSystemImage(abiList, platform);
+ *platformList << platform;
+
+ platform = SdkPlatform();
+ abiList.clear();
+ }
+ }
+
+ // The last parsed Platform.
+ if (platform.apiLevel != -1) {
+ addSystemImage(abiList, platform);
+ *platformList << platform;
+ }
+
+ Utils::sort(*platformList);
+}
+
+} // namespace Internal
+} // namespace Android
diff --git a/src/plugins/android/androidtoolmanager.h b/src/plugins/android/androidtoolmanager.h
new file mode 100644
index 0000000000..befb095b92
--- /dev/null
+++ b/src/plugins/android/androidtoolmanager.h
@@ -0,0 +1,72 @@
+/****************************************************************************
+**
+** 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/fileutils.h"
+#include "androidconfigurations.h"
+
+#include <QStringList>
+
+#include <memory>
+
+namespace Android {
+class AndroidConfig;
+
+namespace Internal {
+
+class AndroidToolOutputParser;
+/*!
+ Wraps the \c android tool's usage. The tool itself is deprecated since SDK tools version 25.3.0.
+ */
+class AndroidToolManager
+{
+ Q_DECLARE_TR_FUNCTIONS(AndroidToolManager)
+
+public:
+ AndroidToolManager(const AndroidConfig &config);
+ ~AndroidToolManager();
+
+ SdkPlatformList availableSdkPlatforms() const;
+ void launchAvdManager() const;
+
+ QFuture<AndroidConfig::CreateAvdInfo> createAvd(AndroidConfig::CreateAvdInfo info) const;
+ bool removeAvd(const QString &name) const;
+ QFuture<AndroidDeviceInfoList> androidVirtualDevicesFuture() const;
+
+// Helper methods
+private:
+ Utils::Environment androidToolEnvironment() const;
+ static AndroidConfig::CreateAvdInfo createAvdImpl(AndroidConfig::CreateAvdInfo info,
+ Utils::FileName androidToolPath, Utils::Environment env);
+ static AndroidDeviceInfoList androidVirtualDevices(const Utils::FileName &androidTool,
+ const Utils::FileName &sdkLlocationPath,
+ const Utils::Environment &environment);
+private:
+ const AndroidConfig &m_config;
+ std::unique_ptr<AndroidToolOutputParser> m_parser;
+};
+
+} // namespace Internal
+} // namespace Android
diff --git a/src/plugins/android/avddialog.cpp b/src/plugins/android/avddialog.cpp
index 9bfea8ef21..eb7da93e90 100644
--- a/src/plugins/android/avddialog.cpp
+++ b/src/plugins/android/avddialog.cpp
@@ -26,6 +26,7 @@
#include "avddialog.h"
#include "androidconfigurations.h"
+#include <utils/algorithm.h>
#include <utils/tooltip/tooltip.h>
#include <utils/utilsicons.h>
@@ -67,12 +68,12 @@ AvdDialog::AvdDialog(int minApiLevel, const QString &targetArch, const AndroidCo
bool AvdDialog::isValid() const
{
- return !name().isEmpty() && !target().isEmpty() && !abi().isEmpty();
+ return !name().isEmpty() && target().isValid() && !abi().isEmpty();
}
-QString AvdDialog::target() const
+SdkPlatform AvdDialog::target() const
{
- return m_avdDialog.targetComboBox->currentText();
+ return m_avdDialog.targetComboBox->currentData().value<SdkPlatform>();
}
QString AvdDialog::name() const
@@ -92,15 +93,23 @@ int AvdDialog::sdcardSize() const
void AvdDialog::updateApiLevelComboBox()
{
- QList<SdkPlatform> filteredList;
- QList<SdkPlatform> platforms = m_config->sdkTargets(m_minApiLevel);
- foreach (const SdkPlatform &platform, platforms) {
- if (platform.abis.contains(abi()))
- filteredList << platform;
- }
+ SdkPlatformList filteredList;
+ SdkPlatformList platforms = m_config->sdkTargets(m_minApiLevel);
+
+ QString selectedAbi = abi();
+ auto hasAbi = [selectedAbi](const SystemImage &image) {
+ return image.isValid() && (image.abiName == selectedAbi);
+ };
+
+ filteredList = Utils::filtered(platforms, [hasAbi](const SdkPlatform &platform) {
+ return Utils::anyOf(platform.systemImages,hasAbi);
+ });
m_avdDialog.targetComboBox->clear();
- m_avdDialog.targetComboBox->addItems(AndroidConfig::apiLevelNamesFor(filteredList));
+ foreach (const SdkPlatform &platform, filteredList) {
+ m_avdDialog.targetComboBox->addItem(AndroidConfig::apiLevelNameFor(platform),
+ QVariant::fromValue<SdkPlatform>(platform));
+ }
if (platforms.isEmpty()) {
m_avdDialog.warningIcon->setVisible(true);
diff --git a/src/plugins/android/avddialog.h b/src/plugins/android/avddialog.h
index 950285aadc..d22e6af64f 100644
--- a/src/plugins/android/avddialog.h
+++ b/src/plugins/android/avddialog.h
@@ -32,6 +32,7 @@
namespace Android {
class AndroidConfig;
+class SdkPlatform;
namespace Internal {
@@ -42,7 +43,7 @@ public:
explicit AvdDialog(int minApiLevel, const QString &targetArch,
const AndroidConfig *config, QWidget *parent = 0);
- QString target() const;
+ Android::SdkPlatform target() const;
QString name() const;
QString abi() const;
int sdcardSize() const;
diff --git a/src/plugins/autotest/testconfiguration.cpp b/src/plugins/autotest/testconfiguration.cpp
index 9ecd8d97ad..880c42457a 100644
--- a/src/plugins/autotest/testconfiguration.cpp
+++ b/src/plugins/autotest/testconfiguration.cpp
@@ -130,6 +130,7 @@ void TestConfiguration::completeTestInformation(int runMode)
m_executableFile = exeString;
m_project = project;
m_guessedConfiguration = true;
+ m_guessedFrom = rc->displayName();
if (runMode == TestRunner::Debug)
m_runConfig = new TestRunConfiguration(rc->target(), this);
}
@@ -203,11 +204,6 @@ void TestConfiguration::setProject(Project *project)
m_project = project;
}
-void TestConfiguration::setGuessedConfiguration(bool guessed)
-{
- m_guessedConfiguration = guessed;
-}
-
QString TestConfiguration::executableFilePath() const
{
if (m_executableFile.isEmpty())
diff --git a/src/plugins/autotest/testconfiguration.h b/src/plugins/autotest/testconfiguration.h
index d694df14cd..e220ea2d36 100644
--- a/src/plugins/autotest/testconfiguration.h
+++ b/src/plugins/autotest/testconfiguration.h
@@ -66,7 +66,6 @@ public:
void setDisplayName(const QString &displayName);
void setEnvironment(const Utils::Environment &env);
void setProject(ProjectExplorer::Project *project);
- void setGuessedConfiguration(bool guessed);
QStringList testCases() const { return m_testCases; }
int testCaseCount() const { return m_testCaseCount; }
@@ -77,7 +76,9 @@ public:
Utils::Environment environment() const { return m_environment; }
ProjectExplorer::Project *project() const { return m_project.data(); }
TestRunConfiguration *runConfiguration() const { return m_runConfig; }
- bool guessedConfiguration() const { return m_guessedConfiguration; }
+ bool isGuessed() const { return m_guessedConfiguration; }
+ QString runConfigDisplayName() const { return m_guessedConfiguration ? m_guessedFrom
+ : m_displayName; }
virtual TestOutputReader *outputReader(const QFutureInterface<TestResultPtr> &fi,
QProcess *app) const = 0;
@@ -91,6 +92,7 @@ private:
QString m_workingDir;
QString m_buildDir;
QString m_displayName;
+ QString m_guessedFrom;
Utils::Environment m_environment;
QPointer<ProjectExplorer::Project> m_project;
bool m_guessedConfiguration = false;
diff --git a/src/plugins/autotest/testrunner.cpp b/src/plugins/autotest/testrunner.cpp
index f02262f891..6d406943e0 100644
--- a/src/plugins/autotest/testrunner.cpp
+++ b/src/plugins/autotest/testrunner.cpp
@@ -43,6 +43,7 @@
#include <utils/outputformat.h>
#include <utils/runextensions.h>
+#include <utils/hostosinfo.h>
#include <QFuture>
#include <QFutureInterface>
@@ -96,6 +97,28 @@ void TestRunner::setSelectedTests(const QList<TestConfiguration *> &selected)
m_selectedTests = selected;
}
+static QString processInformation(const QProcess &proc)
+{
+ QString information("\nCommand line: " + proc.program() + ' ' + proc.arguments().join(' '));
+ QStringList important = { "PATH" };
+ if (Utils::HostOsInfo::isLinuxHost())
+ important.append("LD_LIBRARY_PATH");
+ else if (Utils::HostOsInfo::isMacHost())
+ important.append({ "DYLD_LIBRARY_PATH", "DYLD_FRAMEWORK_PATH" });
+ const QProcessEnvironment &environment = proc.processEnvironment();
+ for (const QString &var : important)
+ information.append('\n' + var + ": " + environment.value(var));
+ return information;
+}
+
+static QString rcInfo(const TestConfiguration * const config)
+{
+ QString info = '\n' + TestRunner::tr("Run configuration:") + ' ';
+ if (config->isGuessed())
+ info += TestRunner::tr("guessed from");
+ return info + " \"" + config->runConfigDisplayName() + '"';
+}
+
static void performTestRun(QFutureInterface<TestResultPtr> &futureInterface,
const QList<TestConfiguration *> selectedTests,
const TestSettings &settings)
@@ -108,11 +131,14 @@ static void performTestRun(QFutureInterface<TestResultPtr> &futureInterface,
config->completeTestInformation(TestRunner::Run);
if (config->project()) {
testCaseCount += config->testCaseCount();
- if (!omitRunConfigWarnings && config->guessedConfiguration()) {
- futureInterface.reportResult(TestResultPtr(new FaultyTestResult(Result::MessageWarn,
- TestRunner::tr("Project's run configuration was guessed for \"%1\".\n"
- "This might cause trouble during execution."
- ).arg(config->displayName()))));
+ if (!omitRunConfigWarnings && config->isGuessed()) {
+ QString message = TestRunner::tr(
+ "Project's run configuration was guessed for \"%1\".\n"
+ "This might cause trouble during execution.\n"
+ "(guessed from \"%2\")");
+ message = message.arg(config->displayName()).arg(config->runConfigDisplayName());
+ futureInterface.reportResult(
+ TestResultPtr(new FaultyTestResult(Result::MessageWarn, message)));
}
} else {
futureInterface.reportResult(TestResultPtr(new FaultyTestResult(Result::MessageWarn,
@@ -173,11 +199,15 @@ static void performTestRun(QFutureInterface<TestResultPtr> &futureInterface,
}
} else {
futureInterface.reportResult(TestResultPtr(new FaultyTestResult(Result::MessageFatal,
- TestRunner::tr("Failed to start test for project \"%1\".").arg(testConfiguration->displayName()))));
+ TestRunner::tr("Failed to start test for project \"%1\".")
+ .arg(testConfiguration->displayName()) + processInformation(testProcess)
+ + rcInfo(testConfiguration))));
}
if (testProcess.exitStatus() == QProcess::CrashExit) {
futureInterface.reportResult(TestResultPtr(new FaultyTestResult(Result::MessageFatal,
- TestRunner::tr("Test for project \"%1\" crashed.").arg(testConfiguration->displayName()))));
+ TestRunner::tr("Test for project \"%1\" crashed.")
+ .arg(testConfiguration->displayName()) + processInformation(testProcess)
+ + rcInfo(testConfiguration))));
}
if (canceledByTimeout) {
diff --git a/src/plugins/autotoolsprojectmanager/autotoolsproject.cpp b/src/plugins/autotoolsprojectmanager/autotoolsproject.cpp
index a4a733d0cd..7240fab3a5 100644
--- a/src/plugins/autotoolsprojectmanager/autotoolsproject.cpp
+++ b/src/plugins/autotoolsprojectmanager/autotoolsproject.cpp
@@ -75,6 +75,7 @@ AutotoolsProject::AutotoolsProject(const Utils::FileName &fileName) :
setId(Constants::AUTOTOOLS_PROJECT_ID);
setProjectContext(Core::Context(Constants::PROJECT_CONTEXT));
setProjectLanguages(Core::Context(ProjectExplorer::Constants::CXX_LANGUAGE_ID));
+ setDisplayName(projectDirectory().fileName());
}
AutotoolsProject::~AutotoolsProject()
@@ -90,11 +91,6 @@ AutotoolsProject::~AutotoolsProject()
}
}
-QString AutotoolsProject::displayName() const
-{
- return projectFilePath().toFileInfo().absoluteDir().dirName();
-}
-
QString AutotoolsProject::defaultBuildDirectory(const QString &projectPath)
{
return QFileInfo(projectPath).absolutePath();
diff --git a/src/plugins/autotoolsprojectmanager/autotoolsproject.h b/src/plugins/autotoolsprojectmanager/autotoolsproject.h
index 3ebaeb763a..2183ee92b7 100644
--- a/src/plugins/autotoolsprojectmanager/autotoolsproject.h
+++ b/src/plugins/autotoolsprojectmanager/autotoolsproject.h
@@ -57,7 +57,6 @@ public:
explicit AutotoolsProject(const Utils::FileName &fileName);
~AutotoolsProject() override;
- QString displayName() const override;
static QString defaultBuildDirectory(const QString &projectPath);
QStringList buildTargets() const;
diff --git a/src/plugins/autotoolsprojectmanager/autotoolsprojectnode.cpp b/src/plugins/autotoolsprojectmanager/autotoolsprojectnode.cpp
index e98246ed52..793d63a762 100644
--- a/src/plugins/autotoolsprojectmanager/autotoolsprojectnode.cpp
+++ b/src/plugins/autotoolsprojectmanager/autotoolsprojectnode.cpp
@@ -42,9 +42,3 @@ bool AutotoolsProjectNode::showInSimpleTree() const
{
return true;
}
-
-QList<ProjectAction> AutotoolsProjectNode::supportedActions(Node *node) const
-{
- Q_UNUSED(node);
- return QList<ProjectAction>();
-}
diff --git a/src/plugins/autotoolsprojectmanager/autotoolsprojectnode.h b/src/plugins/autotoolsprojectmanager/autotoolsprojectnode.h
index 088e007a4a..a60479eb8c 100644
--- a/src/plugins/autotoolsprojectmanager/autotoolsprojectnode.h
+++ b/src/plugins/autotoolsprojectmanager/autotoolsprojectnode.h
@@ -51,7 +51,6 @@ public:
AutotoolsProjectNode(const Utils::FileName &projectDirectory);
bool showInSimpleTree() const override;
- QList<ProjectExplorer::ProjectAction> supportedActions(Node *node) const override;
};
} // namespace Internal
diff --git a/src/plugins/beautifier/beautifierplugin.cpp b/src/plugins/beautifier/beautifierplugin.cpp
index ad2598152c..4120643882 100644
--- a/src/plugins/beautifier/beautifierplugin.cpp
+++ b/src/plugins/beautifier/beautifierplugin.cpp
@@ -215,7 +215,7 @@ void BeautifierPlugin::extensionsInitialized()
addAutoReleasedObject(object);
}
- m_generalSettings = new GeneralSettings;
+ m_generalSettings.reset(new GeneralSettings);
auto settingsPage = new GeneralOptionsPage(m_generalSettings, toolIds, this);
addAutoReleasedObject(settingsPage);
diff --git a/src/plugins/beautifier/beautifierplugin.h b/src/plugins/beautifier/beautifierplugin.h
index 8fab2a4e03..b75f34bab0 100644
--- a/src/plugins/beautifier/beautifierplugin.h
+++ b/src/plugins/beautifier/beautifierplugin.h
@@ -31,6 +31,7 @@
#include <QPlainTextEdit>
#include <QPointer>
+#include <QSharedPointer>
namespace Core {
class IDocument;
@@ -86,7 +87,7 @@ public:
private:
void updateActions(Core::IEditor *editor = nullptr);
QList<BeautifierAbstractTool *> m_tools;
- GeneralSettings *m_generalSettings = nullptr;
+ QSharedPointer<GeneralSettings> m_generalSettings;
QHash<QObject*, QMetaObject::Connection> m_autoFormatConnections;
void formatEditor(TextEditor::TextEditorWidget *editor, const Command &command,
int startPos = -1, int endPos = 0);
diff --git a/src/plugins/beautifier/generaloptionspage.cpp b/src/plugins/beautifier/generaloptionspage.cpp
index b4c620054e..4f160e320f 100644
--- a/src/plugins/beautifier/generaloptionspage.cpp
+++ b/src/plugins/beautifier/generaloptionspage.cpp
@@ -36,7 +36,7 @@
namespace Beautifier {
namespace Internal {
-GeneralOptionsPageWidget::GeneralOptionsPageWidget(GeneralSettings *settings,
+GeneralOptionsPageWidget::GeneralOptionsPageWidget(const QSharedPointer<GeneralSettings> &settings,
const QStringList &toolIds, QWidget *parent) :
QWidget(parent),
ui(new Ui::GeneralOptionsPage),
@@ -73,8 +73,8 @@ void GeneralOptionsPageWidget::apply(bool *autoFormatChanged)
m_settings->save();
}
-GeneralOptionsPage::GeneralOptionsPage(GeneralSettings *settings, const QStringList &toolIds,
- QObject *parent) :
+GeneralOptionsPage::GeneralOptionsPage(const QSharedPointer<GeneralSettings> &settings,
+ const QStringList &toolIds, QObject *parent) :
IOptionsPage(parent),
m_settings(settings),
m_toolIds(toolIds)
diff --git a/src/plugins/beautifier/generaloptionspage.h b/src/plugins/beautifier/generaloptionspage.h
index 2f6d79dd90..3500e7c2db 100644
--- a/src/plugins/beautifier/generaloptionspage.h
+++ b/src/plugins/beautifier/generaloptionspage.h
@@ -28,6 +28,7 @@
#include <coreplugin/dialogs/ioptionspage.h>
#include <QPointer>
+#include <QSharedPointer>
#include <QWidget>
namespace Beautifier {
@@ -42,15 +43,15 @@ class GeneralOptionsPageWidget : public QWidget
Q_OBJECT
public:
- explicit GeneralOptionsPageWidget(GeneralSettings *settings, const QStringList &toolIds,
- QWidget *parent = nullptr);
+ explicit GeneralOptionsPageWidget(const QSharedPointer<GeneralSettings> &settings,
+ const QStringList &toolIds, QWidget *parent = nullptr);
virtual ~GeneralOptionsPageWidget();
void restore();
void apply(bool *autoFormatChanged);
private:
Ui::GeneralOptionsPage *ui;
- GeneralSettings *m_settings;
+ QSharedPointer<GeneralSettings> m_settings;
};
class GeneralOptionsPage : public Core::IOptionsPage
@@ -58,8 +59,8 @@ class GeneralOptionsPage : public Core::IOptionsPage
Q_OBJECT
public:
- explicit GeneralOptionsPage(GeneralSettings *settings, const QStringList &toolIds,
- QObject *parent = nullptr);
+ explicit GeneralOptionsPage(const QSharedPointer<GeneralSettings> &settings,
+ const QStringList &toolIds, QObject *parent = nullptr);
QWidget *widget() override;
void apply() override;
void finish() override;
@@ -69,7 +70,7 @@ signals:
private:
QPointer<GeneralOptionsPageWidget> m_widget;
- GeneralSettings *m_settings;
+ QSharedPointer<GeneralSettings> m_settings;
QStringList m_toolIds;
};
diff --git a/src/plugins/classview/classviewparser.cpp b/src/plugins/classview/classviewparser.cpp
index 901edacf91..8d4663819a 100644
--- a/src/plugins/classview/classviewparser.cpp
+++ b/src/plugins/classview/classviewparser.cpp
@@ -101,7 +101,7 @@ public:
CPlusPlus::Overview overview;
//! timer
- QPointer<QTimer> timer;
+ QTimer timer;
// documents
//! Documents read write lock
@@ -161,16 +161,14 @@ Parser::Parser(QObject *parent)
: QObject(parent),
d(new ParserPrivate())
{
- d->timer = new QTimer(this);
- d->timer->setObjectName(QLatin1String("ClassViewParser::timer"));
- d->timer->setSingleShot(true);
+ d->timer.setSingleShot(true);
// connect signal/slots
// internal data reset
connect(this, &Parser::resetDataDone, this, &Parser::onResetDataDone, Qt::QueuedConnection);
// timer for emitting changes
- connect(d->timer.data(), &QTimer::timeout, this, &Parser::requestCurrentState, Qt::QueuedConnection);
+ connect(&d->timer, &QTimer::timeout, this, &Parser::requestCurrentState, Qt::QueuedConnection);
}
/*!
@@ -294,11 +292,12 @@ ParserTreeItem::ConstPtr Parser::parse()
item = ParserTreeItem::Ptr(new ParserTreeItem());
if (d->flatMode)
- addFlatTree(item, prj->rootProjectNode());
+ addFlatTree(item, prj);
else
- addProjectNode(item, prj->rootProjectNode());
+ addProjectTree(item, prj);
+
+ item->setIcon(prj->containerNode()->icon());
- item->setIcon(prj->rootProjectNode()->icon());
rootItem->appendChild(item, inf);
}
@@ -315,7 +314,7 @@ ParserTreeItem::ConstPtr Parser::parse()
*/
void Parser::addProject(const ParserTreeItem::Ptr &item, const QStringList &fileList,
- const QString &projectId)
+ const QString &projectId)
{
// recalculate cache tree if needed
ParserTreeItem::Ptr prj(getCachedOrParseProjectTree(fileList, projectId));
@@ -542,10 +541,8 @@ void Parser::parseDocument(const CPlusPlus::Document::Ptr &doc)
getParseDocumentTree(doc);
- QTC_ASSERT(d->timer, return);
-
- if (!d->timer->isActive())
- d->timer->start(400); //! Delay in msecs before an update
+ if (!d->timer.isActive())
+ d->timer.start(400); //! Delay in msecs before an update
return;
}
@@ -688,7 +685,7 @@ void Parser::requestCurrentState()
void Parser::emitCurrentTree()
{
// stop timer if it is active right now
- d->timer->stop();
+ d->timer.stop();
d->rootItemLocker.lockForWrite();
d->rootItem = parse();
@@ -703,110 +700,69 @@ void Parser::emitCurrentTree()
}
/*!
- Generates a project node file list for the root node \a node.
-*/
-
-QStringList Parser::projectNodeFileList(const FolderNode *folderNode) const
-{
- QStringList list;
- folderNode->forEachNode(
- [&](FileNode *node) {
- if (!node->isGenerated())
- list.append(node->filePath().toString());
- },
- {},
- [&](const FolderNode *node) {
- return node->nodeType() == NodeType::Folder || node->nodeType() == NodeType::VirtualFolder;
- }
- );
- return list;
-}
-
-/*!
Generates projects like the Project Explorer.
\a item specifies the item and \a node specifies the root node.
Returns a list of projects which were added to the item.
*/
-QStringList Parser::addProjectNode(const ParserTreeItem::Ptr &item, const ProjectNode *node)
+QStringList Parser::addProjectTree(const ParserTreeItem::Ptr &item, const Project *project)
{
QStringList projectList;
- if (!node)
+ if (!project)
return projectList;
- const QString nodePath = node->filePath().toString();
+ const QString projectPath = project->projectFilePath().toString();
// our own files
QStringList fileList;
- CitCachedPrjFileLists cit = d->cachedPrjFileLists.constFind(nodePath);
+ CitCachedPrjFileLists cit = d->cachedPrjFileLists.constFind(projectPath);
// try to improve parsing speed by internal cache
if (cit != d->cachedPrjFileLists.constEnd()) {
fileList = cit.value();
} else {
- fileList = projectNodeFileList(node);
- d->cachedPrjFileLists[nodePath] = fileList;
+ fileList = project->files(Project::SourceFiles);
+ d->cachedPrjFileLists[projectPath] = fileList;
}
if (fileList.count() > 0) {
- addProject(item, fileList, node->filePath().toString());
- projectList << node->filePath().toString();
- }
-
- // subnodes
- for (const Node *n : node->nodes()) {
- if (const ProjectNode *project = n->asProjectNode()) {
- ParserTreeItem::Ptr itemPrj(new ParserTreeItem());
- SymbolInformation information(project->displayName(), project->filePath().toString());
-
- projectList += addProjectNode(itemPrj, project);
-
- itemPrj->setIcon(project->icon());
-
- // append child if item is not null and there is at least 1 child
- if (!item.isNull() && itemPrj->childCount() > 0)
- item->appendChild(itemPrj, information);
- }
+ addProject(item, fileList, projectPath);
+ projectList << projectPath;
}
return projectList;
}
-QStringList Parser::getAllFiles(const ProjectNode *node)
+QStringList Parser::getAllFiles(const Project *project)
{
QStringList fileList;
- if (!node)
+ if (!project)
return fileList;
- const QString nodePath = node->filePath().toString();
+ const QString nodePath = project->projectFilePath().toString();
CitCachedPrjFileLists cit = d->cachedPrjFileLists.constFind(nodePath);
// try to improve parsing speed by internal cache
if (cit != d->cachedPrjFileLists.constEnd()) {
fileList = cit.value();
} else {
- fileList = projectNodeFileList(node);
+ fileList = project->files(Project::SourceFiles);
d->cachedPrjFileLists[nodePath] = fileList;
}
- // subnodes
-
- for (const Node *n : node->nodes())
- if (const ProjectNode *project = n->asProjectNode())
- fileList += getAllFiles(project);
return fileList;
}
-void Parser::addFlatTree(const ParserTreeItem::Ptr &item, const ProjectNode *node)
+void Parser::addFlatTree(const ParserTreeItem::Ptr &item, const Project *project)
{
- if (!node)
+ if (!project)
return;
- QStringList fileList = getAllFiles(node);
+ QStringList fileList = getAllFiles(project);
fileList.removeDuplicates();
if (fileList.count() > 0) {
- addProject(item, fileList, node->filePath().toString());
+ addProject(item, fileList, project->projectFilePath().toString());
}
}
diff --git a/src/plugins/classview/classviewparser.h b/src/plugins/classview/classviewparser.h
index cb90e4e8c7..918397b3c4 100644
--- a/src/plugins/classview/classviewparser.h
+++ b/src/plugins/classview/classviewparser.h
@@ -111,13 +111,9 @@ protected:
ParserTreeItem::ConstPtr findItemByRoot(const QStandardItem *item, bool skipRoot = false) const;
- QStringList addProjectNode(const ParserTreeItem::Ptr &item,
- const ProjectExplorer::ProjectNode *node);
- QStringList getAllFiles(const ProjectExplorer::ProjectNode *node);
- void addFlatTree(const ParserTreeItem::Ptr &item,
- const ProjectExplorer::ProjectNode *node);
-
- QStringList projectNodeFileList(const ProjectExplorer::FolderNode *node) const;
+ QStringList addProjectTree(const ParserTreeItem::Ptr &item, const ProjectExplorer::Project *project);
+ QStringList getAllFiles(const ProjectExplorer::Project *project);
+ void addFlatTree(const ParserTreeItem::Ptr &item, const ProjectExplorer::Project *project);
private:
//! Private class data pointer
diff --git a/src/plugins/clearcase/clearcaseplugin.cpp b/src/plugins/clearcase/clearcaseplugin.cpp
index c5beb51b43..f4ba55d093 100644
--- a/src/plugins/clearcase/clearcaseplugin.cpp
+++ b/src/plugins/clearcase/clearcaseplugin.cpp
@@ -257,7 +257,7 @@ FileStatus::Status ClearCasePlugin::getFileStatus(const QString &fileName) const
const QString absFile =
viewRootDir.absoluteFilePath(
QDir::fromNativeSeparators(buffer.left(atatpos)));
- QTC_CHECK(QFile(absFile).exists());
+ QTC_CHECK(QFileInfo::exists(absFile));
QTC_CHECK(!absFile.isEmpty());
// "cleartool ls" of a derived object looks like this:
@@ -274,7 +274,7 @@ FileStatus::Status ClearCasePlugin::getFileStatus(const QString &fileName) const
else
return FileStatus::CheckedIn;
} else {
- QTC_CHECK(QFile(fileName).exists());
+ QTC_CHECK(QFileInfo::exists(fileName));
QTC_CHECK(!fileName.isEmpty());
return FileStatus::NotManaged;
}
diff --git a/src/plugins/clearcase/clearcasesync.cpp b/src/plugins/clearcase/clearcasesync.cpp
index 8f8262ee7c..2a9c16dfd7 100644
--- a/src/plugins/clearcase/clearcasesync.cpp
+++ b/src/plugins/clearcase/clearcasesync.cpp
@@ -92,7 +92,7 @@ void ClearCaseSync::processCleartoolLsLine(const QDir &viewRootDir, const QStrin
const QString absFile =
viewRootDir.absoluteFilePath(
QDir::fromNativeSeparators(buffer.left(atatpos)));
- QTC_CHECK(QFile(absFile).exists());
+ QTC_CHECK(QFileInfo::exists(absFile));
QTC_CHECK(!absFile.isEmpty());
QString ccState;
diff --git a/src/plugins/cmakeprojectmanager/cmakebuildconfiguration.cpp b/src/plugins/cmakeprojectmanager/cmakebuildconfiguration.cpp
index 6db04c5287..fbebafb9d5 100644
--- a/src/plugins/cmakeprojectmanager/cmakebuildconfiguration.cpp
+++ b/src/plugins/cmakeprojectmanager/cmakebuildconfiguration.cpp
@@ -149,10 +149,7 @@ void CMakeBuildConfiguration::ctor()
emit dataAvailable();
});
connect(m_buildDirManager.get(), &BuildDirManager::errorOccured,
- this, [this, project](const QString &msg) {
- project->updateProjectData(this);
- setError(msg);
- });
+ this, &CMakeBuildConfiguration::setError);
connect(m_buildDirManager.get(), &BuildDirManager::configurationStarted,
this, [this, project]() {
project->handleParsingStarted();
diff --git a/src/plugins/cmakeprojectmanager/cmakebuildsettingswidget.cpp b/src/plugins/cmakeprojectmanager/cmakebuildsettingswidget.cpp
index a13a7e57f9..f77acdac10 100644
--- a/src/plugins/cmakeprojectmanager/cmakebuildsettingswidget.cpp
+++ b/src/plugins/cmakeprojectmanager/cmakebuildsettingswidget.cpp
@@ -258,6 +258,8 @@ CMakeBuildSettingsWidget::CMakeBuildSettingsWidget(CMakeBuildConfiguration *bc)
updateFromKit();
connect(m_buildConfiguration->target(), &ProjectExplorer::Target::kitChanged,
this, &CMakeBuildSettingsWidget::updateFromKit);
+ connect(m_buildConfiguration, &CMakeBuildConfiguration::enabledChanged,
+ this, [this]() { setError(m_buildConfiguration->disabledReason()); });
}
void CMakeBuildSettingsWidget::setError(const QString &message)
diff --git a/src/plugins/cmakeprojectmanager/cmakebuildstep.cpp b/src/plugins/cmakeprojectmanager/cmakebuildstep.cpp
index 24ce40dcaa..f92f129c09 100644
--- a/src/plugins/cmakeprojectmanager/cmakebuildstep.cpp
+++ b/src/plugins/cmakeprojectmanager/cmakebuildstep.cpp
@@ -444,19 +444,26 @@ QString CMakeBuildStepConfigWidget::displayName() const
return tr("Build", "CMakeProjectManager::CMakeBuildStepConfigWidget display name.");
}
-void CMakeBuildStepConfigWidget::buildTargetsChanged()
+static void createSpecialItem(const QString &text, const QString &data, QListWidget *parent)
{
- const bool wasBlocked = m_buildTargetsList->blockSignals(true);
- m_buildTargetsList->clear();
+ auto item = new QListWidgetItem(text, parent);
- auto item = new QListWidgetItem(tr(ADD_RUNCONFIGURATION_TEXT), m_buildTargetsList);
-
- item->setData(Qt::UserRole, QString::fromLatin1(ADD_RUNCONFIGURATION_TEXT));
+ item->setData(Qt::UserRole, data);
QFont f;
f.setItalic(true);
item->setFont(f);
+}
+
+void CMakeBuildStepConfigWidget::buildTargetsChanged()
+{
+ const bool wasBlocked = m_buildTargetsList->blockSignals(true);
+ m_buildTargetsList->clear();
+
+ createSpecialItem(tr(ADD_RUNCONFIGURATION_TEXT), ADD_RUNCONFIGURATION_TEXT, m_buildTargetsList);
+ createSpecialItem(tr("all"), "all", m_buildTargetsList);
+ createSpecialItem(tr("clean"), "clean", m_buildTargetsList);
- CMakeProject *pro = static_cast<CMakeProject *>(m_buildStep->project());
+ auto pro = static_cast<CMakeProject *>(m_buildStep->project());
QStringList targetList = pro->buildTargetTitles();
targetList.sort();
diff --git a/src/plugins/cmakeprojectmanager/cmakecbpparser.cpp b/src/plugins/cmakeprojectmanager/cmakecbpparser.cpp
index 350950388f..591768f515 100644
--- a/src/plugins/cmakeprojectmanager/cmakecbpparser.cpp
+++ b/src/plugins/cmakeprojectmanager/cmakecbpparser.cpp
@@ -180,15 +180,6 @@ bool CMakeCbpParser::parseCbpFile(CMakeTool::PathMapper mapper, const FileName &
fi.close();
- // There is always a clean target:
- CMakeBuildTarget cleanTarget;
- cleanTarget.title = "clean";
- cleanTarget.targetType = UtilityType;
- cleanTarget.workingDirectory = m_buildDirectory;
- cleanTarget.sourceDirectory = m_sourceDirectory;
-
- m_buildTargets.append(cleanTarget);
-
return true;
}
return false;
diff --git a/src/plugins/cmakeprojectmanager/cmakeproject.cpp b/src/plugins/cmakeprojectmanager/cmakeproject.cpp
index 4bf0f0dcdc..b11480eb2c 100644
--- a/src/plugins/cmakeprojectmanager/cmakeproject.cpp
+++ b/src/plugins/cmakeprojectmanager/cmakeproject.cpp
@@ -79,6 +79,7 @@ CMakeProject::CMakeProject(const FileName &fileName) : Project(Constants::CMAKEM
setId(CMakeProjectManager::Constants::CMAKEPROJECT_ID);
setProjectContext(Core::Context(CMakeProjectManager::Constants::PROJECTCONTEXT));
setProjectLanguages(Core::Context(ProjectExplorer::Constants::CXX_LANGUAGE_ID));
+ setDisplayName(projectDirectory().fileName());
connect(this, &CMakeProject::activeTargetChanged, this, &CMakeProject::handleActiveTargetChanged);
connect(&m_treeScanner, &TreeScanner::finished, this, &CMakeProject::handleTreeScanningFinished);
@@ -145,8 +146,10 @@ void CMakeProject::updateProjectData(CMakeBuildConfiguration *bc)
Kit *k = t->kit();
auto newRoot = bc->generateProjectTree(m_allFiles);
- if (newRoot)
+ if (newRoot) {
setRootProjectNode(newRoot);
+ setDisplayName(newRoot->displayName());
+ }
updateApplicationAndDeploymentTargets();
updateTargetRunConfigurations(t);
@@ -296,12 +299,6 @@ bool CMakeProject::hasBuildTarget(const QString &title) const
return anyOf(buildTargets(), [title](const CMakeBuildTarget &ct) { return ct.title == title; });
}
-QString CMakeProject::displayName() const
-{
- auto root = dynamic_cast<CMakeProjectNode *>(rootProjectNode());
- return root ? root->displayName() : projectDirectory().fileName();
-}
-
Project::RestoreResult CMakeProject::fromMap(const QVariantMap &map, QString *errorMessage)
{
RestoreResult result = Project::fromMap(map, errorMessage);
diff --git a/src/plugins/cmakeprojectmanager/cmakeproject.h b/src/plugins/cmakeprojectmanager/cmakeproject.h
index f0bc68ce12..2b20a7479c 100644
--- a/src/plugins/cmakeprojectmanager/cmakeproject.h
+++ b/src/plugins/cmakeprojectmanager/cmakeproject.h
@@ -86,8 +86,6 @@ public:
explicit CMakeProject(const Utils::FileName &filename);
~CMakeProject() final;
- QString displayName() const final;
-
QStringList buildTargetTitles(bool runnable = false) const;
bool hasBuildTarget(const QString &title) const;
diff --git a/src/plugins/cmakeprojectmanager/cmakeprojectmanager.cpp b/src/plugins/cmakeprojectmanager/cmakeprojectmanager.cpp
index 844a8a95bb..7464261e8c 100644
--- a/src/plugins/cmakeprojectmanager/cmakeprojectmanager.cpp
+++ b/src/plugins/cmakeprojectmanager/cmakeprojectmanager.cpp
@@ -57,7 +57,7 @@ CMakeManager::CMakeManager() :
m_runCMakeAction(new QAction(QIcon(), tr("Run CMake"), this)),
m_clearCMakeCacheAction(new QAction(QIcon(), tr("Clear CMake Configuration"), this)),
m_runCMakeActionContextMenu(new QAction(QIcon(), tr("Run CMake"), this)),
- m_rescanProjectAction(new QAction(QIcon(), tr("Rescan project"), this))
+ m_rescanProjectAction(new QAction(QIcon(), tr("Rescan Project"), this))
{
Core::ActionContainer *mbuild =
Core::ActionManager::actionContainer(ProjectExplorer::Constants::M_BUILDPROJECT);
diff --git a/src/plugins/cmakeprojectmanager/cmakeprojectnodes.cpp b/src/plugins/cmakeprojectmanager/cmakeprojectnodes.cpp
index 21b491e299..79337e0440 100644
--- a/src/plugins/cmakeprojectmanager/cmakeprojectnodes.cpp
+++ b/src/plugins/cmakeprojectmanager/cmakeprojectnodes.cpp
@@ -56,12 +56,6 @@ bool CMakeInputsNode::showInSimpleTree() const
return false;
}
-QList<ProjectExplorer::ProjectAction> CMakeInputsNode::supportedActions(ProjectExplorer::Node *node) const
-{
- Q_UNUSED(node);
- return QList<ProjectExplorer::ProjectAction>();
-}
-
CMakeListsNode::CMakeListsNode(const Utils::FileName &cmakeListPath) :
ProjectExplorer::ProjectNode(cmakeListPath)
{
@@ -80,12 +74,6 @@ bool CMakeListsNode::showInSimpleTree() const
return false;
}
-QList<ProjectExplorer::ProjectAction> CMakeListsNode::supportedActions(ProjectExplorer::Node *node) const
-{
- Q_UNUSED(node);
- return QList<ProjectExplorer::ProjectAction>();
-}
-
CMakeProjectNode::CMakeProjectNode(const Utils::FileName &directory) :
ProjectExplorer::ProjectNode(directory)
{
@@ -103,12 +91,6 @@ QString CMakeProjectNode::tooltip() const
return QString();
}
-QList<ProjectExplorer::ProjectAction> CMakeProjectNode::supportedActions(ProjectExplorer::Node *node) const
-{
- Q_UNUSED(node);
- return QList<ProjectExplorer::ProjectAction>();
-}
-
CMakeTargetNode::CMakeTargetNode(const Utils::FileName &directory) :
ProjectExplorer::ProjectNode(directory)
{
@@ -126,12 +108,6 @@ QString CMakeTargetNode::tooltip() const
return m_tooltip;
}
-QList<ProjectExplorer::ProjectAction> CMakeTargetNode::supportedActions(ProjectExplorer::Node *node) const
-{
- Q_UNUSED(node);
- return QList<ProjectExplorer::ProjectAction>();
-}
-
void CMakeTargetNode::setTargetInformation(const QList<Utils::FileName> &artifacts,
const QString &type)
{
diff --git a/src/plugins/cmakeprojectmanager/cmakeprojectnodes.h b/src/plugins/cmakeprojectmanager/cmakeprojectnodes.h
index ca1fedd6e8..d4160c7762 100644
--- a/src/plugins/cmakeprojectmanager/cmakeprojectnodes.h
+++ b/src/plugins/cmakeprojectmanager/cmakeprojectnodes.h
@@ -28,8 +28,6 @@
#include <projectexplorer/projectnodes.h>
namespace CMakeProjectManager {
-class CMakeProject;
-
namespace Internal {
class CMakeInputsNode : public ProjectExplorer::ProjectNode
@@ -40,7 +38,6 @@ public:
static Utils::FileName inputsPathFromCMakeListsPath(const Utils::FileName &cmakeLists);
bool showInSimpleTree() const final;
- QList<ProjectExplorer::ProjectAction> supportedActions(Node *node) const final;
};
class CMakeListsNode : public ProjectExplorer::ProjectNode
@@ -49,7 +46,6 @@ public:
CMakeListsNode(const Utils::FileName &cmakeListPath);
bool showInSimpleTree() const final;
- QList<ProjectExplorer::ProjectAction> supportedActions(Node *node) const final;
};
class CMakeProjectNode : public ProjectExplorer::ProjectNode
@@ -59,7 +55,6 @@ public:
bool showInSimpleTree() const final;
QString tooltip() const final;
- QList<ProjectExplorer::ProjectAction> supportedActions(Node *node) const final;
};
class CMakeTargetNode : public ProjectExplorer::ProjectNode
@@ -71,7 +66,6 @@ public:
bool showInSimpleTree() const final;
QString tooltip() const final;
- QList<ProjectExplorer::ProjectAction> supportedActions(Node *node) const final;
private:
QString m_tooltip;
diff --git a/src/plugins/cmakeprojectmanager/servermodereader.cpp b/src/plugins/cmakeprojectmanager/servermodereader.cpp
index 9225642025..a83ca14aaf 100644
--- a/src/plugins/cmakeprojectmanager/servermodereader.cpp
+++ b/src/plugins/cmakeprojectmanager/servermodereader.cpp
@@ -414,14 +414,16 @@ void ServerModeReader::extractConfigurationData(const QVariantMap &data)
{
const QString name = data.value(NAME_KEY).toString();
Q_UNUSED(name);
+ QSet<QString> knownTargets; // To filter duplicate target names:-/
const QVariantList projects = data.value("projects").toList();
for (const QVariant &p : projects) {
const QVariantMap pData = p.toMap();
- m_projects.append(extractProjectData(pData));
+ m_projects.append(extractProjectData(pData, knownTargets));
}
}
-ServerModeReader::Project *ServerModeReader::extractProjectData(const QVariantMap &data)
+ServerModeReader::Project *ServerModeReader::extractProjectData(const QVariantMap &data,
+ QSet<QString> &knownTargets)
{
auto project = new Project;
project->name = data.value(NAME_KEY).toString();
@@ -430,16 +432,28 @@ ServerModeReader::Project *ServerModeReader::extractProjectData(const QVariantMa
const QVariantList targets = data.value("targets").toList();
for (const QVariant &t : targets) {
const QVariantMap tData = t.toMap();
- project->targets.append(extractTargetData(tData, project));
+ Target *tp = extractTargetData(tData, project, knownTargets);
+ if (tp)
+ project->targets.append(tp);
}
return project;
}
-ServerModeReader::Target *ServerModeReader::extractTargetData(const QVariantMap &data, Project *p)
+ServerModeReader::Target *ServerModeReader::extractTargetData(const QVariantMap &data, Project *p,
+ QSet<QString> &knownTargets)
{
+ const QString targetName = data.value(NAME_KEY).toString();
+
+ // Remove duplicate targets: CMake unfortunately does duplicate targets for all projects that
+ // contain them. Keep at least till cmake 3.9 is deprecated.
+ const int count = knownTargets.count();
+ knownTargets.insert(targetName);
+ if (knownTargets.count() == count)
+ return nullptr;
+
auto target = new Target;
target->project = p;
- target->name = data.value(NAME_KEY).toString();
+ target->name = targetName;
target->sourceDirectory = FileName::fromString(data.value(SOURCE_DIRECTORY_KEY).toString());
target->buildDirectory = FileName::fromString(data.value("buildDirectory").toString());
@@ -664,7 +678,6 @@ void ServerModeReader::addHeaderNodes(ProjectNode *root, const QList<FileNode *>
{
auto headerNode = new VirtualFolderNode(root->filePath(), Node::DefaultPriority - 5);
headerNode->setDisplayName(tr("<Headers>"));
- root->addNode(headerNode);
// knownHeaders are already listed in their targets:
QSet<Utils::FileName> seenHeaders = Utils::transform<QSet>(knownHeaders, &FileNode::filePath);
@@ -681,6 +694,11 @@ void ServerModeReader::addHeaderNodes(ProjectNode *root, const QList<FileNode *>
headerNode->addNestedNode(node);
}
}
+
+ if (headerNode->nodes().isEmpty())
+ delete headerNode; // No Headers, do not show this Folder.
+ else
+ root->addNode(headerNode);
}
} // namespace Internal
diff --git a/src/plugins/cmakeprojectmanager/servermodereader.h b/src/plugins/cmakeprojectmanager/servermodereader.h
index 01c98182ea..3b1202c009 100644
--- a/src/plugins/cmakeprojectmanager/servermodereader.h
+++ b/src/plugins/cmakeprojectmanager/servermodereader.h
@@ -107,8 +107,8 @@ private:
void extractCodeModelData(const QVariantMap &data);
void extractConfigurationData(const QVariantMap &data);
- Project *extractProjectData(const QVariantMap &data);
- Target *extractTargetData(const QVariantMap &data, Project *p);
+ Project *extractProjectData(const QVariantMap &data, QSet<QString> &knownTargets);
+ Target *extractTargetData(const QVariantMap &data, Project *p, QSet<QString> &knownTargets);
FileGroup *extractFileGroupData(const QVariantMap &data, const QDir &srcDir, Target *t);
void extractCMakeInputsData(const QVariantMap &data);
void extractCacheData(const QVariantMap &data);
diff --git a/src/plugins/coreplugin/dialogs/saveitemsdialog.cpp b/src/plugins/coreplugin/dialogs/saveitemsdialog.cpp
index b7b1d8c4b4..bad8aef38e 100644
--- a/src/plugins/coreplugin/dialogs/saveitemsdialog.cpp
+++ b/src/plugins/coreplugin/dialogs/saveitemsdialog.cpp
@@ -60,7 +60,7 @@ SaveItemsDialog::SaveItemsDialog(QWidget *parent,
connect(m_diffButton, &QAbstractButton::clicked, this, &SaveItemsDialog::collectFilesToDiff);
}
- QPushButton *discardButton = m_ui.buttonBox->addButton(tr("Do &not Save"), discardButtonRole);
+ QPushButton *discardButton = m_ui.buttonBox->addButton(tr("Do &Not Save"), discardButtonRole);
m_ui.buttonBox->button(QDialogButtonBox::Save)->setDefault(true);
m_ui.treeWidget->setFocus();
diff --git a/src/plugins/coreplugin/editormanager/documentmodel.cpp b/src/plugins/coreplugin/editormanager/documentmodel.cpp
index 465ff09ae8..bf88039cc8 100644
--- a/src/plugins/coreplugin/editormanager/documentmodel.cpp
+++ b/src/plugins/coreplugin/editormanager/documentmodel.cpp
@@ -283,7 +283,7 @@ QVariant DocumentModelPrivate::data(const QModelIndex &index, int role) const
case Qt::ToolTipRole:
return entry->fileName().isEmpty() ? entry->displayName() : entry->fileName().toUserOutput();
default:
- return QVariant();
+ break;
}
return QVariant();
}
diff --git a/src/plugins/coreplugin/editormanager/editormanager.cpp b/src/plugins/coreplugin/editormanager/editormanager.cpp
index 44c010ba8f..1bfb5face4 100644
--- a/src/plugins/coreplugin/editormanager/editormanager.cpp
+++ b/src/plugins/coreplugin/editormanager/editormanager.cpp
@@ -931,6 +931,7 @@ Id EditorManagerPrivate::getOpenWithEditorId(const QString &fileName, bool *isEx
// Built-in
const EditorManager::EditorFactoryList editors = EditorManager::editorFactories(mt, false);
const int size = editors.size();
+ allEditorDisplayNames.reserve(size);
for (int i = 0; i < size; i++) {
allEditorIds.push_back(editors.at(i)->id());
allEditorDisplayNames.push_back(editors.at(i)->displayName());
diff --git a/src/plugins/coreplugin/editormanager/editorview.cpp b/src/plugins/coreplugin/editormanager/editorview.cpp
index 99556068e1..b46c71f772 100644
--- a/src/plugins/coreplugin/editormanager/editorview.cpp
+++ b/src/plugins/coreplugin/editormanager/editorview.cpp
@@ -547,7 +547,7 @@ void EditorView::updateCurrentPositionInNavigationHistory()
namespace {
static inline bool fileNameWasRemoved(const QString &fileName)
{
- return !fileName.isEmpty() && !QFileInfo(fileName).exists();
+ return !fileName.isEmpty() && !QFileInfo::exists(fileName);
}
} // End of anonymous namespace
diff --git a/src/plugins/coreplugin/find/itemviewfind.cpp b/src/plugins/coreplugin/find/itemviewfind.cpp
index 3588f125ec..cc2dd466e5 100644
--- a/src/plugins/coreplugin/find/itemviewfind.cpp
+++ b/src/plugins/coreplugin/find/itemviewfind.cpp
@@ -249,12 +249,13 @@ QModelIndex ItemViewFind::nextIndex(const QModelIndex &idx, bool *wrapped) const
return model->index(0, 0);
// same parent has more columns, go to next column
- if (idx.column() + 1 < model->columnCount(idx.parent()))
- return model->index(idx.row(), idx.column() + 1, idx.parent());
+ const QModelIndex parentIdx = idx.parent();
+ if (idx.column() + 1 < model->columnCount(parentIdx))
+ return model->index(idx.row(), idx.column() + 1, parentIdx);
// tree views have their children attached to first column
// make sure we are at first column
- QModelIndex current = model->index(idx.row(), 0, idx.parent());
+ QModelIndex current = model->index(idx.row(), 0, parentIdx);
// check for children
if (d->m_option == FetchMoreWhileSearching && model->canFetchMore(current))
diff --git a/src/plugins/coreplugin/find/searchresultwidget.cpp b/src/plugins/coreplugin/find/searchresultwidget.cpp
index 842abb9aa5..2aa443630d 100644
--- a/src/plugins/coreplugin/find/searchresultwidget.cpp
+++ b/src/plugins/coreplugin/find/searchresultwidget.cpp
@@ -166,7 +166,7 @@ SearchResultWidget::SearchResultWidget(QWidget *parent) :
connect(m_cancelButton, &QAbstractButton::clicked, this, &SearchResultWidget::cancel);
m_searchAgainButton = new QToolButton(topFindWidget);
m_searchAgainButton->setToolTip(tr("Repeat the search with same parameters."));
- m_searchAgainButton->setText(tr("&Search again"));
+ m_searchAgainButton->setText(tr("&Search Again"));
m_searchAgainButton->setToolButtonStyle(Qt::ToolButtonTextOnly);
m_searchAgainButton->setVisible(false);
connect(m_searchAgainButton, &QAbstractButton::clicked, this, &SearchResultWidget::searchAgain);
diff --git a/src/plugins/coreplugin/icore.cpp b/src/plugins/coreplugin/icore.cpp
index 2790075638..a9c9c59cad 100644
--- a/src/plugins/coreplugin/icore.cpp
+++ b/src/plugins/coreplugin/icore.cpp
@@ -448,12 +448,10 @@ static QString compilerString()
#elif defined(Q_CC_MSVC)
if (_MSC_VER > 1999)
return QLatin1String("MSVC <unknown>");
- if (_MSC_VER >= 1900) // 1900: MSVC 2015
+ if (_MSC_VER >= 1910)
+ return QLatin1String("MSVC 2017");
+ if (_MSC_VER >= 1900)
return QLatin1String("MSVC 2015");
- if (_MSC_VER >= 1800) // 1800: MSVC 2013 (yearly release cycle)
- return QLatin1String("MSVC ") + QString::number(2008 + ((_MSC_VER / 100) - 13));
- if (_MSC_VER >= 1500) // 1500: MSVC 2008, 1600: MSVC 2010, ... (2-year release cycle)
- return QLatin1String("MSVC ") + QString::number(2008 + 2 * ((_MSC_VER / 100) - 15));
#endif
return QLatin1String("<unknown compiler>");
}
diff --git a/src/plugins/coreplugin/mainwindow.cpp b/src/plugins/coreplugin/mainwindow.cpp
index 71e1f9a5a9..f587f0cc36 100644
--- a/src/plugins/coreplugin/mainwindow.cpp
+++ b/src/plugins/coreplugin/mainwindow.cpp
@@ -710,7 +710,7 @@ void MainWindow::registerDefaultActions()
m_toggleRightSideBarAction->setCheckable(true);
cmd = ActionManager::registerAction(m_toggleRightSideBarAction, Constants::TOGGLE_RIGHT_SIDEBAR);
cmd->setAttribute(Command::CA_UpdateText);
- cmd->setDefaultKeySequence(QKeySequence(UseMacShortcuts ? tr("Ctrl+Meta+0") : tr("Ctrl+Shift+0")));
+ cmd->setDefaultKeySequence(QKeySequence(UseMacShortcuts ? tr("Ctrl+Meta+0") : tr("Ctrl+0")));
connect(m_toggleRightSideBarAction, &QAction::triggered,
this, [this](bool visible) { setSidebarVisible(visible, Side::Right); });
ProxyAction *toggleRightSideBarProxyAction =
diff --git a/src/plugins/coreplugin/manhattanstyle.cpp b/src/plugins/coreplugin/manhattanstyle.cpp
index 375d38afb5..4a68fa4110 100644
--- a/src/plugins/coreplugin/manhattanstyle.cpp
+++ b/src/plugins/coreplugin/manhattanstyle.cpp
@@ -231,12 +231,12 @@ QPalette ManhattanStyle::standardPalette() const
void ManhattanStyle::polish(QApplication *app)
{
- return QProxyStyle::polish(app);
+ QProxyStyle::polish(app);
}
void ManhattanStyle::unpolish(QApplication *app)
{
- return QProxyStyle::unpolish(app);
+ QProxyStyle::unpolish(app);
}
QPalette panelPalette(const QPalette &oldPalette, bool lightColored = false)
@@ -381,8 +381,10 @@ int ManhattanStyle::styleHint(StyleHint hint, const QStyleOption *option, const
void ManhattanStyle::drawPrimitive(PrimitiveElement element, const QStyleOption *option,
QPainter *painter, const QWidget *widget) const
{
- if (!panelWidget(widget))
- return QProxyStyle::drawPrimitive(element, option, painter, widget);
+ if (!panelWidget(widget)) {
+ QProxyStyle::drawPrimitive(element, option, painter, widget);
+ return;
+ }
bool animating = (option->state & State_Animating);
int state = option->state;
@@ -614,8 +616,10 @@ void ManhattanStyle::drawPrimitive(PrimitiveElement element, const QStyleOption
void ManhattanStyle::drawControl(ControlElement element, const QStyleOption *option,
QPainter *painter, const QWidget *widget) const
{
- if (!panelWidget(widget) && !qobject_cast<const QMenu *>(widget))
- return QProxyStyle::drawControl(element, option, painter, widget);
+ if (!panelWidget(widget) && !qobject_cast<const QMenu *>(widget)) {
+ QProxyStyle::drawControl(element, option, painter, widget);
+ return;
+ }
switch (element) {
case CE_MenuItem:
diff --git a/src/plugins/coreplugin/plugindialog.cpp b/src/plugins/coreplugin/plugindialog.cpp
index 27436952fb..f55ddd5e2a 100644
--- a/src/plugins/coreplugin/plugindialog.cpp
+++ b/src/plugins/coreplugin/plugindialog.cpp
@@ -61,7 +61,7 @@ PluginDialog::PluginDialog(QWidget *parent)
m_view, &ExtensionSystem::PluginView::setFilter);
filterLayout->addWidget(filterEdit);
m_view->setShowHidden(false);
- auto showHidden = new QCheckBox(tr("Show All"));
+ auto showHidden = new QCheckBox(tr("Show all"));
showHidden->setToolTip(tr("Show all installed plugins, including base plugins "
"and plugins that are not available on this platform."));
showHidden->setChecked(m_view->isShowingHidden());
diff --git a/src/plugins/coreplugin/statusbarmanager.cpp b/src/plugins/coreplugin/statusbarmanager.cpp
index 33eaf62d71..cae5177f19 100644
--- a/src/plugins/coreplugin/statusbarmanager.cpp
+++ b/src/plugins/coreplugin/statusbarmanager.cpp
@@ -157,5 +157,5 @@ void NonResizingSplitter::resizeEvent(QResizeEvent *ev)
int leftSplitWidth = qMin(sizes().at(0), ev->size().width());
int rightSplitWidth = qMax(0, ev->size().width() - leftSplitWidth);
setSizes(QList<int>() << leftSplitWidth << rightSplitWidth);
- return QWidget::resizeEvent(ev);
+ QWidget::resizeEvent(ev);
}
diff --git a/src/plugins/coreplugin/themechooser.cpp b/src/plugins/coreplugin/themechooser.cpp
index 6f81aaa950..ff62406dba 100644
--- a/src/plugins/coreplugin/themechooser.cpp
+++ b/src/plugins/coreplugin/themechooser.cpp
@@ -221,8 +221,16 @@ QList<ThemeEntry> ThemeEntry::availableThemes()
Id ThemeEntry::themeSetting()
{
- return Id::fromSetting(ICore::settings()->value(QLatin1String(Constants::SETTINGS_THEME),
- QLatin1String(Constants::DEFAULT_THEME)));
+ const Id setting =
+ Id::fromSetting(ICore::settings()->value(QLatin1String(Constants::SETTINGS_THEME),
+ QLatin1String(Constants::DEFAULT_THEME)));
+
+ const QList<ThemeEntry> themes = availableThemes();
+ if (themes.empty())
+ return Id();
+ const bool settingValid = Utils::contains(themes, Utils::equal(&ThemeEntry::id, setting));
+
+ return settingValid ? setting : themes.first().id();
}
Theme *ThemeEntry::createTheme(Id id)
diff --git a/src/plugins/coreplugin/variablechooser.cpp b/src/plugins/coreplugin/variablechooser.cpp
index 4d336e61c7..dc595b61d9 100644
--- a/src/plugins/coreplugin/variablechooser.cpp
+++ b/src/plugins/coreplugin/variablechooser.cpp
@@ -499,7 +499,7 @@ void VariableChooserPrivate::updateCurrentEditor(QWidget *old, QWidget *widget)
m_textEdit = 0;
m_plainTextEdit = 0;
QWidget *chooser = widget->property(kVariableSupportProperty).value<QWidget *>();
- m_currentVariableName = widget->property(kVariableNameProperty).value<QByteArray>();
+ m_currentVariableName = widget->property(kVariableNameProperty).toByteArray();
bool supportsVariables = chooser == q;
if (QLineEdit *lineEdit = qobject_cast<QLineEdit *>(widget))
m_lineEdit = (supportsVariables ? lineEdit : 0);
diff --git a/src/plugins/cpaster/authenticationdialog.cpp b/src/plugins/cpaster/authenticationdialog.cpp
new file mode 100644
index 0000000000..326cdb2d80
--- /dev/null
+++ b/src/plugins/cpaster/authenticationdialog.cpp
@@ -0,0 +1,64 @@
+/****************************************************************************
+**
+** 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 "authenticationdialog.h"
+
+#include <QDialogButtonBox>
+#include <QFormLayout>
+#include <QLabel>
+#include <QLineEdit>
+#include <QVBoxLayout>
+
+namespace CodePaster {
+
+AuthenticationDialog::AuthenticationDialog(const QString &details, QWidget *parent)
+ : QDialog(parent)
+{
+ setWindowFlags(windowFlags() & ~Qt::WindowContextHelpButtonHint);
+ auto *mainLayout = new QVBoxLayout;
+ mainLayout->addWidget(new QLabel(details));
+ auto *formLayout = new QFormLayout;
+ formLayout->addRow(tr("Username:"), m_user = new QLineEdit);
+ formLayout->addRow(tr("Password:"), m_pass = new QLineEdit);
+ m_pass->setEchoMode(QLineEdit::Password);
+ mainLayout->addLayout(formLayout);
+ auto buttonBox = new QDialogButtonBox(QDialogButtonBox::Ok | QDialogButtonBox::Cancel);
+ connect(buttonBox, &QDialogButtonBox::accepted, this, &QDialog::accept);
+ connect(buttonBox, &QDialogButtonBox::rejected, this, &QDialog::reject);
+ mainLayout->addWidget(buttonBox);
+ setLayout(mainLayout);
+}
+
+QString AuthenticationDialog::userName() const
+{
+ return m_user->text();
+}
+
+QString AuthenticationDialog::password() const
+{
+ return m_pass->text();
+}
+
+} // namespace CodePaster
diff --git a/src/plugins/cpaster/authenticationdialog.h b/src/plugins/cpaster/authenticationdialog.h
new file mode 100644
index 0000000000..f52dbaef24
--- /dev/null
+++ b/src/plugins/cpaster/authenticationdialog.h
@@ -0,0 +1,51 @@
+/****************************************************************************
+**
+** 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.
+**
+****************************************************************************/
+
+#pragma once
+
+#include <QDialog>
+
+QT_BEGIN_NAMESPACE
+class QLineEdit;
+QT_END_NAMESPACE
+
+namespace CodePaster {
+
+class AuthenticationDialog : public QDialog
+{
+public:
+ AuthenticationDialog(const QString &details, QWidget *parent = nullptr);
+
+ bool authenticated() const { return m_authenticated; }
+ QString userName() const;
+ QString password() const;
+
+private:
+ bool m_authenticated = false;
+ QLineEdit *m_user = nullptr;
+ QLineEdit *m_pass = nullptr;
+};
+
+} // namespace CodePaster
diff --git a/src/plugins/cpaster/cpaster.pro b/src/plugins/cpaster/cpaster.pro
index cc30094162..20c85c596b 100644
--- a/src/plugins/cpaster/cpaster.pro
+++ b/src/plugins/cpaster/cpaster.pro
@@ -14,7 +14,8 @@ HEADERS += cpasterplugin.h \
fileshareprotocolsettingspage.h \
kdepasteprotocol.h \
urlopenprotocol.h \
- codepasterservice.h
+ codepasterservice.h \
+ authenticationdialog.h
SOURCES += cpasterplugin.cpp \
settingspage.cpp \
@@ -28,7 +29,8 @@ SOURCES += cpasterplugin.cpp \
fileshareprotocol.cpp \
fileshareprotocolsettingspage.cpp \
kdepasteprotocol.cpp \
- urlopenprotocol.cpp
+ urlopenprotocol.cpp \
+ authenticationdialog.cpp
FORMS += settingspage.ui \
pasteselect.ui \
@@ -39,3 +41,5 @@ include(../../shared/cpaster/cpaster.pri)
RESOURCES += \
cpaster.qrc
+
+DEFINES *= CPASTER_PLUGIN_GUI
diff --git a/src/plugins/cpaster/cpaster.qbs b/src/plugins/cpaster/cpaster.qbs
index 4b3cb99a84..f9144b53d8 100644
--- a/src/plugins/cpaster/cpaster.qbs
+++ b/src/plugins/cpaster/cpaster.qbs
@@ -45,6 +45,8 @@ QtcPlugin {
"settingspage.ui",
"urlopenprotocol.cpp",
"urlopenprotocol.h",
+ "authenticationdialog.cpp",
+ "authenticationdialog.h"
]
Group {
diff --git a/src/plugins/cpaster/kdepasteprotocol.cpp b/src/plugins/cpaster/kdepasteprotocol.cpp
index d182005c1d..c5c09cb9bf 100644
--- a/src/plugins/cpaster/kdepasteprotocol.cpp
+++ b/src/plugins/cpaster/kdepasteprotocol.cpp
@@ -24,7 +24,11 @@
****************************************************************************/
#include "kdepasteprotocol.h"
+#ifdef CPASTER_PLUGIN_GUI
+#include "authenticationdialog.h"
+#endif
+#include <coreplugin/icore.h>
#include <utils/qtcassert.h>
#include <QDebug>
@@ -33,7 +37,7 @@
#include <QJsonDocument>
#include <QJsonObject>
#include <QJsonArray>
-
+#include <QRegularExpression>
#include <QNetworkReply>
#include <algorithm>
@@ -118,7 +122,7 @@ void StickyNotesPasteProtocol::paste(const QString &text,
pasteData += QUrl::toPercentEncoding(description.left(maxDescriptionLength));
}
- m_pasteReply = httpPost(m_hostUrl + QLatin1String("api/json/create"), pasteData);
+ m_pasteReply = httpPost(m_hostUrl + QLatin1String("api/json/create"), pasteData, true);
connect(m_pasteReply, &QNetworkReply::finished, this, &StickyNotesPasteProtocol::pasteFinished);
if (debug)
qDebug() << "paste: sending " << m_pasteReply << pasteData;
@@ -262,9 +266,127 @@ void StickyNotesPasteProtocol::listFinished()
m_listReply = nullptr;
}
+KdePasteProtocol::KdePasteProtocol()
+{
+ setHostUrl(QLatin1String("https://pastebin.kde.org/"));
+ connect(this, &KdePasteProtocol::authenticationFailed, this, [this] () {
+ m_loginFailed = true;
+ paste(m_text, m_contentType, m_expiryDays, QString(), QString(), m_description);
+ });
+}
+
+void KdePasteProtocol::paste(const QString &text, Protocol::ContentType ct, int expiryDays,
+ const QString &username, const QString &comment,
+ const QString &description)
+{
+ Q_UNUSED(username);
+ Q_UNUSED(comment);
+ // KDE paster needs authentication nowadays
+#ifdef CPASTER_PLUGIN_GUI
+ QString details = tr("Pasting to KDE paster needs authentication.<br/>"
+ "Enter your KDE Identity credentials to continue.");
+ if (m_loginFailed)
+ details.prepend(tr("<span style='background-color:LightYellow;color:red'>Login failed</span><br/><br/>"));
+
+ AuthenticationDialog authDialog(details, Core::ICore::dialogParent());
+ authDialog.setWindowTitle("Authenticate for KDE paster");
+ if (authDialog.exec() != QDialog::Accepted) {
+ m_loginFailed = false;
+ return;
+ }
+ const QString user = authDialog.userName();
+ const QString passwd = authDialog.password();
+#else
+ // FIXME get the credentials for the cmdline cpaster somehow
+ const QString user;
+ const QString passwd;
+ qDebug() << "KDE needs credentials for pasting";
+ return;
+#endif
+ // store input data as members to be able to use them after the authentication succeeded
+ m_text = text;
+ m_contentType = ct;
+ m_expiryDays = expiryDays;
+ m_description = description;
+ authenticate(user, passwd);
+}
+
QString KdePasteProtocol::protocolName()
{
return QLatin1String("Paste.KDE.Org");
}
+void KdePasteProtocol::authenticate(const QString &user, const QString &passwd)
+{
+ QTC_ASSERT(!m_authReply, return);
+
+ // first we need to obtain the hidden form token for logging in
+ m_authReply = httpGet(hostUrl() + "user/login");
+ connect(m_authReply, &QNetworkReply::finished, this, [this, user, passwd] () {
+ onPreAuthFinished(user, passwd);
+ });
+}
+
+void KdePasteProtocol::onPreAuthFinished(const QString &user, const QString &passwd)
+{
+ if (m_authReply->error() != QNetworkReply::NoError) {
+ m_authReply->deleteLater();
+ m_authReply = nullptr;
+ return;
+ }
+ const QByteArray page = m_authReply->readAll();
+ m_authReply->deleteLater();
+ const QRegularExpression regex("name=\"_token\"\\s+type=\"hidden\"\\s+value=\"(.*?)\">");
+ const QRegularExpressionMatch match = regex.match(QLatin1String(page));
+ if (!match.hasMatch()) {
+ m_authReply = nullptr;
+ return;
+ }
+ const QString token = match.captured(1);
+
+ QByteArray data("username=" + QUrl::toPercentEncoding(user)
+ + "&password=" + QUrl::toPercentEncoding(passwd)
+ + "&_token=" + QUrl::toPercentEncoding(token));
+ m_authReply = httpPost(hostUrl() + "user/login", data, true);
+ connect(m_authReply, &QNetworkReply::finished, this, &KdePasteProtocol::onAuthFinished);
+}
+
+void KdePasteProtocol::onAuthFinished()
+{
+ if (m_authReply->error() != QNetworkReply::NoError) {
+ m_authReply->deleteLater();
+ m_authReply = nullptr;
+ return;
+ }
+ const QVariant attribute = m_authReply->attribute(QNetworkRequest::RedirectionTargetAttribute);
+ m_redirectUrl = redirectUrl(attribute.toUrl().toString(), m_redirectUrl);
+ if (!m_redirectUrl.isEmpty()) { // we need to perform a redirect
+ QUrl url(m_redirectUrl);
+ if (url.path().isEmpty())
+ url.setPath("/"); // avoid issue inside cookiesForUrl()
+ m_authReply->deleteLater();
+ m_authReply = httpGet(url.url(), true);
+ connect(m_authReply, &QNetworkReply::finished, this, &KdePasteProtocol::onAuthFinished);
+ } else { // auth should be done now
+ const QByteArray page = m_authReply->readAll();
+ m_authReply->deleteLater();
+ m_authReply = nullptr;
+ if (page.contains("https://identity.kde.org")) // we're back on the login page
+ emit authenticationFailed();
+ else {
+ m_loginFailed = false;
+ StickyNotesPasteProtocol::paste(m_text, m_contentType, m_expiryDays, QString(),
+ QString(), m_description);
+ }
+ }
+}
+
+QString KdePasteProtocol::redirectUrl(const QString &redirect, const QString &oldRedirect) const
+{
+ QString redirectUrl;
+ if (!redirect.isEmpty() && redirect != oldRedirect)
+ redirectUrl = redirect;
+ return redirectUrl;
+}
+
} // namespace CodePaster
diff --git a/src/plugins/cpaster/kdepasteprotocol.h b/src/plugins/cpaster/kdepasteprotocol.h
index 7cd3d0d83b..e7bbd1ba1d 100644
--- a/src/plugins/cpaster/kdepasteprotocol.h
+++ b/src/plugins/cpaster/kdepasteprotocol.h
@@ -70,14 +70,33 @@ private:
class KdePasteProtocol : public StickyNotesPasteProtocol
{
+ Q_OBJECT
public:
- KdePasteProtocol()
- {
- setHostUrl(QLatin1String("https://pastebin.kde.org/"));
- }
+ KdePasteProtocol();
+
+ void paste(const QString &text, ContentType ct = Text, int expiryDays = 1,
+ const QString &username = QString(),
+ const QString &comment = QString() ,
+ const QString &description = QString()) override;
QString name() const override { return protocolName(); }
static QString protocolName();
+signals:
+ void authenticationFailed();
+private:
+ void authenticate(const QString &user, const QString &passwd);
+ void onPreAuthFinished(const QString &user, const QString &passwd);
+ void onAuthFinished();
+ QString redirectUrl(const QString &redirect, const QString &oldRedirect) const;
+
+ QNetworkReply *m_authReply = nullptr;
+ QString m_text;
+ ContentType m_contentType = Text;
+ int m_expiryDays = 1;
+ bool m_loginFailed = false;
+ QString m_description;
+ QString m_redirectUrl;
+
};
} // namespace CodePaster
diff --git a/src/plugins/cpaster/pastebindotcaprotocol.cpp b/src/plugins/cpaster/pastebindotcaprotocol.cpp
index 6d413a37b7..aeb83d20d4 100644
--- a/src/plugins/cpaster/pastebindotcaprotocol.cpp
+++ b/src/plugins/cpaster/pastebindotcaprotocol.cpp
@@ -28,9 +28,11 @@
#include <utils/qtcassert.h>
#include <QNetworkReply>
-#include <QXmlStreamReader>
-#include <QXmlStreamAttributes>
#include <QStringList>
+#include <QJsonArray>
+#include <QJsonDocument>
+#include <QJsonValue>
+#include <QJsonObject>
static const char urlC[] = "http://pastebin.ca/";
static const char internalUrlC[] = "http://pbin.ca/";
@@ -180,58 +182,39 @@ bool PasteBinDotCaProtocol::checkConfiguration(QString *errorMessage)
return ok;
}
-/* Quick & dirty: Parse the <div>-elements with the "Recent Posts" listing
- * out of the page.
+/* Quick & dirty: Parse page does no more work due to internal javascript/websocket magic - so,
+ * search for _initial_ json array containing the last added pastes.
\code
-<div class="menutitle"><h2>Recent Posts</h2></div>
- <div class="items" id="idmenurecent-collapse">
- <div class='recentlink'>
- <a href="/[id]" class="rjt" rel="/preview.php?id=[id]">[nameTitle]</a>
- <div class='recentdetail'>[time spec]</div>
- </div>
- ...<h2>Create a New Pastebin Post</h2>
+<script type="text/javascript">var pHistoryInitial = [{"id":3791300,"ts":1491288268,"name":"try",
+"expires":1491374668},
\endcode */
static inline QStringList parseLists(QIODevice *io)
{
- enum State { OutsideRecentLink, InsideRecentLink };
-
QStringList rc;
- const QString classAttribute = QLatin1String("class");
- const QString divElement = QLatin1String("div");
- const QString anchorElement = QLatin1String("a");
-
- // Start parsing at the 'recent posts' entry as the HTML above is not well-formed
- // as of 8.4.2010. This will then terminate with an error.
QByteArray data = io->readAll();
- const QByteArray recentPosts("<h2>Recent Posts</h2></div>");
- const int recentPostsPos = data.indexOf(recentPosts);
- if (recentPostsPos == -1)
+ const QByteArray history("<script type=\"text/javascript\">var pHistoryInitial = ");
+ int pos = data.indexOf(history);
+ if (pos == -1)
+ return rc;
+ data.remove(0, pos + history.size());
+ pos = data.indexOf(";</script>");
+ if (pos == -1)
return rc;
- data.remove(0, recentPostsPos + recentPosts.size());
- QXmlStreamReader reader(data);
- State state = OutsideRecentLink;
- while (!reader.atEnd()) {
- switch (reader.readNext()) {
- case QXmlStreamReader::StartElement:
- // Inside a <div> of an entry: Anchor or description
- if (state == InsideRecentLink && reader.name() == anchorElement) { // Anchor
- // Strip host from link
- QString link = reader.attributes().value(QLatin1String("href")).toString();
- if (link.startsWith(QLatin1Char('/')))
- link.remove(0, 1);
- const QString nameTitle = reader.readElementText();
- rc.push_back(link + QLatin1Char(' ') + nameTitle);
- } else if (state == OutsideRecentLink && reader.name() == divElement) { // "<div>" state switching
- if (reader.attributes().value(classAttribute) == QLatin1String("recentlink"))
- state = InsideRecentLink;
- } // divElement
- break;
- default:
- break;
- } // switch reader
- } // while reader.atEnd()
+ data.truncate(pos);
+ QJsonParseError error;
+ const QJsonDocument doc = QJsonDocument::fromJson(data, &error);
+ if (error.error != QJsonParseError::NoError)
+ return rc;
+ QJsonArray array = doc.array();
+ for (const QJsonValue &val : array) {
+ const QJsonObject obj = val.toObject();
+ const QJsonValue id = obj.value("id");
+ const QJsonValue name = obj.value("name");
+ if (!id.isUndefined())
+ rc.append(QString::number(id.toInt()) + ' ' + name.toString());
+ }
return rc;
}
diff --git a/src/plugins/cpaster/pastebindotcomprotocol.cpp b/src/plugins/cpaster/pastebindotcomprotocol.cpp
index 20e071d537..cdd3d18c05 100644
--- a/src/plugins/cpaster/pastebindotcomprotocol.cpp
+++ b/src/plugins/cpaster/pastebindotcomprotocol.cpp
@@ -37,7 +37,7 @@
enum { debug = 0 };
-static const char PASTEBIN_BASE[]="http://pastebin.com/";
+static const char PASTEBIN_BASE[]="https://pastebin.com/";
static const char PASTEBIN_API[]="api/api_post.php";
static const char PASTEBIN_RAW[]="raw/";
static const char PASTEBIN_ARCHIVE[]="archive";
diff --git a/src/plugins/cpaster/protocol.cpp b/src/plugins/cpaster/protocol.cpp
index f79bed2a46..8b745006d2 100644
--- a/src/plugins/cpaster/protocol.cpp
+++ b/src/plugins/cpaster/protocol.cpp
@@ -35,6 +35,8 @@
#include <coreplugin/icore.h>
#include <coreplugin/dialogs/ioptionspage.h>
+#include <QNetworkCookie>
+#include <QNetworkCookieJar>
#include <QNetworkRequest>
#include <QNetworkReply>
@@ -173,17 +175,30 @@ bool Protocol::showConfigurationError(const Protocol *p,
// --------- NetworkProtocol
-QNetworkReply *NetworkProtocol::httpGet(const QString &link)
+static void addCookies(QNetworkRequest &request)
+{
+ auto accessMgr = Utils::NetworkAccessManager::instance();
+ const QList<QNetworkCookie> cookies = accessMgr->cookieJar()->cookiesForUrl(request.url());
+ for (const QNetworkCookie &cookie : cookies)
+ request.setHeader(QNetworkRequest::CookieHeader, QVariant::fromValue(cookie));
+}
+
+QNetworkReply *NetworkProtocol::httpGet(const QString &link, bool handleCookies)
{
QUrl url(link);
QNetworkRequest r(url);
+ if (handleCookies)
+ addCookies(r);
return Utils::NetworkAccessManager::instance()->get(r);
}
-QNetworkReply *NetworkProtocol::httpPost(const QString &link, const QByteArray &data)
+QNetworkReply *NetworkProtocol::httpPost(const QString &link, const QByteArray &data,
+ bool handleCookies)
{
QUrl url(link);
QNetworkRequest r(url);
+ if (handleCookies)
+ addCookies(r);
r.setHeader(QNetworkRequest::ContentTypeHeader,
QVariant(QByteArray("application/x-www-form-urlencoded")));
return Utils::NetworkAccessManager::instance()->post(r, data);
diff --git a/src/plugins/cpaster/protocol.h b/src/plugins/cpaster/protocol.h
index 76891ae279..4dc2acb6b2 100644
--- a/src/plugins/cpaster/protocol.h
+++ b/src/plugins/cpaster/protocol.h
@@ -110,9 +110,10 @@ public:
~NetworkProtocol() override;
protected:
- QNetworkReply *httpGet(const QString &url);
+ QNetworkReply *httpGet(const QString &url, bool handleCookies = false);
- QNetworkReply *httpPost(const QString &link, const QByteArray &data);
+ QNetworkReply *httpPost(const QString &link, const QByteArray &data,
+ bool handleCookies = false);
// Check connectivity of host, displaying a message box.
bool httpStatus(QString url, QString *errorMessage, bool useHttps = false);
diff --git a/src/plugins/cppeditor/cppautocompleter.cpp b/src/plugins/cppeditor/cppautocompleter.cpp
index d980e53e37..d5a97c38ae 100644
--- a/src/plugins/cppeditor/cppautocompleter.cpp
+++ b/src/plugins/cppeditor/cppautocompleter.cpp
@@ -131,7 +131,7 @@ static QString fileContent(int fileContent, QChar charToInsert)
case ']': return QLatin1String("[[|]");
default: return QString();
}
- default: return QString();
+ default: break;
}
return QString();
}
diff --git a/src/plugins/cpptools/modelmanagertesthelper.cpp b/src/plugins/cpptools/modelmanagertesthelper.cpp
index 9eebbee15d..c21760f1b2 100644
--- a/src/plugins/cpptools/modelmanagertesthelper.cpp
+++ b/src/plugins/cpptools/modelmanagertesthelper.cpp
@@ -42,13 +42,10 @@ TestProject::TestProject(const QString &name, QObject *parent) :
{
setParent(parent);
setId(Core::Id::fromString(name));
+ setDisplayName(name);
qRegisterMetaType<QSet<QString> >();
}
-TestProject::~TestProject()
-{
-}
-
ModelManagerTestHelper::ModelManagerTestHelper(QObject *parent,
bool testOnlyForCleanedProjects)
: QObject(parent)
diff --git a/src/plugins/cpptools/modelmanagertesthelper.h b/src/plugins/cpptools/modelmanagertesthelper.h
index 18f0d6b5ef..47e49fefe9 100644
--- a/src/plugins/cpptools/modelmanagertesthelper.h
+++ b/src/plugins/cpptools/modelmanagertesthelper.h
@@ -41,9 +41,6 @@ class CPPTOOLS_EXPORT TestProject: public ProjectExplorer::Project
public:
TestProject(const QString &name, QObject *parent);
- ~TestProject() override;
-
- QString displayName() const override { return m_name; }
private:
QString m_name;
diff --git a/src/plugins/debugger/breakhandler.cpp b/src/plugins/debugger/breakhandler.cpp
index 8c104e0dd8..eba7a8025c 100644
--- a/src/plugins/debugger/breakhandler.cpp
+++ b/src/plugins/debugger/breakhandler.cpp
@@ -363,19 +363,19 @@ BreakpointDialog::BreakpointDialog(Breakpoint b, QWidget *parent)
// Match BreakpointType (omitting unknown type).
const QStringList types = {
- tr("File name and line number"),
- tr("Function name"),
- tr("Break on memory address"),
- tr("Break when C++ exception is thrown"),
- tr("Break when C++ exception is caught"),
- tr("Break when function \"main\" starts"),
- tr("Break when a new process is forked"),
- tr("Break when a new process is executed"),
- tr("Break when a system call is executed"),
- tr("Break on data access at fixed address"),
- tr("Break on data access at address given by expression"),
- tr("Break on QML signal emit"),
- tr("Break when JavaScript exception is thrown")
+ tr("File Name and Line Number"),
+ tr("Function Name"),
+ tr("Break on Memory Address"),
+ tr("Break When C++ Exception Is Thrown"),
+ tr("Break When C++ Exception Is Caught"),
+ tr("Break When Function \"main\" Starts"),
+ tr("Break When a New Process Is Forked"),
+ tr("Break When a New Process Is Executed"),
+ tr("Break When a System Call Is Executed"),
+ tr("Break on Data Access at Fixed Address"),
+ tr("Break on Data Access at Address Given by Expression"),
+ tr("Break on QML Signal Emit"),
+ tr("Break When JavaScript Exception Is Thrown")
};
// We don't list UnknownBreakpointType, so 1 less:
QTC_CHECK(types.size() + 1 == LastBreakpointType);
diff --git a/src/plugins/debugger/cdb/cdbengine.cpp b/src/plugins/debugger/cdb/cdbengine.cpp
index 3531e882a6..af3939d445 100644
--- a/src/plugins/debugger/cdb/cdbengine.cpp
+++ b/src/plugins/debugger/cdb/cdbengine.cpp
@@ -1238,10 +1238,18 @@ void CdbEngine::doUpdateLocals(const UpdateParameters &updateParameters)
cmd.arg("stringcutoff", action(MaximalStringLength)->value().toString());
cmd.arg("displaystringlimit", action(DisplayStringLimit)->value().toString());
+ if (boolSetting(UseCodeModel)) {
+ QStringList uninitializedVariables;
+ getUninitializedVariables(Internal::cppCodeModelSnapshot(),
+ frame.function, frame.file, frame.line, &uninitializedVariables);
+ cmd.arg("uninitialized", uninitializedVariables);
+ }
+
cmd.callback = [this](const DebuggerResponse &response) {
if (response.resultClass == ResultDone) {
- showMessage(response.data.toString(), LogMisc);
- updateLocalsView(response.data);
+ const GdbMi &result = response.data["result"];
+ showMessage(result.toString(), LogMisc);
+ updateLocalsView(result);
} else {
showMessage(response.data["msg"].data(), LogError);
}
@@ -1428,6 +1436,21 @@ void CdbEngine::postResolveSymbol(const QString &module, const QString &function
}
}
+void CdbEngine::showScriptMessages(const QString &message) const
+{
+ GdbMi gdmiMessage;
+ gdmiMessage.fromString(message);
+ if (!gdmiMessage.isValid())
+ showMessage(message, LogMisc);
+ const GdbMi &messages = gdmiMessage["msg"];
+ for (const GdbMi &msg : messages.children()) {
+ if (msg.name() == "bridgemessage")
+ showMessage(msg["msg"].data(), LogMisc);
+ else
+ showMessage(msg.data(), LogMisc);
+ }
+}
+
// Parse address from 'x' response.
// "00000001`3f7ebe80 module!foo (void)"
static inline quint64 resolvedAddress(const QString &line)
@@ -2228,7 +2251,7 @@ void CdbEngine::handleExtensionMessage(char t, int token, const QString &what, c
// Is there a reply expected, some command queued?
if (t == 'R' || t == 'N') {
if (token == -1) { // Default token, user typed in extension command
- showMessage(message, LogMisc);
+ showScriptMessages(message);
return;
}
// Did the command finish? Take off queue and complete, invoke CB
@@ -2239,7 +2262,7 @@ void CdbEngine::handleExtensionMessage(char t, int token, const QString &what, c
if (!command.callback) {
if (!message.isEmpty()) // log unhandled output
- showMessage(message, LogMisc);
+ showScriptMessages(message);
return;
}
DebuggerResponse response;
@@ -2250,6 +2273,8 @@ void CdbEngine::handleExtensionMessage(char t, int token, const QString &what, c
if (!response.data.isValid()) {
response.data.m_data = message;
response.data.m_type = GdbMi::Tuple;
+ } else {
+ showScriptMessages(message);
}
} else {
response.resultClass = ResultError;
@@ -2899,14 +2924,19 @@ void CdbEngine::handleAdditionalQmlStack(const DebuggerResponse &response)
void CdbEngine::setupScripting(const DebuggerResponse &response)
{
- GdbMi data = response.data;
+ GdbMi data = response.data["msg"];
if (response.resultClass != ResultDone) {
showMessage(data["msg"].data(), LogMisc);
return;
}
- const QString &verOutput = data.data();
+ if (data.childCount() == 0) {
+ showMessage(QString("No output from sys.version"), LogWarning);
+ return;
+ }
+
+ const QString &verOutput = data.childAt(0).data();
const QString firstToken = verOutput.split(QLatin1Char(' ')).constFirst();
- const QVector<QStringRef> pythonVersion =firstToken.splitRef(QLatin1Char('.'));
+ const QVector<QStringRef> pythonVersion = firstToken.splitRef(QLatin1Char('.'));
bool ok = false;
if (pythonVersion.size() == 3) {
@@ -2934,7 +2964,7 @@ void CdbEngine::setupScripting(const DebuggerResponse &response)
runCommand({"theDumper = Dumper()", ScriptCommand});
runCommand({"theDumper.loadDumpers(None)", ScriptCommand,
[this](const DebuggerResponse &response) {
- watchHandler()->addDumpers(response.data["dumpers"]);
+ watchHandler()->addDumpers(response.data["result"]["dumpers"]);
}});
}
diff --git a/src/plugins/debugger/cdb/cdbengine.h b/src/plugins/debugger/cdb/cdbengine.h
index aaf8b25319..ac2e0679d6 100644
--- a/src/plugins/debugger/cdb/cdbengine.h
+++ b/src/plugins/debugger/cdb/cdbengine.h
@@ -189,6 +189,7 @@ private:
DisassemblerAgent *agent);
void postResolveSymbol(const QString &module, const QString &function,
DisassemblerAgent *agent);
+ void showScriptMessages(const QString &message) const;
// Builtin commands
void handleStackTrace(const DebuggerResponse &);
void handleRegisters(const DebuggerResponse &);
diff --git a/src/plugins/debugger/commonoptionspage.cpp b/src/plugins/debugger/commonoptionspage.cpp
index 1972fe57cd..644fdabbda 100644
--- a/src/plugins/debugger/commonoptionspage.cpp
+++ b/src/plugins/debugger/commonoptionspage.cpp
@@ -115,13 +115,11 @@ QWidget *CommonOptionsPage::widget()
"will automatically open views associated with the current location.") + QLatin1Char('\n');
auto checkBoxCloseSourceBuffersOnExit = new QCheckBox(behaviorBox);
checkBoxCloseSourceBuffersOnExit->setText(tr("Close temporary source views on debugger exit"));
- checkBoxCloseSourceBuffersOnExit->setToolTip(t + tr("Select this option to close "
- "automatically opened source views when the debugger exits."));
+ 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("Select this option to close "
- "automatically opened memory views when the debugger exits."));
+ 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"));
diff --git a/src/plugins/debugger/debuggerengine.cpp b/src/plugins/debugger/debuggerengine.cpp
index 0d1bd2668b..58f2ae0054 100644
--- a/src/plugins/debugger/debuggerengine.cpp
+++ b/src/plugins/debugger/debuggerengine.cpp
@@ -2112,7 +2112,7 @@ void DebuggerEngine::checkState(DebuggerState state, const char *file, int line)
return;
QString msg = QString("UNEXPECTED STATE: %1 WANTED: %2 IN %3:%4")
- .arg(current).arg(state).arg(QLatin1String(file)).arg(line);
+ .arg(stateName(current)).arg(stateName(state)).arg(QLatin1String(file)).arg(line);
showMessage(msg, LogError);
qDebug("%s", qPrintable(msg));
diff --git a/src/plugins/debugger/debuggerplugin.cpp b/src/plugins/debugger/debuggerplugin.cpp
index c983c096ba..599ba02bf5 100644
--- a/src/plugins/debugger/debuggerplugin.cpp
+++ b/src/plugins/debugger/debuggerplugin.cpp
@@ -1913,12 +1913,13 @@ void DebuggerPluginPrivate::onCurrentProjectChanged(Project *project)
for (int i = 0, n = m_snapshotHandler->size(); i != n; ++i) {
// Run controls might be deleted during exit.
if (DebuggerEngine *engine = m_snapshotHandler->at(i)) {
- DebuggerRunControl *runControl = engine->runControl();
- RunConfiguration *rc = runControl->runConfiguration();
- if (rc == activeRc) {
- m_snapshotHandler->setCurrentIndex(i);
- updateState(engine);
- return;
+ if (DebuggerRunControl *runControl = engine->runControl()) {
+ RunConfiguration *rc = runControl->runConfiguration();
+ if (rc == activeRc) {
+ m_snapshotHandler->setCurrentIndex(i);
+ updateState(engine);
+ return;
+ }
}
}
}
diff --git a/src/plugins/debugger/debuggerruncontrol.cpp b/src/plugins/debugger/debuggerruncontrol.cpp
index 23a71d06e4..87e5e47dfa 100644
--- a/src/plugins/debugger/debuggerruncontrol.cpp
+++ b/src/plugins/debugger/debuggerruncontrol.cpp
@@ -648,7 +648,6 @@ class DummyProject : public Project
{
public:
DummyProject() : Project(QString(""), FileName::fromString("")) {}
- QString displayName() const final { return QString(); }
};
RunConfiguration *dummyRunConfigForKit(ProjectExplorer::Kit *kit)
diff --git a/src/plugins/debugger/gdb/gdbengine.cpp b/src/plugins/debugger/gdb/gdbengine.cpp
index 6b0740baca..db71ce6ecc 100644
--- a/src/plugins/debugger/gdb/gdbengine.cpp
+++ b/src/plugins/debugger/gdb/gdbengine.cpp
@@ -147,6 +147,11 @@ static bool isMostlyHarmlessMessage(const QStringRef &msg)
"Invalid argument\\n";
}
+static QString mainFunction(const DebuggerRunParameters &rp)
+{
+ return QLatin1String(rp.toolChainAbi.os() == Abi::WindowsOS && !rp.useTerminal ? "qMain" : "main");
+}
+
///////////////////////////////////////////////////////////////////////
//
// Debuginfo Taskhandler
@@ -1182,7 +1187,7 @@ void GdbEngine::executeDebuggerCommand(const QString &command, DebuggerLanguages
if (!(languages & CppLanguage))
return;
QTC_CHECK(acceptsDebuggerCommands());
- runCommand({command});
+ runCommand({command, NativeCommand});
}
// This is triggered when switching snapshots.
@@ -2372,10 +2377,8 @@ QString GdbEngine::breakpointLocation(const BreakpointParameters &data)
return QLatin1String("__cxa_throw");
if (data.type == BreakpointAtCatch)
return QLatin1String("__cxa_begin_catch");
- if (data.type == BreakpointAtMain) {
- const Abi abi = runParameters().toolChainAbi;
- return QLatin1String(abi.os() == Abi::WindowsOS ? "qMain" : "main");
- }
+ if (data.type == BreakpointAtMain)
+ return mainFunction(runParameters());
if (data.type == BreakpointByFunction)
return '"' + data.functionName + '"';
if (data.type == BreakpointByAddress)
@@ -4153,11 +4156,8 @@ void GdbEngine::handleInferiorPrepared()
}
//runCommand("set follow-exec-mode new");
- if (rp.breakOnMain) {
- QString cmd = "tbreak ";
- cmd += QLatin1String(rp.toolChainAbi.os() == Abi::WindowsOS ? "qMain" : "main");
- runCommand({cmd});
- }
+ if (rp.breakOnMain)
+ runCommand({"tbreak " + mainFunction(rp)});
// Initial attempt to set breakpoints.
if (rp.startMode != AttachCore) {
diff --git a/src/plugins/debugger/gdb/termgdbadapter.cpp b/src/plugins/debugger/gdb/termgdbadapter.cpp
index 359f26f831..e1ace5fca8 100644
--- a/src/plugins/debugger/gdb/termgdbadapter.cpp
+++ b/src/plugins/debugger/gdb/termgdbadapter.cpp
@@ -186,6 +186,7 @@ void GdbTermEngine::interruptInferior2()
void GdbTermEngine::stubError(const QString &msg)
{
Core::AsynchronousMessageBox::critical(tr("Debugger Error"), msg);
+ notifyEngineIll();
}
void GdbTermEngine::stubExited()
diff --git a/src/plugins/diffeditor/differ.cpp b/src/plugins/diffeditor/differ.cpp
index a99b14a127..1e452a7d46 100644
--- a/src/plugins/diffeditor/differ.cpp
+++ b/src/plugins/diffeditor/differ.cpp
@@ -89,6 +89,7 @@ static QList<Diff> decode(const QList<Diff> &diffList,
const QStringList &lines)
{
QList<Diff> newDiffList;
+ newDiffList.reserve(diffList.count());
for (int i = 0; i < diffList.count(); i++) {
Diff diff = diffList.at(i);
QString text;
diff --git a/src/plugins/genericprojectmanager/genericproject.cpp b/src/plugins/genericprojectmanager/genericproject.cpp
index d125b58889..97d884c871 100644
--- a/src/plugins/genericprojectmanager/genericproject.cpp
+++ b/src/plugins/genericprojectmanager/genericproject.cpp
@@ -126,9 +126,13 @@ public:
bool showInSimpleTree() const override { return true; }
- QList<ProjectExplorer::ProjectAction> supportedActions(Node *) const override
+ bool supportsAction(ProjectAction action, Node *) const override
{
- return {AddNewFile, AddExistingFile, AddExistingDirectory, RemoveFile, Rename};
+ return action == AddNewFile
+ || action == AddExistingFile
+ || action == AddExistingDirectory
+ || action == RemoveFile
+ || action == Rename;
}
bool addFiles(const QStringList &filePaths, QStringList * = 0) override
@@ -164,6 +168,7 @@ GenericProject::GenericProject(const Utils::FileName &fileName) :
setId(Constants::GENERICPROJECT_ID);
setProjectContext(Context(GenericProjectManager::Constants::PROJECTCONTEXT));
setProjectLanguages(Context(ProjectExplorer::Constants::CXX_LANGUAGE_ID));
+ setDisplayName(fileName.toFileInfo().completeBaseName());
const QFileInfo fileInfo = projectFilePath().toFileInfo();
const QDir dir = fileInfo.dir();
@@ -467,11 +472,6 @@ void GenericProject::activeBuildConfigurationWasChanged()
refresh(Everything);
}
-QString GenericProject::displayName() const
-{
- return projectFilePath().toFileInfo().completeBaseName();
-}
-
QStringList GenericProject::buildTargets() const
{
const QStringList targets = { "all", "clean" };
diff --git a/src/plugins/genericprojectmanager/genericproject.h b/src/plugins/genericprojectmanager/genericproject.h
index 118ec01f41..2a294ba917 100644
--- a/src/plugins/genericprojectmanager/genericproject.h
+++ b/src/plugins/genericprojectmanager/genericproject.h
@@ -40,8 +40,6 @@ public:
explicit GenericProject(const Utils::FileName &filename);
~GenericProject() override;
- QString displayName() const override;
-
QStringList buildTargets() const;
bool addFiles(const QStringList &filePaths);
diff --git a/src/plugins/git/gitclient.cpp b/src/plugins/git/gitclient.cpp
index 7fb0790cbf..1e730091ac 100644
--- a/src/plugins/git/gitclient.cpp
+++ b/src/plugins/git/gitclient.cpp
@@ -2187,7 +2187,7 @@ bool GitClient::tryLauchingGitK(const QProcessEnvironment &env,
if (HostOsInfo::isWindowsHost()) {
// If git/bin is in path, use 'wish' shell to run. Otherwise (git/cmd), directly run gitk
QString wish = gitBinDirectory + "/wish";
- if (QFileInfo(wish + ".exe").exists()) {
+ if (QFileInfo::exists(wish + ".exe")) {
arguments << binary;
binary = wish;
}
diff --git a/src/plugins/git/gitplugin.cpp b/src/plugins/git/gitplugin.cpp
index d3253dd19d..4e30062424 100644
--- a/src/plugins/git/gitplugin.cpp
+++ b/src/plugins/git/gitplugin.cpp
@@ -241,24 +241,13 @@ QAction *GitPlugin::createFileAction(ActionContainer *ac,
return action;
}
-QAction *GitPlugin::createFileAction(ActionContainer *ac, const QString &defaultText,
- const QString &parameterText, Id id, const Context &context,
- bool addToLocator, void (GitPlugin::*func)(),
- const QKeySequence &keys)
-{
- return createFileAction(ac, defaultText, parameterText, id, context, addToLocator,
- [this, func]() { return (this->*func)(); }, keys);
-}
-
QAction *GitPlugin::createProjectAction(ActionContainer *ac, const QString &defaultText,
const QString &parameterText, Id id, const Context &context,
bool addToLocator, void (GitPlugin::*func)(),
const QKeySequence &keys)
{
ParameterAction *action = createParameterAction(ac, defaultText, parameterText, id, context,
- addToLocator,
- [this, func]() { return (this->*func)(); },
- keys);
+ addToLocator, std::bind(func, this), keys);
m_projectActions.push_back(action);
return action;
}
@@ -279,7 +268,8 @@ QAction *GitPlugin::createChangeRelatedRepositoryAction(const QString &text, Id
const Context &context)
{
return createRepositoryAction(nullptr, text, id, context, true,
- [this, id] { startChangeRelatedAction(id); }, QKeySequence());
+ std::bind(&GitPlugin::startChangeRelatedAction, this, id),
+ QKeySequence());
}
// Action to act on the repository forwarded to a git client member function
@@ -345,33 +335,33 @@ bool GitPlugin::initialize(const QStringList &arguments, QString *errorMessage)
gitContainer->addMenu(currentFileMenu);
createFileAction(currentFileMenu, tr("Diff Current File"), tr("Diff of \"%1\""),
- "Git.Diff", context, true, &GitPlugin::diffCurrentFile,
+ "Git.Diff", context, true, std::bind(&GitPlugin::diffCurrentFile, this),
QKeySequence(UseMacShortcuts ? tr("Meta+G,Meta+D") : tr("Alt+G,Alt+D")));
createFileAction(currentFileMenu, tr("Log Current File"), tr("Log of \"%1\""),
- "Git.Log", context, true, &GitPlugin::logFile,
+ "Git.Log", context, true, std::bind(&GitPlugin::logFile, this),
QKeySequence(UseMacShortcuts ? tr("Meta+G,Meta+L") : tr("Alt+G,Alt+L")));
createFileAction(currentFileMenu, tr("Blame Current File"), tr("Blame for \"%1\""),
- "Git.Blame", context, true, &GitPlugin::blameFile,
+ "Git.Blame", context, true, std::bind(&GitPlugin::blameFile, this),
QKeySequence(UseMacShortcuts ? tr("Meta+G,Meta+B") : tr("Alt+G,Alt+B")));
currentFileMenu->addSeparator(context);
createFileAction(currentFileMenu, tr("Stage File for Commit"), tr("Stage \"%1\" for Commit"),
- "Git.Stage", context, true, &GitPlugin::stageFile,
+ "Git.Stage", context, true, std::bind(&GitPlugin::stageFile, this),
QKeySequence(UseMacShortcuts ? tr("Meta+G,Meta+A") : tr("Alt+G,Alt+A")));
createFileAction(currentFileMenu, tr("Unstage File from Commit"), tr("Unstage \"%1\" from Commit"),
- "Git.Unstage", context, true, &GitPlugin::unstageFile);
+ "Git.Unstage", context, true, std::bind(&GitPlugin::unstageFile, this));
createFileAction(currentFileMenu, tr("Undo Unstaged Changes"), tr("Undo Unstaged Changes for \"%1\""),
"Git.UndoUnstaged", context,
- true, [this]() { return undoFileChanges(false); });
+ true, std::bind(&GitPlugin::undoFileChanges, this, false));
createFileAction(currentFileMenu, tr("Undo Uncommitted Changes"), tr("Undo Uncommitted Changes for \"%1\""),
"Git.Undo", context,
- true, [this]() { return undoFileChanges(true); },
+ true, std::bind(&GitPlugin::undoFileChanges, this, true),
QKeySequence(UseMacShortcuts ? tr("Meta+G,Meta+U") : tr("Alt+G,Alt+U")));
@@ -401,7 +391,7 @@ bool GitPlugin::initialize(const QStringList &arguments, QString *errorMessage)
context, true, &GitClient::diffRepository);
createRepositoryAction(localRepositoryMenu, tr("Log"), "Git.LogRepository",
- context, true, [this] { logRepository(); });
+ context, true, std::bind(&GitPlugin::logRepository, this));
createRepositoryAction(localRepositoryMenu, tr("Reflog"), "Git.ReflogRepository",
context, true, &GitClient::reflog);
@@ -416,77 +406,85 @@ bool GitPlugin::initialize(const QStringList &arguments, QString *errorMessage)
localRepositoryMenu->addSeparator(context);
createRepositoryAction(localRepositoryMenu, tr("Commit..."), "Git.Commit",
- context, true, [this] { startCommit(); },
+ context, true, std::bind(&GitPlugin::startCommit, this, SimpleCommit),
QKeySequence(UseMacShortcuts ? tr("Meta+G,Meta+C") : tr("Alt+G,Alt+C")));
createRepositoryAction(localRepositoryMenu, tr("Amend Last Commit..."), "Git.AmendCommit",
- context, true, [this] { startAmendCommit(); });
+ context, true, std::bind(&GitPlugin::startCommit, this, AmendCommit));
m_fixupCommitAction
= createRepositoryAction(localRepositoryMenu,
tr("Fixup Previous Commit..."), "Git.FixupCommit", context, true,
- [this] { startFixupCommit(); });
+ std::bind(&GitPlugin::startCommit, this, FixupCommit));
// --------------
localRepositoryMenu->addSeparator(context);
createRepositoryAction(localRepositoryMenu, tr("Reset..."), "Git.Reset",
- context, true, [this] { resetRepository(); });
+ context, true, std::bind(&GitPlugin::resetRepository, this));
m_interactiveRebaseAction
= createRepositoryAction(localRepositoryMenu,
tr("Interactive Rebase..."), "Git.InteractiveRebase",
- context, true, [this] { startRebase(); });
+ context, true, std::bind(&GitPlugin::startRebase, this));
m_submoduleUpdateAction
= createRepositoryAction(localRepositoryMenu,
tr("Update Submodules"), "Git.SubmoduleUpdate",
- context, true, [this] { updateSubmodules(); });
+ context, true, std::bind(&GitPlugin::updateSubmodules, this));
m_abortMergeAction
= createRepositoryAction(localRepositoryMenu,
tr("Abort Merge"), "Git.MergeAbort",
- context, true, [this] { continueOrAbortCommand(); });
+ context, true,
+ std::bind(&GitPlugin::continueOrAbortCommand, this));
m_abortRebaseAction
= createRepositoryAction(localRepositoryMenu,
tr("Abort Rebase"), "Git.RebaseAbort",
- context, true, [this] { continueOrAbortCommand(); });
+ context, true,
+ std::bind(&GitPlugin::continueOrAbortCommand, this));
m_abortCherryPickAction
= createRepositoryAction(localRepositoryMenu,
tr("Abort Cherry Pick"), "Git.CherryPickAbort",
- context, true, [this] { continueOrAbortCommand(); });
+ context, true,
+ std::bind(&GitPlugin::continueOrAbortCommand, this));
m_abortRevertAction
= createRepositoryAction(localRepositoryMenu,
tr("Abort Revert"), "Git.RevertAbort",
- context, true, [this] { continueOrAbortCommand(); });
+ context, true,
+ std::bind(&GitPlugin::continueOrAbortCommand, this));
m_continueRebaseAction
= createRepositoryAction(localRepositoryMenu,
tr("Continue Rebase"), "Git.RebaseContinue",
- context, true, [this] { continueOrAbortCommand(); });
+ context, true,
+ std::bind(&GitPlugin::continueOrAbortCommand, this));
m_skipRebaseAction
= createRepositoryAction(localRepositoryMenu,
tr("Skip Rebase"), "Git.RebaseSkip",
- context, true, [this] { continueOrAbortCommand(); });
+ context, true,
+ std::bind(&GitPlugin::continueOrAbortCommand, this));
m_continueCherryPickAction
= createRepositoryAction(localRepositoryMenu,
tr("Continue Cherry Pick"), "Git.CherryPickContinue",
- context, true, [this] { continueOrAbortCommand(); });
+ context, true,
+ std::bind(&GitPlugin::continueOrAbortCommand, this));
m_continueRevertAction
= createRepositoryAction(localRepositoryMenu,
tr("Continue Revert"), "Git.RevertContinue",
- context, true, [this] { continueOrAbortCommand(); });
+ context, true,
+ std::bind(&GitPlugin::continueOrAbortCommand, this));
// --------------
localRepositoryMenu->addSeparator(context);
createRepositoryAction(localRepositoryMenu, tr("Branches..."), "Git.BranchList",
- context, true, [this] { branchList(); });
+ context, true, std::bind(&GitPlugin::branchList, this));
// --------------
localRepositoryMenu->addSeparator(context);
@@ -501,9 +499,9 @@ bool GitPlugin::initialize(const QStringList &arguments, QString *errorMessage)
= createParameterAction(patchMenu,
tr("Apply from Editor"), tr("Apply \"%1\""),
"Git.ApplyCurrentFilePatch",
- context, true, [this] { applyCurrentFilePatch(); });
+ context, true, std::bind(&GitPlugin::applyCurrentFilePatch, this));
createRepositoryAction(patchMenu, tr("Apply from File..."), "Git.ApplyPatch",
- context, true, [this] { promptApplyPatch(); });
+ context, true, std::bind(&GitPlugin::promptApplyPatch, this));
// "Stash" menu
ActionContainer *stashMenu = ActionManager::createMenu("Git.StashMenu");
@@ -511,27 +509,27 @@ bool GitPlugin::initialize(const QStringList &arguments, QString *errorMessage)
localRepositoryMenu->addMenu(stashMenu);
createRepositoryAction(stashMenu, tr("Stashes..."), "Git.StashList",
- context, false, [this] { stashList(); });
+ context, false, std::bind(&GitPlugin::stashList, this));
stashMenu->addSeparator(context);
QAction *action = createRepositoryAction(stashMenu, tr("Stash"), "Git.Stash",
- context, true, [this] { stash(); });
+ context, true, std::bind(&GitPlugin::stash, this, false));
action->setToolTip(tr("Saves the current state of your work and resets the repository."));
action = createRepositoryAction(stashMenu, tr("Stash Unstaged Files"), "Git.StashUnstaged",
- context, true, [this] { stashUnstaged(); });
+ context, true, std::bind(&GitPlugin::stashUnstaged, this));
action->setToolTip(tr("Saves the current state of your unstaged files and resets the repository "
"to its staged state."));
action = createRepositoryAction(stashMenu, tr("Take Snapshot..."), "Git.StashSnapshot",
- context, true, [this] { stashSnapshot(); });
+ context, true, std::bind(&GitPlugin::stashSnapshot, this));
action->setToolTip(tr("Saves the current state of your work."));
stashMenu->addSeparator(context);
action = createRepositoryAction(stashMenu, tr("Stash Pop"), "Git.StashPop",
- context, true, [this] { stashPop(); });
+ context, true, std::bind(&GitPlugin::stashPop, this));
action->setToolTip(tr("Restores changes saved to the stash list using \"Stash\"."));
@@ -545,13 +543,13 @@ bool GitPlugin::initialize(const QStringList &arguments, QString *errorMessage)
gitContainer->addMenu(remoteRepositoryMenu);
createRepositoryAction(remoteRepositoryMenu, tr("Fetch"), "Git.Fetch",
- context, true, [this] { fetch(); });
+ context, true, std::bind(&GitPlugin::fetch, this));
createRepositoryAction(remoteRepositoryMenu, tr("Pull"), "Git.Pull",
- context, true, [this] { pull(); });
+ context, true, std::bind(&GitPlugin::pull, this));
createRepositoryAction(remoteRepositoryMenu, tr("Push"), "Git.Push",
- context, true, [this] { push(); });
+ context, true, std::bind(&GitPlugin::push, this));
// --------------
remoteRepositoryMenu->addSeparator(context);
@@ -571,7 +569,7 @@ bool GitPlugin::initialize(const QStringList &arguments, QString *errorMessage)
remoteRepositoryMenu->addSeparator(context);
createRepositoryAction(remoteRepositoryMenu, tr("Manage Remotes..."), "Git.RemoteList",
- context, false, [this] { remoteList(); });
+ context, false, std::bind(&GitPlugin::remoteList, this));
/* \"Remote Repository" menu */
@@ -583,8 +581,10 @@ bool GitPlugin::initialize(const QStringList &arguments, QString *errorMessage)
createChangeRelatedRepositoryAction(tr("Cherry Pick..."), "Git.CherryPick", context);
createChangeRelatedRepositoryAction(tr("Checkout..."), "Git.Checkout", context);
- createRepositoryAction(0, tr("Rebase..."), "Git.Rebase", context, true, [this] { branchList(); });
- createRepositoryAction(0, tr("Merge..."), "Git.Merge", context, true, [this] { branchList(); });
+ createRepositoryAction(nullptr, tr("Rebase..."), "Git.Rebase", context, true,
+ std::bind(&GitPlugin::branchList, this));
+ createRepositoryAction(nullptr, tr("Merge..."), "Git.Merge", context, true,
+ std::bind(&GitPlugin::branchList, this));
/* \Actions only in locator */
// --------------
@@ -598,16 +598,16 @@ bool GitPlugin::initialize(const QStringList &arguments, QString *errorMessage)
context, true, &GitClient::launchGitK);
createFileAction(gitToolsMenu, tr("Gitk Current File"), tr("Gitk of \"%1\""),
- "Git.GitkFile", context, true, &GitPlugin::gitkForCurrentFile);
+ "Git.GitkFile", context, true, std::bind(&GitPlugin::gitkForCurrentFile, this));
createFileAction(gitToolsMenu, tr("Gitk for folder of Current File"), tr("Gitk for folder of \"%1\""),
- "Git.GitkFolder", context, true, &GitPlugin::gitkForCurrentFolder);
+ "Git.GitkFolder", context, true, std::bind(&GitPlugin::gitkForCurrentFolder, this));
// --------------
gitToolsMenu->addSeparator(context);
createRepositoryAction(gitToolsMenu, tr("Git Gui"), "Git.GitGui",
- context, true, [this] { gitGui(); });
+ context, true, std::bind(&GitPlugin::gitGui, this));
// --------------
gitToolsMenu->addSeparator(context);
@@ -619,7 +619,7 @@ bool GitPlugin::initialize(const QStringList &arguments, QString *errorMessage)
m_mergeToolAction
= createRepositoryAction(gitToolsMenu, tr("Merge Tool"), "Git.MergeTool",
- context, true, [this] { startMergeTool(); });
+ context, true, std::bind(&GitPlugin::startMergeTool, this));
/* \"Git Tools" menu */
@@ -921,21 +921,6 @@ void GitPlugin::gitGui()
m_gitClient->launchGitGui(state.topLevel());
}
-void GitPlugin::startAmendCommit()
-{
- startCommit(AmendCommit);
-}
-
-void GitPlugin::startFixupCommit()
-{
- startCommit(FixupCommit);
-}
-
-void GitPlugin::startCommit()
-{
- startCommit(SimpleCommit);
-}
-
void GitPlugin::startCommit(CommitType commitType)
{
if (raiseSubmitEditor())
diff --git a/src/plugins/git/gitplugin.h b/src/plugins/git/gitplugin.h
index 5948c3b293..790f0959a8 100644
--- a/src/plugins/git/gitplugin.h
+++ b/src/plugins/git/gitplugin.h
@@ -89,7 +89,7 @@ public:
bool isCommitEditorOpen() const;
static QString msgRepositoryLabel(const QString &repository);
static QString invalidBranchAndRemoteNamePattern();
- void startCommit();
+ void startCommit(CommitType commitType = SimpleCommit);
void updateBranches(const QString &repository);
protected:
@@ -128,8 +128,6 @@ private:
void applyCurrentFilePatch();
void promptApplyPatch();
- void startAmendCommit();
- void startFixupCommit();
void stash(bool unstagedOnly = false);
void stashUnstaged();
void stashSnapshot();
@@ -160,11 +158,6 @@ private:
Core::Id id, const Core::Context &context, bool addToLocator,
const std::function<void()> &callback,
const QKeySequence &keys = QKeySequence());
- QAction *createFileAction(Core::ActionContainer *ac,
- const QString &defaultText, const QString &parameterText,
- Core::Id id, const Core::Context &context, bool addToLocator,
- void (GitPlugin::*func)(),
- const QKeySequence &keys = QKeySequence());
QAction *createProjectAction(Core::ActionContainer *ac,
const QString &defaultText, const QString &parameterText,
@@ -188,7 +181,6 @@ private:
void cleanCommitMessageFile();
void cleanRepository(const QString &directory);
void applyPatch(const QString &workingDirectory, QString file = QString());
- void startCommit(CommitType commitType);
void updateVersionWarning();
Core::CommandLocator *m_commandLocator = nullptr;
diff --git a/src/plugins/nim/project/nimproject.cpp b/src/plugins/nim/project/nimproject.cpp
index 39c8ac3e80..fe58ea5c37 100644
--- a/src/plugins/nim/project/nimproject.cpp
+++ b/src/plugins/nim/project/nimproject.cpp
@@ -57,6 +57,7 @@ const int MIN_TIME_BETWEEN_PROJECT_SCANS = 4500;
NimProject::NimProject(const FileName &fileName) : Project(Constants::C_NIM_MIMETYPE, fileName)
{
setId(Constants::C_NIMPROJECT_ID);
+ setDisplayName(fileName.toFileInfo().completeBaseName());
m_projectScanTimer.setSingleShot(true);
connect(&m_projectScanTimer, &QTimer::timeout, this, &NimProject::collectProjectFiles);
@@ -66,11 +67,6 @@ NimProject::NimProject(const FileName &fileName) : Project(Constants::C_NIM_MIME
collectProjectFiles();
}
-QString NimProject::displayName() const
-{
- return projectFilePath().toFileInfo().completeBaseName();
-}
-
bool NimProject::needsConfiguration() const
{
return targets().empty();
@@ -159,12 +155,12 @@ bool NimProject::supportsKit(Kit *k, QString *errorMessage) const
auto tc = dynamic_cast<NimToolChain*>(ToolChainKitInformation::toolChain(k, Constants::C_NIMLANGUAGE_ID));
if (!tc) {
if (errorMessage)
- *errorMessage = tr("No nim compiler set.");
+ *errorMessage = tr("No Nim compiler set.");
return false;
}
if (!tc->compilerCommand().exists()) {
if (errorMessage)
- *errorMessage = tr("Nim compiler doesn't exist");
+ *errorMessage = tr("Nim compiler does not exist");
return false;
}
return true;
diff --git a/src/plugins/nim/project/nimproject.h b/src/plugins/nim/project/nimproject.h
index 5072ce478d..50e03a3fa3 100644
--- a/src/plugins/nim/project/nimproject.h
+++ b/src/plugins/nim/project/nimproject.h
@@ -41,7 +41,6 @@ class NimProject : public ProjectExplorer::Project
public:
explicit NimProject(const Utils::FileName &fileName);
- QString displayName() const override;
bool needsConfiguration() const override;
bool supportsKit(ProjectExplorer::Kit *k, QString *errorMessage) const override;
Utils::FileNameList nimFiles() const;
diff --git a/src/plugins/nim/project/nimprojectnode.cpp b/src/plugins/nim/project/nimprojectnode.cpp
index 5c22cea185..223c6f950d 100644
--- a/src/plugins/nim/project/nimprojectnode.cpp
+++ b/src/plugins/nim/project/nimprojectnode.cpp
@@ -37,23 +37,19 @@ NimProjectNode::NimProjectNode(NimProject &project,
, m_project(project)
{}
-QList<ProjectAction> NimProjectNode::supportedActions(Node *node) const
+bool NimProjectNode::supportsAction(ProjectAction action, Node *node) const
{
- static const QList<ProjectAction> fileActions = {ProjectAction::Rename,
- ProjectAction::RemoveFile
- };
- static const QList<ProjectAction> folderActions = {ProjectAction::AddNewFile,
- ProjectAction::RemoveFile,
- ProjectAction::AddExistingFile
- };
switch (node->nodeType()) {
case NodeType::File:
- return fileActions;
+ return action == ProjectAction::Rename
+ || action == ProjectAction::RemoveFile;
case NodeType::Folder:
case NodeType::Project:
- return folderActions;
+ return action == ProjectAction::AddNewFile
+ || action == ProjectAction::RemoveFile
+ || action == ProjectAction::AddExistingFile;
default:
- return ProjectNode::supportedActions(node);
+ return ProjectNode::supportsAction(action, node);
}
}
diff --git a/src/plugins/nim/project/nimprojectnode.h b/src/plugins/nim/project/nimprojectnode.h
index ba4dd63415..05270846f9 100644
--- a/src/plugins/nim/project/nimprojectnode.h
+++ b/src/plugins/nim/project/nimprojectnode.h
@@ -38,7 +38,7 @@ class NimProjectNode : public ProjectExplorer::ProjectNode
public:
NimProjectNode(NimProject &project, const Utils::FileName &projectFilePath);
- QList<ProjectExplorer::ProjectAction> supportedActions(Node *node) const override;
+ bool supportsAction(ProjectExplorer::ProjectAction action, Node *node) const override;
bool addFiles(const QStringList &filePaths, QStringList *) override;
bool removeFiles(const QStringList &filePaths, QStringList *) override;
bool deleteFiles(const QStringList &) override;
diff --git a/src/plugins/projectexplorer/abi.cpp b/src/plugins/projectexplorer/abi.cpp
index fa504ca3b8..7c5295fac5 100644
--- a/src/plugins/projectexplorer/abi.cpp
+++ b/src/plugins/projectexplorer/abi.cpp
@@ -545,7 +545,7 @@ Abi Abi::abiFromTargetTriplet(const QString &triple)
format = Abi::ElfFormat;
} else if (p == QLatin1String("mingw32") || p == QLatin1String("win32")
|| p == QLatin1String("mingw32msvc") || p == QLatin1String("msys")
- || p == QLatin1String("cygwin")) {
+ || p == QLatin1String("cygwin") || p == QLatin1String("windows")) {
arch = Abi::X86Architecture;
os = Abi::WindowsOS;
flavor = Abi::WindowsMSysFlavor;
@@ -789,6 +789,28 @@ QList<Abi::OSFlavor> Abi::flavorsForOs(const Abi::OS &o)
return result;
}
+Abi::OSFlavor Abi::flavorForMsvcVersion(int version)
+{
+ if (version >= 1910)
+ return WindowsMsvc2017Flavor;
+ switch (version) {
+ case 1900:
+ return WindowsMsvc2015Flavor;
+ case 1800:
+ return WindowsMsvc2013Flavor;
+ case 1700:
+ return WindowsMsvc2012Flavor;
+ case 1600:
+ return WindowsMsvc2010Flavor;
+ case 1500:
+ return WindowsMsvc2008Flavor;
+ case 1400:
+ return WindowsMsvc2005Flavor;
+ default:
+ return WindowsMSysFlavor;
+ }
+}
+
Abi Abi::hostAbi()
{
Architecture arch = QTC_CPU; // define set by qmake
@@ -798,20 +820,8 @@ Abi Abi::hostAbi()
#if defined (Q_OS_WIN)
os = WindowsOS;
-#if _MSC_VER >= 1910
- subos = WindowsMsvc2017Flavor;
-#elif _MSC_VER == 1900
- subos = WindowsMsvc2015Flavor;
-#elif _MSC_VER == 1800
- subos = WindowsMsvc2013Flavor;
-#elif _MSC_VER == 1700
- subos = WindowsMsvc2012Flavor;
-#elif _MSC_VER == 1600
- subos = WindowsMsvc2010Flavor;
-#elif _MSC_VER == 1500
- subos = WindowsMsvc2008Flavor;
-#elif _MSC_VER == 1400
- subos = WindowsMsvc2005Flavor;
+#ifdef _MSC_VER
+ subos = flavorForMsvcVersion(_MSC_VER);
#elif defined (Q_CC_MINGW)
subos = WindowsMSysFlavor;
#endif
@@ -1133,6 +1143,10 @@ void ProjectExplorer::ProjectExplorerPlugin::testAbiFromTargetTriplet_data()
<< int(Abi::WindowsOS) << int(Abi::WindowsMSysFlavor)
<< int(Abi::PEFormat) << 64;
+ QTest::newRow("x86-pc-windows-msvc") << int(Abi::X86Architecture)
+ << int(Abi::WindowsOS) << int(Abi::WindowsMSysFlavor)
+ << int(Abi::PEFormat) << 32;
+
QTest::newRow("mingw32") << int(Abi::X86Architecture)
<< int(Abi::WindowsOS) << int(Abi::WindowsMSysFlavor)
<< int(Abi::PEFormat) << 0;
diff --git a/src/plugins/projectexplorer/abi.h b/src/plugins/projectexplorer/abi.h
index 77e769131e..06157aa81b 100644
--- a/src/plugins/projectexplorer/abi.h
+++ b/src/plugins/projectexplorer/abi.h
@@ -139,6 +139,7 @@ public:
static QString toString(int w);
static QList<OSFlavor> flavorsForOs(const OS &o);
+ static OSFlavor flavorForMsvcVersion(int version);
static Abi hostAbi();
static QList<Abi> abisOfBinary(const Utils::FileName &path);
diff --git a/src/plugins/projectexplorer/abiwidget.cpp b/src/plugins/projectexplorer/abiwidget.cpp
index 278a37a378..5c7671f37f 100644
--- a/src/plugins/projectexplorer/abiwidget.cpp
+++ b/src/plugins/projectexplorer/abiwidget.cpp
@@ -190,6 +190,7 @@ void AbiWidget::setAbis(const QList<Abi> &abiList, const Abi &current)
QList<Abi> AbiWidget::supportedAbis() const
{
QList<Abi> result;
+ result.reserve(d->m_abi->count());
for (int i = 1; i < d->m_abi->count(); ++i)
result << Abi(d->m_abi->itemData(i).toString());
return result;
diff --git a/src/plugins/projectexplorer/devicesupport/devicemanager.cpp b/src/plugins/projectexplorer/devicesupport/devicemanager.cpp
index b1792e6fd5..39b17a6444 100644
--- a/src/plugins/projectexplorer/devicesupport/devicemanager.cpp
+++ b/src/plugins/projectexplorer/devicesupport/devicemanager.cpp
@@ -357,7 +357,7 @@ DeviceManager::DeviceManager(bool isInstance) : d(new DeviceManagerPrivate)
m_instance = this;
d->hostKeyDatabase = QSsh::SshHostKeyDatabasePtr::create();
const QString keyFilePath = hostKeysFilePath();
- if (QFileInfo(keyFilePath).exists()) {
+ if (QFileInfo::exists(keyFilePath)) {
QString error;
if (!d->hostKeyDatabase->load(keyFilePath, &error))
Core::MessageManager::write(error);
diff --git a/src/plugins/projectexplorer/gcctoolchain.cpp b/src/plugins/projectexplorer/gcctoolchain.cpp
index ae4c9813d8..8bb25b5a6d 100644
--- a/src/plugins/projectexplorer/gcctoolchain.cpp
+++ b/src/plugins/projectexplorer/gcctoolchain.cpp
@@ -269,11 +269,19 @@ static QList<Abi> guessGccAbi(const QString &m, const QByteArray &macros)
Abi::OSFlavor flavor = guessed.osFlavor();
Abi::BinaryFormat format = guessed.binaryFormat();
int width = guessed.wordWidth();
+ const QByteArray mscVer = "#define _MSC_VER ";
if (macros.contains("#define __SIZEOF_SIZE_T__ 8"))
width = 64;
else if (macros.contains("#define __SIZEOF_SIZE_T__ 4"))
width = 32;
+ int mscVerIndex = macros.indexOf(mscVer);
+ if (mscVerIndex != -1) {
+ mscVerIndex += mscVer.length();
+ const int eol = macros.indexOf('\n', mscVerIndex);
+ const int msvcVersion = macros.mid(mscVerIndex, eol - mscVerIndex).toInt();
+ flavor = Abi::flavorForMsvcVersion(msvcVersion);
+ }
if (os == Abi::DarwinOS) {
// Apple does PPC and x86!
diff --git a/src/plugins/projectexplorer/jsonwizard/jsonwizard.cpp b/src/plugins/projectexplorer/jsonwizard/jsonwizard.cpp
index 3c2a247e9a..9b97254f60 100644
--- a/src/plugins/projectexplorer/jsonwizard/jsonwizard.cpp
+++ b/src/plugins/projectexplorer/jsonwizard/jsonwizard.cpp
@@ -327,7 +327,7 @@ void JsonWizard::openFiles(const JsonWizard::GeneratorFiles &files)
bool openedSomething = false;
foreach (const JsonWizard::GeneratorFile &f, files) {
const Core::GeneratedFile &file = f.file;
- if (!QFileInfo(file.path()).exists()) {
+ if (!QFileInfo::exists(file.path())) {
errorMessage = QCoreApplication::translate("ProjectExplorer::JsonWizard",
"\"%1\" does not exist in the file system.")
.arg(QDir::toNativeSeparators(file.path()));
diff --git a/src/plugins/projectexplorer/msvcparser.cpp b/src/plugins/projectexplorer/msvcparser.cpp
index 25e0f3131d..ae7a621f92 100644
--- a/src/plugins/projectexplorer/msvcparser.cpp
+++ b/src/plugins/projectexplorer/msvcparser.cpp
@@ -30,24 +30,24 @@
#include <utils/qtcassert.h>
#include <utils/fileutils.h>
+using namespace Utils;
+
// As of MSVC 2015: "foo.cpp(42) :" -> "foo.cpp(42):"
-static const char FILE_POS_PATTERN[] = "(?:\\d+>)?(cl|LINK|.+[^ ]) ?: ";
-static const char ERROR_PATTERN[] = "[A-Z]+\\d\\d\\d\\d ?:";
+static const char FILE_POS_PATTERN[] = "^(?:\\d+>)?(cl|LINK|.+[^ ]) ?: ";
-static QPair<Utils::FileName, int> parseFileName(const QString &input)
+static QPair<FileName, int> parseFileName(const QString &input)
{
QString fileName = input;
- if (fileName.startsWith(QLatin1String("LINK"))
- || fileName.startsWith(QLatin1String("cl")))
- return qMakePair(Utils::FileName(), -1);
+ if (fileName.startsWith("LINK") || fileName.startsWith("cl"))
+ return qMakePair(FileName(), -1);
// Extract linenumber (if it is there):
int linenumber = -1;
- if (fileName.endsWith(QLatin1Char(')'))) {
- int pos = fileName.lastIndexOf(QLatin1Char('('));
+ if (fileName.endsWith(')')) {
+ int pos = fileName.lastIndexOf('(');
if (pos >= 0) {
// clang-cl gives column, too: "foo.cpp(34,1)" as opposed to MSVC "foo.cpp(34)".
- int endPos = fileName.indexOf(QLatin1Char(','), pos + 1);
+ int endPos = fileName.indexOf(',', pos + 1);
if (endPos < 0)
endPos = fileName.size() - 1;
bool ok = false;
@@ -58,8 +58,8 @@ static QPair<Utils::FileName, int> parseFileName(const QString &input)
}
}
}
- const QString normalized = Utils::FileUtils::normalizePathName(fileName);
- return qMakePair(Utils::FileName::fromUserInput(normalized), linenumber);
+ const QString normalized = FileUtils::normalizePathName(fileName);
+ return qMakePair(FileName::fromUserInput(normalized), linenumber);
}
using namespace ProjectExplorer;
@@ -68,9 +68,9 @@ using namespace ProjectExplorer;
static bool handleNmakeJomMessage(const QString &line, Task *task)
{
int matchLength = 0;
- if (line.startsWith(QLatin1String("Error:")))
+ if (line.startsWith("Error:"))
matchLength = 6;
- else if (line.startsWith(QLatin1String("Warning:")))
+ else if (line.startsWith("Warning:"))
matchLength = 8;
if (!matchLength)
@@ -78,7 +78,7 @@ static bool handleNmakeJomMessage(const QString &line, Task *task)
*task = Task(Task::Error,
line.mid(matchLength).trimmed(), /* description */
- Utils::FileName(), /* fileName */
+ FileName(), /* fileName */
-1, /* linenumber */
Constants::TASK_CATEGORY_COMPILE);
return true;
@@ -87,32 +87,32 @@ static bool handleNmakeJomMessage(const QString &line, Task *task)
static Task::TaskType taskType(const QString &category)
{
Task::TaskType type = Task::Unknown;
- if (category == QLatin1String("warning"))
+ if (category == "warning")
type = Task::Warning;
- else if (category == QLatin1String("error"))
+ else if (category == "error")
type = Task::Error;
return type;
}
MsvcParser::MsvcParser()
{
- setObjectName(QLatin1String("MsvcParser"));
- m_compileRegExp.setPattern(QString::fromLatin1("^") + QLatin1String(FILE_POS_PATTERN)
- + QLatin1String("(Command line |fatal )?(warning|error) (")
- + QLatin1String(ERROR_PATTERN) + QLatin1String(".*)$"));
+ setObjectName("MsvcParser");
+ m_compileRegExp.setPattern(QString(FILE_POS_PATTERN)
+ + "(?:Command line |fatal )?(?:(warning|error) "
+ "([A-Z]+\\d{4} ?: )|note: )(.*)$");
QTC_CHECK(m_compileRegExp.isValid());
- m_additionalInfoRegExp.setPattern(QString::fromLatin1("^ (?:(could be |or )\\s*')?(.*)\\((\\d+)\\) : (.*)$"));
+ m_additionalInfoRegExp.setPattern("^ (?:(could be |or )\\s*')?(.*)\\((\\d+)\\) : (.*)$");
QTC_CHECK(m_additionalInfoRegExp.isValid());
}
void MsvcParser::stdOutput(const QString &line)
{
QRegularExpressionMatch match = m_additionalInfoRegExp.match(line);
- if (line.startsWith(QLatin1String(" ")) && !match.hasMatch()) {
+ if (line.startsWith(" ") && !match.hasMatch()) {
if (m_lastTask.isNull())
return;
- m_lastTask.description.append(QLatin1Char('\n'));
+ m_lastTask.description.append('\n');
m_lastTask.description.append(line.mid(8));
// trim trailing spaces:
int i = 0;
@@ -124,7 +124,7 @@ void MsvcParser::stdOutput(const QString &line)
if (m_lastTask.formats.isEmpty()) {
QTextLayout::FormatRange fr;
- fr.start = m_lastTask.description.indexOf(QLatin1Char('\n')) + 1;
+ fr.start = m_lastTask.description.indexOf('\n') + 1;
fr.length = m_lastTask.description.length() - fr.start;
fr.format.setFontItalic(true);
m_lastTask.formats.append(fr);
@@ -147,7 +147,7 @@ void MsvcParser::stdOutput(const QString &line)
if (!match.captured(1).isEmpty())
description.chop(1); // Remove trailing quote
m_lastTask = Task(Task::Unknown, description,
- Utils::FileName::fromUserInput(match.captured(2)), /* fileName */
+ FileName::fromUserInput(match.captured(2)), /* fileName */
match.captured(3).toInt(), /* linenumber */
Constants::TASK_CATEGORY_COMPILE);
m_lines = 1;
@@ -174,9 +174,9 @@ bool MsvcParser::processCompileLine(const QString &line)
QRegularExpressionMatch match = m_compileRegExp.match(line);
if (match.hasMatch()) {
- QPair<Utils::FileName, int> position = parseFileName(match.captured(1));
- m_lastTask = Task(taskType(match.captured(3)),
- match.captured(4).trimmed() /* description */,
+ QPair<FileName, int> position = parseFileName(match.captured(1));
+ m_lastTask = Task(taskType(match.captured(2)),
+ match.captured(3) + match.captured(4).trimmed(), // description
position.first, position.second,
Constants::TASK_CATEGORY_COMPILE);
m_lines = 1;
@@ -204,15 +204,13 @@ void MsvcParser::doFlush()
// ".\qwindowsgdinativeinterface.cpp(48,3) : error: unknown type name 'errr'"
static inline QString clangClCompilePattern()
{
- return QLatin1Char('^') + QLatin1String(FILE_POS_PATTERN)
- + QLatin1String(" (warning|error): (")
- + QLatin1String(".*)$");
+ return QLatin1String(FILE_POS_PATTERN) + " (warning|error): (.*)$";
}
ClangClParser::ClangClParser()
- : m_compileRegExp(clangClCompilePattern())
+ : m_compileRegExp(clangClCompilePattern())
{
- setObjectName(QLatin1String("ClangClParser"));
+ setObjectName("ClangClParser");
QTC_CHECK(m_compileRegExp.isValid());
}
@@ -230,8 +228,8 @@ void ClangClParser::stdOutput(const QString &line)
static inline bool isClangCodeMarker(const QString &trimmedLine)
{
return trimmedLine.constEnd() ==
- std::find_if(trimmedLine.constBegin(), trimmedLine.constEnd(),
- [] (QChar c) { return c != QLatin1Char(' ') && c != QLatin1Char('^') && c != QLatin1Char('~'); });
+ std::find_if(trimmedLine.constBegin(), trimmedLine.constEnd(),
+ [] (QChar c) { return c != ' ' && c != '^' && c != '~'; });
}
void ClangClParser::stdError(const QString &lineIn)
@@ -245,13 +243,13 @@ void ClangClParser::stdError(const QString &lineIn)
}
// Finish a sequence of warnings/errors: "2 warnings generated."
- if (!line.isEmpty() && line.at(0).isDigit() && line.endsWith(QLatin1String("generated."))) {
+ if (!line.isEmpty() && line.at(0).isDigit() && line.endsWith("generated.")) {
doFlush();
return;
}
// Start a new error message by a sequence of "In file included from " which is to be skipped.
- if (line.startsWith(QLatin1String("In file included from "))) {
+ if (line.startsWith("In file included from ")) {
doFlush();
return;
}
@@ -259,7 +257,7 @@ void ClangClParser::stdError(const QString &lineIn)
QRegularExpressionMatch match = m_compileRegExp.match(line);
if (match.hasMatch()) {
doFlush();
- const QPair<Utils::FileName, int> position = parseFileName(match.captured(1));
+ const QPair<FileName, int> position = parseFileName(match.captured(1));
m_lastTask = Task(taskType(match.captured(2)), match.captured(3).trimmed(),
position.first, position.second,
Constants::TASK_CATEGORY_COMPILE);
@@ -273,7 +271,7 @@ void ClangClParser::stdError(const QString &lineIn)
doFlush();
return;
}
- m_lastTask.description.append(QLatin1Char('\n'));
+ m_lastTask.description.append('\n');
m_lastTask.description.append(trimmed);
++m_linkedLines;
return;
@@ -294,13 +292,10 @@ void ClangClParser::doFlush()
#ifdef WITH_TESTS
# include <QTest>
-
# include "projectexplorer.h"
-
# include "projectexplorer/outputparser_test.h"
-using namespace ProjectExplorer::Internal;
-using namespace ProjectExplorer;
+namespace ProjectExplorer {
void ProjectExplorerPlugin::testMsvcOutputParsers_data()
{
@@ -313,240 +308,261 @@ void ProjectExplorerPlugin::testMsvcOutputParsers_data()
QTest::newRow("pass-through stdout")
- << QString::fromLatin1("Sometext") << OutputParserTester::STDOUT
- << QString::fromLatin1("Sometext\n") << QString()
+ << "Sometext" << OutputParserTester::STDOUT
+ << "Sometext\n" << ""
<< QList<Task>()
- << QString();
+ << "";
QTest::newRow("pass-through stderr")
- << QString::fromLatin1("Sometext") << OutputParserTester::STDERR
- << QString() << QString::fromLatin1("Sometext\n")
+ << "Sometext" << OutputParserTester::STDERR
+ << "" << "Sometext\n"
<< QList<Task>()
- << QString();
+ << "";
QTest::newRow("labeled error")
- << QString::fromLatin1("qmlstandalone\\main.cpp(54) : error C4716: 'findUnresolvedModule' : must return a value") << OutputParserTester::STDOUT
- << QString() << QString()
+ << "qmlstandalone\\main.cpp(54) : error C4716: 'findUnresolvedModule' : must return a value"
+ << OutputParserTester::STDOUT
+ << "" << ""
<< (QList<Task>()
<< Task(Task::Error,
- QLatin1String("C4716: 'findUnresolvedModule' : must return a value"),
- Utils::FileName::fromUserInput(QLatin1String("qmlstandalone\\main.cpp")), 54,
+ "C4716: 'findUnresolvedModule' : must return a value",
+ FileName::fromUserInput("qmlstandalone\\main.cpp"), 54,
Constants::TASK_CATEGORY_COMPILE))
- << QString();
+ << "";
QTest::newRow("labeled error-2015")
- << QString::fromLatin1("qmlstandalone\\main.cpp(54): error C4716: 'findUnresolvedModule' : must return a value") << OutputParserTester::STDOUT
- << QString() << QString()
+ << "qmlstandalone\\main.cpp(54): error C4716: 'findUnresolvedModule' : must return a value"
+ << OutputParserTester::STDOUT
+ << "" << ""
<< (QList<Task>()
<< Task(Task::Error,
- QLatin1String("C4716: 'findUnresolvedModule' : must return a value"),
- Utils::FileName::fromUserInput(QLatin1String("qmlstandalone\\main.cpp")), 54,
+ "C4716: 'findUnresolvedModule' : must return a value",
+ FileName::fromUserInput("qmlstandalone\\main.cpp"), 54,
Constants::TASK_CATEGORY_COMPILE))
- << QString();
+ << "";
QTest::newRow("labeled error with number prefix")
- << QString::fromLatin1("1>qmlstandalone\\main.cpp(54) : error C4716: 'findUnresolvedModule' : must return a value") << OutputParserTester::STDOUT
- << QString() << QString()
+ << "1>qmlstandalone\\main.cpp(54) : error C4716: 'findUnresolvedModule' : must return a value"
+ << OutputParserTester::STDOUT
+ << "" << ""
<< (QList<Task>()
<< Task(Task::Error,
- QLatin1String("C4716: 'findUnresolvedModule' : must return a value"),
- Utils::FileName::fromUserInput(QLatin1String("qmlstandalone\\main.cpp")), 54,
+ "C4716: 'findUnresolvedModule' : must return a value",
+ FileName::fromUserInput("qmlstandalone\\main.cpp"), 54,
Constants::TASK_CATEGORY_COMPILE))
- << QString();
+ << "";
QTest::newRow("labeled warning")
- << QString::fromLatin1("x:\\src\\plugins\\projectexplorer\\msvcparser.cpp(69) : warning C4100: 'something' : unreferenced formal parameter") << OutputParserTester::STDOUT
- << QString() << QString()
+ << "x:\\src\\plugins\\projectexplorer\\msvcparser.cpp(69) : warning C4100: 'something' : unreferenced formal parameter"
+ << OutputParserTester::STDOUT
+ << "" << ""
<< (QList<Task>()
<< Task(Task::Warning,
- QLatin1String("C4100: 'something' : unreferenced formal parameter"),
- Utils::FileName::fromUserInput(QLatin1String("x:\\src\\plugins\\projectexplorer\\msvcparser.cpp")), 69,
+ "C4100: 'something' : unreferenced formal parameter",
+ FileName::fromUserInput("x:\\src\\plugins\\projectexplorer\\msvcparser.cpp"), 69,
Constants::TASK_CATEGORY_COMPILE))
- << QString();
+ << "";
QTest::newRow("labeled warning with number prefix")
- << QString::fromLatin1("1>x:\\src\\plugins\\projectexplorer\\msvcparser.cpp(69) : warning C4100: 'something' : unreferenced formal parameter") << OutputParserTester::STDOUT
- << QString() << QString()
+ << "1>x:\\src\\plugins\\projectexplorer\\msvcparser.cpp(69) : warning C4100: 'something' : unreferenced formal parameter"
+ << OutputParserTester::STDOUT
+ << "" << ""
<< (QList<Task>()
<< Task(Task::Warning,
- QLatin1String("C4100: 'something' : unreferenced formal parameter"),
- Utils::FileName::fromUserInput(QLatin1String("x:\\src\\plugins\\projectexplorer\\msvcparser.cpp")), 69,
+ "C4100: 'something' : unreferenced formal parameter",
+ FileName::fromUserInput("x:\\src\\plugins\\projectexplorer\\msvcparser.cpp"), 69,
Constants::TASK_CATEGORY_COMPILE))
- << QString();
+ << "";
QTest::newRow("additional information")
- << QString::fromLatin1("x:\\src\\plugins\\texteditor\\icompletioncollector.h(50) : warning C4099: 'TextEditor::CompletionItem' : type name first seen using 'struct' now seen using 'class'\n"
- " x:\\src\\plugins\\texteditor\\completionsupport.h(39) : see declaration of 'TextEditor::CompletionItem'")
+ << "x:\\src\\plugins\\texteditor\\icompletioncollector.h(50) : warning C4099: 'TextEditor::CompletionItem' : type name first seen using 'struct' now seen using 'class'\n"
+ " x:\\src\\plugins\\texteditor\\completionsupport.h(39) : see declaration of 'TextEditor::CompletionItem'"
<< OutputParserTester::STDOUT
- << QString() << QString()
+ << "" << ""
<< (QList<Task>()
<< Task(Task::Warning,
- QLatin1String("C4099: 'TextEditor::CompletionItem' : type name first seen using 'struct' now seen using 'class'"),
- Utils::FileName::fromUserInput(QLatin1String("x:\\src\\plugins\\texteditor\\icompletioncollector.h")), 50,
+ "C4099: 'TextEditor::CompletionItem' : type name first seen using 'struct' now seen using 'class'",
+ FileName::fromUserInput("x:\\src\\plugins\\texteditor\\icompletioncollector.h"), 50,
Constants::TASK_CATEGORY_COMPILE)
<< Task(Task::Unknown,
- QLatin1String("see declaration of 'TextEditor::CompletionItem'"),
- Utils::FileName::fromUserInput(QLatin1String("x:\\src\\plugins\\texteditor\\completionsupport.h")), 39,
+ "see declaration of 'TextEditor::CompletionItem'",
+ FileName::fromUserInput("x:\\src\\plugins\\texteditor\\completionsupport.h"), 39,
Constants::TASK_CATEGORY_COMPILE))
- << QString();
+ << "";
QTest::newRow("additional information with prefix")
- << QString::fromLatin1("2>x:\\src\\plugins\\texteditor\\icompletioncollector.h(50) : warning C4099: 'TextEditor::CompletionItem' : type name first seen using 'struct' now seen using 'class'\n"
- " x:\\src\\plugins\\texteditor\\completionsupport.h(39) : see declaration of 'TextEditor::CompletionItem'")
+ << "2>x:\\src\\plugins\\texteditor\\icompletioncollector.h(50) : warning C4099: 'TextEditor::CompletionItem' : type name first seen using 'struct' now seen using 'class'\n"
+ " x:\\src\\plugins\\texteditor\\completionsupport.h(39) : see declaration of 'TextEditor::CompletionItem'"
<< OutputParserTester::STDOUT
- << QString() << QString()
+ << "" << ""
<< (QList<Task>()
<< Task(Task::Warning,
- QLatin1String("C4099: 'TextEditor::CompletionItem' : type name first seen using 'struct' now seen using 'class'"),
- Utils::FileName::fromUserInput(QLatin1String("x:\\src\\plugins\\texteditor\\icompletioncollector.h")), 50,
+ "C4099: 'TextEditor::CompletionItem' : type name first seen using 'struct' now seen using 'class'",
+ FileName::fromUserInput("x:\\src\\plugins\\texteditor\\icompletioncollector.h"), 50,
Constants::TASK_CATEGORY_COMPILE)
<< Task(Task::Unknown,
- QLatin1String("see declaration of 'TextEditor::CompletionItem'"),
- Utils::FileName::fromUserInput(QLatin1String("x:\\src\\plugins\\texteditor\\completionsupport.h")), 39,
+ "see declaration of 'TextEditor::CompletionItem'",
+ FileName::fromUserInput("x:\\src\\plugins\\texteditor\\completionsupport.h"), 39,
Constants::TASK_CATEGORY_COMPILE))
- << QString();
+ << "";
QTest::newRow("fatal linker error")
- << QString::fromLatin1("LINK : fatal error LNK1146: no argument specified with option '/LIBPATH:'")
+ << "LINK : fatal error LNK1146: no argument specified with option '/LIBPATH:'"
<< OutputParserTester::STDOUT
- << QString() << QString()
+ << "" << ""
<< (QList<Task>()
<< Task(Task::Error,
- QLatin1String("LNK1146: no argument specified with option '/LIBPATH:'"),
- Utils::FileName(), -1,
+ "LNK1146: no argument specified with option '/LIBPATH:'",
+ FileName(), -1,
Constants::TASK_CATEGORY_COMPILE))
- << QString();
+ << "";
// This actually comes through stderr!
QTest::newRow("command line warning")
- << QString::fromLatin1("cl : Command line warning D9002 : ignoring unknown option '-fopenmp'")
+ << "cl : Command line warning D9002 : ignoring unknown option '-fopenmp'"
<< OutputParserTester::STDERR
- << QString() << QString()
+ << "" << ""
<< (QList<Task>()
<< Task(Task::Warning,
- QLatin1String("D9002 : ignoring unknown option '-fopenmp'"),
- Utils::FileName(), -1,
+ "D9002 : ignoring unknown option '-fopenmp'",
+ FileName(), -1,
Constants::TASK_CATEGORY_COMPILE))
- << QString();
+ << "";
QTest::newRow("complex error")
- << QString::fromLatin1("..\\untitled\\main.cpp(19) : error C2440: 'initializing' : cannot convert from 'int' to 'std::_Tree<_Traits>::iterator'\n"
- " with\n"
- " [\n"
- " _Traits=std::_Tmap_traits<int,double,std::less<int>,std::allocator<std::pair<const int,double>>,false>\n"
- " ]\n"
- " No constructor could take the source type, or constructor overload resolution was ambiguous")
+ << "..\\untitled\\main.cpp(19) : error C2440: 'initializing' : cannot convert from 'int' to 'std::_Tree<_Traits>::iterator'\n"
+ " with\n"
+ " [\n"
+ " _Traits=std::_Tmap_traits<int,double,std::less<int>,std::allocator<std::pair<const int,double>>,false>\n"
+ " ]\n"
+ " No constructor could take the source type, or constructor overload resolution was ambiguous"
<< OutputParserTester::STDOUT
- << QString() << QString()
+ << "" << ""
<< (QList<Task>()
<< Task(Task::Error,
- QLatin1String("C2440: 'initializing' : cannot convert from 'int' to 'std::_Tree<_Traits>::iterator'\n"
- "with\n"
- "[\n"
- " _Traits=std::_Tmap_traits<int,double,std::less<int>,std::allocator<std::pair<const int,double>>,false>\n"
- "]\n"
- "No constructor could take the source type, or constructor overload resolution was ambiguous"),
- Utils::FileName::fromUserInput(QLatin1String("..\\untitled\\main.cpp")), 19,
+ "C2440: 'initializing' : cannot convert from 'int' to 'std::_Tree<_Traits>::iterator'\n"
+ "with\n"
+ "[\n"
+ " _Traits=std::_Tmap_traits<int,double,std::less<int>,std::allocator<std::pair<const int,double>>,false>\n"
+ "]\n"
+ "No constructor could take the source type, or constructor overload resolution was ambiguous",
+ FileName::fromUserInput("..\\untitled\\main.cpp"), 19,
Constants::TASK_CATEGORY_COMPILE))
- << QString();
+ << "";
QTest::newRow("Linker error 1")
- << QString::fromLatin1("main.obj : error LNK2019: unresolved external symbol \"public: void __thiscall Data::doit(void)\" (?doit@Data@@QAEXXZ) referenced in function _main")
+ << "main.obj : error LNK2019: unresolved external symbol \"public: void __thiscall Data::doit(void)\" (?doit@Data@@QAEXXZ) referenced in function _main"
<< OutputParserTester::STDOUT
- << QString() << QString()
+ << "" << ""
<< (QList<Task>()
<< Task(Task::Error,
- QLatin1String("LNK2019: unresolved external symbol \"public: void __thiscall Data::doit(void)\" (?doit@Data@@QAEXXZ) referenced in function _main"),
- Utils::FileName::fromUserInput(QLatin1String("main.obj")), -1,
+ "LNK2019: unresolved external symbol \"public: void __thiscall Data::doit(void)\" (?doit@Data@@QAEXXZ) referenced in function _main",
+ FileName::fromUserInput("main.obj"), -1,
Constants::TASK_CATEGORY_COMPILE))
- << QString();
+ << "";
QTest::newRow("Linker error 2")
- << QString::fromLatin1("debug\\Experimentation.exe : fatal error LNK1120: 1 unresolved externals")
+ << "debug\\Experimentation.exe : fatal error LNK1120: 1 unresolved externals"
<< OutputParserTester::STDOUT
- << QString() << QString()
+ << "" << ""
<< (QList<Task>()
<< Task(Task::Error,
- QLatin1String("LNK1120: 1 unresolved externals"),
- Utils::FileName::fromUserInput(QLatin1String("debug\\Experimentation.exe")), -1,
+ "LNK1120: 1 unresolved externals",
+ FileName::fromUserInput("debug\\Experimentation.exe"), -1,
Constants::TASK_CATEGORY_COMPILE))
- << QString();
+ << "";
QTest::newRow("nmake error")
- << QString::fromLatin1("Error: dependent '..\\..\\..\\..\\creator-2.5\\src\\plugins\\coreplugin\\ifile.h' does not exist.")
+ << "Error: dependent '..\\..\\..\\..\\creator-2.5\\src\\plugins\\coreplugin\\ifile.h' does not exist."
<< OutputParserTester::STDOUT
- << QString() << QString()
+ << "" << ""
<< (QList<Task>()
<< Task(Task::Error,
- QLatin1String("dependent '..\\..\\..\\..\\creator-2.5\\src\\plugins\\coreplugin\\ifile.h' does not exist."),
- Utils::FileName(), -1,
+ "dependent '..\\..\\..\\..\\creator-2.5\\src\\plugins\\coreplugin\\ifile.h' does not exist.",
+ FileName(), -1,
Constants::TASK_CATEGORY_COMPILE))
- << QString();
+ << "";
QTest::newRow("jom error")
- << QString::fromLatin1("Error: dependent 'main.cpp' does not exist.")
+ << "Error: dependent 'main.cpp' does not exist."
<< OutputParserTester::STDERR
- << QString() << QString()
+ << "" << ""
<< (QList<Task>()
<< Task(Task::Error,
- QLatin1String("dependent 'main.cpp' does not exist."),
- Utils::FileName(), -1,
+ "dependent 'main.cpp' does not exist.",
+ FileName(), -1,
Constants::TASK_CATEGORY_COMPILE))
- << QString();
+ << "";
QTest::newRow("Multiline error")
- << QString::fromLatin1("c:\\Program Files (x86)\\Microsoft Visual Studio 10.0\\VC\\INCLUDE\\xutility(2227) : warning C4996: 'std::_Copy_impl': Function call with parameters that may be unsafe - this call relies on the caller to check that the passed values are correct. To disable this warning, use -D_SCL_SECURE_NO_WARNINGS. See documentation on how to use Visual C++ 'Checked Iterators'\n"
- " c:\\Program Files (x86)\\Microsoft Visual Studio 10.0\\VC\\INCLUDE\\xutility(2212) : see declaration of 'std::_Copy_impl'\n"
- " symbolgroupvalue.cpp(2314) : see reference to function template instantiation '_OutIt std::copy<const unsigned char*,unsigned short*>(_InIt,_InIt,_OutIt)' being compiled\n"
- " with\n"
- " [\n"
- " _OutIt=unsigned short *,\n"
- " _InIt=const unsigned char *\n"
- " ]")
+ << "c:\\Program Files (x86)\\Microsoft Visual Studio 10.0\\VC\\INCLUDE\\xutility(2227) : warning C4996: 'std::_Copy_impl': Function call with parameters that may be unsafe - this call relies on the caller to check that the passed values are correct. To disable this warning, use -D_SCL_SECURE_NO_WARNINGS. See documentation on how to use Visual C++ 'Checked Iterators'\n"
+ " c:\\Program Files (x86)\\Microsoft Visual Studio 10.0\\VC\\INCLUDE\\xutility(2212) : see declaration of 'std::_Copy_impl'\n"
+ " symbolgroupvalue.cpp(2314) : see reference to function template instantiation '_OutIt std::copy<const unsigned char*,unsigned short*>(_InIt,_InIt,_OutIt)' being compiled\n"
+ " with\n"
+ " [\n"
+ " _OutIt=unsigned short *,\n"
+ " _InIt=const unsigned char *\n"
+ " ]"
<< OutputParserTester::STDOUT
- << QString() << QString()
+ << "" << ""
<< (QList<Task>()
<< Task(Task::Warning,
- QLatin1String("C4996: 'std::_Copy_impl': Function call with parameters that may be unsafe - this call relies on the caller to check that the passed values are correct. To disable this warning, use -D_SCL_SECURE_NO_WARNINGS. See documentation on how to use Visual C++ 'Checked Iterators'"),
- Utils::FileName::fromUserInput(QLatin1String("c:\\Program Files (x86)\\Microsoft Visual Studio 10.0\\VC\\INCLUDE\\xutility")), 2227,
+ "C4996: 'std::_Copy_impl': Function call with parameters that may be unsafe - this call relies on the caller to check that the passed values are correct. To disable this warning, use -D_SCL_SECURE_NO_WARNINGS. See documentation on how to use Visual C++ 'Checked Iterators'",
+ FileName::fromUserInput("c:\\Program Files (x86)\\Microsoft Visual Studio 10.0\\VC\\INCLUDE\\xutility"), 2227,
Constants::TASK_CATEGORY_COMPILE)
<< Task(Task::Unknown,
- QLatin1String("see declaration of 'std::_Copy_impl'"),
- Utils::FileName::fromUserInput(QLatin1String("c:\\Program Files (x86)\\Microsoft Visual Studio 10.0\\VC\\INCLUDE\\xutility")), 2212,
+ "see declaration of 'std::_Copy_impl'",
+ FileName::fromUserInput("c:\\Program Files (x86)\\Microsoft Visual Studio 10.0\\VC\\INCLUDE\\xutility"), 2212,
Constants::TASK_CATEGORY_COMPILE)
<< Task(Task::Unknown,
- QLatin1String("see reference to function template instantiation '_OutIt std::copy<const unsigned char*,unsigned short*>(_InIt,_InIt,_OutIt)' being compiled\n"
- "with\n"
- "[\n"
- " _OutIt=unsigned short *,\n"
- " _InIt=const unsigned char *\n"
- "]"),
- Utils::FileName::fromUserInput(QLatin1String("symbolgroupvalue.cpp")), 2314,
+ "see reference to function template instantiation '_OutIt std::copy<const unsigned char*,unsigned short*>(_InIt,_InIt,_OutIt)' being compiled\n"
+ "with\n"
+ "[\n"
+ " _OutIt=unsigned short *,\n"
+ " _InIt=const unsigned char *\n"
+ "]",
+ FileName::fromUserInput("symbolgroupvalue.cpp"), 2314,
Constants::TASK_CATEGORY_COMPILE))
- << QString();
+ << "";
QTest::newRow("Ambiguous symbol")
- << QString::fromLatin1("D:\\Project\\file.h(98) : error C2872: 'UINT64' : ambiguous symbol\n"
- " could be 'C:\\Program Files (x86)\\Microsoft SDKs\\Windows\\v7.0A\\include\\basetsd.h(83) : unsigned __int64 UINT64'\n"
- " or 'D:\\Project\\types.h(71) : Types::UINT64'")
+ << "D:\\Project\\file.h(98) : error C2872: 'UINT64' : ambiguous symbol\n"
+ " could be 'C:\\Program Files (x86)\\Microsoft SDKs\\Windows\\v7.0A\\include\\basetsd.h(83) : unsigned __int64 UINT64'\n"
+ " or 'D:\\Project\\types.h(71) : Types::UINT64'"
<< OutputParserTester::STDOUT
- << QString() << QString()
+ << "" << ""
<< (QList<Task>()
<< Task(Task::Error,
- QLatin1String("C2872: 'UINT64' : ambiguous symbol"),
- Utils::FileName::fromUserInput(QLatin1String("D:\\Project\\file.h")), 98,
+ "C2872: 'UINT64' : ambiguous symbol",
+ FileName::fromUserInput("D:\\Project\\file.h"), 98,
+ Constants::TASK_CATEGORY_COMPILE)
+ << Task(Task::Unknown,
+ "could be unsigned __int64 UINT64",
+ FileName::fromUserInput("C:\\Program Files (x86)\\Microsoft SDKs\\Windows\\v7.0A\\include\\basetsd.h"), 83,
Constants::TASK_CATEGORY_COMPILE)
- << Task(Task::Unknown,
- QLatin1String("could be unsigned __int64 UINT64"),
- Utils::FileName::fromUserInput(QLatin1String("C:\\Program Files (x86)\\Microsoft SDKs\\Windows\\v7.0A\\include\\basetsd.h")), 83,
- Constants::TASK_CATEGORY_COMPILE)
- << Task(Task::Unknown,
- QLatin1String("or Types::UINT64"),
- Utils::FileName::fromUserInput(QLatin1String("D:\\Project\\types.h")), 71,
- Constants::TASK_CATEGORY_COMPILE))
- << QString();
+ << Task(Task::Unknown,
+ "or Types::UINT64",
+ FileName::fromUserInput("D:\\Project\\types.h"), 71,
+ Constants::TASK_CATEGORY_COMPILE))
+ << "";
QTest::newRow("ignore moc note")
- << QString::fromLatin1("/home/qtwebkithelpviewer.h:0: Note: No relevant classes found. No output generated.")
+ << "/home/qtwebkithelpviewer.h:0: Note: No relevant classes found. No output generated."
<< OutputParserTester::STDERR
- << QString() << QString::fromLatin1("/home/qtwebkithelpviewer.h:0: Note: No relevant classes found. No output generated.\n")
+ << "" << "/home/qtwebkithelpviewer.h:0: Note: No relevant classes found. No output generated.\n"
<< (QList<ProjectExplorer::Task>())
- << QString();
+ << "";
+
+ QTest::newRow("error with note")
+ << "main.cpp(7): error C2733: 'func': second C linkage of overloaded function not allowed\n"
+ "main.cpp(6): note: see declaration of 'func'"
+ << OutputParserTester::STDOUT
+ << "" << ""
+ << (QList<Task>()
+ << Task(Task::Error,
+ "C2733: 'func': second C linkage of overloaded function not allowed",
+ FileName::fromUserInput("main.cpp"), 7,
+ Constants::TASK_CATEGORY_COMPILE)
+ << Task(Task::Unknown,
+ "see declaration of 'func'",
+ FileName::fromUserInput("main.cpp"), 6,
+ Constants::TASK_CATEGORY_COMPILE))
+ << "";
}
void ProjectExplorerPlugin::testMsvcOutputParsers()
@@ -574,68 +590,63 @@ void ProjectExplorerPlugin::testClangClOutputParsers_data()
QTest::addColumn<QList<Task> >("tasks");
QTest::addColumn<QString>("outputLines");
- const QString warning1 = QLatin1String(
-"private field 'm_version' is not used [-Wunused-private-field]\n"
-"const int m_version; //! majorVersion<<8 + minorVersion");
- const QString warning2 = QLatin1String(
-"unused variable 'formatTextPlainC' [-Wunused-const-variable]\n"
-"static const char formatTextPlainC[] = \"text/plain\";");
- const QString warning3 = QLatin1String(
-"unused variable 'formatTextHtmlC' [-Wunused-const-variable]\n"
-"static const char formatTextHtmlC[] = \"text/html\";");
- const QString error1 = QLatin1String(
-"unknown type name 'errr'\n"
-" errr");
- const QString expectedError1 = QLatin1String(
-"unknown type name 'errr'\n"
-"errr"); // Line 2 trimmed.
- const QString error2 = QLatin1String(
-"expected unqualified-id\n"
-"void *QWindowsGdiNativeInterface::nativeResourceForBackingStore(const QByteArray &resource, QBackingStore *bs)");
-
- const QString clangClCompilerLog = QLatin1String(
-"In file included from .\\qwindowseglcontext.cpp:40:\n"
-"./qwindowseglcontext.h(282,15) : warning: ") + warning1 + QLatin1String("\n"
-"5 warnings generated.\n"
-".\\qwindowsclipboard.cpp(60,19) : warning: ") + warning2 + QLatin1String("\n"
-" ^\n"
-".\\qwindowsclipboard.cpp(61,19) : warning: ") + warning3 + QLatin1String("\n"
-" ^\n"
-"2 warnings generated.\n"
-".\\qwindowsgdinativeinterface.cpp(48,3) : error: ") + error1 + QLatin1String("\n"
-" ^\n"
-".\\qwindowsgdinativeinterface.cpp(51,1) : error: ") + error2 + QLatin1String("\n"
-"^\n"
-"2 errors generated.\n");
-
- const QString ignoredStderr = QLatin1String(
-"NMAKE : fatal error U1077: 'D:\\opt\\LLVM64_390\\bin\\clang-cl.EXE' : return code '0x1'\n"
-"Stop.");
+ const QString warning1 = "private field 'm_version' is not used [-Wunused-private-field]\n"
+ "const int m_version; //! majorVersion<<8 + minorVersion\n";
+ const QString warning2 = "unused variable 'formatTextPlainC' [-Wunused-const-variable]\n"
+ "static const char formatTextPlainC[] = \"text/plain\";\n";
+ const QString warning3 = "unused variable 'formatTextHtmlC' [-Wunused-const-variable]\n"
+ "static const char formatTextHtmlC[] = \"text/html\";\n";
+ const QString error1 = "unknown type name 'errr'\n"
+ " errr\n";
+ const QString expectedError1 = "unknown type name 'errr'\n"
+ "errr"; // Line 2 trimmed.
+ const QString error2 =
+ "expected unqualified-id\n"
+ "void *QWindowsGdiNativeInterface::nativeResourceForBackingStore(const QByteArray &resource, QBackingStore *bs)\n";
+
+ const QString clangClCompilerLog =
+ "In file included from .\\qwindowseglcontext.cpp:40:\n"
+ "./qwindowseglcontext.h(282,15) : warning: " + warning1 +
+ "5 warnings generated.\n"
+ ".\\qwindowsclipboard.cpp(60,19) : warning: " + warning2 +
+ " ^\n"
+ ".\\qwindowsclipboard.cpp(61,19) : warning: " + warning3 +
+ " ^\n"
+ "2 warnings generated.\n"
+ ".\\qwindowsgdinativeinterface.cpp(48,3) : error: " + error1 +
+ " ^\n"
+ ".\\qwindowsgdinativeinterface.cpp(51,1) : error: " + error2 +
+ "^\n"
+ "2 errors generated.\n";
+
+ const QString ignoredStderr =
+ "NMAKE : fatal error U1077: 'D:\\opt\\LLVM64_390\\bin\\clang-cl.EXE' : return code '0x1'\n"
+ "Stop.";
const QString input = clangClCompilerLog + ignoredStderr;
- const QString expectedStderr = ignoredStderr + QLatin1Char('\n');
+ const QString expectedStderr = ignoredStderr + '\n';
QTest::newRow("error")
<< input
<< OutputParserTester::STDERR
- << QString() << expectedStderr
+ << "" << expectedStderr
<< (QList<Task>()
- << Task(Task::Warning, warning1,
- Utils::FileName::fromUserInput(QLatin1String("./qwindowseglcontext.h")), 282,
+ << Task(Task::Warning, warning1.trimmed(),
+ FileName::fromUserInput("./qwindowseglcontext.h"), 282,
Constants::TASK_CATEGORY_COMPILE)
- << Task(Task::Warning, warning2,
- Utils::FileName::fromUserInput(QLatin1String(".\\qwindowsclipboard.cpp")), 60,
+ << Task(Task::Warning, warning2.trimmed(),
+ FileName::fromUserInput(".\\qwindowsclipboard.cpp"), 60,
Constants::TASK_CATEGORY_COMPILE)
- << Task(Task::Warning, warning3,
- Utils::FileName::fromUserInput(QLatin1String(".\\qwindowsclipboard.cpp")), 61,
+ << Task(Task::Warning, warning3.trimmed(),
+ FileName::fromUserInput(".\\qwindowsclipboard.cpp"), 61,
Constants::TASK_CATEGORY_COMPILE)
<< Task(Task::Error, expectedError1,
- Utils::FileName::fromUserInput(QLatin1String(".\\qwindowsgdinativeinterface.cpp")), 48,
+ FileName::fromUserInput(".\\qwindowsgdinativeinterface.cpp"), 48,
Constants::TASK_CATEGORY_COMPILE)
- << Task(Task::Error, error2,
- Utils::FileName::fromUserInput(QLatin1String(".\\qwindowsgdinativeinterface.cpp")), 51,
+ << Task(Task::Error, error2.trimmed(),
+ FileName::fromUserInput(".\\qwindowsgdinativeinterface.cpp"), 51,
Constants::TASK_CATEGORY_COMPILE))
- << QString();
+ << "";
}
void ProjectExplorerPlugin::testClangClOutputParsers()
@@ -654,4 +665,6 @@ void ProjectExplorerPlugin::testClangClOutputParsers()
outputLines);
}
+} // namespace ProjectExplorer
+
#endif // WITH_TEST
diff --git a/src/plugins/projectexplorer/processstep.cpp b/src/plugins/projectexplorer/processstep.cpp
index 9b95a0870c..0d5334c0e6 100644
--- a/src/plugins/projectexplorer/processstep.cpp
+++ b/src/plugins/projectexplorer/processstep.cpp
@@ -86,7 +86,7 @@ bool ProcessStep::init(QList<const BuildStep *> &earlierSteps)
void ProcessStep::run(QFutureInterface<bool> & fi)
{
- return AbstractProcessStep::run(fi);
+ AbstractProcessStep::run(fi);
}
BuildStepConfigWidget *ProcessStep::createConfigWidget()
diff --git a/src/plugins/projectexplorer/project.cpp b/src/plugins/projectexplorer/project.cpp
index 578cc033ec..bb62390fe4 100644
--- a/src/plugins/projectexplorer/project.cpp
+++ b/src/plugins/projectexplorer/project.cpp
@@ -141,6 +141,8 @@ public:
QVariantMap m_pluginSettings;
Internal::UserFileAccessor *m_accessor = nullptr;
+ QString m_displayName;
+
Kit::Predicate m_requiredKitPredicate;
Kit::Predicate m_preferredKitPredicate;
@@ -178,6 +180,11 @@ Project::~Project()
delete d;
}
+QString Project::displayName() const
+{
+ return d->m_displayName;
+}
+
Core::Id Project::id() const
{
QTC_CHECK(d->m_id.isValid());
@@ -455,6 +462,14 @@ bool Project::setupTarget(Target *t)
return true;
}
+void Project::setDisplayName(const QString &name)
+{
+ if (name == d->m_displayName)
+ return;
+ d->m_displayName = name;
+ emit displayNameChanged();
+}
+
void Project::setId(Core::Id id)
{
d->m_id = id;
@@ -477,10 +492,13 @@ void Project::setRootProjectNode(ProjectNode *root)
ProjectNode *oldNode = d->m_rootProjectNode;
d->m_rootProjectNode = root;
- if (root)
+ if (root) {
root->setParentFolderNode(d->m_containerNode);
- ProjectTree::emitSubtreeChanged(root);
- emit fileListChanged();
+ // Only announce non-null root, null is only used when project is destroyed.
+ // In that case SessionManager::projectRemoved() triggers the update.
+ ProjectTree::emitSubtreeChanged(root);
+ emit fileListChanged();
+ }
delete oldNode;
}
diff --git a/src/plugins/projectexplorer/project.h b/src/plugins/projectexplorer/project.h
index 343643b281..edc5b4c2ce 100644
--- a/src/plugins/projectexplorer/project.h
+++ b/src/plugins/projectexplorer/project.h
@@ -92,7 +92,7 @@ public:
const ProjectDocument::ProjectCallback &callback = {});
~Project() override;
- virtual QString displayName() const = 0;
+ QString displayName() const;
Core::Id id() const;
Core::IDocument *document() const;
@@ -164,6 +164,7 @@ public:
Utils::MacroExpander *macroExpander() const;
signals:
+ void displayNameChanged();
void fileListChanged();
// Note: activeTarget can be 0 (if no targets are defined).
@@ -190,6 +191,7 @@ protected:
virtual RestoreResult fromMap(const QVariantMap &map, QString *errorMessage);
virtual bool setupTarget(Target *t);
+ void setDisplayName(const QString &name);
void setRequiredKitPredicate(const Kit::Predicate &predicate);
void setPreferredKitPredicate(const Kit::Predicate &predicate);
diff --git a/src/plugins/projectexplorer/projectexplorer.cpp b/src/plugins/projectexplorer/projectexplorer.cpp
index 20f4d27ea1..c18c65a13c 100644
--- a/src/plugins/projectexplorer/projectexplorer.cpp
+++ b/src/plugins/projectexplorer/projectexplorer.cpp
@@ -2927,8 +2927,6 @@ void ProjectExplorerPluginPrivate::updateContextMenuActions()
Node *currentNode = ProjectTree::currentNode();
if (currentNode && currentNode->managingProject()) {
- QList<ProjectAction> actions = currentNode->supportedActions(currentNode);
-
ProjectNode *pn;
if (ContainerNode *cn = currentNode->asContainerNode())
pn = cn->rootProjectNode();
@@ -2956,56 +2954,61 @@ void ProjectExplorerPluginPrivate::updateContextMenuActions()
}
}
}
+
+ auto supports = [currentNode](ProjectAction action) {
+ return currentNode->supportsAction(action, currentNode);
+ };
+
if (currentNode->asFolderNode()) {
// Also handles ProjectNode
- m_addNewFileAction->setEnabled(actions.contains(AddNewFile)
+ m_addNewFileAction->setEnabled(currentNode->supportsAction(AddNewFile, currentNode)
&& !ICore::isNewItemDialogRunning());
m_addNewSubprojectAction->setEnabled(currentNode->nodeType() == NodeType::Project
- && actions.contains(AddSubProject)
+ && supports(AddSubProject)
&& !ICore::isNewItemDialogRunning());
m_removeProjectAction->setEnabled(currentNode->nodeType() == NodeType::Project
- && actions.contains(RemoveSubProject));
- m_addExistingFilesAction->setEnabled(actions.contains(AddExistingFile));
- m_addExistingDirectoryAction->setEnabled(actions.contains(AddExistingDirectory));
- m_renameFileAction->setEnabled(actions.contains(Rename));
+ && supports(RemoveSubProject));
+ m_addExistingFilesAction->setEnabled(supports(AddExistingFile));
+ m_addExistingDirectoryAction->setEnabled(supports(AddExistingDirectory));
+ m_renameFileAction->setEnabled(supports(Rename));
} else if (currentNode->asFileNode()) {
// Enable and show remove / delete in magic ways:
// If both are disabled show Remove
// If both are enabled show both (can't happen atm)
// If only removeFile is enabled only show it
// If only deleteFile is enable only show it
- bool enableRemove = actions.contains(RemoveFile);
+ bool enableRemove = supports(RemoveFile);
m_removeFileAction->setEnabled(enableRemove);
- bool enableDelete = actions.contains(EraseFile);
+ bool enableDelete = supports(EraseFile);
m_deleteFileAction->setEnabled(enableDelete);
m_deleteFileAction->setVisible(enableDelete);
m_removeFileAction->setVisible(!enableDelete || enableRemove);
- m_renameFileAction->setEnabled(actions.contains(Rename));
+ m_renameFileAction->setEnabled(supports(Rename));
const bool currentNodeIsTextFile = isTextFile(
ProjectTree::currentNode()->filePath().toString());
m_diffFileAction->setEnabled(isDiffServiceAvailable()
&& currentNodeIsTextFile && TextEditor::TextDocument::currentTextDocument());
- m_duplicateFileAction->setVisible(actions.contains(DuplicateFile));
- m_duplicateFileAction->setEnabled(actions.contains(DuplicateFile));
+ m_duplicateFileAction->setVisible(supports(DuplicateFile));
+ m_duplicateFileAction->setEnabled(supports(DuplicateFile));
EditorManager::populateOpenWithMenu(m_openWithMenu,
ProjectTree::currentNode()->filePath().toString());
}
- if (actions.contains(HidePathActions)) {
+ if (supports(HidePathActions)) {
m_openTerminalHere->setVisible(false);
m_showInGraphicalShell->setVisible(false);
m_searchOnFileSystem->setVisible(false);
}
- if (actions.contains(HideFileActions)) {
+ if (supports(HideFileActions)) {
m_deleteFileAction->setVisible(false);
m_removeFileAction->setVisible(false);
}
- if (actions.contains(HideFolderActions)) {
+ if (supports(HideFolderActions)) {
m_addNewFileAction->setVisible(false);
m_addNewSubprojectAction->setVisible(false);
m_removeProjectAction->setVisible(false);
@@ -3041,8 +3044,7 @@ void ProjectExplorerPluginPrivate::addNewSubproject()
QString location = directoryFor(currentNode);
if (currentNode->nodeType() == NodeType::Project
- && currentNode->supportedActions(
- currentNode).contains(AddSubProject)) {
+ && currentNode->supportsAction(AddSubProject, currentNode)) {
QVariantMap map;
map.insert(QLatin1String(Constants::PREFERRED_PROJECT_NODE), QVariant::fromValue(currentNode));
Project *project = ProjectTree::currentProject();
@@ -3163,29 +3165,33 @@ void ProjectExplorerPluginPrivate::removeFile()
Node *currentNode = ProjectTree::currentNode();
QTC_ASSERT(currentNode && currentNode->nodeType() == NodeType::File, return);
- FileNode *fileNode = currentNode->asFileNode();
-
- QString filePath = currentNode->filePath().toString();
- RemoveFileDialog removeFileDialog(filePath, ICore::mainWindow());
+ const Utils::FileName filePath = currentNode->filePath();
+ RemoveFileDialog removeFileDialog(filePath.toString(), ICore::mainWindow());
if (removeFileDialog.exec() == QDialog::Accepted) {
const bool deleteFile = removeFileDialog.isDeleteFileChecked();
+ // Re-read the current node, in case the project is re-parsed while the dialog is open
+ if (currentNode != ProjectTree::currentNode()) {
+ currentNode = ProjectTreeWidget::nodeForFile(filePath);
+ QTC_ASSERT(currentNode && currentNode->nodeType() == NodeType::File, return);
+ }
+
// remove from project
- FolderNode *folderNode = fileNode->parentFolderNode();
- Q_ASSERT(folderNode);
+ FolderNode *folderNode = currentNode->asFileNode()->parentFolderNode();
+ QTC_ASSERT(folderNode, return);
- if (!folderNode->removeFiles(QStringList(filePath))) {
+ if (!folderNode->removeFiles(QStringList(filePath.toString()))) {
QMessageBox::warning(ICore::mainWindow(), tr("Removing File Failed"),
tr("Could not remove file %1 from project %2.")
- .arg(QDir::toNativeSeparators(filePath))
+ .arg(filePath.toUserOutput())
.arg(folderNode->managingProject()->displayName()));
if (!deleteFile)
return;
}
- FileChangeBlocker changeGuard(filePath);
- FileUtils::removeFile(filePath, deleteFile);
+ FileChangeBlocker changeGuard(filePath.toString());
+ FileUtils::removeFile(filePath.toString(), deleteFile);
}
}
@@ -3212,7 +3218,7 @@ void ProjectExplorerPluginPrivate::duplicateFile()
// Create a copy and add the file to the parent folder node.
FolderNode *folderNode = fileNode->parentFolderNode();
- Q_ASSERT(folderNode);
+ QTC_ASSERT(folderNode, return);
if (!(QFile::copy(filePath, newFilePath) && folderNode->addFiles(QStringList(newFilePath)))) {
QMessageBox::warning(ICore::mainWindow(), tr("Duplicating File Failed"),
tr("Could not duplicate the file %1.")
diff --git a/src/plugins/projectexplorer/projectmodels.cpp b/src/plugins/projectexplorer/projectmodels.cpp
index d9b7a80d41..9a5bb11407 100644
--- a/src/plugins/projectexplorer/projectmodels.cpp
+++ b/src/plugins/projectexplorer/projectmodels.cpp
@@ -74,15 +74,14 @@ FlatModel::FlatModel(QObject *parent)
: TreeModel<WrapperNode, WrapperNode>(new WrapperNode(nullptr), parent)
{
ProjectTree *tree = ProjectTree::instance();
- connect(tree, &ProjectTree::subtreeChanged, this, &FlatModel::update);
+ connect(tree, &ProjectTree::subtreeChanged, this, &FlatModel::updateSubtree);
SessionManager *sm = SessionManager::instance();
- connect(sm, &SessionManager::projectRemoved, this, &FlatModel::update);
- connect(sm, &SessionManager::sessionLoaded, this, &FlatModel::loadExpandData);
+ connect(sm, &SessionManager::projectRemoved, this, &FlatModel::handleProjectRemoved);
+ connect(sm, &SessionManager::aboutToLoadSession, this, &FlatModel::loadExpandData);
connect(sm, &SessionManager::aboutToSaveSession, this, &FlatModel::saveExpandData);
connect(sm, &SessionManager::projectAdded, this, &FlatModel::handleProjectAdded);
connect(sm, &SessionManager::startupProjectChanged, this, [this] { layoutChanged(); });
- update();
}
QVariant FlatModel::data(const QModelIndex &index, int role) const
@@ -145,7 +144,7 @@ Qt::ItemFlags FlatModel::flags(const QModelIndex &index) const
if (Node *node = nodeForIndex(index)) {
if (!node->asProjectNode()) {
// either folder or file node
- if (node->supportedActions(node).contains(Rename))
+ if (node->supportsAction(Rename, node))
f = f | Qt::ItemIsEditable;
}
}
@@ -170,42 +169,27 @@ bool FlatModel::setData(const QModelIndex &index, const QVariant &value, int rol
return true;
}
-void FlatModel::update()
+void FlatModel::addOrRebuildProjectModel(Project *project)
{
- rebuildModel();
-}
-
-void FlatModel::rebuildModel()
-{
- QList<Project *> projects = SessionManager::projects();
-
- Utils::sort(projects, [](Project *p1, Project *p2) {
- const int displayNameResult = caseFriendlyCompare(p1->displayName(), p2->displayName());
- if (displayNameResult != 0)
- return displayNameResult < 0;
- return p1 < p2; // sort by pointer value
- });
+ WrapperNode *container = nodeForProject(project);
+ if (container) {
+ container->removeChildren();
+ } else {
+ container = new WrapperNode(project->containerNode());
+ rootItem()->appendChild(container);
+ }
QSet<Node *> seen;
- rootItem()->removeChildren();
- for (Project *project : projects) {
- WrapperNode *container = new WrapperNode(project->containerNode());
-
- ProjectNode *projectNode = project->rootProjectNode();
- if (projectNode) {
- addFolderNode(container, projectNode, &seen);
- } else {
- FileNode *projectFileNode = new FileNode(project->projectFilePath(), FileType::Project, false);
- seen.insert(projectFileNode);
- container->appendChild(new WrapperNode(projectFileNode));
- }
-
- container->sortChildren(&sortWrapperNodes);
- rootItem()->appendChild(container);
+ if (ProjectNode *projectNode = project->rootProjectNode()) {
+ addFolderNode(container, projectNode, &seen);
+ } else {
+ FileNode *projectFileNode = new FileNode(project->projectFilePath(), FileType::Project, false);
+ seen.insert(projectFileNode);
+ container->appendChild(new WrapperNode(projectFileNode));
}
- forAllItems([this](WrapperNode *node) {
+ container->forAllChildren([this](WrapperNode *node) {
if (node->m_node) {
const QString path = node->m_node->filePath().toString();
const QString displayName = node->m_node->displayName();
@@ -216,6 +200,37 @@ void FlatModel::rebuildModel()
emit requestExpansion(node->index());
}
});
+
+ const QString path = container->m_node->filePath().toString();
+ const QString displayName = container->m_node->displayName();
+ ExpandData ed(path, displayName);
+ if (m_toExpand.contains(ed))
+ emit requestExpansion(container->index());
+}
+
+void FlatModel::updateSubtree(FolderNode *node)
+{
+ // FIXME: This is still excessive, should be limited to the affected subtree.
+ while (FolderNode *parent = node->parentFolderNode())
+ node = parent;
+ if (ContainerNode *container = node->asContainerNode())
+ addOrRebuildProjectModel(container->project());
+}
+
+void FlatModel::rebuildModel()
+{
+ QList<Project *> projects = SessionManager::projects();
+ QTC_CHECK(projects.size() == rootItem()->childCount());
+
+ Utils::sort(projects, [](Project *p1, Project *p2) {
+ const int displayNameResult = caseFriendlyCompare(p1->displayName(), p2->displayName());
+ if (displayNameResult != 0)
+ return displayNameResult < 0;
+ return p1 < p2; // sort by pointer value
+ });
+
+ for (Project *project : projects)
+ addOrRebuildProjectModel(project);
}
void FlatModel::onCollapsed(const QModelIndex &idx)
@@ -238,9 +253,22 @@ ExpandData FlatModel::expandDataForNode(const Node *node) const
void FlatModel::handleProjectAdded(Project *project)
{
- Node *node = project->containerNode();
- m_toExpand.insert(expandDataForNode(node));
- update();
+ addOrRebuildProjectModel(project);
+}
+
+void FlatModel::handleProjectRemoved(Project *project)
+{
+ destroyItem(nodeForProject(project));
+}
+
+WrapperNode *FlatModel::nodeForProject(Project *project)
+{
+ QTC_ASSERT(project, return nullptr);
+ ContainerNode *containerNode = project->containerNode();
+ QTC_ASSERT(containerNode, return nullptr);
+ return rootItem()->findFirstLevelChild([containerNode](WrapperNode *node) {
+ return node->m_node == containerNode;
+ });
}
void FlatModel::loadExpandData()
diff --git a/src/plugins/projectexplorer/projectmodels.h b/src/plugins/projectexplorer/projectmodels.h
index b59e08e04f..18129a7ddc 100644
--- a/src/plugins/projectexplorer/projectmodels.h
+++ b/src/plugins/projectexplorer/projectmodels.h
@@ -90,7 +90,7 @@ private:
static const QLoggingCategory &logger();
- void update();
+ void updateSubtree(FolderNode *node);
void rebuildModel();
void addFolderNode(WrapperNode *parent, FolderNode *folderNode, QSet<Node *> *seen);
@@ -98,6 +98,9 @@ private:
void loadExpandData();
void saveExpandData();
void handleProjectAdded(Project *project);
+ void handleProjectRemoved(Project *project);
+ WrapperNode *nodeForProject(Project *project);
+ void addOrRebuildProjectModel(Project *project);
QTimer m_timer;
QSet<ExpandData> m_toExpand;
diff --git a/src/plugins/projectexplorer/projectnodes.cpp b/src/plugins/projectexplorer/projectnodes.cpp
index 45c78f72ca..8a04235ea6 100644
--- a/src/plugins/projectexplorer/projectnodes.cpp
+++ b/src/plugins/projectexplorer/projectnodes.cpp
@@ -215,14 +215,9 @@ bool Node::isEnabled() const
return parent ? parent->isEnabled() : true;
}
-QList<ProjectAction> Node::supportedActions(Node *node) const
+bool Node::supportsAction(ProjectAction, Node *) const
{
- if (FolderNode *folder = parentFolderNode()) {
- QList<ProjectAction> list = folder->supportedActions(node);
- list.append(InheritedFromParent);
- return list;
- }
- return {};
+ return false;
}
void Node::setEnabled(bool enabled)
@@ -364,6 +359,14 @@ QList<FileNode *> FileNode::scanForFiles(const Utils::FileName &directory,
return scanForFilesRecursively(directory, factory, visited, future, 0.0, 1000000.0);
}
+bool FileNode::supportsAction(ProjectAction action, Node *node) const
+{
+ if (action == InheritedFromParent)
+ return true;
+ FolderNode *parentFolder = parentFolderNode();
+ return parentFolder && parentFolder->supportsAction(action, node);
+}
+
/*!
\class ProjectExplorer::FolderNode
@@ -593,6 +596,14 @@ QString FolderNode::addFileFilter() const
return parentFolderNode()->addFileFilter();
}
+bool FolderNode::supportsAction(ProjectAction action, Node *node) const
+{
+ if (action == InheritedFromParent)
+ return true;
+ FolderNode *parentFolder = parentFolderNode();
+ return parentFolder && parentFolder->supportsAction(action, node);
+}
+
bool FolderNode::addFiles(const QStringList &filePaths, QStringList *notAdded)
{
ProjectNode *pn = managingProject();
@@ -762,6 +773,11 @@ bool ProjectNode::renameFile(const QString &filePath, const QString &newFilePath
return false;
}
+bool ProjectNode::supportsAction(ProjectAction, Node *) const
+{
+ return false;
+}
+
bool ProjectNode::deploysFolder(const QString &folder) const
{
Q_UNUSED(folder);
@@ -812,11 +828,10 @@ QString ContainerNode::displayName() const
return name;
}
-QList<ProjectAction> ContainerNode::supportedActions(Node *node) const
+bool ContainerNode::supportsAction(ProjectAction action, Node *node) const
{
- if (Node *rootNode = m_project->rootProjectNode())
- return rootNode->supportedActions(node);
- return {};
+ Node *rootNode = m_project->rootProjectNode();
+ return rootNode && rootNode->supportsAction(action, node);
}
ProjectNode *ContainerNode::rootProjectNode() const
diff --git a/src/plugins/projectexplorer/projectnodes.h b/src/plugins/projectexplorer/projectnodes.h
index 4ed5b4eb56..d82c02f53c 100644
--- a/src/plugins/projectexplorer/projectnodes.h
+++ b/src/plugins/projectexplorer/projectnodes.h
@@ -130,7 +130,7 @@ public:
virtual QString tooltip() const;
bool isEnabled() const;
- virtual QList<ProjectAction> supportedActions(Node *node) const;
+ virtual bool supportsAction(ProjectAction action, Node *node) const;
void setEnabled(bool enabled);
void setAbsoluteFilePathAndLine(const Utils::FileName &filePath, int line);
@@ -179,6 +179,7 @@ public:
static QList<FileNode *> scanForFiles(const Utils::FileName &directory,
const std::function<FileNode *(const Utils::FileName &fileName)> factory,
QFutureInterface<QList<FileNode *>> *future = nullptr);
+ bool supportsAction(ProjectAction action, Node *node) const override;
private:
FileType m_fileType;
@@ -225,6 +226,8 @@ public:
virtual QString addFileFilter() const;
+ bool supportsAction(ProjectAction action, Node *node) const override;
+
virtual bool addFiles(const QStringList &filePaths, QStringList *notAdded = 0);
virtual bool removeFiles(const QStringList &filePaths, QStringList *notRemoved = 0);
virtual bool deleteFiles(const QStringList &filePaths);
@@ -288,6 +291,7 @@ public:
bool deleteFiles(const QStringList &filePaths) override;
bool canRenameFile(const QString &filePath, const QString &newFilePath) override;
bool renameFile(const QString &filePath, const QString &newFilePath) override;
+ bool supportsAction(ProjectAction action, Node *node) const override;
// by default returns false
virtual bool deploysFolder(const QString &folder) const;
@@ -309,12 +313,13 @@ public:
ContainerNode(Project *project);
QString displayName() const final;
- QList<ProjectAction> supportedActions(Node *node) const final;
+ bool supportsAction(ProjectAction action, Node *node) const final;
ContainerNode *asContainerNode() final { return this; }
const ContainerNode *asContainerNode() const final { return this; }
ProjectNode *rootProjectNode() const;
+ Project *project() const { return m_project; }
private:
Project *m_project;
diff --git a/src/plugins/projectexplorer/projectwelcomepage.cpp b/src/plugins/projectexplorer/projectwelcomepage.cpp
index f7e442ed5e..9518891ece 100644
--- a/src/plugins/projectexplorer/projectwelcomepage.cpp
+++ b/src/plugins/projectexplorer/projectwelcomepage.cpp
@@ -56,6 +56,7 @@ using namespace Core;
using namespace Utils;
const int LINK_HEIGHT = 35;
+const int SESSION_LINE_HEIGHT = 30;
const char PROJECT_BASE_ID[] = "Welcome.OpenRecentProject";
namespace ProjectExplorer {
@@ -292,7 +293,7 @@ public:
if (isActiveSession && !isDefaultVirgin)
fullSessionName = ProjectWelcomePage::tr("%1 (current session)").arg(fullSessionName);
- const QRect switchRect = QRect(x, y, rc.width() - 24, firstBase + 3 - y);
+ const QRect switchRect = QRect(x, y, rc.width() - 24, SESSION_LINE_HEIGHT);
const bool switchActive = switchRect.contains(mousePos);
painter->setPen(linkColor);
painter->setFont(sizedFont(13, option.widget, switchActive));
@@ -350,7 +351,7 @@ public:
QSize sizeHint(const QStyleOptionViewItem &, const QModelIndex &idx) const final
{
- int h = 30;
+ int h = SESSION_LINE_HEIGHT;
QString sessionName = idx.data(Qt::DisplayRole).toString();
if (m_expandedSessions.contains(sessionName)) {
QStringList projects = SessionManager::projectsForSessionName(sessionName);
@@ -364,7 +365,7 @@ public:
{
if (ev->type() == QEvent::MouseButtonRelease) {
const QPoint pos = static_cast<QMouseEvent *>(ev)->pos();
- const QRect rc(option.rect.right() - 24, option.rect.top(), 24, 30);
+ const QRect rc(option.rect.right() - 24, option.rect.top(), 24, SESSION_LINE_HEIGHT);
const QString sessionName = idx.data(Qt::DisplayRole).toString();
if (rc.contains(pos)) {
// The expand/collapse "button".
diff --git a/src/plugins/projectexplorer/projectwindow.cpp b/src/plugins/projectexplorer/projectwindow.cpp
index b3ae4b85f9..88eac526e0 100644
--- a/src/plugins/projectexplorer/projectwindow.cpp
+++ b/src/plugins/projectexplorer/projectwindow.cpp
@@ -544,7 +544,7 @@ public:
QString dir = project->projectDirectory().toString();
QString importDir = QFileDialog::getExistingDirectory(ICore::mainWindow(),
- ProjectWindow::tr("Import directory"),
+ ProjectWindow::tr("Import Directory"),
dir);
FileName path = FileName::fromString(importDir);
diff --git a/src/plugins/projectexplorer/projectwizardpage.cpp b/src/plugins/projectexplorer/projectwizardpage.cpp
index 88756a3599..951f2b10fd 100644
--- a/src/plugins/projectexplorer/projectwizardpage.cpp
+++ b/src/plugins/projectexplorer/projectwizardpage.cpp
@@ -240,8 +240,7 @@ static inline AddNewTree *buildAddProjectTree(ProjectNode *root, const QString &
}
}
- const QList<ProjectAction> &list = root->supportedActions(root);
- if (list.contains(AddSubProject) && !list.contains(InheritedFromParent)) {
+ if (root->supportsAction(AddSubProject, root) && !root->supportsAction(InheritedFromParent, root)) {
if (projectPath.isEmpty() || root->canAddSubProject(projectPath)) {
FolderNode::AddNewInformation info = root->addNewInformation(QStringList() << projectPath, contextNode);
auto item = new AddNewTree(root, children, info);
@@ -265,8 +264,7 @@ static inline AddNewTree *buildAddFilesTree(FolderNode *root, const QStringList
children.append(child);
}
- const QList<ProjectAction> &list = root->supportedActions(root);
- if (list.contains(AddNewFile) && !list.contains(InheritedFromParent)) {
+ if (root->supportsAction(AddNewFile, root) && !root->supportsAction(InheritedFromParent, root)) {
FolderNode::AddNewInformation info = root->addNewInformation(files, contextNode);
auto item = new AddNewTree(root, children, info);
selector->inspect(item, root == contextNode);
diff --git a/src/plugins/projectexplorer/session.cpp b/src/plugins/projectexplorer/session.cpp
index 9286155bfb..5b8e6d382c 100644
--- a/src/plugins/projectexplorer/session.cpp
+++ b/src/plugins/projectexplorer/session.cpp
@@ -382,6 +382,8 @@ void SessionManager::addProject(Project *pro)
d->m_projects.append(pro);
connect(pro, &Project::fileListChanged, m_instance, &SessionManager::clearProjectFileCache);
+ connect(pro, &Project::displayNameChanged,
+ m_instance, [pro]() { m_instance->projectDisplayNameChanged(pro); });
emit m_instance->projectAdded(pro);
configureEditors(pro);
diff --git a/src/plugins/projectexplorer/sessiondialog.cpp b/src/plugins/projectexplorer/sessiondialog.cpp
index 53be179640..d3eba933c5 100644
--- a/src/plugins/projectexplorer/sessiondialog.cpp
+++ b/src/plugins/projectexplorer/sessiondialog.cpp
@@ -121,6 +121,7 @@ bool SessionNameInputDialog::isSwitchToRequested() const
SessionDialog::SessionDialog(QWidget *parent) : QDialog(parent)
{
m_ui.setupUi(this);
+ m_ui.sessionView->setActivationMode(Utils::DoubleClickActivation);
connect(m_ui.btCreateNew, &QAbstractButton::clicked,
m_ui.sessionView, &SessionView::createNewSession);
diff --git a/src/plugins/projectexplorer/sessionview.cpp b/src/plugins/projectexplorer/sessionview.cpp
index f08438d07b..374f6e0745 100644
--- a/src/plugins/projectexplorer/sessionview.cpp
+++ b/src/plugins/projectexplorer/sessionview.cpp
@@ -53,7 +53,7 @@ void RemoveItemFocusDelegate::paint(QPainter* painter, const QStyleOptionViewIte
}
SessionView::SessionView(QWidget *parent)
- : QTreeView(parent)
+ : Utils::TreeView(parent)
{
setItemDelegate(new RemoveItemFocusDelegate(this));
setSelectionBehavior(QAbstractItemView::SelectRows);
@@ -68,7 +68,7 @@ SessionView::SessionView(QWidget *parent)
selectionModel()->select(firstRow, QItemSelectionModel::QItemSelectionModel::
SelectCurrent);
- connect(this, &QTreeView::activated, [this](const QModelIndex &index){
+ connect(this, &Utils::TreeView::activated, [this](const QModelIndex &index){
emit activated(m_sessionModel.sessionAt(index.row()));
});
connect(selectionModel(), &QItemSelectionModel::currentRowChanged, [this]
@@ -133,7 +133,7 @@ void SessionView::selectSession(const QString &sessionName)
void SessionView::showEvent(QShowEvent *event)
{
- QTreeView::showEvent(event);
+ Utils::TreeView::showEvent(event);
selectActiveSession();
setFocus();
}
diff --git a/src/plugins/projectexplorer/sessionview.h b/src/plugins/projectexplorer/sessionview.h
index b43f703045..0f85e6ed21 100644
--- a/src/plugins/projectexplorer/sessionview.h
+++ b/src/plugins/projectexplorer/sessionview.h
@@ -27,13 +27,14 @@
#include "sessionmodel.h"
+#include <utils/itemviews.h>
+
#include <QAbstractTableModel>
-#include <QTreeView>
namespace ProjectExplorer {
namespace Internal {
-class SessionView : public QTreeView {
+class SessionView : public Utils::TreeView {
Q_OBJECT
public:
diff --git a/src/plugins/projectexplorer/targetsettingspanel.cpp b/src/plugins/projectexplorer/targetsettingspanel.cpp
index 65780a6d35..de40db6c66 100644
--- a/src/plugins/projectexplorer/targetsettingspanel.cpp
+++ b/src/plugins/projectexplorer/targetsettingspanel.cpp
@@ -442,7 +442,7 @@ public:
m_project->removeTarget(t);
});
- QMenu *copyMenu = menu->addMenu(tr("Copy Steps From Other Kit..."));
+ QMenu *copyMenu = menu->addMenu(tr("Copy Steps From Another Kit..."));
if (m_kitId.isValid() && m_project->target(m_kitId)) {
const QList<Kit *> kits = KitManager::kits();
for (Kit *kit : kits) {
diff --git a/src/plugins/pythoneditor/pythoneditorplugin.cpp b/src/plugins/pythoneditor/pythoneditorplugin.cpp
index 1e97696fb3..265212d39d 100644
--- a/src/plugins/pythoneditor/pythoneditorplugin.cpp
+++ b/src/plugins/pythoneditor/pythoneditorplugin.cpp
@@ -94,8 +94,6 @@ class PythonProject : public Project
public:
explicit PythonProject(const Utils::FileName &filename);
- QString displayName() const override;
-
bool addFiles(const QStringList &filePaths);
bool removeFiles(const QStringList &filePaths);
bool setFiles(const QStringList &filePaths);
@@ -122,11 +120,7 @@ public:
PythonProjectNode(PythonProject *project);
bool showInSimpleTree() const override;
-
- QList<ProjectAction> supportedActions(Node *node) const override;
-
QString addFileFilter() const override;
-
bool renameFile(const QString &filePath, const QString &newFilePath) override;
private:
@@ -381,11 +375,7 @@ PythonProject::PythonProject(const FileName &fileName) :
setId(PythonProjectId);
setProjectContext(Context(PythonProjectContext));
setProjectLanguages(Context(ProjectExplorer::Constants::CXX_LANGUAGE_ID));
-}
-
-QString PythonProject::displayName() const
-{
- return projectFilePath().toFileInfo().completeBaseName();
+ setDisplayName(fileName.toFileInfo().completeBaseName());
}
static QStringList readLines(const QString &absoluteFileName)
@@ -655,13 +645,6 @@ bool PythonProjectNode::showInSimpleTree() const
return true;
}
-QList<ProjectAction> PythonProjectNode::supportedActions(Node *node) const
-{
- Q_UNUSED(node);
- //return { AddNewFile, AddExistingFile, AddExistingDirectory, RemoveFile, Rename };
- return {};
-}
-
QString PythonProjectNode::addFileFilter() const
{
return QLatin1String("*.py");
diff --git a/src/plugins/qbsprojectmanager/defaultpropertyprovider.cpp b/src/plugins/qbsprojectmanager/defaultpropertyprovider.cpp
index f5a8ddb46d..84905e8f17 100644
--- a/src/plugins/qbsprojectmanager/defaultpropertyprovider.cpp
+++ b/src/plugins/qbsprojectmanager/defaultpropertyprovider.cpp
@@ -40,7 +40,6 @@
#include <qbs.h>
#include <ios/iosconstants.h>
-#include <qnx/qnxconstants.h>
#include <winrt/winrtconstants.h>
#include <QDir>
@@ -54,7 +53,6 @@ using namespace Constants;
namespace Internal {
using namespace ProjectExplorer::Constants;
using namespace Ios::Constants;
-using namespace Qnx::Constants;
using namespace WinRt::Internal::Constants;
static QString extractToolchainPrefix(QString *compilerName)
@@ -119,10 +117,11 @@ static QStringList targetOSList(const ProjectExplorer::Abi &abi, const ProjectEx
}
os << QLatin1String("bsd") << QLatin1String("unix");
break;
+ case ProjectExplorer::Abi::QnxOS:
+ os << QLatin1String("qnx") << QLatin1String("unix");
+ break;
case ProjectExplorer::Abi::UnixOS:
- if (device == QNX_QNX_OS_TYPE)
- os << QLatin1String("qnx");
- else if (abi.osFlavor() == ProjectExplorer::Abi::SolarisUnixFlavor)
+ if (abi.osFlavor() == ProjectExplorer::Abi::SolarisUnixFlavor)
os << QLatin1String("solaris");
os << QLatin1String("unix");
break;
diff --git a/src/plugins/qbsprojectmanager/qbsnodes.cpp b/src/plugins/qbsprojectmanager/qbsnodes.cpp
index 730c63ef7f..262145ec6d 100644
--- a/src/plugins/qbsprojectmanager/qbsnodes.cpp
+++ b/src/plugins/qbsprojectmanager/qbsnodes.cpp
@@ -45,6 +45,8 @@
#include <QIcon>
#include <QStyle>
+using namespace ProjectExplorer;
+
// ----------------------------------------------------------------------
// Helpers:
// ----------------------------------------------------------------------
@@ -223,20 +225,23 @@ public:
};
-static QList<ProjectExplorer::ProjectAction> supportedNodeActions(ProjectExplorer::Node *node,
- bool managesFiles)
+static bool supportsNodeAction(ProjectAction action, Node *node)
{
- QList<ProjectExplorer::ProjectAction> actions;
const QbsProject * const project = parentQbsProjectNode(node)->project();
if (!project->isProjectEditable())
- return actions;
- if (managesFiles)
- actions << ProjectExplorer::AddNewFile << ProjectExplorer::AddExistingFile;
- if (node->nodeType() == ProjectExplorer::NodeType::File
- && !project->qbsProject().buildSystemFiles().contains(node->filePath().toString())) {
- actions << ProjectExplorer::RemoveFile << ProjectExplorer::Rename;
+ return false;
+
+ auto equalsNodeFilePath = [node](const QString &str)
+ {
+ return str == node->filePath().toString();
+ };
+
+ if (action == RemoveFile || action == Rename) {
+ if (node->nodeType() == ProjectExplorer::NodeType::File)
+ return !Utils::contains(project->qbsProject().buildSystemFiles(), equalsNodeFilePath);
}
- return actions;
+
+ return false;
}
// ----------------------------------------------------------------------
@@ -265,9 +270,9 @@ QbsFolderNode::QbsFolderNode(const Utils::FileName &folderPath, ProjectExplorer:
{
}
-QList<ProjectExplorer::ProjectAction> QbsFolderNode::supportedActions(ProjectExplorer::Node *node) const
+bool QbsFolderNode::supportsAction(ProjectAction action, Node *node) const
{
- return supportedNodeActions(node, false);
+ return supportsNodeAction(action, node);
}
// ---------------------------------------------------------------------------
@@ -283,12 +288,6 @@ bool QbsBaseProjectNode::showInSimpleTree() const
return false;
}
-QList<ProjectExplorer::ProjectAction> QbsBaseProjectNode::supportedActions(ProjectExplorer::Node *node) const
-{
- Q_UNUSED(node);
- return QList<ProjectExplorer::ProjectAction>();
-}
-
// --------------------------------------------------------------------
// QbsGroupNode:
// --------------------------------------------------------------------
@@ -303,9 +302,12 @@ QbsGroupNode::QbsGroupNode(const qbs::GroupData &grp, const QString &productPath
m_qbsGroupData = grp;
}
-QList<ProjectExplorer::ProjectAction> QbsGroupNode::supportedActions(ProjectExplorer::Node *node) const
+bool QbsGroupNode::supportsAction(ProjectAction action, Node *node) const
{
- return supportedNodeActions(node, true);
+ if (action == AddNewFile || action == AddExistingFile)
+ return true;
+
+ return supportsNodeAction(action, node);
}
bool QbsGroupNode::addFiles(const QStringList &filePaths, QStringList *notAdded)
@@ -382,9 +384,12 @@ bool QbsProductNode::showInSimpleTree() const
return true;
}
-QList<ProjectExplorer::ProjectAction> QbsProductNode::supportedActions(ProjectExplorer::Node *node) const
+bool QbsProductNode::supportsAction(ProjectAction action, Node *node) const
{
- return supportedNodeActions(node, true);
+ if (action == AddNewFile || action == AddExistingFile)
+ return true;
+
+ return supportsNodeAction(action, node);
}
bool QbsProductNode::addFiles(const QStringList &filePaths, QStringList *notAdded)
diff --git a/src/plugins/qbsprojectmanager/qbsnodes.h b/src/plugins/qbsprojectmanager/qbsnodes.h
index 313fa2a6ff..904851bc81 100644
--- a/src/plugins/qbsprojectmanager/qbsnodes.h
+++ b/src/plugins/qbsprojectmanager/qbsnodes.h
@@ -55,7 +55,7 @@ public:
const QString &displayName);
private:
- QList<ProjectExplorer::ProjectAction> supportedActions(ProjectExplorer::Node *node) const override;
+ bool supportsAction(ProjectExplorer::ProjectAction action, Node *node) const final;
};
// ---------------------------------------------------------------------------
@@ -70,10 +70,6 @@ public:
explicit QbsBaseProjectNode(const Utils::FileName &absoluteFilePath);
bool showInSimpleTree() const override;
-
- QList<ProjectExplorer::ProjectAction> supportedActions(Node *node) const override;
-private:
- friend class QbsGroupNode;
};
// --------------------------------------------------------------------
@@ -85,7 +81,7 @@ class QbsGroupNode : public QbsBaseProjectNode
public:
QbsGroupNode(const qbs::GroupData &grp, const QString &productPath);
- QList<ProjectExplorer::ProjectAction> supportedActions(Node *node) const override;
+ bool supportsAction(ProjectExplorer::ProjectAction action, Node *node) const final;
bool addFiles(const QStringList &filePaths, QStringList *notAdded = 0) override;
bool removeFiles(const QStringList &filePaths, QStringList *notRemoved = 0) override;
bool renameFile(const QString &filePath, const QString &newFilePath) override;
@@ -107,7 +103,7 @@ public:
explicit QbsProductNode(const qbs::ProductData &prd);
bool showInSimpleTree() const override;
- QList<ProjectExplorer::ProjectAction> supportedActions(Node *node) const override;
+ bool supportsAction(ProjectExplorer::ProjectAction action, Node *node) const final;
bool addFiles(const QStringList &filePaths, QStringList *notAdded = 0) override;
bool removeFiles(const QStringList &filePaths, QStringList *notRemoved = 0) override;
bool renameFile(const QString &filePath, const QString &newFilePath) override;
diff --git a/src/plugins/qbsprojectmanager/qbsnodetreebuilder.cpp b/src/plugins/qbsprojectmanager/qbsnodetreebuilder.cpp
index 1f2d1dc445..db80627f68 100644
--- a/src/plugins/qbsprojectmanager/qbsnodetreebuilder.cpp
+++ b/src/plugins/qbsprojectmanager/qbsnodetreebuilder.cpp
@@ -133,6 +133,10 @@ buildProductNodeTree(const qbs::Project &project, const qbs::ProductData &prd)
void setupProjectNode(QbsProjectManager::Internal::QbsProjectNode *node, const qbs::ProjectData &prjData,
const qbs::Project &qbsProject)
{
+ using namespace QbsProjectManager::Internal;
+ node->addNode(new QbsFileNode(Utils::FileName::fromString(prjData.location().filePath()),
+ ProjectExplorer::FileType::Project, false,
+ prjData.location().line()));
foreach (const qbs::ProjectData &subData, prjData.subProjects()) {
auto subProject =
new QbsProjectManager::Internal::QbsProjectNode(
@@ -169,9 +173,16 @@ QSet<QString> referencedBuildSystemFiles(const qbs::ProjectData &data)
QStringList unreferencedBuildSystemFiles(const qbs::Project &p)
{
- return p.isValid()
- ? p.buildSystemFiles().subtract(referencedBuildSystemFiles(p.projectData())).toList()
- : QStringList();
+ QStringList result;
+ if (!p.isValid())
+ return result;
+
+ const std::set<QString> &available = p.buildSystemFiles();
+ QList<QString> referenced = referencedBuildSystemFiles(p.projectData()).toList();
+ Utils::sort(referenced);
+ std::set_difference(available.begin(), available.end(), referenced.begin(), referenced.end(),
+ std::back_inserter(result));
+ return result;
}
} // namespace
@@ -182,9 +193,7 @@ namespace Internal {
QbsRootProjectNode *QbsNodeTreeBuilder::buildTree(QbsProject *project)
{
auto root = new QbsRootProjectNode(project);
- root->addNode(new ProjectExplorer::FileNode(project->projectFilePath(),
- ProjectExplorer::FileType::Project, false));
-
+ setupProjectNode(root, project->qbsProjectData(), project->qbsProject());
auto buildSystemFiles
= new ProjectExplorer::FolderNode(project->projectDirectory(),
ProjectExplorer::NodeType::Folder,
@@ -194,12 +203,11 @@ QbsRootProjectNode *QbsNodeTreeBuilder::buildTree(QbsProject *project)
for (const QString &f : unreferencedBuildSystemFiles(project->qbsProject())) {
const Utils::FileName filePath = Utils::FileName::fromString(f);
if (filePath.isChildOf(base))
- root->addNestedNode(new ProjectExplorer::FileNode(filePath, ProjectExplorer::FileType::Project, false));
+ buildSystemFiles->addNestedNode(new ProjectExplorer::FileNode(filePath, ProjectExplorer::FileType::Project, false));
}
buildSystemFiles->compress();
root->addNode(buildSystemFiles);
- setupProjectNode(root, project->qbsProjectData(), project->qbsProject());
return root;
}
diff --git a/src/plugins/qbsprojectmanager/qbsproject.cpp b/src/plugins/qbsprojectmanager/qbsproject.cpp
index 9bdd11a611..33c5117765 100644
--- a/src/plugins/qbsprojectmanager/qbsproject.cpp
+++ b/src/plugins/qbsprojectmanager/qbsproject.cpp
@@ -133,6 +133,8 @@ QbsProject::QbsProject(const FileName &fileName) :
setProjectContext(Context(Constants::PROJECT_ID));
setProjectLanguages(Context(ProjectExplorer::Constants::CXX_LANGUAGE_ID));
+ setDisplayName(fileName.toFileInfo().completeBaseName());
+
connect(this, &Project::activeTargetChanged, this, &QbsProject::changeActiveTarget);
connect(this, &Project::addedTarget, this, &QbsProject::targetWasAdded);
connect(this, &Project::removedTarget, this, &QbsProject::targetWasRemoved);
@@ -159,11 +161,6 @@ QbsProject::~QbsProject()
qDeleteAll(m_extraCompilers);
}
-QString QbsProject::displayName() const
-{
- return projectFilePath().toFileInfo().completeBaseName();
-}
-
QbsRootProjectNode *QbsProject::rootProjectNode() const
{
return static_cast<QbsRootProjectNode *>(Project::rootProjectNode());
@@ -434,12 +431,20 @@ bool QbsProject::checkCancelStatus()
return true;
}
+static QSet<QString> toQStringSet(const std::set<QString> &src)
+{
+ QSet<QString> result;
+ result.reserve(int(src.size()));
+ std::copy(src.begin(), src.end(), Utils::inserter(result));
+ return result;
+}
+
void QbsProject::updateAfterParse()
{
qCDebug(qbsPmLog) << "Updating data after parse";
OpTimer opTimer("updateAfterParse");
updateProjectNodes();
- updateDocuments(m_qbsProject.buildSystemFiles());
+ updateDocuments(toQStringSet(m_qbsProject.buildSystemFiles()));
updateBuildTargetData();
updateCppCodeModel();
updateQmlJsCodeModel();
diff --git a/src/plugins/qbsprojectmanager/qbsproject.h b/src/plugins/qbsprojectmanager/qbsproject.h
index 6c787ef449..ea987fd36a 100644
--- a/src/plugins/qbsprojectmanager/qbsproject.h
+++ b/src/plugins/qbsprojectmanager/qbsproject.h
@@ -61,7 +61,6 @@ public:
explicit QbsProject(const Utils::FileName &filename);
~QbsProject() override;
- QString displayName() const override;
QbsRootProjectNode *rootProjectNode() const override;
QStringList filesGeneratedFrom(const QString &sourceFile) const override;
diff --git a/src/plugins/qmakeandroidsupport/createandroidmanifestwizard.cpp b/src/plugins/qmakeandroidsupport/createandroidmanifestwizard.cpp
index f1cf7cbdae..4140f038bc 100644
--- a/src/plugins/qmakeandroidsupport/createandroidmanifestwizard.cpp
+++ b/src/plugins/qmakeandroidsupport/createandroidmanifestwizard.cpp
@@ -328,10 +328,13 @@ void CreateAndroidManifestWizard::createAndroidTemplateFiles()
FileName::fromString(m_directory),
0, [this, &addedFiles](QFileInfo src, QFileInfo dst, QString *){return copy(src, dst, &addedFiles);});
- if (m_copyGradle)
- FileUtils::copyRecursively(AndroidConfigurations::currentConfig().sdkLocation().appendPath(QLatin1String("/tools/templates/gradle/wrapper")),
- FileName::fromString(m_directory),
+ if (m_copyGradle) {
+ FileName gradlePath = FileName::fromString(version->qmakeProperty("QT_INSTALL_PREFIX").append(QLatin1String("/src/3rdparty/gradle")));
+ if (!gradlePath.exists())
+ gradlePath = AndroidConfigurations::currentConfig().sdkLocation().appendPath(QLatin1String("/tools/templates/gradle/wrapper"));
+ FileUtils::copyRecursively(gradlePath, FileName::fromString(m_directory),
0, [this, &addedFiles](QFileInfo src, QFileInfo dst, QString *){return copy(src, dst, &addedFiles);});
+ }
AndroidManager::updateGradleProperties(m_target);
}
diff --git a/src/plugins/qmakeandroidsupport/qmakeandroidbuildapkstep.cpp b/src/plugins/qmakeandroidsupport/qmakeandroidbuildapkstep.cpp
index c336329c9c..ce087ff9df 100644
--- a/src/plugins/qmakeandroidsupport/qmakeandroidbuildapkstep.cpp
+++ b/src/plugins/qmakeandroidsupport/qmakeandroidbuildapkstep.cpp
@@ -182,13 +182,6 @@ bool QmakeAndroidBuildApkStep::init(QList<const BuildStep *> &earlierSteps)
QStringList argumentsPasswordConcealed = arguments;
- if (version->qtVersion() >= QtSupport::QtVersionNumber(5, 6, 0)) {
- if (bc->buildType() == ProjectExplorer::BuildConfiguration::Debug)
- arguments << QLatin1String("--gdbserver");
- else
- arguments << QLatin1String("--no-gdbserver");
- }
-
if (m_signPackage) {
arguments << QLatin1String("--sign")
<< m_keystorePath.toString()
@@ -206,6 +199,15 @@ bool QmakeAndroidBuildApkStep::init(QList<const BuildStep *> &earlierSteps)
}
+ // Must be the last option, otherwise androiddeployqt might use the other
+ // params (e.g. --sign) to choose not to add gdbserver
+ if (version->qtVersion() >= QtSupport::QtVersionNumber(5, 6, 0)) {
+ if (m_addDebugger || bc->buildType() == ProjectExplorer::BuildConfiguration::Debug)
+ arguments << QLatin1String("--gdbserver");
+ else
+ arguments << QLatin1String("--no-gdbserver");
+ }
+
ProjectExplorer::ProcessParameters *pp = processParameters();
setupProcessParameters(pp, bc, arguments, command);
diff --git a/src/plugins/qmakeprojectmanager/desktopqmakerunconfiguration.cpp b/src/plugins/qmakeprojectmanager/desktopqmakerunconfiguration.cpp
index 88c6b3f78a..2c9ea0dd02 100644
--- a/src/plugins/qmakeprojectmanager/desktopqmakerunconfiguration.cpp
+++ b/src/plugins/qmakeprojectmanager/desktopqmakerunconfiguration.cpp
@@ -344,8 +344,8 @@ bool DesktopQmakeRunConfiguration::fromMap(const QVariantMap &map)
QString DesktopQmakeRunConfiguration::executable() const
{
- if (QmakeProFileNode *node = projectNode())
- return extractWorkingDirAndExecutable(node).second;
+ if (QmakeProFile *pro = proFile())
+ return extractWorkingDirAndExecutable(pro).second;
return QString();
}
@@ -377,18 +377,18 @@ void DesktopQmakeRunConfiguration::setUsingLibrarySearchPath(bool state)
QString DesktopQmakeRunConfiguration::baseWorkingDirectory() const
{
- if (QmakeProFileNode *node = projectNode())
- return extractWorkingDirAndExecutable(node).first;
+ if (QmakeProFile *pro = proFile())
+ return extractWorkingDirAndExecutable(pro).first;
return QString();
}
bool DesktopQmakeRunConfiguration::isConsoleApplication() const
{
- if (QmakeProFileNode *node = projectNode()) {
- const QStringList config = node->variableValue(Variable::Config);
+ if (QmakeProFile *pro = proFile()) {
+ const QStringList config = pro->variableValue(Variable::Config);
if (!config.contains("console") || config.contains("testcase"))
return false;
- const QStringList qt = node->variableValue(Variable::Qt);
+ const QStringList qt = pro->variableValue(Variable::Qt);
return !qt.contains("testlib") && !qt.contains("qmltest");
}
return false;
@@ -402,11 +402,11 @@ void DesktopQmakeRunConfiguration::addToBaseEnvironment(Environment &env) const
// The user could be linking to a library found via a -L/some/dir switch
// to find those libraries while actually running we explicitly prepend those
// dirs to the library search path
- const QmakeProFileNode *node = projectNode();
- if (m_isUsingLibrarySearchPath && node) {
- const QStringList libDirectories = node->variableValue(Variable::LibDirectories);
+ const QmakeProFile *pro = proFile();
+ if (m_isUsingLibrarySearchPath && pro) {
+ const QStringList libDirectories = pro->variableValue(Variable::LibDirectories);
if (!libDirectories.isEmpty()) {
- const QString proDirectory = node->buildDir();
+ const QString proDirectory = pro->buildDir().toString();
foreach (QString dir, libDirectories) {
// Fix up relative entries like "LIBS+=-L.."
const QFileInfo fi(dir);
@@ -415,7 +415,7 @@ void DesktopQmakeRunConfiguration::addToBaseEnvironment(Environment &env) const
env.prependOrSetLibrarySearchPath(dir);
} // foreach
} // libDirectories
- } // node
+ } // pro
QtSupport::BaseQtVersion *qtVersion = QtSupport::QtKitInformation::qtVersion(target()->kit());
if (qtVersion && m_isUsingLibrarySearchPath)
@@ -437,20 +437,18 @@ QmakeProject *DesktopQmakeRunConfiguration::qmakeProject() const
return static_cast<QmakeProject *>(target()->project());
}
-QmakeProFileNode *DesktopQmakeRunConfiguration::projectNode() const
+QmakeProFile *DesktopQmakeRunConfiguration::proFile() const
{
QmakeProject *project = qmakeProject();
QTC_ASSERT(project, return nullptr);
- QmakeProFileNode *rootNode = project->rootProjectNode();
- if (!rootNode)
- return nullptr;
- return rootNode->findProFileFor(m_proFilePath);
+ QmakeProFile *rootProFile = project->rootProFile();
+ return rootProFile ? rootProFile->findProFile(m_proFilePath) : nullptr;
}
QString DesktopQmakeRunConfiguration::defaultDisplayName()
{
- if (QmakeProFileNode *node = projectNode())
- return node->displayName();
+ if (QmakeProFile *pro = proFile())
+ return pro->displayName();
QString defaultName;
if (!m_proFilePath.isEmpty())
@@ -465,19 +463,16 @@ OutputFormatter *DesktopQmakeRunConfiguration::createOutputFormatter() const
return new QtSupport::QtOutputFormatter(target()->project());
}
-QPair<QString, QString> DesktopQmakeRunConfiguration::extractWorkingDirAndExecutable(const QmakeProFileNode *node) const
+QPair<QString, QString> DesktopQmakeRunConfiguration::extractWorkingDirAndExecutable(const QmakeProFile *proFile) const
{
- if (!node)
- return { };
+ if (!proFile)
+ return {};
- QmakeProFile *pro = node->proFile();
- QTC_ASSERT(pro, return { });
-
- TargetInformation ti = pro->targetInformation();
+ TargetInformation ti = proFile->targetInformation();
if (!ti.valid)
return qMakePair(QString(), QString());
- const QStringList &config = pro->variableValue(Variable::Config);
+ const QStringList &config = proFile->variableValue(Variable::Config);
QString destDir = ti.destDir.toString();
QString workingDir;
diff --git a/src/plugins/qmakeprojectmanager/desktopqmakerunconfiguration.h b/src/plugins/qmakeprojectmanager/desktopqmakerunconfiguration.h
index d32cd008a5..18ece5ecd4 100644
--- a/src/plugins/qmakeprojectmanager/desktopqmakerunconfiguration.h
+++ b/src/plugins/qmakeprojectmanager/desktopqmakerunconfiguration.h
@@ -98,12 +98,12 @@ protected:
bool fromMap(const QVariantMap &map) override;
private:
- QPair<QString, QString> extractWorkingDirAndExecutable(const QmakeProFileNode *node) const;
+ QPair<QString, QString> extractWorkingDirAndExecutable(const QmakeProFile *proFile) const;
QString baseWorkingDirectory() const;
QString defaultDisplayName();
bool isConsoleApplication() const;
QmakeProject *qmakeProject() const;
- QmakeProFileNode *projectNode() const;
+ QmakeProFile *proFile() const;
void ctor();
diff --git a/src/plugins/qmakeprojectmanager/qmakenodes.cpp b/src/plugins/qmakeprojectmanager/qmakenodes.cpp
index b2ea316330..98c0cae52e 100644
--- a/src/plugins/qmakeprojectmanager/qmakenodes.cpp
+++ b/src/plugins/qmakeprojectmanager/qmakenodes.cpp
@@ -74,9 +74,13 @@ QmakeProFileNode *QmakePriFileNode::proFileNode() const
return m_qmakeProFileNode;
}
-QList<ProjectAction> QmakePriFileNode::supportedActions(Node *node) const
+bool QmakePriFileNode::supportsAction(ProjectAction action, Node *node) const
{
- QList<ProjectAction> actions;
+ if (action == Rename || action == DuplicateFile) {
+ FileNode *fileNode = node->asFileNode();
+ return (fileNode && fileNode->fileType() != FileType::Project)
+ || dynamic_cast<ResourceEditor::ResourceTopLevelNode *>(node);
+ }
const FolderNode *folderNode = this;
const QmakeProFileNode *proFileNode;
@@ -93,12 +97,12 @@ QList<ProjectAction> QmakePriFileNode::supportedActions(Node *node) const
// TODO: Some of the file types don't make much sense for aux
// projects (e.g. cpp). It'd be nice if the "add" action could
// work on a subset of the file types according to project type.
-
- actions << AddNewFile;
- if (pro && pro->knowsFile(node->filePath()))
- actions << EraseFile;
- else
- actions << RemoveFile;
+ if (action == AddNewFile)
+ return true;
+ if (action == EraseFile)
+ return pro && pro->knowsFile(node->filePath());
+ if (action == RemoveFile)
+ return !(pro && pro->knowsFile(node->filePath()));
bool addExistingFiles = true;
if (node->nodeType() == NodeType::VirtualFolder) {
@@ -115,31 +119,26 @@ QList<ProjectAction> QmakePriFileNode::supportedActions(Node *node) const
addExistingFiles = addExistingFiles && !deploysFolder(node->filePath().toString());
- if (addExistingFiles)
- actions << AddExistingFile << AddExistingDirectory;
+ if (action == AddExistingFile || action == AddExistingDirectory)
+ return addExistingFiles;
break;
}
case ProjectType::SubDirsTemplate:
- actions << AddSubProject << RemoveSubProject;
+ if (action == AddSubProject || action == RemoveSubProject)
+ return true;
break;
default:
break;
}
- FileNode *fileNode = node->asFileNode();
- if ((fileNode && fileNode->fileType() != FileType::Project)
- || dynamic_cast<ResourceEditor::ResourceTopLevelNode *>(node)) {
- actions << Rename;
- actions << DuplicateFile;
+ if (action == HasSubProjectRunConfigurations) {
+ Target *target = m_project->activeTarget();
+ QmakeRunConfigurationFactory *factory = QmakeRunConfigurationFactory::find(target);
+ return factory && !factory->runConfigurationsForNode(target, node).isEmpty();
}
- Target *target = m_project->activeTarget();
- QmakeRunConfigurationFactory *factory = QmakeRunConfigurationFactory::find(target);
- if (factory && !factory->runConfigurationsForNode(target, node).isEmpty())
- actions << HasSubProjectRunConfigurations;
-
- return actions;
+ return false;
}
bool QmakePriFileNode::canAddSubProject(const QString &proFilePath) const
diff --git a/src/plugins/qmakeprojectmanager/qmakenodes.h b/src/plugins/qmakeprojectmanager/qmakenodes.h
index b04751809a..719e42a05a 100644
--- a/src/plugins/qmakeprojectmanager/qmakenodes.h
+++ b/src/plugins/qmakeprojectmanager/qmakenodes.h
@@ -47,7 +47,7 @@ public:
QmakePriFile *priFile() const;
// ProjectNode interface
- QList<ProjectExplorer::ProjectAction> supportedActions(Node *node) const override;
+ bool supportsAction(ProjectExplorer::ProjectAction action, Node *node) const override;
bool showInSimpleTree() const override { return false; }
diff --git a/src/plugins/qmakeprojectmanager/qmakeproject.cpp b/src/plugins/qmakeprojectmanager/qmakeproject.cpp
index d2ce349211..b335fc2484 100644
--- a/src/plugins/qmakeprojectmanager/qmakeproject.cpp
+++ b/src/plugins/qmakeprojectmanager/qmakeproject.cpp
@@ -74,6 +74,8 @@ using namespace Utils;
namespace QmakeProjectManager {
namespace Internal {
+const int UPDATE_INTERVAL = 3000;
+
/// Watches folders for QmakePriFile nodes
/// use one file system watcher to watch all folders
/// such minimizing system ressouce usage
@@ -167,12 +169,13 @@ QmakeProject::QmakeProject(const FileName &fileName) :
setProjectContext(Core::Context(QmakeProjectManager::Constants::PROJECT_ID));
setProjectLanguages(Core::Context(ProjectExplorer::Constants::CXX_LANGUAGE_ID));
setRequiredKitPredicate(QtSupport::QtKitInformation::qtVersionPredicate());
+ setDisplayName(fileName.toFileInfo().completeBaseName());
const QTextCodec *codec = Core::EditorManager::defaultTextCodec();
m_qmakeVfs->setTextCodec(codec);
m_asyncUpdateTimer.setSingleShot(true);
- m_asyncUpdateTimer.setInterval(3000);
+ m_asyncUpdateTimer.setInterval(UPDATE_INTERVAL);
connect(&m_asyncUpdateTimer, &QTimer::timeout, this, &QmakeProject::asyncUpdate);
m_rootProFile = std::make_unique<QmakeProFile>(this, projectFilePath());
@@ -480,7 +483,8 @@ void QmakeProject::scheduleAsyncUpdate(QmakeProFile::AsyncUpdateDelay delay)
void QmakeProject::startAsyncTimer(QmakeProFile::AsyncUpdateDelay delay)
{
m_asyncUpdateTimer.stop();
- m_asyncUpdateTimer.setInterval(qMin(m_asyncUpdateTimer.interval(), delay == QmakeProFile::ParseLater ? 3000 : 0));
+ m_asyncUpdateTimer.setInterval(qMin(m_asyncUpdateTimer.interval(),
+ delay == QmakeProFile::ParseLater ? UPDATE_INTERVAL : 0));
m_asyncUpdateTimer.start();
}
@@ -533,7 +537,7 @@ bool QmakeProject::wasEvaluateCanceled()
void QmakeProject::asyncUpdate()
{
- m_asyncUpdateTimer.setInterval(3000);
+ m_asyncUpdateTimer.setInterval(UPDATE_INTERVAL);
m_qmakeVfs->invalidateCache();
@@ -572,11 +576,6 @@ bool QmakeProject::supportsKit(Kit *k, QString *errorMessage) const
return version;
}
-QString QmakeProject::displayName() const
-{
- return projectFilePath().toFileInfo().completeBaseName();
-}
-
// Find the folder that contains a file with a certain name (recurse down)
static FolderNode *folderOf(FolderNode *in, const FileName &fileName)
{
@@ -1215,14 +1214,15 @@ void QmakeProject::collectLibraryData(const QmakeProFile *file, DeploymentData &
QString version = file->singleVariableValue(Variable::Version);
if (version.isEmpty())
version = QLatin1String("1.0.0");
+ QStringList versionComponents = version.split('.');
+ while (versionComponents.size() < 3)
+ versionComponents << QLatin1String("0");
targetFileName += QLatin1Char('.');
- while (true) {
+ while (!versionComponents.isEmpty()) {
+ const QString versionString = versionComponents.join(QLatin1Char('.'));
deploymentData.addFile(destDirFor(ti).toString() + '/'
- + targetFileName + version, targetPath);
- const QString tmpVersion = version.left(version.lastIndexOf(QLatin1Char('.')));
- if (tmpVersion == version)
- break;
- version = tmpVersion;
+ + targetFileName + versionString, targetPath);
+ versionComponents.removeLast();
}
}
}
diff --git a/src/plugins/qmakeprojectmanager/qmakeproject.h b/src/plugins/qmakeprojectmanager/qmakeproject.h
index 2f4fb8a427..590fe4f46e 100644
--- a/src/plugins/qmakeprojectmanager/qmakeproject.h
+++ b/src/plugins/qmakeprojectmanager/qmakeproject.h
@@ -65,8 +65,6 @@ public:
QmakeProFile *rootProFile() const;
- QString displayName() const final;
-
bool supportsKit(ProjectExplorer::Kit *k, QString *errorMesage) const final;
QmakeProFileNode *rootProjectNode() const final;
diff --git a/src/plugins/qmldesigner/components/componentcore/componentcore_constants.h b/src/plugins/qmldesigner/components/componentcore/componentcore_constants.h
index 61af942312..6b0015f082 100644
--- a/src/plugins/qmldesigner/components/componentcore/componentcore_constants.h
+++ b/src/plugins/qmldesigner/components/componentcore/componentcore_constants.h
@@ -70,7 +70,7 @@ const char moveToComponentCommandId[] = "MoveToComponent";
const char addItemToStackedContainerCommandId[] = "AddItemToStackedContainer";
const char addTabBarToStackedContainerCommandId[] = "AddTabBarToStackedContainer";
const char increaseIndexOfStackedContainerCommandId[] = "IncreaseIndexOfStackedContainer";
-const char decreaseIndexOfStackedContainerCommandId[] = "decreaseIndexOfStackedContainer";
+const char decreaseIndexOfStackedContainerCommandId[] = "DecreaseIndexOfStackedContainer";
const char selectionCategoryDisplayName[] = QT_TRANSLATE_NOOP("QmlDesignerContextMenu", "Selection");
const char stackCategoryDisplayName[] = QT_TRANSLATE_NOOP("QmlDesignerContextMenu", "Stack (z)");
diff --git a/src/plugins/qmldesigner/components/componentcore/modelnodeoperations.cpp b/src/plugins/qmldesigner/components/componentcore/modelnodeoperations.cpp
index 9375f40503..da2aeb6641 100644
--- a/src/plugins/qmldesigner/components/componentcore/modelnodeoperations.cpp
+++ b/src/plugins/qmldesigner/components/componentcore/modelnodeoperations.cpp
@@ -898,7 +898,7 @@ void static setIndexProperty(const AbstractProperty &property, const QVariant &v
const QString propertyName = QString::fromUtf8(property.name());
- QString title = QCoreApplication::translate("ModelNodeOperations", "Cannot set property %1.").arg(propertyName);
+ QString title = QCoreApplication::translate("ModelNodeOperations", "Cannot Set Property %1").arg(propertyName);
QString description = QCoreApplication::translate("ModelNodeOperations", "The property %1 is bound to an expression.").arg(propertyName);
Core::AsynchronousMessageBox::warning(title, description);
}
diff --git a/src/plugins/qmldesigner/components/importmanager/importmanagercombobox.cpp b/src/plugins/qmldesigner/components/importmanager/importmanagercombobox.cpp
index e2204cae32..b703f780c8 100644
--- a/src/plugins/qmldesigner/components/importmanager/importmanagercombobox.cpp
+++ b/src/plugins/qmldesigner/components/importmanager/importmanagercombobox.cpp
@@ -27,11 +27,15 @@
#include <utils/fileutils.h>
+#include <QStyle>
+#include <QStyleFactory>
#include <QStylePainter>
ImportManagerComboBox::ImportManagerComboBox(QWidget *parent) :
QComboBox(parent)
{
+ QStyle *style = QStyleFactory::create("fusion");
+ setStyle(style);
setStyleSheet(QString::fromUtf8(Utils::FileReader::fetchQrc(QLatin1String(":/importmanager/importmanager.css"))));
setToolTip(tr("Add new import"));
}
diff --git a/src/plugins/qmldesigner/components/navigator/navigatortreemodel.cpp b/src/plugins/qmldesigner/components/navigator/navigatortreemodel.cpp
index 6f8968cda2..3a0a602b5b 100644
--- a/src/plugins/qmldesigner/components/navigator/navigatortreemodel.cpp
+++ b/src/plugins/qmldesigner/components/navigator/navigatortreemodel.cpp
@@ -380,6 +380,7 @@ void NavigatorTreeModel::updateItemRow(const ModelNode &modelNode, ItemRow items
items.idItem->setToolTip(QString::fromUtf8(modelNode.type()));
else
items.idItem->setToolTip(msgUnknownItem(QString::fromUtf8(modelNode.type())));
+ items.idItem->setIcon(getTypeIcon(modelNode));
}
blockItemChangedSignal(blockSignal);
diff --git a/src/plugins/qmldesigner/components/texteditor/texteditorwidget.cpp b/src/plugins/qmldesigner/components/texteditor/texteditorwidget.cpp
index b7f20e77a2..9ac4a66aaf 100644
--- a/src/plugins/qmldesigner/components/texteditor/texteditorwidget.cpp
+++ b/src/plugins/qmldesigner/components/texteditor/texteditorwidget.cpp
@@ -40,6 +40,7 @@
#include <coreplugin/editormanager/editormanager.h>
#include <QEvent>
+#include <QScrollBar>
#include <QVBoxLayout>
#include <vector>
@@ -61,7 +62,6 @@ TextEditorWidget::TextEditorWidget(TextEditorView *textEditorView)
m_updateSelectionTimer.setInterval(200);
connect(&m_updateSelectionTimer, &QTimer::timeout, this, &TextEditorWidget::updateSelectionByCursorPosition);
- setStyleSheet(Theme::replaceCssColors(QString::fromUtf8(Utils::FileReader::fetchQrc(QLatin1String(":/qmldesigner/scrollbar.css")))));
}
void TextEditorWidget::setTextEditor(TextEditor::BaseTextEditor *textEditor)
@@ -85,6 +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"))));
+ textEditor->editorWidget()->verticalScrollBar()->setStyleSheet(styleSheet);
+ textEditor->editorWidget()->horizontalScrollBar()->setStyleSheet(styleSheet);
}
if (oldEditor)
diff --git a/src/plugins/qmldesigner/designercore/include/rewriterview.h b/src/plugins/qmldesigner/designercore/include/rewriterview.h
index 53f4045264..b99a9815bd 100644
--- a/src/plugins/qmldesigner/designercore/include/rewriterview.h
+++ b/src/plugins/qmldesigner/designercore/include/rewriterview.h
@@ -116,6 +116,8 @@ public:
void clearErrorAndWarnings();
void setErrors(const QList<DocumentMessage> &errors);
void setWarnings(const QList<DocumentMessage> &warnings);
+ void setIncompleteTypeInformation(bool b);
+ bool hasIncompleteTypeInformation() const;
void addError(const DocumentMessage &error);
void enterErrorState(const QString &errorMessage);
@@ -195,6 +197,7 @@ private: //variables
QTimer m_amendTimer;
bool m_instantQmlTextUpdate = false;
std::function<void(bool)> m_setWidgetStatusCallback;
+ bool m_hasIncompleteTypeInformation = false;
};
} //QmlDesigner
diff --git a/src/plugins/qmldesigner/designercore/instances/nodeinstanceview.cpp b/src/plugins/qmldesigner/designercore/instances/nodeinstanceview.cpp
index dd9b66d57b..a88184bbbd 100644
--- a/src/plugins/qmldesigner/designercore/instances/nodeinstanceview.cpp
+++ b/src/plugins/qmldesigner/designercore/instances/nodeinstanceview.cpp
@@ -199,6 +199,10 @@ void NodeInstanceView::handleCrash()
void NodeInstanceView::restartProcess()
{
+ if (rootNodeInstance().isValid())
+ rootNodeInstance().setError({});
+ emitInstanceErrorChange({});
+
if (m_restartProcessTimerId)
killTimer(m_restartProcessTimerId);
diff --git a/src/plugins/qmldesigner/designercore/model/qmlitemnode.cpp b/src/plugins/qmldesigner/designercore/model/qmlitemnode.cpp
index f1665484b3..a5ff121584 100644
--- a/src/plugins/qmldesigner/designercore/model/qmlitemnode.cpp
+++ b/src/plugins/qmldesigner/designercore/model/qmlitemnode.cpp
@@ -371,6 +371,9 @@ bool itemIsMovable(const ModelNode &modelNode)
if (modelNode.metaInfo().isSubclassOf("QtQuick.Controls.Tab"))
return false;
+ if (!modelNode.hasParentProperty())
+ return false;
+
if (!modelNode.parentProperty().isNodeListProperty())
return false;
diff --git a/src/plugins/qmldesigner/designercore/model/rewriterview.cpp b/src/plugins/qmldesigner/designercore/model/rewriterview.cpp
index 6996a3f00b..d550e82fbd 100644
--- a/src/plugins/qmldesigner/designercore/model/rewriterview.cpp
+++ b/src/plugins/qmldesigner/designercore/model/rewriterview.cpp
@@ -86,6 +86,11 @@ void RewriterView::modelAttached(Model *model)
if (!(m_errors.isEmpty() && m_warnings.isEmpty()))
notifyErrorsAndWarnings(m_errors);
+
+ if (hasIncompleteTypeInformation())
+ QTimer::singleShot(1000, this, [this, model](){
+ modelAttached(model);
+ });
}
void RewriterView::modelAboutToBeDetached(Model * /*model*/)
@@ -465,6 +470,16 @@ void RewriterView::setWarnings(const QList<DocumentMessage> &warnings)
notifyErrorsAndWarnings(m_errors);
}
+void RewriterView::setIncompleteTypeInformation(bool b)
+{
+ m_hasIncompleteTypeInformation = b;
+}
+
+bool RewriterView::hasIncompleteTypeInformation() const
+{
+ return m_hasIncompleteTypeInformation;
+}
+
void RewriterView::setErrors(const QList<DocumentMessage> &errors)
{
m_errors = errors;
diff --git a/src/plugins/qmldesigner/designercore/model/texttomodelmerger.cpp b/src/plugins/qmldesigner/designercore/model/texttomodelmerger.cpp
index c66b4ef6a8..af2d24ce95 100644
--- a/src/plugins/qmldesigner/designercore/model/texttomodelmerger.cpp
+++ b/src/plugins/qmldesigner/designercore/model/texttomodelmerger.cpp
@@ -928,6 +928,7 @@ bool TextToModelMerger::load(const QString &data, DifferenceHandler &differenceH
const QUrl url = m_rewriterView->model()->fileUrl();
setActive(true);
+ m_rewriterView->setIncompleteTypeInformation(false);
try {
Snapshot snapshot = m_rewriterView->textModifier()->qmljsSnapshot();
@@ -1953,6 +1954,9 @@ void TextToModelMerger::setupComponent(const ModelNode &node)
void TextToModelMerger::collectLinkErrors(QList<DocumentMessage> *errors, const ReadingContext &ctxt)
{
foreach (const QmlJS::DiagnosticMessage &diagnosticMessage, ctxt.diagnosticLinkMessages()) {
+ if (diagnosticMessage.kind == QmlJS::Severity::ReadingTypeInfoWarning)
+ m_rewriterView->setIncompleteTypeInformation(true);
+
errors->append(DocumentMessage(diagnosticMessage, QUrl::fromLocalFile(m_document->fileName())));
}
}
diff --git a/src/plugins/qmldesigner/designmodewidget.cpp b/src/plugins/qmldesigner/designmodewidget.cpp
index 33056bf9be..e1bff9bfb6 100644
--- a/src/plugins/qmldesigner/designmodewidget.cpp
+++ b/src/plugins/qmldesigner/designmodewidget.cpp
@@ -454,10 +454,6 @@ static Core::MiniSplitter *createCentralSplitter(const QList<WidgetInfo> &widget
SwitchSplitTabWidget *switchSplitTabWidget = new SwitchSplitTabWidget();
- QString sheet = QString::fromUtf8(Utils::FileReader::fetchQrc(":/qmldesigner/centerwidget.css"));
- switchSplitTabWidget->setStyleSheet(Theme::replaceCssColors(sheet));
-
-
foreach (const WidgetInfo &widgetInfo, widgetInfos) {
if (widgetInfo.placementHint == widgetInfo.CentralPane)
switchSplitTabWidget->addTab(widgetInfo.widget, widgetInfo.tabName);
diff --git a/src/plugins/qmldesigner/documentmanager.cpp b/src/plugins/qmldesigner/documentmanager.cpp
index 357420c1d8..abf45bfbb1 100644
--- a/src/plugins/qmldesigner/documentmanager.cpp
+++ b/src/plugins/qmldesigner/documentmanager.cpp
@@ -438,7 +438,7 @@ bool DocumentManager::isoProFileSupportsAddingExistingFiles(const QString &resou
ProjectExplorer::ProjectNode *projectNode = node->parentFolderNode()->asProjectNode();
if (!projectNode)
return false;
- if (!projectNode->supportedActions(projectNode).contains(ProjectExplorer::AddExistingFile)) {
+ if (!projectNode->supportsAction(ProjectExplorer::AddExistingFile, projectNode)) {
qCWarning(documentManagerLog) << "Project" << projectNode->displayName() << "does not support adding existing files";
return false;
}
diff --git a/src/plugins/qmldesigner/qmldesignerplugin.cpp b/src/plugins/qmldesigner/qmldesignerplugin.cpp
index b7eb2ce63e..37bdd3402d 100644
--- a/src/plugins/qmldesigner/qmldesignerplugin.cpp
+++ b/src/plugins/qmldesigner/qmldesignerplugin.cpp
@@ -415,6 +415,7 @@ void QmlDesignerPlugin::deactivateAutoSynchronization()
viewManager().detachViewsExceptRewriterAndComponetView();
viewManager().detachComponentView();
viewManager().detachRewriterView();
+ emitCurrentTextEditorChanged(documentManager().currentDesignDocument()->textEditor());
documentManager().currentDesignDocument()->resetToDocumentModel();
}
diff --git a/src/plugins/qmldesigner/switchsplittabwidget.cpp b/src/plugins/qmldesigner/switchsplittabwidget.cpp
index 08ad71ef12..6fcc98beb5 100644
--- a/src/plugins/qmldesigner/switchsplittabwidget.cpp
+++ b/src/plugins/qmldesigner/switchsplittabwidget.cpp
@@ -24,8 +24,10 @@
****************************************************************************/
#include "switchsplittabwidget.h"
+#include <theme.h>
#include <utils/utilsicons.h>
+#include <utils/fileutils.h>
#include <QVector>
#include <QBoxLayout>
@@ -48,6 +50,9 @@ SwitchSplitTabWidget::SwitchSplitTabWidget(QWidget *parent)
m_splitter->setObjectName("centralTabWidget");
m_splitter->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding);
+ QString sheet = QString::fromUtf8(Utils::FileReader::fetchQrc(":/qmldesigner/centerwidget.css"));
+ m_tabBarBackground->setStyleSheet(Theme::replaceCssColors(sheet));
+
m_tabBar->setObjectName("centralTabBar");
m_tabBar->setShape(QTabBar::RoundedEast);
m_tabBar->setDocumentMode(false);
diff --git a/src/plugins/qmljseditor/qmljseditor.cpp b/src/plugins/qmljseditor/qmljseditor.cpp
index f68a9d0e4a..cf84adfae4 100644
--- a/src/plugins/qmljseditor/qmljseditor.cpp
+++ b/src/plugins/qmljseditor/qmljseditor.cpp
@@ -105,10 +105,7 @@ namespace Internal {
QmlJSEditorWidget::QmlJSEditorWidget()
{
- m_outlineCombo = 0;
- m_contextPane = 0;
m_findReferences = new FindReferences(this);
-
setLanguageSettingsId(QmlJSTools::Constants::QML_JS_SETTINGS_ID);
}
@@ -142,7 +139,6 @@ void QmlJSEditorWidget::finalizeInitialization()
&m_contextPaneTimer, static_cast<void (QTimer::*)()>(&QTimer::start));
connect(m_contextPane, &IContextPane::closed, this, &QmlJSEditorWidget::showTextMarker);
}
- m_oldCursorPosition = -1;
connect(this->document(), &QTextDocument::modificationChanged,
this, &QmlJSEditorWidget::modificationChanged);
@@ -161,7 +157,6 @@ QModelIndex QmlJSEditorWidget::outlineModelIndex()
{
if (!m_outlineModelIndex.isValid()) {
m_outlineModelIndex = indexForPosition(position());
- emit outlineModelIndexChanged(m_outlineModelIndex);
}
return m_outlineModelIndex;
}
@@ -223,6 +218,11 @@ void QmlJSEditorWidget::modificationChanged(bool changed)
m_modelManager->fileChangedOnDisk(textDocument()->filePath().toString());
}
+bool QmlJSEditorWidget::isOutlineCursorChangesBlocked()
+{
+ return hasFocus() || m_blockOutLineCursorChanges;
+}
+
void QmlJSEditorWidget::jumpToOutlineElement(int /*index*/)
{
QModelIndex index = m_outlineCombo->view()->currentIndex();
@@ -253,6 +253,7 @@ void QmlJSEditorWidget::updateOutlineIndexNow()
m_outlineModelIndex = QModelIndex(); // invalidate
QModelIndex comboIndex = outlineModelIndex();
+ emit outlineModelIndexChanged(m_outlineModelIndex);
if (comboIndex.isValid()) {
bool blocked = m_outlineCombo->blockSignals(true);
@@ -504,18 +505,6 @@ QString QmlJSEditorWidget::wordUnderCursor() const
return word;
}
-bool QmlJSEditorWidget::isClosingBrace(const QList<Token> &tokens) const
-{
-
- if (tokens.size() == 1) {
- const Token firstToken = tokens.first();
-
- return firstToken.is(Token::RightBrace) || firstToken.is(Token::RightBracket);
- }
-
- return false;
-}
-
void QmlJSEditorWidget::createToolBar()
{
m_outlineCombo = new QComboBox;
@@ -546,8 +535,6 @@ void QmlJSEditorWidget::createToolBar()
this, &QmlJSEditorWidget::jumpToOutlineElement);
connect(m_qmlJsEditorDocument->outlineModel(), &QmlOutlineModel::updated,
static_cast<QTreeView *>(m_outlineCombo->view()), &QTreeView::expandAll);
- connect(m_qmlJsEditorDocument->outlineModel(), &QmlOutlineModel::updated,
- this, &QmlJSEditorWidget::updateOutlineIndexNow);
connect(this, &QmlJSEditorWidget::cursorPositionChanged,
&m_updateOutlineIndexTimer, static_cast<void (QTimer::*)()>(&QTimer::start));
@@ -826,6 +813,7 @@ void QmlJSEditorWidget::showContextPane()
void QmlJSEditorWidget::contextMenuEvent(QContextMenuEvent *e)
{
+ m_blockOutLineCursorChanges = true;
QPointer<QMenu> menu(new QMenu(this));
QMenu *refactoringMenu = new QMenu(tr("Refactoring"), menu);
@@ -870,6 +858,7 @@ void QmlJSEditorWidget::contextMenuEvent(QContextMenuEvent *e)
menu->exec(e->globalPos());
delete menu;
+ m_blockOutLineCursorChanges = false;
}
bool QmlJSEditorWidget::event(QEvent *e)
diff --git a/src/plugins/qmljseditor/qmljseditor.h b/src/plugins/qmljseditor/qmljseditor.h
index 9a086e65c0..2710e29fa0 100644
--- a/src/plugins/qmljseditor/qmljseditor.h
+++ b/src/plugins/qmljseditor/qmljseditor.h
@@ -66,6 +66,8 @@ public:
QmlJSEditorDocument *qmlJsEditorDocument() const;
QModelIndex outlineModelIndex();
+ void updateOutlineIndexNow();
+ bool isOutlineCursorChangesBlocked();
TextEditor::AssistInterface *createAssistInterface(TextEditor::AssistKind assistKind,
TextEditor::AssistReason reason) const override;
@@ -84,7 +86,6 @@ private:
void modificationChanged(bool);
void jumpToOutlineElement(int index);
- void updateOutlineIndexNow();
void updateContextPane();
void showTextMarker();
@@ -109,24 +110,23 @@ protected:
void onRefactorMarkerClicked(const TextEditor::RefactorMarker &marker) override;
private:
- bool isClosingBrace(const QList<QmlJS::Token> &tokens) const;
-
void setSelectedElements();
QString wordUnderCursor() const;
QModelIndex indexForPosition(unsigned cursorPosition, const QModelIndex &rootIndex = QModelIndex()) const;
bool hideContextPane();
- QmlJSEditorDocument *m_qmlJsEditorDocument;
+ QmlJSEditorDocument *m_qmlJsEditorDocument = nullptr;
QTimer m_updateUsesTimer; // to wait for multiple text cursor position changes
QTimer m_updateOutlineIndexTimer;
QTimer m_contextPaneTimer;
QComboBox *m_outlineCombo;
QModelIndex m_outlineModelIndex;
- QmlJS::ModelManagerInterface *m_modelManager;
+ bool m_blockOutLineCursorChanges = false;
+ QmlJS::ModelManagerInterface *m_modelManager = nullptr;
- QmlJS::IContextPane *m_contextPane;
- int m_oldCursorPosition;
+ QmlJS::IContextPane *m_contextPane = nullptr;
+ int m_oldCursorPosition = -1;
FindReferences *m_findReferences;
};
diff --git a/src/plugins/qmljseditor/qmljseditordocument.cpp b/src/plugins/qmljseditor/qmljseditordocument.cpp
index 6ef9f3bdee..732deddb4b 100644
--- a/src/plugins/qmljseditor/qmljseditordocument.cpp
+++ b/src/plugins/qmljseditor/qmljseditordocument.cpp
@@ -455,12 +455,9 @@ namespace QmlJSEditor {
namespace Internal {
QmlJSEditorDocumentPrivate::QmlJSEditorDocumentPrivate(QmlJSEditorDocument *parent)
- : q(parent),
- m_semanticInfoDocRevision(-1),
- m_semanticHighlighter(new SemanticHighlighter(parent)),
- m_semanticHighlightingNecessary(false),
- m_outlineModelNeedsUpdate(false),
- m_outlineModel(new QmlOutlineModel(parent))
+ : q(parent)
+ , m_semanticHighlighter(new SemanticHighlighter(parent))
+ , m_outlineModel(new QmlOutlineModel(parent))
{
ModelManagerInterface *modelManager = ModelManagerInterface::instance();
diff --git a/src/plugins/qmljseditor/qmljseditordocument_p.h b/src/plugins/qmljseditor/qmljseditordocument_p.h
index f2cee06d76..854b81519f 100644
--- a/src/plugins/qmljseditor/qmljseditordocument_p.h
+++ b/src/plugins/qmljseditor/qmljseditordocument_p.h
@@ -58,19 +58,19 @@ public:
void updateOutlineModel();
public:
- QmlJSEditorDocument *q;
+ QmlJSEditorDocument *q = nullptr;
QTimer m_updateDocumentTimer; // used to compress multiple document changes
QTimer m_reupdateSemanticInfoTimer; // used to compress multiple libraryInfo changes
- int m_semanticInfoDocRevision; // document revision to which the semantic info is currently updated to
+ int m_semanticInfoDocRevision = -1; // document revision to which the semantic info is currently updated to
SemanticInfoUpdater *m_semanticInfoUpdater;
QmlJSTools::SemanticInfo m_semanticInfo;
QVector<QTextLayout::FormatRange> m_diagnosticRanges;
- Internal::SemanticHighlighter *m_semanticHighlighter;
- bool m_semanticHighlightingNecessary;
- bool m_outlineModelNeedsUpdate;
+ Internal::SemanticHighlighter *m_semanticHighlighter = nullptr;
+ bool m_semanticHighlightingNecessary = false;
+ bool m_outlineModelNeedsUpdate = false;
bool m_firstSementicInfo = true;
QTimer m_updateOutlineModelTimer;
- Internal::QmlOutlineModel *m_outlineModel;
+ Internal::QmlOutlineModel *m_outlineModel = nullptr;
};
} // Internal
diff --git a/src/plugins/qmljseditor/qmljsoutline.cpp b/src/plugins/qmljseditor/qmljsoutline.cpp
index bf37940983..ffe938e543 100644
--- a/src/plugins/qmljseditor/qmljsoutline.cpp
+++ b/src/plugins/qmljseditor/qmljsoutline.cpp
@@ -94,13 +94,10 @@ void QmlJSOutlineFilterModel::setFilterBindings(bool filterBindings)
invalidateFilter();
}
-QmlJSOutlineWidget::QmlJSOutlineWidget(QWidget *parent) :
- TextEditor::IOutlineWidget(parent),
- m_treeView(new QmlJSOutlineTreeView(this)),
- m_filterModel(new QmlJSOutlineFilterModel(this)),
- m_editor(0),
- m_enableCursorSync(true),
- m_blockCursorSync(false)
+QmlJSOutlineWidget::QmlJSOutlineWidget(QWidget *parent)
+ : TextEditor::IOutlineWidget(parent)
+ , m_treeView(new QmlJSOutlineTreeView(this))
+ , m_filterModel(new QmlJSOutlineFilterModel(this))
{
m_filterModel->setFilterBindings(false);
@@ -127,7 +124,7 @@ void QmlJSOutlineWidget::setEditor(QmlJSEditorWidget *editor)
m_editor = editor;
m_filterModel->setSourceModel(m_editor->qmlJsEditorDocument()->outlineModel());
- modelUpdated();
+ m_treeView->expandAll();
connect(m_treeView->selectionModel(), &QItemSelectionModel::selectionChanged,
this, &QmlJSOutlineWidget::updateSelectionInText);
@@ -137,22 +134,21 @@ void QmlJSOutlineWidget::setEditor(QmlJSEditorWidget *editor)
connect(m_editor, &QmlJSEditorWidget::outlineModelIndexChanged,
this, &QmlJSOutlineWidget::updateSelectionInTree);
- connect(m_editor->qmlJsEditorDocument()->outlineModel(), &QmlOutlineModel::updated,
- this, &QmlJSOutlineWidget::modelUpdated);
+ connect(m_editor->qmlJsEditorDocument()->outlineModel(), &QmlOutlineModel::updated, this, [this] () {
+ m_treeView->expandAll();
+ m_editor->updateOutlineIndexNow();
+ });
}
QList<QAction*> QmlJSOutlineWidget::filterMenuActions() const
{
- QList<QAction*> list;
- list.append(m_showBindingsAction);
- return list;
+ return {m_showBindingsAction};
}
void QmlJSOutlineWidget::setCursorSynchronization(bool syncWithCursor)
{
m_enableCursorSync = syncWithCursor;
- if (m_enableCursorSync)
- updateSelectionInTree(m_editor->outlineModelIndex());
+ m_editor->updateOutlineIndexNow();
}
void QmlJSOutlineWidget::restoreSettings(const QVariantMap &map)
@@ -163,14 +159,7 @@ void QmlJSOutlineWidget::restoreSettings(const QVariantMap &map)
QVariantMap QmlJSOutlineWidget::settings() const
{
- QVariantMap map;
- map.insert(QLatin1String("QmlJSOutline.ShowBindings"), m_showBindingsAction->isChecked());
- return map;
-}
-
-void QmlJSOutlineWidget::modelUpdated()
-{
- m_treeView->expandAll();
+ return {{QLatin1String("QmlJSOutline.ShowBindings"), m_showBindingsAction->isChecked()}};
}
void QmlJSOutlineWidget::updateSelectionInTree(const QModelIndex &index)
@@ -206,27 +195,29 @@ void QmlJSOutlineWidget::updateSelectionInText(const QItemSelection &selection)
void QmlJSOutlineWidget::updateTextCursor(const QModelIndex &index)
{
- QModelIndex sourceIndex = m_filterModel->mapToSource(index);
- AST::SourceLocation location
- = m_editor->qmlJsEditorDocument()->outlineModel()->sourceLocation(sourceIndex);
-
- if (!location.isValid())
- return;
-
- const QTextBlock lastBlock = m_editor->document()->lastBlock();
- const uint textLength = lastBlock.position() + lastBlock.length();
- if (location.offset >= textLength)
- return;
-
- Core::EditorManager::cutForwardNavigationHistory();
- Core::EditorManager::addCurrentPositionToNavigationHistory();
-
- QTextCursor textCursor = m_editor->textCursor();
- m_blockCursorSync = true;
- textCursor.setPosition(location.offset);
- m_editor->setTextCursor(textCursor);
- m_editor->centerCursor();
- m_blockCursorSync = false;
+ if (!m_editor->isOutlineCursorChangesBlocked()) {
+ QModelIndex sourceIndex = m_filterModel->mapToSource(index);
+ AST::SourceLocation location
+ = m_editor->qmlJsEditorDocument()->outlineModel()->sourceLocation(sourceIndex);
+
+ if (!location.isValid())
+ return;
+
+ const QTextBlock lastBlock = m_editor->document()->lastBlock();
+ const uint textLength = lastBlock.position() + lastBlock.length();
+ if (location.offset >= textLength)
+ return;
+
+ Core::EditorManager::cutForwardNavigationHistory();
+ Core::EditorManager::addCurrentPositionToNavigationHistory();
+
+ QTextCursor textCursor = m_editor->textCursor();
+ m_blockCursorSync = true;
+ textCursor.setPosition(location.offset);
+ m_editor->setTextCursor(textCursor);
+ m_editor->centerCursor();
+ m_blockCursorSync = false;
+ }
}
void QmlJSOutlineWidget::focusEditor()
@@ -237,8 +228,8 @@ void QmlJSOutlineWidget::focusEditor()
void QmlJSOutlineWidget::setShowBindings(bool showBindings)
{
m_filterModel->setFilterBindings(!showBindings);
- modelUpdated();
- updateSelectionInTree(m_editor->outlineModelIndex());
+ m_treeView->expandAll();
+ m_editor->updateOutlineIndexNow();
}
bool QmlJSOutlineWidget::syncCursor()
diff --git a/src/plugins/qmljseditor/qmljsoutline.h b/src/plugins/qmljseditor/qmljsoutline.h
index 799aaf812a..a8f15c53e3 100644
--- a/src/plugins/qmljseditor/qmljsoutline.h
+++ b/src/plugins/qmljseditor/qmljsoutline.h
@@ -31,6 +31,10 @@
#include <QSortFilterProxyModel>
+QT_BEGIN_NAMESPACE
+class QAction;
+QT_END_NAMESPACE
+
namespace Core { class IEditor; }
namespace QmlJS { class Editor; }
@@ -66,13 +70,12 @@ public:
void setEditor(QmlJSEditorWidget *editor);
// IOutlineWidget
- virtual QList<QAction*> filterMenuActions() const;
- virtual void setCursorSynchronization(bool syncWithCursor);
- virtual void restoreSettings(const QVariantMap &map);
- virtual QVariantMap settings() const;
+ virtual QList<QAction*> filterMenuActions() const override;
+ virtual void setCursorSynchronization(bool syncWithCursor) override;
+ virtual void restoreSettings(const QVariantMap &map) override;
+ virtual QVariantMap settings() const override;
private:
- void modelUpdated();
void updateSelectionInTree(const QModelIndex &index);
void updateSelectionInText(const QItemSelection &selection);
void updateTextCursor(const QModelIndex &index);
@@ -81,14 +84,14 @@ private:
bool syncCursor();
private:
- QmlJSOutlineTreeView *m_treeView;
- QmlJSOutlineFilterModel *m_filterModel;
- QmlJSEditorWidget *m_editor;
+ QmlJSOutlineTreeView *m_treeView = nullptr;
+ QmlJSOutlineFilterModel *m_filterModel = nullptr;
+ QmlJSEditorWidget *m_editor = nullptr;
- QAction *m_showBindingsAction;
+ QAction *m_showBindingsAction = nullptr;
- bool m_enableCursorSync;
- bool m_blockCursorSync;
+ bool m_enableCursorSync = true;
+ bool m_blockCursorSync = false;
};
class QmlJSOutlineWidgetFactory : public TextEditor::IOutlineWidgetFactory
diff --git a/src/plugins/qmljseditor/qmljssemantichighlighter.cpp b/src/plugins/qmljseditor/qmljssemantichighlighter.cpp
index d2a855062f..4cd696a046 100644
--- a/src/plugins/qmljseditor/qmljssemantichighlighter.cpp
+++ b/src/plugins/qmljseditor/qmljssemantichighlighter.cpp
@@ -436,7 +436,9 @@ protected:
const TextEditor::FontSettings &fontSettings = TextEditor::TextEditorSettings::instance()->fontSettings();
QTextCharFormat format;
- if (d.severity == Severity::Warning || d.severity == Severity::MaybeWarning) {
+ if (d.severity == Severity::Warning
+ || d.severity == Severity::MaybeWarning
+ || d.severity == Severity::ReadingTypeInfoWarning) {
format = fontSettings.toTextCharFormat(TextEditor::C_WARNING);
} else if (d.severity == Severity::Error || d.severity == Severity::MaybeError) {
format = fontSettings.toTextCharFormat(TextEditor::C_ERROR);
diff --git a/src/plugins/qmlprofiler/tests/flamegraphview_test.cpp b/src/plugins/qmlprofiler/tests/flamegraphview_test.cpp
index 799f3c3ac1..5d94a1a8b1 100644
--- a/src/plugins/qmlprofiler/tests/flamegraphview_test.cpp
+++ b/src/plugins/qmlprofiler/tests/flamegraphview_test.cpp
@@ -116,38 +116,42 @@ void FlameGraphViewTest::testContextMenu()
targetHeight = (testMenu.height() + prevHeight) / 2;
}
+ QTest::mouseMove(&view, QPoint(250, 250));
+ QSignalSpy spy(&view, SIGNAL(showFullRange()));
+
QTimer timer;
timer.setInterval(50);
- timer.start();
+ int menuClicks = 0;
connect(&timer, &QTimer::timeout, this, [&]() {
auto activePopup = qApp->activePopupWidget();
- if (!activePopup || !activePopup->windowHandle()->isExposed())
+ if (!activePopup || !activePopup->windowHandle()->isExposed()) {
+ QContextMenuEvent *event = new QContextMenuEvent(QContextMenuEvent::Mouse,
+ QPoint(250, 250));
+ qApp->postEvent(&view, event);
return;
+ }
+
QTest::mouseMove(activePopup, QPoint(targetWidth, targetHeight));
QTest::mouseClick(activePopup, Qt::LeftButton, Qt::NoModifier,
QPoint(targetWidth, targetHeight));
+ ++menuClicks;
if (!manager.isRestrictedToRange()) {
// click somewhere else to remove the menu and return to outer function
- QTest::mouseClick(qApp->activePopupWidget(), Qt::LeftButton, Qt::NoModifier,
- QPoint(500, 500));
+ QTest::mouseMove(activePopup, QPoint(-10, -10));
+ QTest::mouseClick(activePopup, Qt::LeftButton, Qt::NoModifier, QPoint(-10, -10));
}
});
- QTest::mouseMove(&view, QPoint(250, 250));
- QSignalSpy spy(&view, SIGNAL(showFullRange()));
-
- QContextMenuEvent event(QContextMenuEvent::Mouse, QPoint(250, 250));
- QVERIFY(qApp->notify(&view, &event));
+ timer.start();
+ QTRY_VERIFY(menuClicks > 0);
QCOMPARE(spy.count(), 0);
-
manager.restrictToRange(1, 10);
-
- QVERIFY(qApp->notify(&view, &event));
-
- if (spy.count() != 1)
- QTRY_COMPARE(spy.count(), 1);
+ QVERIFY(manager.isRestrictedToRange());
+ QTRY_COMPARE(spy.count(), 1);
+ QVERIFY(menuClicks > 1);
+ timer.stop();
}
void FlameGraphViewTest::cleanupTestCase()
diff --git a/src/plugins/qmlprojectmanager/qmlproject.cpp b/src/plugins/qmlprojectmanager/qmlproject.cpp
index 601f153582..a8554be3ec 100644
--- a/src/plugins/qmlprojectmanager/qmlproject.cpp
+++ b/src/plugins/qmlprojectmanager/qmlproject.cpp
@@ -61,6 +61,7 @@ QmlProject::QmlProject(const Utils::FileName &fileName) :
setId("QmlProjectManager.QmlProject");
setProjectContext(Context(QmlProjectManager::Constants::PROJECTCONTEXT));
setProjectLanguages(Context(ProjectExplorer::Constants::QMLJS_LANGUAGE_ID));
+ setDisplayName(fileName.toFileInfo().completeBaseName());
}
QmlProject::~QmlProject()
@@ -239,11 +240,6 @@ void QmlProject::refreshFiles(const QSet<QString> &/*added*/, const QSet<QString
}
}
-QString QmlProject::displayName() const
-{
- return projectFilePath().toFileInfo().completeBaseName();
-}
-
bool QmlProject::supportsKit(Kit *k, QString *errorMessage) const
{
Id deviceType = DeviceTypeKitInformation::deviceTypeId(k);
diff --git a/src/plugins/qmlprojectmanager/qmlproject.h b/src/plugins/qmlprojectmanager/qmlproject.h
index 616c2c6d18..75db80a866 100644
--- a/src/plugins/qmlprojectmanager/qmlproject.h
+++ b/src/plugins/qmlprojectmanager/qmlproject.h
@@ -46,8 +46,6 @@ public:
explicit QmlProject(const Utils::FileName &filename);
~QmlProject() override;
- QString displayName() const override;
-
bool supportsKit(ProjectExplorer::Kit *k, QString *errorMessage) const override;
Internal::QmlProjectNode *rootProjectNode() const override;
diff --git a/src/plugins/qmlprojectmanager/qmlprojectnodes.cpp b/src/plugins/qmlprojectmanager/qmlprojectnodes.cpp
index c3e1034baf..ecf191a02f 100644
--- a/src/plugins/qmlprojectmanager/qmlprojectnodes.cpp
+++ b/src/plugins/qmlprojectmanager/qmlprojectnodes.cpp
@@ -57,15 +57,17 @@ bool QmlProjectNode::showInSimpleTree() const
return true;
}
-QList<ProjectAction> QmlProjectNode::supportedActions(Node *node) const
+bool QmlProjectNode::supportsAction(ProjectAction action, Node *node) const
{
- QList<ProjectAction> actions = {AddNewFile, EraseFile};
- if (node->nodeType() == NodeType::File) {
+ if (action == AddNewFile || action == EraseFile)
+ return true;
+
+ if (action == Rename && node->nodeType() == NodeType::File) {
FileNode *fileNode = static_cast<FileNode *>(node);
- if (fileNode->fileType() != FileType::Project)
- actions.append(Rename);
+ return fileNode->fileType() != FileType::Project;
}
- return actions;
+
+ return false;
}
bool QmlProjectNode::addFiles(const QStringList &filePaths, QStringList * /*notAdded*/)
diff --git a/src/plugins/qmlprojectmanager/qmlprojectnodes.h b/src/plugins/qmlprojectmanager/qmlprojectnodes.h
index 3df7d7e3be..bc715d86f6 100644
--- a/src/plugins/qmlprojectmanager/qmlprojectnodes.h
+++ b/src/plugins/qmlprojectmanager/qmlprojectnodes.h
@@ -38,13 +38,11 @@ class QmlProjectNode : public ProjectExplorer::ProjectNode
public:
QmlProjectNode(QmlProject *project);
- virtual bool showInSimpleTree() const override;
-
- virtual QList<ProjectExplorer::ProjectAction> supportedActions(Node *node) const override;
-
- virtual bool addFiles(const QStringList &filePaths, QStringList *notAdded = 0) override;
- virtual bool deleteFiles(const QStringList &filePaths) override;
- virtual bool renameFile(const QString &filePath, const QString &newFilePath) override;
+ bool showInSimpleTree() const override;
+ bool supportsAction(ProjectExplorer::ProjectAction action, Node *node) const override;
+ bool addFiles(const QStringList &filePaths, QStringList *notAdded = 0) override;
+ bool deleteFiles(const QStringList &filePaths) override;
+ bool renameFile(const QString &filePath, const QString &newFilePath) override;
private:
QmlProject *m_project;
diff --git a/src/plugins/qnx/qnxconfiguration.cpp b/src/plugins/qnx/qnxconfiguration.cpp
index 295b942c4f..22718c6385 100644
--- a/src/plugins/qnx/qnxconfiguration.cpp
+++ b/src/plugins/qnx/qnxconfiguration.cpp
@@ -276,6 +276,7 @@ QnxToolChain *QnxConfiguration::createToolChain(const Target &target)
.arg(displayName())
.arg(target.shortDescription()));
toolChain->setSdpPath(sdpPath().toString());
+ toolChain->setCpuDir(target.cpuDir());
toolChain->resetToolChain(qccCompilerPath());
ToolChainManager::registerToolChain(toolChain);
return toolChain;
diff --git a/src/plugins/qnx/qnxtoolchain.cpp b/src/plugins/qnx/qnxtoolchain.cpp
index 1ae34f2a7a..99a90c89a9 100644
--- a/src/plugins/qnx/qnxtoolchain.cpp
+++ b/src/plugins/qnx/qnxtoolchain.cpp
@@ -42,6 +42,7 @@ namespace Qnx {
namespace Internal {
static const char CompilerSdpPath[] = "Qnx.QnxToolChain.NDKPath";
+static const char CpuDirKey[] = "Qnx.QnxToolChain.CpuDir";
static QList<Abi> detectTargetAbis(const FileName &sdpPath)
{
@@ -146,6 +147,7 @@ QVariantMap QnxToolChain::toMap() const
{
QVariantMap data = GccToolChain::toMap();
data.insert(QLatin1String(CompilerSdpPath), m_sdpPath);
+ data.insert(QLatin1String(CpuDirKey), m_cpuDir);
return data;
}
@@ -155,6 +157,7 @@ bool QnxToolChain::fromMap(const QVariantMap &data)
return false;
m_sdpPath = data.value(QLatin1String(CompilerSdpPath)).toString();
+ m_cpuDir = data.value(QLatin1String(CpuDirKey)).toString();
// Make the ABIs QNX specific (if they aren't already).
setSupportedAbis(QnxUtils::convertAbis(supportedAbis()));
@@ -176,11 +179,34 @@ void QnxToolChain::setSdpPath(const QString &sdpPath)
toolChainUpdated();
}
+QString QnxToolChain::cpuDir() const
+{
+ return m_cpuDir;
+}
+
+void QnxToolChain::setCpuDir(const QString &cpuDir)
+{
+ if (m_cpuDir == cpuDir)
+ return;
+ m_cpuDir = cpuDir;
+ toolChainUpdated();
+}
+
GccToolChain::DetectedAbisResult QnxToolChain::detectSupportedAbis() const
{
return detectTargetAbis(FileName::fromString(m_sdpPath));
}
+bool QnxToolChain::operator ==(const ToolChain &other) const
+{
+ if (!GccToolChain::operator ==(other))
+ return false;
+
+ auto qnxTc = static_cast<const QnxToolChain *>(&other);
+
+ return m_sdpPath == qnxTc->m_sdpPath && m_cpuDir == qnxTc->m_cpuDir;
+}
+
// --------------------------------------------------------------------------
// QnxToolChainFactory
// --------------------------------------------------------------------------
diff --git a/src/plugins/qnx/qnxtoolchain.h b/src/plugins/qnx/qnxtoolchain.h
index 93f2c15bc6..1d930a80d3 100644
--- a/src/plugins/qnx/qnxtoolchain.h
+++ b/src/plugins/qnx/qnxtoolchain.h
@@ -49,12 +49,17 @@ public:
QString sdpPath() const;
void setSdpPath(const QString &sdpPath);
+ QString cpuDir() const;
+ void setCpuDir(const QString &cpuDir);
+
+ bool operator ==(const ToolChain &) const override;
protected:
virtual DetectedAbisResult detectSupportedAbis() const override;
private:
QString m_sdpPath;
+ QString m_cpuDir;
};
// --------------------------------------------------------------------------
diff --git a/src/plugins/resourceeditor/resourceeditorplugin.cpp b/src/plugins/resourceeditor/resourceeditorplugin.cpp
index 474092d350..1ae83161ca 100644
--- a/src/plugins/resourceeditor/resourceeditorplugin.cpp
+++ b/src/plugins/resourceeditor/resourceeditorplugin.cpp
@@ -338,8 +338,8 @@ void ResourceEditorPlugin::updateContextActions()
if (isResourceNode) {
FolderNode *parent = node ? node->parentFolderNode() : 0;
- enableRename = parent && parent->supportedActions(node).contains(Rename);
- enableRemove = parent && parent->supportedActions(node).contains(RemoveFile);
+ enableRename = parent && parent->supportsAction(Rename, node);
+ enableRemove = parent && parent->supportsAction(RemoveFile, node);
}
m_renameResourceFile->setEnabled(isResourceNode && enableRename);
diff --git a/src/plugins/resourceeditor/resourcenode.cpp b/src/plugins/resourceeditor/resourcenode.cpp
index 49c640840a..ffe74eeb42 100644
--- a/src/plugins/resourceeditor/resourcenode.cpp
+++ b/src/plugins/resourceeditor/resourcenode.cpp
@@ -160,7 +160,7 @@ public:
ResourceTopLevelNode *topLevel, ResourceFolderNode *prefixNode);
QString displayName() const final;
- QList<ProjectAction> supportedActions(Node *node) const final;
+ bool supportsAction(ProjectAction, Node *node) const final;
bool addFiles(const QStringList &filePaths, QStringList *notAdded) final;
bool removeFiles(const QStringList &filePaths, QStringList *notRemoved) final;
bool renameFile(const QString &filePath, const QString &newFilePath) final;
@@ -199,17 +199,15 @@ SimpleResourceFolderNode::SimpleResourceFolderNode(const QString &afolderName, c
}
-QList<ProjectAction> SimpleResourceFolderNode::supportedActions(Node *) const
+bool SimpleResourceFolderNode::supportsAction(ProjectAction action, Node *) const
{
- return {
- AddNewFile,
- AddExistingFile,
- AddExistingDirectory,
- RemoveFile,
- DuplicateFile,
- Rename, // Note: only works for the filename, works akwardly for relative file paths
- InheritedFromParent // Do not add to list of projects when adding new file
- };
+ return action == AddNewFile
+ || action == AddExistingFile
+ || action == AddExistingDirectory
+ || action == RemoveFile
+ || action == DuplicateFile
+ || action == Rename // Note: only works for the filename, works akwardly for relative file paths
+ || action == InheritedFromParent; // Do not add to list of projects when adding new file
}
bool SimpleResourceFolderNode::addFiles(const QStringList &filePaths, QStringList *notAdded)
@@ -387,11 +385,15 @@ QString ResourceTopLevelNode::addFileFilter() const
return QLatin1String("*.png; *.jpg; *.gif; *.svg; *.ico; *.qml; *.qml.ui");
}
-QList<ProjectAction> ResourceTopLevelNode::supportedActions(Node *node) const
+bool ResourceTopLevelNode::supportsAction(ProjectAction action, Node *node) const
{
if (node != this)
- return {};
- return {AddNewFile, AddExistingFile, AddExistingDirectory, HidePathActions, Rename};
+ return false;
+ return action == AddNewFile
+ || action == AddExistingFile
+ || action == AddExistingDirectory
+ || action == HidePathActions
+ || action == Rename;
}
bool ResourceTopLevelNode::addFiles(const QStringList &filePaths, QStringList *notAdded)
@@ -504,25 +506,23 @@ ResourceFolderNode::~ResourceFolderNode()
}
-QList<ProjectAction> ResourceFolderNode::supportedActions(Node *node) const
+bool ResourceFolderNode::supportsAction(ProjectAction action, Node *node) const
{
Q_UNUSED(node)
- QList<ProjectAction> actions = {
- AddNewFile,
- AddExistingFile,
- AddExistingDirectory,
- RemoveFile,
- DuplicateFile,
- Rename, // Note: only works for the filename, works akwardly for relative file paths
- HidePathActions, // hides open terminal etc.
- };
- // if the prefix is '/' (without lang) hide this node in add new dialog,
- // as the ResouceTopLevelNode is always shown for the '/' prefix
- if (m_prefix == QLatin1String("/") && m_lang.isEmpty())
- actions << InheritedFromParent;
+ if (action == InheritedFromParent) {
+ // if the prefix is '/' (without lang) hide this node in add new dialog,
+ // as the ResouceTopLevelNode is always shown for the '/' prefix
+ return m_prefix == QLatin1String("/") && m_lang.isEmpty();
+ }
- return actions;
+ return action == AddNewFile
+ || action == AddExistingFile
+ || action == AddExistingDirectory
+ || action == RemoveFile
+ || action == DuplicateFile
+ || action == Rename // Note: only works for the filename, works akwardly for relative file paths
+ || action == HidePathActions; // hides open terminal etc.
}
bool ResourceFolderNode::addFiles(const QStringList &filePaths, QStringList *notAdded)
@@ -674,12 +674,11 @@ QString ResourceFileNode::qrcPath() const
return m_qrcPath;
}
-QList<ProjectAction> ResourceFileNode::supportedActions(Node *node) const
+bool ResourceFileNode::supportsAction(ProjectAction action, Node *node) const
{
- QList<ProjectAction> actions = parentFolderNode()->supportedActions(node);
- actions.removeOne(HidePathActions);
- return actions;
+ if (action == HidePathActions)
+ return false;
+ return parentFolderNode()->supportsAction(action, node);
}
-
} // ResourceEditor
diff --git a/src/plugins/resourceeditor/resourcenode.h b/src/plugins/resourceeditor/resourcenode.h
index aa7ff02580..0d6b7a1b64 100644
--- a/src/plugins/resourceeditor/resourcenode.h
+++ b/src/plugins/resourceeditor/resourcenode.h
@@ -41,7 +41,7 @@ public:
QString addFileFilter() const override;
- QList<ProjectExplorer::ProjectAction> supportedActions(Node *node) const override;
+ bool supportsAction(ProjectExplorer::ProjectAction action, Node *node) const override;
bool addFiles(const QStringList &filePaths, QStringList *notAdded) override;
bool removeFiles(const QStringList &filePaths, QStringList *notRemoved) override;
@@ -67,7 +67,7 @@ public:
ResourceFolderNode(const QString &prefix, const QString &lang, ResourceTopLevelNode *parent);
~ResourceFolderNode() override;
- QList<ProjectExplorer::ProjectAction> supportedActions(Node *node) const override;
+ bool supportsAction(ProjectExplorer::ProjectAction action, Node *node) const override;
QString displayName() const override;
@@ -97,7 +97,7 @@ public:
QString displayName() const override;
QString qrcPath() const;
- QList<ProjectExplorer::ProjectAction> supportedActions(Node *node) const override;
+ bool supportsAction(ProjectExplorer::ProjectAction action, Node *node) const override;
private:
QString m_qrcPath;
diff --git a/src/plugins/scxmleditor/common/colorthemes.cpp b/src/plugins/scxmleditor/common/colorthemes.cpp
index 821e98e123..fc06f03584 100644
--- a/src/plugins/scxmleditor/common/colorthemes.cpp
+++ b/src/plugins/scxmleditor/common/colorthemes.cpp
@@ -98,7 +98,7 @@ void ColorThemes::updateColorThemeMenu()
for (const QString &key: keys) {
const QString actionText = key == Constants::C_COLOR_SCHEME_DEFAULT
? tr("Factory Default") : key == Constants::C_COLOR_SCHEME_SCXMLDOCUMENT
- ? tr("Colors from SCXML-document")
+ ? tr("Colors from SCXML Document")
: key;
QAction *action = m_menu->addAction(actionText, this, [this, key]() {
selectColorTheme(key);
diff --git a/src/plugins/scxmleditor/plugin_interface/idwarningitem.cpp b/src/plugins/scxmleditor/plugin_interface/idwarningitem.cpp
index 8752196405..2e50ac5b64 100644
--- a/src/plugins/scxmleditor/plugin_interface/idwarningitem.cpp
+++ b/src/plugins/scxmleditor/plugin_interface/idwarningitem.cpp
@@ -33,7 +33,7 @@ IdWarningItem::IdWarningItem(QGraphicsItem *parent)
{
setSeverity(OutputPane::Warning::ErrorType);
setTypeName(tr("State"));
- setDescription(tr("Each State has to be unique ID."));
+ setDescription(tr("Each state must have a unique ID."));
setReason(tr("Missing ID"));
setX(-boundingRect().width());
}
diff --git a/src/plugins/scxmleditor/plugin_interface/initialwarningitem.cpp b/src/plugins/scxmleditor/plugin_interface/initialwarningitem.cpp
index 5b15f1d8bf..987113eca0 100644
--- a/src/plugins/scxmleditor/plugin_interface/initialwarningitem.cpp
+++ b/src/plugins/scxmleditor/plugin_interface/initialwarningitem.cpp
@@ -35,8 +35,8 @@ InitialWarningItem::InitialWarningItem(InitialStateItem *parent)
{
setSeverity(OutputPane::Warning::ErrorType);
setTypeName(tr("Initial"));
- setDescription(tr("It is possible to have max 1 initial-state in the same level."));
- setReason(tr("Too many initial states in the same level"));
+ setDescription(tr("One level can contain only one initial state."));
+ setReason(tr("Too many initial states at the same level"));
}
void InitialWarningItem::updatePos()
diff --git a/src/plugins/scxmleditor/plugin_interface/scxmldocument.cpp b/src/plugins/scxmleditor/plugin_interface/scxmldocument.cpp
index ed4ce3e507..4b7d61175c 100644
--- a/src/plugins/scxmleditor/plugin_interface/scxmldocument.cpp
+++ b/src/plugins/scxmleditor/plugin_interface/scxmldocument.cpp
@@ -262,16 +262,16 @@ void ScxmlDocument::initErrorMessage(const QXmlStreamReader &xml, QIODevice *io)
QString errorString;
switch (xml.error()) {
case QXmlStreamReader::Error::UnexpectedElementError:
- errorString = tr("Unexpected element");
+ errorString = tr("Unexpected element.");
break;
case QXmlStreamReader::Error::NotWellFormedError:
- errorString = tr("Not well formed");
+ errorString = tr("Not well formed.");
break;
case QXmlStreamReader::Error::PrematureEndOfDocumentError:
- errorString = tr("Premature end of document");
+ errorString = tr("Premature end of document.");
break;
case QXmlStreamReader::Error::CustomError:
- errorString = tr("Custom error");
+ errorString = tr("Custom error.");
break;
default:
break;
@@ -299,7 +299,7 @@ bool ScxmlDocument::pasteData(const QByteArray &data, const QPointF &minPos, con
if (!m_currentTag) {
m_hasError = true;
- m_lastError = tr("Current tag not selected");
+ m_lastError = tr("Current tag is not selected.");
return false;
}
@@ -310,7 +310,7 @@ bool ScxmlDocument::pasteData(const QByteArray &data, const QPointF &minPos, con
}
bool ok = true;
- m_undoStack->beginMacro(tr("Paste item(s)"));
+ m_undoStack->beginMacro(tr("Paste items"));
QByteArray d(data);
QBuffer buffer(&d);
@@ -458,7 +458,7 @@ bool ScxmlDocument::save(const QString &fileName)
}
file.close();
if (!ok)
- m_lastError = tr("Cannot save xml to the file %1.").arg(fileName);
+ m_lastError = tr("Cannot save XML to the file %1.").arg(fileName);
} else {
ok = false;
m_lastError = tr("Cannot open file %1.").arg(fileName);
diff --git a/src/plugins/scxmleditor/plugin_interface/stateitem.cpp b/src/plugins/scxmleditor/plugin_interface/stateitem.cpp
index 3f88a25ec0..532851632c 100644
--- a/src/plugins/scxmleditor/plugin_interface/stateitem.cpp
+++ b/src/plugins/scxmleditor/plugin_interface/stateitem.cpp
@@ -329,7 +329,7 @@ void StateItem::selectedMenuAction(const QAction *action)
case TagUtils::SetAsInitial: {
ScxmlTag *parentTag = tag->parentTag();
if (parentTag) {
- document->undoStack()->beginMacro(tr("Change initial-state"));
+ document->undoStack()->beginMacro(tr("Change initial state"));
ScxmlTag *initialTag = parentTag->child("initial");
if (initialTag) {
diff --git a/src/plugins/scxmleditor/scxmleditorconstants.h b/src/plugins/scxmleditor/scxmleditorconstants.h
index 8dd3bc360e..c503ab5f48 100644
--- a/src/plugins/scxmleditor/scxmleditorconstants.h
+++ b/src/plugins/scxmleditor/scxmleditorconstants.h
@@ -33,7 +33,7 @@ namespace Constants {
const char INFO_READ_ONLY[] = "ScxmlEditor.ReadOnly";
const char C_SCXMLEDITOR[] = "Qt5.ScxmlEditor";
-const char C_SCXMLEDITOR_DISPLAY_NAME[] = QT_TRANSLATE_NOOP("OpenWith::Editors", "Scxml Editor");
+const char C_SCXMLEDITOR_DISPLAY_NAME[] = QT_TRANSLATE_NOOP("OpenWith::Editors", "SCXML Editor");
const char K_SCXML_EDITOR_ID[] = "ScxmlEditor.XmlEditor";
const char C_SCXML_EDITOR[] = "Scxml Editor";
diff --git a/src/plugins/texteditor/circularclipboardassist.cpp b/src/plugins/texteditor/circularclipboardassist.cpp
index 6f3e4e4349..0941a83bfe 100644
--- a/src/plugins/texteditor/circularclipboardassist.cpp
+++ b/src/plugins/texteditor/circularclipboardassist.cpp
@@ -94,6 +94,7 @@ public:
QIcon icon = QIcon::fromTheme(QLatin1String("edit-paste"), Utils::Icons::PASTE.icon()).pixmap(16);
CircularClipboard * clipboard = CircularClipboard::instance();
QList<AssistProposalItemInterface *> items;
+ items.reserve(clipboard->size());
for (int i = 0; i < clipboard->size(); ++i) {
QSharedPointer<const QMimeData> data = clipboard->next();
diff --git a/src/plugins/texteditor/textdocumentlayout.cpp b/src/plugins/texteditor/textdocumentlayout.cpp
index f413b5c363..df6a82495d 100644
--- a/src/plugins/texteditor/textdocumentlayout.cpp
+++ b/src/plugins/texteditor/textdocumentlayout.cpp
@@ -527,7 +527,7 @@ void TextDocumentLayout::setFolded(const QTextBlock &block, bool folded)
if (folded)
userData(block)->setFolded(true);
else if (TextBlockUserData *userData = testUserData(block))
- return userData->setFolded(false);
+ userData->setFolded(false);
}
void TextDocumentLayout::requestExtraAreaUpdate()
diff --git a/src/plugins/valgrind/callgrind/callgrindproxymodel.cpp b/src/plugins/valgrind/callgrind/callgrindproxymodel.cpp
index 44df8fbbc8..c1ac384062 100644
--- a/src/plugins/valgrind/callgrind/callgrindproxymodel.cpp
+++ b/src/plugins/valgrind/callgrind/callgrindproxymodel.cpp
@@ -121,14 +121,17 @@ bool DataProxyModel::filterAcceptsRow(int source_row, const QModelIndex &source_
const Function *func = source_index.data(DataModel::FunctionRole).value<const Function *>();
+ if (!func)
+ return false;
+
// check if func is located in the specific base directory, if any
- if (func && !m_baseDir.isEmpty()) {
+ if (!m_baseDir.isEmpty()) {
if (!func->location().startsWith(m_baseDir))
return false;
}
// check if the function from this index is a child of (called by) the filter function
- if (func && m_function) {
+ if (m_function) {
bool isValid = false;
foreach (const FunctionCall *call, func->incomingCalls()) {
if (call->caller() == m_function) {
diff --git a/src/shared/qbs b/src/shared/qbs
-Subproject 28f803d359c5f3102514d7817478cb492711410
+Subproject cc99f7de4e1578feb1ca8e5a2ca7384b25b6d42
diff --git a/tests/auto/debugger/tst_dumpers.cpp b/tests/auto/debugger/tst_dumpers.cpp
index 7f5cd801f8..aa57ee7fe9 100644
--- a/tests/auto/debugger/tst_dumpers.cpp
+++ b/tests/auto/debugger/tst_dumpers.cpp
@@ -1546,6 +1546,7 @@ void tst_Dumpers::dumper()
Context context(m_debuggerEngine);
QByteArray contents;
+ GdbMi actual;
if (m_debuggerEngine == GdbEngine) {
int posDataStart = output.indexOf("data=");
if (posDataStart == -1) {
@@ -1555,9 +1556,9 @@ void tst_Dumpers::dumper()
contents = output.mid(posDataStart);
contents.replace("\\\"", "\"");
- GdbMi actualx;
- actualx.fromStringMultiple(contents);
- context.nameSpace = actualx["qtnamespace"].data();
+ actual.fromStringMultiple(contents);
+ context.nameSpace = actual["qtnamespace"].data();
+ actual = actual["data"];
//qDebug() << "FOUND NS: " << context.nameSpace;
} else if (m_debuggerEngine == LldbEngine) {
@@ -1579,6 +1580,7 @@ void tst_Dumpers::dumper()
if (context.nameSpace == "::")
context.nameSpace.clear();
contents.replace("\\\"", "\"");
+ actual.fromString(contents);
} else {
QByteArray localsAnswerStart("<qtcreatorcdbext>|R|42|");
QByteArray locals("|script|");
@@ -1594,15 +1596,10 @@ void tst_Dumpers::dumper()
if (localsBeginPos != -1)
localsBeginPos = output.indexOf(locals, localsBeginPos);
} while (localsBeginPos != -1);
- GdbMi result;
- result.fromString(contents);
- if (result.childCount() != 0)
- contents = result.childAt(0).toString().toLocal8Bit();
+ actual.fromString(contents);
+ actual = actual["result"]["data"];
}
- GdbMi actual;
- actual.fromString(contents);
-
WatchItem local;
local.iname = "local";
@@ -1895,6 +1892,17 @@ void tst_Dumpers::dumper_data()
+ Check("c", "120", "@QChar");
+ QTest::newRow("QFlags")
+ << Data("#include <QFlags>\n"
+ "enum Foo { a = 0x1, b = 0x2 };\n"
+ "Q_DECLARE_FLAGS(FooFlags, Foo)\n"
+ "Q_DECLARE_OPERATORS_FOR_FLAGS(FooFlags)\n",
+ "FooFlags f1(a);\n"
+ "FooFlags f2(a | b);\n")
+ + CoreProfile()
+ + Check("f1", "a (1)", TypeDef("QFlags<enum Foo>", "FooFlags"))
+ + Check("f2", "(a | b) (3)", "FooFlags") % GdbEngine;
+
QTest::newRow("QDateTime")
<< Data("#include <QDateTime>\n",
@@ -5236,6 +5244,18 @@ void tst_Dumpers::dumper_data()
+ Check("s32s", "-2147483648", TypeDef("int", "@qint32"));
+ QTest::newRow("Float")
+ << Data("#include <QFloat16>\n",
+ "qfloat16 f1 = 45.3f; unused(&f1);\n"
+ "qfloat16 f2 = 45.1f; unused(&f2);\n")
+ + CoreProfile()
+ + QtVersion(0x50900)
+ // Using numpy:
+ // + Check("f1", "45.281", "@qfloat16")
+ // + Check("f2", "45.094", "@qfloat16");
+ + Check("f1", "45.28125", "@qfloat16")
+ + Check("f2", "45.09375", "@qfloat16");
+
QTest::newRow("Enum")
<< Data("\n"
diff --git a/tests/auto/extensionsystem/pluginspec/tst_pluginspec.cpp b/tests/auto/extensionsystem/pluginspec/tst_pluginspec.cpp
index 2c01134fad..b277d77d80 100644
--- a/tests/auto/extensionsystem/pluginspec/tst_pluginspec.cpp
+++ b/tests/auto/extensionsystem/pluginspec/tst_pluginspec.cpp
@@ -60,7 +60,7 @@ static QString libraryName(const QString &basename)
#elif defined(Q_OS_UNIX)
return QLatin1String("lib") + basename + QLatin1String(".so");
#else
- return basename + QLatin1String("d.dll");
+ return basename + QLatin1String("d4.dll");
#endif
}
diff --git a/tests/auto/qml/qmldesigner/coretests/tst_testcore.cpp b/tests/auto/qml/qmldesigner/coretests/tst_testcore.cpp
index 177df3a4f3..25fd1008d3 100644
--- a/tests/auto/qml/qmldesigner/coretests/tst_testcore.cpp
+++ b/tests/auto/qml/qmldesigner/coretests/tst_testcore.cpp
@@ -205,7 +205,7 @@ void tst_TestCore::initTestCase()
#endif
qDebug() << pluginPath;
- Q_ASSERT(QFileInfo(pluginPath).exists());
+ Q_ASSERT(QFileInfo::exists(pluginPath));
MetaInfo::setPluginPaths(QStringList() << pluginPath);
QFileInfo builtins(resourcePath() + "/qml-type-descriptions/builtins.qmltypes");
diff --git a/tests/auto/qml/reformatter/comments.qml b/tests/auto/qml/reformatter/comments.qml
index 61889ea007..5bffa03d81 100644
--- a/tests/auto/qml/reformatter/comments.qml
+++ b/tests/auto/qml/reformatter/comments.qml
@@ -13,4 +13,14 @@ Item {
/*
Indented multiline comment.
*/
+
+ // Comment over a signal.
+ signal foo
+
+ function test() {
+ for (var i = model.count - 1; i >= 0; --i) // in-line comment
+ {
+ console.log("test")
+ }
+ }
}
diff --git a/tests/system/shared/debugger.py b/tests/system/shared/debugger.py
index 74ea190a30..49a83b1ca2 100644
--- a/tests/system/shared/debugger.py
+++ b/tests/system/shared/debugger.py
@@ -128,7 +128,6 @@ def doSimpleDebugging(kitCount, currentKit, currentConfigName, pressContinueCoun
expectedLabelTexts = ['Stopped\.', 'Stopped at breakpoint \d+ \(\d+\) in thread \d+\.']
if len(expectedBPOrder) == 0:
expectedLabelTexts.append("Running\.")
- expectedLabelTexts.append("QML Debugger: Error: Unknown socket error 0")
switchViewTo(ViewConstants.PROJECTS)
switchToBuildOrRunSettingsFor(kitCount, currentKit, ProjectSettings.RUN)
ensureChecked(waitForObject("{container=':Qt Creator.scrollArea_QScrollArea' text='Enable QML' "
diff --git a/tests/system/suite_tools/tst_codepasting/test.py b/tests/system/suite_tools/tst_codepasting/test.py
index 5a5c16dfa5..037b0f2090 100644
--- a/tests/system/suite_tools/tst_codepasting/test.py
+++ b/tests/system/suite_tools/tst_codepasting/test.py
@@ -44,6 +44,7 @@ def main():
aut = currentApplicationContext()
# make sure General Messages is open
openGeneralMessages()
+ clickButton(waitForObject(":*Qt Creator.Clear_QToolButton"))
for protocol in protocolsToTest:
invokeMenuItem("File", "Open File or Project...")
selectFromFileDialog(sourceFile)