project tree watcher interface plan
dukju ahn
dukjuahn at gmail.com
Mon Jun 4 17:45:25 UTC 2007
2007/6/4, Andreas Pakulat <apaku at gmx.de>:
> On 04.06.07 13:19:50, dukju ahn wrote:
> > 2007/6/4, Matt Rogers <mattr at kde.org>:
> > >
> > >On Jun 4, 2007, at 9:43 AM, dukju ahn wrote:
> > >
> > >> Apart from the general wrapper around QFileSystemWatcher, what
> > >> I want to discuss here is specific project tree watcher which
> > >> targets project managers.
> > >>
> > >> Although we can use the general wrapper discussed, I think that
> > >> using general wrapper for project managers is duplication of memory
> > >> usages. The key to project manager tree watcher is that it should
> > >> stores
> > >> Project**Items for each watched path. And it can compare difference
> > >> using that project**items.
> > >>
> > >> So my plan is that the "general" wrapper around QFSWachter will not
> > >> be used for projecttreewatcher.
> > >>
> > >> Also, rather than emitting signal, my plan is that we have base class
> > >> named "projecttreewatcher", and provides virtual interfaces, because
> > >> we can provide some default implementations. Especially,
> > >> directoryCreated() and deleted() implementation would be common
> > >> among the project managers, since makefile parsing event will be
> > >> taken place in fileCreated() deleted() modified() method..
> > >>
> > >> Any objection?. I expect as before.
Index: projectfilesystemwatcher.h
===================================================================
--- projectfilesystemwatcher.h (revision 671357)
+++ projectfilesystemwatcher.h (working copy)
@@ -16,12 +16,17 @@
class QFileSystemWatcher;
// template <typename T1, typename T2> class QHash;
#include <QHash>
+#include <QEvent>
+#include "kurl.h"
namespace KDevelop
{
class ProjectFolderItem;
class ProjectFileItem;
+class IProjectFileManager;
}
+class ProjectFileSystemWatcherPrivate;
+
/**
* Simple QFileSystemWatcher wrapper. Designed to be used in custom
make manager.
* Emits directory/file changed signal with ProjectFolderItem or
ProjectFileItem
@@ -30,7 +35,7 @@
{
Q_OBJECT
public:
- ProjectFileSystemWatcher( QObject* parent = 0 );
+ ProjectFileSystemWatcher( KDevelop::IProjectFileManager* manager,
QObject* parent = 0 );
virtual ~ProjectFileSystemWatcher();
void addDirectory( const QString &path,
KDevelop::ProjectFolderItem *folderItem );
@@ -40,7 +45,7 @@
void removeFile( const QString & path );
// void removePaths ( const QStringList & paths );
-Q_SIGNALS:
+// Q_SIGNALS:
/**
* Emitted when the files or subdirectories under @arg path were
created or deleted.
*
@@ -51,22 +56,43 @@
* is deleted, the directoryChanged( parentDir ) will be emitted.
But if child directory
* is not empty, then directoryChanged( childDir ) will be emitted.
*/
- void directoryChanged( const QString & path,
KDevelop::ProjectFolderItem* folderItem );
+// void directoryChanged( const QString & path,
KDevelop::ProjectFolderItem* folderItem );
/**
* Emitted when the contents of file were modified, or the file
itself was deleted on disk.
*/
- void fileChanged( const QString & path,
KDevelop::ProjectFileItem* fileItem );
+// void fileChanged( const QString & path,
KDevelop::ProjectFileItem* fileItem );
private Q_SLOTS:
void slotDirChanged( const QString& path );
+ void slotDirChangedInternal( const QString &dir,
KDevelop::ProjectFolderItem* folderItem );
void slotFileChanged( const QString& path );
+protected:
+ /**
+ * called when the contents of file were modified, or the file
itself was deleted on disk.
+ */
+ virtual void fileChanged( const QString & path,
KDevelop::ProjectFileItem* fileItem ) = 0;
+
+ /**
+ * called when files under @arg parentFolder were created or deleted
+ */
+ virtual void filesCreated( const KUrl::List &files,
KDevelop::ProjectFolderItem *parentFolder ) = 0;
+ virtual void filesDeleted( const QList<KDevelop::ProjectFileItem*> &files,
+ KDevelop::ProjectFolderItem *parentFolder ) = 0;
+
+ /**
+ * called when subdirectories under @arg parentFolder were
created or deleted
+ */
+ virtual void directoriesCreated( const KUrl::List &files,
KDevelop::ProjectFolderItem *parentFolder );
+ virtual void directoriesDeleted( const
QList<KDevelop::ProjectFolderItem*> &dirs,
+ KDevelop::ProjectFolderItem
*parentFolder );
+
+ void parseDirectoryRecursively( KDevelop::ProjectFolderItem* dir,
+ KDevelop::IProjectFileManager* manager );
+
private:
- QFileSystemWatcher *m_watch;
- QHash< QString, KDevelop::ProjectFolderItem* > m_folderHash;
- QHash< QString, KDevelop::ProjectFileItem* > m_fileHash;
-
+ ProjectFileSystemWatcherPrivate *d;
};
#endif
Index: custommakefswatcher.cpp
===================================================================
--- custommakefswatcher.cpp (revision 0)
+++ custommakefswatcher.cpp (revision 0)
@@ -0,0 +1,117 @@
+#include "custommakefswatcher.h"
+#include "custommakemanager.h"
+#include "custommakemodelitems.h"
+#include <QFileInfo>
+#include "iprojectcontroller.h"
+#include "iproject.h"
+#include "icore.h"
+#include <kdebug.h>
+
+CustomMakeFSWatcher::CustomMakeFSWatcher(CustomMakeManager* manager,
QObject* parent)
+ : ProjectFileSystemWatcher( manager, parent )
+{
+ m_customMan = manager;
+}
+CustomMakeFSWatcher::~CustomMakeFSWatcher()
+{}
+
+void CustomMakeFSWatcher::filesCreated( const KUrl::List &files,
KDevelop::ProjectFolderItem *parentFolder )
+{
+ Q_FOREACH( KUrl _file, files )
+ {
+ KDevelop::ProjectFileItem *newitem = new KDevelop::ProjectFileItem(
+ parentFolder->project(), _file, parentFolder );
+ // if Makefile, parse new targets and add to watcher
+ if( _file.fileName() == QString( "Makefile" ) ) // TODO
portable, setting aware
+ {
+ QStringList newTargets = m_customMan->parseCustomMakeFile( _file );
+ Q_FOREACH( QString newTarget, newTargets )
+ {
+ new CustomMakeTargetItem( parentFolder->project(),
newTarget, parentFolder );
+ }
+ addFile( _file.toLocalFile(), newitem );
+ }
+ }
+}
+void CustomMakeFSWatcher::filesDeleted( const
QList<KDevelop::ProjectFileItem*> &files,
+ KDevelop::ProjectFolderItem *parentFolder )
+{
+ Q_FOREACH( KDevelop::ProjectFileItem *_item, files )
+ {
+ int row = _item->row();
+ parentFolder->removeRow( row );
+ }
+}
+
+// void CustomMakeFSWatcher::directoriesCreated( const KUrl::List
&files, KDevelop::ProjectFolderItem *parentFolder )
+// {
+//
+// }
+// void CustomMakeFSWatcher::directoriesDeleted( const
QList<KDevelop::ProjectFolderItem*> &dirs,
+// KDevelop::ProjectFolderItem
*parentFolder )
+// {
+// }
+
+void CustomMakeFSWatcher::fileChanged( const QString& file,
KDevelop::ProjectFileItem* fileItem)
+{
+ kDebug() << "File " << file << " changed " << endl;
+
+ QFileInfo info( file );
+ if( info.fileName() != QString("Makefile") )
+ return;
+
+ // find Makefile item, because it is allowed to be null
+ KDevelop::ProjectFileItem *makefileItem=0;
+ KDevelop::IProject *project=0;
+ if( !fileItem )
+ {
+ KUrl url(file);
+ project =
m_customMan->core()->projectController()->findProjectForUrl( url );
+ Q_ASSERT(project);
+ makefileItem = project->fileForUrl( KUrl(file) );
+ }
+ else
+ {
+ makefileItem = fileItem;
+ project = fileItem->project();
+ }
+ Q_ASSERT(makefileItem);
+
+ // find parent folder item
+ QStandardItem *stditem = makefileItem->parent();
+ KDevelop::ProjectBuildFolderItem *parentFolder =
+ dynamic_cast<KDevelop::ProjectBuildFolderItem*>( stditem );
+ if( !parentFolder )
+ return;
+
+ // delete every targets in the fileItem's parent directory
+ QList<KDevelop::ProjectTargetItem*> targets = parentFolder->targetList();
+ Q_FOREACH( KDevelop::ProjectTargetItem* _deletingTarget, targets )
+ {
+ int targetrow = _deletingTarget->row();
+ parentFolder->removeRow( targetrow );
+ }
+
+ // determine whether the file contents were modified or the
entire file itself was deleted.
+ if( info.exists() == false )
+ {
+ // Makefile deleted
+ KDevelop::ProjectItem *prjitem = project->projectItem();
+ CustomMakeProjectItem *cmpi =
dynamic_cast<CustomMakeProjectItem*>( prjitem );
+ cmpi->fsWatcher()->removeFile( file );
+ int makefileRow = makefileItem->row();
+ parentFolder->removeRow( makefileRow );
+ }
+ else
+ {
+ // Makefile contents modified
+ QStringList newTargets = m_customMan->parseCustomMakeFile(
KUrl(file) );
+ Q_FOREACH( QString newTarget, newTargets )
+ {
+ new CustomMakeTargetItem( project, newTarget, parentFolder );
+ }
+ }
+
+}
+
+#include "custommakefswatcher.moc"
Index: custommakefswatcher.h
===================================================================
--- custommakefswatcher.h (revision 0)
+++ custommakefswatcher.h (revision 0)
@@ -0,0 +1,41 @@
+#ifndef CUSTOMMAKEFSWATCHER_H
+#define CUSTOMMAKEFSWATCHER_H
+
+#include "projectfilesystemwatcher.h"
+
+class KUrl;
+class KUrl::List;
+
+namespace KDevelop
+{
+class ProjectFileItem;
+class ProjectFolderItem;
+class IProjectFileManager;
+}
+
+class CustomMakeManager;
+
+class CustomMakeFSWatcher : public ProjectFileSystemWatcher
+{
+ Q_OBJECT
+public:
+ CustomMakeFSWatcher(CustomMakeManager* manager, QObject* parent = 0);
+ virtual ~CustomMakeFSWatcher();
+
+protected:
+ virtual void filesCreated( const KUrl::List &files,
KDevelop::ProjectFolderItem *parentFolder );
+ virtual void filesDeleted( const QList<KDevelop::ProjectFileItem*> &files,
+ KDevelop::ProjectFolderItem *parentFolder );
+
+// virtual void directoriesCreated( const KUrl::List &files,
KDevelop::ProjectFolderItem *parentFolder );
+// virtual void directoriesDeleted( const
QList<KDevelop::ProjectFolderItem*> &dirs,
+// KDevelop::ProjectFolderItem
*parentFolder );
+
+ virtual void fileChanged( const QString& file,
KDevelop::ProjectFileItem* fileItem);
+
+private:
+ CustomMakeManager *m_customMan;
+
+};
+
+#endif
Index: projectfilesystemwatcher.cpp
===================================================================
--- projectfilesystemwatcher.cpp (revision 671357)
+++ projectfilesystemwatcher.cpp (working copy)
@@ -10,78 +10,293 @@
#include "projectmodel.h"
#include "projectfilesystemwatcher.h"
+#include "iprojectfilemanager.h"
#include <QHash>
#include <QFileSystemWatcher>
+#include <QDir>
+#include <QFileInfo>
+#include <QQueue>
+#include <QCoreApplication>
+#include "kdebug.h"
-ProjectFileSystemWatcher::ProjectFileSystemWatcher( QObject* parent )
+class ProjectFileSystemWatcherPrivate
+{
+public:
+ QFileSystemWatcher *m_watch;
+ QHash< QString, KDevelop::ProjectFolderItem* > m_folderHash;
+ QHash< QString, KDevelop::ProjectFileItem* > m_fileHash;
+ KDevelop::IProjectFileManager *m_manager;
+};
+
+ProjectFileSystemWatcher::ProjectFileSystemWatcher(
KDevelop::IProjectFileManager *manager,
+ QObject* parent )
: QObject( parent )
+ , d( new ProjectFileSystemWatcherPrivate )
{
- m_watch = new QFileSystemWatcher(this);
- connect( m_watch, SIGNAL(directoryChanged ( const QString &)),
+ d->m_watch = new QFileSystemWatcher(this);
+ connect( d->m_watch, SIGNAL(directoryChanged ( const QString &)),
this, SLOT(slotDirChanged(const QString&)) );
- connect( m_watch, SIGNAL(fileChanged ( const QString &)),
+ connect( d->m_watch, SIGNAL(fileChanged ( const QString &)),
this, SLOT(slotFileChanged(const QString&)) );
+ d->m_manager = manager;
}
ProjectFileSystemWatcher::~ProjectFileSystemWatcher()
{
- delete m_watch;
+ delete d->m_watch;
+ delete d;
}
void ProjectFileSystemWatcher::addDirectory( const QString &path,
KDevelop::ProjectFolderItem *folderItem )
{
- m_watch->addPath( path );
- m_folderHash.insert( path, folderItem );
+ d->m_watch->addPath( path );
+ d->m_folderHash.insert( path, folderItem );
}
void ProjectFileSystemWatcher::addFile( const QString &path,
KDevelop::ProjectFileItem *fileItem )
{
- m_watch->addPath( path );
+ d->m_watch->addPath( path );
if( fileItem )
{
- m_fileHash.insert( path, fileItem );
+ d->m_fileHash.insert( path, fileItem );
}
}
void ProjectFileSystemWatcher::removeDirectory( const QString & path )
{
- m_watch->removePath( path );
+// d->m_watch->removePath( path );
// if( m_folderHash.contains( path ) )
// {
- m_folderHash.remove( path );
+ kDebug() << "Removing Directory from Watcher " << path << endl;
+ d->m_folderHash.remove( path );
// }
}
void ProjectFileSystemWatcher::removeFile( const QString & path )
{
- m_watch->removePath( path );
- m_fileHash.remove( path );
+// d->m_watch->removePath( path );
+ kDebug() << "Removing file from Watcher " << path << endl;
+ d->m_fileHash.remove( path );
}
// void ProjectFileSystemWatcher::removePaths( const QStringList & paths );
void ProjectFileSystemWatcher::slotDirChanged( const QString& path )
{
- Q_ASSERT( m_folderHash.contains(path) );
- if( m_folderHash.contains(path) )
+// Q_ASSERT( d->m_folderHash.contains(path) );
+ if( d->m_folderHash.contains(path) )
{
- KDevelop::ProjectFolderItem *folder = m_folderHash.value( path );
- emit directoryChanged( path, folder );
+ KDevelop::ProjectFolderItem *folder = d->m_folderHash.value( path );
+ slotDirChangedInternal( path, folder );
}
}
void ProjectFileSystemWatcher::slotFileChanged( const QString& path )
{
- if( m_fileHash.contains(path) )
+ Q_ASSERT( d->m_fileHash.contains(path) );
+ if( d->m_fileHash.contains(path) )
{
- KDevelop::ProjectFileItem *file = m_fileHash.value( path );
- emit fileChanged( path, file );
+ KDevelop::ProjectFileItem *file = d->m_fileHash.value( path );
+ fileChanged( path, file );
}
else
{
- emit fileChanged( path, 0 );
+ fileChanged( path, 0 );
}
}
+void ProjectFileSystemWatcher::slotDirChangedInternal( const QString
&dir, KDevelop::ProjectFolderItem* folderItem )
+{
+ kDebug() << "Directory " << dir << " changed " << endl;
+
+ QDir changedDir( dir );
+
+ if( !changedDir.exists() )
+ {
+ //directory itself deleted
+ int row = folderItem->row();
+ QStandardItem *parent = folderItem->parent();
+ parent->removeRow( row );
+
+ this->removeDirectory( dir );
+
+ return;
+ }
+ else //subdirectory or file is created or deleted.
+ {
+ // retrieve current disk info
+ QFileInfoList fileEntries = changedDir.entryInfoList(QDir::Files);
+ QFileInfoList dirEntries =
changedDir.entryInfoList(QDir::NoDotAndDotDot | QDir::Dirs);
+
+ // convert disk info into QStringList
+ QStringList fileList;
+ for ( int i = 0; i < fileEntries.count(); ++i )
+ {
+ QFileInfo fileInfo = fileEntries.at( i );
+ QString absFilePath = fileInfo.absoluteFilePath();
+ fileList << absFilePath;
+ }
+ QStringList dirList;
+ for ( int i = 0; i < dirEntries.count(); ++i )
+ {
+ QFileInfo fileInfo = dirEntries.at( i );
+ QString absFilePath = fileInfo.absoluteFilePath();
+ dirList << absFilePath;
+ }
+
+ // retrieve model item info, and convert into QStringList
+ QList<KDevelop::ProjectFileItem*> itemFileList =
folderItem->fileList();
+ QStringList itemFileListString;
+ Q_FOREACH( KDevelop::ProjectFileItem* _item, itemFileList )
+ {
+ itemFileListString << _item->url().toLocalFile();
+ }
+
+ QList<KDevelop::ProjectFolderItem*> itemFolderList =
folderItem->folderList();
+ QStringList itemFolderListString;
+ Q_FOREACH( KDevelop::ProjectFolderItem *_item, itemFolderList )
+ {
+ itemFolderListString << _item->url().toLocalFile();
+ }
+
+ // Compare the difference between disk file and model items
+
+ // round 1 -- file
+// KUrl::List deletedFileUrl;
+ QList< KDevelop::ProjectFileItem* > deletedItems;
+ Q_FOREACH( KDevelop::ProjectFileItem* _fileItem, itemFileList )
+ {
+ if( fileList.contains( _fileItem->url().toLocalFile() ) == false )
+ {
+ // disk file was deleted, so project file items
should be also deleted
+
+ // ### note: if some file, previously added to
watching list, was deleted,
+ // than this directoryChanged() is not emitted.
Rather fileChanged() is emitted.
+// if( deletingCandidate.fileName() ==
QString("Makefile") ) // TODO portable, setting aware
+// {
+// //delete every targets in this directory
+// QList<KDevelop::ProjectTargetItem*> targets =
folderItem->targetList();
+// Q_FOREACH( KDevelop::ProjectTargetItem*
_deletingTarget, targets )
+// {
+// int targetrow = _deletingTarget->row();
+// folderItem->removeRow( targetrow );
+// }
+// cmpi->fsWatcher()->removeFile(
deletingCandidate.toLocalFile() );
+// }
+// int row = _fileItem->row();
+// folderItem->removeRow( row );
+
+// deletedFileUrl << deletingCandidate;
+ deletedItems << _fileItem;
+ }
+ }
+ if( !deletedItems.isEmpty() )
+ filesDeleted( deletedItems, folderItem );
+
+ KUrl::List createdFileUrl;
+ Q_FOREACH( QString diskFile, fileList )
+ {
+ if( itemFileListString.contains( diskFile ) == false )
+ {
+ // disk file was created, file items should be also created
+// KDevelop::ProjectFileItem *newitem = new
KDevelop::ProjectFileItem(
+// folderItem->project(), KUrl(diskFile), folderItem );
+// // if Makefile, parse new targets and add to watcher
+// if( diskFile.endsWith( "/Makefile" ) ) // TODO
portable, setting aware
+// {
+// QStringList newTargets = parseCustomMakeFile(
KUrl(diskFile) );
+// Q_FOREACH( QString newTarget, newTargets )
+// {
+// new CustomMakeTargetItem(
folderItem->project(), newTarget, folderItem );
+// }
+// cmpi->fsWatcher()->addFile( diskFile, newitem );
+// }
+ createdFileUrl << KUrl(diskFile);
+ }
+ }
+ if( !createdFileUrl.isEmpty() )
+ filesCreated( createdFileUrl, folderItem );
+
+ // round 2 -- directory
+// KUrl::List deletedDirs;
+ QList< KDevelop::ProjectFolderItem* > deletedDirs;
+ Q_FOREACH( KDevelop::ProjectFolderItem* _folderItem, itemFolderList )
+ {
+ if( dirList.contains( _folderItem->url().toLocalFile() ) == false)
+ {
+// int row = _folderItem->row();
+// QString tobeRemovedDir = _folderItem->url().toLocalFile();
+// folderItem->removeRow( row );
+//
+// this->removeDirectory( tobeRemovedDir );
+ deletedDirs << _folderItem;
+ }
+ }
+ if( !deletedDirs.isEmpty() )
+ directoriesDeleted( deletedDirs, folderItem );
+
+ KUrl::List createdDirs;
+ Q_FOREACH( QString diskDir, dirList )
+ {
+ if( itemFolderListString.contains( diskDir ) == false )
+ {
+// KDevelop::ProjectBuildFolderItem *newitem =new
KDevelop::ProjectBuildFolderItem(
+// folderItem->project(), KUrl(diskDir), folderItem );
+//
+// this->addDirectory( diskDir, newitem );
+// this->parseDirectoryRecursively( newitem, d->m_manager );
+ createdDirs << KUrl(diskDir);
+ }
+ }
+ if( !createdDirs.isEmpty() )
+ directoriesCreated( createdDirs, folderItem );
+ }
+}
+
+void ProjectFileSystemWatcher::parseDirectoryRecursively(
KDevelop::ProjectFolderItem* dir,
+
KDevelop::IProjectFileManager* manager )
+{
+ QQueue< QList<KDevelop::ProjectFolderItem*> > workQueue;
+ QList<KDevelop::ProjectFolderItem*> initial;
+ initial.append( dir );
+ workQueue.enqueue( initial );
+
+ while( workQueue.count() > 0 )
+ {
+ QList<KDevelop::ProjectFolderItem*> front = workQueue.dequeue();
+ Q_FOREACH( KDevelop::ProjectFolderItem* _item, front )
+ {
+ QList<KDevelop::ProjectFolderItem*> workingList =
manager->parse( _item );
+ if( workingList.count() > 0 )
+ workQueue.enqueue( workingList );
+ }
+ }
+}
+
+void ProjectFileSystemWatcher::directoriesCreated( const KUrl::List &files,
+ KDevelop::ProjectFolderItem *parentFolder )
+{
+ Q_FOREACH( KUrl _file, files )
+ {
+ KDevelop::ProjectBuildFolderItem *newitem = new
KDevelop::ProjectBuildFolderItem(
+ parentFolder->project(), _file, parentFolder );
+
+ this->addDirectory( _file.toLocalFile(), newitem );
+ this->parseDirectoryRecursively( newitem, d->m_manager );
+ }
+}
+void ProjectFileSystemWatcher::directoriesDeleted( const
QList<KDevelop::ProjectFolderItem*> &dirs,
+ KDevelop::ProjectFolderItem *parentFolder )
+{
+ Q_FOREACH( KDevelop::ProjectFolderItem *_item, dirs )
+ {
+ int row = _item->row();
+ QString tobeRemovedDir = _item->url().toLocalFile();
+ parentFolder->removeRow( row );
+
+ this->removeDirectory( tobeRemovedDir );
+ }
+}
+
#include "projectfilesystemwatcher.moc"
More information about the KDevelop-devel
mailing list