From ab8fc52d0bd654e4027a942a6ac16904a31f9494 Mon Sep 17 00:00:00 2001 From: dt <qtc-committer@nokia.com> Date: Wed, 10 Mar 2010 16:55:37 +0100 Subject: [PATCH] Use exact and aysnc .pro file evaluate This is a big change touching almost all of our .pro file parsing. With this patch we only evaluate once exact for all needs and once greedy for the filelist. That is the qt runconfigurations don't have own evaluaters but reuse the project wide exact evaluation. We reevaluate if the user changes the build directory, the qmake buildconfiguration or the qmake arguments. That is if you open src.pro (or projects.pro) of qt with a shadow build you still don't get all the files, but after correcting the build directory, we reevaluate the .pro files and find all files. So for a suitable definition of fixed, that bug is now fixed. We now get the exact defines of all .pro files instead of all defines for all buildconfigurations. We still don't distinguish in which .pro file a DEFINE is set. So the code model now knows about all the defines set for the given configuration but not for which files it is actually set. Also that includes all DEFINES set in .qmake.cache or the mkspecs. This means all defines from .pro files should now work. The intial loading is still synchronous. I haven't looked into it to deeply, but it seems possible to make it also async.There are probably a few issues which need to be solved fist. Also due to the asynchronous nature of the code, the executable is updated a few seconds after actually changing the build configuration --- src/plugins/projectexplorer/projectnodes.cpp | 1 + .../qt4projectmanager/profilereader.cpp | 23 +- src/plugins/qt4projectmanager/profilereader.h | 5 +- .../qt-maemo/maemorunconfiguration.cpp | 49 +- .../qt-maemo/maemorunconfiguration.h | 4 - .../qt-s60/s60devicerunconfiguration.cpp | 139 ++--- .../qt-s60/s60devicerunconfiguration.h | 8 - .../qt-s60/s60emulatorrunconfiguration.cpp | 54 +- .../qt-s60/s60emulatorrunconfiguration.h | 3 - .../qt4buildconfiguration.cpp | 12 +- .../qt4projectmanager/qt4buildconfiguration.h | 9 +- src/plugins/qt4projectmanager/qt4nodes.cpp | 484 +++++++++++++----- src/plugins/qt4projectmanager/qt4nodes.h | 66 ++- src/plugins/qt4projectmanager/qt4project.cpp | 438 +++++++++------- src/plugins/qt4projectmanager/qt4project.h | 64 ++- .../qt4projectconfigwidget.cpp | 4 +- .../qt4projectmanager/qt4projectmanager.cpp | 1 - .../qt4projectmanagerconstants.h | 3 + .../qt4projectmanager/qt4runconfiguration.cpp | 54 +- .../qt4projectmanager/qt4runconfiguration.h | 10 +- src/plugins/qt4projectmanager/qt4target.cpp | 100 +--- src/plugins/qt4projectmanager/qt4target.h | 27 +- .../qt4projectmanager/qtversionmanager.cpp | 2 + 23 files changed, 868 insertions(+), 692 deletions(-) diff --git a/src/plugins/projectexplorer/projectnodes.cpp b/src/plugins/projectexplorer/projectnodes.cpp index c552b11235b..d9cd9b11a1a 100644 --- a/src/plugins/projectexplorer/projectnodes.cpp +++ b/src/plugins/projectexplorer/projectnodes.cpp @@ -61,6 +61,7 @@ Node::Node(NodeType nodeType, m_folderNode(0), m_path(filePath) { + } NodeType Node::nodeType() const diff --git a/src/plugins/qt4projectmanager/profilereader.cpp b/src/plugins/qt4projectmanager/profilereader.cpp index cb7cb52715e..30c7ad70ea7 100644 --- a/src/plugins/qt4projectmanager/profilereader.cpp +++ b/src/plugins/qt4projectmanager/profilereader.cpp @@ -116,12 +116,27 @@ ProFileCacheManager *ProFileCacheManager::s_instance = 0; ProFileCacheManager::ProFileCacheManager(QObject *parent) : QObject(parent), - m_cache(0) + m_cache(0), + m_refCount(0) { s_instance = this; - m_timer.setSingleShot(true); m_timer.setInterval(5000); - connect(&m_timer, SIGNAL(timeout()), SLOT(clear())); + 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() @@ -132,7 +147,6 @@ ProFileCacheManager::~ProFileCacheManager() ProFileCache *ProFileCacheManager::cache() { - m_timer.start(); if (!m_cache) m_cache = new ProFileCache; return m_cache; @@ -140,6 +154,7 @@ ProFileCache *ProFileCacheManager::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. diff --git a/src/plugins/qt4projectmanager/profilereader.h b/src/plugins/qt4projectmanager/profilereader.h index 0e8fda774fe..b749bc3e569 100644 --- a/src/plugins/qt4projectmanager/profilereader.h +++ b/src/plugins/qt4projectmanager/profilereader.h @@ -77,13 +77,16 @@ public: 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(); - QTimer m_timer; ProFileCache *m_cache; + int m_refCount; + QTimer m_timer; static ProFileCacheManager *s_instance; diff --git a/src/plugins/qt4projectmanager/qt-maemo/maemorunconfiguration.cpp b/src/plugins/qt4projectmanager/qt-maemo/maemorunconfiguration.cpp index 9d02d33efb5..68862439fce 100644 --- a/src/plugins/qt4projectmanager/qt-maemo/maemorunconfiguration.cpp +++ b/src/plugins/qt4projectmanager/qt-maemo/maemorunconfiguration.cpp @@ -52,7 +52,6 @@ MaemoRunConfiguration::MaemoRunConfiguration(Qt4Target *parent, const QString &proFilePath) : RunConfiguration(parent, QLatin1String(MAEMO_RC_ID)) , m_proFilePath(proFilePath) - , m_cachedTargetInformationValid(false) , m_cachedSimulatorInformationValid(false) , qemu(0) { @@ -62,9 +61,7 @@ MaemoRunConfiguration::MaemoRunConfiguration(Qt4Target *parent, MaemoRunConfiguration::MaemoRunConfiguration(Qt4Target *parent, MaemoRunConfiguration *source) : RunConfiguration(parent, source) - , m_executable(source->m_executable) , m_proFilePath(source->m_proFilePath) - , m_cachedTargetInformationValid(false) , m_simulator(source->m_simulator) , m_simulatorArgs(source->m_simulatorArgs) , m_simulatorPath(source->m_simulatorPath) @@ -95,8 +92,8 @@ void MaemoRunConfiguration::init() connect(&MaemoDeviceConfigurations::instance(), SIGNAL(updated()), this, SLOT(updateDeviceConfigurations())); - connect(qt4Target(), SIGNAL(targetInformationChanged()), this, - SLOT(invalidateCachedTargetInformation())); + connect(qt4Target()->qt4Project(), SIGNAL(proFileUpdated(Qt4ProjectManager::Internal::Qt4ProFileNode*)), + this, SLOT(proFileUpdate(Qt4ProjectManager::Internal::Qt4ProFileNode*))); connect(qt4Target()->qt4Project(), SIGNAL(proFileUpdated(Qt4ProjectManager::Internal::Qt4ProFileNode*)), @@ -148,7 +145,7 @@ QWidget *MaemoRunConfiguration::configurationWidget() void MaemoRunConfiguration::proFileUpdate(Qt4ProjectManager::Internal::Qt4ProFileNode *pro) { if (m_proFilePath == pro->path()) - invalidateCachedTargetInformation(); + emit targetInformationChanged(); } QVariantMap MaemoRunConfiguration::toMap() const @@ -329,8 +326,11 @@ const QString MaemoRunConfiguration::dumperLib() const QString MaemoRunConfiguration::executable() const { - updateTarget(); - return m_executable; + TargetInformation ti = qt4Target()->qt4Project()->rootProjectNode()->targetInformation(m_proFilePath); + if (!ti.valid) + return QString(); + + return QDir::cleanPath(ti.workingDir + QLatin1Char('/') + ti.target); } QString MaemoRunConfiguration::simulatorSshPort() const @@ -379,39 +379,6 @@ bool MaemoRunConfiguration::isQemuRunning() const return (qemu && qemu->state() != QProcess::NotRunning); } -void MaemoRunConfiguration::invalidateCachedTargetInformation() -{ - m_cachedTargetInformationValid = false; - emit targetInformationChanged(); -} - -void MaemoRunConfiguration::updateTarget() const -{ - if (m_cachedTargetInformationValid) - return; - - m_executable.clear(); - m_cachedTargetInformationValid = true; - - Qt4TargetInformation info = - qt4Target()->targetInformation(activeQt4BuildConfiguration(), - m_proFilePath); - if (info.error != Qt4TargetInformation::NoError) { - if (info.error == Qt4TargetInformation::ProParserError) { - Core::ICore::instance()->messageManager()->printToOutputPane(tr( - "Could not parse %1. The Maemo run configuration %2 " - "can not be started.").arg(m_proFilePath).arg(displayName())); - } - emit targetInformationChanged(); - return; - } - - m_executable - = QDir::cleanPath(info.workingDir % QLatin1Char('/') % info.target); - - emit targetInformationChanged(); -} - void MaemoRunConfiguration::updateSimulatorInformation() const { if (m_cachedSimulatorInformationValid) diff --git a/src/plugins/qt4projectmanager/qt-maemo/maemorunconfiguration.h b/src/plugins/qt4projectmanager/qt-maemo/maemorunconfiguration.h index 6c7ae254ab4..b2734459d97 100644 --- a/src/plugins/qt4projectmanager/qt-maemo/maemorunconfiguration.h +++ b/src/plugins/qt4projectmanager/qt-maemo/maemorunconfiguration.h @@ -114,14 +114,12 @@ protected: private slots: void proFileUpdate(Qt4ProjectManager::Internal::Qt4ProFileNode *pro); void updateDeviceConfigurations(); - void invalidateCachedTargetInformation(); void startStopQemu(); void qemuProcessFinished(); private: void init(); - void updateTarget() const; void updateSimulatorInformation() const; const QString cmd(const QString &cmdName) const; const MaemoToolChain *toolchain() const; @@ -133,9 +131,7 @@ private: QMap<QString, QDateTime> &deployTimes, const QVariantMap &map); - mutable QString m_executable; QString m_proFilePath; - mutable bool m_cachedTargetInformationValid; mutable QString m_simulator; mutable QString m_simulatorArgs; diff --git a/src/plugins/qt4projectmanager/qt-s60/s60devicerunconfiguration.cpp b/src/plugins/qt4projectmanager/qt-s60/s60devicerunconfiguration.cpp index c4cdaa6dab0..1420e039eac 100644 --- a/src/plugins/qt4projectmanager/qt-s60/s60devicerunconfiguration.cpp +++ b/src/plugins/qt4projectmanager/qt-s60/s60devicerunconfiguration.cpp @@ -112,7 +112,6 @@ QString pathToId(const QString &path) S60DeviceRunConfiguration::S60DeviceRunConfiguration(Target *parent, const QString &proFilePath) : RunConfiguration(parent, QLatin1String(S60_DEVICE_RC_ID)), m_proFilePath(proFilePath), - m_cachedTargetInformationValid(false), #ifdef Q_OS_WIN m_serialPortName(QLatin1String("COM5")), #else @@ -126,7 +125,6 @@ S60DeviceRunConfiguration::S60DeviceRunConfiguration(Target *parent, const QStri S60DeviceRunConfiguration::S60DeviceRunConfiguration(Target *target, S60DeviceRunConfiguration *source) : RunConfiguration(target, source), m_proFilePath(source->m_proFilePath), - m_cachedTargetInformationValid(false), m_serialPortName(source->m_serialPortName), m_signingMode(source->m_signingMode), m_customSignaturePath(source->m_customSignaturePath), @@ -135,12 +133,6 @@ S60DeviceRunConfiguration::S60DeviceRunConfiguration(Target *target, S60DeviceRu ctor(); } -void S60DeviceRunConfiguration::proFileUpdate(Qt4ProjectManager::Internal::Qt4ProFileNode *pro) -{ - if (m_proFilePath == pro->path()) - invalidateCachedTargetInformation(); -} - void S60DeviceRunConfiguration::ctor() { if (!m_proFilePath.isEmpty()) @@ -148,11 +140,17 @@ void S60DeviceRunConfiguration::ctor() else setDisplayName(tr("QtS60DeviceRunConfiguration")); - connect(target(), SIGNAL(targetInformationChanged()), - this, SLOT(invalidateCachedTargetInformation())); - connect(qt4Target()->qt4Project(), SIGNAL(proFileUpdated(Qt4ProjectManager::Internal::Qt4ProFileNode*)), this, SLOT(proFileUpdate(Qt4ProjectManager::Internal::Qt4ProFileNode*))); + + connect(qt4Target()->qt4Project(), SIGNAL(targetInformationChanged(Qt4ProjectManager::Internal::Qt4ProFileNode*)), + this, SLOT(proFileUpdate(Qt4ProjectManager::Internal::Qt4ProFileNode*))); +} + +void S60DeviceRunConfiguration::proFileUpdate(Qt4ProjectManager::Internal::Qt4ProFileNode *pro) +{ + if (m_proFilePath == pro->path()) + emit targetInformationChanged(); } @@ -246,32 +244,60 @@ void S60DeviceRunConfiguration::setSerialPortName(const QString &name) QString S60DeviceRunConfiguration::targetName() const { - const_cast<S60DeviceRunConfiguration *>(this)->updateTarget(); - return m_targetName; + TargetInformation ti = qt4Target()->qt4Project()->rootProjectNode()->targetInformation(m_proFilePath); + if (!ti.valid) + return QString(); + return ti.target; +} + +static inline QString fixBaseNameTarget(const QString &in) +{ + if (in == QLatin1String("udeb")) + return QLatin1String("debug"); + if (in == QLatin1String("urel")) + return QLatin1String("release"); + return in; } QString S60DeviceRunConfiguration::basePackageFilePath() const { - const_cast<S60DeviceRunConfiguration *>(this)->updateTarget(); - return m_baseFileName; + TargetInformation ti = qt4Target()->qt4Project()->rootProjectNode()->targetInformation(m_proFilePath); + if (!ti.valid) + return QString(); + QString baseFileName = ti.workingDir + QLatin1Char('/') + ti.target; + baseFileName += QLatin1Char('_') + fixBaseNameTarget(symbianPlatform()) + QLatin1Char('_') + symbianTarget(); + return baseFileName; } QString S60DeviceRunConfiguration::symbianPlatform() const { - const_cast<S60DeviceRunConfiguration *>(this)->updateTarget(); - return m_platform; + Qt4BuildConfiguration *qt4bc = qt4Target()->qt4Project()->activeTarget()->activeBuildConfiguration(); + switch (qt4bc->toolChainType()) { + case ToolChain::GCCE: + case ToolChain::GCCE_GNUPOC: + return QLatin1String("gcce"); + case ToolChain::RVCT_ARMV5: + return QLatin1String("armv5"); + default: // including ToolChain::RVCT_ARMV6_GNUPOC: + return QLatin1String("armv6"); + } } QString S60DeviceRunConfiguration::symbianTarget() const { - const_cast<S60DeviceRunConfiguration *>(this)->updateTarget(); - return m_target; + Qt4BuildConfiguration *qt4bc = qt4Target()->qt4Project()->activeTarget()->activeBuildConfiguration(); + if (qt4bc->qmakeBuildConfiguration() & QtVersion::DebugBuild) + return QString("udeb"); + else + return QString("urel"); } QString S60DeviceRunConfiguration::packageTemplateFileName() const { - const_cast<S60DeviceRunConfiguration *>(this)->updateTarget(); - return m_packageTemplateFileName; + TargetInformation ti = qt4Target()->qt4Project()->rootProjectNode()->targetInformation(m_proFilePath); + if (!ti.valid) + return QString(); + return ti.workingDir + QLatin1Char('/') + ti.target + QLatin1String("_template.pkg"); } S60DeviceRunConfiguration::SigningMode S60DeviceRunConfiguration::signingMode() const @@ -373,8 +399,7 @@ QString S60DeviceRunConfiguration::localExecutableFileName() const QString S60DeviceRunConfiguration::signedPackage() const { - const_cast<S60DeviceRunConfiguration *>(this)->updateTarget(); - return QDir::toNativeSeparators(m_baseFileName + QLatin1String(".sis")); + return QDir::toNativeSeparators(basePackageFilePath() + QLatin1String(".sis")); } QStringList S60DeviceRunConfiguration::commandLineArguments() const @@ -387,74 +412,6 @@ void S60DeviceRunConfiguration::setCommandLineArguments(const QStringList &args) m_commandLineArguments = args; } -// Fix up target specification for "make sis": -// "udeb"-> "debug", "urel" -> "release" -static inline QString fixBaseNameTarget(const QString &in) -{ - if (in == QLatin1String("udeb")) - return QLatin1String("debug"); - if (in == QLatin1String("urel")) - return QLatin1String("release"); - return in; -} - -void S60DeviceRunConfiguration::updateTarget() -{ - if (m_cachedTargetInformationValid) - return; - Qt4TargetInformation info = qt4Target()->targetInformation(qt4Target()->activeBuildConfiguration(), - m_proFilePath); - if (info.error != Qt4TargetInformation::NoError) { - if (info.error == Qt4TargetInformation::ProParserError) { - Core::ICore::instance()->messageManager()->printToOutputPane( - tr("Could not parse %1. The Qt Symbian Device run configuration %2 can not be started.") - .arg(m_proFilePath).arg(displayName())); - } - m_targetName.clear(); - m_baseFileName.clear(); - m_packageTemplateFileName.clear(); - m_platform.clear(); - m_cachedTargetInformationValid = true; - emit targetInformationChanged(); - return; - } - - m_targetName = info.target; - - m_baseFileName = info.workingDir + QLatin1Char('/') + m_targetName; - m_packageTemplateFileName = m_baseFileName + QLatin1String("_template.pkg"); - - Qt4BuildConfiguration *qt4bc = qt4Target()->activeBuildConfiguration(); - switch (qt4bc->toolChainType()) { - case ToolChain::GCCE: - case ToolChain::GCCE_GNUPOC: - m_platform = QLatin1String("gcce"); - break; - case ToolChain::RVCT_ARMV5: - case ToolChain::RVCT_ARMV5_GNUPOC: - m_platform = QLatin1String("armv5"); - break; - default: - m_platform = QLatin1String("armv6"); - break; - } - if (qt4bc->qmakeBuildConfiguration() & QtVersion::DebugBuild) - m_target = QLatin1String("udeb"); - else - m_target = QLatin1String("urel"); - m_baseFileName += QLatin1Char('_') + fixBaseNameTarget(m_target) - + QLatin1Char('-') + m_platform; - m_cachedTargetInformationValid = true; - emit targetInformationChanged(); -} - -void S60DeviceRunConfiguration::invalidateCachedTargetInformation() -{ - m_cachedTargetInformationValid = false; - emit targetInformationChanged(); -} - - // ======== S60DeviceRunConfigurationFactory S60DeviceRunConfigurationFactory::S60DeviceRunConfigurationFactory(QObject *parent) : diff --git a/src/plugins/qt4projectmanager/qt-s60/s60devicerunconfiguration.h b/src/plugins/qt4projectmanager/qt-s60/s60devicerunconfiguration.h index 5fc034e3c12..f4a0d2c6605 100644 --- a/src/plugins/qt4projectmanager/qt-s60/s60devicerunconfiguration.h +++ b/src/plugins/qt4projectmanager/qt-s60/s60devicerunconfiguration.h @@ -110,7 +110,6 @@ signals: void serialPortNameChanged(); private slots: - void invalidateCachedTargetInformation(); void proFileUpdate(Qt4ProjectManager::Internal::Qt4ProFileNode *pro); protected: @@ -119,16 +118,9 @@ protected: private: ProjectExplorer::ToolChain::ToolChainType toolChainType(ProjectExplorer::BuildConfiguration *configuration) const; - void updateTarget(); void ctor(); QString m_proFilePath; - QString m_targetName; - QString m_platform; - QString m_target; - QString m_baseFileName; - QString m_packageTemplateFileName; - bool m_cachedTargetInformationValid; QString m_serialPortName; SigningMode m_signingMode; QString m_customSignaturePath; diff --git a/src/plugins/qt4projectmanager/qt-s60/s60emulatorrunconfiguration.cpp b/src/plugins/qt4projectmanager/qt-s60/s60emulatorrunconfiguration.cpp index 523cbe60caa..b132284fdc4 100644 --- a/src/plugins/qt4projectmanager/qt-s60/s60emulatorrunconfiguration.cpp +++ b/src/plugins/qt4projectmanager/qt-s60/s60emulatorrunconfiguration.cpp @@ -76,16 +76,14 @@ QString pathToId(const QString &path) S60EmulatorRunConfiguration::S60EmulatorRunConfiguration(Target *parent, const QString &proFilePath) : RunConfiguration(parent, QLatin1String(S60_EMULATOR_RC_ID)), - m_proFilePath(proFilePath), - m_cachedTargetInformationValid(false) + m_proFilePath(proFilePath) { ctor(); } S60EmulatorRunConfiguration::S60EmulatorRunConfiguration(Target *parent, S60EmulatorRunConfiguration *source) : RunConfiguration(parent, source), - m_proFilePath(source->m_proFilePath), - m_cachedTargetInformationValid(false) + m_proFilePath(source->m_proFilePath) { ctor(); } @@ -97,11 +95,11 @@ void S60EmulatorRunConfiguration::ctor() else setDisplayName(tr("Qt Symbian Emulator RunConfiguration")); - connect(qt4Target(), SIGNAL(targetInformationChanged()), - this, SLOT(invalidateCachedTargetInformation())); - connect(qt4Target()->qt4Project(), SIGNAL(proFileUpdated(Qt4ProjectManager::Internal::Qt4ProFileNode*)), this, SLOT(proFileUpdate(Qt4ProjectManager::Internal::Qt4ProFileNode*))); + + connect(qt4Target()->qt4Project(), SIGNAL(targetInformationChanged(Qt4ProjectManager::Internal::Qt4ProFileNode*)), + this, SLOT(proFileUpdate(Qt4ProjectManager::Internal::Qt4ProFileNode*))); } @@ -112,10 +110,9 @@ S60EmulatorRunConfiguration::~S60EmulatorRunConfiguration() void S60EmulatorRunConfiguration::proFileUpdate(Qt4ProjectManager::Internal::Qt4ProFileNode *pro) { if (m_proFilePath == pro->path()) - invalidateCachedTargetInformation(); + emit targetInformationChanged(); } - Qt4Target *S60EmulatorRunConfiguration::qt4Target() const { return static_cast<Qt4Target *>(target()); @@ -152,28 +149,6 @@ bool S60EmulatorRunConfiguration::fromMap(const QVariantMap &map) QString S60EmulatorRunConfiguration::executable() const { - const_cast<S60EmulatorRunConfiguration *>(this)->updateTarget(); - return m_executable; -} - -void S60EmulatorRunConfiguration::updateTarget() -{ - if (m_cachedTargetInformationValid) - return; - Qt4TargetInformation info = qt4Target()->targetInformation(qt4Target()->activeBuildConfiguration(), - m_proFilePath); - if (info.error != Qt4TargetInformation::NoError) { - if (info.error == Qt4TargetInformation::ProParserError) { - Core::ICore::instance()->messageManager()->printToOutputPane( - tr("Could not parse %1. The Qt for Symbian emulator run configuration %2 can not be started.") - .arg(m_proFilePath).arg(displayName())); - } - m_executable.clear(); - m_cachedTargetInformationValid = true; - emit targetInformationChanged(); - return; - } - Qt4BuildConfiguration *qt4bc = qt4Target()->activeBuildConfiguration(); QtVersion *qtVersion = qt4bc->qtVersion(); QString baseDir = S60Manager::instance()->deviceForQtVersion(qtVersion).epocRoot; @@ -182,18 +157,13 @@ void S60EmulatorRunConfiguration::updateTarget() qmakeBuildConfig = "udeb"; baseDir += "/epoc32/release/winscw/" + qmakeBuildConfig; - m_executable = QDir::toNativeSeparators( - QDir::cleanPath(baseDir + QLatin1Char('/') + info.target)); - m_executable += QLatin1String(".exe"); - - m_cachedTargetInformationValid = true; - emit targetInformationChanged(); -} + TargetInformation ti = qt4Target()->qt4Project()->rootProjectNode()->targetInformation(m_proFilePath); + if (!ti.valid) + return QString(); + QString executable = QDir::toNativeSeparators(QDir::cleanPath(baseDir + QLatin1Char('/') + ti.target)); + executable += QLatin1String(".exe"); -void S60EmulatorRunConfiguration::invalidateCachedTargetInformation() -{ - m_cachedTargetInformationValid = false; - emit targetInformationChanged(); + return executable; } // ======== S60EmulatorRunConfigurationWidget diff --git a/src/plugins/qt4projectmanager/qt-s60/s60emulatorrunconfiguration.h b/src/plugins/qt4projectmanager/qt-s60/s60emulatorrunconfiguration.h index 8191c1b46b8..decd95bcff4 100644 --- a/src/plugins/qt4projectmanager/qt-s60/s60emulatorrunconfiguration.h +++ b/src/plugins/qt4projectmanager/qt-s60/s60emulatorrunconfiguration.h @@ -75,7 +75,6 @@ signals: void targetInformationChanged(); private slots: - void invalidateCachedTargetInformation(); void proFileUpdate(Qt4ProjectManager::Internal::Qt4ProFileNode *pro); protected: @@ -87,8 +86,6 @@ private: void updateTarget(); QString m_proFilePath; - QString m_executable; - bool m_cachedTargetInformationValid; }; class S60EmulatorRunConfigurationWidget : public QWidget diff --git a/src/plugins/qt4projectmanager/qt4buildconfiguration.cpp b/src/plugins/qt4projectmanager/qt4buildconfiguration.cpp index 417280f4282..4ca104c5edd 100644 --- a/src/plugins/qt4projectmanager/qt4buildconfiguration.cpp +++ b/src/plugins/qt4projectmanager/qt4buildconfiguration.cpp @@ -277,10 +277,11 @@ void Qt4BuildConfiguration::setShadowBuildAndDirectory(bool shadowBuild, const Q { if (m_shadowBuild == shadowBuild && m_buildDirectory == buildDirectory) return; + m_shadowBuild = shadowBuild; m_buildDirectory = buildDirectory; emit buildDirectoryChanged(); - emit targetInformationChanged(); + emit proFileEvaluateNeeded(this); } ProjectExplorer::ToolChain *Qt4BuildConfiguration::toolChain() const @@ -340,8 +341,9 @@ void Qt4BuildConfiguration::setQtVersion(QtVersion *version) return; m_qtVersionId = version->uniqueId(); + + emit proFileEvaluateNeeded(this); emit qtVersionChanged(); - emit targetInformationChanged(); emit environmentChanged(); } @@ -351,8 +353,9 @@ void Qt4BuildConfiguration::setToolChainType(ProjectExplorer::ToolChain::ToolCha m_toolChainType == type) return; m_toolChainType = type; + + emit proFileEvaluateNeeded(this); emit toolChainTypeChanged(); - emit targetInformationChanged(); emit environmentChanged(); } @@ -371,8 +374,9 @@ void Qt4BuildConfiguration::setQMakeBuildConfiguration(QtVersion::QmakeBuildConf if (m_qmakeBuildConfiguration == config) return; m_qmakeBuildConfiguration = config; + + emit proFileEvaluateNeeded(this); emit qmakeBuildConfigurationChanged(); - emit targetInformationChanged(); } void Qt4BuildConfiguration::emitQMakeBuildConfigurationChanged() diff --git a/src/plugins/qt4projectmanager/qt4buildconfiguration.h b/src/plugins/qt4projectmanager/qt4buildconfiguration.h index 8886f48e87e..074b0310598 100644 --- a/src/plugins/qt4projectmanager/qt4buildconfiguration.h +++ b/src/plugins/qt4projectmanager/qt4buildconfiguration.h @@ -84,7 +84,8 @@ public: QtVersion::QmakeBuildConfigs qmakeBuildConfiguration() const; void setQMakeBuildConfiguration(QtVersion::QmakeBuildConfigs config); // used by qmake step to notify that the qmake args have changed - // not really nice + // not really nice, the build configuration should save the arguments + // since they are needed for reevaluation void emitQMakeBuildConfigurationChanged(); // used by qmake step to notify that the build directory was initialized // not really nice @@ -119,9 +120,9 @@ signals: /// if those change the qmakebuildconfig void qmakeBuildConfigurationChanged(); - /// a covenience signal, emitted if either the qtversion, the toolchainType or the qmake build - /// configuration changed - void targetInformationChanged(); + /// emitted if the build configuration changed in a way that + /// should trigger a reevaluation of all .pro files + void proFileEvaluateNeeded(Qt4ProjectManager::Internal::Qt4BuildConfiguration *); void buildDirectoryInitialized(); diff --git a/src/plugins/qt4projectmanager/qt4nodes.cpp b/src/plugins/qt4projectmanager/qt4nodes.cpp index ddb802e214c..168517d292e 100644 --- a/src/plugins/qt4projectmanager/qt4nodes.cpp +++ b/src/plugins/qt4projectmanager/qt4nodes.cpp @@ -58,12 +58,12 @@ #include <QtCore/QDir> #include <QtCore/QFile> #include <QtCore/QFileInfo> -#include <QtCore/QTimer> #include <QtGui/QPainter> #include <QtGui/QMainWindow> #include <QtGui/QMessageBox> #include <QtGui/QPushButton> +#include <qtconcurrent/QtConcurrentTools> // Static cached data in struct Qt4NodeStaticData providing information and icons // for file types and the project. Do some magic via qAddPostRoutine() @@ -453,22 +453,44 @@ struct InternalNode } }; -void Qt4PriFileNode::update(ProFile *includeFile, ProFileReader *reader) + +QStringList Qt4PriFileNode::baseVPaths(ProFileReader *reader, const QString &projectDir) { - Q_ASSERT(includeFile); - Q_ASSERT(reader); + QStringList result; + if (!reader) + return result; + result += reader->absolutePathValues("VPATH", projectDir); + result << projectDir; // QMAKE_ABSOLUTE_SOURCE_PATH + result += reader->absolutePathValues("DEPENDPATH", projectDir); + result.removeDuplicates(); + return result; +} +QStringList Qt4PriFileNode::fullVPaths(const QStringList &baseVPaths, ProFileReader *reader, FileType type, const QString &qmakeVariable, const QString &projectDir) +{ + QStringList vPaths; + if (!reader) + return vPaths; + if (type == ProjectExplorer::SourceType) + vPaths = reader->absolutePathValues("VPATH_" + qmakeVariable, projectDir); + vPaths += baseVPaths; + if (type == ProjectExplorer::HeaderType) + vPaths += reader->absolutePathValues("INCLUDEPATH", projectDir); + vPaths.removeDuplicates(); + return vPaths; +} + + +void Qt4PriFileNode::update(ProFile *includeFileExact, ProFileReader *readerExact, ProFile *includeFileCumlative, ProFileReader *readerCumulative) +{ // add project file node if (m_fileNodes.isEmpty()) addFileNodes(QList<FileNode*>() << new FileNode(m_projectFilePath, ProjectFileType, false), this); const QString &projectDir = m_qt4ProFileNode->m_projectDir; - QStringList baseVPaths; - baseVPaths += reader->absolutePathValues("VPATH", projectDir); - baseVPaths << projectDir; // QMAKE_ABSOLUTE_SOURCE_PATH - baseVPaths += reader->absolutePathValues("DEPENDPATH", projectDir); - baseVPaths.removeDuplicates(); + QStringList baseVPathsExact = baseVPaths(readerExact, projectDir); + QStringList baseVPathsCumulative = baseVPaths(readerCumulative, projectDir); const QVector<Qt4NodeStaticData::FileTypeData> &fileTypes = qt4NodeStaticData()->fileTypeData; @@ -481,14 +503,14 @@ void Qt4PriFileNode::update(ProFile *includeFile, ProFileReader *reader) QStringList newFilePaths; foreach (const QString &qmakeVariable, qmakeVariables) { - QStringList vPaths; - if (type == ProjectExplorer::SourceType) - vPaths = reader->absolutePathValues("VPATH_" + qmakeVariable, projectDir); - vPaths += baseVPaths; - if (type == ProjectExplorer::HeaderType) - vPaths += reader->absolutePathValues("INCLUDEPATH", projectDir); - vPaths.removeDuplicates(); - newFilePaths += reader->absoluteFileValues(qmakeVariable, projectDir, vPaths, includeFile); + QStringList vPathsExact = fullVPaths(baseVPathsExact, readerExact, type, qmakeVariable, projectDir); + QStringList vPathsCumulative = fullVPaths(baseVPathsCumulative, readerCumulative, type, qmakeVariable, projectDir); + + + newFilePaths += readerExact->absoluteFileValues(qmakeVariable, projectDir, vPathsExact, includeFileExact); + if (readerCumulative) + newFilePaths += readerCumulative->absoluteFileValues(qmakeVariable, projectDir, vPathsCumulative, includeFileCumlative); + } newFilePaths.removeDuplicates(); @@ -773,6 +795,16 @@ Qt4ProFileNode *Qt4ProFileNode::findProFileFor(const QString &fileName) return 0; } +TargetInformation Qt4ProFileNode::targetInformation(const QString &fileName) +{ + TargetInformation result; + Qt4ProFileNode *qt4ProFileNode = findProFileFor(fileName); + if (!qt4ProFileNode) + return result; + + return qt4ProFileNode->targetInformation(); +} + /*! \class Qt4ProFileNode Implements abstract ProjectNode class @@ -781,20 +813,19 @@ Qt4ProFileNode::Qt4ProFileNode(Qt4Project *project, const QString &filePath, QObject *parent) : Qt4PriFileNode(project, this, filePath), - // own stuff - m_projectType(InvalidProject) + m_projectType(InvalidProject), + m_readerExact(0), + m_readerCumulative(0) { + if (parent) setParent(parent); - m_updateTimer.setInterval(100); - m_updateTimer.setSingleShot(true); - - connect(&m_updateTimer, SIGNAL(timeout()), - this, SLOT(update())); - connect(ProjectExplorer::ProjectExplorerPlugin::instance()->buildManager(), SIGNAL(buildStateChanged(ProjectExplorer::Project*)), this, SLOT(buildStateChanged(ProjectExplorer::Project*))); + + connect(&m_parseFutureWatcher, SIGNAL(finished()), + this, SLOT(applyAsyncEvaluate())); } Qt4ProFileNode::~Qt4ProFileNode() @@ -807,6 +838,16 @@ Qt4ProFileNode::~Qt4ProFileNode() modelManager->removeEditorSupport(it.value()); delete it.value(); } + m_parseFutureWatcher.waitForFinished(); +} + +bool Qt4ProFileNode::isParent(Qt4ProFileNode *node) +{ + while (node = qobject_cast<Qt4ProFileNode *>(node->parentFolderNode())) { + if (node == this) + return true; + } + return false; } void Qt4ProFileNode::buildStateChanged(ProjectExplorer::Project *project) @@ -834,17 +875,97 @@ QStringList Qt4ProFileNode::variableValue(const Qt4Variable var) const void Qt4ProFileNode::scheduleUpdate() { - m_updateTimer.start(); + m_project->scheduleAsyncUpdate(this); +} + +void Qt4ProFileNode::asyncUpdate() +{ + m_project->incrementPendingEvaluateFutures(); + setupReader(); + QFuture<bool> future = QtConcurrent::run(&Qt4ProFileNode::asyncEvaluate, this); + m_parseFutureWatcher.setFuture(future); } void Qt4ProFileNode::update() { - ProFileReader *reader = m_project->createProFileReader(this); - Q_ASSERT(reader); - if (!reader->readProFile(m_projectFilePath)) { + setupReader(); + bool parserError = evaluate(); + applyEvaluate(!parserError, false); +} + +void Qt4ProFileNode::setupReader() +{ + Q_ASSERT(!m_readerExact); + Q_ASSERT(!m_readerCumulative); + + m_readerExact = m_project->createProFileReader(this); + m_readerExact->setCumulative(false); + + m_readerCumulative = m_project->createProFileReader(this); + + // Find out what flags we pass on to qmake + QStringList addedUserConfigArguments; + QStringList removedUserConfigArguments; + m_project->activeTarget()->activeBuildConfiguration()->getConfigCommandLineArguments(&addedUserConfigArguments, &removedUserConfigArguments); + + m_readerExact->setConfigCommandLineArguments(addedUserConfigArguments, removedUserConfigArguments); + m_readerCumulative->setConfigCommandLineArguments(addedUserConfigArguments, removedUserConfigArguments); +} + +bool Qt4ProFileNode::evaluate() +{ + bool parserError = false; + if (!m_readerExact->readProFile(m_projectFilePath)) { m_project->proFileParseError(tr("Error while parsing file %1. Giving up.").arg(m_projectFilePath)); - m_project->destroyProFileReader(reader); - invalidate(); + parserError = true; + } + + if (!m_readerCumulative->readProFile(m_projectFilePath)) { + m_project->proFileParseError(tr("Error while parsing file %1. Giving up.").arg(m_projectFilePath)); + parserError = true; + } + return parserError; +} + +void Qt4ProFileNode::asyncEvaluate(QFutureInterface<bool> &fi) +{ + bool parserError = evaluate(); + fi.reportResult(!parserError); +} + +void Qt4ProFileNode::applyAsyncEvaluate() +{ + applyEvaluate(m_parseFutureWatcher.result(), true); + m_project->decrementPendingEvaluateFutures(); +} + +Qt4ProjectType proFileTemplateTypeToProjectType(ProFileEvaluator::TemplateType type) +{ + switch (type) { + case ProFileEvaluator::TT_Unknown: + case ProFileEvaluator::TT_Application: + return ApplicationTemplate; + case ProFileEvaluator::TT_Library: + return LibraryTemplate; + case ProFileEvaluator::TT_Script: + return ScriptTemplate; + case ProFileEvaluator::TT_Subdirs: + return SubDirsTemplate; + default: + return InvalidProject; + } +} + +void Qt4ProFileNode::applyEvaluate(bool parseResult, bool async) +{ + if (!parseResult || m_project->wasEvaluateCanceled()) { + if (m_readerExact) + m_project->destroyProFileReader(m_readerExact); + if (m_readerCumulative) + m_project->destroyProFileReader(m_readerCumulative); + m_readerExact = m_readerCumulative = 0; + if (!parseResult) // Invalidate + invalidate(); return; } @@ -852,29 +973,25 @@ void Qt4ProFileNode::update() qDebug() << "Qt4ProFileNode - updating files for file " << m_projectFilePath; Qt4ProjectType projectType = InvalidProject; - switch (reader->templateType()) { - case ProFileEvaluator::TT_Unknown: - case ProFileEvaluator::TT_Application: { - projectType = ApplicationTemplate; - break; - } - case ProFileEvaluator::TT_Library: { - projectType = LibraryTemplate; - break; - } - case ProFileEvaluator::TT_Script: { - projectType = ScriptTemplate; - break; - } - case ProFileEvaluator::TT_Subdirs: - projectType = SubDirsTemplate; - break; + // Check that both are the same if we have both + if (m_readerExact->templateType() != m_readerCumulative->templateType()) { + // Now what. The only thing which could be reasonable is that someone + // changes between template app and library. + // Well, we are conservative here for now. + // Let's wait until someone complains and look at what they are doing. + m_project->destroyProFileReader(m_readerCumulative); + m_readerCumulative = 0; } + + projectType = proFileTemplateTypeToProjectType(m_readerExact->templateType()); + if (projectType != m_projectType) { Qt4ProjectType oldType = m_projectType; // probably all subfiles/projects have changed anyway ... clear(); m_projectType = projectType; + // really emit here? or at the end? Noone is connected to this signal at the moment + // so we kind of can ignore that question for now foreach (NodesWatcher *watcher, watchers()) if (Qt4NodesWatcher *qt4Watcher = qobject_cast<Qt4NodesWatcher*>(watcher)) emit qt4Watcher->projectTypeChanged(this, oldType, projectType); @@ -886,97 +1003,165 @@ void Qt4ProFileNode::update() QList<ProjectNode*> existingProjectNodes = subProjectNodes(); - QList<QString> newProjectFiles; - QHash<QString, ProFile*> includeFiles; - ProFile *fileForCurrentProject = 0; - { - if (projectType == SubDirsTemplate) { - foreach (const QString &subDirProject, subDirsPaths(reader)) - newProjectFiles << subDirProject; + QStringList newProjectFilesExact; + QHash<QString, ProFile*> includeFilesExact; + ProFile *fileForCurrentProjectExact = 0; + if (m_projectType == SubDirsTemplate) + newProjectFilesExact = subDirsPaths(m_readerExact); + foreach (ProFile *includeFile, m_readerExact->includeFiles()) { + if (includeFile->fileName() == m_projectFilePath) { // this file + fileForCurrentProjectExact = includeFile; + } else { + newProjectFilesExact << includeFile->fileName(); + includeFilesExact.insert(includeFile->fileName(), includeFile); } + } - foreach (ProFile *includeFile, reader->includeFiles()) { - if (includeFile->fileName() == m_projectFilePath) { // this file - fileForCurrentProject = includeFile; + + QStringList newProjectFilesCumlative; + QHash<QString, ProFile*> includeFilesCumlative; + ProFile *fileForCurrentProjectCumlative = 0; + if (m_readerCumulative) { + if (m_projectType == SubDirsTemplate) + newProjectFilesCumlative = subDirsPaths(m_readerCumulative); + foreach (ProFile *includeFile, m_readerCumulative->includeFiles()) { + if (includeFile->fileName() == m_projectFilePath) { + fileForCurrentProjectCumlative = includeFile; } else { - newProjectFiles << includeFile->fileName(); - includeFiles.insert(includeFile->fileName(), includeFile); + newProjectFilesCumlative << includeFile->fileName(); + includeFilesCumlative.insert(includeFile->fileName(), includeFile); } } } qSort(existingProjectNodes.begin(), existingProjectNodes.end(), sortNodesByPath); - qSort(newProjectFiles.begin(), newProjectFiles.end()); + qSort(newProjectFilesExact); + qSort(newProjectFilesCumlative); QList<ProjectNode*> toAdd; QList<ProjectNode*> toRemove; - QList<ProjectNode*>::const_iterator existingNodeIter = existingProjectNodes.constBegin(); - QList<QString>::const_iterator newProjectFileIter = newProjectFiles.constBegin(); - while (existingNodeIter != existingProjectNodes.constEnd() - && newProjectFileIter != newProjectFiles.constEnd()) { - if ((*existingNodeIter)->path() < *newProjectFileIter) { - toRemove << *existingNodeIter; - ++existingNodeIter; - } else if ((*existingNodeIter)->path() > *newProjectFileIter) { - if (ProFile *file = includeFiles.value(*newProjectFileIter)) { - Qt4PriFileNode *priFileNode - = new Qt4PriFileNode(m_project, this, - *newProjectFileIter); - priFileNode->update(file, reader); - toAdd << priFileNode; + QList<ProjectNode*>::const_iterator existingIt = existingProjectNodes.constBegin(); + QStringList::const_iterator newExactIt = newProjectFilesExact.constBegin(); + QStringList::const_iterator newCumlativeIt = newProjectFilesCumlative.constBegin(); + + forever { + bool existingAtEnd = (existingIt == existingProjectNodes.constEnd()); + bool newExactAtEnd = (newExactIt == newProjectFilesExact.constEnd()); + bool newCumlativeAtEnd = (newCumlativeIt == newProjectFilesCumlative.constEnd()); + + if (existingAtEnd && newExactAtEnd && newCumlativeAtEnd) + break; // we are done, hurray! + + // So this is one giant loop comparing 3 lists at once and sorting the comparision + // into mainly 2 buckets: toAdd and toRemove + // We need to distinguish between nodes that came from exact and cumalative + // parsing, since the update call is diffrent for them + // I believe this code to be correct, be careful in changing it + + QString nodeToAdd; + if (! existingAtEnd + && (newExactAtEnd || (*existingIt)->path() < *newExactIt) + && (newCumlativeAtEnd || (*existingIt)->path() < *newCumlativeIt)) { + // Remove case + toRemove << *existingIt; + ++existingIt; + } else if(! newExactAtEnd + && (existingAtEnd || *newExactIt < (*existingIt)->path()) + && (newCumlativeAtEnd || *newExactIt < *newCumlativeIt)) { + // Mark node from exact for adding + nodeToAdd = *newExactIt; + ++newExactIt; + } else if (! newCumlativeAtEnd + && (existingAtEnd || *newCumlativeIt < (*existingIt)->path()) + && (newExactAtEnd || *newCumlativeIt < *newExactIt)) { + // Mark node from cumalative for adding + nodeToAdd = *newCumlativeIt; + ++newCumlativeIt; + } else if (!newExactAtEnd + && !newCumlativeAtEnd + && (existingAtEnd || *newExactIt < (*existingIt)->path()) + && (existingAtEnd || *newCumlativeIt < (*existingIt)->path())) { + // Mark node from both for adding + nodeToAdd = *newExactIt; + ++newExactIt; + ++newCumlativeIt; + } else { + Q_ASSERT(!newExactAtEnd || !newCumlativeAtEnd); + // update case, figure out which case exactly + if (newExactAtEnd) { + ++newCumlativeIt; + } else if (newCumlativeAtEnd) { + ++newExactIt; + } else if(*newExactIt < *newCumlativeIt) { + ++newExactIt; + } else if (*newCumlativeIt < *newExactIt) { + ++newCumlativeIt; } else { - toAdd << createSubProFileNode(*newProjectFileIter); + ++newExactIt; + ++newCumlativeIt; } - ++newProjectFileIter; - } else { // *existingNodeIter->path() == *newProjectFileIter - if (ProFile *file = includeFiles.value(*newProjectFileIter)) { - Qt4PriFileNode *priFileNode = static_cast<Qt4PriFileNode*>(*existingNodeIter); - priFileNode->update(file, reader); + // Update existingNodeIte + ProFile *fileExact = includeFilesCumlative.value((*existingIt)->path()); + ProFile *fileCumlative = includeFilesCumlative.value((*existingIt)->path()); + if (fileExact || fileCumlative) { + static_cast<Qt4PriFileNode *>(*existingIt)->update(fileExact, m_readerExact, fileCumlative, m_readerCumulative); + } else { + // We always parse exactly, because we later when async parsing don't know whether + // the .pro file is included in this .pro file + // So to compare that later parse with the sync one + if (async) + static_cast<Qt4ProFileNode *>(*existingIt)->asyncUpdate(); + else + static_cast<Qt4ProFileNode *>(*existingIt)->update(); } + ++existingIt; + // newCumalativeIt and newExactIt are already incremented - ++existingNodeIter; - ++newProjectFileIter; } - } - while (existingNodeIter != existingProjectNodes.constEnd()) { - toRemove << *existingNodeIter; - ++existingNodeIter; - } - while (newProjectFileIter != newProjectFiles.constEnd()) { - if (ProFile *file = includeFiles.value(*newProjectFileIter)) { - Qt4PriFileNode *priFileNode - = new Qt4PriFileNode(m_project, this, - *newProjectFileIter); - priFileNode->update(file, reader); - toAdd << priFileNode; - } else { - toAdd << createSubProFileNode(*newProjectFileIter); + // If we found something to add do it + if (!nodeToAdd.isEmpty()) { + ProFile *fileExact = includeFilesCumlative.value(nodeToAdd); + ProFile *fileCumlative = includeFilesCumlative.value(nodeToAdd); + if (fileExact || fileCumlative) { + Qt4PriFileNode *qt4PriFileNode = new Qt4PriFileNode(m_project, this, nodeToAdd); + qt4PriFileNode->update(fileExact, m_readerExact, fileCumlative, m_readerCumulative); + toAdd << qt4PriFileNode; + } else { + Qt4ProFileNode *qt4ProFileNode = new Qt4ProFileNode(m_project, nodeToAdd); + if (async) + qt4ProFileNode->asyncUpdate(); + else + qt4ProFileNode->update(); + toAdd << qt4ProFileNode; + } } - ++newProjectFileIter; - } + } // for if (!toRemove.isEmpty()) removeProjectNodes(toRemove); if (!toAdd.isEmpty()) addProjectNodes(toAdd); - Qt4PriFileNode::update(fileForCurrentProject, reader); + Qt4PriFileNode::update(fileForCurrentProjectExact, m_readerExact, fileForCurrentProjectCumlative, m_readerCumulative); + + // update TargetInformation + m_qt4targetInformation = targetInformation(m_readerExact); // update other variables QHash<Qt4Variable, QStringList> newVarValues; - newVarValues[DefinesVar] = reader->values(QLatin1String("DEFINES")); - newVarValues[IncludePathVar] = includePaths(reader); - newVarValues[UiDirVar] = uiDirPaths(reader); - newVarValues[MocDirVar] = mocDirPaths(reader); - newVarValues[PkgConfigVar] = reader->values(QLatin1String("PKGCONFIG")); + newVarValues[DefinesVar] = m_readerExact->values(QLatin1String("DEFINES")); + newVarValues[IncludePathVar] = includePaths(m_readerExact); + newVarValues[UiDirVar] = uiDirPaths(m_readerExact); + newVarValues[MocDirVar] = mocDirPaths(m_readerExact); + newVarValues[PkgConfigVar] = m_readerExact->values(QLatin1String("PKGCONFIG")); newVarValues[PrecompiledHeaderVar] = - reader->absoluteFileValues(QLatin1String("PRECOMPILED_HEADER"), - m_projectDir, - QStringList() << m_projectDir, - 0); + m_readerExact->absoluteFileValues(QLatin1String("PRECOMPILED_HEADER"), + m_projectDir, + QStringList() << m_projectDir, + 0); if (m_varValues != newVarValues) { m_varValues = newVarValues; @@ -992,7 +1177,12 @@ void Qt4ProFileNode::update() if (Qt4NodesWatcher *qt4Watcher = qobject_cast<Qt4NodesWatcher*>(watcher)) emit qt4Watcher->proFileUpdated(this); - m_project->destroyProFileReader(reader); + m_project->destroyProFileReader(m_readerExact); + if (m_readerCumulative) + m_project->destroyProFileReader(m_readerCumulative); + + m_readerExact = 0; + m_readerCumulative = 0; } namespace { @@ -1124,13 +1314,6 @@ QStringList Qt4ProFileNode::updateUiFiles() return toUpdate; } -Qt4ProFileNode *Qt4ProFileNode::createSubProFileNode(const QString &path) -{ - Qt4ProFileNode *subProFileNode = new Qt4ProFileNode(m_project, path); - subProFileNode->update(); - return subProFileNode; -} - QStringList Qt4ProFileNode::uiDirPaths(ProFileReader *reader) const { QStringList candidates = reader->absolutePathValues(QLatin1String("UI_DIR"), @@ -1205,6 +1388,73 @@ QStringList Qt4ProFileNode::subDirsPaths(ProFileReader *reader) const return subProjectPaths; } +TargetInformation Qt4ProFileNode::targetInformation(ProFileReader *reader) const +{ + TargetInformation result; + if (!reader) + return result; + + const QString baseDir = buildDir(); + // qDebug() << "base build dir is:"<<baseDir; + + // Working Directory + if (reader->contains("DESTDIR")) { + //qDebug() << "reader contains destdir:" << reader->value("DESTDIR"); + result.workingDir = reader->value("DESTDIR"); + if (QDir::isRelativePath(result.workingDir)) { + result.workingDir = baseDir + QLatin1Char('/') + result.workingDir; + //qDebug() << "was relative and expanded to" << result.workingDir; + } + } else { + //qDebug() << "reader didn't contain DESTDIR, setting to " << baseDir; + result.workingDir = baseDir; + } + + result.target = reader->value("TARGET"); + if (result.target.isEmpty()) + result.target = QFileInfo(m_projectFilePath).baseName(); + +#if defined (Q_OS_MAC) + if (reader->values("CONFIG").contains("app_bundle")) { + result.workingDir += QLatin1Char('/') + + result.target + + QLatin1String(".app/Contents/MacOS"); + } +#endif + + result.workingDir = QDir::cleanPath(result.workingDir); + + QString wd = result.workingDir; + if (!reader->contains("DESTDIR") + && reader->values("CONFIG").contains("debug_and_release") + && reader->values("CONFIG").contains("debug_and_release_target")) { + // If we don't have a destdir and debug and release is set + // then the executable is in a debug/release folder + //qDebug() << "reader has debug_and_release_target"; + + // Hmm can we find out whether it's debug or release in a saner way? + // Theoretically it's in CONFIG + QString qmakeBuildConfig = "release"; + if (m_project->activeTarget()->activeBuildConfiguration()->qmakeBuildConfiguration() & QtVersion::DebugBuild) + qmakeBuildConfig = "debug"; + wd += QLatin1Char('/') + qmakeBuildConfig; + } + + result.executable = QDir::cleanPath(wd + QLatin1Char('/') + result.target); + //qDebug() << "##### updateTarget sets:" << result.workingDir << result.executable; + +#if defined (Q_OS_WIN) + result.executable += QLatin1String(".exe"); +#endif + result.valid = true; + return result; +} + +TargetInformation Qt4ProFileNode::targetInformation() +{ + return m_qt4targetInformation; +} + QString Qt4ProFileNode::buildDir() const { const QDir srcDirRoot = QFileInfo(m_project->rootProjectNode()->path()).absoluteDir(); diff --git a/src/plugins/qt4projectmanager/qt4nodes.h b/src/plugins/qt4projectmanager/qt4nodes.h index cd830960a44..ea9216a617d 100644 --- a/src/plugins/qt4projectmanager/qt4nodes.h +++ b/src/plugins/qt4projectmanager/qt4nodes.h @@ -36,9 +36,9 @@ #include <QtCore/QHash> #include <QtCore/QStringList> -#include <QtCore/QTimer> #include <QtCore/QDateTime> #include <QtCore/QMap> +#include <QtCore/QFutureWatcher> // defined in proitems.h QT_BEGIN_NAMESPACE @@ -127,7 +127,8 @@ class Qt4PriFileNode : public ProjectExplorer::ProjectNode public: Qt4PriFileNode(Qt4Project *project, Qt4ProFileNode* qt4ProFileNode, const QString &filePath); - void update(ProFile *includeFile, ProFileReader *reader); + void update(ProFile *includeFileExact, ProFileReader *readerExact, ProFile *includeFileCumlative, ProFileReader *readerCumalative); + // ProjectNode interface QList<ProjectAction> supportedActions() const; @@ -169,6 +170,8 @@ private: void save(const QStringList &lines); bool priFileWritable(const QString &path); bool saveModifiedEditors(); + QStringList baseVPaths(ProFileReader *reader, const QString &projectDir); + QStringList fullVPaths(const QStringList &baseVPaths, ProFileReader *reader, FileType type, const QString &qmakeVariable, const QString &projectDir); Qt4Project *m_project; Qt4ProFileNode *m_qt4ProFileNode; @@ -185,6 +188,38 @@ private: friend struct InternalNode; }; +struct TargetInformation +{ + bool valid; + QString workingDir; + QString target; + QString executable; + bool operator==(const TargetInformation &other) const + { + return workingDir == other.workingDir + && target == other.target + && executable == other.executable + && valid == valid; + } + bool operator!=(const TargetInformation &other) const + { + return !(*this == other); + } + + TargetInformation() + : valid(false) + {} + + TargetInformation(const TargetInformation &other) + : valid(other.valid), + workingDir(other.workingDir), + target(other.target), + executable(other.executable) + { + } + +}; + // Implements ProjectNode for qt4 pro files class Qt4ProFileNode : public Qt4PriFileNode { @@ -196,6 +231,8 @@ public: QObject *parent = 0); ~Qt4ProFileNode(); + bool isParent(Qt4ProFileNode *node); + bool hasBuildTargets() const; Qt4ProjectType projectType() const; @@ -211,33 +248,50 @@ public: static QString uiHeaderFile(const QString &uiDir, const QString &formFile); Qt4ProFileNode *findProFileFor(const QString &string); + TargetInformation targetInformation(const QString &fileName); + TargetInformation targetInformation(); -public slots: - void scheduleUpdate(); void update(); + void scheduleUpdate(); + +public slots: + void asyncUpdate(); + private slots: void buildStateChanged(ProjectExplorer::Project*); + void applyAsyncEvaluate(); private: + void setupReader(); + bool evaluate(); + void applyEvaluate(bool parseResult, bool async); + + void asyncEvaluate(QFutureInterface<bool> &fi); + typedef QHash<Qt4Variable, QStringList> Qt4VariablesHash; void createUiCodeModelSupport(); QStringList updateUiFiles(); - Qt4ProFileNode *createSubProFileNode(const QString &path); QStringList uiDirPaths(ProFileReader *reader) const; QStringList mocDirPaths(ProFileReader *reader) const; QStringList includePaths(ProFileReader *reader) const; QStringList subDirsPaths(ProFileReader *reader) const; + TargetInformation targetInformation(ProFileReader *reader) const; void invalidate(); Qt4ProjectType m_projectType; Qt4VariablesHash m_varValues; - QTimer m_updateTimer; QMap<QString, QDateTime> m_uitimestamps; + TargetInformation m_qt4targetInformation; friend class Qt4NodeHierarchy; + + // Async stuff + QFutureWatcher<bool> m_parseFutureWatcher; + ProFileReader *m_readerExact; + ProFileReader *m_readerCumulative; }; class Qt4NodesWatcher : public ProjectExplorer::NodesWatcher diff --git a/src/plugins/qt4projectmanager/qt4project.cpp b/src/plugins/qt4projectmanager/qt4project.cpp index 4e4292b0147..68b7dc9b371 100644 --- a/src/plugins/qt4projectmanager/qt4project.cpp +++ b/src/plugins/qt4projectmanager/qt4project.cpp @@ -44,6 +44,7 @@ #include <coreplugin/icore.h> #include <coreplugin/messagemanager.h> #include <coreplugin/coreconstants.h> +#include <coreplugin/progressmanager/progressmanager.h> #include <extensionsystem/pluginmanager.h> #include <projectexplorer/customexecutablerunconfiguration.h> #include <projectexplorer/nodesvisitor.h> @@ -232,21 +233,16 @@ Qt4Project::Qt4Project(Qt4Manager *manager, const QString& fileName) : m_fileInfo(new Qt4ProjectFile(this, fileName, this)), m_isApplication(true), m_projectFiles(new Qt4ProjectFiles), - m_proFileOption(0) + m_proFileOption(0), + m_asyncUpdateFutureInterface(0), + m_pendingEvaluateFuturesCount(0), + m_asyncUpdateState(NoState), + m_cancelEvaluate(false) { - m_updateCodeModelTimer.setSingleShot(true); - m_updateCodeModelTimer.setInterval(20); - connect(&m_updateCodeModelTimer, SIGNAL(timeout()), this, SLOT(updateCodeModel())); + m_asyncUpdateTimer.setSingleShot(true); + m_asyncUpdateTimer.setInterval(3000); + connect(&m_asyncUpdateTimer, SIGNAL(timeout()), this, SLOT(asyncUpdate())); - m_rootProjectNode = new Qt4ProFileNode(this, m_fileInfo->fileName(), this); - m_rootProjectNode->registerWatcher(m_nodesWatcher); - - connect(this, SIGNAL(addedTarget(ProjectExplorer::Target*)), - this, SLOT(onAddedTarget(ProjectExplorer::Target*))); - - // Setup Qt versions supported (== possible targets). - connect(QtVersionManager::instance(), SIGNAL(qtVersionsChanged(QList<int>)), - this, SLOT(qtVersionsChanged())); setSupportedTargetIds(QtVersionManager::instance()->supportedTargetIds()); } @@ -295,31 +291,30 @@ bool Qt4Project::fromMap(const QVariantMap &map) Q_ASSERT(activeTarget()); Q_ASSERT(activeTarget()->activeBuildConfiguration()); + m_manager->registerProject(this); + + m_rootProjectNode = new Qt4ProFileNode(this, m_fileInfo->fileName(), this); + m_rootProjectNode->registerWatcher(m_nodesWatcher); + update(); updateFileList(); // This might be incorrect, need a full update - scheduleUpdateCodeModel(rootProjectNode()); + updateCodeModel(); - // Now connect - connect(m_nodesWatcher, SIGNAL(foldersAdded()), this, SLOT(updateFileList())); - connect(m_nodesWatcher, SIGNAL(foldersRemoved()), this, SLOT(updateFileList())); - connect(m_nodesWatcher, SIGNAL(filesAdded()), this, SLOT(updateFileList())); - connect(m_nodesWatcher, SIGNAL(filesRemoved()), this, SLOT(updateFileList())); - connect(m_nodesWatcher, SIGNAL(proFileUpdated(Qt4ProjectManager::Internal::Qt4ProFileNode *)), - this, SLOT(scheduleUpdateCodeModel(Qt4ProjectManager::Internal::Qt4ProFileNode *))); + checkForNewApplicationProjects(); + checkForDeletedApplicationProjects(); - connect(m_nodesWatcher, SIGNAL(foldersAboutToBeAdded(FolderNode *, const QList<FolderNode*> &)), - this, SLOT(foldersAboutToBeAdded(FolderNode *, const QList<FolderNode*> &))); - connect(m_nodesWatcher, SIGNAL(foldersAdded()), this, SLOT(checkForNewApplicationProjects())); + foreach (Target *t, targets()) + onAddedTarget(t); - connect(m_nodesWatcher, SIGNAL(foldersRemoved()), this, SLOT(checkForDeletedApplicationProjects())); + setSupportedTargetIds(QtVersionManager::instance()->supportedTargetIds()); - connect(m_nodesWatcher, SIGNAL(projectTypeChanged(Qt4ProjectManager::Internal::Qt4ProFileNode *, - const Qt4ProjectManager::Internal::Qt4ProjectType, - const Qt4ProjectManager::Internal::Qt4ProjectType)), - this, SLOT(projectTypeChanged(Qt4ProjectManager::Internal::Qt4ProFileNode *, - const Qt4ProjectManager::Internal::Qt4ProjectType, - const Qt4ProjectManager::Internal::Qt4ProjectType))); + // Setup Qt versions supported (== possible targets). + connect(this, SIGNAL(addedTarget(ProjectExplorer::Target*)), + this, SLOT(onAddedTarget(ProjectExplorer::Target*))); + + connect(QtVersionManager::instance(), SIGNAL(qtVersionsChanged(QList<int>)), + this, SLOT(qtVersionsChanged())); connect(m_nodesWatcher, SIGNAL(proFileUpdated(Qt4ProjectManager::Internal::Qt4ProFileNode *)), this, SIGNAL(proFileUpdated(Qt4ProjectManager::Internal::Qt4ProFileNode *))); @@ -327,22 +322,6 @@ bool Qt4Project::fromMap(const QVariantMap &map) connect(this, SIGNAL(activeTargetChanged(ProjectExplorer::Target*)), this, SLOT(activeTargetWasChanged())); - // Add RunConfigurations to targets: - // If we have no application targets then add a empty CustomExecutableRC as - // it will ask the user for an executable to run. - QStringList pathes = applicationProFilePathes(); - foreach (Target *t, targets()) { - Qt4Target * qt4target = static_cast<Qt4Target*>(t); - if (t->runConfigurations().isEmpty()) { - if (pathes.isEmpty()) { - t->addRunConfiguration(new ProjectExplorer::CustomExecutableRunConfiguration(t)); - } else { - foreach (const QString &path, pathes) - qt4target->addRunConfigurationForPath(path); - } - } - } - return true; } @@ -377,28 +356,46 @@ namespace { }; } -void Qt4Project::scheduleUpdateCodeModel(Qt4ProjectManager::Internal::Qt4ProFileNode *pro) -{ - m_updateCodeModelTimer.start(); - m_proFilesForCodeModelUpdate.append(pro); -} - -void Qt4Project::changeTargetInformation() -{ - Qt4Target *t(qobject_cast<Qt4Target *>(sender())); - if (t && t == activeTarget()) - emit targetInformationChanged(); -} - void Qt4Project::onAddedTarget(ProjectExplorer::Target *t) { Q_ASSERT(t); - connect(t, SIGNAL(targetInformationChanged()), - this, SLOT(changeTargetInformation())); Qt4Target *qt4target = qobject_cast<Qt4Target *>(t); Q_ASSERT(qt4target); connect(qt4target, SIGNAL(buildDirectoryInitialized()), this, SIGNAL(buildDirectoryInitialized())); + connect(qt4target, SIGNAL(proFileEvaluateNeeded(Qt4ProjectManager::Internal::Qt4Target*)), + this, SLOT(proFileEvaluateNeeded(Qt4ProjectManager::Internal::Qt4Target*))); +} + +void Qt4Project::proFileEvaluateNeeded(Qt4ProjectManager::Internal::Qt4Target *target) +{ + if (activeTarget() == target) + scheduleAsyncUpdate(); +} + +/// equalFileList compares two file lists ignoring +/// <configuration> without generating temporary lists + +bool Qt4Project::equalFileList(const QStringList &a, const QStringList &b) +{ + if (abs(a.length() - b.length()) > 1) + return false; + QStringList::const_iterator ait = a.constBegin(); + QStringList::const_iterator bit = b.constBegin(); + QStringList::const_iterator aend = a.constEnd(); + QStringList::const_iterator bend = b.constEnd(); + + while (ait != aend && bit != bend) { + if (*ait == QLatin1String("<configuration>")) + ++ait; + else if (*bit == QLatin1String("<configuration>")) + ++bit; + else if (*ait == *bit) + ++ait, ++bit; + else + return false; + } + return (ait == aend && bit == bend); } void Qt4Project::updateCodeModel() @@ -406,6 +403,8 @@ void Qt4Project::updateCodeModel() if (debug) qDebug()<<"Qt4Project::updateCodeModel()"; + // TODO cancel still running indexing + if (!activeTarget() || !activeTarget()->activeBuildConfiguration()) return; @@ -424,64 +423,35 @@ void Qt4Project::updateCodeModel() QByteArray predefinedMacros; ToolChain *tc = activeBC->toolChain(); - QList<HeaderPath> allHeaderPaths; if (tc) { predefinedMacros = tc->predefinedMacros(); - allHeaderPaths = tc->systemHeaderPaths(); //qDebug()<<"Predefined Macros"; //qDebug()<<tc->predefinedMacros(); //qDebug()<<""; //qDebug()<<"System Header Paths"; //foreach(const HeaderPath &hp, tc->systemHeaderPaths()) // qDebug()<<hp.path(); - } - foreach (const HeaderPath &headerPath, allHeaderPaths) { - if (headerPath.kind() == HeaderPath::FrameworkHeaderPath) - predefinedFrameworkPaths.append(headerPath.path()); - else - predefinedIncludePaths.append(headerPath.path()); - } - - const QHash<QString, QString> versionInfo = activeBC->qtVersion()->versionInfo(); - const QString newQtIncludePath = versionInfo.value(QLatin1String("QT_INSTALL_HEADERS")); - predefinedIncludePaths.append(newQtIncludePath); - QDir dir(newQtIncludePath); - foreach (QFileInfo info, dir.entryInfoList(QDir::Dirs)) { - const QString path = info.fileName(); - - if (path == QLatin1String("Qt")) - continue; // skip $QT_INSTALL_HEADERS/Qt. There's no need to include it. - else if (path.startsWith(QLatin1String("Qt")) || path == QLatin1String("phonon")) - predefinedIncludePaths.append(info.absoluteFilePath()); + foreach (const HeaderPath &headerPath, tc->systemHeaderPaths()) { + if (headerPath.kind() == HeaderPath::FrameworkHeaderPath) + predefinedFrameworkPaths.append(headerPath.path()); + else + predefinedIncludePaths.append(headerPath.path()); + } } FindQt4ProFiles findQt4ProFiles; QList<Qt4ProFileNode *> proFiles = findQt4ProFiles(rootProjectNode()); - QByteArray definedMacros = predefinedMacros; - QStringList allIncludePaths = predefinedIncludePaths; + QByteArray allDefinedMacros = predefinedMacros; + QStringList allIncludePaths; QStringList allFrameworkPaths = predefinedFrameworkPaths; QStringList allPrecompileHeaders; -#ifdef Q_OS_MAC - const QString newQtLibsPath = versionInfo.value(QLatin1String("QT_INSTALL_LIBS")); - allFrameworkPaths.append(newQtLibsPath); - // put QtXXX.framework/Headers directories in include path since that qmake's behavior - QDir frameworkDir(newQtLibsPath); - foreach (QFileInfo info, frameworkDir.entryInfoList(QDir::Dirs)) { - if (! info.fileName().startsWith(QLatin1String("Qt"))) - continue; - allIncludePaths.append(info.absoluteFilePath()+"/Headers"); - } -#endif - - // Collect per .pro file information m_codeModelInfo.clear(); foreach (Qt4ProFileNode *pro, proFiles) { Internal::CodeModelInfo info; info.defines = predefinedMacros; - info.includes = predefinedIncludePaths; info.frameworkPaths = predefinedFrameworkPaths; info.precompiledHeader = pro->variableValue(PrecompiledHeaderVar); @@ -489,22 +459,23 @@ void Qt4Project::updateCodeModel() allPrecompileHeaders.append(info.precompiledHeader); // Add custom defines + foreach (const QString &def, pro->variableValue(DefinesVar)) { - definedMacros += "#define "; + allDefinedMacros += "#define "; info.defines += "#define "; const int index = def.indexOf(QLatin1Char('=')); if (index == -1) { - definedMacros += def.toLatin1(); - definedMacros += " 1\n"; + allDefinedMacros += def.toLatin1(); + allDefinedMacros += " 1\n"; info.defines += def.toLatin1(); info.defines += " 1\n"; } else { const QString name = def.left(index); const QString value = def.mid(index + 1); - definedMacros += name.toLatin1(); - definedMacros += ' '; - definedMacros += value.toLocal8Bit(); - definedMacros += '\n'; + allDefinedMacros += name.toLatin1(); + allDefinedMacros += ' '; + allDefinedMacros += value.toLocal8Bit(); + allDefinedMacros += '\n'; info.defines += name.toLatin1(); info.defines += ' '; info.defines += value.toLocal8Bit(); @@ -520,10 +491,7 @@ void Qt4Project::updateCodeModel() info.includes.append(includePath); } -#if 0 - // Disable for now, we need better .pro parsing first - // Also the information gathered here isn't used - // by the codemodel yet +#if 0 // Experimental PKGCONFIG support { // Pkg Config support QStringList pkgConfig = pro->variableValue(PkgConfigVar); if (!pkgConfig.isEmpty()) { @@ -541,8 +509,14 @@ void Qt4Project::updateCodeModel() // Add mkspec directory info.includes.append(activeBC->qtVersion()->mkspecPath()); + info.includes.append(predefinedIncludePaths); - info.frameworkPaths = allFrameworkPaths; +// qDebug()<<"Dumping code model information"; +// qDebug()<<"for .pro file"<< pro->path(); +// qDebug()<<info.defines; +// qDebug()<<info.includes; +// qDebug()<<info.frameworkPaths; +// qDebug()<<"\n"; #if 0 //Disable for now, we need better .pro file parsing first, and code model @@ -564,15 +538,7 @@ void Qt4Project::updateCodeModel() // Add mkspec directory allIncludePaths.append(activeBC->qtVersion()->mkspecPath()); - // Dump things out - // This is debugging output... -// qDebug()<<"CodeModel stuff:"; -// QMap<QString, CodeModelInfo>::const_iterator it, end; -// end = m_codeModelInfo.constEnd(); -// for(it = m_codeModelInfo.constBegin(); it != end; ++it) { -// qDebug()<<"File: "<<it.key()<<"\nIncludes:"<<it.value().includes<<"\nDefines"<<it.value().defines<<"\n"; -// } -// qDebug()<<"----------------------------"; + allIncludePaths.append(predefinedIncludePaths); QStringList files; files += m_projectFiles->files[HeaderType]; @@ -584,37 +550,34 @@ void Qt4Project::updateCodeModel() //qDebug()<<"Using precompiled header"<<allPrecompileHeaders; - if (pinfo.defines == predefinedMacros + bool fileList = equalFileList(pinfo.sourceFiles, files); + + if (pinfo.defines == allDefinedMacros && pinfo.includePaths == allIncludePaths && pinfo.frameworkPaths == allFrameworkPaths - && pinfo.sourceFiles == files + && fileList && pinfo.precompiledHeaders == allPrecompileHeaders) { // Nothing to update... } else { - if (pinfo.defines != predefinedMacros || - pinfo.includePaths != allIncludePaths || - pinfo.frameworkPaths != allFrameworkPaths) { + pinfo.sourceFiles.clear(); + if (pinfo.defines != allDefinedMacros + || pinfo.includePaths != allIncludePaths + || pinfo.frameworkPaths != allFrameworkPaths + || pinfo.precompiledHeaders != allPrecompileHeaders) + { pinfo.sourceFiles.append(QLatin1String("<configuration>")); } - - pinfo.defines = predefinedMacros; - // pinfo.defines += definedMacros; // ### FIXME: me + //pinfo.defines = predefinedMacros; + pinfo.defines = allDefinedMacros; pinfo.includePaths = allIncludePaths; pinfo.frameworkPaths = allFrameworkPaths; - pinfo.sourceFiles = files; + pinfo.sourceFiles += files; pinfo.precompiledHeaders = allPrecompileHeaders; modelmanager->updateProjectInfo(pinfo); modelmanager->updateSourceFiles(pinfo.sourceFiles); } - - // TODO use this information - // These are the pro files that were actually changed - // if the list is empty we are at the initial stage - // TODO check that this also works if pro files get added - // and removed - m_proFilesForCodeModelUpdate.clear(); } void Qt4Project::qtVersionsChanged() @@ -654,8 +617,167 @@ QStringList Qt4Project::frameworkPaths(const QString &fileName) const // */ void Qt4Project::update() { + qDebug()<<"Doing sync update"; m_rootProjectNode->update(); - //updateCodeModel(); + qDebug()<<"State is now Base"; + m_asyncUpdateState = Base; +} + +void Qt4Project::scheduleAsyncUpdate(Qt4ProFileNode *node) +{ + qDebug()<<"schduleAsyncUpdate (node)"; + Q_ASSERT(m_asyncUpdateState != NoState); + + if (m_cancelEvaluate) { + qDebug()<<" Already canceling, nothing to do"; + // A cancel is in progress + // That implies that a full update is going to happen afterwards + // So we don't need to do anything + return; + } + + if (m_asyncUpdateState == AsyncFullUpdatePending) { + // Just postpone + qDebug()<<" full update pending, restarting timer"; + m_asyncUpdateTimer.start(); + } else if (m_asyncUpdateState == AsyncPartialUpdatePending + || m_asyncUpdateState == Base) { + qDebug()<<" adding node to async update list, setting state to AsyncPartialUpdatePending"; + // Add the node + m_asyncUpdateState = AsyncPartialUpdatePending; + + QList<Internal::Qt4ProFileNode *>::iterator it; + bool add = true; + qDebug()<<"scheduleAsyncUpdate();"<<m_partialEvaluate.size()<<"nodes"; + int count = 0; + it = m_partialEvaluate.begin(); + while (it != m_partialEvaluate.end()) { + if (*it == node) { + add = false; + break; + } else if (node->isParent(*it)) { // We already have the parent in the list, nothing to do + add = false; + break; + } else if ((*it)->isParent(node)) { // The node is the parent of a child already in the list + it = m_partialEvaluate.erase(it); + } else { + ++it; + } + } + + if (add) + m_partialEvaluate.append(node); + // and start the timer anew + m_asyncUpdateTimer.start(); + } else if (m_asyncUpdateState == AsyncUpdateInProgress) { + // A update is in progress + // And this slot only gets called if a file changed on disc + // So we'll play it safe and schedule a complete evaluate + // This might trigger if due to version control a few files + // change a partial update gets in progress and then another + // batch of changes come in, which triggers a full update + // even if that's not really needed + qDebug()<<" Async update in progress, scheduling new one afterwards"; + scheduleAsyncUpdate(); + } +} + +void Qt4Project::scheduleAsyncUpdate() +{ + qDebug()<<"scheduleAsyncUpdate"; + Q_ASSERT(m_asyncUpdateState != NoState); + if (m_cancelEvaluate) { // we are in progress of canceling + // and will start the evaluation after that + qDebug()<<" canceling is in progress, doing nothing"; + return; + } + if (m_asyncUpdateState == AsyncUpdateInProgress) { + qDebug()<<" update in progress, canceling and setting state to full update pending"; + m_cancelEvaluate = true; + m_asyncUpdateState = AsyncFullUpdatePending; + return; + } + + qDebug()<<" starting timer for full update, setting state to full update pending"; + m_partialEvaluate.clear(); + m_asyncUpdateState = AsyncFullUpdatePending; + m_asyncUpdateTimer.start(); +} + + +void Qt4Project::incrementPendingEvaluateFutures() +{ + ++m_pendingEvaluateFuturesCount; + qDebug()<<"incrementPendingEvaluateFutures to"<<m_pendingEvaluateFuturesCount; + + m_asyncUpdateFutureInterface->setProgressRange(m_asyncUpdateFutureInterface->progressMinimum(), + m_asyncUpdateFutureInterface->progressMaximum() + 1); +} + +void Qt4Project::decrementPendingEvaluateFutures() +{ + --m_pendingEvaluateFuturesCount; + + qDebug()<<"decrementPendingEvaluateFutures to"<<m_pendingEvaluateFuturesCount; + + m_asyncUpdateFutureInterface->setProgressValue(m_asyncUpdateFutureInterface->progressValue() + 1); + if (m_pendingEvaluateFuturesCount == 0) { + qDebug()<<" WOHOO, no pending futures, cleaning up"; + // We are done! + qDebug()<<" reporting finished"; + m_asyncUpdateFutureInterface->reportFinished(); + delete m_asyncUpdateFutureInterface; + m_asyncUpdateFutureInterface = 0; + m_cancelEvaluate = false; + + // After beeing done, we need to call: + updateFileList(); + updateCodeModel(); + checkForNewApplicationProjects(); + checkForDeletedApplicationProjects(); + + // TODO clear the profile cache ? + if (m_asyncUpdateState == AsyncFullUpdatePending || m_asyncUpdateState == AsyncPartialUpdatePending) { + qDebug()<<" Oh update is pending start the timer"; + m_asyncUpdateTimer.start(); + } else { + qDebug()<<" Setting state to Base"; + m_asyncUpdateState = Base; + } + } +} + +bool Qt4Project::wasEvaluateCanceled() +{ + return m_cancelEvaluate; +} + +void Qt4Project::asyncUpdate() +{ + qDebug()<<"async update, timer expired, doing now"; + Q_ASSERT(!m_asyncUpdateFutureInterface); + m_asyncUpdateFutureInterface = new QFutureInterface<void>(); + + Core::ProgressManager *progressManager = Core::ICore::instance()->progressManager(); + + progressManager->addTask(m_asyncUpdateFutureInterface->future(), tr("Evaluate"), Constants::PROFILE_EVALUATE); + qDebug()<<" adding task"; + + m_asyncUpdateFutureInterface->setProgressRange(0, 0); + m_asyncUpdateFutureInterface->reportStarted(); + + if (m_asyncUpdateState == AsyncFullUpdatePending) { + qDebug()<<" full update, starting with root node"; + m_rootProjectNode->asyncUpdate(); + } else { + qDebug()<<" partial update,"<<m_partialEvaluate.size()<<"nodes to update"; + foreach(Qt4ProFileNode *node, m_partialEvaluate) + node->asyncUpdate(); + } + + m_partialEvaluate.clear(); + qDebug()<<" Setting state to AsyncUpdateInProgress"; + m_asyncUpdateState = AsyncUpdateInProgress; } /*! @@ -666,11 +788,6 @@ bool Qt4Project::isApplication() const return m_isApplication; } -ProjectExplorer::ProjectExplorerPlugin *Qt4Project::projectExplorer() const -{ - return m_manager->projectExplorer(); -} - ProjectExplorer::IProjectManager *Qt4Project::projectManager() const { return m_manager; @@ -773,6 +890,7 @@ ProFileReader *Qt4Project::createProFileReader(Qt4ProFileNode *qt4ProFileNode) m_proFileOption->properties = version->versionInfo(); } + ProFileCacheManager::instance()->incRefCount(); m_proFileOption->cache = ProFileCacheManager::instance()->cache(); } ++m_proFileOptionRefCnt; @@ -797,6 +915,7 @@ void Qt4Project::destroyProFileReader(ProFileReader *reader) delete m_proFileOption; m_proFileOption = 0; + ProFileCacheManager::instance()->decRefCount(); } } @@ -830,23 +949,12 @@ void Qt4Project::collectApplicationProFiles(QList<Qt4ProFileNode *> &list, Qt4Pr } } -void Qt4Project::foldersAboutToBeAdded(FolderNode *, const QList<FolderNode*> &nodes) -{ - QList<Qt4ProFileNode *> list; - foreach (FolderNode *node, nodes) { - Qt4ProFileNode *qt4ProFileNode = qobject_cast<Qt4ProFileNode *>(node); - if (qt4ProFileNode) - collectApplicationProFiles(list, qt4ProFileNode); - } - m_applicationProFileChange = list; -} - void Qt4Project::checkForNewApplicationProjects() { // Check all new project nodes // against all runConfigurations in all targets. - foreach (Qt4ProFileNode *qt4proFile, m_applicationProFileChange) { + foreach (Qt4ProFileNode *qt4proFile, applicationProFiles()) { foreach (Target *target, targets()) { Qt4Target *qt4Target = static_cast<Qt4Target *>(target); bool found = false; @@ -879,7 +987,6 @@ void Qt4Project::checkForDeletedApplicationProjects() if (Qt4RunConfiguration *qt4rc = qobject_cast<Qt4RunConfiguration *>(rc)) { if (!paths.contains(qt4rc->proFilePath())) { removeList.append(qt4rc); - // qDebug()<<"Removing runConfiguration for "<<qt4rc->proFilePath(); } } } @@ -922,31 +1029,12 @@ QStringList Qt4Project::applicationProFilePathes(const QString &prepend) const return proFiles; } -void Qt4Project::projectTypeChanged(Qt4ProFileNode *node, const Qt4ProjectType oldType, const Qt4ProjectType newType) -{ - if (oldType == Internal::ApplicationTemplate - || oldType == Internal::ScriptTemplate) { - // check whether we need to delete a Run Configuration - checkForDeletedApplicationProjects(); - } - - if (newType == Internal::ApplicationTemplate - || newType == Internal::ScriptTemplate) { - // add a new Run Configuration - m_applicationProFileChange.clear(); - m_applicationProFileChange.append(node); - checkForNewApplicationProjects(); - } -} - void Qt4Project::activeTargetWasChanged() { - emit targetInformationChanged(); - if (!activeTarget()) return; - update(); + scheduleAsyncUpdate(); } bool Qt4Project::hasSubNode(Qt4PriFileNode *root, const QString &path) diff --git a/src/plugins/qt4projectmanager/qt4project.h b/src/plugins/qt4projectmanager/qt4project.h index d3d2d5bb40b..f4d9d48cea4 100644 --- a/src/plugins/qt4projectmanager/qt4project.h +++ b/src/plugins/qt4projectmanager/qt4project.h @@ -51,6 +51,7 @@ #include <QtCore/QMap> #include <QtGui/QDirModel> #include <QtCore/QFutureInterface> +#include <QtCore/QTimer> QT_BEGIN_NAMESPACE struct ProFileOption; @@ -67,6 +68,7 @@ namespace Internal { class GCCPreprocessor; struct Qt4ProjectFiles; class Qt4ProjectConfigWidget; + class Qt4Target; class CodeModelInfo { @@ -152,47 +154,54 @@ public: virtual QStringList includePaths(const QString &fileName) const; virtual QStringList frameworkPaths(const QString &fileName) const; + /// \internal Internal::ProFileReader *createProFileReader(Internal::Qt4ProFileNode *qt4ProFileNode); + /// \internal void destroyProFileReader(Internal::ProFileReader *reader); + /// \internal + void scheduleAsyncUpdate(Qt4ProjectManager::Internal::Qt4ProFileNode *node); + /// \internal + void incrementPendingEvaluateFutures(); + /// \internal + void decrementPendingEvaluateFutures(); + /// \internal + bool wasEvaluateCanceled(); + signals: - /// convenience signal, emitted if either the active buildconfiguration emits - /// targetInformationChanged() or if the active build configuration changes - /// (which can happen by the active target changing, too). - void targetInformationChanged(); + /// emitted after parse void proFileUpdated(Qt4ProjectManager::Internal::Qt4ProFileNode *node); void buildDirectoryInitialized(); public slots: void proFileParseError(const QString &errorMessage); void update(); - void changeTargetInformation(); + +protected: + virtual bool fromMap(const QVariantMap &map); private slots: - void updateCodeModel(); - void scheduleUpdateCodeModel(Qt4ProjectManager::Internal::Qt4ProFileNode *); + void proFileEvaluateNeeded(Qt4ProjectManager::Internal::Qt4Target *target); + + void asyncUpdate(); + void qtVersionsChanged(); - void updateFileList(); void onAddedTarget(ProjectExplorer::Target *t); + void activeTargetWasChanged(); + +private: + void scheduleAsyncUpdate(); - void foldersAboutToBeAdded(FolderNode *, const QList<FolderNode*> &); void checkForNewApplicationProjects(); void checkForDeletedApplicationProjects(); - void projectTypeChanged(Qt4ProjectManager::Internal::Qt4ProFileNode *node, - const Qt4ProjectManager::Internal::Qt4ProjectType oldType, - const Qt4ProjectManager::Internal::Qt4ProjectType newType); - void activeTargetWasChanged(); - -protected: - virtual bool fromMap(const QVariantMap &map); + void updateCodeModel(); + void updateFileList(); -private: static void collectApplicationProFiles(QList<Internal::Qt4ProFileNode *> &list, Internal::Qt4ProFileNode *node); static void findProFile(const QString& fileName, Internal::Qt4ProFileNode *root, QList<Internal::Qt4ProFileNode *> &list); static bool hasSubNode(Internal::Qt4PriFileNode *root, const QString &path); - QList<Internal::Qt4ProFileNode *> m_applicationProFileChange; - ProjectExplorer::ProjectExplorerPlugin *projectExplorer() const; + static bool equalFileList(const QStringList &a, const QStringList &b); void addDefaultBuild(); @@ -213,17 +222,22 @@ private: // cached lists of all of files Internal::Qt4ProjectFiles *m_projectFiles; - QTimer m_updateCodeModelTimer; - QList<Qt4ProjectManager::Internal::Qt4ProFileNode *> m_proFilesForCodeModelUpdate; + // cached data during project rescan + ProFileOption *m_proFileOption; + int m_proFileOptionRefCnt; + + QTimer m_asyncUpdateTimer; + QFutureInterface<void> *m_asyncUpdateFutureInterface; + int m_pendingEvaluateFuturesCount; + enum AsyncUpdateState { NoState, Base, AsyncFullUpdatePending, AsyncPartialUpdatePending, AsyncUpdateInProgress }; + AsyncUpdateState m_asyncUpdateState; + bool m_cancelEvaluate; + QList<Internal::Qt4ProFileNode *> m_partialEvaluate; QMap<QString, Internal::CodeModelInfo> m_codeModelInfo; friend class Qt4ProjectFile; friend class Internal::Qt4ProjectConfigWidget; - - // cached data during project rescan - ProFileOption *m_proFileOption; - int m_proFileOptionRefCnt; }; } // namespace Qt4ProjectManager diff --git a/src/plugins/qt4projectmanager/qt4projectconfigwidget.cpp b/src/plugins/qt4projectmanager/qt4projectconfigwidget.cpp index 0195ea63e5c..86214075477 100644 --- a/src/plugins/qt4projectmanager/qt4projectconfigwidget.cpp +++ b/src/plugins/qt4projectmanager/qt4projectconfigwidget.cpp @@ -161,8 +161,6 @@ void Qt4ProjectConfigWidget::init(ProjectExplorer::BuildConfiguration *bc) qDebug() << "Qt4ProjectConfigWidget::init() for"<<bc->displayName(); if (m_buildConfiguration) { - disconnect(m_buildConfiguration, SIGNAL(buildDirectoryChanged()), - this, SLOT(buildDirectoryChanged())); disconnect(m_buildConfiguration, SIGNAL(qtVersionChanged()), this, SLOT(qtVersionChanged())); disconnect(m_buildConfiguration, SIGNAL(qmakeBuildConfigurationChanged()), @@ -185,7 +183,7 @@ void Qt4ProjectConfigWidget::init(ProjectExplorer::BuildConfiguration *bc) m_ui->shadowBuildCheckBox->setChecked(shadowBuild); m_ui->shadowBuildDirEdit->setEnabled(shadowBuild); m_browseButton->setEnabled(shadowBuild); - m_ui->shadowBuildDirEdit->setPath(m_buildConfiguration->buildDirectory()); + m_ui->shadowBuildDirEdit->setPath(m_buildConfiguration->shadowBuildDirectory()); updateImportLabel(); updateToolChainCombo(); updateDetails(); diff --git a/src/plugins/qt4projectmanager/qt4projectmanager.cpp b/src/plugins/qt4projectmanager/qt4projectmanager.cpp index 48dcc2a74a3..751ff411be1 100644 --- a/src/plugins/qt4projectmanager/qt4projectmanager.cpp +++ b/src/plugins/qt4projectmanager/qt4projectmanager.cpp @@ -203,7 +203,6 @@ ProjectExplorer::Project* Qt4Manager::openProject(const QString &fileName) } Qt4Project *pro = new Qt4Project(this, canonicalFilePath); - registerProject(pro); return pro; } diff --git a/src/plugins/qt4projectmanager/qt4projectmanagerconstants.h b/src/plugins/qt4projectmanager/qt4projectmanagerconstants.h index 00709dbbe1c..6728889bdf3 100644 --- a/src/plugins/qt4projectmanager/qt4projectmanagerconstants.h +++ b/src/plugins/qt4projectmanager/qt4projectmanagerconstants.h @@ -85,6 +85,9 @@ const char * const QT_APP_WIZARD_CATEGORY = "C.QtApplicationProjects"; const char * const QT_APP_WIZARD_TR_SCOPE = "Qt4ProjectManager"; const char * const QT_APP_WIZARD_TR_CATEGORY = QT_TRANSLATE_NOOP("Qt4ProjectManager", "Qt Application Project"); +// Tasks +const char * const PROFILE_EVALUATE = "Qt4ProjectManager.ProFileEvaluate"; + } // namespace Constants } // namespace Qt4ProjectManager diff --git a/src/plugins/qt4projectmanager/qt4runconfiguration.cpp b/src/plugins/qt4projectmanager/qt4runconfiguration.cpp index 3ca4e5cccc6..78a7cace614 100644 --- a/src/plugins/qt4projectmanager/qt4runconfiguration.cpp +++ b/src/plugins/qt4projectmanager/qt4runconfiguration.cpp @@ -95,7 +95,6 @@ Qt4RunConfiguration::Qt4RunConfiguration(Qt4Target *parent, const QString &proFi m_proFilePath(proFilePath), m_runMode(Gui), m_userSetName(false), - m_cachedTargetInformationValid(false), m_isUsingDyldImageSuffix(false), m_userSetWokingDirectory(false), m_baseEnvironmentBase(Qt4RunConfiguration::BuildEnvironmentBase) @@ -109,7 +108,6 @@ Qt4RunConfiguration::Qt4RunConfiguration(Qt4Target *parent, Qt4RunConfiguration m_proFilePath(source->m_proFilePath), m_runMode(source->m_runMode), m_userSetName(source->m_userSetName), - m_cachedTargetInformationValid(false), m_isUsingDyldImageSuffix(source->m_isUsingDyldImageSuffix), m_userSetWokingDirectory(source->m_userSetWokingDirectory), m_userWorkingDirectory(source->m_userWorkingDirectory), @@ -156,15 +154,12 @@ bool Qt4RunConfiguration::isEnabled(ProjectExplorer::BuildConfiguration *configu void Qt4RunConfiguration::proFileUpdate(Qt4ProjectManager::Internal::Qt4ProFileNode *pro) { if (m_proFilePath == pro->path()) - invalidateCachedTargetInformation(); + emit effectiveTargetInformationChanged(); } void Qt4RunConfiguration::ctor() { setDefaultDisplayName(); - connect(qt4Target(), SIGNAL(targetInformationChanged()), - this, SLOT(invalidateCachedTargetInformation())); - connect(qt4Target(), SIGNAL(environmentChanged()), this, SIGNAL(baseEnvironmentChanged())); @@ -475,7 +470,6 @@ bool Qt4RunConfiguration::fromMap(const QVariantMap &map) m_userWorkingDirectory = map.value(QLatin1String(USER_WORKING_DIRECTORY_KEY)).toString(); if (!m_proFilePath.isEmpty()) { - m_cachedTargetInformationValid = false; if (!m_userSetName) setDefaultDisplayName(); } @@ -487,8 +481,11 @@ bool Qt4RunConfiguration::fromMap(const QVariantMap &map) QString Qt4RunConfiguration::executable() const { - const_cast<Qt4RunConfiguration *>(this)->updateTarget(); - return m_executable; + Qt4Project *pro = qt4Target()->qt4Project(); + TargetInformation ti = pro->rootProjectNode()->targetInformation(m_proFilePath); + if (!ti.valid) + return QString(); + return ti.executable; } LocalApplicationRunConfiguration::RunMode Qt4RunConfiguration::runMode() const @@ -514,8 +511,11 @@ QString Qt4RunConfiguration::workingDirectory() const return m_userWorkingDirectory; // else what the pro file reader tells us - const_cast<Qt4RunConfiguration *>(this)->updateTarget(); - return m_workingDir; + Qt4Project *pro = qt4Target()->qt4Project(); + TargetInformation ti = pro->rootProjectNode()->targetInformation(m_proFilePath); + if(!ti.valid) + return QString(); + return ti.workingDir; } QStringList Qt4RunConfiguration::commandLineArguments() const @@ -611,38 +611,6 @@ QString Qt4RunConfiguration::proFilePath() const return m_proFilePath; } -void Qt4RunConfiguration::updateTarget() -{ - if (m_cachedTargetInformationValid) - return; - Qt4TargetInformation info = qt4Target()->targetInformation(qt4Target()->activeBuildConfiguration(), - m_proFilePath); - if (info.error != Qt4TargetInformation::NoError) { - if (info.error == Qt4TargetInformation::ProParserError) { - Core::ICore::instance()->messageManager()->printToOutputPane( - tr("Could not parse %1. The Qt4 run configuration %2 can not be started.") - .arg(m_proFilePath).arg(displayName())); - } - m_workingDir.clear(); - m_executable.clear(); - m_cachedTargetInformationValid = true; - emit effectiveTargetInformationChanged(); - return; - } - m_workingDir = info.workingDir; - m_executable = info.executable; - - m_cachedTargetInformationValid = true; - - emit effectiveTargetInformationChanged(); -} - -void Qt4RunConfiguration::invalidateCachedTargetInformation() -{ - m_cachedTargetInformationValid = false; - emit effectiveTargetInformationChanged(); -} - QString Qt4RunConfiguration::dumperLibrary() const { QtVersion *version = qt4Target()->activeBuildConfiguration()->qtVersion(); diff --git a/src/plugins/qt4projectmanager/qt4runconfiguration.h b/src/plugins/qt4projectmanager/qt4runconfiguration.h index 3243a3f26b0..9f23e25298d 100644 --- a/src/plugins/qt4projectmanager/qt4runconfiguration.h +++ b/src/plugins/qt4projectmanager/qt4runconfiguration.h @@ -91,12 +91,7 @@ public: QVariantMap toMap() const; public slots: - // This function is called if: - // X the pro file changes - // X the active buildconfiguration changes - // X the qmake parameters change - // X the build directory changes - void invalidateCachedTargetInformation(); + void targetInformationChanged(); signals: void commandLineArgumentsChanged(const QString&); @@ -140,11 +135,8 @@ private: QString m_proFilePath; // Full path to the Application Pro File // Cached startup sub project information - QString m_executable; - QString m_workingDir; ProjectExplorer::LocalApplicationRunConfiguration::RunMode m_runMode; bool m_userSetName; - bool m_cachedTargetInformationValid; bool m_isUsingDyldImageSuffix; bool m_userSetWokingDirectory; QString m_userWorkingDirectory; diff --git a/src/plugins/qt4projectmanager/qt4target.cpp b/src/plugins/qt4projectmanager/qt4target.cpp index 9d4c088267a..1ce701fa9b0 100644 --- a/src/plugins/qt4projectmanager/qt4target.cpp +++ b/src/plugins/qt4projectmanager/qt4target.cpp @@ -202,8 +202,9 @@ Qt4Target::Qt4Target(Qt4Project *parent, const QString &id) : { connect(project(), SIGNAL(supportedTargetIdsChanged()), this, SLOT(updateQtVersion())); + connect(this, SIGNAL(activeBuildConfigurationChanged(ProjectExplorer::BuildConfiguration*)), - this, SIGNAL(targetInformationChanged())); + this, SLOT(emitProFileEvaluateNeeded())); connect(this, SIGNAL(activeBuildConfigurationChanged(ProjectExplorer::BuildConfiguration*)), this, SIGNAL(environmentChanged())); connect(this, SIGNAL(addedRunConfiguration(ProjectExplorer::RunConfiguration*)), @@ -231,89 +232,6 @@ Qt4Project *Qt4Target::qt4Project() const return static_cast<Qt4Project *>(project()); } -Qt4TargetInformation Qt4Target::targetInformation(Qt4BuildConfiguration *buildConfiguration, - const QString &proFilePath) -{ - Qt4TargetInformation info; - Qt4ProFileNode *proFileNode = qt4Project()->rootProjectNode()->findProFileFor(proFilePath); - if (!proFileNode) { - info.error = Qt4TargetInformation::InvalidProjectError; - return info; - } - ProFileReader *reader = qt4Project()->createProFileReader(proFileNode); - reader->setCumulative(false); - - // Find out what flags we pass on to qmake - QStringList addedUserConfigArguments; - QStringList removedUserConfigArguments; - buildConfiguration->getConfigCommandLineArguments(&addedUserConfigArguments, &removedUserConfigArguments); - reader->setConfigCommandLineArguments(addedUserConfigArguments, removedUserConfigArguments); - - if (!reader->readProFile(proFilePath)) { - qt4Project()->destroyProFileReader(reader); - info.error = Qt4TargetInformation::ProParserError; - return info; - } - - // Extract data - const QDir baseProjectDirectory = QFileInfo(project()->file()->fileName()).absoluteDir(); - const QString relSubDir = baseProjectDirectory.relativeFilePath(QFileInfo(proFilePath).path()); - const QDir baseBuildDirectory = buildConfiguration->buildDirectory(); - const QString baseDir = baseBuildDirectory.absoluteFilePath(relSubDir); - //qDebug()<<relSubDir<<baseDir; - - // Working Directory - if (reader->contains("DESTDIR")) { - //qDebug() << "reader contains destdir:" << reader->value("DESTDIR"); - info.workingDir = reader->value("DESTDIR"); - if (QDir::isRelativePath(info.workingDir)) { - info.workingDir = baseDir + QLatin1Char('/') + info.workingDir; - //qDebug() << "was relative and expanded to" << info.workingDir; - } - } else { - //qDebug() << "reader didn't contain DESTDIR, setting to " << baseDir; - info.workingDir = baseDir; - } - - info.target = reader->value("TARGET"); - if (info.target.isEmpty()) - info.target = QFileInfo(proFilePath).baseName(); - -#if defined (Q_OS_MAC) - if (reader->values("CONFIG").contains("app_bundle")) { - info.workingDir += QLatin1Char('/') - + info.target - + QLatin1String(".app/Contents/MacOS"); - } -#endif - - info.workingDir = QDir::cleanPath(info.workingDir); - - QString wd = info.workingDir; - if (!reader->contains("DESTDIR") - && reader->values("CONFIG").contains("debug_and_release") - && reader->values("CONFIG").contains("debug_and_release_target")) { - // If we don't have a destdir and debug and release is set - // then the executable is in a debug/release folder - //qDebug() << "reader has debug_and_release_target"; - QString qmakeBuildConfig = "release"; - if (buildConfiguration->qmakeBuildConfiguration() & QtVersion::DebugBuild) - qmakeBuildConfig = "debug"; - wd += QLatin1Char('/') + qmakeBuildConfig; - } - - info.executable = QDir::cleanPath(wd + QLatin1Char('/') + info.target); - //qDebug() << "##### updateTarget sets:" << info.workingDir << info.executable; - -#if defined (Q_OS_WIN) - info.executable += QLatin1String(".exe"); -#endif - - qt4Project()->destroyProFileReader(reader); - info.error = Qt4TargetInformation::NoError; - return info; -} - Qt4BuildConfiguration *Qt4Target::addQt4BuildConfiguration(QString displayName, QtVersion *qtversion, QtVersion::QmakeBuildConfigs qmakeBuildConfiguration, QStringList additionalArguments) @@ -429,8 +347,8 @@ void Qt4Target::onAddedBuildConfiguration(ProjectExplorer::BuildConfiguration *b Q_ASSERT(qt4bc); connect(qt4bc, SIGNAL(buildDirectoryInitialized()), this, SIGNAL(buildDirectoryInitialized())); - connect(qt4bc, SIGNAL(targetInformationChanged()), - this, SLOT(changeTargetInformation())); + connect(qt4bc, SIGNAL(proFileEvaluateNeeded(Qt4ProjectManager::Internal::Qt4BuildConfiguration *)), + this, SLOT(onProFileEvaluateNeeded(Qt4ProjectManager::Internal::Qt4BuildConfiguration *))); } void Qt4Target::slotUpdateDeviceInformation() @@ -441,11 +359,15 @@ void Qt4Target::slotUpdateDeviceInformation() } } -void Qt4Target::changeTargetInformation() +void Qt4Target::onProFileEvaluateNeeded(Qt4ProjectManager::Internal::Qt4BuildConfiguration *bc) { - Qt4BuildConfiguration * bc = qobject_cast<Qt4BuildConfiguration *>(sender()); if (bc && bc == activeBuildConfiguration()) - emit targetInformationChanged(); + emit proFileEvaluateNeeded(this); +} + +void Qt4Target::emitProFileEvaluateNeeded() +{ + emit proFileEvaluateNeeded(this); } void Qt4Target::updateToolTipAndIcon() diff --git a/src/plugins/qt4projectmanager/qt4target.h b/src/plugins/qt4projectmanager/qt4target.h index 724df410190..ebc105ca285 100644 --- a/src/plugins/qt4projectmanager/qt4target.h +++ b/src/plugins/qt4projectmanager/qt4target.h @@ -53,20 +53,6 @@ class ProFileReader; class Qt4ProFileNode; class Qt4TargetFactory; -struct Qt4TargetInformation -{ - enum ErrorCode { - NoError, - InvalidProjectError, - ProParserError - }; - - ErrorCode error; - QString workingDir; - QString target; - QString executable; -}; - class Qt4Target : public ProjectExplorer::Target { Q_OBJECT @@ -79,9 +65,6 @@ public: Qt4BuildConfiguration *activeBuildConfiguration() const; Qt4ProjectManager::Qt4Project *qt4Project() const; - Qt4TargetInformation targetInformation(Internal::Qt4BuildConfiguration *buildConfiguration, - const QString &proFilePath); - Internal::Qt4BuildConfiguration *addQt4BuildConfiguration(QString displayName, QtVersion *qtversion, QtVersion::QmakeBuildConfigs qmakeBuildConfiguration, @@ -94,11 +77,10 @@ public: ProjectExplorer::ToolChain::ToolChainType preferredToolChainType(const QList<ProjectExplorer::ToolChain::ToolChainType> &candidates) const; signals: - /// convenience signal, emitted if either the active buildconfiguration emits - /// targetInformationChanged() or if the active build configuration changes - void targetInformationChanged(); - void buildDirectoryInitialized(); + /// emitted if the build configuration changed in a way that + /// should trigger a reevaluation of all .pro files + void proFileEvaluateNeeded(Qt4ProjectManager::Internal::Qt4Target *); protected: bool fromMap(const QVariantMap &map); @@ -108,7 +90,8 @@ private slots: void onAddedRunConfiguration(ProjectExplorer::RunConfiguration *rc); void onAddedBuildConfiguration(ProjectExplorer::BuildConfiguration *bc); void slotUpdateDeviceInformation(); - void changeTargetInformation(); + void onProFileEvaluateNeeded(Qt4ProjectManager::Internal::Qt4BuildConfiguration *bc); + void emitProFileEvaluateNeeded(); void updateToolTipAndIcon(); private: diff --git a/src/plugins/qt4projectmanager/qtversionmanager.cpp b/src/plugins/qt4projectmanager/qtversionmanager.cpp index cf7035cdc52..0e096280225 100644 --- a/src/plugins/qt4projectmanager/qtversionmanager.cpp +++ b/src/plugins/qt4projectmanager/qtversionmanager.cpp @@ -1221,6 +1221,7 @@ void QtVersion::updateToolChainAndMkspec() const ProFileOption option; option.properties = versionInfo(); option.cache = ProFileCacheManager::instance()->cache(); + ProFileCacheManager::instance()->incRefCount(); ProFileReader *reader = new ProFileReader(&option); reader->setCumulative(false); reader->setParsePreAndPostFiles(false); @@ -1302,6 +1303,7 @@ void QtVersion::updateToolChainAndMkspec() const } delete reader; + ProFileCacheManager::instance()->decRefCount(); m_toolChainUpToDate = true; } -- GitLab