Merge remote-tracking branch 'origin/master' into 4.4

Change-Id: I071b3016e11f94c5421822935c13cecda7075f40
This commit is contained in:
Orgad Shaneh
2017-06-30 14:22:00 +03:00
122 changed files with 1117 additions and 1317 deletions

View File

@@ -208,6 +208,6 @@ private:
CMBIPC_EXPORT QDebug operator<<(QDebug debug, CodeCompletion::Kind kind); CMBIPC_EXPORT QDebug operator<<(QDebug debug, CodeCompletion::Kind kind);
std::ostream &operator<<(std::ostream &os, const CodeCompletion::Kind kind); CMBIPC_EXPORT std::ostream &operator<<(std::ostream &os, const CodeCompletion::Kind kind);
std::ostream &operator<<(std::ostream &os, const CodeCompletion::Availability availability); CMBIPC_EXPORT std::ostream &operator<<(std::ostream &os, const CodeCompletion::Availability availability);
} // namespace ClangBackEnd } // namespace ClangBackEnd

View File

@@ -365,7 +365,7 @@ void QmlDebugConnection::connectToHost(const QString &hostName, quint16 port)
}); });
connect(socket, &QAbstractSocket::connected, this, &QmlDebugConnection::socketConnected); connect(socket, &QAbstractSocket::connected, this, &QmlDebugConnection::socketConnected);
connect(socket, &QAbstractSocket::disconnected, this, &QmlDebugConnection::socketDisconnected); connect(socket, &QAbstractSocket::disconnected, this, &QmlDebugConnection::socketDisconnected);
socket->connectToHost(hostName, port); socket->connectToHost(hostName.isEmpty() ? QString("localhost") : hostName, port);
} }
void QmlDebugConnection::startLocalServer(const QString &fileName) void QmlDebugConnection::startLocalServer(const QString &fileName)

View File

@@ -430,6 +430,7 @@ void Wizard::showVariables()
auto label = new QLabel(result); auto label = new QLabel(result);
label->setWordWrap(true); label->setWordWrap(true);
label->setTextInteractionFlags(Qt::TextSelectableByMouse | Qt::TextSelectableByKeyboard);
scrollArea->setWidget(label); scrollArea->setWidget(label);
layout->addWidget(scrollArea); layout->addWidget(scrollArea);

View File

@@ -55,14 +55,18 @@ void WizardPage::pageWasAdded()
void WizardPage::registerFieldWithName(const QString &name, QWidget *widget, void WizardPage::registerFieldWithName(const QString &name, QWidget *widget,
const char *property, const char *changedSignal) const char *property, const char *changedSignal)
{
registerFieldName(name);
registerField(name, widget, property, changedSignal);
}
void WizardPage::registerFieldName(const QString &name)
{ {
Wizard *wiz = qobject_cast<Wizard *>(wizard()); Wizard *wiz = qobject_cast<Wizard *>(wizard());
if (wiz) if (wiz)
wiz->registerFieldName(name); wiz->registerFieldName(name);
else else
m_toRegister.insert(name); m_toRegister.insert(name);
registerField(name, widget, property, changedSignal);
} }
bool WizardPage::handleReject() bool WizardPage::handleReject()

View File

@@ -54,6 +54,8 @@ signals:
void reportError(const QString &errorMessage); void reportError(const QString &errorMessage);
private: private:
void registerFieldName(const QString &name);
QSet<QString> m_toRegister; QSet<QString> m_toRegister;
}; };

View File

@@ -12,7 +12,6 @@ HEADERS += \
androidmanager.h \ androidmanager.h \
androidrunconfiguration.h \ androidrunconfiguration.h \
androidruncontrol.h \ androidruncontrol.h \
androidrunfactories.h \
androidsettingspage.h \ androidsettingspage.h \
androidsettingswidget.h \ androidsettingswidget.h \
androidtoolchain.h \ androidtoolchain.h \
@@ -58,7 +57,6 @@ SOURCES += \
androidmanager.cpp \ androidmanager.cpp \
androidrunconfiguration.cpp \ androidrunconfiguration.cpp \
androidruncontrol.cpp \ androidruncontrol.cpp \
androidrunfactories.cpp \
androidsettingspage.cpp \ androidsettingspage.cpp \
androidsettingswidget.cpp \ androidsettingswidget.cpp \
androidtoolchain.cpp \ androidtoolchain.cpp \

View File

