diff --git a/src/plugins/projectexplorer/projectnodes.cpp b/src/plugins/projectexplorer/projectnodes.cpp index c552b11235be08f9a78da1db3c525311b56a3130..d9cd9b11a1a7b96713a5096139bb2296aa7c34f7 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 cb7cb52715e4d3676d040989c439174daf3f7500..30c7ad70ea7dbf7b7415d7060d02cca2a3ec805d 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 0e8fda774fe7a6bc90167ca1fa8b12e5e5d28a97..b749bc3e569455525a0bf536e2123da1aa672c5d 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 9d02d33efb53ef0616c88ddbfa95ef20c73dc27c..68862439fcea5b25e934b234bd82f34199e5f38b 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 6c7ae254ab46dff3bcaea6ec15ba88ffc11c14ff..b2734459d97df78202324e9184bc6bb1a00d2ce1 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 c4cdaa6dab09a46c45b7bbb736193bdb6a15a8da..1420e039eac4bb444ec733b5ceccd75630748ee1 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 5fc034e3c1215281c5eb7557d49a33cd6cc43d57..f4a0d2c6605bd7c407651494c1d7748907054ba0 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 523cbe60caa555f4ac0fe5803d6387cd3e65184e..b132284fdc44fa62266b0ffc94f657b599f70ef6 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 8191c1b46b8c4bf49bfbb003fcc2a07a9b4c494b..decd95bcff4fd24b698d4aa0a74653ed9497ceb5 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 417280f4282f831138922a9d193d3b4d1ab9c909..4ca104c5edd474fd59fdf85c0389988b7e77e6bb 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 8886f48e87ec17e60ebf613caf92bb8e60a38c32..074b03105984cf254d6603bfbcb6094c38191f07 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 ddb802e214c40f64ef084a9957435d1a97a7e156..168517d292eff9aaedfc9123e89ea620931ea020 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 cd830960a44b8324a73fef41e74bf9e587984e89..ea9216a617d5804df1e0b916f2c09c5404ee14cc 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 4e4292b0147f1f8e4dd2d8a340861577dc5a5515..68b7dc9b3711d3b8d4029cbb97a64007e0a7bb24 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 d3d2d5bb40b4b3004db2bb01fb617c03506cb2a1..f4d9d48cea468a5d07871c09ba30184fa8399dcb 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 0195ea63e5cae00ace496c6ac8efbe2937192bad..8621407547791e8950f9871c43dbba7215d965ba 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 48dcc2a74a353cc94863decc40bd3eff0b836f87..751ff411be16696d628549d1f976741318e9e0c9 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 00709dbbe1c347728f7ed706316832bb16be6cb2..6728889bdf3746322970daba675a38d141620289 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 3ca4e5cccc627884bccb7e9d0aa547f8f14c1fe6..78a7cace614e887c808edbfe723af65c2eaadf58 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 3243a3f26b030508995c92197401baacd899fdf4..9f23e25298d3ff7471b9d7eec63760ee8623d1cd 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 9d4c088267ad64637a483cfdd2fd32ed6815943b..1ce701fa9b0d485a3ae2c59ca2fd1c29d10e5c07 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 724df410190ac52d18edd3f550268f77d56f5da2..ebc105ca285cacc978f6660cacce0efd3d3bcfb6 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 cf7035cdc52ae1e4d24a91066ef5c6d93339cebc..0e096280225c15d49ed2b4df468bfba335e48a84 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; }