aboutsummaryrefslogtreecommitdiffstats
path: root/src/plugins/qtsupport
diff options
context:
space:
mode:
authordt <qtc-committer@nokia.com>2011-05-20 21:40:53 +0200
committerDaniel Teske <daniel.teske@nokia.com>2011-05-24 18:35:11 +0200
commit754be1bcfcd22e41f591ae78642605f639b075b1 (patch)
treea0f0d1f36165bacede673a13ed26904dc04f3970 /src/plugins/qtsupport
parentdcd34febabccdcb96fc7963172cba270e20aa483 (diff)
Move a lot of qmake independent classes to a new plugin qtsupport
Also adjust qmldumptool to remove the dependency on qt4project/qmlproject, by passing in the qtversion instead of figuring it out in qmldumptool. Change-Id: Ie6ac582d36bfef290313c0716b33b62fcf42630c Reviewed-on: http://codereview.qt.nokia.com/70 Reviewed-by: Qt Sanity Bot <qt_sanity_bot@ovi.com> Reviewed-by: Daniel Teske <daniel.teske@nokia.com>
Diffstat (limited to 'src/plugins/qtsupport')
-rw-r--r--src/plugins/qtsupport/QtSupport.pluginspec.in19
-rw-r--r--src/plugins/qtsupport/baseqtversion.cpp1151
-rw-r--r--src/plugins/qtsupport/baseqtversion.h260
-rw-r--r--src/plugins/qtsupport/debugginghelper.ui207
-rw-r--r--src/plugins/qtsupport/debugginghelperbuildtask.cpp261
-rw-r--r--src/plugins/qtsupport/debugginghelperbuildtask.h94
-rw-r--r--src/plugins/qtsupport/profilereader.cpp181
-rw-r--r--src/plugins/qtsupport/profilereader.h120
-rw-r--r--src/plugins/qtsupport/qmldebugginglibrary.cpp160
-rw-r--r--src/plugins/qtsupport/qmldebugginglibrary.h72
-rw-r--r--src/plugins/qtsupport/qmldumptool.cpp339
-rw-r--r--src/plugins/qtsupport/qmldumptool.h76
-rw-r--r--src/plugins/qtsupport/qmlobservertool.cpp177
-rw-r--r--src/plugins/qtsupport/qmlobservertool.h75
-rw-r--r--src/plugins/qtsupport/qtoptionspage.cpp837
-rw-r--r--src/plugins/qtsupport/qtoptionspage.h138
-rw-r--r--src/plugins/qtsupport/qtoutputformatter.cpp268
-rw-r--r--src/plugins/qtsupport/qtoutputformatter.h91
-rw-r--r--src/plugins/qtsupport/qtsupport.pri4
-rw-r--r--src/plugins/qtsupport/qtsupport.pro46
-rw-r--r--src/plugins/qtsupport/qtsupport_dependencies.pri2
-rw-r--r--src/plugins/qtsupport/qtsupport_global.h44
-rw-r--r--src/plugins/qtsupport/qtsupportconstants.h63
-rw-r--r--src/plugins/qtsupport/qtsupportplugin.cpp71
-rw-r--r--src/plugins/qtsupport/qtsupportplugin.h57
-rw-r--r--src/plugins/qtsupport/qtversionfactory.cpp102
-rw-r--r--src/plugins/qtsupport/qtversionfactory.h65
-rw-r--r--src/plugins/qtsupport/qtversioninfo.ui52
-rw-r--r--src/plugins/qtsupport/qtversionmanager.cpp927
-rw-r--r--src/plugins/qtsupport/qtversionmanager.h170
-rw-r--r--src/plugins/qtsupport/qtversionmanager.ui117
-rw-r--r--src/plugins/qtsupport/showbuildlog.ui74
32 files changed, 6320 insertions, 0 deletions
diff --git a/src/plugins/qtsupport/QtSupport.pluginspec.in b/src/plugins/qtsupport/QtSupport.pluginspec.in
new file mode 100644
index 0000000000..27c49fd590
--- /dev/null
+++ b/src/plugins/qtsupport/QtSupport.pluginspec.in
@@ -0,0 +1,19 @@
+<plugin name=\"QtSupport\" version=\"$$QTCREATOR_VERSION\" compatVersion=\"$$QTCREATOR_VERSION\">
+ <vendor>Nokia Corporation</vendor>
+ <copyright>(C) 2011 Nokia Corporation</copyright>
+ <license>
+Commercial Usage
+
+Licensees holding valid Qt Commercial licenses may use this plugin in accordance with the Qt Commercial License Agreement provided with the Software or, alternatively, in accordance with the terms contained in a written agreement between you and Nokia.
+
+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.
+ </license>
+ <category>Build Systems</category>
+ <description>Provides support code for build systems.</description>
+ <url>http://qt.nokia.com</url>
+ <dependencyList>
+ <dependency name=\"ProjectExplorer\" version=\"$$QTCREATOR_VERSION\"/>
+ </dependencyList>
+</plugin>
diff --git a/src/plugins/qtsupport/baseqtversion.cpp b/src/plugins/qtsupport/baseqtversion.cpp
new file mode 100644
index 0000000000..0d8ddf8b57
--- /dev/null
+++ b/src/plugins/qtsupport/baseqtversion.cpp
@@ -0,0 +1,1151 @@
+/**************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2011 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Nokia Corporation (info@qt.nokia.com)
+**
+**
+** GNU Lesser General Public License Usage
+**
+** 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.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** Other Usage
+**
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at info@qt.nokia.com.
+**
+**************************************************************************/
+
+#include "baseqtversion.h"
+#include "qmlobservertool.h"
+#include "qmldumptool.h"
+#include "qmldebugginglibrary.h"
+
+#include "qtversionmanager.h"
+#include "profilereader.h"
+#include <projectexplorer/toolchainmanager.h>
+#include <projectexplorer/debugginghelper.h>
+#include <projectexplorer/gnumakeparser.h>
+#include <projectexplorer/projectexplorer.h>
+#include <projectexplorer/projectexplorerconstants.h>
+#include <projectexplorer/toolchainmanager.h>
+#include <projectexplorer/persistentsettings.h>
+
+#include <utils/synchronousprocess.h>
+
+#include <QtCore/QDir>
+#include <QtCore/QFileInfo>
+#include <QtCore/QCoreApplication>
+#include <QtCore/QProcess>
+
+using namespace QtSupport;
+using namespace QtSupport::Internal;
+
+static const char QTVERSIONID[] = "Id";
+static const char QTVERSIONNAME[] = "Name";
+static const char QTVERSIONAUTODETECTED[] = "isAutodetected";
+static const char QTVERSIONAUTODETECTIONSOURCE []= "autodetectionSource";
+static const char QTVERSIONQMAKEPATH[] = "QMakePath";
+
+///////////////
+// QtVersionNumber
+///////////////
+QtVersionNumber::QtVersionNumber(int ma, int mi, int p)
+ : majorVersion(ma), minorVersion(mi), patchVersion(p)
+{
+}
+
+QtVersionNumber::QtVersionNumber(const QString &versionString)
+{
+ if (!checkVersionString(versionString)) {
+ majorVersion = minorVersion = patchVersion = -1;
+ return;
+ }
+
+ QStringList parts = versionString.split(QLatin1Char('.'));
+ majorVersion = parts.at(0).toInt();
+ minorVersion = parts.at(1).toInt();
+ patchVersion = parts.at(2).toInt();
+}
+
+QtVersionNumber::QtVersionNumber()
+{
+ majorVersion = minorVersion = patchVersion = -1;
+}
+
+bool QtVersionNumber::checkVersionString(const QString &version) const
+{
+ int dots = 0;
+ QString validChars = "0123456789.";
+ foreach (const QChar &c, version) {
+ if (!validChars.contains(c))
+ return false;
+ if (c == '.')
+ ++dots;
+ }
+ if (dots != 2)
+ return false;
+ return true;
+}
+
+bool QtVersionNumber::operator <(const QtVersionNumber &b) const
+{
+ if (majorVersion < b.majorVersion)
+ return true;
+ if (majorVersion > b.majorVersion)
+ return false;
+ if (minorVersion < b.minorVersion)
+ return true;
+ if (minorVersion > b.minorVersion)
+ return false;
+ if (patchVersion < b.patchVersion)
+ return true;
+ return false;
+}
+
+bool QtVersionNumber::operator >(const QtVersionNumber &b) const
+{
+ return b < *this;
+}
+
+bool QtVersionNumber::operator ==(const QtVersionNumber &b) const
+{
+ return majorVersion == b.majorVersion
+ && minorVersion == b.minorVersion
+ && patchVersion == b.patchVersion;
+}
+
+bool QtVersionNumber::operator !=(const QtVersionNumber &b) const
+{
+ return !(*this == b);
+}
+
+bool QtVersionNumber::operator <=(const QtVersionNumber &b) const
+{
+ return !(*this > b);
+}
+
+bool QtVersionNumber::operator >=(const QtVersionNumber &b) const
+{
+ return b <= *this;
+}
+
+///////////////
+// QtConfigWidget
+///////////////
+QtConfigWidget::QtConfigWidget()
+{
+
+}
+
+///////////////
+// BaseQtVersion
+///////////////
+int BaseQtVersion::getUniqueId()
+{
+ return QtVersionManager::instance()->getUniqueId();
+}
+
+BaseQtVersion::BaseQtVersion(const QString &qmakeCommand, bool isAutodetected, const QString &autodetectionSource)
+ : m_id(getUniqueId()),
+ m_isAutodetected(isAutodetected),
+ m_autodetectionSource(autodetectionSource),
+ m_hasDebuggingHelper(false),
+ m_hasQmlDump(false),
+ m_hasQmlDebuggingLibrary(false),
+ m_hasQmlObserver(false),
+ m_mkspecUpToDate(false),
+ m_mkspecReadUpToDate(false),
+ m_defaultConfigIsDebug(true),
+ m_defaultConfigIsDebugAndRelease(true),
+ m_versionInfoUpToDate(false),
+ m_notInstalled(false),
+ m_hasExamples(false),
+ m_hasDemos(false),
+ m_hasDocumentation(false),
+ m_qmakeIsExecutable(false)
+{
+ ctor(qmakeCommand);
+ setDisplayName(defaultDisplayName(qtVersionString(), qmakeCommand, false));
+}
+
+BaseQtVersion::BaseQtVersion()
+ : m_id(-1), m_isAutodetected(false),
+ m_hasDebuggingHelper(false),
+ m_hasQmlDump(false),
+ m_hasQmlDebuggingLibrary(false),
+ m_hasQmlObserver(false),
+ m_mkspecUpToDate(false),
+ m_mkspecReadUpToDate(false),
+ m_defaultConfigIsDebug(true),
+ m_defaultConfigIsDebugAndRelease(true),
+ m_versionInfoUpToDate(false),
+ m_notInstalled(false),
+ m_hasExamples(false),
+ m_hasDemos(false),
+ m_hasDocumentation(false)
+{
+ ctor(QString());
+}
+
+void BaseQtVersion::ctor(const QString& qmakePath)
+{
+ m_qmakeCommand = QDir::fromNativeSeparators(qmakePath);
+#ifdef Q_OS_WIN
+ m_qmakeCommand = m_qmakeCommand.toLower();
+#endif
+ m_designerCommand.clear();
+ m_linguistCommand.clear();
+ m_qmlviewerCommand.clear();
+ m_uicCommand.clear();
+ m_mkspecUpToDate = false;
+ m_mkspecReadUpToDate = false;
+ m_versionInfoUpToDate = false;
+ m_qtVersionString.clear();
+ m_sourcePath.clear();
+}
+
+BaseQtVersion::~BaseQtVersion()
+{
+}
+
+QString BaseQtVersion::defaultDisplayName(const QString &versionString, const QString &qmakePath,
+ bool fromPath)
+{
+ QString location;
+ if (qmakePath.isEmpty()) {
+ location = QCoreApplication::translate("QtVersion", "<unknown>");
+ } else {
+ // Deduce a description from '/foo/qt-folder/[qtbase]/bin/qmake' -> '/foo/qt-folder'.
+ // '/usr' indicates System Qt 4.X on Linux.
+ QDir dir = QFileInfo(qmakePath).absoluteDir();
+ do {
+ const QString dirName = dir.dirName();
+ if (dirName == QLatin1String("usr")) { // System-installed Qt.
+ location = QCoreApplication::translate("QtVersion", "System");
+ break;
+ }
+ if (dirName.compare(QLatin1String("bin"), Qt::CaseInsensitive)
+ && dirName.compare(QLatin1String("qtbase"), Qt::CaseInsensitive)) {
+ location = dirName;
+ break;
+ }
+ } while (dir.cdUp());
+ }
+
+ return fromPath ?
+ QCoreApplication::translate("QtVersion", "Qt %1 in PATH (%2)").arg(versionString, location) :
+ QCoreApplication::translate("QtVersion", "Qt %1 (%2)").arg(versionString, location);
+}
+
+void BaseQtVersion::setId(int id)
+{
+ m_id = id;
+}
+
+void BaseQtVersion::restoreLegacySettings(QSettings *s)
+{
+ Q_UNUSED(s);
+}
+
+void BaseQtVersion::fromMap(const QVariantMap &map)
+{
+ m_id = map.value(QLatin1String(QTVERSIONID)).toInt();
+ if (m_id == -1) // this happens on adding from installer, see updateFromInstaller => get a new unique id
+ m_id = QtVersionManager::instance()->getUniqueId();
+ m_displayName = map.value(QLatin1String(QTVERSIONNAME)).toString();
+ m_isAutodetected = map.value(QLatin1String(QTVERSIONAUTODETECTED)).toBool();
+ if (m_isAutodetected)
+ m_autodetectionSource = map.value(QLatin1String(QTVERSIONAUTODETECTIONSOURCE)).toString();
+ ctor(map.value(QLatin1String(QTVERSIONQMAKEPATH)).toString());
+}
+
+QVariantMap BaseQtVersion::toMap() const
+{
+ QVariantMap result;
+ result.insert(QLatin1String(QTVERSIONID), uniqueId());
+ result.insert(QLatin1String(QTVERSIONNAME), displayName());
+ result.insert(QLatin1String(QTVERSIONAUTODETECTED), isAutodetected());
+ if (isAutodetected())
+ result.insert(QLatin1String(QTVERSIONAUTODETECTIONSOURCE), autodetectionSource());
+ result.insert(QLatin1String(QTVERSIONQMAKEPATH), qmakeCommand());
+ return result;
+}
+
+bool BaseQtVersion::isValid() const
+{
+ if (uniqueId() == -1 || displayName().isEmpty())
+ return false;
+ updateVersionInfo();
+ updateMkspec();
+
+ return !qmakeCommand().isEmpty()
+ && !m_notInstalled
+ && m_versionInfo.contains("QT_INSTALL_BINS")
+ && (!m_mkspecFullPath.isEmpty() || !m_mkspecUpToDate)
+ && m_qmakeIsExecutable;
+}
+
+QString BaseQtVersion::invalidReason() const
+{
+ if (displayName().isEmpty())
+ return QCoreApplication::translate("QtVersion", "Qt version has no name");
+ if (qmakeCommand().isEmpty())
+ return QCoreApplication::translate("QtVersion", "No qmake path set");
+ if (!m_qmakeIsExecutable)
+ return QCoreApplication::translate("QtVersion", "qmake does not exist or is not executable");
+ if (m_notInstalled)
+ return QCoreApplication::translate("QtVersion", "Qt version is not properly installed, please run make install");
+ if (!m_versionInfo.contains("QT_INSTALL_BINS"))
+ return QCoreApplication::translate("QtVersion",
+ "Could not determine the path to the binaries of the Qt installation, maybe the qmake path is wrong?");
+ if (m_mkspecUpToDate && m_mkspecFullPath.isEmpty())
+ return QCoreApplication::translate("QtVersion", "The default mkspec symlink is broken.");
+ return QString();
+}
+
+QString BaseQtVersion::qmakeCommand() const
+{
+ return m_qmakeCommand;
+}
+
+bool BaseQtVersion::toolChainAvailable(const QString &id) const
+{
+ Q_UNUSED(id)
+ if (!isValid())
+ return false;
+ foreach (const ProjectExplorer::Abi &abi, qtAbis())
+ if (!ProjectExplorer::ToolChainManager::instance()->findToolChains(abi).isEmpty())
+ return true;
+ return false;
+}
+
+bool BaseQtVersion::equals(BaseQtVersion *other)
+{
+ if (type() != other->type())
+ return false;
+ if (uniqueId() != other->uniqueId())
+ return false;
+ if (displayName() != other->displayName())
+ return false;
+
+ return true;
+}
+
+int BaseQtVersion::uniqueId() const
+{
+ return m_id;
+}
+
+bool BaseQtVersion::isAutodetected() const
+{
+ return m_isAutodetected;
+}
+
+QString BaseQtVersion::autodetectionSource() const
+{
+ return m_autodetectionSource;
+}
+
+void BaseQtVersion::setAutoDetectionSource(const QString &autodetectionSource)
+{
+ m_autodetectionSource = autodetectionSource;
+}
+
+QString BaseQtVersion::displayName() const
+{
+ return m_displayName;
+}
+
+void BaseQtVersion::setDisplayName(const QString &name)
+{
+ m_displayName = name;
+}
+
+QString BaseQtVersion::toHtml(bool verbose) const
+{
+ QString rc;
+ QTextStream str(&rc);
+ str << "<html><body><table>";
+ str << "<tr><td><b>" << QCoreApplication::translate("BaseQtVersion", "Name:")
+ << "</b></td><td>" << displayName() << "</td></tr>";
+ if (!isValid()) {
+ str << "<tr><td colspan=2><b>" + QCoreApplication::translate("BaseQtVersion", "Invalid Qt version") +"</b></td></tr>";
+ } else {
+ QString prefix = QLatin1String("<tr><td><b>") + QCoreApplication::translate("BaseQtVersion", "ABI:") + QLatin1String("</b></td>");
+ foreach (const ProjectExplorer::Abi &abi, qtAbis()) {
+ str << prefix << "<td>" << abi.toString() << "</td></tr>";
+ prefix = QLatin1String("<tr><td></td>");
+ }
+ str << "<tr><td><b>" << QCoreApplication::translate("BaseQtVersion", "Source:")
+ << "</b></td><td>" << sourcePath() << "</td></tr>";
+ str << "<tr><td><b>" << QCoreApplication::translate("BaseQtVersion", "mkspec:")
+ << "</b></td><td>" << mkspec() << "</td></tr>";
+ str << "<tr><td><b>" << QCoreApplication::translate("BaseQtVersion", "qmake:")
+ << "</b></td><td>" << m_qmakeCommand << "</td></tr>";
+ ensureMkSpecParsed();
+ if (!mkspecPath().isEmpty()) {
+ if (m_defaultConfigIsDebug || m_defaultConfigIsDebugAndRelease) {
+ str << "<tr><td><b>" << QCoreApplication::translate("BaseQtVersion", "Default:") << "</b></td><td>"
+ << (m_defaultConfigIsDebug ? "debug" : "release");
+ if (m_defaultConfigIsDebugAndRelease)
+ str << " debug_and_release";
+ str << "</td></tr>";
+ } // default config.
+ }
+ str << "<tr><td><b>" << QCoreApplication::translate("BaseQtVersion", "Version:")
+ << "</b></td><td>" << qtVersionString() << "</td></tr>";
+ if (verbose) {
+ const QHash<QString,QString> vInfo = versionInfo();
+ if (!vInfo.isEmpty()) {
+ const QHash<QString,QString>::const_iterator vcend = vInfo.constEnd();
+ for (QHash<QString,QString>::const_iterator it = vInfo.constBegin(); it != vcend; ++it)
+ str << "<tr><td><pre>" << it.key() << "</pre></td><td>" << it.value() << "</td></tr>";
+ }
+ }
+ }
+ str << "</table></body></html>";
+ return rc;
+}
+
+void BaseQtVersion::updateSourcePath() const
+{
+ if (!m_sourcePath.isEmpty())
+ return;
+ updateVersionInfo();
+ const QString installData = m_versionInfo["QT_INSTALL_DATA"];
+ m_sourcePath = installData;
+ QFile qmakeCache(installData + QLatin1String("/.qmake.cache"));
+ if (qmakeCache.exists()) {
+ qmakeCache.open(QIODevice::ReadOnly | QIODevice::Text);
+ QTextStream stream(&qmakeCache);
+ while (!stream.atEnd()) {
+ QString line = stream.readLine().trimmed();
+ if (line.startsWith(QLatin1String("QT_SOURCE_TREE"))) {
+ m_sourcePath = line.split(QLatin1Char('=')).at(1).trimmed();
+ if (m_sourcePath.startsWith(QLatin1String("$$quote("))) {
+ m_sourcePath.remove(0, 8);
+ m_sourcePath.chop(1);
+ }
+ break;
+ }
+ }
+ }
+ m_sourcePath = QDir::cleanPath(m_sourcePath);
+#ifdef Q_OS_WIN
+ m_sourcePath = m_sourcePath.toLower();
+#endif
+}
+
+QString BaseQtVersion::sourcePath() const
+{
+ updateSourcePath();
+ return m_sourcePath;
+}
+
+// Return a list of GUI binary names
+// 'foo', 'foo.exe', 'Foo.app/Contents/MacOS/Foo'
+static inline QStringList possibleGuiBinaries(const QString &name)
+{
+#ifdef Q_OS_WIN
+ return QStringList(name + QLatin1String(".exe"));
+#elif defined(Q_OS_MAC) // 'Foo.app/Contents/MacOS/Foo'
+ QString upCaseName = name;
+ upCaseName[0] = upCaseName.at(0).toUpper();
+ QString macBinary = upCaseName;
+ macBinary += QLatin1String(".app/Contents/MacOS/");
+ macBinary += upCaseName;
+ return QStringList(macBinary);
+#else
+ return QStringList(name);
+#endif
+}
+
+QString BaseQtVersion::designerCommand() const
+{
+ if (!isValid())
+ return QString();
+ if (m_designerCommand.isNull())
+ m_designerCommand = findQtBinary(possibleGuiBinaries(QLatin1String("designer")));
+ return m_designerCommand;
+}
+
+QString BaseQtVersion::linguistCommand() const
+{
+ if (!isValid())
+ return QString();
+ if (m_linguistCommand.isNull())
+ m_linguistCommand = findQtBinary(possibleGuiBinaries(QLatin1String("linguist")));
+ return m_linguistCommand;
+}
+
+QString BaseQtVersion::qmlviewerCommand() const
+{
+ if (!isValid())
+ return QString();
+
+ if (m_qmlviewerCommand.isNull()) {
+#ifdef Q_OS_MAC
+ const QString qmlViewerName = QLatin1String("QMLViewer");
+#else
+ const QString qmlViewerName = QLatin1String("qmlviewer");
+#endif
+
+ m_qmlviewerCommand = findQtBinary(possibleGuiBinaries(qmlViewerName));
+ }
+ return m_qmlviewerCommand;
+}
+
+QString BaseQtVersion::findQtBinary(const QStringList &possibleCommands) const
+{
+ QString qtdirbin = versionInfo().value(QLatin1String("QT_INSTALL_BINS"));
+ if (qtdirbin.isEmpty())
+ return QString();
+ qtdirbin += QLatin1Char('/');
+
+ foreach (const QString &possibleCommand, possibleCommands) {
+ const QString fullPath = qtdirbin + possibleCommand;
+ if (QFileInfo(fullPath).isFile())
+ return QDir::cleanPath(fullPath);
+ }
+ return QString();
+}
+
+QString BaseQtVersion::uicCommand() const
+{
+ if (!isValid())
+ return QString();
+ if (!m_uicCommand.isNull())
+ return m_uicCommand;
+#ifdef Q_OS_WIN
+ const QStringList possibleCommands(QLatin1String("uic.exe"));
+#else
+ QStringList possibleCommands;
+ possibleCommands << QLatin1String("uic-qt4") << QLatin1String("uic4") << QLatin1String("uic");
+#endif
+ m_uicCommand = findQtBinary(possibleCommands);
+ return m_uicCommand;
+}
+
+QString BaseQtVersion::systemRoot() const
+{
+ return QString();
+}
+
+void BaseQtVersion::updateMkspec() const
+{
+ if (uniqueId() == -1 || m_mkspecUpToDate)
+ return;
+
+ m_mkspecUpToDate = true;
+ m_mkspecFullPath = mkspecFromVersionInfo(versionInfo());
+
+ m_mkspec = m_mkspecFullPath;
+ if (m_mkspecFullPath.isEmpty())
+ return;
+
+ QString baseMkspecDir = versionInfo().value("QMAKE_MKSPECS");
+ if (baseMkspecDir.isEmpty())
+ baseMkspecDir = versionInfo().value("QT_INSTALL_DATA") + "/mkspecs";
+
+#ifdef Q_OS_WIN
+ baseMkspecDir = baseMkspecDir.toLower();
+#endif
+
+ if (m_mkspec.startsWith(baseMkspecDir)) {
+ m_mkspec = m_mkspec.mid(baseMkspecDir.length() + 1);
+// qDebug() << "Setting mkspec to"<<mkspec;
+ } else {
+ QString sourceMkSpecPath = sourcePath() + "/mkspecs";
+ if (m_mkspec.startsWith(sourceMkSpecPath)) {
+ m_mkspec = m_mkspec.mid(sourceMkSpecPath.length() + 1);
+ } else {
+ // Do nothing
+ }
+ }
+}
+
+void BaseQtVersion::ensureMkSpecParsed() const
+{
+ if (m_mkspecReadUpToDate)
+ return;
+ m_mkspecReadUpToDate = true;
+
+ if (mkspecPath().isEmpty())
+ return;
+
+ ProFileOption option;
+ option.properties = versionInfo();
+ ProMessageHandler msgHandler(true);
+ ProFileCacheManager::instance()->incRefCount();
+ ProFileParser parser(ProFileCacheManager::instance()->cache(), &msgHandler);
+ ProFileEvaluator evaluator(&option, &parser, &msgHandler);
+ if (ProFile *pro = parser.parsedProFile(mkspecPath() + "/qmake.conf")) {
+ evaluator.setCumulative(false);
+ evaluator.accept(pro, ProFileEvaluator::LoadProOnly);
+ pro->deref();
+ }
+
+ parseMkSpec(&evaluator);
+
+ ProFileCacheManager::instance()->decRefCount();
+}
+
+void BaseQtVersion::parseMkSpec(ProFileEvaluator *evaluator) const
+{
+ QStringList configValues = evaluator->values("CONFIG");
+ m_defaultConfigIsDebugAndRelease = false;
+ foreach (const QString &value, configValues) {
+ if (value == "debug")
+ m_defaultConfigIsDebug = true;
+ else if (value == "release")
+ m_defaultConfigIsDebug = false;
+ else if (value == "build_all")
+ m_defaultConfigIsDebugAndRelease = true;
+ }
+}
+
+QString BaseQtVersion::mkspec() const
+{
+ updateMkspec();
+ return m_mkspec;
+}
+
+QString BaseQtVersion::mkspecPath() const
+{
+ updateMkspec();
+ return m_mkspecFullPath;
+}
+
+bool BaseQtVersion::hasMkspec(const QString &spec) const
+{
+ updateVersionInfo();
+ QFileInfo fi;
+ fi.setFile(QDir::fromNativeSeparators(m_versionInfo.value("QMAKE_MKSPECS")) + '/' + spec);
+ if (fi.isDir())
+ return true;
+ fi.setFile(sourcePath() + QLatin1String("/mkspecs/") + spec);
+ return fi.isDir();
+}
+
+BaseQtVersion::QmakeBuildConfigs BaseQtVersion::defaultBuildConfig() const
+{
+ ensureMkSpecParsed();
+ BaseQtVersion::QmakeBuildConfigs result = BaseQtVersion::QmakeBuildConfig(0);
+
+ if (m_defaultConfigIsDebugAndRelease)
+ result = BaseQtVersion::BuildAll;
+ if (m_defaultConfigIsDebug)
+ result = result | BaseQtVersion::DebugBuild;
+ return result;
+}
+
+QString BaseQtVersion::qtVersionString() const
+{
+ if (m_qtVersionString.isNull()) {
+ QFileInfo qmake(m_qmakeCommand);
+ if (qmake.exists() && qmake.isExecutable())
+ m_qtVersionString = ProjectExplorer::DebuggingHelperLibrary::qtVersionForQMake(qmake.absoluteFilePath());
+ else
+ m_qtVersionString = QLatin1String("");
+ }
+ return m_qtVersionString;
+}
+
+QtVersionNumber BaseQtVersion::qtVersion() const
+{
+ return QtVersionNumber(qtVersionString());
+}
+
+void BaseQtVersion::updateVersionInfo() const
+{
+ if (m_versionInfoUpToDate)
+ return;
+
+ // extract data from qmake executable
+ m_versionInfo.clear();
+ m_notInstalled = false;
+ m_hasExamples = false;
+ m_hasDocumentation = false;
+ m_hasDebuggingHelper = false;
+ m_hasQmlDump = false;
+ m_hasQmlDebuggingLibrary = false;
+ m_hasQmlObserver = false;
+
+ m_qmakeIsExecutable = true;
+
+ QFileInfo fi(qmakeCommand());
+ if (!fi.exists() || !fi.isExecutable() || fi.isDir()) {
+ m_qmakeIsExecutable = false;
+ return;
+ }
+
+ if (!queryQMakeVariables(qmakeCommand(), &m_versionInfo))
+ return;
+
+ if (m_versionInfo.contains("QT_INSTALL_DATA")) {
+ QString qtInstallData = m_versionInfo.value("QT_INSTALL_DATA");
+ QString qtHeaderData = m_versionInfo.value("QT_INSTALL_HEADERS");
+ m_versionInfo.insert("QMAKE_MKSPECS", QDir::cleanPath(qtInstallData+"/mkspecs"));
+
+ if (!qtInstallData.isEmpty()) {
+ m_hasDebuggingHelper = !ProjectExplorer::DebuggingHelperLibrary::debuggingHelperLibraryByInstallData(qtInstallData).isEmpty();
+ m_hasQmlDump
+ = !QmlDumpTool::toolByInstallData(qtInstallData, qtHeaderData, false).isEmpty()
+ || !QmlDumpTool::toolByInstallData(qtInstallData, qtHeaderData, true).isEmpty();
+ m_hasQmlDebuggingLibrary
+ = !QmlDebuggingLibrary::libraryByInstallData(qtInstallData, false).isEmpty()
+ || !QmlDebuggingLibrary::libraryByInstallData(qtInstallData, true).isEmpty();
+ m_hasQmlObserver = !QmlObserverTool::toolByInstallData(qtInstallData).isEmpty();
+ }
+ }
+
+ // Now check for a qt that is configured with a prefix but not installed
+ if (m_versionInfo.contains("QT_INSTALL_BINS")) {
+ QFileInfo fi(m_versionInfo.value("QT_INSTALL_BINS"));
+ if (!fi.exists())
+ m_notInstalled = true;
+ }
+ if (m_versionInfo.contains("QT_INSTALL_HEADERS")){
+ QFileInfo fi(m_versionInfo.value("QT_INSTALL_HEADERS"));
+ if (!fi.exists())
+ m_notInstalled = true;
+ }
+ if (m_versionInfo.contains("QT_INSTALL_DOCS")){
+ QFileInfo fi(m_versionInfo.value("QT_INSTALL_DOCS"));
+ if (fi.exists())
+ m_hasDocumentation = true;
+ }
+ if (m_versionInfo.contains("QT_INSTALL_EXAMPLES")){
+ QFileInfo fi(m_versionInfo.value("QT_INSTALL_EXAMPLES"));
+ if (fi.exists())
+ m_hasExamples = true;
+ }
+ if (m_versionInfo.contains("QT_INSTALL_DEMOS")){
+ QFileInfo fi(m_versionInfo.value("QT_INSTALL_DEMOS"));
+ if (fi.exists())
+ m_hasDemos = true;
+ }
+
+ m_versionInfoUpToDate = true;
+}
+
+QHash<QString,QString> BaseQtVersion::versionInfo() const
+{
+ updateVersionInfo();
+ return m_versionInfo;
+}
+
+bool BaseQtVersion::hasDocumentation() const
+{
+ updateVersionInfo();
+ return m_hasDocumentation;
+}
+
+QString BaseQtVersion::documentationPath() const
+{
+ updateVersionInfo();
+ return m_versionInfo["QT_INSTALL_DOCS"];
+}
+
+bool BaseQtVersion::hasDemos() const
+{
+ updateVersionInfo();
+ return m_hasDemos;
+}
+
+QString BaseQtVersion::demosPath() const
+{
+ updateVersionInfo();
+ return m_versionInfo["QT_INSTALL_DEMOS"];
+}
+
+QString BaseQtVersion::frameworkInstallPath() const
+{
+#ifdef Q_OS_MAC
+ updateVersionInfo();
+ return m_versionInfo["QT_INSTALL_LIBS"];
+#else
+ return QString();
+#endif
+}
+
+bool BaseQtVersion::hasExamples() const
+{
+ updateVersionInfo();
+ return m_hasExamples;
+}
+
+QString BaseQtVersion::examplesPath() const
+{
+ updateVersionInfo();
+ return m_versionInfo["QT_INSTALL_EXAMPLES"];
+}
+
+QList<ProjectExplorer::HeaderPath> BaseQtVersion::systemHeaderPathes() const
+{
+ QList<ProjectExplorer::HeaderPath> result;
+ result.append(ProjectExplorer::HeaderPath(mkspecPath(), ProjectExplorer::HeaderPath::GlobalHeaderPath));
+ return result;
+}
+
+void BaseQtVersion::addToEnvironment(Utils::Environment &env) const
+{
+ env.set("QTDIR", QDir::toNativeSeparators(versionInfo().value("QT_INSTALL_DATA")));
+ env.prependOrSetPath(versionInfo().value("QT_INSTALL_BINS"));
+ env.prependOrSetLibrarySearchPath(versionInfo().value("QT_INSTALL_LIBS"));
+}
+
+bool BaseQtVersion::hasGdbDebuggingHelper() const
+{
+ updateVersionInfo();
+ return m_hasDebuggingHelper;
+}
+
+
+bool BaseQtVersion::hasQmlDump() const
+{
+ updateVersionInfo();
+ return m_hasQmlDump;
+}
+
+bool BaseQtVersion::hasQmlDebuggingLibrary() const
+{
+ updateVersionInfo();
+ return m_hasQmlDebuggingLibrary;
+}
+
+bool BaseQtVersion::needsQmlDebuggingLibrary() const
+{
+ updateVersionInfo();
+ return qtVersion() < QtVersionNumber(4, 8, 0);
+}
+
+bool BaseQtVersion::hasQmlObserver() const
+{
+ updateVersionInfo();
+ return m_hasQmlObserver;
+}
+
+Utils::Environment BaseQtVersion::qmlToolsEnvironment() const
+{
+ // FIXME: This seems broken!
+ Utils::Environment environment = Utils::Environment::systemEnvironment();
+ addToEnvironment(environment);
+
+ // add preferred tool chain, as that is how the tools are built, compare QtVersion::buildDebuggingHelperLibrary
+ QList<ProjectExplorer::ToolChain *> alltc =
+ ProjectExplorer::ToolChainManager::instance()->findToolChains(qtAbis().at(0));
+ if (!alltc.isEmpty())
+ alltc.first()->addToEnvironment(environment);
+
+ return environment;
+}
+
+QString BaseQtVersion::gdbDebuggingHelperLibrary() const
+{
+ QString qtInstallData = versionInfo().value("QT_INSTALL_DATA");
+ if (qtInstallData.isEmpty())
+ return QString();
+ return ProjectExplorer::DebuggingHelperLibrary::debuggingHelperLibraryByInstallData(qtInstallData);
+}
+
+QString BaseQtVersion::qmlDumpTool(bool debugVersion) const
+{
+ QString qtInstallData = versionInfo().value("QT_INSTALL_DATA");
+ QString qtHeaderData = versionInfo().value("QT_INSTALL_HEADERS");
+ if (qtInstallData.isEmpty())
+ return QString();
+ return QmlDumpTool::toolByInstallData(qtInstallData, qtHeaderData, debugVersion);
+}
+
+QString BaseQtVersion::qmlDebuggingHelperLibrary(bool debugVersion) const
+{
+ QString qtInstallData = versionInfo().value("QT_INSTALL_DATA");
+ if (qtInstallData.isEmpty())
+ return QString();
+ return QmlDebuggingLibrary::libraryByInstallData(qtInstallData, debugVersion);
+}
+
+QString BaseQtVersion::qmlObserverTool() const
+{
+ QString qtInstallData = versionInfo().value("QT_INSTALL_DATA");
+ if (qtInstallData.isEmpty())
+ return QString();
+ return QmlObserverTool::toolByInstallData(qtInstallData);
+}
+
+QStringList BaseQtVersion::debuggingHelperLibraryLocations() const
+{
+ QString qtInstallData = versionInfo().value("QT_INSTALL_DATA");
+ if (qtInstallData.isEmpty())
+ return QStringList();
+ return ProjectExplorer::DebuggingHelperLibrary::locationsByInstallData(qtInstallData);
+}
+
+bool BaseQtVersion::supportsBinaryDebuggingHelper() const
+{
+ if (!isValid())
+ return false;
+ return true;
+}
+
+void BaseQtVersion::recheckDumper()
+{
+ m_versionInfoUpToDate = false;
+}
+
+bool BaseQtVersion::supportsShadowBuilds() const
+{
+ return true;
+}
+
+QList<ProjectExplorer::Task> BaseQtVersion::reportIssuesImpl(const QString &proFile, const QString &buildDir)
+{
+ QList<ProjectExplorer::Task> results;
+
+ QString tmpBuildDir = QDir(buildDir).absolutePath();
+ if (!tmpBuildDir.endsWith(QLatin1Char('/')))
+ tmpBuildDir.append(QLatin1Char('/'));
+
+ if (!isValid()) {
+ //: %1: Reason for being invalid
+ const QString msg = QCoreApplication::translate("Qt4ProjectManager::QtVersion", "The Qt version is invalid: %1").arg(invalidReason());
+ results.append(ProjectExplorer::Task(ProjectExplorer::Task::Error, msg, QString(), -1,
+ QLatin1String(ProjectExplorer::Constants::TASK_CATEGORY_BUILDSYSTEM)));
+ }
+
+ QFileInfo qmakeInfo(qmakeCommand());
+ if (!qmakeInfo.exists() ||
+ !qmakeInfo.isExecutable()) {
+ //: %1: Path to qmake executable
+ const QString msg = QCoreApplication::translate("Qt4ProjectManager::QtVersion",
+ "The qmake command \"%1\" was not found or is not executable.").arg(qmakeCommand());
+ results.append(ProjectExplorer::Task(ProjectExplorer::Task::Error, msg, QString(), -1,
+ QLatin1String(ProjectExplorer::Constants::TASK_CATEGORY_BUILDSYSTEM)));
+ }
+
+ QString sourcePath = QFileInfo(proFile).absolutePath();
+ if (!sourcePath.endsWith(QLatin1Char('/')))
+ sourcePath.append(QLatin1Char('/'));
+ if ((tmpBuildDir.startsWith(sourcePath)) && (tmpBuildDir != sourcePath)) {
+ const QString msg = QCoreApplication::translate("Qt4ProjectManager::QtVersion",
+ "Qmake does not support build directories below the source directory.");
+ results.append(ProjectExplorer::Task(ProjectExplorer::Task::Warning, msg, QString(), -1,
+ QLatin1String(ProjectExplorer::Constants::TASK_CATEGORY_BUILDSYSTEM)));
+ } else if (tmpBuildDir.count(QChar('/')) != sourcePath.count(QChar('/'))) {
+ const QString msg = QCoreApplication::translate("Qt4ProjectManager::QtVersion",
+ "The build directory needs to be at the same level as the source directory.");
+
+ results.append(ProjectExplorer::Task(ProjectExplorer::Task::Warning, msg, QString(), -1,
+ QLatin1String(ProjectExplorer::Constants::TASK_CATEGORY_BUILDSYSTEM)));
+ }
+
+ return results;
+}
+
+QList<ProjectExplorer::Task>
+BaseQtVersion::reportIssues(const QString &proFile, const QString &buildDir)
+{
+ QList<ProjectExplorer::Task> results = reportIssuesImpl(proFile, buildDir);
+ qSort(results);
+ return results;
+}
+
+ProjectExplorer::IOutputParser *BaseQtVersion::createOutputParser() const
+{
+ return new ProjectExplorer::GnuMakeParser;
+}
+
+QtConfigWidget *BaseQtVersion::createConfigurationWidget() const
+{
+ return 0;
+}
+
+bool BaseQtVersion::queryQMakeVariables(const QString &binary, QHash<QString, QString> *versionInfo)
+{
+ const int timeOutMS = 30000; // Might be slow on some machines.
+ QFileInfo qmake(binary);
+ if (!qmake.exists() || !qmake.isExecutable() || qmake.isDir())
+ return false;
+ static const char * const variables[] = {
+ "QT_VERSION",
+ "QT_INSTALL_DATA",
+ "QT_INSTALL_LIBS",
+ "QT_INSTALL_HEADERS",
+ "QT_INSTALL_DEMOS",
+ "QT_INSTALL_EXAMPLES",
+ "QT_INSTALL_CONFIGURATION",
+ "QT_INSTALL_TRANSLATIONS",
+ "QT_INSTALL_PLUGINS",
+ "QT_INSTALL_BINS",
+ "QT_INSTALL_DOCS",
+ "QT_INSTALL_PREFIX",
+ "QT_INSTALL_IMPORTS",
+ "QMAKEFEATURES"
+ };
+ QStringList args;
+ for (uint i = 0; i < sizeof variables / sizeof variables[0]; ++i)
+ args << "-query" << variables[i];
+ QProcess process;
+ process.start(qmake.absoluteFilePath(), args, QIODevice::ReadOnly);
+ if (!process.waitForStarted()) {
+ qWarning("Cannot start '%s': %s", qPrintable(binary), qPrintable(process.errorString()));
+ return false;
+ }
+ if (!process.waitForFinished(timeOutMS)) {
+ Utils::SynchronousProcess::stopProcess(process);
+ qWarning("Timeout running '%s' (%dms).", qPrintable(binary), timeOutMS);
+ return false;
+ }
+ if (process.exitStatus() != QProcess::NormalExit) {
+ qWarning("'%s' crashed.", qPrintable(binary));
+ return false;
+ }
+ QByteArray output = process.readAllStandardOutput();
+ QTextStream stream(&output);
+ while (!stream.atEnd()) {
+ const QString line = stream.readLine();
+ const int index = line.indexOf(QLatin1Char(':'));
+ if (index != -1) {
+ const QString value = QDir::fromNativeSeparators(line.mid(index+1));
+ if (value != "**Unknown**")
+ versionInfo->insert(line.left(index), value);
+ }
+ }
+ return true;
+}
+
+QString BaseQtVersion::mkspecFromVersionInfo(const QHash<QString, QString> &versionInfo)
+{
+ QString baseMkspecDir = versionInfo.value("QMAKE_MKSPECS");
+ if (baseMkspecDir.isEmpty())
+ baseMkspecDir = versionInfo.value("QT_INSTALL_DATA") + "/mkspecs";
+ if (baseMkspecDir.isEmpty())
+ return QString();
+
+#ifdef Q_OS_WIN
+ baseMkspecDir = baseMkspecDir.toLower();
+#endif
+
+ QString mkspecFullPath = baseMkspecDir + "/default";
+
+ // qDebug() << "default mkspec is located at" << mkspecFullPath;
+
+#ifdef Q_OS_WIN
+ QFile f2(mkspecFullPath + "/qmake.conf");
+ if (f2.exists() && f2.open(QIODevice::ReadOnly)) {
+ while (!f2.atEnd()) {
+ QByteArray line = f2.readLine();
+ if (line.startsWith("QMAKESPEC_ORIGINAL")) {
+ const QList<QByteArray> &temp = line.split('=');
+ if (temp.size() == 2) {
+ QString possibleFullPath = temp.at(1).trimmed();
+ // We sometimes get a mix of different slash styles here...
+ possibleFullPath = possibleFullPath.replace('\\', '/');
+ if (QFileInfo(possibleFullPath).exists()) // Only if the path exists
+ mkspecFullPath = possibleFullPath;
+ }
+ break;
+ }
+ }
+ f2.close();
+ }
+#elif defined(Q_OS_MAC)
+ QFile f2(mkspecFullPath + "/qmake.conf");
+ if (f2.exists() && f2.open(QIODevice::ReadOnly)) {
+ while (!f2.atEnd()) {
+ QByteArray line = f2.readLine();
+ if (line.startsWith("MAKEFILE_GENERATOR")) {
+ const QList<QByteArray> &temp = line.split('=');
+ if (temp.size() == 2) {
+ const QByteArray &value = temp.at(1);
+ if (value.contains("XCODE")) {
+ // we don't want to generate xcode projects...
+// qDebug() << "default mkspec is xcode, falling back to g++";
+ mkspecFullPath = baseMkspecDir + "/macx-g++";
+ }
+ //resolve mkspec link
+ mkspecFullPath = QFileInfo(mkspecFullPath).canonicalFilePath();
+ }
+ break;
+ }
+ }
+ f2.close();
+ }
+#else
+ mkspecFullPath = QFileInfo(mkspecFullPath).canonicalFilePath();
+#endif
+
+#ifdef Q_OS_WIN
+ mkspecFullPath = mkspecFullPath.toLower();
+#endif
+ return mkspecFullPath;
+}
+
+QString BaseQtVersion::qtCorePath(const QHash<QString,QString> &versionInfo, const QString &versionString)
+{
+ QStringList dirs;
+ dirs << versionInfo.value(QLatin1String("QT_INSTALL_LIBS"))
+ << versionInfo.value(QLatin1String("QT_INSTALL_BINS"));
+
+ QFileInfoList staticLibs;
+ foreach (const QString &dir, dirs) {
+ if (dir.isEmpty())
+ continue;
+ QDir d(dir);
+ QFileInfoList infoList = d.entryInfoList();
+ foreach (const QFileInfo &info, infoList) {
+ const QString file = info.fileName();
+ if (info.isDir()
+ && file.startsWith(QLatin1String("QtCore"))
+ && file.endsWith(QLatin1String(".framework"))) {
+ // handle Framework
+ const QString libName = file.left(file.lastIndexOf('.'));
+ return info.absoluteFilePath() + '/' + libName;
+ }
+ if (info.isReadable()) {
+ if (file.startsWith(QLatin1String("libQtCore"))
+ || file.startsWith(QLatin1String("QtCore"))) {
+ // Only handle static libs if we can not find dynamic ones:
+ if (file.endsWith(".a") || file.endsWith(".lib"))
+ staticLibs.append(info);
+ else if (file.endsWith(QLatin1String(".dll"))
+ || file.endsWith(QString::fromLatin1(".so.") + versionString)
+ || file.endsWith(QLatin1Char('.') + versionString + QLatin1String(".dylib")))
+
+ return info.absoluteFilePath();
+ }
+ }
+ }
+ }
+ // Return path to first static library found:
+ if (!staticLibs.isEmpty())
+ return staticLibs.at(0).absoluteFilePath();
+ return QString();
+}
+
+QList<ProjectExplorer::Abi> BaseQtVersion::qtAbisFromLibrary(const QString &coreLibrary)
+{
+ QList<ProjectExplorer::Abi> qtAbis = ProjectExplorer::Abi::abisOfBinary(coreLibrary);
+ if (qtAbis.isEmpty() && !coreLibrary.isEmpty()) {
+ qWarning("Warning: Could not find ABI for '%s'"
+ "Qt Creator does not know about the system includes, "
+ "nor the system defines.", qPrintable(coreLibrary));
+ }
+ return qtAbis;
+}
diff --git a/src/plugins/qtsupport/baseqtversion.h b/src/plugins/qtsupport/baseqtversion.h
new file mode 100644
index 0000000000..d07c22d6cf
--- /dev/null
+++ b/src/plugins/qtsupport/baseqtversion.h
@@ -0,0 +1,260 @@
+/**************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2011 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Nokia Corporation (info@qt.nokia.com)
+**
+**
+** GNU Lesser General Public License Usage
+**
+** 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.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** Other Usage
+**
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at info@qt.nokia.com.
+**
+**************************************************************************/
+
+#ifndef BASEQTVERSION_H
+#define BASEQTVERSION_H
+
+#include "qtsupport_global.h"
+
+#include <projectexplorer/abi.h>
+#include <projectexplorer/headerpath.h>
+#include <projectexplorer/task.h>
+#include <projectexplorer/ioutputparser.h>
+#include <utils/environment.h>
+
+#include <QtCore/QVariantMap>
+
+QT_BEGIN_NAMESPACE
+class ProFileEvaluator;
+class QSettings;
+QT_END_NAMESPACE
+
+namespace QtSupport
+{
+class QTSUPPORT_EXPORT QtVersionNumber
+{
+public:
+ QtVersionNumber(int ma, int mi, int p);
+ QtVersionNumber(const QString &versionString);
+ QtVersionNumber();
+
+ int majorVersion;
+ int minorVersion;
+ int patchVersion;
+ bool operator <(const QtVersionNumber &b) const;
+ bool operator <=(const QtVersionNumber &b) const;
+ bool operator >(const QtVersionNumber &b) const;
+ bool operator >=(const QtVersionNumber &b) const;
+ bool operator !=(const QtVersionNumber &b) const;
+ bool operator ==(const QtVersionNumber &b) const;
+private:
+ bool checkVersionString(const QString &version) const;
+};
+
+class QTSUPPORT_EXPORT QtConfigWidget : public QWidget
+{
+ Q_OBJECT
+public:
+ QtConfigWidget();
+signals:
+ void changed();
+};
+
+class QTSUPPORT_EXPORT BaseQtVersion
+{
+ friend class QtVersionFactory;
+ friend class QtVersionManager;
+public:
+ virtual ~BaseQtVersion();
+
+ virtual void fromMap(const QVariantMap &map);
+ // pre 2.3 settings, only used by SymbianQt
+ virtual void restoreLegacySettings(QSettings *s);
+ virtual BaseQtVersion *clone() const = 0;
+ virtual bool equals(BaseQtVersion *other);
+
+ bool isAutodetected() const;
+ QString autodetectionSource() const;
+
+ QString displayName() const;
+ void setDisplayName(const QString &name);
+
+ // All valid Ids are >= 0
+ int uniqueId() const;
+
+ virtual QString type() const = 0;
+
+ virtual QVariantMap toMap() const;
+ virtual bool isValid() const;
+ virtual QString invalidReason() const;
+
+ virtual bool toolChainAvailable(const QString &id) const;
+
+ virtual QString description() const = 0;
+ virtual QString toHtml(bool verbose) const;
+
+ virtual bool supportsTargetId(const QString &id) const = 0;
+ virtual QSet<QString> supportedTargetIds() const = 0;
+ virtual QList<ProjectExplorer::Abi> qtAbis() const = 0;
+
+ // Returns the PREFIX, BINPREFIX, DOCPREFIX and similar information
+ virtual QHash<QString,QString> versionInfo() const;
+ virtual void addToEnvironment(Utils::Environment &env) const;
+
+ virtual QString sourcePath() const;
+ // used by QtUiCodeModelSupport
+ virtual QString uicCommand() const;
+ virtual QString designerCommand() const;
+ virtual QString linguistCommand() const;
+ QString qmlviewerCommand() const;
+
+ virtual QString qtVersionString() const;
+ virtual QtVersionNumber qtVersion() const;
+
+ bool hasExamples() const;
+ QString examplesPath() const;
+
+ bool hasDocumentation() const;
+ QString documentationPath() const;
+
+ bool hasDemos() const;
+ QString demosPath() const;
+
+ virtual QList<ProjectExplorer::HeaderPath> systemHeaderPathes() const;
+ virtual QString frameworkInstallPath() const;
+
+ // former local functions
+ QString qmakeCommand() const;
+ virtual QString systemRoot() const;
+
+ /// @returns the name of the mkspec
+ QString mkspec() const;
+ /// @returns the full path to the default directory
+ /// specifally not the directory the symlink/ORIGINAL_QMAKESPEC points to
+ QString mkspecPath() const;
+
+ bool hasMkspec(const QString &) const;
+
+ enum QmakeBuildConfig
+ {
+ NoBuild = 1,
+ DebugBuild = 2,
+ BuildAll = 8
+ };
+
+ Q_DECLARE_FLAGS(QmakeBuildConfigs, QmakeBuildConfig)
+
+ virtual QmakeBuildConfigs defaultBuildConfig() const;
+ virtual void recheckDumper();
+ virtual bool supportsShadowBuilds() const;
+
+ /// Check a .pro-file/Qt version combination on possible issues
+ /// @return a list of tasks, ordered on severity (errors first, then
+ /// warnings and finally info items.
+ QList<ProjectExplorer::Task> reportIssues(const QString &proFile, const QString &buildDir);
+
+ virtual ProjectExplorer::IOutputParser *createOutputParser() const;
+
+ static bool queryQMakeVariables(const QString &binary, QHash<QString, QString> *versionInfo);
+ static QString mkspecFromVersionInfo(const QHash<QString, QString> &versionInfo);
+
+
+ virtual bool supportsBinaryDebuggingHelper() const;
+ virtual QString gdbDebuggingHelperLibrary() const;
+ virtual QString qmlDebuggingHelperLibrary(bool debugVersion) const;
+ virtual QString qmlDumpTool(bool debugVersion) const;
+ virtual QString qmlObserverTool() const;
+ virtual QStringList debuggingHelperLibraryLocations() const;
+
+ virtual bool hasGdbDebuggingHelper() const;
+ virtual bool hasQmlDump() const;
+ virtual bool hasQmlDebuggingLibrary() const;
+ virtual bool needsQmlDebuggingLibrary() const;
+ virtual bool hasQmlObserver() const;
+ Utils::Environment qmlToolsEnvironment() const;
+
+ virtual QtConfigWidget *createConfigurationWidget() const;
+
+ static QString defaultDisplayName(const QString &versionString,
+ const QString &qmakePath,
+ bool fromPath = false);
+
+protected:
+ BaseQtVersion();
+ BaseQtVersion(const QString &path, bool isAutodetected = false, const QString &autodetectionSource = QString());
+
+ virtual QList<ProjectExplorer::Task> reportIssuesImpl(const QString &proFile, const QString &buildDir);
+
+ // helper function for desktop and simulator to figure out the supported abis based on the libraries
+ static QString qtCorePath(const QHash<QString,QString> &versionInfo, const QString &versionString);
+ static QList<ProjectExplorer::Abi> qtAbisFromLibrary(const QString &coreLibrary);
+
+ void ensureMkSpecParsed() const;
+ virtual void parseMkSpec(ProFileEvaluator *) const;
+private:
+ void setAutoDetectionSource(const QString &autodetectionSource);
+ static int getUniqueId();
+ void ctor(const QString &qmakePath);
+ void updateSourcePath() const;
+ void updateVersionInfo() const;
+ QString findQtBinary(const QStringList &possibleName) const;
+ void updateMkspec() const;
+ void setId(int id); // used by the qtversionmanager for legacy restore
+ QString m_displayName;
+ int m_id;
+ bool m_isAutodetected;
+ QString m_autodetectionSource;
+
+ mutable QString m_sourcePath;
+ mutable bool m_hasDebuggingHelper; // controlled by m_versionInfoUpToDate
+ mutable bool m_hasQmlDump; // controlled by m_versionInfoUpToDate
+ mutable bool m_hasQmlDebuggingLibrary; // controlled by m_versionInfoUpdate
+ mutable bool m_hasQmlObserver; // controlled by m_versionInfoUpToDate
+
+ mutable bool m_mkspecUpToDate;
+ mutable QString m_mkspec;
+ mutable QString m_mkspecFullPath;
+
+ mutable bool m_mkspecReadUpToDate;
+ mutable bool m_defaultConfigIsDebug;
+ mutable bool m_defaultConfigIsDebugAndRelease;
+
+ mutable bool m_versionInfoUpToDate;
+ mutable QHash<QString,QString> m_versionInfo;
+ mutable bool m_notInstalled;
+ mutable bool m_hasExamples;
+ mutable bool m_hasDemos;
+ mutable bool m_hasDocumentation;
+
+ mutable QString m_qmakeCommand;
+ mutable QString m_qtVersionString;
+ mutable QString m_uicCommand;
+ mutable QString m_designerCommand;
+ mutable QString m_linguistCommand;
+ mutable QString m_qmlviewerCommand;
+
+ mutable bool m_qmakeIsExecutable;
+};
+}
+
+Q_DECLARE_OPERATORS_FOR_FLAGS(QtSupport::BaseQtVersion::QmakeBuildConfigs)
+#endif // BASEQTVERSION_H
diff --git a/src/plugins/qtsupport/debugginghelper.ui b/src/plugins/qtsupport/debugginghelper.ui
new file mode 100644
index 0000000000..a3cf9e5349
--- /dev/null
+++ b/src/plugins/qtsupport/debugginghelper.ui
@@ -0,0 +1,207 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<ui version="4.0">
+ <class>QtSupport::Internal::DebuggingHelper</class>
+ <widget class="QWidget" name="QtSupport::Internal::DebuggingHelper">
+ <property name="geometry">
+ <rect>
+ <x>0</x>
+ <y>0</y>
+ <width>321</width>
+ <height>150</height>
+ </rect>
+ </property>
+ <layout class="QVBoxLayout" name="verticalLayout">
+ <property name="margin">
+ <number>0</number>
+ </property>
+ <item>
+ <layout class="QGridLayout" name="gridLayout">
+ <item row="1" column="0">
+ <widget class="QLabel" name="qmlDumpLabel">
+ <property name="toolTip">
+ <string>Used to extract QML type information from library-based plugins.</string>
+ </property>
+ <property name="text">
+ <string>QML Dump:</string>
+ </property>
+ </widget>
+ </item>
+ <item row="1" column="1">
+ <widget class="QLabel" name="qmlDumpStatus">
+ <property name="text">
+ <string notr="true">TextLabel</string>
+ </property>
+ </widget>
+ </item>
+ <item row="1" column="2">
+ <spacer name="horizontalSpacer_2">
+ <property name="orientation">
+ <enum>Qt::Horizontal</enum>
+ </property>
+ <property name="sizeHint" stdset="0">
+ <size>
+ <width>40</width>
+ <height>20</height>
+ </size>
+ </property>
+ </spacer>
+ </item>
+ <item row="3" column="0">
+ <widget class="QLabel" name="qmlObserverLabel">
+ <property name="toolTip">
+ <string>A modified version of qmlviewer with support for QML/JS debugging.</string>
+ </property>
+ <property name="text">
+ <string>QML Observer:</string>
+ </property>
+ </widget>
+ </item>
+ <item row="3" column="1">
+ <widget class="QLabel" name="qmlObserverStatus">
+ <property name="text">
+ <string notr="true">TextLabel</string>
+ </property>
+ </widget>
+ </item>
+ <item row="3" column="2">
+ <spacer name="horizontalSpacer_3">
+ <property name="orientation">
+ <enum>Qt::Horizontal</enum>
+ </property>
+ <property name="sizeHint" stdset="0">
+ <size>
+ <width>40</width>
+ <height>20</height>
+ </size>
+ </property>
+ </spacer>
+ </item>
+ <item row="1" column="4">
+ <widget class="QPushButton" name="qmlDumpBuildButton">
+ <property name="text">
+ <string>Build</string>
+ </property>
+ </widget>
+ </item>
+ <item row="3" column="4">
+ <widget class="QPushButton" name="qmlObserverBuildButton">
+ <property name="text">
+ <string>Build</string>
+ </property>
+ </widget>
+ </item>
+ <item row="2" column="0">
+ <widget class="QLabel" name="qmlDebuggingLibLabel">
+ <property name="text">
+ <string>QML Debugging Library:</string>
+ </property>
+ </widget>
+ </item>
+ <item row="2" column="1">
+ <widget class="QLabel" name="qmlDebuggingLibStatus">
+ <property name="text">
+ <string notr="true">TextLabel</string>
+ </property>
+ </widget>
+ </item>
+ <item row="2" column="2">
+ <spacer name="horizontalSpacer_5">
+ <property name="orientation">
+ <enum>Qt::Horizontal</enum>
+ </property>
+ <property name="sizeHint" stdset="0">
+ <size>
+ <width>40</width>
+ <height>20</height>
+ </size>
+ </property>
+ </spacer>
+ </item>
+ <item row="2" column="4">
+ <widget class="QPushButton" name="qmlDebuggingLibBuildButton">
+ <property name="text">
+ <string>Build</string>
+ </property>
+ </widget>
+ </item>
+ <item row="4" column="0">
+ <widget class="QLabel" name="gdbHelperLabel">
+ <property name="toolTip">
+ <string>Helps showing content of Qt types. Only used in older versions of GDB.</string>
+ </property>
+ <property name="text">
+ <string>GDB Helper:</string>
+ </property>
+ </widget>
+ </item>
+ <item row="4" column="1">
+ <widget class="QLabel" name="gdbHelperStatus">
+ <property name="text">
+ <string notr="true">TextLabel</string>
+ </property>
+ </widget>
+ </item>
+ <item row="4" column="2">
+ <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>
+ <item row="4" column="4">
+ <widget class="QPushButton" name="gdbHelperBuildButton">
+ <property name="text">
+ <string>Build</string>
+ </property>
+ </widget>
+ </item>
+ </layout>
+ </item>
+ <item>
+ <layout class="QHBoxLayout" name="horizontalLayout">
+ <item>
+ <spacer name="horizontalSpacer_4">
+ <property name="orientation">
+ <enum>Qt::Horizontal</enum>
+ </property>
+ <property name="sizeHint" stdset="0">
+ <size>
+ <width>40</width>
+ <height>20</height>
+ </size>
+ </property>
+ </spacer>
+ </item>
+ <item>
+ <widget class="QPushButton" name="showLogButton">
+ <property name="toolTip">
+ <string>Show compiler output of last build.</string>
+ </property>
+ <property name="text">
+ <string>Show Log</string>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <widget class="QPushButton" name="rebuildButton">
+ <property name="toolTip">
+ <string>Compile debugging helpers that are checked.</string>
+ </property>
+ <property name="text">
+ <string>Build All</string>
+ </property>
+ </widget>
+ </item>
+ </layout>
+ </item>
+ </layout>
+ </widget>
+ <resources/>
+ <connections/>
+</ui>
diff --git a/src/plugins/qtsupport/debugginghelperbuildtask.cpp b/src/plugins/qtsupport/debugginghelperbuildtask.cpp
new file mode 100644
index 0000000000..432151fad5
--- /dev/null
+++ b/src/plugins/qtsupport/debugginghelperbuildtask.cpp
@@ -0,0 +1,261 @@
+/**************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2011 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Nokia Corporation (info@qt.nokia.com)
+**
+**
+** GNU Lesser General Public License Usage
+**
+** 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.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** Other Usage
+**
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at info@qt.nokia.com.
+**
+**************************************************************************/
+
+#include "debugginghelperbuildtask.h"
+#include "qmldumptool.h"
+#include "qmlobservertool.h"
+#include "qmldebugginglibrary.h"
+#include "baseqtversion.h"
+#include "qtversionmanager.h"
+#include <coreplugin/messagemanager.h>
+#include <projectexplorer/toolchainmanager.h>
+#include <projectexplorer/debugginghelper.h>
+#include <projectexplorer/abi.h>
+#include <utils/qtcassert.h>
+
+#include <QtCore/QCoreApplication>
+
+using namespace QtSupport;
+using namespace QtSupport::Internal;
+using ProjectExplorer::DebuggingHelperLibrary;
+
+DebuggingHelperBuildTask::DebuggingHelperBuildTask(const BaseQtVersion *version, Tools tools) :
+ m_tools(tools & availableTools(version)),
+ m_invalidQt(false),
+ m_showErrors(true)
+{
+ if (!version || !version->isValid())
+ return;
+ // allow type to be used in queued connections.
+ qRegisterMetaType<DebuggingHelperBuildTask::Tools>("DebuggingHelperBuildTask::Tools");
+
+ // Print result in application ouptut
+ Core::MessageManager *messageManager = Core::MessageManager::instance();
+ connect(this, SIGNAL(logOutput(QString,bool)),
+ messageManager, SLOT(printToOutputPane(QString,bool)),
+ Qt::QueuedConnection);
+
+ //
+ // Extract all information we need from version, such that we don't depend on the existence
+ // of the version pointer while compiling
+ //
+ m_qtId = version->uniqueId();
+ m_qtInstallData = version->versionInfo().value("QT_INSTALL_DATA");
+ if (m_qtInstallData.isEmpty()) {
+ const QString error
+ = QCoreApplication::translate(
+ "QtVersion",
+ "Cannot determine the installation path for Qt version '%1'."
+ ).arg(version->displayName());
+ log(QString(), error);
+ m_invalidQt = true;
+ return;
+ }
+
+ m_environment = Utils::Environment::systemEnvironment();
+ version->addToEnvironment(m_environment);
+
+ // TODO: the debugging helper doesn't comply to actual tool chain yet
+ QList<ProjectExplorer::ToolChain *> tcList = ProjectExplorer::ToolChainManager::instance()->findToolChains(version->qtAbis().at(0));
+ if (tcList.isEmpty()) {
+ const QString error
+ = QCoreApplication::translate(
+ "QtVersion",
+ "The Qt Version has no tool chain.");
+ log(QString(), error);
+ m_invalidQt = true;
+ return;
+ }
+ ProjectExplorer::ToolChain *tc = tcList.at(0);
+ tc->addToEnvironment(m_environment);
+
+ if (tc->targetAbi().os() == ProjectExplorer::Abi::LinuxOS
+ && ProjectExplorer::Abi::hostAbi().os() == ProjectExplorer::Abi::WindowsOS)
+ m_target = QLatin1String("-unix");
+ m_qmakeCommand = version->qmakeCommand();
+ m_makeCommand = tc->makeCommand();
+ m_mkspec = version->mkspec();
+
+ // Make sure QtVersion cache is invalidated
+ connect(this, SIGNAL(finished(int,QString,DebuggingHelperBuildTask::Tools)),
+ QtVersionManager::instance(), SLOT(updateQtVersion(int)),
+ Qt::QueuedConnection);
+}
+
+DebuggingHelperBuildTask::~DebuggingHelperBuildTask()
+{
+}
+
+DebuggingHelperBuildTask::Tools DebuggingHelperBuildTask::availableTools(const BaseQtVersion *version)
+{
+ QTC_ASSERT(version, return 0; )
+ // Check the build requirements of the tools
+ DebuggingHelperBuildTask::Tools tools = 0;
+ // Gdb helpers are needed on Mac/gdb only.
+ foreach (const ProjectExplorer::Abi &abi, version->qtAbis()) {
+ if (abi.os() == ProjectExplorer::Abi::MacOS) {
+ tools |= DebuggingHelperBuildTask::GdbDebugging;
+ break;
+ }
+ }
+ if (QmlDumpTool::canBuild(version))
+ tools |= QmlDump;
+ if (QmlDebuggingLibrary::canBuild(version)) {
+ tools |= QmlDebugging;
+ if (QmlObserverTool::canBuild(version))
+ tools |= QmlObserver; // requires QML debugging.
+ }
+ return tools;
+}
+
+void DebuggingHelperBuildTask::showOutputOnError(bool show)
+{
+ m_showErrors = show;
+}
+
+void DebuggingHelperBuildTask::run(QFutureInterface<void> &future)
+{
+ future.setProgressRange(0, 5);
+ future.setProgressValue(1);
+
+ if (m_invalidQt || !buildDebuggingHelper(future)) {
+ const QString error
+ = QCoreApplication::translate(
+ "QtVersion",
+ "Build failed!");
+ log(QString(), error);
+ } else {
+ const QString result
+ = QCoreApplication::translate(
+ "QtVersion",
+ "Build succeeded!");
+ log(result, QString());
+ }
+
+ emit finished(m_qtId, m_log, m_tools);
+ deleteLater();
+}
+
+bool DebuggingHelperBuildTask::buildDebuggingHelper(QFutureInterface<void> &future)
+{
+ Utils::BuildableHelperLibrary::BuildHelperArguments arguments;
+ arguments.makeCommand = m_makeCommand;
+ arguments.qmakeCommand = m_qmakeCommand;
+ arguments.targetMode = m_target;
+ arguments.mkspec = m_mkspec;
+ arguments.environment = m_environment;
+
+ if (m_tools & GdbDebugging) {
+ QString output, error;
+ bool success = true;
+
+ arguments.directory = DebuggingHelperLibrary::copy(m_qtInstallData, &error);
+ if (arguments.directory.isEmpty()
+ || !DebuggingHelperLibrary::build(arguments, &output, &error))
+ success = false;
+ log(output, error);
+ if (!success)
+ return false;
+ }
+ future.setProgressValue(2);
+
+ if (m_tools & QmlDump) {
+ QString output, error;
+ bool success = true;
+
+ arguments.directory = QmlDumpTool::copy(m_qtInstallData, &error);
+ if (arguments.directory.isEmpty()
+ || !QmlDumpTool::build(arguments, &output, &error))
+ success = false;
+ log(output, error);
+ if (!success)
+ return false;
+ }
+ future.setProgressValue(3);
+
+ QString qmlDebuggingDirectory;
+ if (m_tools & QmlDebugging) {
+ QString output, error;
+
+ qmlDebuggingDirectory = QmlDebuggingLibrary::copy(m_qtInstallData, &error);
+
+ bool success = true;
+ arguments.directory = qmlDebuggingDirectory;
+ arguments.makeArguments += QLatin1String("all"); // build debug and release
+ if (arguments.directory.isEmpty()
+ || !QmlDebuggingLibrary::build(arguments, &output, &error)) {
+ success = false;
+ }
+
+ log(output, error);
+ if (!success) {
+ return false;
+ }
+ arguments.makeArguments.clear();
+ }
+ future.setProgressValue(4);
+
+ if (m_tools & QmlObserver) {
+ QString output, error;
+ bool success = true;
+
+ arguments.directory = QmlObserverTool::copy(m_qtInstallData, &error);
+ arguments.qmakeArguments << QLatin1String("INCLUDEPATH+=\"\\\"") + qmlDebuggingDirectory + "include\\\"\"";
+ arguments.qmakeArguments << QLatin1String("LIBS+=-L\"\\\"") + qmlDebuggingDirectory + QLatin1String("\\\"\"");
+
+ if (arguments.directory.isEmpty()
+ || !QmlObserverTool::build(arguments, &output, &error)) {
+ success = false;
+ }
+ log(output, error);
+ if (!success) {
+ return false;
+ }
+ }
+ future.setProgressValue(5);
+ return true;
+}
+
+void DebuggingHelperBuildTask::log(const QString &output, const QString &error)
+{
+ if (output.isEmpty() && error.isEmpty())
+ return;
+
+ QString logEntry;
+ if (!output.isEmpty())
+ logEntry.append(output);
+ if (!error.isEmpty())
+ logEntry.append(error);
+ m_log.append(logEntry);
+
+ emit logOutput(logEntry, m_showErrors && !error.isEmpty());
+}
diff --git a/src/plugins/qtsupport/debugginghelperbuildtask.h b/src/plugins/qtsupport/debugginghelperbuildtask.h
new file mode 100644
index 0000000000..9a0a7fceeb
--- /dev/null
+++ b/src/plugins/qtsupport/debugginghelperbuildtask.h
@@ -0,0 +1,94 @@
+/**************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2011 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Nokia Corporation (info@qt.nokia.com)
+**
+**
+** GNU Lesser General Public License Usage
+**
+** 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.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** Other Usage
+**
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at info@qt.nokia.com.
+**
+**************************************************************************/
+
+#ifndef DEBUGGINGHELPERBUILDTASK_H
+#define DEBUGGINGHELPERBUILDTASK_H
+
+#include "qtsupport_global.h"
+#include <utils/environment.h>
+
+#include <QtCore/QObject>
+#include <QtCore/QFutureInterface>
+#include <QtCore/QMetaType>
+
+namespace QtSupport {
+class BaseQtVersion;
+
+class QTSUPPORT_EXPORT DebuggingHelperBuildTask : public QObject {
+ Q_DISABLE_COPY(DebuggingHelperBuildTask)
+ Q_OBJECT
+public:
+ enum DebuggingHelper {
+ GdbDebugging = 0x01,
+ QmlDebugging = 0x02,
+ QmlObserver = 0x04,
+ QmlDump = 0x08,
+ AllTools = GdbDebugging | QmlDebugging | QmlObserver | QmlDump
+ };
+ Q_DECLARE_FLAGS(Tools, DebuggingHelper)
+
+ explicit DebuggingHelperBuildTask(const BaseQtVersion *version, Tools tools = AllTools);
+ virtual ~DebuggingHelperBuildTask();
+
+ void showOutputOnError(bool show);
+ void run(QFutureInterface<void> &future);
+
+ static Tools availableTools(const BaseQtVersion *version);
+
+signals:
+ // used internally
+ void logOutput(const QString &output, bool bringToForeground);
+ void finished(int qtVersionId, const QString &output, DebuggingHelperBuildTask::Tools tools);
+
+private:
+ bool buildDebuggingHelper(QFutureInterface<void> &future);
+ void log(const QString &output, const QString &error);
+
+ const Tools m_tools;
+
+ int m_qtId;
+ QString m_qtInstallData;
+ QString m_target;
+ QString m_qmakeCommand;
+ QString m_makeCommand;
+ QString m_mkspec;
+ Utils::Environment m_environment;
+ QString m_log;
+ bool m_invalidQt;
+ bool m_showErrors;
+};
+
+} //namespace Qt4ProjectManager
+
+Q_DECLARE_METATYPE(QtSupport::DebuggingHelperBuildTask::Tools)
+
+#endif // DEBUGGINGHELPERBUILDTASK_H
diff --git a/src/plugins/qtsupport/profilereader.cpp b/src/plugins/qtsupport/profilereader.cpp
new file mode 100644
index 0000000000..a92344b5e4
--- /dev/null
+++ b/src/plugins/qtsupport/profilereader.cpp
@@ -0,0 +1,181 @@
+/**************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2011 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Nokia Corporation (info@qt.nokia.com)
+**
+**
+** GNU Lesser General Public License Usage
+**
+** 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.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** Other Usage
+**
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at info@qt.nokia.com.
+**
+**************************************************************************/
+
+#include "profilereader.h"
+
+#include <coreplugin/icore.h>
+#include <coreplugin/messagemanager.h>
+
+#include <QtCore/QDir>
+#include <QtCore/QDebug>
+
+using namespace QtSupport;
+
+static QString format(const QString &fileName, int lineNo, const QString &msg)
+{
+ if (lineNo)
+ return QString::fromLatin1("%1(%2): %3").arg(fileName, QString::number(lineNo), msg);
+ else
+ return msg;
+}
+
+ProMessageHandler::ProMessageHandler(bool verbose)
+ : m_verbose(verbose)
+{
+ QObject::connect(this, SIGNAL(errorFound(QString)),
+ Core::ICore::instance()->messageManager(), SLOT(printToOutputPane(QString)),
+ Qt::QueuedConnection);
+}
+
+void ProMessageHandler::parseError(const QString &fileName, int lineNo, const QString &msg)
+{
+ emit errorFound(format(fileName, lineNo, msg));
+}
+
+void ProMessageHandler::configError(const QString &msg)
+{
+ emit errorFound(msg);
+}
+
+void ProMessageHandler::evalError(const QString &fileName, int lineNo, const QString &msg)
+{
+ if (m_verbose)
+ emit errorFound(format(fileName, lineNo, msg));
+}
+
+void ProMessageHandler::fileMessage(const QString &)
+{
+ // we ignore these...
+}
+
+
+ProFileReader::ProFileReader(ProFileOption *option)
+ : ProFileParser(ProFileCacheManager::instance()->cache(), this)
+ , ProFileEvaluator(option, this, this)
+ , m_ignoreLevel(0)
+{
+}
+
+ProFileReader::~ProFileReader()
+{
+ foreach (ProFile *pf, m_proFiles)
+ pf->deref();
+}
+
+void ProFileReader::aboutToEval(ProFile *, ProFile *pro, EvalFileType type)
+{
+ if (m_ignoreLevel || (type != EvalProjectFile && type != EvalIncludeFile)) {
+ m_ignoreLevel++;
+ } else if (!m_includeFiles.contains(pro->fileName())) {
+ m_includeFiles.insert(pro->fileName(), pro);
+ m_proFiles.append(pro);
+ pro->ref();
+ }
+}
+
+void ProFileReader::doneWithEval(ProFile *)
+{
+ if (m_ignoreLevel)
+ m_ignoreLevel--;
+}
+
+QList<ProFile*> ProFileReader::includeFiles() const
+{
+ return m_includeFiles.values();
+}
+
+ProFile *ProFileReader::proFileFor(const QString &name)
+{
+ return m_includeFiles.value(name);
+}
+
+ProFileCacheManager *ProFileCacheManager::s_instance = 0;
+
+ProFileCacheManager::ProFileCacheManager(QObject *parent) :
+ QObject(parent),
+ m_cache(0),
+ m_refCount(0)
+{
+ s_instance = this;
+ m_timer.setInterval(5000);
+ m_timer.setSingleShot(true);
+ connect(&m_timer, SIGNAL(timeout()),
+ this, SLOT(clear()));
+}
+
+void ProFileCacheManager::incRefCount()
+{
+ ++m_refCount;
+ m_timer.stop();
+}
+
+void ProFileCacheManager::decRefCount()
+{
+ --m_refCount;
+ if (!m_refCount)
+ m_timer.start();
+}
+
+ProFileCacheManager::~ProFileCacheManager()
+{
+ s_instance = 0;
+ clear();
+}
+
+ProFileCache *ProFileCacheManager::cache()
+{
+ if (!m_cache)
+ m_cache = new ProFileCache;
+ return m_cache;
+}
+
+void ProFileCacheManager::clear()
+{
+ Q_ASSERT(m_refCount == 0);
+ // Just deleting the cache will be safe as long as the sequence of
+ // obtaining a cache pointer and using it is atomic as far as the main
+ // loop is concerned. Use a shared pointer once this is not true anymore.
+ delete m_cache;
+ m_cache = 0;
+}
+
+void ProFileCacheManager::discardFiles(const QString &prefix)
+{
+ if (m_cache)
+ m_cache->discardFiles(prefix);
+}
+
+void ProFileCacheManager::discardFile(const QString &fileName)
+{
+ if (m_cache)
+ m_cache->discardFile(fileName);
+}
diff --git a/src/plugins/qtsupport/profilereader.h b/src/plugins/qtsupport/profilereader.h
new file mode 100644
index 0000000000..7993818a49
--- /dev/null
+++ b/src/plugins/qtsupport/profilereader.h
@@ -0,0 +1,120 @@
+/**************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2011 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Nokia Corporation (info@qt.nokia.com)
+**
+**
+** GNU Lesser General Public License Usage
+**
+** 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.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** Other Usage
+**
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at info@qt.nokia.com.
+**
+**************************************************************************/
+
+#ifndef PROFILEREADER_H
+#define PROFILEREADER_H
+
+#include "qtsupport_global.h"
+#include "proparser/profileparser.h"
+#include "proparser/profileevaluator.h"
+
+#include <QtCore/QObject>
+#include <QtCore/QMap>
+#include <QtCore/QTimer>
+
+namespace QtSupport {
+namespace Internal {
+class QtSupportPlugin;
+}
+
+class QTSUPPORT_EXPORT ProMessageHandler : public QObject,
+ public ProFileParserHandler, public ProFileEvaluatorHandler
+{
+ Q_OBJECT
+
+public:
+ ProMessageHandler(bool verbose = false);
+ virtual ~ProMessageHandler() {}
+
+ virtual void aboutToEval(ProFile *, ProFile *, EvalFileType) {}
+ virtual void doneWithEval(ProFile *) {}
+ virtual void parseError(const QString &filename, int lineNo, const QString &msg);
+ virtual void configError(const QString &msg);
+ virtual void evalError(const QString &filename, int lineNo, const QString &msg);
+ virtual void fileMessage(const QString &msg);
+
+signals:
+ void errorFound(const QString &error);
+
+private:
+ bool m_verbose;
+};
+
+class QTSUPPORT_EXPORT ProFileReader : public ProMessageHandler, public ProFileParser, public ProFileEvaluator
+{
+ Q_OBJECT
+
+public:
+ ProFileReader(ProFileOption *option);
+ ~ProFileReader();
+
+ QList<ProFile*> includeFiles() const;
+
+ ProFile *proFileFor(const QString &name);
+
+ virtual void aboutToEval(ProFile *parent, ProFile *proFile, EvalFileType type);
+ virtual void doneWithEval(ProFile *parent);
+
+private:
+ QMap<QString, ProFile *> m_includeFiles;
+ QList<ProFile *> m_proFiles;
+ int m_ignoreLevel;
+};
+
+class QTSUPPORT_EXPORT ProFileCacheManager : public QObject
+{
+ Q_OBJECT
+
+public:
+ static ProFileCacheManager *instance() { return s_instance; }
+ ProFileCache *cache();
+ void discardFiles(const QString &prefix);
+ void discardFile(const QString &fileName);
+ void incRefCount();
+ void decRefCount();
+
+private:
+ ProFileCacheManager(QObject *parent);
+ ~ProFileCacheManager();
+ Q_SLOT void clear();
+ ProFileCache *m_cache;
+ int m_refCount;
+ QTimer m_timer;
+
+ static ProFileCacheManager *s_instance;
+
+ friend class QtSupport::Internal::QtSupportPlugin;
+};
+
+} // namespace QtSupport
+
+#endif // PROFILEREADER_H
diff --git a/src/plugins/qtsupport/qmldebugginglibrary.cpp b/src/plugins/qtsupport/qmldebugginglibrary.cpp
new file mode 100644
index 0000000000..cff3af70f9
--- /dev/null
+++ b/src/plugins/qtsupport/qmldebugginglibrary.cpp
@@ -0,0 +1,160 @@
+/**************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2010 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Nokia Corporation (info@qt.nokia.com)
+**
+**
+** GNU Lesser General Public License Usage
+**
+** 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.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** Other Usage
+**
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at info@qt.nokia.com.
+**
+**************************************************************************/
+
+#include "qmldebugginglibrary.h"
+
+#include "baseqtversion.h"
+#include "qtsupportconstants.h"
+#include <coreplugin/icore.h>
+#include <utils/qtcassert.h>
+
+#include <projectexplorer/project.h>
+#include <QDesktopServices>
+#include <QCoreApplication>
+#include <QDir>
+#include <QDebug>
+
+namespace QtSupport {
+
+
+QString QmlDebuggingLibrary::libraryByInstallData(const QString &qtInstallData, bool debugBuild)
+{
+ if (!Core::ICore::instance())
+ return QString();
+
+ const QStringList directories = installDirectories(qtInstallData);
+
+ QStringList binFilenames;
+ if (debugBuild) {
+ binFilenames << QLatin1String("QmlJSDebuggerd.lib");
+ binFilenames << QLatin1String("libQmlJSDebuggerd.a"); // mingw
+ } else {
+ binFilenames << QLatin1String("QmlJSDebugger.lib");
+ }
+ binFilenames << QLatin1String("libQmlJSDebugger.a");
+ binFilenames << QLatin1String("QmlJSDebugger.prl"); // Symbian. Note that the actual lib is in EPOCROOT
+
+ return byInstallDataHelper(sourcePath(), sourceFileNames(), directories, binFilenames, false);
+}
+
+bool QmlDebuggingLibrary::canBuild(const BaseQtVersion *qtVersion, QString *reason)
+{
+ if (qtVersion->qtVersion() < QtVersionNumber(4, 7, 1)) {
+ if (reason)
+ *reason = QCoreApplication::translate("Qt4ProjectManager::QmlDebuggingLibrary", "Only available for Qt 4.7.1 or newer.");
+ return false;
+ }
+ return true;
+}
+
+bool QmlDebuggingLibrary::build(BuildHelperArguments arguments, QString *log, QString *errorMessage)
+{
+ arguments.helperName = QCoreApplication::translate("Qt4ProjectManager::QmlDebuggingLibrary", "QML Debugging");
+ arguments.proFilename = QLatin1String("qmljsdebugger.pro");
+ return buildHelper(arguments, log, errorMessage);
+}
+
+static inline bool mkpath(const QString &targetDirectory, QString *errorMessage)
+{
+ if (!QDir().mkpath(targetDirectory)) {
+ *errorMessage = QCoreApplication::translate("Qt4ProjectManager::QmlDebuggingLibrary", "The target directory %1 could not be created.").arg(targetDirectory);
+ return false;
+ }
+ return true;
+}
+
+QString QmlDebuggingLibrary::copy(const QString &qtInstallData, QString *errorMessage)
+{
+ const QStringList directories = QmlDebuggingLibrary::installDirectories(qtInstallData);
+
+ // Try to find a writeable directory.
+ foreach (const QString &directory, directories) {
+ if (!mkpath(directory, errorMessage)) {
+ continue;
+ } else {
+ errorMessage->clear();
+ }
+
+ if (copyFiles(sourcePath(), sourceFileNames(),
+ directory, errorMessage))
+ {
+ errorMessage->clear();
+ return directory;
+ }
+ }
+ *errorMessage = QCoreApplication::translate("Qt4ProjectManager::QmlDebuggingLibrary",
+ "QML Debugging library could not be built in any of the directories:\n- %1\n\nReason: %2")
+ .arg(directories.join(QLatin1String("\n- ")), *errorMessage);
+ return QString();
+}
+
+QStringList QmlDebuggingLibrary::recursiveFileList(const QDir &dir, const QString &prefix)
+{
+ QStringList files;
+
+ QString _prefix = prefix;
+ if (!_prefix.isEmpty() && !_prefix.endsWith('/')) {
+ _prefix = _prefix + '/';
+ }
+ foreach (const QString &fileName, dir.entryList(QDir::Files)) {
+ files << _prefix + fileName;
+ }
+
+ foreach (const QString &subDir, dir.entryList(QDir::Dirs | QDir::NoDotAndDotDot)) {
+ files += recursiveFileList(QDir(dir.absoluteFilePath(subDir)), _prefix + subDir);
+ }
+ return files;
+}
+
+QStringList QmlDebuggingLibrary::installDirectories(const QString &qtInstallData)
+{
+ const QChar slash = QLatin1Char('/');
+ const uint hash = qHash(qtInstallData);
+ QStringList directories;
+ directories
+ << (qtInstallData + QLatin1String("/qtc-qmldbg/"))
+ << QDir::cleanPath((QCoreApplication::applicationDirPath() + QLatin1String("/../qtc-qmldbg/") + QString::number(hash))) + slash
+ << (QDesktopServices::storageLocation(QDesktopServices::DataLocation) + QLatin1String("/qtc-qmldbg/") + QString::number(hash)) + slash;
+ return directories;
+}
+
+QString QmlDebuggingLibrary::sourcePath()
+{
+ return Core::ICore::instance()->resourcePath() + QLatin1String("/qml/qmljsdebugger/");
+}
+
+QStringList QmlDebuggingLibrary::sourceFileNames()
+{
+ return recursiveFileList(QDir(sourcePath()));
+}
+
+} // namespace
diff --git a/src/plugins/qtsupport/qmldebugginglibrary.h b/src/plugins/qtsupport/qmldebugginglibrary.h
new file mode 100644
index 0000000000..85726cc440
--- /dev/null
+++ b/src/plugins/qtsupport/qmldebugginglibrary.h
@@ -0,0 +1,72 @@
+/**************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2010 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Nokia Corporation (info@qt.nokia.com)
+**
+**
+** GNU Lesser General Public License Usage
+**
+** 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.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** Other Usage
+**
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at info@qt.nokia.com.
+**
+**************************************************************************/
+
+#ifndef QMLDEBUGGINGLIBRARY_H
+#define QMLDEBUGGINGLIBRARY_H
+
+#include "qtsupport_global.h"
+#include <utils/buildablehelperlibrary.h>
+
+QT_FORWARD_DECLARE_CLASS(QDir)
+
+namespace Utils {
+ class Environment;
+}
+
+namespace ProjectExplorer {
+ class Project;
+}
+
+namespace QtSupport {
+
+class BaseQtVersion;
+
+class QmlDebuggingLibrary : public Utils::BuildableHelperLibrary
+{
+public:
+ static QString libraryByInstallData(const QString &qtInstallData, bool debugBuild);
+
+ static bool canBuild(const BaseQtVersion *qtVersion, QString *reason = 0);
+ static bool build(BuildHelperArguments arguments, QString *log, QString *errorMessage);
+
+ static QString copy(const QString &qtInstallData, QString *errorMessage);
+
+private:
+ static QStringList recursiveFileList(const QDir &dir, const QString &prefix = QString());
+ static QStringList installDirectories(const QString &qtInstallData);
+ static QString sourcePath();
+ static QStringList sourceFileNames();
+};
+
+} // namespace
+
+#endif // QMLDEBUGGINGLIBRARY_H
diff --git a/src/plugins/qtsupport/qmldumptool.cpp b/src/plugins/qtsupport/qmldumptool.cpp
new file mode 100644
index 0000000000..fda6d7cf72
--- /dev/null
+++ b/src/plugins/qtsupport/qmldumptool.cpp
@@ -0,0 +1,339 @@
+/**************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2011 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Nokia Corporation (info@qt.nokia.com)
+**
+**
+** GNU Lesser General Public License Usage
+**
+** 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.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** Other Usage
+**
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at info@qt.nokia.com.
+**
+**************************************************************************/
+
+#include "qmldumptool.h"
+#include "qtsupportconstants.h"
+#include "qtversionmanager.h"
+#include "debugginghelperbuildtask.h"
+
+#include <coreplugin/icore.h>
+#include <coreplugin/progressmanager/progressmanager.h>
+
+#include <projectexplorer/project.h>
+#include <projectexplorer/projectexplorer.h>
+#include <projectexplorer/runconfiguration.h>
+#include <qtconcurrent/runextensions.h>
+#include <qmljs/qmljsmodelmanagerinterface.h>
+#include <utils/qtcassert.h>
+#include <QtGui/QDesktopServices>
+#include <QtCore/QCoreApplication>
+#include <QtCore/QDir>
+#include <QtCore/QDebug>
+#include <QtCore/QHash>
+
+namespace {
+
+using namespace QtSupport;
+using QtSupport::DebuggingHelperBuildTask;
+
+
+class QmlDumpBuildTask;
+
+typedef QHash<int, QmlDumpBuildTask *> QmlDumpByVersion;
+Q_GLOBAL_STATIC(QmlDumpByVersion, qmlDumpBuilds)
+
+// A task suitable to be run by QtConcurrent to build qmldump.
+class QmlDumpBuildTask : public QObject {
+ Q_DISABLE_COPY(QmlDumpBuildTask)
+ Q_OBJECT
+public:
+ explicit QmlDumpBuildTask(BaseQtVersion *version)
+ : m_buildTask(new DebuggingHelperBuildTask(version, DebuggingHelperBuildTask::QmlDump))
+ , m_failed(false)
+ {
+ qmlDumpBuilds()->insert(version->uniqueId(), this);
+ // Don't open General Messages pane with errors
+ m_buildTask->showOutputOnError(false);
+ connect(m_buildTask, SIGNAL(finished(int,QString,DebuggingHelperBuildTask::Tools)),
+ this, SLOT(finish(int,QString,DebuggingHelperBuildTask::Tools)),
+ Qt::QueuedConnection);
+ }
+
+ void run(QFutureInterface<void> &future)
+ {
+ m_buildTask->run(future);
+ }
+
+ void updateProjectWhenDone(QPointer<ProjectExplorer::Project> project, bool preferDebug)
+ {
+ foreach (const ProjectToUpdate &update, m_projectsToUpdate) {
+ if (update.project == project)
+ return;
+ }
+
+ ProjectToUpdate update;
+ update.project = project;
+ update.preferDebug = preferDebug;
+ m_projectsToUpdate += update;
+ }
+
+ bool hasFailed() const
+ {
+ return m_failed;
+ }
+
+private slots:
+ void finish(int qtId, const QString &output, DebuggingHelperBuildTask::Tools tools)
+ {
+ BaseQtVersion *version = QtVersionManager::instance()->version(qtId);
+
+ QTC_ASSERT(tools == DebuggingHelperBuildTask::QmlDump, return);
+ QString errorMessage;
+ if (!version) {
+ m_failed = true;
+ errorMessage = QString::fromLatin1("Qt version became invalid");
+ } else {
+ if (!version->hasQmlDump()) {
+ m_failed = true;
+ errorMessage = QString::fromLatin1("Could not build QML plugin dumping helper for %1\n"
+ "Output:\n%2").
+ arg(version->displayName(), output);
+ }
+ }
+
+ if (m_failed) {
+ qWarning("%s", qPrintable(errorMessage));
+ }
+
+ // update qmldump path for all the project
+ QmlJS::ModelManagerInterface *modelManager = QmlJS::ModelManagerInterface::instance();
+ if (!modelManager)
+ return;
+
+ foreach (const ProjectToUpdate &update, m_projectsToUpdate) {
+ if (!update.project)
+ continue;
+ QmlJS::ModelManagerInterface::ProjectInfo projectInfo = modelManager->projectInfo(update.project);
+ projectInfo.qmlDumpPath = version->qmlDumpTool(update.preferDebug);
+ if (projectInfo.qmlDumpPath.isEmpty())
+ projectInfo.qmlDumpPath = version->qmlDumpTool(!update.preferDebug);
+ projectInfo.qmlDumpEnvironment = version->qmlToolsEnvironment();
+ modelManager->updateProjectInfo(projectInfo);
+ }
+
+ // clean up
+ qmlDumpBuilds()->remove(qtId);
+ deleteLater();
+ }
+
+private:
+ class ProjectToUpdate {
+ public:
+ QPointer<ProjectExplorer::Project> project;
+ bool preferDebug;
+ };
+
+ QList<ProjectToUpdate> m_projectsToUpdate;
+ DebuggingHelperBuildTask *m_buildTask; // deletes itself after run()
+ bool m_failed;
+};
+} // end of anonymous namespace
+
+
+namespace QtSupport {
+
+static inline QStringList validBinaryFilenames(bool debugBuild)
+{
+ QStringList list = QStringList()
+ << QLatin1String("qmldump.exe")
+ << QLatin1String("qmldump")
+ << QLatin1String("qmldump.app/Contents/MacOS/qmldump");
+ if (debugBuild)
+ list.prepend(QLatin1String("debug/qmldump.exe"));
+ else
+ list.prepend(QLatin1String("release/qmldump.exe"));
+ return list;
+}
+
+static bool hasPrivateHeaders(const QString &qtInstallHeaders) {
+ const QString header = qtInstallHeaders
+ + QLatin1String("/QtDeclarative/private/qdeclarativemetatype_p.h");
+ return QFile::exists(header);
+}
+
+bool QmlDumpTool::canBuild(const BaseQtVersion *qtVersion, QString *reason)
+{
+ const QString installHeaders = qtVersion->versionInfo().value("QT_INSTALL_HEADERS");
+
+ if (qtVersion->type() != Constants::DESKTOPQT
+ && qtVersion->type() != Constants::SIMULATORQT) {
+ if (reason)
+ *reason = QCoreApplication::translate("Qt4ProjectManager::QmlDumpTool", "Only available for Qt for Desktop and Qt for Qt Simulator.");
+ return false;
+ }
+ if (qtVersion->qtVersion() < QtVersionNumber(4, 7, 1)) {
+ if (reason)
+ *reason = QCoreApplication::translate("Qt4ProjectManager::QmlDumpTool", "Only available for Qt 4.7.1 or newer.");
+ return false;
+ }
+
+ if (!hasPrivateHeaders(installHeaders)) {
+ if (reason)
+ *reason = QCoreApplication::translate("Qt4ProjectManager::QmlDumpTool", "Private headers are missing for this Qt version.");
+ return false;
+ }
+ return true;
+}
+
+QString QmlDumpTool::toolForVersion(BaseQtVersion *version, bool debugDump)
+{
+ if (version) {
+ QString qtInstallData = version->versionInfo().value("QT_INSTALL_DATA");
+ QString qtInstallHeaders = version->versionInfo().value("QT_INSTALL_HEADERS");
+ QString toolPath = toolByInstallData(qtInstallData, qtInstallHeaders, debugDump);
+ return toolPath;
+ }
+
+ return QString();
+}
+
+static QString sourcePath()
+{
+ return Core::ICore::instance()->resourcePath() + QLatin1String("/qml/qmldump/");
+}
+
+static QStringList sourceFileNames()
+{
+ QStringList files;
+ files << QLatin1String("main.cpp") << QLatin1String("qmldump.pro")
+ << QLatin1String("qmlstreamwriter.cpp") << QLatin1String("qmlstreamwriter.h")
+ << QLatin1String("LICENSE.LGPL") << QLatin1String("LGPL_EXCEPTION.TXT");
+#ifdef Q_OS_MAC
+ files << QLatin1String("Info.plist");
+#endif
+ return files;
+}
+
+QString QmlDumpTool::toolByInstallData(const QString &qtInstallData, const QString &qtInstallHeaders,
+ bool debugDump)
+{
+ if (!Core::ICore::instance())
+ return QString();
+
+ const QStringList directories = installDirectories(qtInstallData);
+ const QStringList binFilenames = validBinaryFilenames(debugDump);
+
+ return byInstallDataHelper(sourcePath(), sourceFileNames(), directories, binFilenames,
+ !hasPrivateHeaders(qtInstallHeaders));
+}
+
+QStringList QmlDumpTool::locationsByInstallData(const QString &qtInstallData, bool debugDump)
+{
+ QStringList result;
+ QFileInfo fileInfo;
+ const QStringList binFilenames = validBinaryFilenames(debugDump);
+ foreach(const QString &directory, installDirectories(qtInstallData)) {
+ if (getHelperFileInfoFor(binFilenames, directory, &fileInfo))
+ result << fileInfo.filePath();
+ }
+ return result;
+}
+
+bool QmlDumpTool::build(BuildHelperArguments arguments, QString *log, QString *errorMessage)
+{
+ arguments.helperName = QCoreApplication::translate("Qt4ProjectManager::QmlDumpTool", "qmldump");
+ arguments.proFilename = QLatin1String("qmldump.pro");
+ return buildHelper(arguments, log, errorMessage);
+}
+
+QString QmlDumpTool::copy(const QString &qtInstallData, QString *errorMessage)
+{
+ const QStringList directories = QmlDumpTool::installDirectories(qtInstallData);
+
+ // Try to find a writeable directory.
+ foreach(const QString &directory, directories) {
+ if (copyFiles(sourcePath(), sourceFileNames(), directory, errorMessage)) {
+ return directory;
+ }
+ }
+ *errorMessage = QCoreApplication::translate("ProjectExplorer::QmlDumpTool",
+ "qmldump could not be built in any of the directories:\n- %1\n\nReason: %2")
+ .arg(directories.join(QLatin1String("\n- ")), *errorMessage);
+ return QString();
+}
+
+QStringList QmlDumpTool::installDirectories(const QString &qtInstallData)
+{
+ const QChar slash = QLatin1Char('/');
+ const uint hash = qHash(qtInstallData);
+ QStringList directories;
+ directories
+ << (qtInstallData + QLatin1String("/qtc-qmldump/"))
+ << QDir::cleanPath((QCoreApplication::applicationDirPath() + QLatin1String("/../qtc-qmldump/") + QString::number(hash))) + slash
+ << (QDesktopServices::storageLocation(QDesktopServices::DataLocation) + QLatin1String("/qtc-qmldump/") + QString::number(hash)) + slash;
+ return directories;
+}
+
+void QmlDumpTool::pathAndEnvironment(ProjectExplorer::Project *project, BaseQtVersion *version,
+ bool preferDebug, QString *dumperPath, Utils::Environment *env)
+{
+ QString path;
+ if (version && !version->hasQmlDump() && QmlDumpTool::canBuild(version)) {
+ QmlDumpBuildTask *qmlDumpBuildTask = qmlDumpBuilds()->value(version->uniqueId());
+ if (qmlDumpBuildTask) {
+ if (!qmlDumpBuildTask->hasFailed())
+ qmlDumpBuildTask->updateProjectWhenDone(project, preferDebug);
+ } else {
+ QmlDumpBuildTask *buildTask = new QmlDumpBuildTask(version);
+ buildTask->updateProjectWhenDone(project, preferDebug);
+ QFuture<void> task = QtConcurrent::run(&QmlDumpBuildTask::run, buildTask);
+ const QString taskName = QmlDumpBuildTask::tr("Building helper");
+ Core::ICore::instance()->progressManager()->addTask(task, taskName,
+ QLatin1String("Qt4ProjectManager::BuildHelpers"));
+ }
+ return;
+ }
+
+ path = toolForVersion(version, preferDebug);
+ if (path.isEmpty())
+ path = toolForVersion(version, !preferDebug);
+
+ if (!path.isEmpty()) {
+ QFileInfo qmldumpFileInfo(path);
+ if (!qmldumpFileInfo.exists()) {
+ qWarning() << "QmlDumpTool::qmlDumpPath: qmldump executable does not exist at" << path;
+ path.clear();
+ } else if (!qmldumpFileInfo.isFile()) {
+ qWarning() << "QmlDumpTool::qmlDumpPath: " << path << " is not a file";
+ path.clear();
+ }
+ }
+
+ if (!path.isEmpty() && version && dumperPath && env) {
+ *dumperPath = path;
+ *env = version->qmlToolsEnvironment();
+ }
+}
+
+} // namespace Qt4ProjectManager
+
+#include "qmldumptool.moc"
diff --git a/src/plugins/qtsupport/qmldumptool.h b/src/plugins/qtsupport/qmldumptool.h
new file mode 100644
index 0000000000..4192fc8a06
--- /dev/null
+++ b/src/plugins/qtsupport/qmldumptool.h
@@ -0,0 +1,76 @@
+/**************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2011 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Nokia Corporation (info@qt.nokia.com)
+**
+**
+** GNU Lesser General Public License Usage
+**
+** 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.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** Other Usage
+**
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at info@qt.nokia.com.
+**
+**************************************************************************/
+
+#ifndef QMLDUMPTOOL_H
+#define QMLDUMPTOOL_H
+
+#include "qtsupport_global.h"
+
+#include <utils/buildablehelperlibrary.h>
+
+namespace Utils {
+ class Environment;
+}
+
+namespace ProjectExplorer {
+ class Project;
+}
+
+namespace QtSupport {
+class BaseQtVersion;
+
+class QTSUPPORT_EXPORT QmlDumpTool : public Utils::BuildableHelperLibrary
+{
+public:
+ static bool canBuild(const BaseQtVersion *qtVersion, QString *reason = 0);
+ static QString toolForVersion(BaseQtVersion *version, bool debugDump);
+ static QString toolByInstallData(const QString &qtInstallData, const QString &qtInstallHeaders,
+ bool debugDump);
+ static QStringList locationsByInstallData(const QString &qtInstallData, bool debugDump);
+
+ // Build the helpers and return the output log/errormessage.
+ static bool build(BuildHelperArguments arguments, QString *log, QString *errorMessage);
+
+ // Copy the source files to a target location and return the chosen target location.
+ static QString copy(const QString &qtInstallData, QString *errorMessage);
+
+ static void pathAndEnvironment(ProjectExplorer::Project *project, BaseQtVersion *version,
+ bool preferDebug, QString *path, Utils::Environment *env);
+
+private:
+ static QStringList installDirectories(const QString &qtInstallData);
+
+};
+
+} // namespace
+
+#endif // QMLDUMPTOOL_H
diff --git a/src/plugins/qtsupport/qmlobservertool.cpp b/src/plugins/qtsupport/qmlobservertool.cpp
new file mode 100644
index 0000000000..1eb16ca27d
--- /dev/null
+++ b/src/plugins/qtsupport/qmlobservertool.cpp
@@ -0,0 +1,177 @@
+/**************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2011 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Nokia Corporation (info@qt.nokia.com)
+**
+**
+** GNU Lesser General Public License Usage
+**
+** 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.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** Other Usage
+**
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at info@qt.nokia.com.
+**
+**************************************************************************/
+
+#include "qmlobservertool.h"
+
+#include "qtsupportconstants.h"
+#include "baseqtversion.h"
+#include <coreplugin/icore.h>
+#include <utils/qtcassert.h>
+
+#include <projectexplorer/project.h>
+#include <QtGui/QDesktopServices>
+#include <QtCore/QCoreApplication>
+#include <QtCore/QDir>
+#include <QtCore/QDebug>
+
+namespace QtSupport {
+
+static inline QStringList validBinaryFilenames()
+{
+ return QStringList()
+ << QLatin1String("debug/qmlobserver.exe")
+ << QLatin1String("qmlobserver.exe")
+ << QLatin1String("qmlobserver")
+ << QLatin1String("QMLObserver.app/Contents/MacOS/QMLObserver");
+}
+
+bool QmlObserverTool::canBuild(const BaseQtVersion *qtVersion, QString *reason)
+{
+ if (qtVersion->type() != Constants::DESKTOPQT
+ && qtVersion->type() != Constants::SIMULATORQT) {
+ if (reason)
+ *reason = QCoreApplication::translate("Qt4ProjectManager::QmlObserverTool", "Only available for Qt for Desktop or Qt for Qt Simulator.");
+ return false;
+ }
+
+ if (qtVersion->qtVersion() < QtVersionNumber(4, 7, 1)) {
+ if (reason)
+ *reason = QCoreApplication::translate("Qt4ProjectManager::QmlObserverTool", "Only available for Qt 4.7.1 or newer.");
+ return false;
+ }
+ return true;
+}
+
+QString QmlObserverTool::toolByInstallData(const QString &qtInstallData)
+{
+ if (!Core::ICore::instance())
+ return QString();
+
+ const QStringList directories = installDirectories(qtInstallData);
+ const QStringList binFilenames = validBinaryFilenames();
+
+ return byInstallDataHelper(sourcePath(), sourceFileNames(), directories, binFilenames, false);
+}
+
+QStringList QmlObserverTool::locationsByInstallData(const QString &qtInstallData)
+{
+ QStringList result;
+ QFileInfo fileInfo;
+ const QStringList binFilenames = validBinaryFilenames();
+ foreach(const QString &directory, installDirectories(qtInstallData)) {
+ if (getHelperFileInfoFor(binFilenames, directory, &fileInfo))
+ result << fileInfo.filePath();
+ }
+ return result;
+}
+
+bool QmlObserverTool::build(BuildHelperArguments arguments, QString *log, QString *errorMessage)
+{
+ arguments.helperName = QCoreApplication::translate("Qt4ProjectManager::QmlObserverTool", "QMLObserver");
+ arguments.proFilename = QLatin1String("qmlobserver.pro");
+
+ return buildHelper(arguments, log, errorMessage);
+}
+
+static inline bool mkpath(const QString &targetDirectory, QString *errorMessage)
+{
+ if (!QDir().mkpath(targetDirectory)) {
+ *errorMessage = QCoreApplication::translate("ProjectExplorer::QmlObserverTool", "The target directory %1 could not be created.").arg(targetDirectory);
+ return false;
+ }
+ return true;
+}
+
+QString QmlObserverTool::copy(const QString &qtInstallData, QString *errorMessage)
+{
+ const QStringList directories = QmlObserverTool::installDirectories(qtInstallData);
+
+ // Try to find a writeable directory.
+ foreach(const QString &directory, directories) {
+ if (!mkpath(directory, errorMessage)) {
+ continue;
+ } else {
+ errorMessage->clear();
+ }
+
+ if (copyFiles(sourcePath(), sourceFileNames(), directory, errorMessage)) {
+ errorMessage->clear();
+ return directory;
+ }
+ }
+ *errorMessage = QCoreApplication::translate("ProjectExplorer::QmlObserverTool",
+ "QMLObserver could not be built in any of the directories:\n- %1\n\nReason: %2")
+ .arg(directories.join(QLatin1String("\n- ")), *errorMessage);
+ return QString();
+}
+
+QStringList QmlObserverTool::recursiveFileList(const QDir &dir, const QString &prefix)
+{
+ QStringList files;
+
+ QString _prefix = prefix;
+ if (!_prefix.isEmpty() && !_prefix.endsWith('/')) {
+ _prefix = _prefix + '/';
+ }
+ foreach (const QString &fileName, dir.entryList(QDir::Files)) {
+ files << _prefix + fileName;
+ }
+
+ foreach (const QString &subDir, dir.entryList(QDir::Dirs | QDir::NoDotAndDotDot)) {
+ files += recursiveFileList(QDir(dir.absoluteFilePath(subDir)), _prefix + subDir);
+ }
+ return files;
+}
+
+QStringList QmlObserverTool::installDirectories(const QString &qtInstallData)
+{
+ const QChar slash = QLatin1Char('/');
+ const uint hash = qHash(qtInstallData);
+ QStringList directories;
+ directories
+ << (qtInstallData + QLatin1String("/qtc-qmlobserver/"))
+ << QDir::cleanPath((QCoreApplication::applicationDirPath() + QLatin1String("/../qtc-qmlobserver/") + QString::number(hash))) + slash
+ << (QDesktopServices::storageLocation(QDesktopServices::DataLocation) + QLatin1String("/qtc-qmlobserver/") + QString::number(hash)) + slash;
+ return directories;
+}
+
+QString QmlObserverTool::sourcePath()
+{
+ return Core::ICore::instance()->resourcePath() + QLatin1String("/qml/qmlobserver/");
+}
+
+QStringList QmlObserverTool::sourceFileNames()
+{
+ return recursiveFileList(QDir(sourcePath()));
+}
+
+} // namespace
diff --git a/src/plugins/qtsupport/qmlobservertool.h b/src/plugins/qtsupport/qmlobservertool.h
new file mode 100644
index 0000000000..8b895cdde8
--- /dev/null
+++ b/src/plugins/qtsupport/qmlobservertool.h
@@ -0,0 +1,75 @@
+/**************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2011 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Nokia Corporation (info@qt.nokia.com)
+**
+**
+** GNU Lesser General Public License Usage
+**
+** 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.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** Other Usage
+**
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at info@qt.nokia.com.
+**
+**************************************************************************/
+
+#ifndef QMLOBSERVERTOOL_H
+#define QMLOBSERVERTOOL_H
+
+#include "qtsupport_global.h"
+#include <utils/buildablehelperlibrary.h>
+
+QT_FORWARD_DECLARE_CLASS(QDir)
+
+namespace Utils {
+ class Environment;
+}
+
+namespace ProjectExplorer {
+ class Project;
+}
+
+namespace QtSupport {
+
+class BaseQtVersion;
+
+class QTSUPPORT_EXPORT QmlObserverTool : public Utils::BuildableHelperLibrary
+{
+public:
+ static bool canBuild(const BaseQtVersion *qtVersion, QString *reason = 0);
+ static QString toolByInstallData(const QString &qtInstallData);
+ static QStringList locationsByInstallData(const QString &qtInstallData);
+
+ // Build the helpers and return the output log/errormessage.
+ static bool build(BuildHelperArguments arguments, QString *out, QString *err);
+
+ // Copy the source files to a target location and return the chosen target location.
+ static QString copy(const QString &qtInstallData, QString *errorMessage);
+
+private:
+ static QStringList recursiveFileList(const QDir &dir, const QString &prefix = QString());
+ static QStringList installDirectories(const QString &qtInstallData);
+ static QString sourcePath();
+ static QStringList sourceFileNames();
+};
+
+} // namespace
+
+#endif // QMLOBSERVERTOOL_H
diff --git a/src/plugins/qtsupport/qtoptionspage.cpp b/src/plugins/qtsupport/qtoptionspage.cpp
new file mode 100644
index 0000000000..534676c56b
--- /dev/null
+++ b/src/plugins/qtsupport/qtoptionspage.cpp
@@ -0,0 +1,837 @@
+/**************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2011 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Nokia Corporation (info@qt.nokia.com)
+**
+**
+** GNU Lesser General Public License Usage
+**
+** 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.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** Other Usage
+**
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at info@qt.nokia.com.
+**
+**************************************************************************/
+
+#include "qtoptionspage.h"
+#include "ui_showbuildlog.h"
+#include "ui_qtversionmanager.h"
+#include "ui_qtversioninfo.h"
+#include "ui_debugginghelper.h"
+#include "qtsupportconstants.h"
+#include "qtversionmanager.h"
+#include "qtversionfactory.h"
+#include "qmldumptool.h"
+#include "qmldebugginglibrary.h"
+#include "qmlobservertool.h"
+
+#include <coreplugin/icore.h>
+#include <coreplugin/progressmanager/progressmanager.h>
+#include <utils/treewidgetcolumnstretcher.h>
+#include <utils/qtcassert.h>
+#include <utils/buildablehelperlibrary.h>
+#include <qtconcurrent/runextensions.h>
+
+#include <QtCore/QDir>
+#include <QtGui/QToolTip>
+#include <QtGui/QMessageBox>
+#include <QtGui/QFileDialog>
+#include <QtGui/QMainWindow>
+
+enum ModelRoles { VersionIdRole = Qt::UserRole, BuildLogRole, BuildRunningRole};
+
+using namespace QtSupport;
+using namespace QtSupport::Internal;
+
+///
+// QtOptionsPage
+///
+
+QtOptionsPage::QtOptionsPage()
+ : m_widget(0)
+{
+}
+
+QString QtOptionsPage::id() const
+{
+ return QLatin1String(Constants::QTVERSION_SETTINGS_PAGE_ID);
+}
+
+QString QtOptionsPage::displayName() const
+{
+ return QCoreApplication::translate("Qt4ProjectManager", Constants::QTVERSION_SETTINGS_PAGE_NAME);
+}
+
+QString QtOptionsPage::category() const
+{
+ return QLatin1String(Constants::QT_SETTINGS_CATEGORY);
+}
+
+QString QtOptionsPage::displayCategory() const
+{
+ return QCoreApplication::translate("Qt4ProjectManager", Constants::QT_SETTINGS_TR_CATEGORY);
+}
+
+QIcon QtOptionsPage::categoryIcon() const
+{
+ return QIcon(QLatin1String(Constants::QT_SETTINGS_CATEGORY_ICON));
+}
+
+QWidget *QtOptionsPage::createPage(QWidget *parent)
+{
+ QtVersionManager *vm = QtVersionManager::instance();
+ m_widget = new QtOptionsPageWidget(parent, vm->versions());
+ if (m_searchKeywords.isEmpty())
+ m_searchKeywords = m_widget->searchKeywords();
+ return m_widget;
+}
+
+void QtOptionsPage::apply()
+{
+ if (!m_widget) // page was never shown
+ return;
+ m_widget->finish();
+
+ QtVersionManager *vm = QtVersionManager::instance();
+ vm->setNewQtVersions(m_widget->versions());
+}
+
+bool QtOptionsPage::matches(const QString &s) const
+{
+ return m_searchKeywords.contains(s, Qt::CaseInsensitive);
+}
+
+//-----------------------------------------------------
+
+
+QtOptionsPageWidget::QtOptionsPageWidget(QWidget *parent, QList<BaseQtVersion *> versions)
+ : QWidget(parent)
+ , m_specifyNameString(tr("<specify a name>"))
+ , m_ui(new Internal::Ui::QtVersionManager())
+ , m_versionUi(new Internal::Ui::QtVersionInfo())
+ , m_debuggingHelperUi(new Internal::Ui::DebuggingHelper())
+ , m_invalidVersionIcon(":/projectexplorer/images/compile_error.png")
+ , m_configurationWidget(0)
+{
+ // Initialize m_versions
+ foreach (BaseQtVersion *version, versions)
+ m_versions.push_back(version->clone());
+
+ QWidget *versionInfoWidget = new QWidget();
+ m_versionUi->setupUi(versionInfoWidget);
+
+ QWidget *debuggingHelperDetailsWidget = new QWidget();
+ m_debuggingHelperUi->setupUi(debuggingHelperDetailsWidget);
+
+ m_ui->setupUi(this);
+
+ m_ui->versionInfoWidget->setWidget(versionInfoWidget);
+ m_ui->versionInfoWidget->setState(Utils::DetailsWidget::NoSummary);
+
+ m_ui->debuggingHelperWidget->setWidget(debuggingHelperDetailsWidget);
+
+ // setup parent items for auto-detected and manual versions
+ m_ui->qtdirList->header()->setResizeMode(QHeaderView::ResizeToContents);
+ m_ui->qtdirList->header()->setStretchLastSection(false);
+ m_ui->qtdirList->setTextElideMode(Qt::ElideNone);
+ QTreeWidgetItem *autoItem = new QTreeWidgetItem(m_ui->qtdirList);
+ m_ui->qtdirList->installEventFilter(this);
+ autoItem->setText(0, tr("Auto-detected"));
+ autoItem->setFirstColumnSpanned(true);
+ autoItem->setFlags(Qt::ItemIsEnabled);
+ QTreeWidgetItem *manualItem = new QTreeWidgetItem(m_ui->qtdirList);
+ manualItem->setText(0, tr("Manual"));
+ manualItem->setFirstColumnSpanned(true);
+ manualItem->setFlags(Qt::ItemIsEnabled);
+
+ for (int i = 0; i < m_versions.count(); ++i) {
+ BaseQtVersion *version = m_versions.at(i);
+ QTreeWidgetItem *item = new QTreeWidgetItem(version->isAutodetected()? autoItem : manualItem);
+ item->setText(0, version->displayName());
+ item->setText(1, QDir::toNativeSeparators(version->qmakeCommand()));
+ item->setData(0, VersionIdRole, version->uniqueId());
+ item->setIcon(0, version->isValid()? m_validVersionIcon : m_invalidVersionIcon);
+ }
+ m_ui->qtdirList->expandAll();
+
+ connect(m_versionUi->nameEdit, SIGNAL(textEdited(const QString &)),
+ this, SLOT(updateCurrentQtName()));
+
+ connect(m_ui->addButton, SIGNAL(clicked()),
+ this, SLOT(addQtDir()));
+ connect(m_ui->delButton, SIGNAL(clicked()),
+ this, SLOT(removeQtDir()));
+
+ connect(m_ui->qtdirList, SIGNAL(currentItemChanged(QTreeWidgetItem *, QTreeWidgetItem *)),
+ this, SLOT(versionChanged(QTreeWidgetItem *, QTreeWidgetItem *)));
+
+ connect(m_debuggingHelperUi->rebuildButton, SIGNAL(clicked()),
+ this, SLOT(buildDebuggingHelper()));
+ connect(m_debuggingHelperUi->gdbHelperBuildButton, SIGNAL(clicked()),
+ this, SLOT(buildGdbHelper()));
+ connect(m_debuggingHelperUi->qmlDumpBuildButton, SIGNAL(clicked()),
+ this, SLOT(buildQmlDump()));
+ connect(m_debuggingHelperUi->qmlDebuggingLibBuildButton, SIGNAL(clicked()),
+ this, SLOT(buildQmlDebuggingLibrary()));
+ connect(m_debuggingHelperUi->qmlObserverBuildButton, SIGNAL(clicked()),
+ this, SLOT(buildQmlObserver()));
+
+ connect(m_debuggingHelperUi->showLogButton, SIGNAL(clicked()),
+ this, SLOT(slotShowDebuggingBuildLog()));
+
+ connect(m_ui->cleanUpButton, SIGNAL(clicked()), this, SLOT(cleanUpQtVersions()));
+ userChangedCurrentVersion();
+ updateCleanUpButton();
+
+ connect(QtVersionManager::instance(), SIGNAL(dumpUpdatedFor(QString)),
+ this, SLOT(qtVersionsDumpUpdated(QString)));
+}
+
+bool QtOptionsPageWidget::eventFilter(QObject *o, QEvent *e)
+{
+ // Set the items tooltip, which may cause costly initialization
+ // of QtVersion and must be up-to-date
+ if (o != m_ui->qtdirList || e->type() != QEvent::ToolTip)
+ return false;
+ QHelpEvent *helpEvent = static_cast<QHelpEvent *>(e);
+ const QPoint treePos = helpEvent->pos() - QPoint(0, m_ui->qtdirList->header()->height());
+ QTreeWidgetItem *item = m_ui->qtdirList->itemAt(treePos);
+ if (!item)
+ return false;
+ const int index = indexForTreeItem(item);
+ if (index == -1)
+ return false;
+ const QString tooltip = m_versions.at(index)->toHtml(true);
+ QToolTip::showText(helpEvent->globalPos(), tooltip, m_ui->qtdirList);
+ helpEvent->accept();
+ return true;
+}
+
+int QtOptionsPageWidget::currentIndex() const
+{
+ if (QTreeWidgetItem *currentItem = m_ui->qtdirList->currentItem())
+ return indexForTreeItem(currentItem);
+ return -1;
+}
+
+BaseQtVersion *QtOptionsPageWidget::currentVersion() const
+{
+ const int currentItemIndex = currentIndex();
+ if (currentItemIndex >= 0 && currentItemIndex < m_versions.size())
+ return m_versions.at(currentItemIndex);
+ return 0;
+}
+
+static inline int findVersionById(const QList<BaseQtVersion *> &l, int id)
+{
+ const int size = l.size();
+ for (int i = 0; i < size; i++)
+ if (l.at(i)->uniqueId() == id)
+ return i;
+ return -1;
+}
+
+// Update with results of terminated helper build
+void QtOptionsPageWidget::debuggingHelperBuildFinished(int qtVersionId, const QString &output, DebuggingHelperBuildTask::Tools tools)
+{
+ const int index = findVersionById(m_versions, qtVersionId);
+ if (index == -1)
+ return; // Oops, somebody managed to delete the version
+
+ BaseQtVersion *version = m_versions.at(index);
+
+ // Update item view
+ QTreeWidgetItem *item = treeItemForIndex(index);
+ QTC_ASSERT(item, return);
+ DebuggingHelperBuildTask::Tools buildFlags
+ = item->data(0, BuildRunningRole).value<DebuggingHelperBuildTask::Tools>();
+ buildFlags &= ~tools;
+ item->setData(0, BuildRunningRole, QVariant::fromValue(buildFlags));
+ item->setData(0, BuildLogRole, output);
+
+ bool success = true;
+ if (tools & DebuggingHelperBuildTask::GdbDebugging)
+ success &= version->hasGdbDebuggingHelper();
+ if (tools & DebuggingHelperBuildTask::QmlDebugging)
+ success &= version->hasQmlDebuggingLibrary();
+ if (tools & DebuggingHelperBuildTask::QmlDump)
+ success &= version->hasQmlDump();
+ if (tools & DebuggingHelperBuildTask::QmlObserver)
+ success &= version->hasQmlObserver();
+
+ // Update bottom control if the selection is still the same
+ if (index == currentIndex()) {
+ updateDebuggingHelperUi();
+ }
+
+ if (!success)
+ showDebuggingBuildLog(item);
+}
+
+void QtOptionsPageWidget::cleanUpQtVersions()
+{
+ QStringList toRemove;
+ foreach (const BaseQtVersion *v, m_versions) {
+ if (!v->isValid() && !v->isAutodetected())
+ toRemove.append(v->displayName());
+ }
+
+ if (toRemove.isEmpty())
+ return;
+
+ if (QMessageBox::warning(0, tr("Remove invalid Qt Versions"),
+ tr("Do you want to remove all invalid Qt Versions?<br>"
+ "<ul><li>%1</li></ul><br>"
+ "will be removed.").arg(toRemove.join(QLatin1String("</li><li>"))),
+ QMessageBox::Yes, QMessageBox::No) == QMessageBox::No)
+ return;
+
+ for (int i = m_versions.count() - 1; i >= 0; --i) {
+ if (!m_versions.at(i)->isValid()) {
+ QTreeWidgetItem *item = treeItemForIndex(i);
+ delete item;
+
+ delete m_versions.at(i);
+ m_versions.removeAt(i);
+ }
+ }
+ updateCleanUpButton();
+}
+
+void QtOptionsPageWidget::qtVersionsDumpUpdated(const QString &qmakeCommand)
+{
+ foreach (BaseQtVersion *version, m_versions) {
+ if (version->qmakeCommand() == qmakeCommand)
+ version->recheckDumper();
+ }
+ if (currentVersion()
+ && currentVersion()->qmakeCommand() == qmakeCommand) {
+ updateWidgets();
+ updateDescriptionLabel();
+ updateDebuggingHelperUi();
+ }
+}
+
+void QtOptionsPageWidget::buildDebuggingHelper(DebuggingHelperBuildTask::Tools tools)
+{
+ const int index = currentIndex();
+ if (index < 0)
+ return;
+
+ QTreeWidgetItem *item = treeItemForIndex(index);
+ QTC_ASSERT(item, return);
+
+ DebuggingHelperBuildTask::Tools buildFlags
+ = item->data(0, BuildRunningRole).value<DebuggingHelperBuildTask::Tools>();
+ buildFlags |= tools;
+ item->setData(0, BuildRunningRole, QVariant::fromValue(buildFlags));
+
+ BaseQtVersion *version = m_versions.at(index);
+ if (!version)
+ return;
+
+ updateDebuggingHelperUi();
+
+ // Run a debugging helper build task in the background.
+ DebuggingHelperBuildTask *buildTask = new DebuggingHelperBuildTask(version, tools);
+ // Don't open General Messages pane with errors
+ buildTask->showOutputOnError(false);
+ connect(buildTask, SIGNAL(finished(int,QString,DebuggingHelperBuildTask::Tools)),
+ this, SLOT(debuggingHelperBuildFinished(int,QString,DebuggingHelperBuildTask::Tools)),
+ Qt::QueuedConnection);
+ QFuture<void> task = QtConcurrent::run(&DebuggingHelperBuildTask::run, buildTask);
+ const QString taskName = tr("Building helpers");
+
+ Core::ICore::instance()->progressManager()->addTask(task, taskName,
+ QLatin1String("Qt4ProjectManager::BuildHelpers"));
+}
+void QtOptionsPageWidget::buildGdbHelper()
+{
+ buildDebuggingHelper(DebuggingHelperBuildTask::GdbDebugging);
+}
+
+void QtOptionsPageWidget::buildQmlDump()
+{
+ buildDebuggingHelper(DebuggingHelperBuildTask::QmlDump);
+}
+
+void QtOptionsPageWidget::buildQmlDebuggingLibrary()
+{
+ buildDebuggingHelper(DebuggingHelperBuildTask::QmlDebugging);
+}
+
+void QtOptionsPageWidget::buildQmlObserver()
+{
+ DebuggingHelperBuildTask::Tools qmlDbgTools =
+ DebuggingHelperBuildTask::QmlObserver;
+ qmlDbgTools |= DebuggingHelperBuildTask::QmlDebugging;
+ buildDebuggingHelper(qmlDbgTools);
+}
+
+// Non-modal dialog
+class BuildLogDialog : public QDialog {
+public:
+ explicit BuildLogDialog(QWidget *parent = 0);
+ void setText(const QString &text);
+
+private:
+ Ui_ShowBuildLog m_ui;
+};
+
+BuildLogDialog::BuildLogDialog(QWidget *parent) : QDialog(parent)
+{
+ m_ui.setupUi(this);
+ setAttribute(Qt::WA_DeleteOnClose, true);
+}
+
+void BuildLogDialog::setText(const QString &text)
+{
+ m_ui.log->setPlainText(text); // Show and scroll to bottom
+ m_ui.log->moveCursor(QTextCursor::End);
+ m_ui.log->ensureCursorVisible();
+}
+
+void QtOptionsPageWidget::slotShowDebuggingBuildLog()
+{
+ if (const QTreeWidgetItem *currentItem = m_ui->qtdirList->currentItem())
+ showDebuggingBuildLog(currentItem);
+}
+
+void QtOptionsPageWidget::showDebuggingBuildLog(const QTreeWidgetItem *currentItem)
+{
+ const int currentItemIndex = indexForTreeItem(currentItem);
+ if (currentItemIndex < 0)
+ return;
+ BuildLogDialog *dialog = new BuildLogDialog(this);
+ dialog->setWindowTitle(tr("Debugging Helper Build Log for '%1'").arg(currentItem->text(0)));
+ dialog->setText(currentItem->data(0, BuildLogRole).toString());
+ dialog->show();
+}
+
+QtOptionsPageWidget::~QtOptionsPageWidget()
+{
+ delete m_ui;
+ delete m_versionUi;
+ delete m_debuggingHelperUi;
+ delete m_configurationWidget;
+ qDeleteAll(m_versions);
+}
+
+void QtOptionsPageWidget::addQtDir()
+{
+ QString filter("qmake (");
+ foreach (const QString &s, Utils::BuildableHelperLibrary::possibleQMakeCommands()) {
+ filter += s + " ";
+ }
+ filter += ")";
+
+ QString qtVersion = QFileDialog::getOpenFileName(this,
+ tr("Select a qmake executable"), QString(), filter);
+ if (qtVersion.isNull())
+ return;
+ if (QtVersionManager::instance()->qtVersionForQMakeBinary(qtVersion)) {
+ // Already exist
+ }
+
+ BaseQtVersion *version = QtVersionFactory::createQtVersionFromQMakePath(qtVersion);
+ if (version) {
+ m_versions.append(version);
+
+ QTreeWidgetItem *item = new QTreeWidgetItem(m_ui->qtdirList->topLevelItem(1));
+ item->setText(0, version->displayName());
+ item->setText(1, QDir::toNativeSeparators(version->qmakeCommand()));
+ item->setData(0, VersionIdRole, version->uniqueId());
+ item->setIcon(0, version->isValid()? m_validVersionIcon : m_invalidVersionIcon);
+ m_ui->qtdirList->setCurrentItem(item); // should update the rest of the ui
+ m_versionUi->nameEdit->setFocus();
+ m_versionUi->nameEdit->selectAll();
+ }
+ updateCleanUpButton();
+}
+
+void QtOptionsPageWidget::removeQtDir()
+{
+ QTreeWidgetItem *item = m_ui->qtdirList->currentItem();
+ int index = indexForTreeItem(item);
+ if (index < 0)
+ return;
+
+ delete item;
+
+ BaseQtVersion *version = m_versions.at(index);
+ m_versions.removeAt(index);
+ delete version;
+ updateCleanUpButton();
+}
+
+void QtOptionsPageWidget::updateDebuggingHelperUi()
+{
+ BaseQtVersion *version = currentVersion();
+ const QTreeWidgetItem *currentItem = m_ui->qtdirList->currentItem();
+
+ if (!version || !version->isValid()) {
+ m_ui->debuggingHelperWidget->setVisible(false);
+ } else {
+ const DebuggingHelperBuildTask::Tools availableTools = DebuggingHelperBuildTask::availableTools(version);
+ const bool canBuildGdbHelper = availableTools & DebuggingHelperBuildTask::GdbDebugging;
+ const bool canBuildQmlDumper = availableTools & DebuggingHelperBuildTask::QmlDump;
+ const bool canBuildQmlDebuggingLib = availableTools & DebuggingHelperBuildTask::QmlDebugging;
+ const bool canBuildQmlObserver = availableTools & DebuggingHelperBuildTask::QmlObserver;
+
+ const bool hasGdbHelper = !version->gdbDebuggingHelperLibrary().isEmpty();
+ const bool hasQmlDumper = version->hasQmlDump();
+ const bool hasQmlDebuggingLib = version->hasQmlDebuggingLibrary();
+ const bool needsQmlDebuggingLib = version->needsQmlDebuggingLibrary();
+ const bool hasQmlObserver = !version->qmlObserverTool().isEmpty();
+
+ bool isBuildingGdbHelper = false;
+ bool isBuildingQmlDumper = false;
+ bool isBuildingQmlDebuggingLib = false;
+ bool isBuildingQmlObserver = false;
+
+ if (currentItem) {
+ DebuggingHelperBuildTask::Tools buildingTools
+ = currentItem->data(0, BuildRunningRole).value<DebuggingHelperBuildTask::Tools>();
+ isBuildingGdbHelper = buildingTools & DebuggingHelperBuildTask::GdbDebugging;
+ isBuildingQmlDumper = buildingTools & DebuggingHelperBuildTask::QmlDump;
+ isBuildingQmlDebuggingLib = buildingTools & DebuggingHelperBuildTask::QmlDebugging;
+ isBuildingQmlObserver = buildingTools & DebuggingHelperBuildTask::QmlObserver;
+ }
+
+ // get names of tools from labels
+ QStringList helperNames;
+ if (hasGdbHelper)
+ helperNames << m_debuggingHelperUi->gdbHelperLabel->text().remove(':');
+ if (hasQmlDumper)
+ helperNames << m_debuggingHelperUi->qmlDumpLabel->text().remove(':');
+ if (hasQmlDebuggingLib)
+ helperNames << m_debuggingHelperUi->qmlDebuggingLibLabel->text().remove(':');
+ if (hasQmlObserver)
+ helperNames << m_debuggingHelperUi->qmlObserverLabel->text().remove(':');
+
+ QString status;
+ if (helperNames.isEmpty()) {
+ status = tr("Helpers: None available");
+ } else {
+ //: %1 is list of tool names.
+ status = tr("Helpers: %1.").arg(helperNames.join(QLatin1String(", ")));
+ }
+
+ m_ui->debuggingHelperWidget->setSummaryText(status);
+
+ QString gdbHelperText;
+ Qt::TextInteractionFlags gdbHelperTextFlags = Qt::NoTextInteraction;
+ if (hasGdbHelper) {
+ gdbHelperText = QDir::toNativeSeparators(version->gdbDebuggingHelperLibrary());
+ gdbHelperTextFlags = Qt::TextSelectableByMouse;
+ } else {
+ if (canBuildGdbHelper) {
+ gdbHelperText = tr("<i>Not yet built.</i>");
+ } else {
+ gdbHelperText = tr("<i>Not needed.</i>");
+ }
+ }
+ m_debuggingHelperUi->gdbHelperStatus->setText(gdbHelperText);
+ m_debuggingHelperUi->gdbHelperStatus->setTextInteractionFlags(gdbHelperTextFlags);
+ m_debuggingHelperUi->gdbHelperBuildButton->setEnabled(canBuildGdbHelper && !isBuildingGdbHelper);
+
+ QString qmlDumpStatusText, qmlDumpStatusToolTip;
+ Qt::TextInteractionFlags qmlDumpStatusTextFlags = Qt::NoTextInteraction;
+ if (hasQmlDumper) {
+ qmlDumpStatusText = QDir::toNativeSeparators(version->qmlDumpTool(false));
+ const QString debugQmlDumpPath = QDir::toNativeSeparators(version->qmlDumpTool(true));
+ if (qmlDumpStatusText != debugQmlDumpPath) {
+ if (!qmlDumpStatusText.isEmpty()
+ && !debugQmlDumpPath.isEmpty())
+ qmlDumpStatusText += QLatin1String("\n");
+ qmlDumpStatusText += debugQmlDumpPath;
+ }
+ qmlDumpStatusTextFlags = Qt::TextSelectableByMouse;
+ } else {
+ if (canBuildQmlDumper) {
+ qmlDumpStatusText = tr("<i>Not yet built.</i>");
+ } else {
+ qmlDumpStatusText = tr("<i>Cannot be compiled.</i>");
+ QmlDumpTool::canBuild(version, &qmlDumpStatusToolTip);
+ }
+ }
+ m_debuggingHelperUi->qmlDumpStatus->setText(qmlDumpStatusText);
+ m_debuggingHelperUi->qmlDumpStatus->setTextInteractionFlags(qmlDumpStatusTextFlags);
+ m_debuggingHelperUi->qmlDumpStatus->setToolTip(qmlDumpStatusToolTip);
+ m_debuggingHelperUi->qmlDumpBuildButton->setEnabled(canBuildQmlDumper & !isBuildingQmlDumper);
+
+ QString qmlDebuggingLibStatusText, qmlDebuggingLibToolTip;
+ Qt::TextInteractionFlags qmlDebuggingLibStatusTextFlags = Qt::NoTextInteraction;
+ if (hasQmlDebuggingLib) {
+ qmlDebuggingLibStatusText = QDir::toNativeSeparators(
+ version->qmlDebuggingHelperLibrary(false));
+ const QString debugPath = QDir::toNativeSeparators(
+ version->qmlDebuggingHelperLibrary(true));
+
+ if (qmlDebuggingLibStatusText != debugPath) {
+ if (!qmlDebuggingLibStatusText.isEmpty()
+ && !debugPath.isEmpty()) {
+ qmlDebuggingLibStatusText += QLatin1Char('\n');
+ }
+ qmlDebuggingLibStatusText += debugPath;
+ }
+ qmlDebuggingLibStatusTextFlags = Qt::TextSelectableByMouse;
+ } else {
+ if (!needsQmlDebuggingLib) {
+ qmlDebuggingLibStatusText = tr("<i>Not needed.</i>");
+ } else if (canBuildQmlDebuggingLib) {
+ qmlDebuggingLibStatusText = tr("<i>Not yet built.</i>");
+ } else {
+ qmlDebuggingLibStatusText = tr("<i>Cannot be compiled.</i>");
+ QmlDebuggingLibrary::canBuild(version, &qmlDebuggingLibToolTip);
+ }
+ }
+ m_debuggingHelperUi->qmlDebuggingLibStatus->setText(qmlDebuggingLibStatusText);
+ m_debuggingHelperUi->qmlDebuggingLibStatus->setTextInteractionFlags(qmlDebuggingLibStatusTextFlags);
+ m_debuggingHelperUi->qmlDebuggingLibStatus->setToolTip(qmlDebuggingLibToolTip);
+ m_debuggingHelperUi->qmlDebuggingLibBuildButton->setEnabled(needsQmlDebuggingLib
+ && canBuildQmlDebuggingLib
+ && !isBuildingQmlDebuggingLib);
+
+ QString qmlObserverStatusText, qmlObserverToolTip;
+ Qt::TextInteractionFlags qmlObserverStatusTextFlags = Qt::NoTextInteraction;
+ if (hasQmlObserver) {
+ qmlObserverStatusText = QDir::toNativeSeparators(version->qmlObserverTool());
+ qmlObserverStatusTextFlags = Qt::TextSelectableByMouse;
+ } else {
+ if (!needsQmlDebuggingLib) {
+ qmlObserverStatusText = tr("<i>Not needed.</i>");
+ } else if (canBuildQmlObserver) {
+ qmlObserverStatusText = tr("<i>Not yet built.</i>");
+ } else {
+ qmlObserverStatusText = tr("<i>Cannot be compiled.</i>");
+ QmlObserverTool::canBuild(version, &qmlObserverToolTip);
+ }
+ }
+ m_debuggingHelperUi->qmlObserverStatus->setText(qmlObserverStatusText);
+ m_debuggingHelperUi->qmlObserverStatus->setTextInteractionFlags(qmlObserverStatusTextFlags);
+ m_debuggingHelperUi->qmlObserverStatus->setToolTip(qmlObserverToolTip);
+ m_debuggingHelperUi->qmlObserverBuildButton->setEnabled(canBuildQmlObserver
+ & !isBuildingQmlObserver);
+
+ const bool hasLog = currentItem && !currentItem->data(0, BuildLogRole).toString().isEmpty();
+ m_debuggingHelperUi->showLogButton->setEnabled(hasLog);
+
+ m_debuggingHelperUi->rebuildButton->setEnabled((!isBuildingGdbHelper
+ && !isBuildingQmlDumper
+ && !isBuildingQmlDebuggingLib
+ && !isBuildingQmlObserver)
+ && (canBuildGdbHelper
+ || canBuildQmlDumper
+ || (canBuildQmlDebuggingLib && needsQmlDebuggingLib)
+ || canBuildQmlObserver));
+
+ m_ui->debuggingHelperWidget->setVisible(true);
+ }
+}
+
+// To be called if a qt version was removed or added
+void QtOptionsPageWidget::updateCleanUpButton()
+{
+ bool hasInvalidVersion = false;
+ for (int i = 0; i < m_versions.count(); ++i) {
+ if (!m_versions.at(i)->isValid()) {
+ hasInvalidVersion = true;
+ break;
+ }
+ }
+ m_ui->cleanUpButton->setEnabled(hasInvalidVersion);
+}
+
+void QtOptionsPageWidget::userChangedCurrentVersion()
+{
+ updateWidgets();
+ updateDescriptionLabel();
+ updateDebuggingHelperUi();
+}
+
+void QtOptionsPageWidget::qtVersionChanged()
+{
+ updateDescriptionLabel();
+ updateDebuggingHelperUi();
+}
+
+void QtOptionsPageWidget::updateDescriptionLabel()
+{
+ QTreeWidgetItem *item = m_ui->qtdirList->currentItem();
+ const BaseQtVersion *version = currentVersion();
+ if (!version) {
+ m_versionUi->errorLabel->setText(QString());
+ } else if (version->isValid()) {
+ m_versionUi->errorLabel->setText( tr("Qt version %1 for %2").arg(version->qtVersionString(),
+ version->description()));
+ item->setIcon(0, m_validVersionIcon);
+ } else {
+ m_versionUi->errorLabel->setText(version->invalidReason());
+ item->setIcon(0, m_invalidVersionIcon);
+ }
+}
+
+int QtOptionsPageWidget::indexForTreeItem(const QTreeWidgetItem *item) const
+{
+ if (!item || !item->parent())
+ return -1;
+ const int uniqueId = item->data(0, VersionIdRole).toInt();
+ for (int index = 0; index < m_versions.size(); ++index) {
+ if (m_versions.at(index)->uniqueId() == uniqueId)
+ return index;
+ }
+ return -1;
+}
+
+QTreeWidgetItem *QtOptionsPageWidget::treeItemForIndex(int index) const
+{
+ const int uniqueId = m_versions.at(index)->uniqueId();
+ for (int i = 0; i < m_ui->qtdirList->topLevelItemCount(); ++i) {
+ QTreeWidgetItem *toplevelItem = m_ui->qtdirList->topLevelItem(i);
+ for (int j = 0; j < toplevelItem->childCount(); ++j) {
+ QTreeWidgetItem *item = toplevelItem->child(j);
+ if (item->data(0, VersionIdRole).toInt() == uniqueId) {
+ return item;
+ }
+ }
+ }
+ return 0;
+}
+
+void QtOptionsPageWidget::versionChanged(QTreeWidgetItem *newItem, QTreeWidgetItem *old)
+{
+ Q_UNUSED(newItem)
+ if (old)
+ fixQtVersionName(indexForTreeItem(old));
+ userChangedCurrentVersion();
+}
+
+void QtOptionsPageWidget::updateWidgets()
+{
+ delete m_configurationWidget;
+ m_configurationWidget = 0;
+ BaseQtVersion *version = currentVersion();
+ if (version) {
+ m_versionUi->nameEdit->setText(version->displayName());
+ m_versionUi->qmakePath->setText(QDir::toNativeSeparators(version->qmakeCommand()));
+ m_configurationWidget = version->createConfigurationWidget();
+ if (m_configurationWidget) {
+ m_versionUi->formLayout->addRow(m_configurationWidget);
+ m_configurationWidget->setEnabled(!version->isAutodetected());
+ connect(m_configurationWidget, SIGNAL(changed()),
+ this, SLOT(qtVersionChanged()));
+ }
+ } else {
+ m_versionUi->nameEdit->clear();
+ m_versionUi->qmakePath->setText(QString()); // clear()
+ }
+
+ const bool enabled = version != 0;
+ const bool isAutodetected = enabled && version->isAutodetected();
+ m_ui->delButton->setEnabled(enabled && !isAutodetected);
+ m_versionUi->nameEdit->setEnabled(enabled && !isAutodetected);
+}
+
+void QtOptionsPageWidget::updateCurrentQtName()
+{
+ QTreeWidgetItem *currentItem = m_ui->qtdirList->currentItem();
+ Q_ASSERT(currentItem);
+ int currentItemIndex = indexForTreeItem(currentItem);
+ if (currentItemIndex < 0)
+ return;
+ m_versions[currentItemIndex]->setDisplayName(m_versionUi->nameEdit->text());
+ currentItem->setText(0, m_versions[currentItemIndex]->displayName());
+ updateDescriptionLabel();
+}
+
+
+void QtOptionsPageWidget::finish()
+{
+ if (QTreeWidgetItem *item = m_ui->qtdirList->currentItem())
+ fixQtVersionName(indexForTreeItem(item));
+}
+
+/* Checks that the qt version name is unique
+ * and otherwise changes the name
+ *
+ */
+void QtOptionsPageWidget::fixQtVersionName(int index)
+{
+ if (index < 0)
+ return;
+ int count = m_versions.count();
+ QString name = m_versions.at(index)->displayName();
+ if (name.isEmpty())
+ return;
+ for (int i = 0; i < count; ++i) {
+ if (i != index) {
+ if (m_versions.at(i)->displayName() == m_versions.at(index)->displayName()) {
+ // Same name, find new name
+ QRegExp regexp("^(.*)\\((\\d)\\)$");
+ if (regexp.exactMatch(name)) {
+ // Already in Name (#) format
+ name = regexp.cap(1);
+ name += QLatin1Char('(');
+ name += QString::number(regexp.cap(2).toInt() + 1);
+ name += QLatin1Char(')');
+ } else {
+ name += QLatin1String(" (2)");
+ }
+ // set new name
+ m_versions[index]->setDisplayName(name);
+ treeItemForIndex(index)->setText(0, name);
+
+ // Now check again...
+ fixQtVersionName(index);
+ }
+ }
+ }
+}
+
+QList<BaseQtVersion *> QtOptionsPageWidget::versions() const
+{
+ QList<BaseQtVersion *> result;
+ for (int i = 0; i < m_versions.count(); ++i)
+ result.append(m_versions.at(i)->clone());
+ return result;
+}
+
+QString QtOptionsPageWidget::searchKeywords() const
+{
+ QString rc;
+ QLatin1Char sep(' ');
+ QTextStream ts(&rc);
+ ts << sep << m_versionUi->versionNameLabel->text()
+ << sep << m_versionUi->pathLabel->text()
+ << sep << m_debuggingHelperUi->gdbHelperLabel->text()
+ << sep << m_debuggingHelperUi->qmlDumpLabel->text()
+ << sep << m_debuggingHelperUi->qmlObserverLabel->text();
+
+ // Symbian specific, could be factored out to the factory
+ // checking m_configurationWidget is not enough, we want them to be a keyword
+ // regardless of which qt versions configuration widget is currently active
+ ts << sep << tr("S60 SDK:")
+ << sep << tr("SBS v2 directory:");
+
+
+ rc.remove(QLatin1Char('&'));
+ return rc;
+}
diff --git a/src/plugins/qtsupport/qtoptionspage.h b/src/plugins/qtsupport/qtoptionspage.h
new file mode 100644
index 0000000000..f8eff141dd
--- /dev/null
+++ b/src/plugins/qtsupport/qtoptionspage.h
@@ -0,0 +1,138 @@
+/**************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2011 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Nokia Corporation (info@qt.nokia.com)
+**
+**
+** GNU Lesser General Public License Usage
+**
+** 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.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** Other Usage
+**
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at info@qt.nokia.com.
+**
+**************************************************************************/
+
+#ifndef QTOPTIONSPAGE_H
+#define QTOPTIONSPAGE_H
+
+#include "debugginghelperbuildtask.h"
+#include <coreplugin/dialogs/ioptionspage.h>
+
+#include <QtGui/QWidget>
+#include <QtGui/QIcon>
+
+QT_BEGIN_NAMESPACE
+class QTreeWidgetItem;
+QT_END_NAMESPACE
+
+namespace QtSupport {
+
+class BaseQtVersion;
+class QtConfigWidget;
+
+namespace Internal {
+namespace Ui {
+class QtVersionManager;
+class QtVersionInfo;
+class DebuggingHelper;
+}
+
+class QtOptionsPageWidget : public QWidget
+{
+ Q_OBJECT
+ Q_DISABLE_COPY(QtOptionsPageWidget)
+public:
+ QtOptionsPageWidget(QWidget *parent, QList<BaseQtVersion *> versions);
+ ~QtOptionsPageWidget();
+ QList<BaseQtVersion *> versions() const;
+ void finish();
+ QString searchKeywords() const;
+
+ virtual bool eventFilter(QObject *o, QEvent *e);
+
+private:
+ void updateDescriptionLabel();
+ void userChangedCurrentVersion();
+ void updateWidgets();
+ void updateDebuggingHelperUi();
+ void fixQtVersionName(int index);
+ int indexForTreeItem(const QTreeWidgetItem *item) const;
+ QTreeWidgetItem *treeItemForIndex(int index) const;
+ BaseQtVersion *currentVersion() const;
+ int currentIndex() const;
+ void showDebuggingBuildLog(const QTreeWidgetItem *currentItem);
+
+ const QString m_specifyNameString;
+
+ Internal::Ui::QtVersionManager *m_ui;
+ Internal::Ui::QtVersionInfo *m_versionUi;
+ Internal::Ui::DebuggingHelper *m_debuggingHelperUi;
+ QList<BaseQtVersion *> m_versions;
+ int m_defaultVersion;
+ QIcon m_invalidVersionIcon;
+ QIcon m_validVersionIcon;
+ QtConfigWidget *m_configurationWidget;
+
+private slots:
+ void qtVersionChanged();
+ void versionChanged(QTreeWidgetItem *item, QTreeWidgetItem *old);
+ void addQtDir();
+ void removeQtDir();
+ void updateCleanUpButton();
+ void updateCurrentQtName();
+ void buildDebuggingHelper(DebuggingHelperBuildTask::Tools tools
+ = DebuggingHelperBuildTask::AllTools);
+ void buildGdbHelper();
+ void buildQmlDump();
+ void buildQmlDebuggingLibrary();
+ void buildQmlObserver();
+ void slotShowDebuggingBuildLog();
+ void debuggingHelperBuildFinished(int qtVersionId, const QString &output, DebuggingHelperBuildTask::Tools tools);
+ void cleanUpQtVersions();
+
+ void qtVersionsDumpUpdated(const QString &qmakeCommand);
+};
+
+class QtOptionsPage : public Core::IOptionsPage
+{
+ Q_OBJECT
+public:
+ QtOptionsPage();
+ QString id() const;
+ QString displayName() const;
+ QString category() const;
+ QString displayCategory() const;
+ QIcon categoryIcon() const;
+ QWidget *createPage(QWidget *parent);
+ void apply();
+ void finish() {}
+ virtual bool matches(const QString &) const;
+
+private:
+ QtOptionsPageWidget *m_widget;
+ QString m_searchKeywords;
+};
+
+} //namespace Internal
+} //namespace Qt4ProjectManager
+
+
+#endif // QTOPTIONSPAGE_H
diff --git a/src/plugins/qtsupport/qtoutputformatter.cpp b/src/plugins/qtsupport/qtoutputformatter.cpp
new file mode 100644
index 0000000000..036521ac52
--- /dev/null
+++ b/src/plugins/qtsupport/qtoutputformatter.cpp
@@ -0,0 +1,268 @@
+/**************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2011 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Nokia Corporation (info@qt.nokia.com)
+**
+**
+** GNU Lesser General Public License Usage
+**
+** 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.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** Other Usage
+**
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at info@qt.nokia.com.
+**
+**************************************************************************/
+
+#include "qtoutputformatter.h"
+
+#include <texteditor/basetexteditor.h>
+#include <qt4projectmanager/qt4project.h>
+#include <utils/qtcassert.h>
+
+#include <QtCore/QFileInfo>
+#include <QtCore/QUrl>
+#include <QtGui/QPlainTextEdit>
+#include <QtGui/QTextCursor>
+
+using namespace ProjectExplorer;
+using namespace QtSupport;
+
+QtOutputFormatter::QtOutputFormatter(ProjectExplorer::Project *project)
+ : OutputFormatter()
+ , m_qmlError(QLatin1String("^(?:\\[Qt Message\\] )?" // '[Qt Message] ' prefix (optional, on Symbian)
+ "(file:///.+" // file url
+ ":\\d+" // colon, line
+ "(?::\\d+)?)" // colon, column (optional)
+ ":")) // colon
+ , m_qtError(QLatin1String("Object::.*in (.*:\\d+)"))
+ , m_qtAssert(QLatin1String("ASSERT: .* in file (.+, line \\d+)"))
+ , m_qtTestFail(QLatin1String("^ Loc: \\[(.*)\\]"))
+ , m_project(project)
+{
+ if(project) {
+ m_projectFinder.setProjectFiles(project->files(Project::ExcludeGeneratedFiles));
+ m_projectFinder.setProjectDirectory(project->projectDirectory());
+
+ connect(project, SIGNAL(fileListChanged()),
+ this, SLOT(updateProjectFileList()));
+ }
+}
+
+LinkResult QtOutputFormatter::matchLine(const QString &line) const
+{
+ LinkResult lr;
+ lr.start = -1;
+ lr.end = -1;
+
+ if (m_qmlError.indexIn(line) != -1) {
+ lr.href = m_qmlError.cap(1);
+ lr.start = m_qmlError.pos(1);
+ lr.end = lr.start + lr.href.length();
+ } else if (m_qtError.indexIn(line) != -1) {
+ lr.href = m_qtError.cap(1);
+ lr.start = m_qtError.pos(1);
+ lr.end = lr.start + lr.href.length();
+ } else if (m_qtAssert.indexIn(line) != -1) {
+ lr.href = m_qtAssert.cap(1);
+ lr.start = m_qtAssert.pos(1);
+ lr.end = lr.start + lr.href.length();
+ } else if (m_qtTestFail.indexIn(line) != -1) {
+ lr.href = m_qtTestFail.cap(1);
+ lr.start = m_qtTestFail.pos(1);
+ lr.end = lr.start + lr.href.length();
+ }
+ return lr;
+}
+
+void QtOutputFormatter::appendMessage(const QString &txt, Utils::OutputFormat format)
+{
+ QTextCursor cursor(plainTextEdit()->document());
+ cursor.movePosition(QTextCursor::End);
+ cursor.beginEditBlock();
+
+ QString text = txt;
+ text.remove(QLatin1Char('\r'));
+
+ QString deferedText;
+
+ int start = 0;
+ int pos = txt.indexOf(QLatin1Char('\n'));
+ while (pos != -1) {
+ // Line identified
+ if (!m_lastLine.isEmpty()) {
+ // Line continuation
+ const QString newPart = txt.mid(start, pos - start + 1);
+ const QString line = m_lastLine + newPart;
+ LinkResult lr = matchLine(line);
+ if (!lr.href.isEmpty()) {
+ // Found something && line continuation
+ cursor.insertText(deferedText, charFormat(format));
+ deferedText.clear();
+ clearLastLine();
+ appendLine(cursor, lr, line, format);
+ } else {
+ // Found nothing, just emit the new part
+ deferedText += newPart;
+ }
+ // Handled line continuation
+ m_lastLine.clear();
+ } else {
+ const QString line = txt.mid(start, pos - start + 1);
+ LinkResult lr = matchLine(line);
+ if (!lr.href.isEmpty()) {
+ cursor.insertText(deferedText, charFormat(format));
+ deferedText.clear();
+ appendLine(cursor, lr, line, format);
+ } else {
+ deferedText += line;
+ }
+ }
+ start = pos + 1;
+ pos = txt.indexOf(QLatin1Char('\n'), start);
+ }
+
+ // Handle left over stuff
+ if (start < txt.length()) {
+ if (!m_lastLine.isEmpty()) {
+ // Line continuation
+ const QString newPart = txt.mid(start);
+ m_lastLine.append(newPart);
+ LinkResult lr = matchLine(m_lastLine);
+ if (!lr.href.isEmpty()) {
+ // Found something && line continuation
+ cursor.insertText(deferedText, charFormat(format));
+ deferedText.clear();
+ clearLastLine();
+ appendLine(cursor, lr, m_lastLine, format);
+ } else {
+ // Found nothing, just emit the new part
+ deferedText += newPart;
+ }
+ } else {
+ m_lastLine = txt.mid(start);
+ LinkResult lr = matchLine(m_lastLine);
+ if (!lr.href.isEmpty()) {
+ cursor.insertText(deferedText, charFormat(format));
+ deferedText.clear();
+ appendLine(cursor, lr, m_lastLine, format);
+ } else {
+ deferedText += m_lastLine;
+ }
+ }
+ }
+ cursor.insertText(deferedText, charFormat(format));
+ // deferedText.clear();
+ cursor.endEditBlock();
+}
+
+void QtOutputFormatter::appendLine(QTextCursor &cursor, LinkResult lr,
+ const QString &line, Utils::OutputFormat format)
+{
+ const QTextCharFormat normalFormat = charFormat(format);
+ cursor.insertText(line.left(lr.start), normalFormat);
+
+ QTextCharFormat linkFormat = normalFormat;
+ const QColor textColor = plainTextEdit()->palette().color(QPalette::Text);
+ linkFormat.setForeground(mixColors(textColor, QColor(Qt::blue)));
+ linkFormat.setUnderlineStyle(QTextCharFormat::SingleUnderline);
+ linkFormat.setAnchor(true);
+ linkFormat.setAnchorHref(lr.href);
+ cursor.insertText(line.mid(lr.start, lr.end - lr.start), linkFormat);
+ cursor.insertText(line.mid(lr.end), normalFormat);
+}
+
+void QtOutputFormatter::handleLink(const QString &href)
+{
+ if (!href.isEmpty()) {
+ const QRegExp qmlLineColumnLink(QLatin1String("^(file:///.+)" // file url
+ ":(\\d+)" // line
+ ":(\\d+)$")); // column
+
+ if (qmlLineColumnLink.indexIn(href) != -1) {
+ const QString fileName = QUrl(qmlLineColumnLink.cap(1)).toLocalFile();
+ const int line = qmlLineColumnLink.cap(2).toInt();
+ const int column = qmlLineColumnLink.cap(3).toInt();
+
+ TextEditor::BaseTextEditorWidget::openEditorAt(m_projectFinder.findFile(fileName), line, column - 1);
+
+ return;
+ }
+
+ const QRegExp qmlLineLink(QLatin1String("^(file:///.+)" // file url
+ ":(\\d+)$")); // line
+
+ if (qmlLineLink.indexIn(href) != -1) {
+ const QString fileName = QUrl(qmlLineLink.cap(1)).toLocalFile();
+ const int line = qmlLineLink.cap(2).toInt();
+ TextEditor::BaseTextEditorWidget::openEditorAt(m_projectFinder.findFile(fileName), line);
+ return;
+ }
+
+ QString fileName;
+ int line = -1;
+
+ QRegExp qtErrorLink(QLatin1String("^(.*):(\\d+)$"));
+ if (qtErrorLink.indexIn(href) != -1) {
+ fileName = qtErrorLink.cap(1);
+ line = qtErrorLink.cap(2).toInt();
+ }
+
+ QRegExp qtAssertLink(QLatin1String("^(.+), line (\\d+)$"));
+ if (qtAssertLink.indexIn(href) != -1) {
+ fileName = qtAssertLink.cap(1);
+ line = qtAssertLink.cap(2).toInt();
+ }
+
+ QRegExp qtTestFailLink(QLatin1String("^(.*)\\((\\d+)\\)$"));
+ if (qtTestFailLink.indexIn(href) != -1) {
+ fileName = qtTestFailLink.cap(1);
+ line = qtTestFailLink.cap(2).toInt();
+ }
+
+ if (!fileName.isEmpty()) {
+ QFileInfo fi(fileName);
+ if (fi.isRelative()) {
+ // Yeah fileName is relative, no surprise
+ ProjectExplorer::Project *pro = m_project.data();
+ if (pro) {
+ QString baseName = fi.fileName();
+ foreach (const QString &file, pro->files(Project::AllFiles)) {
+ if (file.endsWith(baseName)) {
+ // pick the first one...
+ fileName = file;
+ break;
+ }
+ }
+ }
+ } else if (!fi.exists()) {
+ // map possible on-device path to source path
+ fileName = m_projectFinder.findFile(fileName);
+ }
+ TextEditor::BaseTextEditorWidget::openEditorAt(fileName, line, 0);
+ return;
+ }
+ }
+}
+
+void QtOutputFormatter::updateProjectFileList()
+{
+ if (m_project)
+ m_projectFinder.setProjectFiles(m_project.data()->files(Project::ExcludeGeneratedFiles));
+}
diff --git a/src/plugins/qtsupport/qtoutputformatter.h b/src/plugins/qtsupport/qtoutputformatter.h
new file mode 100644
index 0000000000..b120650aec
--- /dev/null
+++ b/src/plugins/qtsupport/qtoutputformatter.h
@@ -0,0 +1,91 @@
+/**************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2011 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Nokia Corporation (info@qt.nokia.com)
+**
+**
+** GNU Lesser General Public License Usage
+**
+** 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.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** Other Usage
+**
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at info@qt.nokia.com.
+**
+**************************************************************************/
+
+#ifndef QTOUTPUTFORMATTER_H
+#define QTOUTPUTFORMATTER_H
+
+#include "qtsupport_global.h"
+
+#include <utils/outputformatter.h>
+#include <utils/fileinprojectfinder.h>
+
+#include <QtCore/QRegExp>
+#include <QtCore/QWeakPointer>
+
+QT_FORWARD_DECLARE_CLASS(QTextCursor)
+
+namespace ProjectExplorer {
+class Project;
+} // namespace ProjectExplorer
+
+namespace QtSupport {
+
+struct LinkResult
+{
+ int start;
+ int end;
+ QString href;
+};
+
+class QTSUPPORT_EXPORT QtOutputFormatter
+ : public Utils::OutputFormatter
+{
+ Q_OBJECT
+public:
+ QtOutputFormatter(ProjectExplorer::Project *project);
+
+ virtual void appendMessage(const QString &text,
+ Utils::OutputFormat format);
+ virtual void handleLink(const QString &href);
+
+private slots:
+ void updateProjectFileList();
+
+private:
+ LinkResult matchLine(const QString &line) const;
+ void appendLine(QTextCursor & cursor, LinkResult lr,
+ const QString &line, Utils::OutputFormat);
+
+ QRegExp m_qmlError;
+ QRegExp m_qtError;
+ QRegExp m_qtAssert;
+ QRegExp m_qtTestFail;
+ QWeakPointer<ProjectExplorer::Project> m_project;
+ QString m_lastLine;
+ QString m_deferedText;
+ Utils::FileInProjectFinder m_projectFinder;
+};
+
+
+} // namespace QtSupport
+
+#endif // QTOUTPUTFORMATTER_H
diff --git a/src/plugins/qtsupport/qtsupport.pri b/src/plugins/qtsupport/qtsupport.pri
new file mode 100644
index 0000000000..834156ccd6
--- /dev/null
+++ b/src/plugins/qtsupport/qtsupport.pri
@@ -0,0 +1,4 @@
+include(qtsupport_dependencies.pri)
+
+LIBS *= -l$$qtLibraryName(QtSupport)
+DEFINES += PROPARSER_AS_LIBRARY PROPARSER_THREAD_SAFE PROEVALUATOR_THREAD_SAFE
diff --git a/src/plugins/qtsupport/qtsupport.pro b/src/plugins/qtsupport/qtsupport.pro
new file mode 100644
index 0000000000..5c3484d0b0
--- /dev/null
+++ b/src/plugins/qtsupport/qtsupport.pro
@@ -0,0 +1,46 @@
+TEMPLATE = lib
+TARGET = QtSupport
+DEFINES += QT_CREATOR QTSUPPORT_LIBRARY
+QT += network
+include(../../qtcreatorplugin.pri)
+include(qtsupport_dependencies.pri)
+DEFINES += PROPARSER_AS_LIBRARY PROPARSER_LIBRARY PROPARSER_THREAD_SAFE PROEVALUATOR_THREAD_SAFE
+include(../../shared/proparser/proparser.pri)
+
+HEADERS += \
+ qtsupportplugin.h \
+ qtsupport_global.h \
+ qtoutputformatter.h \
+ qtversionmanager.h \
+ qtversionfactory.h \
+ baseqtversion.h \
+ qmldumptool.h \
+ qmlobservertool.h \
+ qmldebugginglibrary.h \
+ qtoptionspage.h \
+ debugginghelperbuildtask.h \
+ qtsupportconstants.h \
+ profilereader.h \
+
+SOURCES += \
+ qtsupportplugin.cpp \
+ qtoutputformatter.cpp \
+ qtversionmanager.cpp \
+ qtversionfactory.cpp \
+ baseqtversion.cpp \
+ qmldumptool.cpp \
+ qmlobservertool.cpp \
+ qmldebugginglibrary.cpp \
+ qtoptionspage.cpp \
+ debugginghelperbuildtask.cpp \
+ profilereader.cpp \
+
+FORMS += \
+ showbuildlog.ui \
+ qtversioninfo.ui \
+ debugginghelper.ui \
+ qtversionmanager.ui \
+
+
+DEFINES += QT_NO_CAST_TO_ASCII
+
diff --git a/src/plugins/qtsupport/qtsupport_dependencies.pri b/src/plugins/qtsupport/qtsupport_dependencies.pri
new file mode 100644
index 0000000000..7f68594566
--- /dev/null
+++ b/src/plugins/qtsupport/qtsupport_dependencies.pri
@@ -0,0 +1,2 @@
+include(../../plugins/projectexplorer/projectexplorer.pri)
+include(../../libs/qmljs/qmljs.pri)
diff --git a/src/plugins/qtsupport/qtsupport_global.h b/src/plugins/qtsupport/qtsupport_global.h
new file mode 100644
index 0000000000..b38eda4c6a
--- /dev/null
+++ b/src/plugins/qtsupport/qtsupport_global.h
@@ -0,0 +1,44 @@
+/**************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2011 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Nokia Corporation (info@qt.nokia.com)
+**
+**
+** GNU Lesser General Public License Usage
+**
+** 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.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** Other Usage
+**
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at info@qt.nokia.com.
+**
+**************************************************************************/
+
+#ifndef QTSUPPORT_GLOBAL_H
+#define QTSUPPORT_GLOBAL_H
+
+#include <QtCore/qglobal.h>
+
+#if defined(QTSUPPORT_LIBRARY)
+# define QTSUPPORT_EXPORT Q_DECL_EXPORT
+#else
+# define QTSUPPORT_EXPORT Q_DECL_IMPORT
+#endif
+
+#endif
diff --git a/src/plugins/qtsupport/qtsupportconstants.h b/src/plugins/qtsupport/qtsupportconstants.h
new file mode 100644
index 0000000000..802dabdd55
--- /dev/null
+++ b/src/plugins/qtsupport/qtsupportconstants.h
@@ -0,0 +1,63 @@
+/**************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2011 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Nokia Corporation (info@qt.nokia.com)
+**
+**
+** GNU Lesser General Public License Usage
+**
+** 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.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** Other Usage
+**
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at info@qt.nokia.com.
+**
+**************************************************************************/
+
+#ifndef QTSUPPORTCONSTANTS_H
+#define QTSUPPORTCONSTANTS_H
+
+namespace QtSupport {
+namespace Constants {
+
+//Qt4 settings pages
+const char * const QT_SETTINGS_CATEGORY = "L.Qt4";
+const char * const QT_SETTINGS_CATEGORY_ICON = ":/core/images/category_qt.png";
+const char * const QT_SETTINGS_TR_CATEGORY = QT_TRANSLATE_NOOP("Qt4ProjectManager", "Qt4");
+const char * const QTVERSION_SETTINGS_PAGE_ID = "Qt Versions";
+const char * const QTVERSION_SETTINGS_PAGE_NAME = QT_TRANSLATE_NOOP("Qt4ProjectManager", "Qt Versions");
+
+// QtVersions
+const char * const SYMBIANQT = "Qt4ProjectManager.QtVersion.Symbian";
+const char * const MAEMOQT = "Qt4ProjectManager.QtVersion.Maemo";
+const char * const DESKTOPQT = "Qt4ProjectManager.QtVersion.Desktop";
+const char * const SIMULATORQT = "Qt4ProjectManager.QtVersion.Simulator";
+const char * const WINCEQT = "Qt4ProjectManager.QtVersion.WinCE";
+
+// QML wizard categories
+// both the qt4projectmanager and the qmlprojectmanager do have qt quick wizards
+// so we define the category here
+const char * const QML_WIZARD_CATEGORY = "C.Projects"; // (before Qt)
+const char * const QML_WIZARD_TR_SCOPE = "QmlProjectManager";
+const char * const QML_WIZARD_TR_CATEGORY = QT_TRANSLATE_NOOP("QmlProjectManager", "Qt Quick Project");
+const char * const QML_WIZARD_ICON = ":/qmlproject/images/qml_wizard.png";
+
+}
+}
+#endif // QTSUPPORTCONSTANTS_H
diff --git a/src/plugins/qtsupport/qtsupportplugin.cpp b/src/plugins/qtsupport/qtsupportplugin.cpp
new file mode 100644
index 0000000000..2c2fc4093d
--- /dev/null
+++ b/src/plugins/qtsupport/qtsupportplugin.cpp
@@ -0,0 +1,71 @@
+/**************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2011 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Nokia Corporation (info@qt.nokia.com)
+**
+**
+** GNU Lesser General Public License Usage
+**
+** 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.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** Other Usage
+**
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at info@qt.nokia.com.
+**
+**************************************************************************/
+
+#include "qtsupportplugin.h"
+
+#include "qtoptionspage.h"
+#include "qtversionmanager.h"
+
+#include "profilereader.h"
+
+#include <extensionsystem/pluginmanager.h>
+
+#include <QtCore/QtPlugin>
+#include <QtGui/QMenu>
+
+using namespace QtSupport;
+using namespace QtSupport::Internal;
+
+QtSupportPlugin::~QtSupportPlugin()
+{
+}
+
+bool QtSupportPlugin::initialize(const QStringList &arguments, QString *errorMessage)
+{
+ Q_UNUSED(arguments);
+ Q_UNUSED(errorMessage);
+ ProFileParser::initialize();
+ ProFileEvaluator::initialize();
+ new ProFileCacheManager(this);
+
+ QtVersionManager *mgr = new QtVersionManager;
+ addAutoReleasedObject(mgr);
+ addAutoReleasedObject(new QtOptionsPage);
+ return true;
+}
+
+void QtSupportPlugin::extensionsInitialized()
+{
+ QtVersionManager::instance()->extensionsInitialized();
+}
+
+Q_EXPORT_PLUGIN(QtSupportPlugin)
diff --git a/src/plugins/qtsupport/qtsupportplugin.h b/src/plugins/qtsupport/qtsupportplugin.h
new file mode 100644
index 0000000000..15659040af
--- /dev/null
+++ b/src/plugins/qtsupport/qtsupportplugin.h
@@ -0,0 +1,57 @@
+/**************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2011 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Nokia Corporation (info@qt.nokia.com)
+**
+**
+** GNU Lesser General Public License Usage
+**
+** 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.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** Other Usage
+**
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at info@qt.nokia.com.
+**
+**************************************************************************/
+
+#ifndef QTSUPPORTPLUGIN_H
+#define QTSUPPORTPLUGIN_H
+
+#include <extensionsystem/iplugin.h>
+#include <coreplugin/icontext.h>
+
+
+namespace QtSupport {
+
+namespace Internal {
+
+class QtSupportPlugin : public ExtensionSystem::IPlugin
+{
+ Q_OBJECT
+
+public:
+ ~QtSupportPlugin();
+ bool initialize(const QStringList &arguments, QString *error_message);
+ void extensionsInitialized();
+};
+
+} // namespace Internal
+} // namespace QtSupport
+
+#endif // QTSUPPORTPLUGIN_H
diff --git a/src/plugins/qtsupport/qtversionfactory.cpp b/src/plugins/qtsupport/qtversionfactory.cpp
new file mode 100644
index 0000000000..8488993c78
--- /dev/null
+++ b/src/plugins/qtsupport/qtversionfactory.cpp
@@ -0,0 +1,102 @@
+/**************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2011 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Nokia Corporation (info@qt.nokia.com)
+**
+**
+** GNU Lesser General Public License Usage
+**
+** 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.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** Other Usage
+**
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at info@qt.nokia.com.
+**
+**************************************************************************/
+
+#include "qtversionfactory.h"
+#include "profilereader.h"
+#include "qtversionmanager.h"
+
+#include <extensionsystem/pluginmanager.h>
+#include <QtCore/QSettings>
+
+using namespace QtSupport;
+using namespace QtSupport::Internal;
+
+QtVersionFactory::QtVersionFactory(QObject *parent) :
+ QObject(parent)
+{
+
+}
+
+QtVersionFactory::~QtVersionFactory()
+{
+
+}
+
+bool sortByPriority(QtVersionFactory *a, QtVersionFactory *b)
+{
+ return a->priority() > b->priority();
+}
+
+BaseQtVersion *QtVersionFactory::createQtVersionFromLegacySettings(const QString &qmakePath, int id, QSettings *s)
+{
+ BaseQtVersion *v = createQtVersionFromQMakePath(qmakePath);
+ if (!v)
+ return 0;
+ v->setId(id);
+ v->setDisplayName(s->value("Name").toString());
+ v->restoreLegacySettings(s);
+ return v;
+}
+
+BaseQtVersion *QtVersionFactory::createQtVersionFromQMakePath(const QString &qmakePath, bool isAutoDetected, const QString &autoDetectionSource)
+{
+ QHash<QString, QString> versionInfo;
+ bool success = BaseQtVersion::queryQMakeVariables(qmakePath, &versionInfo);
+ if (!success)
+ return 0;
+ QString mkspec = BaseQtVersion::mkspecFromVersionInfo(versionInfo);
+
+ ProFileOption option;
+ option.properties = versionInfo;
+ ProMessageHandler msgHandler(true);
+ ProFileCacheManager::instance()->incRefCount();
+ ProFileParser parser(ProFileCacheManager::instance()->cache(), &msgHandler);
+ ProFileEvaluator evaluator(&option, &parser, &msgHandler);
+ if (ProFile *pro = parser.parsedProFile(mkspec + "/qmake.conf")) {
+ evaluator.setCumulative(false);
+ evaluator.accept(pro, ProFileEvaluator::LoadProOnly);
+ pro->deref();
+ }
+
+ QList<QtVersionFactory *> factories = ExtensionSystem::PluginManager::instance()->getObjects<QtVersionFactory>();
+ qSort(factories.begin(), factories.end(), &sortByPriority);
+
+ foreach (QtVersionFactory *factory, factories) {
+ BaseQtVersion *ver = factory->create(qmakePath, &evaluator, isAutoDetected, autoDetectionSource);
+ if (ver) {
+ ProFileCacheManager::instance()->decRefCount();
+ return ver;
+ }
+ }
+ ProFileCacheManager::instance()->decRefCount();
+ return 0;
+}
diff --git a/src/plugins/qtsupport/qtversionfactory.h b/src/plugins/qtsupport/qtversionfactory.h
new file mode 100644
index 0000000000..c4a157f5da
--- /dev/null
+++ b/src/plugins/qtsupport/qtversionfactory.h
@@ -0,0 +1,65 @@
+/**************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2011 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Nokia Corporation (info@qt.nokia.com)
+**
+**
+** GNU Lesser General Public License Usage
+**
+** 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.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** Other Usage
+**
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at info@qt.nokia.com.
+**
+**************************************************************************/
+
+#ifndef QTVERSIONFACTORY_H
+#define QTVERSIONFACTORY_H
+
+#include "baseqtversion.h"
+#include "qtsupport_global.h"
+
+#include <QtCore/QObject>
+#include <QtCore/QVariantMap>
+
+namespace QtSupport {
+
+class QTSUPPORT_EXPORT QtVersionFactory : public QObject
+{
+ Q_OBJECT
+public:
+ explicit QtVersionFactory(QObject *parent = 0);
+ ~QtVersionFactory();
+
+ virtual bool canRestore(const QString &type) = 0;
+ virtual BaseQtVersion *restore(const QVariantMap &data) = 0;
+
+ /// factories with higher priority are asked first to identify
+ /// a qtversion, the priority of the desktop factory is 0 and
+ /// the desktop factory claims to handle all paths
+ virtual int priority() const = 0;
+ virtual BaseQtVersion *create(const QString &qmakePath, ProFileEvaluator *evaluator, bool isAutoDetected = false, const QString &autoDetectionSource = QString()) = 0;
+
+ static BaseQtVersion *createQtVersionFromQMakePath(const QString &qmakePath, bool isAutoDetected = false, const QString &autoDetectionSource = QString());
+ static BaseQtVersion *createQtVersionFromLegacySettings(const QString &qmakePath, int id, QSettings *s);
+};
+
+}
+#endif // QTVERSIONFACTORY_H
diff --git a/src/plugins/qtsupport/qtversioninfo.ui b/src/plugins/qtsupport/qtversioninfo.ui
new file mode 100644
index 0000000000..02375e193d
--- /dev/null
+++ b/src/plugins/qtsupport/qtversioninfo.ui
@@ -0,0 +1,52 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<ui version="4.0">
+ <class>QtSupport::Internal::QtVersionInfo</class>
+ <widget class="QWidget" name="QtSupport::Internal::QtVersionInfo">
+ <property name="geometry">
+ <rect>
+ <x>0</x>
+ <y>0</y>
+ <width>222</width>
+ <height>70</height>
+ </rect>
+ </property>
+ <layout class="QFormLayout" name="formLayout">
+ <item row="0" column="0">
+ <widget class="QLabel" name="versionNameLabel">
+ <property name="text">
+ <string>Version name:</string>
+ </property>
+ </widget>
+ </item>
+ <item row="0" column="1">
+ <widget class="QLineEdit" name="nameEdit"/>
+ </item>
+ <item row="1" column="0">
+ <widget class="QLabel" name="pathLabel">
+ <property name="text">
+ <string>qmake location:</string>
+ </property>
+ </widget>
+ </item>
+ <item row="1" column="1">
+ <widget class="QLabel" name="qmakePath">
+ <property name="text">
+ <string/>
+ </property>
+ <property name="textInteractionFlags">
+ <set>Qt::LinksAccessibleByMouse|Qt::TextSelectableByMouse</set>
+ </property>
+ </widget>
+ </item>
+ <item row="2" column="0" colspan="2">
+ <widget class="QLabel" name="errorLabel">
+ <property name="text">
+ <string/>
+ </property>
+ </widget>
+ </item>
+ </layout>
+ </widget>
+ <resources/>
+ <connections/>
+</ui>
diff --git a/src/plugins/qtsupport/qtversionmanager.cpp b/src/plugins/qtsupport/qtversionmanager.cpp
new file mode 100644
index 0000000000..d403ac6557
--- /dev/null
+++ b/src/plugins/qtsupport/qtversionmanager.cpp
@@ -0,0 +1,927 @@
+/**************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2011 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Nokia Corporation (info@qt.nokia.com)
+**
+**
+** GNU Lesser General Public License Usage
+**
+** 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.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** Other Usage
+**
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at info@qt.nokia.com.
+**
+**************************************************************************/
+
+#include "qtversionmanager.h"
+
+#include "qtversionfactory.h"
+
+#include <projectexplorer/debugginghelper.h>
+#include <projectexplorer/persistentsettings.h>
+// only for legay restore
+#include <projectexplorer/projectexplorerconstants.h>
+#include <projectexplorer/toolchainmanager.h>
+#include <projectexplorer/gcctoolchain.h>
+
+#include <coreplugin/icore.h>
+#include <coreplugin/helpmanager.h>
+
+#include <extensionsystem/pluginmanager.h>
+
+#include <utils/qtcprocess.h>
+#include <utils/qtcassert.h>
+#ifdef Q_OS_WIN
+# include <utils/winutils.h>
+#endif
+
+#include <QtCore/QFile>
+#include <QtCore/QSettings>
+#include <QtCore/QTextStream>
+#include <QtCore/QDir>
+#include <QtGui/QMainWindow>
+
+#include <algorithm>
+
+using namespace QtSupport;
+using namespace QtSupport::Internal;
+
+using ProjectExplorer::DebuggingHelperLibrary;
+
+static const char QTVERSION_DATA_KEY[] = "QtVersion.";
+static const char QTVERSION_TYPE_KEY[] = "QtVersion.Type";
+static const char QTVERSION_COUNT_KEY[] = "QtVersion.Count";
+static const char OLDQTVERSION_COUNT_KEY[] = "QtVersion.Old.Count";
+static const char OLDQTVERSION_DATA_KEY[] = "QtVersion.Old.";
+static const char OLDQTVERSION_SDKSOURCE[] = "QtVersion.Old.SdkSource";
+static const char OLDQTVERSION_PATH[] = "QtVersion.Old.Path";
+static const char QTVERSION_FILE_VERSION_KEY[] = "Version";
+static const char QTVERSION_FILENAME[] = "/qtversion.xml";
+
+// legacy settings
+static const char QtVersionsSectionName[] = "QtVersions";
+
+enum { debug = 0 };
+
+template<class T>
+static T *createToolChain(const QString &id)
+{
+ QList<ProjectExplorer::ToolChainFactory *> factories =
+ ExtensionSystem::PluginManager::instance()->getObjects<ProjectExplorer::ToolChainFactory>();
+ foreach (ProjectExplorer::ToolChainFactory *f, factories) {
+ if (f->id() == id) {
+ Q_ASSERT(f->canCreate());
+ return static_cast<T *>(f->create());
+ }
+ }
+ return 0;
+}
+
+static QString settingsFileName()
+{
+ ExtensionSystem::PluginManager *pm = ExtensionSystem::PluginManager::instance();
+ QFileInfo settingsLocation(pm->settings()->fileName());
+ return settingsLocation.absolutePath() + QLatin1String(QTVERSION_FILENAME);
+}
+
+
+// prefer newer qts otherwise compare on id
+bool qtVersionNumberCompare(BaseQtVersion *a, BaseQtVersion *b)
+{
+ return a->qtVersion() > b->qtVersion() || (a->qtVersion() == b->qtVersion() && a->uniqueId() < b->uniqueId());
+}
+
+// --------------------------------------------------------------------------
+// QtVersionManager
+// --------------------------------------------------------------------------
+QtVersionManager *QtVersionManager::m_self = 0;
+
+QtVersionManager::QtVersionManager()
+{
+ m_self = this;
+ m_idcount = 1;
+}
+
+void QtVersionManager::extensionsInitialized()
+{
+ bool success = restoreQtVersions();
+ if (!success)
+ success = legacyRestore();
+ updateFromInstaller();
+ if (!success) {
+ // We did neither restore our settings or upgraded
+ // in that case figure out if there's a qt in path
+ // and add it to the qt versions
+ findSystemQt();
+ }
+ updateDocumentation();
+
+ updateSettings();
+ saveQtVersions();
+}
+
+QtVersionManager::~QtVersionManager()
+{
+ qDeleteAll(m_versions);
+ m_versions.clear();
+}
+
+QtVersionManager *QtVersionManager::instance()
+{
+ return m_self;
+}
+
+bool QtVersionManager::restoreQtVersions()
+{
+ ExtensionSystem::PluginManager *pm = ExtensionSystem::PluginManager::instance();
+ QList<QtVersionFactory *> factories = pm->getObjects<QtVersionFactory>();
+
+ ProjectExplorer::PersistentSettingsReader reader;
+ if (!reader.load(settingsFileName()))
+ return false;
+ QVariantMap data = reader.restoreValues();
+
+ // Check version:
+ int version = data.value(QLatin1String(QTVERSION_FILE_VERSION_KEY), 0).toInt();
+ if (version < 1)
+ return false;
+
+
+ int count = data.value(QLatin1String(QTVERSION_COUNT_KEY), 0).toInt();
+ for (int i = 0; i < count; ++i) {
+ const QString key = QString::fromLatin1(QTVERSION_DATA_KEY) + QString::number(i);
+ if (!data.contains(key))
+ break;
+
+ const QVariantMap qtversionMap = data.value(key).toMap();
+ const QString type = qtversionMap.value(QTVERSION_TYPE_KEY).toString();
+
+ bool restored = false;
+ foreach (QtVersionFactory *f, factories) {
+ if (f->canRestore(type)) {
+ if (BaseQtVersion *qtv = f->restore(qtversionMap)) {
+ if (m_versions.contains(qtv->uniqueId())) {
+ // This shouldn't happen, we are restoring the same id multiple times?
+ qWarning() << "A qt version with id"<<qtv->uniqueId()<<"already exists";
+ delete qtv;
+ } else {
+ m_versions.insert(qtv->uniqueId(), qtv);
+ m_idcount = qtv->uniqueId() > m_idcount ? qtv->uniqueId() : m_idcount;
+ restored = true;
+ break;
+ }
+ }
+ }
+ }
+ if (!restored)
+ qWarning("Warning: Unable to restore qtversion '%s' stored in %s.",
+ qPrintable(type),
+ qPrintable(QDir::toNativeSeparators(settingsFileName())));
+ }
+ ++m_idcount;
+ return true;
+}
+
+void QtVersionManager::updateFromInstaller()
+{
+ bool debug = true;
+ ExtensionSystem::PluginManager *pm = ExtensionSystem::PluginManager::instance();
+ QList<QtVersionFactory *> factories = pm->getObjects<QtVersionFactory>();
+ ProjectExplorer::PersistentSettingsReader reader;
+ if (!reader.load(Core::ICore::instance()->resourcePath()
+ + QLatin1String("/Nokia") + QLatin1String(QTVERSION_FILENAME)))
+ return;
+
+ QVariantMap data = reader.restoreValues();
+
+ if (debug) {
+ qDebug()<< "======= Existing qt versions =======";
+ foreach (BaseQtVersion *version, m_versions) {
+ qDebug() << version->qmakeCommand() << "id:"<<version->uniqueId();
+ qDebug() << " autodetection source:"<< version->autodetectionSource();
+ qDebug() << "";
+ }
+ }
+
+ int oldcount = data.value(QLatin1String(OLDQTVERSION_COUNT_KEY), 0).toInt();
+ for (int i=0; i < oldcount; ++i) {
+ const QString key = QString::fromLatin1(OLDQTVERSION_DATA_KEY) +QString::number(i);
+ if (!data.contains(key))
+ break;
+ QVariantMap map = data.value(key).toMap();
+ QString path = map.value(OLDQTVERSION_PATH).toString();
+#ifdef Q_OS_WIN
+ path = path.toLower();
+#endif
+ QString autodetectionSource = map.value(OLDQTVERSION_SDKSOURCE).toString();
+ foreach (BaseQtVersion *v, m_versions) {
+ if (v->qmakeCommand() == path) {
+ if (v->autodetectionSource().isEmpty()) {
+ v->setAutoDetectionSource(autodetectionSource);
+ } else {
+ if (debug)
+ qDebug() << "## Conflicting autodetictonSource for"<<path<<"\n"
+ <<" version retains"<<v->autodetectionSource();
+ }
+ // No break, we want to mark all qt versions matching that path
+ // There's no way for us to decide whether this qt was added
+ // by the user or by the installer, so we treat them all as coming
+ // from the installer. Thus removing/updating them deletes/updates them all
+ // Note: This only applies to versions that are marked via QtVersion.Old
+ }
+ }
+ }
+
+ if (debug) {
+ qDebug()<< "======= After using OLD QtVersion data to mark versions =======";
+ foreach (BaseQtVersion *version, m_versions) {
+ qDebug() << version->qmakeCommand() << "id:"<<version->uniqueId();
+ qDebug() << " autodetection source:"<< version->autodetectionSource();
+ qDebug() << "";
+ }
+
+ qDebug()<< "======= Adding sdk versions =======";
+ }
+ QStringList sdkVersions;
+ int count = data.value(QLatin1String(QTVERSION_COUNT_KEY), 0).toInt();
+ for (int i = 0; i < count; ++i) {
+ const QString key = QString::fromLatin1(QTVERSION_DATA_KEY) + QString::number(i);
+ if (!data.contains(key))
+ break;
+
+ QVariantMap qtversionMap = data.value(key).toMap();
+ const QString type = qtversionMap.value(QTVERSION_TYPE_KEY).toString();
+ const QString autoDetectionSource = qtversionMap.value(QLatin1String("autodetectionSource")).toString();
+ sdkVersions << autoDetectionSource;
+ int id = -1; // see BaseQtVersion::fromMap()
+ QtVersionFactory *factory = 0;
+ foreach (QtVersionFactory *f, factories) {
+ if (f->canRestore(type)) {
+ factory = f;
+ }
+ }
+ if (!factory) {
+ if (debug)
+ qDebug("Warning: Unable to find factory for type '%s'", qPrintable(type));
+ continue;
+ }
+ // First try to find a existing qt version to update
+ bool restored = false;
+ foreach (BaseQtVersion *v, m_versions) {
+ if (v->autodetectionSource() == autoDetectionSource) {
+ id = v->uniqueId();
+ if (debug)
+ qDebug() << " Qt version found with same autodetection source" << autoDetectionSource << " => Migrating id:" << id;
+ removeVersion(v);
+ qtversionMap[QLatin1String("Id")] = id;
+
+ if (BaseQtVersion *qtv = factory->restore(qtversionMap)) {
+ Q_ASSERT(qtv->isAutodetected());
+ addVersion(qtv);
+ restored = true;
+ }
+ }
+ }
+ // Create a new qtversion
+ if (!restored) { // didn't replace any existing versions
+ if (debug)
+ qDebug() << " No Qt version found matching" << autoDetectionSource << " => Creating new version";
+ if (BaseQtVersion *qtv = factory->restore(qtversionMap)) {
+ Q_ASSERT(qtv->isAutodetected());
+ addVersion(qtv);
+ restored = true;
+ }
+ }
+ if (!restored)
+ if (debug)
+ qDebug("Warning: Unable to update qtversion '%s' from sdk installer.",
+ qPrintable(autoDetectionSource));
+ }
+
+ if (debug) {
+ qDebug() << "======= Before removing outdated sdk versions =======";
+ foreach (BaseQtVersion *version, m_versions) {
+ qDebug() << version->qmakeCommand() << "id:"<<version->uniqueId();
+ qDebug() << " autodetection source:"<< version->autodetectionSource();
+ qDebug() << "";
+ }
+ }
+ foreach (BaseQtVersion *qtVersion, QtVersionManager::instance()->versions()) {
+ if (qtVersion->autodetectionSource().startsWith("SDK.")) {
+ if (!sdkVersions.contains(qtVersion->autodetectionSource())) {
+ if (debug)
+ qDebug() << " removing version"<<qtVersion->autodetectionSource();
+ removeVersion(qtVersion);
+ }
+ }
+ }
+
+ if (debug) {
+ qDebug()<< "======= End result =======";
+ foreach (BaseQtVersion *version, m_versions) {
+ qDebug() << version->qmakeCommand() << "id:"<<version->uniqueId();
+ qDebug() << " autodetection source:"<< version->autodetectionSource();
+ qDebug() << "";
+ }
+ }
+}
+
+void QtVersionManager::saveQtVersions()
+{
+ ProjectExplorer::PersistentSettingsWriter writer;
+ writer.saveValue(QLatin1String(QTVERSION_FILE_VERSION_KEY), 1);
+
+ int count = 0;
+ foreach (BaseQtVersion *qtv, m_versions) {
+ QVariantMap tmp = qtv->toMap();
+ if (tmp.isEmpty())
+ continue;
+ tmp.insert(QTVERSION_TYPE_KEY, qtv->type());
+ writer.saveValue(QString::fromLatin1(QTVERSION_DATA_KEY) + QString::number(count), tmp);
+ ++count;
+
+ }
+ writer.saveValue(QLatin1String(QTVERSION_COUNT_KEY), count);
+ writer.save(settingsFileName(), "QtCreatorQtVersions", Core::ICore::instance()->mainWindow());
+}
+
+void QtVersionManager::findSystemQt()
+{
+ QString systemQMakePath = ProjectExplorer::DebuggingHelperLibrary::findSystemQt(Utils::Environment::systemEnvironment());
+ if (systemQMakePath.isNull())
+ return;
+
+ BaseQtVersion *version = QtVersionFactory::createQtVersionFromQMakePath(systemQMakePath);
+ version->setDisplayName(BaseQtVersion::defaultDisplayName(version->qtVersionString(), systemQMakePath, true));
+ m_versions.insert(version->uniqueId(), version);
+}
+
+bool QtVersionManager::legacyRestore()
+{
+ QSettings *s = Core::ICore::instance()->settings();
+ if (!s->contains(QLatin1String(QtVersionsSectionName) + QLatin1String("/size")))
+ return false;
+ int size = s->beginReadArray(QtVersionsSectionName);
+ for (int i = 0; i < size; ++i) {
+ s->setArrayIndex(i);
+ // Find the right id
+ // Either something saved or something generated
+ // Note: This code assumes that either all ids are read from the settings
+ // or generated on the fly.
+ int id = s->value("Id", -1).toInt();
+ if (id == -1)
+ id = getUniqueId();
+ else if (m_idcount < id)
+ m_idcount = id + 1;
+
+ QString qmakePath = s->value("QMakePath").toString();
+ if (qmakePath.isEmpty())
+ continue; //skip this version
+
+ BaseQtVersion *version = QtVersionFactory::createQtVersionFromLegacySettings(qmakePath, id, s);
+ if (!version) // Likely to be a invalid version
+ continue;
+
+ if (m_versions.contains(version->uniqueId())) {
+ // oh uh;
+ delete version;
+ } else {
+ m_versions.insert(version->uniqueId(), version);
+ }
+ // Update from 2.1 or earlier:
+ QString mingwDir = s->value(QLatin1String("MingwDirectory")).toString();
+ if (!mingwDir.isEmpty()) {
+ QFileInfo fi(mingwDir + QLatin1String("/bin/g++.exe"));
+ if (fi.exists() && fi.isExecutable()) {
+ ProjectExplorer::MingwToolChain *tc = createToolChain<ProjectExplorer::MingwToolChain>(ProjectExplorer::Constants::MINGW_TOOLCHAIN_ID);
+ if (tc) {
+ tc->setCompilerPath(fi.absoluteFilePath());
+ tc->setDisplayName(tr("MinGW from %1").arg(version->displayName()));
+ // The debugger is set later in the autoDetect method of the MinGw tool chain factory
+ // as the default debuggers are not yet registered.
+ ProjectExplorer::ToolChainManager::instance()->registerToolChain(tc);
+ }
+ }
+ }
+ const QString mwcDir = s->value(QLatin1String("MwcDirectory")).toString();
+ if (!mwcDir.isEmpty())
+ m_pendingMwcUpdates.append(mwcDir);
+ const QString gcceDir = s->value(QLatin1String("GcceDirectory")).toString();
+ if (!gcceDir.isEmpty())
+ m_pendingGcceUpdates.append(gcceDir);
+
+ }
+ s->endArray();
+ // TODO add removal of old settings
+ // s->remove(QtVersionsSectionName);
+ return true;
+}
+
+void QtVersionManager::addVersion(BaseQtVersion *version)
+{
+ QTC_ASSERT(version != 0, return);
+ if (m_versions.contains(version->uniqueId()))
+ return;
+
+ int uniqueId = version->uniqueId();
+ m_versions.insert(uniqueId, version);
+
+ emit qtVersionsChanged(QList<int>() << uniqueId);
+ saveQtVersions();
+}
+
+void QtVersionManager::removeVersion(BaseQtVersion *version)
+{
+ QTC_ASSERT(version != 0, return);
+ m_versions.remove(version->uniqueId());
+ emit qtVersionsChanged(QList<int>() << version->uniqueId());
+ saveQtVersions();
+ delete version;
+}
+
+bool QtVersionManager::supportsTargetId(const QString &id) const
+{
+ QList<BaseQtVersion *> versions = QtVersionManager::instance()->versionsForTargetId(id);
+ foreach (BaseQtVersion *v, versions)
+ if (v->isValid() && v->toolChainAvailable(id))
+ return true;
+ return false;
+}
+
+QList<BaseQtVersion *> QtVersionManager::versionsForTargetId(const QString &id, const QtVersionNumber &minimumQtVersion) const
+{
+ QList<BaseQtVersion *> targetVersions;
+ foreach (BaseQtVersion *version, m_versions) {
+ if (version->supportsTargetId(id) && version->qtVersion() >= minimumQtVersion)
+ targetVersions.append(version);
+ }
+ qSort(targetVersions.begin(), targetVersions.end(), &qtVersionNumberCompare);
+ return targetVersions;
+}
+
+QSet<QString> QtVersionManager::supportedTargetIds() const
+{
+ QSet<QString> results;
+ foreach (BaseQtVersion *version, m_versions)
+ results.unite(version->supportedTargetIds());
+ return results;
+}
+
+void QtVersionManager::updateDocumentation()
+{
+ Core::HelpManager *helpManager = Core::HelpManager::instance();
+ Q_ASSERT(helpManager);
+ QStringList files;
+ foreach (BaseQtVersion *v, m_versions) {
+ const QString docPath = v->documentationPath() + QLatin1String("/qch/");
+ const QDir versionHelpDir(docPath);
+ foreach (const QString &helpFile,
+ versionHelpDir.entryList(QStringList() << QLatin1String("*.qch"), QDir::Files))
+ files << docPath + helpFile;
+
+ }
+ helpManager->registerDocumentation(files);
+}
+
+void QtVersionManager::updateQtVersion(int id)
+{
+ BaseQtVersion *qtVersion = version(id);
+ QTC_ASSERT(qtVersion, return);
+
+ // update actually all Qt versions with the same qmake command
+ const QString qmakeCommand = qtVersion->qmakeCommand();
+ foreach (BaseQtVersion *v, versions()) {
+ if (v->qmakeCommand() == qmakeCommand)
+ v->recheckDumper();
+ }
+ emit dumpUpdatedFor(qmakeCommand);
+}
+
+void QtVersionManager::updateSettings()
+{
+ updateDocumentation();
+
+ BaseQtVersion *version = 0;
+ QList<BaseQtVersion *> candidates;
+
+ // try to find a version which has both, demos and examples
+ foreach (BaseQtVersion *version, m_versions) {
+ if (version && version->hasExamples() && version->hasDemos())
+ candidates.append(version);
+ }
+
+ // in SDKs, we want to prefer the Qt version shipping with the SDK
+ QSettings *settings = Core::ICore::instance()->settings();
+ QString preferred = settings->value(QLatin1String("PreferredQMakePath")).toString();
+ preferred = QDir::fromNativeSeparators(preferred);
+ if (!preferred.isEmpty()) {
+#ifdef Q_OS_WIN
+ preferred = preferred.toLower();
+ if (!preferred.endsWith(QLatin1String(".exe")))
+ preferred.append(QLatin1String(".exe"));
+#endif
+ foreach (version, candidates) {
+ if (version->qmakeCommand() == preferred) {
+ emit updateExamples(version->examplesPath(), version->demosPath(), version->sourcePath());
+ return;
+ }
+ }
+ }
+
+ // prefer versions with declarative examples
+ foreach (version, candidates) {
+ if (QDir(version->examplesPath()+"/declarative").exists()) {
+ emit updateExamples(version->examplesPath(), version->demosPath(), version->sourcePath());
+ return;
+ }
+ }
+
+ if (!candidates.isEmpty()) {
+ version = candidates.first();
+ emit updateExamples(version->examplesPath(), version->demosPath(), version->sourcePath());
+ return;
+ }
+ return;
+
+}
+
+int QtVersionManager::getUniqueId()
+{
+ return m_idcount++;
+}
+
+QList<BaseQtVersion *> QtVersionManager::versions() const
+{
+ QList<BaseQtVersion *> versions;
+ foreach (BaseQtVersion *version, m_versions)
+ versions << version;
+ qSort(versions.begin(), versions.end(), &qtVersionNumberCompare);
+ return versions;
+}
+
+QList<BaseQtVersion *> QtVersionManager::validVersions() const
+{
+ QList<BaseQtVersion *> results;
+ foreach (BaseQtVersion *v, m_versions) {
+ if (v->isValid())
+ results.append(v);
+ }
+ qSort(results.begin(), results.end(), &qtVersionNumberCompare);
+ return results;
+}
+
+bool QtVersionManager::isValidId(int id) const
+{
+ return m_versions.contains(id);
+}
+
+QString QtVersionManager::popPendingMwcUpdate()
+{
+ if (m_pendingMwcUpdates.isEmpty())
+ return QString();
+ return m_pendingMwcUpdates.takeFirst();
+}
+
+QString QtVersionManager::popPendingGcceUpdate()
+{
+ if (m_pendingGcceUpdates.isEmpty())
+ return QString();
+ return m_pendingGcceUpdates.takeFirst();
+}
+
+BaseQtVersion *QtVersionManager::version(int id) const
+{
+ QMap<int, BaseQtVersion *>::const_iterator it = m_versions.find(id);
+ if (it == m_versions.constEnd())
+ return 0;
+ return it.value();
+}
+
+class SortByUniqueId
+{
+public:
+ bool operator()(BaseQtVersion *a, BaseQtVersion *b)
+ {
+ return a->uniqueId() < b->uniqueId();
+ }
+};
+
+bool QtVersionManager::equals(BaseQtVersion *a, BaseQtVersion *b)
+{
+ return a->equals(b);
+}
+
+void QtVersionManager::setNewQtVersions(QList<BaseQtVersion *> newVersions)
+{
+ // We want to preserve the same order as in the settings dialog
+ // so we sort a copy
+ QList<BaseQtVersion *> sortedNewVersions = newVersions;
+ SortByUniqueId sortByUniqueId;
+ qSort(sortedNewVersions.begin(), sortedNewVersions.end(), sortByUniqueId);
+
+ QList<int> changedVersions;
+ // So we trying to find the minimal set of changed versions,
+ // iterate over both sorted list
+
+ // newVersions and oldVersions iterator
+ QList<BaseQtVersion *>::const_iterator nit, nend;
+ QMap<int, BaseQtVersion *>::const_iterator oit, oend;
+ nit = sortedNewVersions.constBegin();
+ nend = sortedNewVersions.constEnd();
+ oit = m_versions.constBegin();
+ oend = m_versions.constEnd();
+
+ while (nit != nend && oit != oend) {
+ int nid = (*nit)->uniqueId();
+ int oid = (*oit)->uniqueId();
+ if (nid < oid) {
+ changedVersions.push_back(nid);
+ ++nit;
+ } else if (oid < nid) {
+ changedVersions.push_back(oid);
+ ++oit;
+ } else {
+ if (!equals(*oit, *nit))
+ changedVersions.push_back(oid);
+ ++oit;
+ ++nit;
+ }
+ }
+
+ while (nit != nend) {
+ changedVersions.push_back((*nit)->uniqueId());
+ ++nit;
+ }
+
+ while (oit != oend) {
+ changedVersions.push_back((*oit)->uniqueId());
+ ++oit;
+ }
+
+ qDeleteAll(m_versions);
+ m_versions.clear();
+ foreach (BaseQtVersion *v, sortedNewVersions)
+ m_versions.insert(v->uniqueId(), v);
+
+ if (!changedVersions.isEmpty())
+ updateDocumentation();
+
+ updateSettings();
+ saveQtVersions();
+
+ if (!changedVersions.isEmpty())
+ emit qtVersionsChanged(changedVersions);
+}
+
+// Returns the version that was used to build the project in that directory
+// That is returns the directory
+// To find out whether we already have a qtversion for that directory call
+// QtVersion *QtVersionManager::qtVersionForDirectory(const QString directory);
+QString QtVersionManager::findQMakeBinaryFromMakefile(const QString &makefile)
+{
+ bool debugAdding = false;
+ QFile fi(makefile);
+ if (fi.exists() && fi.open(QFile::ReadOnly)) {
+ QTextStream ts(&fi);
+ QRegExp r1("QMAKE\\s*=(.*)");
+ while (!ts.atEnd()) {
+ QString line = ts.readLine();
+ if (r1.exactMatch(line)) {
+ if (debugAdding)
+ qDebug()<<"#~~ QMAKE is:"<<r1.cap(1).trimmed();
+ QFileInfo qmake(r1.cap(1).trimmed());
+ QString qmakePath = qmake.filePath();
+#ifdef Q_OS_WIN
+ if (!qmakePath.endsWith(QLatin1String(".exe")))
+ qmakePath.append(QLatin1String(".exe"));
+#endif
+ // Is qmake still installed?
+ QFileInfo fi(qmakePath);
+ if (fi.exists()) {
+ qmakePath = fi.absoluteFilePath();
+#ifdef Q_OS_WIN
+ qmakePath = qmakePath.toLower();
+#endif
+ return qmakePath;
+ }
+ }
+ }
+ }
+ return QString();
+}
+
+BaseQtVersion *QtVersionManager::qtVersionForQMakeBinary(const QString &qmakePath)
+{
+ foreach (BaseQtVersion *version, versions()) {
+ if (version->qmakeCommand() == qmakePath) {
+ return version;
+ break;
+ }
+ }
+ return 0;
+}
+
+void dumpQMakeAssignments(const QList<QMakeAssignment> &list)
+{
+ foreach(const QMakeAssignment &qa, list) {
+ qDebug()<<qa.variable<<qa.op<<qa.value;
+ }
+}
+
+QtVersionManager::MakefileCompatible QtVersionManager::makefileIsFor(const QString &makefile, const QString &proFile)
+{
+ if (proFile.isEmpty())
+ return CouldNotParse;
+
+ QString line = findQMakeLine(makefile, QLatin1String("# Project:")).trimmed();
+ if (line.isEmpty())
+ return CouldNotParse;
+
+ line = line.mid(line.indexOf(QChar(':')) + 1);
+ line = line.trimmed();
+
+ QFileInfo srcFileInfo(QFileInfo(makefile).absoluteDir(), line);
+ QFileInfo proFileInfo(proFile);
+ return (srcFileInfo == proFileInfo) ? SameProject : DifferentProject;
+}
+
+QPair<BaseQtVersion::QmakeBuildConfigs, QString> QtVersionManager::scanMakeFile(const QString &makefile, BaseQtVersion::QmakeBuildConfigs defaultBuildConfig)
+{
+ if (debug)
+ qDebug()<<"ScanMakeFile, the gory details:";
+ BaseQtVersion::QmakeBuildConfigs result = defaultBuildConfig;
+ QString result2;
+
+ QString line = findQMakeLine(makefile, QLatin1String("# Command:"));
+ if (!line.isEmpty()) {
+ if (debug)
+ qDebug()<<"Found line"<<line;
+ line = trimLine(line);
+ QList<QMakeAssignment> assignments;
+ QList<QMakeAssignment> afterAssignments;
+ parseArgs(line, &assignments, &afterAssignments, &result2);
+
+ if (debug) {
+ dumpQMakeAssignments(assignments);
+ if (!afterAssignments.isEmpty())
+ qDebug()<<"-after";
+ dumpQMakeAssignments(afterAssignments);
+ }
+
+ // Search in assignments for CONFIG(+=,-=,=)(debug,release,debug_and_release)
+ // Also remove them from the list
+ result = qmakeBuildConfigFromCmdArgs(&assignments, defaultBuildConfig);
+
+ if (debug)
+ dumpQMakeAssignments(assignments);
+
+ foreach(const QMakeAssignment &qa, assignments)
+ Utils::QtcProcess::addArg(&result2, qa.variable + qa.op + qa.value);
+ if (!afterAssignments.isEmpty()) {
+ Utils::QtcProcess::addArg(&result2, QLatin1String("-after"));
+ foreach(const QMakeAssignment &qa, afterAssignments)
+ Utils::QtcProcess::addArg(&result2, qa.variable + qa.op + qa.value);
+ }
+ }
+
+ // Dump the gathered information:
+ if (debug) {
+ qDebug()<<"\n\nDumping information from scanMakeFile";
+ qDebug()<<"QMake CONFIG variable parsing";
+ qDebug()<<" "<< (result & BaseQtVersion::NoBuild ? "No Build" : QString::number(int(result)));
+ qDebug()<<" "<< (result & BaseQtVersion::DebugBuild ? "debug" : "release");
+ qDebug()<<" "<< (result & BaseQtVersion::BuildAll ? "debug_and_release" : "no debug_and_release");
+ qDebug()<<"\nAddtional Arguments";
+ qDebug()<<result2;
+ qDebug()<<"\n\n";
+ }
+ return qMakePair(result, result2);
+}
+
+QString QtVersionManager::findQMakeLine(const QString &makefile, const QString &key)
+{
+ QFile fi(makefile);
+ if (fi.exists() && fi.open(QFile::ReadOnly)) {
+ QTextStream ts(&fi);
+ while (!ts.atEnd()) {
+ const QString line = ts.readLine();
+ if (line.startsWith(key))
+ return line;
+ }
+ }
+ return QString();
+}
+
+/// This function trims the "#Command /path/to/qmake" from the the line
+QString QtVersionManager::trimLine(const QString line)
+{
+
+ // Actually the first space after #Command: /path/to/qmake
+ const int firstSpace = line.indexOf(QLatin1Char(' '), 11);
+ return line.mid(firstSpace).trimmed();
+}
+
+void QtVersionManager::parseArgs(const QString &args, QList<QMakeAssignment> *assignments, QList<QMakeAssignment> *afterAssignments, QString *additionalArguments)
+{
+ QRegExp regExp("([^\\s\\+-]*)\\s*(\\+=|=|-=|~=)(.*)");
+ bool after = false;
+ bool ignoreNext = false;
+ *additionalArguments = args;
+ Utils::QtcProcess::ArgIterator ait(additionalArguments);
+ while (ait.next()) {
+ if (ignoreNext) {
+ // Ignoring
+ ignoreNext = false;
+ ait.deleteArg();
+ } else if (ait.value() == QLatin1String("-after")) {
+ after = true;
+ ait.deleteArg();
+ } else if (ait.value().contains(QLatin1Char('='))) {
+ if (regExp.exactMatch(ait.value())) {
+ QMakeAssignment qa;
+ qa.variable = regExp.cap(1);
+ qa.op = regExp.cap(2);
+ qa.value = regExp.cap(3).trimmed();
+ if (after)
+ afterAssignments->append(qa);
+ else
+ assignments->append(qa);
+ } else {
+ qDebug()<<"regexp did not match";
+ }
+ ait.deleteArg();
+ } else if (ait.value() == QLatin1String("-o")) {
+ ignoreNext = true;
+ ait.deleteArg();
+#if defined(Q_OS_WIN32)
+ } else if (ait.value() == QLatin1String("-win32")) {
+#elif defined(Q_OS_MAC)
+ } else if (ait.value() == QLatin1String("-macx")) {
+#elif defined(Q_OS_QNX6)
+ } else if (ait.value() == QLatin1String("-qnx6")) {
+#else
+ } else if (ait.value() == QLatin1String("-unix")) {
+#endif
+ ait.deleteArg();
+ }
+ }
+ ait.deleteArg(); // The .pro file is always the last arg
+}
+
+/// This function extracts all the CONFIG+=debug, CONFIG+=release
+BaseQtVersion::QmakeBuildConfigs QtVersionManager::qmakeBuildConfigFromCmdArgs(QList<QMakeAssignment> *assignments, BaseQtVersion::QmakeBuildConfigs defaultBuildConfig)
+{
+ BaseQtVersion::QmakeBuildConfigs result = defaultBuildConfig;
+ QList<QMakeAssignment> oldAssignments = *assignments;
+ assignments->clear();
+ foreach(const QMakeAssignment &qa, oldAssignments) {
+ if (qa.variable == "CONFIG") {
+ QStringList values = qa.value.split(' ');
+ QStringList newValues;
+ foreach(const QString &value, values) {
+ if (value == "debug") {
+ if (qa.op == "+=")
+ result = result | BaseQtVersion::DebugBuild;
+ else
+ result = result & ~BaseQtVersion::DebugBuild;
+ } else if (value == "release") {
+ if (qa.op == "+=")
+ result = result & ~BaseQtVersion::DebugBuild;
+ else
+ result = result | BaseQtVersion::DebugBuild;
+ } else if (value == "debug_and_release") {
+ if (qa.op == "+=")
+ result = result | BaseQtVersion::BuildAll;
+ else
+ result = result & ~BaseQtVersion::BuildAll;
+ } else {
+ newValues.append(value);
+ }
+ QMakeAssignment newQA = qa;
+ newQA.value = newValues.join(" ");
+ if (!newValues.isEmpty())
+ assignments->append(newQA);
+ }
+ } else {
+ assignments->append(qa);
+ }
+ }
+ return result;
+}
diff --git a/src/plugins/qtsupport/qtversionmanager.h b/src/plugins/qtsupport/qtversionmanager.h
new file mode 100644
index 0000000000..8346241187
--- /dev/null
+++ b/src/plugins/qtsupport/qtversionmanager.h
@@ -0,0 +1,170 @@
+/**************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2011 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Nokia Corporation (info@qt.nokia.com)
+**
+**
+** GNU Lesser General Public License Usage
+**
+** 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.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** Other Usage
+**
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at info@qt.nokia.com.
+**
+**************************************************************************/
+
+#ifndef QTVERSIONMANAGER_H
+#define QTVERSIONMANAGER_H
+
+#include "qtsupport_global.h"
+#include "baseqtversion.h"
+
+#include <projectexplorer/abi.h>
+
+#include <QtCore/QHash>
+#include <QtCore/QSet>
+#include <QtCore/QSharedPointer>
+#include <QtCore/QFutureInterface>
+#include <QtCore/QStringList>
+#include <QtCore/QVariantMap>
+
+namespace Utils {
+class Environment;
+}
+
+namespace ProjectExplorer {
+class HeaderPath;
+class IOutputParser;
+class Task;
+}
+
+namespace QtSupport {
+class BaseQtVersion;
+
+namespace Internal {
+class QtOptionsPageWidget;
+class QtOptionsPage;
+}
+
+struct QMakeAssignment
+{
+ QString variable;
+ QString op;
+ QString value;
+};
+
+class QTSUPPORT_EXPORT QtVersionManager : public QObject
+{
+ Q_OBJECT
+ // for getUniqueId();
+ friend class BaseQtVersion;
+ friend class Internal::QtOptionsPage;
+public:
+ static QtVersionManager *instance();
+ QtVersionManager();
+ ~QtVersionManager();
+ void extensionsInitialized();
+
+ // This will *always* return at least one (Qt in Path), even if that is
+ // unconfigured.
+ QList<BaseQtVersion *> versions() const;
+ QList<BaseQtVersion *> validVersions() const;
+
+ // Note: DO NOT STORE THIS POINTER!
+ // The QtVersionManager will delete it at random times and you will
+ // need to get a new pointer by calling this method again!
+ BaseQtVersion *version(int id) const;
+
+ BaseQtVersion *qtVersionForQMakeBinary(const QString &qmakePath);
+
+ // Used by the projectloadwizard
+ void addVersion(BaseQtVersion *version);
+ void removeVersion(BaseQtVersion *version);
+
+ // Target Support:
+ bool supportsTargetId(const QString &id) const;
+ // This returns a list of versions that support the target with the given id.
+ // @return A list of QtVersions that supports a target. This list may be empty!
+
+ QList<BaseQtVersion *> versionsForTargetId(const QString &id, const QtVersionNumber &minimumQtVersion = QtVersionNumber()) const;
+ QSet<QString> supportedTargetIds() const;
+
+ // Static Methods
+ enum MakefileCompatible { CouldNotParse, DifferentProject, SameProject };
+ static MakefileCompatible makefileIsFor(const QString &makefile, const QString &proFile);
+ static QPair<BaseQtVersion::QmakeBuildConfigs, QString> scanMakeFile(const QString &makefile,
+ BaseQtVersion::QmakeBuildConfigs defaultBuildConfig);
+ static QString findQMakeBinaryFromMakefile(const QString &directory);
+ bool isValidId(int id) const;
+
+ // Compatibility with pre-2.2:
+ QString popPendingMwcUpdate();
+ QString popPendingGcceUpdate();
+signals:
+ // content of BaseQtVersion objects with qmake path might have changed
+ void dumpUpdatedFor(const QString &qmakeCommand);
+ void qtVersionsChanged(const QList<int> &uniqueIds);
+ void updateExamples(QString, QString, QString);
+
+public slots:
+ void updateQtVersion(int id);
+
+private slots:
+ void updateSettings();
+
+private:
+ // This function is really simplistic...
+ static bool equals(BaseQtVersion *a, BaseQtVersion *b);
+ static QString findQMakeLine(const QString &directory, const QString &key);
+ static QString trimLine(const QString line);
+ static void parseArgs(const QString &args,
+ QList<QMakeAssignment> *assignments,
+ QList<QMakeAssignment> *afterAssignments,
+ QString *additionalArguments);
+ static BaseQtVersion::QmakeBuildConfigs qmakeBuildConfigFromCmdArgs(QList<QMakeAssignment> *assignments,
+ BaseQtVersion::QmakeBuildConfigs defaultBuildConfig);
+ bool restoreQtVersions();
+ bool legacyRestore();
+ void findSystemQt();
+ void updateFromInstaller();
+ void saveQtVersions();
+ // Used by QtOptionsPage
+ void setNewQtVersions(QList<BaseQtVersion *> newVersions);
+ // Used by QtVersion
+ int getUniqueId();
+ void addNewVersionsFromInstaller();
+ void updateDocumentation();
+
+ static int indexOfVersionInList(const BaseQtVersion * const version, const QList<BaseQtVersion *> &list);
+ void updateUniqueIdToIndexMap();
+
+ QMap<int, BaseQtVersion *> m_versions;
+ int m_idcount;
+ // managed by QtProjectManagerPlugin
+ static QtVersionManager *m_self;
+
+ // Compatibility with pre-2.2:
+ QStringList m_pendingMwcUpdates;
+ QStringList m_pendingGcceUpdates;
+};
+
+} // namespace Qt4ProjectManager
+
+#endif // QTVERSIONMANAGER_H
diff --git a/src/plugins/qtsupport/qtversionmanager.ui b/src/plugins/qtsupport/qtversionmanager.ui
new file mode 100644
index 0000000000..8ebf7b8439
--- /dev/null
+++ b/src/plugins/qtsupport/qtversionmanager.ui
@@ -0,0 +1,117 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<ui version="4.0">
+ <class>QtSupport::Internal::QtVersionManager</class>
+ <widget class="QWidget" name="QtSupport::Internal::QtVersionManager">
+ <property name="geometry">
+ <rect>
+ <x>0</x>
+ <y>0</y>
+ <width>446</width>
+ <height>450</height>
+ </rect>
+ </property>
+ <layout class="QGridLayout" name="gridLayout">
+ <item row="0" column="0">
+ <layout class="QHBoxLayout" name="horizontalLayout">
+ <item>
+ <widget class="QTreeWidget" name="qtdirList">
+ <property name="uniformRowHeights">
+ <bool>true</bool>
+ </property>
+ <property name="columnCount">
+ <number>2</number>
+ </property>
+ <column>
+ <property name="text">
+ <string>Name</string>
+ </property>
+ </column>
+ <column>
+ <property name="text">
+ <string>qmake Location</string>
+ </property>
+ </column>
+ </widget>
+ </item>
+ <item>
+ <layout class="QVBoxLayout">
+ <property name="spacing">
+ <number>6</number>
+ </property>
+ <property name="margin">
+ <number>0</number>
+ </property>
+ <item>
+ <widget class="QPushButton" name="addButton">
+ <property name="minimumSize">
+ <size>
+ <width>21</width>
+ <height>23</height>
+ </size>
+ </property>
+ <property name="text">
+ <string>Add</string>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <widget class="QPushButton" name="delButton">
+ <property name="minimumSize">
+ <size>
+ <width>21</width>
+ <height>23</height>
+ </size>
+ </property>
+ <property name="text">
+ <string>Remove</string>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <spacer>
+ <property name="orientation">
+ <enum>Qt::Vertical</enum>
+ </property>
+ <property name="sizeHint" stdset="0">
+ <size>
+ <width>10</width>
+ <height>40</height>
+ </size>
+ </property>
+ </spacer>
+ </item>
+ <item>
+ <widget class="QPushButton" name="cleanUpButton">
+ <property name="text">
+ <string>Clean up</string>
+ </property>
+ </widget>
+ </item>
+ </layout>
+ </item>
+ </layout>
+ </item>
+ <item row="1" column="0">
+ <widget class="Utils::DetailsWidget" name="versionInfoWidget" native="true"/>
+ </item>
+ <item row="2" column="0">
+ <widget class="Utils::DetailsWidget" name="debuggingHelperWidget" native="true"/>
+ </item>
+ </layout>
+ </widget>
+ <customwidgets>
+ <customwidget>
+ <class>Utils::DetailsWidget</class>
+ <extends>QWidget</extends>
+ <header location="global">utils/detailswidget.h</header>
+ <container>1</container>
+ </customwidget>
+ </customwidgets>
+ <tabstops>
+ <tabstop>qtdirList</tabstop>
+ <tabstop>addButton</tabstop>
+ <tabstop>delButton</tabstop>
+ </tabstops>
+ <resources/>
+ <connections/>
+</ui>
diff --git a/src/plugins/qtsupport/showbuildlog.ui b/src/plugins/qtsupport/showbuildlog.ui
new file mode 100644
index 0000000000..e29e89494d
--- /dev/null
+++ b/src/plugins/qtsupport/showbuildlog.ui
@@ -0,0 +1,74 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<ui version="4.0">
+ <class>ShowBuildLog</class>
+ <widget class="QDialog" name="ShowBuildLog">
+ <property name="geometry">
+ <rect>
+ <x>0</x>
+ <y>0</y>
+ <width>400</width>
+ <height>300</height>
+ </rect>
+ </property>
+ <property name="windowTitle">
+ <string>Debugging Helper Build Log</string>
+ </property>
+ <layout class="QVBoxLayout" name="verticalLayout">
+ <item>
+ <widget class="QPlainTextEdit" name="log">
+ <property name="tabChangesFocus">
+ <bool>true</bool>
+ </property>
+ <property name="readOnly">
+ <bool>true</bool>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <widget class="QDialogButtonBox" name="buttonBox">
+ <property name="orientation">
+ <enum>Qt::Horizontal</enum>
+ </property>
+ <property name="standardButtons">
+ <set>QDialogButtonBox::Close</set>
+ </property>
+ </widget>
+ </item>
+ </layout>
+ </widget>
+ <resources/>
+ <connections>
+ <connection>
+ <sender>buttonBox</sender>
+ <signal>accepted()</signal>
+ <receiver>ShowBuildLog</receiver>
+ <slot>accept()</slot>
+ <hints>
+ <hint type="sourcelabel">
+ <x>248</x>
+ <y>254</y>
+ </hint>
+ <hint type="destinationlabel">
+ <x>157</x>
+ <y>274</y>
+ </hint>
+ </hints>
+ </connection>
+ <connection>
+ <sender>buttonBox</sender>
+ <signal>rejected()</signal>
+ <receiver>ShowBuildLog</receiver>
+ <slot>reject()</slot>
+ <hints>
+ <hint type="sourcelabel">
+ <x>316</x>
+ <y>260</y>
+ </hint>
+ <hint type="destinationlabel">
+ <x>286</x>
+ <y>274</y>
+ </hint>
+ </hints>
+ </connection>
+ </connections>
+</ui>