@@ -83,8 +83,6 @@ Project {
"androidrunconfigurationwidget.ui", "androidrunconfigurationwidget.ui",
"androidruncontrol.cpp", "androidruncontrol.cpp",
"androidruncontrol.h", "androidruncontrol.h",
"androidrunfactories.cpp",
"androidrunfactories.h",
"androidrunnable.cpp", "androidrunnable.cpp",
"androidrunnable.h", "androidrunnable.h",
"androidrunner.cpp", "androidrunner.cpp",

View File

@@ -24,66 +24,37 @@
****************************************************************************/ ****************************************************************************/
#include "androidanalyzesupport.h" #include "androidanalyzesupport.h"
#include "androidrunner.h" #include "androidrunner.h"
#include "androidmanager.h"
#include <debugger/analyzer/analyzermanager.h>
#include <projectexplorer/project.h>
#include <projectexplorer/runconfiguration.h>
#include <projectexplorer/target.h>
#include <qtsupport/qtkitinformation.h>
using namespace Debugger;
using namespace ProjectExplorer; using namespace ProjectExplorer;
namespace Android { namespace Android {
namespace Internal { namespace Internal {
AndroidAnalyzeSupport::AndroidAnalyzeSupport(RunControl *runControl) AndroidQmlProfilerSupport::AndroidQmlProfilerSupport(RunControl *runControl)
: RunWorker(runControl) : RunWorker(runControl)
{ {
setDisplayName("AndroidAnalyzeSupport"); setDisplayName("AndroidQmlProfilerSupport");
RunConfiguration *runConfig = runControl->runConfiguration();
runControl->setDisplayName(AndroidManager::packageName(runConfig->target()));
runControl->setConnection(UrlConnection::localHostWithoutPort());
auto runner = new AndroidRunner(runControl); auto runner = new AndroidRunner(runControl);
addDependency(runner);
connect(runControl, &RunControl::finished, runner, [runner] { runner->stop(); }); auto profiler = runControl->createWorker(runControl->runMode());
profiler->addDependency(this);
connect(runControl, &RunControl::starting, runner, [runner] { runner->start(); }); connect(runner, &AndroidRunner::qmlServerReady, [this, runner, profiler](const QUrl &server) {
profiler->recordData("QmlServerUrl", server);
reportStarted();
});
}
connect(&m_outputParser, &QmlDebug::QmlOutputParser::waitingForConnectionOnPort, this, void AndroidQmlProfilerSupport::start()
[this, runControl](Utils::Port) { {
runControl->notifyRemoteSetupDone(m_qmlPort); }
});
// connect(runner, &AndroidRunner::handleRemoteProcessStarted, this, void AndroidQmlProfilerSupport::stop()
// [this](Utils::Port, Utils::Port qmlPort) { {
// m_qmlPort = qmlPort; reportStopped();
// });
// connect(runner, &AndroidRunner::handleRemoteProcessFinished, this,
// [this, runControl](const QString &errorMsg) {
// runControl->notifyRemoteFinished();
// appendMessage(errorMsg, Utils::NormalMessageFormat);
// });
connect(runner, &AndroidRunner::remoteErrorOutput, this,
[this, runControl](const QString &msg) {
appendMessage(msg, Utils::StdErrFormatSameLine);
m_outputParser.processOutput(msg);
});
connect(runner, &AndroidRunner::remoteOutput, this,
[this, runControl](const QString &msg) {
appendMessage(msg, Utils::StdOutFormatSameLine);
m_outputParser.processOutput(msg);
});
} }
} // namespace Internal } // namespace Internal

View File

@@ -25,25 +25,21 @@
#pragma once #pragma once
#include "androidrunconfiguration.h"
#include <projectexplorer/runconfiguration.h> #include <projectexplorer/runconfiguration.h>
#include <qmldebug/qmloutputparser.h>
namespace Android { namespace Android {
namespace Internal { namespace Internal {
class AndroidAnalyzeSupport : public ProjectExplorer::RunWorker class AndroidQmlProfilerSupport : public ProjectExplorer::RunWorker
{ {
Q_OBJECT Q_OBJECT
public: public:
explicit AndroidAnalyzeSupport(ProjectExplorer::RunControl *runControl); explicit AndroidQmlProfilerSupport(ProjectExplorer::RunControl *runControl);
private: private:
QmlDebug::QmlOutputParser m_outputParser; void start() override;
Utils::Port m_qmlPort; void stop() override;
}; };
} // namespace Internal } // namespace Internal

View File

@@ -94,6 +94,11 @@ DeviceProcessSignalOperation::Ptr AndroidDevice::signalOperation() const
return DeviceProcessSignalOperation::Ptr(new AndroidSignalOperation()); return DeviceProcessSignalOperation::Ptr(new AndroidSignalOperation());
} }
Utils::OsType AndroidDevice::osType() const
{
return Utils::OsTypeOtherUnix;
}
IDevice::Ptr AndroidDevice::clone() const IDevice::Ptr AndroidDevice::clone() const
{ {
return IDevice::Ptr(new AndroidDevice(*this)); return IDevice::Ptr(new AndroidDevice(*this));

View File

@@ -44,6 +44,7 @@ public:
void executeAction(Core::Id actionId, QWidget *parent = 0) override; void executeAction(Core::Id actionId, QWidget *parent = 0) override;
bool canAutoDetectPorts() const override; bool canAutoDetectPorts() const override;
ProjectExplorer::DeviceProcessSignalOperation::Ptr signalOperation() const override; ProjectExplorer::DeviceProcessSignalOperation::Ptr signalOperation() const override;
Utils::OsType osType() const override;
ProjectExplorer::IDevice::Ptr clone() const override; ProjectExplorer::IDevice::Ptr clone() const override;
ProjectExplorer::Connection toolControlChannel(const ControlChannelHint &) const override; ProjectExplorer::Connection toolControlChannel(const ControlChannelHint &) const override;

View File

@@ -25,22 +25,26 @@
#include "androidplugin.h" #include "androidplugin.h"
#include "androidconstants.h" #include "androidanalyzesupport.h"
#include "androidconfigurations.h" #include "androidconfigurations.h"
#include "androidconstants.h"
#include "androiddebugsupport.h"
#include "androiddeployconfiguration.h"
#include "androiddeployqtstep.h" #include "androiddeployqtstep.h"
#include "androiddevice.h" #include "androiddevice.h"
#include "androiddevicefactory.h" #include "androiddevicefactory.h"
#include "androidmanager.h"
#include "androidrunfactories.h"
#include "androidsettingspage.h"
#include "androidtoolchain.h"
#include "androidqtversionfactory.h"
#include "androiddeployconfiguration.h"
#include "androidgdbserverkitinformation.h" #include "androidgdbserverkitinformation.h"
#include "androidmanager.h"
#include "androidmanifesteditorfactory.h" #include "androidmanifesteditorfactory.h"
#include "androidpotentialkit.h" #include "androidpotentialkit.h"
#include "androidqtversionfactory.h"
#include "androidrunconfiguration.h"
#include "androidruncontrol.h"
#include "androidsettingspage.h"
#include "androidtoolchain.h"
#include "javacompletionassistprovider.h" #include "javacompletionassistprovider.h"
#include "javaeditor.h" #include "javaeditor.h"
#ifdef HAVE_QBS #ifdef HAVE_QBS
# include "androidqbspropertyprovider.h" # include "androidqbspropertyprovider.h"
#endif #endif
@@ -55,6 +59,8 @@
#include <QtPlugin> #include <QtPlugin>
using namespace ProjectExplorer; using namespace ProjectExplorer;
using namespace ProjectExplorer::Constants;
using namespace Android::Internal;
namespace Android { namespace Android {
@@ -66,9 +72,13 @@ bool AndroidPlugin::initialize(const QStringList &arguments, QString *errorMessa
Q_UNUSED(arguments); Q_UNUSED(arguments);
Q_UNUSED(errorMessage); Q_UNUSED(errorMessage);
RunControl::registerWorker<AndroidRunConfiguration, AndroidRunSupport>(NORMAL_RUN_MODE);
RunControl::registerWorker<AndroidRunConfiguration, AndroidDebugSupport>(DEBUG_RUN_MODE);
RunControl::registerWorker<AndroidRunConfiguration, AndroidDebugSupport>(DEBUG_RUN_MODE_WITH_BREAK_ON_MAIN);
RunControl::registerWorker<AndroidRunConfiguration, AndroidQmlProfilerSupport>(QML_PROFILER_RUN_MODE);
new AndroidConfigurations(this); new AndroidConfigurations(this);
addAutoReleasedObject(new Internal::AndroidRunControlFactory);
addAutoReleasedObject(new Internal::AndroidDeployQtStepFactory); addAutoReleasedObject(new Internal::AndroidDeployQtStepFactory);
addAutoReleasedObject(new Internal::AndroidSettingsPage); addAutoReleasedObject(new Internal::AndroidSettingsPage);
addAutoReleasedObject(new Internal::AndroidQtVersionFactory); addAutoReleasedObject(new Internal::AndroidQtVersionFactory);

View File

@@ -1,84 +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.
**
****************************************************************************/
#include "androidrunfactories.h"
#include "androidconstants.h"
#include "androiddebugsupport.h"
#include "androidanalyzesupport.h"
#include "androidrunconfiguration.h"
#include "androidruncontrol.h"
#include "androidmanager.h"
#include <debugger/debuggerconstants.h>
using namespace ProjectExplorer;
namespace Android {
namespace Internal {
AndroidRunControlFactory::AndroidRunControlFactory(QObject *parent)
: IRunControlFactory(parent)
{
}
bool AndroidRunControlFactory::canRun(RunConfiguration *runConfiguration, Core::Id mode) const
{
if (mode != ProjectExplorer::Constants::NORMAL_RUN_MODE
&& mode != ProjectExplorer::Constants::DEBUG_RUN_MODE
&& mode != ProjectExplorer::Constants::DEBUG_RUN_MODE_WITH_BREAK_ON_MAIN
&& mode != ProjectExplorer::Constants::QML_PROFILER_RUN_MODE) {
return false;
}
return qobject_cast<AndroidRunConfiguration *>(runConfiguration);
}
RunControl *AndroidRunControlFactory::create(RunConfiguration *runConfig, Core::Id mode, QString *)
{
Q_ASSERT(canRun(runConfig, mode));
if (mode == ProjectExplorer::Constants::NORMAL_RUN_MODE) {
auto runControl = new RunControl(runConfig, mode);
(void) new AndroidRunSupport(runControl);
return runControl;
}
if (mode == ProjectExplorer::Constants::DEBUG_RUN_MODE
|| mode == ProjectExplorer::Constants::DEBUG_RUN_MODE_WITH_BREAK_ON_MAIN) {
auto runControl = new RunControl(runConfig, mode);
(void) new AndroidDebugSupport(runControl);
return runControl;
}
if (mode == ProjectExplorer::Constants::QML_PROFILER_RUN_MODE) {
auto runControl = new RunControl(runConfig, mode);
auto profiler = runControl->createWorker(mode);
auto profilee = new AndroidAnalyzeSupport(runControl);
profiler->addDependency(profilee);
return runControl;
}
QTC_CHECK(false); // The other run modes are not supported
return 0;
}
} // namespace Internal
} // namespace Android

View File

@@ -1,56 +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/runconfiguration.h>
namespace ProjectExplorer {
class RunControl;
class RunConfigWidget;
class Target;
class Node;
} // namespace ProjectExplorer
namespace Android {
namespace Internal {
class AndroidRunControlFactory : public ProjectExplorer::IRunControlFactory
{
Q_OBJECT
public:
explicit AndroidRunControlFactory(QObject *parent = 0);
bool canRun(ProjectExplorer::RunConfiguration *runConfiguration,
Core::Id mode) const override;
ProjectExplorer::RunControl *create(ProjectExplorer::RunConfiguration *runConfiguration,
Core::Id mode, QString *errorMessage) override;
};
} // namespace Internal
} // namespace Android

View File

@@ -34,6 +34,7 @@
#include "androidavdmanager.h" #include "androidavdmanager.h"
#include <debugger/debuggerrunconfigurationaspect.h> #include <debugger/debuggerrunconfigurationaspect.h>
#include <coreplugin/messagemanager.h>
#include <projectexplorer/projectexplorer.h> #include <projectexplorer/projectexplorer.h>
#include <projectexplorer/projectexplorerconstants.h> #include <projectexplorer/projectexplorerconstants.h>
#include <projectexplorer/projectexplorersettings.h> #include <projectexplorer/projectexplorersettings.h>
@@ -632,7 +633,7 @@ void AndroidRunnerWorker::onProcessIdChanged(qint64 pid)
// Don't write to m_psProc from a different thread // Don't write to m_psProc from a different thread
QTC_ASSERT(QThread::currentThread() == thread(), return); QTC_ASSERT(QThread::currentThread() == thread(), return);
m_processPID = pid; m_processPID = pid;
if (m_processPID == -1) { if (pid == -1) {
emit remoteProcessFinished(QLatin1String("\n\n") + tr("\"%1\" died.") emit remoteProcessFinished(QLatin1String("\n\n") + tr("\"%1\" died.")
.arg(m_packageName)); .arg(m_packageName));
// App died/killed. Reset log and monitor processes. // App died/killed. Reset log and monitor processes.
@@ -714,6 +715,9 @@ AndroidRunner::AndroidRunner(RunControl *runControl)
connect(m_worker.data(), &AndroidRunnerWorker::remoteErrorOutput, connect(m_worker.data(), &AndroidRunnerWorker::remoteErrorOutput,
this, &AndroidRunner::remoteErrorOutput); this, &AndroidRunner::remoteErrorOutput);
connect(&m_outputParser, &QmlDebug::QmlOutputParser::waitingForConnectionOnPort,
this, &AndroidRunner::qmlServerPortReady);
m_thread.start(); m_thread.start();
} }
@@ -749,14 +753,28 @@ void AndroidRunner::stop()
emit asyncStop(m_androidRunnable); emit asyncStop(m_androidRunnable);
} }
void AndroidRunner::qmlServerPortReady(Port port)
{
// FIXME: Note that the passed is nonsense, as the port is on the
// device side. It only happens to work since we redirect
// host port n to target port n via adb.
QUrl serverUrl;
serverUrl.setPort(port.number());
emit qmlServerReady(serverUrl);
}
void AndroidRunner::remoteOutput(const QString &output) void AndroidRunner::remoteOutput(const QString &output)
{ {
Core::MessageManager::write("LOGCAT: " + output, Core::MessageManager::Silent);
appendMessage(output, Utils::StdOutFormatSameLine); appendMessage(output, Utils::StdOutFormatSameLine);
m_outputParser.processOutput(output);
} }
void AndroidRunner::remoteErrorOutput(const QString &output) void AndroidRunner::remoteErrorOutput(const QString &output)
{ {
Core::MessageManager::write("LOGCAT: " + output, Core::MessageManager::Silent);
appendMessage(output, Utils::StdErrFormatSameLine); appendMessage(output, Utils::StdErrFormatSameLine);
m_outputParser.processOutput(output);
} }
void AndroidRunner::handleRemoteProcessStarted(Utils::Port gdbServerPort, Utils::Port qmlServerPort, int pid) void AndroidRunner::handleRemoteProcessStarted(Utils::Port gdbServerPort, Utils::Port qmlServerPort, int pid)
@@ -770,6 +788,8 @@ void AndroidRunner::handleRemoteProcessStarted(Utils::Port gdbServerPort, Utils:
void AndroidRunner::handleRemoteProcessFinished(const QString &errString) void AndroidRunner::handleRemoteProcessFinished(const QString &errString)
{ {
appendMessage(errString, Utils::DebugFormat); appendMessage(errString, Utils::DebugFormat);
if (runControl()->isRunning())
runControl()->initiateStop();
reportStopped(); reportStopped();
} }

View File

@@ -30,6 +30,7 @@
#include <projectexplorer/runconfiguration.h> #include <projectexplorer/runconfiguration.h>
#include <qmldebug/qmldebugcommandlinearguments.h> #include <qmldebug/qmldebugcommandlinearguments.h>
#include <qmldebug/qmloutputparser.h>
#include <QFutureInterface> #include <QFutureInterface>
#include <QObject> #include <QObject>
@@ -62,18 +63,20 @@ public:
void start() override; void start() override;
void stop() override; void stop() override;
virtual void remoteOutput(const QString &output);
virtual void remoteErrorOutput(const QString &output);
signals: signals:
void asyncStart(const AndroidRunnable &runnable); void asyncStart(const AndroidRunnable &runnable);
void asyncStop(const AndroidRunnable &runnable); void asyncStop(const AndroidRunnable &runnable);
void remoteDebuggerRunning(); void remoteDebuggerRunning();
void qmlServerReady(const QUrl &serverUrl);
void adbParametersChanged(const QString &packageName, const QStringList &selector); void adbParametersChanged(const QString &packageName, const QStringList &selector);
void avdDetected(); void avdDetected();
private: private:
void qmlServerPortReady(Utils::Port port);
void remoteOutput(const QString &output);
void remoteErrorOutput(const QString &output);
void gotRemoteOutput(const QString &output);
void handleRemoteProcessStarted(Utils::Port gdbServerPort, Utils::Port qmlServerPort, int pid); void handleRemoteProcessStarted(Utils::Port gdbServerPort, Utils::Port qmlServerPort, int pid);
void handleRemoteProcessFinished(const QString &errString = QString()); void handleRemoteProcessFinished(const QString &errString = QString());
void checkAVD(); void checkAVD();
@@ -88,6 +91,7 @@ private:
Utils::Port m_gdbServerPort; Utils::Port m_gdbServerPort;
Utils::Port m_qmlServerPort; Utils::Port m_qmlServerPort;
Utils::ProcessHandle m_pid; Utils::ProcessHandle m_pid;
QmlDebug::QmlOutputParser m_outputParser;
}; };
} // namespace Internal } // namespace Internal

View File

@@ -57,6 +57,7 @@ QVariant GTestTreeItem::data(int column, int role) const
} }
case Qt::CheckStateRole: case Qt::CheckStateRole:
switch (type()) { switch (type()) {
case Root:
case TestCase: case TestCase:
case TestFunctionOrSet: case TestFunctionOrSet:
return checked(); return checked();

View File

@@ -49,7 +49,6 @@ QVariant QtTestTreeItem::data(int column, int role) const
return QVariant(name() + nameSuffix()); return QVariant(name() + nameSuffix());
case Qt::CheckStateRole: case Qt::CheckStateRole:
switch (type()) { switch (type()) {
case Root:
case TestDataFunction: case TestDataFunction:
case TestSpecialFunction: case TestSpecialFunction:
return QVariant(); return QVariant();

View File

@@ -50,7 +50,6 @@ QVariant QuickTestTreeItem::data(int column, int role) const
break; break;
case Qt::CheckStateRole: case Qt::CheckStateRole:
switch (type()) { switch (type()) {
case Root:
case TestDataFunction: case TestDataFunction:
case TestSpecialFunction: case TestSpecialFunction:
case TestDataTag: case TestDataTag:

View File

@@ -42,7 +42,8 @@ TestTreeItem::TestTreeItem(const QString &name, const QString &filePath, Type ty
m_filePath(filePath), m_filePath(filePath),
m_type(type) m_type(type)
{ {
m_checked = (m_type == TestCase || m_type == TestFunctionOrSet) ? Qt::Checked : Qt::Unchecked; m_checked = (m_type == TestCase || m_type == TestFunctionOrSet || m_type == Root)
? Qt::Checked : Qt::Unchecked;
} }
static QIcon testTreeIcon(TestTreeItem::Type type) static QIcon testTreeIcon(TestTreeItem::Type type)
@@ -103,7 +104,7 @@ Qt::ItemFlags TestTreeItem::flags(int /*column*/) const
static const Qt::ItemFlags defaultFlags = Qt::ItemIsEnabled | Qt::ItemIsSelectable; static const Qt::ItemFlags defaultFlags = Qt::ItemIsEnabled | Qt::ItemIsSelectable;
switch (m_type) { switch (m_type) {
case Root: case Root:
return Qt::ItemIsEnabled; return Qt::ItemIsEnabled | Qt::ItemIsAutoTristate | Qt::ItemIsUserCheckable;
case TestCase: case TestCase:
return defaultFlags | Qt::ItemIsAutoTristate | Qt::ItemIsUserCheckable; return defaultFlags | Qt::ItemIsAutoTristate | Qt::ItemIsUserCheckable;
case TestFunctionOrSet: case TestFunctionOrSet:
@@ -161,13 +162,14 @@ void TestTreeItem::setChecked(const Qt::CheckState checkState)
parent->revalidateCheckState(); parent->revalidateCheckState();
break; break;
} }
case Root:
case TestFunctionOrSet: case TestFunctionOrSet:
case TestCase: { case TestCase: {
Qt::CheckState usedState = (checkState == Qt::Unchecked ? Qt::Unchecked : Qt::Checked); Qt::CheckState usedState = (checkState == Qt::Unchecked ? Qt::Unchecked : Qt::Checked);
for (int row = 0, count = childCount(); row < count; ++row) for (int row = 0, count = childCount(); row < count; ++row)
childItem(row)->setChecked(usedState); childItem(row)->setChecked(usedState);
m_checked = usedState; m_checked = usedState;
if (m_type == TestFunctionOrSet) { if (m_type != Root) {
if (auto parent = parentItem()) if (auto parent = parentItem())
parent->revalidateCheckState(); parent->revalidateCheckState();
} }
@@ -181,6 +183,7 @@ void TestTreeItem::setChecked(const Qt::CheckState checkState)
Qt::CheckState TestTreeItem::checked() const Qt::CheckState TestTreeItem::checked() const
{ {
switch (m_type) { switch (m_type) {
case Root:
case TestCase: case TestCase:
case TestFunctionOrSet: case TestFunctionOrSet:
case TestDataTag: case TestDataTag:
@@ -295,7 +298,7 @@ QSet<QString> TestTreeItem::internalTargets() const
void TestTreeItem::revalidateCheckState() void TestTreeItem::revalidateCheckState()
{ {
const Type ttiType = type(); const Type ttiType = type();
if (ttiType != TestCase && ttiType != TestFunctionOrSet) if (ttiType != TestCase && ttiType != TestFunctionOrSet && ttiType != Root)
return; return;
if (childCount() == 0) // can this happen? (we're calling revalidateCS() on parentItem() if (childCount() == 0) // can this happen? (we're calling revalidateCS() on parentItem()
return; return;
@@ -317,13 +320,13 @@ void TestTreeItem::revalidateCheckState()
foundPartiallyChecked |= (child->checked() == Qt::PartiallyChecked); foundPartiallyChecked |= (child->checked() == Qt::PartiallyChecked);
if (foundPartiallyChecked || (foundChecked && foundUnchecked)) { if (foundPartiallyChecked || (foundChecked && foundUnchecked)) {
m_checked = Qt::PartiallyChecked; m_checked = Qt::PartiallyChecked;
if (ttiType == TestFunctionOrSet) if (ttiType == TestFunctionOrSet || ttiType == TestCase)
parentItem()->revalidateCheckState(); parentItem()->revalidateCheckState();
return; return;
} }
} }
m_checked = (foundUnchecked ? Qt::Unchecked : Qt::Checked); m_checked = (foundUnchecked ? Qt::Unchecked : Qt::Checked);
if (ttiType == TestFunctionOrSet) if (ttiType == TestFunctionOrSet || ttiType == TestCase)
parentItem()->revalidateCheckState(); parentItem()->revalidateCheckState();
} }

View File

@@ -135,6 +135,8 @@ private:
unsigned m_column = 0; unsigned m_column = 0;
QString m_proFile; QString m_proFile;
Status m_status = NewlyAdded; Status m_status = NewlyAdded;
friend class TestTreeModel; // grant access to (private) revalidateCheckState()
}; };
class TestCodeLocationAndType class TestCodeLocationAndType

View File

@@ -110,6 +110,7 @@ bool TestTreeModel::setData(const QModelIndex &index, const QVariant &value, int
emit dataChanged(index, index); emit dataChanged(index, index);
if (role == Qt::CheckStateRole) { if (role == Qt::CheckStateRole) {
switch (item->type()) { switch (item->type()) {
case TestTreeItem::Root:
case TestTreeItem::TestCase: case TestTreeItem::TestCase:
if (item->childCount() > 0) if (item->childCount() > 0)
emit dataChanged(index.child(0, 0), index.child(item->childCount() - 1, 0)); emit dataChanged(index.child(0, 0), index.child(item->childCount() - 1, 0));
@@ -228,6 +229,7 @@ bool TestTreeModel::sweepChildren(TestTreeItem *item)
if (child->type() != TestTreeItem::Root && child->markedForRemoval()) { if (child->type() != TestTreeItem::Root && child->markedForRemoval()) {
destroyItem(child); destroyItem(child);
item->revalidateCheckState();
hasChanged = true; hasChanged = true;
} else if (child->hasChildren()) { } else if (child->hasChildren()) {
hasChanged |= sweepChildren(child); hasChanged |= sweepChildren(child);
@@ -266,6 +268,12 @@ void TestTreeModel::handleParseResult(const TestParseResult *result, TestTreeIte
TestTreeItem *newItem = result->createTestTreeItem(); TestTreeItem *newItem = result->createTestTreeItem();
QTC_ASSERT(newItem, return); QTC_ASSERT(newItem, return);
parentNode->appendChild(newItem); parentNode->appendChild(newItem);
// new items are checked by default - revalidation of parents might be necessary
if (parentNode->checked() != Qt::Checked) {
parentNode->revalidateCheckState();
const QModelIndex &idx = indexForItem(parentNode);
emit dataChanged(idx, idx);
}
} }
void TestTreeModel::removeAllTestItems() void TestTreeModel::removeAllTestItems()

View File

@@ -82,6 +82,10 @@ void TestTreeView::changeCheckStateAll(const Qt::CheckState checkState)
item->setChecked(checkState); item->setChecked(checkState);
} }
} }
if (count == 0) {
if (auto item = static_cast<TestTreeItem *>(currentRootIndex.internalPointer()))
item->setChecked(checkState);
}
emit dataChanged(currentRootIndex, last); emit dataChanged(currentRootIndex, last);
} }
} }

View File

@@ -176,6 +176,11 @@ void BareMetalDevice::executeAction(Core::Id actionId, QWidget *parent)
Q_UNUSED(parent); Q_UNUSED(parent);
} }
Utils::OsType BareMetalDevice::osType() const
{
return Utils::OsTypeOther;
}
DeviceProcess *BareMetalDevice::createProcess(QObject *parent) const DeviceProcess *BareMetalDevice::createProcess(QObject *parent) const
{ {
return new GdbServerProviderProcess(sharedFromThis(), parent); return new GdbServerProviderProcess(sharedFromThis(), parent);

View File

@@ -50,6 +50,7 @@ public:
QList<Core::Id> actionIds() const override; QList<Core::Id> actionIds() const override;
QString displayNameForActionId(Core::Id actionId) const override; QString displayNameForActionId(Core::Id actionId) const override;
void executeAction(Core::Id actionId, QWidget *parent) override; void executeAction(Core::Id actionId, QWidget *parent) override;
Utils::OsType osType() const override;
ProjectExplorer::IDevice::Ptr clone() const override; ProjectExplorer::IDevice::Ptr clone() const override;
ProjectExplorer::DeviceProcessSignalOperation::Ptr signalOperation() const override; ProjectExplorer::DeviceProcessSignalOperation::Ptr signalOperation() const override;

View File

@@ -50,6 +50,16 @@ void Bookmark::removedFromEditor()
m_manager->deleteBookmark(this); m_manager->deleteBookmark(this);
} }
bool Bookmark::isDraggable() const
{
return true;
}
void Bookmark::dragToLine(int lineNumber)
{
move(lineNumber);
}
void Bookmark::updateLineNumber(int line) void Bookmark::updateLineNumber(int line)
{ {
if (line != lineNumber()) { if (line != lineNumber()) {
@@ -63,6 +73,7 @@ void Bookmark::move(int line)
if (line != lineNumber()) { if (line != lineNumber()) {
TextMark::move(line); TextMark::move(line);
m_manager->updateBookmark(this); m_manager->updateBookmark(this);
updateMarker();
} }
} }
@@ -84,6 +95,8 @@ void Bookmark::updateFileName(const QString &fileName)
void Bookmark::setNote(const QString &note) void Bookmark::setNote(const QString &note)
{ {
setToolTip(note); setToolTip(note);
setLineAnnotation(note);
updateMarker();
} }
void Bookmark::updateNote(const QString &note) void Bookmark::updateNote(const QString &note)

View File

@@ -43,6 +43,9 @@ public:
void updateFileName(const QString &fileName) override; void updateFileName(const QString &fileName) override;
void removedFromEditor() override; void removedFromEditor() override;
bool isDraggable() const override;
void dragToLine(int lineNumber) override;
void setNote(const QString &note); void setNote(const QString &note);
void updateNote(const QString &note); void updateNote(const QString &note);

View File

@@ -248,9 +248,9 @@ void IpcReceiver::references(const ReferencesMessage &message)
QTC_CHECK(futureInterface != QFutureInterface<CppTools::CursorInfo>()); QTC_CHECK(futureInterface != QFutureInterface<CppTools::CursorInfo>());
if (futureInterface.isCanceled()) if (futureInterface.isCanceled())
return; // A new request was issued making this one outdated. return; // Editor document closed or a new request was issued making this result outdated.
QTC_CHECK(entry.textDocument); QTC_ASSERT(entry.textDocument, return);
futureInterface.reportResult(toCursorInfo(*entry.textDocument, message)); futureInterface.reportResult(toCursorInfo(*entry.textDocument, message));
futureInterface.reportFinished(); futureInterface.reportFinished();
} }

View File

@@ -35,6 +35,7 @@
#include <QFuture> #include <QFuture>
#include <QObject> #include <QObject>
#include <QPointer>
#include <QSharedPointer> #include <QSharedPointer>
#include <QTextDocument> #include <QTextDocument>
#include <QVector> #include <QVector>
@@ -102,7 +103,7 @@ private:
: futureInterface(futureInterface) : futureInterface(futureInterface)
, textDocument(textDocument) {} , textDocument(textDocument) {}
QFutureInterface<CppTools::CursorInfo> futureInterface; QFutureInterface<CppTools::CursorInfo> futureInterface;
QTextDocument *textDocument = nullptr; QPointer<QTextDocument> textDocument;
}; };
QHash<quint64, ReferencesEntry> m_referencesTable; QHash<quint64, ReferencesEntry> m_referencesTable;
}; };

View File

@@ -79,6 +79,7 @@ ClangTextMark::ClangTextMark(const QString &fileName,
setPriority(warning ? TextEditor::TextMark::NormalPriority setPriority(warning ? TextEditor::TextMark::NormalPriority
: TextEditor::TextMark::HighPriority); : TextEditor::TextMark::HighPriority);
setIcon(diagnostic.severity()); setIcon(diagnostic.severity());
setLineAnnotation(diagnostic.text().toString());
} }
void ClangTextMark::setIcon(ClangBackEnd::DiagnosticSeverity severity) void ClangTextMark::setIcon(ClangBackEnd::DiagnosticSeverity severity)
@@ -96,7 +97,7 @@ void ClangTextMark::setIcon(ClangBackEnd::DiagnosticSeverity severity)
TextMark::setIcon(errorIcon); TextMark::setIcon(errorIcon);
} }
bool ClangTextMark::addToolTipContent(QLayout *target) bool ClangTextMark::addToolTipContent(QLayout *target) const
{ {
using Internal::ClangDiagnosticWidget; using Internal::ClangDiagnosticWidget;

View File

@@ -45,7 +45,7 @@ public:
private: private:
void setIcon(ClangBackEnd::DiagnosticSeverity severity); void setIcon(ClangBackEnd::DiagnosticSeverity severity);
bool addToolTipContent(QLayout *target) override; bool addToolTipContent(QLayout *target) const override;
void removedFromEditor() override; void removedFromEditor() override;
private: private:

View File

@@ -193,9 +193,8 @@ bool CMakeBuildStep::init(QList<const BuildStep *> &earlierSteps)
CMakeTool *tool = CMakeKitInformation::cmakeTool(target()->kit()); CMakeTool *tool = CMakeKitInformation::cmakeTool(target()->kit());
if (!tool || !tool->isValid()) { if (!tool || !tool->isValid()) {
emit addTask(Task(Task::Error, emit addTask(Task(Task::Error,
QCoreApplication::translate("CMakeProjectManager::CMakeBuildStep", tr("Qt Creator needs a CMake Tool set up to build. "
"Qt Creator needs a CMake Tool set up to build. " "Configure a CMake Tool in the kit options."),
"Configure a CMake Tool in the kit options."),
Utils::FileName(), -1, Utils::FileName(), -1,
ProjectExplorer::Constants::TASK_CATEGORY_BUILDSYSTEM)); ProjectExplorer::Constants::TASK_CATEGORY_BUILDSYSTEM));
canInit = false; canInit = false;
@@ -218,6 +217,22 @@ bool CMakeBuildStep::init(QList<const BuildStep *> &earlierSteps)
return false; return false;
} }
// Warn if doing out-of-source builds with a CMakeCache.txt is the source directory
const Utils::FileName projectDirectory = bc->target()->project()->projectDirectory();
if (bc->buildDirectory() != projectDirectory) {
Utils::FileName cmc = projectDirectory;
cmc.appendPath("CMakeCache.txt");
if (cmc.exists()) {
emit addTask(Task(Task::Warning,
tr("There is a CMakeCache.txt file in \"%1\", which suggest an "
"in-source build was done before. You are now building in \"%2\", "
"and the CMakeCache.txt file might confuse CMake.")
.arg(projectDirectory.toUserOutput(), bc->buildDirectory().toUserOutput()),
Utils::FileName(), -1,
ProjectExplorer::Constants::TASK_CATEGORY_BUILDSYSTEM));
}
}
QString arguments = allArguments(rc); QString arguments = allArguments(rc);
setIgnoreReturnValue(m_buildTarget == CMakeBuildStep::cleanTarget()); setIgnoreReturnValue(m_buildTarget == CMakeBuildStep::cleanTarget());

View File

@@ -97,7 +97,7 @@ void CppHoverHandler::identifyMatch(TextEditorWidget *editorWidget, int pos)
m_positionForEditorDocumentProcessor = -1; m_positionForEditorDocumentProcessor = -1;
if (editorDocumentProcessorHasDiagnosticAt(editorWidget, pos)) { if (editorDocumentProcessorHasDiagnosticAt(editorWidget, pos)) {
setIsDiagnosticTooltip(true); setPriority(Priority_Diagnostic);
m_positionForEditorDocumentProcessor = pos; m_positionForEditorDocumentProcessor = pos;
} else if (!editorWidget->extraSelectionTooltip(pos).isEmpty()) { } else if (!editorWidget->extraSelectionTooltip(pos).isEmpty()) {
setToolTip(editorWidget->extraSelectionTooltip(pos)); setToolTip(editorWidget->extraSelectionTooltip(pos));
@@ -110,12 +110,14 @@ void CppHoverHandler::identifyMatch(TextEditorWidget *editorWidget, int pos)
evaluator.execute(); evaluator.execute();
if (evaluator.hasDiagnosis()) { if (evaluator.hasDiagnosis()) {
setToolTip(evaluator.diagnosis()); setToolTip(evaluator.diagnosis());
setIsDiagnosticTooltip(true); setPriority(Priority_Diagnostic);
} }
if (evaluator.identifiedCppElement()) { if (evaluator.identifiedCppElement()) {
const QSharedPointer<CppElement> &cppElement = evaluator.cppElement(); const QSharedPointer<CppElement> &cppElement = evaluator.cppElement();
if (!isDiagnosticTooltip()) if (priority() != Priority_Diagnostic) {
setToolTip(cppElement->tooltip); setToolTip(cppElement->tooltip);
setPriority(cppElement->tooltip.isEmpty() ? Priority_None : Priority_Tooltip);
}
QStringList candidates = cppElement->helpIdCandidates; QStringList candidates = cppElement->helpIdCandidates;
candidates.removeDuplicates(); candidates.removeDuplicates();
foreach (const QString &helpId, candidates) { foreach (const QString &helpId, candidates) {
@@ -143,7 +145,7 @@ void CppHoverHandler::decorateToolTip()
if (Qt::mightBeRichText(toolTip())) if (Qt::mightBeRichText(toolTip()))
setToolTip(toolTip().toHtmlEscaped()); setToolTip(toolTip().toHtmlEscaped());
if (isDiagnosticTooltip()) if (priority() != Priority_Diagnostic)
return; return;
const HelpItem &help = lastHelpItemIdentified(); const HelpItem &help = lastHelpItemIdentified();

View File

@@ -29,6 +29,7 @@
#include "cppeditordocument.h" #include "cppeditordocument.h"
#include <cpptools/cpptoolsreuse.h> #include <cpptools/cpptoolsreuse.h>
#include <texteditor/convenience.h>
#include <QTextBlock> #include <QTextBlock>
#include <QTextCursor> #include <QTextCursor>
@@ -49,6 +50,12 @@ CppUseSelectionsUpdater::CppUseSelectionsUpdater(TextEditor::TextEditorWidget *e
connect(&m_timer, &QTimer::timeout, this, [this]() { update(); }); connect(&m_timer, &QTimer::timeout, this, [this]() { update(); });
} }
CppUseSelectionsUpdater::~CppUseSelectionsUpdater()
{
if (m_runnerWatcher)
m_runnerWatcher->cancel();
}
void CppUseSelectionsUpdater::scheduleUpdate() void CppUseSelectionsUpdater::scheduleUpdate()
{ {
m_timer.start(); m_timer.start();
@@ -59,23 +66,6 @@ void CppUseSelectionsUpdater::abortSchedule()
m_timer.stop(); m_timer.stop();
} }
static QTextCursor cursorAtWordStart(const QTextCursor &textCursor)
{
const int originalPosition = textCursor.position();
QTextCursor cursor(textCursor);
cursor.movePosition(QTextCursor::StartOfWord);
const int wordStartPosition = cursor.position();
if (originalPosition == wordStartPosition) {
// Cursor is not on an identifier, check whether we are right after one.
const QChar c = textCursor.document()->characterAt(originalPosition - 1);
if (CppTools::isValidIdentifierChar(c))
cursor.movePosition(QTextCursor::PreviousWord);
}
return cursor;
}
void CppUseSelectionsUpdater::update(CallType callType) void CppUseSelectionsUpdater::update(CallType callType)
{ {
auto *cppEditorWidget = qobject_cast<CppEditorWidget *>(m_editorWidget); auto *cppEditorWidget = qobject_cast<CppEditorWidget *>(m_editorWidget);
@@ -86,7 +76,7 @@ void CppUseSelectionsUpdater::update(CallType callType)
CppTools::CursorInfoParams params; CppTools::CursorInfoParams params;
params.semanticInfo = cppEditorWidget->semanticInfo(); params.semanticInfo = cppEditorWidget->semanticInfo();
params.textCursor = cursorAtWordStart(cppEditorWidget->textCursor()); params.textCursor = TextEditor::Convenience::wordStartCursor(cppEditorWidget->textCursor());
if (callType == Asynchronous) { if (callType == Asynchronous) {
if (isSameIdentifierAsBefore(params.textCursor)) if (isSameIdentifierAsBefore(params.textCursor))
@@ -144,8 +134,10 @@ void CppUseSelectionsUpdater::onFindUsesFinished()
return; return;
if (m_runnerRevision != m_editorWidget->document()->revision()) if (m_runnerRevision != m_editorWidget->document()->revision())
return; return;
if (m_runnerWordStartPosition != cursorAtWordStart(m_editorWidget->textCursor()).position()) if (m_runnerWordStartPosition
!= TextEditor::Convenience::wordStartCursor(m_editorWidget->textCursor()).position()) {
return; return;
}
processResults(m_runnerWatcher->result()); processResults(m_runnerWatcher->result());

View File

@@ -44,6 +44,7 @@ class CppUseSelectionsUpdater : public QObject
public: public:
explicit CppUseSelectionsUpdater(TextEditor::TextEditorWidget *editorWidget); explicit CppUseSelectionsUpdater(TextEditor::TextEditorWidget *editorWidget);
~CppUseSelectionsUpdater();
void scheduleUpdate(); void scheduleUpdate();
void abortSchedule(); void abortSchedule();

View File

@@ -34,8 +34,6 @@ namespace Internal {
class ResourcePreviewHoverHandler : public TextEditor::BaseHoverHandler class ResourcePreviewHoverHandler : public TextEditor::BaseHoverHandler
{ {
public:
private: private:
void identifyMatch(TextEditor::TextEditorWidget *editorWidget, int pos) override; void identifyMatch(TextEditor::TextEditorWidget *editorWidget, int pos) override;
void operateTooltip(TextEditor::TextEditorWidget *editorWidget, const QPoint &point) override; void operateTooltip(TextEditor::TextEditorWidget *editorWidget, const QPoint &point) override;

View File

@@ -128,19 +128,11 @@ void StartRemoteDialog::validate()
d->buttonBox->button(QDialogButtonBox::Ok)->setEnabled(valid); d->buttonBox->button(QDialogButtonBox::Ok)->setEnabled(valid);
} }
QUrl StartRemoteDialog::serverUrl() const
{
QUrl url;
Kit *kit = d->kitChooser->currentKit();
IDevice::ConstPtr device = DeviceKitInformation::device(kit);
url.setHost(device->sshParameters().host);
url.setPort(device->sshParameters().port);
return url;
}
StandardRunnable StartRemoteDialog::runnable() const StandardRunnable StartRemoteDialog::runnable() const
{ {
Kit *kit = d->kitChooser->currentKit();
StandardRunnable r; StandardRunnable r;
r.device = DeviceKitInformation::device(kit);
r.executable = d->executable->text(); r.executable = d->executable->text();
r.commandLineArguments = d->arguments->text(); r.commandLineArguments = d->arguments->text();
r.workingDirectory = d->workingDirectory->text(); r.workingDirectory = d->workingDirectory->text();

View File

@@ -28,7 +28,6 @@
#include <debugger/debugger_global.h> #include <debugger/debugger_global.h>
#include <QDialog> #include <QDialog>
#include <QUrl>
namespace ProjectExplorer { class StandardRunnable; } namespace ProjectExplorer { class StandardRunnable; }
@@ -44,7 +43,6 @@ public:
explicit StartRemoteDialog(QWidget *parent = 0); explicit StartRemoteDialog(QWidget *parent = 0);
~StartRemoteDialog() override; ~StartRemoteDialog() override;
QUrl serverUrl() const;
ProjectExplorer::StandardRunnable runnable() const; ProjectExplorer::StandardRunnable runnable() const;
private: private:

View File

@@ -468,12 +468,24 @@ static DebuggerRunConfigurationAspect *debuggerAspect(const RunControl *runContr
return runControl->runConfiguration()->extraAspect<DebuggerRunConfigurationAspect>(); return runControl->runConfiguration()->extraAspect<DebuggerRunConfigurationAspect>();
} }
static bool cppDebugging(const RunControl *runControl)
{
auto aspect = debuggerAspect(runControl);
return aspect ? aspect->useCppDebugger() : true; // For cases like valgrind-with-gdb.
}
static bool qmlDebugging(const RunControl *runControl)
{
auto aspect = debuggerAspect(runControl);
return aspect ? aspect->useCppDebugger() : false; // For cases like valgrind-with-gdb.
}
/// DebuggerRunTool /// DebuggerRunTool
DebuggerRunTool::DebuggerRunTool(RunControl *runControl) DebuggerRunTool::DebuggerRunTool(RunControl *runControl)
: RunWorker(runControl), : RunWorker(runControl),
m_isCppDebugging(debuggerAspect(runControl)->useCppDebugger()), m_isCppDebugging(cppDebugging(runControl)),
m_isQmlDebugging(debuggerAspect(runControl)->useQmlDebugger()) m_isQmlDebugging(qmlDebugging(runControl))
{ {
setDisplayName("DebuggerRunTool"); setDisplayName("DebuggerRunTool");
} }

View File

@@ -582,7 +582,7 @@ static QList<RowData> readLines(QStringRef patch,
break; break;
} }
Diff diffToBeAdded(command, line.mid(1) + newLine); Diff diffToBeAdded(command, line.mid(1).toString() + newLine);
if (!diffList.isEmpty() && diffList.last().command == command) if (!diffList.isEmpty() && diffList.last().command == command)
diffList.last().text.append(diffToBeAdded.text); diffList.last().text.append(diffToBeAdded.text);

View File

@@ -66,6 +66,8 @@ BranchDialog::BranchDialog(QWidget *parent) :
m_ui->includeOldCheckBox->setToolTip( m_ui->includeOldCheckBox->setToolTip(
tr("Include branches and tags that have not been active for %n days.", 0, tr("Include branches and tags that have not been active for %n days.", 0,
Constants::OBSOLETE_COMMIT_AGE_IN_DAYS)); Constants::OBSOLETE_COMMIT_AGE_IN_DAYS));
m_ui->includeTagsCheckBox->setChecked(GitPlugin::client()->settings().boolValue(
GitSettings::showTagsKey));
connect(m_ui->refreshButton, &QAbstractButton::clicked, this, &BranchDialog::refreshCurrentRepository); connect(m_ui->refreshButton, &QAbstractButton::clicked, this, &BranchDialog::refreshCurrentRepository);
connect(m_ui->addButton, &QAbstractButton::clicked, this, &BranchDialog::add); connect(m_ui->addButton, &QAbstractButton::clicked, this, &BranchDialog::add);
@@ -83,6 +85,10 @@ BranchDialog::BranchDialog(QWidget *parent) :
m_model->setOldBranchesIncluded(value); m_model->setOldBranchesIncluded(value);
refreshCurrentRepository(); refreshCurrentRepository();
}); });
connect(m_ui->includeTagsCheckBox, &QCheckBox::toggled, this, [this](bool value) {
GitPlugin::client()->settings().setValue(GitSettings::showTagsKey, value);
refreshCurrentRepository();
});
m_ui->branchView->setModel(m_model); m_ui->branchView->setModel(m_model);
m_ui->branchView->setFocus(); m_ui->branchView->setFocus();

View File

@@ -65,6 +65,13 @@
</attribute> </attribute>
</widget> </widget>
</item> </item>
<item>
<widget class="QCheckBox" name="includeTagsCheckBox">
<property name="text">
<string>Include ta&amp;gs</string>
</property>
</widget>
</item>
<item> <item>
<widget class="QCheckBox" name="includeOldCheckBox"> <widget class="QCheckBox" name="includeOldCheckBox">
<property name="text"> <property name="text">

View File

@@ -76,7 +76,6 @@ VcsBaseClientSettings SettingsPageWidget::settings() const
rc.setValue(GitSettings::logCountKey, m_ui.logCountSpinBox->value()); rc.setValue(GitSettings::logCountKey, m_ui.logCountSpinBox->value());
rc.setValue(GitSettings::timeoutKey, m_ui.timeoutSpinBox->value()); rc.setValue(GitSettings::timeoutKey, m_ui.timeoutSpinBox->value());
rc.setValue(GitSettings::pullRebaseKey, m_ui.pullRebaseCheckBox->isChecked()); rc.setValue(GitSettings::pullRebaseKey, m_ui.pullRebaseCheckBox->isChecked());
rc.setValue(GitSettings::showTagsKey, m_ui.showTagsCheckBox->isChecked());
rc.setValue(GitSettings::winSetHomeEnvironmentKey, m_ui.winHomeCheckBox->isChecked()); rc.setValue(GitSettings::winSetHomeEnvironmentKey, m_ui.winHomeCheckBox->isChecked());
rc.setValue(GitSettings::gitkOptionsKey, m_ui.gitkOptionsLineEdit->text().trimmed()); rc.setValue(GitSettings::gitkOptionsKey, m_ui.gitkOptionsLineEdit->text().trimmed());
rc.setValue(GitSettings::repositoryBrowserCmd, m_ui.repBrowserCommandPathChooser->path().trimmed()); rc.setValue(GitSettings::repositoryBrowserCmd, m_ui.repBrowserCommandPathChooser->path().trimmed());
@@ -90,7 +89,6 @@ void SettingsPageWidget::setSettings(const VcsBaseClientSettings &s)
m_ui.logCountSpinBox->setValue(s.intValue(GitSettings::logCountKey)); m_ui.logCountSpinBox->setValue(s.intValue(GitSettings::logCountKey));
m_ui.timeoutSpinBox->setValue(s.intValue(GitSettings::timeoutKey)); m_ui.timeoutSpinBox->setValue(s.intValue(GitSettings::timeoutKey));
m_ui.pullRebaseCheckBox->setChecked(s.boolValue(GitSettings::pullRebaseKey)); m_ui.pullRebaseCheckBox->setChecked(s.boolValue(GitSettings::pullRebaseKey));
m_ui.showTagsCheckBox->setChecked(s.boolValue(GitSettings::showTagsKey));
m_ui.winHomeCheckBox->setChecked(s.boolValue(GitSettings::winSetHomeEnvironmentKey)); m_ui.winHomeCheckBox->setChecked(s.boolValue(GitSettings::winSetHomeEnvironmentKey));
m_ui.gitkOptionsLineEdit->setText(s.stringValue(GitSettings::gitkOptionsKey)); m_ui.gitkOptionsLineEdit->setText(s.stringValue(GitSettings::gitkOptionsKey));
m_ui.repBrowserCommandPathChooser->setPath(s.stringValue(GitSettings::repositoryBrowserCmd)); m_ui.repBrowserCommandPathChooser->setPath(s.stringValue(GitSettings::repositoryBrowserCmd));

View File

@@ -7,7 +7,7 @@
<x>0</x> <x>0</x>
<y>0</y> <y>0</y>
<width>705</width> <width>705</width>
<height>427</height> <height>403</height>
</rect> </rect>
</property> </property>
<layout class="QVBoxLayout" name="verticalLayout"> <layout class="QVBoxLayout" name="verticalLayout">
@@ -123,13 +123,6 @@
</property> </property>
</widget> </widget>
</item> </item>
<item row="2" column="0">
<widget class="QCheckBox" name="showTagsCheckBox">
<property name="text">
<string>Show tags in Branches dialog</string>
</property>
</widget>
</item>
</layout> </layout>
</widget> </widget>
</item> </item>
@@ -214,7 +207,6 @@
<tabstop>logCountSpinBox</tabstop> <tabstop>logCountSpinBox</tabstop>
<tabstop>timeoutSpinBox</tabstop> <tabstop>timeoutSpinBox</tabstop>
<tabstop>pullRebaseCheckBox</tabstop> <tabstop>pullRebaseCheckBox</tabstop>
<tabstop>showTagsCheckBox</tabstop>
<tabstop>gitkOptionsLineEdit</tabstop> <tabstop>gitkOptionsLineEdit</tabstop>
</tabstops> </tabstops>
<resources/> <resources/>

View File

@@ -27,7 +27,6 @@
#include "glsleditorconstants.h" #include "glsleditorconstants.h"
#include "glsleditorplugin.h" #include "glsleditorplugin.h"
#include "glslhighlighter.h" #include "glslhighlighter.h"
#include "glslhoverhandler.h"
#include "glslautocompleter.h" #include "glslautocompleter.h"
#include "glslcompletionassist.h" #include "glslcompletionassist.h"
#include "glslindenter.h" #include "glslindenter.h"
@@ -332,8 +331,6 @@ GlslEditorFactory::GlslEditorFactory()
setEditorActionHandlers(TextEditorActionHandler::Format setEditorActionHandlers(TextEditorActionHandler::Format
| TextEditorActionHandler::UnCommentSelection | TextEditorActionHandler::UnCommentSelection
| TextEditorActionHandler::UnCollapseAll); | TextEditorActionHandler::UnCollapseAll);
addHoverHandler(new GlslHoverHandler);
} }
} // namespace Internal } // namespace Internal

View File

@@ -10,7 +10,6 @@ glsleditorplugin.h \
glslhighlighter.h \ glslhighlighter.h \
glslautocompleter.h \ glslautocompleter.h \
glslindenter.h \ glslindenter.h \
glslhoverhandler.h \
glslcompletionassist.h glslcompletionassist.h
SOURCES += \ SOURCES += \
@@ -19,7 +18,6 @@ glsleditorplugin.cpp \
glslhighlighter.cpp \ glslhighlighter.cpp \
glslautocompleter.cpp \ glslautocompleter.cpp \
glslindenter.cpp \ glslindenter.cpp \
glslhoverhandler.cpp \
glslcompletionassist.cpp glslcompletionassist.cpp
RESOURCES += glsleditor.qrc RESOURCES += glsleditor.qrc

View File

@@ -25,8 +25,6 @@ QtcPlugin {
"glsleditorplugin.h", "glsleditorplugin.h",
"glslhighlighter.cpp", "glslhighlighter.cpp",
"glslhighlighter.h", "glslhighlighter.h",
"glslhoverhandler.cpp",
"glslhoverhandler.h",
"glslindenter.cpp", "glslindenter.cpp",
"glslindenter.h", "glslindenter.h",
] ]

View File

@@ -1,45 +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 "glslhoverhandler.h"
#include "glsleditor.h"
namespace GlslEditor {
namespace Internal {
void GlslHoverHandler::identifyMatch(TextEditor::TextEditorWidget *editorWidget, int pos)
{
if (!editorWidget->extraSelectionTooltip(pos).isEmpty())
setToolTip(editorWidget->extraSelectionTooltip(pos));
}
void GlslHoverHandler::decorateToolTip()
{
if (Qt::mightBeRichText(toolTip()))
setToolTip(toolTip().toHtmlEscaped());
}
} // namespace Internal
} // namespace GlslEditor

View File

@@ -1,44 +0,0 @@
/****************************************************************************
**
** Copyright (C) 2016 The Qt Company Ltd.
** Contact: https://www.qt.io/licensing/
**
** This file is part of Qt Creator.
**
** Commercial License Usage
** Licensees holding valid commercial Qt licenses may use this file in
** accordance with the commercial license agreement provided with the
** Software or, alternatively, in accordance with the terms contained in
** a written agreement between you and The Qt Company. For licensing terms
** and conditions see https://www.qt.io/terms-conditions. For further
** information use the contact form at https://www.qt.io/contact-us.
**
** GNU General Public License Usage
** Alternatively, this file may be used under the terms of the GNU
** General Public License version 3 as published by the Free Software
** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
** included in the packaging of this file. Please review the following
** information to ensure the GNU General Public License requirements will
** be met: https://www.gnu.org/licenses/gpl-3.0.html.
**
****************************************************************************/
#pragma once
#include <texteditor/basehoverhandler.h>
namespace GlslEditor {
namespace Internal {
class GlslHoverHandler : public TextEditor::BaseHoverHandler
{
public:
GlslHoverHandler() {}
private:
void identifyMatch(TextEditor::TextEditorWidget *editorWidget, int pos) override;
void decorateToolTip() override;
};
} // namespace Internal
} // namespace GlslEditor

View File

@@ -213,6 +213,11 @@ bool IosDevice::canAutoDetectPorts() const
return true; return true;
} }
Utils::OsType IosDevice::osType() const
{
return Utils::OsTypeMac;
}
// IosDeviceManager // IosDeviceManager

View File

@@ -68,6 +68,7 @@ public:
QString osVersion() const; QString osVersion() const;
Utils::Port nextPort() const; Utils::Port nextPort() const;
bool canAutoDetectPorts() const override; bool canAutoDetectPorts() const override;
Utils::OsType osType() const override;
static QString name(); static QString name();

View File

@@ -154,6 +154,11 @@ bool IosSimulator::canAutoDetectPorts() const
return true; return true;
} }
Utils::OsType IosSimulator::osType() const
{
return Utils::OsTypeMac;
}
IosSimulator::ConstPtr IosKitInformation::simulator(Kit *kit) IosSimulator::ConstPtr IosKitInformation::simulator(Kit *kit)
{ {
if (!kit) if (!kit)

View File

@@ -77,6 +77,7 @@ public:
QVariantMap toMap() const override; QVariantMap toMap() const override;
Utils::Port nextPort() const; Utils::Port nextPort() const;
bool canAutoDetectPorts() const override; bool canAutoDetectPorts() const override;
Utils::OsType osType() const override;
ProjectExplorer::IDevice::Ptr clone() const override; ProjectExplorer::IDevice::Ptr clone() const override;
protected: protected:

View File

@@ -142,6 +142,11 @@ Connection DesktopDevice::toolControlChannel(const ControlChannelHint &) const
return HostName("localhost"); return HostName("localhost");
} }
Utils::OsType DesktopDevice::osType() const
{
return Utils::HostOsInfo::hostOs();
}
IDevice::Ptr DesktopDevice::clone() const IDevice::Ptr DesktopDevice::clone() const
{ {
return Ptr(new DesktopDevice(*this)); return Ptr(new DesktopDevice(*this));

View File

@@ -53,6 +53,7 @@ public:
DeviceProcessSignalOperation::Ptr signalOperation() const override; DeviceProcessSignalOperation::Ptr signalOperation() const override;
DeviceEnvironmentFetcher::Ptr environmentFetcher() const override; DeviceEnvironmentFetcher::Ptr environmentFetcher() const override;
Connection toolControlChannel(const ControlChannelHint &) const override; Connection toolControlChannel(const ControlChannelHint &) const override;
Utils::OsType osType() const override;
IDevice::Ptr clone() const override; IDevice::Ptr clone() const override;

View File

@@ -441,6 +441,7 @@ private:
{ {
return DeviceProcessSignalOperation::Ptr(); return DeviceProcessSignalOperation::Ptr();
} }
Utils::OsType osType() const override { return Utils::HostOsInfo::hostOs(); }
}; };
void ProjectExplorerPlugin::testDeviceManager() void ProjectExplorerPlugin::testDeviceManager()

View File

@@ -278,6 +278,11 @@ DeviceTester *IDevice::createDeviceTester() const
return 0; return 0;
} }
Utils::OsType IDevice::osType() const
{
return Utils::OsTypeOther;
}
DeviceProcess *IDevice::createProcess(QObject * /* parent */) const DeviceProcess *IDevice::createProcess(QObject * /* parent */) const
{ {
QTC_CHECK(false); QTC_CHECK(false);

View File

@@ -28,6 +28,7 @@
#include "../projectexplorer_export.h" #include "../projectexplorer_export.h"
#include <coreplugin/id.h> #include <coreplugin/id.h>
#include <utils/hostosinfo.h>
#include <QAbstractSocket> #include <QAbstractSocket>
#include <QList> #include <QList>
@@ -160,6 +161,7 @@ public:
virtual DeviceProcessList *createProcessListModel(QObject *parent = 0) const; virtual DeviceProcessList *createProcessListModel(QObject *parent = 0) const;
virtual bool hasDeviceTester() const { return false; } virtual bool hasDeviceTester() const { return false; }
virtual DeviceTester *createDeviceTester() const; virtual DeviceTester *createDeviceTester() const;
virtual Utils::OsType osType() const;
virtual bool canCreateProcess() const { return false; } virtual bool canCreateProcess() const { return false; }
virtual DeviceProcess *createProcess(QObject *parent) const; virtual DeviceProcess *createProcess(QObject *parent) const;

View File

@@ -44,6 +44,7 @@
#include <coreplugin/icore.h> #include <coreplugin/icore.h>
#include <coreplugin/icontext.h> #include <coreplugin/icontext.h>
#include <coreplugin/messagemanager.h>
#include <QDir> #include <QDir>
#include <QPushButton> #include <QPushButton>
@@ -1178,7 +1179,7 @@ void RunControlPrivate::setState(RunControlState newState)
void RunControlPrivate::debugMessage(const QString &msg) void RunControlPrivate::debugMessage(const QString &msg)
{ {
//q->appendMessage(msg + '\n', Utils::DebugFormat); Core::MessageManager::write(msg, Core::MessageManager::Silent);
qCDebug(statesLog()) << msg; qCDebug(statesLog()) << msg;
} }

View File

@@ -523,7 +523,6 @@ signals:
void appendMessageRequested(ProjectExplorer::RunControl *runControl, void appendMessageRequested(ProjectExplorer::RunControl *runControl,
const QString &msg, Utils::OutputFormat format); const QString &msg, Utils::OutputFormat format);
void aboutToStart(); void aboutToStart();
void starting();
void started(); void started();
void finished(); void finished();
void applicationProcessHandleChanged(QPrivateSignal); // Use setApplicationProcessHandle void applicationProcessHandleChanged(QPrivateSignal); // Use setApplicationProcessHandle

View File

@@ -25,13 +25,10 @@
#pragma once #pragma once
#include <android/androidrunfactories.h>
#include <projectexplorer/runconfiguration.h> #include <projectexplorer/runconfiguration.h>
#include <qmakeprojectmanager/qmakerunconfigurationfactory.h> #include <qmakeprojectmanager/qmakerunconfigurationfactory.h>
namespace ProjectExplorer { namespace ProjectExplorer {
class RunControl;
class RunConfigWidget;
class Target; class Target;
class Node; class Node;
} // namespace ProjectExplorer } // namespace ProjectExplorer

View File

@@ -37,14 +37,9 @@ namespace Internal {
class ProFileHoverHandler : public TextEditor::BaseHoverHandler class ProFileHoverHandler : public TextEditor::BaseHoverHandler
{ {
Q_OBJECT
public: public:
explicit ProFileHoverHandler(const TextEditor::Keywords &keywords); explicit ProFileHoverHandler(const TextEditor::Keywords &keywords);
signals:
void creatorHelpRequested(const QUrl &url);
private: private:
void identifyMatch(TextEditor::TextEditorWidget *editorWidget, int pos) override; void identifyMatch(TextEditor::TextEditorWidget *editorWidget, int pos) override;
void identifyQMakeKeyword(const QString &text, int pos); void identifyQMakeKeyword(const QString &text, int pos);

View File

@@ -29,6 +29,7 @@
#include <texteditor/basehoverhandler.h> #include <texteditor/basehoverhandler.h>
#include <QColor> #include <QColor>
#include <QCoreApplication>
QT_BEGIN_NAMESPACE QT_BEGIN_NAMESPACE
template <class> class QList; template <class> class QList;
@@ -49,7 +50,7 @@ class QmlJSEditorWidget;
class QmlJSHoverHandler : public TextEditor::BaseHoverHandler class QmlJSHoverHandler : public TextEditor::BaseHoverHandler
{ {
Q_OBJECT Q_DECLARE_TR_FUNCTIONS(QmlJSHoverHandler)
public: public:
QmlJSHoverHandler(); QmlJSHoverHandler();

View File

@@ -114,7 +114,7 @@ void QmlProfilerRunner::start()
QUrl serverUrl = this->serverUrl(); QUrl serverUrl = this->serverUrl();
if (serverUrl.port() != -1) { if (serverUrl.port() != -1) {
auto clientManager = Internal::QmlProfilerTool::clientManager(); QmlProfilerClientManager *clientManager = Internal::QmlProfilerTool::clientManager();
clientManager->setServerUrl(serverUrl); clientManager->setServerUrl(serverUrl);
clientManager->connectToTcpServer(); clientManager->connectToTcpServer();
} }
@@ -149,6 +149,7 @@ void QmlProfilerRunner::stop()
} }
break; break;
} }
reportStopped();
} }
void QmlProfilerRunner::notifyRemoteFinished() void QmlProfilerRunner::notifyRemoteFinished()
@@ -232,6 +233,7 @@ void QmlProfilerRunner::notifyRemoteSetupDone(Utils::Port port)
auto clientManager = Internal::QmlProfilerTool::clientManager(); auto clientManager = Internal::QmlProfilerTool::clientManager();
clientManager->setServerUrl(serverUrl); clientManager->setServerUrl(serverUrl);
clientManager->connectToTcpServer(); clientManager->connectToTcpServer();
reportStarted();
} }
} }

