diff options
author | Eike Ziller <eike.ziller@theqtcompany.com> | 2014-11-24 15:43:48 +0100 |
---|---|---|
committer | Eike Ziller <eike.ziller@theqtcompany.com> | 2014-11-24 15:43:48 +0100 |
commit | a47fbb83094ac2d2014fdd563ae22be9f0200baa (patch) | |
tree | 2b29ca96979b5facf549131aee58c13e9c2c368b /src/plugins | |
parent | 63487158f1928f2d8499995783610839904ab149 (diff) | |
parent | a4a4f7a4759e97142f751fdb91cb11536e5102e2 (diff) | |
download | qt-creator-a47fbb83094ac2d2014fdd563ae22be9f0200baa.tar.gz |
Merge remote-tracking branch 'origin/3.3'
Conflicts:
src/plugins/coreplugin/coreplugin.cpp
src/plugins/coreplugin/themesettingswidget.cpp
src/plugins/qbsprojectmanager/qbsprojectmanager.cpp
src/plugins/qbsprojectmanager/qbsprojectmanager.h
src/plugins/qmlprofiler/qml/Overview.js
src/shared/qbs
Change-Id: Ibe92c166fc5bfbcb4d6964e50ca7298d8459d60e
Diffstat (limited to 'src/plugins')
167 files changed, 2162 insertions, 1458 deletions
diff --git a/src/plugins/android/androidbuildapkstep.cpp b/src/plugins/android/androidbuildapkstep.cpp index dcf63147c5..1fcb21fd6f 100644 --- a/src/plugins/android/androidbuildapkstep.cpp +++ b/src/plugins/android/androidbuildapkstep.cpp @@ -72,10 +72,8 @@ AndroidBuildApkStep::AndroidBuildApkStep(ProjectExplorer::BuildStepList *parent, m_buildTargetSdk(AndroidConfig::apiLevelNameFor(AndroidConfigurations::currentConfig().highestAndroidSdk())) { const QtSupport::BaseQtVersion *version = QtSupport::QtKitInformation::qtVersion(target()->kit()); - if (version && version->qtVersion() >= QtSupport::QtVersionNumber(5, 4, 0)) { - m_deployAction = DebugDeployment; + if (version && version->qtVersion() >= QtSupport::QtVersionNumber(5, 4, 0)) m_useGradle = AndroidConfigurations::currentConfig().useGrandle(); - } //: AndroidBuildApkStep default display name setDefaultDisplayName(tr("Build Android APK")); } @@ -159,12 +157,7 @@ void AndroidBuildApkStep::processFinished(int exitCode, QProcess::ExitStatus sta bool AndroidBuildApkStep::fromMap(const QVariantMap &map) { - AndroidDeployAction defaultDeploy = BundleLibrariesDeployment; - const QtSupport::BaseQtVersion *version = QtSupport::QtKitInformation::qtVersion(target()->kit()); - if (version && version->qtVersion() >= QtSupport::QtVersionNumber(5, 4, 0)) - defaultDeploy = DebugDeployment; - - m_deployAction = AndroidDeployAction(map.value(DeployActionKey, defaultDeploy).toInt()); + m_deployAction = AndroidDeployAction(map.value(DeployActionKey, BundleLibrariesDeployment).toInt()); if ( m_deployAction == DebugDeployment && QtSupport::QtKitInformation::qtVersion(target()->kit())->qtVersion() < QtSupport::QtVersionNumber(5, 4, 0)) { m_deployAction = BundleLibrariesDeployment; diff --git a/src/plugins/android/androidbuildapkwidget.ui b/src/plugins/android/androidbuildapkwidget.ui index 13d638b659..51ba40b30c 100644 --- a/src/plugins/android/androidbuildapkwidget.ui +++ b/src/plugins/android/androidbuildapkwidget.ui @@ -139,6 +139,9 @@ <property name="pixmap"> <pixmap resource="../coreplugin/core.qrc">:/core/images/error.png</pixmap> </property> + <property name="alignment"> + <set>Qt::AlignLeading|Qt::AlignLeft|Qt::AlignTop</set> + </property> </widget> </item> <item> @@ -150,7 +153,8 @@ </sizepolicy> </property> <property name="text"> - <string>Signing an APK that uses "Deploy local Qt libraries" is not allowed</string> + <string>Signing an APK that uses "Deploy local Qt libraries" is not allowed. +Deploying local Qt libraries is incompatible with Android 5</string> </property> </widget> </item> diff --git a/src/plugins/android/androidconfigurations.cpp b/src/plugins/android/androidconfigurations.cpp index 8057b8c678..909a13c5b9 100644 --- a/src/plugins/android/androidconfigurations.cpp +++ b/src/plugins/android/androidconfigurations.cpp @@ -210,7 +210,7 @@ void AndroidConfig::load(const QSettings &settings) m_sdkLocation = FileName::fromString(settings.value(SDKLocationKey).toString()); m_ndkLocation = FileName::fromString(settings.value(NDKLocationKey).toString()); m_antLocation = FileName::fromString(settings.value(AntLocationKey).toString()); - m_useGradle = settings.value(UseGradleKey, true).toBool(); + m_useGradle = settings.value(UseGradleKey, false).toBool(); m_openJDKLocation = FileName::fromString(settings.value(OpenJDKLocationKey).toString()); m_keystoreLocation = FileName::fromString(settings.value(KeystoreLocationKey).toString()); m_toolchainHost = settings.value(ToolchainHostKey).toString(); @@ -244,7 +244,7 @@ void AndroidConfig::load(const QSettings &settings) } AndroidConfig::AndroidConfig() - : m_useGradle(true), + : m_useGradle(false), m_availableSdkPlatformsUpToDate(false), m_NdkInformationUpToDate(false) { @@ -840,6 +840,24 @@ bool AndroidConfig::hasFinishedBooting(const QString &device) const QStringList AndroidConfig::getAbis(const QString &device) const { QStringList result; + // First try via ro.product.cpu.abilist + QStringList arguments = AndroidDeviceInfo::adbSelector(device); + arguments << QLatin1String("shell") << QLatin1String("getprop"); + arguments << QLatin1String("ro.product.cpu.abilist"); + QProcess adbProc; + adbProc.start(adbToolPath().toString(), arguments); + if (!adbProc.waitForFinished(10000)) { + adbProc.kill(); + return result; + } + QString output = QString::fromLocal8Bit(adbProc.readAll().trimmed()); + if (!output.isEmpty()) { + QStringList result = output.split(QLatin1Char(',')); + if (!result.isEmpty()) + return result; + } + + // Fall back to ro.product.cpu.abi, ro.product.cpu.abi2 ... for (int i = 1; i < 6; ++i) { QStringList arguments = AndroidDeviceInfo::adbSelector(device); arguments << QLatin1String("shell") << QLatin1String("getprop"); @@ -989,7 +1007,9 @@ void AndroidConfigurations::setConfig(const AndroidConfig &devConfigs) emit m_instance->updated(); } -AndroidDeviceInfo AndroidConfigurations::showDeviceDialog(ProjectExplorer::Project *project, int apiLevel, const QString &abi) +AndroidDeviceInfo AndroidConfigurations::showDeviceDialog(ProjectExplorer::Project *project, + int apiLevel, const QString &abi, + Options options) { QString serialNumber = defaultDevice(project, abi); if (!serialNumber.isEmpty()) { @@ -1005,7 +1025,7 @@ AndroidDeviceInfo AndroidConfigurations::showDeviceDialog(ProjectExplorer::Proje return info; } - AndroidDeviceDialog dialog(apiLevel, abi, Core::ICore::mainWindow()); + AndroidDeviceDialog dialog(apiLevel, abi, options, Core::ICore::mainWindow()); if (dialog.exec() == QDialog::Accepted) { AndroidDeviceInfo info = dialog.device(); if (dialog.saveDeviceSelection()) { diff --git a/src/plugins/android/androidconfigurations.h b/src/plugins/android/androidconfigurations.h index 81a1678a3e..ba39917a27 100644 --- a/src/plugins/android/androidconfigurations.h +++ b/src/plugins/android/androidconfigurations.h @@ -208,7 +208,8 @@ public: static AndroidConfigurations *instance(); static void updateAndroidDevice(); - static AndroidDeviceInfo showDeviceDialog(ProjectExplorer::Project *project, int apiLevel, const QString &abi); + enum Options { None, FilterAndroid5 }; + static AndroidDeviceInfo showDeviceDialog(ProjectExplorer::Project *project, int apiLevel, const QString &abi, Options options); static void setDefaultDevice(ProjectExplorer::Project *project, const QString &abi, const QString &serialNumber); // serial number or avd name static QString defaultDevice(ProjectExplorer::Project *project, const QString &abi); // serial number or avd name public slots: diff --git a/src/plugins/android/androiddeployqtstep.cpp b/src/plugins/android/androiddeployqtstep.cpp index a6b38e20b6..8f0d6d512f 100644 --- a/src/plugins/android/androiddeployqtstep.cpp +++ b/src/plugins/android/androiddeployqtstep.cpp @@ -176,8 +176,19 @@ bool AndroidDeployQtStep::init() emit addOutput(tr("No Android arch set by the .pro file."), ErrorOutput); return false; } + + AndroidBuildApkStep *androidBuildApkStep + = AndroidGlobal::buildStep<AndroidBuildApkStep>(target()->activeBuildConfiguration()); + if (!androidBuildApkStep) { + emit addOutput(tr("Cannot find the android build step."), ErrorOutput); + return false; + } + m_deviceAPILevel = AndroidManager::minimumSDK(target()); - AndroidDeviceInfo info = AndroidConfigurations::showDeviceDialog(project(), m_deviceAPILevel, m_targetArch); + AndroidConfigurations::Options options = AndroidConfigurations::None; + if (androidBuildApkStep->deployAction() == AndroidBuildApkStep::DebugDeployment) + options = AndroidConfigurations::FilterAndroid5; + AndroidDeviceInfo info = AndroidConfigurations::showDeviceDialog(project(), m_deviceAPILevel, m_targetArch, options); if (info.serialNumber.isEmpty()) // aborted return false; @@ -205,12 +216,6 @@ bool AndroidDeployQtStep::init() ProjectExplorer::ProcessParameters *pp = processParameters(); m_useAndroiddeployqt = version->qtVersion() >= QtSupport::QtVersionNumber(5, 4, 0); if (m_useAndroiddeployqt) { - AndroidBuildApkStep *androidBuildApkStep - = AndroidGlobal::buildStep<AndroidBuildApkStep>(target()->activeBuildConfiguration()); - if (!androidBuildApkStep) { - emit addOutput(tr("Cannot find the android build step."), ErrorOutput); - return false; - } Utils::FileName tmp = AndroidManager::androidQtSupport(target())->androiddeployqtPath(target()); if (tmp.isEmpty()) { emit addOutput(tr("Cannot find the androiddeployqt tool."), ErrorOutput); @@ -253,6 +258,16 @@ bool AndroidDeployQtStep::init() } if (androidBuildApkStep->useGradle()) Utils::QtcProcess::addArg(&m_androiddeployqtArgs, QLatin1String("--gradle")); + + if (androidBuildApkStep->signPackage()) { + // The androiddeployqt tool is not really written to do stand-alone installations. + // This hack forces it to use the correct filename for the apk file when installing + // as a temporary fix until androiddeployqt gets the support. Since the --sign is + // only used to get the correct file name of the apk, its parameters are ignored. + Utils::QtcProcess::addArg(&m_androiddeployqtArgs, QLatin1String("--sign")); + Utils::QtcProcess::addArg(&m_androiddeployqtArgs, QLatin1String("foo")); + Utils::QtcProcess::addArg(&m_androiddeployqtArgs, QLatin1String("bar")); + } } else { m_uninstallPreviousPackageRun = true; pp->setCommand(AndroidConfigurations::currentConfig().adbToolPath().toString()); diff --git a/src/plugins/android/androiddevicedialog.cpp b/src/plugins/android/androiddevicedialog.cpp index abc3d6cde2..43a3acd6a8 100644 --- a/src/plugins/android/androiddevicedialog.cpp +++ b/src/plugins/android/androiddevicedialog.cpp @@ -213,7 +213,7 @@ public: class AndroidDeviceModel : public QAbstractItemModel { public: - AndroidDeviceModel(int apiLevel, const QString &abi); + AndroidDeviceModel(int apiLevel, const QString &abi, AndroidConfigurations::Options options); QModelIndex index(int row, int column, const QModelIndex &parent = QModelIndex()) const; QModelIndex parent(const QModelIndex &child) const; @@ -229,6 +229,7 @@ public: private: int m_apiLevel; QString m_abi; + AndroidConfigurations::Options m_options; AndroidDeviceModelNode *m_root; }; @@ -237,8 +238,8 @@ private: ///////////////// // AndroidDeviceModel ///////////////// -AndroidDeviceModel::AndroidDeviceModel(int apiLevel, const QString &abi) - : m_apiLevel(apiLevel), m_abi(abi), m_root(0) +AndroidDeviceModel::AndroidDeviceModel(int apiLevel, const QString &abi, AndroidConfigurations::Options options) + : m_apiLevel(apiLevel), m_abi(abi), m_options(options), m_root(0) { } @@ -347,6 +348,8 @@ void AndroidDeviceModel::setDevices(const QVector<AndroidDeviceInfo> &devices) } else if (device.sdk < m_apiLevel) { error = AndroidDeviceDialog::tr("API Level of device is: %1.") .arg(device.sdk); + } else if (device.sdk > 20 && (m_options & AndroidConfigurations::FilterAndroid5)) { + error = AndroidDeviceDialog::tr("Android 5 devices are incompatible with deploying Qt to a temporary directory."); } else { new AndroidDeviceModelNode(compatibleDevices, device); continue; @@ -386,9 +389,9 @@ static inline QString msgAdbListDevices() return AndroidDeviceDialog::tr("<p>The adb tool in the Android SDK lists all connected devices if run via "adb devices".</p>"); } -AndroidDeviceDialog::AndroidDeviceDialog(int apiLevel, const QString &abi, QWidget *parent) : +AndroidDeviceDialog::AndroidDeviceDialog(int apiLevel, const QString &abi, AndroidConfigurations::Options options, QWidget *parent) : QDialog(parent), - m_model(new AndroidDeviceModel(apiLevel, abi)), + m_model(new AndroidDeviceModel(apiLevel, abi, options)), m_ui(new Ui::AndroidDeviceDialog), m_apiLevel(apiLevel), m_abi(abi) diff --git a/src/plugins/android/androiddevicedialog.h b/src/plugins/android/androiddevicedialog.h index 34d0ed074b..e557650c2e 100644 --- a/src/plugins/android/androiddevicedialog.h +++ b/src/plugins/android/androiddevicedialog.h @@ -52,7 +52,7 @@ class AndroidDeviceDialog : public QDialog Q_OBJECT public: - explicit AndroidDeviceDialog(int apiLevel, const QString &abi, QWidget *parent = 0); + explicit AndroidDeviceDialog(int apiLevel, const QString &abi, AndroidConfigurations::Options opts, QWidget *parent = 0); ~AndroidDeviceDialog(); AndroidDeviceInfo device(); diff --git a/src/plugins/android/androidmanager.cpp b/src/plugins/android/androidmanager.cpp index c0ecde4484..8a4b8563c2 100644 --- a/src/plugins/android/androidmanager.cpp +++ b/src/plugins/android/androidmanager.cpp @@ -308,7 +308,8 @@ QString AndroidManager::androidNameForApiLevel(int x) case 19: return QLatin1String("Android 4.4"); case 20: - return QLatin1String("Android L"); // prelimary name? + case 21: + return QLatin1String("Android 5.0"); default: return tr("Unknown Android version. API Level: %1").arg(QString::number(x)); } @@ -478,7 +479,7 @@ void AndroidManager::cleanLibsOnDevice(ProjectExplorer::Target *target) if (targetArch.isEmpty()) return; int deviceAPILevel = AndroidManager::minimumSDK(target); - AndroidDeviceInfo info = AndroidConfigurations::showDeviceDialog(target->project(), deviceAPILevel, targetArch); + AndroidDeviceInfo info = AndroidConfigurations::showDeviceDialog(target->project(), deviceAPILevel, targetArch, AndroidConfigurations::None); if (info.serialNumber.isEmpty()) // aborted return; @@ -508,7 +509,7 @@ void AndroidManager::installQASIPackage(ProjectExplorer::Target *target, const Q if (targetArch.isEmpty()) return; int deviceAPILevel = AndroidManager::minimumSDK(target); - AndroidDeviceInfo info = AndroidConfigurations::showDeviceDialog(target->project(), deviceAPILevel, targetArch); + AndroidDeviceInfo info = AndroidConfigurations::showDeviceDialog(target->project(), deviceAPILevel, targetArch, AndroidConfigurations::None); if (info.serialNumber.isEmpty()) // aborted return; diff --git a/src/plugins/android/androidqtsupport.cpp b/src/plugins/android/androidqtsupport.cpp index 6f99c57b92..a8d2f21d46 100644 --- a/src/plugins/android/androidqtsupport.cpp +++ b/src/plugins/android/androidqtsupport.cpp @@ -51,17 +51,11 @@ Utils::FileName Android::AndroidQtSupport::apkPath(ProjectExplorer::Target *targ apkPath = QLatin1String("/build/outputs/apk/android-build-"); else apkPath = QLatin1String("/bin/QtApp-"); - if (buildApkStep->buildConfiguration()->buildType() == ProjectExplorer::BuildConfiguration::Release) { - apkPath += QLatin1String("release-"); - if (!buildApkStep->signPackage()) - apkPath += QLatin1String("un"); - apkPath += QLatin1String("signed.apk"); - } else { - apkPath += QLatin1String("debug"); - if (buildApkStep->signPackage()) - apkPath += QLatin1String("-signed"); - apkPath += QLatin1String(".apk"); - } + if (buildApkStep->signPackage()) + apkPath += QLatin1String("release.apk"); + else + apkPath += QLatin1String("debug.apk"); + return target->activeBuildConfiguration()->buildDirectory() .appendPath(QLatin1String(Android::Constants::ANDROID_BUILDDIRECTORY)) .appendPath(apkPath); diff --git a/src/plugins/android/androidrunner.cpp b/src/plugins/android/androidrunner.cpp index 47740bd9b2..50729eda92 100644 --- a/src/plugins/android/androidrunner.cpp +++ b/src/plugins/android/androidrunner.cpp @@ -1,6 +1,7 @@ /************************************************************************** ** ** Copyright (c) 2014 BogDan Vatra <bog_dan_ro@yahoo.com> +** Copyright (C) 2014 Digia Plc and/or its subsidiary(-ies). ** Contact: http://www.qt-project.org/legal ** ** This file is part of Qt Creator. @@ -41,17 +42,30 @@ #include <qtsupport/qtkitinformation.h> #include <utils/qtcassert.h> +#include <QApplication> #include <QDir> #include <QTime> #include <QtConcurrentRun> #include <QTemporaryFile> #include <QTcpServer> +#include <QTcpSocket> /* This uses explicit handshakes between the application and the - gdbserver start and the host side by using the gdbserver socket - and two files ("ping" file in the application dir, "pong" file - in /data/local/tmp/qt) + gdbserver start and the host side by using the gdbserver socket. + + For the handshake there are two mechanisms. Only the first method works + on Android 5.x devices and is chosen as default option. The second + method can be enabled by setting the QTC_ANDROID_USE_FILE_HANDSHAKE + environment variable before starting Qt Creator. + + 1.) This method uses a TCP server on the Android device which starts + listening for incoming connections. The socket is forwarded by adb + and creator connects to it. This is the only method that works + on Android 5.x devices. + + 2.) This method uses two files ("ping" file in the application dir, + "pong" file in /data/local/tmp/qt). The sequence is as follows: @@ -67,8 +81,8 @@ gdbserver: normal start up including opening debug-socket, not yet attached to any process - app start up: touch ping file - app start up: loop until pong file appears + app start up: 1.) set up ping connection or 2.) touch ping file + app start up: 1.) accept() or 2.) loop until pong file appears host: start gdb host: gdb: set up binary, breakpoints, path etc @@ -90,7 +104,7 @@ app start up: resumed (still waiting for the pong) - host: write pong file + host: 1) write "ok" to ping pong connection or 2.) write pong file app start up: java code continues now, the process is already fully under control @@ -104,11 +118,16 @@ namespace Android { namespace Internal { typedef QLatin1String _; +const int MIN_SOCKET_HANDSHAKE_PORT = 20001; +const int MAX_SOCKET_HANDSHAKE_PORT = 20999; + +static int socketHandShakePort = MIN_SOCKET_HANDSHAKE_PORT; AndroidRunner::AndroidRunner(QObject *parent, AndroidRunConfiguration *runConfig, ProjectExplorer::RunMode runMode) - : QThread(parent) + : QThread(parent), m_handShakeMethod(SocketHandShake), m_socket(0), + m_customPort(false) { m_tries = 0; Debugger::DebuggerRunConfigurationAspect *aspect @@ -170,11 +189,32 @@ AndroidRunner::AndroidRunner(QObject *parent, connect(&m_adbLogcatProcess, SIGNAL(readyReadStandardOutput()), SLOT(logcatReadStandardOutput())); connect(&m_adbLogcatProcess, SIGNAL(readyReadStandardError()), SLOT(logcatReadStandardError())); connect(&m_checkPIDTimer, SIGNAL(timeout()), SLOT(checkPID())); + + if (version && version->qtVersion() >= QtSupport::QtVersionNumber(5, 4, 0)) { + if (qEnvironmentVariableIsSet("QTC_ANDROID_USE_FILE_HANDSHAKE")) + m_handShakeMethod = PingPongFiles; + } else { + m_handShakeMethod = PingPongFiles; + } + + if (qEnvironmentVariableIsSet("QTC_ANDROID_SOCKET_HANDSHAKE_PORT")) { + QByteArray envData = qgetenv("QTC_ANDROID_SOCKET_HANDSHAKE_PORT"); + if (!envData.isEmpty()) { + bool ok = false; + int port = 0; + port = envData.toInt(&ok); + if (ok && port > 0 && port < 65535) { + socketHandShakePort = port; + m_customPort = true; + } + } + } } AndroidRunner::~AndroidRunner() { //stop(); + delete m_socket; } static int extractPidFromChunk(const QByteArray &chunk, int from) @@ -308,11 +348,30 @@ void AndroidRunner::asyncStart() return; } + const QString pingPongSocket(m_packageName + _(".ping_pong_socket")); args << _("-e") << _("debug_ping") << _("true"); - args << _("-e") << _("ping_file") << m_pingFile; - args << _("-e") << _("pong_file") << m_pongFile; + if (m_handShakeMethod == SocketHandShake) { + args << _("-e") << _("ping_socket") << pingPongSocket; + } else if (m_handShakeMethod == PingPongFiles) { + args << _("-e") << _("ping_file") << m_pingFile; + args << _("-e") << _("pong_file") << m_pongFile; + } args << _("-e") << _("gdbserver_command") << m_gdbserverCommand; args << _("-e") << _("gdbserver_socket") << m_gdbserverSocket; + + if (m_handShakeMethod == SocketHandShake) { + QProcess adb; + const QString port = QString::fromLatin1("tcp:%1").arg(socketHandShakePort); + adb.start(m_adb, selector() << _("forward") << port << _("localabstract:") + pingPongSocket); + if (!adb.waitForStarted()) { + emit remoteProcessFinished(tr("Failed to forward ping pong ports. Reason: %1.").arg(adb.errorString())); + return; + } + if (!adb.waitForFinished()) { + emit remoteProcessFinished(tr("Failed to forward ping pong ports.")); + return; + } + } } if (m_useQmlDebugger || m_useQmlProfiler) { @@ -353,29 +412,72 @@ void AndroidRunner::asyncStart() } if (m_useCppDebugger) { + if (m_handShakeMethod == SocketHandShake) { + //Handling socket + bool wasSuccess = false; + const int maxAttempts = 20; //20 seconds + if (m_socket) + delete m_socket; + m_socket = new QTcpSocket(); + for (int i = 0; i < maxAttempts; i++) { + + QThread::sleep(1); // give Android time to start process + m_socket->connectToHost(QHostAddress(QStringLiteral("127.0.0.1")), socketHandShakePort); + if (!m_socket->waitForConnected()) + continue; + + if (!m_socket->waitForReadyRead()) { + m_socket->close(); + continue; + } + + const QByteArray pid = m_socket->readLine(); + if (pid.isEmpty()) { + m_socket->close(); + continue; + } + + wasSuccess = true; + m_socket->moveToThread(QApplication::instance()->thread()); - // Handling ping. - for (int i = 0; ; ++i) { - QTemporaryFile tmp(QDir::tempPath() + _("/pingpong")); - tmp.open(); - tmp.close(); - - QProcess process; - process.start(m_adb, selector() << _("pull") << m_pingFile << tmp.fileName()); - process.waitForFinished(); - - QFile res(tmp.fileName()); - const bool doBreak = res.size(); - res.remove(); - if (doBreak) break; + } - if (i == 20) { - emit remoteProcessFinished(tr("Unable to start \"%1\".").arg(m_packageName)); - return; + if (!wasSuccess) + emit remoteProcessFinished(tr("Failed to contact debugging port.")); + + if (!m_customPort) { + // increment running port to avoid clash when using multiple + // debug sessions at the same time + socketHandShakePort++; + // wrap ports around to avoid overflow + if (socketHandShakePort == MAX_SOCKET_HANDSHAKE_PORT) + socketHandShakePort = MIN_SOCKET_HANDSHAKE_PORT; + } + } else { + // Handling ping. + for (int i = 0; ; ++i) { + QTemporaryFile tmp(QDir::tempPath() + _("/pingpong")); + tmp.open(); + tmp.close(); + + QProcess process; + process.start(m_adb, selector() << _("pull") << m_pingFile << tmp.fileName()); + process.waitForFinished(); + + QFile res(tmp.fileName()); + const bool doBreak = res.size(); + res.remove(); + if (doBreak) + break; + + if (i == 20) { + emit remoteProcessFinished(tr("Unable to start \"%1\".").arg(m_packageName)); + return; + } + qDebug() << "WAITING FOR " << tmp.fileName(); + QThread::msleep(500); } - qDebug() << "WAITING FOR " << tmp.fileName(); - QThread::msleep(500); } } @@ -388,13 +490,18 @@ void AndroidRunner::asyncStart() void AndroidRunner::handleRemoteDebuggerRunning() { if (m_useCppDebugger) { - QTemporaryFile tmp(QDir::tempPath() + _("/pingpong")); - tmp.open(); - - QProcess process; - process.start(m_adb, selector() << _("push") << tmp.fileName() << m_pongFile); - process.waitForFinished(); + if (m_handShakeMethod == SocketHandShake) { + m_socket->write("OK"); + m_socket->waitForBytesWritten(); + m_socket->close(); + } else { + QTemporaryFile tmp(QDir::tempPath() + _("/pingpong")); + tmp.open(); + QProcess process; + process.start(m_adb, selector() << _("push") << tmp.fileName() << m_pongFile); + process.waitForFinished(); + } QTC_CHECK(m_processPID != -1); } emit remoteProcessStarted(m_localGdbServerPort, m_qmlPort); diff --git a/src/plugins/android/androidrunner.h b/src/plugins/android/androidrunner.h index 1af23bc88f..ac21371d7d 100644 --- a/src/plugins/android/androidrunner.h +++ b/src/plugins/android/androidrunner.h @@ -37,6 +37,7 @@ #include <QObject> #include <QTimer> +#include <QTcpSocket> #include <QThread> #include <QProcess> #include <QMutex> @@ -50,6 +51,11 @@ class AndroidRunner : public QThread { Q_OBJECT + enum DebugHandShakeType { + PingPongFiles, + SocketHandShake + }; + public: AndroidRunner(QObject *parent, AndroidRunConfiguration *runConfig, ProjectExplorer::RunMode runMode); @@ -114,6 +120,9 @@ private: bool m_isBusyBox; QStringList m_selector; QMutex m_mutex; + DebugHandShakeType m_handShakeMethod; + QTcpSocket *m_socket; + bool m_customPort; }; } // namespace Internal diff --git a/src/plugins/android/androidsettingswidget.ui b/src/plugins/android/androidsettingswidget.ui index 147d49ed55..7343d334c4 100644 --- a/src/plugins/android/androidsettingswidget.ui +++ b/src/plugins/android/androidsettingswidget.ui @@ -14,24 +14,24 @@ <string>Android Configuration</string> </property> <layout class="QGridLayout" name="gridLayout"> - <item row="2" column="0"> - <widget class="QLabel" name="SDKLocationLabel"> + <item row="0" column="0"> + <widget class="QLabel" name="OpenJDKLocationLabel"> <property name="sizePolicy"> - <sizepolicy hsizetype="Preferred" vsizetype="Fixed"> + <sizepolicy hsizetype="Preferred" vsizetype="Preferred"> <horstretch>0</horstretch> <verstretch>0</verstretch> </sizepolicy> </property> <property name="text"> - <string>Android SDK location:</string> + <string>JDK location:</string> </property> <property name="alignment"> <set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set> </property> </widget> </item> - <item row="11" column="1"> - <widget class="Utils::PathChooser" name="AntLocationPathChooser" native="true"/> + <item row="0" column="1"> + <widget class="Utils::PathChooser" name="OpenJDKLocationPathChooser" native="true"/> </item> <item row="1" column="1"> <layout class="QHBoxLayout" name="horizontalLayout_5"> @@ -69,6 +69,47 @@ </item> </layout> </item> + <item row="0" column="2"> + <widget class="QToolButton" name="downloadOpenJDKToolButton"> + <property name="toolTip"> + <string>Download JDK</string> + </property> + <property name="icon"> + <iconset resource="android.qrc"> + <normaloff>:/android/images/download.png</normaloff>:/android/images/download.png</iconset> + </property> + </widget> + </item> + <item row="2" column="0"> + <widget class="QLabel" name="SDKLocationLabel"> + <property name="sizePolicy"> + <sizepolicy hsizetype="Preferred" vsizetype="Fixed"> + <horstretch>0</horstretch> + <verstretch>0</verstretch> + </sizepolicy> + </property> + <property name="text"> + <string>Android SDK location:</string> + </property> + <property name="alignment"> + <set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set> + </property> + </widget> + </item> + <item row="2" column="1"> + <widget class="Utils::PathChooser" name="SDKLocationPathChooser" native="true"/> + </item> + <item row="2" column="2"> + <widget class="QToolButton" name="downloadSDKToolButton"> + <property name="toolTip"> + <string>Download Android SDK</string> + </property> + <property name="icon"> + <iconset resource="android.qrc"> + <normaloff>:/android/images/download.png</normaloff>:/android/images/download.png</iconset> + </property> + </widget> + </item> <item row="3" column="1"> <layout class="QHBoxLayout" name="horizontalLayout_4"> <item> @@ -105,13 +146,29 @@ </item> </layout> </item> - <item row="0" column="1"> - <widget class="Utils::PathChooser" name="OpenJDKLocationPathChooser" native="true"/> + <item row="4" column="0"> + <widget class="QLabel" name="NDKLocationLabel"> + <property name="sizePolicy"> + <sizepolicy hsizetype="Preferred" vsizetype="Preferred"> + <horstretch>0</horstretch> + <verstretch>0</verstretch> + </sizepolicy> + </property> + <property name="text"> + <string>Android NDK location:</string> + </property> + <property name="alignment"> + <set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set> + </property> + </widget> </item> - <item row="11" column="2"> - <widget class="QToolButton" name="downloadAntToolButton"> + <item row="4" column="1"> + <widget class="Utils::PathChooser" name="NDKLocationPathChooser" native="true"/> + </item> + <item row="4" column="2"> + <widget class="QToolButton" name="downloadNDKToolButton"> <property name="toolTip"> - <string>Download Ant</string> + <string>Download Android NDK</string> </property> <property name="icon"> <iconset resource="android.qrc"> @@ -119,6 +176,146 @@ </property> </widget> </item> + <item row="5" column="1"> + <layout class="QHBoxLayout" name="horizontalLayout_6"> + <property name="spacing"> + <number>2</number> + </property> + <item> + <widget class="QLabel" name="gdbWarningIconLabel"> + <property name="sizePolicy"> + <sizepolicy hsizetype="Fixed" vsizetype="Fixed"> + <horstretch>0</horstretch> + <verstretch>0</verstretch> + </sizepolicy> + </property> + <property name="text"> + <string/> + </property> + <property name="pixmap"> + <pixmap resource="../coreplugin/core.qrc">:/core/images/error.png</pixmap> + </property> + </widget> + </item> + <item> + <widget class="QLabel" name="gdbWarningLabel"> + <property name="sizePolicy"> + <sizepolicy hsizetype="Expanding" vsizetype="Preferred"> + <horstretch>0</horstretch> + <verstretch>0</verstretch> + </sizepolicy> + </property> + <property name="text"> + <string><a href="xx">The GDB in the NDK appears to have broken python support.</a></string> + </property> + </widget> + </item> + </layout> + </item> + <item row="6" column="1"> + <layout class="QHBoxLayout" name="horizontalLayout_3"> + <property name="spacing"> + <number>2</number> + </property> + <item> + <widget class="QLabel" name="ndkWarningIconLabel"> + <property name="sizePolicy"> + <sizepolicy hsizetype="Fixed" vsizetype="Fixed"> + <horstretch>0</horstretch> + <verstretch>0</verstretch> + </sizepolicy> + </property> + <property name="text"> + <string/> + </property> + <property name="pixmap"> + <pixmap resource="../coreplugin/core.qrc">:/core/images/error.png</pixmap> + </property> + </widget> + </item> + <item> + <widget class="QLabel" name="toolchainFoundLabel"> + <property name="sizePolicy"> + <sizepolicy hsizetype="Expanding" vsizetype="Preferred"> + <horstretch>0</horstretch> + <verstretch>0</verstretch> + </sizepolicy> + </property> + <property name="text"> + <string/> + </property> + </widget> + </item> + </layout> + </item> + <item row="8" column="1"> + <widget class="QCheckBox" name="CreateKitCheckBox"> + <property name="sizePolicy"> + <sizepolicy hsizetype="Expanding" vsizetype="Fixed"> + <horstretch>0</horstretch> + <verstretch>0</verstretch> + </sizepolicy> + </property> + <property name="text"> + <string>Automatically create kits for Android tool chains</string> + </property> + <property name="checked"> + <bool>true</bool> + </property> + </widget> + </item> + <item row="9" column="1"> + <layout class="QHBoxLayout" name="horizontalLayout_2"> + <property name="spacing"> + <number>2</number> + </property> + <item> + <widget class="QLabel" name="kitWarningIconLabel"> + <property name="sizePolicy"> + <sizepolicy hsizetype="Fixed" vsizetype="Fixed"> + <horstretch>0</horstretch> + <verstretch>0</verstretch> + </sizepolicy> + </property> + <property name="text"> + <string/> + </property> + <property name="pixmap"> + <pixmap resource="../coreplugin/core.qrc">:/core/images/warning.png</pixmap> + </property> + </widget> + </item> + <item> + <widget class="QLabel" name="kitWarningLabel"> + <property name="sizePolicy"> + <sizepolicy hsizetype="Preferred" vsizetype="Preferred"> + <horstretch>0</horstretch> + <verstretch>0</verstretch> + </sizepolicy> + </property> + <property name="text"> + <string/> + </property> + <property name="wordWrap"> + <bool>true</bool> + </property> + </widget> + </item> + </layout> + </item> + <item row="10" column="1"> + <widget class="QCheckBox" name="UseGradleCheckBox"> + <property name="sizePolicy"> + <sizepolicy hsizetype="Expanding" vsizetype="Fixed"> + <horstretch>0</horstretch> + <verstretch>0</verstretch> + </sizepolicy> + </property> + <property name="text"> + <string>Use Gradle instead of Ant</string> + </property> + </widget> + </item> <item row="11" column="0"> <widget class="QLabel" name="AntLocationLabel"> <property name="sizePolicy"> @@ -135,21 +332,13 @@ </property> </widget> </item> - <item row="2" column="2"> - <widget class="QToolButton" name="downloadSDKToolButton"> - <property name="toolTip"> - <string>Download Android SDK</string> - </property> - <property name="icon"> - <iconset resource="android.qrc"> - <normaloff>:/android/images/download.png</normaloff>:/android/images/download.png</iconset> - </property> - </widget> + <item row="11" column="1"> + <widget class="Utils::PathChooser" name="AntLocationPathChooser" native="true"/> </item> - <item row="4" column="2"> - <widget class="QToolButton" name="downloadNDKToolButton"> + <item row="11" column="2"> + <widget class="QToolButton" name="downloadAntToolButton"> <property name="toolTip"> - <string>Download Android NDK</string> + <string>Download Ant</string> </property> <property name="icon"> <iconset resource="android.qrc"> @@ -276,195 +465,6 @@ </layout> </widget> </item> - <item row="0" column="0"> - <widget class="QLabel" name="OpenJDKLocationLabel"> - <property name="sizePolicy"> - <sizepolicy hsizetype="Preferred" vsizetype="Preferred"> - <horstretch>0</horstretch> - <verstretch>0</verstretch> - </sizepolicy> - </property> - <property name="text"> - <string>JDK location:</string> - </property> - <property name="alignment"> - <set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set> - </property> - </widget> - </item> - <item row="6" column="1"> - <layout class="QHBoxLayout" name="horizontalLayout_3"> - <property name="spacing"> - <number>2</number> - </property> - <item> - <widget class="QLabel" name="ndkWarningIconLabel"> - <property name="sizePolicy"> - <sizepolicy hsizetype="Fixed" vsizetype="Fixed"> - <horstretch>0</horstretch> - <verstretch>0</verstretch> - </sizepolicy> - </property> - <property name="text"> - <string/> - </property> - <property name="pixmap"> - <pixmap resource="../coreplugin/core.qrc">:/core/images/error.png</pixmap> - </property> - </widget> - </item> - <item> - <widget class="QLabel" name="toolchainFoundLabel"> - <property name="sizePolicy"> - <sizepolicy hsizetype="Expanding" vsizetype="Preferred"> - <horstretch>0</horstretch> - <verstretch>0</verstretch> - </sizepolicy> - </property> - <property name="text"> - <string/> - </property> - </widget> - </item> - </layout> - </item> - <item row="4" column="0"> - <widget class="QLabel" name="NDKLocationLabel"> - <property name="sizePolicy"> - <sizepolicy hsizetype="Preferred" vsizetype="Preferred"> - <horstretch>0</horstretch> - <verstretch>0</verstretch> - </sizepolicy> - </property> - <property name="text"> - <string>Android NDK location:</string> - </property> - <property name="alignment"> - <set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set> - </property> - </widget> - </item> - <item row="4" column="1"> - <widget class="Utils::PathChooser" name="NDKLocationPathChooser" native="true"/> - </item> - <item row="0" column="2"> - <widget class="QToolButton" name="downloadOpenJDKToolButton"> - <property name="toolTip"> - <string>Download JDK</string> - </property> - <property name="icon"> - <iconset resource="android.qrc"> - <normaloff>:/android/images/download.png</normaloff>:/android/images/download.png</iconset> - </property> - </widget> - </item> - <item row="8" column="1"> - <widget class="QCheckBox" name="CreateKitCheckBox"> - <property name="sizePolicy"> - <sizepolicy hsizetype="Expanding" vsizetype="Fixed"> - <horstretch>0</horstretch> - <verstretch>0</verstretch> - </sizepolicy> - </property> - <property name="text"> - <string>Automatically create kits for Android tool chains</string> - </property> - <property name="checked"> - <bool>true</bool> - </property> - </widget> - </item> - <item row="9" column="1"> - <layout class="QHBoxLayout" name="horizontalLayout_2"> - <property name="spacing"> - <number>2</number> - </property> - <item> - <widget class="QLabel" name="kitWarningIconLabel"> - <property name="sizePolicy"> - <sizepolicy hsizetype="Fixed" vsizetype="Fixed"> - <horstretch>0</horstretch> - <verstretch>0</verstretch> - </sizepolicy> - </property> - <property name="text"> - <string/> - </property> - <property name="pixmap"> - <pixmap resource="../coreplugin/core.qrc">:/core/images/warning.png</pixmap> - </property> - </widget> - </item> - <item> - <widget class="QLabel" name="kitWarningLabel"> - <property name="sizePolicy"> - <sizepolicy hsizetype="Preferred" vsizetype="Preferred"> - <horstretch>0</horstretch> - <verstretch>0</verstretch> - </sizepolicy> - </property> - <property name="text"> - <string/> - </property> - <property name="wordWrap"> - <bool>true</bool> - </property> - </widget> - </item> - </layout> - </item> - <item row="2" column="1"> - <widget class="Utils::PathChooser" name="SDKLocationPathChooser" native="true"/> - </item> - <item row="5" column="1"> - <layout class="QHBoxLayout" name="horizontalLayout_6"> - <property name="spacing"> - <number>2</number> - </property> - <item> - <widget class="QLabel" name="gdbWarningIconLabel"> - <property name="sizePolicy"> - <sizepolicy hsizetype="Fixed" vsizetype="Fixed"> - <horstretch>0</horstretch> - <verstretch>0</verstretch> - </sizepolicy> - </property> - <property name="text"> - <string/> - </property> - <property name="pixmap"> - <pixmap resource="../coreplugin/core.qrc">:/core/images/error.png</pixmap> - </property> - </widget> - </item> - <item> - <widget class="QLabel" name="gdbWarningLabel"> - <property name="sizePolicy"> - <sizepolicy hsizetype="Expanding" vsizetype="Preferred"> - <horstretch>0</horstretch> - <verstretch>0</verstretch> - </sizepolicy> - </property> - <property name="text"> - <string><a href="xx">The GDB in the NDK appears to have broken python support.</a></string> - </property> - </widget> - </item> - </layout> - </item> - <item row="10" column="1"> - <widget class="QCheckBox" name="UseGradleCheckBox"> - <property name="sizePolicy"> - <sizepolicy hsizetype="Expanding" vsizetype="Fixed"> - <horstretch>0</horstretch> - <verstretch>0</verstretch> - </sizepolicy> - </property> - <property name="text"> - <string>Use Gradle instead of Ant</string> - </property> - </widget> - </item> </layout> </widget> <customwidgets> diff --git a/src/plugins/bazaar/bazaarplugin.cpp b/src/plugins/bazaar/bazaarplugin.cpp index 95d624247c..f6d537b3e6 100644 --- a/src/plugins/bazaar/bazaarplugin.cpp +++ b/src/plugins/bazaar/bazaarplugin.cpp @@ -162,8 +162,10 @@ bool BazaarPlugin::initialize(const QStringList &arguments, QString *errorMessag Q_UNUSED(arguments); Q_UNUSED(errorMessage); + Context context(Constants::BAZAAR_CONTEXT); + m_client = new BazaarClient(&m_bazaarSettings); - initializeVcs(new BazaarControl(m_client)); + initializeVcs(new BazaarControl(m_client), context); addAutoReleasedObject(new OptionsPage); m_bazaarSettings.readSettings(ICore::settings()); @@ -193,7 +195,7 @@ bool BazaarPlugin::initialize(const QStringList &arguments, QString *errorMessag m_commandLocator = new CommandLocator("Bazaar", prefix, prefix); addAutoReleasedObject(m_commandLocator); - createMenu(); + createMenu(context); createSubmitEditorActions(); @@ -226,10 +228,8 @@ void BazaarPlugin::setSettings(const BazaarSettings &settings) } } -void BazaarPlugin::createMenu() +void BazaarPlugin::createMenu(const Context &context) { - Context context(Core::Constants::C_GLOBAL); - // Create menu item for Bazaar m_bazaarContainer = ActionManager::createMenu("Bazaar.BazaarMenu"); QMenu *menu = m_bazaarContainer->menu(); diff --git a/src/plugins/bazaar/bazaarplugin.h b/src/plugins/bazaar/bazaarplugin.h index 906842119f..133a5cdc25 100644 --- a/src/plugins/bazaar/bazaarplugin.h +++ b/src/plugins/bazaar/bazaarplugin.h @@ -109,7 +109,7 @@ protected: private: // Functions - void createMenu(); + void createMenu(const Core::Context &context); void createSubmitEditorActions(); void createFileActions(const Core::Context &context); void createDirectoryActions(const Core::Context &context); diff --git a/src/plugins/bazaar/constants.h b/src/plugins/bazaar/constants.h index f4d5c6918b..38ec34e916 100644 --- a/src/plugins/bazaar/constants.h +++ b/src/plugins/bazaar/constants.h @@ -36,6 +36,7 @@ namespace Constants { const char BAZAAR[] = "bazaar"; const char BAZAARREPO[] = ".bzr"; const char BAZAARDEFAULT[] = "bzr"; +const char BAZAAR_CONTEXT[] = "Bazaar Context"; // Changeset identifiers const char CHANGESET_ID[] = "^(" diff --git a/src/plugins/clangcodemodel/ClangCodeModel.json.in b/src/plugins/clangcodemodel/ClangCodeModel.json.in index 743e5cecb3..c33dcd6975 100644 --- a/src/plugins/clangcodemodel/ClangCodeModel.json.in +++ b/src/plugins/clangcodemodel/ClangCodeModel.json.in @@ -11,7 +11,7 @@ \"\", \"GNU Lesser General Public License Usage\", \"\", - \"Alternatively, this plugin may be used under the terms of the GNU Lesser General Public License version 2.1 as published by the Free Software Foundation. Please review the following information to ensure the GNU Lesser General Public License version 2.1 requirements will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.\" + \"Alternatively, this plugin may be used under the terms of the GNU Lesser General Public License version 2.1 or version 3 as published by the Free Software Foundation. Please review the following information to ensure the GNU Lesser General Public License requirements will be met: https://www.gnu.org/licenses/lgpl.html and http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.\" ], \"Category\" : \"C++\", \"Description\" : \"Clang Code Model plugin.\", diff --git a/src/plugins/clearcase/clearcaseplugin.cpp b/src/plugins/clearcase/clearcaseplugin.cpp index 67fd8ef7a6..c77a3aa458 100644 --- a/src/plugins/clearcase/clearcaseplugin.cpp +++ b/src/plugins/clearcase/clearcaseplugin.cpp @@ -111,6 +111,7 @@ using namespace Utils; namespace ClearCase { namespace Internal { +static const char CLEARCASE_CONTEXT[] = "ClearCase Context"; static const char CMD_ID_CLEARCASE_MENU[] = "ClearCase.Menu"; static const char CMD_ID_CHECKOUT[] = "ClearCase.CheckOut"; static const char CMD_ID_CHECKIN[] = "ClearCase.CheckInCurrent"; @@ -437,7 +438,9 @@ bool ClearCasePlugin::initialize(const QStringList & /*arguments */, QString *er using namespace Constants; using namespace Core::Constants; - initializeVcs(new ClearCaseControl(this)); + Context context(CLEARCASE_CONTEXT); + + initializeVcs(new ClearCaseControl(this), context); m_clearcasePluginInstance = this; connect(ICore::instance(), SIGNAL(coreAboutToClose()), this, SLOT(closing())); @@ -478,12 +481,11 @@ bool ClearCasePlugin::initialize(const QStringList & /*arguments */, QString *er clearcaseMenu->menu()->setTitle(tr("C&learCase")); toolsContainer->addMenu(clearcaseMenu); m_menuAction = clearcaseMenu->menu()->menuAction(); - Context globalcontext(C_GLOBAL); Command *command; m_checkOutAction = new ParameterAction(tr("Check Out..."), tr("Check &Out \"%1\"..."), ParameterAction::AlwaysEnabled, this); command = ActionManager::registerAction(m_checkOutAction, CMD_ID_CHECKOUT, - globalcontext); + context); command->setAttribute(Command::CA_UpdateText); command->setDefaultKeySequence(QKeySequence(UseMacShortcuts ? tr("Meta+L,Meta+O") : tr("Alt+L,Alt+O"))); connect(m_checkOutAction, SIGNAL(triggered()), this, SLOT(checkOutCurrentFile())); @@ -491,7 +493,7 @@ bool ClearCasePlugin::initialize(const QStringList & /*arguments */, QString *er m_commandLocator->appendCommand(command); m_checkInCurrentAction = new ParameterAction(tr("Check &In..."), tr("Check &In \"%1\"..."), ParameterAction::AlwaysEnabled, this); - command = ActionManager::registerAction(m_checkInCurrentAction, CMD_ID_CHECKIN, globalcontext); + command = ActionManager::registerAction(m_checkInCurrentAction, CMD_ID_CHECKIN, context); command->setAttribute(Command::CA_UpdateText); command->setDefaultKeySequence(QKeySequence(UseMacShortcuts ? tr("Meta+L,Meta+I") : tr("Alt+L,Alt+I"))); connect(m_checkInCurrentAction, SIGNAL(triggered()), this, SLOT(startCheckInCurrentFile())); @@ -499,7 +501,7 @@ bool ClearCasePlugin::initialize(const QStringList & /*arguments */, QString *er m_commandLocator->appendCommand(command); m_undoCheckOutAction = new ParameterAction(tr("Undo Check Out"), tr("&Undo Check Out \"%1\""), ParameterAction::AlwaysEnabled, this); - command = ActionManager::registerAction(m_undoCheckOutAction, CMD_ID_UNDOCHECKOUT, globalcontext); + command = ActionManager::registerAction(m_undoCheckOutAction, CMD_ID_UNDOCHECKOUT, context); command->setAttribute(Command::CA_UpdateText); command->setDefaultKeySequence(QKeySequence(UseMacShortcuts ? tr("Meta+L,Meta+U") : tr("Alt+L,Alt+U"))); connect(m_undoCheckOutAction, SIGNAL(triggered()), this, SLOT(undoCheckOutCurrent())); @@ -507,18 +509,18 @@ bool ClearCasePlugin::initialize(const QStringList & /*arguments */, QString *er m_commandLocator->appendCommand(command); m_undoHijackAction = new ParameterAction(tr("Undo Hijack"), tr("Undo Hi&jack \"%1\""), ParameterAction::AlwaysEnabled, this); - command = ActionManager::registerAction(m_undoHijackAction, CMD_ID_UNDOHIJACK, globalcontext); + command = ActionManager::registerAction(m_undoHijackAction, CMD_ID_UNDOHIJACK, context); command->setAttribute(Command::CA_UpdateText); command->setDefaultKeySequence(QKeySequence(UseMacShortcuts ? tr("Meta+L,Meta+R") : tr("Alt+L,Alt+R"))); connect(m_undoHijackAction, SIGNAL(triggered()), this, SLOT(undoHijackCurrent())); clearcaseMenu->addAction(command); m_commandLocator->appendCommand(command); - clearcaseMenu->addSeparator(globalcontext); + clearcaseMenu->addSeparator(context); m_diffCurrentAction = new ParameterAction(tr("Diff Current File"), tr("&Diff \"%1\""), ParameterAction::EnabledWithParameter, this); command = ActionManager::registerAction(m_diffCurrentAction, - CMD_ID_DIFF_CURRENT, globalcontext); + CMD_ID_DIFF_CURRENT, context); command->setAttribute(Command::CA_UpdateText); command->setDefaultKeySequence(QKeySequence(UseMacShortcuts ? tr("Meta+L,Meta+D") : tr("Alt+L,Alt+D"))); connect(m_diffCurrentAction, SIGNAL(triggered()), this, SLOT(diffCurrentFile())); @@ -527,7 +529,7 @@ bool ClearCasePlugin::initialize(const QStringList & /*arguments */, QString *er m_historyCurrentAction = new ParameterAction(tr("History Current File"), tr("&History \"%1\""), ParameterAction::EnabledWithParameter, this); command = ActionManager::registerAction(m_historyCurrentAction, - CMD_ID_HISTORY_CURRENT, globalcontext); + CMD_ID_HISTORY_CURRENT, context); command->setAttribute(Command::CA_UpdateText); command->setDefaultKeySequence(QKeySequence(UseMacShortcuts ? tr("Meta+L,Meta+H") : tr("Alt+L,Alt+H"))); connect(m_historyCurrentAction, SIGNAL(triggered()), this, @@ -537,7 +539,7 @@ bool ClearCasePlugin::initialize(const QStringList & /*arguments */, QString *er m_annotateCurrentAction = new ParameterAction(tr("Annotate Current File"), tr("&Annotate \"%1\""), ParameterAction::EnabledWithParameter, this); command = ActionManager::registerAction(m_annotateCurrentAction, - CMD_ID_ANNOTATE, globalcontext); + CMD_ID_ANNOTATE, context); command->setAttribute(Command::CA_UpdateText); command->setDefaultKeySequence(QKeySequence(UseMacShortcuts ? tr("Meta+L,Meta+A") : tr("Alt+L,Alt+A"))); connect(m_annotateCurrentAction, SIGNAL(triggered()), this, @@ -546,52 +548,52 @@ bool ClearCasePlugin::initialize(const QStringList & /*arguments */, QString *er m_commandLocator->appendCommand(command); m_addFileAction = new ParameterAction(tr("Add File..."), tr("Add File \"%1\""), ParameterAction::EnabledWithParameter, this); - command = ActionManager::registerAction(m_addFileAction, CMD_ID_ADD_FILE, globalcontext); + command = ActionManager::registerAction(m_addFileAction, CMD_ID_ADD_FILE, context); command->setAttribute(Command::CA_UpdateText); connect(m_addFileAction, SIGNAL(triggered()), this, SLOT(addCurrentFile())); clearcaseMenu->addAction(command); - clearcaseMenu->addSeparator(globalcontext); + clearcaseMenu->addSeparator(context); m_diffActivityAction = new QAction(tr("Diff A&ctivity..."), this); m_diffActivityAction->setEnabled(false); - command = ActionManager::registerAction(m_diffActivityAction, CMD_ID_DIFF_ACTIVITY, globalcontext); + command = ActionManager::registerAction(m_diffActivityAction, CMD_ID_DIFF_ACTIVITY, context); connect(m_diffActivityAction, SIGNAL(triggered()), this, SLOT(diffActivity())); clearcaseMenu->addAction(command); m_commandLocator->appendCommand(command); m_checkInActivityAction = new ParameterAction(tr("Ch&eck In Activity"), tr("Chec&k In Activity \"%1\"..."), ParameterAction::EnabledWithParameter, this); m_checkInActivityAction->setEnabled(false); - command = ActionManager::registerAction(m_checkInActivityAction, CMD_ID_CHECKIN_ACTIVITY, globalcontext); + command = ActionManager::registerAction(m_checkInActivityAction, CMD_ID_CHECKIN_ACTIVITY, context); connect(m_checkInActivityAction, SIGNAL(triggered()), this, SLOT(startCheckInActivity())); command->setAttribute(Command::CA_UpdateText); clearcaseMenu->addAction(command); m_commandLocator->appendCommand(command); - clearcaseMenu->addSeparator(globalcontext); + clearcaseMenu->addSeparator(context); m_updateIndexAction = new QAction(tr("Update Index"), this); - command = ActionManager::registerAction(m_updateIndexAction, CMD_ID_UPDATEINDEX, globalcontext); + command = ActionManager::registerAction(m_updateIndexAction, CMD_ID_UPDATEINDEX, context); connect(m_updateIndexAction, SIGNAL(triggered()), this, SLOT(updateIndex())); clearcaseMenu->addAction(command); m_updateViewAction = new ParameterAction(tr("Update View"), tr("U&pdate View \"%1\""), ParameterAction::EnabledWithParameter, this); - command = ActionManager::registerAction(m_updateViewAction, CMD_ID_UPDATE_VIEW, globalcontext); + command = ActionManager::registerAction(m_updateViewAction, CMD_ID_UPDATE_VIEW, context); connect(m_updateViewAction, SIGNAL(triggered()), this, SLOT(updateView())); command->setAttribute(Command::CA_UpdateText); clearcaseMenu->addAction(command); - clearcaseMenu->addSeparator(globalcontext); + clearcaseMenu->addSeparator(context); m_checkInAllAction = new QAction(tr("Check In All &Files..."), this); - command = ActionManager::registerAction(m_checkInAllAction, CMD_ID_CHECKIN_ALL, globalcontext); + command = ActionManager::registerAction(m_checkInAllAction, CMD_ID_CHECKIN_ALL, context); command->setDefaultKeySequence(QKeySequence(UseMacShortcuts ? tr("Meta+L,Meta+F") : tr("Alt+L,Alt+F"))); connect(m_checkInAllAction, SIGNAL(triggered()), this, SLOT(startCheckInAll())); clearcaseMenu->addAction(command); m_commandLocator->appendCommand(command); m_statusAction = new QAction(tr("View &Status"), this); - command = ActionManager::registerAction(m_statusAction, CMD_ID_STATUS, globalcontext); + command = ActionManager::registerAction(m_statusAction, CMD_ID_STATUS, context); command->setDefaultKeySequence(QKeySequence(UseMacShortcuts ? tr("Meta+L,Meta+S") : tr("Alt+L,Alt+S"))); connect(m_statusAction, SIGNAL(triggered()), this, SLOT(viewStatus())); clearcaseMenu->addAction(command); diff --git a/src/plugins/cmakeprojectmanager/cmakeproject.cpp b/src/plugins/cmakeprojectmanager/cmakeproject.cpp index b1d7db64b7..75c300f210 100644 --- a/src/plugins/cmakeprojectmanager/cmakeproject.cpp +++ b/src/plugins/cmakeprojectmanager/cmakeproject.cpp @@ -853,12 +853,22 @@ void CMakeBuildSettingsWidget::runCMake() // CMakeCbpParser //// +namespace { +int distance(const QString &targetDirectory, const Utils::FileName &fileName) +{ + const QString commonParent = Utils::commonPath(QStringList() << targetDirectory << fileName.toString()); + return targetDirectory.mid(commonParent.size()).count(QLatin1Char('/')) + + fileName.toString().mid(commonParent.size()).count(QLatin1Char('/')); +} +} + // called after everything is parsed // this function tries to figure out to which CMakeBuildTarget // each file belongs, so that it gets the appropriate defines and // compiler flags void CMakeCbpParser::sortFiles() { + QLoggingCategory log("qtc.cmakeprojectmanager.filetargetmapping"); QList<Utils::FileName> fileNames = Utils::transform(m_fileList, [] (FileNode *node) { return Utils::FileName::fromString(node->path()); }); @@ -869,12 +879,21 @@ void CMakeCbpParser::sortFiles() CMakeBuildTarget *last = 0; Utils::FileName parentDirectory; + qCDebug(log) << "###############"; + qCDebug(log) << "# Pre Dump #"; + qCDebug(log) << "###############"; + foreach (const CMakeBuildTarget &target, m_buildTargets) + qCDebug(log) << target.title << target.sourceDirectory << + target.includeFiles << target.defines << target.files << "\n"; + // find a good build target to fall back int fallbackIndex = 0; { int bestIncludeCount = -1; for (int i = 0; i < m_buildTargets.size(); ++i) { const CMakeBuildTarget &target = m_buildTargets.at(i); + if (target.includeFiles.isEmpty()) + continue; if (target.sourceDirectory == m_sourceDirectory && target.includeFiles.count() > bestIncludeCount) { bestIncludeCount = target.includeFiles.count(); @@ -883,37 +902,55 @@ void CMakeCbpParser::sortFiles() } } + qCDebug(log) << "###############"; + qCDebug(log) << "# Sorting #"; + qCDebug(log) << "###############"; + foreach (const Utils::FileName &fileName, fileNames) { + qCDebug(log) << fileName; if (fileName.parentDir() == parentDirectory && last) { // easy case, same parent directory as last file last->files.append(fileName.toString()); + qCDebug(log) << " into" << last->title; } else { - int bestLength = -1; + int bestDistance = std::numeric_limits<int>::max(); int bestIndex = -1; int bestIncludeCount = -1; for (int i = 0; i < m_buildTargets.size(); ++i) { const CMakeBuildTarget &target = m_buildTargets.at(i); - if (fileName.isChildOf(Utils::FileName::fromString(target.sourceDirectory)) && - (target.sourceDirectory.size() > bestLength || - (target.sourceDirectory.size() == bestLength && - target.includeFiles.count() > bestIncludeCount))) { - bestLength = target.sourceDirectory.size(); + if (target.includeFiles.isEmpty()) + continue; + int dist = distance(target.sourceDirectory, fileName); + qCDebug(log) << "distance to target" << target.title << dist; + if (dist < bestDistance || + (dist == bestDistance && + target.includeFiles.count() > bestIncludeCount)) { + bestDistance = dist; bestIncludeCount = target.includeFiles.count(); bestIndex = i; } } - if (bestIndex == -1 && !m_buildTargets.isEmpty()) + if (bestIndex == -1 && !m_buildTargets.isEmpty()) { bestIndex = fallbackIndex; + qCDebug(log) << " using fallbackIndex"; + } if (bestIndex != -1) { m_buildTargets[bestIndex].files.append(fileName.toString()); last = &m_buildTargets[bestIndex]; parentDirectory = fileName.parentDir(); + qCDebug(log) << " into" << last->title; } } } + + qCDebug(log) << "###############"; + qCDebug(log) << "# After Dump #"; + qCDebug(log) << "###############"; + foreach (const CMakeBuildTarget &target, m_buildTargets) + qCDebug(log) << target.title << target.sourceDirectory << target.includeFiles << target.defines << target.files << "\n"; } bool CMakeCbpParser::parseCbpFile(const QString &fileName, const QString &sourceDirectory) diff --git a/src/plugins/coreplugin/actionmanager/actioncontainer.cpp b/src/plugins/coreplugin/actionmanager/actioncontainer.cpp index 893e217937..6cf8ba718e 100644 --- a/src/plugins/coreplugin/actionmanager/actioncontainer.cpp +++ b/src/plugins/coreplugin/actionmanager/actioncontainer.cpp @@ -307,18 +307,6 @@ Command *ActionContainerPrivate::addSeparator(const Context &context, Id group, return cmd; } -void ActionContainerPrivate::setEnabled(bool enabled) -{ - foreach (const Group &group, m_groups) { - foreach (QObject *item, group.items) { - if (Command *command = qobject_cast<Command *>(item)) - command->action()->setEnabled(enabled); - else if (ActionContainer *container = qobject_cast<ActionContainer *>(item)) - container->setEnabled(enabled); - } - } -} - void ActionContainerPrivate::clear() { QMutableListIterator<Group> it(m_groups); diff --git a/src/plugins/coreplugin/actionmanager/actioncontainer.h b/src/plugins/coreplugin/actionmanager/actioncontainer.h index 4f03da9617..4c3c9d9cff 100644 --- a/src/plugins/coreplugin/actionmanager/actioncontainer.h +++ b/src/plugins/coreplugin/actionmanager/actioncontainer.h @@ -72,7 +72,6 @@ public: virtual void addMenu(ActionContainer *menu, Id group = Id()) = 0; virtual void addMenu(ActionContainer *before, ActionContainer *menu, Id group = Id()) = 0; virtual Command *addSeparator(const Context &context, Id group = Id(), QAction **outSeparator = 0) = 0; - virtual void setEnabled(bool enabled) = 0; // This clears this menu and submenus from all actions and submenus. // It does not destroy the submenus and commands, just removes them from their parents. diff --git a/src/plugins/coreplugin/actionmanager/actioncontainer_p.h b/src/plugins/coreplugin/actionmanager/actioncontainer_p.h index 5d7d7de6fe..4434c0b65b 100644 --- a/src/plugins/coreplugin/actionmanager/actioncontainer_p.h +++ b/src/plugins/coreplugin/actionmanager/actioncontainer_p.h @@ -64,7 +64,6 @@ public: void addMenu(ActionContainer *menu, Id group = Id()); void addMenu(ActionContainer *before, ActionContainer *menu, Id group = Id()); Command *addSeparator(const Context &context, Id group = Id(), QAction **outSeparator = 0); - void setEnabled(bool enabled); virtual void clear(); Id id() const; diff --git a/src/plugins/coreplugin/coreplugin.cpp b/src/plugins/coreplugin/coreplugin.cpp index cf7541140a..bf058c6ca4 100644 --- a/src/plugins/coreplugin/coreplugin.cpp +++ b/src/plugins/coreplugin/coreplugin.cpp @@ -48,6 +48,7 @@ #include <utils/savefile.h> #include <utils/stringutils.h> #include <utils/theme/theme.h> +#include <utils/theme/theme_p.h> #include <QtPlugin> #include <QDebug> @@ -90,11 +91,36 @@ CorePlugin::~CorePlugin() setCreatorTheme(0); } +static QString absoluteThemePath(const QString &themeName) +{ + if (themeName.isEmpty()) + return themeName; + QString res = QDir::fromNativeSeparators(themeName); + QFileInfo fi(res); + // Try the given name + if (fi.exists()) + return fi.absoluteFilePath(); + const QString suffix = QLatin1String("creatortheme"); + // Try name.creatortheme + if (fi.suffix() != suffix) { + res = themeName + QLatin1Char('.') + suffix; + fi.setFile(res); + if (fi.exists()) + return fi.absoluteFilePath(); + } + if (fi.path().isEmpty()) + return QString(); // absolute/relative path, but not found + // If only name was given, look it up in qtcreator/themes + res.prepend(ICore::resourcePath() + QLatin1String("/themes/")); + return QFileInfo::exists(res) ? res : QString(); +} + void CorePlugin::parseArguments(const QStringList &arguments) { - QString themeName = QLatin1String("default"); + const QString defaultTheme = QLatin1String("default"); + QString themeName = ICore::settings()->value( + QLatin1String(Constants::SETTINGS_THEME), defaultTheme).toString(); QColor overrideColor; - bool overrideTheme = false; bool presentationMode = false; for (int i = 0; i < arguments.size(); ++i) { @@ -106,34 +132,27 @@ void CorePlugin::parseArguments(const QStringList &arguments) if (arguments.at(i) == QLatin1String("-presentationMode")) presentationMode = true; if (arguments.at(i) == QLatin1String("-theme")) { - overrideTheme = true; themeName = arguments.at(i + 1); i++; } } - QSettings *settings = Core::ICore::settings(); - QString themeURI = settings->value(QLatin1String(Core::Constants::SETTINGS_THEME)).toString(); - - if (!QFileInfo::exists(themeURI) || overrideTheme) { - const QString builtInTheme = QStringLiteral("%1/themes/%2.creatortheme") - .arg(ICore::resourcePath()).arg(themeName); - if (QFile::exists(builtInTheme)) { - themeURI = builtInTheme; - } else if (themeName.endsWith(QLatin1String(".creatortheme"))) { - themeURI = themeName; - } else { // TODO: Fallback to default theme + QString themeURI = absoluteThemePath(themeName); + if (themeURI.isEmpty()) { + themeName = defaultTheme; + themeURI = QStringLiteral("%1/themes/%2.creatortheme").arg(ICore::resourcePath()).arg(themeName); + if (themeURI.isEmpty()) { qCritical("%s", qPrintable(QCoreApplication::translate("Application", "No valid theme \"%1\"") .arg(themeName))); } } QSettings themeSettings(themeURI, QSettings::IniFormat); - Theme *theme = new Theme(qApp); + Theme *theme = new Theme(themeName, qApp); theme->readSettings(themeSettings); - setCreatorTheme(theme); if (theme->flag(Theme::ApplyThemePaletteGlobally)) - QApplication::setPalette(creatorTheme()->palette(QApplication::palette())); + QApplication::setPalette(theme->palette()); + setCreatorTheme(theme); // defer creation of these widgets until here, // because they need a valid theme set @@ -148,6 +167,7 @@ void CorePlugin::parseArguments(const QStringList &arguments) bool CorePlugin::initialize(const QStringList &arguments, QString *errorMessage) { + Theme::initialPalette(); // Initialize palette before setting it qsrand(QDateTime::currentDateTime().toTime_t()); parseArguments(arguments); const bool success = m_mainWindow->init(errorMessage); diff --git a/src/plugins/coreplugin/coreplugin.h b/src/plugins/coreplugin/coreplugin.h index fafc896a0c..ffc8df457e 100644 --- a/src/plugins/coreplugin/coreplugin.h +++ b/src/plugins/coreplugin/coreplugin.h @@ -33,6 +33,8 @@ #include <extensionsystem/iplugin.h> +namespace Utils { class Theme; } + namespace Core { class DesignMode; diff --git a/src/plugins/coreplugin/designmode.cpp b/src/plugins/coreplugin/designmode.cpp index 598f7cd136..49f99650fa 100644 --- a/src/plugins/coreplugin/designmode.cpp +++ b/src/plugins/coreplugin/designmode.cpp @@ -247,13 +247,10 @@ void DesignMode::updateActions() void DesignMode::updateContext(Core::IMode *newMode, Core::IMode *oldMode) { - if (newMode == this) { - // Apply active context - Core::ICore::updateAdditionalContexts(Context(), d->m_activeContext); - } else if (oldMode == this) { - // Remove active context - Core::ICore::updateAdditionalContexts(d->m_activeContext, Context()); - } + if (newMode == this) + ICore::addAdditionalContext(d->m_activeContext); + else if (oldMode == this) + ICore::removeAdditionalContext(d->m_activeContext); } void DesignMode::setActiveContext(const Context &context) diff --git a/src/plugins/coreplugin/dialogs/settingsdialog.cpp b/src/plugins/coreplugin/dialogs/settingsdialog.cpp index 6aaed1a092..22975a9f3e 100644 --- a/src/plugins/coreplugin/dialogs/settingsdialog.cpp +++ b/src/plugins/coreplugin/dialogs/settingsdialog.cpp @@ -412,7 +412,6 @@ void SettingsDialog::createGui() QDialogButtonBox *buttonBox = new QDialogButtonBox(QDialogButtonBox::Ok | QDialogButtonBox::Apply | QDialogButtonBox::Cancel); - buttonBox->button(QDialogButtonBox::Ok)->setDefault(true); connect(buttonBox->button(QDialogButtonBox::Apply), SIGNAL(clicked()), this, SLOT(apply())); connect(buttonBox, SIGNAL(accepted()), this, SLOT(accept())); connect(buttonBox, SIGNAL(rejected()), this, SLOT(reject())); @@ -425,6 +424,9 @@ void SettingsDialog::createGui() mainGridLayout->addWidget(buttonBox, 2, 0, 1, 2); mainGridLayout->setColumnStretch(1, 4); setLayout(mainGridLayout); + + buttonBox->button(QDialogButtonBox::Ok)->setDefault(true); + setMinimumSize(1000, 550); if (Utils::HostOsInfo::isMacHost()) setMinimumHeight(minimumHeight() * 1.1); diff --git a/src/plugins/coreplugin/documentmanager.cpp b/src/plugins/coreplugin/documentmanager.cpp index 87261bf7ea..dbf647afdc 100644 --- a/src/plugins/coreplugin/documentmanager.cpp +++ b/src/plugins/coreplugin/documentmanager.cpp @@ -723,13 +723,16 @@ QString DocumentManager::getSaveAsFileName(const IDocument *document, const QStr return QLatin1String(""); QString absoluteFilePath = document->filePath(); const QFileInfo fi(absoluteFilePath); - QString fileName = fi.fileName(); - QString path = fi.absolutePath(); + QString path; + QString fileName; if (absoluteFilePath.isEmpty()) { fileName = document->suggestedFileName(); const QString defaultPath = document->defaultPath(); if (!defaultPath.isEmpty()) path = defaultPath; + } else { + path = fi.absolutePath(); + fileName = fi.fileName(); } QString filterString; @@ -905,14 +908,16 @@ void DocumentManager::checkForReload() if (!QApplication::activeWindow()) return; - if (QApplication::activeModalWidget()) { // a modal dialog, recheck later + if (QApplication::activeModalWidget() || d->m_blockActivated) { + // We do not want to prompt for modified file if we currently have some modal dialog open. + // If d->m_blockActivated is true, then it means that the event processing of either the + // file modified dialog, or of loading large files, has delivered a file change event from + // a watcher *and* the timer triggered. We may never end up here in a nested way, so + // recheck later. QTimer::singleShot(200, this, SLOT(checkForReload())); return; } - if (d->m_blockActivated) - return; - d->m_blockActivated = true; IDocument::ReloadSetting defaultBehavior = EditorManagerPrivate::reloadSetting(); @@ -1006,6 +1011,14 @@ void DocumentManager::checkForReload() // handle it! d->m_blockedIDocument = document; + // Update file info, also handling if e.g. link target has changed. + // We need to do that before the file is reloaded, because removing the watcher will + // loose any pending change events. Loosing change events *before* the file is reloaded + // doesn't matter, because in that case we then reload the new version of the file already + // anyhow. + removeFileInfo(document); + addFileInfo(document); + bool success = true; QString errorString; // we've got some modification @@ -1107,9 +1120,6 @@ void DocumentManager::checkForReload() errorStrings << errorString; } - // update file info, also handling if e.g. link target has changed - removeFileInfo(document); - addFileInfo(document); d->m_blockedIDocument = 0; } if (!errorStrings.isEmpty()) diff --git a/src/plugins/coreplugin/editormanager/editormanager.cpp b/src/plugins/coreplugin/editormanager/editormanager.cpp index 6a72d24265..1ff1d26552 100644 --- a/src/plugins/coreplugin/editormanager/editormanager.cpp +++ b/src/plugins/coreplugin/editormanager/editormanager.cpp @@ -1009,7 +1009,7 @@ IEditor *EditorManagerPrivate::activateEditor(EditorView *view, IEditor *editor, setCurrentEditor(editor, (flags & EditorManager::IgnoreNavigationHistory)); if (!(flags & EditorManager::DoNotMakeVisible)) { // switch to design mode? - if (editor->isDesignModePreferred()) { + if (!(flags & EditorManager::DoNotSwitchToDesignMode) && editor->isDesignModePreferred()) { ModeManager::activateMode(Core::Constants::MODE_DESIGN); ModeManager::setFocusToCurrentMode(); } else { diff --git a/src/plugins/coreplugin/editormanager/editormanager.h b/src/plugins/coreplugin/editormanager/editormanager.h index 41cb9c2993..e4393c3dc9 100644 --- a/src/plugins/coreplugin/editormanager/editormanager.h +++ b/src/plugins/coreplugin/editormanager/editormanager.h @@ -106,7 +106,8 @@ public: IgnoreNavigationHistory = 2, DoNotMakeVisible = 4, CanContainLineNumber = 8, - OpenInOtherSplit = 16 + OpenInOtherSplit = 16, + DoNotSwitchToDesignMode = 32 }; Q_DECLARE_FLAGS(OpenEditorFlags, OpenEditorFlag) diff --git a/src/plugins/coreplugin/find/searchresultwindow.cpp b/src/plugins/coreplugin/find/searchresultwindow.cpp index 930bc906a7..dd940a6747 100644 --- a/src/plugins/coreplugin/find/searchresultwindow.cpp +++ b/src/plugins/coreplugin/find/searchresultwindow.cpp @@ -449,7 +449,10 @@ void SearchResultWindow::clearContents() */ bool SearchResultWindow::hasFocus() const { - return d->m_widget->focusWidget() && d->m_widget->focusWidget()->hasFocus(); + QWidget *widget = d->m_widget->focusWidget(); + if (!widget) + return false; + return widget->window()->focusWidget() == widget; } /*! diff --git a/src/plugins/coreplugin/generalsettings.cpp b/src/plugins/coreplugin/generalsettings.cpp index 02dff644d4..53cde45436 100644 --- a/src/plugins/coreplugin/generalsettings.cpp +++ b/src/plugins/coreplugin/generalsettings.cpp @@ -188,6 +188,7 @@ void GeneralSettings::apply() PatchTool::setPatchCommand(m_page->patchChooser->path()); EditorManagerPrivate::setAutoSaveEnabled(m_page->autoSaveCheckBox->isChecked()); EditorManagerPrivate::setAutoSaveInterval(m_page->autoSaveInterval->value()); + m_page->themeWidget->apply(); } void GeneralSettings::finish() diff --git a/src/plugins/coreplugin/icore.cpp b/src/plugins/coreplugin/icore.cpp index 495b202fe4..256c06bf27 100644 --- a/src/plugins/coreplugin/icore.cpp +++ b/src/plugins/coreplugin/icore.cpp @@ -514,6 +514,16 @@ void ICore::updateAdditionalContexts(const Context &remove, const Context &add) m_mainwindow->updateAdditionalContexts(remove, add); } +void ICore::addAdditionalContext(const Context &context) +{ + m_mainwindow->updateAdditionalContexts(Context(), context); +} + +void ICore::removeAdditionalContext(const Context &context) +{ + m_mainwindow->updateAdditionalContexts(context, Context()); +} + void ICore::addContextObject(IContext *context) { m_mainwindow->addContextObject(context); diff --git a/src/plugins/coreplugin/icore.h b/src/plugins/coreplugin/icore.h index 64ee8155dc..ce7fcd1658 100644 --- a/src/plugins/coreplugin/icore.h +++ b/src/plugins/coreplugin/icore.h @@ -107,6 +107,8 @@ public: // Adds and removes additional active contexts, these contexts are appended // to the currently active contexts. static void updateAdditionalContexts(const Context &remove, const Context &add); + static void addAdditionalContext(const Context &context); + static void removeAdditionalContext(const Context &context); static void addContextObject(IContext *context); static void removeContextObject(IContext *context); @@ -137,6 +139,7 @@ signals: void coreAboutToClose(); void contextAboutToChange(const QList<Core::IContext *> &context); void contextChanged(const QList<Core::IContext *> &context, const Core::Context &additionalContexts); + void themeChanged(); }; } // namespace Core diff --git a/src/plugins/coreplugin/images/logo/128/QtProject-qtcreator.png b/src/plugins/coreplugin/images/logo/128/QtProject-qtcreator.png Binary files differindex c24d1d9eb9..b7d8b35ea4 100644 --- a/src/plugins/coreplugin/images/logo/128/QtProject-qtcreator.png +++ b/src/plugins/coreplugin/images/logo/128/QtProject-qtcreator.png diff --git a/src/plugins/coreplugin/images/logo/16/QtProject-qtcreator.png b/src/plugins/coreplugin/images/logo/16/QtProject-qtcreator.png Binary files differindex eb218d703e..e1adcdc5c2 100644 --- a/src/plugins/coreplugin/images/logo/16/QtProject-qtcreator.png +++ b/src/plugins/coreplugin/images/logo/16/QtProject-qtcreator.png diff --git a/src/plugins/coreplugin/images/logo/24/QtProject-qtcreator.png b/src/plugins/coreplugin/images/logo/24/QtProject-qtcreator.png Binary files differindex d6a2ab0c51..5a0674d0a0 100644 --- a/src/plugins/coreplugin/images/logo/24/QtProject-qtcreator.png +++ b/src/plugins/coreplugin/images/logo/24/QtProject-qtcreator.png diff --git a/src/plugins/coreplugin/images/logo/256/QtProject-qtcreator.png b/src/plugins/coreplugin/images/logo/256/QtProject-qtcreator.png Binary files differindex 58090bc3d0..4fc92d89f5 100644 --- a/src/plugins/coreplugin/images/logo/256/QtProject-qtcreator.png +++ b/src/plugins/coreplugin/images/logo/256/QtProject-qtcreator.png diff --git a/src/plugins/coreplugin/images/logo/32/QtProject-qtcreator.png b/src/plugins/coreplugin/images/logo/32/QtProject-qtcreator.png Binary files differindex 07e8d08df4..58d934aa89 100644 --- a/src/plugins/coreplugin/images/logo/32/QtProject-qtcreator.png +++ b/src/plugins/coreplugin/images/logo/32/QtProject-qtcreator.png diff --git a/src/plugins/coreplugin/images/logo/48/QtProject-qtcreator.png b/src/plugins/coreplugin/images/logo/48/QtProject-qtcreator.png Binary files differindex ae3551a61b..bef97356bd 100644 --- a/src/plugins/coreplugin/images/logo/48/QtProject-qtcreator.png +++ b/src/plugins/coreplugin/images/logo/48/QtProject-qtcreator.png diff --git a/src/plugins/coreplugin/images/logo/512/QtProject-qtcreator.png b/src/plugins/coreplugin/images/logo/512/QtProject-qtcreator.png Binary files differindex c56fb0383e..556e512aed 100644 --- a/src/plugins/coreplugin/images/logo/512/QtProject-qtcreator.png +++ b/src/plugins/coreplugin/images/logo/512/QtProject-qtcreator.png diff --git a/src/plugins/coreplugin/images/logo/64/QtProject-qtcreator.png b/src/plugins/coreplugin/images/logo/64/QtProject-qtcreator.png Binary files differindex 5b6847e812..4a5476ef9c 100644 --- a/src/plugins/coreplugin/images/logo/64/QtProject-qtcreator.png +++ b/src/plugins/coreplugin/images/logo/64/QtProject-qtcreator.png diff --git a/src/plugins/coreplugin/infobar.cpp b/src/plugins/coreplugin/infobar.cpp index a4a495545f..7aa89bf58e 100644 --- a/src/plugins/coreplugin/infobar.cpp +++ b/src/plugins/coreplugin/infobar.cpp @@ -207,7 +207,7 @@ void InfoBarDisplay::update() QPalette pal; pal.setColor(QPalette::Window, creatorTheme()->color(Theme::InfoBarBackground)); - pal.setColor(QPalette::WindowText, Theme::InfoBarText); + pal.setColor(QPalette::WindowText, creatorTheme()->color(Theme::InfoBarText)); infoWidget->setPalette(pal); infoWidget->setFrameStyle(QFrame::Panel | QFrame::Raised); diff --git a/src/plugins/coreplugin/mainwindow.cpp b/src/plugins/coreplugin/mainwindow.cpp index fe609f40fb..2db94d27dc 100644 --- a/src/plugins/coreplugin/mainwindow.cpp +++ b/src/plugins/coreplugin/mainwindow.cpp @@ -154,7 +154,7 @@ MainWindow::MainWindow() : Utils::HistoryCompleter::setSettings(PluginManager::settings()); setWindowTitle(tr("Qt Creator")); - if (!Utils::HostOsInfo::isMacHost()) + if (Utils::HostOsInfo::isLinuxHost()) QApplication::setWindowIcon(QIcon(QLatin1String(Constants::ICON_QTLOGO_128))); QCoreApplication::setApplicationName(QLatin1String("QtCreator")); QCoreApplication::setApplicationVersion(QLatin1String(Core::Constants::IDE_VERSION_LONG)); diff --git a/src/plugins/coreplugin/messageoutputwindow.cpp b/src/plugins/coreplugin/messageoutputwindow.cpp index ffbe83e146..53e62372cd 100644 --- a/src/plugins/coreplugin/messageoutputwindow.cpp +++ b/src/plugins/coreplugin/messageoutputwindow.cpp @@ -62,7 +62,7 @@ MessageOutputWindow::~MessageOutputWindow() bool MessageOutputWindow::hasFocus() const { - return m_widget->hasFocus(); + return m_widget->window()->focusWidget() == m_widget; } bool MessageOutputWindow::canFocus() const diff --git a/src/plugins/coreplugin/themeeditor/themesettingstablemodel.cpp b/src/plugins/coreplugin/themeeditor/themesettingstablemodel.cpp index 87826f87bb..ef92141759 100644 --- a/src/plugins/coreplugin/themeeditor/themesettingstablemodel.cpp +++ b/src/plugins/coreplugin/themeeditor/themesettingstablemodel.cpp @@ -267,7 +267,6 @@ void ThemeSettingsTableModel::toTheme(Theme *t) const theme->widgetStyle = m_widgetStyle; theme->name = m_name; theme->preferredStyles = m_preferredStyles; - emit t->changed(); } Qt::ItemFlags ThemeSettingsTableModel::sectionHeaderFlags(int section) const diff --git a/src/plugins/coreplugin/themesettings.ui b/src/plugins/coreplugin/themesettings.ui index 55bc0794ce..a429a24289 100644 --- a/src/plugins/coreplugin/themesettings.ui +++ b/src/plugins/coreplugin/themesettings.ui @@ -2,6 +2,14 @@ <ui version="4.0"> <class>Core::Internal::ThemeSettings</class> <widget class="QWidget" name="Core::Internal::ThemeSettings"> + <property name="geometry"> + <rect> + <x>0</x> + <y>0</y> + <width>338</width> + <height>40</height> + </rect> + </property> <layout class="QVBoxLayout" name="verticalLayout"> <property name="leftMargin"> <number>0</number> @@ -18,14 +26,7 @@ <item> <layout class="QHBoxLayout" name="horizontalLayout"> <item> - <widget class="QComboBox" name="themeComboBox"> - <property name="sizePolicy"> - <sizepolicy hsizetype="Expanding" vsizetype="Fixed"> - <horstretch>0</horstretch> - <verstretch>0</verstretch> - </sizepolicy> - </property> - </widget> + <widget class="QComboBox" name="themeComboBox"/> </item> <item> <widget class="QPushButton" name="renameButton"> @@ -48,6 +49,19 @@ </property> </widget> </item> + <item> + <spacer name="horizontalSpacer"> + <property name="orientation"> + <enum>Qt::Horizontal</enum> + </property> + <property name="sizeHint" stdset="0"> + <size> + <width>40</width> + <height>20</height> + </size> + </property> + </spacer> + </item> </layout> </item> <item> diff --git a/src/plugins/coreplugin/themesettingswidget.cpp b/src/plugins/coreplugin/themesettingswidget.cpp index ed5579ed3e..f1eaac7bb9 100644 --- a/src/plugins/coreplugin/themesettingswidget.cpp +++ b/src/plugins/coreplugin/themesettingswidget.cpp @@ -31,9 +31,11 @@ #include "themesettingswidget.h" #include "coreconstants.h" #include "icore.h" +#include "manhattanstyle.h" #include "themeeditor/themesettingstablemodel.h" #include <utils/theme/theme.h> +#include <utils/theme/theme_p.h> #include <utils/qtcassert.h> #include <QDebug> @@ -41,6 +43,7 @@ #include <QInputDialog> #include <QMessageBox> #include <QSettings> +#include <QStyleFactory> #include "ui_themesettings.h" @@ -53,9 +56,7 @@ const char themeNameKey[] = "ThemeName"; static QString customThemesPath() { - QString path = Core::ICore::userResourcePath(); - path.append(QLatin1String("/themes/")); - return path; + return ICore::userResourcePath() + QLatin1String("/themes/"); } static QString createThemeFileName(const QString &pattern) @@ -84,25 +85,35 @@ static QString createThemeFileName(const QString &pattern) struct ThemeEntry { ThemeEntry() {} - ThemeEntry(const QString &fileName, bool readOnly): - m_fileName(fileName), + ThemeEntry(const QString &name, const QString &filePath, bool readOnly): + m_name(name), + m_filePath(filePath), m_readOnly(readOnly) - { } + { + } - QString fileName() const { return m_fileName; } - QString name() const; + QString name() const { return m_name; } + QString displayName() const; + QString filePath() const { return m_filePath; } bool readOnly() const { return m_readOnly; } private: - QString m_fileName; + QString m_name; + QString m_filePath; + mutable QString m_displayName; bool m_readOnly; }; -QString ThemeEntry::name() const +QString ThemeEntry::displayName() const { - QSettings settings(m_fileName, QSettings::IniFormat); - QString n = settings.value(QLatin1String(themeNameKey), QCoreApplication::tr("unnamed")).toString(); - return m_readOnly ? QCoreApplication::tr("%1 (built-in)").arg(n) : n; + if (m_displayName.isEmpty()) { + QSettings settings(filePath(), QSettings::IniFormat); + m_displayName = settings.value(QLatin1String(themeNameKey), + QCoreApplication::tr("unnamed")).toString(); + if (false) // TODO: Revert to m_readOnly + m_displayName = QCoreApplication::tr("%1 (built-in)").arg(m_displayName); + } + return m_displayName; } @@ -122,7 +133,7 @@ public: QVariant data(const QModelIndex &index, int role) const { if (role == Qt::DisplayRole) - return m_themes.at(index.row()).name(); + return m_themes.at(index.row()).displayName(); return QVariant(); } @@ -168,9 +179,13 @@ ThemeSettingsPrivate::ThemeSettingsPrivate(QWidget *widget) , m_refreshingThemeList(false) , m_ui(new Ui::ThemeSettings) { - m_currentTheme = ThemeEntry(creatorTheme()->fileName(), true); + m_currentTheme = ThemeEntry(creatorTheme()->name(), creatorTheme()->filePath(), true); m_ui->setupUi(widget); - m_ui->editor->hide(); // TODO: Restore after improving the editor + // TODO: Restore the editor and the buttons after improving the editor + m_ui->editor->hide(); + m_ui->copyButton->hide(); + m_ui->deleteButton->hide(); + m_ui->renameButton->hide(); m_ui->themeComboBox->setModel(m_themeListModel); } @@ -203,22 +218,24 @@ void ThemeSettingsWidget::refreshThemeList() { QList<ThemeEntry> themes; - QString resourcePath = Core::ICore::resourcePath(); - QDir themeDir(resourcePath + QLatin1String("/themes")); + QDir themeDir(ICore::resourcePath() + QLatin1String("/themes")); themeDir.setNameFilters(QStringList() << QLatin1String("*.creatortheme")); themeDir.setFilter(QDir::Files); int selected = 0; QStringList themeList = themeDir.entryList(); - QString defaultTheme = QFileInfo(defaultThemeFileName()).fileName(); - if (themeList.removeAll(defaultTheme)) + const QString defaultTheme = QLatin1String("default.creatortheme"); + if (themeList.removeOne(defaultTheme)) themeList.prepend(defaultTheme); - foreach (const QString &file, themeList) { - const QString fileName = themeDir.absoluteFilePath(file); - if (d->m_currentTheme.fileName() == fileName) - selected = themes.size(); - themes.append(ThemeEntry(fileName, true)); + const QLatin1String extension(".creatortheme"); + for (int i = 0, total = themeList.count(); i < total; ++i) { + const QString fileName = themeList.at(i); + if (d->m_currentTheme.name() + extension == fileName) + selected = i; + QString name = fileName; + name.remove(extension); + themes.append(ThemeEntry(name, themeDir.absoluteFilePath(fileName), true)); } if (themes.isEmpty()) @@ -227,9 +244,9 @@ void ThemeSettingsWidget::refreshThemeList() themeDir.setPath(customThemesPath()); foreach (const QString &file, themeDir.entryList()) { const QString fileName = themeDir.absoluteFilePath(file); - if (d->m_currentTheme.fileName() == fileName) + if (d->m_currentTheme.name() == fileName) selected = themes.size(); - themes.append(ThemeEntry(fileName, false)); + themes.append(ThemeEntry(fileName, fileName, false)); } d->m_currentTheme = themes[selected]; @@ -240,19 +257,6 @@ void ThemeSettingsWidget::refreshThemeList() d->m_refreshingThemeList = false; } -QString ThemeSettingsWidget::defaultThemeFileName(const QString &fileName) -{ - QString defaultScheme = Core::ICore::resourcePath(); - defaultScheme += QLatin1String("/themes/"); - - if (!fileName.isEmpty() && QFile::exists(defaultScheme + fileName)) - defaultScheme += fileName; - else - defaultScheme += QLatin1String("default.creatortheme"); - - return defaultScheme; -} - void ThemeSettingsWidget::themeSelected(int index) { bool readOnly = true; @@ -265,8 +269,8 @@ void ThemeSettingsWidget::themeSelected(int index) readOnly = entry.readOnly(); d->m_currentTheme = entry; - QSettings settings(entry.fileName(), QSettings::IniFormat); - Theme theme; + QSettings settings(entry.filePath(), QSettings::IniFormat); + Theme theme(entry.name()); theme.readSettings(settings); d->m_ui->editor->initFrom(&theme); } @@ -288,7 +292,7 @@ void ThemeSettingsWidget::confirmDeleteTheme() QMessageBox *messageBox = new QMessageBox(QMessageBox::Warning, tr("Delete Theme"), - tr("Are you sure you want to delete the theme \"%1\" permanently?").arg(entry.name()), + tr("Are you sure you want to delete the theme \"%1\" permanently?").arg(entry.displayName()), QMessageBox::Discard | QMessageBox::Cancel, d->m_ui->deleteButton->window()); @@ -312,7 +316,7 @@ void ThemeSettingsWidget::deleteTheme() const ThemeEntry &entry = d->m_themeListModel->themeAt(index); QTC_ASSERT(!entry.readOnly(), return); - if (QFile::remove(entry.fileName())) + if (QFile::remove(entry.filePath())) d->m_themeListModel->removeTheme(index); } @@ -339,7 +343,7 @@ void ThemeSettingsWidget::maybeSaveTheme() QMessageBox *messageBox = new QMessageBox(QMessageBox::Warning, tr("Theme Changed"), tr("The theme \"%1\" was modified, do you want to save the changes?") - .arg(d->m_currentTheme.name()), + .arg(d->m_currentTheme.displayName()), QMessageBox::Discard | QMessageBox::Save, d->m_ui->themeComboBox->window()); @@ -350,9 +354,9 @@ void ThemeSettingsWidget::maybeSaveTheme() messageBox->setDefaultButton(QMessageBox::Save); if (messageBox->exec() == QMessageBox::Save) { - Theme newTheme; + Theme newTheme(d->m_currentTheme.name()); d->m_ui->editor->model()->toTheme(&newTheme); - newTheme.writeSettings(d->m_currentTheme.fileName()); + newTheme.writeSettings(d->m_currentTheme.filePath()); } } @@ -378,10 +382,10 @@ void ThemeSettingsWidget::renameTheme() return; // overwrite file with new name - Theme newTheme; + Theme newTheme(entry.name()); d->m_ui->editor->model()->toTheme(&newTheme); newTheme.setName(newName); - newTheme.writeSettings(entry.fileName()); + newTheme.writeSettings(entry.filePath()); refreshThemeList(); } @@ -394,7 +398,7 @@ void ThemeSettingsWidget::copyThemeByName(const QString &name) const ThemeEntry &entry = d->m_themeListModel->themeAt(index); - QString baseFileName = QFileInfo(entry.fileName()).completeBaseName(); + QString baseFileName = QFileInfo(entry.filePath()).completeBaseName(); baseFileName += QLatin1String("_copy%1.creatortheme"); QString fileName = createThemeFileName(baseFileName); @@ -404,36 +408,46 @@ void ThemeSettingsWidget::copyThemeByName(const QString &name) // Ask about saving any existing modifactions maybeSaveTheme(); - Theme newTheme; + Theme newTheme(fileName); d->m_ui->editor->model()->toTheme(&newTheme); newTheme.setName(name); newTheme.writeSettings(fileName); - d->m_currentTheme = ThemeEntry(fileName, true); + d->m_currentTheme = ThemeEntry(fileName, fileName, true); refreshThemeList(); } void ThemeSettingsWidget::apply() { - { - d->m_ui->editor->model()->toTheme(creatorTheme()); - if (creatorTheme()->flag(Theme::ApplyThemePaletteGlobally)) - QApplication::setPalette(creatorTheme()->palette(QApplication::palette())); - foreach (QWidget *w, QApplication::topLevelWidgets()) - w->update(); + const QString themeName = d->m_currentTheme.name(); + Theme *newTheme = new Theme(themeName); + if (d->m_currentTheme.readOnly()) { + QSettings themeSettings(d->m_currentTheme.filePath(), QSettings::IniFormat); + newTheme->readSettings(themeSettings); + } else { + d->m_ui->editor->model()->toTheme(newTheme); + newTheme->writeSettings(d->m_currentTheme.filePath()); } - - // save definition of theme - if (!d->m_currentTheme.readOnly()) { - Theme newTheme; - d->m_ui->editor->model()->toTheme(&newTheme); - newTheme.writeSettings(d->m_currentTheme.fileName()); + setCreatorTheme(newTheme); + emit ICore::instance()->themeChanged(); + QPalette pal = newTheme->flag(Theme::ApplyThemePaletteGlobally) ? newTheme->palette() + : Theme::initialPalette(); + QApplication::setPalette(pal); + if (ManhattanStyle *style = qobject_cast<ManhattanStyle *>(QApplication::style())) { + QStyle *baseStyle = 0; + foreach (const QString &s, creatorTheme()->preferredStyles()) { + if ((baseStyle = QStyleFactory::create(s))) + break; + } + style->setBaseStyle(baseStyle); } + foreach (QWidget *w, QApplication::topLevelWidgets()) + w->update(); // save filename of selected theme in global config QSettings *settings = Core::ICore::settings(); - settings->setValue(QLatin1String(Core::Constants::SETTINGS_THEME), d->m_currentTheme.fileName()); + settings->setValue(QLatin1String(Core::Constants::SETTINGS_THEME), themeName); } } // namespace Internal diff --git a/src/plugins/coreplugin/themesettingswidget.h b/src/plugins/coreplugin/themesettingswidget.h index 8ed5dd882d..24ce6a2f01 100644 --- a/src/plugins/coreplugin/themesettingswidget.h +++ b/src/plugins/coreplugin/themesettingswidget.h @@ -46,8 +46,6 @@ public: ThemeSettingsWidget(QWidget *parent = 0); ~ThemeSettingsWidget(); - static QString defaultThemeFileName(const QString &fileName = QString()); - void apply(); private slots: diff --git a/src/plugins/coreplugin/versiondialog.cpp b/src/plugins/coreplugin/versiondialog.cpp index 50905598d2..126e29142f 100644 --- a/src/plugins/coreplugin/versiondialog.cpp +++ b/src/plugins/coreplugin/versiondialog.cpp @@ -33,6 +33,7 @@ #include <app/app_version.h> #include <coreplugin/coreconstants.h> #include <coreplugin/icore.h> +#include <utils/hostosinfo.h> #include <utils/qtcassert.h> #include <QDialogButtonBox> @@ -49,7 +50,8 @@ VersionDialog::VersionDialog(QWidget *parent) { // We need to set the window icon explicitly here since for some reason the // application icon isn't used when the size of the dialog is fixed (at least not on X11/GNOME) - setWindowIcon(QIcon(QLatin1String(Constants::ICON_QTLOGO_128))); + if (Utils::HostOsInfo::isLinuxHost()) + setWindowIcon(QIcon(QLatin1String(Constants::ICON_QTLOGO_128))); setWindowTitle(tr("About Qt Creator")); setWindowFlags(windowFlags() & ~Qt::WindowContextHelpButtonHint); diff --git a/src/plugins/coreplugin/windowsupport.cpp b/src/plugins/coreplugin/windowsupport.cpp index d5055be5ce..87b2eb6d2e 100644 --- a/src/plugins/coreplugin/windowsupport.cpp +++ b/src/plugins/coreplugin/windowsupport.cpp @@ -158,14 +158,14 @@ void WindowList::addWindow(QWidget *window) m_windowActionIds.append(id); auto action = new QAction(window->windowTitle(), 0); m_windowActions.append(action); - connect(action, &QAction::triggered, [action]() { WindowList::activateWindow(action); }); + QObject::connect(action, &QAction::triggered, [action]() { WindowList::activateWindow(action); }); action->setCheckable(true); action->setChecked(false); Command *cmd = ActionManager::registerAction(action, id, Context(Constants::C_GLOBAL)); cmd->setAttribute(Command::CA_UpdateText); ActionManager::actionContainer(Constants::M_WINDOW)->addAction(cmd, Constants::G_WINDOW_LIST); - connect(window, &QWidget::windowTitleChanged, [window]() { WindowList::updateTitle(window); }); + QObject::connect(window, &QWidget::windowTitleChanged, [window]() { WindowList::updateTitle(window); }); if (m_dockMenu) m_dockMenu->addAction(action); if (window->isActiveWindow()) @@ -200,7 +200,7 @@ void WindowList::removeWindow(QWidget *window) QTC_ASSERT(index >= 0, return); ActionManager::unregisterAction(m_windowActions.last(), m_windowActionIds.last()); - m_windowActions.removeLast(); + delete m_windowActions.takeLast(); m_windowActionIds.removeLast(); m_windows.removeOne(window); diff --git a/src/plugins/coreplugin/windowsupport.h b/src/plugins/coreplugin/windowsupport.h index a6259cf03c..88e779dd28 100644 --- a/src/plugins/coreplugin/windowsupport.h +++ b/src/plugins/coreplugin/windowsupport.h @@ -44,9 +44,8 @@ QT_END_NAMESPACE namespace Core { namespace Internal { -class WindowList : public QObject +class WindowList { - Q_OBJECT public: static void addWindow(QWidget *window); static void removeWindow(QWidget *window); diff --git a/src/plugins/cpaster/cpasterplugin.cpp b/src/plugins/cpaster/cpasterplugin.cpp index 9b8df0801a..e4a34d49fb 100644 --- a/src/plugins/cpaster/cpasterplugin.cpp +++ b/src/plugins/cpaster/cpasterplugin.cpp @@ -90,13 +90,13 @@ void CodePasterService::postText(const QString &text, const QString &mimeType) void CodePasterService::postCurrentEditor() { QTC_ASSERT(CodepasterPlugin::instance(), return); - CodepasterPlugin::instance()->postEditor(); + CodepasterPlugin::instance()->post(CodepasterPlugin::PasteEditor); } void CodePasterService::postClipboard() { QTC_ASSERT(CodepasterPlugin::instance(), return); - CodepasterPlugin::instance()->postClipboard(); + CodepasterPlugin::instance()->post(CodepasterPlugin::PasteClipboard); } // ---------- CodepasterPlugin @@ -104,7 +104,7 @@ CodepasterPlugin *CodepasterPlugin::m_instance = 0; CodepasterPlugin::CodepasterPlugin() : m_settings(new Settings), - m_postEditorAction(0), m_postClipboardAction(0), m_fetchAction(0) + m_postEditorAction(0), m_fetchAction(0) { CodepasterPlugin::m_instance = this; } @@ -165,12 +165,7 @@ bool CodepasterPlugin::initialize(const QStringList &arguments, QString *errorMe m_postEditorAction = new QAction(tr("Paste Snippet..."), this); command = Core::ActionManager::registerAction(m_postEditorAction, "CodePaster.Post", globalcontext); command->setDefaultKeySequence(QKeySequence(UseMacShortcuts ? tr("Meta+C,Meta+P") : tr("Alt+C,Alt+P"))); - connect(m_postEditorAction, SIGNAL(triggered()), this, SLOT(postEditor())); - cpContainer->addAction(command); - - m_postClipboardAction = new QAction(tr("Paste Clipboard..."), this); - command = Core::ActionManager::registerAction(m_postClipboardAction, "CodePaster.PostClipboard", globalcontext); - connect(m_postClipboardAction, SIGNAL(triggered()), this, SLOT(postClipboard())); + connect(m_postEditorAction, &QAction::triggered, this, &CodepasterPlugin::pasteSnippet); cpContainer->addAction(command); m_fetchAction = new QAction(tr("Fetch Snippet..."), this); @@ -204,29 +199,28 @@ ExtensionSystem::IPlugin::ShutdownFlag CodepasterPlugin::aboutToShutdown() return SynchronousShutdown; } -void CodepasterPlugin::postEditor() +static inline void textFromCurrentEditor(QString *text, QString *mimeType) { IEditor *editor = EditorManager::currentEditor(); if (!editor) return; const IDocument *document = editor->document(); - const QString mimeType = document->mimeType(); QString data; if (const BaseTextEditor *textEditor = qobject_cast<const BaseTextEditor *>(editor)) data = textEditor->selectedText(); if (data.isEmpty()) { - if (auto textDocument = qobject_cast<const TextDocument *>(document)) + if (auto textDocument = qobject_cast<const TextDocument *>(document)) { data = textDocument->plainText(); + } else { + const QVariant textV = document->property("plainText"); // Diff Editor. + if (textV.type() == QVariant::String) + data = textV.toString(); + } + } + if (!data.isEmpty()) { + *text = data; + *mimeType = document->mimeType(); } - post(data, mimeType); -} - -void CodepasterPlugin::postClipboard() -{ - QString subtype = QLatin1String("plain"); - const QString text = qApp->clipboard()->text(subtype, QClipboard::Clipboard); - if (!text.isEmpty()) - post(text, QString()); } static inline void fixSpecialCharacters(QString &data) @@ -251,6 +245,19 @@ static inline void fixSpecialCharacters(QString &data) } } +void CodepasterPlugin::post(PasteSources pasteSources) +{ + QString data; + QString mimeType; + if (pasteSources & PasteEditor) + textFromCurrentEditor(&data, &mimeType); + if (data.isEmpty() && (pasteSources & PasteClipboard)) { + QString subType = QStringLiteral("plain"); + data = qApp->clipboard()->text(subType, QClipboard::Clipboard); + } + post(data, mimeType); +} + void CodepasterPlugin::post(QString data, const QString &mimeType) { fixSpecialCharacters(data); @@ -284,6 +291,11 @@ void CodepasterPlugin::fetchUrl() m_urlOpen->fetch(url.toString()); } +void CodepasterPlugin::pasteSnippet() +{ + post(PasteEditor | PasteClipboard); +} + void CodepasterPlugin::fetch() { PasteSelectDialog dialog(m_protocols, ICore::dialogParent()); diff --git a/src/plugins/cpaster/cpasterplugin.h b/src/plugins/cpaster/cpasterplugin.h index d568e2b046..e9dc9dc9e7 100644 --- a/src/plugins/cpaster/cpasterplugin.h +++ b/src/plugins/cpaster/cpasterplugin.h @@ -64,6 +64,12 @@ class CodepasterPlugin : public ExtensionSystem::IPlugin Q_PLUGIN_METADATA(IID "org.qt-project.Qt.QtCreatorPlugin" FILE "CodePaster.json") public: + enum PasteSource { + PasteEditor = 0x1, + PasteClipboard = 0x2 + }; + Q_DECLARE_FLAGS(PasteSources, PasteSource) + CodepasterPlugin(); ~CodepasterPlugin(); @@ -74,14 +80,14 @@ public: static CodepasterPlugin *instance(); public slots: - void postEditor(); - void postClipboard(); + void pasteSnippet(); void fetch(); void finishPost(const QString &link); void finishFetch(const QString &titleDescription, const QString &content, bool error); + void post(PasteSources pasteSources); void post(QString data, const QString &mimeType); void fetchUrl(); private: @@ -89,7 +95,6 @@ private: static CodepasterPlugin *m_instance; const QSharedPointer<Settings> m_settings; QAction *m_postEditorAction; - QAction *m_postClipboardAction; QAction *m_fetchAction; QAction *m_fetchUrlAction; QList<Protocol*> m_protocols; @@ -97,6 +102,8 @@ private: Protocol *m_urlOpen; }; +Q_DECLARE_OPERATORS_FOR_FLAGS(CodepasterPlugin::PasteSources) + } // namespace CodePaster #endif // CPASTERPLUGIN_H diff --git a/src/plugins/cpptools/cppprojects.cpp b/src/plugins/cpptools/cppprojects.cpp index 1de89d1880..2e35d4a178 100644 --- a/src/plugins/cpptools/cppprojects.cpp +++ b/src/plugins/cpptools/cppprojects.cpp @@ -376,7 +376,6 @@ void ProjectPartBuilder::setIncludePaths(const QStringList &includePaths) if (slashIdx != -1) { hp = ProjectPart::HeaderPath(includeFile.left(slashIdx), ProjectPart::HeaderPath::FrameworkPath); - continue; } } diff --git a/src/plugins/cpptools/cppsemanticinfoupdater.cpp b/src/plugins/cpptools/cppsemanticinfoupdater.cpp index 2ee0501aa7..9c9d87ac6a 100644 --- a/src/plugins/cpptools/cppsemanticinfoupdater.cpp +++ b/src/plugins/cpptools/cppsemanticinfoupdater.cpp @@ -125,6 +125,7 @@ SemanticInfo SemanticInfoUpdaterPrivate::update(const SemanticInfo::Source &sour Document::Ptr doc = newSemanticInfo.snapshot.preprocessedDocument(source.code, source.fileName); if (processor) doc->control()->setTopLevelDeclarationProcessor(processor); + doc->setRetryHarderToParseDeclarations(true); doc->check(); if (processor && processor->isCanceled()) newSemanticInfo.complete = false; diff --git a/src/plugins/cpptools/stringtable.cpp b/src/plugins/cpptools/stringtable.cpp index 0e669b27bb..b6393d5520 100644 --- a/src/plugins/cpptools/stringtable.cpp +++ b/src/plugins/cpptools/stringtable.cpp @@ -76,9 +76,7 @@ QString StringTable::insert(const QString &string) void StringTable::scheduleGC() { - QMutexLocker locker(&m_lock); - - m_gcCountDown.start(); + QMetaObject::invokeMethod(&m_gcCountDown, "start", Qt::QueuedConnection); } void StringTable::startGC() diff --git a/src/plugins/cvs/cvsplugin.cpp b/src/plugins/cvs/cvsplugin.cpp index fb10e3b968..630616c0b1 100644 --- a/src/plugins/cvs/cvsplugin.cpp +++ b/src/plugins/cvs/cvsplugin.cpp @@ -95,6 +95,7 @@ static inline QString msgLogParsingFailed() return CvsPlugin::tr("Parsing of the log output failed"); } +const char CVS_CONTEXT[] = "CVS Context"; const char CMD_ID_CVS_MENU[] = "CVS.Menu"; const char CMD_ID_ADD[] = "CVS.Add"; const char CMD_ID_DELETE_FILE[] = "CVS.Delete"; @@ -232,7 +233,9 @@ bool CvsPlugin::initialize(const QStringList &arguments, QString *errorMessage) using namespace Constants; using namespace Core::Constants; - initializeVcs(new CvsControl(this)); + Context context(CVS_CONTEXT); + + initializeVcs(new CvsControl(this), context); m_cvsPluginInstance = this; @@ -275,13 +278,11 @@ bool CvsPlugin::initialize(const QStringList &arguments, QString *errorMessage) toolsContainer->addMenu(cvsMenu); m_menuAction = cvsMenu->menu()->menuAction(); - Context globalcontext(C_GLOBAL); - Command *command; m_diffCurrentAction = new ParameterAction(tr("Diff Current File"), tr("Diff \"%1\""), ParameterAction::EnabledWithParameter, this); command = ActionManager::registerAction(m_diffCurrentAction, - CMD_ID_DIFF_CURRENT, globalcontext); + CMD_ID_DIFF_CURRENT, context); command->setAttribute(Command::CA_UpdateText); command->setDefaultKeySequence(QKeySequence(UseMacShortcuts ? tr("Meta+C,Meta+D") : tr("Alt+C,Alt+D"))); connect(m_diffCurrentAction, SIGNAL(triggered()), this, SLOT(diffCurrentFile())); @@ -290,7 +291,7 @@ bool CvsPlugin::initialize(const QStringList &arguments, QString *errorMessage) m_filelogCurrentAction = new ParameterAction(tr("Filelog Current File"), tr("Filelog \"%1\""), ParameterAction::EnabledWithParameter, this); command = ActionManager::registerAction(m_filelogCurrentAction, - CMD_ID_FILELOG_CURRENT, globalcontext); + CMD_ID_FILELOG_CURRENT, context); command->setAttribute(Command::CA_UpdateText); connect(m_filelogCurrentAction, SIGNAL(triggered()), this, SLOT(filelogCurrentFile())); @@ -299,18 +300,18 @@ bool CvsPlugin::initialize(const QStringList &arguments, QString *errorMessage) m_annotateCurrentAction = new ParameterAction(tr("Annotate Current File"), tr("Annotate \"%1\""), ParameterAction::EnabledWithParameter, this); command = ActionManager::registerAction(m_annotateCurrentAction, - CMD_ID_ANNOTATE_CURRENT, globalcontext); + CMD_ID_ANNOTATE_CURRENT, context); command->setAttribute(Command::CA_UpdateText); connect(m_annotateCurrentAction, SIGNAL(triggered()), this, SLOT(annotateCurrentFile())); cvsMenu->addAction(command); m_commandLocator->appendCommand(command); - cvsMenu->addSeparator(globalcontext); + cvsMenu->addSeparator(context); m_addAction = new ParameterAction(tr("Add"), tr("Add \"%1\""), ParameterAction::EnabledWithParameter, this); command = ActionManager::registerAction(m_addAction, CMD_ID_ADD, - globalcontext); + context); command->setAttribute(Command::CA_UpdateText); command->setDefaultKeySequence(QKeySequence(UseMacShortcuts ? tr("Meta+C,Meta+A") : tr("Alt+C,Alt+A"))); connect(m_addAction, SIGNAL(triggered()), this, SLOT(addCurrentFile())); @@ -319,7 +320,7 @@ bool CvsPlugin::initialize(const QStringList &arguments, QString *errorMessage) m_commitCurrentAction = new ParameterAction(tr("Commit Current File"), tr("Commit \"%1\""), ParameterAction::EnabledWithParameter, this); command = ActionManager::registerAction(m_commitCurrentAction, - CMD_ID_COMMIT_CURRENT, globalcontext); + CMD_ID_COMMIT_CURRENT, context); command->setAttribute(Command::CA_UpdateText); command->setDefaultKeySequence(QKeySequence(UseMacShortcuts ? tr("Meta+C,Meta+C") : tr("Alt+C,Alt+C"))); connect(m_commitCurrentAction, SIGNAL(triggered()), this, SLOT(startCommitCurrentFile())); @@ -328,7 +329,7 @@ bool CvsPlugin::initialize(const QStringList &arguments, QString *errorMessage) m_deleteAction = new ParameterAction(tr("Delete..."), tr("Delete \"%1\"..."), ParameterAction::EnabledWithParameter, this); command = ActionManager::registerAction(m_deleteAction, CMD_ID_DELETE_FILE, - globalcontext); + context); command->setAttribute(Command::CA_UpdateText); connect(m_deleteAction, SIGNAL(triggered()), this, SLOT(promptToDeleteCurrentFile())); cvsMenu->addAction(command); @@ -336,39 +337,39 @@ bool CvsPlugin::initialize(const QStringList &arguments, QString *errorMessage) m_revertAction = new ParameterAction(tr("Revert..."), tr("Revert \"%1\"..."), ParameterAction::EnabledWithParameter, this); command = ActionManager::registerAction(m_revertAction, CMD_ID_REVERT, - globalcontext); + context); command->setAttribute(Command::CA_UpdateText); connect(m_revertAction, SIGNAL(triggered()), this, SLOT(revertCurrentFile())); cvsMenu->addAction(command); m_commandLocator->appendCommand(command); - cvsMenu->addSeparator(globalcontext); + cvsMenu->addSeparator(context); m_editCurrentAction = new ParameterAction(tr("Edit"), tr("Edit \"%1\""), ParameterAction::EnabledWithParameter, this); - command = ActionManager::registerAction(m_editCurrentAction, CMD_ID_EDIT_FILE, globalcontext); + command = ActionManager::registerAction(m_editCurrentAction, CMD_ID_EDIT_FILE, context); command->setAttribute(Command::CA_UpdateText); connect(m_editCurrentAction, SIGNAL(triggered()), this, SLOT(editCurrentFile())); cvsMenu->addAction(command); m_commandLocator->appendCommand(command); m_uneditCurrentAction = new ParameterAction(tr("Unedit"), tr("Unedit \"%1\""), ParameterAction::EnabledWithParameter, this); - command = ActionManager::registerAction(m_uneditCurrentAction, CMD_ID_UNEDIT_FILE, globalcontext); + command = ActionManager::registerAction(m_uneditCurrentAction, CMD_ID_UNEDIT_FILE, context); command->setAttribute(Command::CA_UpdateText); connect(m_uneditCurrentAction, SIGNAL(triggered()), this, SLOT(uneditCurrentFile())); cvsMenu->addAction(command); m_commandLocator->appendCommand(command); m_uneditRepositoryAction = new QAction(tr("Unedit Repository"), this); - command = ActionManager::registerAction(m_uneditRepositoryAction, CMD_ID_UNEDIT_REPOSITORY, globalcontext); + command = ActionManager::registerAction(m_uneditRepositoryAction, CMD_ID_UNEDIT_REPOSITORY, context); connect(m_uneditRepositoryAction, SIGNAL(triggered()), this, SLOT(uneditCurrentRepository())); cvsMenu->addAction(command); m_commandLocator->appendCommand(command); - cvsMenu->addSeparator(globalcontext); + cvsMenu->addSeparator(context); m_diffProjectAction = new ParameterAction(tr("Diff Project"), tr("Diff Project \"%1\""), ParameterAction::EnabledWithParameter, this); command = ActionManager::registerAction(m_diffProjectAction, CMD_ID_DIFF_PROJECT, - globalcontext); + context); command->setAttribute(Command::CA_UpdateText); connect(m_diffProjectAction, SIGNAL(triggered()), this, SLOT(diffProject())); cvsMenu->addAction(command); @@ -376,37 +377,37 @@ bool CvsPlugin::initialize(const QStringList &arguments, QString *errorMessage) m_statusProjectAction = new ParameterAction(tr("Project Status"), tr("Status of Project \"%1\""), ParameterAction::EnabledWithParameter, this); command = ActionManager::registerAction(m_statusProjectAction, CMD_ID_STATUS, - globalcontext); + context); command->setAttribute(Command::CA_UpdateText); connect(m_statusProjectAction, SIGNAL(triggered()), this, SLOT(projectStatus())); cvsMenu->addAction(command); m_commandLocator->appendCommand(command); m_logProjectAction = new ParameterAction(tr("Log Project"), tr("Log Project \"%1\""), ParameterAction::EnabledWithParameter, this); - command = ActionManager::registerAction(m_logProjectAction, CMD_ID_PROJECTLOG, globalcontext); + command = ActionManager::registerAction(m_logProjectAction, CMD_ID_PROJECTLOG, context); command->setAttribute(Command::CA_UpdateText); connect(m_logProjectAction, SIGNAL(triggered()), this, SLOT(logProject())); cvsMenu->addAction(command); m_commandLocator->appendCommand(command); m_updateProjectAction = new ParameterAction(tr("Update Project"), tr("Update Project \"%1\""), ParameterAction::EnabledWithParameter, this); - command = ActionManager::registerAction(m_updateProjectAction, CMD_ID_UPDATE, globalcontext); + command = ActionManager::registerAction(m_updateProjectAction, CMD_ID_UPDATE, context); command->setAttribute(Command::CA_UpdateText); connect(m_updateProjectAction, SIGNAL(triggered()), this, SLOT(updateProject())); cvsMenu->addAction(command); m_commandLocator->appendCommand(command); m_commitProjectAction = new ParameterAction(tr("Commit Project"), tr("Commit Project \"%1\""), ParameterAction::EnabledWithParameter, this); - command = ActionManager::registerAction(m_commitProjectAction, CMD_ID_PROJECTCOMMIT, globalcontext); + command = ActionManager::registerAction(m_commitProjectAction, CMD_ID_PROJECTCOMMIT, context); command->setAttribute(Command::CA_UpdateText); connect(m_commitProjectAction, SIGNAL(triggered()), this, SLOT(commitProject())); cvsMenu->addAction(command); m_commandLocator->appendCommand(command); - cvsMenu->addSeparator(globalcontext); + cvsMenu->addSeparator(context); m_updateDirectoryAction = new ParameterAction(tr("Update Directory"), tr("Update Directory \"%1\""), Utils::ParameterAction::EnabledWithParameter, this); - command = Core::ActionManager::registerAction(m_updateDirectoryAction, CMD_ID_UPDATE_DIRECTORY, globalcontext); + command = Core::ActionManager::registerAction(m_updateDirectoryAction, CMD_ID_UPDATE_DIRECTORY, context); command->setAttribute(Command::CA_UpdateText); connect(m_updateDirectoryAction, SIGNAL(triggered()), this, SLOT(updateDirectory())); cvsMenu->addAction(command); @@ -414,48 +415,48 @@ bool CvsPlugin::initialize(const QStringList &arguments, QString *errorMessage) m_commitDirectoryAction = new ParameterAction(tr("Commit Directory"), tr("Commit Directory \"%1\""), Utils::ParameterAction::EnabledWithParameter, this); command = Core::ActionManager::registerAction(m_commitDirectoryAction, - CMD_ID_COMMIT_DIRECTORY, globalcontext); + CMD_ID_COMMIT_DIRECTORY, context); command->setAttribute(Command::CA_UpdateText); connect(m_commitDirectoryAction, SIGNAL(triggered()), this, SLOT(startCommitDirectory())); cvsMenu->addAction(command); m_commandLocator->appendCommand(command); - cvsMenu->addSeparator(globalcontext); + cvsMenu->addSeparator(context); m_diffRepositoryAction = new QAction(tr("Diff Repository"), this); - command = ActionManager::registerAction(m_diffRepositoryAction, CMD_ID_REPOSITORYDIFF, globalcontext); + command = ActionManager::registerAction(m_diffRepositoryAction, CMD_ID_REPOSITORYDIFF, context); connect(m_diffRepositoryAction, SIGNAL(triggered()), this, SLOT(diffRepository())); cvsMenu->addAction(command); m_commandLocator->appendCommand(command); m_statusRepositoryAction = new QAction(tr("Repository Status"), this); - command = ActionManager::registerAction(m_statusRepositoryAction, CMD_ID_REPOSITORYSTATUS, globalcontext); + command = ActionManager::registerAction(m_statusRepositoryAction, CMD_ID_REPOSITORYSTATUS, context); connect(m_statusRepositoryAction, SIGNAL(triggered()), this, SLOT(statusRepository())); cvsMenu->addAction(command); m_commandLocator->appendCommand(command); m_logRepositoryAction = new QAction(tr("Repository Log"), this); - command = ActionManager::registerAction(m_logRepositoryAction, CMD_ID_REPOSITORYLOG, globalcontext); + command = ActionManager::registerAction(m_logRepositoryAction, CMD_ID_REPOSITORYLOG, context); connect(m_logRepositoryAction, SIGNAL(triggered()), this, SLOT(logRepository())); cvsMenu->addAction(command); m_commandLocator->appendCommand(command); m_updateRepositoryAction = new QAction(tr("Update Repository"), this); - command = ActionManager::registerAction(m_updateRepositoryAction, CMD_ID_REPOSITORYUPDATE, globalcontext); + command = ActionManager::registerAction(m_updateRepositoryAction, CMD_ID_REPOSITORYUPDATE, context); connect(m_updateRepositoryAction, SIGNAL(triggered()), this, SLOT(updateRepository())); cvsMenu->addAction(command); m_commandLocator->appendCommand(command); m_commitAllAction = new QAction(tr("Commit All Files"), this); command = ActionManager::registerAction(m_commitAllAction, CMD_ID_COMMIT_ALL, - globalcontext); + context); connect(m_commitAllAction, SIGNAL(triggered()), this, SLOT(startCommitAll())); cvsMenu->addAction(command); m_commandLocator->appendCommand(command); m_revertRepositoryAction = new QAction(tr("Revert Repository..."), this); command = ActionManager::registerAction(m_revertRepositoryAction, CMD_ID_REVERT_ALL, - globalcontext); + context); connect(m_revertRepositoryAction, SIGNAL(triggered()), this, SLOT(revertAll())); cvsMenu->addAction(command); m_commandLocator->appendCommand(command); diff --git a/src/plugins/debugger/cdb/cdbengine.cpp b/src/plugins/debugger/cdb/cdbengine.cpp index 86acd62f2f..fc3c40f231 100644 --- a/src/plugins/debugger/cdb/cdbengine.cpp +++ b/src/plugins/debugger/cdb/cdbengine.cpp @@ -442,28 +442,14 @@ void CdbEngine::syncVerboseLog(bool verboseLog) } bool CdbEngine::setToolTipExpression(TextEditor::TextEditorWidget *editorWidget, - const DebuggerToolTipContext &contextIn) + const DebuggerToolTipContext &context) { - if (debug) - qDebug() << Q_FUNC_INFO; - // Need a stopped debuggee and a cpp file in a valid frame - if (state() != InferiorStopOk || !isCppEditor(editorWidget) || stackHandler()->currentIndex() < 0) - return false; - // Determine expression and function - int line; - int column; - DebuggerToolTipContext context = contextIn; - QString exp = fixCppExpression(cppExpressionAt(editorWidget, context.position, &line, &column, &context.function)); - // Are we in the current stack frame - if (context.function.isEmpty() || exp.isEmpty() || context.function != stackHandler()->currentFrame().function) - return false; - // Show tooltips of local variables only. Anything else can slow debugging down. - const WatchData *localVariable = watchHandler()->findCppLocalVariable(exp); - if (!localVariable) - return false; - context.iname = localVariable->iname; - DebuggerToolTipManager::showToolTip(context, this); - return true; + Q_UNUSED(editorWidget); + Q_UNUSED(context); + // Tooltips matching local variables are already handled in the + // base class. We don't handle anything else here in CDB + // as it can slow debugging down. + return false; } // Determine full path to the CDB extension library. diff --git a/src/plugins/debugger/cdb/cdbengine.h b/src/plugins/debugger/cdb/cdbengine.h index 33b92042c2..37ed92c68b 100644 --- a/src/plugins/debugger/cdb/cdbengine.h +++ b/src/plugins/debugger/cdb/cdbengine.h @@ -78,7 +78,7 @@ public: // Factory function that returns 0 if the debug engine library cannot be found. virtual bool setToolTipExpression(TextEditor::TextEditorWidget *editorWidget, - const DebuggerToolTipContext &ctx); + const DebuggerToolTipContext &context); virtual void setupEngine(); virtual void setupInferior(); virtual void runEngine(); diff --git a/src/plugins/debugger/commonoptionspage.cpp b/src/plugins/debugger/commonoptionspage.cpp index 56fdb67f5a..b832ee4956 100644 --- a/src/plugins/debugger/commonoptionspage.cpp +++ b/src/plugins/debugger/commonoptionspage.cpp @@ -69,7 +69,8 @@ private: QCheckBox *checkBoxFontSizeFollowsEditor; QCheckBox *checkBoxUseToolTipsInMainEditor; QCheckBox *checkBoxListSourceFiles; - QCheckBox *checkBoxCloseBuffersOnExit; + QCheckBox *checkBoxCloseSourceBuffersOnExit; + QCheckBox *checkBoxCloseMemoryBuffersOnExit; QCheckBox *checkBoxSwitchModeOnExit; QCheckBox *checkBoxBringToForegroundOnInterrrupt; QCheckBox *checkBoxShowQmlObjectTree; @@ -105,12 +106,17 @@ CommonOptionsPageWidget::CommonOptionsPageWidget checkBoxListSourceFiles->setToolTip(tr("Populates the source file view automatically. This might slow down debugger startup considerably.")); checkBoxListSourceFiles->setText(tr("Populate source file view automatically")); - checkBoxCloseBuffersOnExit = new QCheckBox(behaviorBox); - checkBoxCloseBuffersOnExit->setText(tr("Close temporary views on debugger exit")); - checkBoxCloseBuffersOnExit->setToolTip(tr("Stopping and stepping in the debugger " - "will automatically open source or disassembler views associated with the " - "current location. Select this option to automatically close them when " - "the debugger exits.")); + QString t = tr("Stopping and stepping in the debugger " + "will automatically open views associated with the current location.") + QLatin1Char('\n'); + checkBoxCloseSourceBuffersOnExit = new QCheckBox(behaviorBox); + checkBoxCloseSourceBuffersOnExit->setText(tr("Close temporary source views on debugger exit")); + checkBoxCloseSourceBuffersOnExit->setToolTip(t + tr("Select this option to close " + "automatically opened source views when the debugger exits.")); + + checkBoxCloseMemoryBuffersOnExit = new QCheckBox(behaviorBox); + checkBoxCloseMemoryBuffersOnExit->setText(tr("Close temporary memory views on debugger exit")); + checkBoxCloseMemoryBuffersOnExit->setToolTip(t + tr("Select this option to close " + "automatically opened memory views when the debugger exits.")); checkBoxSwitchModeOnExit = new QCheckBox(behaviorBox); checkBoxSwitchModeOnExit->setText(tr("Switch to previous mode on debugger exit")); @@ -160,11 +166,12 @@ CommonOptionsPageWidget::CommonOptionsPageWidget QGridLayout *gridLayout = new QGridLayout(behaviorBox); gridLayout->addWidget(checkBoxUseAlternatingRowColors, 0, 0, 1, 1); gridLayout->addWidget(checkBoxUseToolTipsInMainEditor, 1, 0, 1, 1); - gridLayout->addWidget(checkBoxCloseBuffersOnExit, 2, 0, 1, 1); - gridLayout->addWidget(checkBoxBringToForegroundOnInterrrupt, 3, 0, 1, 1); - gridLayout->addWidget(checkBoxBreakpointsFullPath, 4, 0, 1, 1); - gridLayout->addWidget(checkBoxWarnOnReleaseBuilds, 5, 0, 1, 1); - gridLayout->addLayout(horizontalLayout, 6, 0, 1, 2); + gridLayout->addWidget(checkBoxCloseSourceBuffersOnExit, 2, 0, 1, 1); + gridLayout->addWidget(checkBoxCloseMemoryBuffersOnExit, 3, 0, 1, 1); + gridLayout->addWidget(checkBoxBringToForegroundOnInterrrupt, 4, 0, 1, 1); + gridLayout->addWidget(checkBoxBreakpointsFullPath, 5, 0, 1, 1); + gridLayout->addWidget(checkBoxWarnOnReleaseBuilds, 6, 0, 1, 1); + gridLayout->addLayout(horizontalLayout, 7, 0, 1, 2); gridLayout->addWidget(checkBoxFontSizeFollowsEditor, 0, 1, 1, 1); gridLayout->addWidget(checkBoxListSourceFiles, 1, 1, 1, 1); @@ -186,8 +193,10 @@ CommonOptionsPageWidget::CommonOptionsPageWidget checkBoxUseAlternatingRowColors); m_group->insert(action(UseToolTipsInMainEditor), checkBoxUseToolTipsInMainEditor); - m_group->insert(action(CloseBuffersOnExit), - checkBoxCloseBuffersOnExit); + m_group->insert(action(CloseSourceBuffersOnExit), + checkBoxCloseSourceBuffersOnExit); + m_group->insert(action(CloseMemoryBuffersOnExit), + checkBoxCloseMemoryBuffersOnExit); m_group->insert(action(SwitchModeOnExit), checkBoxSwitchModeOnExit); m_group->insert(action(BreakpointsFullPathByDefault), diff --git a/src/plugins/debugger/debuggeractions.cpp b/src/plugins/debugger/debuggeractions.cpp index cf11fe9fa5..c6b59cc60f 100644 --- a/src/plugins/debugger/debuggeractions.cpp +++ b/src/plugins/debugger/debuggeractions.cpp @@ -373,11 +373,11 @@ DebuggerSettings::DebuggerSettings() insertItem(LoadGdbInit, item); item = new SavedAction(this); - item->setSettingsKey(debugModeGroup, QLatin1String("LoadGdbDumpers1")); + item->setSettingsKey(debugModeGroup, QLatin1String("LoadGdbDumpers2")); item->setDefaultValue(QString()); item->setCheckable(true); - item->setDefaultValue(true); - item->setValue(true); + item->setDefaultValue(false); + item->setValue(false); insertItem(LoadGdbDumpers, item); item = new SavedAction(this); @@ -433,7 +433,13 @@ DebuggerSettings::DebuggerSettings() item->setSettingsKey(debugModeGroup, QLatin1String("CloseBuffersOnExit")); item->setCheckable(true); item->setDefaultValue(false); - insertItem(CloseBuffersOnExit, item); + insertItem(CloseSourceBuffersOnExit, item); + + item = new SavedAction(this); + item->setSettingsKey(debugModeGroup, QLatin1String("CloseMemoryBuffersOnExit")); + item->setCheckable(true); + item->setDefaultValue(true); + insertItem(CloseMemoryBuffersOnExit, item); item = new SavedAction(this); item->setSettingsKey(debugModeGroup, QLatin1String("SwitchModeOnExit")); diff --git a/src/plugins/debugger/debuggeractions.h b/src/plugins/debugger/debuggeractions.h index a88f4842c2..47db715802 100644 --- a/src/plugins/debugger/debuggeractions.h +++ b/src/plugins/debugger/debuggeractions.h @@ -99,7 +99,8 @@ enum DebuggerActionCode LogTimeStamps, VerboseLog, OperateByInstruction, - CloseBuffersOnExit, + CloseSourceBuffersOnExit, + CloseMemoryBuffersOnExit, SwitchModeOnExit, BreakpointsFullPathByDefault, RaiseOnInterrupt, diff --git a/src/plugins/debugger/debuggerengine.cpp b/src/plugins/debugger/debuggerengine.cpp index b978f95af6..9c767602c2 100644 --- a/src/plugins/debugger/debuggerengine.cpp +++ b/src/plugins/debugger/debuggerengine.cpp @@ -269,6 +269,7 @@ public slots: m_watchHandler.resetLocation(); m_threadsHandler.resetLocation(); m_disassemblerAgent.resetLocation(); + DebuggerToolTipManager::resetLocation(); } public: diff --git a/src/plugins/debugger/debuggerengine.h b/src/plugins/debugger/debuggerengine.h index b8f1dd922f..0b8f999ec6 100644 --- a/src/plugins/debugger/debuggerengine.h +++ b/src/plugins/debugger/debuggerengine.h @@ -100,6 +100,7 @@ public: void setNeedsRaise(bool on) { m_needsRaise = on; } void setNeedsMarker(bool on) { m_needsMarker = on; } void setFileName(const QString &fileName) { m_fileName = fileName; } + void setUseAssembler(bool on) { m_hasDebugInfo = !on; } bool needsRaise() const { return m_needsRaise; } bool needsMarker() const { return m_needsMarker; } bool hasDebugInfo() const { return m_hasDebugInfo; } diff --git a/src/plugins/debugger/debuggerkitinformation.cpp b/src/plugins/debugger/debuggerkitinformation.cpp index bbb7f73d1f..0d64eece47 100644 --- a/src/plugins/debugger/debuggerkitinformation.cpp +++ b/src/plugins/debugger/debuggerkitinformation.cpp @@ -303,11 +303,17 @@ KitConfigWidget *DebuggerKitInformation::createConfigWidget(Kit *k) const void DebuggerKitInformation::addToMacroExpander(Kit *kit, MacroExpander *expander) const { - expander->registerVariable("Debugger:EngineType", tr("Type of Debugger Backend"), + expander->registerVariable("Debugger:Type", tr("Type of Debugger Backend"), [this, kit]() -> QString { const DebuggerItem *item = debugger(kit); return item ? item->engineTypeName() : tr("unknown"); }); + // FIXME: Use better strings. + expander->registerVariable("Debugger:Name", tr("Debugger"), + [this, kit]() -> QString { + const DebuggerItem *item = debugger(kit); + return item ? item->displayName() : tr("unknown"); + }); } KitInformation::ItemList DebuggerKitInformation::toUserOutput(const Kit *k) const diff --git a/src/plugins/debugger/debuggermainwindow.cpp b/src/plugins/debugger/debuggermainwindow.cpp index 650195ddf0..91f9c02a9f 100644 --- a/src/plugins/debugger/debuggermainwindow.cpp +++ b/src/plugins/debugger/debuggermainwindow.cpp @@ -346,15 +346,14 @@ void DebuggerMainWindowPrivate::activateQmlCppLayout() if (m_previousDebugLanguages & QmlLanguage) { m_dockWidgetActiveStateQmlCpp = q->saveSettings(); - ICore::updateAdditionalContexts(qmlCppContext, Context()); + ICore::removeAdditionalContext(qmlCppContext); } else if (m_previousDebugLanguages & CppLanguage) { m_dockWidgetActiveStateCpp = q->saveSettings(); - ICore::updateAdditionalContexts(m_contextsForLanguage.value(CppLanguage), - Context()); + ICore::removeAdditionalContext(m_contextsForLanguage.value(CppLanguage)); } q->restoreSettings(m_dockWidgetActiveStateQmlCpp); - ICore::updateAdditionalContexts(Context(), qmlCppContext); + ICore::addAdditionalContext(qmlCppContext); } void DebuggerMainWindowPrivate::activateCppLayout() @@ -368,17 +367,16 @@ void DebuggerMainWindowPrivate::activateCppLayout() if (m_previousDebugLanguages & QmlLanguage) { m_dockWidgetActiveStateQmlCpp = q->saveSettings(); - ICore::updateAdditionalContexts(qmlCppContext, Context()); + ICore::removeAdditionalContext(qmlCppContext); } else if (m_previousDebugLanguages & CppLanguage) { m_dockWidgetActiveStateCpp = q->saveSettings(); - ICore::updateAdditionalContexts(m_contextsForLanguage.value(CppLanguage), - Context()); + ICore::removeAdditionalContext(m_contextsForLanguage.value(CppLanguage)); } q->restoreSettings(m_dockWidgetActiveStateCpp); const Context &cppContext = m_contextsForLanguage.value(CppLanguage); - ICore::updateAdditionalContexts(Context(), cppContext); + ICore::addAdditionalContext(cppContext); } void DebuggerMainWindow::setToolBar(DebuggerLanguage language, QWidget *widget) diff --git a/src/plugins/debugger/debuggerplugin.cpp b/src/plugins/debugger/debuggerplugin.cpp index 92d263944a..7cf5b79d70 100644 --- a/src/plugins/debugger/debuggerplugin.cpp +++ b/src/plugins/debugger/debuggerplugin.cpp @@ -1982,21 +1982,22 @@ void DebuggerPluginPrivate::cleanupViews() m_reverseDirectionAction->setChecked(false); m_reverseDirectionAction->setEnabled(false); - if (!boolSetting(CloseBuffersOnExit)) - return; + const bool closeSource = boolSetting(CloseSourceBuffersOnExit); + const bool closeMemory = boolSetting(CloseMemoryBuffersOnExit); QList<IDocument *> toClose; foreach (IDocument *document, DocumentModel::openedDocuments()) { + const bool isMemory = document->property(Constants::OPENED_WITH_DISASSEMBLY).toBool(); if (document->property(Constants::OPENED_BY_DEBUGGER).toBool()) { bool keepIt = true; - if (document->property(Constants::OPENED_WITH_DISASSEMBLY).toBool()) - keepIt = false; - else if (document->isModified()) + if (document->isModified()) keepIt = true; else if (document->filePath().contains(_("qeventdispatcher"))) keepIt = false; + else if (isMemory) + keepIt = !closeMemory; else - keepIt = (document == EditorManager::currentDocument()); + keepIt = !closeSource; if (keepIt) document->setProperty(Constants::OPENED_BY_DEBUGGER, false); diff --git a/src/plugins/debugger/debuggertooltipmanager.cpp b/src/plugins/debugger/debuggertooltipmanager.cpp index 2079511b21..a9cb7b2126 100644 --- a/src/plugins/debugger/debuggertooltipmanager.cpp +++ b/src/plugins/debugger/debuggertooltipmanager.cpp @@ -47,10 +47,12 @@ #include <utils/tooltip/tipcontents.h> #include <utils/qtcassert.h> +#include <QAbstractItemModel> #include <QApplication> #include <QClipboard> #include <QDebug> #include <QDesktopWidget> +#include <QFileInfo> #include <QLabel> #include <QScrollBar> #include <QSortFilterProxyModel> @@ -68,9 +70,8 @@ using namespace TextEditor; namespace Debugger { namespace Internal { -class DebuggerToolTipWidget; -QList<QPointer<DebuggerToolTipWidget>> m_tooltips; -bool m_debugModeActive; +//#define DEBUG(x) qDebug() << x +#define DEBUG(x) // Expire tooltips after n days on (no longer load them) in order // to avoid them piling up. @@ -80,7 +81,7 @@ const char sessionSettingsKeyC[] = "DebuggerToolTips"; const char sessionDocumentC[] = "DebuggerToolTips"; const char sessionVersionAttributeC[] = "version"; const char toolTipElementC[] = "DebuggerToolTip"; -const char toolTipClassAttributeC[] = "class"; +//const char toolTipClassAttributeC[] = "class"; const char fileNameAttributeC[] = "name"; const char functionAttributeC[] = "function"; const char textPositionAttributeC[] = "position"; @@ -98,12 +99,11 @@ const char modelColumnCountAttributeC[] = "columncount"; const char modelRowElementC[] = "row"; const char modelItemElementC[] = "item"; -static void purgeClosedToolTips() -{ - for (int i = m_tooltips.size(); --i >= 0; ) - if (!m_tooltips.at(i)) - m_tooltips.removeAt(i); -} +static void purgeClosedToolTips(); + +class DebuggerToolTipHolder; +QList<QPointer<DebuggerToolTipHolder>> m_tooltips; +bool m_debugModeActive; // Forward a stream reader across end elements looking for the // next start element of a desired type. @@ -407,7 +407,7 @@ static QDebug operator<<(QDebug d, const QAbstractItemModel &model) QTextStream str(&s); Debugger::Internal::DumpTreeModelVisitor v(&model, Debugger::Internal::DumpTreeModelVisitor::DebugMode, str); v.run(); - qDebug().nospace() << s; + qCDebug(tooltip).nospace() << s; return d; } */ @@ -443,7 +443,7 @@ public: { const QModelIndex nameIndex = sourceModel()->index(sourceRow, 0, sourceParent); const QByteArray iname = nameIndex.data(LocalsINameRole).toByteArray(); -// qDebug() << "ACCEPTING FILTER" << iname +// DEBUG("ACCEPTING FILTER" << iname // << (iname == m_iname || isSubIname(iname, m_iname) || isSubIname(m_iname, iname)); return iname == m_iname || isSubIname(iname, m_iname) || isSubIname(m_iname, iname); } @@ -612,68 +612,157 @@ QString DebuggerToolTipManager::treeModelClipboardContents(const QAbstractItemMo class DebuggerToolTipWidget : public QWidget { public: - DebuggerToolTipWidget(const DebuggerToolTipContext &context); + DebuggerToolTipWidget() + { + setAttribute(Qt::WA_DeleteOnClose); + + isPinned = false; + const QIcon pinIcon(QLatin1String(":/debugger/images/pin.xpm")); + + pinButton = new QToolButton; + pinButton->setIcon(pinIcon); + + auto copyButton = new QToolButton; + copyButton->setIcon(QIcon(QLatin1String(Core::Constants::ICON_COPY))); + + titleLabel = new DraggableLabel(this); + titleLabel->setMinimumWidth(40); // Ensure a draggable area even if text is empty. + titleLabel->setSizePolicy(QSizePolicy::MinimumExpanding, QSizePolicy::Preferred); + + auto toolBar = new QToolBar(this); + toolBar->setProperty("_q_custom_style_disabled", QVariant(true)); + const QList<QSize> pinIconSizes = pinIcon.availableSizes(); + if (!pinIconSizes.isEmpty()) + toolBar->setIconSize(pinIconSizes.front()); + toolBar->addWidget(pinButton); + toolBar->addWidget(copyButton); + toolBar->addWidget(titleLabel); + + treeView = new DebuggerToolTipTreeView(this); + treeView->setFocusPolicy(Qt::NoFocus); + + auto mainLayout = new QVBoxLayout(this); + mainLayout->setSizeConstraint(QLayout::SetFixedSize); + mainLayout->setContentsMargins(0, 0, 0, 0); + mainLayout->addWidget(toolBar); + mainLayout->addWidget(treeView); + + connect(copyButton, &QAbstractButton::clicked, [this] { + QString clipboardText = DebuggerToolTipManager::treeModelClipboardContents(treeView->model()); + QClipboard *clipboard = QApplication::clipboard(); + clipboard->setText(clipboardText, QClipboard::Selection); + clipboard->setText(clipboardText, QClipboard::Clipboard); + }); + DEBUG("CREATE DEBUGGERTOOLTIP WIDGET"); + } + + ~DebuggerToolTipWidget() + { + DEBUG("DESTROY DEBUGGERTOOLTIP WIDGET"); + } + + void closeEvent(QCloseEvent *) + { + DEBUG("CLOSE DEBUGGERTOOLTIP WIDGET"); + } + + void enterEvent(QEvent *) + { + DEBUG("ENTER DEBUGGERTOOLTIP WIDGET"); + } - bool isPinned() const { return m_isPinned; } - QString fileName() const { return m_context.fileName; } - QString function() const { return m_context.function; } - int position() const { return m_context.position; } + void leaveEvent(QEvent *) + { + DEBUG("LEAVE DEBUGGERTOOLTIP WIDGET"); + if (BaseTextEditor *editor = BaseTextEditor::currentTextEditor()) + editor->editorWidget()->activateWindow(); + } + + void pin() + { + if (isPinned) + return; + isPinned = true; + pinButton->setIcon(style()->standardIcon(QStyle::SP_DockWidgetCloseButton)); + + if (parentWidget()) { + // We are currently within a text editor tooltip: + // Rip out of parent widget and re-show as a tooltip + Utils::WidgetContent::pinToolTip(this, ICore::mainWindow()); + } else { + // We have just be restored from session data. + setWindowFlags(Qt::ToolTip); + } + titleLabel->active = true; // User can now drag + } + +public: + bool isPinned; + QToolButton *pinButton; + DraggableLabel *titleLabel; + DebuggerToolTipTreeView *treeView; +}; + +///////////////////////////////////////////////////////////////////////// +// +// DebuggerToolTipHolder +// +///////////////////////////////////////////////////////////////////////// + +enum DebuggerTootipState +{ + New, // All new, widget not shown, not async (yet) + PendingUnshown, // Widget not (yet) shown, async. + PendingShown, // Widget shown, async + Acquired, // Widget shown, engine attached + Released // Widget shown, engine released +}; - const DebuggerToolTipContext &context() const { return m_context; } +class DebuggerToolTipHolder : public QObject +{ +public: + DebuggerToolTipHolder(const DebuggerToolTipContext &context); + ~DebuggerToolTipHolder(); void acquireEngine(); void releaseEngine(); void saveSessionData(QXmlStreamWriter &w) const; - void setWatchModel(WatchModelBase *watchModel); void handleStackFrameCompleted(const QString &frameFile, const QString &frameFunction); - void copy(); void positionShow(const TextEditorWidget *editorWidget); - void pin(); - void handleItemIsExpanded(const QModelIndex &sourceIdx) - { - QTC_ASSERT(m_filterModel.sourceModel() == sourceIdx.model(), return); - QModelIndex mappedIdx = m_filterModel.mapFromSource(sourceIdx); - if (!m_treeView->isExpanded(mappedIdx)) - m_treeView->expand(mappedIdx); - } + void handleItemIsExpanded(const QModelIndex &sourceIdx); + void updateTooltip(const StackFrame &frame); + + void setState(DebuggerTootipState newState); + void destroy(); public: - bool m_isPinned; - QToolButton *m_toolButton; - DraggableLabel *m_titleLabel; - QDate m_creationDate; - DebuggerToolTipTreeView *m_treeView; //!< Pointing to either m_defaultModel oder m_filterModel - DebuggerToolTipContext m_context; - TooltipFilterModel m_filterModel; //!< Pointing to a valid watchModel - QStandardItemModel m_defaultModel; + QPointer<DebuggerToolTipWidget> widget; + QPointer<DebuggerEngine> engine; + QDate creationDate; + DebuggerToolTipContext context; + TooltipFilterModel filterModel; //!< Pointing to a valid watchModel + QStandardItemModel defaultModel; + + DebuggerTootipState state; }; static void hideAllToolTips() { purgeClosedToolTips(); - foreach (const QPointer<DebuggerToolTipWidget> &tw, m_tooltips) - tw->hide(); + foreach (const DebuggerToolTipHolder *tooltip, m_tooltips) + tooltip->widget->hide(); } -void DebuggerToolTipWidget::pin() +void DebuggerToolTipHolder::handleItemIsExpanded(const QModelIndex &sourceIdx) { - if (m_isPinned) - return; - m_isPinned = true; - m_toolButton->setIcon(style()->standardIcon(QStyle::SP_DockWidgetCloseButton)); - - if (parentWidget()) { - // We are currently within a text editor tooltip: - // Rip out of parent widget and re-show as a tooltip - Utils::WidgetContent::pinToolTip(this); - } else { - // We have just be restored from session data. - setWindowFlags(Qt::ToolTip); - } - m_titleLabel->active = true; // User can now drag + QTC_ASSERT(filterModel.sourceModel() == sourceIdx.model(), return); + QModelIndex mappedIdx = filterModel.mapFromSource(sourceIdx); + QTC_ASSERT(widget.data(), return); + if (!widget->treeView->isExpanded(mappedIdx)) + widget->treeView->expand(mappedIdx); } /*! @@ -688,29 +777,37 @@ void DebuggerToolTipWidget::pin() */ DebuggerToolTipContext::DebuggerToolTipContext() - : position(0), line(0), column(0) + : position(0), line(0), column(0), scopeFromLine(0), scopeToLine(0) { } -bool DebuggerToolTipContext::matchesFrame(const QString &frameFile, const QString &frameFunction) const +static bool filesMatch(const QString &file1, const QString &file2) { - return (fileName.isEmpty() || frameFile.isEmpty() || fileName == frameFile) - && (function.isEmpty() || frameFunction.isEmpty() || function == frameFunction); + QFileInfo f1(file1); + QFileInfo f2(file2); + return f1.canonicalFilePath() == f2.canonicalFilePath(); +} + +bool DebuggerToolTipContext::matchesFrame(const StackFrame &frame) const +{ + return (fileName.isEmpty() || frame.file.isEmpty() || filesMatch(fileName, frame.file)) + //&& (function.isEmpty() || frame.function.isEmpty() || function == frame.function); + && (frame.line <= 0 || (scopeFromLine <= frame.line && frame.line <= scopeToLine)); } bool DebuggerToolTipContext::isSame(const DebuggerToolTipContext &other) const { - return fileName == other.fileName - && function == other.function + return filesMatch(fileName, other.fileName) + && scopeFromLine == other.scopeFromLine + && scopeToLine == other.scopeToLine && iname == other.iname; } QDebug operator<<(QDebug d, const DebuggerToolTipContext &c) { QDebug nsp = d.nospace(); - nsp << c.fileName << '@' << c.line << ',' << c.column << " (" << c.position << ')' << "INAME: " << c.iname << " EXP: " << c.expression; - if (!c.function.isEmpty()) - nsp << ' ' << c.function << "()"; + nsp << c.fileName << '@' << c.line << ',' << c.column << " (" << c.position << ')' + << "INAME: " << c.iname << " EXP: " << c.expression << " FUNCTION: " << c.function; return d; } @@ -752,159 +849,178 @@ QDebug operator<<(QDebug d, const DebuggerToolTipContext &c) of them. On closing or session changes, the contents it saved. */ - -static QString msgReleasedText() { return DebuggerToolTipWidget::tr("Previous"); } - -DebuggerToolTipWidget::DebuggerToolTipWidget(const DebuggerToolTipContext &context) +DebuggerToolTipHolder::DebuggerToolTipHolder(const DebuggerToolTipContext &context_) { - setFocusPolicy(Qt::NoFocus); + widget = new DebuggerToolTipWidget; + widget->setObjectName(QLatin1String("DebuggerTreeViewToolTipWidget: ") + QLatin1String(context_.iname)); - m_isPinned = false; - m_context = context; - m_filterModel.m_iname = context.iname; + context = context_; + context.creationDate = QDate::currentDate(); - const QIcon pinIcon(QLatin1String(":/debugger/images/pin.xpm")); + state = New; - m_toolButton = new QToolButton; - m_toolButton->setIcon(pinIcon); + filterModel.m_iname = context.iname; - auto copyButton = new QToolButton; - copyButton->setIcon(QIcon(QLatin1String(Core::Constants::ICON_COPY))); + QObject::connect(widget->pinButton, &QAbstractButton::clicked, [this] { + if (widget->isPinned) { + widget->close(); + } else { + widget->pin(); + } + }); + DEBUG("CREATE DEBUGGERTOOLTIPHOLDER" << context.iname); +} - m_titleLabel = new DraggableLabel(this); - m_titleLabel->setText(msgReleasedText()); - m_titleLabel->setMinimumWidth(40); // Ensure a draggable area even if text is empty. - m_titleLabel->setSizePolicy(QSizePolicy::MinimumExpanding, QSizePolicy::Preferred); +DebuggerToolTipHolder::~DebuggerToolTipHolder() +{ + DEBUG("DESTROY DEBUGGERTOOLTIPHOLDER" << context.iname << " STATE: " << state); + delete widget; widget.clear(); +} - auto toolBar = new QToolBar(this); - toolBar->setProperty("_q_custom_style_disabled", QVariant(true)); - const QList<QSize> pinIconSizes = pinIcon.availableSizes(); - if (!pinIconSizes.isEmpty()) - toolBar->setIconSize(pinIconSizes.front()); - toolBar->addWidget(m_toolButton); - toolBar->addWidget(copyButton); - toolBar->addWidget(m_titleLabel); +// This is called back from the engines after they populated the +// WatchModel. If the populating result from evaluation of this +// tooltip here, we are in "PendingUnshown" state (no Widget show yet), +// or "PendingShown" state (old widget reused). +// +// If we are in "Acquired" or "Released", this is an update +// after normal WatchModel update. - m_treeView = new DebuggerToolTipTreeView(this); - m_treeView->setFocusPolicy(Qt::NoFocus); +void DebuggerToolTipHolder::updateTooltip(const StackFrame &frame) +{ + const bool sameFrame = context.matchesFrame(frame); + DEBUG("UPDATE TOOLTIP: STATE " << state << context.iname + << "PINNED: " << widget->isPinned + << "SHOW NEEDED: " << widget->isPinned + << "SAME FRAME: " << sameFrame); - auto mainLayout = new QVBoxLayout(this); - mainLayout->setSizeConstraint(QLayout::SetFixedSize); - mainLayout->setContentsMargins(0, 0, 0, 0); - mainLayout->addWidget(toolBar); - mainLayout->addWidget(m_treeView); + if (state == PendingUnshown) { + const Utils::WidgetContent widgetContent(widget, true); + Utils::ToolTip::show(context.mousePosition, widgetContent, Internal::mainWindow()); + setState(PendingShown); + } - connect(m_toolButton, &QAbstractButton::clicked, [this]() { - if (m_isPinned) - close(); - else - pin(); - }); + if (state == PendingShown) { + acquireEngine(); + Utils::ToolTip::move(context.mousePosition, Internal::mainWindow()); + } else if (state == Acquired && !sameFrame) { + releaseEngine(); + } else if (state == Released && sameFrame) { + acquireEngine(); + } - connect(copyButton, &QAbstractButton::clicked, this, &DebuggerToolTipWidget::copy); -} + if (state == Acquired) { + // Save data to stream and restore to the backup m_defaultModel. + // Doing it on releaseEngine() is too later. + defaultModel.removeRows(0, defaultModel.rowCount()); + TreeModelCopyVisitor v(&filterModel, &defaultModel); + v.run(); -void DebuggerToolTipWidget::setWatchModel(WatchModelBase *watchModel) -{ - QTC_ASSERT(watchModel, return); - m_filterModel.setSourceModel(watchModel); - connect(watchModel, &WatchModelBase::itemIsExpanded, - this, &DebuggerToolTipWidget::handleItemIsExpanded, Qt::UniqueConnection); - connect(watchModel, &WatchModelBase::columnAdjustmentRequested, - m_treeView, &DebuggerToolTipTreeView::computeSize, Qt::UniqueConnection); + widget->treeView->expand(filterModel.index(0, 0)); + WatchTreeView::reexpand(widget->treeView, filterModel.index(0, 0)); + } } -void DebuggerToolTipWidget::handleStackFrameCompleted(const QString &frameFile, const QString &frameFunction) +void DebuggerToolTipHolder::setState(DebuggerTootipState newState) { - const bool sameFrame = m_context.matchesFrame(frameFile, frameFunction); - const bool isAcquired = m_treeView->model() == &m_filterModel; - if (isAcquired && !sameFrame) - releaseEngine(); - else if (!isAcquired && sameFrame) - acquireEngine(); + bool ok = (state == New && newState == PendingUnshown) + || (state == PendingUnshown && newState == PendingShown) + || (state == PendingShown && newState == Acquired) + || (state == Acquired && (newState == Released)) + || (state == Released && (newState == Acquired)); - if (isAcquired) { - m_treeView->expand(m_filterModel.index(0, 0)); - WatchTreeView::reexpand(m_treeView, m_filterModel.index(0, 0)); - } + // FIXME: These happen when a tooltip is re-used in findOrCreate. + ok = ok + || (state == Acquired && newState == PendingShown) + || (state == Released && newState == PendingShown); + + DEBUG("TRANSITION STATE FROM " << state << " TO " << newState); + QTC_ASSERT(ok, qDebug() << "Unexpected tooltip state transition from " + << state << " to " << newState); + + state = newState; } -void DebuggerToolTipWidget::acquireEngine() +void DebuggerToolTipHolder::destroy() { - m_titleLabel->setText(m_context.expression); - m_treeView->setModel(&m_filterModel); - m_treeView->setRootIndex(m_filterModel.index(0, 0)); - m_treeView->expand(m_filterModel.index(0, 0)); - WatchTreeView::reexpand(m_treeView, m_filterModel.index(0, 0)); + if (widget) { + widget->close(); + widget = 0; + } } -void DebuggerToolTipWidget::releaseEngine() +void DebuggerToolTipHolder::acquireEngine() { - // Save data to stream and restore to the backup m_defaultModel. - m_defaultModel.removeRows(0, m_defaultModel.rowCount()); - TreeModelCopyVisitor v(&m_filterModel, &m_defaultModel); - v.run(); + DEBUG("ACQUIRE ENGINE: STATE " << state); + setState(Acquired); - m_titleLabel->setText(msgReleasedText()); - m_treeView->setModel(&m_defaultModel); - m_treeView->setRootIndex(m_defaultModel.index(0, 0)); - m_treeView->expandAll(); + QTC_ASSERT(widget, return); + widget->titleLabel->setText(context.expression); + widget->treeView->setModel(&filterModel); + widget->treeView->setRootIndex(filterModel.index(0, 0)); + widget->treeView->expand(filterModel.index(0, 0)); + WatchTreeView::reexpand(widget->treeView, filterModel.index(0, 0)); } -void DebuggerToolTipWidget::copy() +void DebuggerToolTipHolder::releaseEngine() { - QString clipboardText = DebuggerToolTipManager::treeModelClipboardContents(m_treeView->model()); - QClipboard *clipboard = QApplication::clipboard(); - clipboard->setText(clipboardText, QClipboard::Selection); - clipboard->setText(clipboardText, QClipboard::Clipboard); + DEBUG("RELEASE ENGINE: STATE " << state); + setState(Released); + + QTC_ASSERT(widget, return); + widget->titleLabel->setText(DebuggerToolTipManager::tr("%1 (Previous)").arg(context.expression)); + widget->treeView->setModel(&defaultModel); + widget->treeView->setRootIndex(defaultModel.index(0, 0)); + widget->treeView->expandAll(); } -void DebuggerToolTipWidget::positionShow(const TextEditorWidget *editorWidget) +void DebuggerToolTipHolder::positionShow(const TextEditorWidget *editorWidget) { // Figure out new position of tooltip using the text edit. // If the line changed too much, close this tip. QTC_ASSERT(editorWidget, return); QTextCursor cursor = editorWidget->textCursor(); - cursor.setPosition(m_context.position); + cursor.setPosition(context.position); const int line = cursor.blockNumber(); - if (qAbs(m_context.line - line) > 2) { - close(); + if (qAbs(context.line - line) > 2) { + widget->close(); return ; } - const QPoint screenPos = editorWidget->toolTipPosition(cursor) + m_titleLabel->m_offset; - const QRect toolTipArea = QRect(screenPos, QSize(sizeHint())); + const QPoint screenPos = editorWidget->toolTipPosition(cursor) + widget->titleLabel->m_offset; + const QRect toolTipArea = QRect(screenPos, QSize(widget->sizeHint())); const QRect plainTextArea = QRect(editorWidget->mapToGlobal(QPoint(0, 0)), editorWidget->size()); const bool visible = plainTextArea.intersects(toolTipArea); - // qDebug() << "DebuggerToolTipWidget::positionShow() " << this << m_context + // DEBUG("DebuggerToolTipWidget::positionShow() " << this << m_context // << " line: " << line << " plainTextPos " << toolTipArea // << " offset: " << m_titleLabel->m_offset // << " Area: " << plainTextArea << " Screen pos: " - // << screenPos << te.widget << " visible=" << visible; + // << screenPos << te.widget << " visible=" << visible); - if (!visible) { - hide(); - return; + if (visible) { + widget->move(screenPos); + widget->show(); + } else { + widget->hide(); } - - move(screenPos); - show(); } -static DebuggerToolTipWidget *findOrCreateWidget(const DebuggerToolTipContext &context) +static DebuggerToolTipHolder *findOrCreateTooltip(const DebuggerToolTipContext &context, bool allowReuse = true) { - foreach (const QPointer<DebuggerToolTipWidget> &tw, m_tooltips) - if (tw && tw->m_context.isSame(context)) - return tw; - - auto tw = new DebuggerToolTipWidget(context); - tw->setAttribute(Qt::WA_DeleteOnClose); - tw->setObjectName(QLatin1String("DebuggerTreeViewToolTipWidget: ") + QLatin1String(context.iname)); - tw->m_context.creationDate = QDate::currentDate(); + purgeClosedToolTips(); - m_tooltips.push_back(tw); + for (int i = 0, n = m_tooltips.size(); i != n; ++i) { + DebuggerToolTipHolder *tooltip = m_tooltips.at(i); + if (tooltip->context.isSame(context)) { + if (allowReuse) + return tooltip; + tooltip->destroy(); + } + } + purgeClosedToolTips(); - return tw; + auto newTooltip = new DebuggerToolTipHolder(context); + m_tooltips.push_back(newTooltip); + return newTooltip; } static void restoreTreeModel(QXmlStreamReader &r, QStandardItemModel *m) @@ -975,27 +1091,26 @@ static void loadSessionDataHelper(QXmlStreamReader &r) context.iname = attributes.value(QLatin1String(treeInameAttributeC)).toString().toLatin1(); context.expression = attributes.value(QLatin1String(treeExpressionAttributeC)).toString(); - const QStringRef className = attributes.value(QLatin1String(toolTipClassAttributeC)); +// const QStringRef className = attributes.value(QLatin1String(toolTipClassAttributeC)); context.engineType = attributes.value(QLatin1String(engineTypeAttributeC)).toString(); context.creationDate = dateFromString(attributes.value(QLatin1String(dateAttributeC)).toString()); bool readTree = context.isValid(); if (!context.creationDate.isValid() || context.creationDate.daysTo(QDate::currentDate()) > toolTipsExpiryDays) { - // qDebug() << "Expiring tooltip " << context.fileName << '@' << context.position << " from " << creationDate; + // DEBUG("Expiring tooltip " << context.fileName << '@' << context.position << " from " << creationDate) + //readTree = false; + } else { //if (className != QLatin1String("Debugger::Internal::DebuggerToolTipWidget")) { + //qWarning("Unable to create debugger tool tip widget of class %s", qPrintable(className.toString())); //readTree = false; - } else if (className != QLatin1String("Debugger::Internal::DebuggerToolTipWidget")) { - qWarning("Unable to create debugger tool tip widget of class %s", qPrintable(className.toString())); - readTree = false; } if (readTree) { - DebuggerToolTipWidget *tw = findOrCreateWidget(context); - restoreTreeModel(r, &tw->m_defaultModel); - tw->pin(); - tw->acquireEngine(); - tw->m_titleLabel->setText(DebuggerToolTipManager::tr("Restored")); - tw->m_treeView->setModel(&tw->m_defaultModel); - tw->m_treeView->setRootIndex(tw->m_defaultModel.index(0, 0)); - tw->m_treeView->expandAll(); + DebuggerToolTipHolder *tw = findOrCreateTooltip(context); + restoreTreeModel(r, &tw->defaultModel); + tw->widget->pin(); + tw->widget->titleLabel->setText(DebuggerToolTipManager::tr("%1 (Restored").arg(context.expression)); + tw->widget->treeView->setModel(&tw->defaultModel); + tw->widget->treeView->setRootIndex(tw->defaultModel.index(0, 0)); + tw->widget->treeView->expandAll(); } else { r.readElementText(QXmlStreamReader::SkipChildElements); // Skip } @@ -1003,29 +1118,30 @@ static void loadSessionDataHelper(QXmlStreamReader &r) r.readNext(); // Skip </tree> } -void DebuggerToolTipWidget::saveSessionData(QXmlStreamWriter &w) const +void DebuggerToolTipHolder::saveSessionData(QXmlStreamWriter &w) const { w.writeStartElement(QLatin1String(toolTipElementC)); QXmlStreamAttributes attributes; - attributes.append(QLatin1String(toolTipClassAttributeC), QString::fromLatin1(metaObject()->className())); - attributes.append(QLatin1String(fileNameAttributeC), m_context.fileName); - if (!m_context.function.isEmpty()) - attributes.append(QLatin1String(functionAttributeC), m_context.function); - attributes.append(QLatin1String(textPositionAttributeC), QString::number(m_context.position)); - attributes.append(QLatin1String(textLineAttributeC), QString::number(m_context.line)); - attributes.append(QLatin1String(textColumnAttributeC), QString::number(m_context.column)); - attributes.append(QLatin1String(dateAttributeC), m_creationDate.toString(QLatin1String("yyyyMMdd"))); - if (m_titleLabel->m_offset.x()) - attributes.append(QLatin1String(offsetXAttributeC), QString::number(m_titleLabel->m_offset.x())); - if (m_titleLabel->m_offset.y()) - attributes.append(QLatin1String(offsetYAttributeC), QString::number(m_titleLabel->m_offset.y())); - attributes.append(QLatin1String(engineTypeAttributeC), m_context.engineType); - attributes.append(QLatin1String(treeExpressionAttributeC), m_context.expression); - attributes.append(QLatin1String(treeInameAttributeC), QLatin1String(m_context.iname)); +// attributes.append(QLatin1String(toolTipClassAttributeC), QString::fromLatin1(metaObject()->className())); + attributes.append(QLatin1String(fileNameAttributeC), context.fileName); + if (!context.function.isEmpty()) + attributes.append(QLatin1String(functionAttributeC), context.function); + attributes.append(QLatin1String(textPositionAttributeC), QString::number(context.position)); + attributes.append(QLatin1String(textLineAttributeC), QString::number(context.line)); + attributes.append(QLatin1String(textColumnAttributeC), QString::number(context.column)); + attributes.append(QLatin1String(dateAttributeC), creationDate.toString(QLatin1String("yyyyMMdd"))); + QPoint offset = widget->titleLabel->m_offset; + if (offset.x()) + attributes.append(QLatin1String(offsetXAttributeC), QString::number(offset.x())); + if (offset.y()) + attributes.append(QLatin1String(offsetYAttributeC), QString::number(offset.y())); + attributes.append(QLatin1String(engineTypeAttributeC), context.engineType); + attributes.append(QLatin1String(treeExpressionAttributeC), context.expression); + attributes.append(QLatin1String(treeInameAttributeC), QLatin1String(context.iname)); w.writeAttributes(attributes); w.writeStartElement(QLatin1String(treeElementC)); - XmlWriterTreeModelVisitor v(&m_filterModel, w); + XmlWriterTreeModelVisitor v(&filterModel, w); v.run(); w.writeEndElement(); @@ -1047,18 +1163,16 @@ void DebuggerToolTipWidget::saveSessionData(QXmlStreamWriter &w) const (by file name and function) acquire the engine, others release. */ +static DebuggerToolTipManager *m_instance = 0; DebuggerToolTipManager::DebuggerToolTipManager() { + m_instance = this; } DebuggerToolTipManager::~DebuggerToolTipManager() { -} - -void DebuggerToolTipManager::registerEngine(DebuggerEngine *) -{ - loadSessionData(); + m_instance = 0; } void DebuggerToolTipManager::slotUpdateVisibleToolTips() @@ -1084,11 +1198,26 @@ void DebuggerToolTipManager::slotUpdateVisibleToolTips() } // Reposition and show all tooltips of that file. - foreach (const QPointer<DebuggerToolTipWidget> &tw, m_tooltips) { - if (tw->fileName() == fileName) - tw->positionShow(toolTipEditor->editorWidget()); + foreach (DebuggerToolTipHolder *tooltip, m_tooltips) { + if (tooltip->context.fileName == fileName) + tooltip->positionShow(toolTipEditor->editorWidget()); else - tw->hide(); + tooltip->widget->hide(); + } +} + +void DebuggerToolTipManager::slotItemIsExpanded(const QModelIndex &idx) +{ + foreach (DebuggerToolTipHolder *tooltip, m_tooltips) + tooltip->handleItemIsExpanded(idx); +} + +void DebuggerToolTipManager::slotColumnAdjustmentRequested() +{ + foreach (DebuggerToolTipHolder *tooltip, m_tooltips) { + QTC_ASSERT(tooltip, continue); + QTC_ASSERT(tooltip->widget, continue); + tooltip->widget->treeView->computeSize(); } } @@ -1101,27 +1230,43 @@ void DebuggerToolTipManager::updateEngine(DebuggerEngine *engine) // Stack frame changed: All tooltips of that file acquire the engine, // all others release (arguable, this could be more precise?) - QString fileName; - QString function; - const int index = engine->stackHandler()->currentIndex(); - if (index >= 0) { - const StackFrame frame = engine->stackHandler()->currentFrame(); - if (frame.usable) { - fileName = frame.file; - function = frame.function; - } - } - foreach (const QPointer<DebuggerToolTipWidget> &tw, m_tooltips) - tw->handleStackFrameCompleted(fileName, function); - slotUpdateVisibleToolTips(); // Move out when stepping in same file. + StackFrame frame = engine->stackHandler()->currentFrame(); + foreach (DebuggerToolTipHolder *tooltip, m_tooltips) + tooltip->updateTooltip(frame); + slotUpdateVisibleToolTips(); // Move tooltip when stepping in same file. +} + + +void DebuggerToolTipManager::registerEngine(DebuggerEngine *engine) +{ + DEBUG("REGISTER ENGINE"); + WatchModelBase *watchModel = engine->watchHandler()->model(); + connect(watchModel, &WatchModelBase::itemIsExpanded, + m_instance, &DebuggerToolTipManager::slotItemIsExpanded); + connect(watchModel, &WatchModelBase::columnAdjustmentRequested, + m_instance, &DebuggerToolTipManager::slotColumnAdjustmentRequested); } void DebuggerToolTipManager::deregisterEngine(DebuggerEngine *engine) { + DEBUG("DEREGISTER ENGINE"); QTC_ASSERT(engine, return); - foreach (const QPointer<DebuggerToolTipWidget> &tw, m_tooltips) - if (tw && tw->m_context.engineType == engine->objectName()) - tw->releaseEngine(); + + // FIXME: For now remove all. + purgeClosedToolTips(); + foreach (DebuggerToolTipHolder *tooltip, m_tooltips) + tooltip->destroy(); + purgeClosedToolTips(); + return; + + WatchModelBase *watchModel = engine->watchHandler()->model(); + disconnect(watchModel, &WatchModelBase::itemIsExpanded, + m_instance, &DebuggerToolTipManager::slotItemIsExpanded); + disconnect(watchModel, &WatchModelBase::columnAdjustmentRequested, + m_instance, &DebuggerToolTipManager::slotColumnAdjustmentRequested); + foreach (DebuggerToolTipHolder *tooltip, m_tooltips) + if (tooltip->context.engineType == engine->objectName()) + tooltip->releaseEngine(); saveSessionData(); } @@ -1130,20 +1275,6 @@ bool DebuggerToolTipManager::hasToolTips() return !m_tooltips.isEmpty(); } -void DebuggerToolTipManager::showToolTip - (const DebuggerToolTipContext &context, DebuggerEngine *engine) -{ - QTC_ASSERT(engine, return); - QTC_ASSERT(!context.expression.isEmpty(), qDebug(" BUT EMPTY"); return); - - DebuggerToolTipWidget *tw = findOrCreateWidget(context); - tw->setWatchModel(engine->watchHandler()->model()); - tw->acquireEngine(); - - const Utils::WidgetContent widgetContent(tw, true); - Utils::ToolTip::show(context.mousePosition, widgetContent, Internal::mainWindow()); -} - void DebuggerToolTipManager::sessionAboutToChange() { closeAllToolTips(); @@ -1151,6 +1282,8 @@ void DebuggerToolTipManager::sessionAboutToChange() void DebuggerToolTipManager::loadSessionData() { + return; // FIXME + const QString data = sessionValue(sessionSettingsKeyC).toString(); QXmlStreamReader r(data); r.readNextStartElement(); @@ -1161,6 +1294,8 @@ void DebuggerToolTipManager::loadSessionData() void DebuggerToolTipManager::saveSessionData() { + return; // FIXME + QString data; purgeClosedToolTips(); @@ -1168,9 +1303,9 @@ void DebuggerToolTipManager::saveSessionData() w.writeStartDocument(); w.writeStartElement(QLatin1String(sessionDocumentC)); w.writeAttribute(QLatin1String(sessionVersionAttributeC), QLatin1String("1.0")); - foreach (const QPointer<DebuggerToolTipWidget> &tw, m_tooltips) - if (tw->isPinned()) - tw->saveSessionData(w); + foreach (DebuggerToolTipHolder *tooltip, m_tooltips) + if (tooltip->widget->isPinned) + tooltip->saveSessionData(w); w.writeEndDocument(); setSessionValue(sessionSettingsKeyC, QVariant(data)); @@ -1178,12 +1313,18 @@ void DebuggerToolTipManager::saveSessionData() void DebuggerToolTipManager::closeAllToolTips() { - purgeClosedToolTips(); - foreach (const QPointer<DebuggerToolTipWidget> &tw, m_tooltips) - tw->close(); + foreach (DebuggerToolTipHolder *tooltip, m_tooltips) + tooltip->destroy(); m_tooltips.clear(); } +void DebuggerToolTipManager::resetLocation() +{ + purgeClosedToolTips(); + foreach (DebuggerToolTipHolder *tooltip, m_tooltips) + tooltip->widget->pin(); +} + static void slotTooltipOverrideRequested (TextEditorWidget *editorWidget, const QPoint &point, int pos, bool *handled) { @@ -1202,35 +1343,68 @@ static void slotTooltipOverrideRequested context.engineType = engine->objectName(); context.fileName = editorWidget->textDocument()->filePath(); context.position = pos; - context.mousePosition = point; editorWidget->convertPosition(pos, &context.line, &context.column); - QString raw = cppExpressionAt(editorWidget, context.position, &context.line, &context.column, &context.function); + QString raw = cppExpressionAt(editorWidget, context.position, &context.line, &context.column, + &context.function, &context.scopeFromLine, &context.scopeToLine); context.expression = fixCppExpression(raw); if (context.expression.isEmpty()) { - const Utils::WidgetContent widgetContent(new QLabel(DebuggerToolTipManager::tr("No valid expression")), true); - Utils::ToolTip::show(context.mousePosition, widgetContent, Internal::mainWindow()); + const Utils::TextContent text(DebuggerToolTipManager::tr("No valid expression")); + Utils::ToolTip::show(point, text, Internal::mainWindow()); *handled = true; return; } // Prefer a filter on an existing local variable if it can be found. - if (const WatchData *localVariable = engine->watchHandler()->findCppLocalVariable(context.expression)) { + const WatchData *localVariable = engine->watchHandler()->findCppLocalVariable(context.expression); + if (localVariable) { context.expression = QLatin1String(localVariable->exp); if (context.expression.isEmpty()) context.expression = localVariable->name; context.iname = localVariable->iname; - DebuggerToolTipManager::showToolTip(context, engine); + } else { + context.iname = "tooltip." + context.expression.toLatin1().toHex(); + } + + bool allowReuse = false; + DebuggerToolTipHolder *tooltip = findOrCreateTooltip(context, allowReuse); + tooltip->context.mousePosition = point; + if (tooltip->state == PendingUnshown || tooltip->state == PendingShown) { + DEBUG("FOUND PENDING TOOLTIP, WAITING..."); *handled = true; return; } - context.iname = "tooltip." + context.expression.toLatin1().toHex(); - - *handled = engine->setToolTipExpression(editorWidget, context); + tooltip->filterModel.setSourceModel(engine->watchHandler()->model()); - // Other tooltip, close all in case mouse never entered the tooltip - // and no leave was triggered. + if (localVariable) { + DEBUG("SYNC IN STATE" << tooltip->state); + if (tooltip->state == New) { + tooltip->setState(PendingUnshown); + tooltip->setState(PendingShown); + tooltip->acquireEngine(); + const Utils::WidgetContent widgetContent(tooltip->widget, true); + Utils::ToolTip::show(point, widgetContent, Internal::mainWindow()); + } else { + tooltip->acquireEngine(); + Utils::ToolTip::move(point, Internal::mainWindow()); + } + *handled = true; + } else { + DEBUG("ASYNC TIP IN STATE" << tooltip->state); + if (tooltip->state == New) + tooltip->setState(PendingUnshown); + else if (tooltip->state == Acquired || tooltip->state == Released) + tooltip->setState(PendingShown); + else + QTC_CHECK(false); + *handled = engine->setToolTipExpression(editorWidget, context); + if (!*handled) { + const Utils::TextContent text(DebuggerToolTipManager::tr("Expression too complex")); + Utils::ToolTip::show(point, text, Internal::mainWindow()); + tooltip->destroy(); + } + } } @@ -1284,13 +1458,14 @@ void DebuggerToolTipManager::leavingDebugMode() } } -DebuggerToolTipContexts DebuggerToolTipManager::treeWidgetExpressions - (DebuggerEngine *, const QString &fileName, const QString &function) +DebuggerToolTipContexts DebuggerToolTipManager::pendingTooltips(DebuggerEngine *engine) { + StackFrame frame = engine->stackHandler()->currentFrame(); DebuggerToolTipContexts rc; - foreach (const QPointer<DebuggerToolTipWidget> &tw, m_tooltips) { - if (tw && tw->context().matchesFrame(fileName, function)) - rc.push_back(tw->context()); + foreach (DebuggerToolTipHolder *tooltip, m_tooltips) { + const DebuggerToolTipContext &context = tooltip->context; + if (context.iname.startsWith("tooltip") && context.matchesFrame(frame)) + rc.push_back(context); } return rc; } @@ -1304,9 +1479,9 @@ bool DebuggerToolTipManager::eventFilter(QObject *o, QEvent *e) const QMoveEvent *me = static_cast<const QMoveEvent *>(e); const QPoint dist = me->pos() - me->oldPos(); purgeClosedToolTips(); - foreach (const QPointer<DebuggerToolTipWidget> &tw, m_tooltips) - if (tw->isVisible()) - tw->move(tw->pos() + dist); + foreach (DebuggerToolTipHolder *tooltip, m_tooltips) + if (tooltip->widget && tooltip->widget->isVisible()) + tooltip->widget->move(tooltip->widget->pos() + dist); } break; case QEvent::WindowStateChange: { // Hide/Show along with parent (toplevel) @@ -1315,8 +1490,8 @@ bool DebuggerToolTipManager::eventFilter(QObject *o, QEvent *e) const bool isMinimized = static_cast<const QWidget *>(o)->windowState() & Qt::WindowMinimized; if (wasMinimized ^ isMinimized) { purgeClosedToolTips(); - foreach (const QPointer<DebuggerToolTipWidget> &tw, m_tooltips) - tw->setVisible(!isMinimized); + foreach (DebuggerToolTipHolder *tooltip, m_tooltips) + tooltip->widget->setVisible(!isMinimized); } } break; @@ -1326,5 +1501,16 @@ bool DebuggerToolTipManager::eventFilter(QObject *o, QEvent *e) return false; } +static void purgeClosedToolTips() +{ + for (int i = m_tooltips.size(); --i >= 0; ) { + DebuggerToolTipHolder *tooltip = m_tooltips.at(i); + if (!tooltip || !tooltip->widget) { + DEBUG("PURGE TOOLTIP, LEFT: " << m_tooltips.size()); + m_tooltips.removeAt(i); + } + } +} + } // namespace Internal } // namespace Debugger diff --git a/src/plugins/debugger/debuggertooltipmanager.h b/src/plugins/debugger/debuggertooltipmanager.h index 6fbc5480cc..2ff2f591d6 100644 --- a/src/plugins/debugger/debuggertooltipmanager.h +++ b/src/plugins/debugger/debuggertooltipmanager.h @@ -47,19 +47,23 @@ class DebuggerEngine; namespace Internal { +class StackFrame; + class DebuggerToolTipContext { public: DebuggerToolTipContext(); bool isValid() const { return !expression.isEmpty(); } - bool matchesFrame(const QString &frameFile, const QString &frameFunction) const; + bool matchesFrame(const StackFrame &frame) const; bool isSame(const DebuggerToolTipContext &other) const; QString fileName; int position; int line; int column; - QString function; //!< Optional function. This must be set by the engine as it is language-specific. + int scopeFromLine; + int scopeToLine; + QString function; //!< Optional, informational only. QString engineType; QDate creationDate; @@ -83,12 +87,7 @@ public: static void updateEngine(DebuggerEngine *engine); static bool hasToolTips(); - // Collect all expressions of DebuggerTreeViewToolTipWidget - static DebuggerToolTipContexts treeWidgetExpressions(DebuggerEngine *engine, - const QString &fileName, const QString &function = QString()); - - static void showToolTip(const DebuggerToolTipContext &context, - DebuggerEngine *engine); + static DebuggerToolTipContexts pendingTooltips(DebuggerEngine *engine); virtual bool eventFilter(QObject *, QEvent *); @@ -100,9 +99,12 @@ public: static void loadSessionData(); static void saveSessionData(); static void closeAllToolTips(); + static void resetLocation(); public slots: static void slotUpdateVisibleToolTips(); + void slotItemIsExpanded(const QModelIndex &idx); + void slotColumnAdjustmentRequested(); }; } // namespace Internal diff --git a/src/plugins/debugger/gdb/gdbengine.cpp b/src/plugins/debugger/gdb/gdbengine.cpp index 979e4a00db..54a429933d 100644 --- a/src/plugins/debugger/gdb/gdbengine.cpp +++ b/src/plugins/debugger/gdb/gdbengine.cpp @@ -3632,43 +3632,16 @@ void GdbEngine::handleRegisterListValues(const GdbResponse &response) // ////////////////////////////////////////////////////////////////////// -//void GdbEngine::showToolTip() -//{ -// const QString expression = m_toolTipContext.expression; -// if (DebuggerToolTipManager::debug()) -// qDebug() << "GdbEngine::showToolTip " << expression << m_toolTipContext.iname << m_toolTipContext; - -// if (m_toolTipContext.iname.startsWith("tooltip") -// && (!boolSetting(UseToolTipsInMainEditor) -// || !watchHandler()->isValidToolTip(m_toolTipContext.iname))) { -// watchHandler()->removeData(m_toolTipContext.iname); -// return; -// } - -// DebuggerToolTipManager::showToolTip(m_toolTipContext, this); -//} - -void GdbEngine::resetLocation() -{ - m_toolTipContext.expression.clear(); - DebuggerEngine::resetLocation(); -} - bool GdbEngine::setToolTipExpression(TextEditor::TextEditorWidget *editor, const DebuggerToolTipContext &context) { - if (state() != InferiorStopOk || !isCppEditor(editor)) { - //qDebug() << "SUPPRESSING DEBUGGER TOOLTIP, INFERIOR NOT STOPPED " - // " OR NOT A CPPEDITOR"; + if (state() != InferiorStopOk || !isCppEditor(editor)) return false; - } - - m_toolTipContext = context; - // qDebug() << "GdbEngine::setToolTipExpression2 " << exp << m_toolTipContext; UpdateParameters params; params.tryPartial = true; params.tooltipOnly = true; + params.tooltipExpression = context.expression; params.varList = context.iname; updateLocalsPython(params); return true; @@ -3736,10 +3709,6 @@ void GdbEngine::rebuildWatchModel() showMessage(_("<Rebuild Watchmodel %1>").arg(count), LogMiscInput); showStatusMessage(tr("Finished retrieving data"), 400); - if (m_toolTipContext.isValid()) { - DebuggerToolTipManager::showToolTip(m_toolTipContext, this); - m_toolTipContext = DebuggerToolTipContext(); - } DebuggerToolTipManager::updateEngine(this); } @@ -4829,42 +4798,16 @@ void GdbEngine::updateLocalsPython(const UpdateParameters ¶ms) + " displaystringlimit:" + action(DisplayStringLimit)->value().toByteArray(); - + // Re-create tooltip items that are not filters on existing local variables in + // the tooltip model. QByteArray watchers; - const QString fileName = stackHandler()->currentFrame().file; - const QString function = stackHandler()->currentFrame().function; - if (!fileName.isEmpty()) { - // Re-create tooltip items that are not filters on existing local variables in - // the tooltip model. - DebuggerToolTipContexts toolTips = - DebuggerToolTipManager::treeWidgetExpressions(this, fileName, function); - - const QString currentExpression = m_toolTipContext.expression; - if (!currentExpression.isEmpty()) { - int currentIndex = -1; - for (int i = 0; i < toolTips.size(); ++i) { - if (toolTips.at(i).expression == currentExpression) { - currentIndex = i; - break; - } - } - if (currentIndex < 0) { - DebuggerToolTipContext context; - context.expression = currentExpression; - context.iname = tooltipIName(currentExpression); - toolTips.push_back(context); - } - } - - foreach (const DebuggerToolTipContext &p, toolTips) { - if (p.iname.startsWith("tooltip")) { - if (!watchers.isEmpty()) - watchers += "##"; - watchers += p.expression.toLatin1(); - watchers += '#'; - watchers += p.iname; - } - } + DebuggerToolTipContexts toolTips = DebuggerToolTipManager::pendingTooltips(this); + foreach (const DebuggerToolTipContext &p, toolTips) { + if (!watchers.isEmpty()) + watchers += "##"; + watchers += p.expression.toLatin1(); + watchers += '#'; + watchers += p.iname; } QHash<QByteArray, int> watcherNames = handler->watcherNames(); diff --git a/src/plugins/debugger/gdb/gdbengine.h b/src/plugins/debugger/gdb/gdbengine.h index 4f953e8d69..bcae9fc78e 100644 --- a/src/plugins/debugger/gdb/gdbengine.h +++ b/src/plugins/debugger/gdb/gdbengine.h @@ -298,7 +298,6 @@ private: ////////// View & Data Stuff ////////// void selectThread(ThreadId threadId); void activateFrame(int index); - void resetLocation(); // // Breakpoint specific stuff @@ -469,7 +468,6 @@ protected: void showExecutionError(const QString &message); static QByteArray tooltipIName(const QString &exp); - DebuggerToolTipContext m_toolTipContext; // For short-circuiting stack and thread list evaluation. bool m_stackNeeded; diff --git a/src/plugins/debugger/lldb/lldbengine.cpp b/src/plugins/debugger/lldb/lldbengine.cpp index afb1afe377..ee0b45a772 100644 --- a/src/plugins/debugger/lldb/lldbengine.cpp +++ b/src/plugins/debugger/lldb/lldbengine.cpp @@ -74,11 +74,6 @@ using namespace Utils; namespace Debugger { namespace Internal { -static QByteArray tooltipIName(const QString &exp) -{ - return "tooltip." + exp.toLatin1().toHex(); -} - /////////////////////////////////////////////////////////////////////// // // LldbEngine @@ -254,7 +249,7 @@ void LldbEngine::startLldb() args.append(_("-i")); args.append(Core::ICore::resourcePath() + _("/debugger/lldbbridge.py")); args.append(m_lldbCmd); - showMessage(_("STARTING LLDB ") + args.join(QLatin1Char(' '))); + showMessage(_("STARTING LLDB: python ") + args.join(QLatin1Char(' '))); m_lldbProc.setEnvironment(startParameters().environment.toStringList()); if (!startParameters().workingDirectory.isEmpty()) m_lldbProc.setWorkingDirectory(startParameters().workingDirectory); @@ -524,7 +519,8 @@ void LldbEngine::activateFrame(int frameIndex) cmd.arg("thread", threadsHandler()->currentThread().raw()); runCommand(cmd); - updateAll(); + reloadRegisters(); + updateLocals(); } void LldbEngine::selectThread(ThreadId threadId) @@ -680,7 +676,8 @@ void LldbEngine::updateBreakpointData(const GdbMi &bkpt, bool added) response.address = location["addr"].toAddress(); response.functionName = location["func"].toUtf8(); } else { - QTC_CHECK(false); + // This can happen for pending breakpoints. + showMessage(_("NO LOCATIONS (YET) FOR BP %1").arg(response.toString())); } handler->setResponse(id, response); if (added) @@ -815,25 +812,8 @@ void LldbEngine::refreshSymbols(const GdbMi &symbols) // ////////////////////////////////////////////////////////////////////// -static WatchData m_toolTip; -static QPoint m_toolTipPos; -static QHash<QString, WatchData> m_toolTipCache; - -void LldbEngine::showToolTip() -{ - if (m_toolTipContext.expression.isEmpty()) - return; - //const QString expression = m_toolTipContext->expression; - // qDebug() << "LldbEngine::showToolTip " << expression << m_toolTipContext->iname << (*m_toolTipContext); - - DebuggerToolTipManager::showToolTip(m_toolTipContext, this); - // Prevent tooltip from re-occurring (classic GDB, QTCREATORBUG-4711). - m_toolTipContext.expression.clear(); -} - void LldbEngine::resetLocation() { - m_toolTipContext.expression.clear(); DebuggerEngine::resetLocation(); } @@ -845,11 +825,10 @@ bool LldbEngine::setToolTipExpression(TextEditor::TextEditorWidget *editorWidget return false; } - m_toolTipContext = context; - UpdateParameters params; params.tryPartial = true; params.tooltipOnly = true; + params.tooltipExpression = context.expression; params.varList = context.iname; doUpdateLocals(params); @@ -924,6 +903,7 @@ void LldbEngine::doUpdateLocals(UpdateParameters params) cmd.arg("tooltiponly", params.tooltipOnly); cmd.beginList("watchers"); + // Watchers QHashIterator<QByteArray, int> it(WatchHandler::watcherNames()); while (it.hasNext()) { @@ -933,38 +913,16 @@ void LldbEngine::doUpdateLocals(UpdateParameters params) .arg("exp", it.key().toHex()) .endGroup(); } - // Tooltip - const StackFrame frame = stackHandler()->currentFrame(); - if (!frame.file.isEmpty()) { - // Re-create tooltip items that are not filters on existing local variables in - // the tooltip model. - DebuggerToolTipContexts toolTips = - DebuggerToolTipManager::treeWidgetExpressions(this, frame.file, frame.function); - - const QString currentExpression = m_toolTipContext.expression; - if (!currentExpression.isEmpty()) { - int currentIndex = -1; - for (int i = 0; i < toolTips.size(); ++i) { - if (toolTips.at(i).expression == currentExpression) { - currentIndex = i; - break; - } - } - if (currentIndex < 0) { - DebuggerToolTipContext context; - context.expression = currentExpression; - context.iname = tooltipIName(currentExpression); - toolTips.push_back(context); - } - } - foreach (const DebuggerToolTipContext &p, toolTips) { - if (p.iname.startsWith("tooltip")) - cmd.beginGroup() - .arg("iname", p.iname) - .arg("exp", p.expression.toLatin1().toHex()) - .endGroup(); - } + + // Tooltips + DebuggerToolTipContexts toolTips = DebuggerToolTipManager::pendingTooltips(this); + foreach (const DebuggerToolTipContext &p, toolTips) { + cmd.beginGroup() + .arg("iname", p.iname) + .arg("exp", p.expression.toLatin1().toHex()) + .endGroup(); } + cmd.endList(); //cmd.arg("resultvarname", m_resultVarName); @@ -1034,9 +992,8 @@ void LldbEngine::handleLldbFinished(int code, QProcess::ExitStatus type) void LldbEngine::readLldbStandardError() { QByteArray err = m_lldbProc.readAllStandardError(); - qDebug() << "\nLLDB STDERR" << err; - //qWarning() << "Unexpected lldb stderr:" << err; - showMessage(_(err), LogError); + qDebug() << "\nLLDB STDERR UNEXPECTED: " << err; + showMessage(_("Lldb stderr: " + err), LogError); } void LldbEngine::readLldbStandardOutput() @@ -1083,7 +1040,7 @@ void LldbEngine::refreshLocals(const GdbMi &vars) } handler->insertData(list); - showToolTip(); + DebuggerToolTipManager::updateEngine(this); } void LldbEngine::refreshStack(const GdbMi &stack) @@ -1199,6 +1156,8 @@ void LldbEngine::refreshState(const GdbMi &reportedState) notifyEngineRunFailed(); else if (newState == "inferiorsetupok") notifyInferiorSetupOk(); + else if (newState == "inferiorsetupfailed") + notifyInferiorSetupFailed(); else if (newState == "enginerunandinferiorrunok") { if (startParameters().continueAfterAttach) m_continueAtNextSpontaneousStop = true; @@ -1219,15 +1178,16 @@ void LldbEngine::refreshState(const GdbMi &reportedState) void LldbEngine::refreshLocation(const GdbMi &reportedLocation) { - if (boolSetting(OperateByInstruction)) { - Location loc(reportedLocation["addr"].toAddress()); + qulonglong addr = reportedLocation["addr"].toAddress(); + QString file = reportedLocation["file"].toUtf8(); + int line = reportedLocation["line"].toInt(); + Location loc = Location(file, line); + if (boolSetting(OperateByInstruction) || !QFileInfo::exists(file) || line <= 0) { + loc = Location(addr); loc.setNeedsMarker(true); - gotoLocation(loc); - } else { - QString file = reportedLocation["file"].toUtf8(); - int line = reportedLocation["line"].toInt(); - gotoLocation(Location(file, line)); + loc.setUseAssembler(true); } + gotoLocation(loc); } void LldbEngine::reloadRegisters() diff --git a/src/plugins/debugger/lldb/lldbengine.h b/src/plugins/debugger/lldb/lldbengine.h index 955e58fa1d..cb4ce7fc7b 100644 --- a/src/plugins/debugger/lldb/lldbengine.h +++ b/src/plugins/debugger/lldb/lldbengine.h @@ -218,9 +218,6 @@ private: QMap<QPointer<DisassemblerAgent>, int> m_disassemblerAgents; QMap<QPointer<MemoryAgent>, int> m_memoryAgents; QHash<int, QPointer<QObject> > m_memoryAgentTokens; - DebuggerToolTipContext m_toolTipContext; - - void showToolTip(); // Console handling. Q_SLOT void stubError(const QString &msg); diff --git a/src/plugins/debugger/qml/qmlinspectoradapter.cpp b/src/plugins/debugger/qml/qmlinspectoradapter.cpp index c7ea47450d..207a706673 100644 --- a/src/plugins/debugger/qml/qmlinspectoradapter.cpp +++ b/src/plugins/debugger/qml/qmlinspectoradapter.cpp @@ -226,7 +226,7 @@ void QmlInspectorAdapter::toolsClientStateChanged(QmlDebugClient::State state) Core::Id(Constants::QML_UPDATE_ON_SAVE), m_inspectorToolsContext); - Core::ICore::updateAdditionalContexts(Core::Context(), m_inspectorToolsContext); + Core::ICore::addAdditionalContext(m_inspectorToolsContext); m_toolsClientConnected = true; onEngineStateChanged(m_engine->state()); @@ -246,7 +246,7 @@ void QmlInspectorAdapter::toolsClientStateChanged(QmlDebugClient::State state) Core::ActionManager::unregisterAction(m_updateOnSaveAction, Core::Id(Constants::QML_UPDATE_ON_SAVE)); - Core::ICore::updateAdditionalContexts(m_inspectorToolsContext, Core::Context()); + Core::ICore::removeAdditionalContext(m_inspectorToolsContext); enableTools(false); m_toolsClientConnected = false; diff --git a/src/plugins/debugger/sourceutils.cpp b/src/plugins/debugger/sourceutils.cpp index d3bf19ff6d..eec4b595cf 100644 --- a/src/plugins/debugger/sourceutils.cpp +++ b/src/plugins/debugger/sourceutils.cpp @@ -269,11 +269,7 @@ bool isCppEditor(TextEditorWidget *editorWidget) QString cppFunctionAt(const QString &fileName, int line, int column) { - CppModelManager *modelManager = CppModelManager::instance(); - if (!modelManager) - return QString(); - - const Snapshot snapshot = modelManager->snapshot(); + const Snapshot snapshot = CppModelManager::instance()->snapshot(); if (const Document::Ptr document = snapshot.document(fileName)) return document->functionAt(line, column); @@ -283,7 +279,8 @@ QString cppFunctionAt(const QString &fileName, int line, int column) // Return the Cpp expression, and, if desired, the function QString cppExpressionAt(TextEditorWidget *editorWidget, int pos, - int *line, int *column, QString *function /* = 0 */) + int *line, int *column, QString *function, + int *scopeFromLine, int *scopeToLine) { *line = *column = 0; if (function) @@ -291,8 +288,7 @@ QString cppExpressionAt(TextEditorWidget *editorWidget, int pos, QTextCursor tc = editorWidget->textCursor(); QString expr = tc.selectedText(); - CppModelManager *modelManager = CppModelManager::instance(); - if (expr.isEmpty() && modelManager) { + if (expr.isEmpty()) { tc.setPosition(pos); const QChar ch = editorWidget->characterAt(pos); if (ch.isLetterOrNumber() || ch == QLatin1Char('_')) @@ -308,8 +304,15 @@ QString cppExpressionAt(TextEditorWidget *editorWidget, int pos, *line = tc.blockNumber(); } - if (function && !expr.isEmpty()) - *function = cppFunctionAt(editorWidget->textDocument()->filePath(), *line, *column); + if (!expr.isEmpty()) { + QString fileName = editorWidget->textDocument()->filePath(); + const Snapshot snapshot = CppModelManager::instance()->snapshot(); + if (const Document::Ptr document = snapshot.document(fileName)) { + QString func = document->functionAt(*line, *column, scopeFromLine, scopeToLine); + if (function) + *function = func; + } + } return expr; } diff --git a/src/plugins/debugger/sourceutils.h b/src/plugins/debugger/sourceutils.h index cb5f9edf39..9dda73c08c 100644 --- a/src/plugins/debugger/sourceutils.h +++ b/src/plugins/debugger/sourceutils.h @@ -42,7 +42,8 @@ namespace Internal { // Editor tooltip support bool isCppEditor(TextEditor::TextEditorWidget *editorWidget); QString cppExpressionAt(TextEditor::TextEditorWidget *editorWidget, int pos, - int *line, int *column, QString *function = 0); + int *line, int *column, QString *function = 0, + int *scopeFromLine = 0, int *scopeToLine = 0); QString fixCppExpression(const QString &exp); QString cppFunctionAt(const QString &fileName, int line, int column = 0); diff --git a/src/plugins/debugger/watchhandler.cpp b/src/plugins/debugger/watchhandler.cpp index 0070f3567d..05afb7c061 100644 --- a/src/plugins/debugger/watchhandler.cpp +++ b/src/plugins/debugger/watchhandler.cpp @@ -2015,10 +2015,10 @@ const WatchData *WatchHandler::findCppLocalVariable(const QString &name) const QByteArray iname = localsPrefix + name.toLatin1(); if (const WatchData *wd = findData(iname)) return wd; - // Nope, try a 'local.this.m_foo'. - iname.insert(localsPrefix.size(), "this."); - if (const WatchData *wd = findData(iname)) - return wd; +// // Nope, try a 'local.this.m_foo'. +// iname.insert(localsPrefix.size(), "this."); +// if (const WatchData *wd = findData(iname)) +// return wd; return 0; } diff --git a/src/plugins/debugger/watchhandler.h b/src/plugins/debugger/watchhandler.h index e34578bca8..987095c375 100644 --- a/src/plugins/debugger/watchhandler.h +++ b/src/plugins/debugger/watchhandler.h @@ -121,6 +121,7 @@ public: bool tryPartial; bool tooltipOnly; QByteArray varList; + QString tooltipExpression; }; typedef QHash<QString, QStringList> DumperTypeFormats; // Type name -> Dumper Formats diff --git a/src/plugins/designer/formtemplatewizardpage.cpp b/src/plugins/designer/formtemplatewizardpage.cpp index 6d5abd5d79..f12c770ffa 100644 --- a/src/plugins/designer/formtemplatewizardpage.cpp +++ b/src/plugins/designer/formtemplatewizardpage.cpp @@ -122,7 +122,7 @@ bool FormTemplateWizardPage::validatePage() QMessageBox::critical(this, tr("%1 - Error").arg(title()), errorMessage); return false; } - wizard()->setProperty("FormContents", m_templateContents.replace(QLatin1Char('\n'), QLatin1String("\\n"))); + wizard()->setProperty("FormContents", m_templateContents.split(QLatin1Char('\n'))); return true; } diff --git a/src/plugins/diffeditor/diffeditorcontroller.cpp b/src/plugins/diffeditor/diffeditorcontroller.cpp index 796ff19673..df10cf1f33 100644 --- a/src/plugins/diffeditor/diffeditorcontroller.cpp +++ b/src/plugins/diffeditor/diffeditorcontroller.cpp @@ -108,6 +108,44 @@ bool DiffEditorController::isIgnoreWhitespace() const return m_ignoreWhitespace; } +// ### fixme: git-specific handling should be done in the git plugin: +// Remove unexpanded branches and follows-tag, clear indentation +// and create E-mail +static void formatGitDescription(QString *description) +{ + QString result; + result.reserve(description->size()); + foreach (QString line, description->split(QLatin1Char('\n'))) { + if (line.startsWith(QLatin1String("commit ")) + || line.startsWith(QLatin1String("Branches: <Expand>"))) { + continue; + } + if (line.startsWith(QLatin1String("Author: "))) + line.replace(0, 8, QStringLiteral("From: ")); + else if (line.startsWith(QLatin1String(" "))) + line.remove(0, 4); + result.append(line); + result.append(QLatin1Char('\n')); + } + *description = result; +} + +QString DiffEditorController::contents() const +{ + QString result = m_description; + const int formattingOptions = DiffUtils::GitFormat; + if (formattingOptions & DiffUtils::GitFormat) + formatGitDescription(&result); + + const QString diff = DiffUtils::makePatch(diffFiles(), formattingOptions); + if (!diff.isEmpty()) { + if (!result.isEmpty()) + result += QLatin1Char('\n'); + result += diff; + } + return result; +} + QString DiffEditorController::makePatch(bool revert, bool addPrefix) const { if (m_diffFileIndex < 0 || m_chunkIndex < 0) diff --git a/src/plugins/diffeditor/diffeditorcontroller.h b/src/plugins/diffeditor/diffeditorcontroller.h index f310364414..43f65a86a1 100644 --- a/src/plugins/diffeditor/diffeditorcontroller.h +++ b/src/plugins/diffeditor/diffeditorcontroller.h @@ -58,6 +58,7 @@ public: bool isIgnoreWhitespace() const; QString makePatch(bool revert, bool addPrefix = false) const; + QString contents() const; DiffEditorReloader *reloader() const; void setReloader(DiffEditorReloader *reloader); diff --git a/src/plugins/diffeditor/diffeditordocument.cpp b/src/plugins/diffeditor/diffeditordocument.cpp index e34a184444..3aaedf549a 100644 --- a/src/plugins/diffeditor/diffeditordocument.cpp +++ b/src/plugins/diffeditor/diffeditordocument.cpp @@ -78,9 +78,7 @@ bool DiffEditorDocument::save(QString *errorString, const QString &fileName, boo Q_UNUSED(errorString) Q_UNUSED(autoSave) - const QString contents = DiffUtils::makePatch(m_controller->diffFiles()); - - const bool ok = write(fileName, format(), contents, errorString); + const bool ok = write(fileName, format(), m_controller->contents(), errorString); if (!ok) return false; @@ -127,4 +125,39 @@ bool DiffEditorDocument::open(QString *errorString, const QString &fileName) return true; } +QString DiffEditorDocument::suggestedFileName() const +{ + enum { maxSubjectLength = 50 }; + QString result = QStringLiteral("0001"); + const QString description = m_controller->description(); + if (!description.isEmpty()) { + // Derive "git format-patch-type" file name from subject. + const int pos = description.indexOf(QLatin1String("\n\n ")); + const int endPos = pos >= 0 ? description.indexOf(QLatin1Char('\n'), pos + 6) : -1; + if (endPos > pos) { + const QChar space(QLatin1Char(' ')); + const QChar dash(QLatin1Char('-')); + QString subject = description.mid(pos, endPos - pos); + for (int i = 0; i < subject.size(); ++i) { + if (!subject.at(i).isLetterOrNumber()) + subject[i] = space; + } + subject = subject.simplified(); + if (subject.size() > maxSubjectLength) { + const int lastSpace = subject.lastIndexOf(space, maxSubjectLength); + subject.truncate(lastSpace > 0 ? lastSpace : maxSubjectLength); + } + subject.replace(space, dash); + result += dash; + result += subject; + } + } + return result + QStringLiteral(".patch"); +} + +QString DiffEditorDocument::plainText() const +{ + return m_controller->contents(); +} + } // namespace DiffEditor diff --git a/src/plugins/diffeditor/diffeditordocument.h b/src/plugins/diffeditor/diffeditordocument.h index 01c2400ba9..e52d739d57 100644 --- a/src/plugins/diffeditor/diffeditordocument.h +++ b/src/plugins/diffeditor/diffeditordocument.h @@ -42,6 +42,7 @@ class DiffEditorController; class DIFFEDITOR_EXPORT DiffEditorDocument : public Core::BaseTextDocument { Q_OBJECT + Q_PROPERTY(QString plainText READ plainText STORED false) // For access by code pasters public: explicit DiffEditorDocument(); virtual ~DiffEditorDocument(); @@ -50,7 +51,7 @@ public: bool setContents(const QByteArray &contents); QString defaultPath() const; - QString suggestedFileName() const { return QString(); } + QString suggestedFileName() const Q_DECL_OVERRIDE; bool isModified() const { return false; } bool isSaveAsAllowed() const { return true; } @@ -58,6 +59,8 @@ public: bool reload(QString *errorString, ReloadFlag flag, ChangeType type); bool open(QString *errorString, const QString &fileName); + QString plainText() const; + private: DiffEditorController *m_controller; }; diff --git a/src/plugins/diffeditor/diffeditorplugin.cpp b/src/plugins/diffeditor/diffeditorplugin.cpp index 78f8cfee6b..a3d89c823b 100644 --- a/src/plugins/diffeditor/diffeditorplugin.cpp +++ b/src/plugins/diffeditor/diffeditorplugin.cpp @@ -194,9 +194,8 @@ void DiffEditorPlugin::diff() const QString documentId = QLatin1String("Diff ") + fileName1 + QLatin1String(", ") + fileName2; - DiffEditorDocument *document = DiffEditorManager::find(documentId); QString title = tr("Diff \"%1\", \"%2\"").arg(fileName1).arg(fileName2); - document = DiffEditorManager::findOrCreate(documentId, title); + DiffEditorDocument * const document = DiffEditorManager::findOrCreate(documentId, title); if (!document) return; diff --git a/src/plugins/diffeditor/diffutils.cpp b/src/plugins/diffeditor/diffutils.cpp index fdfb548fdf..bed256c01e 100644 --- a/src/plugins/diffeditor/diffutils.cpp +++ b/src/plugins/diffeditor/diffutils.cpp @@ -31,6 +31,7 @@ #include "diffutils.h" #include "differ.h" #include <QStringList> +#include <QTextStream> #include "texteditor/fontsettings.h" namespace DiffEditor { @@ -483,31 +484,35 @@ QString DiffUtils::makePatch(const ChunkData &chunkData, return diffText; } -QString DiffUtils::makePatch(const QList<FileData> &fileDataList) +QString DiffUtils::makePatch(const QList<FileData> &fileDataList, unsigned formatFlags) { QString diffText; + QTextStream str(&diffText); for (int i = 0; i < fileDataList.count(); i++) { const FileData &fileData = fileDataList.at(i); - + if (formatFlags & GitFormat) { + str << "diff --git a/" << fileData.leftFileInfo.fileName + << " b/" << fileData.rightFileInfo.fileName << '\n'; + } if (fileData.binaryFiles) { - const QString binaryLine = QLatin1String("Binary files ") - + fileData.leftFileInfo.fileName - + QLatin1String(" and ") - + fileData.rightFileInfo.fileName - + QLatin1String(" differ\n"); - diffText += binaryLine; + str << "Binary files "; + if (formatFlags & AddLevel) + str << "a/"; + str << fileData.leftFileInfo.fileName << " and "; + if (formatFlags & AddLevel) + str << "b/"; + str << fileData.rightFileInfo.fileName << " differ\n"; } else { - const QString leftFileInfo = QLatin1String("--- ") - + fileData.leftFileInfo.fileName + QLatin1Char('\n'); - const QString rightFileInfo = QLatin1String("+++ ") - + fileData.rightFileInfo.fileName + QLatin1Char('\n'); - - diffText += leftFileInfo; - diffText += rightFileInfo; - + str << "--- "; + if (formatFlags & AddLevel) + str << "a/"; + str << fileData.leftFileInfo.fileName << "\n+++ "; + if (formatFlags & AddLevel) + str << "b/"; + str << fileData.rightFileInfo.fileName << '\n'; for (int j = 0; j < fileData.chunks.count(); j++) { - diffText += makePatch(fileData.chunks.at(j), + str << makePatch(fileData.chunks.at(j), (j == fileData.chunks.count() - 1) && fileData.lastChunkAtTheEndOfFile); } diff --git a/src/plugins/diffeditor/diffutils.h b/src/plugins/diffeditor/diffutils.h index bb0d3ed0d4..ee74f9672a 100644 --- a/src/plugins/diffeditor/diffutils.h +++ b/src/plugins/diffeditor/diffutils.h @@ -130,6 +130,10 @@ public: class DIFFEDITOR_EXPORT DiffUtils { public: + enum PatchFormattingFlags { + AddLevel = 0x1, // Add 'a/' , '/b' for git am + GitFormat = AddLevel | 0x2, // Add line 'diff ..' as git does + }; static ChunkData calculateOriginalData(const QList<Diff> &leftDiffList, const QList<Diff> &rightDiffList); @@ -146,7 +150,8 @@ public: const QString &leftFileName, const QString &rightFileName, bool lastChunk = false); - static QString makePatch(const QList<FileData> &fileDataList); + static QString makePatch(const QList<FileData> &fileDataList, + unsigned formatFlags = 0); static QList<FileData> readPatch(const QString &patch, bool *ok = 0); }; diff --git a/src/plugins/git/gitconstants.h b/src/plugins/git/gitconstants.h index e831858394..ccb2827709 100644 --- a/src/plugins/git/gitconstants.h +++ b/src/plugins/git/gitconstants.h @@ -47,6 +47,7 @@ const char GIT_COMMIT_TEXT_EDITOR_DISPLAY_NAME[] = QT_TRANSLATE_NOOP("VCS", "Git const char GIT_REBASE_EDITOR_ID[] = "Git Rebase Editor"; const char GIT_REBASE_EDITOR_DISPLAY_NAME[] = QT_TRANSLATE_NOOP("VCS", "Git Rebase Editor"); +const char GIT_CONTEXT[] = "Git Context"; const char GITSUBMITEDITOR_ID[] = "Git Submit Editor"; const char GITSUBMITEDITOR_DISPLAY_NAME[] = QT_TRANSLATE_NOOP("VCS", "Git Submit Editor"); const char SUBMIT_CURRENT[] = "Git.SubmitCurrentLog"; diff --git a/src/plugins/git/gitplugin.cpp b/src/plugins/git/gitplugin.cpp index 52270ad0e7..547132b1c5 100644 --- a/src/plugins/git/gitplugin.cpp +++ b/src/plugins/git/gitplugin.cpp @@ -132,7 +132,6 @@ static GitPlugin *m_instance = 0; GitPlugin::GitPlugin() : m_commandLocator(0), - m_gitContainer(0), m_submitCurrentAction(0), m_diffSelectedFilesAction(0), m_undoAction(0), @@ -271,13 +270,15 @@ bool GitPlugin::initialize(const QStringList &arguments, QString *errorMessage) { Q_UNUSED(arguments) + Context context(Constants::GIT_CONTEXT); + m_settings.readSettings(ICore::settings()); m_gitClient = new GitClient(&m_settings); - initializeVcs(new GitVersionControl(m_gitClient)); + initializeVcs(new GitVersionControl(m_gitClient), context); - // Create the globalcontext list to register actions accordingly + // Create the contexts to register actions accordingly Context globalcontext(Core::Constants::C_GLOBAL); // Create the settings Page @@ -309,44 +310,44 @@ bool GitPlugin::initialize(const QStringList &arguments, QString *errorMessage) //register actions ActionContainer *toolsContainer = ActionManager::actionContainer(Core::Constants::M_TOOLS); - m_gitContainer = ActionManager::createMenu("Git"); - m_gitContainer->menu()->setTitle(tr("&Git")); - toolsContainer->addMenu(m_gitContainer); - m_menuAction = m_gitContainer->menu()->menuAction(); + Core::ActionContainer *gitContainer = ActionManager::createMenu("Git"); + gitContainer->menu()->setTitle(tr("&Git")); + toolsContainer->addMenu(gitContainer); + m_menuAction = gitContainer->menu()->menuAction(); /* "Current File" menu */ ActionContainer *currentFileMenu = ActionManager::createMenu("Git.CurrentFileMenu"); currentFileMenu->menu()->setTitle(tr("Current &File")); - m_gitContainer->addMenu(currentFileMenu); + gitContainer->addMenu(currentFileMenu); createFileAction(currentFileMenu, tr("Diff Current File"), tr("Diff of \"%1\""), - "Git.Diff", globalcontext, true, SLOT(diffCurrentFile()), + "Git.Diff", context, true, SLOT(diffCurrentFile()), QKeySequence(UseMacShortcuts ? tr("Meta+G,Meta+D") : tr("Alt+G,Alt+D"))); createFileAction(currentFileMenu, tr("Log Current File"), tr("Log of \"%1\""), - "Git.Log", globalcontext, true, SLOT(logFile()), + "Git.Log", context, true, SLOT(logFile()), QKeySequence(UseMacShortcuts ? tr("Meta+G,Meta+L") : tr("Alt+G,Alt+L"))); createFileAction(currentFileMenu, tr("Blame Current File"), tr("Blame for \"%1\""), - "Git.Blame", globalcontext, true, SLOT(blameFile()), + "Git.Blame", context, true, SLOT(blameFile()), QKeySequence(UseMacShortcuts ? tr("Meta+G,Meta+B") : tr("Alt+G,Alt+B"))); - currentFileMenu->addSeparator(globalcontext); + currentFileMenu->addSeparator(context); createFileAction(currentFileMenu, tr("Stage File for Commit"), tr("Stage \"%1\" for Commit"), - "Git.Stage", globalcontext, true, SLOT(stageFile()), + "Git.Stage", context, true, SLOT(stageFile()), QKeySequence(UseMacShortcuts ? tr("Meta+G,Meta+A") : tr("Alt+G,Alt+A"))); createFileAction(currentFileMenu, tr("Unstage File from Commit"), tr("Unstage \"%1\" from Commit"), - "Git.Unstage", globalcontext, true, SLOT(unstageFile())); + "Git.Unstage", context, true, SLOT(unstageFile())); createFileAction(currentFileMenu, tr("Undo Unstaged Changes"), tr("Undo Unstaged Changes for \"%1\""), - "Git.UndoUnstaged", globalcontext, + "Git.UndoUnstaged", context, true, SLOT(undoUnstagedFileChanges())); createFileAction(currentFileMenu, tr("Undo Uncommitted Changes"), tr("Undo Uncommitted Changes for \"%1\""), - "Git.Undo", globalcontext, + "Git.Undo", context, true, SLOT(undoFileChanges()), QKeySequence(UseMacShortcuts ? tr("Meta+G,Meta+U") : tr("Alt+G,Alt+U"))); @@ -354,118 +355,118 @@ bool GitPlugin::initialize(const QStringList &arguments, QString *errorMessage) /* "Current Project" menu */ ActionContainer *currentProjectMenu = ActionManager::createMenu("Git.CurrentProjectMenu"); currentProjectMenu->menu()->setTitle(tr("Current &Project")); - m_gitContainer->addMenu(currentProjectMenu); + gitContainer->addMenu(currentProjectMenu); createProjectAction(currentProjectMenu, tr("Diff Current Project"), tr("Diff Project \"%1\""), - "Git.DiffProject", globalcontext, true, SLOT(diffCurrentProject()), + "Git.DiffProject", context, true, SLOT(diffCurrentProject()), QKeySequence(UseMacShortcuts ? tr("Meta+G,Meta+Shift+D") : tr("Alt+G,Alt+Shift+D"))); createProjectAction(currentProjectMenu, tr("Log Project"), tr("Log Project \"%1\""), - "Git.LogProject", globalcontext, true, SLOT(logProject()), + "Git.LogProject", context, true, SLOT(logProject()), QKeySequence(UseMacShortcuts ? tr("Meta+G,Meta+K") : tr("Alt+G,Alt+K"))); createProjectAction(currentProjectMenu, tr("Clean Project..."), tr("Clean Project \"%1\"..."), - "Git.CleanProject", globalcontext, true, SLOT(cleanProject())); + "Git.CleanProject", context, true, SLOT(cleanProject())); /* "Local Repository" menu */ ActionContainer *localRepositoryMenu = ActionManager::createMenu("Git.LocalRepositoryMenu"); localRepositoryMenu->menu()->setTitle(tr("&Local Repository")); - m_gitContainer->addMenu(localRepositoryMenu); + gitContainer->addMenu(localRepositoryMenu); createRepositoryAction(localRepositoryMenu, tr("Diff"), "Git.DiffRepository", - globalcontext, true, SLOT(diffRepository())); + context, true, SLOT(diffRepository())); createRepositoryAction(localRepositoryMenu, tr("Log"), "Git.LogRepository", - globalcontext, true, + context, true, SLOT(logRepository())); createRepositoryAction(localRepositoryMenu, tr("Reflog"), "Git.ReflogRepository", - globalcontext, true, + context, true, SLOT(reflogRepository())); createRepositoryAction(localRepositoryMenu, tr("Clean..."), "Git.CleanRepository", - globalcontext, true, SLOT(cleanRepository())); + context, true, SLOT(cleanRepository())); createRepositoryAction(localRepositoryMenu, tr("Status"), "Git.StatusRepository", - globalcontext, true, &GitClient::status); + context, true, &GitClient::status); // -------------- - localRepositoryMenu->addSeparator(globalcontext); + localRepositoryMenu->addSeparator(context); createRepositoryAction(localRepositoryMenu, tr("Commit..."), "Git.Commit", - globalcontext, true, SLOT(startCommit()), + context, true, SLOT(startCommit()), QKeySequence(UseMacShortcuts ? tr("Meta+G,Meta+C") : tr("Alt+G,Alt+C"))); createRepositoryAction(localRepositoryMenu, tr("Amend Last Commit..."), "Git.AmendCommit", - globalcontext, true, SLOT(startAmendCommit())); + context, true, SLOT(startAmendCommit())); m_fixupCommitAction = createRepositoryAction(localRepositoryMenu, tr("Fixup Previous Commit..."), "Git.FixupCommit", - globalcontext, true, SLOT(startFixupCommit())); + context, true, SLOT(startFixupCommit())); // -------------- - localRepositoryMenu->addSeparator(globalcontext); + localRepositoryMenu->addSeparator(context); createRepositoryAction(localRepositoryMenu, tr("Reset..."), "Git.Reset", - globalcontext, true, SLOT(resetRepository())); + context, true, SLOT(resetRepository())); m_interactiveRebaseAction = createRepositoryAction(localRepositoryMenu, tr("Interactive Rebase..."), "Git.InteractiveRebase", - globalcontext, true, SLOT(startRebase())); + context, true, SLOT(startRebase())); m_submoduleUpdateAction = createRepositoryAction(localRepositoryMenu, tr("Update Submodules"), "Git.SubmoduleUpdate", - globalcontext, true, SLOT(updateSubmodules())); + context, true, SLOT(updateSubmodules())); m_abortMergeAction = createRepositoryAction(localRepositoryMenu, tr("Abort Merge"), "Git.MergeAbort", - globalcontext, true, SLOT(continueOrAbortCommand())); + context, true, SLOT(continueOrAbortCommand())); m_abortRebaseAction = createRepositoryAction(localRepositoryMenu, tr("Abort Rebase"), "Git.RebaseAbort", - globalcontext, true, SLOT(continueOrAbortCommand())); + context, true, SLOT(continueOrAbortCommand())); m_abortCherryPickAction = createRepositoryAction(localRepositoryMenu, tr("Abort Cherry Pick"), "Git.CherryPickAbort", - globalcontext, true, SLOT(continueOrAbortCommand())); + context, true, SLOT(continueOrAbortCommand())); m_abortRevertAction = createRepositoryAction(localRepositoryMenu, tr("Abort Revert"), "Git.RevertAbort", - globalcontext, true, SLOT(continueOrAbortCommand())); + context, true, SLOT(continueOrAbortCommand())); m_continueRebaseAction = createRepositoryAction(localRepositoryMenu, tr("Continue Rebase"), "Git.RebaseContinue", - globalcontext, true, SLOT(continueOrAbortCommand())); + context, true, SLOT(continueOrAbortCommand())); m_continueCherryPickAction = createRepositoryAction(localRepositoryMenu, tr("Continue Cherry Pick"), "Git.CherryPickContinue", - globalcontext, true, SLOT(continueOrAbortCommand())); + context, true, SLOT(continueOrAbortCommand())); m_continueRevertAction = createRepositoryAction(localRepositoryMenu, tr("Continue Revert"), "Git.RevertContinue", - globalcontext, true, SLOT(continueOrAbortCommand())); + context, true, SLOT(continueOrAbortCommand())); // -------------- - localRepositoryMenu->addSeparator(globalcontext); + localRepositoryMenu->addSeparator(context); createRepositoryAction(localRepositoryMenu, tr("Branches..."), "Git.BranchList", - globalcontext, true, SLOT(branchList())); + context, true, SLOT(branchList())); // -------------- - localRepositoryMenu->addSeparator(globalcontext); + localRepositoryMenu->addSeparator(context); // "Patch" menu ActionContainer *patchMenu = ActionManager::createMenu("Git.PatchMenu"); @@ -477,14 +478,14 @@ bool GitPlugin::initialize(const QStringList &arguments, QString *errorMessage) createParameterAction(patchMenu, tr("Apply from Editor"), tr("Apply \"%1\""), "Git.ApplyCurrentFilePatch", - globalcontext, true); + context, true); connect(m_applyCurrentFilePatchAction, SIGNAL(triggered()), this, SLOT(applyCurrentFilePatch())); createRepositoryAction(patchMenu, tr("Apply from File..."), "Git.ApplyPatch", - globalcontext, true, SLOT(promptApplyPatch())); + context, true, SLOT(promptApplyPatch())); // "Stash" menu ActionContainer *stashMenu = ActionManager::createMenu("Git.StashMenu"); @@ -493,22 +494,22 @@ bool GitPlugin::initialize(const QStringList &arguments, QString *errorMessage) createRepositoryAction(stashMenu, tr("Stashes..."), "Git.StashList", - globalcontext, false, SLOT(stashList())); + context, false, SLOT(stashList())); - stashMenu->addSeparator(globalcontext); + stashMenu->addSeparator(context); QAction *action = createRepositoryAction(stashMenu, tr("Stash"), "Git.Stash", - globalcontext, true, SLOT(stash())); + context, true, SLOT(stash())); action->setToolTip(tr("Saves the current state of your work and resets the repository.")); action = createRepositoryAction(stashMenu, tr("Take Snapshot..."), "Git.StashSnapshot", - globalcontext, true, SLOT(stashSnapshot())); + context, true, SLOT(stashSnapshot())); action->setToolTip(tr("Saves the current state of your work.")); - stashMenu->addSeparator(globalcontext); + stashMenu->addSeparator(context); action = createRepositoryAction(stashMenu, tr("Stash Pop"), "Git.StashPop", - globalcontext, true, &GitClient::stashPop); + context, true, &GitClient::stashPop); action->setToolTip(tr("Restores changes saved to the stash list using \"Stash\".")); @@ -519,19 +520,19 @@ bool GitPlugin::initialize(const QStringList &arguments, QString *errorMessage) /* "Remote Repository" menu */ ActionContainer *remoteRepositoryMenu = ActionManager::createMenu("Git.RemoteRepositoryMenu"); remoteRepositoryMenu->menu()->setTitle(tr("&Remote Repository")); - m_gitContainer->addMenu(remoteRepositoryMenu); + gitContainer->addMenu(remoteRepositoryMenu); createRepositoryAction(remoteRepositoryMenu, tr("Fetch"), "Git.Fetch", - globalcontext, true, SLOT(fetch())); + context, true, SLOT(fetch())); createRepositoryAction(remoteRepositoryMenu, tr("Pull"), "Git.Pull", - globalcontext, true, SLOT(pull())); + context, true, SLOT(pull())); createRepositoryAction(remoteRepositoryMenu, tr("Push"), "Git.Push", - globalcontext, true, SLOT(push())); + context, true, SLOT(push())); // -------------- - remoteRepositoryMenu->addSeparator(globalcontext); + remoteRepositoryMenu->addSeparator(context); // "Subversion" menu ActionContainer *subversionMenu = ActionManager::createMenu("Git.Subversion"); @@ -540,18 +541,18 @@ bool GitPlugin::initialize(const QStringList &arguments, QString *errorMessage) createRepositoryAction(subversionMenu, tr("Log"), "Git.Subversion.Log", - globalcontext, false, &GitClient::subversionLog); + context, false, &GitClient::subversionLog); createRepositoryAction(subversionMenu, tr("Fetch"), "Git.Subversion.Fetch", - globalcontext, false, &GitClient::synchronousSubversionFetch); + context, false, &GitClient::synchronousSubversionFetch); // -------------- - remoteRepositoryMenu->addSeparator(globalcontext); + remoteRepositoryMenu->addSeparator(context); createRepositoryAction(remoteRepositoryMenu, tr("Manage Remotes..."), "Git.RemoteList", - globalcontext, false, SLOT(remoteList())); + context, false, SLOT(remoteList())); /* \"Remote Repository" menu */ @@ -559,22 +560,22 @@ bool GitPlugin::initialize(const QStringList &arguments, QString *errorMessage) /* Actions only in locator */ createRepositoryAction(0, tr("Show..."), "Git.Show", - globalcontext, true, SLOT(startChangeRelatedAction())); + context, true, SLOT(startChangeRelatedAction())); createRepositoryAction(0, tr("Revert..."), "Git.Revert", - globalcontext, true, SLOT(startChangeRelatedAction())); + context, true, SLOT(startChangeRelatedAction())); createRepositoryAction(0, tr("Cherry Pick..."), "Git.CherryPick", - globalcontext, true, SLOT(startChangeRelatedAction())); + context, true, SLOT(startChangeRelatedAction())); createRepositoryAction(0, tr("Checkout..."), "Git.Checkout", - globalcontext, true, SLOT(startChangeRelatedAction())); + context, true, SLOT(startChangeRelatedAction())); createRepositoryAction(0, tr("Rebase..."), "Git.Rebase", - globalcontext, true, SLOT(branchList())); + context, true, SLOT(branchList())); createRepositoryAction(0, tr("Merge..."), "Git.Merge", - globalcontext, true, SLOT(branchList())); + context, true, SLOT(branchList())); /* \Actions only in locator */ @@ -583,50 +584,50 @@ bool GitPlugin::initialize(const QStringList &arguments, QString *errorMessage) /* "Git Tools" menu */ ActionContainer *gitToolsMenu = ActionManager::createMenu("Git.GitToolsMenu"); gitToolsMenu->menu()->setTitle(tr("Git &Tools")); - m_gitContainer->addMenu(gitToolsMenu); + gitContainer->addMenu(gitToolsMenu); createRepositoryAction(gitToolsMenu, tr("Gitk"), "Git.LaunchGitK", - globalcontext, true, &GitClient::launchGitK); + context, true, &GitClient::launchGitK); createFileAction(gitToolsMenu, tr("Gitk Current File"), tr("Gitk of \"%1\""), - "Git.GitkFile", globalcontext, true, SLOT(gitkForCurrentFile())); + "Git.GitkFile", context, true, SLOT(gitkForCurrentFile())); createFileAction(gitToolsMenu, tr("Gitk for folder of Current File"), tr("Gitk for folder of \"%1\""), - "Git.GitkFolder", globalcontext, true, SLOT(gitkForCurrentFolder())); + "Git.GitkFolder", context, true, SLOT(gitkForCurrentFolder())); // -------------- - gitToolsMenu->addSeparator(globalcontext); + gitToolsMenu->addSeparator(context); createRepositoryAction(gitToolsMenu, tr("Git Gui"), "Git.GitGui", - globalcontext, true, SLOT(gitGui())); + context, true, SLOT(gitGui())); // -------------- - gitToolsMenu->addSeparator(globalcontext); + gitToolsMenu->addSeparator(context); m_repositoryBrowserAction = createRepositoryAction(gitToolsMenu, tr("Repository Browser"), "Git.LaunchRepositoryBrowser", - globalcontext, true, &GitClient::launchRepositoryBrowser); + context, true, &GitClient::launchRepositoryBrowser); m_mergeToolAction = createRepositoryAction(gitToolsMenu, tr("Merge Tool"), "Git.MergeTool", - globalcontext, true, SLOT(startMergeTool())); + context, true, SLOT(startMergeTool())); /* \"Git Tools" menu */ // -------------- - m_gitContainer->addSeparator(globalcontext); + gitContainer->addSeparator(context); - createRepositoryAction(m_gitContainer, tr("Actions on Commits..."), "Git.ChangeActions", - globalcontext, false, SLOT(startChangeRelatedAction())); + createRepositoryAction(gitContainer, tr("Actions on Commits..."), "Git.ChangeActions", + context, false, SLOT(startChangeRelatedAction())); m_createRepositryAction = new QAction(tr("Create Repository..."), this); Core::Command *createRepositoryCommand = ActionManager::registerAction( m_createRepositryAction, "Git.CreateRepository", globalcontext); connect(m_createRepositryAction, SIGNAL(triggered()), this, SLOT(createRepository())); - m_gitContainer->addAction(createRepositoryCommand); + gitContainer->addAction(createRepositoryCommand); // Submit editor Context submitContext(Constants::GITSUBMITEDITOR_ID); @@ -1326,7 +1327,6 @@ void GitPlugin::updateActions(VcsBasePlugin::ActionState as) m_remoteDialog->refresh(currentState().topLevel(), false); m_commandLocator->setEnabled(repositoryEnabled); - m_gitContainer->setEnabled(repositoryEnabled); m_createRepositryAction->setEnabled(true); if (!enableMenuAction(as, m_menuAction)) return; diff --git a/src/plugins/git/gitplugin.h b/src/plugins/git/gitplugin.h index e10e2e5c85..ba0cc266d3 100644 --- a/src/plugins/git/gitplugin.h +++ b/src/plugins/git/gitplugin.h @@ -199,7 +199,6 @@ private: void updateVersionWarning(); Core::CommandLocator *m_commandLocator; - Core::ActionContainer *m_gitContainer; QAction *m_submitCurrentAction; QAction *m_diffSelectedFilesAction; diff --git a/src/plugins/mercurial/constants.h b/src/plugins/mercurial/constants.h index 80d1deefe3..fbc682725f 100644 --- a/src/plugins/mercurial/constants.h +++ b/src/plugins/mercurial/constants.h @@ -37,6 +37,7 @@ namespace Constants { enum { debug = 0 }; const char MERCURIALREPO[] = ".hg"; const char MERCURIALDEFAULT[] = "hg"; +const char MERCURIAL_CONTEXT[] = "Mercurial Context"; // Changeset identifiers const char CHANGESETID12[] = " ([a-f0-9]{12,12}) "; //match 12 hex chars and capture diff --git a/src/plugins/mercurial/mercurialplugin.cpp b/src/plugins/mercurial/mercurialplugin.cpp index 863232c2b6..5b57e492c3 100644 --- a/src/plugins/mercurial/mercurialplugin.cpp +++ b/src/plugins/mercurial/mercurialplugin.cpp @@ -133,8 +133,10 @@ MercurialPlugin::~MercurialPlugin() bool MercurialPlugin::initialize(const QStringList & /* arguments */, QString * /*errorMessage */) { + Core::Context context(Constants::MERCURIAL_CONTEXT); + m_client = new MercurialClient(&mercurialSettings); - initializeVcs(new MercurialControl(m_client)); + initializeVcs(new MercurialControl(m_client), context); optionsPage = new OptionsPage(); addAutoReleasedObject(optionsPage); @@ -166,7 +168,7 @@ bool MercurialPlugin::initialize(const QStringList & /* arguments */, QString * m_commandLocator = new Core::CommandLocator("Mercurial", prefix, prefix); addAutoReleasedObject(m_commandLocator); - createMenu(); + createMenu(context); createSubmitEditorActions(); @@ -186,10 +188,8 @@ void MercurialPlugin::setSettings(const MercurialSettings &settings) } } -void MercurialPlugin::createMenu() +void MercurialPlugin::createMenu(const Core::Context &context) { - Core::Context context(Core::Constants::C_GLOBAL); - // Create menu item for Mercurial m_mercurialContainer = Core::ActionManager::createMenu("Mercurial.MercurialMenu"); QMenu *menu = m_mercurialContainer->menu(); @@ -659,13 +659,11 @@ void MercurialPlugin::createRepositoryManagementActions(const Core::Context &con void MercurialPlugin::updateActions(VcsBasePlugin::ActionState as) { if (!enableMenuAction(as, m_menuAction)) { - m_mercurialContainer->setEnabled(false); m_commandLocator->setEnabled(false); return; } const QString filename = currentState().currentFileName(); const bool repoEnabled = currentState().hasTopLevel(); - m_mercurialContainer->setEnabled(repoEnabled); m_commandLocator->setEnabled(repoEnabled); annotateFile->setParameter(filename); diff --git a/src/plugins/mercurial/mercurialplugin.h b/src/plugins/mercurial/mercurialplugin.h index 5fc4edf017..2716186b9e 100644 --- a/src/plugins/mercurial/mercurialplugin.h +++ b/src/plugins/mercurial/mercurialplugin.h @@ -129,7 +129,7 @@ protected: bool submitEditorAboutToClose(); private: - void createMenu(); + void createMenu(const Core::Context &context); void createSubmitEditorActions(); void createFileActions(const Core::Context &context); void createDirectoryActions(const Core::Context &context); diff --git a/src/plugins/perforce/perforceplugin.cpp b/src/plugins/perforce/perforceplugin.cpp index c20856c332..5525e95db3 100644 --- a/src/plugins/perforce/perforceplugin.cpp +++ b/src/plugins/perforce/perforceplugin.cpp @@ -83,6 +83,7 @@ const char SUBMIT_CURRENT[] = "Perforce.SubmitCurrentLog"; const char DIFF_SELECTED[] = "Perforce.DiffSelectedFilesInLog"; const char SUBMIT_MIMETYPE[] = "text/vnd.qtcreator.p4.submit"; +const char PERFORCE_CONTEXT[] = "Perforce Context"; const char PERFORCE_SUBMIT_EDITOR_ID[] = "Perforce.SubmitEditor"; const char PERFORCE_SUBMIT_EDITOR_DISPLAY_NAME[] = QT_TRANSLATE_NOOP("VCS", "Perforce.SubmitEditor"); @@ -182,7 +183,6 @@ PerforcePlugin *PerforcePlugin::m_instance = NULL; PerforcePlugin::PerforcePlugin() : m_commandLocator(0), - m_perforceContainer(0), m_editAction(0), m_addAction(0), m_deleteAction(0), @@ -221,7 +221,9 @@ static const VcsBaseSubmitEditorParameters submitParameters = { bool PerforcePlugin::initialize(const QStringList & /* arguments */, QString *errorMessage) { - initializeVcs(new PerforceVersionControl(this)); + Context context(PERFORCE_CONTEXT); + + initializeVcs(new PerforceVersionControl(this), context); if (!MimeDatabase::addMimeTypes(QLatin1String(":/trolltech.perforce/Perforce.mimetypes.xml"), errorMessage)) return false; @@ -247,177 +249,176 @@ bool PerforcePlugin::initialize(const QStringList & /* arguments */, QString *er ActionContainer *mtools = ActionManager::actionContainer(Core::Constants::M_TOOLS); - m_perforceContainer = ActionManager::createMenu(CMD_ID_PERFORCE_MENU); - m_perforceContainer->menu()->setTitle(tr("&Perforce")); - mtools->addMenu(m_perforceContainer); - m_menuAction = m_perforceContainer->menu()->menuAction(); + Core::ActionContainer *perforceContainer = ActionManager::createMenu(CMD_ID_PERFORCE_MENU); + perforceContainer->menu()->setTitle(tr("&Perforce")); + mtools->addMenu(perforceContainer); + m_menuAction = perforceContainer->menu()->menuAction(); - Context globalcontext(Core::Constants::C_GLOBAL); Context perforcesubmitcontext(PERFORCE_SUBMIT_EDITOR_ID); Core::Command *command; m_diffFileAction = new ParameterAction(tr("Diff Current File"), tr("Diff \"%1\""), ParameterAction::EnabledWithParameter, this); - command = ActionManager::registerAction(m_diffFileAction, CMD_ID_DIFF_CURRENT, globalcontext); + command = ActionManager::registerAction(m_diffFileAction, CMD_ID_DIFF_CURRENT, context); command->setAttribute(Core::Command::CA_UpdateText); command->setDescription(tr("Diff Current File")); connect(m_diffFileAction, SIGNAL(triggered()), this, SLOT(diffCurrentFile())); - m_perforceContainer->addAction(command); + perforceContainer->addAction(command); m_commandLocator->appendCommand(command); m_annotateCurrentAction = new ParameterAction(tr("Annotate Current File"), tr("Annotate \"%1\""), ParameterAction::EnabledWithParameter, this); - command = ActionManager::registerAction(m_annotateCurrentAction, CMD_ID_ANNOTATE_CURRENT, globalcontext); + command = ActionManager::registerAction(m_annotateCurrentAction, CMD_ID_ANNOTATE_CURRENT, context); command->setAttribute(Core::Command::CA_UpdateText); command->setDescription(tr("Annotate Current File")); connect(m_annotateCurrentAction, SIGNAL(triggered()), this, SLOT(annotateCurrentFile())); - m_perforceContainer->addAction(command); + perforceContainer->addAction(command); m_commandLocator->appendCommand(command); m_filelogCurrentAction = new ParameterAction(tr("Filelog Current File"), tr("Filelog \"%1\""), ParameterAction::EnabledWithParameter, this); - command = ActionManager::registerAction(m_filelogCurrentAction, CMD_ID_FILELOG_CURRENT, globalcontext); + command = ActionManager::registerAction(m_filelogCurrentAction, CMD_ID_FILELOG_CURRENT, context); command->setAttribute(Core::Command::CA_UpdateText); command->setDefaultKeySequence(QKeySequence(UseMacShortcuts ? tr("Meta+P,Meta+F") : tr("Alt+P,Alt+F"))); command->setDescription(tr("Filelog Current File")); connect(m_filelogCurrentAction, SIGNAL(triggered()), this, SLOT(filelogCurrentFile())); - m_perforceContainer->addAction(command); + perforceContainer->addAction(command); m_commandLocator->appendCommand(command); - m_perforceContainer->addSeparator(globalcontext); + perforceContainer->addSeparator(context); m_editAction = new ParameterAction(tr("Edit"), tr("Edit \"%1\""), ParameterAction::EnabledWithParameter, this); - command = ActionManager::registerAction(m_editAction, CMD_ID_EDIT, globalcontext); + command = ActionManager::registerAction(m_editAction, CMD_ID_EDIT, context); command->setAttribute(Core::Command::CA_UpdateText); command->setDefaultKeySequence(QKeySequence(UseMacShortcuts ? tr("Meta+P,Meta+E") : tr("Alt+P,Alt+E"))); command->setDescription(tr("Edit File")); connect(m_editAction, SIGNAL(triggered()), this, SLOT(openCurrentFile())); - m_perforceContainer->addAction(command); + perforceContainer->addAction(command); m_commandLocator->appendCommand(command); m_addAction = new ParameterAction(tr("Add"), tr("Add \"%1\""), ParameterAction::EnabledWithParameter, this); - command = ActionManager::registerAction(m_addAction, CMD_ID_ADD, globalcontext); + command = ActionManager::registerAction(m_addAction, CMD_ID_ADD, context); command->setAttribute(Core::Command::CA_UpdateText); command->setDefaultKeySequence(QKeySequence(UseMacShortcuts ? tr("Meta+P,Meta+A") : tr("Alt+P,Alt+A"))); command->setDescription(tr("Add File")); connect(m_addAction, SIGNAL(triggered()), this, SLOT(addCurrentFile())); - m_perforceContainer->addAction(command); + perforceContainer->addAction(command); m_commandLocator->appendCommand(command); m_deleteAction = new ParameterAction(tr("Delete..."), tr("Delete \"%1\"..."), ParameterAction::EnabledWithParameter, this); - command = ActionManager::registerAction(m_deleteAction, CMD_ID_DELETE_FILE, globalcontext); + command = ActionManager::registerAction(m_deleteAction, CMD_ID_DELETE_FILE, context); command->setAttribute(Core::Command::CA_UpdateText); command->setDescription(tr("Delete File")); connect(m_deleteAction, SIGNAL(triggered()), this, SLOT(promptToDeleteCurrentFile())); - m_perforceContainer->addAction(command); + perforceContainer->addAction(command); m_commandLocator->appendCommand(command); m_revertFileAction = new ParameterAction(tr("Revert"), tr("Revert \"%1\""), ParameterAction::EnabledWithParameter, this); - command = ActionManager::registerAction(m_revertFileAction, CMD_ID_REVERT, globalcontext); + command = ActionManager::registerAction(m_revertFileAction, CMD_ID_REVERT, context); command->setAttribute(Core::Command::CA_UpdateText); command->setDefaultKeySequence(QKeySequence(UseMacShortcuts ? tr("Meta+P,Meta+R") : tr("Alt+P,Alt+R"))); command->setDescription(tr("Revert File")); connect(m_revertFileAction, SIGNAL(triggered()), this, SLOT(revertCurrentFile())); - m_perforceContainer->addAction(command); + perforceContainer->addAction(command); m_commandLocator->appendCommand(command); - m_perforceContainer->addSeparator(globalcontext); + perforceContainer->addSeparator(context); const QString diffProjectDefaultText = tr("Diff Current Project/Session"); m_diffProjectAction = new ParameterAction(diffProjectDefaultText, tr("Diff Project \"%1\""), ParameterAction::AlwaysEnabled, this); - command = ActionManager::registerAction(m_diffProjectAction, CMD_ID_DIFF_PROJECT, globalcontext); + command = ActionManager::registerAction(m_diffProjectAction, CMD_ID_DIFF_PROJECT, context); command->setAttribute(Core::Command::CA_UpdateText); command->setDefaultKeySequence(QKeySequence(UseMacShortcuts ? tr("Meta+P,Meta+D") : tr("Alt+P,Alt+D"))); command->setDescription(diffProjectDefaultText); connect(m_diffProjectAction, SIGNAL(triggered()), this, SLOT(diffCurrentProject())); - m_perforceContainer->addAction(command); + perforceContainer->addAction(command); m_commandLocator->appendCommand(command); m_logProjectAction = new ParameterAction(tr("Log Project"), tr("Log Project \"%1\""), ParameterAction::EnabledWithParameter, this); - command = ActionManager::registerAction(m_logProjectAction, CMD_ID_PROJECTLOG, globalcontext); + command = ActionManager::registerAction(m_logProjectAction, CMD_ID_PROJECTLOG, context); command->setAttribute(Core::Command::CA_UpdateText); connect(m_logProjectAction, SIGNAL(triggered()), this, SLOT(logProject())); - m_perforceContainer->addAction(command); + perforceContainer->addAction(command); m_commandLocator->appendCommand(command); m_submitProjectAction = new ParameterAction(tr("Submit Project"), tr("Submit Project \"%1\""), ParameterAction::EnabledWithParameter, this); - command = ActionManager::registerAction(m_submitProjectAction, CMD_ID_SUBMIT, globalcontext); + command = ActionManager::registerAction(m_submitProjectAction, CMD_ID_SUBMIT, context); command->setAttribute(Core::Command::CA_UpdateText); command->setDefaultKeySequence(QKeySequence(UseMacShortcuts ? tr("Meta+P,Meta+S") : tr("Alt+P,Alt+S"))); connect(m_submitProjectAction, SIGNAL(triggered()), this, SLOT(startSubmitProject())); - m_perforceContainer->addAction(command); + perforceContainer->addAction(command); m_commandLocator->appendCommand(command); const QString updateProjectDefaultText = tr("Update Current Project"); m_updateProjectAction = new ParameterAction(updateProjectDefaultText, tr("Update Project \"%1\""), ParameterAction::AlwaysEnabled, this); - command = ActionManager::registerAction(m_updateProjectAction, CMD_ID_UPDATE_PROJECT, globalcontext); + command = ActionManager::registerAction(m_updateProjectAction, CMD_ID_UPDATE_PROJECT, context); command->setDescription(updateProjectDefaultText); command->setAttribute(Core::Command::CA_UpdateText); connect(m_updateProjectAction, SIGNAL(triggered()), this, SLOT(updateCurrentProject())); - m_perforceContainer->addAction(command); + perforceContainer->addAction(command); m_commandLocator->appendCommand(command); m_revertUnchangedAction = new ParameterAction(tr("Revert Unchanged"), tr("Revert Unchanged Files of Project \"%1\""), ParameterAction::EnabledWithParameter, this); - command = ActionManager::registerAction(m_revertUnchangedAction, CMD_ID_REVERT_UNCHANGED_PROJECT, globalcontext); + command = ActionManager::registerAction(m_revertUnchangedAction, CMD_ID_REVERT_UNCHANGED_PROJECT, context); command->setAttribute(Core::Command::CA_UpdateText); connect(m_revertUnchangedAction, SIGNAL(triggered()), this, SLOT(revertUnchangedCurrentProject())); - m_perforceContainer->addAction(command); + perforceContainer->addAction(command); m_commandLocator->appendCommand(command); m_revertProjectAction = new ParameterAction(tr("Revert Project"), tr("Revert Project \"%1\""), ParameterAction::EnabledWithParameter, this); - command = ActionManager::registerAction(m_revertProjectAction, CMD_ID_REVERT_PROJECT, globalcontext); + command = ActionManager::registerAction(m_revertProjectAction, CMD_ID_REVERT_PROJECT, context); command->setAttribute(Core::Command::CA_UpdateText); connect(m_revertProjectAction, SIGNAL(triggered()), this, SLOT(revertCurrentProject())); - m_perforceContainer->addAction(command); + perforceContainer->addAction(command); m_commandLocator->appendCommand(command); - m_perforceContainer->addSeparator(globalcontext); + perforceContainer->addSeparator(context); m_diffAllAction = new QAction(tr("Diff Opened Files"), this); - command = ActionManager::registerAction(m_diffAllAction, CMD_ID_DIFF_ALL, globalcontext); + command = ActionManager::registerAction(m_diffAllAction, CMD_ID_DIFF_ALL, context); connect(m_diffAllAction, SIGNAL(triggered()), this, SLOT(diffAllOpened())); - m_perforceContainer->addAction(command); + perforceContainer->addAction(command); m_commandLocator->appendCommand(command); m_openedAction = new QAction(tr("Opened"), this); - command = ActionManager::registerAction(m_openedAction, CMD_ID_OPENED, globalcontext); + command = ActionManager::registerAction(m_openedAction, CMD_ID_OPENED, context); command->setDefaultKeySequence(QKeySequence(UseMacShortcuts ? tr("Meta+P,Meta+O") : tr("Alt+P,Alt+O"))); connect(m_openedAction, SIGNAL(triggered()), this, SLOT(printOpenedFileList())); - m_perforceContainer->addAction(command); + perforceContainer->addAction(command); m_commandLocator->appendCommand(command); m_logRepositoryAction = new QAction(tr("Repository Log"), this); - command = ActionManager::registerAction(m_logRepositoryAction, CMD_ID_REPOSITORYLOG, globalcontext); + command = ActionManager::registerAction(m_logRepositoryAction, CMD_ID_REPOSITORYLOG, context); connect(m_logRepositoryAction, SIGNAL(triggered()), this, SLOT(logRepository())); - m_perforceContainer->addAction(command); + perforceContainer->addAction(command); m_commandLocator->appendCommand(command); m_pendingAction = new QAction(tr("Pending Changes..."), this); - command = ActionManager::registerAction(m_pendingAction, CMD_ID_PENDING_CHANGES, globalcontext); + command = ActionManager::registerAction(m_pendingAction, CMD_ID_PENDING_CHANGES, context); connect(m_pendingAction, SIGNAL(triggered()), this, SLOT(printPendingChanges())); - m_perforceContainer->addAction(command); + perforceContainer->addAction(command); m_commandLocator->appendCommand(command); m_updateAllAction = new QAction(tr("Update All"), this); - command = ActionManager::registerAction(m_updateAllAction, CMD_ID_UPDATEALL, globalcontext); + command = ActionManager::registerAction(m_updateAllAction, CMD_ID_UPDATEALL, context); connect(m_updateAllAction, SIGNAL(triggered()), this, SLOT(updateAll())); - m_perforceContainer->addAction(command); + perforceContainer->addAction(command); m_commandLocator->appendCommand(command); - m_perforceContainer->addSeparator(globalcontext); + perforceContainer->addSeparator(context); m_describeAction = new QAction(tr("Describe..."), this); - command = ActionManager::registerAction(m_describeAction, CMD_ID_DESCRIBE, globalcontext); + command = ActionManager::registerAction(m_describeAction, CMD_ID_DESCRIBE, context); connect(m_describeAction, SIGNAL(triggered()), this, SLOT(describeChange())); - m_perforceContainer->addAction(command); + perforceContainer->addAction(command); m_annotateAction = new QAction(tr("Annotate..."), this); - command = ActionManager::registerAction(m_annotateAction, CMD_ID_ANNOTATE, globalcontext); + command = ActionManager::registerAction(m_annotateAction, CMD_ID_ANNOTATE, context); connect(m_annotateAction, SIGNAL(triggered()), this, SLOT(annotate())); - m_perforceContainer->addAction(command); + perforceContainer->addAction(command); m_filelogAction = new QAction(tr("Filelog..."), this); - command = ActionManager::registerAction(m_filelogAction, CMD_ID_FILELOG, globalcontext); + command = ActionManager::registerAction(m_filelogAction, CMD_ID_FILELOG, context); connect(m_filelogAction, SIGNAL(triggered()), this, SLOT(filelog())); - m_perforceContainer->addAction(command); + perforceContainer->addAction(command); m_submitCurrentLogAction = new QAction(VcsBaseSubmitEditor::submitIcon(), tr("Submit"), this); command = ActionManager::registerAction(m_submitCurrentLogAction, SUBMIT_CURRENT, perforcesubmitcontext); @@ -796,7 +797,6 @@ void PerforcePlugin::updateActions(VcsBasePlugin::ActionState as) { const bool menuActionEnabled = enableMenuAction(as, m_menuAction); const bool enableActions = currentState().hasTopLevel() && menuActionEnabled; - m_perforceContainer->setEnabled(enableActions); m_commandLocator->setEnabled(enableActions); if (!menuActionEnabled) return; diff --git a/src/plugins/perforce/perforceplugin.h b/src/plugins/perforce/perforceplugin.h index 37291f310e..6bd8f65cd5 100644 --- a/src/plugins/perforce/perforceplugin.h +++ b/src/plugins/perforce/perforceplugin.h @@ -207,7 +207,6 @@ private: static PerforceVersionControl *perforceVersionControl(); Core::CommandLocator *m_commandLocator; - Core::ActionContainer *m_perforceContainer; Utils::ParameterAction *m_editAction; Utils::ParameterAction *m_addAction; Utils::ParameterAction *m_deleteAction; diff --git a/src/plugins/plugins.pro b/src/plugins/plugins.pro index 79103a7f06..0c8fe74320 100644 --- a/src/plugins/plugins.pro +++ b/src/plugins/plugins.pro @@ -51,10 +51,16 @@ SUBDIRS = \ beautifier \ qmakeandroidsupport \ winrt \ - qmldesigner \ qmlprofiler \ welcome +DO_NOT_BUILD_QMLDESIGNER = $$(DO_NOT_BUILD_QMLDESIGNER) +isEmpty(DO_NOT_BUILD_QMLDESIGNER) { + SUBDIRS += qmldesigner +} else { + warning("QmlDesigner plugin has been disabled.") +} + isEmpty(QBS_INSTALL_DIR): QBS_INSTALL_DIR = $$(QBS_INSTALL_DIR) exists(../shared/qbs/qbs.pro)|!isEmpty(QBS_INSTALL_DIR): \ diff --git a/src/plugins/projectexplorer/appoutputpane.cpp b/src/plugins/projectexplorer/appoutputpane.cpp index a1c5dc54e7..14436cbc27 100644 --- a/src/plugins/projectexplorer/appoutputpane.cpp +++ b/src/plugins/projectexplorer/appoutputpane.cpp @@ -306,7 +306,10 @@ void AppOutputPane::visibilityChanged(bool /* b */) bool AppOutputPane::hasFocus() const { - return m_tabWidget->currentWidget() && m_tabWidget->currentWidget()->hasFocus(); + QWidget *widget = m_tabWidget->currentWidget(); + if (!widget) + return false; + return widget->window()->focusWidget() == widget; } bool AppOutputPane::canFocus() const diff --git a/src/plugins/projectexplorer/compileoutputwindow.cpp b/src/plugins/projectexplorer/compileoutputwindow.cpp index 9210bd6733..6ab318334a 100644 --- a/src/plugins/projectexplorer/compileoutputwindow.cpp +++ b/src/plugins/projectexplorer/compileoutputwindow.cpp @@ -154,7 +154,7 @@ void CompileOutputWindow::updateWordWrapMode() bool CompileOutputWindow::hasFocus() const { - return m_outputWindow->hasFocus(); + return m_outputWindow->window()->focusWidget() == m_outputWindow; } bool CompileOutputWindow::canFocus() const diff --git a/src/plugins/projectexplorer/jsonwizard/jsonfieldpage.cpp b/src/plugins/projectexplorer/jsonwizard/jsonfieldpage.cpp index 23a899ba7d..baa03b0d51 100644 --- a/src/plugins/projectexplorer/jsonwizard/jsonfieldpage.cpp +++ b/src/plugins/projectexplorer/jsonwizard/jsonfieldpage.cpp @@ -45,7 +45,6 @@ #include <QFormLayout> #include <QLabel> #include <QLineEdit> -#include <QRegularExpression> #include <QRegularExpressionValidator> #include <QTextEdit> #include <QVariant> @@ -88,6 +87,45 @@ static JsonFieldPage::Field *createFieldData(const QString &type) return 0; } +class LineEditValidator : public QRegularExpressionValidator +{ +public: + LineEditValidator(MacroExpander *expander, const QRegularExpression &pattern, QObject *parent) : + QRegularExpressionValidator(pattern, parent) + { + m_expander.setDisplayName(tr("Line Edit Validator Expander")); + m_expander.setAccumulating(true); + m_expander.registerVariable("INPUT", tr("The text edit input to fix up."), + [this]() { return m_currentInput; }); + m_expander.registerSubProvider([expander]() -> Utils::MacroExpander * { return expander; }); + } + + void setFixupExpando(const QString &expando) + { + m_fixupExpando = expando; + } + + QValidator::State validate(QString &input, int &pos) const + { + fixup(input); + return QRegularExpressionValidator::validate(input, pos); + } + + void fixup(QString &fixup) const + { + if (m_fixupExpando.isEmpty()) + return; + + m_currentInput = fixup; + fixup = m_expander.expand(m_fixupExpando); + } + +private: + MacroExpander m_expander; + QString m_fixupExpando; + mutable QString m_currentInput; +}; + // -------------------------------------------------------------------- // JsonFieldPage::FieldData: // -------------------------------------------------------------------- @@ -144,7 +182,7 @@ JsonFieldPage::Field *JsonFieldPage::Field::parse(const QVariant &input, QString void JsonFieldPage::Field::createWidget(JsonFieldPage *page) { - QWidget *w = widget(displayName); + QWidget *w = widget(displayName, page); w->setObjectName(name); QFormLayout *layout = page->layout(); @@ -200,9 +238,10 @@ bool JsonFieldPage::LabelField::parseData(const QVariant &data, QString *errorMe return true; } -QWidget *JsonFieldPage::LabelField::widget(const QString &displayName) +QWidget *JsonFieldPage::LabelField::widget(const QString &displayName, JsonFieldPage *page) { Q_UNUSED(displayName); + Q_UNUSED(page); QTC_ASSERT(!m_widget, return m_widget); QLabel *w = new QLabel(); @@ -246,9 +285,10 @@ bool JsonFieldPage::SpacerField::parseData(const QVariant &data, QString *errorM return true; } -QWidget *JsonFieldPage::SpacerField::widget(const QString &displayName) +QWidget *JsonFieldPage::SpacerField::widget(const QString &displayName, JsonFieldPage *page) { Q_UNUSED(displayName); + Q_UNUSED(page); QTC_ASSERT(!m_widget, return m_widget); int size = qApp->style()->pixelMetric(QStyle::PM_DefaultLayoutSpacing) * m_factor; @@ -264,15 +304,9 @@ QWidget *JsonFieldPage::SpacerField::widget(const QString &displayName) // JsonFieldPage::LineEditFieldData: // -------------------------------------------------------------------- -JsonFieldPage::LineEditField::LineEditField() : - m_validatorRegExp(0), m_isModified(false) +JsonFieldPage::LineEditField::LineEditField() : m_isModified(false), m_isValidating(false) { } -JsonFieldPage::LineEditField::~LineEditField() -{ - delete m_validatorRegExp; -} - bool JsonFieldPage::LineEditField::parseData(const QVariant &data, QString *errorMessage) { if (data.isNull()) @@ -291,29 +325,31 @@ bool JsonFieldPage::LineEditField::parseData(const QVariant &data, QString *erro m_placeholderText = JsonWizardFactory::localizedString(tmp.value(QLatin1String("trPlaceholder")).toString()); QString pattern = tmp.value(QLatin1String("validator")).toString(); if (!pattern.isEmpty()) { - m_validatorRegExp = new QRegularExpression(pattern); - if (!m_validatorRegExp->isValid()) { + m_validatorRegExp = QRegularExpression(pattern); + if (!m_validatorRegExp.isValid()) { *errorMessage = QCoreApplication::translate("ProjectExplorer::JsonFieldPage", "Invalid regular expression \"%1\" in \"validator\".") .arg(pattern); - delete m_validatorRegExp; - m_validatorRegExp = 0; + m_validatorRegExp = QRegularExpression(); return false; } } + m_fixupExpando = tmp.value(QLatin1String("fixup")).toString(); return true; } -QWidget *JsonFieldPage::LineEditField::widget(const QString &displayName) +QWidget *JsonFieldPage::LineEditField::widget(const QString &displayName, JsonFieldPage *page) { Q_UNUSED(displayName); QTC_ASSERT(!m_widget, return m_widget); QLineEdit *w = new QLineEdit; - connect(w, &QLineEdit::textEdited, [this](){ m_isModified = true; }); - if (m_validatorRegExp) - w->setValidator(new QRegularExpressionValidator(*m_validatorRegExp, w)); + if (m_validatorRegExp.isValid()) { + LineEditValidator *lv = new LineEditValidator(page->expander(), m_validatorRegExp, w); + lv->setFixupExpando(m_fixupExpando); + w->setValidator(lv); + } m_widget = w; return m_widget; @@ -323,25 +359,37 @@ void JsonFieldPage::LineEditField::setup(JsonFieldPage *page, const QString &nam { QLineEdit *w = static_cast<QLineEdit *>(m_widget); page->registerFieldWithName(name, w); - connect(w, &QLineEdit::textChanged, page, [page](QString) { page->completeChanged(); }); + connect(w, &QLineEdit::textChanged, + page, [this, page]() -> void { m_isModified = true; emit page->completeChanged(); }); } bool JsonFieldPage::LineEditField::validate(MacroExpander *expander, QString *message) { Q_UNUSED(message); + if (m_isValidating) + return true; + + m_isValidating = true; + QLineEdit *w = static_cast<QLineEdit *>(m_widget); - if (!m_isModified) { - w->setText(expander->expand(m_defaultText)); - } else if (!w->isEnabled() && !m_disabledText.isNull() && m_currentText.isNull()) { - m_currentText = w->text(); - w->setText(expander->expand(m_disabledText)); - } else if (w->isEnabled() && !m_currentText.isNull()) { - w->setText(m_currentText); - m_currentText.clear(); + if (w->isEnabled()) { + if (m_isModified) { + if (!m_currentText.isNull()) { + w->setText(m_currentText); + m_currentText.clear(); + } + } else { + w->setText(expander->expand(m_defaultText)); + m_isModified = false; + } + } else { + if (!m_disabledText.isNull() && m_currentText.isNull()) + m_currentText = w->text(); } - // TODO: Add support for validators + m_isValidating = false; + return !w->text().isEmpty(); } @@ -349,11 +397,12 @@ void JsonFieldPage::LineEditField::initializeData(MacroExpander *expander) { QTC_ASSERT(m_widget, return); - m_isModified = false; - QLineEdit *w = static_cast<QLineEdit *>(m_widget); + m_isValidating = true; w->setText(expander->expand(m_defaultText)); w->setPlaceholderText(m_placeholderText); + m_isModified = false; + m_isValidating = false; } // -------------------------------------------------------------------- @@ -385,10 +434,11 @@ bool JsonFieldPage::TextEditField::parseData(const QVariant &data, QString *erro return true; } -QWidget *JsonFieldPage::TextEditField::widget(const QString &displayName) +QWidget *JsonFieldPage::TextEditField::widget(const QString &displayName, JsonFieldPage *page) { // TODO: Set up modification monitoring... Q_UNUSED(displayName); + Q_UNUSED(page); QTC_ASSERT(!m_widget, return m_widget); QTextEdit *w = new QTextEdit; w->setAcceptRichText(m_acceptRichText); @@ -478,9 +528,10 @@ bool JsonFieldPage::PathChooserField::parseData(const QVariant &data, QString *e return true; } -QWidget *JsonFieldPage::PathChooserField::widget(const QString &displayName) +QWidget *JsonFieldPage::PathChooserField::widget(const QString &displayName, JsonFieldPage *page) { Q_UNUSED(displayName); + Q_UNUSED(page); QTC_ASSERT(!m_widget, return m_widget); m_widget = new PathChooser; return m_widget; @@ -556,8 +607,9 @@ bool JsonFieldPage::CheckBoxField::parseData(const QVariant &data, QString *erro return true; } -QWidget *JsonFieldPage::CheckBoxField::widget(const QString &displayName) +QWidget *JsonFieldPage::CheckBoxField::widget(const QString &displayName, JsonFieldPage *page) { + Q_UNUSED(page); QTC_ASSERT(!m_widget, return m_widget); TextFieldCheckBox *w = new TextFieldCheckBox(displayName); m_widget = w; @@ -671,9 +723,10 @@ bool JsonFieldPage::ComboBoxField::parseData(const QVariant &data, QString *erro return true; } -QWidget *JsonFieldPage::ComboBoxField::widget(const QString &displayName) +QWidget *JsonFieldPage::ComboBoxField::widget(const QString &displayName, JsonFieldPage *page) { Q_UNUSED(displayName); + Q_UNUSED(page); QTC_ASSERT(!m_widget, return m_widget); m_widget = new TextFieldComboBox; return m_widget; diff --git a/src/plugins/projectexplorer/jsonwizard/jsonfieldpage.h b/src/plugins/projectexplorer/jsonwizard/jsonfieldpage.h index 9219fe50d6..8c8c564da8 100644 --- a/src/plugins/projectexplorer/jsonwizard/jsonfieldpage.h +++ b/src/plugins/projectexplorer/jsonwizard/jsonfieldpage.h @@ -34,13 +34,13 @@ #include <utils/pathchooser.h> #include <utils/wizardpage.h> +#include <QRegularExpression> #include <QVariant> QT_BEGIN_NAMESPACE class QFormLayout; class QLabel; class QLineEdit; -class QRegularExpression; class QTextEdit; QT_END_NAMESPACE @@ -90,7 +90,7 @@ public: virtual bool parseData(const QVariant &data, QString *errorMessage) = 0; virtual void initializeData(Utils::MacroExpander *expander) { Q_UNUSED(expander); } - virtual QWidget *widget(const QString &displayName) = 0; + virtual QWidget *widget(const QString &displayName, JsonFieldPage *page) = 0; virtual void setup(JsonFieldPage *page, const QString &name) { Q_UNUSED(page); Q_UNUSED(name); } @@ -103,7 +103,7 @@ public: LabelField(); private: - QWidget *widget(const QString &displayName); + QWidget *widget(const QString &displayName, JsonFieldPage *page); bool parseData(const QVariant &data, QString *errorMessage); bool m_wordWrap; @@ -119,7 +119,7 @@ public: private: bool parseData(const QVariant &data, QString *errorMessage); - QWidget *widget(const QString &displayName); + QWidget *widget(const QString &displayName, JsonFieldPage *page); int m_factor; }; @@ -128,23 +128,23 @@ public: { public: LineEditField(); - ~LineEditField(); private: bool parseData(const QVariant &data, QString *errorMessage); - QWidget *widget(const QString &displayName); + QWidget *widget(const QString &displayName, JsonFieldPage *page); void setup(JsonFieldPage *page, const QString &name); bool validate(Utils::MacroExpander *expander, QString *message); void initializeData(Utils::MacroExpander *expander); + bool m_isModified; + bool m_isValidating; QString m_placeholderText; QString m_defaultText; QString m_disabledText; - QRegularExpression *m_validatorRegExp; - - bool m_isModified; + QRegularExpression m_validatorRegExp; + QString m_fixupExpando; mutable QString m_currentText; }; @@ -155,7 +155,7 @@ public: private: bool parseData(const QVariant &data, QString *errorMessage); - QWidget *widget(const QString &displayName); + QWidget *widget(const QString &displayName, JsonFieldPage *page); void setup(JsonFieldPage *page, const QString &name); @@ -177,7 +177,7 @@ public: private: bool parseData(const QVariant &data, QString *errorMessage); - QWidget *widget(const QString &displayName); + QWidget *widget(const QString &displayName, JsonFieldPage *page); void setEnabled(bool e); void setup(JsonFieldPage *page, const QString &name); @@ -202,7 +202,7 @@ public: private: bool parseData(const QVariant &data, QString *errorMessage); - QWidget *widget(const QString &displayName); + QWidget *widget(const QString &displayName, JsonFieldPage *page); void setup(JsonFieldPage *page, const QString &name); @@ -224,7 +224,7 @@ public: private: bool parseData(const QVariant &data, QString *errorMessage); - QWidget *widget(const QString &displayName); + QWidget *widget(const QString &displayName, JsonFieldPage *page); void setup(JsonFieldPage *page, const QString &name); diff --git a/src/plugins/projectexplorer/jsonwizard/jsonfilepage.cpp b/src/plugins/projectexplorer/jsonwizard/jsonfilepage.cpp index 7b0fb0e691..e4d4dbe0c3 100644 --- a/src/plugins/projectexplorer/jsonwizard/jsonfilepage.cpp +++ b/src/plugins/projectexplorer/jsonwizard/jsonfilepage.cpp @@ -48,9 +48,9 @@ void JsonFilePage::initializePage() return; if (fileName().isEmpty()) - setFileName(wiz->value(QLatin1String("InitialFileName")).toString()); + setFileName(wiz->stringValue(QLatin1String("InitialFileName"))); if (path().isEmpty()) - setPath(wiz->value(QLatin1String("InitialPath")).toString()); + setPath(wiz->stringValue(QLatin1String("InitialPath"))); } bool JsonFilePage::validatePage() diff --git a/src/plugins/projectexplorer/jsonwizard/jsonkitspage.cpp b/src/plugins/projectexplorer/jsonwizard/jsonkitspage.cpp index 5d92f0bf41..f9381ff3f8 100644 --- a/src/plugins/projectexplorer/jsonwizard/jsonkitspage.cpp +++ b/src/plugins/projectexplorer/jsonwizard/jsonkitspage.cpp @@ -10,16 +10,17 @@ ** 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 Digia. For licensing terms and -** conditions see http://qt.digia.com/licensing. For further information -** use the contact form at http://qt.digia.com/contact-us. +** conditions see http://www.qt.io/licensing. For further information +** use the contact form at http://www.qt.io/contact-us. ** ** GNU Lesser General Public License Usage ** Alternatively, this file may be used under the terms of the GNU Lesser -** General Public License version 2.1 as published by the Free Software -** Foundation and appearing in the file LICENSE.LGPL included in the -** packaging of this file. Please review the following information to -** ensure the GNU Lesser General Public License version 2.1 requirements -** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** General Public License version 2.1 or version 3 as published by the Free +** Software Foundation and appearing in the file LICENSE.LGPLv21 and +** LICENSE.LGPLv3 included in the packaging of this file. Please review the +** following information to ensure the GNU Lesser General Public License +** requirements will be met: https://www.gnu.org/licenses/lgpl.html and +** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. ** ** In addition, as a special exception, Digia gives you certain additional ** rights. These rights are described in the Digia Qt LGPL Exception @@ -40,6 +41,7 @@ #include <extensionsystem/pluginmanager.h> +#include <utils/algorithm.h> #include <utils/macroexpander.h> #include <utils/qtcassert.h> @@ -55,15 +57,13 @@ void JsonKitsPage::initializePage() connect(wiz, &JsonWizard::filesReady, this, &JsonKitsPage::setupProjectFiles); - const QString platform = wiz->value(QLatin1String("Platform")).toString(); + const QString platform = wiz->stringValue(QLatin1String("Platform")); const Core::FeatureSet preferred = Core::FeatureSet::fromStringList(wiz->value(QLatin1String("PreferredFeatures")).toStringList()); const Core::FeatureSet required = Core::FeatureSet::fromStringList(wiz->value(QLatin1String("RequiredFeatures")).toStringList()); - const QString path = wiz->expander()->expand(m_projectFilePath); - - setProjectPath(path); setRequiredKitMatcher(KitMatcher([required](const Kit *k) { return k->hasFeatures(required); })); setPreferredKitMatcher(KitMatcher([platform, preferred](const Kit *k) { return k->hasPlatform(platform) && k->hasFeatures(preferred); })); + setProjectPath(wiz->expander()->expand(unexpandedProjectPath())); TargetSetupPage::initializePage(); } @@ -78,6 +78,16 @@ void JsonKitsPage::cleanupPage() TargetSetupPage::cleanupPage(); } +void JsonKitsPage::setUnexpandedProjectPath(const QString &path) +{ + m_unexpandedProjectPath = path; +} + +QString JsonKitsPage::unexpandedProjectPath() const +{ + return m_unexpandedProjectPath; +} + void JsonKitsPage::setupProjectFiles(const JsonWizard::GeneratorFiles &files) { Project *project = 0; @@ -96,18 +106,13 @@ void JsonKitsPage::setupProjectFiles(const JsonWizard::GeneratorFiles &files) if (mt.isNull()) continue; - foreach (IProjectManager *manager, managerList) { - if (manager->mimeType() == mt.type()) { - project = manager->openProject(path, &errorMessage); - break; - } - } - + auto manager = Utils::findOrDefault(managerList, Utils::equal(&IProjectManager::mimeType, mt.type())); + project = manager ? manager->openProject(path, &errorMessage) : 0; if (project) { - bool success = setupProject(project); - if (success) + if (setupProject(project)) project->saveSettings(); delete project; + project = 0; } } } diff --git a/src/plugins/projectexplorer/jsonwizard/jsonkitspage.h b/src/plugins/projectexplorer/jsonwizard/jsonkitspage.h index 1e530cbe7a..95934e868c 100644 --- a/src/plugins/projectexplorer/jsonwizard/jsonkitspage.h +++ b/src/plugins/projectexplorer/jsonwizard/jsonkitspage.h @@ -10,16 +10,17 @@ ** 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 Digia. For licensing terms and -** conditions see http://qt.digia.com/licensing. For further information -** use the contact form at http://qt.digia.com/contact-us. +** conditions see http://www.qt.io/licensing. For further information +** use the contact form at http://www.qt.io/contact-us. ** ** GNU Lesser General Public License Usage ** Alternatively, this file may be used under the terms of the GNU Lesser -** General Public License version 2.1 as published by the Free Software -** Foundation and appearing in the file LICENSE.LGPL included in the -** packaging of this file. Please review the following information to -** ensure the GNU Lesser General Public License version 2.1 requirements -** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** General Public License version 2.1 or version 3 as published by the Free +** Software Foundation and appearing in the file LICENSE.LGPLv21 and +** LICENSE.LGPLv3 included in the packaging of this file. Please review the +** following information to ensure the GNU Lesser General Public License +** requirements will be met: https://www.gnu.org/licenses/lgpl.html and +** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. ** ** In addition, as a special exception, Digia gives you certain additional ** rights. These rights are described in the Digia Qt LGPL Exception @@ -43,16 +44,17 @@ class JsonKitsPage : public TargetSetupPage public: JsonKitsPage(QWidget *parent = 0); - void setProjectFilePath(const QString &path) { m_projectFilePath = path; } - void initializePage(); void cleanupPage(); + void setUnexpandedProjectPath(const QString &path); + QString unexpandedProjectPath() const; + private slots: void setupProjectFiles(const JsonWizard::GeneratorFiles &files); private: - QString m_projectFilePath; + QString m_unexpandedProjectPath; }; } // namespace ProjectExplorer diff --git a/src/plugins/projectexplorer/jsonwizard/jsonprojectpage.cpp b/src/plugins/projectexplorer/jsonwizard/jsonprojectpage.cpp index 4aaf185be3..68ee47c5aa 100644 --- a/src/plugins/projectexplorer/jsonwizard/jsonprojectpage.cpp +++ b/src/plugins/projectexplorer/jsonwizard/jsonprojectpage.cpp @@ -10,16 +10,17 @@ ** 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 Digia. For licensing terms and -** conditions see http://qt.digia.com/licensing. For further information -** use the contact form at http://qt.digia.com/contact-us. +** conditions see http://www.qt.io/licensing. For further information +** use the contact form at http://www.qt.io/contact-us. ** ** GNU Lesser General Public License Usage ** Alternatively, this file may be used under the terms of the GNU Lesser -** General Public License version 2.1 as published by the Free Software -** Foundation and appearing in the file LICENSE.LGPL included in the -** packaging of this file. Please review the following information to -** ensure the GNU Lesser General Public License version 2.1 requirements -** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** General Public License version 2.1 or version 3 as published by the Free +** Software Foundation and appearing in the file LICENSE.LGPLv21 and +** LICENSE.LGPLv3 included in the packaging of this file. Please review the +** following information to ensure the GNU Lesser General Public License +** requirements will be met: https://www.gnu.org/licenses/lgpl.html and +** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. ** ** In addition, as a special exception, Digia gives you certain additional ** rights. These rights are described in the Digia Qt LGPL Exception @@ -47,7 +48,7 @@ void JsonProjectPage::initializePage() { JsonWizard *wiz = qobject_cast<JsonWizard *>(wizard()); QTC_ASSERT(wiz, return); - setPath(wiz->value(QLatin1String("InitialPath")).toString()); + setPath(wiz->stringValue(QLatin1String("InitialPath"))); setProjectName(uniqueProjectName(path())); } diff --git a/src/plugins/projectexplorer/jsonwizard/jsonprojectpage.h b/src/plugins/projectexplorer/jsonwizard/jsonprojectpage.h index 6b542ee34b..eedf736450 100644 --- a/src/plugins/projectexplorer/jsonwizard/jsonprojectpage.h +++ b/src/plugins/projectexplorer/jsonwizard/jsonprojectpage.h @@ -10,16 +10,17 @@ ** 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 Digia. For licensing terms and -** conditions see http://qt.digia.com/licensing. For further information -** use the contact form at http://qt.digia.com/contact-us. +** conditions see http://www.qt.io/licensing. For further information +** use the contact form at http://www.qt.io/contact-us. ** ** GNU Lesser General Public License Usage ** Alternatively, this file may be used under the terms of the GNU Lesser -** General Public License version 2.1 as published by the Free Software -** Foundation and appearing in the file LICENSE.LGPL included in the -** packaging of this file. Please review the following information to -** ensure the GNU Lesser General Public License version 2.1 requirements -** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** General Public License version 2.1 or version 3 as published by the Free +** Software Foundation and appearing in the file LICENSE.LGPLv21 and +** LICENSE.LGPLv3 included in the packaging of this file. Please review the +** following information to ensure the GNU Lesser General Public License +** requirements will be met: https://www.gnu.org/licenses/lgpl.html and +** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. ** ** In addition, as a special exception, Digia gives you certain additional ** rights. These rights are described in the Digia Qt LGPL Exception diff --git a/src/plugins/projectexplorer/jsonwizard/jsonsummarypage.cpp b/src/plugins/projectexplorer/jsonwizard/jsonsummarypage.cpp index e45f84b515..8b0b47c4ed 100644 --- a/src/plugins/projectexplorer/jsonwizard/jsonsummarypage.cpp +++ b/src/plugins/projectexplorer/jsonwizard/jsonsummarypage.cpp @@ -65,7 +65,7 @@ static QString generatedProjectFilePath(const QList<JsonWizard::GeneratorFile> & static IWizardFactory::WizardKind wizardKind(JsonWizard *wiz) { IWizardFactory::WizardKind kind = IWizardFactory::ProjectWizard; - const QString kindStr = wiz->value(QLatin1String("kind")).toString(); + const QString kindStr = wiz->stringValue(QLatin1String("kind")); if (kindStr == QLatin1String(Core::Constants::WIZARD_KIND_PROJECT)) kind = IWizardFactory::ProjectWizard; else if (kindStr == QLatin1String(Core::Constants::WIZARD_KIND_CLASS)) @@ -108,18 +108,23 @@ void JsonSummaryPage::initializePage() IWizardFactory::WizardKind kind = wizardKind(m_wizard); bool isProject = (kind == IWizardFactory::ProjectWizard); - QStringList projectFiles; + QStringList files; if (isProject) { JsonWizard::GeneratorFile f = Utils::findOrDefault(m_fileList, [](const JsonWizard::GeneratorFile &f) { return f.file.attributes() & GeneratedFile::OpenProjectAttribute; }); - projectFiles << f.file.path(); + files << f.file.path(); + } else { + files = Utils::transform(m_fileList, + [](const JsonWizard::GeneratorFile &f) { + return f.file.path(); + }); } Node *contextNode = m_wizard->value(QLatin1String(Constants::PREFERRED_PROJECT_NODE)) .value<Node *>(); - initializeProjectTree(contextNode, projectFiles, kind, + initializeProjectTree(contextNode, files, kind, isProject ? AddSubProject : AddNewFile); initializeVersionControls(); diff --git a/src/plugins/projectexplorer/jsonwizard/jsonwizard.cpp b/src/plugins/projectexplorer/jsonwizard/jsonwizard.cpp index d5372b7923..0c0543c2b9 100644 --- a/src/plugins/projectexplorer/jsonwizard/jsonwizard.cpp +++ b/src/plugins/projectexplorer/jsonwizard/jsonwizard.cpp @@ -46,14 +46,8 @@ JsonWizard::JsonWizard(QWidget *parent) : { setMinimumSize(800, 500); m_expander.registerExtraResolver([this](const QString &name, QString *ret) -> bool { - QVariant v = value(name); - if (v.isValid()) { - if (v.type() == QVariant::Bool) - *ret = v.toBool() ? QLatin1String("true") : QString(); - else - *ret = v.toString(); - } - return v.isValid(); + *ret = stringValue(name); + return !ret->isNull(); }); m_expander.registerPrefix("Exists", tr("Check whether a variable exists. Returns \"true\" if it does and an empty string if not."), [this](const QString &value) -> QString @@ -87,14 +81,14 @@ JsonWizard::GeneratorFiles JsonWizard::generateFileList() QString errorMessage; GeneratorFiles list; - QString targetPath = value(QLatin1String("TargetPath")).toString(); + QString targetPath = stringValue(QLatin1String("TargetPath")); if (targetPath.isEmpty()) errorMessage = tr("Could not determine target path. \"TargetPath\" was not set on any page."); if (m_files.isEmpty() && errorMessage.isEmpty()) { emit preGenerateFiles(); foreach (JsonWizardGenerator *gen, m_generators) { - Core::GeneratedFiles tmp = gen->fileList(&m_expander, value(QStringLiteral("WizardDir")).toString(), + Core::GeneratedFiles tmp = gen->fileList(&m_expander, stringValue(QStringLiteral("WizardDir")), targetPath, &errorMessage); if (!errorMessage.isEmpty()) break; @@ -120,18 +114,25 @@ void JsonWizard::commitToFileList(const JsonWizard::GeneratorFiles &list) emit postGenerateFiles(m_files); } -QVariant JsonWizard::value(const QString &n) const +QString JsonWizard::stringValue(const QString &n) const { - QVariant v = property(n.toUtf8()); - if (v.isValid()) { - if (v.type() == QVariant::String) - return m_expander.expand(v.toString()); - else - return v; + QVariant v = value(n); + if (!v.isValid()) + return QString(); + + if (v.type() == QVariant::Bool) + return v.toBool() ? QString::fromLatin1("true") : QString(); + + if (v.type() == QVariant::String) + return m_expander.expand(v.toString()); + + if (v.type() == QVariant::StringList) { + QStringList tmp = Utils::transform(v.toStringList(), [this](const QString &i) -> QString { + return m_expander.expand(i).replace(QLatin1Char('\''), QLatin1String("\\'")); + }); + return QString(QString(QLatin1Char('\'')) + tmp.join(QLatin1String("', '")) + QString(QLatin1Char('\''))); } - if (hasField(n)) - return field(n); // Can not contain macros! - return QVariant(); + return v.toString(); } void JsonWizard::setValue(const QString &key, const QVariant &value) @@ -139,6 +140,16 @@ void JsonWizard::setValue(const QString &key, const QVariant &value) setProperty(key.toUtf8(), value); } +QVariant JsonWizard::value(const QString &n) const +{ + QVariant v = property(n.toUtf8()); + if (v.isValid()) + return v; + if (hasField(n)) + return field(n); // Can not contain macros! + return QVariant(); +} + bool JsonWizard::boolFromVariant(const QVariant &v, Utils::MacroExpander *expander) { if (v.type() == QVariant::String) diff --git a/src/plugins/projectexplorer/jsonwizard/jsonwizard.h b/src/plugins/projectexplorer/jsonwizard/jsonwizard.h index 6fed7f8237..b58876c0c3 100644 --- a/src/plugins/projectexplorer/jsonwizard/jsonwizard.h +++ b/src/plugins/projectexplorer/jsonwizard/jsonwizard.h @@ -73,6 +73,8 @@ public: GeneratorFiles generateFileList(); void commitToFileList(const GeneratorFiles &list); + QString stringValue(const QString &n) const; + QVariant value(const QString &n) const; void setValue(const QString &key, const QVariant &value); diff --git a/src/plugins/projectexplorer/jsonwizard/jsonwizardpagefactory_p.cpp b/src/plugins/projectexplorer/jsonwizard/jsonwizardpagefactory_p.cpp index fd3c0d4f49..87384a16a8 100644 --- a/src/plugins/projectexplorer/jsonwizard/jsonwizardpagefactory_p.cpp +++ b/src/plugins/projectexplorer/jsonwizard/jsonwizardpagefactory_p.cpp @@ -139,7 +139,7 @@ Utils::WizardPage *KitsPageFactory::create(JsonWizard *wizard, Core::Id typeId, QTC_ASSERT(canCreate(typeId), return 0); JsonKitsPage *page = new JsonKitsPage; - page->setProjectFilePath(data.toMap().value(QLatin1String("projectFilePath")).toString()); + page->setUnexpandedProjectPath(data.toMap().value(QLatin1String("projectFilePath")).toString()); return page; } diff --git a/src/plugins/projectexplorer/kitinformation.cpp b/src/plugins/projectexplorer/kitinformation.cpp index 98878ef867..68bd7131b3 100644 --- a/src/plugins/projectexplorer/kitinformation.cpp +++ b/src/plugins/projectexplorer/kitinformation.cpp @@ -208,6 +208,17 @@ void ToolChainKitInformation::addToEnvironment(const Kit *k, Utils::Environment tc->addToEnvironment(env); } +void ToolChainKitInformation::addToMacroExpander(Kit *kit, Utils::MacroExpander *expander) const +{ + // FIXME: Use better strings + expander->registerVariable("Compiler:Name", tr("Compiler"), + [this, kit]() -> QString { + const ToolChain *tc = toolChain(kit); + return tc ? tc->displayName() : tr("None"); + }); +} + + IOutputParser *ToolChainKitInformation::createOutputParser(const Kit *k) const { ToolChain *tc = toolChain(k); diff --git a/src/plugins/projectexplorer/kitinformation.h b/src/plugins/projectexplorer/kitinformation.h index cdaa7463dd..75a71c6f89 100644 --- a/src/plugins/projectexplorer/kitinformation.h +++ b/src/plugins/projectexplorer/kitinformation.h @@ -93,6 +93,7 @@ public: ItemList toUserOutput(const Kit *k) const; void addToEnvironment(const Kit *k, Utils::Environment &env) const; + void addToMacroExpander(Kit *kit, Utils::MacroExpander *expander) const; IOutputParser *createOutputParser(const Kit *k) const; static Core::Id id(); diff --git a/src/plugins/projectexplorer/kitmanager.h b/src/plugins/projectexplorer/kitmanager.h index 094af9307d..fb1223caf1 100644 --- a/src/plugins/projectexplorer/kitmanager.h +++ b/src/plugins/projectexplorer/kitmanager.h @@ -115,9 +115,10 @@ class PROJECTEXPLORER_EXPORT KitMatcher { public: typedef std::function<bool(const Kit *)> Matcher; - KitMatcher() : m_matcher([](const Kit *k) -> bool { Q_UNUSED(k); return true; }) {} KitMatcher(const Matcher &m) : m_matcher(m) {} + KitMatcher() {} + bool isValid() const { return !!m_matcher; } bool matches(const Kit *kit) const { return m_matcher(kit); } private: diff --git a/src/plugins/projectexplorer/project.cpp b/src/plugins/projectexplorer/project.cpp index b01024c55e..1c73409d91 100644 --- a/src/plugins/projectexplorer/project.cpp +++ b/src/plugins/projectexplorer/project.cpp @@ -42,9 +42,12 @@ #include <coreplugin/icore.h> #include <projectexplorer/buildmanager.h> #include <projectexplorer/kitmanager.h> -#include <limits> -#include <utils/qtcassert.h> + #include <utils/algorithm.h> +#include <utils/macroexpander.h> +#include <utils/qtcassert.h> + +#include <limits> /*! \class ProjectExplorer::Project @@ -98,6 +101,8 @@ public: KitMatcher m_requiredKitMatcher; KitMatcher m_preferredKitMatcher; + + Utils::MacroExpander m_macroExpander; }; ProjectPrivate::ProjectPrivate() : @@ -109,7 +114,11 @@ ProjectPrivate::~ProjectPrivate() { delete m_accessor; } Project::Project() : d(new ProjectPrivate) -{ } +{ + d->m_macroExpander.setDisplayName(tr("Project")); + d->m_macroExpander.registerVariable("Project:Name", tr("Project Name"), + [this] { return displayName(); }); +} Project::~Project() { @@ -516,6 +525,11 @@ void Project::setup(QList<const BuildInfo *> infoList) } } +Utils::MacroExpander *Project::macroExpander() const +{ + return &d->m_macroExpander; +} + ProjectImporter *Project::createProjectImporter() const { return 0; diff --git a/src/plugins/projectexplorer/project.h b/src/plugins/projectexplorer/project.h index b4a917fd4a..76a2b8432b 100644 --- a/src/plugins/projectexplorer/project.h +++ b/src/plugins/projectexplorer/project.h @@ -45,6 +45,8 @@ class IDocument; class Context; } +namespace Utils { class MacroExpander; } + namespace ProjectExplorer { class BuildInfo; @@ -141,6 +143,7 @@ public: virtual bool needsSpecialDeployment() const; void setup(QList<const BuildInfo *> infoList); + Utils::MacroExpander *macroExpander() const; signals: void displayNameChanged(); diff --git a/src/plugins/projectexplorer/projectexplorer.cpp b/src/plugins/projectexplorer/projectexplorer.cpp index 090aa2ab0f..14a26c3abc 100644 --- a/src/plugins/projectexplorer/projectexplorer.cpp +++ b/src/plugins/projectexplorer/projectexplorer.cpp @@ -294,6 +294,7 @@ public: bool m_ignoreDocumentManagerChangedFile; QStringList m_arguments; QList<ProjectPanelFactory *> m_panelFactories; + QString m_renameFileError; }; ProjectExplorerPluginPrivate::ProjectExplorerPluginPrivate() : @@ -740,7 +741,7 @@ bool ProjectExplorerPlugin::initialize(const QStringList &arguments, QString *er // unload action dd->m_unloadAction = new Utils::ParameterAction(tr("Close Project"), tr("Close Project \"%1\""), - Utils::ParameterAction::EnabledWithParameter, this); + Utils::ParameterAction::AlwaysEnabled, this); cmd = ActionManager::registerAction(dd->m_unloadAction, Constants::UNLOAD, globalcontext); cmd->setAttribute(Command::CA_UpdateText); cmd->setDescription(dd->m_unloadAction->text()); @@ -2147,7 +2148,7 @@ void ProjectExplorerPluginPrivate::updateActions() QString projectName = project ? project->displayName() : QString(); QString projectNameContextMenu = m_currentProject ? m_currentProject->displayName() : QString(); - m_unloadAction->setParameter(projectNameContextMenu); + m_unloadAction->setParameter(projectName); m_unloadActionContextMenu->setParameter(projectNameContextMenu); // Normal actions @@ -2197,6 +2198,7 @@ void ProjectExplorerPluginPrivate::updateActions() // Session actions m_closeAllProjects->setEnabled(SessionManager::hasProjects()); m_unloadAction->setVisible(SessionManager::projects().size() <= 1); + m_unloadAction->setEnabled(SessionManager::projects().size() == 1); m_unloadActionContextMenu->setEnabled(SessionManager::hasProjects()); ActionContainer *aci = @@ -3265,11 +3267,12 @@ void ProjectExplorerPlugin::renameFile(Node *node, const QString &to) FolderNode *folderNode = node->parentFolderNode(); QString projectDisplayName = folderNode->projectNode()->displayName(); if (!folderNode->renameFile(orgFilePath, newFilePath)) { - QMessageBox::warning(ICore::mainWindow(), tr("Project Editing Failed"), - tr("The file %1 was renamed to %2, but the project file %3 could not be automatically changed.") - .arg(orgFilePath) - .arg(newFilePath) - .arg(projectDisplayName)); + dd->m_renameFileError = tr("The file %1 was renamed to %2, but the project file %3 could not be automatically changed.") + .arg(orgFilePath) + .arg(newFilePath) + .arg(projectDisplayName); + + QTimer::singleShot(0, m_instance, SLOT(showRenameFileError())); } else { dd->setCurrent(SessionManager::projectForFile(newFilePath), newFilePath, 0); } @@ -3281,6 +3284,11 @@ void ProjectExplorerPlugin::setStartupProject() setStartupProject(dd->m_currentProject); } +void ProjectExplorerPlugin::showRenameFileError() +{ + QMessageBox::warning(ICore::mainWindow(), tr("Project Editing Failed"), dd->m_renameFileError); +} + void ProjectExplorerPlugin::populateOpenWithMenu() { DocumentManager::populateOpenWithMenu(dd->m_openWithMenu, currentNode()->path()); diff --git a/src/plugins/projectexplorer/projectexplorer.h b/src/plugins/projectexplorer/projectexplorer.h index b7ad5851a2..5ab8e7adf1 100644 --- a/src/plugins/projectexplorer/projectexplorer.h +++ b/src/plugins/projectexplorer/projectexplorer.h @@ -230,6 +230,7 @@ private slots: void updateActions(); void updateContext(); void runConfigurationConfigurationFinished(); + void showRenameFileError(); #ifdef WITH_TESTS void testAnsiFilterOutputParser_data(); diff --git a/src/plugins/projectexplorer/targetsetuppage.cpp b/src/plugins/projectexplorer/targetsetuppage.cpp index 56738f7aeb..a560009504 100644 --- a/src/plugins/projectexplorer/targetsetuppage.cpp +++ b/src/plugins/projectexplorer/targetsetuppage.cpp @@ -260,7 +260,11 @@ void TargetSetupPage::setupWidgets() { // Known profiles: QList<Kit *> kitList; - kitList = KitManager::matchingKits(m_requiredMatcher); + if (m_requiredMatcher.isValid()) + kitList = KitManager::matchingKits(m_requiredMatcher); + else + kitList = KitManager::kits(); + foreach (Kit *k, kitList) addWidget(k); @@ -374,7 +378,7 @@ void TargetSetupPage::handleKitUpdate(Kit *k) TargetSetupWidget *widget = m_widgets.value(k->id()); - bool acceptable = m_requiredMatcher.matches(k); + bool acceptable = !m_requiredMatcher.isValid() || m_requiredMatcher.matches(k); if (widget && !acceptable) removeWidget(k); @@ -510,7 +514,7 @@ void TargetSetupPage::removeWidget(Kit *k) TargetSetupWidget *TargetSetupPage::addWidget(Kit *k) { - if (!k || !m_requiredMatcher.matches(k)) + if (!k || (m_requiredMatcher.isValid() && !m_requiredMatcher.matches(k))) return 0; IBuildConfigurationFactory *factory @@ -528,7 +532,7 @@ TargetSetupWidget *TargetSetupPage::addWidget(Kit *k) m_baseLayout->removeWidget(widget); m_baseLayout->removeItem(m_spacer); - widget->setKitSelected(m_preferredMatcher.matches(k)); + widget->setKitSelected(m_preferredMatcher.isValid() && m_preferredMatcher.matches(k)); m_widgets.insert(k->id(), widget); connect(widget, SIGNAL(selectedToggled()), this, SLOT(kitSelectionChanged())); diff --git a/src/plugins/projectexplorer/taskwindow.cpp b/src/plugins/projectexplorer/taskwindow.cpp index d95066a4cb..feecc9c80c 100644 --- a/src/plugins/projectexplorer/taskwindow.cpp +++ b/src/plugins/projectexplorer/taskwindow.cpp @@ -565,7 +565,7 @@ void TaskWindow::clearContents() bool TaskWindow::hasFocus() const { - return d->m_listview->hasFocus(); + return d->m_listview->window()->focusWidget() == d->m_listview; } bool TaskWindow::canFocus() const diff --git a/src/plugins/qbsprojectmanager/qbsbuildstep.cpp b/src/plugins/qbsprojectmanager/qbsbuildstep.cpp index dbab019706..3be5c3f38a 100644 --- a/src/plugins/qbsprojectmanager/qbsbuildstep.cpp +++ b/src/plugins/qbsprojectmanager/qbsbuildstep.cpp @@ -381,10 +381,12 @@ void QbsBuildStep::build() options.setFilesToConsider(m_changedFiles); options.setActiveFileTags(m_activeFileTags); - m_job = qbsProject()->build(options, m_products); - + QString error; + m_job = qbsProject()->build(options, m_products, error); if (!m_job) { + emit addOutput(error, ErrorMessageOutput); m_fi->reportResult(false); + emit finished(); return; } @@ -452,6 +454,11 @@ QbsBuildStepConfigWidget::QbsBuildStepConfigWidget(QbsBuildStep *step) : updateState(); } +QbsBuildStepConfigWidget::~QbsBuildStepConfigWidget() +{ + delete m_ui; +} + QString QbsBuildStepConfigWidget::summaryText() const { return m_summary; diff --git a/src/plugins/qbsprojectmanager/qbsbuildstep.h b/src/plugins/qbsprojectmanager/qbsbuildstep.h index 74a6cfe9d2..90ef336b71 100644 --- a/src/plugins/qbsprojectmanager/qbsbuildstep.h +++ b/src/plugins/qbsprojectmanager/qbsbuildstep.h @@ -131,6 +131,7 @@ class QbsBuildStepConfigWidget : public ProjectExplorer::BuildStepConfigWidget Q_OBJECT public: QbsBuildStepConfigWidget(QbsBuildStep *step); + ~QbsBuildStepConfigWidget(); QString summaryText() const; QString displayName() const; diff --git a/src/plugins/qbsprojectmanager/qbscleanstep.cpp b/src/plugins/qbsprojectmanager/qbscleanstep.cpp index 6468e667ca..5cc015c395 100644 --- a/src/plugins/qbsprojectmanager/qbscleanstep.cpp +++ b/src/plugins/qbsprojectmanager/qbscleanstep.cpp @@ -105,6 +105,7 @@ void QbsCleanStep::run(QFutureInterface<bool> &fi) if (!m_job) { m_fi->reportResult(false); + emit finished(); return; } @@ -271,6 +272,11 @@ QbsCleanStepConfigWidget::QbsCleanStepConfigWidget(QbsCleanStep *step) : updateState(); } +QbsCleanStepConfigWidget::~QbsCleanStepConfigWidget() +{ + delete m_ui; +} + QString QbsCleanStepConfigWidget::summaryText() const { return m_summary; diff --git a/src/plugins/qbsprojectmanager/qbscleanstep.h b/src/plugins/qbsprojectmanager/qbscleanstep.h index 0e05afcb09..7127ae4658 100644 --- a/src/plugins/qbsprojectmanager/qbscleanstep.h +++ b/src/plugins/qbsprojectmanager/qbscleanstep.h @@ -104,6 +104,7 @@ class QbsCleanStepConfigWidget : public ProjectExplorer::BuildStepConfigWidget Q_OBJECT public: QbsCleanStepConfigWidget(QbsCleanStep *step); + ~QbsCleanStepConfigWidget(); QString summaryText() const; QString displayName() const; diff --git a/src/plugins/qbsprojectmanager/qbsinstallstep.cpp b/src/plugins/qbsprojectmanager/qbsinstallstep.cpp index dd047ca471..c1bf7ef6ad 100644 --- a/src/plugins/qbsprojectmanager/qbsinstallstep.cpp +++ b/src/plugins/qbsprojectmanager/qbsinstallstep.cpp @@ -98,6 +98,7 @@ void QbsInstallStep::run(QFutureInterface<bool> &fi) if (!m_job) { m_fi->reportResult(false); + emit finished(); return; } @@ -290,6 +291,11 @@ QbsInstallStepConfigWidget::QbsInstallStepConfigWidget(QbsInstallStep *step) : updateState(); } +QbsInstallStepConfigWidget::~QbsInstallStepConfigWidget() +{ + delete m_ui; +} + QString QbsInstallStepConfigWidget::summaryText() const { return m_summary; diff --git a/src/plugins/qbsprojectmanager/qbsinstallstep.h b/src/plugins/qbsprojectmanager/qbsinstallstep.h index 9a4f7eef30..9899e6aa97 100644 --- a/src/plugins/qbsprojectmanager/qbsinstallstep.h +++ b/src/plugins/qbsprojectmanager/qbsinstallstep.h @@ -106,6 +106,7 @@ class QbsInstallStepConfigWidget : public ProjectExplorer::BuildStepConfigWidget Q_OBJECT public: QbsInstallStepConfigWidget(QbsInstallStep *step); + ~QbsInstallStepConfigWidget(); QString summaryText() const; QString displayName() const; diff --git a/src/plugins/qbsprojectmanager/qbsprofilessettingspage.cpp b/src/plugins/qbsprojectmanager/qbsprofilessettingspage.cpp index a842b8bfe7..930283029d 100644 --- a/src/plugins/qbsprojectmanager/qbsprofilessettingspage.cpp +++ b/src/plugins/qbsprojectmanager/qbsprofilessettingspage.cpp @@ -177,7 +177,8 @@ void QbsProfilesSettingsWidget::displayCurrentProfile() return; const Core::Id kitId = Core::Id::fromSetting(m_ui.kitsComboBox->currentData()); const ProjectExplorer::Kit * const kit = ProjectExplorer::KitManager::find(kitId); - const QString profileName = QbsManager::profileForKit(kit); + QTC_ASSERT(kit, return); + const QString profileName = QString::fromLatin1("qtc_") + kit->fileSystemFriendlyName(); m_ui.profileValueLabel->setText(profileName); for (int i = 0; i < m_model.rowCount(); ++i) { const QModelIndex profilesIndex = m_model.index(i, 0); @@ -225,8 +226,8 @@ void QbsProfilesSettingsWidget::mergeCustomPropertiesIntoModel() const Core::Id kitId = it.key(); const ProjectExplorer::Kit * const kit = ProjectExplorer::KitManager::find(kitId); QTC_ASSERT(kit, continue); - const QString keyPrefix = QLatin1String("profiles.") + QbsManager::profileForKit(kit) - + QLatin1Char('.'); + const QString keyPrefix = QLatin1String("profiles.") + + QString::fromLatin1("qtc_") + kit->fileSystemFriendlyName() + QLatin1Char('.'); for (QVariantMap::ConstIterator it2 = it.value().constBegin(); it2 != it.value().constEnd(); ++it2) { customProperties.insert(keyPrefix + it2.key(), it2.value()); diff --git a/src/plugins/qbsprojectmanager/qbsproject.cpp b/src/plugins/qbsprojectmanager/qbsproject.cpp index 52de2f4864..ed812bae39 100644 --- a/src/plugins/qbsprojectmanager/qbsproject.cpp +++ b/src/plugins/qbsprojectmanager/qbsproject.cpp @@ -110,6 +110,7 @@ QbsProject::QbsProject(QbsManager *manager, const QString &fileName) : m_qbsUpdateFutureInterface(0), m_parsingScheduled(false), m_cancelStatus(CancelStatusNone), + m_codeModelProjectInfo(this), m_currentBc(0) { m_parsingDelay.setInterval(1000); // delay parsing by 1s. @@ -344,29 +345,32 @@ void QbsProject::invalidate() prepareForParsing(); } -qbs::BuildJob *QbsProject::build(const qbs::BuildOptions &opts, QStringList productNames) +qbs::BuildJob *QbsProject::build(const qbs::BuildOptions &opts, QStringList productNames, + QString &error) { - if (!qbsProject().isValid() || isParsing()) - return 0; - if (productNames.isEmpty()) { + QTC_ASSERT(qbsProject().isValid(), return 0); + QTC_ASSERT(!isParsing(), return 0); + + if (productNames.isEmpty()) return qbsProject().buildAllProducts(opts); - } else { - QList<qbs::ProductData> products; - foreach (const QString &productName, productNames) { - bool found = false; - foreach (const qbs::ProductData &data, qbsProjectData().allProducts()) { - if (uniqueProductName(data) == productName) { - found = true; - products.append(data); - break; - } + + QList<qbs::ProductData> products; + foreach (const QString &productName, productNames) { + bool found = false; + foreach (const qbs::ProductData &data, qbsProjectData().allProducts()) { + if (uniqueProductName(data) == productName) { + found = true; + products.append(data); + break; } - if (!found) - return 0; } - - return qbsProject().buildSomeProducts(products, opts); + if (!found) { + error = QLatin1String("Cannot build: Selected products do not exist anymore."); // TODO: Use tr() in 3.4 + return 0; + } } + + return qbsProject().buildSomeProducts(products, opts); } qbs::CleanJob *QbsProject::clean(const qbs::CleanOptions &opts) @@ -727,6 +731,8 @@ void QbsProject::updateCppCodeModel() int pos = data.indexOf('='); if (pos >= 0) data[pos] = ' '; + else + data.append(" 1"); // cpp.defines: [ "FOO" ] is considered to be "FOO=1" grpDefines += (QByteArray("#define ") + data + '\n'); } ppBuilder.setDefines(grpDefines); diff --git a/src/plugins/qbsprojectmanager/qbsproject.h b/src/plugins/qbsprojectmanager/qbsproject.h index 8a08a0ecb7..1d6155b690 100644 --- a/src/plugins/qbsprojectmanager/qbsproject.h +++ b/src/plugins/qbsprojectmanager/qbsproject.h @@ -84,7 +84,7 @@ public: const QString &newPath, const qbs::ProductData &productData, const qbs::GroupData &groupData); - qbs::BuildJob *build(const qbs::BuildOptions &opts, QStringList products = QStringList()); + qbs::BuildJob *build(const qbs::BuildOptions &opts, QStringList products, QString &error); qbs::CleanJob *clean(const qbs::CleanOptions &opts); qbs::InstallJob *install(const qbs::InstallOptions &opts); diff --git a/src/plugins/qbsprojectmanager/qbsprojectmanager.cpp b/src/plugins/qbsprojectmanager/qbsprojectmanager.cpp index 57b0263637..a0b804fb14 100644 --- a/src/plugins/qbsprojectmanager/qbsprojectmanager.cpp +++ b/src/plugins/qbsprojectmanager/qbsprojectmanager.cpp @@ -116,10 +116,11 @@ ProjectExplorer::Project *QbsManager::openProject(const QString &fileName, QStri return new Internal::QbsProject(this, fileName); } -QString QbsManager::profileForKit(const ProjectExplorer::Kit *k) +QString QbsManager::profileForKit(ProjectExplorer::Kit *k) { if (!k) return QString(); + updateProfileIfNecessary(k); return m_settings->value(qtcProfilePrefix() + k->id().toString()).toString(); } diff --git a/src/plugins/qbsprojectmanager/qbsprojectmanager.h b/src/plugins/qbsprojectmanager/qbsprojectmanager.h index bb032f34a0..375f0417b3 100644 --- a/src/plugins/qbsprojectmanager/qbsprojectmanager.h +++ b/src/plugins/qbsprojectmanager/qbsprojectmanager.h @@ -72,8 +72,8 @@ public: ProjectExplorer::Project *openProject(const QString &fileName, QString *errorString); // QBS profiles management: - static QString profileForKit(const ProjectExplorer::Kit *k); - static void setProfileForKit(const QString &name, const ProjectExplorer::Kit *k); + QString profileForKit(ProjectExplorer::Kit *k); + void setProfileForKit(const QString &name, const ProjectExplorer::Kit *k); void updateProfileIfNecessary(ProjectExplorer::Kit *kit); diff --git a/src/plugins/qbsprojectmanager/qbsprojectmanagerplugin.cpp b/src/plugins/qbsprojectmanager/qbsprojectmanagerplugin.cpp index 61c1813668..0b84f35fdb 100644 --- a/src/plugins/qbsprojectmanager/qbsprojectmanagerplugin.cpp +++ b/src/plugins/qbsprojectmanager/qbsprojectmanagerplugin.cpp @@ -375,7 +375,11 @@ void QbsProjectManagerPlugin::buildProductContextMenu() QTC_ASSERT(m_selectedNode, return); QTC_ASSERT(m_selectedProject, return); - buildProducts(m_selectedProject, QStringList(m_selectedNode->displayName())); + const QbsProductNode * const productNode = qobject_cast<QbsProductNode *>(m_selectedNode); + QTC_ASSERT(productNode, return); + + buildProducts(m_selectedProject, + QStringList(QbsProject::uniqueProductName(productNode->qbsProductData()))); } void QbsProjectManagerPlugin::buildProduct() @@ -388,7 +392,8 @@ void QbsProjectManagerPlugin::buildProduct() if (!product) return; - buildProducts(m_editorProject, QStringList(product->displayName())); + buildProducts(m_editorProject, + QStringList(QbsProject::uniqueProductName(product->qbsProductData()))); } void QbsProjectManagerPlugin::buildSubprojectContextMenu() diff --git a/src/plugins/qbsprojectmanager/qbsrunconfiguration.cpp b/src/plugins/qbsprojectmanager/qbsrunconfiguration.cpp index e4449c47ea..36b5d220df 100644 --- a/src/plugins/qbsprojectmanager/qbsrunconfiguration.cpp +++ b/src/plugins/qbsprojectmanager/qbsrunconfiguration.cpp @@ -119,6 +119,9 @@ QbsRunConfiguration::QbsRunConfiguration(Target *parent, Core::Id id) : { addExtraAspect(new LocalEnvironmentAspect(this)); + m_runModeForced = false; + m_runMode = isConsoleApplication() ? ApplicationLauncher::Console : ApplicationLauncher::Gui; + ctor(); } @@ -127,6 +130,7 @@ QbsRunConfiguration::QbsRunConfiguration(Target *parent, QbsRunConfiguration *so m_uniqueProductName(source->m_uniqueProductName), m_commandLineArguments(source->m_commandLineArguments), m_runMode(source->m_runMode), + m_runModeForced(source->m_runModeForced), m_userWorkingDirectory(source->m_userWorkingDirectory), m_currentInstallStep(0), // no need to copy this, we will get if from the DC anyway. m_currentBuildStepList(0) // ditto @@ -156,15 +160,17 @@ void QbsRunConfiguration::ctor() setDefaultDisplayName(defaultDisplayName()); QbsProject *project = static_cast<QbsProject *>(target()->project()); - connect(project, SIGNAL(projectParsingStarted()), this, SIGNAL(enabledChanged())); - connect(project, SIGNAL(projectParsingDone(bool)), this, SIGNAL(enabledChanged())); - - connect(target(), SIGNAL(activeDeployConfigurationChanged(ProjectExplorer::DeployConfiguration*)), - this, SLOT(installStepChanged())); + connect(project, &QbsProject::projectParsingStarted, this, &RunConfiguration::enabledChanged); + connect(project, &QbsProject::projectParsingDone, this, [this](bool success) { + if (success && !m_runModeForced) + m_runMode = isConsoleApplication() ? ApplicationLauncher::Console + : ApplicationLauncher::Gui; + emit enabledChanged(); + }); + + connect(target(), &Target::activeDeployConfigurationChanged, + this, &QbsRunConfiguration::installStepChanged); installStepChanged(); - - if (isConsoleApplication()) - m_runMode = ApplicationLauncher::Console; } QWidget *QbsRunConfiguration::createConfigurationWidget() @@ -176,7 +182,8 @@ QVariantMap QbsRunConfiguration::toMap() const { QVariantMap map(LocalApplicationRunConfiguration::toMap()); map.insert(QLatin1String(COMMAND_LINE_ARGUMENTS_KEY), m_commandLineArguments); - map.insert(QLatin1String(USE_TERMINAL_KEY), m_runMode == ApplicationLauncher::Console); + if (m_runModeForced) + map.insert(QLatin1String(USE_TERMINAL_KEY), m_runMode == ApplicationLauncher::Console); map.insert(QLatin1String(USER_WORKING_DIRECTORY_KEY), m_userWorkingDirectory); return map; } @@ -184,8 +191,11 @@ QVariantMap QbsRunConfiguration::toMap() const bool QbsRunConfiguration::fromMap(const QVariantMap &map) { m_commandLineArguments = map.value(QLatin1String(COMMAND_LINE_ARGUMENTS_KEY)).toString(); - m_runMode = map.value(QLatin1String(USE_TERMINAL_KEY), false).toBool() ? - ApplicationLauncher::Console : ApplicationLauncher::Gui; + if (map.contains(QLatin1String(USE_TERMINAL_KEY))) { + m_runMode = map.value(QLatin1String(USE_TERMINAL_KEY), false).toBool() ? + ApplicationLauncher::Console : ApplicationLauncher::Gui; + m_runModeForced = true; + } m_userWorkingDirectory = map.value(QLatin1String(USER_WORKING_DIRECTORY_KEY)).toString(); @@ -251,18 +261,13 @@ bool QbsRunConfiguration::isConsoleApplication() const { QbsProject *pro = static_cast<QbsProject *>(target()->project()); const qbs::ProductData product = findProduct(pro->qbsProjectData(), m_uniqueProductName); - foreach (const qbs::TargetArtifact &ta, product.targetArtifacts()) { - if (ta.isExecutable()) - return !ta.properties().getProperty(QLatin1String("consoleApplication")).toBool(); - } - - return false; + return product.properties().value(QLatin1String("consoleApplication"), false).toBool(); } QString QbsRunConfiguration::workingDirectory() const { EnvironmentAspect *aspect = extraAspect<EnvironmentAspect>(); - QTC_ASSERT(aspect, baseWorkingDirectory()); + QTC_ASSERT(aspect, return baseWorkingDirectory()); return QDir::cleanPath(aspect->environment().expandVariables( macroExpander()->expand(baseWorkingDirectory()))); } @@ -309,6 +314,10 @@ void QbsRunConfiguration::setCommandLineArguments(const QString &argumentsString void QbsRunConfiguration::setRunMode(ApplicationLauncher::Mode runMode) { + if (m_runMode == runMode) + return; + + m_runModeForced = true; m_runMode = runMode; emit runModeChanged(runMode); } diff --git a/src/plugins/qbsprojectmanager/qbsrunconfiguration.h b/src/plugins/qbsprojectmanager/qbsrunconfiguration.h index 7faf6697fe..39aaa9f542 100644 --- a/src/plugins/qbsprojectmanager/qbsrunconfiguration.h +++ b/src/plugins/qbsprojectmanager/qbsrunconfiguration.h @@ -126,6 +126,7 @@ private: // Cached startup sub project information ProjectExplorer::ApplicationLauncher::Mode m_runMode; + bool m_runModeForced; QString m_userWorkingDirectory; QbsInstallStep *m_currentInstallStep; // We do not take ownership! diff --git a/src/plugins/qmakeandroidsupport/createandroidmanifestwizard.cpp b/src/plugins/qmakeandroidsupport/createandroidmanifestwizard.cpp index 3b6dbda315..a7ced8234e 100644 --- a/src/plugins/qmakeandroidsupport/createandroidmanifestwizard.cpp +++ b/src/plugins/qmakeandroidsupport/createandroidmanifestwizard.cpp @@ -304,7 +304,9 @@ void CreateAndroidManifestWizard::createAndroidTemplateFiles() QStringList addedFiles; QtSupport::BaseQtVersion *version = QtSupport::QtKitInformation::qtVersion(m_target->kit()); - if (!version || version->qtVersion() < QtSupport::QtVersionNumber(5, 4, 0)) { + if (!version) + return; + if (version->qtVersion() < QtSupport::QtVersionNumber(5, 4, 0)) { const QString src(version->qmakeProperty("QT_INSTALL_PREFIX") .append(QLatin1String("/src/android/java/AndroidManifest.xml"))); FileUtils::copyRecursively(FileName::fromString(src), diff --git a/src/plugins/qmakeandroidsupport/qmakeandroidbuildapkstep.cpp b/src/plugins/qmakeandroidsupport/qmakeandroidbuildapkstep.cpp index 4e48094d0d..6579fc8d16 100644 --- a/src/plugins/qmakeandroidsupport/qmakeandroidbuildapkstep.cpp +++ b/src/plugins/qmakeandroidsupport/qmakeandroidbuildapkstep.cpp @@ -238,8 +238,6 @@ bool QmakeAndroidBuildApkStep::init() arguments << QLatin1String("--ant") << AndroidConfigurations::currentConfig().antToolPath().toString(); - if (buildConfiguration()->buildType() == ProjectExplorer::BuildConfiguration::Release) - arguments << QLatin1String("--release"); QStringList argumentsPasswordConcealed = arguments; diff --git a/src/plugins/qmakeandroidsupport/qmakeandroidsupport_global.h b/src/plugins/qmakeandroidsupport/qmakeandroidsupport_global.h index cf2d1436e7..73fbd1b870 100644 --- a/src/plugins/qmakeandroidsupport/qmakeandroidsupport_global.h +++ b/src/plugins/qmakeandroidsupport/qmakeandroidsupport_global.h @@ -10,16 +10,17 @@ ** 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 Digia. For licensing terms and -** conditions see http://qt.digia.com/licensing. For further information -** use the contact form at http://qt.digia.com/contact-us. +** conditions see http://www.qt.io/licensing. For further information +** use the contact form at http://www.qt.io/contact-us. ** ** GNU Lesser General Public License Usage ** Alternatively, this file may be used under the terms of the GNU Lesser -** General Public License version 2.1 as published by the Free Software -** Foundation and appearing in the file LICENSE.LGPL included in the -** packaging of this file. Please review the following information to -** ensure the GNU Lesser General Public License version 2.1 requirements -** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** General Public License version 2.1 or version 3 as published by the Free +** Software Foundation and appearing in the file LICENSE.LGPLv21 and +** LICENSE.LGPLv3 included in the packaging of this file. Please review the +** following information to ensure the GNU Lesser General Public License +** requirements will be met: https://www.gnu.org/licenses/lgpl.html and +** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. ** ** In addition, as a special exception, Digia gives you certain additional ** rights. These rights are described in the Digia Qt LGPL Exception diff --git a/src/plugins/qmakeprojectmanager/qmakebuildconfiguration.cpp b/src/plugins/qmakeprojectmanager/qmakebuildconfiguration.cpp index f0eb2a96f2..8ab2c79d5f 100644 --- a/src/plugins/qmakeprojectmanager/qmakebuildconfiguration.cpp +++ b/src/plugins/qmakeprojectmanager/qmakebuildconfiguration.cpp @@ -651,7 +651,7 @@ QmakeBuildInfo *QmakeBuildConfigurationFactory::createBuildInfo(const Kit *k, // check if this project is in the source directory: Utils::FileName projectFilePath = Utils::FileName::fromString(projectPath); - if (version->isInSourceDirectory(projectFilePath)) { + if (version->isSubProject(projectFilePath)) { // assemble build directory QString projectDirectory = projectFilePath.toFileInfo().absolutePath(); QDir qtSourceDir = QDir(version->sourcePath().toString()); diff --git a/src/plugins/qmakeprojectmanager/qmakenodes.cpp b/src/plugins/qmakeprojectmanager/qmakenodes.cpp index 3929570312..bf199406ce 100644 --- a/src/plugins/qmakeprojectmanager/qmakenodes.cpp +++ b/src/plugins/qmakeprojectmanager/qmakenodes.cpp @@ -2026,6 +2026,11 @@ void QmakeProFileNode::applyEvaluate(EvalResult *evalResult) if (!m_readerExact) return; + if (m_project->asyncUpdateState() == QmakeProject::ShuttingDown) { + cleanupProFileReaders(); + return; + } + foreach (const QString &error, evalResult->errors) QmakeProject::proFileParseError(error); @@ -2258,6 +2263,11 @@ void QmakeProFileNode::applyEvaluate(EvalResult *evalResult) updateUiFiles(buildDirectory); + cleanupProFileReaders(); +} + +void QmakeProFileNode::cleanupProFileReaders() +{ m_project->destroyProFileReader(m_readerExact); m_project->destroyProFileReader(m_readerCumulative); diff --git a/src/plugins/qmakeprojectmanager/qmakenodes.h b/src/plugins/qmakeprojectmanager/qmakenodes.h index 2acbce6532..7cf4ba8cb5 100644 --- a/src/plugins/qmakeprojectmanager/qmakenodes.h +++ b/src/plugins/qmakeprojectmanager/qmakenodes.h @@ -447,6 +447,7 @@ private: void applyEvaluate(Internal::EvalResult *parseResult); void asyncEvaluate(QFutureInterface<Internal::EvalResult *> &fi, Internal::EvalInput input); + void cleanupProFileReaders(); typedef QHash<QmakeVariable, QStringList> QmakeVariablesHash; diff --git a/src/plugins/qmakeprojectmanager/qmakeproject.cpp b/src/plugins/qmakeprojectmanager/qmakeproject.cpp index bcfbdbfd2a..a0b030b7f8 100644 --- a/src/plugins/qmakeprojectmanager/qmakeproject.cpp +++ b/src/plugins/qmakeprojectmanager/qmakeproject.cpp @@ -42,6 +42,7 @@ #include "wizards/qtquickapp.h" #include <utils/algorithm.h> +#include <coreplugin/documentmanager.h> #include <coreplugin/icontext.h> #include <coreplugin/icore.h> #include <coreplugin/progressmanager/progressmanager.h> @@ -54,6 +55,7 @@ #include <projectexplorer/headerpath.h> #include <projectexplorer/target.h> #include <projectexplorer/projectexplorer.h> +#include <projectexplorer/session.h> #include <proparser/qmakevfs.h> #include <qtsupport/profilereader.h> #include <qtsupport/qtkitinformation.h> @@ -374,7 +376,6 @@ QmakeProject::~QmakeProject() m_codeModelFuture.cancel(); m_asyncUpdateState = ShuttingDown; m_manager->unregisterProject(this); - delete m_qmakeVfs; delete m_projectFiles; m_cancelEvaluate = true; // Deleting the root node triggers a few things, make sure rootProjectNode @@ -383,6 +384,7 @@ QmakeProject::~QmakeProject() m_rootProjectNode = 0; delete root; Q_ASSERT(m_qmakeGlobalsRefCnt == 0); + delete m_qmakeVfs; } void QmakeProject::updateFileList() @@ -649,10 +651,8 @@ void QmakeProject::updateQmlJSCodeModel() // library then chances of the project being a QML project is quite high. // This assumption fails when there are no QDeclarativeEngine/QDeclarativeView (QtQuick 1) // or QQmlEngine/QQuickView (QtQuick 2) instances. - Core::Context pl(ProjectExplorer::Constants::LANG_CXX); if (hasQmlLib) - pl.add(ProjectExplorer::Constants::LANG_QMLJS); - setProjectLanguages(pl); + addProjectLanguage(ProjectExplorer::Constants::LANG_QMLJS); projectInfo.activeResourceFiles.removeDuplicates(); projectInfo.allResourceFiles.removeDuplicates(); @@ -842,6 +842,11 @@ void QmakeProject::decrementPendingEvaluateFutures() updateBoilerPlateCodeFiles(&qtQuickApp, path); } } + + ProjectExplorer::Node *node = ProjectExplorer::SessionManager::nodeForFile(Core::DocumentManager::currentFile()); + if (node) + ProjectExplorerPlugin::setCurrentNode(node); + m_checkForTemplateUpdate = false; } @@ -1623,14 +1628,14 @@ bool QmakeProject::matchesKit(const Kit *kit) QList<QtSupport::BaseQtVersion *> parentQts; Utils::FileName filePath = projectFilePath(); foreach (QtSupport::BaseQtVersion *version, QtSupport::QtVersionManager::validVersions()) { - if (version->isInSourceDirectory(filePath)) + if (version->isSubProject(filePath)) parentQts.append(version); } QtSupport::BaseQtVersion *version = QtSupport::QtKitInformation::qtVersion(kit); if (!parentQts.isEmpty()) return parentQts.contains(version); - return true; + return false; } QString QmakeProject::executableFor(const QmakeProFileNode *node) @@ -1670,6 +1675,11 @@ ProjectImporter *QmakeProject::createProjectImporter() const return new QmakeProjectImporter(projectFilePath().toString()); } +QmakeProject::AsyncUpdateState QmakeProject::asyncUpdateState() const +{ + return m_asyncUpdateState; +} + } // namespace QmakeProjectManager #include "qmakeproject.moc" diff --git a/src/plugins/qmakeprojectmanager/qmakeproject.h b/src/plugins/qmakeprojectmanager/qmakeproject.h index 103dd6983a..7959c5242b 100644 --- a/src/plugins/qmakeprojectmanager/qmakeproject.h +++ b/src/plugins/qmakeprojectmanager/qmakeproject.h @@ -141,6 +141,9 @@ public: ProjectExplorer::ProjectImporter *createProjectImporter() const; + enum AsyncUpdateState { Base, AsyncFullUpdatePending, AsyncPartialUpdatePending, AsyncUpdateInProgress, ShuttingDown }; + AsyncUpdateState asyncUpdateState() const; + signals: void proFileUpdated(QmakeProjectManager::QmakeProFileNode *node, bool, bool); void buildDirectoryInitialized(); @@ -203,7 +206,6 @@ private: QTimer m_asyncUpdateTimer; QFutureInterface<void> *m_asyncUpdateFutureInterface; int m_pendingEvaluateFuturesCount; - enum AsyncUpdateState { Base, AsyncFullUpdatePending, AsyncPartialUpdatePending, AsyncUpdateInProgress, ShuttingDown }; AsyncUpdateState m_asyncUpdateState; bool m_cancelEvaluate; QList<QmakeProFileNode *> m_partialEvaluate; diff --git a/src/plugins/qmakeprojectmanager/qmakestep.cpp b/src/plugins/qmakeprojectmanager/qmakestep.cpp index e18ff27e6d..0d2f3836f1 100644 --- a/src/plugins/qmakeprojectmanager/qmakestep.cpp +++ b/src/plugins/qmakeprojectmanager/qmakestep.cpp @@ -476,14 +476,20 @@ QMakeStepConfigWidget::QMakeStepConfigWidget(QMakeStep *step) this, SLOT(qmakeArgumentsLineEdited())); connect(m_ui->buildConfigurationComboBox, SIGNAL(currentIndexChanged(int)), this, SLOT(buildConfigurationSelected())); - connect(m_ui->qmlDebuggingLibraryCheckBox, SIGNAL(toggled(bool)), - this, SLOT(linkQmlDebuggingLibraryChecked(bool))); + connect(m_ui->qmlDebuggingLibraryCheckBox, &QCheckBox::toggled, + this, &QMakeStepConfigWidget::linkQmlDebuggingLibraryChecked); + connect(m_ui->qmlDebuggingLibraryCheckBox, &QCheckBox::clicked, + this, &QMakeStepConfigWidget::askForRebuild); connect(m_ui->qtQuickCompilerCheckBox, &QAbstractButton::toggled, this, &QMakeStepConfigWidget::useQtQuickCompilerChecked); + connect(m_ui->qtQuickCompilerCheckBox, &QCheckBox::clicked, + this, &QMakeStepConfigWidget::askForRebuild); connect(step, SIGNAL(userArgumentsChanged()), this, SLOT(userArgumentsChanged())); connect(step, SIGNAL(linkQmlDebuggingLibraryChanged()), this, SLOT(linkQmlDebuggingLibraryChanged())); + connect(step->project(), &Project::projectLanguagesUpdated, + this, &QMakeStepConfigWidget::linkQmlDebuggingLibraryChanged); connect(step, &QMakeStep::useQtQuickCompilerChanged, this, &QMakeStepConfigWidget::useQtQuickCompilerChanged); connect(step->qmakeBuildConfiguration(), SIGNAL(qmakeBuildConfigurationChanged()), @@ -603,7 +609,6 @@ void QMakeStepConfigWidget::linkQmlDebuggingLibraryChecked(bool checked) updateSummaryLabel(); updateEffectiveQMakeCall(); updateQmlDebuggingOption(); - askForRebuild(); } void QMakeStepConfigWidget::askForRebuild() @@ -629,7 +634,6 @@ void QMakeStepConfigWidget::useQtQuickCompilerChecked(bool checked) updateSummaryLabel(); updateEffectiveQMakeCall(); updateQtQuickCompilerOption(); - askForRebuild(); } void QMakeStepConfigWidget::updateSummaryLabel() diff --git a/src/plugins/qmakeprojectmanager/qmakestep.h b/src/plugins/qmakeprojectmanager/qmakestep.h index ee8bbf67ed..352ff17e34 100644 --- a/src/plugins/qmakeprojectmanager/qmakestep.h +++ b/src/plugins/qmakeprojectmanager/qmakestep.h @@ -165,6 +165,7 @@ private slots: void buildConfigurationSelected(); void linkQmlDebuggingLibraryChecked(bool checked); void useQtQuickCompilerChecked(bool checked); + void askForRebuild(); private slots: void recompileMessageBoxFinished(int button); @@ -174,7 +175,6 @@ private: void updateQmlDebuggingOption(); void updateQtQuickCompilerOption(); void updateEffectiveQMakeCall(); - void askForRebuild(); void setSummaryText(const QString &); diff --git a/src/plugins/qmljstools/qmlconsolepane.cpp b/src/plugins/qmljstools/qmlconsolepane.cpp index 74245eb662..f0419be234 100644 --- a/src/plugins/qmljstools/qmlconsolepane.cpp +++ b/src/plugins/qmljstools/qmlconsolepane.cpp @@ -187,7 +187,7 @@ bool QmlConsolePane::canFocus() const bool QmlConsolePane::hasFocus() const { - return m_consoleWidget->hasFocus(); + return m_consoleWidget->window()->focusWidget() == m_consoleWidget; } void QmlConsolePane::setFocus() diff --git a/src/plugins/qmlprofiler/qml/Overview.js b/src/plugins/qmlprofiler/qml/Overview.js index 2388e2b760..57e3f3a249 100644 --- a/src/plugins/qmlprofiler/qml/Overview.js +++ b/src/plugins/qmlprofiler/qml/Overview.js @@ -79,7 +79,7 @@ function drawBindingLoops(canvas, ctxt) { ii += canvas.increment) { if (qmlProfilerModelProxy.bindingLoopDest(modelIndex,ii) >= 0) { var xcenter = Math.round(qmlProfilerModelProxy.startTime(modelIndex,ii) + - qmlProfilerModelProxy.duration(modelIndex,ii) - + qmlProfilerModelProxy.duration(modelIndex,ii) / 2 - zoomControl.traceStart) * canvas.spacing; var ycenter = Math.round(canvas.bump + canvas.blockHeight * modelIndex + canvas.blockHeight / 2); diff --git a/src/plugins/qmlprofiler/qmlprofilerbasemodel.cpp b/src/plugins/qmlprofiler/qmlprofilerbasemodel.cpp index 54f694481a..4bbc2a9f19 100644 --- a/src/plugins/qmlprofiler/qmlprofilerbasemodel.cpp +++ b/src/plugins/qmlprofiler/qmlprofilerbasemodel.cpp @@ -36,7 +36,9 @@ namespace QmlProfiler { QmlProfilerBaseModel::QmlProfilerBaseModel(Utils::FileInProjectFinder *fileFinder, QmlProfilerModelManager *manager, - QmlProfilerBaseModelPrivate *dd) : d_ptr(dd) + QmlProfilerBaseModelPrivate *dd) + : QObject(manager) + , d_ptr(dd) { Q_D(QmlProfilerBaseModel); d->modelManager = manager; diff --git a/src/plugins/qmlprofiler/qmlprofilertool.cpp b/src/plugins/qmlprofiler/qmlprofilertool.cpp index 8758d7b81b..2cbca776ea 100644 --- a/src/plugins/qmlprofiler/qmlprofilertool.cpp +++ b/src/plugins/qmlprofiler/qmlprofilertool.cpp @@ -328,14 +328,21 @@ void QmlProfilerTool::populateFileFinder(QString projectDirectory, QString activ void QmlProfilerTool::recordingButtonChanged(bool recording) { + // clientRecording is our intention for new sessions. That may differ from the state of the + // current session, as indicated by the button. To synchronize it, toggle once. + if (recording && d->m_profilerState->currentState() == QmlProfilerStateManager::AppRunning) { if (checkForUnsavedNotes()) { clearData(); // clear right away, before the application starts + if (d->m_profilerState->clientRecording()) + d->m_profilerState->setClientRecording(false); d->m_profilerState->setClientRecording(true); } else { d->m_recordButton->setChecked(false); } } else { + if (d->m_profilerState->clientRecording() == recording) + d->m_profilerState->setClientRecording(!recording); d->m_profilerState->setClientRecording(recording); } } @@ -348,7 +355,6 @@ void QmlProfilerTool::setRecording(bool recording) QLatin1String(":/qmlprofiler/recordOff.png"))); d->m_recordButton->setChecked(recording); - d->m_profilerState->setClientRecording(recording); // manage timer if (d->m_profilerState->currentState() == QmlProfilerStateManager::AppRunning) { @@ -375,16 +381,10 @@ void QmlProfilerTool::gotoSourceLocation(const QString &fileUrl, int lineNumber, if (!fileInfo.exists() || !fileInfo.isReadable()) return; - IEditor *editor = EditorManager::openEditor(projectFileName); - TextEditor::BaseTextEditor *textEditor = qobject_cast<TextEditor::BaseTextEditor*>(editor); - - if (textEditor) { - EditorManager::addCurrentPositionToNavigationHistory(); - // textEditor counts columns starting with 0, but the ASTs store the - // location starting with 1, therefore the -1 in the call to gotoLine - textEditor->gotoLine(lineNumber, columnNumber - 1); - textEditor->widget()->setFocus(); - } + // The text editors count columns starting with 0, but the ASTs store the + // location starting with 1, therefore the -1. + EditorManager::openEditorAt(projectFileName, lineNumber, columnNumber - 1, Id(), + EditorManager::DoNotSwitchToDesignMode); } void QmlProfilerTool::updateTimeDisplay() @@ -454,7 +454,6 @@ static void startRemoteTool(IAnalyzerTool *tool, StartMode mode) sp.analyzerPort = port; AnalyzerRunControl *rc = tool->createRunControl(sp, 0); - QObject::connect(AnalyzerManager::stopAction(), SIGNAL(triggered()), rc, SLOT(stopIt())); ProjectExplorerPlugin::startRunControl(rc, tool->runMode()); } diff --git a/src/plugins/qmlprofiler/qv8profilereventview.cpp b/src/plugins/qmlprofiler/qv8profilereventview.cpp index 722548df50..4ecf025811 100644 --- a/src/plugins/qmlprofiler/qv8profilereventview.cpp +++ b/src/plugins/qmlprofiler/qv8profilereventview.cpp @@ -643,7 +643,7 @@ QV8ProfilerEventRelativesView::~QV8ProfilerEventRelativesView() void QV8ProfilerEventRelativesView::displayType(int index) { QV8ProfilerDataModel::QV8EventData *event = m_v8Model->v8EventDescription(index); - QTC_CHECK(event); + QTC_ASSERT(event, return); QList<QV8ProfilerDataModel::QV8EventSub*> events; if (m_type == ParentsView) diff --git a/src/plugins/qmlprofiler/timelinerenderer.cpp b/src/plugins/qmlprofiler/timelinerenderer.cpp index 25bdaf2c29..64eb6feaff 100644 --- a/src/plugins/qmlprofiler/timelinerenderer.cpp +++ b/src/plugins/qmlprofiler/timelinerenderer.cpp @@ -315,14 +315,14 @@ void TimelineRenderer::drawBindingLoopMarkers(QPainter *p, int modelIndex, int f // to getItemXExtent(modelIndex, destindex, xto, width); xto += width / 2; - yto = getYPosition(modelIndex, destindex) + - m_profilerModelProxy->rowHeight(modelIndex, destindex) / 2 - y(); + yto = getYPosition(modelIndex, destindex) + m_profilerModelProxy->rowHeight(modelIndex, + m_profilerModelProxy->row(modelIndex, destindex)) / 2 - y(); // from getItemXExtent(modelIndex, i, xfrom, width); xfrom += width / 2; - yfrom = getYPosition(modelIndex, i) + - m_profilerModelProxy->rowHeight(modelIndex, i) / 2 - y(); + yfrom = getYPosition(modelIndex, i) + m_profilerModelProxy->rowHeight(modelIndex, + m_profilerModelProxy->row(modelIndex, i)) / 2 - y(); // radius (derived from width of origin event) radius = 5; diff --git a/src/plugins/qtsupport/baseqtversion.cpp b/src/plugins/qtsupport/baseqtversion.cpp index 0acdc2adfb..bf89085e57 100644 --- a/src/plugins/qtsupport/baseqtversion.cpp +++ b/src/plugins/qtsupport/baseqtversion.cpp @@ -61,6 +61,7 @@ #include <QFuture> #include <QCoreApplication> #include <QProcess> +#include <QRegExp> using namespace Core; using namespace QtSupport; @@ -1399,6 +1400,13 @@ FileName BaseQtVersion::mkspecFromVersionInfo(const QHash<QString, QString> &ver const QList<QByteArray> &temp = line.split('='); if (temp.size() == 2) { QString possibleFullPath = QString::fromLocal8Bit(temp.at(1).trimmed().constData()); + if (possibleFullPath.contains(QLatin1Char('$'))) { // QTBUG-28792 + const QRegExp rex(QLatin1String("\\binclude\\(([^)]+)/qmake\\.conf\\)")); + if (rex.indexIn(QString::fromLocal8Bit(f2.readAll())) != -1) { + possibleFullPath = mkspecFullPath.toString() + QLatin1Char('/') + + rex.cap(1); + } + } // We sometimes get a mix of different slash styles here... possibleFullPath = possibleFullPath.replace(QLatin1Char('\\'), QLatin1Char('/')); if (QFileInfo::exists(possibleFullPath)) // Only if the path exists @@ -1470,16 +1478,27 @@ FileName BaseQtVersion::sourcePath(const QHash<QString, QString> &versionInfo) return FileName::fromUserInput(sourcePath); } -bool BaseQtVersion::isInSourceDirectory(const Utils::FileName &filePath) +bool BaseQtVersion::isSubProject(const Utils::FileName &filePath) { const Utils::FileName &source = sourcePath(); - if (source.isEmpty()) - return false; - QDir dir = QDir(source.toString()); - if (dir.dirName() == QLatin1String("qtbase")) - dir.cdUp(); + if (!source.isEmpty()) { + QDir dir = QDir(source.toString()); + if (dir.dirName() == QLatin1String("qtbase")) + dir.cdUp(); + + if (filePath.isChildOf(dir)) + return true; + } + + const QString &examples = examplesPath(); + if (!examples.isEmpty() && filePath.isChildOf(QDir(examples))) + return true; + + const QString &demos = demosPath(); + if (!demos.isEmpty() && filePath.isChildOf(QDir(demos))) + return true; - return filePath.isChildOf(dir); + return false; } bool BaseQtVersion::isQmlDebuggingSupported(Kit *k, QString *reason) diff --git a/src/plugins/qtsupport/baseqtversion.h b/src/plugins/qtsupport/baseqtversion.h index a04510d0ba..e876c24bc9 100644 --- a/src/plugins/qtsupport/baseqtversion.h +++ b/src/plugins/qtsupport/baseqtversion.h @@ -124,7 +124,7 @@ public: virtual Utils::Environment qmakeRunEnvironment() const; virtual Utils::FileName sourcePath() const; - bool isInSourceDirectory(const Utils::FileName &filePath); + bool isSubProject(const Utils::FileName &filePath); // used by UiCodeModelSupport virtual QString uicCommand() const; diff --git a/src/plugins/qtsupport/qtkitinformation.cpp b/src/plugins/qtsupport/qtkitinformation.cpp index 386f8e2ea7..969cb92a03 100644 --- a/src/plugins/qtsupport/qtkitinformation.cpp +++ b/src/plugins/qtsupport/qtkitinformation.cpp @@ -77,13 +77,14 @@ QVariant QtKitInformation::defaultValue(ProjectExplorer::Kit *k) const result = findOrDefault(versionList, [qmakePath](const BaseQtVersion *v) { return v->qmakeCommand() == qmakePath; }); + if (result) + return result->uniqueId(); } // Use *any* desktop Qt: result = findOrDefault(versionList, [](const BaseQtVersion *v) { return v->type() == QLatin1String(QtSupport::Constants::DESKTOPQT); }); - return result ? result->uniqueId() : -1; } diff --git a/src/plugins/resourceeditor/qrceditor/qrceditor.cpp b/src/plugins/resourceeditor/qrceditor/qrceditor.cpp index 846f0136c6..4afdf830cb 100644 --- a/src/plugins/resourceeditor/qrceditor/qrceditor.cpp +++ b/src/plugins/resourceeditor/qrceditor/qrceditor.cpp @@ -136,6 +136,11 @@ bool QrcEditor::save() return m_treeview->save(); } +QString QrcEditor::contents() const +{ + return m_treeview->contents(); +} + bool QrcEditor::isDirty() { return m_treeview->isDirty(); diff --git a/src/plugins/resourceeditor/qrceditor/qrceditor.h b/src/plugins/resourceeditor/qrceditor/qrceditor.h index 7a24d9653c..fbcafeb7e6 100644 --- a/src/plugins/resourceeditor/qrceditor/qrceditor.h +++ b/src/plugins/resourceeditor/qrceditor/qrceditor.h @@ -49,6 +49,7 @@ public: bool load(const QString &fileName); bool save(); + QString contents() const; QTreeView *treeView() { return m_treeview; } QString errorMessage() const { return m_treeview->errorMessage(); } diff --git a/src/plugins/resourceeditor/qrceditor/resourcefile.cpp b/src/plugins/resourceeditor/qrceditor/resourcefile.cpp index e4a13ca869..ff57423cb5 100644 --- a/src/plugins/resourceeditor/qrceditor/resourcefile.cpp +++ b/src/plugins/resourceeditor/qrceditor/resourcefile.cpp @@ -183,15 +183,8 @@ bool ResourceFile::load() return true; } -bool ResourceFile::save() +QString ResourceFile::contents() const { - m_error_message.clear(); - - if (m_file_name.isEmpty()) { - m_error_message = tr("The file name is empty."); - return false; - } - QDomDocument doc; QDomElement root = doc.createElement(QLatin1String("RCC")); doc.appendChild(root); @@ -222,11 +215,19 @@ bool ResourceFile::save() felt.setAttribute(QLatin1String("threshold"), file.threshold); } } + return doc.toString(4); +} - QString data = doc.toString(4); - if (!m_textFileFormat.writeFile(m_file_name, data, &m_error_message)) +bool ResourceFile::save() +{ + m_error_message.clear(); + + if (m_file_name.isEmpty()) { + m_error_message = tr("The file name is empty."); return false; - return true; + } + + return m_textFileFormat.writeFile(m_file_name, contents(), &m_error_message); } void ResourceFile::refresh() diff --git a/src/plugins/resourceeditor/qrceditor/resourcefile_p.h b/src/plugins/resourceeditor/qrceditor/resourcefile_p.h index b60d5ca628..598f805844 100644 --- a/src/plugins/resourceeditor/qrceditor/resourcefile_p.h +++ b/src/plugins/resourceeditor/qrceditor/resourcefile_p.h @@ -139,6 +139,7 @@ public: QString fileName() const { return m_file_name; } bool load(); bool save(); + QString contents() const; QString errorMessage() const { return m_error_message; } void refresh(); @@ -252,6 +253,8 @@ private: public: virtual bool reload(); virtual bool save(); + QString contents() const { return m_resource_file.contents(); } + // QString errorMessage() const { return m_resource_file.errorMessage(); } bool dirty() const { return m_dirty; } diff --git a/src/plugins/resourceeditor/qrceditor/resourceview.cpp b/src/plugins/resourceeditor/qrceditor/resourceview.cpp index 4a7d7c905c..2b24dfa578 100644 --- a/src/plugins/resourceeditor/qrceditor/resourceview.cpp +++ b/src/plugins/resourceeditor/qrceditor/resourceview.cpp @@ -381,6 +381,11 @@ bool ResourceView::save() return m_qrcModel->save(); } +QString ResourceView::contents() const +{ + return m_qrcModel->contents(); +} + QString ResourceView::currentAlias() const { const QModelIndex current = currentIndex(); diff --git a/src/plugins/resourceeditor/qrceditor/resourceview.h b/src/plugins/resourceeditor/qrceditor/resourceview.h index 840897e7a0..96d2dadf9a 100644 --- a/src/plugins/resourceeditor/qrceditor/resourceview.h +++ b/src/plugins/resourceeditor/qrceditor/resourceview.h @@ -85,6 +85,7 @@ public: bool load(const QString &fileName); bool save(); + QString contents() const; QString errorMessage() const { return m_qrcFile.errorMessage(); } QString fileName() const; void setFileName(const QString &fileName); diff --git a/src/plugins/resourceeditor/resourceeditorw.cpp b/src/plugins/resourceeditor/resourceeditorw.cpp index 0b0dbd4e56..dc9fae45b1 100644 --- a/src/plugins/resourceeditor/resourceeditorw.cpp +++ b/src/plugins/resourceeditor/resourceeditorw.cpp @@ -187,6 +187,11 @@ bool ResourceEditorDocument::save(QString *errorString, const QString &name, boo return true; } +QString ResourceEditorDocument::plainText() const +{ + return m_parent->m_resourceEditor->contents(); +} + bool ResourceEditorDocument::setContents(const QByteArray &contents) { Utils::TempFileSaver saver; diff --git a/src/plugins/resourceeditor/resourceeditorw.h b/src/plugins/resourceeditor/resourceeditorw.h index 2ddfba91a9..908a936506 100644 --- a/src/plugins/resourceeditor/resourceeditorw.h +++ b/src/plugins/resourceeditor/resourceeditorw.h @@ -50,12 +50,14 @@ class ResourceEditorDocument : public Core::IDocument { Q_OBJECT + Q_PROPERTY(QString plainText READ plainText STORED false) // For access by code pasters public: ResourceEditorDocument(ResourceEditorW *parent = 0); //IDocument bool save(QString *errorString, const QString &fileName, bool autoSave); + QString plainText() const; bool setContents(const QByteArray &contents); bool shouldAutoSave() const; bool isModified() const; diff --git a/src/plugins/subversion/checkoutwizard.cpp b/src/plugins/subversion/checkoutwizard.cpp index 8f89d21329..6ba31be58e 100644 --- a/src/plugins/subversion/checkoutwizard.cpp +++ b/src/plugins/subversion/checkoutwizard.cpp @@ -76,7 +76,7 @@ VcsCommand *CheckoutWizard::createCommand(FileName *checkoutDir) const QString directory = cwp->directory(); QStringList args; args << QLatin1String("checkout"); - args << SubversionClient::addAuthenticationOptions(settings) << cwp->repository() << directory; + args << SubversionClient::addAuthenticationOptions(settings); args << QLatin1String(Constants::NON_INTERACTIVE_OPTION); if (cwp->trustServerCert()) args << QLatin1String("--trust-server-cert"); diff --git a/src/plugins/subversion/subversionplugin.cpp b/src/plugins/subversion/subversionplugin.cpp index c18243320a..e90083b57d 100644 --- a/src/plugins/subversion/subversionplugin.cpp +++ b/src/plugins/subversion/subversionplugin.cpp @@ -92,6 +92,7 @@ using namespace VcsBase; namespace Subversion { namespace Internal { +const char SUBVERSION_CONTEXT[] = "Subversion Context"; const char CMD_ID_SUBVERSION_MENU[] = "Subversion.Menu"; const char CMD_ID_ADD[] = "Subversion.Add"; const char CMD_ID_DELETE_FILE[] = "Subversion.Delete"; @@ -242,7 +243,9 @@ bool SubversionPlugin::initialize(const QStringList & /*arguments */, QString *e using namespace Constants; using namespace Core::Constants; - initializeVcs(new SubversionControl(this)); + Context context(SUBVERSION_CONTEXT); + + initializeVcs(new SubversionControl(this), context); m_subversionPluginInstance = this; @@ -284,12 +287,11 @@ bool SubversionPlugin::initialize(const QStringList & /*arguments */, QString *e subversionMenu->menu()->setTitle(tr("&Subversion")); toolsContainer->addMenu(subversionMenu); m_menuAction = subversionMenu->menu()->menuAction(); - Context globalcontext(C_GLOBAL); Core::Command *command; m_diffCurrentAction = new ParameterAction(tr("Diff Current File"), tr("Diff \"%1\""), ParameterAction::EnabledWithParameter, this); command = ActionManager::registerAction(m_diffCurrentAction, - CMD_ID_DIFF_CURRENT, globalcontext); + CMD_ID_DIFF_CURRENT, context); command->setAttribute(Core::Command::CA_UpdateText); command->setDefaultKeySequence(QKeySequence(UseMacShortcuts ? tr("Meta+S,Meta+D") : tr("Alt+S,Alt+D"))); connect(m_diffCurrentAction, SIGNAL(triggered()), this, SLOT(diffCurrentFile())); @@ -298,7 +300,7 @@ bool SubversionPlugin::initialize(const QStringList & /*arguments */, QString *e m_filelogCurrentAction = new ParameterAction(tr("Filelog Current File"), tr("Filelog \"%1\""), ParameterAction::EnabledWithParameter, this); command = ActionManager::registerAction(m_filelogCurrentAction, - CMD_ID_FILELOG_CURRENT, globalcontext); + CMD_ID_FILELOG_CURRENT, context); command->setAttribute(Core::Command::CA_UpdateText); connect(m_filelogCurrentAction, SIGNAL(triggered()), this, SLOT(filelogCurrentFile())); @@ -307,18 +309,18 @@ bool SubversionPlugin::initialize(const QStringList & /*arguments */, QString *e m_annotateCurrentAction = new ParameterAction(tr("Annotate Current File"), tr("Annotate \"%1\""), ParameterAction::EnabledWithParameter, this); command = ActionManager::registerAction(m_annotateCurrentAction, - CMD_ID_ANNOTATE_CURRENT, globalcontext); + CMD_ID_ANNOTATE_CURRENT, context); command->setAttribute(Core::Command::CA_UpdateText); connect(m_annotateCurrentAction, SIGNAL(triggered()), this, SLOT(annotateCurrentFile())); subversionMenu->addAction(command); m_commandLocator->appendCommand(command); - subversionMenu->addSeparator(globalcontext); + subversionMenu->addSeparator(context); m_addAction = new ParameterAction(tr("Add"), tr("Add \"%1\""), ParameterAction::EnabledWithParameter, this); command = ActionManager::registerAction(m_addAction, CMD_ID_ADD, - globalcontext); + context); command->setAttribute(Core::Command::CA_UpdateText); command->setDefaultKeySequence(QKeySequence(UseMacShortcuts ? tr("Meta+S,Meta+A") : tr("Alt+S,Alt+A"))); connect(m_addAction, SIGNAL(triggered()), this, SLOT(addCurrentFile())); @@ -327,7 +329,7 @@ bool SubversionPlugin::initialize(const QStringList & /*arguments */, QString *e m_commitCurrentAction = new ParameterAction(tr("Commit Current File"), tr("Commit \"%1\""), ParameterAction::EnabledWithParameter, this); command = ActionManager::registerAction(m_commitCurrentAction, - CMD_ID_COMMIT_CURRENT, globalcontext); + CMD_ID_COMMIT_CURRENT, context); command->setAttribute(Core::Command::CA_UpdateText); command->setDefaultKeySequence(QKeySequence(UseMacShortcuts ? tr("Meta+S,Meta+C") : tr("Alt+S,Alt+C"))); connect(m_commitCurrentAction, SIGNAL(triggered()), this, SLOT(startCommitCurrentFile())); @@ -336,7 +338,7 @@ bool SubversionPlugin::initialize(const QStringList & /*arguments */, QString *e m_deleteAction = new ParameterAction(tr("Delete..."), tr("Delete \"%1\"..."), ParameterAction::EnabledWithParameter, this); command = ActionManager::registerAction(m_deleteAction, CMD_ID_DELETE_FILE, - globalcontext); + context); command->setAttribute(Core::Command::CA_UpdateText); connect(m_deleteAction, SIGNAL(triggered()), this, SLOT(promptToDeleteCurrentFile())); subversionMenu->addAction(command); @@ -344,17 +346,17 @@ bool SubversionPlugin::initialize(const QStringList & /*arguments */, QString *e m_revertAction = new ParameterAction(tr("Revert..."), tr("Revert \"%1\"..."), ParameterAction::EnabledWithParameter, this); command = ActionManager::registerAction(m_revertAction, CMD_ID_REVERT, - globalcontext); + context); command->setAttribute(Core::Command::CA_UpdateText); connect(m_revertAction, SIGNAL(triggered()), this, SLOT(revertCurrentFile())); subversionMenu->addAction(command); m_commandLocator->appendCommand(command); - subversionMenu->addSeparator(globalcontext); + subversionMenu->addSeparator(context); m_diffProjectAction = new ParameterAction(tr("Diff Project"), tr("Diff Project \"%1\""), ParameterAction::EnabledWithParameter, this); command = ActionManager::registerAction(m_diffProjectAction, CMD_ID_DIFF_PROJECT, - globalcontext); + context); command->setAttribute(Core::Command::CA_UpdateText); connect(m_diffProjectAction, SIGNAL(triggered()), this, SLOT(diffProject())); subversionMenu->addAction(command); @@ -362,74 +364,74 @@ bool SubversionPlugin::initialize(const QStringList & /*arguments */, QString *e m_statusProjectAction = new ParameterAction(tr("Project Status"), tr("Status of Project \"%1\""), ParameterAction::EnabledWithParameter, this); command = ActionManager::registerAction(m_statusProjectAction, CMD_ID_STATUS, - globalcontext); + context); command->setAttribute(Core::Command::CA_UpdateText); connect(m_statusProjectAction, SIGNAL(triggered()), this, SLOT(projectStatus())); subversionMenu->addAction(command); m_commandLocator->appendCommand(command); m_logProjectAction = new ParameterAction(tr("Log Project"), tr("Log Project \"%1\""), ParameterAction::EnabledWithParameter, this); - command = ActionManager::registerAction(m_logProjectAction, CMD_ID_PROJECTLOG, globalcontext); + command = ActionManager::registerAction(m_logProjectAction, CMD_ID_PROJECTLOG, context); command->setAttribute(Core::Command::CA_UpdateText); connect(m_logProjectAction, SIGNAL(triggered()), this, SLOT(logProject())); subversionMenu->addAction(command); m_commandLocator->appendCommand(command); m_updateProjectAction = new ParameterAction(tr("Update Project"), tr("Update Project \"%1\""), ParameterAction::EnabledWithParameter, this); - command = ActionManager::registerAction(m_updateProjectAction, CMD_ID_UPDATE, globalcontext); + command = ActionManager::registerAction(m_updateProjectAction, CMD_ID_UPDATE, context); connect(m_updateProjectAction, SIGNAL(triggered()), this, SLOT(updateProject())); command->setAttribute(Core::Command::CA_UpdateText); subversionMenu->addAction(command); m_commandLocator->appendCommand(command); m_commitProjectAction = new ParameterAction(tr("Commit Project"), tr("Commit Project \"%1\""), ParameterAction::EnabledWithParameter, this); - command = ActionManager::registerAction(m_commitProjectAction, CMD_ID_COMMIT_PROJECT, globalcontext); + command = ActionManager::registerAction(m_commitProjectAction, CMD_ID_COMMIT_PROJECT, context); connect(m_commitProjectAction, SIGNAL(triggered()), this, SLOT(startCommitProject())); command->setAttribute(Core::Command::CA_UpdateText); subversionMenu->addAction(command); m_commandLocator->appendCommand(command); - subversionMenu->addSeparator(globalcontext); + subversionMenu->addSeparator(context); m_diffRepositoryAction = new QAction(tr("Diff Repository"), this); - command = ActionManager::registerAction(m_diffRepositoryAction, CMD_ID_REPOSITORYDIFF, globalcontext); + command = ActionManager::registerAction(m_diffRepositoryAction, CMD_ID_REPOSITORYDIFF, context); connect(m_diffRepositoryAction, SIGNAL(triggered()), this, SLOT(diffRepository())); subversionMenu->addAction(command); m_commandLocator->appendCommand(command); m_statusRepositoryAction = new QAction(tr("Repository Status"), this); - command = ActionManager::registerAction(m_statusRepositoryAction, CMD_ID_REPOSITORYSTATUS, globalcontext); + command = ActionManager::registerAction(m_statusRepositoryAction, CMD_ID_REPOSITORYSTATUS, context); connect(m_statusRepositoryAction, SIGNAL(triggered()), this, SLOT(statusRepository())); subversionMenu->addAction(command); m_commandLocator->appendCommand(command); m_logRepositoryAction = new QAction(tr("Log Repository"), this); - command = ActionManager::registerAction(m_logRepositoryAction, CMD_ID_REPOSITORYLOG, globalcontext); + command = ActionManager::registerAction(m_logRepositoryAction, CMD_ID_REPOSITORYLOG, context); connect(m_logRepositoryAction, SIGNAL(triggered()), this, SLOT(logRepository())); subversionMenu->addAction(command); m_commandLocator->appendCommand(command); m_updateRepositoryAction = new QAction(tr("Update Repository"), this); - command = ActionManager::registerAction(m_updateRepositoryAction, CMD_ID_REPOSITORYUPDATE, globalcontext); + command = ActionManager::registerAction(m_updateRepositoryAction, CMD_ID_REPOSITORYUPDATE, context); connect(m_updateRepositoryAction, SIGNAL(triggered()), this, SLOT(updateRepository())); subversionMenu->addAction(command); m_commandLocator->appendCommand(command); m_commitAllAction = new QAction(tr("Commit All Files"), this); command = ActionManager::registerAction(m_commitAllAction, CMD_ID_COMMIT_ALL, - globalcontext); + context); connect(m_commitAllAction, SIGNAL(triggered()), this, SLOT(startCommitAll())); subversionMenu->addAction(command); m_commandLocator->appendCommand(command); m_describeAction = new QAction(tr("Describe..."), this); - command = ActionManager::registerAction(m_describeAction, CMD_ID_DESCRIBE, globalcontext); + command = ActionManager::registerAction(m_describeAction, CMD_ID_DESCRIBE, context); connect(m_describeAction, SIGNAL(triggered()), this, SLOT(slotDescribe())); subversionMenu->addAction(command); m_revertRepositoryAction = new QAction(tr("Revert Repository..."), this); command = ActionManager::registerAction(m_revertRepositoryAction, CMD_ID_REVERT_ALL, - globalcontext); + context); connect(m_revertRepositoryAction, SIGNAL(triggered()), this, SLOT(revertAll())); subversionMenu->addAction(command); m_commandLocator->appendCommand(command); @@ -1092,7 +1094,6 @@ bool SubversionPlugin::vcsCheckout(const QString &directory, const QByteArray &u } args << QLatin1String(tempUrl.toEncoded()) << directory; - args << QLatin1String(url) << directory; const SubversionResponse response = runSvn(directory, args, 10 * m_settings.timeOutMs(), diff --git a/src/plugins/texteditor/texteditorsettings.cpp b/src/plugins/texteditor/texteditorsettings.cpp index a8f49e096a..89f8c84297 100644 --- a/src/plugins/texteditor/texteditorsettings.cpp +++ b/src/plugins/texteditor/texteditorsettings.cpp @@ -303,6 +303,8 @@ TextEditorSettings::TextEditorSettings(QObject *parent) this, SIGNAL(storageSettingsChanged(TextEditor::StorageSettings))); connect(d->m_behaviorSettingsPage, SIGNAL(behaviorSettingsChanged(TextEditor::BehaviorSettings)), this, SIGNAL(behaviorSettingsChanged(TextEditor::BehaviorSettings))); + connect(d->m_behaviorSettingsPage, SIGNAL(extraEncodingSettingsChanged(TextEditor::ExtraEncodingSettings)), + this, SIGNAL(extraEncodingSettingsChanged(TextEditor::ExtraEncodingSettings))); connect(d->m_displaySettingsPage, SIGNAL(marginSettingsChanged(TextEditor::MarginSettings)), this, SIGNAL(marginSettingsChanged(TextEditor::MarginSettings))); connect(d->m_displaySettingsPage, SIGNAL(displaySettingsChanged(TextEditor::DisplaySettings)), diff --git a/src/plugins/todo/todooutputpane.cpp b/src/plugins/todo/todooutputpane.cpp index e71e17e53b..eeabbc55bc 100755 --- a/src/plugins/todo/todooutputpane.cpp +++ b/src/plugins/todo/todooutputpane.cpp @@ -99,7 +99,7 @@ void TodoOutputPane::setFocus() bool TodoOutputPane::hasFocus() const { - return m_todoTreeView->hasFocus(); + return m_todoTreeView->window()->focusWidget() == m_todoTreeView; } bool TodoOutputPane::canFocus() const diff --git a/src/plugins/updateinfo/UpdateInfo.json.in b/src/plugins/updateinfo/UpdateInfo.json.in index b382c7612b..4adb8d3b94 100644 --- a/src/plugins/updateinfo/UpdateInfo.json.in +++ b/src/plugins/updateinfo/UpdateInfo.json.in @@ -11,7 +11,7 @@ \"\", \"GNU Lesser General Public License Usage\", \"\", - \"Alternatively, this plugin may be used under the terms of the GNU Lesser General Public License version 2.1 as published by the Free Software Foundation. Please review the following information to ensure the GNU Lesser General Public License version 2.1 requirements will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.\" + \"Alternatively, this plugin may be used under the terms of the GNU Lesser General Public License version 2.1 or version 3 as published by the Free Software Foundation. Please review the following information to ensure the GNU Lesser General Public License requirements will be met: http://www.gnu.org/licenses/lgpl.html and http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.\" ], \"Category\" : \"Qt Creator\", \"Description\" : \"Displays Update-Infos for Qt Installer Framework-based Updaters.\", diff --git a/src/plugins/valgrind/valgrindtool.cpp b/src/plugins/valgrind/valgrindtool.cpp index 361fc9c5f5..f348288c67 100644 --- a/src/plugins/valgrind/valgrindtool.cpp +++ b/src/plugins/valgrind/valgrindtool.cpp @@ -150,7 +150,6 @@ static void startRemoteTool(IAnalyzerTool *tool) sp.workingDirectory = dlg.workingDirectory(); AnalyzerRunControl *rc = tool->createRunControl(sp, 0); - QObject::connect(AnalyzerManager::stopAction(), SIGNAL(triggered()), rc, SLOT(stopIt())); ProjectExplorerPlugin::startRunControl(rc, tool->runMode()); } diff --git a/src/plugins/vcsbase/vcsbaseplugin.cpp b/src/plugins/vcsbase/vcsbaseplugin.cpp index 2dcae7c161..55a05f66a8 100644 --- a/src/plugins/vcsbase/vcsbaseplugin.cpp +++ b/src/plugins/vcsbase/vcsbaseplugin.cpp @@ -529,6 +529,7 @@ public: QPointer<VcsBaseSubmitEditor> m_submitEditor; Core::IVersionControl *m_versionControl; + Core::Context m_context; VcsBasePluginState m_state; int m_actionState; @@ -558,9 +559,10 @@ VcsBasePlugin::~VcsBasePlugin() delete d; } -void VcsBasePlugin::initializeVcs(Core::IVersionControl *vc) +void VcsBasePlugin::initializeVcs(Core::IVersionControl *vc, const Core::Context &context) { d->m_versionControl = vc; + d->m_context = context; addAutoReleasedObject(vc); Internal::VcsPlugin *plugin = Internal::VcsPlugin::instance(); @@ -609,6 +611,7 @@ void VcsBasePlugin::slotStateChanged(const VcsBase::Internal::State &newInternal if (!d->m_state.equals(newInternalState)) { d->m_state.setState(newInternalState); updateActions(VcsEnabled); + Core::ICore::addAdditionalContext(d->m_context); } } else { // Some other VCS plugin or state changed: Reset us to empty state. @@ -619,6 +622,7 @@ void VcsBasePlugin::slotStateChanged(const VcsBase::Internal::State &newInternal d->m_state = emptyState; updateActions(newActionState); } + Core::ICore::removeAdditionalContext(d->m_context); } } @@ -632,16 +636,16 @@ bool VcsBasePlugin::enableMenuAction(ActionState as, QAction *menuAction) const if (debug) qDebug() << "enableMenuAction" << menuAction->text() << as; switch (as) { - case VcsBase::VcsBasePlugin::NoVcsEnabled: { + case NoVcsEnabled: { const bool supportsCreation = d->supportsRepositoryCreation(); menuAction->setVisible(supportsCreation); menuAction->setEnabled(supportsCreation); return supportsCreation; } - case VcsBase::VcsBasePlugin::OtherVcsEnabled: + case OtherVcsEnabled: menuAction->setVisible(false); return false; - case VcsBase::VcsBasePlugin::VcsEnabled: + case VcsEnabled: menuAction->setVisible(true); menuAction->setEnabled(true); break; diff --git a/src/plugins/vcsbase/vcsbaseplugin.h b/src/plugins/vcsbase/vcsbaseplugin.h index ecc32534b7..789a953250 100644 --- a/src/plugins/vcsbase/vcsbaseplugin.h +++ b/src/plugins/vcsbase/vcsbaseplugin.h @@ -48,6 +48,7 @@ QT_END_NAMESPACE namespace Utils { struct SynchronousProcessResponse; } namespace Core { +class Context; class IVersionControl; class Id; class IDocument; @@ -131,7 +132,7 @@ class VCSBASE_EXPORT VcsBasePlugin : public ExtensionSystem::IPlugin protected: explicit VcsBasePlugin(); - void initializeVcs(Core::IVersionControl *vc); + void initializeVcs(Core::IVersionControl *vc, const Core::Context &context); virtual void extensionsInitialized(); public: diff --git a/src/plugins/vcsbase/vcsconfigurationpage.cpp b/src/plugins/vcsbase/vcsconfigurationpage.cpp index bda344572f..81bce4a6bb 100644 --- a/src/plugins/vcsbase/vcsconfigurationpage.cpp +++ b/src/plugins/vcsbase/vcsconfigurationpage.cpp @@ -57,7 +57,7 @@ VcsConfigurationPage::VcsConfigurationPage(const Core::IVersionControl *vc, QWid QWizardPage(parent), d(new Internal::VcsConfigurationPagePrivate) { - QTC_CHECK(vc); + QTC_ASSERT(vc, return); setTitle(tr("Configuration")); setSubTitle(tr("Please configure <b>%1</b> now.").arg(vc->displayName())); diff --git a/src/plugins/welcome/welcomeplugin.cpp b/src/plugins/welcome/welcomeplugin.cpp index c4d64f6d43..0364836925 100644 --- a/src/plugins/welcome/welcomeplugin.cpp +++ b/src/plugins/welcome/welcomeplugin.cpp @@ -258,7 +258,7 @@ void WelcomeMode::initPlugins() ctx->setContextProperty(QLatin1String("pagesModel"), QVariant::fromValue(m_pluginList)); onThemeChanged(); - connect(creatorTheme(), &Theme::changed, this, &WelcomeMode::onThemeChanged); + connect(Core::ICore::instance(), &Core::ICore::themeChanged, this, &WelcomeMode::onThemeChanged); ctx->setContextProperty(QLatin1String("creatorTheme"), &m_themeProperties); QString path = resourcePath() + QLatin1String("/welcomescreen/welcomescreen.qml"); |