Commit 8e171e0b authored by dt's avatar dt

Qt Version refactoring

Split up target specific code into subclasses. Also change
Qt4BuildConfiguration to allow a null qtversion.

Remove code that relied on always having a qt version.
Also make it possible to remove all qt versions.

Completly change the qt in path autodetection to be only
a fall back if no configuration was found.

Note: For now the old settings are not removed, as such 2.2 and master
can coexist.

Reviewed-By: hunger
parent 9ef4ea40
......@@ -211,6 +211,7 @@ void BuildConfiguration::setToolChain(ProjectExplorer::ToolChain *tc)
return;
m_toolChain = tc;
emit toolChainChanged();
emit environmentChanged();
}
Utils::Environment BuildConfiguration::baseEnvironment() const
......
......@@ -33,6 +33,8 @@
#ifndef HEADERPATH_H
#define HEADERPATH_H
#include <QtCore/QString>
#include "projectexplorer_export.h"
namespace ProjectExplorer {
......
......@@ -42,7 +42,7 @@
#include <coreplugin/messagemanager.h>
#include <extensionsystem/pluginmanager.h>
#include <qt4projectmanager/qmldumptool.h>
#include <qt4projectmanager/qtversionmanager.h>
#include <qt4projectmanager/baseqtversion.h>
#include <qmljs/qmljsmodelmanagerinterface.h>
#include <utils/fileutils.h>
......@@ -192,7 +192,7 @@ QStringList QmlProject::importPaths() const
const QmlProjectRunConfiguration *runConfig =
qobject_cast<QmlProjectRunConfiguration*>(activeTarget()->activeRunConfiguration());
if (runConfig) {
const Qt4ProjectManager::QtVersion *qtVersion = runConfig->qtVersion();
const Qt4ProjectManager::BaseQtVersion *qtVersion = runConfig->qtVersion();
if (qtVersion && qtVersion->isValid()) {
const QString qtVersionImportPath = qtVersion->versionInfo().value("QT_INSTALL_IMPORTS");
if (!qtVersionImportPath.isEmpty())
......
......@@ -120,7 +120,7 @@ QmlProjectTarget *QmlProjectRunConfiguration::qmlTarget() const
QString QmlProjectRunConfiguration::viewerPath() const
{
Qt4ProjectManager::QtVersion *version = qtVersion();
Qt4ProjectManager::BaseQtVersion *version = qtVersion();
if (!version) {
return QString();
} else {
......@@ -130,7 +130,7 @@ QString QmlProjectRunConfiguration::viewerPath() const
QString QmlProjectRunConfiguration::observerPath() const
{
Qt4ProjectManager::QtVersion *version = qtVersion();
Qt4ProjectManager::BaseQtVersion *version = qtVersion();
if (!version) {
return QString();
} else {
......@@ -193,13 +193,13 @@ QString QmlProjectRunConfiguration::canonicalCapsPath(const QString &fileName)
}
Qt4ProjectManager::QtVersion *QmlProjectRunConfiguration::qtVersion() const
Qt4ProjectManager::BaseQtVersion *QmlProjectRunConfiguration::qtVersion() const
{
if (m_qtVersionId == -1)
return 0;
QtVersionManager *versionManager = QtVersionManager::instance();
Qt4ProjectManager::QtVersion *version = versionManager->version(m_qtVersionId);
Qt4ProjectManager::BaseQtVersion *version = versionManager->version(m_qtVersionId);
QTC_ASSERT(version, return 0);
return version;
......@@ -381,7 +381,7 @@ void QmlProjectRunConfiguration::updateQtVersions()
|| !isValidVersion(qtVersions->version(m_qtVersionId))) {
int newVersionId = -1;
// take first one you find
foreach (Qt4ProjectManager::QtVersion *version, qtVersions->validVersions()) {
foreach (Qt4ProjectManager::BaseQtVersion *version, qtVersions->validVersions()) {
if (isValidVersion(version)) {
newVersionId = version->uniqueId();
break;
......@@ -393,7 +393,7 @@ void QmlProjectRunConfiguration::updateQtVersions()
updateEnabled();
}
bool QmlProjectRunConfiguration::isValidVersion(Qt4ProjectManager::QtVersion *version)
bool QmlProjectRunConfiguration::isValidVersion(Qt4ProjectManager::BaseQtVersion *version)
{
if (version
&& (version->supportsTargetId(Qt4ProjectManager::Constants::DESKTOP_TARGET_ID)
......
......@@ -51,7 +51,7 @@ namespace Utils {
}
namespace Qt4ProjectManager {
class QtVersion;
class BaseQtVersion;
}
namespace QmlProjectManager {
......@@ -82,7 +82,7 @@ public:
QString viewerArguments() const;
QString workingDirectory() const;
int qtVersionId() const;
Qt4ProjectManager::QtVersion *qtVersion() const;
Qt4ProjectManager::BaseQtVersion *qtVersion() const;
enum MainScriptSource {
FileInEditor,
......@@ -119,7 +119,7 @@ protected:
private:
void ctor();
static bool isValidVersion(Qt4ProjectManager::QtVersion *version);
static bool isValidVersion(Qt4ProjectManager::BaseQtVersion *version);
void setQtVersionId(int id);
static QString canonicalCapsPath(const QString &filePath);
......
......@@ -295,7 +295,7 @@ void QmlProjectRunConfigurationWidget::updateQtVersionComboBox()
m_qtVersionComboBox->clear();
QtVersionManager *qtVersions = QtVersionManager::instance();
foreach (Qt4ProjectManager::QtVersion *version, qtVersions->validVersions()) {
foreach (Qt4ProjectManager::BaseQtVersion *version, qtVersions->validVersions()) {
if (m_runConfiguration->isValidVersion(version)) {
m_qtVersionComboBox->addItem(version->displayName(), version->uniqueId());
}
......
/**************************************************************************
**
** 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 "qt4projectmanagerconstants.h"
#include "qmlobservertool.h"
#include "qmldumptool.h"
#include "qmldebugginglibrary.h"
#include "profilereader.h"
#include "qt4basetargetfactory.h"
#include "qtversionmanager.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/QCoreApplication>
#include <QtCore/QProcess>
#include <algorithm>
using namespace Qt4ProjectManager;
using namespace Qt4ProjectManager::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(qtVersionString());
}
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()
{
}
void BaseQtVersion::setId(int id)
{
m_id = id;
}
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;
}
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();
}