View File

@@ -44,7 +44,7 @@ void QmlProfilerTextMark::addTypeId(int typeId)
m_typeIds.append(typeId); m_typeIds.append(typeId);
} }
void QmlProfilerTextMark::paint(QPainter *painter, const QRect &paintRect) const void QmlProfilerTextMark::paintIcon(QPainter *painter, const QRect &paintRect) const
{ {
painter->save(); painter->save();
painter->setPen(Qt::black); painter->setPen(Qt::black);
@@ -108,7 +108,7 @@ void QmlProfilerTextMarkModel::createMarks(QmlProfilerTool *tool, const QString
} }
} }
bool QmlProfilerTextMark::addToolTipContent(QLayout *target) bool QmlProfilerTextMark::addToolTipContent(QLayout *target) const
{ {
QGridLayout *layout = new QGridLayout; QGridLayout *layout = new QGridLayout;
layout->setHorizontalSpacing(10); layout->setHorizontalSpacing(10);

View File

@@ -37,10 +37,10 @@ public:
QmlProfilerTextMark(QmlProfilerTool *tool, int typeId, const QString &fileName, int lineNumber); QmlProfilerTextMark(QmlProfilerTool *tool, int typeId, const QString &fileName, int lineNumber);
void addTypeId(int typeId); void addTypeId(int typeId);
void paint(QPainter *painter, const QRect &rect) const override; void paintIcon(QPainter *painter, const QRect &rect) const override;
void clicked() override; void clicked() override;
bool isClickable() const override { return true; } bool isClickable() const override { return true; }
bool addToolTipContent(QLayout *target) override; bool addToolTipContent(QLayout *target) const override;
private: private:
QmlProfilerTool *m_tool; QmlProfilerTool *m_tool;

View File

@@ -122,6 +122,11 @@ QString QnxDevice::displayType() const
return tr("QNX"); return tr("QNX");
} }
OsType QnxDevice::osType() const
{
return OsTypeOtherUnix;
}
int QnxDevice::qnxVersion() const int QnxDevice::qnxVersion() const
{ {
if (m_versionNumber == 0) if (m_versionNumber == 0)

View File

@@ -56,6 +56,7 @@ public:
void executeAction(Core::Id actionId, QWidget *parent) override; void executeAction(Core::Id actionId, QWidget *parent) override;
QString displayType() const override; QString displayType() const override;
Utils::OsType osType() const override;
int qnxVersion() const; int qnxVersion() const;

View File

@@ -203,6 +203,11 @@ void LinuxDevice::executeAction(Core::Id actionId, QWidget *parent)
delete d; delete d;
} }
Utils::OsType LinuxDevice::osType() const
{
return Utils::OsTypeLinux;
}
LinuxDevice::LinuxDevice(const QString &name, Core::Id type, MachineType machineType, LinuxDevice::LinuxDevice(const QString &name, Core::Id type, MachineType machineType,
Origin origin, Core::Id id) Origin origin, Core::Id id)
: IDevice(type, origin, machineType, id) : IDevice(type, origin, machineType, id)

