forked from qt-creator/qt-creator
Merge remote-tracking branch 'origin/master' into 4.4
Change-Id: I071b3016e11f94c5421822935c13cecda7075f40
This commit is contained in:
@@ -208,6 +208,6 @@ private:
|
||||
|
||||
CMBIPC_EXPORT QDebug operator<<(QDebug debug, CodeCompletion::Kind kind);
|
||||
|
||||
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::Kind kind);
|
||||
CMBIPC_EXPORT std::ostream &operator<<(std::ostream &os, const CodeCompletion::Availability availability);
|
||||
} // namespace ClangBackEnd
|
||||
|
@@ -365,7 +365,7 @@ void QmlDebugConnection::connectToHost(const QString &hostName, quint16 port)
|
||||
});
|
||||
connect(socket, &QAbstractSocket::connected, this, &QmlDebugConnection::socketConnected);
|
||||
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)
|
||||
|
@@ -430,6 +430,7 @@ void Wizard::showVariables()
|
||||
|
||||
auto label = new QLabel(result);
|
||||
label->setWordWrap(true);
|
||||
label->setTextInteractionFlags(Qt::TextSelectableByMouse | Qt::TextSelectableByKeyboard);
|
||||
scrollArea->setWidget(label);
|
||||
|
||||
layout->addWidget(scrollArea);
|
||||
|
@@ -55,14 +55,18 @@ void WizardPage::pageWasAdded()
|
||||
|
||||
void WizardPage::registerFieldWithName(const QString &name, QWidget *widget,
|
||||
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());
|
||||
if (wiz)
|
||||
wiz->registerFieldName(name);
|
||||
else
|
||||
m_toRegister.insert(name);
|
||||
|
||||
registerField(name, widget, property, changedSignal);
|
||||
}
|
||||
|
||||
bool WizardPage::handleReject()
|
||||
|
@@ -54,6 +54,8 @@ signals:
|
||||
void reportError(const QString &errorMessage);
|
||||
|
||||
private:
|
||||
void registerFieldName(const QString &name);
|
||||
|
||||
QSet<QString> m_toRegister;
|
||||
};
|
||||
|
||||
|
@@ -12,7 +12,6 @@ HEADERS += \
|
||||
androidmanager.h \
|
||||
androidrunconfiguration.h \
|
||||
androidruncontrol.h \
|
||||
androidrunfactories.h \
|
||||
androidsettingspage.h \
|
||||
androidsettingswidget.h \
|
||||
androidtoolchain.h \
|
||||
@@ -58,7 +57,6 @@ SOURCES += \
|
||||
androidmanager.cpp \
|
||||
androidrunconfiguration.cpp \
|
||||
androidruncontrol.cpp \
|
||||
androidrunfactories.cpp \
|
||||
androidsettingspage.cpp \
|
||||
androidsettingswidget.cpp \
|
||||
androidtoolchain.cpp \
|
||||
|
@@ -83,8 +83,6 @@ Project {
|
||||
"androidrunconfigurationwidget.ui",
|
||||
"androidruncontrol.cpp",
|
||||
"androidruncontrol.h",
|
||||
"androidrunfactories.cpp",
|
||||
"androidrunfactories.h",
|
||||
"androidrunnable.cpp",
|
||||
"androidrunnable.h",
|
||||
"androidrunner.cpp",
|
||||
|
@@ -24,66 +24,37 @@
|
||||
****************************************************************************/
|
||||
|
||||
#include "androidanalyzesupport.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;
|
||||
|
||||
namespace Android {
|
||||
namespace Internal {
|
||||
|
||||
AndroidAnalyzeSupport::AndroidAnalyzeSupport(RunControl *runControl)
|
||||
AndroidQmlProfilerSupport::AndroidQmlProfilerSupport(RunControl *runControl)
|
||||
: RunWorker(runControl)
|
||||
{
|
||||
setDisplayName("AndroidAnalyzeSupport");
|
||||
|
||||
RunConfiguration *runConfig = runControl->runConfiguration();
|
||||
runControl->setDisplayName(AndroidManager::packageName(runConfig->target()));
|
||||
runControl->setConnection(UrlConnection::localHostWithoutPort());
|
||||
setDisplayName("AndroidQmlProfilerSupport");
|
||||
|
||||
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(&m_outputParser, &QmlDebug::QmlOutputParser::waitingForConnectionOnPort, this,
|
||||
[this, runControl](Utils::Port) {
|
||||
runControl->notifyRemoteSetupDone(m_qmlPort);
|
||||
connect(runner, &AndroidRunner::qmlServerReady, [this, runner, profiler](const QUrl &server) {
|
||||
profiler->recordData("QmlServerUrl", server);
|
||||
reportStarted();
|
||||
});
|
||||
}
|
||||
|
||||
// connect(runner, &AndroidRunner::handleRemoteProcessStarted, this,
|
||||
// [this](Utils::Port, Utils::Port qmlPort) {
|
||||
// m_qmlPort = qmlPort;
|
||||
// });
|
||||
void AndroidQmlProfilerSupport::start()
|
||||
{
|
||||
}
|
||||
|
||||
// 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);
|
||||
});
|
||||
void AndroidQmlProfilerSupport::stop()
|
||||
{
|
||||
reportStopped();
|
||||
}
|
||||
|
||||
} // namespace Internal
|
||||
|
@@ -25,25 +25,21 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "androidrunconfiguration.h"
|
||||
|
||||
#include <projectexplorer/runconfiguration.h>
|
||||
|
||||
#include <qmldebug/qmloutputparser.h>
|
||||
|
||||
namespace Android {
|
||||
namespace Internal {
|
||||
|
||||
class AndroidAnalyzeSupport : public ProjectExplorer::RunWorker
|
||||
class AndroidQmlProfilerSupport : public ProjectExplorer::RunWorker
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
explicit AndroidAnalyzeSupport(ProjectExplorer::RunControl *runControl);
|
||||
explicit AndroidQmlProfilerSupport(ProjectExplorer::RunControl *runControl);
|
||||
|
||||
private:
|
||||
QmlDebug::QmlOutputParser m_outputParser;
|
||||
Utils::Port m_qmlPort;
|
||||
void start() override;
|
||||
void stop() override;
|
||||
};
|
||||
|
||||
} // namespace Internal
|
||||
|
@@ -94,6 +94,11 @@ DeviceProcessSignalOperation::Ptr AndroidDevice::signalOperation() const
|
||||
return DeviceProcessSignalOperation::Ptr(new AndroidSignalOperation());
|
||||
}
|
||||
|
||||
Utils::OsType AndroidDevice::osType() const
|
||||
{
|
||||
return Utils::OsTypeOtherUnix;
|
||||
}
|
||||
|
||||
IDevice::Ptr AndroidDevice::clone() const
|
||||
{
|
||||
return IDevice::Ptr(new AndroidDevice(*this));
|
||||
|
@@ -44,6 +44,7 @@ public:
|
||||
void executeAction(Core::Id actionId, QWidget *parent = 0) override;
|
||||
bool canAutoDetectPorts() const override;
|
||||
ProjectExplorer::DeviceProcessSignalOperation::Ptr signalOperation() const override;
|
||||
Utils::OsType osType() const override;
|
||||
|
||||
ProjectExplorer::IDevice::Ptr clone() const override;
|
||||
ProjectExplorer::Connection toolControlChannel(const ControlChannelHint &) const override;
|
||||
|
@@ -25,22 +25,26 @@
|
||||
|
||||
#include "androidplugin.h"
|
||||
|
||||
#include "androidconstants.h"
|
||||
#include "androidanalyzesupport.h"
|
||||
#include "androidconfigurations.h"
|
||||
#include "androidconstants.h"
|
||||
#include "androiddebugsupport.h"
|
||||
#include "androiddeployconfiguration.h"
|
||||
#include "androiddeployqtstep.h"
|
||||
#include "androiddevice.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 "androidmanager.h"
|
||||
#include "androidmanifesteditorfactory.h"
|
||||
#include "androidpotentialkit.h"
|
||||
#include "androidqtversionfactory.h"
|
||||
#include "androidrunconfiguration.h"
|
||||
#include "androidruncontrol.h"
|
||||
#include "androidsettingspage.h"
|
||||
#include "androidtoolchain.h"
|
||||
#include "javacompletionassistprovider.h"
|
||||
#include "javaeditor.h"
|
||||
|
||||
#ifdef HAVE_QBS
|
||||
# include "androidqbspropertyprovider.h"
|
||||
#endif
|
||||
@@ -55,6 +59,8 @@
|
||||
#include <QtPlugin>
|
||||
|
||||
using namespace ProjectExplorer;
|
||||
using namespace ProjectExplorer::Constants;
|
||||
using namespace Android::Internal;
|
||||
|
||||
namespace Android {
|
||||
|
||||
@@ -66,9 +72,13 @@ bool AndroidPlugin::initialize(const QStringList &arguments, QString *errorMessa
|
||||
Q_UNUSED(arguments);
|
||||
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);
|
||||
|
||||
addAutoReleasedObject(new Internal::AndroidRunControlFactory);
|
||||
addAutoReleasedObject(new Internal::AndroidDeployQtStepFactory);
|
||||
addAutoReleasedObject(new Internal::AndroidSettingsPage);
|
||||
addAutoReleasedObject(new Internal::AndroidQtVersionFactory);
|
||||
|
@@ -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
|
@@ -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
|
@@ -34,6 +34,7 @@
|
||||
#include "androidavdmanager.h"
|
||||
|
||||
#include <debugger/debuggerrunconfigurationaspect.h>
|
||||
#include <coreplugin/messagemanager.h>
|
||||
#include <projectexplorer/projectexplorer.h>
|
||||
#include <projectexplorer/projectexplorerconstants.h>
|
||||
#include <projectexplorer/projectexplorersettings.h>
|
||||
@@ -632,7 +633,7 @@ void AndroidRunnerWorker::onProcessIdChanged(qint64 pid)
|
||||
// Don't write to m_psProc from a different thread
|
||||
QTC_ASSERT(QThread::currentThread() == thread(), return);
|
||||
m_processPID = pid;
|
||||
if (m_processPID == -1) {
|
||||
if (pid == -1) {
|
||||
emit remoteProcessFinished(QLatin1String("\n\n") + tr("\"%1\" died.")
|
||||
.arg(m_packageName));
|
||||
// App died/killed. Reset log and monitor processes.
|
||||
@@ -714,6 +715,9 @@ AndroidRunner::AndroidRunner(RunControl *runControl)
|
||||
connect(m_worker.data(), &AndroidRunnerWorker::remoteErrorOutput,
|
||||
this, &AndroidRunner::remoteErrorOutput);
|
||||
|
||||
connect(&m_outputParser, &QmlDebug::QmlOutputParser::waitingForConnectionOnPort,
|
||||
this, &AndroidRunner::qmlServerPortReady);
|
||||
|
||||
m_thread.start();
|
||||
}
|
||||
|
||||
@@ -749,14 +753,28 @@ void AndroidRunner::stop()
|
||||
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)
|
||||
{
|
||||
Core::MessageManager::write("LOGCAT: " + output, Core::MessageManager::Silent);
|
||||
appendMessage(output, Utils::StdOutFormatSameLine);
|
||||
m_outputParser.processOutput(output);
|
||||
}
|
||||
|
||||
void AndroidRunner::remoteErrorOutput(const QString &output)
|
||||
{
|
||||
Core::MessageManager::write("LOGCAT: " + output, Core::MessageManager::Silent);
|
||||
appendMessage(output, Utils::StdErrFormatSameLine);
|
||||
m_outputParser.processOutput(output);
|
||||
}
|
||||
|
||||
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)
|
||||
{
|
||||
appendMessage(errString, Utils::DebugFormat);
|
||||
if (runControl()->isRunning())
|
||||
runControl()->initiateStop();
|
||||
reportStopped();
|
||||
}
|
||||
|
||||
|
@@ -30,6 +30,7 @@
|
||||
|
||||
#include <projectexplorer/runconfiguration.h>
|
||||
#include <qmldebug/qmldebugcommandlinearguments.h>
|
||||
#include <qmldebug/qmloutputparser.h>
|
||||
|
||||
#include <QFutureInterface>
|
||||
#include <QObject>
|
||||
@@ -62,18 +63,20 @@ public:
|
||||
void start() override;
|
||||
void stop() override;
|
||||
|
||||
virtual void remoteOutput(const QString &output);
|
||||
virtual void remoteErrorOutput(const QString &output);
|
||||
|
||||
signals:
|
||||
void asyncStart(const AndroidRunnable &runnable);
|
||||
void asyncStop(const AndroidRunnable &runnable);
|
||||
void remoteDebuggerRunning();
|
||||
void qmlServerReady(const QUrl &serverUrl);
|
||||
|
||||
void adbParametersChanged(const QString &packageName, const QStringList &selector);
|
||||
void avdDetected();
|
||||
|
||||
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 handleRemoteProcessFinished(const QString &errString = QString());
|
||||
void checkAVD();
|
||||
@@ -88,6 +91,7 @@ private:
|
||||
Utils::Port m_gdbServerPort;
|
||||
Utils::Port m_qmlServerPort;
|
||||
Utils::ProcessHandle m_pid;
|
||||
QmlDebug::QmlOutputParser m_outputParser;
|
||||
};
|
||||
|
||||
} // namespace Internal
|
||||
|
@@ -57,6 +57,7 @@ QVariant GTestTreeItem::data(int column, int role) const
|
||||
}
|
||||
case Qt::CheckStateRole:
|
||||
switch (type()) {
|
||||
case Root:
|
||||
case TestCase:
|
||||
case TestFunctionOrSet:
|
||||
return checked();
|
||||
|
@@ -49,7 +49,6 @@ QVariant QtTestTreeItem::data(int column, int role) const
|
||||
return QVariant(name() + nameSuffix());
|
||||
case Qt::CheckStateRole:
|
||||
switch (type()) {
|
||||
case Root:
|
||||
case TestDataFunction:
|
||||
case TestSpecialFunction:
|
||||
return QVariant();
|
||||
|
@@ -50,7 +50,6 @@ QVariant QuickTestTreeItem::data(int column, int role) const
|
||||
break;
|
||||
case Qt::CheckStateRole:
|
||||
switch (type()) {
|
||||
case Root:
|
||||
case TestDataFunction:
|
||||
case TestSpecialFunction:
|
||||
case TestDataTag:
|
||||
|
@@ -42,7 +42,8 @@ TestTreeItem::TestTreeItem(const QString &name, const QString &filePath, Type ty
|
||||
m_filePath(filePath),
|
||||
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)
|
||||
@@ -103,7 +104,7 @@ Qt::ItemFlags TestTreeItem::flags(int /*column*/) const
|
||||
static const Qt::ItemFlags defaultFlags = Qt::ItemIsEnabled | Qt::ItemIsSelectable;
|
||||
switch (m_type) {
|
||||
case Root:
|
||||
return Qt::ItemIsEnabled;
|
||||
return Qt::ItemIsEnabled | Qt::ItemIsAutoTristate | Qt::ItemIsUserCheckable;
|
||||
case TestCase:
|
||||
return defaultFlags | Qt::ItemIsAutoTristate | Qt::ItemIsUserCheckable;
|
||||
case TestFunctionOrSet:
|
||||
@@ -161,13 +162,14 @@ void TestTreeItem::setChecked(const Qt::CheckState checkState)
|
||||
parent->revalidateCheckState();
|
||||
break;
|
||||
}
|
||||
case Root:
|
||||
case TestFunctionOrSet:
|
||||
case TestCase: {
|
||||
Qt::CheckState usedState = (checkState == Qt::Unchecked ? Qt::Unchecked : Qt::Checked);
|
||||
for (int row = 0, count = childCount(); row < count; ++row)
|
||||
childItem(row)->setChecked(usedState);
|
||||
m_checked = usedState;
|
||||
if (m_type == TestFunctionOrSet) {
|
||||
if (m_type != Root) {
|
||||
if (auto parent = parentItem())
|
||||
parent->revalidateCheckState();
|
||||
}
|
||||
@@ -181,6 +183,7 @@ void TestTreeItem::setChecked(const Qt::CheckState checkState)
|
||||
Qt::CheckState TestTreeItem::checked() const
|
||||
{
|
||||
switch (m_type) {
|
||||
case Root:
|
||||
case TestCase:
|
||||
case TestFunctionOrSet:
|
||||
case TestDataTag:
|
||||
@@ -295,7 +298,7 @@ QSet<QString> TestTreeItem::internalTargets() const
|
||||
void TestTreeItem::revalidateCheckState()
|
||||
{
|
||||
const Type ttiType = type();
|
||||
if (ttiType != TestCase && ttiType != TestFunctionOrSet)
|
||||
if (ttiType != TestCase && ttiType != TestFunctionOrSet && ttiType != Root)
|
||||
return;
|
||||
if (childCount() == 0) // can this happen? (we're calling revalidateCS() on parentItem()
|
||||
return;
|
||||
@@ -317,13 +320,13 @@ void TestTreeItem::revalidateCheckState()
|
||||
foundPartiallyChecked |= (child->checked() == Qt::PartiallyChecked);
|
||||
if (foundPartiallyChecked || (foundChecked && foundUnchecked)) {
|
||||
m_checked = Qt::PartiallyChecked;
|
||||
if (ttiType == TestFunctionOrSet)
|
||||
if (ttiType == TestFunctionOrSet || ttiType == TestCase)
|
||||
parentItem()->revalidateCheckState();
|
||||
return;
|
||||
}
|
||||
}
|
||||
m_checked = (foundUnchecked ? Qt::Unchecked : Qt::Checked);
|
||||
if (ttiType == TestFunctionOrSet)
|
||||
if (ttiType == TestFunctionOrSet || ttiType == TestCase)
|
||||
parentItem()->revalidateCheckState();
|
||||
}
|
||||
|
||||
|
@@ -135,6 +135,8 @@ private:
|
||||
unsigned m_column = 0;
|
||||
QString m_proFile;
|
||||
Status m_status = NewlyAdded;
|
||||
|
||||
friend class TestTreeModel; // grant access to (private) revalidateCheckState()
|
||||
};
|
||||
|
||||
class TestCodeLocationAndType
|
||||
|
@@ -110,6 +110,7 @@ bool TestTreeModel::setData(const QModelIndex &index, const QVariant &value, int
|
||||
emit dataChanged(index, index);
|
||||
if (role == Qt::CheckStateRole) {
|
||||
switch (item->type()) {
|
||||
case TestTreeItem::Root:
|
||||
case TestTreeItem::TestCase:
|
||||
if (item->childCount() > 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()) {
|
||||
destroyItem(child);
|
||||
item->revalidateCheckState();
|
||||
hasChanged = true;
|
||||
} else if (child->hasChildren()) {
|
||||
hasChanged |= sweepChildren(child);
|
||||
@@ -266,6 +268,12 @@ void TestTreeModel::handleParseResult(const TestParseResult *result, TestTreeIte
|
||||
TestTreeItem *newItem = result->createTestTreeItem();
|
||||
QTC_ASSERT(newItem, return);
|
||||
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()
|
||||
|
@@ -82,6 +82,10 @@ void TestTreeView::changeCheckStateAll(const Qt::CheckState checkState)
|
||||
item->setChecked(checkState);
|
||||
}
|
||||
}
|
||||
if (count == 0) {
|
||||
if (auto item = static_cast<TestTreeItem *>(currentRootIndex.internalPointer()))
|
||||
item->setChecked(checkState);
|
||||
}
|
||||
emit dataChanged(currentRootIndex, last);
|
||||
}
|
||||
}
|
||||
|
@@ -176,6 +176,11 @@ void BareMetalDevice::executeAction(Core::Id actionId, QWidget *parent)
|
||||
Q_UNUSED(parent);
|
||||
}
|
||||
|
||||
Utils::OsType BareMetalDevice::osType() const
|
||||
{
|
||||
return Utils::OsTypeOther;
|
||||
}
|
||||
|
||||
DeviceProcess *BareMetalDevice::createProcess(QObject *parent) const
|
||||
{
|
||||
return new GdbServerProviderProcess(sharedFromThis(), parent);
|
||||
|
@@ -50,6 +50,7 @@ public:
|
||||
QList<Core::Id> actionIds() const override;
|
||||
QString displayNameForActionId(Core::Id actionId) const override;
|
||||
void executeAction(Core::Id actionId, QWidget *parent) override;
|
||||
Utils::OsType osType() const override;
|
||||
ProjectExplorer::IDevice::Ptr clone() const override;
|
||||
|
||||
ProjectExplorer::DeviceProcessSignalOperation::Ptr signalOperation() const override;
|
||||
|
@@ -50,6 +50,16 @@ void Bookmark::removedFromEditor()
|
||||
m_manager->deleteBookmark(this);
|
||||
}
|
||||
|
||||
bool Bookmark::isDraggable() const
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
void Bookmark::dragToLine(int lineNumber)
|
||||
{
|
||||
move(lineNumber);
|
||||
}
|
||||
|
||||
void Bookmark::updateLineNumber(int line)
|
||||
{
|
||||
if (line != lineNumber()) {
|
||||
@@ -63,6 +73,7 @@ void Bookmark::move(int line)
|
||||
if (line != lineNumber()) {
|
||||
TextMark::move(line);
|
||||
m_manager->updateBookmark(this);
|
||||
updateMarker();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -84,6 +95,8 @@ void Bookmark::updateFileName(const QString &fileName)
|
||||
void Bookmark::setNote(const QString ¬e)
|
||||
{
|
||||
setToolTip(note);
|
||||
setLineAnnotation(note);
|
||||
updateMarker();
|
||||
}
|
||||
|
||||
void Bookmark::updateNote(const QString ¬e)
|
||||
|
@@ -43,6 +43,9 @@ public:
|
||||
void updateFileName(const QString &fileName) override;
|
||||
void removedFromEditor() override;
|
||||
|
||||
bool isDraggable() const override;
|
||||
void dragToLine(int lineNumber) override;
|
||||
|
||||
void setNote(const QString ¬e);
|
||||
void updateNote(const QString ¬e);
|
||||
|
||||
|
@@ -248,9 +248,9 @@ void IpcReceiver::references(const ReferencesMessage &message)
|
||||
QTC_CHECK(futureInterface != QFutureInterface<CppTools::CursorInfo>());
|
||||
|
||||
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.reportFinished();
|
||||
}
|
||||
|
@@ -35,6 +35,7 @@
|
||||
|
||||
#include <QFuture>
|
||||
#include <QObject>
|
||||
#include <QPointer>
|
||||
#include <QSharedPointer>
|
||||
#include <QTextDocument>
|
||||
#include <QVector>
|
||||
@@ -102,7 +103,7 @@ private:
|
||||
: futureInterface(futureInterface)
|
||||
, textDocument(textDocument) {}
|
||||
QFutureInterface<CppTools::CursorInfo> futureInterface;
|
||||
QTextDocument *textDocument = nullptr;
|
||||
QPointer<QTextDocument> textDocument;
|
||||
};
|
||||
QHash<quint64, ReferencesEntry> m_referencesTable;
|
||||
};
|
||||
|
@@ -79,6 +79,7 @@ ClangTextMark::ClangTextMark(const QString &fileName,
|
||||
setPriority(warning ? TextEditor::TextMark::NormalPriority
|
||||
: TextEditor::TextMark::HighPriority);
|
||||
setIcon(diagnostic.severity());
|
||||
setLineAnnotation(diagnostic.text().toString());
|
||||
}
|
||||
|
||||
void ClangTextMark::setIcon(ClangBackEnd::DiagnosticSeverity severity)
|
||||
@@ -96,7 +97,7 @@ void ClangTextMark::setIcon(ClangBackEnd::DiagnosticSeverity severity)
|
||||
TextMark::setIcon(errorIcon);
|
||||
}
|
||||
|
||||
bool ClangTextMark::addToolTipContent(QLayout *target)
|
||||
bool ClangTextMark::addToolTipContent(QLayout *target) const
|
||||
{
|
||||
using Internal::ClangDiagnosticWidget;
|
||||
|
||||
|
@@ -45,7 +45,7 @@ public:
|
||||
|
||||
private:
|
||||
void setIcon(ClangBackEnd::DiagnosticSeverity severity);
|
||||
bool addToolTipContent(QLayout *target) override;
|
||||
bool addToolTipContent(QLayout *target) const override;
|
||||
void removedFromEditor() override;
|
||||
|
||||
private:
|
||||
|
@@ -193,8 +193,7 @@ bool CMakeBuildStep::init(QList<const BuildStep *> &earlierSteps)
|
||||
CMakeTool *tool = CMakeKitInformation::cmakeTool(target()->kit());
|
||||
if (!tool || !tool->isValid()) {
|
||||
emit addTask(Task(Task::Error,
|
||||
QCoreApplication::translate("CMakeProjectManager::CMakeBuildStep",
|
||||
"Qt Creator needs a CMake Tool set up to build. "
|
||||
tr("Qt Creator needs a CMake Tool set up to build. "
|
||||
"Configure a CMake Tool in the kit options."),
|
||||
Utils::FileName(), -1,
|
||||
ProjectExplorer::Constants::TASK_CATEGORY_BUILDSYSTEM));
|
||||
@@ -218,6 +217,22 @@ bool CMakeBuildStep::init(QList<const BuildStep *> &earlierSteps)
|
||||
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);
|
||||
|
||||
setIgnoreReturnValue(m_buildTarget == CMakeBuildStep::cleanTarget());
|
||||
|
@@ -97,7 +97,7 @@ void CppHoverHandler::identifyMatch(TextEditorWidget *editorWidget, int pos)
|
||||
m_positionForEditorDocumentProcessor = -1;
|
||||
|
||||
if (editorDocumentProcessorHasDiagnosticAt(editorWidget, pos)) {
|
||||
setIsDiagnosticTooltip(true);
|
||||
setPriority(Priority_Diagnostic);
|
||||
m_positionForEditorDocumentProcessor = pos;
|
||||
} else if (!editorWidget->extraSelectionTooltip(pos).isEmpty()) {
|
||||
setToolTip(editorWidget->extraSelectionTooltip(pos));
|
||||
@@ -110,12 +110,14 @@ void CppHoverHandler::identifyMatch(TextEditorWidget *editorWidget, int pos)
|
||||
evaluator.execute();
|
||||
if (evaluator.hasDiagnosis()) {
|
||||
setToolTip(evaluator.diagnosis());
|
||||
setIsDiagnosticTooltip(true);
|
||||
setPriority(Priority_Diagnostic);
|
||||
}
|
||||
if (evaluator.identifiedCppElement()) {
|
||||
const QSharedPointer<CppElement> &cppElement = evaluator.cppElement();
|
||||
if (!isDiagnosticTooltip())
|
||||
if (priority() != Priority_Diagnostic) {
|
||||
setToolTip(cppElement->tooltip);
|
||||
setPriority(cppElement->tooltip.isEmpty() ? Priority_None : Priority_Tooltip);
|
||||
}
|
||||
QStringList candidates = cppElement->helpIdCandidates;
|
||||
candidates.removeDuplicates();
|
||||
foreach (const QString &helpId, candidates) {
|
||||
@@ -143,7 +145,7 @@ void CppHoverHandler::decorateToolTip()
|
||||
if (Qt::mightBeRichText(toolTip()))
|
||||
setToolTip(toolTip().toHtmlEscaped());
|
||||
|
||||
if (isDiagnosticTooltip())
|
||||
if (priority() != Priority_Diagnostic)
|
||||
return;
|
||||
|
||||
const HelpItem &help = lastHelpItemIdentified();
|
||||
|
@@ -29,6 +29,7 @@
|
||||
#include "cppeditordocument.h"
|
||||
|
||||
#include <cpptools/cpptoolsreuse.h>
|
||||
#include <texteditor/convenience.h>
|
||||
|
||||
#include <QTextBlock>
|
||||
#include <QTextCursor>
|
||||
@@ -49,6 +50,12 @@ CppUseSelectionsUpdater::CppUseSelectionsUpdater(TextEditor::TextEditorWidget *e
|
||||
connect(&m_timer, &QTimer::timeout, this, [this]() { update(); });
|
||||
}
|
||||
|
||||
CppUseSelectionsUpdater::~CppUseSelectionsUpdater()
|
||||
{
|
||||
if (m_runnerWatcher)
|
||||
m_runnerWatcher->cancel();
|
||||
}
|
||||
|
||||
void CppUseSelectionsUpdater::scheduleUpdate()
|
||||
{
|
||||
m_timer.start();
|
||||
@@ -59,23 +66,6 @@ void CppUseSelectionsUpdater::abortSchedule()
|
||||
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)
|
||||
{
|
||||
auto *cppEditorWidget = qobject_cast<CppEditorWidget *>(m_editorWidget);
|
||||
@@ -86,7 +76,7 @@ void CppUseSelectionsUpdater::update(CallType callType)
|
||||
|
||||
CppTools::CursorInfoParams params;
|
||||
params.semanticInfo = cppEditorWidget->semanticInfo();
|
||||
params.textCursor = cursorAtWordStart(cppEditorWidget->textCursor());
|
||||
params.textCursor = TextEditor::Convenience::wordStartCursor(cppEditorWidget->textCursor());
|
||||
|
||||
if (callType == Asynchronous) {
|
||||
if (isSameIdentifierAsBefore(params.textCursor))
|
||||
@@ -144,8 +134,10 @@ void CppUseSelectionsUpdater::onFindUsesFinished()
|
||||
return;
|
||||
if (m_runnerRevision != m_editorWidget->document()->revision())
|
||||
return;
|
||||
if (m_runnerWordStartPosition != cursorAtWordStart(m_editorWidget->textCursor()).position())
|
||||
if (m_runnerWordStartPosition
|
||||
!= TextEditor::Convenience::wordStartCursor(m_editorWidget->textCursor()).position()) {
|
||||
return;
|
||||
}
|
||||
|
||||
processResults(m_runnerWatcher->result());
|
||||
|
||||
|
@@ -44,6 +44,7 @@ class CppUseSelectionsUpdater : public QObject
|
||||
|
||||
public:
|
||||
explicit CppUseSelectionsUpdater(TextEditor::TextEditorWidget *editorWidget);
|
||||
~CppUseSelectionsUpdater();
|
||||
|
||||
void scheduleUpdate();
|
||||
void abortSchedule();
|
||||
|
@@ -34,8 +34,6 @@ namespace Internal {
|
||||
|
||||
class ResourcePreviewHoverHandler : public TextEditor::BaseHoverHandler
|
||||
{
|
||||
public:
|
||||
|
||||
private:
|
||||
void identifyMatch(TextEditor::TextEditorWidget *editorWidget, int pos) override;
|
||||
void operateTooltip(TextEditor::TextEditorWidget *editorWidget, const QPoint &point) override;
|
||||
|
@@ -128,19 +128,11 @@ void StartRemoteDialog::validate()
|
||||
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
|
||||
{
|
||||
Kit *kit = d->kitChooser->currentKit();
|
||||
StandardRunnable r;
|
||||
r.device = DeviceKitInformation::device(kit);
|
||||
r.executable = d->executable->text();
|
||||
r.commandLineArguments = d->arguments->text();
|
||||
r.workingDirectory = d->workingDirectory->text();
|
||||
|
@@ -28,7 +28,6 @@
|
||||
#include <debugger/debugger_global.h>
|
||||
|
||||
#include <QDialog>
|
||||
#include <QUrl>
|
||||
|
||||
namespace ProjectExplorer { class StandardRunnable; }
|
||||
|
||||
@@ -44,7 +43,6 @@ public:
|
||||
explicit StartRemoteDialog(QWidget *parent = 0);
|
||||
~StartRemoteDialog() override;
|
||||
|
||||
QUrl serverUrl() const;
|
||||
ProjectExplorer::StandardRunnable runnable() const;
|
||||
|
||||
private:
|
||||
|
@@ -468,12 +468,24 @@ static DebuggerRunConfigurationAspect *debuggerAspect(const RunControl *runContr
|
||||
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(RunControl *runControl)
|
||||
: RunWorker(runControl),
|
||||
m_isCppDebugging(debuggerAspect(runControl)->useCppDebugger()),
|
||||
m_isQmlDebugging(debuggerAspect(runControl)->useQmlDebugger())
|
||||
m_isCppDebugging(cppDebugging(runControl)),
|
||||
m_isQmlDebugging(qmlDebugging(runControl))
|
||||
{
|
||||
setDisplayName("DebuggerRunTool");
|
||||
}
|
||||
|
@@ -582,7 +582,7 @@ static QList<RowData> readLines(QStringRef patch,
|
||||
break;
|
||||
}
|
||||
|
||||
Diff diffToBeAdded(command, line.mid(1) + newLine);
|
||||
Diff diffToBeAdded(command, line.mid(1).toString() + newLine);
|
||||
|
||||
if (!diffList.isEmpty() && diffList.last().command == command)
|
||||
diffList.last().text.append(diffToBeAdded.text);
|
||||
|
@@ -66,6 +66,8 @@ BranchDialog::BranchDialog(QWidget *parent) :
|
||||
m_ui->includeOldCheckBox->setToolTip(
|
||||
tr("Include branches and tags that have not been active for %n days.", 0,
|
||||
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->addButton, &QAbstractButton::clicked, this, &BranchDialog::add);
|
||||
@@ -83,6 +85,10 @@ BranchDialog::BranchDialog(QWidget *parent) :
|
||||
m_model->setOldBranchesIncluded(value);
|
||||
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->setFocus();
|
||||
|
@@ -65,6 +65,13 @@
|
||||
</attribute>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QCheckBox" name="includeTagsCheckBox">
|
||||
<property name="text">
|
||||
<string>Include ta&gs</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QCheckBox" name="includeOldCheckBox">
|
||||
<property name="text">
|
||||
|
@@ -76,7 +76,6 @@ VcsBaseClientSettings SettingsPageWidget::settings() const
|
||||
rc.setValue(GitSettings::logCountKey, m_ui.logCountSpinBox->value());
|
||||
rc.setValue(GitSettings::timeoutKey, m_ui.timeoutSpinBox->value());
|
||||
rc.setValue(GitSettings::pullRebaseKey, m_ui.pullRebaseCheckBox->isChecked());
|
||||
rc.setValue(GitSettings::showTagsKey, m_ui.showTagsCheckBox->isChecked());
|
||||
rc.setValue(GitSettings::winSetHomeEnvironmentKey, m_ui.winHomeCheckBox->isChecked());
|
||||
rc.setValue(GitSettings::gitkOptionsKey, m_ui.gitkOptionsLineEdit->text().trimmed());
|
||||
rc.setValue(GitSettings::repositoryBrowserCmd, m_ui.repBrowserCommandPathChooser->path().trimmed());
|
||||
@@ -90,7 +89,6 @@ void SettingsPageWidget::setSettings(const VcsBaseClientSettings &s)
|
||||
m_ui.logCountSpinBox->setValue(s.intValue(GitSettings::logCountKey));
|
||||
m_ui.timeoutSpinBox->setValue(s.intValue(GitSettings::timeoutKey));
|
||||
m_ui.pullRebaseCheckBox->setChecked(s.boolValue(GitSettings::pullRebaseKey));
|
||||
m_ui.showTagsCheckBox->setChecked(s.boolValue(GitSettings::showTagsKey));
|
||||
m_ui.winHomeCheckBox->setChecked(s.boolValue(GitSettings::winSetHomeEnvironmentKey));
|
||||
m_ui.gitkOptionsLineEdit->setText(s.stringValue(GitSettings::gitkOptionsKey));
|
||||
m_ui.repBrowserCommandPathChooser->setPath(s.stringValue(GitSettings::repositoryBrowserCmd));
|
||||
|
@@ -7,7 +7,7 @@
|
||||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>705</width>
|
||||
<height>427</height>
|
||||
<height>403</height>
|
||||
</rect>
|
||||
</property>
|
||||
<layout class="QVBoxLayout" name="verticalLayout">
|
||||
@@ -123,13 +123,6 @@
|
||||
</property>
|
||||
</widget>
|
||||
</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>
|
||||
</widget>
|
||||
</item>
|
||||
@@ -214,7 +207,6 @@
|
||||
<tabstop>logCountSpinBox</tabstop>
|
||||
<tabstop>timeoutSpinBox</tabstop>
|
||||
<tabstop>pullRebaseCheckBox</tabstop>
|
||||
<tabstop>showTagsCheckBox</tabstop>
|
||||
<tabstop>gitkOptionsLineEdit</tabstop>
|
||||
</tabstops>
|
||||
<resources/>
|
||||
|
@@ -27,7 +27,6 @@
|
||||
#include "glsleditorconstants.h"
|
||||
#include "glsleditorplugin.h"
|
||||
#include "glslhighlighter.h"
|
||||
#include "glslhoverhandler.h"
|
||||
#include "glslautocompleter.h"
|
||||
#include "glslcompletionassist.h"
|
||||
#include "glslindenter.h"
|
||||
@@ -332,8 +331,6 @@ GlslEditorFactory::GlslEditorFactory()
|
||||
setEditorActionHandlers(TextEditorActionHandler::Format
|
||||
| TextEditorActionHandler::UnCommentSelection
|
||||
| TextEditorActionHandler::UnCollapseAll);
|
||||
|
||||
addHoverHandler(new GlslHoverHandler);
|
||||
}
|
||||
|
||||
} // namespace Internal
|
||||
|
@@ -10,7 +10,6 @@ glsleditorplugin.h \
|
||||
glslhighlighter.h \
|
||||
glslautocompleter.h \
|
||||
glslindenter.h \
|
||||
glslhoverhandler.h \
|
||||
glslcompletionassist.h
|
||||
|
||||
SOURCES += \
|
||||
@@ -19,7 +18,6 @@ glsleditorplugin.cpp \
|
||||
glslhighlighter.cpp \
|
||||
glslautocompleter.cpp \
|
||||
glslindenter.cpp \
|
||||
glslhoverhandler.cpp \
|
||||
glslcompletionassist.cpp
|
||||
|
||||
RESOURCES += glsleditor.qrc
|
||||
|
@@ -25,8 +25,6 @@ QtcPlugin {
|
||||
"glsleditorplugin.h",
|
||||
"glslhighlighter.cpp",
|
||||
"glslhighlighter.h",
|
||||
"glslhoverhandler.cpp",
|
||||
"glslhoverhandler.h",
|
||||
"glslindenter.cpp",
|
||||
"glslindenter.h",
|
||||
]
|
||||
|
@@ -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
|
@@ -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
|
@@ -213,6 +213,11 @@ bool IosDevice::canAutoDetectPorts() const
|
||||
return true;
|
||||
}
|
||||
|
||||
Utils::OsType IosDevice::osType() const
|
||||
{
|
||||
return Utils::OsTypeMac;
|
||||
}
|
||||
|
||||
|
||||
// IosDeviceManager
|
||||
|
||||
|
@@ -68,6 +68,7 @@ public:
|
||||
QString osVersion() const;
|
||||
Utils::Port nextPort() const;
|
||||
bool canAutoDetectPorts() const override;
|
||||
Utils::OsType osType() const override;
|
||||
|
||||
static QString name();
|
||||
|
||||
|
@@ -154,6 +154,11 @@ bool IosSimulator::canAutoDetectPorts() const
|
||||
return true;
|
||||
}
|
||||
|
||||
Utils::OsType IosSimulator::osType() const
|
||||
{
|
||||
return Utils::OsTypeMac;
|
||||
}
|
||||
|
||||
IosSimulator::ConstPtr IosKitInformation::simulator(Kit *kit)
|
||||
{
|
||||
if (!kit)
|
||||
|
@@ -77,6 +77,7 @@ public:
|
||||
QVariantMap toMap() const override;
|
||||
Utils::Port nextPort() const;
|
||||
bool canAutoDetectPorts() const override;
|
||||
Utils::OsType osType() const override;
|
||||
|
||||
ProjectExplorer::IDevice::Ptr clone() const override;
|
||||
protected:
|
||||
|
@@ -142,6 +142,11 @@ Connection DesktopDevice::toolControlChannel(const ControlChannelHint &) const
|
||||
return HostName("localhost");
|
||||
}
|
||||
|
||||
Utils::OsType DesktopDevice::osType() const
|
||||
{
|
||||
return Utils::HostOsInfo::hostOs();
|
||||
}
|
||||
|
||||
IDevice::Ptr DesktopDevice::clone() const
|
||||
{
|
||||
return Ptr(new DesktopDevice(*this));
|
||||
|
@@ -53,6 +53,7 @@ public:
|
||||
DeviceProcessSignalOperation::Ptr signalOperation() const override;
|
||||
DeviceEnvironmentFetcher::Ptr environmentFetcher() const override;
|
||||
Connection toolControlChannel(const ControlChannelHint &) const override;
|
||||
Utils::OsType osType() const override;
|
||||
|
||||
IDevice::Ptr clone() const override;
|
||||
|
||||
|
@@ -441,6 +441,7 @@ private:
|
||||
{
|
||||
return DeviceProcessSignalOperation::Ptr();
|
||||
}
|
||||
Utils::OsType osType() const override { return Utils::HostOsInfo::hostOs(); }
|
||||
};
|
||||
|
||||
void ProjectExplorerPlugin::testDeviceManager()
|
||||
|
@@ -278,6 +278,11 @@ DeviceTester *IDevice::createDeviceTester() const
|
||||
return 0;
|
||||
}
|
||||
|
||||
Utils::OsType IDevice::osType() const
|
||||
{
|
||||
return Utils::OsTypeOther;
|
||||
}
|
||||
|
||||
DeviceProcess *IDevice::createProcess(QObject * /* parent */) const
|
||||
{
|
||||
QTC_CHECK(false);
|
||||
|
@@ -28,6 +28,7 @@
|
||||
#include "../projectexplorer_export.h"
|
||||
|
||||
#include <coreplugin/id.h>
|
||||
#include <utils/hostosinfo.h>
|
||||
|
||||
#include <QAbstractSocket>
|
||||
#include <QList>
|
||||
@@ -160,6 +161,7 @@ public:
|
||||
virtual DeviceProcessList *createProcessListModel(QObject *parent = 0) const;
|
||||
virtual bool hasDeviceTester() const { return false; }
|
||||
virtual DeviceTester *createDeviceTester() const;
|
||||
virtual Utils::OsType osType() const;
|
||||
|
||||
virtual bool canCreateProcess() const { return false; }
|
||||
virtual DeviceProcess *createProcess(QObject *parent) const;
|
||||
|
@@ -44,6 +44,7 @@
|
||||
|
||||
#include <coreplugin/icore.h>
|
||||
#include <coreplugin/icontext.h>
|
||||
#include <coreplugin/messagemanager.h>
|
||||
|
||||
#include <QDir>
|
||||
#include <QPushButton>
|
||||
@@ -1178,7 +1179,7 @@ void RunControlPrivate::setState(RunControlState newState)
|
||||
|
||||
void RunControlPrivate::debugMessage(const QString &msg)
|
||||
{
|
||||
//q->appendMessage(msg + '\n', Utils::DebugFormat);
|
||||
Core::MessageManager::write(msg, Core::MessageManager::Silent);
|
||||
qCDebug(statesLog()) << msg;
|
||||
}
|
||||
|
||||
|
@@ -523,7 +523,6 @@ signals:
|
||||
void appendMessageRequested(ProjectExplorer::RunControl *runControl,
|
||||
const QString &msg, Utils::OutputFormat format);
|
||||
void aboutToStart();
|
||||
void starting();
|
||||
void started();
|
||||
void finished();
|
||||
void applicationProcessHandleChanged(QPrivateSignal); // Use setApplicationProcessHandle
|
||||
|
@@ -25,13 +25,10 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <android/androidrunfactories.h>
|
||||
#include <projectexplorer/runconfiguration.h>
|
||||
#include <qmakeprojectmanager/qmakerunconfigurationfactory.h>
|
||||
|
||||
namespace ProjectExplorer {
|
||||
class RunControl;
|
||||
class RunConfigWidget;
|
||||
class Target;
|
||||
class Node;
|
||||
} // namespace ProjectExplorer
|
||||
|
@@ -37,14 +37,9 @@ namespace Internal {
|
||||
|
||||
class ProFileHoverHandler : public TextEditor::BaseHoverHandler
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
explicit ProFileHoverHandler(const TextEditor::Keywords &keywords);
|
||||
|
||||
signals:
|
||||
void creatorHelpRequested(const QUrl &url);
|
||||
|
||||
private:
|
||||
void identifyMatch(TextEditor::TextEditorWidget *editorWidget, int pos) override;
|
||||
void identifyQMakeKeyword(const QString &text, int pos);
|
||||
|
@@ -29,6 +29,7 @@
|
||||
#include <texteditor/basehoverhandler.h>
|
||||
|
||||
#include <QColor>
|
||||
#include <QCoreApplication>
|
||||
|
||||
QT_BEGIN_NAMESPACE
|
||||
template <class> class QList;
|
||||
@@ -49,7 +50,7 @@ class QmlJSEditorWidget;
|
||||
|
||||
class QmlJSHoverHandler : public TextEditor::BaseHoverHandler
|
||||
{
|
||||
Q_OBJECT
|
||||
Q_DECLARE_TR_FUNCTIONS(QmlJSHoverHandler)
|
||||
|
||||
public:
|
||||
QmlJSHoverHandler();
|
||||
|
@@ -114,7 +114,7 @@ void QmlProfilerRunner::start()
|
||||
QUrl serverUrl = this->serverUrl();
|
||||
|
||||
if (serverUrl.port() != -1) {
|
||||
auto clientManager = Internal::QmlProfilerTool::clientManager();
|
||||
QmlProfilerClientManager *clientManager = Internal::QmlProfilerTool::clientManager();
|
||||
clientManager->setServerUrl(serverUrl);
|
||||
clientManager->connectToTcpServer();
|
||||
}
|
||||
@@ -149,6 +149,7 @@ void QmlProfilerRunner::stop()
|
||||
}
|
||||
break;
|
||||
}
|
||||
reportStopped();
|
||||
}
|
||||
|
||||
void QmlProfilerRunner::notifyRemoteFinished()
|
||||
@@ -232,6 +233,7 @@ void QmlProfilerRunner::notifyRemoteSetupDone(Utils::Port port)
|
||||
auto clientManager = Internal::QmlProfilerTool::clientManager();
|
||||
clientManager->setServerUrl(serverUrl);
|
||||
clientManager->connectToTcpServer();
|
||||
reportStarted();
|
||||
}
|
||||
}
|
||||
|
||||
|
@@ -44,7 +44,7 @@ void QmlProfilerTextMark::addTypeId(int 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->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;
|
||||
layout->setHorizontalSpacing(10);
|
||||
|
@@ -37,10 +37,10 @@ public:
|
||||
QmlProfilerTextMark(QmlProfilerTool *tool, int typeId, const QString &fileName, int lineNumber);
|
||||
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;
|
||||
bool isClickable() const override { return true; }
|
||||
bool addToolTipContent(QLayout *target) override;
|
||||
bool addToolTipContent(QLayout *target) const override;
|
||||
|
||||
private:
|
||||
QmlProfilerTool *m_tool;
|
||||
|
@@ -122,6 +122,11 @@ QString QnxDevice::displayType() const
|
||||
return tr("QNX");
|
||||
}
|
||||
|
||||
OsType QnxDevice::osType() const
|
||||
{
|
||||
return OsTypeOtherUnix;
|
||||
}
|
||||
|
||||
int QnxDevice::qnxVersion() const
|
||||
{
|
||||
if (m_versionNumber == 0)
|
||||
|
@@ -56,6 +56,7 @@ public:
|
||||
void executeAction(Core::Id actionId, QWidget *parent) override;
|
||||
|
||||
QString displayType() const override;
|
||||
Utils::OsType osType() const override;
|
||||
|
||||
int qnxVersion() const;
|
||||
|
||||
|
@@ -203,6 +203,11 @@ void LinuxDevice::executeAction(Core::Id actionId, QWidget *parent)
|
||||
delete d;
|
||||
}
|
||||
|
||||
Utils::OsType LinuxDevice::osType() const
|
||||
{
|
||||
return Utils::OsTypeLinux;
|
||||
}
|
||||
|
||||
LinuxDevice::LinuxDevice(const QString &name, Core::Id type, MachineType machineType,
|
||||
Origin origin, Core::Id id)
|
||||
: IDevice(type, origin, machineType, id)
|
||||
|
@@ -54,6 +54,7 @@ public:
|
||||
QList<Core::Id> actionIds() const;
|
||||
QString displayNameForActionId(Core::Id actionId) const;
|
||||
void executeAction(Core::Id actionId, QWidget *parent);
|
||||
Utils::OsType osType() const override;
|
||||
ProjectExplorer::IDevice::Ptr clone() const;
|
||||
|
||||
bool canCreateProcess() const { return true; }
|
||||
|
@@ -26,27 +26,17 @@
|
||||
#include "basehoverhandler.h"
|
||||
#include "texteditor.h"
|
||||
|
||||
#include <coreplugin/icore.h>
|
||||
#include <utils/tooltip/tooltip.h>
|
||||
|
||||
#include <QPoint>
|
||||
|
||||
using namespace Core;
|
||||
|
||||
namespace TextEditor {
|
||||
|
||||
BaseHoverHandler::BaseHoverHandler() : m_diagnosticTooltip(false), m_priority(-1)
|
||||
{
|
||||
}
|
||||
|
||||
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());
|
||||
|
||||
process(widget, pos);
|
||||
if (decorate)
|
||||
decorateToolTip();
|
||||
operateTooltip(widget, point);
|
||||
}
|
||||
|
||||
@@ -64,9 +54,6 @@ int BaseHoverHandler::priority() const
|
||||
if (m_priority >= 0)
|
||||
return m_priority;
|
||||
|
||||
if (isDiagnosticTooltip())
|
||||
return Priority_Diagnostic;
|
||||
|
||||
if (lastHelpItemIdentified().isValid())
|
||||
return Priority_Help;
|
||||
|
||||
@@ -103,21 +90,6 @@ const QString &BaseHoverHandler::toolTip() const
|
||||
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)
|
||||
{
|
||||
m_lastHelpItemIdentified = help;
|
||||
@@ -128,19 +100,13 @@ const HelpItem &BaseHoverHandler::lastHelpItemIdentified() const
|
||||
return m_lastHelpItemIdentified;
|
||||
}
|
||||
|
||||
void BaseHoverHandler::clear()
|
||||
void BaseHoverHandler::process(TextEditorWidget *widget, int pos)
|
||||
{
|
||||
m_diagnosticTooltip = false;
|
||||
m_toolTip.clear();
|
||||
m_priority = -1;
|
||||
m_lastHelpItemIdentified = HelpItem();
|
||||
}
|
||||
|
||||
void BaseHoverHandler::process(TextEditorWidget *widget, int pos)
|
||||
{
|
||||
clear();
|
||||
identifyMatch(widget, pos);
|
||||
decorateToolTip();
|
||||
}
|
||||
|
||||
void BaseHoverHandler::identifyMatch(TextEditorWidget *editorWidget, int pos)
|
||||
@@ -155,11 +121,11 @@ void BaseHoverHandler::decorateToolTip()
|
||||
if (Qt::mightBeRichText(toolTip()))
|
||||
setToolTip(toolTip().toHtmlEscaped());
|
||||
|
||||
if (!isDiagnosticTooltip() && lastHelpItemIdentified().isValid()) {
|
||||
if (priority() != Priority_Diagnostic && lastHelpItemIdentified().isValid()) {
|
||||
const QString &contents = lastHelpItemIdentified().extractContent(false);
|
||||
if (!contents.isEmpty()) {
|
||||
setToolTip(toolTip().toHtmlEscaped());
|
||||
appendToolTip(contents);
|
||||
m_toolTip = toolTip().toHtmlEscaped();
|
||||
m_toolTip.append(contents);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@@ -28,43 +28,25 @@
|
||||
#include "texteditor_global.h"
|
||||
#include "helpitem.h"
|
||||
|
||||
#include <QObject>
|
||||
|
||||
namespace Core { class IEditor; }
|
||||
QT_BEGIN_NAMESPACE
|
||||
class QPoint;
|
||||
QT_END_NAMESPACE
|
||||
|
||||
namespace TextEditor {
|
||||
|
||||
class BaseTextEditor;
|
||||
class TextEditorWidget;
|
||||
|
||||
class TEXTEDITOR_EXPORT BaseHoverHandler : public QObject
|
||||
class TEXTEDITOR_EXPORT BaseHoverHandler
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
BaseHoverHandler();
|
||||
~BaseHoverHandler();
|
||||
virtual ~BaseHoverHandler();
|
||||
|
||||
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:
|
||||
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 {
|
||||
Priority_None = 0,
|
||||
Priority_Tooltip = 5,
|
||||
@@ -72,16 +54,24 @@ protected:
|
||||
Priority_Diagnostic = 20
|
||||
};
|
||||
void setPriority(int priority);
|
||||
private:
|
||||
void clear();
|
||||
void process(TextEditorWidget *widget, int pos);
|
||||
int priority() const;
|
||||
|
||||
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 decorateToolTip();
|
||||
virtual void operateTooltip(TextEditorWidget *editorWidget, const QPoint &point);
|
||||
|
||||
private:
|
||||
void process(TextEditorWidget *widget, int pos);
|
||||
|
||||
bool m_diagnosticTooltip;
|
||||
QString m_toolTip;
|
||||
HelpItem m_lastHelpItemIdentified;
|
||||
int m_priority;
|
||||
int m_priority = -1;
|
||||
};
|
||||
|
||||
} // namespace TextEditor
|
||||
|
@@ -38,9 +38,6 @@ class TextEditorWidget;
|
||||
|
||||
class TEXTEDITOR_EXPORT ColorPreviewHoverHandler : public BaseHoverHandler
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
|
||||
private:
|
||||
void identifyMatch(TextEditorWidget *editorWidget, int pos) override;
|
||||
void operateTooltip(TextEditorWidget *editorWidget, const QPoint &point) override;
|
||||
|
@@ -86,5 +86,31 @@ QTextCursor flippedCursor(const QTextCursor &cursor)
|
||||
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
|
||||
} // TextEditor
|
||||
|
@@ -47,5 +47,7 @@ TEXTEDITOR_EXPORT QTextCursor selectAt(QTextCursor textCursor, uint line, uint c
|
||||
|
||||
TEXTEDITOR_EXPORT QTextCursor flippedCursor(const QTextCursor &cursor);
|
||||
|
||||
TEXTEDITOR_EXPORT QTextCursor wordStartCursor(const QTextCursor &cursor);
|
||||
|
||||
} // Util
|
||||
} // TextEditor
|
||||
|
@@ -44,6 +44,7 @@ static const char displayFileEncodingKey[] = "DisplayFileEncoding";
|
||||
static const char scrollBarHighlightsKey[] = "ScrollBarHighlights";
|
||||
static const char animateNavigationWithinFileKey[] = "AnimateNavigationWithinFile";
|
||||
static const char animateWithinFileTimeMaxKey[] = "AnimateWithinFileTimeMax";
|
||||
static const char displayAnnotationsKey[] = "DisplayAnnotations";
|
||||
static const char groupPostfix[] = "DisplaySettings";
|
||||
|
||||
namespace TextEditor {
|
||||
@@ -69,6 +70,7 @@ void DisplaySettings::toSettings(const QString &category, QSettings *s) const
|
||||
s->setValue(QLatin1String(displayFileEncodingKey), m_displayFileEncoding);
|
||||
s->setValue(QLatin1String(scrollBarHighlightsKey), m_scrollBarHighlights);
|
||||
s->setValue(QLatin1String(animateNavigationWithinFileKey), m_animateNavigationWithinFile);
|
||||
s->setValue(QLatin1String(displayAnnotationsKey), m_displayAnnotations);
|
||||
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_animateNavigationWithinFile = s->value(group + QLatin1String(animateNavigationWithinFileKey), m_animateNavigationWithinFile).toBool();
|
||||
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
|
||||
@@ -118,6 +121,7 @@ bool DisplaySettings::equals(const DisplaySettings &ds) const
|
||||
&& m_scrollBarHighlights == ds.m_scrollBarHighlights
|
||||
&& m_animateNavigationWithinFile == ds.m_animateNavigationWithinFile
|
||||
&& m_animateWithinFileTimeMax == ds.m_animateWithinFileTimeMax
|
||||
&& m_displayAnnotations == ds.m_displayAnnotations
|
||||
;
|
||||
}
|
||||
|
||||
|
@@ -58,6 +58,7 @@ public:
|
||||
bool m_scrollBarHighlights = true;
|
||||
bool m_animateNavigationWithinFile = false;
|
||||
int m_animateWithinFileTimeMax = 333; // read only setting
|
||||
bool m_displayAnnotations = true;
|
||||
|
||||
bool equals(const DisplaySettings &ds) const;
|
||||
};
|
||||
|
@@ -119,6 +119,7 @@ void DisplaySettingsPage::settingsFromUI(DisplaySettings &displaySettings,
|
||||
displaySettings.m_displayFileEncoding = d->m_page->displayFileEncoding->isChecked();
|
||||
displaySettings.m_scrollBarHighlights = d->m_page->scrollBarHighlights->isChecked();
|
||||
displaySettings.m_animateNavigationWithinFile = d->m_page->animateNavigationWithinFile->isChecked();
|
||||
displaySettings.m_displayAnnotations = d->m_page->displayAnnotations->isChecked();
|
||||
}
|
||||
|
||||
void DisplaySettingsPage::settingsToUI()
|
||||
@@ -142,6 +143,7 @@ void DisplaySettingsPage::settingsToUI()
|
||||
d->m_page->displayFileEncoding->setChecked(displaySettings.m_displayFileEncoding);
|
||||
d->m_page->scrollBarHighlights->setChecked(displaySettings.m_scrollBarHighlights);
|
||||
d->m_page->animateNavigationWithinFile->setChecked(displaySettings.m_animateNavigationWithinFile);
|
||||
d->m_page->displayAnnotations->setChecked(displaySettings.m_displayAnnotations);
|
||||
}
|
||||
|
||||
const DisplaySettings &DisplaySettingsPage::displaySettings() const
|
||||
|
@@ -80,17 +80,10 @@
|
||||
<string>Display</string>
|
||||
</property>
|
||||
<layout class="QGridLayout" name="gridLayout_2">
|
||||
<item row="1" column="0">
|
||||
<widget class="QCheckBox" name="displayFoldingMarkers">
|
||||
<item row="4" column="1">
|
||||
<widget class="QCheckBox" name="highlightMatchingParentheses">
|
||||
<property name="text">
|
||||
<string>Display &folding markers</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="5" column="0">
|
||||
<widget class="QCheckBox" name="centerOnScroll">
|
||||
<property name="text">
|
||||
<string>Center &cursor on scroll</string>
|
||||
<string>&Highlight matching parentheses</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
@@ -101,20 +94,6 @@
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="6" column="0">
|
||||
<widget class="QCheckBox" name="autoFoldFirstComment">
|
||||
<property name="text">
|
||||
<string>Auto-fold first &comment</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="2" column="1">
|
||||
<widget class="QCheckBox" name="animateMatchingParentheses">
|
||||
<property name="text">
|
||||
<string>&Animate matching parentheses</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="0" column="1">
|
||||
<widget class="QCheckBox" name="highlightCurrentLine">
|
||||
<property name="text">
|
||||
@@ -129,6 +108,20 @@
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="6" column="0">
|
||||
<widget class="QCheckBox" name="autoFoldFirstComment">
|
||||
<property name="text">
|
||||
<string>Auto-fold first &comment</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="2" column="1">
|
||||
<widget class="QCheckBox" name="animateMatchingParentheses">
|
||||
<property name="text">
|
||||
<string>&Animate matching parentheses</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="5" column="1">
|
||||
<widget class="QCheckBox" name="openLinksInNextSplit">
|
||||
<property name="text">
|
||||
@@ -143,6 +136,13 @@
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="5" column="0">
|
||||
<widget class="QCheckBox" name="centerOnScroll">
|
||||
<property name="text">
|
||||
<string>Center &cursor on scroll</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="4" column="0">
|
||||
<widget class="QCheckBox" name="visualizeWhitespace">
|
||||
<property name="toolTip">
|
||||
@@ -153,17 +153,17 @@
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="4" column="1">
|
||||
<widget class="QCheckBox" name="highlightMatchingParentheses">
|
||||
<item row="1" column="0">
|
||||
<widget class="QCheckBox" name="displayFoldingMarkers">
|
||||
<property name="text">
|
||||
<string>&Highlight matching parentheses</string>
|
||||
<string>Display &folding markers</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="2" column="0">
|
||||
<widget class="QCheckBox" name="markTextChanges">
|
||||
<item row="7" column="1">
|
||||
<widget class="QCheckBox" name="animateNavigationWithinFile">
|
||||
<property name="text">
|
||||
<string>Mark &text changes</string>
|
||||
<string>Animate navigation within file</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
@@ -174,10 +174,17 @@
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="7" column="1">
|
||||
<widget class="QCheckBox" name="animateNavigationWithinFile">
|
||||
<item row="2" column="0">
|
||||
<widget class="QCheckBox" name="markTextChanges">
|
||||
<property name="text">
|
||||
<string>Animate navigation within file</string>
|
||||
<string>Mark &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>
|
||||
</widget>
|
||||
</item>
|
||||
@@ -197,12 +204,14 @@
|
||||
<tabstop>centerOnScroll</tabstop>
|
||||
<tabstop>autoFoldFirstComment</tabstop>
|
||||
<tabstop>scrollBarHighlights</tabstop>
|
||||
<tabstop>displayAnnotations</tabstop>
|
||||
<tabstop>highlightCurrentLine</tabstop>
|
||||
<tabstop>highlightBlocks</tabstop>
|
||||
<tabstop>animateMatchingParentheses</tabstop>
|
||||
<tabstop>highlightMatchingParentheses</tabstop>
|
||||
<tabstop>openLinksInNextSplit</tabstop>
|
||||
<tabstop>displayFileEncoding</tabstop>
|
||||
<tabstop>animateNavigationWithinFile</tabstop>
|
||||
</tabstops>
|
||||
<resources/>
|
||||
<connections>
|
||||
|
@@ -845,6 +845,13 @@ void TextDocument::modificationChanged(bool modified)
|
||||
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
|
||||
{
|
||||
return d->m_marksCache;
|
||||
@@ -953,6 +960,7 @@ void TextDocument::removeMark(TextMark *mark)
|
||||
|
||||
removeMarkFromMarksCache(mark);
|
||||
mark->setBaseTextDocument(0);
|
||||
updateLayout();
|
||||
}
|
||||
|
||||
void TextDocument::updateMark(TextMark *mark)
|
||||
@@ -964,9 +972,7 @@ void TextDocument::updateMark(TextMark *mark)
|
||||
userData->removeMark(mark);
|
||||
userData->addMark(mark);
|
||||
}
|
||||
auto documentLayout = qobject_cast<TextDocumentLayout*>(d->m_document.documentLayout());
|
||||
QTC_ASSERT(documentLayout, return);
|
||||
documentLayout->requestUpdate();
|
||||
updateLayout();
|
||||
}
|
||||
|
||||
void TextDocument::moveMark(TextMark *mark, int previousLine)
|
||||
|
@@ -154,6 +154,7 @@ private:
|
||||
void cleanWhitespace(QTextCursor &cursor, bool cleanIndentation, bool inEntireDocument);
|
||||
void ensureFinalNewLine(QTextCursor &cursor);
|
||||
void modificationChanged(bool modified);
|
||||
void updateLayout() const;
|
||||
|
||||
TextDocumentPrivate *d;
|
||||
};
|
||||
|
@@ -73,6 +73,8 @@
|
||||
#include <coreplugin/manhattanstyle.h>
|
||||
#include <coreplugin/find/basetextfind.h>
|
||||
#include <coreplugin/find/highlightscrollbar.h>
|
||||
#include <utils/algorithm.h>
|
||||
#include <utils/asconst.h>
|
||||
#include <utils/linecolumnlabel.h>
|
||||
#include <utils/fileutils.h>
|
||||
#include <utils/dropsupport.h>
|
||||
@@ -278,6 +280,7 @@ public:
|
||||
bool expanded,
|
||||
bool active,
|
||||
bool hovered) const;
|
||||
void drawLineAnnotation(QPainter &painter, const QTextBlock &block);
|
||||
|
||||
void toggleBlockVisible(const QTextBlock &block);
|
||||
QRect foldBox();
|
||||
@@ -296,6 +299,7 @@ public:
|
||||
bool camelCaseLeft(QTextCursor &cursor, QTextCursor::MoveMode mode);
|
||||
|
||||
void processTooltipRequest(const QTextCursor &c);
|
||||
bool processAnnotaionTooltipRequest(const QTextBlock &block, const QPoint &pos) const;
|
||||
|
||||
void transformSelection(TransformationMethod method);
|
||||
void transformBlockSelection(TransformationMethod method);
|
||||
@@ -383,6 +387,13 @@ public:
|
||||
bool snippetCheckCursor(const QTextCursor &cursor);
|
||||
void snippetTabOrBacktab(bool forward);
|
||||
|
||||
struct AnnotationRect
|
||||
{
|
||||
QRectF rect;
|
||||
const TextMark *mark;
|
||||
};
|
||||
QMap<int, QList<AnnotationRect>> m_annotationRects;
|
||||
|
||||
RefactorOverlay *m_refactorOverlay = nullptr;
|
||||
QString m_contextHelpId;
|
||||
|
||||
@@ -457,6 +468,26 @@ public:
|
||||
|
||||
CodeAssistant m_codeAssistant;
|
||||
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
|
||||
|
||||
QPointer<QSequentialAnimationGroup> m_navigationAnimation;
|
||||
@@ -470,7 +501,8 @@ public:
|
||||
bool m_skipAutoCompletedText = true;
|
||||
bool m_removeAutoCompletedText = true;
|
||||
bool m_keepAutoCompletionHighlight = false;
|
||||
QTextCursor m_autoCompleteHighlightPos;
|
||||
QList<QTextCursor> m_autoCompleteHighlightPos;
|
||||
void updateAutoCompleteHighlight();
|
||||
|
||||
int m_cursorBlockNumber = -1;
|
||||
int m_blockCount = 0;
|
||||
@@ -943,6 +975,21 @@ int TextEditorWidgetPrivate::visualIndent(const QTextBlock &block) const
|
||||
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()
|
||||
{
|
||||
TextDocument *doc = d->m_document.data();
|
||||
@@ -2366,8 +2413,10 @@ void TextEditorWidget::keyPressEvent(QKeyEvent *e)
|
||||
QTextCursor cursor = textCursor();
|
||||
QString autoText;
|
||||
if (!inOverwriteMode) {
|
||||
autoText = autoCompleter()->autoComplete(cursor, eventText,
|
||||
d->m_skipAutoCompletedText && cursor == d->m_autoCompleteHighlightPos);
|
||||
const bool skipChar = d->m_skipAutoCompletedText
|
||||
&& !d->m_autoCompleteHighlightPos.isEmpty()
|
||||
&& cursor == d->m_autoCompleteHighlightPos.last();
|
||||
autoText = autoCompleter()->autoComplete(cursor, eventText, skipChar);
|
||||
}
|
||||
const bool cursorWithinSnippet = d->snippetCheckCursor(cursor);
|
||||
|
||||
@@ -3132,6 +3181,15 @@ void TextEditorWidgetPrivate::processTooltipRequest(const QTextCursor &c)
|
||||
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;
|
||||
BaseHoverHandler *highest = 0;
|
||||
foreach (BaseHoverHandler *handler, m_hoverHandlers) {
|
||||
@@ -3142,8 +3200,47 @@ void TextEditorWidgetPrivate::processTooltipRequest(const QTextCursor &c)
|
||||
}
|
||||
}
|
||||
|
||||
if (highest)
|
||||
highest->showToolTip(q, toolTipPoint, c.position());
|
||||
// Let the best handler show the tooltip
|
||||
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)
|
||||
@@ -3173,10 +3270,14 @@ bool TextEditorWidget::viewportEvent(QEvent *event)
|
||||
QTC_CHECK(line.isValid());
|
||||
// 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.
|
||||
if (line.isValid()
|
||||
&& pos.x() <= blockBoundingGeometry(block).left() + line.naturalTextRect().right()) {
|
||||
if (line.isValid()) {
|
||||
if (pos.x() <= blockBoundingGeometry(block).left() + line.naturalTextRect().right()) {
|
||||
d->processTooltipRequest(tc);
|
||||
return true;
|
||||
} else if (d->processAnnotaionTooltipRequest(block, pos)) {
|
||||
return true;
|
||||
}
|
||||
ToolTip::hide();
|
||||
}
|
||||
}
|
||||
return QPlainTextEdit::viewportEvent(event);
|
||||
@@ -3613,6 +3714,52 @@ static QTextLayout::FormatRange createBlockCursorCharFormatRange(int pos, const
|
||||
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)
|
||||
{
|
||||
// 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;
|
||||
QPen cursor_pen;
|
||||
|
||||
d->m_annotationRects.clear();
|
||||
d->m_searchResultOverlay->clear();
|
||||
if (!d->m_searchExpr.isEmpty()) { // first pass for the search result overlays
|
||||
|
||||
@@ -4253,6 +4401,7 @@ void TextEditorWidget::paintEvent(QPaintEvent *e)
|
||||
painter.restore();
|
||||
}
|
||||
}
|
||||
d->drawLineAnnotation(painter, block);
|
||||
|
||||
block = nextVisibleBlock;
|
||||
top = bottom;
|
||||
@@ -4538,7 +4687,7 @@ void TextEditorWidget::extraAreaPaintEvent(QPaintEvent *e)
|
||||
const int height = fmLineSpacing - 1;
|
||||
const int width = int(.5 + height * mark->widthFactor());
|
||||
const QRect r(xoffset, top, width, height);
|
||||
mark->paint(&painter, r);
|
||||
mark->paintIcon(&painter, r);
|
||||
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](){
|
||||
if ((!m_keepAutoCompletionHighlight && !q->hasFocus())
|
||||
|| m_autoCompleteHighlightPos != q->textCursor()) {
|
||||
q->setExtraSelections(TextEditorWidget::AutoCompleteSelection,
|
||||
QList<QTextEdit::ExtraSelection>()); // clear
|
||||
m_autoCompleteHighlightPos = QTextCursor();
|
||||
const QTextCursor &cursor = q->textCursor();
|
||||
auto popAutoCompletion = [&]() {
|
||||
return !m_autoCompleteHighlightPos.isEmpty()
|
||||
&& m_autoCompleteHighlightPos.last() != cursor;
|
||||
};
|
||||
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 TypingSettings &typingSettings = m_document->typingSettings();
|
||||
|
||||
if (typingSettings.m_autoIndent && (m_autoCompleteHighlightPos == cursor)
|
||||
&& m_removeAutoCompletedText && m_autoCompleter->autoBackspace(cursor)) {
|
||||
if (typingSettings.m_autoIndent
|
||||
&& !m_autoCompleteHighlightPos.isEmpty()
|
||||
&& (m_autoCompleteHighlightPos.last() == cursor)
|
||||
&& m_removeAutoCompletedText
|
||||
&& m_autoCompleter->autoBackspace(cursor)) {
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -6082,25 +6238,14 @@ void TextEditorWidgetPrivate::_q_highlightBlocks()
|
||||
|
||||
void TextEditorWidgetPrivate::autocompleterHighlight(const QTextCursor &cursor)
|
||||
{
|
||||
QList<QTextEdit::ExtraSelection> extraSelections;
|
||||
if ((!m_animateAutoComplete && !m_highlightAutoComplete)
|
||||
|| q->isReadOnly() || !cursor.hasSelection()) {
|
||||
q->setExtraSelections(TextEditorWidget::AutoCompleteSelection, extraSelections); // clear
|
||||
return;
|
||||
}
|
||||
|
||||
m_autoCompleteHighlightPos.clear();
|
||||
} else if (m_highlightAutoComplete) {
|
||||
m_autoCompleteHighlightPos.push_back(cursor);
|
||||
} else if (m_animateAutoComplete) {
|
||||
const QTextCharFormat &matchFormat
|
||||
= 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
|
||||
QPalette pal;
|
||||
pal.setBrush(QPalette::Text, matchFormat.foreground());
|
||||
@@ -6110,7 +6255,7 @@ void TextEditorWidgetPrivate::autocompleterHighlight(const QTextCursor &cursor)
|
||||
connect(m_autocompleteAnimator.data(), &TextEditorAnimator::updateRequest,
|
||||
this, &TextEditorWidgetPrivate::_q_animateUpdate);
|
||||
}
|
||||
q->setExtraSelections(TextEditorWidget::AutoCompleteSelection, extraSelections);
|
||||
updateAutoCompleteHighlight();
|
||||
}
|
||||
|
||||
void TextEditorWidgetPrivate::updateAnimator(QPointer<TextEditorAnimator> animator,
|
||||
@@ -8060,7 +8205,11 @@ IEditor *BaseTextEditor::duplicate()
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
} // namespace TextEditor
|
||||
|
||||
uint qHash(const QColor &color)
|
||||
{
|
||||
return color.rgba();
|
||||
}
|
||||
|
||||
#include "texteditor.moc"
|
||||
|
@@ -672,4 +672,6 @@ private:
|
||||
|
||||
} // namespace TextEditor
|
||||
|
||||
uint qHash(const QColor &color);
|
||||
|
||||
Q_DECLARE_METATYPE(TextEditor::TextEditorWidget::Link)
|
||||
|
@@ -33,6 +33,7 @@
|
||||
#include <utils/qtcassert.h>
|
||||
|
||||
#include <QGridLayout>
|
||||
#include <QPainter>
|
||||
|
||||
using namespace Core;
|
||||
using namespace Utils;
|
||||
@@ -57,6 +58,24 @@ private:
|
||||
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;
|
||||
|
||||
TextMark::TextMark(const QString &fileName, int lineNumber, Id category, double widthFactor)
|
||||
@@ -99,11 +118,49 @@ int TextMark::lineNumber() const
|
||||
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);
|
||||
}
|
||||
|
||||
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)
|
||||
{
|
||||
m_lineNumber = lineNumber;
|
||||
@@ -176,7 +233,7 @@ void TextMark::dragToLine(int lineNumber)
|
||||
Q_UNUSED(lineNumber);
|
||||
}
|
||||
|
||||
void TextMark::addToToolTipLayout(QGridLayout *target)
|
||||
void TextMark::addToToolTipLayout(QGridLayout *target) const
|
||||
{
|
||||
auto *contentLayout = new QVBoxLayout;
|
||||
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;
|
||||
if (text.isEmpty()) {
|
||||
@@ -304,6 +361,33 @@ void TextMarkRegistry::allDocumentsRenamed(const QString &oldName, const QString
|
||||
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
|
||||
|
||||
#include "textmark.moc"
|
||||
|
@@ -63,7 +63,8 @@ public:
|
||||
QString fileName() 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
|
||||
virtual void updateFileName(const QString &fileName);
|
||||
virtual void updateLineNumber(int lineNumber);
|
||||
@@ -74,8 +75,8 @@ public:
|
||||
virtual void clicked();
|
||||
virtual bool isDraggable() const;
|
||||
virtual void dragToLine(int lineNumber);
|
||||
void addToToolTipLayout(QGridLayout *target);
|
||||
virtual bool addToolTipContent(QLayout *target);
|
||||
void addToToolTipLayout(QGridLayout *target) const;
|
||||
virtual bool addToolTipContent(QLayout *target) const;
|
||||
|
||||
void setIcon(const QIcon &icon) { m_icon = icon; }
|
||||
const QIcon &icon() const { return m_icon; }
|
||||
@@ -99,6 +100,9 @@ public:
|
||||
TextDocument *baseTextDocument() const { return m_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; }
|
||||
void setToolTip(const QString &toolTip) { m_toolTip = toolTip; }
|
||||
|
||||
@@ -115,6 +119,7 @@ private:
|
||||
bool m_hasColor = false;
|
||||
Core::Id m_category;
|
||||
double m_widthFactor = 1.0;
|
||||
QString m_lineAnnotation;
|
||||
QString m_toolTip;
|
||||
QString m_defaultToolTip;
|
||||
};
|
||||
|
@@ -24,28 +24,31 @@
|
||||
****************************************************************************/
|
||||
|
||||
#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 <QDir>
|
||||
|
||||
#include <utils/hostosinfo.h>
|
||||
#include <utils/qtcassert.h>
|
||||
#include <utils/temporaryfile.h>
|
||||
#include <ssh/sftpchannel.h>
|
||||
#include <QEventLoop>
|
||||
|
||||
#define CALLGRIND_CONTROL_DEBUG 0
|
||||
|
||||
const QLatin1String CALLGRIND_CONTROL_BINARY("callgrind_control");
|
||||
using namespace ProjectExplorer;
|
||||
using namespace Utils;
|
||||
|
||||
namespace Valgrind {
|
||||
namespace Callgrind {
|
||||
|
||||
CallgrindController::CallgrindController(QObject *parent)
|
||||
: QObject(parent)
|
||||
, m_process(0)
|
||||
, m_valgrindProc(0)
|
||||
, m_lastOption(Unknown)
|
||||
const QLatin1String CALLGRIND_CONTROL_BINARY("callgrind_control");
|
||||
|
||||
CallgrindController::CallgrindController()
|
||||
{
|
||||
}
|
||||
|
||||
@@ -54,7 +57,7 @@ CallgrindController::~CallgrindController()
|
||||
cleanupTempFile();
|
||||
}
|
||||
|
||||
QString toOptionString(CallgrindController::Option option)
|
||||
static QString toOptionString(CallgrindController::Option option)
|
||||
{
|
||||
/* callgrind_control help from v3.9.0
|
||||
|
||||
@@ -86,23 +89,15 @@ QString toOptionString(CallgrindController::Option option)
|
||||
|
||||
void CallgrindController::run(Option option)
|
||||
{
|
||||
if (m_process) {
|
||||
if (m_controllerProcess) {
|
||||
emit statusMessage(tr("Previous command has not yet finished."));
|
||||
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
|
||||
m_lastOption = option;
|
||||
|
||||
const QString optionString = toOptionString(option);
|
||||
m_controllerProcess = new ApplicationLauncher;
|
||||
|
||||
switch (option) {
|
||||
case CallgrindController::Dump:
|
||||
@@ -122,31 +117,49 @@ void CallgrindController::run(Option option)
|
||||
}
|
||||
|
||||
#if CALLGRIND_CONTROL_DEBUG
|
||||
m_process->setProcessChannelMode(QProcess::ForwardedChannels);
|
||||
m_controllerProcess->setProcessChannelMode(QProcess::ForwardedChannels);
|
||||
#endif
|
||||
const int pid = Utils::HostOsInfo::isWindowsHost() ? 0 : m_valgrindProc->pid();
|
||||
m_process->setValgrindExecutable(CALLGRIND_CONTROL_BINARY);
|
||||
m_process->setValgrindArguments(QStringList() << optionString << QString::number(pid));
|
||||
m_process->run(ProjectExplorer::ApplicationLauncher::Gui);
|
||||
connect(m_controllerProcess, &ApplicationLauncher::processExited,
|
||||
this, &CallgrindController::controllerProcessFinished);
|
||||
connect(m_controllerProcess, &ApplicationLauncher::error,
|
||||
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);
|
||||
const QString error = m_process->errorString();
|
||||
m_pid = pid;
|
||||
}
|
||||
|
||||
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));
|
||||
|
||||
m_process->deleteLater();
|
||||
m_process = 0;
|
||||
m_controllerProcess->deleteLater();
|
||||
m_controllerProcess = nullptr;
|
||||
}
|
||||
|
||||
void CallgrindController::processFinished(int rc, QProcess::ExitStatus status)
|
||||
void CallgrindController::controllerProcessFinished(int rc, QProcess::ExitStatus status)
|
||||
{
|
||||
QTC_ASSERT(m_process, return);
|
||||
const QString error = m_process->errorString();
|
||||
QTC_ASSERT(m_controllerProcess, return);
|
||||
const QString error = m_controllerProcess->errorString();
|
||||
|
||||
m_process->deleteLater(); // Called directly from finished() signal in m_process
|
||||
m_process = 0;
|
||||
m_controllerProcess->deleteLater(); // Called directly from finished() signal in m_process
|
||||
m_controllerProcess = nullptr;
|
||||
|
||||
if (rc != 0 || status != QProcess::NormalExit) {
|
||||
qWarning() << "Controller exited abnormally:" << error;
|
||||
@@ -175,32 +188,43 @@ void CallgrindController::processFinished(int rc, QProcess::ExitStatus status)
|
||||
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()
|
||||
{
|
||||
QTC_ASSERT(m_valgrindProc, return);
|
||||
|
||||
// we look for callgrind.out.PID, but there may be updated ones called ~.PID.NUM
|
||||
QString baseFileName = QString::fromLatin1("callgrind.out.%1").
|
||||
arg(m_valgrindProc->pid());
|
||||
const QString workingDir = m_valgrindProc->workingDirectory();
|
||||
const QString baseFileName = QString("callgrind.out.%1").arg(m_pid);
|
||||
const QString workingDir = m_valgrindRunnable.workingDirectory;
|
||||
// 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()) {
|
||||
///TODO: error handling
|
||||
emit statusMessage(tr("Downloading remote profile data..."));
|
||||
m_ssh = m_valgrindProc->connection();
|
||||
// if there are files like callgrind.out.PID.NUM, set it to the most recent one of those
|
||||
QString cmd = QString::fromLatin1("ls -t %1* | head -n 1").arg(fileName);
|
||||
m_findRemoteFile = m_ssh->createRemoteProcess(cmd.toUtf8());
|
||||
connect(m_findRemoteFile.data(), &QSsh::SshRemoteProcess::readyReadStandardOutput,
|
||||
this, &CallgrindController::foundRemoteFile);
|
||||
m_findRemoteFile->start();
|
||||
if (m_valgrindRunnable.device
|
||||
&& m_valgrindRunnable.device->type() != ProjectExplorer::Constants::DESKTOP_DEVICE_TYPE) {
|
||||
// ///TODO: error handling
|
||||
// emit statusMessage(tr("Downloading remote profile data..."));
|
||||
// m_ssh = m_valgrindProc->connection();
|
||||
// // if there are files like callgrind.out.PID.NUM, set it to the most recent one of those
|
||||
// QString cmd = QString::fromLatin1("ls -t %1* | head -n 1").arg(fileName);
|
||||
// m_findRemoteFile = m_ssh->createRemoteProcess(cmd.toUtf8());
|
||||
// connect(m_findRemoteFile.data(), &QSsh::SshRemoteProcess::readyReadStandardOutput,
|
||||
// this, &CallgrindController::foundRemoteFile);
|
||||
// m_findRemoteFile->start();
|
||||
} else {
|
||||
QDir dir(workingDir, QString::fromLatin1("%1.*").arg(baseFileName), QDir::Time);
|
||||
QStringList outputFiles = dir.entryList();
|
||||
@@ -254,5 +278,11 @@ void CallgrindController::cleanupTempFile()
|
||||
m_tempDataFile.clear();
|
||||
}
|
||||
|
||||
void CallgrindController::setValgrindRunnable(const Runnable &runnable)
|
||||
{
|
||||
QTC_ASSERT(runnable.is<StandardRunnable>(), return);
|
||||
m_valgrindRunnable = runnable.as<StandardRunnable>();
|
||||
}
|
||||
|
||||
} // namespace Callgrind
|
||||
} // namespace Valgrind
|
||||
|
@@ -25,18 +25,15 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <QObject>
|
||||
|
||||
#include <qprocess.h>
|
||||
|
||||
#include <ssh/sshconnection.h>
|
||||
#include <ssh/sshremoteprocess.h>
|
||||
#include <ssh/sftpchannel.h>
|
||||
#include <ssh/sshconnection.h>
|
||||
|
||||
#include <projectexplorer/runnables.h>
|
||||
|
||||
#include <QProcess>
|
||||
|
||||
namespace Valgrind {
|
||||
|
||||
class ValgrindProcess;
|
||||
|
||||
namespace Callgrind {
|
||||
|
||||
class CallgrindController : public QObject
|
||||
@@ -49,16 +46,14 @@ public:
|
||||
Unknown,
|
||||
Dump,
|
||||
ResetEventCounters,
|
||||
Pause, UnPause
|
||||
Pause,
|
||||
UnPause
|
||||
};
|
||||
|
||||
explicit CallgrindController(QObject *parent = 0);
|
||||
virtual ~CallgrindController();
|
||||
CallgrindController();
|
||||
~CallgrindController() override;
|
||||
|
||||
void run(Valgrind::Callgrind::CallgrindController::Option option);
|
||||
|
||||
void setValgrindProcess(ValgrindProcess *process);
|
||||
ValgrindProcess *valgrindProcess() { return m_valgrindProc; }
|
||||
void run(Option option);
|
||||
|
||||
/**
|
||||
* Make data file available locally, triggers @c localParseDataAvailable.
|
||||
@@ -67,32 +62,34 @@ public:
|
||||
* downloads the data file first and returns a local path.
|
||||
*/
|
||||
void getLocalDataFile();
|
||||
void setValgrindPid(qint64 pid);
|
||||
void setValgrindRunnable(const ProjectExplorer::Runnable &runnable);
|
||||
|
||||
signals:
|
||||
void finished(Valgrind::Callgrind::CallgrindController::Option option);
|
||||
|
||||
void localParseDataAvailable(const QString &file);
|
||||
|
||||
void statusMessage(const QString &msg);
|
||||
|
||||
private:
|
||||
void processError(QProcess::ProcessError);
|
||||
void processFinished(int, QProcess::ExitStatus);
|
||||
void handleControllerProcessError(QProcess::ProcessError);
|
||||
|
||||
void foundRemoteFile();
|
||||
void sftpInitialized();
|
||||
void sftpJobFinished(QSsh::SftpJobId job, const QString &error);
|
||||
void cleanupTempFile();
|
||||
|
||||
// callgrind_control process
|
||||
Valgrind::ValgrindProcess *m_process;
|
||||
// valgrind process
|
||||
Valgrind::ValgrindProcess *m_valgrindProc;
|
||||
void controllerProcessFinished(int, QProcess::ExitStatus);
|
||||
void controllerProcessError(QProcess::ProcessError);
|
||||
void controllerProcessClosed(bool success);
|
||||
|
||||
Option m_lastOption;
|
||||
ProjectExplorer::ApplicationLauncher *m_controllerProcess;
|
||||
ProjectExplorer::StandardRunnable m_valgrindRunnable;
|
||||
qint64 m_pid = 0;
|
||||
|
||||
Option m_lastOption = Unknown;
|
||||
|
||||
// remote callgrind support
|
||||
QSsh::SshConnection *m_ssh;
|
||||
QSsh::SshConnection *m_ssh = nullptr;
|
||||
QString m_tempDataFile;
|
||||
QSsh::SshRemoteProcess::Ptr m_findRemoteFile;
|
||||
QSsh::SftpChannel::Ptr m_sftp;
|
||||
|
@@ -30,21 +30,22 @@
|
||||
|
||||
#include <valgrind/callgrind/callgrindcontroller.h>
|
||||
#include <valgrind/callgrind/callgrindparser.h>
|
||||
#include <valgrind/valgrindrunner.h>
|
||||
|
||||
#include <debugger/analyzer/analyzermanager.h>
|
||||
|
||||
#include <utils/qtcassert.h>
|
||||
|
||||
using namespace Debugger;
|
||||
using namespace Valgrind;
|
||||
using namespace Valgrind::Internal;
|
||||
using namespace ProjectExplorer;
|
||||
using namespace Valgrind::Callgrind;
|
||||
|
||||
CallgrindToolRunner::CallgrindToolRunner(ProjectExplorer::RunControl *runControl)
|
||||
namespace Valgrind {
|
||||
namespace Internal {
|
||||
|
||||
CallgrindToolRunner::CallgrindToolRunner(RunControl *runControl)
|
||||
: ValgrindToolRunner(runControl)
|
||||
{
|
||||
setDisplayName("CallgrindToolRunner");
|
||||
m_runner.setToolName("callgrind");
|
||||
|
||||
connect(&m_runner, &ValgrindRunner::finished,
|
||||
this, &CallgrindToolRunner::slotFinished);
|
||||
@@ -58,19 +59,19 @@ CallgrindToolRunner::CallgrindToolRunner(ProjectExplorer::RunControl *runControl
|
||||
connect(&m_controller, &CallgrindController::statusMessage,
|
||||
this, &CallgrindToolRunner::showStatusMessage);
|
||||
|
||||
connect(&m_runner, &ValgrindRunner::extraStart, this, [this] {
|
||||
m_controller.setValgrindProcess(m_runner.valgrindProcess());
|
||||
});
|
||||
connect(&m_runner, &ValgrindRunner::valgrindStarted,
|
||||
&m_controller, &CallgrindController::setValgrindPid);
|
||||
|
||||
connect(&m_runner, &ValgrindRunner::extraProcessFinished, this, [this] {
|
||||
triggerParse();
|
||||
m_controller.setValgrindProcess(nullptr);
|
||||
});
|
||||
|
||||
m_controller.setValgrindRunnable(runnable());
|
||||
}
|
||||
|
||||
QStringList CallgrindToolRunner::toolArguments() const
|
||||
{
|
||||
QStringList arguments;
|
||||
QStringList arguments = {"--tool=callgrind"};
|
||||
|
||||
QTC_ASSERT(m_settings, return arguments);
|
||||
|
||||
@@ -120,12 +121,10 @@ void CallgrindToolRunner::setPaused(bool paused)
|
||||
m_markAsPaused = paused;
|
||||
|
||||
// call controller only if it is attached to a valgrind process
|
||||
if (m_controller.valgrindProcess()) {
|
||||
if (paused)
|
||||
pause();
|
||||
else
|
||||
unpause();
|
||||
}
|
||||
}
|
||||
|
||||
void CallgrindToolRunner::setToggleCollectFunction(const QString &toggleCollectFunction)
|
||||
@@ -202,3 +201,6 @@ void CallgrindToolRunner::controllerFinished(CallgrindController::Option option)
|
||||
break; // do nothing
|
||||
}
|
||||
}
|
||||
|
||||
} // Internal
|
||||
} // Valgrind
|
||||
|
@@ -48,7 +48,7 @@ CallgrindTextMark::CallgrindTextMark(const QPersistentModelIndex &index,
|
||||
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())
|
||||
return;
|
||||
|
@@ -49,7 +49,7 @@ public:
|
||||
|
||||
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:
|
||||
QPersistentModelIndex m_modelIndex;
|
||||
|
@@ -289,7 +289,6 @@ CallgrindTool::CallgrindTool(QObject *parent)
|
||||
auto runControl = new RunControl(runConfig, CALLGRIND_RUN_MODE);
|
||||
const auto runnable = dlg.runnable();
|
||||
runControl->setRunnable(runnable);
|
||||
runControl->setConnection(UrlConnection(dlg.serverUrl()));
|
||||
runControl->setDisplayName(runnable.executable);
|
||||
createRunTool(runControl);
|
||||
ProjectExplorerPlugin::startRunControl(runControl);
|
||||
|
@@ -26,7 +26,6 @@
|
||||
|
||||
#include "memcheckengine.h"
|
||||
#include "memchecktool.h"
|
||||
#include "valgrindprocess.h"
|
||||
#include "valgrindsettings.h"
|
||||
#include "xmlprotocol/error.h"
|
||||
#include "xmlprotocol/status.h"
|
||||
@@ -51,8 +50,33 @@ using namespace Valgrind::XmlProtocol;
|
||||
namespace Valgrind {
|
||||
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)
|
||||
: ValgrindToolRunner(runControl), m_withGdb(withGdb)
|
||||
: ValgrindToolRunner(runControl),
|
||||
m_withGdb(withGdb),
|
||||
m_localServerAddress(QHostAddress::LocalHost)
|
||||
{
|
||||
setDisplayName("MemcheckToolRunner");
|
||||
connect(m_runner.parser(), &XmlProtocol::ThreadedParser::error,
|
||||
@@ -61,15 +85,19 @@ MemcheckToolRunner::MemcheckToolRunner(RunControl *runControl, bool withGdb)
|
||||
this, &MemcheckToolRunner::suppressionCount);
|
||||
|
||||
if (withGdb) {
|
||||
connect(&m_runner, &ValgrindRunner::started,
|
||||
connect(&m_runner, &ValgrindRunner::valgrindStarted,
|
||||
this, &MemcheckToolRunner::startDebugger);
|
||||
connect(&m_runner, &ValgrindRunner::logMessageReceived,
|
||||
this, &MemcheckToolRunner::appendLog);
|
||||
m_runner.disableXml();
|
||||
// m_runner.disableXml();
|
||||
} else {
|
||||
connect(m_runner.parser(), &XmlProtocol::ThreadedParser::internalError,
|
||||
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
|
||||
@@ -79,10 +107,7 @@ QString MemcheckToolRunner::progressTitle() const
|
||||
|
||||
void MemcheckToolRunner::start()
|
||||
{
|
||||
// MemcheckTool::engineStarting(this);
|
||||
|
||||
appendMessage(tr("Analyzing memory of %1").arg(executable()) + QLatin1Char('\n'),
|
||||
Utils::NormalMessageFormat);
|
||||
m_runner.setLocalServerAddress(m_localServerAddress);
|
||||
ValgrindToolRunner::start();
|
||||
}
|
||||
|
||||
@@ -95,8 +120,7 @@ void MemcheckToolRunner::stop()
|
||||
|
||||
QStringList MemcheckToolRunner::toolArguments() const
|
||||
{
|
||||
QStringList arguments;
|
||||
arguments << "--gen-suppressions=all";
|
||||
QStringList arguments = {"--tool=memcheck", "--gen-suppressions=all"};
|
||||
|
||||
QTC_ASSERT(m_settings, return arguments);
|
||||
|
||||
@@ -137,10 +161,8 @@ QStringList MemcheckToolRunner::suppressionFiles() const
|
||||
return m_settings->suppressionFiles();
|
||||
}
|
||||
|
||||
void MemcheckToolRunner::startDebugger()
|
||||
void MemcheckToolRunner::startDebugger(qint64 valgrindPid)
|
||||
{
|
||||
const qint64 valgrindPid = m_runner.valgrindProcess()->pid();
|
||||
|
||||
Debugger::DebuggerStartParameters sp;
|
||||
sp.inferior = runnable().as<StandardRunnable>();
|
||||
sp.startMode = Debugger::AttachToRemoteServer;
|
||||
@@ -149,12 +171,10 @@ void MemcheckToolRunner::startDebugger()
|
||||
sp.useContinueInsteadOfRun = true;
|
||||
sp.expectedSignals.append("SIGTRAP");
|
||||
|
||||
QString errorMessage;
|
||||
auto gdbRunControl = new RunControl(nullptr, ProjectExplorer::Constants::DEBUG_RUN_MODE);
|
||||
(void) new Debugger::DebuggerRunTool(gdbRunControl, sp, &errorMessage);
|
||||
connect(gdbRunControl, &RunControl::finished,
|
||||
gdbRunControl, &RunControl::deleteLater);
|
||||
gdbRunControl->initiateStart();
|
||||
auto gdbWorker = new Debugger::DebuggerRunTool(runControl());
|
||||
gdbWorker->setStartParameters(sp);
|
||||
gdbWorker->initiateStart();
|
||||
connect(runControl(), &RunControl::finished, gdbWorker, &RunControl::deleteLater);
|
||||
}
|
||||
|
||||
void MemcheckToolRunner::appendLog(const QByteArray &data)
|
||||
|
@@ -31,6 +31,8 @@
|
||||
#include "valgrindrunner.h"
|
||||
#include "xmlprotocol/threadedparser.h"
|
||||
|
||||
#include <QHostAddress>
|
||||
|
||||
namespace Valgrind {
|
||||
namespace Internal {
|
||||
|
||||
@@ -56,10 +58,11 @@ private:
|
||||
QString progressTitle() const override;
|
||||
QStringList toolArguments() const override;
|
||||
|
||||
void startDebugger();
|
||||
void startDebugger(qint64 valgrindPid);
|
||||
void appendLog(const QByteArray &data);
|
||||
|
||||
const bool m_withGdb;
|
||||
QHostAddress m_localServerAddress;
|
||||
};
|
||||
|
||||
} // namespace Internal
|
||||
|
@@ -454,7 +454,6 @@ MemcheckTool::MemcheckTool(QObject *parent)
|
||||
rc->createWorker(MEMCHECK_RUN_MODE);
|
||||
const auto runnable = dlg.runnable();
|
||||
rc->setRunnable(runnable);
|
||||
rc->setConnection(UrlConnection(dlg.serverUrl()));
|
||||
rc->setDisplayName(runnable.executable);
|
||||
ProjectExplorerPlugin::startRunControl(rc);
|
||||
});
|
||||
|
@@ -11,7 +11,6 @@ HEADERS += \
|
||||
valgrindconfigwidget.h \
|
||||
valgrindsettings.h \
|
||||
valgrindrunner.h \
|
||||
valgrindprocess.h \
|
||||
callgrindcostdelegate.h \
|
||||
callgrindcostview.h \
|
||||
callgrindhelper.h \
|
||||
@@ -33,7 +32,6 @@ SOURCES += \
|
||||
valgrindconfigwidget.cpp \
|
||||
valgrindsettings.cpp \
|
||||
valgrindrunner.cpp \
|
||||
valgrindprocess.cpp \
|
||||
callgrindcostdelegate.cpp \
|
||||
callgrindcostview.cpp \
|
||||
callgrindhelper.cpp \
|
||||
|
@@ -34,7 +34,6 @@ QtcPlugin {
|
||||
"valgrindconfigwidget.cpp", "valgrindconfigwidget.h", "valgrindconfigwidget.ui",
|
||||
"valgrindengine.cpp", "valgrindengine.h",
|
||||
"valgrindplugin.cpp", "valgrindplugin.h",
|
||||
"valgrindprocess.cpp", "valgrindprocess.h",
|
||||
"valgrindruncontrolfactory.cpp", "valgrindruncontrolfactory.h",
|
||||
"valgrindrunner.cpp", "valgrindrunner.h",
|
||||
"valgrindsettings.cpp", "valgrindsettings.h",
|
||||
|
@@ -27,8 +27,7 @@ HEADERS += \
|
||||
$$PWD/callgrind/callgrindcycledetection.h \
|
||||
$$PWD/callgrind/callgrindproxymodel.h \
|
||||
$$PWD/callgrind/callgrindstackbrowser.h \
|
||||
$$PWD/valgrindrunner.h \
|
||||
$$PWD/valgrindprocess.h
|
||||
$$PWD/valgrindrunner.h
|
||||
|
||||
SOURCES += $$PWD/xmlprotocol/error.cpp \
|
||||
$$PWD/xmlprotocol/frame.cpp \
|
||||
@@ -53,7 +52,6 @@ SOURCES += $$PWD/xmlprotocol/error.cpp \
|
||||
$$PWD/callgrind/callgrindcycledetection.cpp \
|
||||
$$PWD/callgrind/callgrindproxymodel.cpp \
|
||||
$$PWD/callgrind/callgrindstackbrowser.cpp \
|
||||
$$PWD/valgrindrunner.cpp \
|
||||
$$PWD/valgrindprocess.cpp
|
||||
$$PWD/valgrindrunner.cpp
|
||||
|
||||
LIBS += -L$$IDE_PLUGIN_PATH/QtProject
|
||||
|
@@ -106,6 +106,7 @@ void ValgrindToolRunner::stop()
|
||||
{
|
||||
m_isStopping = true;
|
||||
m_runner.stop();
|
||||
reportStopped(); // FIXME: Restrict to non-running scenarios?
|
||||
}
|
||||
|
||||
QString ValgrindToolRunner::executable() const
|
||||
|
@@ -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
|
@@ -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
Reference in New Issue
Block a user