From 0cf9ffc03183f9d460618f928e945448d8ed4f02 Mon Sep 17 00:00:00 2001 From: dt <qtc-commiter@nokia.com> Date: Wed, 14 Jan 2009 17:13:17 +0100 Subject: [PATCH] Fixes: Updating the completion for ui files Details: That is we update all generated headers (which are new or modfied) in the C++ Engine. Big if, this only works if we find the correct path for the ui header files. Which is known to sometimes not work, I'll fix that next. --- .../qt4projectmanager/directorywatcher.cpp | 161 ------------------ .../qt4projectmanager/directorywatcher.h | 40 ----- src/plugins/qt4projectmanager/qt4nodes.cpp | 119 +++++++------ src/plugins/qt4projectmanager/qt4nodes.h | 9 +- 4 files changed, 74 insertions(+), 255 deletions(-) diff --git a/src/plugins/qt4projectmanager/directorywatcher.cpp b/src/plugins/qt4projectmanager/directorywatcher.cpp index d20444098e0..b054f1ff291 100644 --- a/src/plugins/qt4projectmanager/directorywatcher.cpp +++ b/src/plugins/qt4projectmanager/directorywatcher.cpp @@ -44,165 +44,6 @@ enum { debugWatcher = 0 }; namespace Qt4ProjectManager { namespace Internal { -int DirectoryWatcher::m_objectCount = 0; -QHash<QString,int> DirectoryWatcher::m_directoryCount; -QFileSystemWatcher *DirectoryWatcher::m_watcher = 0; - -/* - \class DirectoryWatcher - - A wrapper for QFileSystemWatcher that collects - consecutive changes to a registered directory and emits directoryChanged() and fileChanged(). - - Note that files added are only monitored if the parent directory is added, too. - - All instances of DirectoryWatcher share one QFileSystemWatcher object. - That's because every QFileSystemWatcher object consumes a file descriptor, - even if no files are watched. -*/ -DirectoryWatcher::DirectoryWatcher(QObject *parent) : - QObject(parent), - m_timer(0) -{ - if (!m_watcher) - m_watcher = new QFileSystemWatcher(); - ++m_objectCount; - connect(m_watcher, SIGNAL(directoryChanged(QString)), - this, SLOT(slotDirectoryChanged(QString))); -} - -DirectoryWatcher::~DirectoryWatcher() -{ - foreach (const QString &dir, m_directories) - removeDirectory(dir); - if (--m_objectCount == 0) { - delete m_watcher; - m_watcher = 0; - } -} - -QStringList DirectoryWatcher::directories() const -{ - if (debugWatcher) - qDebug() << Q_FUNC_INFO << m_directories; - return m_directories; -} - -void DirectoryWatcher::addDirectory(const QString &dir) -{ - if (debugWatcher) - qDebug() << Q_FUNC_INFO << dir; - if (m_directories.contains(dir)) - return; - m_directories += dir; - if (m_directoryCount[dir] == 0) - m_watcher->addPath(dir); - m_directoryCount[dir] += 1; -} - -void DirectoryWatcher::removeDirectory(const QString &dir) -{ - if (debugWatcher) - qDebug() << Q_FUNC_INFO << dir; - m_directories.removeOne(dir); - m_directoryCount[dir] -= 1; - if (m_directoryCount[dir] == 0) - m_watcher->removePath(dir); -} - -QStringList DirectoryWatcher::files() const -{ - if (debugWatcher) - qDebug() << Q_FUNC_INFO << m_files.keys(); - return m_files.keys(); -} - -void DirectoryWatcher::addFile(const QString &filePath) -{ - addFiles(QStringList() << filePath); -} - -void DirectoryWatcher::addFiles(const QStringList &filePaths) -{ - foreach (const QString filePath, filePaths) { - QFileInfo file(filePath); - m_files.insert(file.absoluteFilePath(),file.lastModified()); - } -} - -void DirectoryWatcher::removeFile(const QString &filePath) -{ - m_files.remove(filePath); -} - -void DirectoryWatcher::slotDirectoryChanged(const QString &path) -{ - if (debugWatcher) - qDebug() << Q_FUNC_INFO << path; - if (!m_directories.contains(path) - || m_pendingDirectories.contains(path)) - return; - - if (!m_timer) { - m_timer = new QTimer(this); - m_timer->setSingleShot(true); - m_timer->setInterval(500); // delay for 0.5 sec - connect(m_timer, SIGNAL(timeout()), this, SLOT(slotDelayedDirectoriesChanged())); - } - if (!m_timer->isActive()) - m_timer->start(); - m_pendingDirectories.push_back(path); -} - -void DirectoryWatcher::slotDelayedDirectoriesChanged() -{ - if (debugWatcher) - qDebug() << Q_FUNC_INFO << " emitting " << m_pendingDirectories; - const QStringList::const_iterator cend = m_pendingDirectories.constEnd(); - for (QStringList::const_iterator it = m_pendingDirectories.constBegin(); it != cend; ++it) { - const QString dir = *it; - if (!QFileInfo(dir).exists()) - removeDirectory(*it); - emit directoryChanged(*it); - updateFileList(*it); - } - m_pendingDirectories.clear(); -} - -void DirectoryWatcher::updateFileList(const QString &dir) -{ - const QStringList monitoredFiles = m_files.keys(); - QStringList removedFiles = monitoredFiles; - if (QFileInfo(dir).exists()) { - // Compare directory contents and emit signals - QFileInfoList entryInfoList - = QDir(dir).entryInfoList(QDir::Files|QDir::CaseSensitive); - // Loop over directory creating the new map of file->time, removing - // the existing entries from the old map - const QFileInfoList::const_iterator cend = entryInfoList.constEnd(); - for (QFileInfoList::const_iterator filIt = entryInfoList.constBegin(); - filIt != cend; ++filIt) { - const QString path = filIt->absoluteFilePath(); - FileModificationTimeMap::iterator mapIt = m_files.find(path); - if (mapIt != m_files.end()) { - const QDateTime lastModified = filIt->lastModified(); - if (lastModified > mapIt.value()) { - if (debugWatcher) - qDebug() << Q_FUNC_INFO << "emitting file changed" << path; - emit fileChanged(path); - m_files[path] = lastModified; - } - removedFiles.removeOne(path); - } - } - } - - if (!removedFiles.isEmpty()) { - foreach (const QString &file, removedFiles) - removeFile(file); - } -} - int FileWatcher::m_objectCount = 0; QHash<QString,int> FileWatcher::m_fileCount; QFileSystemWatcher *FileWatcher::m_watcher = 0; @@ -256,7 +97,5 @@ void FileWatcher::removeFile(const QString &file) m_watcher->removePath(file); } - - } // namespace Internal } // namespace Qt4ProjectManager diff --git a/src/plugins/qt4projectmanager/directorywatcher.h b/src/plugins/qt4projectmanager/directorywatcher.h index 57f015330a1..35ceaed91e1 100644 --- a/src/plugins/qt4projectmanager/directorywatcher.h +++ b/src/plugins/qt4projectmanager/directorywatcher.h @@ -47,46 +47,6 @@ QT_END_NAMESPACE namespace Qt4ProjectManager { namespace Internal { -class DirectoryWatcher : public QObject -{ - Q_DISABLE_COPY(DirectoryWatcher) - Q_OBJECT -public: - explicit DirectoryWatcher(QObject *parent = 0); - virtual ~DirectoryWatcher(); - - QStringList directories() const; - void addDirectory(const QString &dir); - void removeDirectory(const QString &dir); - - QStringList files() const; - void addFile(const QString &filePath); - void addFiles(const QStringList &filePaths); - void removeFile(const QString &filePath); - -signals: - void directoryChanged(const QString &path); - void fileChanged(const QString &path); - -private slots: - void slotDirectoryChanged(const QString &); - void slotDelayedDirectoriesChanged(); - -private: - void updateFileList(const QString &dir); - - static int m_objectCount; - static QHash<QString,int> m_directoryCount; - static QFileSystemWatcher *m_watcher; - - QTimer *m_timer; - QStringList m_directories; - QStringList m_pendingDirectories; - - typedef QHash<QString, QDateTime> FileModificationTimeMap; - FileModificationTimeMap m_files; -}; - class FileWatcher : public QObject { Q_DISABLE_COPY(FileWatcher) diff --git a/src/plugins/qt4projectmanager/qt4nodes.cpp b/src/plugins/qt4projectmanager/qt4nodes.cpp index 8f836f64982..b32a47ac512 100644 --- a/src/plugins/qt4projectmanager/qt4nodes.cpp +++ b/src/plugins/qt4projectmanager/qt4nodes.cpp @@ -49,6 +49,7 @@ #include <coreplugin/vcsmanager.h> #include <cpptools/cppmodelmanagerinterface.h> +#include <cplusplus/CppDocument.h> #include <utils/qtcassert.h> @@ -488,6 +489,9 @@ QStringList Qt4PriFileNode::varNames(FileType type) return vars; } +#include <projectexplorer/projectexplorer.h> +#include <projectexplorer/buildmanager.h> + /*! \class Qt4ProFileNode Implements abstract ProjectNode class @@ -498,8 +502,7 @@ Qt4ProFileNode::Qt4ProFileNode(Qt4Project *project, : Qt4PriFileNode(project, this, filePath), // own stuff m_projectType(InvalidProject), - m_isQBuildProject(false), - m_dirWatcher(new DirectoryWatcher(this)) + m_isQBuildProject(false) { if (parent) setParent(parent); @@ -507,14 +510,13 @@ Qt4ProFileNode::Qt4ProFileNode(Qt4Project *project, m_updateTimer.setInterval(100); m_updateTimer.setSingleShot(true); - connect(m_dirWatcher, SIGNAL(directoryChanged(const QString&)), - this, SLOT(updateGeneratedFiles())); - connect(m_dirWatcher, SIGNAL(fileChanged(const QString&)), - this, SLOT(fileChanged(const QString&))); connect(m_project, SIGNAL(activeBuildConfigurationChanged()), this, SLOT(update())); connect(&m_updateTimer, SIGNAL(timeout()), this, SLOT(update())); + + connect(ProjectExplorer::ProjectExplorerPlugin::instance()->buildManager(), SIGNAL(buildStateChanged(ProjectExplorer::Project*)), + this, SLOT(buildStateChanged(ProjectExplorer::Project*))); } Qt4ProFileNode::~Qt4ProFileNode() @@ -522,6 +524,12 @@ Qt4ProFileNode::~Qt4ProFileNode() } +void Qt4ProFileNode::buildStateChanged(ProjectExplorer::Project *project) +{ + if (project == m_project && !ProjectExplorer::ProjectExplorerPlugin::instance()->buildManager()->isBuilding(m_project)) + updateUiFiles(); +} + bool Qt4ProFileNode::hasTargets() const { return (projectType() == ApplicationTemplate) || (projectType() == LibraryTemplate); @@ -689,7 +697,7 @@ void Qt4ProFileNode::update() emit qt4Watcher->variablesChanged(this, m_varValues, newVarValues); } - updateGeneratedFiles(); + updateUiFiles(); foreach (NodesWatcher *watcher, watchers()) if (Qt4NodesWatcher *qt4Watcher = qobject_cast<Qt4NodesWatcher*>(watcher)) @@ -698,15 +706,6 @@ void Qt4ProFileNode::update() delete reader; } -void Qt4ProFileNode::fileChanged(const QString &filePath) -{ - CppTools::CppModelManagerInterface *modelManager = - ExtensionSystem::PluginManager::instance()->getObject<CppTools::CppModelManagerInterface>(); - - // TODO compress - modelManager->updateSourceFiles(QStringList() << filePath); -} - namespace { // find all ui files in project class FindUiFileNodesVisitor : public ProjectExplorer::NodesVisitor { @@ -726,53 +725,54 @@ namespace { }; } -/* - Adds ui_xxx.h files to tree and monitors them / the UI_DIR directory for changes - */ -void Qt4ProFileNode::updateGeneratedFiles() +// This function is triggered after a build, and updates the state ui files +// That is it adds files that didn't exist yet to the project tree, and calls +// updateSourceFiles() for files that changed +// It does so by storing a modification time for each ui file we know about. + +// TODO this function should also be called if the build configuration changes +// since the build directory could change, and thus the generated files that are present +// TODO check that it works +void Qt4ProFileNode::updateUiFiles() { + // Only those two project types can have ui files for us if (m_projectType != ApplicationTemplate && m_projectType != LibraryTemplate) return; + // Find all ui files FindUiFileNodesVisitor uiFilesVisitor; this->accept(&uiFilesVisitor); const QList<FileNode*> uiFiles = uiFilesVisitor.uiFileNodes; - // monitor uic dir (only if there are .ui files) + // Find the UiDir, there can only ever be one + QString uiDir; // We should default to the build directory + QStringList tmp = m_varValues[UiDirVar]; + if (tmp.size() != 0) + uiDir = tmp.first(); - QSet<QString> oldUiDirs = m_dirWatcher->directories().toSet(); - QSet<QString> newUiDirs = - (!uiFiles.isEmpty()) ? m_varValues[UiDirVar].toSet() : QSet<QString>(); - foreach (const QString &uiDir, oldUiDirs - newUiDirs) - m_dirWatcher->removeDirectory(uiDir); - foreach (const QString &uiDir, newUiDirs - oldUiDirs) - m_dirWatcher->addDirectory(uiDir); - - // update generated files - - // Already existing FileNodes + // Collect all existing generated files QList<FileNode*> existingFileNodes; foreach (FileNode *file, fileNodes()) { if (file->isGenerated()) existingFileNodes << file; } - // Convert uiFile to uiHeaderFilePath, find all headers that correspond - // and try to find them in uicDirs + // and try to find them in uiDir QStringList newFilePaths; - foreach (const QString &uicDir, m_varValues[UiDirVar]) { - foreach (FileNode *uiFile, uiFiles) { - const QString uiHeaderFilePath - = QString("%1/ui_%2.h").arg(uicDir, QFileInfo(uiFile->path()).baseName()); - if (QFileInfo(uiHeaderFilePath).exists()) - newFilePaths << uiHeaderFilePath; - } + foreach (FileNode *uiFile, uiFiles) { + const QString uiHeaderFilePath + = QString("%1/ui_%2.h").arg(uiDir, QFileInfo(uiFile->path()).baseName()); + if (QFileInfo(uiHeaderFilePath).exists()) + newFilePaths << uiHeaderFilePath; } + // Create a diff between those lists QList<FileNode*> toRemove; QList<FileNode*> toAdd; + // The list of files for which we call updateSourceFile + QStringList toUpdate; qSort(newFilePaths); qSort(existingFileNodes.begin(), existingFileNodes.end(), ProjectNode::sortNodesByPath); @@ -788,6 +788,13 @@ void Qt4ProFileNode::updateGeneratedFiles() toAdd << new FileNode(*newPathIter, ProjectExplorer::HeaderType, true); ++newPathIter; } else { // *existingNodeIter->path() == *newPathIter + QString fileName = (*existingNodeIter)->path(); + QMap<QString, QDateTime>::const_iterator it = m_uitimestamps.find(fileName); + QDateTime lastModified = QFileInfo(fileName).lastModified(); + if (it == m_uitimestamps.constEnd() || it.value() < lastModified) { + toUpdate << fileName; + m_uitimestamps[fileName] = lastModified; + } ++existingNodeIter; ++newPathIter; } @@ -801,16 +808,33 @@ void Qt4ProFileNode::updateGeneratedFiles() ++newPathIter; } + // Update project tree if (!toRemove.isEmpty()) { foreach (FileNode *file, toRemove) - m_dirWatcher->removeFile(file->path()); + m_uitimestamps.remove(file->path()); removeFileNodes(toRemove, this); } + + CppTools::CppModelManagerInterface *modelManager = + ExtensionSystem::PluginManager::instance()->getObject<CppTools::CppModelManagerInterface>(); + if (!toAdd.isEmpty()) { - foreach (FileNode *file, toAdd) - m_dirWatcher->addFile(file->path()); + foreach (FileNode *file, toAdd) { + m_uitimestamps.insert(file->path(), QFileInfo(file->path()).lastModified()); + toUpdate << file->path(); + + // Also adding files depending on that. + QString fileName = QFileInfo(file->path()).fileName(); + foreach (CPlusPlus::Document::Ptr doc, modelManager->snapshot()) { + if (doc->includedFiles().contains(fileName)) { + if (!toUpdate.contains(doc->fileName())) + toUpdate << doc->fileName(); + } + } + } addFileNodes(toAdd, this); } + modelManager->updateSourceFiles(toUpdate); } ProFileReader *Qt4PriFileNode::createProFileReader() const @@ -957,13 +981,6 @@ void Qt4ProFileNode::invalidate() clear(); - // remove monitored files/directories - foreach (const QString &file, m_dirWatcher->files()) - m_dirWatcher->removeFile(file); - foreach (const QString &dir, m_dirWatcher->directories()) - m_dirWatcher->removeDirectory(dir); - - // change project type Qt4ProjectType oldType = m_projectType; m_projectType = InvalidProject; diff --git a/src/plugins/qt4projectmanager/qt4nodes.h b/src/plugins/qt4projectmanager/qt4nodes.h index 9ea6b07c71c..5d428cc6720 100644 --- a/src/plugins/qt4projectmanager/qt4nodes.h +++ b/src/plugins/qt4projectmanager/qt4nodes.h @@ -35,10 +35,13 @@ #define QT4NODES_H #include <projectexplorer/projectnodes.h> +#include <projectexplorer/project.h> #include <QtCore/QHash> #include <QtCore/QStringList> #include <QtCore/QTimer> +#include <QtCore/QDateTime> +#include <QtCore/QMap> // defined in proitems.h QT_BEGIN_NAMESPACE @@ -184,8 +187,8 @@ public slots: void scheduleUpdate(); void update(); private slots: - void fileChanged(const QString &filePath); - void updateGeneratedFiles(); + void updateUiFiles(); + void buildStateChanged(ProjectExplorer::Project*); private: Qt4ProFileNode *createSubProFileNode(const QString &path); @@ -205,7 +208,7 @@ private: bool m_isQBuildProject; QTimer m_updateTimer; - DirectoryWatcher *m_dirWatcher; + QMap<QString, QDateTime> m_uitimestamps; friend class Qt4NodeHierarchy; }; -- GitLab