View File

@@ -54,6 +54,7 @@ public:
QList<Core::Id> actionIds() const; QList<Core::Id> actionIds() const;
QString displayNameForActionId(Core::Id actionId) const; QString displayNameForActionId(Core::Id actionId) const;
void executeAction(Core::Id actionId, QWidget *parent); void executeAction(Core::Id actionId, QWidget *parent);
Utils::OsType osType() const override;
ProjectExplorer::IDevice::Ptr clone() const; ProjectExplorer::IDevice::Ptr clone() const;
bool canCreateProcess() const { return true; } bool canCreateProcess() const { return true; }

View File

@@ -26,27 +26,17 @@
#include "basehoverhandler.h" #include "basehoverhandler.h"
#include "texteditor.h" #include "texteditor.h"
#include <coreplugin/icore.h>
#include <utils/tooltip/tooltip.h> #include <utils/tooltip/tooltip.h>
#include <QPoint>
using namespace Core;
namespace TextEditor { namespace TextEditor {
BaseHoverHandler::BaseHoverHandler() : m_diagnosticTooltip(false), m_priority(-1)
{
}
BaseHoverHandler::~BaseHoverHandler() BaseHoverHandler::~BaseHoverHandler()
{} {}
void BaseHoverHandler::showToolTip(TextEditorWidget *widget, const QPoint &point, int pos) void BaseHoverHandler::showToolTip(TextEditorWidget *widget, const QPoint &point, bool decorate)
{ {
widget->setContextHelpId(QString()); if (decorate)
decorateToolTip();
process(widget, pos);
operateTooltip(widget, point); operateTooltip(widget, point);
} }
@@ -64,9 +54,6 @@ int BaseHoverHandler::priority() const
if (m_priority >= 0) if (m_priority >= 0)
return m_priority; return m_priority;
if (isDiagnosticTooltip())
return Priority_Diagnostic;
if (lastHelpItemIdentified().isValid()) if (lastHelpItemIdentified().isValid())
return Priority_Help; return Priority_Help;
@@ -103,21 +90,6 @@ const QString &BaseHoverHandler::toolTip() const
return m_toolTip; return m_toolTip;
} }
void BaseHoverHandler::appendToolTip(const QString &extension)
{
m_toolTip.append(extension);
}
void BaseHoverHandler::setIsDiagnosticTooltip(bool isDiagnosticTooltip)
{
m_diagnosticTooltip = isDiagnosticTooltip;
}
bool BaseHoverHandler::isDiagnosticTooltip() const
{
return m_diagnosticTooltip;
}
void BaseHoverHandler::setLastHelpItemIdentified(const HelpItem &help) void BaseHoverHandler::setLastHelpItemIdentified(const HelpItem &help)
{ {
m_lastHelpItemIdentified = help; m_lastHelpItemIdentified = help;
@@ -128,19 +100,13 @@ const HelpItem &BaseHoverHandler::lastHelpItemIdentified() const
return m_lastHelpItemIdentified; return m_lastHelpItemIdentified;
} }
void BaseHoverHandler::clear() void BaseHoverHandler::process(TextEditorWidget *widget, int pos)
{ {
m_diagnosticTooltip = false;
m_toolTip.clear(); m_toolTip.clear();
m_priority = -1; m_priority = -1;
m_lastHelpItemIdentified = HelpItem(); m_lastHelpItemIdentified = HelpItem();
}
void BaseHoverHandler::process(TextEditorWidget *widget, int pos)
{
clear();
identifyMatch(widget, pos); identifyMatch(widget, pos);
decorateToolTip();
} }
void BaseHoverHandler::identifyMatch(TextEditorWidget *editorWidget, int pos) void BaseHoverHandler::identifyMatch(TextEditorWidget *editorWidget, int pos)
@@ -155,11 +121,11 @@ void BaseHoverHandler::decorateToolTip()
if (Qt::mightBeRichText(toolTip())) if (Qt::mightBeRichText(toolTip()))
setToolTip(toolTip().toHtmlEscaped()); setToolTip(toolTip().toHtmlEscaped());
if (!isDiagnosticTooltip() && lastHelpItemIdentified().isValid()) { if (priority() != Priority_Diagnostic && lastHelpItemIdentified().isValid()) {
const QString &contents = lastHelpItemIdentified().extractContent(false); const QString &contents = lastHelpItemIdentified().extractContent(false);
if (!contents.isEmpty()) { if (!contents.isEmpty()) {
setToolTip(toolTip().toHtmlEscaped()); m_toolTip = toolTip().toHtmlEscaped();
appendToolTip(contents); m_toolTip.append(contents);
} }
} }
} }

View File

@@ -28,43 +28,25 @@
#include "texteditor_global.h" #include "texteditor_global.h"
#include "helpitem.h" #include "helpitem.h"
#include <QObject> QT_BEGIN_NAMESPACE
class QPoint;
namespace Core { class IEditor; } QT_END_NAMESPACE
namespace TextEditor { namespace TextEditor {
class BaseTextEditor;
class TextEditorWidget; class TextEditorWidget;
class TEXTEDITOR_EXPORT BaseHoverHandler : public QObject class TEXTEDITOR_EXPORT BaseHoverHandler
{ {
Q_OBJECT
public: public:
BaseHoverHandler(); virtual ~BaseHoverHandler();
~BaseHoverHandler();
QString contextHelpId(TextEditorWidget *widget, int pos); QString contextHelpId(TextEditorWidget *widget, int pos);
int checkToolTip(TextEditorWidget *widget, int pos);
void showToolTip(TextEditorWidget *widget, const QPoint &point, int pos);
int priority() const; int checkToolTip(TextEditorWidget *widget, int pos);
void showToolTip(TextEditorWidget *widget, const QPoint &point, bool decorate = true);
protected: protected:
void setToolTip(const QString &tooltip);
void appendToolTip(const QString &extension);
const QString &toolTip() const;
void setIsDiagnosticTooltip(bool isDiagnosticTooltip);
bool isDiagnosticTooltip() const;
void setLastHelpItemIdentified(const HelpItem &help);
const HelpItem &lastHelpItemIdentified() const;
virtual void decorateToolTip();
virtual void operateTooltip(TextEditorWidget *editorWidget, const QPoint &point);
enum { enum {
Priority_None = 0, Priority_None = 0,
Priority_Tooltip = 5, Priority_Tooltip = 5,
@@ -72,16 +54,24 @@ protected:
Priority_Diagnostic = 20 Priority_Diagnostic = 20
}; };
void setPriority(int priority); void setPriority(int priority);
private: int priority() const;
void clear();
void process(TextEditorWidget *widget, int pos); void setToolTip(const QString &tooltip);
const QString &toolTip() const;
void setLastHelpItemIdentified(const HelpItem &help);
const HelpItem &lastHelpItemIdentified() const;
virtual void identifyMatch(TextEditorWidget *editorWidget, int pos); virtual void identifyMatch(TextEditorWidget *editorWidget, int pos);
virtual void decorateToolTip();
virtual void operateTooltip(TextEditorWidget *editorWidget, const QPoint &point);
private:
void process(TextEditorWidget *widget, int pos);
bool m_diagnosticTooltip;
QString m_toolTip; QString m_toolTip;
HelpItem m_lastHelpItemIdentified; HelpItem m_lastHelpItemIdentified;
int m_priority; int m_priority = -1;
}; };
} // namespace TextEditor } // namespace TextEditor

View File

@@ -38,9 +38,6 @@ class TextEditorWidget;
class TEXTEDITOR_EXPORT ColorPreviewHoverHandler : public BaseHoverHandler class TEXTEDITOR_EXPORT ColorPreviewHoverHandler : public BaseHoverHandler
{ {
Q_OBJECT
public:
private: private:
void identifyMatch(TextEditorWidget *editorWidget, int pos) override; void identifyMatch(TextEditorWidget *editorWidget, int pos) override;
void operateTooltip(TextEditorWidget *editorWidget, const QPoint &point) override; void operateTooltip(TextEditorWidget *editorWidget, const QPoint &point) override;

View File

@@ -86,5 +86,31 @@ QTextCursor flippedCursor(const QTextCursor &cursor)
return flipped; return flipped;
} }
static bool isValidIdentifierChar(const QChar &c)
{
return c.isLetter()
|| c.isNumber()
|| c == QLatin1Char('_')
|| c.isHighSurrogate()
|| c.isLowSurrogate();
}
QTextCursor wordStartCursor(const QTextCursor &textCursor)
{
const int originalPosition = textCursor.position();
QTextCursor cursor(textCursor);
cursor.movePosition(QTextCursor::StartOfWord);
const int wordStartPosition = cursor.position();
if (originalPosition == wordStartPosition) {
// Cursor is not on an identifier, check whether we are right after one.
const QChar c = textCursor.document()->characterAt(originalPosition - 1);
if (isValidIdentifierChar(c))
cursor.movePosition(QTextCursor::PreviousWord);
}
return cursor;
}
} // Util } // Util
} // TextEditor } // TextEditor

View File

@@ -47,5 +47,7 @@ TEXTEDITOR_EXPORT QTextCursor selectAt(QTextCursor textCursor, uint line, uint c
TEXTEDITOR_EXPORT QTextCursor flippedCursor(const QTextCursor &cursor); TEXTEDITOR_EXPORT QTextCursor flippedCursor(const QTextCursor &cursor);
TEXTEDITOR_EXPORT QTextCursor wordStartCursor(const QTextCursor &cursor);
} // Util } // Util
} // TextEditor } // TextEditor

View File

