Index: kdevplatform/project/CMakeLists.txt =================================================================== --- kdevplatform/project/CMakeLists.txt +++ kdevplatform/project/CMakeLists.txt @@ -15,6 +15,7 @@ abstractfilemanagerplugin.cpp filemanagerlistjob.cpp projectfiltermanager.cpp + projectwatcher.cpp interfaces/iprojectbuilder.cpp interfaces/iprojectfilemanager.cpp interfaces/ibuildsystemmanager.cpp Index: kdevplatform/project/abstractfilemanagerplugin.h =================================================================== --- kdevplatform/project/abstractfilemanagerplugin.h +++ kdevplatform/project/abstractfilemanagerplugin.h @@ -34,6 +34,8 @@ namespace KDevelop { class AbstractFileManagerPluginPrivate; +class ProjectController; +class AFMPBenchmark; /** * This class can be used as a common base for file managers. @@ -103,6 +105,11 @@ */ KDirWatch* projectWatcher( IProject* project ) const; + /** + * tell the plugin that the given @p project is going to be closed. + */ + void projectClosing( IProject* project ); + Q_SIGNALS: void reloadedFileItem(KDevelop::ProjectFileItem* file); void reloadedFolderItem(KDevelop::ProjectFolderItem* folder); @@ -118,6 +125,9 @@ private: const QScopedPointer d; friend class AbstractFileManagerPluginPrivate; +public: + friend class ProjectController; + friend class AFMPBenchmark; }; } Index: kdevplatform/project/abstractfilemanagerplugin.cpp =================================================================== --- kdevplatform/project/abstractfilemanagerplugin.cpp +++ kdevplatform/project/abstractfilemanagerplugin.cpp @@ -1,3 +1,4 @@ +#define TIME_IMPORT_JOB /*************************************************************************** * This file is part of KDevelop * * Copyright 2010-2012 Milian Wolff * @@ -41,6 +42,7 @@ #include #include "projectfiltermanager.h" +#include "projectwatcher.h" #include "debug.h" #define ifDebug(x) @@ -89,7 +91,7 @@ const KIO::UDSEntryList& entries); void deleted(const QString &path); - void created(const QString &path); + void dirty(const QString &path); void projectClosing(IProject* project); void jobFinished(KJob* job); @@ -103,7 +105,7 @@ void removeFolder(ProjectFolderItem* folder); - QHash m_watchers; + QHash m_watchers; QHash > m_projectJobs; QVector m_stoppedFolders; ProjectFilterManager m_filters; @@ -137,6 +139,7 @@ KIO::Job* AbstractFileManagerPluginPrivate::eventuallyReadFolder(ProjectFolderItem* item) { + ProjectWatcher* watcher = m_watchers.value( item->project(), nullptr ); FileManagerListJob* listJob = new FileManagerListJob( item ); m_projectJobs[ item->project() ] << listJob; qCDebug(FILEMANAGER) << "adding job" << listJob << item << item->path() << "for project" << item->project(); @@ -147,6 +150,9 @@ q->connect( listJob, &FileManagerListJob::entries, q, [&] (FileManagerListJob* job, ProjectFolderItem* baseItem, const KIO::UDSEntryList& entries) { addJobItems(job, baseItem, entries); } ); + q->connect( listJob, &FileManagerListJob::watchDir, + q, [this, item, watcher] (const QString& path) { + watcher->addDir(path); }, Qt::QueuedConnection ); return listJob; } @@ -257,17 +263,17 @@ } } -void AbstractFileManagerPluginPrivate::created(const QString& path_) +void AbstractFileManagerPluginPrivate::dirty(const QString& path_) { - qCDebug(FILEMANAGER) << "created:" << path_; + qCDebug(FILEMANAGER) << "dirty:" << path_; QFileInfo info(path_); ///FIXME: share memory with parent const Path path(path_); const IndexedString indexedPath(path.pathOrUrl()); const IndexedString indexedParent(path.parent().pathOrUrl()); - QHashIterator it(m_watchers); + QHashIterator it(m_watchers); while (it.hasNext()) { const auto p = it.next().key(); if ( !p->projectItem()->model() ) { @@ -295,21 +301,6 @@ // also gets triggered for kate's backup files continue; } - foreach ( ProjectFolderItem* parentItem, p->foldersForPath(indexedParent) ) { - if ( info.isDir() ) { - ProjectFolderItem* folder = q->createFolderItem( p, path, parentItem ); - if (folder) { - emit q->folderAdded( folder ); - auto job = eventuallyReadFolder( folder ); - job->start(); - } - } else { - ProjectFileItem* file = q->createFileItem( p, path, parentItem ); - if (file) { - emit q->fileAdded( file ); - } - } - } } } @@ -330,7 +321,7 @@ const Path path(QUrl::fromLocalFile(path_)); const IndexedString indexed(path.pathOrUrl()); - QHashIterator it(m_watchers); + QHashIterator it(m_watchers); while (it.hasNext()) { const auto p = it.next().key(); if (path == p->path()) { @@ -446,6 +437,9 @@ job->removeSubDir(folder); } } + ProjectWatcher* watcher = m_watchers.value(folder->project(), nullptr); + Q_ASSERT(watcher); + watcher->removeDir(folder->path().toLocalFile()); folder->parent()->removeRow( folder->row() ); } @@ -487,14 +481,13 @@ ///TODO: check if this works for remote files when something gets changed through another KDE app if ( project->path().isLocalFile() ) { - auto watcher = new KDirWatch( project ); + auto watcher = new ProjectWatcher(project, &d->m_filters); - // set up the signal handling - connect(watcher, &KDirWatch::created, - this, [&] (const QString& path_) { d->created(path_); }); + // set up the signal handling; feeding the dirwatcher is handled by FileManagerListJob. + connect(watcher, &KDirWatch::dirty, + this, [&] (const QString& path_) { d->dirty(path_); }); connect(watcher, &KDirWatch::deleted, this, [&] (const QString& path_) { d->deleted(path_); }); - watcher->addDir(project->path().toLocalFile(), KDirWatch::WatchSubDirs | KDirWatch:: WatchFiles ); d->m_watchers[project] = watcher; } Index: kdevplatform/project/filemanagerlistjob.h =================================================================== --- kdevplatform/project/filemanagerlistjob.h +++ kdevplatform/project/filemanagerlistjob.h @@ -52,6 +52,7 @@ void entries(FileManagerListJob* job, ProjectFolderItem* baseItem, const KIO::UDSEntryList& entries); void nextJob(); + void watchDir(const QString& path); private Q_SLOTS: void slotEntries(KIO::Job* job, const KIO::UDSEntryList& entriesIn ); Index: kdevplatform/project/filemanagerlistjob.cpp =================================================================== --- kdevplatform/project/filemanagerlistjob.cpp +++ kdevplatform/project/filemanagerlistjob.cpp @@ -95,6 +95,8 @@ if (m_aborted) { return; } + // signal that this directory has to be watched + emit watchDir(path.toLocalFile()); KIO::UDSEntryList results; std::transform(entries.begin(), entries.end(), std::back_inserter(results), [] (const QFileInfo& info) -> KIO::UDSEntry { KIO::UDSEntry entry; Index: kdevplatform/project/projectwatcher.h =================================================================== --- /dev/null +++ kdevplatform/project/projectwatcher.h @@ -0,0 +1,61 @@ +/*************************************************************************** + * This file is part of KDevelop * + * Copyright 2017 René Bertin * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU Library General Public License as * + * published by the Free Software Foundation; either version 2 of the * + * License, or (at your option) any later version. * + * * + * This program is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * + * GNU General Public License for more details. * + * * + * You should have received a copy of the GNU Library General Public * + * License along with this program; if not, write to the * + * Free Software Foundation, Inc., * + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * + ***************************************************************************/ + +#ifndef KDEVPLATFORM_PROJECTWATCHER_H +#define KDEVPLATFORM_PROJECTWATCHER_H + +#include "projectexport.h" + +#include + +namespace KDevelop { + +class IProject; +class ProjectFilterManager; + +class KDEVPLATFORMPROJECT_EXPORT ProjectWatcher : public KDirWatch +{ + Q_OBJECT +public: + /** + * Create a dirwatcher for @p project based on KDirWatch but + * that will add or remove each directory only once. + */ + explicit ProjectWatcher(IProject* project); + + /** + * Add directory @p path to the project dirwatcher if it is not + * already being watched. + */ + void addDir(const QString& path, WatchModes watchModes = WatchDirOnly); + void removeDir(const QString& path); + + /** + * return the current number of directories being watched. + */ + int size() const; + +private: + IProject* m_project; + int m_watchedCount; +}; + +} +#endif //KDEVPLATFORM_PROJECTWATCHER_H Index: kdevplatform/project/projectwatcher.cpp =================================================================== --- /dev/null +++ kdevplatform/project/projectwatcher.cpp @@ -0,0 +1,56 @@ +/*************************************************************************** + * This file is part of KDevelop * + * Copyright 2017 René Bertin * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU Library General Public License as * + * published by the Free Software Foundation; either version 2 of the * + * License, or (at your option) any later version. * + * * + * This program is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * + * GNU General Public License for more details. * + * * + * You should have received a copy of the GNU Library General Public * + * License along with this program; if not, write to the * + * Free Software Foundation, Inc., * + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * + ***************************************************************************/ + +#include "projectwatcher.h" +#include "iproject.h" +#include "projectfiltermanager.h" +#include "path.h" + +#include + +using namespace KDevelop; + +KDevelop::ProjectWatcher::ProjectWatcher(IProject* project) + : KDirWatch(project) + , m_project(project) + , m_watchedCount(0) +{} + +void KDevelop::ProjectWatcher::addDir(const QString& path, WatchModes watchModes) +{ + if (!contains(path)) { + KDirWatch::addDir(path, watchModes); + m_watchedCount += 1; + } +} + +void KDevelop::ProjectWatcher::removeDir(const QString& path) +{ + if (contains(path)) { + KDirWatch::removeDir(path); + m_watchedCount -= 1; + } +} + +int KDevelop::ProjectWatcher::size() const +{ + return m_watchedCount; +} + Index: kdevplatform/project/tests/CMakeLists.txt =================================================================== --- kdevplatform/project/tests/CMakeLists.txt +++ kdevplatform/project/tests/CMakeLists.txt @@ -21,3 +21,12 @@ KDev::Tests Qt5::QuickWidgets ) + +add_executable(abstractfilemanagerpluginimportbenchmark + abstractfilemanagerpluginimportbenchmark.cpp +) +ecm_mark_nongui_executable(abstractfilemanagerpluginimportbenchmark) +target_link_libraries(abstractfilemanagerpluginimportbenchmark + KDev::Project + KDev::Tests +) Index: kdevplatform/project/tests/abstractfilemanagerpluginimportbenchmark.cpp =================================================================== --- kdevplatform/project/tests/abstractfilemanagerpluginimportbenchmark.cpp +++ kdevplatform/project/tests/abstractfilemanagerpluginimportbenchmark.cpp @@ -23,6 +23,7 @@ #include #include +#include #include @@ -109,8 +110,10 @@ { Q_UNUSED(job); int elapsed = m_timer.elapsed(); + ProjectWatcher* watcher = qobject_cast(m_manager->projectWatcher(m_project)); m_out << "importing " << m_project->fileSet().size() << " items into project #" << m_projectNumber + << " with " << watcher->size() << " watched directories" << " took " << elapsed / 1000.0 << " seconds" << endl; s_numBenchmarksRunning -= 1;