diff options
author | Eike Ziller <eike.ziller@qt.io> | 2018-05-22 09:55:58 +0200 |
---|---|---|
committer | Eike Ziller <eike.ziller@qt.io> | 2018-05-22 09:55:58 +0200 |
commit | d2a9e1b892456b0500bdc79ca749d2bdf02afab5 (patch) | |
tree | fe10e481a90e2a06c335cf4f9790527dc564bc3c /src/plugins | |
parent | a2fe4087ffab6625c81d583d9c2432e63312bcb2 (diff) | |
parent | dab2045099a4482296d5f46faff4e34f08e32f6a (diff) |
Merge remote-tracking branch 'origin/4.7'
Change-Id: I00dd929a4ed32af8f1b76cea57a7c49239dafc7c
Diffstat (limited to 'src/plugins')
34 files changed, 468 insertions, 538 deletions
diff --git a/src/plugins/android/android.pro b/src/plugins/android/android.pro index d26264df20..e17c7e284b 100644 --- a/src/plugins/android/android.pro +++ b/src/plugins/android/android.pro @@ -46,7 +46,6 @@ HEADERS += \ android_global.h \ androidbuildapkstep.h \ androidbuildapkwidget.h \ - androidrunnable.h \ androidtoolmanager.h \ androidsdkmanager.h \ androidavdmanager.h \ @@ -94,7 +93,6 @@ SOURCES += \ androidbuildapkstep.cpp \ androidbuildapkwidget.cpp \ androidqtsupport.cpp \ - androidrunnable.cpp \ androidtoolmanager.cpp \ androidsdkmanager.cpp \ androidavdmanager.cpp \ diff --git a/src/plugins/android/android.qbs b/src/plugins/android/android.qbs index 4b9ce0545e..b573d3883b 100644 --- a/src/plugins/android/android.qbs +++ b/src/plugins/android/android.qbs @@ -86,8 +86,6 @@ Project { "androidrunconfiguration.h", "androidruncontrol.cpp", "androidruncontrol.h", - "androidrunnable.cpp", - "androidrunnable.h", "androidrunner.cpp", "androidrunner.h", "androidrunnerworker.cpp", diff --git a/src/plugins/android/androidavdmanager.cpp b/src/plugins/android/androidavdmanager.cpp index 85351e3228..44ed85b170 100644 --- a/src/plugins/android/androidavdmanager.cpp +++ b/src/plugins/android/androidavdmanager.cpp @@ -297,6 +297,7 @@ bool AndroidAvdManager::startAvdAsync(const QString &avdName) const return false; } QProcess *avdProcess = new QProcess(); + avdProcess->setReadChannelMode(QProcess::MergedChannels); QObject::connect(avdProcess, static_cast<void (QProcess::*)(int)>(&QProcess::finished), avdProcess, diff --git a/src/plugins/android/androidconfigurations.h b/src/plugins/android/androidconfigurations.h index 15d27413bd..58dde7479b 100644 --- a/src/plugins/android/androidconfigurations.h +++ b/src/plugins/android/androidconfigurations.h @@ -232,3 +232,4 @@ private: } // namespace Android +Q_DECLARE_METATYPE(Android::AndroidDeviceInfo) diff --git a/src/plugins/android/androidconstants.h b/src/plugins/android/androidconstants.h index 0015c69ff5..2ff36be77e 100644 --- a/src/plugins/android/androidconstants.h +++ b/src/plugins/android/androidconstants.h @@ -51,9 +51,11 @@ const char ANDROID_SETTINGS_ID[] = "BB.Android Configurations"; const char ANDROID_TOOLCHAIN_ID[] = "Qt4ProjectManager.ToolChain.Android"; const char ANDROIDQT[] = "Qt4ProjectManager.QtVersion.Android"; -const char ANDROID_AMSTARTARGS_ASPECT[] = "Android.AmStartArgs"; -const char ANDROID_PRESTARTSHELLCMDLIST_ASPECT[] = "Android.PreStartShellCmdList"; -const char ANDROID_POSTSTARTSHELLCMDLIST_ASPECT[] = "Android.PostStartShellCmdList"; +const char ANDROID_AMSTARTARGS[] = "Android.AmStartArgs"; +// Note: Can be set on RunConfiguration using an aspect and/or +// the AndroidRunnerWorker using recordData() +const char ANDROID_PRESTARTSHELLCMDLIST[] = "Android.PreStartShellCmdList"; +const char ANDROID_POSTFINISHSHELLCMDLIST[] = "Android.PostFinishShellCmdList"; const char ANDROID_DEVICE_TYPE[] = "Android.Device.Type"; const char ANDROID_DEVICE_ID[] = "Android Device"; @@ -69,6 +71,7 @@ const char ANDROID_DEPLOY_SETTINGS_FILE[] = "AndroidDeploySettingsFile"; const char ANDROID_PACKAGE_SOURCE_DIR[] = "AndroidPackageSourceDir"; const char ANDROID_EXTRA_LIBS[] = "AndroidExtraLibs"; +const char ANDROID_PACKAGENAME[] = "Android.PackageName"; const char ANDROID_PACKAGE_INSTALLATION_STEP_ID[] = "Qt4ProjectManager.AndroidPackageInstallationStep"; } // namespace Constants; diff --git a/src/plugins/android/androidrunconfiguration.cpp b/src/plugins/android/androidrunconfiguration.cpp index ac44a54698..ac1a6858be 100644 --- a/src/plugins/android/androidrunconfiguration.cpp +++ b/src/plugins/android/androidrunconfiguration.cpp @@ -111,20 +111,20 @@ AndroidRunConfiguration::AndroidRunConfiguration(Target *target, Core::Id id) : RunConfiguration(target, id) { auto amStartArgsAspect = new BaseStringAspect(this); - amStartArgsAspect->setId(Constants::ANDROID_AMSTARTARGS_ASPECT); + amStartArgsAspect->setId(Constants::ANDROID_AMSTARTARGS); amStartArgsAspect->setSettingsKey("Android.AmStartArgsKey"); amStartArgsAspect->setLabelText(tr("Activity manager start options:")); amStartArgsAspect->setDisplayStyle(BaseStringAspect::LineEditDisplay); addExtraAspect(amStartArgsAspect); auto preStartShellCmdAspect = new BaseStringListAspect(this); - preStartShellCmdAspect->setId(Constants::ANDROID_PRESTARTSHELLCMDLIST_ASPECT); + preStartShellCmdAspect->setId(Constants::ANDROID_PRESTARTSHELLCMDLIST); preStartShellCmdAspect->setSettingsKey("Android.PreStartShellCmdListKey"); preStartShellCmdAspect->setLabel(tr("Shell commands to run on Android device before application launch.")); addExtraAspect(preStartShellCmdAspect); auto postStartShellCmdAspect = new BaseStringListAspect(this); - postStartShellCmdAspect->setId(Constants::ANDROID_POSTSTARTSHELLCMDLIST_ASPECT); + postStartShellCmdAspect->setId(Constants::ANDROID_POSTFINISHSHELLCMDLIST); postStartShellCmdAspect->setSettingsKey("Android.PostStartShellCmdListKey"); postStartShellCmdAspect->setLabel(tr("Shell commands to run on Android device after application quits.")); addExtraAspect(postStartShellCmdAspect); @@ -140,7 +140,7 @@ QWidget *AndroidRunConfiguration::createConfigurationWidget() auto widget = new QWidget; auto layout = new QFormLayout(widget); - extraAspect(Constants::ANDROID_AMSTARTARGS_ASPECT)->addToConfigurationLayout(layout); + extraAspect(Constants::ANDROID_AMSTARTARGS)->addToConfigurationLayout(layout); auto warningIconLabel = new QLabel; warningIconLabel->setPixmap(Utils::Icons::WARNING.pixmap()); @@ -148,8 +148,8 @@ QWidget *AndroidRunConfiguration::createConfigurationWidget() auto warningLabel = new QLabel(tr("If the \"am start\" options conflict, the application might not start.")); layout->addRow(warningIconLabel, warningLabel); - extraAspect(Constants::ANDROID_PRESTARTSHELLCMDLIST_ASPECT)->addToConfigurationLayout(layout); - extraAspect(Constants::ANDROID_POSTSTARTSHELLCMDLIST_ASPECT)->addToConfigurationLayout(layout); + extraAspect(Constants::ANDROID_PRESTARTSHELLCMDLIST)->addToConfigurationLayout(layout); + extraAspect(Constants::ANDROID_POSTFINISHSHELLCMDLIST)->addToConfigurationLayout(layout); auto wrapped = wrapWidget(widget); auto detailsWidget = qobject_cast<DetailsWidget *>(wrapped); diff --git a/src/plugins/android/androidrunnable.cpp b/src/plugins/android/androidrunnable.cpp deleted file mode 100644 index ae70bd71dd..0000000000 --- a/src/plugins/android/androidrunnable.cpp +++ /dev/null @@ -1,37 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2016 The Qt Company Ltd. -** Contact: https://www.qt.io/licensing/ -** -** This file is part of Qt Creator. -** -** Commercial License Usage -** Licensees holding valid commercial Qt licenses may use this file in -** accordance with the commercial license agreement provided with the -** Software or, alternatively, in accordance with the terms contained in -** a written agreement between you and The Qt Company. For licensing terms -** and conditions see https://www.qt.io/terms-conditions. For further -** information use the contact form at https://www.qt.io/contact-us. -** -** GNU General Public License Usage -** Alternatively, this file may be used under the terms of the GNU -** General Public License version 3 as published by the Free Software -** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT -** included in the packaging of this file. Please review the following -** information to ensure the GNU General Public License requirements will -** be met: https://www.gnu.org/licenses/gpl-3.0.html. -** -****************************************************************************/ - -#include "androidrunnable.h" - -namespace Android { - -void *AndroidRunnable::staticTypeId = &AndroidRunnable::staticTypeId; - -AndroidRunnable::AndroidRunnable() -{ - qRegisterMetaType<AndroidRunnable>("AndroidRunnable"); -} - -} // namespace Android diff --git a/src/plugins/android/androidrunnable.h b/src/plugins/android/androidrunnable.h deleted file mode 100644 index e549acf590..0000000000 --- a/src/plugins/android/androidrunnable.h +++ /dev/null @@ -1,57 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2016 BogDan Vatra <bog_dan_ro@yahoo.com> -** Contact: https://www.qt.io/licensing/ -** -** This file is part of Qt Creator. -** -** Commercial License Usage -** Licensees holding valid commercial Qt licenses may use this file in -** accordance with the commercial license agreement provided with the -** Software or, alternatively, in accordance with the terms contained in -** a written agreement between you and The Qt Company. For licensing terms -** and conditions see https://www.qt.io/terms-conditions. For further -** information use the contact form at https://www.qt.io/contact-us. -** -** GNU General Public License Usage -** Alternatively, this file may be used under the terms of the GNU -** General Public License version 3 as published by the Free Software -** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT -** included in the packaging of this file. Please review the following -** information to ensure the GNU General Public License requirements will -** be met: https://www.gnu.org/licenses/gpl-3.0.html. -** -****************************************************************************/ - -#pragma once - -#include "android_global.h" -#include <projectexplorer/runnables.h> - -namespace Android { - -struct ANDROID_EXPORT AndroidRunnable -{ - AndroidRunnable(); - QString packageName; - QStringList beforeStartAdbCommands; - QStringList afterFinishAdbCommands; - - QString displayName() const { return packageName; } - static void *staticTypeId; -}; - -inline bool operator==(const AndroidRunnable &r1, const AndroidRunnable &r2) -{ - return r1.packageName == r2.packageName - && r1.beforeStartAdbCommands == r2.beforeStartAdbCommands - && r1.afterFinishAdbCommands == r2.afterFinishAdbCommands; -} - -inline bool operator!=(const AndroidRunnable &r1, const AndroidRunnable &r2) -{ - return !(r1 == r2); -} - -} // namespace Android -Q_DECLARE_METATYPE(Android::AndroidRunnable) diff --git a/src/plugins/android/androidrunner.cpp b/src/plugins/android/androidrunner.cpp index ce4a0c918c..4ea111aeb3 100644 --- a/src/plugins/android/androidrunner.cpp +++ b/src/plugins/android/androidrunner.cpp @@ -120,7 +120,8 @@ AndroidRunner::AndroidRunner(RunControl *runControl, setDisplayName("AndroidRunner"); static const int metaTypes[] = { qRegisterMetaType<QVector<QStringList> >("QVector<QStringList>"), - qRegisterMetaType<Utils::Port>("Utils::Port") + qRegisterMetaType<Utils::Port>("Utils::Port"), + qRegisterMetaType<AndroidDeviceInfo>("Android::AndroidDeviceInfo") }; Q_UNUSED(metaTypes); @@ -128,21 +129,10 @@ AndroidRunner::AndroidRunner(RunControl *runControl, connect(&m_checkAVDTimer, &QTimer::timeout, this, &AndroidRunner::checkAVD); QString intent = intentName.isEmpty() ? AndroidManager::intentName(m_target) : intentName; - m_androidRunnable.packageName = intent.left(intent.indexOf('/')); - - RunConfiguration *rc = runControl->runConfiguration(); - if (auto aspect = rc->extraAspect(Constants::ANDROID_PRESTARTSHELLCMDLIST_ASPECT)) { - for (QString shellCmd : static_cast<BaseStringListAspect *>(aspect)->value()) - m_androidRunnable.beforeStartAdbCommands.append(QString("shell %1").arg(shellCmd)); - } - - if (auto aspect = rc->extraAspect(Constants::ANDROID_POSTSTARTSHELLCMDLIST_ASPECT)) { - for (QString shellCmd : static_cast<BaseStringListAspect *>(aspect)->value()) - m_androidRunnable.afterFinishAdbCommands.append(QString("shell %1").arg(shellCmd)); - } + m_packageName = intent.left(intent.indexOf('/')); const int apiLevel = AndroidManager::deviceApiLevel(m_target); - m_worker.reset(new AndroidRunnerWorker(this, m_androidRunnable)); + m_worker.reset(new AndroidRunnerWorker(this, m_packageName)); m_worker->setIntentName(intent); m_worker->setIsPreNougat(apiLevel <= 23); m_worker->setExtraAppParams(extraAppParams); @@ -193,7 +183,7 @@ void AndroidRunner::stop() { if (m_checkAVDTimer.isActive()) { m_checkAVDTimer.stop(); - appendMessage("\n\n" + tr("\"%1\" terminated.").arg(m_androidRunnable.packageName), + appendMessage("\n\n" + tr("\"%1\" terminated.").arg(m_packageName), Utils::DebugFormat); return; } @@ -258,7 +248,7 @@ void AndroidRunner::launchAVD() emit androidDeviceInfoChanged(info); if (info.isValid()) { AndroidAvdManager avdManager; - if (avdManager.findAvd(info.avdname).isEmpty()) { + if (!info.avdname.isEmpty() && avdManager.findAvd(info.avdname).isEmpty()) { bool launched = avdManager.startAvdAsync(info.avdname); m_launchedAVDName = launched ? info.avdname:""; } else { diff --git a/src/plugins/android/androidrunner.h b/src/plugins/android/androidrunner.h index 28212a08db..c1cd170c68 100644 --- a/src/plugins/android/androidrunner.h +++ b/src/plugins/android/androidrunner.h @@ -26,7 +26,6 @@ #pragma once #include "androidconfigurations.h" -#include "androidrunnable.h" #include <projectexplorer/runconfiguration.h> #include <qmldebug/qmldebugcommandlinearguments.h> @@ -67,7 +66,7 @@ signals: void asyncStart(); void asyncStop(); void qmlServerReady(const QUrl &serverUrl); - void androidDeviceInfoChanged(const AndroidDeviceInfo &deviceInfo); + void androidDeviceInfoChanged(const Android::AndroidDeviceInfo &deviceInfo); void avdDetected(); private: @@ -80,7 +79,7 @@ private: void checkAVD(); void launchAVD(); - AndroidRunnable m_androidRunnable; + QString m_packageName; QString m_launchedAVDName; QThread m_thread; QTimer m_checkAVDTimer; diff --git a/src/plugins/android/androidrunnerworker.cpp b/src/plugins/android/androidrunnerworker.cpp index 05071d1d06..62eedaa4c3 100644 --- a/src/plugins/android/androidrunnerworker.cpp +++ b/src/plugins/android/androidrunnerworker.cpp @@ -140,8 +140,8 @@ static void deleter(QProcess *p) p->deleteLater(); } -AndroidRunnerWorker::AndroidRunnerWorker(RunWorker *runner, const AndroidRunnable &runnable) - : m_androidRunnable(runnable) +AndroidRunnerWorker::AndroidRunnerWorker(RunWorker *runner, const QString &packageName) + : m_packageName(packageName) , m_adbLogcatProcess(nullptr, deleter) , m_psIsAlive(nullptr, deleter) , m_logCatRegExp(regExpLogcat) @@ -181,8 +181,22 @@ AndroidRunnerWorker::AndroidRunnerWorker(RunWorker *runner, const AndroidRunnabl m_deviceSerialNumber = AndroidManager::deviceSerialNumber(target); m_apiLevel = AndroidManager::deviceApiLevel(target); - if (auto aspect = runConfig->extraAspect(Constants::ANDROID_AMSTARTARGS_ASPECT)) + if (auto aspect = runConfig->extraAspect(Constants::ANDROID_AMSTARTARGS)) m_amStartExtraArgs = static_cast<BaseStringAspect *>(aspect)->value().split(' '); + + if (auto aspect = runConfig->extraAspect(Constants::ANDROID_PRESTARTSHELLCMDLIST)) { + for (const QString &shellCmd : static_cast<BaseStringListAspect *>(aspect)->value()) + m_beforeStartAdbCommands.append(QString("shell %1").arg(shellCmd)); + } + for (const QString &shellCmd : runner->recordedData(Constants::ANDROID_PRESTARTSHELLCMDLIST).toStringList()) + m_beforeStartAdbCommands.append(QString("shell %1").arg(shellCmd)); + + if (auto aspect = runConfig->extraAspect(Constants::ANDROID_POSTFINISHSHELLCMDLIST)) { + for (const QString &shellCmd : static_cast<BaseStringListAspect *>(aspect)->value()) + m_afterFinishAdbCommands.append(QString("shell %1").arg(shellCmd)); + } + for (const QString &shellCmd : runner->recordedData(Constants::ANDROID_POSTFINISHSHELLCMDLIST).toStringList()) + m_afterFinishAdbCommands.append(QString("shell %1").arg(shellCmd)); } AndroidRunnerWorker::~AndroidRunnerWorker() @@ -229,7 +243,7 @@ bool AndroidRunnerWorker::runAdb(const QStringList &args, int timeoutS) void AndroidRunnerWorker::adbKill(qint64 pid) { runAdb({"shell", "kill", "-9", QString::number(pid)}); - runAdb({"shell", "run-as", m_androidRunnable.packageName, "kill", "-9", QString::number(pid)}); + runAdb({"shell", "run-as", m_packageName, "kill", "-9", QString::number(pid)}); } QStringList AndroidRunnerWorker::selector() const @@ -239,14 +253,14 @@ QStringList AndroidRunnerWorker::selector() const void AndroidRunnerWorker::forceStop() { - runAdb({"shell", "am", "force-stop", m_androidRunnable.packageName}, 30); + runAdb({"shell", "am", "force-stop", m_packageName}, 30); // try killing it via kill -9 const QByteArray out = Utils::SynchronousProcess() .runBlocking(m_adb, selector() << QStringLiteral("shell") << pidScriptPreNougat) .allRawOutput(); - qint64 pid = extractPID(out.simplified(), m_androidRunnable.packageName); + qint64 pid = extractPID(out.simplified(), m_packageName); if (pid != -1) { adbKill(pid); } @@ -346,7 +360,7 @@ void AndroidRunnerWorker::asyncStartHelper() QTC_ASSERT(!m_adbLogcatProcess, /**/); m_adbLogcatProcess = std::move(logcatProcess); - for (const QString &entry: m_androidRunnable.beforeStartAdbCommands) + for (const QString &entry : m_beforeStartAdbCommands) runAdb(entry.split(' ', QString::SkipEmptyParts)); QStringList args({"shell", "am", "start"}); @@ -356,14 +370,14 @@ void AndroidRunnerWorker::asyncStartHelper() args << "-D"; QString gdbServerSocket; // run-as <package-name> pwd fails on API 22 so route the pwd through shell. - if (!runAdb({"shell", "run-as", m_androidRunnable.packageName, "/system/bin/sh", "-c", "pwd"})) { + if (!runAdb({"shell", "run-as", m_packageName, "/system/bin/sh", "-c", "pwd"})) { emit remoteProcessFinished(tr("Failed to get process path. Reason: %1.").arg(m_lastRunAdbError)); return; } gdbServerSocket = QString::fromUtf8(m_lastRunAdbRawOutput.trimmed()) + "/debug-socket"; QString gdbServerExecutable; - if (!runAdb({"shell", "run-as", m_androidRunnable.packageName, "ls", "lib/"})) { + if (!runAdb({"shell", "run-as", m_packageName, "ls", "lib/"})) { emit remoteProcessFinished(tr("Failed to get process path. Reason: %1.").arg(m_lastRunAdbError)); return; } @@ -380,11 +394,11 @@ void AndroidRunnerWorker::asyncStartHelper() return; } - runAdb({"shell", "run-as", m_androidRunnable.packageName, "killall", gdbServerExecutable}); - runAdb({"shell", "run-as", m_androidRunnable.packageName, "rm", gdbServerSocket}); + runAdb({"shell", "run-as", m_packageName, "killall", gdbServerExecutable}); + runAdb({"shell", "run-as", m_packageName, "rm", gdbServerSocket}); std::unique_ptr<QProcess, Deleter> gdbServerProcess(new QProcess, deleter); gdbServerProcess->start(m_adb, selector() << "shell" << "run-as" - << m_androidRunnable.packageName << "lib/" + gdbServerExecutable + << m_packageName << "lib/" + gdbServerExecutable << "--multi" << "+" + gdbServerSocket); if (!gdbServerProcess->waitForStarted()) { emit remoteProcessFinished(tr("Failed to start C++ debugger.")); @@ -398,7 +412,7 @@ void AndroidRunnerWorker::asyncStartHelper() emit remoteProcessFinished(tr("Failed to forward C++ debugging ports. Reason: %1.").arg(m_lastRunAdbError)); return; } - m_androidRunnable.afterFinishAdbCommands.push_back(removeForward.join(' ')); + m_afterFinishAdbCommands.push_back(removeForward.join(' ')); } if (m_qmlDebugServices != QmlDebug::NoQmlDebugServices) { @@ -411,7 +425,7 @@ void AndroidRunnerWorker::asyncStartHelper() .arg(m_lastRunAdbError)); return; } - m_androidRunnable.afterFinishAdbCommands.push_back(removeForward.join(' ')); + m_afterFinishAdbCommands.push_back(removeForward.join(' ')); args << "-e" << "qml_debug" << "true" << "-e" << "qmljsdebugger" @@ -442,7 +456,7 @@ void AndroidRunnerWorker::asyncStart() asyncStartHelper(); m_pidFinder = Utils::onResultReady(Utils::runAsync(findProcessPID, m_adb, selector(), - m_androidRunnable.packageName, m_isPreNougat), + m_packageName, m_isPreNougat), bind(&AndroidRunnerWorker::onProcessIdChanged, this, _1)); } @@ -467,7 +481,7 @@ void AndroidRunnerWorker::handleJdbWaiting() emit remoteProcessFinished(tr("Failed to forward jdb debugging ports. Reason: %1.").arg(m_lastRunAdbError)); return; } - m_androidRunnable.afterFinishAdbCommands.push_back(removeForward.join(' ')); + m_afterFinishAdbCommands.push_back(removeForward.join(' ')); auto jdbPath = AndroidConfigurations::currentConfig().openJDKLocation().appendPath("bin"); if (Utils::HostOsInfo::isWindowsHost()) @@ -527,7 +541,7 @@ void AndroidRunnerWorker::onProcessIdChanged(qint64 pid) m_processPID = pid; if (pid == -1) { emit remoteProcessFinished(QLatin1String("\n\n") + tr("\"%1\" died.") - .arg(m_androidRunnable.packageName)); + .arg(m_packageName)); // App died/killed. Reset log, monitor, jdb & gdb processes. m_adbLogcatProcess.reset(); m_psIsAlive.reset(); @@ -535,7 +549,7 @@ void AndroidRunnerWorker::onProcessIdChanged(qint64 pid) m_gdbServerProcess.reset(); // Run adb commands after application quit. - for (const QString &entry: m_androidRunnable.afterFinishAdbCommands) + for (const QString &entry: m_afterFinishAdbCommands) runAdb(entry.split(' ', QString::SkipEmptyParts)); } else { // In debugging cases this will be funneled to the engine to actually start diff --git a/src/plugins/android/androidrunnerworker.h b/src/plugins/android/androidrunnerworker.h index 768b34a19c..e34207bf03 100644 --- a/src/plugins/android/androidrunnerworker.h +++ b/src/plugins/android/androidrunnerworker.h @@ -26,12 +26,12 @@ #pragma once +#include <projectexplorer/runconfiguration.h> + #include <qmldebug/qmldebugcommandlinearguments.h> #include <QFuture> -#include "androidrunnable.h" - namespace Android { class AndroidDeviceInfo; @@ -44,7 +44,7 @@ class AndroidRunnerWorker : public QObject { Q_OBJECT public: - AndroidRunnerWorker(ProjectExplorer::RunWorker *runner, const AndroidRunnable &runnable); + AndroidRunnerWorker(ProjectExplorer::RunWorker *runner, const QString &packageName); ~AndroidRunnerWorker() override; bool adbShellAmNeedsQuotes(); bool runAdb(const QStringList &args, int timeoutS = 10); @@ -85,8 +85,10 @@ protected: // Create the processes and timer in the worker thread, for correct thread affinity bool m_isPreNougat = false; - AndroidRunnable m_androidRunnable; + QString m_packageName; QString m_intentName; + QStringList m_beforeStartAdbCommands; + QStringList m_afterFinishAdbCommands; QString m_adb; QStringList m_amStartExtraArgs; qint64 m_processPID = -1; diff --git a/src/plugins/autotest/testrunner.cpp b/src/plugins/autotest/testrunner.cpp index 6ed58bb39a..e70870b417 100644 --- a/src/plugins/autotest/testrunner.cpp +++ b/src/plugins/autotest/testrunner.cpp @@ -48,7 +48,6 @@ #include <utils/hostosinfo.h> #include <utils/outputformat.h> #include <utils/qtcprocess.h> -#include <utils/runextensions.h> #include <QComboBox> #include <QDialogButtonBox> @@ -56,8 +55,9 @@ #include <QFuture> #include <QFutureInterface> #include <QLabel> +#include <QProcess> #include <QPushButton> -#include <QTime> +#include <QTimer> #include <debugger/debuggerkitinformation.h> #include <debugger/debuggerruncontrol.h> @@ -88,9 +88,9 @@ TestRunner::TestRunner(QObject *parent) : &m_futureWatcher, &QFutureWatcher<TestResultPtr>::cancel); connect(&m_futureWatcher, &QFutureWatcher<TestResultPtr>::canceled, this, [this]() { + cancelCurrent(UserCanceled); emit testResultReady(TestResultPtr(new FaultyTestResult( Result::MessageFatal, tr("Test run canceled by user.")))); - m_executingTests = false; // avoid being stuck if finished() signal won't get emitted }); } @@ -103,13 +103,15 @@ TestRunner::~TestRunner() void TestRunner::setSelectedTests(const QList<TestConfiguration *> &selected) { - qDeleteAll(m_selectedTests); - m_selectedTests.clear(); - m_selectedTests = selected; + QTC_ASSERT(!m_executingTests, return); + qDeleteAll(m_selectedTests); + m_selectedTests.clear(); + m_selectedTests.append(selected); } void TestRunner::runTest(TestRunMode mode, const TestTreeItem *item) { + QTC_ASSERT(!m_executingTests, return); TestConfiguration *configuration = item->asConfiguration(mode); if (configuration) { @@ -118,15 +120,16 @@ void TestRunner::runTest(TestRunMode mode, const TestTreeItem *item) } } -static QString processInformation(const QProcess &proc) +static QString processInformation(const QProcess *proc) { - QString information("\nCommand line: " + proc.program() + ' ' + proc.arguments().join(' ')); + QTC_ASSERT(proc, return QString()); + 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(); + const QProcessEnvironment &environment = proc->processEnvironment(); for (const QString &var : important) information.append('\n' + var + ": " + environment.value(var)); return information; @@ -142,133 +145,131 @@ static QString rcInfo(const TestConfiguration * const config) static QString constructOmittedDetailsString(const QStringList &omitted) { - QString details = TestRunner::tr("Omitted the following arguments specified on the run " - "configuration page for \"%1\":"); - for (const QString &arg : omitted) - details += "\n" + arg; - return details; + return TestRunner::tr("Omitted the following arguments specified on the run " + "configuration page for \"%1\":") + '\n' + omitted.join('\n'); } -static void performTestRun(QFutureInterface<TestResultPtr> &futureInterface, - const QList<TestConfiguration *> selectedTests, - const TestSettings &settings) +void TestRunner::scheduleNext() { - const int timeout = settings.timeout; - const bool omitRunConfigWarnings = settings.omitRunConfigWarn; - QEventLoop eventLoop; - int testCaseCount = 0; - for (TestConfiguration *config : selectedTests) { - config->completeTestInformation(TestRunMode::Run); - if (config->project()) { - testCaseCount += config->testCaseCount(); - 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, - TestRunner::tr("Project is null for \"%1\". Removing from test run.\n" - "Check the test environment.").arg(config->displayName())))); - } + QTC_ASSERT(!m_selectedTests.isEmpty(), onFinished(); return); + QTC_ASSERT(!m_currentConfig && !m_currentProcess, resetInternalPointers()); + QTC_ASSERT(m_fakeFutureInterface, onFinished(); return); + + m_currentConfig = m_selectedTests.dequeue(); + + QString commandFilePath = m_currentConfig->executableFilePath(); + if (commandFilePath.isEmpty()) { + emit testResultReady(TestResultPtr(new FaultyTestResult(Result::MessageFatal, + tr("Executable path is empty. (%1)").arg(m_currentConfig->displayName())))); + delete m_currentConfig; + m_currentConfig = nullptr; + if (m_selectedTests.isEmpty()) + onFinished(); + else + onProcessFinished(); + return; } + if (!m_currentConfig->project()) + onProcessFinished(); - QProcess testProcess; - testProcess.setReadChannel(QProcess::StandardOutput); + m_currentProcess = new QProcess; + m_currentProcess->setReadChannel(QProcess::StandardOutput); + m_currentProcess->setProgram(commandFilePath); - futureInterface.setProgressRange(0, testCaseCount); - futureInterface.setProgressValue(0); + QTC_ASSERT(!m_currentOutputReader, delete m_currentOutputReader); + m_currentOutputReader = m_currentConfig->outputReader(*m_fakeFutureInterface, m_currentProcess); + QTC_ASSERT(m_currentOutputReader, onProcessFinished();return); - for (const TestConfiguration *testConfiguration : selectedTests) { - QString commandFilePath = testConfiguration->executableFilePath(); - if (commandFilePath.isEmpty()) { - futureInterface.reportResult(TestResultPtr(new FaultyTestResult(Result::MessageFatal, - TestRunner::tr("Executable path is empty. (%1)") - .arg(testConfiguration->displayName())))); - continue; - } - testProcess.setProgram(commandFilePath); - - QScopedPointer<TestOutputReader> outputReader; - outputReader.reset(testConfiguration->outputReader(futureInterface, &testProcess)); - QTC_ASSERT(outputReader, continue); - TestRunner::connect(outputReader.data(), &TestOutputReader::newOutputAvailable, - TestResultsPane::instance(), &TestResultsPane::addOutput); - if (futureInterface.isCanceled()) - break; - - if (!testConfiguration->project()) - continue; - - QStringList omitted; - testProcess.setArguments(testConfiguration->argumentsForTestRunner(&omitted)); - if (!omitted.isEmpty()) { - const QString &details = constructOmittedDetailsString(omitted); - futureInterface.reportResult(TestResultPtr(new FaultyTestResult(Result::MessageWarn, - details.arg(testConfiguration->displayName())))); - } - testProcess.setWorkingDirectory(testConfiguration->workingDirectory()); - QProcessEnvironment environment = testConfiguration->environment().toProcessEnvironment(); - if (Utils::HostOsInfo::isWindowsHost()) - environment.insert("QT_LOGGING_TO_CONSOLE", "1"); - testProcess.setProcessEnvironment(environment); - testProcess.start(); - - bool ok = testProcess.waitForStarted(); - QTime executionTimer; - executionTimer.start(); - bool canceledByTimeout = false; - if (ok) { - while (testProcess.state() == QProcess::Running) { - if (executionTimer.elapsed() >= timeout) { - canceledByTimeout = true; - break; - } - if (futureInterface.isCanceled()) { - testProcess.kill(); - testProcess.waitForFinished(); - return; - } - eventLoop.processEvents(); - } - } else { - futureInterface.reportResult(TestResultPtr(new FaultyTestResult(Result::MessageFatal, - TestRunner::tr("Failed to start test for project \"%1\".") - .arg(testConfiguration->displayName()) + processInformation(testProcess) - + rcInfo(testConfiguration)))); - } - if (testProcess.exitStatus() == QProcess::CrashExit) { - outputReader->reportCrash(); - futureInterface.reportResult(TestResultPtr(new FaultyTestResult(Result::MessageFatal, - TestRunner::tr("Test for project \"%1\" crashed.") - .arg(testConfiguration->displayName()) + processInformation(testProcess) - + rcInfo(testConfiguration)))); - } else if (!outputReader->hadValidOutput()) { - futureInterface.reportResult(TestResultPtr(new FaultyTestResult(Result::MessageFatal, - TestRunner::tr("Test for project \"%1\" did not produce any expected output.") - .arg(testConfiguration->displayName()) + processInformation(testProcess) - + rcInfo(testConfiguration)))); - } + connect(m_currentOutputReader, &TestOutputReader::newOutputAvailable, + TestResultsPane::instance(), &TestResultsPane::addOutput); - if (canceledByTimeout) { - if (testProcess.state() != QProcess::NotRunning) { - testProcess.kill(); - testProcess.waitForFinished(); - } - futureInterface.reportResult(TestResultPtr( - new FaultyTestResult(Result::MessageFatal, TestRunner::tr( - "Test case canceled due to timeout.\nMaybe raise the timeout?")))); + + QStringList omitted; + m_currentProcess->setArguments(m_currentConfig->argumentsForTestRunner(&omitted)); + if (!omitted.isEmpty()) { + const QString &details = constructOmittedDetailsString(omitted); + emit testResultReady(TestResultPtr(new FaultyTestResult(Result::MessageWarn, + details.arg(m_currentConfig->displayName())))); + } + m_currentProcess->setWorkingDirectory(m_currentConfig->workingDirectory()); + QProcessEnvironment environment = m_currentConfig->environment().toProcessEnvironment(); + if (Utils::HostOsInfo::isWindowsHost()) + environment.insert("QT_LOGGING_TO_CONSOLE", "1"); + const int timeout = AutotestPlugin::settings()->timeout; + if (timeout > 5 * 60 * 1000) // Qt5.5 introduced hard limit, Qt5.6.1 added env var to raise this + environment.insert("QTEST_FUNCTION_TIMEOUT", QString::number(timeout)); + m_currentProcess->setProcessEnvironment(environment); + + connect(m_currentProcess, + static_cast<void (QProcess::*)(int, QProcess::ExitStatus)>(&QProcess::finished), + this, &TestRunner::onProcessFinished); + QTimer::singleShot(timeout, m_currentProcess, [this]() { cancelCurrent(Timeout); }); + + m_currentProcess->start(); + if (!m_currentProcess->waitForStarted()) { + emit testResultReady(TestResultPtr(new FaultyTestResult(Result::MessageFatal, + tr("Failed to start test for project \"%1\".").arg(m_currentConfig->displayName()) + + processInformation(m_currentProcess) + rcInfo(m_currentConfig)))); + } +} + +void TestRunner::cancelCurrent(TestRunner::CancelReason reason) +{ + if (reason == UserCanceled) { + if (!m_fakeFutureInterface->isCanceled()) // depends on using the button / progress bar + m_fakeFutureInterface->reportCanceled(); + } + if (m_currentProcess && m_currentProcess->state() != QProcess::NotRunning) { + m_currentProcess->kill(); + m_currentProcess->waitForFinished(); + } + if (reason == Timeout) { + emit testResultReady(TestResultPtr(new FaultyTestResult(Result::MessageFatal, + tr("Test case canceled due to timeout.\nMaybe raise the timeout?")))); + } +} + +void TestRunner::onProcessFinished() +{ + m_fakeFutureInterface->setProgressValue(m_fakeFutureInterface->progressValue() + + m_currentConfig->testCaseCount()); + if (!m_fakeFutureInterface->isCanceled()) { + if (m_currentProcess->exitStatus() == QProcess::CrashExit) { + m_currentOutputReader->reportCrash(); + emit testResultReady(TestResultPtr(new FaultyTestResult(Result::MessageFatal, + tr("Test for project \"%1\" crashed.").arg(m_currentConfig->displayName()) + + processInformation(m_currentProcess) + rcInfo(m_currentConfig)))); + } else if (!m_currentOutputReader->hadValidOutput()) { + emit testResultReady(TestResultPtr(new FaultyTestResult(Result::MessageFatal, + tr("Test for project \"%1\" did not produce any expected output.") + .arg(m_currentConfig->displayName()) + processInformation(m_currentProcess) + + rcInfo(m_currentConfig)))); } } - futureInterface.setProgressValue(testCaseCount); + + resetInternalPointers(); + + if (!m_selectedTests.isEmpty() && !m_fakeFutureInterface->isCanceled()) { + scheduleNext(); + } else { + m_fakeFutureInterface->reportFinished(); + onFinished(); + } +} + +void TestRunner::resetInternalPointers() +{ + delete m_currentOutputReader; + delete m_currentProcess; + delete m_currentConfig; + m_currentOutputReader = nullptr; + m_currentProcess = nullptr; + m_currentConfig = nullptr; } void TestRunner::prepareToRunTests(TestRunMode mode) { + QTC_ASSERT(!m_executingTests, return); m_runMode = mode; ProjectExplorer::Internal::ProjectExplorerSettings projectExplorerSettings = ProjectExplorer::ProjectExplorerPlugin::projectExplorerSettings(); @@ -358,6 +359,32 @@ static ProjectExplorer::RunConfiguration *getRunConfiguration(const QString &dia return runConfig; } +int TestRunner::precheckTestConfigurations() +{ + const bool omitWarnings = AutotestPlugin::settings()->omitRunConfigWarn; + int testCaseCount = 0; + for (TestConfiguration *config : m_selectedTests) { + config->completeTestInformation(TestRunMode::Run); + if (config->project()) { + testCaseCount += config->testCaseCount(); + if (!omitWarnings && config->isGuessed()) { + QString message = 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()); + emit testResultReady( + TestResultPtr(new FaultyTestResult(Result::MessageWarn, message))); + } + } else { + emit testResultReady(TestResultPtr(new FaultyTestResult(Result::MessageWarn, + tr("Project is null for \"%1\". Removing from test run.\n" + "Check the test environment.").arg(config->displayName())))); + } + } + return testCaseCount; +} + void TestRunner::runTests() { QList<TestConfiguration *> toBeRemoved; @@ -381,10 +408,17 @@ void TestRunner::runTests() return; } - QFuture<TestResultPtr> future = Utils::runAsync(&performTestRun, m_selectedTests, - *AutotestPlugin::settings()); + int testCaseCount = precheckTestConfigurations(); + + // Fake future interface - destruction will be handled by QFuture/QFutureWatcher + m_fakeFutureInterface = new QFutureInterface<TestResultPtr>(QFutureInterfaceBase::Running); + QFuture<TestResultPtr> future = m_fakeFutureInterface->future(); + m_fakeFutureInterface->setProgressRange(0, testCaseCount); + m_fakeFutureInterface->setProgressValue(0); m_futureWatcher.setFuture(future); + Core::ProgressManager::addTask(future, tr("Running Tests"), Autotest::Constants::TASK_INDEX); + scheduleNext(); } static void processOutput(TestOutputReader *outputreader, const QString &msg, @@ -552,6 +586,11 @@ void TestRunner::buildFinished(bool success) void TestRunner::onFinished() { + // if we've been canceled and we still have test configurations queued just throw them away + qDeleteAll(m_selectedTests); + m_selectedTests.clear(); + + m_fakeFutureInterface = nullptr; m_executingTests = false; emit testRunFinished(); } diff --git a/src/plugins/autotest/testrunner.h b/src/plugins/autotest/testrunner.h index 0638401ca0..95039b47ac 100644 --- a/src/plugins/autotest/testrunner.h +++ b/src/plugins/autotest/testrunner.h @@ -31,12 +31,13 @@ #include <QDialog> #include <QFutureWatcher> #include <QObject> -#include <QProcess> +#include <QQueue> QT_BEGIN_NAMESPACE class QComboBox; class QDialogButtonBox; class QLabel; +class QProcess; QT_END_NAMESPACE namespace ProjectExplorer { @@ -51,6 +52,8 @@ class TestRunner : public QObject Q_OBJECT public: + enum CancelReason { UserCanceled, Timeout }; + static TestRunner* instance(); ~TestRunner(); @@ -71,14 +74,24 @@ private: void buildFinished(bool success); void onFinished(); + int precheckTestConfigurations(); + void scheduleNext(); + void cancelCurrent(CancelReason reason); + void onProcessFinished(); + void resetInternalPointers(); + void runTests(); void debugTests(); void runOrDebugTests(); explicit TestRunner(QObject *parent = 0); QFutureWatcher<TestResultPtr> m_futureWatcher; - QList<TestConfiguration *> m_selectedTests; - bool m_executingTests; + QFutureInterface<TestResultPtr> *m_fakeFutureInterface = nullptr; + QQueue<TestConfiguration *> m_selectedTests; + bool m_executingTests = false; + TestConfiguration *m_currentConfig = nullptr; + QProcess *m_currentProcess = nullptr; + TestOutputReader *m_currentOutputReader = nullptr; TestRunMode m_runMode = TestRunMode::Run; // temporarily used if building before running is necessary diff --git a/src/plugins/clangcodemodel/clangtextmark.cpp b/src/plugins/clangcodemodel/clangtextmark.cpp index fbe08cb14d..51447e9147 100644 --- a/src/plugins/clangcodemodel/clangtextmark.cpp +++ b/src/plugins/clangcodemodel/clangtextmark.cpp @@ -83,8 +83,8 @@ ClangTextMark::ClangTextMark(const FileName &fileName, updateIcon(); if (fullVisualization) { setLineAnnotation(Utils::diagnosticCategoryPrefixRemoved(diagnostic.text.toString())); - setColor(warning ? ::Utils::Theme::ClangCodeModel_Warning_TextMarkColor - : ::Utils::Theme::ClangCodeModel_Error_TextMarkColor); + setColor(warning ? ::Utils::Theme::CodeModel_Warning_TextMarkColor + : ::Utils::Theme::CodeModel_Error_TextMarkColor); } } diff --git a/src/plugins/clangtools/clangtidyclazytool.cpp b/src/plugins/clangtools/clangtidyclazytool.cpp index fdf6a9adc6..2b977c4548 100644 --- a/src/plugins/clangtools/clangtidyclazytool.cpp +++ b/src/plugins/clangtools/clangtidyclazytool.cpp @@ -161,6 +161,10 @@ ClangTidyClazyTool::ClangTidyClazyTool() // Apply fixits button m_applyFixitsButton = new QToolButton; m_applyFixitsButton->setText(tr("Apply Fixits")); + m_applyFixitsButton->setEnabled(false); + connect(m_diagnosticModel, + &ClangToolsDiagnosticModel::fixItsToApplyCountChanged, + [this](int c) { m_applyFixitsButton->setEnabled(c); }); connect(m_applyFixitsButton, &QToolButton::clicked, [this]() { QVector<Diagnostic> diagnosticsWithFixits; diff --git a/src/plugins/clangtools/clangtools.qbs b/src/plugins/clangtools/clangtools.qbs index b9363f55a9..f947fb6115 100644 --- a/src/plugins/clangtools/clangtools.qbs +++ b/src/plugins/clangtools/clangtools.qbs @@ -6,6 +6,7 @@ QtcPlugin { Depends { name: "Debugger" } Depends { name: "Core" } + Depends { name: "TextEditor" } Depends { name: "CppTools" } Depends { name: "ExtensionSystem" } Depends { name: "ProjectExplorer" } diff --git a/src/plugins/clangtools/clangtoolsdiagnosticmodel.cpp b/src/plugins/clangtools/clangtoolsdiagnosticmodel.cpp index 1ffc3351e5..ddfc4e4bcf 100644 --- a/src/plugins/clangtools/clangtoolsdiagnosticmodel.cpp +++ b/src/plugins/clangtools/clangtoolsdiagnosticmodel.cpp @@ -34,7 +34,6 @@ #include <utils/qtcassert.h> #include <utils/utilsicons.h> -#include <QCoreApplication> #include <QFileInfo> #include <cmath> @@ -61,8 +60,13 @@ ClangToolsDiagnosticModel::ClangToolsDiagnosticModel(QObject *parent) void ClangToolsDiagnosticModel::addDiagnostics(const QList<Diagnostic> &diagnostics) { - foreach (const Diagnostic &d, diagnostics) - rootItem()->appendChild(new DiagnosticItem(d)); + const auto onFixItChanged = [this](bool checked){ + m_fixItsToApplyCount += checked ? +1 : -1; + emit fixItsToApplyCountChanged(m_fixItsToApplyCount); + }; + + for (const Diagnostic &d : diagnostics) + rootItem()->appendChild(new DiagnosticItem(d, onFixItChanged)); } QList<Diagnostic> ClangToolsDiagnosticModel::diagnostics() const @@ -199,7 +203,9 @@ static QString fullText(const Diagnostic &diagnostic) } -DiagnosticItem::DiagnosticItem(const Diagnostic &diag) : m_diagnostic(diag) +DiagnosticItem::DiagnosticItem(const Diagnostic &diag, const OnCheckedFixit &onCheckedFixit) + : m_diagnostic(diag) + , m_onCheckedFixit(onCheckedFixit) { // Don't show explaining steps if they add no information. if (diag.explainingSteps.count() == 1) { @@ -214,21 +220,15 @@ DiagnosticItem::DiagnosticItem(const Diagnostic &diag) : m_diagnostic(diag) Qt::ItemFlags DiagnosticItem::flags(int column) const { - if (column == DiagnosticView::FixItColumn && m_diagnostic.hasFixits) - return TreeItem::flags(column) | Qt::ItemIsUserCheckable; - return TreeItem::flags(column); -} - -static QVariant locationData(int role, const Debugger::DiagnosticLocation &location) -{ - switch (role) { - case Debugger::DetailedErrorView::LocationRole: - return QVariant::fromValue(location); - case Qt::ToolTipRole: - return location.filePath.isEmpty() ? QVariant() : QVariant(location.filePath); - default: - return QVariant(); + const Qt::ItemFlags itemFlags = TreeItem::flags(column); + if (column == DiagnosticView::FixItColumn) { + if (m_diagnostic.hasFixits) + return itemFlags | Qt::ItemIsUserCheckable; + else + return itemFlags & ~Qt::ItemIsEnabled; } + + return itemFlags; } static QVariant iconData(const QString &type) @@ -247,7 +247,7 @@ static QVariant iconData(const QString &type) QVariant DiagnosticItem::data(int column, int role) const { if (column == Debugger::DetailedErrorView::LocationColumn) - return locationData(role, m_diagnostic.location); + return Debugger::DetailedErrorView::locationData(role, m_diagnostic.location); if (column == DiagnosticView::FixItColumn) { if (role == Qt::CheckStateRole) @@ -277,6 +277,8 @@ bool DiagnosticItem::setData(int column, const QVariant &data, int role) if (column == DiagnosticView::FixItColumn && role == Qt::CheckStateRole) { m_applyFixits = data.value<Qt::CheckState>() == Qt::Checked ? true : false; update(); + if (m_onCheckedFixit) + m_onCheckedFixit(m_applyFixits); return true; } @@ -290,7 +292,7 @@ ExplainingStepItem::ExplainingStepItem(const ExplainingStep &step) : m_step(step QVariant ExplainingStepItem::data(int column, int role) const { if (column == Debugger::DetailedErrorView::LocationColumn) - return locationData(role, m_step.location); + return Debugger::DetailedErrorView::locationData(role, m_step.location); if (column == DiagnosticView::FixItColumn) return QVariant(); diff --git a/src/plugins/clangtools/clangtoolsdiagnosticmodel.h b/src/plugins/clangtools/clangtoolsdiagnosticmodel.h index 0fbc99a5b7..61aa6055c5 100644 --- a/src/plugins/clangtools/clangtoolsdiagnosticmodel.h +++ b/src/plugins/clangtools/clangtoolsdiagnosticmodel.h @@ -35,6 +35,8 @@ #include <QPointer> #include <QSortFilterProxyModel> +#include <functional> + namespace ProjectExplorer { class Project; } namespace ClangTools { @@ -43,7 +45,8 @@ namespace Internal { class DiagnosticItem : public Utils::TreeItem { public: - DiagnosticItem(const Diagnostic &diag); + using OnCheckedFixit = std::function<void(bool)>; + DiagnosticItem(const Diagnostic &diag, const OnCheckedFixit &onCheckedFixit); Diagnostic diagnostic() const { return m_diagnostic; } bool applyFixits() const { return m_applyFixits; } @@ -56,6 +59,7 @@ private: private: const Diagnostic m_diagnostic; bool m_applyFixits = false; + OnCheckedFixit m_onCheckedFixit; }; class ClangToolsDiagnosticModel : public Utils::TreeModel<> @@ -71,6 +75,12 @@ public: enum ItemRole { DiagnosticRole = Debugger::DetailedErrorView::FullTextRole + 1 }; + +signals: + void fixItsToApplyCountChanged(int count); + +private: + int m_fixItsToApplyCount = 0; }; class DiagnosticFilterModel : public QSortFilterProxyModel diff --git a/src/plugins/cmakeprojectmanager/builddirmanager.cpp b/src/plugins/cmakeprojectmanager/builddirmanager.cpp index 6af10c3553..27ac6a4504 100644 --- a/src/plugins/cmakeprojectmanager/builddirmanager.cpp +++ b/src/plugins/cmakeprojectmanager/builddirmanager.cpp @@ -196,6 +196,12 @@ void BuildDirManager::setParametersAndRequestParse(const BuildDirParameters &par int newReaderReparseOptions, int existingReaderReparseOptions) { + if (!parameters.cmakeTool) { + TaskHub::addTask(Task::Error, + tr("The kit needs to define a CMake tool to parse this project."), + ProjectExplorer::Constants::TASK_CATEGORY_BUILDSYSTEM); + return; + } QTC_ASSERT(parameters.isValid(), return); if (m_reader) diff --git a/src/plugins/cmakeprojectmanager/servermodereader.cpp b/src/plugins/cmakeprojectmanager/servermodereader.cpp index 8432551696..097840072f 100644 --- a/src/plugins/cmakeprojectmanager/servermodereader.cpp +++ b/src/plugins/cmakeprojectmanager/servermodereader.cpp @@ -279,8 +279,7 @@ static std::vector<std::unique_ptr<FileNode>> && removeKnownNodes(const QSet<Utils::FileName> &knownFiles, std::vector<std::unique_ptr<FileNode>> &&files) { - std::remove_if(std::begin(files), std::end(files), - [&knownFiles](const std::unique_ptr<FileNode> &n) { + Utils::erase(files, [&knownFiles](const std::unique_ptr<FileNode> &n) { return knownFiles.contains(n->filePath()); }); return std::move(files); diff --git a/src/plugins/cppeditor/cppcodemodelinspectordialog.ui b/src/plugins/cppeditor/cppcodemodelinspectordialog.ui index 9eb8bdb1ba..7cb63c005b 100644 --- a/src/plugins/cppeditor/cppcodemodelinspectordialog.ui +++ b/src/plugins/cppeditor/cppcodemodelinspectordialog.ui @@ -19,6 +19,108 @@ <property name="currentIndex"> <number>0</number> </property> + <widget class="QWidget" name="tab_2"> + <attribute name="title"> + <string notr="true">&Project Parts</string> + </attribute> + <layout class="QVBoxLayout" name="verticalLayout_12"> + <item> + <widget class="QSplitter" name="projectPartsSplitter"> + <property name="orientation"> + <enum>Qt::Vertical</enum> + </property> + <widget class="QTabWidget" name="projectPartTab"> + <property name="currentIndex"> + <number>3</number> + </property> + <widget class="QWidget" name="tab_17"> + <attribute name="title"> + <string notr="true">&General</string> + </attribute> + <layout class="QVBoxLayout" name="verticalLayout_9"> + <item> + <widget class="QTreeView" name="partGeneralView"/> + </item> + </layout> + </widget> + <widget class="QWidget" name="tab_13"> + <attribute name="title"> + <string notr="true">Project &Files</string> + </attribute> + <layout class="QVBoxLayout" name="verticalLayout_14"> + <item> + <widget class="QTreeView" name="projectFilesView"/> + </item> + </layout> + </widget> + <widget class="QWidget" name="tab_14"> + <attribute name="title"> + <string notr="true">&Defines</string> + </attribute> + <layout class="QVBoxLayout" name="verticalLayout_19"> + <item> + <widget class="QGroupBox" name="groupBox"> + <property name="title"> + <string notr="true">Toolchain Defines</string> + </property> + <layout class="QVBoxLayout" name="verticalLayout_13"> + <item> + <widget class="QPlainTextEdit" name="partToolchainDefinesEdit"> + <property name="readOnly"> + <bool>true</bool> + </property> + </widget> + </item> + </layout> + </widget> + </item> + <item> + <widget class="QGroupBox" name="groupBox_2"> + <property name="title"> + <string notr="true">Project Defines</string> + </property> + <layout class="QVBoxLayout" name="verticalLayout_15"> + <item> + <widget class="QPlainTextEdit" name="partProjectDefinesEdit"> + <property name="readOnly"> + <bool>true</bool> + </property> + </widget> + </item> + </layout> + </widget> + </item> + </layout> + </widget> + <widget class="QWidget" name="tab_15"> + <attribute name="title"> + <string notr="true">&Header Paths</string> + </attribute> + <layout class="QVBoxLayout" name="verticalLayout_16"> + <item> + <widget class="QTreeView" name="projectHeaderPathsView"/> + </item> + </layout> + </widget> + <widget class="QWidget" name="tab_16"> + <attribute name="title"> + <string notr="true">Pre&compiled Headers</string> + </attribute> + <layout class="QVBoxLayout" name="verticalLayout_18"> + <item> + <widget class="QPlainTextEdit" name="partPrecompiledHeadersEdit"> + <property name="readOnly"> + <bool>true</bool> + </property> + </widget> + </item> + </layout> + </widget> + </widget> + </widget> + </item> + </layout> + </widget> <widget class="QWidget" name="tab"> <attribute name="title"> <string notr="true">&Snapshots and Documents</string> @@ -182,108 +284,6 @@ </item> </layout> </widget> - <widget class="QWidget" name="tab_2"> - <attribute name="title"> - <string notr="true">&Project Parts</string> - </attribute> - <layout class="QVBoxLayout" name="verticalLayout_12"> - <item> - <widget class="QSplitter" name="projectPartsSplitter"> - <property name="orientation"> - <enum>Qt::Vertical</enum> - </property> - <widget class="QTabWidget" name="projectPartTab"> - <property name="currentIndex"> - <number>0</number> - </property> - <widget class="QWidget" name="tab_17"> - <attribute name="title"> - <string notr="true">&General</string> - </attribute> - <layout class="QVBoxLayout" name="verticalLayout_9"> - <item> - <widget class="QTreeView" name="partGeneralView"/> - </item> - </layout> - </widget> - <widget class="QWidget" name="tab_13"> - <attribute name="title"> - <string notr="true">Project &Files</string> - </attribute> - <layout class="QVBoxLayout" name="verticalLayout_14"> - <item> - <widget class="QTreeView" name="projectFilesView"/> - </item> - </layout> - </widget> - <widget class="QWidget" name="tab_14"> - <attribute name="title"> - <string notr="true">&Defines</string> - </attribute> - <layout class="QVBoxLayout" name="verticalLayout_19"> - <item> - <widget class="QGroupBox" name="groupBox"> - <property name="title"> - <string notr="true">Toolchain Defines</string> - </property> - <layout class="QVBoxLayout" name="verticalLayout_13"> - <item> - <widget class="QPlainTextEdit" name="partToolchainDefinesEdit"> - <property name="readOnly"> - <bool>true</bool> - </property> - </widget> - </item> - </layout> - </widget> - </item> - <item> - <widget class="QGroupBox" name="groupBox_2"> - <property name="title"> - <string notr="true">Project Defines</string> - </property> - <layout class="QVBoxLayout" name="verticalLayout_15"> - <item> - <widget class="QPlainTextEdit" name="partProjectDefinesEdit"> - <property name="readOnly"> - <bool>true</bool> - </property> - </widget> - </item> - </layout> - </widget> - </item> - </layout> - </widget> - <widget class="QWidget" name="tab_15"> - <attribute name="title"> - <string notr="true">&Header Paths</string> - </attribute> - <layout class="QVBoxLayout" name="verticalLayout_16"> - <item> - <widget class="QTreeView" name="projectHeaderPathsView"/> - </item> - </layout> - </widget> - <widget class="QWidget" name="tab_16"> - <attribute name="title"> - <string notr="true">Pre&compiled Headers</string> - </attribute> - <layout class="QVBoxLayout" name="verticalLayout_18"> - <item> - <widget class="QPlainTextEdit" name="partPrecompiledHeadersEdit"> - <property name="readOnly"> - <bool>true</bool> - </property> - </widget> - </item> - </layout> - </widget> - </widget> - </widget> - </item> - </layout> - </widget> <widget class="QWidget" name="tab_3"> <attribute name="title"> <string notr="true">&Working Copy</string> diff --git a/src/plugins/debugger/analyzer/detailederrorview.cpp b/src/plugins/debugger/analyzer/detailederrorview.cpp index a5ee070a1a..85ea430f34 100644 --- a/src/plugins/debugger/analyzer/detailederrorview.cpp +++ b/src/plugins/debugger/analyzer/detailederrorview.cpp @@ -41,91 +41,14 @@ #include <QHeaderView> #include <QMenu> #include <QPainter> -#include <QSharedPointer> -#include <QTextDocument> namespace Debugger { -namespace Internal { - -class DetailedErrorDelegate : public QStyledItemDelegate -{ - Q_OBJECT - -public: - DetailedErrorDelegate(QTreeView *parent) : QStyledItemDelegate(parent) { } - -private: - QString actualText(const QModelIndex &index) const - { - const auto location = index.model()->data(index, DetailedErrorView::LocationRole) - .value<DiagnosticLocation>(); - return location.isValid() - ? QString::fromLatin1("<a href=\"file://%1\">%2:%3:%4") - .arg(location.filePath, QFileInfo(location.filePath).fileName()) - .arg(location.line) - .arg(location.column) - : QString(); - } - - using DocConstPtr = QSharedPointer<const QTextDocument>; - DocConstPtr document(const QStyleOptionViewItem &option) const - { - const auto doc = QSharedPointer<QTextDocument>::create(); - doc->setHtml(option.text); - doc->setTextWidth(option.rect.width()); - doc->setDocumentMargin(0); - return doc; - } - - QSize sizeHint(const QStyleOptionViewItem &option, const QModelIndex &index) const override - { - QStyleOptionViewItem opt = option; - opt.text = actualText(index); - initStyleOption(&opt, index); - - const DocConstPtr doc = document(opt); - return QSize(doc->idealWidth(), doc->size().height()); - } - - void paint(QPainter *painter, const QStyleOptionViewItem &option, - const QModelIndex &index) const override - { - QStyleOptionViewItem opt = option; - initStyleOption(&opt, index); - - QStyle *style = opt.widget? opt.widget->style() : QApplication::style(); - - // Painting item without text - opt.text.clear(); - style->drawControl(QStyle::CE_ItemViewItem, &opt, painter); - opt.text = actualText(index); - - QAbstractTextDocumentLayout::PaintContext ctx; - - // Highlighting text if item is selected - if (opt.state & QStyle::State_Selected) { - ctx.palette.setColor(QPalette::Text, opt.palette.color(QPalette::Active, - QPalette::HighlightedText)); - } - - QRect textRect = style->subElementRect(QStyle::SE_ItemViewItemText, &opt); - painter->save(); - painter->translate(textRect.topLeft()); - painter->setClipRect(textRect.translated(-textRect.topLeft())); - document(opt)->documentLayout()->draw(painter, ctx); - painter->restore(); - } -}; - -} // namespace Internal - DetailedErrorView::DetailedErrorView(QWidget *parent) : QTreeView(parent), m_copyAction(new QAction(this)) { header()->setSectionResizeMode(QHeaderView::ResizeToContents); - setItemDelegateForColumn(LocationColumn, new Internal::DetailedErrorDelegate(this)); m_copyAction->setText(tr("Copy")); m_copyAction->setIcon(Utils::Icons::COPY.icon()); @@ -187,6 +110,31 @@ void DetailedErrorView::goBack() setCurrentRow(prevRow >= 0 ? prevRow : rowCount() - 1); } +QVariant DetailedErrorView::locationData(int role, const DiagnosticLocation &location) +{ + switch (role) { + case Debugger::DetailedErrorView::LocationRole: + return QVariant::fromValue(location); + case Qt::DisplayRole: + return location.isValid() ? QString::fromLatin1("%1:%2:%3") + .arg(QFileInfo(location.filePath).fileName()) + .arg(location.line) + .arg(location.column) + : QString(); + case Qt::ToolTipRole: + return location.filePath.isEmpty() ? QVariant() : QVariant(location.filePath); + case Qt::FontRole: { + QFont font = QApplication::font(); + font.setUnderline(true); + return font; + } + case Qt::ForegroundRole: + return QApplication::palette().link().color(); + default: + return QVariant(); + } +} + int DetailedErrorView::rowCount() const { return model() ? model()->rowCount() : 0; @@ -218,5 +166,3 @@ void DetailedErrorView::setCurrentRow(int row) } } // namespace Debugger - -#include "detailederrorview.moc" diff --git a/src/plugins/debugger/analyzer/detailederrorview.h b/src/plugins/debugger/analyzer/detailederrorview.h index 1614605412..845bbee362 100644 --- a/src/plugins/debugger/analyzer/detailederrorview.h +++ b/src/plugins/debugger/analyzer/detailederrorview.h @@ -32,6 +32,8 @@ namespace Debugger { +class DiagnosticLocation; + class DEBUGGER_EXPORT DetailedErrorView : public QTreeView { Q_OBJECT @@ -53,6 +55,8 @@ public: LocationColumn, }; + static QVariant locationData(int role, const DiagnosticLocation &location); + private: void contextMenuEvent(QContextMenuEvent *e) override; void currentChanged(const QModelIndex ¤t, const QModelIndex &previous) override; diff --git a/src/plugins/diffeditor/sidebysidediffeditorwidget.cpp b/src/plugins/diffeditor/sidebysidediffeditorwidget.cpp index 9d016400fb..f1e893cd1f 100644 --- a/src/plugins/diffeditor/sidebysidediffeditorwidget.cpp +++ b/src/plugins/diffeditor/sidebysidediffeditorwidget.cpp @@ -179,6 +179,7 @@ SideDiffEditorWidget::SideDiffEditorWidget(QWidget *parent) connect(documentLayout, &TextDocumentLayout::foldChanged, this, &SideDiffEditorWidget::foldChanged); setCodeFoldingSupported(true); + setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOn); } void SideDiffEditorWidget::saveState() @@ -714,6 +715,13 @@ SideBySideDiffEditorWidget::SideBySideDiffEditorWidget(QWidget *parent) connect(m_rightEditor, &SideDiffEditorWidget::foldChanged, m_leftEditor, &SideDiffEditorWidget::setFolded); + connect(m_leftEditor->horizontalScrollBar(), &QAbstractSlider::rangeChanged, + this, &SideBySideDiffEditorWidget::syncHorizontalScrollBarPolicy); + + connect(m_rightEditor->horizontalScrollBar(), &QAbstractSlider::rangeChanged, + this, &SideBySideDiffEditorWidget::syncHorizontalScrollBarPolicy); + + syncHorizontalScrollBarPolicy(); m_splitter = new MiniSplitter(this); m_splitter->addWidget(m_leftEditor); @@ -1133,6 +1141,18 @@ void SideBySideDiffEditorWidget::rightCursorPositionChanged() rightHSliderChanged(); } +void SideBySideDiffEditorWidget::syncHorizontalScrollBarPolicy() +{ + const bool alwaysOn = m_leftEditor->horizontalScrollBar()->maximum() + || m_rightEditor->horizontalScrollBar()->maximum(); + const Qt::ScrollBarPolicy newPolicy = alwaysOn + ? Qt::ScrollBarAlwaysOn : Qt::ScrollBarAsNeeded; + if (m_leftEditor->horizontalScrollBarPolicy() != newPolicy) + m_leftEditor->setHorizontalScrollBarPolicy(newPolicy); + if (m_rightEditor->horizontalScrollBarPolicy() != newPolicy) + m_rightEditor->setHorizontalScrollBarPolicy(newPolicy); +} + void SideBySideDiffEditorWidget::handlePositionChange(SideDiffEditorWidget *source, SideDiffEditorWidget *dest) { if (m_controller.m_ignoreCurrentIndexChange) diff --git a/src/plugins/diffeditor/sidebysidediffeditorwidget.h b/src/plugins/diffeditor/sidebysidediffeditorwidget.h index c315cec975..ee6f5f0eb7 100644 --- a/src/plugins/diffeditor/sidebysidediffeditorwidget.h +++ b/src/plugins/diffeditor/sidebysidediffeditorwidget.h @@ -95,6 +95,7 @@ private: void rightHSliderChanged(); void leftCursorPositionChanged(); void rightCursorPositionChanged(); + void syncHorizontalScrollBarPolicy(); void handlePositionChange(SideDiffEditorWidget *source, SideDiffEditorWidget *dest); void syncCursor(SideDiffEditorWidget *source, SideDiffEditorWidget *dest); diff --git a/src/plugins/projectexplorer/buildstep.cpp b/src/plugins/projectexplorer/buildstep.cpp index 265a718f14..232a95483a 100644 --- a/src/plugins/projectexplorer/buildstep.cpp +++ b/src/plugins/projectexplorer/buildstep.cpp @@ -337,22 +337,4 @@ BuildStep *BuildStepFactory::restore(BuildStepList *parent, const QVariantMap &m return bs; } -BuildStep *BuildStepFactory::clone(BuildStepList *parent, BuildStep *product) -{ - if ((m_info.flags & BuildStepInfo::Unclonable) != 0) - return nullptr; - if (m_info.id != product->id()) - return nullptr; - BuildStep *bs = m_info.creator(parent); - if (!bs) - return nullptr; - const QVariantMap map = product->toMap(); - if (!bs->fromMap(map)) { - QTC_CHECK(false); - delete bs; - return nullptr; - } - return bs; -} - } // ProjectExplorer diff --git a/src/plugins/projectexplorer/buildstep.h b/src/plugins/projectexplorer/buildstep.h index 840e31ee21..dd68e52216 100644 --- a/src/plugins/projectexplorer/buildstep.h +++ b/src/plugins/projectexplorer/buildstep.h @@ -132,7 +132,6 @@ public: Core::Id stepId() const; BuildStep *create(BuildStepList *parent, Core::Id id); BuildStep *restore(BuildStepList *parent, const QVariantMap &map); - BuildStep *clone(BuildStepList *parent, BuildStep *product); virtual bool canHandle(BuildStepList *bsl) const; diff --git a/src/plugins/projectexplorer/project.cpp b/src/plugins/projectexplorer/project.cpp index e9d5f3f83c..9c25e8d3b5 100644 --- a/src/plugins/projectexplorer/project.cpp +++ b/src/plugins/projectexplorer/project.cpp @@ -701,6 +701,11 @@ void Project::createTargetFromMap(const QVariantMap &map, int index) Target *t = restoreTarget(targetMap); if (!t) return; + if (t->runConfigurations().isEmpty() && t->buildConfigurations().isEmpty()) { + delete t; + return; + } + addTarget(t); } diff --git a/src/plugins/qmldesigner/components/propertyeditor/propertyeditorcontextobject.cpp b/src/plugins/qmldesigner/components/propertyeditor/propertyeditorcontextobject.cpp index 1584d88255..67183e1555 100644 --- a/src/plugins/qmldesigner/components/propertyeditor/propertyeditorcontextobject.cpp +++ b/src/plugins/qmldesigner/components/propertyeditor/propertyeditorcontextobject.cpp @@ -33,6 +33,7 @@ #include <coreplugin/messagebox.h> #include <utils/algorithm.h> +#include <utils/qtcassert.h> #include <QQmlContext> @@ -135,15 +136,13 @@ QStringList PropertyEditorContextObject::autoComplete(const QString &text, int p void PropertyEditorContextObject::toogleExportAlias() { - if (!m_model || !m_model->rewriterView()) - return; + QTC_ASSERT(m_model && m_model->rewriterView(), return); /* Ideally we should not missuse the rewriterView * If we add more code here we have to forward the property editor view */ RewriterView *rewriterView = m_model->rewriterView(); - if (rewriterView->selectedModelNodes().isEmpty()) - return; + QTC_ASSERT(!rewriterView->selectedModelNodes().isEmpty(), return); const ModelNode selectedNode = rewriterView->selectedModelNodes().constFirst(); @@ -174,15 +173,13 @@ void PropertyEditorContextObject::toogleExportAlias() void PropertyEditorContextObject::changeTypeName(const QString &typeName) { - if (!m_model || !m_model->rewriterView()) - return; + QTC_ASSERT(m_model && m_model->rewriterView(), return); /* Ideally we should not missuse the rewriterView * If we add more code here we have to forward the property editor view */ RewriterView *rewriterView = m_model->rewriterView(); - if (rewriterView->selectedModelNodes().isEmpty()) - return; + QTC_ASSERT(!rewriterView->selectedModelNodes().isEmpty(), return); ModelNode selectedNode = rewriterView->selectedModelNodes().constFirst(); @@ -210,15 +207,13 @@ void PropertyEditorContextObject::changeTypeName(const QString &typeName) void PropertyEditorContextObject::insertKeyframe(const QString &propertyName) { - if (!m_model || !m_model->rewriterView()) - return; + QTC_ASSERT(m_model && m_model->rewriterView(), return); /* Ideally we should not missuse the rewriterView * If we add more code here we have to forward the property editor view */ RewriterView *rewriterView = m_model->rewriterView(); - if (rewriterView->selectedModelNodes().isEmpty()) - return; + QTC_ASSERT(!rewriterView->selectedModelNodes().isEmpty(), return); ModelNode selectedNode = rewriterView->selectedModelNodes().constFirst(); diff --git a/src/plugins/qmldesigner/components/propertyeditor/propertyeditorqmlbackend.cpp b/src/plugins/qmldesigner/components/propertyeditor/propertyeditorqmlbackend.cpp index 2cb48df217..6ac07433a4 100644 --- a/src/plugins/qmldesigner/components/propertyeditor/propertyeditorqmlbackend.cpp +++ b/src/plugins/qmldesigner/components/propertyeditor/propertyeditorqmlbackend.cpp @@ -271,6 +271,8 @@ void PropertyEditorQmlBackend::setup(const QmlObjectNode &qmlObjectNode, const Q if (qmlObjectNode.isValid()) { + m_contextObject->setModel(propertyEditor->model()); + qCInfo(propertyEditorBenchmark) << Q_FUNC_INFO; QTime time; diff --git a/src/plugins/qmljseditor/qmljstextmark.cpp b/src/plugins/qmljseditor/qmljstextmark.cpp index 542450a9d4..4eac11b2c6 100644 --- a/src/plugins/qmljseditor/qmljstextmark.cpp +++ b/src/plugins/qmljseditor/qmljstextmark.cpp @@ -90,8 +90,8 @@ void QmlJSTextMark::init(bool warning, const QString message) { setIcon(warning ? Utils::Icons::CODEMODEL_WARNING.icon() : Utils::Icons::CODEMODEL_ERROR.icon()); - setColor(warning ? Utils::Theme::ClangCodeModel_Warning_TextMarkColor - : Utils::Theme::ClangCodeModel_Error_TextMarkColor); + setColor(warning ? Utils::Theme::CodeModel_Warning_TextMarkColor + : Utils::Theme::CodeModel_Error_TextMarkColor); setDefaultToolTip(warning ? QApplication::translate("QmlJS Code Model Marks", "Code Model Warning") : QApplication::translate("QmlJS Code Model Marks", "Code Model Error")); setToolTip(message); diff --git a/src/plugins/texteditor/texteditor.cpp b/src/plugins/texteditor/texteditor.cpp index 5a8486116b..ab10ab7d0b 100644 --- a/src/plugins/texteditor/texteditor.cpp +++ b/src/plugins/texteditor/texteditor.cpp @@ -5363,15 +5363,13 @@ void TextEditorWidgetPrivate::updateCurrentLineInScrollbar() { if (m_highlightCurrentLine && m_highlightScrollBarController) { m_highlightScrollBarController->removeHighlights(Constants::SCROLL_BAR_CURRENT_LINE); - if (m_highlightScrollBarController->scrollBar()->maximum() > 0) { - const QTextCursor &tc = q->textCursor(); - if (QTextLayout *layout = tc.block().layout()) { - const int pos = q->textCursor().block().firstLineNumber() + - layout->lineForTextPosition(tc.positionInBlock()).lineNumber(); - m_highlightScrollBarController->addHighlight({Constants::SCROLL_BAR_CURRENT_LINE, pos, - Theme::TextEditor_CurrentLine_ScrollBarColor, - Highlight::HighestPriority}); - } + const QTextCursor &tc = q->textCursor(); + if (QTextLayout *layout = tc.block().layout()) { + const int pos = q->textCursor().block().firstLineNumber() + + layout->lineForTextPosition(tc.positionInBlock()).lineNumber(); + m_highlightScrollBarController->addHighlight({Constants::SCROLL_BAR_CURRENT_LINE, pos, + Theme::TextEditor_CurrentLine_ScrollBarColor, + Highlight::HighestPriority}); } } } diff --git a/src/plugins/valgrind/xmlprotocol/errorlistmodel.cpp b/src/plugins/valgrind/xmlprotocol/errorlistmodel.cpp index f574f89c24..49e668176d 100644 --- a/src/plugins/valgrind/xmlprotocol/errorlistmodel.cpp +++ b/src/plugins/valgrind/xmlprotocol/errorlistmodel.cpp @@ -173,24 +173,16 @@ ErrorItem::ErrorItem(const ErrorListModel *model, const Error &error) } } -static QVariant location(const Frame &frame, int role) +static QVariant locationData(int role, const Frame &frame) { - switch (role) { - case Debugger::DetailedErrorView::LocationRole: - return QVariant::fromValue(Debugger::DiagnosticLocation(frame.filePath(), frame.line(), 0)); - case Qt::ToolTipRole: - return frame.filePath().isEmpty() ? QVariant() : QVariant(frame.filePath()); - default: - return QVariant(); - } + const Debugger::DiagnosticLocation location(frame.filePath(), frame.line(), 0); + return Debugger::DetailedErrorView::locationData(role, location); } QVariant ErrorItem::data(int column, int role) const { - if (column == Debugger::DetailedErrorView::LocationColumn) { - const Frame frame = m_model->findRelevantFrame(m_error); - return location(frame, role); - } + if (column == Debugger::DetailedErrorView::LocationColumn) + return locationData(role, m_model->findRelevantFrame(m_error)); // DiagnosticColumn switch (role) { @@ -243,7 +235,7 @@ QVariant StackItem::data(int column, int role) const { const ErrorItem * const errorItem = getErrorItem(); if (column == Debugger::DetailedErrorView::LocationColumn) - return location(errorItem->modelPrivate()->findRelevantFrame(errorItem->error()), role); + return locationData(role, errorItem->modelPrivate()->findRelevantFrame(errorItem->error())); // DiagnosticColumn switch (role) { @@ -271,7 +263,7 @@ FrameItem::FrameItem(const Frame &frame) : m_frame(frame) QVariant FrameItem::data(int column, int role) const { if (column == Debugger::DetailedErrorView::LocationColumn) - return location(m_frame, role); + return locationData(role, m_frame); // DiagnosticColumn switch (role) { |