@@ -44,6 +44,7 @@ static const char displayFileEncodingKey[] = "DisplayFileEncoding";
static const char scrollBarHighlightsKey[] = "ScrollBarHighlights"; static const char scrollBarHighlightsKey[] = "ScrollBarHighlights";
static const char animateNavigationWithinFileKey[] = "AnimateNavigationWithinFile"; static const char animateNavigationWithinFileKey[] = "AnimateNavigationWithinFile";
static const char animateWithinFileTimeMaxKey[] = "AnimateWithinFileTimeMax"; static const char animateWithinFileTimeMaxKey[] = "AnimateWithinFileTimeMax";
static const char displayAnnotationsKey[] = "DisplayAnnotations";
static const char groupPostfix[] = "DisplaySettings"; static const char groupPostfix[] = "DisplaySettings";
namespace TextEditor { namespace TextEditor {
@@ -69,6 +70,7 @@ void DisplaySettings::toSettings(const QString &category, QSettings *s) const
s->setValue(QLatin1String(displayFileEncodingKey), m_displayFileEncoding); s->setValue(QLatin1String(displayFileEncodingKey), m_displayFileEncoding);
s->setValue(QLatin1String(scrollBarHighlightsKey), m_scrollBarHighlights); s->setValue(QLatin1String(scrollBarHighlightsKey), m_scrollBarHighlights);
s->setValue(QLatin1String(animateNavigationWithinFileKey), m_animateNavigationWithinFile); s->setValue(QLatin1String(animateNavigationWithinFileKey), m_animateNavigationWithinFile);
s->setValue(QLatin1String(displayAnnotationsKey), m_displayAnnotations);
s->endGroup(); s->endGroup();
} }
@@ -97,6 +99,7 @@ void DisplaySettings::fromSettings(const QString &category, const QSettings *s)
m_scrollBarHighlights = s->value(group + QLatin1String(scrollBarHighlightsKey), m_scrollBarHighlights).toBool(); m_scrollBarHighlights = s->value(group + QLatin1String(scrollBarHighlightsKey), m_scrollBarHighlights).toBool();
m_animateNavigationWithinFile = s->value(group + QLatin1String(animateNavigationWithinFileKey), m_animateNavigationWithinFile).toBool(); m_animateNavigationWithinFile = s->value(group + QLatin1String(animateNavigationWithinFileKey), m_animateNavigationWithinFile).toBool();
m_animateWithinFileTimeMax = s->value(group + QLatin1String(animateWithinFileTimeMaxKey), m_animateWithinFileTimeMax).toInt(); m_animateWithinFileTimeMax = s->value(group + QLatin1String(animateWithinFileTimeMaxKey), m_animateWithinFileTimeMax).toInt();
m_displayAnnotations = s->value(group + QLatin1String(displayAnnotationsKey), m_displayAnnotations).toBool();
} }
bool DisplaySettings::equals(const DisplaySettings &ds) const bool DisplaySettings::equals(const DisplaySettings &ds) const
@@ -118,6 +121,7 @@ bool DisplaySettings::equals(const DisplaySettings &ds) const
&& m_scrollBarHighlights == ds.m_scrollBarHighlights && m_scrollBarHighlights == ds.m_scrollBarHighlights
&& m_animateNavigationWithinFile == ds.m_animateNavigationWithinFile && m_animateNavigationWithinFile == ds.m_animateNavigationWithinFile
&& m_animateWithinFileTimeMax == ds.m_animateWithinFileTimeMax && m_animateWithinFileTimeMax == ds.m_animateWithinFileTimeMax
&& m_displayAnnotations == ds.m_displayAnnotations
; ;
} }

View File

@@ -58,6 +58,7 @@ public:
bool m_scrollBarHighlights = true; bool m_scrollBarHighlights = true;
bool m_animateNavigationWithinFile = false; bool m_animateNavigationWithinFile = false;
int m_animateWithinFileTimeMax = 333; // read only setting int m_animateWithinFileTimeMax = 333; // read only setting
bool m_displayAnnotations = true;
bool equals(const DisplaySettings &ds) const; bool equals(const DisplaySettings &ds) const;
}; };

View File

@@ -119,6 +119,7 @@ void DisplaySettingsPage::settingsFromUI(DisplaySettings &displaySettings,
displaySettings.m_displayFileEncoding = d->m_page->displayFileEncoding->isChecked(); displaySettings.m_displayFileEncoding = d->m_page->displayFileEncoding->isChecked();
displaySettings.m_scrollBarHighlights = d->m_page->scrollBarHighlights->isChecked(); displaySettings.m_scrollBarHighlights = d->m_page->scrollBarHighlights->isChecked();
displaySettings.m_animateNavigationWithinFile = d->m_page->animateNavigationWithinFile->isChecked(); displaySettings.m_animateNavigationWithinFile = d->m_page->animateNavigationWithinFile->isChecked();
displaySettings.m_displayAnnotations = d->m_page->displayAnnotations->isChecked();
} }
void DisplaySettingsPage::settingsToUI() void DisplaySettingsPage::settingsToUI()
@@ -142,6 +143,7 @@ void DisplaySettingsPage::settingsToUI()
d->m_page->displayFileEncoding->setChecked(displaySettings.m_displayFileEncoding); d->m_page->displayFileEncoding->setChecked(displaySettings.m_displayFileEncoding);
d->m_page->scrollBarHighlights->setChecked(displaySettings.m_scrollBarHighlights); d->m_page->scrollBarHighlights->setChecked(displaySettings.m_scrollBarHighlights);
d->m_page->animateNavigationWithinFile->setChecked(displaySettings.m_animateNavigationWithinFile); d->m_page->animateNavigationWithinFile->setChecked(displaySettings.m_animateNavigationWithinFile);
d->m_page->displayAnnotations->setChecked(displaySettings.m_displayAnnotations);
} }
const DisplaySettings &DisplaySettingsPage::displaySettings() const const DisplaySettings &DisplaySettingsPage::displaySettings() const

View File

@@ -80,17 +80,10 @@
<string>Display</string> <string>Display</string>
</property> </property>
<layout class="QGridLayout" name="gridLayout_2"> <layout class="QGridLayout" name="gridLayout_2">
<item row="1" column="0"> <item row="4" column="1">
<widget class="QCheckBox" name="displayFoldingMarkers"> <widget class="QCheckBox" name="highlightMatchingParentheses">
<property name="text"> <property name="text">
<string>Display &amp;folding markers</string> <string>&amp;Highlight matching parentheses</string>
</property>
</widget>
</item>
<item row="5" column="0">
<widget class="QCheckBox" name="centerOnScroll">
<property name="text">
<string>Center &amp;cursor on scroll</string>
</property> </property>
</widget> </widget>
</item> </item>
@@ -101,20 +94,6 @@
</property> </property>
</widget> </widget>
</item> </item>
<item row="6" column="0">
<widget class="QCheckBox" name="autoFoldFirstComment">
<property name="text">
<string>Auto-fold first &amp;comment</string>
</property>
</widget>
</item>
<item row="2" column="1">
<widget class="QCheckBox" name="animateMatchingParentheses">
<property name="text">
<string>&amp;Animate matching parentheses</string>
</property>
</widget>
</item>
<item row="0" column="1"> <item row="0" column="1">
<widget class="QCheckBox" name="highlightCurrentLine"> <widget class="QCheckBox" name="highlightCurrentLine">
<property name="text"> <property name="text">
@@ -129,6 +108,20 @@
</property> </property>
</widget> </widget>
</item> </item>
<item row="6" column="0">
<widget class="QCheckBox" name="autoFoldFirstComment">
<property name="text">
<string>Auto-fold first &amp;comment</string>
</property>
</widget>
</item>
<item row="2" column="1">
<widget class="QCheckBox" name="animateMatchingParentheses">
<property name="text">
<string>&amp;Animate matching parentheses</string>
</property>
</widget>
</item>
<item row="5" column="1"> <item row="5" column="1">
<widget class="QCheckBox" name="openLinksInNextSplit"> <widget class="QCheckBox" name="openLinksInNextSplit">
<property name="text"> <property name="text">
@@ -143,6 +136,13 @@
</property> </property>
</widget> </widget>
</item> </item>
<item row="5" column="0">
<widget class="QCheckBox" name="centerOnScroll">
<property name="text">
<string>Center &amp;cursor on scroll</string>
</property>
</widget>
</item>
<item row="4" column="0"> <item row="4" column="0">
<widget class="QCheckBox" name="visualizeWhitespace"> <widget class="QCheckBox" name="visualizeWhitespace">
<property name="toolTip"> <property name="toolTip">
@@ -153,17 +153,17 @@
</property> </property>
</widget> </widget>
</item> </item>
<item row="4" column="1"> <item row="1" column="0">
<widget class="QCheckBox" name="highlightMatchingParentheses"> <widget class="QCheckBox" name="displayFoldingMarkers">
<property name="text"> <property name="text">
<string>&amp;Highlight matching parentheses</string> <string>Display &amp;folding markers</string>
</property> </property>
</widget> </widget>
</item> </item>
<item row="2" column="0"> <item row="7" column="1">
<widget class="QCheckBox" name="markTextChanges"> <widget class="QCheckBox" name="animateNavigationWithinFile">
<property name="text"> <property name="text">
<string>Mark &amp;text changes</string> <string>Animate navigation within file</string>
</property> </property>
</widget> </widget>
</item> </item>
@@ -174,10 +174,17 @@
</property> </property>
</widget> </widget>
</item> </item>
<item row="7" column="1"> <item row="2" column="0">
<widget class="QCheckBox" name="animateNavigationWithinFile"> <widget class="QCheckBox" name="markTextChanges">
<property name="text"> <property name="text">
<string>Animate navigation within file</string> <string>Mark &amp;text changes</string>
</property>
</widget>
</item>
<item row="8" column="0">
<widget class="QCheckBox" name="displayAnnotations">
<property name="text">
<string>Display annotations behind lines</string>
</property> </property>
</widget> </widget>
</item> </item>
@@ -197,12 +204,14 @@
<tabstop>centerOnScroll</tabstop> <tabstop>centerOnScroll</tabstop>
<tabstop>autoFoldFirstComment</tabstop> <tabstop>autoFoldFirstComment</tabstop>
<tabstop>scrollBarHighlights</tabstop> <tabstop>scrollBarHighlights</tabstop>
<tabstop>displayAnnotations</tabstop>
<tabstop>highlightCurrentLine</tabstop> <tabstop>highlightCurrentLine</tabstop>
<tabstop>highlightBlocks</tabstop> <tabstop>highlightBlocks</tabstop>
<tabstop>animateMatchingParentheses</tabstop> <tabstop>animateMatchingParentheses</tabstop>
<tabstop>highlightMatchingParentheses</tabstop> <tabstop>highlightMatchingParentheses</tabstop>
<tabstop>openLinksInNextSplit</tabstop> <tabstop>openLinksInNextSplit</tabstop>
<tabstop>displayFileEncoding</tabstop> <tabstop>displayFileEncoding</tabstop>
<tabstop>animateNavigationWithinFile</tabstop>
</tabstops> </tabstops>
<resources/> <resources/>
<connections> <connections>

View File

@@ -845,6 +845,13 @@ void TextDocument::modificationChanged(bool modified)
emit changed(); emit changed();
} }
void TextDocument::updateLayout() const
{
auto documentLayout = qobject_cast<TextDocumentLayout*>(d->m_document.documentLayout());
QTC_ASSERT(documentLayout, return);
documentLayout->requestUpdate();
}
TextMarks TextDocument::marks() const TextMarks TextDocument::marks() const
{ {
return d->m_marksCache; return d->m_marksCache;
@@ -953,6 +960,7 @@ void TextDocument::removeMark(TextMark *mark)
removeMarkFromMarksCache(mark); removeMarkFromMarksCache(mark);
mark->setBaseTextDocument(0); mark->setBaseTextDocument(0);
updateLayout();
} }
void TextDocument::updateMark(TextMark *mark) void TextDocument::updateMark(TextMark *mark)
@@ -964,9 +972,7 @@ void TextDocument::updateMark(TextMark *mark)
userData->removeMark(mark); userData->removeMark(mark);
userData->addMark(mark); userData->addMark(mark);
} }
auto documentLayout = qobject_cast<TextDocumentLayout*>(d->m_document.documentLayout()); updateLayout();
QTC_ASSERT(documentLayout, return);
documentLayout->requestUpdate();
} }
void TextDocument::moveMark(TextMark *mark, int previousLine) void TextDocument::moveMark(TextMark *mark, int previousLine)

View File

@@ -154,6 +154,7 @@ private:
void cleanWhitespace(QTextCursor &cursor, bool cleanIndentation, bool inEntireDocument); void cleanWhitespace(QTextCursor &cursor, bool cleanIndentation, bool inEntireDocument);
void ensureFinalNewLine(QTextCursor &cursor); void ensureFinalNewLine(QTextCursor &cursor);
void modificationChanged(bool modified); void modificationChanged(bool modified);
void updateLayout() const;
TextDocumentPrivate *d; TextDocumentPrivate *d;
}; };

View File

