summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-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
213 files changed, 3795 insertions, 1750 deletions
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