@@ -73,6 +73,8 @@
#include <coreplugin/manhattanstyle.h> #include <coreplugin/manhattanstyle.h>
#include <coreplugin/find/basetextfind.h> #include <coreplugin/find/basetextfind.h>
#include <coreplugin/find/highlightscrollbar.h> #include <coreplugin/find/highlightscrollbar.h>
#include <utils/algorithm.h>
#include <utils/asconst.h>
#include <utils/linecolumnlabel.h> #include <utils/linecolumnlabel.h>
#include <utils/fileutils.h> #include <utils/fileutils.h>
#include <utils/dropsupport.h> #include <utils/dropsupport.h>
@@ -278,6 +280,7 @@ public:
bool expanded, bool expanded,
bool active, bool active,
bool hovered) const; bool hovered) const;
void drawLineAnnotation(QPainter &painter, const QTextBlock &block);
void toggleBlockVisible(const QTextBlock &block); void toggleBlockVisible(const QTextBlock &block);
QRect foldBox(); QRect foldBox();
@@ -296,6 +299,7 @@ public:
bool camelCaseLeft(QTextCursor &cursor, QTextCursor::MoveMode mode); bool camelCaseLeft(QTextCursor &cursor, QTextCursor::MoveMode mode);
void processTooltipRequest(const QTextCursor &c); void processTooltipRequest(const QTextCursor &c);
bool processAnnotaionTooltipRequest(const QTextBlock &block, const QPoint &pos) const;
void transformSelection(TransformationMethod method); void transformSelection(TransformationMethod method);
void transformBlockSelection(TransformationMethod method); void transformBlockSelection(TransformationMethod method);
@@ -383,6 +387,13 @@ public:
bool snippetCheckCursor(const QTextCursor &cursor); bool snippetCheckCursor(const QTextCursor &cursor);
void snippetTabOrBacktab(bool forward); void snippetTabOrBacktab(bool forward);
struct AnnotationRect
{
QRectF rect;
const TextMark *mark;
};
QMap<int, QList<AnnotationRect>> m_annotationRects;
RefactorOverlay *m_refactorOverlay = nullptr; RefactorOverlay *m_refactorOverlay = nullptr;
QString m_contextHelpId; QString m_contextHelpId;
@@ -457,6 +468,26 @@ public:
CodeAssistant m_codeAssistant; CodeAssistant m_codeAssistant;
bool m_assistRelevantContentAdded = false; bool m_assistRelevantContentAdded = false;
struct LastHoverHandlerInfo {
LastHoverHandlerInfo() = default;
LastHoverHandlerInfo(BaseHoverHandler *handler, int documentRevision, int cursorPosition)
: handler(handler)
, documentRevision(documentRevision)
, cursorPosition(cursorPosition)
{}
bool applies(int documentRevision, int cursorPosition) const
{
return handler
&& documentRevision == this->documentRevision
&& cursorPosition == this->cursorPosition;
}
BaseHoverHandler *handler = nullptr;
int documentRevision = -1;
int cursorPosition = -1;
} m_lastHoverHandlerInfo;
QList<BaseHoverHandler *> m_hoverHandlers; // Not owned QList<BaseHoverHandler *> m_hoverHandlers; // Not owned
QPointer<QSequentialAnimationGroup> m_navigationAnimation; QPointer<QSequentialAnimationGroup> m_navigationAnimation;
@@ -470,7 +501,8 @@ public:
bool m_skipAutoCompletedText = true; bool m_skipAutoCompletedText = true;
bool m_removeAutoCompletedText = true; bool m_removeAutoCompletedText = true;
bool m_keepAutoCompletionHighlight = false; bool m_keepAutoCompletionHighlight = false;
QTextCursor m_autoCompleteHighlightPos; QList<QTextCursor> m_autoCompleteHighlightPos;
void updateAutoCompleteHighlight();
int m_cursorBlockNumber = -1; int m_cursorBlockNumber = -1;
int m_blockCount = 0; int m_blockCount = 0;
@@ -943,6 +975,21 @@ int TextEditorWidgetPrivate::visualIndent(const QTextBlock &block) const
return 0; return 0;
} }
void TextEditorWidgetPrivate::updateAutoCompleteHighlight()
{
const QTextCharFormat &matchFormat
= q->textDocument()->fontSettings().toTextCharFormat(C_PARENTHESES);
QList<QTextEdit::ExtraSelection> extraSelections;
for (QTextCursor cursor : Utils::asConst(m_autoCompleteHighlightPos)) {
QTextEdit::ExtraSelection sel;
sel.cursor = cursor;
sel.format.setBackground(matchFormat.background());
extraSelections.append(sel);
}
q->setExtraSelections(TextEditorWidget::AutoCompleteSelection, extraSelections);
}
void TextEditorWidget::selectEncoding() void TextEditorWidget::selectEncoding()
{ {
TextDocument *doc = d->m_document.data(); TextDocument *doc = d->m_document.data();
@@ -2366,8 +2413,10 @@ void TextEditorWidget::keyPressEvent(QKeyEvent *e)
QTextCursor cursor = textCursor(); QTextCursor cursor = textCursor();
QString autoText; QString autoText;
if (!inOverwriteMode) { if (!inOverwriteMode) {
autoText = autoCompleter()->autoComplete(cursor, eventText, const bool skipChar = d->m_skipAutoCompletedText
d->m_skipAutoCompletedText && cursor == d->m_autoCompleteHighlightPos); && !d->m_autoCompleteHighlightPos.isEmpty()
&& cursor == d->m_autoCompleteHighlightPos.last();
autoText = autoCompleter()->autoComplete(cursor, eventText, skipChar);
} }
const bool cursorWithinSnippet = d->snippetCheckCursor(cursor); const bool cursorWithinSnippet = d->snippetCheckCursor(cursor);
@@ -3132,6 +3181,15 @@ void TextEditorWidgetPrivate::processTooltipRequest(const QTextCursor &c)
return; return;
} }
// Does the last handler still applies?
const int documentRevision = m_document->document()->revision();
const int cursorPosition = Convenience::wordStartCursor(c).position();
if (m_lastHoverHandlerInfo.applies(documentRevision, cursorPosition)) {
m_lastHoverHandlerInfo.handler->showToolTip(q, toolTipPoint, /*decorate=*/ false);
return;
}
// Determine best handler
int highestPriority = -1; int highestPriority = -1;
BaseHoverHandler *highest = 0; BaseHoverHandler *highest = 0;
foreach (BaseHoverHandler *handler, m_hoverHandlers) { foreach (BaseHoverHandler *handler, m_hoverHandlers) {
@@ -3142,8 +3200,47 @@ void TextEditorWidgetPrivate::processTooltipRequest(const QTextCursor &c)
} }
} }
if (highest) // Let the best handler show the tooltip
highest->showToolTip(q, toolTipPoint, c.position()); if (highest) {
m_lastHoverHandlerInfo = LastHoverHandlerInfo{highest, documentRevision, cursorPosition};
highest->showToolTip(q, toolTipPoint);
}
}
bool TextEditorWidgetPrivate::processAnnotaionTooltipRequest(const QTextBlock &block,
const QPoint &pos) const
{
TextBlockUserData *blockUserData = TextDocumentLayout::testUserData(block);
if (!blockUserData)
return false;
for (const AnnotationRect &annotationRect : m_annotationRects[block.blockNumber()]) {
if (annotationRect.rect.contains(pos)) {
auto layout = new QGridLayout;
layout->setContentsMargins(0, 0, 0, 0);
layout->setSpacing(2);
annotationRect.mark->addToToolTipLayout(layout);
TextMarks marks = blockUserData->marks();
if (marks.size() > 1) {
QFrame* separator = new QFrame();
separator->setFrameShape(QFrame::HLine);
layout->addWidget(separator, 2, 0, 1, layout->columnCount());
layout->addWidget(new QLabel(tr("Other annotations:")), 3, 0, 1,
layout->columnCount());
Utils::sort(marks, [](const TextMark* mark1, const TextMark* mark2){
return mark1->priority() > mark2->priority();
});
for (const TextMark *mark : Utils::asConst(marks)) {
if (mark != annotationRect.mark)
mark->addToToolTipLayout(layout);
}
}
ToolTip::show(q->mapToGlobal(pos), layout, q);
return true;
}
}
return false;
} }
bool TextEditorWidget::viewportEvent(QEvent *event) bool TextEditorWidget::viewportEvent(QEvent *event)
@@ -3173,10 +3270,14 @@ bool TextEditorWidget::viewportEvent(QEvent *event)
QTC_CHECK(line.isValid()); QTC_CHECK(line.isValid());
// Only handle tool tip for text cursor if mouse is within the block for the text cursor, // Only handle tool tip for text cursor if mouse is within the block for the text cursor,
// and not if the mouse is e.g. in the empty space behind a short line. // and not if the mouse is e.g. in the empty space behind a short line.
if (line.isValid() if (line.isValid()) {
&& pos.x() <= blockBoundingGeometry(block).left() + line.naturalTextRect().right()) { if (pos.x() <= blockBoundingGeometry(block).left() + line.naturalTextRect().right()) {
d->processTooltipRequest(tc); d->processTooltipRequest(tc);
return true; return true;
} else if (d->processAnnotaionTooltipRequest(block, pos)) {
return true;
}
ToolTip::hide();
} }
} }
return QPlainTextEdit::viewportEvent(event); return QPlainTextEdit::viewportEvent(event);
@@ -3613,6 +3714,52 @@ static QTextLayout::FormatRange createBlockCursorCharFormatRange(int pos, const
return o; return o;
} }
void TextEditorWidgetPrivate::drawLineAnnotation(QPainter &painter, const QTextBlock &block)
{
if (!m_displaySettings.m_displayAnnotations)
return;
TextBlockUserData *blockUserData = TextDocumentLayout::testUserData(block);
if (!blockUserData)
return;
TextMarks marks = blockUserData->marks();
if (marks.isEmpty())
return;
const QTextLayout *layout = block.layout();
const int lineCount = layout->lineCount();
if (lineCount < 1)
return;
const QTextLine line = layout->lineAt(lineCount - 1);
const QPointF contentOffset = q->contentOffset();
const qreal top = q->blockBoundingGeometry(block).translated(contentOffset).top();
const QRectF lineRect =
line.naturalTextRect().translated(contentOffset.x(), top).adjusted(0, 0, -1, -1);
Utils::sort(marks, [](const TextMark* mark1, const TextMark* mark2){
return mark1->priority() > mark2->priority();
});
constexpr qreal itemOffset = 10;
qreal x = lineRect.right() + itemOffset;
const RefactorMarkers refactorMarkers = m_refactorOverlay->markers();
for (auto refactorMark : refactorMarkers) {
if (refactorMark.cursor.block() == block)
x = qMax(x, refactorMark.rect.right() + itemOffset);
}
for (const TextMark *mark : marks) {
QRectF annotationRect(x, lineRect.top(), q->viewport()->width() - x, lineRect.height());
if (annotationRect.width() <= 0)
break;
mark->paintAnnotation(&painter, &annotationRect, q->fontMetrics());
x += annotationRect.width() + itemOffset;
m_annotationRects[block.blockNumber()].append({annotationRect, mark});
}
}
void TextEditorWidget::paintEvent(QPaintEvent *e) void TextEditorWidget::paintEvent(QPaintEvent *e)
{ {
// draw backgrond to the right of the wrap column before everything else // draw backgrond to the right of the wrap column before everything else
@@ -3738,6 +3885,7 @@ void TextEditorWidget::paintEvent(QPaintEvent *e)
int cursor_cpos = 0; int cursor_cpos = 0;
QPen cursor_pen; QPen cursor_pen;
d->m_annotationRects.clear();
d->m_searchResultOverlay->clear(); d->m_searchResultOverlay->clear();
if (!d->m_searchExpr.isEmpty()) { // first pass for the search result overlays if (!d->m_searchExpr.isEmpty()) { // first pass for the search result overlays
@@ -4253,6 +4401,7 @@ void TextEditorWidget::paintEvent(QPaintEvent *e)
painter.restore(); painter.restore();
} }
} }
d->drawLineAnnotation(painter, block);
block = nextVisibleBlock; block = nextVisibleBlock;
top = bottom; top = bottom;
@@ -4538,7 +4687,7 @@ void TextEditorWidget::extraAreaPaintEvent(QPaintEvent *e)
const int height = fmLineSpacing - 1; const int height = fmLineSpacing - 1;
const int width = int(.5 + height * mark->widthFactor()); const int width = int(.5 + height * mark->widthFactor());
const QRect r(xoffset, top, width, height); const QRect r(xoffset, top, width, height);
mark->paint(&painter, r); mark->paintIcon(&painter, r);
xoffset += 2; xoffset += 2;
} }
} }
@@ -4732,13 +4881,17 @@ void TextEditorWidgetPrivate::updateHighlights()
} }
} }
if (m_highlightAutoComplete && !m_autoCompleteHighlightPos.isNull()) { if (m_highlightAutoComplete && !m_autoCompleteHighlightPos.isEmpty()) {
QTimer::singleShot(0, this, [this](){ QTimer::singleShot(0, this, [this](){
if ((!m_keepAutoCompletionHighlight && !q->hasFocus()) const QTextCursor &cursor = q->textCursor();
|| m_autoCompleteHighlightPos != q->textCursor()) { auto popAutoCompletion = [&]() {
q->setExtraSelections(TextEditorWidget::AutoCompleteSelection, return !m_autoCompleteHighlightPos.isEmpty()
QList<QTextEdit::ExtraSelection>()); // clear && m_autoCompleteHighlightPos.last() != cursor;
m_autoCompleteHighlightPos = QTextCursor(); };
if (!m_keepAutoCompletionHighlight && !q->hasFocus() && popAutoCompletion()) {
while (popAutoCompletion())
m_autoCompleteHighlightPos.pop_back();
updateAutoCompleteHighlight();
} }
}); });
} }
@@ -5405,8 +5558,11 @@ void TextEditorWidgetPrivate::handleBackspaceKey()
const TabSettings &tabSettings = m_document->tabSettings(); const TabSettings &tabSettings = m_document->tabSettings();
const TypingSettings &typingSettings = m_document->typingSettings(); const TypingSettings &typingSettings = m_document->typingSettings();
if (typingSettings.m_autoIndent && (m_autoCompleteHighlightPos == cursor) if (typingSettings.m_autoIndent
&& m_removeAutoCompletedText && m_autoCompleter->autoBackspace(cursor)) { && !m_autoCompleteHighlightPos.isEmpty()
&& (m_autoCompleteHighlightPos.last() == cursor)
&& m_removeAutoCompletedText
&& m_autoCompleter->autoBackspace(cursor)) {
return; return;
} }
@@ -6082,25 +6238,14 @@ void TextEditorWidgetPrivate::_q_highlightBlocks()
void TextEditorWidgetPrivate::autocompleterHighlight(const QTextCursor &cursor) void TextEditorWidgetPrivate::autocompleterHighlight(const QTextCursor &cursor)
{ {
QList<QTextEdit::ExtraSelection> extraSelections;
if ((!m_animateAutoComplete && !m_highlightAutoComplete) if ((!m_animateAutoComplete && !m_highlightAutoComplete)
|| q->isReadOnly() || !cursor.hasSelection()) { || q->isReadOnly() || !cursor.hasSelection()) {
q->setExtraSelections(TextEditorWidget::AutoCompleteSelection, extraSelections); // clear m_autoCompleteHighlightPos.clear();
return; } else if (m_highlightAutoComplete) {
} m_autoCompleteHighlightPos.push_back(cursor);
} else if (m_animateAutoComplete) {
const QTextCharFormat &matchFormat const QTextCharFormat &matchFormat
= q->textDocument()->fontSettings().toTextCharFormat(C_AUTOCOMPLETE); = q->textDocument()->fontSettings().toTextCharFormat(C_AUTOCOMPLETE);
if (m_highlightAutoComplete) {
QTextEdit::ExtraSelection sel;
sel.cursor = cursor;
sel.format.setBackground(matchFormat.background());
extraSelections.append(sel);
m_autoCompleteHighlightPos = cursor;
m_autoCompleteHighlightPos.movePosition(QTextCursor::PreviousCharacter);
}
if (m_animateAutoComplete) {
cancelCurrentAnimations();// one animation is enough cancelCurrentAnimations();// one animation is enough
QPalette pal; QPalette pal;
pal.setBrush(QPalette::Text, matchFormat.foreground()); pal.setBrush(QPalette::Text, matchFormat.foreground());
@@ -6110,7 +6255,7 @@ void TextEditorWidgetPrivate::autocompleterHighlight(const QTextCursor &cursor)
connect(m_autocompleteAnimator.data(), &TextEditorAnimator::updateRequest, connect(m_autocompleteAnimator.data(), &TextEditorAnimator::updateRequest,
this, &TextEditorWidgetPrivate::_q_animateUpdate); this, &TextEditorWidgetPrivate::_q_animateUpdate);
} }
q->setExtraSelections(TextEditorWidget::AutoCompleteSelection, extraSelections); updateAutoCompleteHighlight();
} }
void TextEditorWidgetPrivate::updateAnimator(QPointer<TextEditorAnimator> animator, void TextEditorWidgetPrivate::updateAnimator(QPointer<TextEditorAnimator> animator,
@@ -8060,7 +8205,11 @@ IEditor *BaseTextEditor::duplicate()
return 0; return 0;
} }
} // namespace TextEditor } // namespace TextEditor
uint qHash(const QColor &color)
{
return color.rgba();
}
#include "texteditor.moc" #include "texteditor.moc"

View File

@@ -672,4 +672,6 @@ private:
} // namespace TextEditor } // namespace TextEditor
uint qHash(const QColor &color);
Q_DECLARE_METATYPE(TextEditor::TextEditorWidget::Link) Q_DECLARE_METATYPE(TextEditor::TextEditorWidget::Link)

View File

@@ -33,6 +33,7 @@
#include <utils/qtcassert.h> #include <utils/qtcassert.h>
#include <QGridLayout> #include <QGridLayout>
#include <QPainter>
using namespace Core; using namespace Core;
using namespace Utils; using namespace Utils;
@@ -57,6 +58,24 @@ private:
QHash<Utils::FileName, QSet<TextMark *> > m_marks; QHash<Utils::FileName, QSet<TextMark *> > m_marks;
}; };
class AnnotationColors
{
public:
static AnnotationColors &getAnnotationColors(const QColor &markColor,
const QColor &backgroundColor);
public:
using SourceColors = QPair<QColor, QColor>;
QColor rectColor;
QColor textColor;
private:
static double clipHsl(double value);
private:
static QHash<SourceColors, AnnotationColors> m_colorCache;
};
TextMarkRegistry *m_instance = nullptr; TextMarkRegistry *m_instance = nullptr;
TextMark::TextMark(const QString &fileName, int lineNumber, Id category, double widthFactor) TextMark::TextMark(const QString &fileName, int lineNumber, Id category, double widthFactor)
@@ -99,11 +118,49 @@ int TextMark::lineNumber() const
return m_lineNumber; return m_lineNumber;
} }
void TextMark::paint(QPainter *painter, const QRect &rect) const void TextMark::paintIcon(QPainter *painter, const QRect &rect) const
{ {
m_icon.paint(painter, rect, Qt::AlignCenter); m_icon.paint(painter, rect, Qt::AlignCenter);
} }
void TextMark::paintAnnotation(QPainter *painter,
QRectF *annotationRect,
const QFontMetrics &fm) const
{
QString text = lineAnnotation();
if (text.isEmpty())
return;
const bool drawIcon = !m_icon.isNull();
int textWidth = fm.width(text);
constexpr qreal margin = 1;
const qreal iconHeight = annotationRect->height() - 2 * margin;
const qreal iconWidth = iconHeight * m_widthFactor + 2 * margin;
qreal annotationWidth = (drawIcon ? textWidth + iconWidth : textWidth) + margin;
if (annotationRect->left() + annotationWidth > annotationRect->right()) {
textWidth = int(annotationRect->width() - (drawIcon ? iconWidth + margin : margin));
text = fm.elidedText(text, Qt::ElideRight, textWidth);
annotationWidth = annotationRect->width();
}
const QColor markColor = m_hasColor ? Utils::creatorTheme()->color(m_color).toHsl()
: painter->pen().color();
const AnnotationColors &colors =
AnnotationColors::getAnnotationColors(markColor, painter->background().color());
painter->save();
annotationRect->setWidth(annotationWidth);
painter->setPen(colors.rectColor);
painter->setBrush(colors.rectColor);
painter->drawRect(*annotationRect);
painter->setPen(colors.textColor);
if (drawIcon) {
paintIcon(painter, annotationRect->adjusted(
margin, margin, -(textWidth + 2 * margin), -margin).toAlignedRect());
}
painter->drawText(annotationRect->adjusted(iconWidth, 0, 0, 0), Qt::AlignLeft, text);
painter->restore();
}
void TextMark::updateLineNumber(int lineNumber) void TextMark::updateLineNumber(int lineNumber)
{ {
m_lineNumber = lineNumber; m_lineNumber = lineNumber;
@@ -176,7 +233,7 @@ void TextMark::dragToLine(int lineNumber)
Q_UNUSED(lineNumber); Q_UNUSED(lineNumber);
} }
void TextMark::addToToolTipLayout(QGridLayout *target) void TextMark::addToToolTipLayout(QGridLayout *target) const
{ {
auto *contentLayout = new QVBoxLayout; auto *contentLayout = new QVBoxLayout;
addToolTipContent(contentLayout); addToolTipContent(contentLayout);
@@ -191,7 +248,7 @@ void TextMark::addToToolTipLayout(QGridLayout *target)
} }
} }
bool TextMark::addToolTipContent(QLayout *target) bool TextMark::addToolTipContent(QLayout *target) const
{ {
QString text = m_toolTip; QString text = m_toolTip;
if (text.isEmpty()) { if (text.isEmpty()) {
@@ -304,6 +361,33 @@ void TextMarkRegistry::allDocumentsRenamed(const QString &oldName, const QString
mark->updateFileName(newName); mark->updateFileName(newName);
} }
QHash<AnnotationColors::SourceColors, AnnotationColors> AnnotationColors::m_colorCache;
AnnotationColors &AnnotationColors::getAnnotationColors(const QColor &markColor,
const QColor &backgroundColor)
{
AnnotationColors &colors = m_colorCache[{markColor, backgroundColor}];
if (!colors.rectColor.isValid() || !colors.textColor.isValid()) {
const double backgroundSaturation = clipHsl(markColor.hslSaturationF() / 2);
const double backgroundLightness = clipHsl(backgroundColor.lightnessF());
const double foregroundLightness = clipHsl(backgroundLightness > 0.5
? backgroundLightness - 0.5
: backgroundLightness + 0.5);
colors.rectColor.setHslF(markColor.hslHueF(),
backgroundSaturation,
backgroundLightness);
colors.textColor.setHslF(markColor.hslHueF(),
markColor.hslSaturationF(),
foregroundLightness);
}
return colors;
}
double AnnotationColors::clipHsl(double value)
{
return std::max(0.15, std::min(0.85, value));
}
} // namespace TextEditor } // namespace TextEditor
#include "textmark.moc" #include "textmark.moc"

View File

@@ -63,7 +63,8 @@ public:
QString fileName() const; QString fileName() const;
int lineNumber() const; int lineNumber() const;
virtual void paint(QPainter *painter, const QRect &rect) const; virtual void paintIcon(QPainter *painter, const QRect &rect) const;
virtual void paintAnnotation(QPainter *painter, QRectF *annotationRect, const QFontMetrics &fm) const;
/// called if the filename of the document changed /// called if the filename of the document changed
virtual void updateFileName(const QString &fileName); virtual void updateFileName(const QString &fileName);
virtual void updateLineNumber(int lineNumber); virtual void updateLineNumber(int lineNumber);
@@ -74,8 +75,8 @@ public:
virtual void clicked(); virtual void clicked();
virtual bool isDraggable() const; virtual bool isDraggable() const;
virtual void dragToLine(int lineNumber); virtual void dragToLine(int lineNumber);
void addToToolTipLayout(QGridLayout *target); void addToToolTipLayout(QGridLayout *target) const;
virtual bool addToolTipContent(QLayout *target); virtual bool addToolTipContent(QLayout *target) const;
void setIcon(const QIcon &icon) { m_icon = icon; } void setIcon(const QIcon &icon) { m_icon = icon; }
const QIcon &icon() const { return m_icon; } const QIcon &icon() const { return m_icon; }
@@ -99,6 +100,9 @@ public:
TextDocument *baseTextDocument() const { return m_baseTextDocument; } TextDocument *baseTextDocument() const { return m_baseTextDocument; }
void setBaseTextDocument(TextDocument *baseTextDocument) { m_baseTextDocument = baseTextDocument; } void setBaseTextDocument(TextDocument *baseTextDocument) { m_baseTextDocument = baseTextDocument; }
QString lineAnnotation() const { return m_lineAnnotation; }
void setLineAnnotation(const QString &lineAnnotation) { m_lineAnnotation = lineAnnotation; }
QString toolTip() const { return m_toolTip; } QString toolTip() const { return m_toolTip; }
void setToolTip(const QString &toolTip) { m_toolTip = toolTip; } void setToolTip(const QString &toolTip) { m_toolTip = toolTip; }
@@ -115,6 +119,7 @@ private:
bool m_hasColor = false; bool m_hasColor = false;
Core::Id m_category; Core::Id m_category;
double m_widthFactor = 1.0; double m_widthFactor = 1.0;
QString m_lineAnnotation;
QString m_toolTip; QString m_toolTip;
QString m_defaultToolTip; QString m_defaultToolTip;
}; };

View File

@@ -24,28 +24,31 @@
****************************************************************************/ ****************************************************************************/
#include "callgrindcontroller.h" #include "callgrindcontroller.h"
#include "../valgrindprocess.h"
#include <ssh/sftpchannel.h>
#include <ssh/sshconnectionmanager.h>
#include <utils/fileutils.h>
#include <utils/hostosinfo.h>
#include <utils/qtcassert.h>
#include <utils/qtcprocess.h>
#include <utils/temporaryfile.h>
#include <QDebug> #include <QDebug>
#include <QDir> #include <QDir>
#include <QEventLoop>
#include <utils/hostosinfo.h>
#include <utils/qtcassert.h>
#include <utils/temporaryfile.h>
#include <ssh/sftpchannel.h>
#define CALLGRIND_CONTROL_DEBUG 0 #define CALLGRIND_CONTROL_DEBUG 0
const QLatin1String CALLGRIND_CONTROL_BINARY("callgrind_control"); using namespace ProjectExplorer;
using namespace Utils;
namespace Valgrind { namespace Valgrind {
namespace Callgrind { namespace Callgrind {
CallgrindController::CallgrindController(QObject *parent) const QLatin1String CALLGRIND_CONTROL_BINARY("callgrind_control");
: QObject(parent)
, m_process(0) CallgrindController::CallgrindController()
, m_valgrindProc(0)
, m_lastOption(Unknown)
{ {
} }
@@ -54,7 +57,7 @@ CallgrindController::~CallgrindController()
cleanupTempFile(); cleanupTempFile();
} }
QString toOptionString(CallgrindController::Option option) static QString toOptionString(CallgrindController::Option option)
{ {
/* callgrind_control help from v3.9.0 /* callgrind_control help from v3.9.0
@@ -86,23 +89,15 @@ QString toOptionString(CallgrindController::Option option)
void CallgrindController::run(Option option) void CallgrindController::run(Option option)
{ {
if (m_process) { if (m_controllerProcess) {
emit statusMessage(tr("Previous command has not yet finished.")); emit statusMessage(tr("Previous command has not yet finished."));
return; return;
} }
QTC_ASSERT(m_valgrindProc, return);
m_process = new ValgrindProcess(m_valgrindProc->device(), this);
connect(m_process, &ValgrindProcess::finished,
this, &CallgrindController::processFinished);
connect(m_process, &ValgrindProcess::error,
this, &CallgrindController::processError);
// save back current running operation // save back current running operation
m_lastOption = option; m_lastOption = option;
const QString optionString = toOptionString(option); m_controllerProcess = new ApplicationLauncher;
switch (option) { switch (option) {
case CallgrindController::Dump: case CallgrindController::Dump:
@@ -122,31 +117,49 @@ void CallgrindController::run(Option option)
} }
#if CALLGRIND_CONTROL_DEBUG #if CALLGRIND_CONTROL_DEBUG
m_process->setProcessChannelMode(QProcess::ForwardedChannels); m_controllerProcess->setProcessChannelMode(QProcess::ForwardedChannels);
#endif #endif
const int pid = Utils::HostOsInfo::isWindowsHost() ? 0 : m_valgrindProc->pid(); connect(m_controllerProcess, &ApplicationLauncher::processExited,
m_process->setValgrindExecutable(CALLGRIND_CONTROL_BINARY); this, &CallgrindController::controllerProcessFinished);
m_process->setValgrindArguments(QStringList() << optionString << QString::number(pid)); connect(m_controllerProcess, &ApplicationLauncher::error,
m_process->run(ProjectExplorer::ApplicationLauncher::Gui); this, &CallgrindController::handleControllerProcessError);
connect(m_controllerProcess, &ApplicationLauncher::finished,
this, &CallgrindController::controllerProcessClosed);
StandardRunnable controller = m_valgrindRunnable;
controller.executable = CALLGRIND_CONTROL_BINARY;
controller.runMode = ApplicationLauncher::Gui;
controller.commandLineArguments = QString("%1 %2").arg(toOptionString(option)).arg(m_pid);
if (!m_valgrindRunnable.device
|| m_valgrindRunnable.device->type() == ProjectExplorer::Constants::DESKTOP_DEVICE_TYPE)
m_controllerProcess->start(controller);
else
m_controllerProcess->start(controller, m_valgrindRunnable.device);
} }
void CallgrindController::processError(QProcess::ProcessError) void CallgrindController::setValgrindPid(qint64 pid)
{ {
QTC_ASSERT(m_process, return); m_pid = pid;
const QString error = m_process->errorString(); }
void CallgrindController::handleControllerProcessError(QProcess::ProcessError)
{
QTC_ASSERT(m_controllerProcess, return);
const QString error = m_controllerProcess->errorString();
emit statusMessage(tr("An error occurred while trying to run %1: %2").arg(CALLGRIND_CONTROL_BINARY).arg(error)); emit statusMessage(tr("An error occurred while trying to run %1: %2").arg(CALLGRIND_CONTROL_BINARY).arg(error));
m_process->deleteLater(); m_controllerProcess->deleteLater();
m_process = 0; m_controllerProcess = nullptr;
} }
void CallgrindController::processFinished(int rc, QProcess::ExitStatus status) void CallgrindController::controllerProcessFinished(int rc, QProcess::ExitStatus status)
{ {
QTC_ASSERT(m_process, return); QTC_ASSERT(m_controllerProcess, return);
const QString error = m_process->errorString(); const QString error = m_controllerProcess->errorString();
m_process->deleteLater(); // Called directly from finished() signal in m_process m_controllerProcess->deleteLater(); // Called directly from finished() signal in m_process
m_process = 0; m_controllerProcess = nullptr;
if (rc != 0 || status != QProcess::NormalExit) { if (rc != 0 || status != QProcess::NormalExit) {
qWarning() << "Controller exited abnormally:" << error; qWarning() << "Controller exited abnormally:" << error;
@@ -175,32 +188,43 @@ void CallgrindController::processFinished(int rc, QProcess::ExitStatus status)
m_lastOption = Unknown; m_lastOption = Unknown;
} }
void CallgrindController::setValgrindProcess(ValgrindProcess *proc) void CallgrindController::controllerProcessClosed(bool success)
{ {
m_valgrindProc = proc; Q_UNUSED(success);
// QTC_ASSERT(m_remote.m_process, return);
// m_remote.m_errorString = m_remote.m_process->errorString();
// if (status == QSsh::SshRemoteProcess::FailedToStart) {
// m_remote.m_error = QProcess::FailedToStart;
// emit ValgrindProcessX::error(QProcess::FailedToStart);
// } else if (status == QSsh::SshRemoteProcess::NormalExit) {
// emit finished(m_remote.m_process->exitCode(), QProcess::NormalExit);
// } else if (status == QSsh::SshRemoteProcess::CrashExit) {
// m_remote.m_error = QProcess::Crashed;
// emit finished(m_remote.m_process->exitCode(), QProcess::CrashExit);
// }
controllerProcessFinished(0, QProcess::NormalExit);
} }
void CallgrindController::getLocalDataFile() void CallgrindController::getLocalDataFile()
{ {
QTC_ASSERT(m_valgrindProc, return);
// we look for callgrind.out.PID, but there may be updated ones called ~.PID.NUM // we look for callgrind.out.PID, but there may be updated ones called ~.PID.NUM
QString baseFileName = QString::fromLatin1("callgrind.out.%1"). const QString baseFileName = QString("callgrind.out.%1").arg(m_pid);
arg(m_valgrindProc->pid()); const QString workingDir = m_valgrindRunnable.workingDirectory;
const QString workingDir = m_valgrindProc->workingDirectory();
// first, set the to-be-parsed file to callgrind.out.PID // first, set the to-be-parsed file to callgrind.out.PID
QString fileName = workingDir.isEmpty() ? baseFileName : (workingDir + QLatin1Char('/') + baseFileName); QString fileName = workingDir.isEmpty() ? baseFileName : (workingDir + '/' + baseFileName);
if (!m_valgrindProc->isLocal()) { if (m_valgrindRunnable.device
///TODO: error handling && m_valgrindRunnable.device->type() != ProjectExplorer::Constants::DESKTOP_DEVICE_TYPE) {
emit statusMessage(tr("Downloading remote profile data...")); // ///TODO: error handling
m_ssh = m_valgrindProc->connection(); // emit statusMessage(tr("Downloading remote profile data..."));
// if there are files like callgrind.out.PID.NUM, set it to the most recent one of those // m_ssh = m_valgrindProc->connection();
QString cmd = QString::fromLatin1("ls -t %1* | head -n 1").arg(fileName); // // if there are files like callgrind.out.PID.NUM, set it to the most recent one of those
m_findRemoteFile = m_ssh->createRemoteProcess(cmd.toUtf8()); // QString cmd = QString::fromLatin1("ls -t %1* | head -n 1").arg(fileName);
connect(m_findRemoteFile.data(), &QSsh::SshRemoteProcess::readyReadStandardOutput, // m_findRemoteFile = m_ssh->createRemoteProcess(cmd.toUtf8());
this, &CallgrindController::foundRemoteFile); // connect(m_findRemoteFile.data(), &QSsh::SshRemoteProcess::readyReadStandardOutput,
m_findRemoteFile->start(); // this, &CallgrindController::foundRemoteFile);
// m_findRemoteFile->start();
} else { } else {
QDir dir(workingDir, QString::fromLatin1("%1.*").arg(baseFileName), QDir::Time); QDir dir(workingDir, QString::fromLatin1("%1.*").arg(baseFileName), QDir::Time);
QStringList outputFiles = dir.entryList(); QStringList outputFiles = dir.entryList();
@@ -254,5 +278,11 @@ void CallgrindController::cleanupTempFile()
m_tempDataFile.clear(); m_tempDataFile.clear();
} }
void CallgrindController::setValgrindRunnable(const Runnable &runnable)
{
QTC_ASSERT(runnable.is<StandardRunnable>(), return);
m_valgrindRunnable = runnable.as<StandardRunnable>();
}
} // namespace Callgrind } // namespace Callgrind
} // namespace Valgrind } // namespace Valgrind

View File

@@ -25,18 +25,15 @@
#pragma once #pragma once
#include <QObject>
#include <qprocess.h>
#include <ssh/sshconnection.h>
#include <ssh/sshremoteprocess.h> #include <ssh/sshremoteprocess.h>
#include <ssh/sftpchannel.h> #include <ssh/sftpchannel.h>
#include <ssh/sshconnection.h>
#include <projectexplorer/runnables.h>
#include <QProcess>
namespace Valgrind { namespace Valgrind {
class ValgrindProcess;
namespace Callgrind { namespace Callgrind {
class CallgrindController : public QObject class CallgrindController : public QObject
@@ -49,16 +46,14 @@ public:
Unknown, Unknown,
Dump, Dump,
ResetEventCounters, ResetEventCounters,
Pause, UnPause Pause,
UnPause
}; };
explicit CallgrindController(QObject *parent = 0); CallgrindController();
virtual ~CallgrindController(); ~CallgrindController() override;
void run(Valgrind::Callgrind::CallgrindController::Option option); void run(Option option);
void setValgrindProcess(ValgrindProcess *process);
ValgrindProcess *valgrindProcess() { return m_valgrindProc; }
/** /**
* Make data file available locally, triggers @c localParseDataAvailable. * Make data file available locally, triggers @c localParseDataAvailable.
@@ -67,32 +62,34 @@ public:
* downloads the data file first and returns a local path. * downloads the data file first and returns a local path.
*/ */
void getLocalDataFile(); void getLocalDataFile();
void setValgrindPid(qint64 pid);
void setValgrindRunnable(const ProjectExplorer::Runnable &runnable);
signals: signals:
void finished(Valgrind::Callgrind::CallgrindController::Option option); void finished(Valgrind::Callgrind::CallgrindController::Option option);
void localParseDataAvailable(const QString &file); void localParseDataAvailable(const QString &file);
void statusMessage(const QString &msg); void statusMessage(const QString &msg);
private: private:
void processError(QProcess::ProcessError); void handleControllerProcessError(QProcess::ProcessError);
void processFinished(int, QProcess::ExitStatus);
void foundRemoteFile(); void foundRemoteFile();
void sftpInitialized(); void sftpInitialized();
void sftpJobFinished(QSsh::SftpJobId job, const QString &error); void sftpJobFinished(QSsh::SftpJobId job, const QString &error);
void cleanupTempFile(); void cleanupTempFile();
// callgrind_control process void controllerProcessFinished(int, QProcess::ExitStatus);
Valgrind::ValgrindProcess *m_process; void controllerProcessError(QProcess::ProcessError);
// valgrind process void controllerProcessClosed(bool success);
Valgrind::ValgrindProcess *m_valgrindProc;
Option m_lastOption; ProjectExplorer::ApplicationLauncher *m_controllerProcess;
ProjectExplorer::StandardRunnable m_valgrindRunnable;
qint64 m_pid = 0;
Option m_lastOption = Unknown;
// remote callgrind support // remote callgrind support
QSsh::SshConnection *m_ssh; QSsh::SshConnection *m_ssh = nullptr;
QString m_tempDataFile; QString m_tempDataFile;
QSsh::SshRemoteProcess::Ptr m_findRemoteFile; QSsh::SshRemoteProcess::Ptr m_findRemoteFile;
QSsh::SftpChannel::Ptr m_sftp; QSsh::SftpChannel::Ptr m_sftp;

View File

@@ -30,21 +30,22 @@
#include <valgrind/callgrind/callgrindcontroller.h> #include <valgrind/callgrind/callgrindcontroller.h>
#include <valgrind/callgrind/callgrindparser.h> #include <valgrind/callgrind/callgrindparser.h>
#include <valgrind/valgrindrunner.h>
#include <debugger/analyzer/analyzermanager.h> #include <debugger/analyzer/analyzermanager.h>
#include <utils/qtcassert.h> #include <utils/qtcassert.h>
using namespace Debugger; using namespace ProjectExplorer;
using namespace Valgrind;
using namespace Valgrind::Internal;
using namespace Valgrind::Callgrind; using namespace Valgrind::Callgrind;
CallgrindToolRunner::CallgrindToolRunner(ProjectExplorer::RunControl *runControl) namespace Valgrind {
namespace Internal {
CallgrindToolRunner::CallgrindToolRunner(RunControl *runControl)
: ValgrindToolRunner(runControl) : ValgrindToolRunner(runControl)
{ {
setDisplayName("CallgrindToolRunner"); setDisplayName("CallgrindToolRunner");
m_runner.setToolName("callgrind");
connect(&m_runner, &ValgrindRunner::finished, connect(&m_runner, &ValgrindRunner::finished,
this, &CallgrindToolRunner::slotFinished); this, &CallgrindToolRunner::slotFinished);
@@ -58,19 +59,19 @@ CallgrindToolRunner::CallgrindToolRunner(ProjectExplorer::RunControl *runControl
connect(&m_controller, &CallgrindController::statusMessage, connect(&m_controller, &CallgrindController::statusMessage,
this, &CallgrindToolRunner::showStatusMessage); this, &CallgrindToolRunner::showStatusMessage);
connect(&m_runner, &ValgrindRunner::extraStart, this, [this] { connect(&m_runner, &ValgrindRunner::valgrindStarted,
m_controller.setValgrindProcess(m_runner.valgrindProcess()); &m_controller, &CallgrindController::setValgrindPid);
});
connect(&m_runner, &ValgrindRunner::extraProcessFinished, this, [this] { connect(&m_runner, &ValgrindRunner::extraProcessFinished, this, [this] {
triggerParse(); triggerParse();
m_controller.setValgrindProcess(nullptr);
}); });
m_controller.setValgrindRunnable(runnable());
} }
QStringList CallgrindToolRunner::toolArguments() const QStringList CallgrindToolRunner::toolArguments() const
{ {
QStringList arguments; QStringList arguments = {"--tool=callgrind"};
QTC_ASSERT(m_settings, return arguments); QTC_ASSERT(m_settings, return arguments);
@@ -120,12 +121,10 @@ void CallgrindToolRunner::setPaused(bool paused)
m_markAsPaused = paused; m_markAsPaused = paused;
// call controller only if it is attached to a valgrind process // call controller only if it is attached to a valgrind process
if (m_controller.valgrindProcess()) { if (paused)
if (paused) pause();
pause(); else
else unpause();
unpause();
}
} }
void CallgrindToolRunner::setToggleCollectFunction(const QString &toggleCollectFunction) void CallgrindToolRunner::setToggleCollectFunction(const QString &toggleCollectFunction)
@@ -202,3 +201,6 @@ void CallgrindToolRunner::controllerFinished(CallgrindController::Option option)
break; // do nothing break; // do nothing
} }
} }
} // Internal
} // Valgrind

View File

@@ -48,7 +48,7 @@ CallgrindTextMark::CallgrindTextMark(const QPersistentModelIndex &index,
setPriority(TextEditor::TextMark::HighPriority); setPriority(TextEditor::TextMark::HighPriority);
} }
void CallgrindTextMark::paint(QPainter *painter, const QRect &paintRect) const void CallgrindTextMark::paintIcon(QPainter *painter, const QRect &paintRect) const
{ {
if (!m_modelIndex.isValid()) if (!m_modelIndex.isValid())
return; return;

View File

@@ -49,7 +49,7 @@ public:
const Valgrind::Callgrind::Function *function() const; const Valgrind::Callgrind::Function *function() const;
virtual void paint(QPainter *painter, const QRect &paintRect) const; virtual void paintIcon(QPainter *painter, const QRect &paintRect) const;
private: private:
QPersistentModelIndex m_modelIndex; QPersistentModelIndex m_modelIndex;

View File

@@ -289,7 +289,6 @@ CallgrindTool::CallgrindTool(QObject *parent)
auto runControl = new RunControl(runConfig, CALLGRIND_RUN_MODE); auto runControl = new RunControl(runConfig, CALLGRIND_RUN_MODE);
const auto runnable = dlg.runnable(); const auto runnable = dlg.runnable();
runControl->setRunnable(runnable); runControl->setRunnable(runnable);
runControl->setConnection(UrlConnection(dlg.serverUrl()));
runControl->setDisplayName(runnable.executable); runControl->setDisplayName(runnable.executable);
createRunTool(runControl); createRunTool(runControl);
ProjectExplorerPlugin::startRunControl(runControl); ProjectExplorerPlugin::startRunControl(runControl);

View File

@@ -26,7 +26,6 @@
#include "memcheckengine.h" #include "memcheckengine.h"
#include "memchecktool.h" #include "memchecktool.h"
#include "valgrindprocess.h"
#include "valgrindsettings.h" #include "valgrindsettings.h"
#include "xmlprotocol/error.h" #include "xmlprotocol/error.h"
#include "xmlprotocol/status.h" #include "xmlprotocol/status.h"
@@ -51,8 +50,33 @@ using namespace Valgrind::XmlProtocol;
namespace Valgrind { namespace Valgrind {
namespace Internal { namespace Internal {
class LocalAddressFinder : public RunWorker
{
public:
LocalAddressFinder(RunControl *runControl, QHostAddress *localServerAddress)
: RunWorker(runControl), connection(device()->sshParameters())
{
connect(&connection, &QSsh::SshConnection::connected, this, [this, localServerAddress] {
*localServerAddress = connection.connectionInfo().localAddress;
reportStarted();
});
connect(&connection, &QSsh::SshConnection::error, this, [this] {
reportFailure();
});
}
void start() override
{
connection.connectToHost();
}
QSsh::SshConnection connection;
};
MemcheckToolRunner::MemcheckToolRunner(RunControl *runControl, bool withGdb) MemcheckToolRunner::MemcheckToolRunner(RunControl *runControl, bool withGdb)
: ValgrindToolRunner(runControl), m_withGdb(withGdb) : ValgrindToolRunner(runControl),
m_withGdb(withGdb),
m_localServerAddress(QHostAddress::LocalHost)
{ {
setDisplayName("MemcheckToolRunner"); setDisplayName("MemcheckToolRunner");
connect(m_runner.parser(), &XmlProtocol::ThreadedParser::error, connect(m_runner.parser(), &XmlProtocol::ThreadedParser::error,
@@ -61,15 +85,19 @@ MemcheckToolRunner::MemcheckToolRunner(RunControl *runControl, bool withGdb)
this, &MemcheckToolRunner::suppressionCount); this, &MemcheckToolRunner::suppressionCount);
if (withGdb) { if (withGdb) {
connect(&m_runner, &ValgrindRunner::started, connect(&m_runner, &ValgrindRunner::valgrindStarted,
this, &MemcheckToolRunner::startDebugger); this, &MemcheckToolRunner::startDebugger);
connect(&m_runner, &ValgrindRunner::logMessageReceived, connect(&m_runner, &ValgrindRunner::logMessageReceived,
this, &MemcheckToolRunner::appendLog); this, &MemcheckToolRunner::appendLog);
m_runner.disableXml(); // m_runner.disableXml();
} else { } else {
connect(m_runner.parser(), &XmlProtocol::ThreadedParser::internalError, connect(m_runner.parser(), &XmlProtocol::ThreadedParser::internalError,
this, &MemcheckToolRunner::internalParserError); this, &MemcheckToolRunner::internalParserError);
} }
// We need a real address to connect to from the outside.
if (device()->type() != ProjectExplorer::Constants::DESKTOP_DEVICE_TYPE)
addDependency(new LocalAddressFinder(runControl, &m_localServerAddress));
} }
QString MemcheckToolRunner::progressTitle() const QString MemcheckToolRunner::progressTitle() const
@@ -79,10 +107,7 @@ QString MemcheckToolRunner::progressTitle() const
void MemcheckToolRunner::start() void MemcheckToolRunner::start()
{ {
// MemcheckTool::engineStarting(this); m_runner.setLocalServerAddress(m_localServerAddress);
appendMessage(tr("Analyzing memory of %1").arg(executable()) + QLatin1Char('\n'),
Utils::NormalMessageFormat);
ValgrindToolRunner::start(); ValgrindToolRunner::start();
} }
@@ -95,8 +120,7 @@ void MemcheckToolRunner::stop()
QStringList MemcheckToolRunner::toolArguments() const QStringList MemcheckToolRunner::toolArguments() const
{ {
QStringList arguments; QStringList arguments = {"--tool=memcheck", "--gen-suppressions=all"};
arguments << "--gen-suppressions=all";
QTC_ASSERT(m_settings, return arguments); QTC_ASSERT(m_settings, return arguments);
@@ -137,10 +161,8 @@ QStringList MemcheckToolRunner::suppressionFiles() const
return m_settings->suppressionFiles(); return m_settings->suppressionFiles();
} }
void MemcheckToolRunner::startDebugger() void MemcheckToolRunner::startDebugger(qint64 valgrindPid)
{ {
const qint64 valgrindPid = m_runner.valgrindProcess()->pid();
Debugger::DebuggerStartParameters sp; Debugger::DebuggerStartParameters sp;
sp.inferior = runnable().as<StandardRunnable>(); sp.inferior = runnable().as<StandardRunnable>();
sp.startMode = Debugger::AttachToRemoteServer; sp.startMode = Debugger::AttachToRemoteServer;
@@ -149,12 +171,10 @@ void MemcheckToolRunner::startDebugger()
sp.useContinueInsteadOfRun = true; sp.useContinueInsteadOfRun = true;
sp.expectedSignals.append("SIGTRAP"); sp.expectedSignals.append("SIGTRAP");
QString errorMessage; auto gdbWorker = new Debugger::DebuggerRunTool(runControl());
auto gdbRunControl = new RunControl(nullptr, ProjectExplorer::Constants::DEBUG_RUN_MODE); gdbWorker->setStartParameters(sp);
(void) new Debugger::DebuggerRunTool(gdbRunControl, sp, &errorMessage); gdbWorker->initiateStart();
connect(gdbRunControl, &RunControl::finished, connect(runControl(), &RunControl::finished, gdbWorker, &RunControl::deleteLater);
gdbRunControl, &RunControl::deleteLater);
gdbRunControl->initiateStart();
} }
void MemcheckToolRunner::appendLog(const QByteArray &data) void MemcheckToolRunner::appendLog(const QByteArray &data)

View File

@@ -31,6 +31,8 @@
#include "valgrindrunner.h" #include "valgrindrunner.h"
#include "xmlprotocol/threadedparser.h" #include "xmlprotocol/threadedparser.h"
#include <QHostAddress>
namespace Valgrind { namespace Valgrind {
namespace Internal { namespace Internal {
@@ -56,10 +58,11 @@ private:
QString progressTitle() const override; QString progressTitle() const override;
QStringList toolArguments() const override; QStringList toolArguments() const override;
void startDebugger(); void startDebugger(qint64 valgrindPid);
void appendLog(const QByteArray &data); void appendLog(const QByteArray &data);
const bool m_withGdb; const bool m_withGdb;
QHostAddress m_localServerAddress;
}; };
} // namespace Internal } // namespace Internal

View File

@@ -454,7 +454,6 @@ MemcheckTool::MemcheckTool(QObject *parent)
rc->createWorker(MEMCHECK_RUN_MODE); rc->createWorker(MEMCHECK_RUN_MODE);
const auto runnable = dlg.runnable(); const auto runnable = dlg.runnable();
rc->setRunnable(runnable); rc->setRunnable(runnable);
rc->setConnection(UrlConnection(dlg.serverUrl()));
rc->setDisplayName(runnable.executable); rc->setDisplayName(runnable.executable);
ProjectExplorerPlugin::startRunControl(rc); ProjectExplorerPlugin::startRunControl(rc);
}); });

View File

@@ -11,7 +11,6 @@ HEADERS += \
valgrindconfigwidget.h \ valgrindconfigwidget.h \
valgrindsettings.h \ valgrindsettings.h \
valgrindrunner.h \ valgrindrunner.h \
valgrindprocess.h \
callgrindcostdelegate.h \ callgrindcostdelegate.h \
callgrindcostview.h \ callgrindcostview.h \
callgrindhelper.h \ callgrindhelper.h \
@@ -33,7 +32,6 @@ SOURCES += \
valgrindconfigwidget.cpp \ valgrindconfigwidget.cpp \
valgrindsettings.cpp \ valgrindsettings.cpp \
valgrindrunner.cpp \ valgrindrunner.cpp \
valgrindprocess.cpp \
callgrindcostdelegate.cpp \ callgrindcostdelegate.cpp \
callgrindcostview.cpp \ callgrindcostview.cpp \
callgrindhelper.cpp \ callgrindhelper.cpp \

View File

@@ -34,7 +34,6 @@ QtcPlugin {
"valgrindconfigwidget.cpp", "valgrindconfigwidget.h", "valgrindconfigwidget.ui", "valgrindconfigwidget.cpp", "valgrindconfigwidget.h", "valgrindconfigwidget.ui",
"valgrindengine.cpp", "valgrindengine.h", "valgrindengine.cpp", "valgrindengine.h",
"valgrindplugin.cpp", "valgrindplugin.h", "valgrindplugin.cpp", "valgrindplugin.h",
"valgrindprocess.cpp", "valgrindprocess.h",
"valgrindruncontrolfactory.cpp", "valgrindruncontrolfactory.h", "valgrindruncontrolfactory.cpp", "valgrindruncontrolfactory.h",
"valgrindrunner.cpp", "valgrindrunner.h", "valgrindrunner.cpp", "valgrindrunner.h",
"valgrindsettings.cpp", "valgrindsettings.h", "valgrindsettings.cpp", "valgrindsettings.h",

View File

@@ -27,8 +27,7 @@ HEADERS += \
$$PWD/callgrind/callgrindcycledetection.h \ $$PWD/callgrind/callgrindcycledetection.h \
$$PWD/callgrind/callgrindproxymodel.h \ $$PWD/callgrind/callgrindproxymodel.h \
$$PWD/callgrind/callgrindstackbrowser.h \ $$PWD/callgrind/callgrindstackbrowser.h \
$$PWD/valgrindrunner.h \ $$PWD/valgrindrunner.h
$$PWD/valgrindprocess.h
SOURCES += $$PWD/xmlprotocol/error.cpp \ SOURCES += $$PWD/xmlprotocol/error.cpp \
$$PWD/xmlprotocol/frame.cpp \ $$PWD/xmlprotocol/frame.cpp \
@@ -53,7 +52,6 @@ SOURCES += $$PWD/xmlprotocol/error.cpp \
$$PWD/callgrind/callgrindcycledetection.cpp \ $$PWD/callgrind/callgrindcycledetection.cpp \
$$PWD/callgrind/callgrindproxymodel.cpp \ $$PWD/callgrind/callgrindproxymodel.cpp \
$$PWD/callgrind/callgrindstackbrowser.cpp \ $$PWD/callgrind/callgrindstackbrowser.cpp \
$$PWD/valgrindrunner.cpp \ $$PWD/valgrindrunner.cpp
$$PWD/valgrindprocess.cpp
LIBS += -L$$IDE_PLUGIN_PATH/QtProject LIBS += -L$$IDE_PLUGIN_PATH/QtProject

View File

@@ -106,6 +106,7 @@ void ValgrindToolRunner::stop()
{ {
m_isStopping = true; m_isStopping = true;
m_runner.stop(); m_runner.stop();
reportStopped(); // FIXME: Restrict to non-running scenarios?
} }
QString ValgrindToolRunner::executable() const QString ValgrindToolRunner::executable() const

View File

@@ -1,320 +0,0 @@
/****************************************************************************
**
** Copyright (C) 2016 The Qt Company Ltd.
** Author: Milian Wolff, KDAB (milian.wolff@kdab.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.
**
****************************************************************************/
#include "valgrindprocess.h"
#include <ssh/sshconnectionmanager.h>
#include <utils/fileutils.h>
#include <utils/qtcassert.h>
#include <utils/qtcprocess.h>
#include <QDebug>
#include <QEventLoop>
using namespace ProjectExplorer;
namespace Valgrind {
ValgrindProcess::ValgrindProcess(const IDevice::ConstPtr &device,
QObject *parent)
: QObject(parent), m_device(device)
{
m_remote.m_connection = 0;
m_remote.m_error = QProcess::UnknownError;
m_pid = 0;
}
ValgrindProcess::~ValgrindProcess()
{
if (m_remote.m_connection)
QSsh::releaseConnection(m_remote.m_connection);
}
void ValgrindProcess::setProcessChannelMode(QProcess::ProcessChannelMode mode)
{
if (isLocal())
m_localProcess.setProcessChannelMode(mode);
///TODO: remote support this by handling the mode internally
}
QString ValgrindProcess::workingDirectory() const
{
return m_debuggee.workingDirectory;
}
bool ValgrindProcess::isRunning() const
{
if (isLocal())
return m_localProcess.isRunning();
else
return m_remote.m_process && m_remote.m_process->isRunning();
}
void ValgrindProcess::setValgrindExecutable(const QString &valgrindExecutable)
{
m_valgrindExecutable = valgrindExecutable;
}
void ValgrindProcess::setDebuggee(const StandardRunnable &debuggee)
{
m_debuggee = debuggee;
}
void ValgrindProcess::setValgrindArguments(const QStringList &valgrindArguments)
{
m_valgrindArguments = valgrindArguments;
}
void ValgrindProcess::close()
{
if (isLocal()) {
m_localProcess.stop();
} else {
QTC_ASSERT(m_remote.m_connection->state() == QSsh::SshConnection::Connected, return);
if (m_remote.m_process) {
if (m_pid) {
const QString killTemplate = QString::fromLatin1("kill -%2 %1" // kill
).arg(m_pid);
const QString niceKill = killTemplate.arg(QLatin1String("SIGTERM"));
const QString brutalKill = killTemplate.arg(QLatin1String("SIGKILL"));
const QString remoteCall = niceKill + QLatin1String("; sleep 1; ") + brutalKill;
QSsh::SshRemoteProcess::Ptr cleanup = m_remote.m_connection->createRemoteProcess(remoteCall.toUtf8());
cleanup->start();
}
}
}
}
void ValgrindProcess::run(ApplicationLauncher::Mode runMode)
{
if (isLocal()) {
connect(&m_localProcess, &ApplicationLauncher::processExited,
this, &ValgrindProcess::finished);
connect(&m_localProcess, &ApplicationLauncher::processStarted,
this, &ValgrindProcess::localProcessStarted);
connect(&m_localProcess, &ApplicationLauncher::error,
this, &ValgrindProcess::error);
connect(&m_localProcess, &ApplicationLauncher::appendMessage,
this, &ValgrindProcess::processOutput);
StandardRunnable valgrind;
valgrind.executable = m_valgrindExecutable;
valgrind.runMode = runMode;
valgrind.commandLineArguments = argumentString(Utils::HostOsInfo::hostOs());
valgrind.workingDirectory = m_debuggee.workingDirectory;
valgrind.environment = m_debuggee.environment;
m_localProcess.start(valgrind);
} else {
// connect to host and wait for connection
if (!m_remote.m_connection)
m_remote.m_connection = QSsh::acquireConnection(m_device->sshParameters());
if (m_remote.m_connection->state() != QSsh::SshConnection::Connected) {
connect(m_remote.m_connection, &QSsh::SshConnection::connected,
this, &ValgrindProcess::connected);
connect(m_remote.m_connection, &QSsh::SshConnection::error,
this, &ValgrindProcess::handleError);
if (m_remote.m_connection->state() == QSsh::SshConnection::Unconnected)
m_remote.m_connection->connectToHost();
} else {
connected();
}
}
}
QString ValgrindProcess::errorString() const
{
if (isLocal())
return m_localProcess.errorString();
else
return m_remote.m_errorString;
}
QProcess::ProcessError ValgrindProcess::processError() const
{
if (isLocal())
return m_localProcess.processError();
else
return m_remote.m_error;
}
void ValgrindProcess::handleError(QSsh::SshError error)
{
if (!isLocal()) {
switch (error) {
case QSsh::SshTimeoutError:
m_remote.m_error = QProcess::Timedout;
break;
default:
m_remote.m_error = QProcess::FailedToStart;
break;
}
}
m_remote.m_errorString = m_remote.m_connection->errorString();
emit this->error(m_remote.m_error);
}
qint64 ValgrindProcess::pid() const
{
return m_pid;
}
void ValgrindProcess::handleRemoteStderr()
{
const QString b = QString::fromUtf8(m_remote.m_process->readAllStandardError());
if (!b.isEmpty())
emit processOutput(b, Utils::StdErrFormat);
}
void ValgrindProcess::handleRemoteStdout()
{
const QString b = QString::fromUtf8(m_remote.m_process->readAllStandardOutput());
if (!b.isEmpty())
emit processOutput(b, Utils::StdOutFormat);
}
/// Remote
void ValgrindProcess::connected()
{
QTC_ASSERT(m_remote.m_connection->state() == QSsh::SshConnection::Connected, return);
emit localHostAddressRetrieved(m_remote.m_connection->connectionInfo().localAddress);
// connected, run command
QString cmd;
if (!m_debuggee.workingDirectory.isEmpty())
cmd += QString::fromLatin1("cd '%1' && ").arg(m_debuggee.workingDirectory);
cmd += m_valgrindExecutable + QLatin1Char(' ') + argumentString(Utils::OsTypeLinux);
m_remote.m_process = m_remote.m_connection->createRemoteProcess(cmd.toUtf8());
for (auto it = m_debuggee.environment.constBegin(); it != m_debuggee.environment.constEnd(); ++it)
m_remote.m_process->addToEnvironment(it.key().toUtf8(), it.value().toUtf8());
connect(m_remote.m_process.data(), &QSsh::SshRemoteProcess::readyReadStandardError,
this, &ValgrindProcess::handleRemoteStderr);
connect(m_remote.m_process.data(), &QSsh::SshRemoteProcess::readyReadStandardOutput,
this, &ValgrindProcess::handleRemoteStdout);
connect(m_remote.m_process.data(), &QSsh::SshRemoteProcess::closed,
this, &ValgrindProcess::closed);
connect(m_remote.m_process.data(), &QSsh::SshRemoteProcess::started,
this, &ValgrindProcess::remoteProcessStarted);
m_remote.m_process->start();
}
QSsh::SshConnection *ValgrindProcess::connection() const
{
return m_remote.m_connection;
}
bool ValgrindProcess::isLocal() const
{
return m_device->type() == ProjectExplorer::Constants::DESKTOP_DEVICE_TYPE;
}
void ValgrindProcess::localProcessStarted()
{
m_pid = m_localProcess.applicationPID().pid();
emit started();
}
void ValgrindProcess::remoteProcessStarted()
{
QTC_ASSERT(m_remote.m_connection->state() == QSsh::SshConnection::Connected, return);
// find out what PID our process has
// NOTE: valgrind cloaks its name,
// e.g.: valgrind --tool=memcheck foobar
// => ps aux, pidof will see valgrind.bin
// => pkill/killall/top... will see memcheck-amd64-linux or similar
// hence we need to do something more complex...
// plain path to exe, m_valgrindExe contains e.g. env vars etc. pp.
const QString proc = m_valgrindExecutable.split(QLatin1Char(' ')).last();
// sleep required since otherwise we might only match "bash -c..."
// and not the actual valgrind run
const QString cmd = QString::fromLatin1("sleep 1; ps ax" // list all processes with aliased name
" | grep '\\b%1.*%2'" // find valgrind process
" | tail -n 1" // limit to single process
// we pick the last one, first would be "bash -c ..."
" | awk '{print $1;}'" // get pid
).arg(proc, Utils::FileName::fromString(m_debuggee.executable).fileName());
m_remote.m_findPID = m_remote.m_connection->createRemoteProcess(cmd.toUtf8());
connect(m_remote.m_findPID.data(), &QSsh::SshRemoteProcess::readyReadStandardError,
this, &ValgrindProcess::handleRemoteStderr);
connect(m_remote.m_findPID.data(), &QSsh::SshRemoteProcess::readyReadStandardOutput,
this, &ValgrindProcess::findPIDOutputReceived);
m_remote.m_findPID->start();
}
void ValgrindProcess::findPIDOutputReceived()
{
bool ok;
m_pid = m_remote.m_findPID->readAllStandardOutput().trimmed().toLongLong(&ok);
if (!ok) {
m_pid = 0;
m_remote.m_errorString = tr("Could not determine remote PID.");
m_remote.m_error = QProcess::FailedToStart;
emit ValgrindProcess::error(QProcess::FailedToStart);
close();
} else {
emit started();
}
}
QString ValgrindProcess::argumentString(Utils::OsType osType) const
{
QString arguments = Utils::QtcProcess::joinArgs(m_valgrindArguments, osType);
if (!m_debuggee.executable.isEmpty())
Utils::QtcProcess::addArg(&arguments, m_debuggee.executable, osType);
Utils::QtcProcess::addArgs(&arguments, m_debuggee.commandLineArguments);
return arguments;
}
void ValgrindProcess::closed(int status)
{
QTC_ASSERT(m_remote.m_process, return);
m_remote.m_errorString = m_remote.m_process->errorString();
if (status == QSsh::SshRemoteProcess::FailedToStart) {
m_remote.m_error = QProcess::FailedToStart;
emit ValgrindProcess::error(QProcess::FailedToStart);
} else if (status == QSsh::SshRemoteProcess::NormalExit) {
emit finished(m_remote.m_process->exitCode(), QProcess::NormalExit);
} else if (status == QSsh::SshRemoteProcess::CrashExit) {
m_remote.m_error = QProcess::Crashed;
emit finished(m_remote.m_process->exitCode(), QProcess::CrashExit);
}
}
} // namespace Valgrind

View File

@@ -1,110 +0,0 @@
/****************************************************************************
**
** Copyright (C) 2016 The Qt Company Ltd.
** Author: Milian Wolff, KDAB (milian.wolff@kdab.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 <projectexplorer/applicationlauncher.h>
#include <projectexplorer/devicesupport/idevice.h>
#include <projectexplorer/runnables.h>
#include <ssh/sshremoteprocess.h>
#include <ssh/sshconnection.h>
#include <utils/osspecificaspects.h>
#include <utils/outputformat.h>
namespace Valgrind {
/**
* Process for supplying local and remote valgrind runs
*/
class ValgrindProcess : public QObject
{
Q_OBJECT
public:
ValgrindProcess(const ProjectExplorer::IDevice::ConstPtr &device, QObject *parent);
~ValgrindProcess();
bool isRunning() const;
void setValgrindExecutable(const QString &valgrindExecutable);
void setValgrindArguments(const QStringList &valgrindArguments);
void setDebuggee(const ProjectExplorer::StandardRunnable &debuggee);
void run(ProjectExplorer::ApplicationLauncher::Mode runMode);
void close();
QString errorString() const;
QProcess::ProcessError processError() const;
void setProcessChannelMode(QProcess::ProcessChannelMode mode);
QString workingDirectory() const;
ProjectExplorer::IDevice::ConstPtr device() const { return m_device; }
qint64 pid() const;
QSsh::SshConnection *connection() const;
bool isLocal() const;
signals:
void started();
void finished(int, QProcess::ExitStatus);
void error(QProcess::ProcessError);
void processOutput(const QString &, Utils::OutputFormat format);
void localHostAddressRetrieved(const QHostAddress &localHostAddress);
private:
void handleRemoteStderr();
void handleRemoteStdout();
void handleError(QSsh::SshError);
void closed(int);
void connected();
void localProcessStarted();
void remoteProcessStarted();
void findPIDOutputReceived();
QString argumentString(Utils::OsType osType) const;
ProjectExplorer::StandardRunnable m_debuggee;
ProjectExplorer::ApplicationLauncher m_localProcess;
qint64 m_pid;
ProjectExplorer::IDevice::ConstPtr m_device;
struct Remote {
QSsh::SshConnection *m_connection;
QSsh::SshRemoteProcess::Ptr m_process;
QString m_errorString;
QProcess::ProcessError m_error;
QSsh::SshRemoteProcess::Ptr m_findPID;
} m_remote;
QSsh::SshConnectionParameters m_params;
QString m_valgrindExecutable;
QStringList m_valgrindArguments;
};
} // namespace Valgrind

Some files were not shown because too many files have changed in this diff Show More