diff --git a/project/projectmodel.cpp b/project/projectmodel.cpp index d609406b13..1bc51892c7 100644 --- a/project/projectmodel.cpp +++ b/project/projectmodel.cpp @@ -1,979 +1,982 @@ /* This file is part of KDevelop Copyright 2005 Roberto Raggi Copyright 2007 Andreas Pakulat Copyright 2007 Aleix Pol This library 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 library 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 Library General Public License for more details. You should have received a copy of the GNU Library General Public License along with this library; see the file COPYING.LIB. If not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #include "projectmodel.h" #include #include #include #include #include #include #include #include #include #include #include "interfaces/iprojectfilemanager.h" #include #include #include #include #include #include #include // Utility function to determine between direct connection and blocking-queued-connection // for emitting of signals for data changes/row addition/removal // BlockingQueuedConnection is necessary here as slots connected to the "aboutToBe" signals // expect the actual model content to not have changed yet. So we need to make sure the // signal is delivered before we really do something. static Qt::ConnectionType getConnectionTypeForSignalDelivery( KDevelop::ProjectModel* model ) { if( QThread::currentThread() == model->thread() ) { return Qt::DirectConnection; } else { return Qt::BlockingQueuedConnection; } } namespace KDevelop { QStringList removeProjectBasePath( const QStringList& fullpath, KDevelop::ProjectBaseItem* item ) { QStringList result = fullpath; if( item ) { KDevelop::ProjectModel* model = KDevelop::ICore::self()->projectController()->projectModel(); QStringList basePath = model->pathFromIndex( model->indexFromItem( item ) ); if( basePath.count() >= fullpath.count() ) { return QStringList(); } for( int i = 0; i < basePath.count(); i++ ) { result.takeFirst(); } } return result; } QStringList joinProjectBasePath( const QStringList& partialpath, KDevelop::ProjectBaseItem* item ) { QStringList basePath; if( item ) { KDevelop::ProjectModel* model = KDevelop::ICore::self()->projectController()->projectModel(); basePath = model->pathFromIndex( model->indexFromItem( item ) ); } return basePath + partialpath; } class ProjectModelPrivate { public: ProjectModelPrivate( ProjectModel* model ): model( model ) { } ProjectBaseItem* rootItem; ProjectModel* model; ProjectBaseItem* itemFromIndex( const QModelIndex& idx ) { if( !idx.isValid() ) { return rootItem; } if( idx.model() != model ) { return 0; } return model->itemFromIndex( idx ); } }; class ProjectBaseItemPrivate { public: ProjectBaseItemPrivate() : project(0), parent(0), row(-1), model(0) {} IProject* project; ProjectBaseItem* parent; int row; QList children; QString text; ProjectBaseItem::ProjectItemType type; Qt::ItemFlags flags; ProjectModel* model; KUrl m_url; }; ProjectBaseItem::ProjectBaseItem( IProject* project, const QString &name, ProjectBaseItem *parent ) : d_ptr(new ProjectBaseItemPrivate) { Q_D(ProjectBaseItem); // only the root item has no project (and can be identified by having no name or parent) Q_ASSERT(project || (name.isEmpty() && !parent)); d->project = project; d->text = name; d->flags = Qt::ItemIsSelectable | Qt::ItemIsEnabled; if( parent ) { parent->appendRow( this ); } } ProjectBaseItem::~ProjectBaseItem() { Q_D(ProjectBaseItem); if( parent() ) { parent()->takeRow( d->row ); } else if( model() ) { model()->takeRow( d->row ); } removeRows(0, d->children.size()); delete d; } ProjectBaseItem* ProjectBaseItem::child( int row ) const { Q_D(const ProjectBaseItem); if( row < 0 || row >= d->children.length() ) { return 0; } return d->children.at( row ); } QList< ProjectBaseItem* > ProjectBaseItem::children() const { Q_D(const ProjectBaseItem); return d->children; } ProjectBaseItem* ProjectBaseItem::takeRow(int row) { Q_D(ProjectBaseItem); Q_ASSERT(row >= 0 && row < d->children.size()); if( model() ) { QMetaObject::invokeMethod( model(), "rowsAboutToBeRemoved", getConnectionTypeForSignalDelivery( model() ), Q_ARG(QModelIndex, index()), Q_ARG(int, row), Q_ARG(int, row) ); } ProjectBaseItem* olditem = d->children.takeAt( row ); olditem->d_func()->parent = 0; olditem->d_func()->row = -1; olditem->setModel( 0 ); for(int i=row; id_func()->row--; Q_ASSERT(child(i)->d_func()->row==i); } if( model() ) { QMetaObject::invokeMethod( model(), "rowsRemoved", getConnectionTypeForSignalDelivery( model() ), Q_ARG(QModelIndex, index()), Q_ARG(int, row), Q_ARG(int, row) ); } return olditem; } void ProjectBaseItem::removeRow( int row ) { delete takeRow( row ); } void ProjectBaseItem::removeRows(int row, int count) { for( ; count > 0; count-- ) { removeRow( row ); } } QModelIndex ProjectBaseItem::index() const { if( model() ) { return model()->indexFromItem( this ); } return QModelIndex(); } int ProjectBaseItem::rowCount() const { Q_D(const ProjectBaseItem); return d->children.count(); } int ProjectBaseItem::type() const { return ProjectBaseItem::BaseItem; } ProjectModel* ProjectBaseItem::model() const { Q_D(const ProjectBaseItem); return d->model; } ProjectBaseItem* ProjectBaseItem::parent() const { Q_D(const ProjectBaseItem); if( model() && model()->d->rootItem == d->parent ) { return 0; } return d->parent; } int ProjectBaseItem::row() const { Q_D(const ProjectBaseItem); return d->row; } QString ProjectBaseItem::text() const { Q_D(const ProjectBaseItem); if( project() && !parent() ) { return project()->name(); } else { Q_ASSERT(!d->text.isEmpty()); return d->text; } } void ProjectBaseItem::setModel( ProjectModel* model ) { Q_D(ProjectBaseItem); d->model = model; foreach( ProjectBaseItem* item, d->children ) { item->setModel( model ); } } void ProjectBaseItem::setRow( int row ) { Q_D(ProjectBaseItem); d->row = row; } void ProjectBaseItem::setText( const QString& text ) { Q_D(ProjectBaseItem); d->text = text; if( model() ) { QMetaObject::invokeMethod( model(), "dataChanged", getConnectionTypeForSignalDelivery( model() ), Q_ARG(QModelIndex, index()), Q_ARG(QModelIndex, index()) ); } } ProjectBaseItem::RenameStatus ProjectBaseItem::rename(const QString& newname) { setText( newname ); return RenameOk; } KDevelop::ProjectBaseItem::ProjectItemType baseType( int type ) { if( type == KDevelop::ProjectBaseItem::Folder || type == KDevelop::ProjectBaseItem::BuildFolder ) return KDevelop::ProjectBaseItem::Folder; if( type == KDevelop::ProjectBaseItem::Target || type == KDevelop::ProjectBaseItem::ExecutableTarget || type == KDevelop::ProjectBaseItem::LibraryTarget) return KDevelop::ProjectBaseItem::Target; return static_cast( type ); } bool ProjectBaseItem::lessThan( const KDevelop::ProjectBaseItem* item ) const { if(item->type() >= KDevelop::ProjectBaseItem::CustomProjectItemType ) { // For custom types we want to make sure that if they override lessThan, then we // prefer their lessThan implementation return !item->lessThan( this ); } KDevelop::ProjectBaseItem::ProjectItemType leftType=baseType(type()), rightType=baseType(item->type()); if(leftType==rightType) { if(leftType==KDevelop::ProjectBaseItem::File) { return file()->fileName().compare(item->file()->fileName(), Qt::CaseInsensitive) < 0; } return this->text()text(); } else { return leftTypeproject; } void ProjectBaseItem::appendRow( ProjectBaseItem* item ) { Q_D(ProjectBaseItem); if( !item ) { return; } if( item->parent() ) { // Proper way is to first removeRow() on the original parent, then appendRow on this one kWarning() << "Ignoring double insertion of item" << item; return; } int startrow,endrow; if( model() ) { startrow = endrow = d->children.count(); QMetaObject::invokeMethod( model(), "rowsAboutToBeInserted", getConnectionTypeForSignalDelivery( model() ), Q_ARG(QModelIndex, index()), Q_ARG(int, startrow), Q_ARG(int, endrow) ); } d->children.append( item ); item->setRow( d->children.count() - 1 ); item->d_func()->parent = this; item->setModel( model() ); if( model() ) { QMetaObject::invokeMethod( model(), "rowsInserted", getConnectionTypeForSignalDelivery( model() ), Q_ARG( QModelIndex, index() ), Q_ARG( int, startrow ), Q_ARG( int, endrow ) ); } } KUrl ProjectBaseItem::url( ) const { Q_D(const ProjectBaseItem); return d->m_url; } void ProjectBaseItem::setUrl( const KUrl& url ) { Q_D(ProjectBaseItem); d->m_url = url; setText( d->m_url.fileName() ); } Qt::ItemFlags ProjectBaseItem::flags() { Q_D(ProjectBaseItem); return d->flags; } void ProjectBaseItem::setFlags(Qt::ItemFlags flags) { Q_D(ProjectBaseItem); d->flags = flags; if(d->model) d->model->dataChanged(index(), index()); } QString ProjectBaseItem::iconName() const { return ""; } ProjectFolderItem *ProjectBaseItem::folder() const { return 0; } ProjectTargetItem *ProjectBaseItem::target() const { return 0; } ProjectExecutableTargetItem *ProjectBaseItem::executable() const { return 0; } ProjectFileItem *ProjectBaseItem::file() const { return 0; } QList ProjectBaseItem::folderList() const { QList lst; for ( int i = 0; i < rowCount(); ++i ) { ProjectBaseItem* item = child( i ); if ( item->type() == Folder || item->type() == BuildFolder ) { ProjectFolderItem *kdevitem = dynamic_cast( item ); if ( kdevitem ) lst.append( kdevitem ); } } return lst; } QList ProjectBaseItem::targetList() const { QList lst; for ( int i = 0; i < rowCount(); ++i ) { ProjectBaseItem* item = child( i ); if ( item->type() == Target || item->type() == LibraryTarget || item->type() == ExecutableTarget ) { ProjectTargetItem *kdevitem = dynamic_cast( item ); if ( kdevitem ) lst.append( kdevitem ); } } return lst; } QList ProjectBaseItem::fileList() const { QList lst; for ( int i = 0; i < rowCount(); ++i ) { ProjectBaseItem* item = child( i ); Q_ASSERT(item); if ( item && item->type() == File ) { ProjectFileItem *kdevitem = dynamic_cast( item ); if ( kdevitem ) lst.append( kdevitem ); } } return lst; } void ProjectModel::resetModel() { reset(); } void ProjectModel::clear() { d->rootItem->removeRows(0, d->rootItem->rowCount()); } ProjectFolderItem::ProjectFolderItem( IProject* project, const KUrl & dir, ProjectBaseItem * parent ) : ProjectBaseItem( project, dir.fileName(), parent ) { setUrl( dir ); } ProjectFolderItem::~ProjectFolderItem() { } void ProjectFolderItem::setUrl( const KUrl& url ) { KUrl copy(url); copy.adjustPath(KUrl::AddTrailingSlash); ProjectBaseItem::setUrl(copy); + + propagateRename(url); } ProjectFolderItem *ProjectFolderItem::folder() const { return const_cast(this); } int ProjectFolderItem::type() const { return ProjectBaseItem::Folder; } QString ProjectFolderItem::folderName() const { return url().fileName(); } -void propagateRename( const KDevelop::ProjectFolderItem* item, const KUrl& newBase) +void ProjectFolderItem::propagateRename(const KUrl& newBase) const { KUrl url = newBase; url.addPath("dummy"); - foreach( KDevelop::ProjectBaseItem* child, item->children() ) + foreach( KDevelop::ProjectBaseItem* child, children() ) { url.setFileName( child->text() ); child->setUrl( url ); - if ( child->folder() ) { - propagateRename( child->folder(), url ); + + const ProjectFolderItem* folder = child->folder(); + if ( folder ) { + folder->propagateRename( url ); } } } ProjectBaseItem::RenameStatus ProjectFolderItem::rename(const QString& newname) { //TODO: Same as ProjectFileItem, so should be shared somehow KUrl dest = url().upUrl(); dest.addPath(newname); if( !newname.contains('/') ) { KIO::UDSEntry entry; //There exists a file with that name? if( !KIO::NetAccess::stat(dest, entry, 0) ) { if( !project() || project()->projectFileManager()->renameFolder(this, dest) ) { - setUrl( dest ); - propagateRename(this, dest); return ProjectBaseItem::RenameOk; - } else + } + else { return ProjectBaseItem::ProjectManagerRenameFailed; } } else { return ProjectBaseItem::ExistingItemSameName; } } else { return ProjectBaseItem::InvalidNewName; } } bool ProjectFolderItem::hasFileOrFolder(const QString& name) const { for ( int i = 0; i < rowCount(); ++i ) { ProjectBaseItem* item = child( i ); if ( ProjectFileItem* file = dynamic_cast(item)) if (file->fileName() == name) return true; if ( ProjectFolderItem* folder = dynamic_cast(item)) if (folder->folderName() == name) return true; } return false; } ProjectBuildFolderItem::ProjectBuildFolderItem( IProject* project, const KUrl &dir, ProjectBaseItem *parent) : ProjectFolderItem( project, dir, parent ) { } QString ProjectFolderItem::iconName() const { return "folder"; } int ProjectBuildFolderItem::type() const { return ProjectBaseItem::BuildFolder; } QString ProjectBuildFolderItem::iconName() const { return "folder-development"; } ProjectFileItem::ProjectFileItem( IProject* project, const KUrl & file, ProjectBaseItem * parent ) : ProjectBaseItem( project, file.fileName(), parent ) { setUrl( file ); // Need to this manually here as setUrl() is virtual and hence the above // only calls the version in ProjectBaseItem and not ours if( project ) { project->addToFileSet( KDevelop::IndexedString(file) ); } } ProjectFileItem::~ProjectFileItem() { if( project() ) { project()->removeFromFileSet(KDevelop::IndexedString(url())); } } QString ProjectFileItem::iconName() const { return KMimeType::findByUrl(url(), 0, false, true)->iconName(url()); } ProjectBaseItem::RenameStatus ProjectFileItem::rename(const QString& newname) { KUrl dest = url().upUrl(); dest.addPath(newname); if( !newname.contains('/') ) { KIO::UDSEntry entry; //There exists a file with that name? if( !KIO::NetAccess::stat(dest, entry, 0) ) { if( !project() || project()->projectFileManager()->renameFile(this, dest) ) { - setUrl( dest ); return ProjectBaseItem::RenameOk; - } else + } + else { return ProjectBaseItem::ProjectManagerRenameFailed; } } else { return ProjectBaseItem::ExistingItemSameName; } } else { return ProjectBaseItem::InvalidNewName; } } QString ProjectFileItem::fileName() const { return url().fileName(); } void ProjectFileItem::setUrl( const KUrl& url ) { if( project() ) { if(!this->url().isEmpty()) project()->removeFromFileSet( KDevelop::IndexedString(this->url()) ); project()->addToFileSet( KDevelop::IndexedString(url) ); } ProjectBaseItem::setUrl( url ); } int ProjectFileItem::type() const { return ProjectBaseItem::File; } ProjectFileItem *ProjectFileItem::file() const { return const_cast( this ); } ProjectTargetItem::ProjectTargetItem( IProject* project, const QString &name, ProjectBaseItem *parent ) : ProjectBaseItem( project, name, parent ) { } QString ProjectTargetItem::iconName() const { return "system-run"; } int ProjectTargetItem::type() const { return ProjectBaseItem::Target; } ProjectTargetItem *ProjectTargetItem::target() const { return const_cast( this ); } ProjectExecutableTargetItem::ProjectExecutableTargetItem( IProject* project, const QString &name, ProjectBaseItem *parent ) : ProjectTargetItem(project, name, parent) { } ProjectExecutableTargetItem *ProjectExecutableTargetItem::executable() const { return const_cast( this ); } int ProjectExecutableTargetItem::type() const { return ProjectBaseItem::ExecutableTarget; } ProjectLibraryTargetItem::ProjectLibraryTargetItem( IProject* project, const QString &name, ProjectBaseItem *parent ) : ProjectTargetItem(project, name, parent) {} int ProjectLibraryTargetItem::type() const { return ProjectBaseItem::LibraryTarget; } QModelIndex ProjectModel::pathToIndex(const QStringList& tofetch_) const { if(tofetch_.isEmpty()) return QModelIndex(); QStringList tofetch(tofetch_); if(tofetch.last().isEmpty()) tofetch.takeLast(); QModelIndex current=index(0,0, QModelIndex()); QModelIndex ret; for(int a = 0; a < tofetch.size(); ++a) { const QString& currentName = tofetch[a]; bool matched = false; QModelIndexList l = match(current, Qt::DisplayRole, currentName, -1, Qt::MatchExactly); foreach(const QModelIndex& idx, l) { //If this is not the last item, only match folders, as there may be targets and folders with the same name if(a == tofetch.size()-1 || itemFromIndex(idx)->folder()) { ret = idx; current = index(0,0, ret); matched = true; break; } } if(!matched) { ret = QModelIndex(); break; } } Q_ASSERT(!ret.isValid() || data(ret).toString()==tofetch.last()); return ret; } QStringList ProjectModel::pathFromIndex(const QModelIndex& index) const { if (!index.isValid()) return QStringList(); QModelIndex idx = index; QStringList list; do { QString t = data(idx, Qt::DisplayRole).toString(); list.prepend(t); QModelIndex parent = idx.parent(); idx = parent.sibling(parent.row(), index.column()); } while (idx.isValid()); return list; } int ProjectModel::columnCount( const QModelIndex& ) const { return 1; } int ProjectModel::rowCount( const QModelIndex& parent ) const { ProjectBaseItem* item = d->itemFromIndex( parent ); return item ? item->rowCount() : 0; } QModelIndex ProjectModel::parent( const QModelIndex& child ) const { if( child.isValid() ) { ProjectBaseItem* item = static_cast( child.internalPointer() ); return indexFromItem( item ); } return QModelIndex(); } QModelIndex ProjectModel::indexFromItem( const ProjectBaseItem* item ) const { if( item && item->d_func()->parent ) { return createIndex( item->row(), 0, item->d_func()->parent ); } return QModelIndex(); } ProjectBaseItem* ProjectModel::itemFromIndex( const QModelIndex& index ) const { if( index.row() >= 0 && index.column() == 0 && index.model() == this ) { ProjectBaseItem* parent = static_cast( index.internalPointer() ); if( parent ) { return parent->child( index.row() ); } } return 0; } QVariant ProjectModel::data( const QModelIndex& index, int role ) const { if( ( role == Qt::DisplayRole || role == Qt::ToolTipRole || role == Qt::DecorationRole ) && index.isValid() ) { ProjectBaseItem* item = itemFromIndex( index ); if( item ) { switch(role) { case Qt::DecorationRole: return item->iconName(); case Qt::ToolTipRole: return item->url().prettyUrl(); default: return item->text(); } } } return QVariant(); } ProjectModel::ProjectModel( QObject *parent ) : QAbstractItemModel( parent ), d( new ProjectModelPrivate( this ) ) { d->rootItem = new ProjectBaseItem( 0, "", 0 ); d->rootItem->setModel( this ); } ProjectModel::~ProjectModel() { } ProjectVisitor::ProjectVisitor() { } QModelIndex ProjectModel::index( int row, int column, const QModelIndex& parent ) const { if( hasIndex( row, column, parent ) ) { ProjectBaseItem* parentItem = d->itemFromIndex( parent ); if( parentItem && row >= 0 && row < parentItem->rowCount() && column == 0 ) { return createIndex( row, column, parentItem ); } } return QModelIndex(); } void ProjectModel::appendRow( ProjectBaseItem* item ) { d->rootItem->appendRow( item ); } void ProjectModel::removeRow( int row ) { d->rootItem->removeRow( row ); } ProjectBaseItem* ProjectModel::takeRow( int row ) { return d->rootItem->takeRow( row ); } bool ProjectModel::hasChildren(const QModelIndex& parent) const { bool b = QAbstractItemModel::hasChildren(parent); return b; } Qt::ItemFlags ProjectModel::flags(const QModelIndex& index) const { ProjectBaseItem* item = itemFromIndex( index ); if(item) return item->flags(); else return 0; } bool ProjectModel::insertColumns(int, int, const QModelIndex&) { // Not supported return false; } bool ProjectModel::insertRows(int, int, const QModelIndex&) { // Not supported return false; } bool ProjectModel::setData(const QModelIndex&, const QVariant&, int) { // Not supported return false; } void ProjectVisitor::visit ( IProject* prj ) { visit( prj->projectItem() ); } void ProjectVisitor::visit ( ProjectBuildFolderItem* folder ) { foreach( ProjectFileItem* item, folder->fileList() ) { visit( item ); } foreach( ProjectTargetItem* item, folder->targetList() ) { if( item->type() == ProjectBaseItem::LibraryTarget ) { visit( dynamic_cast( item ) ); } else if( item->type() == ProjectBaseItem::ExecutableTarget ) { visit( dynamic_cast( item ) ); } } foreach( ProjectFolderItem* item, folder->folderList() ) { if( item->type() == ProjectBaseItem::BuildFolder ) { visit( dynamic_cast( item ) ); } else if( item->type() == ProjectBaseItem::Folder ) { visit( dynamic_cast( item ) ); } } } void ProjectVisitor::visit ( ProjectExecutableTargetItem* exec ) { foreach( ProjectFileItem* item, exec->fileList() ) { visit( item ); } } void ProjectVisitor::visit ( ProjectFolderItem* folder ) { foreach( ProjectFileItem* item, folder->fileList() ) { visit( item ); } foreach( ProjectTargetItem* item, folder->targetList() ) { if( item->type() == ProjectBaseItem::LibraryTarget ) { visit( dynamic_cast( item ) ); } else if( item->type() == ProjectBaseItem::ExecutableTarget ) { visit( dynamic_cast( item ) ); } } foreach( ProjectFolderItem* item, folder->folderList() ) { if( item->type() == ProjectBaseItem::BuildFolder ) { visit( dynamic_cast( item ) ); } else if( item->type() == ProjectBaseItem::Folder ) { visit( dynamic_cast( item ) ); } } } void ProjectVisitor::visit ( ProjectFileItem* ) { } void ProjectVisitor::visit ( ProjectLibraryTargetItem* lib ) { foreach( ProjectFileItem* item, lib->fileList() ) { visit( item ); } } ProjectVisitor::~ProjectVisitor() { } } #include "projectmodel.moc" diff --git a/project/projectmodel.h b/project/projectmodel.h index f247b1a12b..4ae32fbef6 100644 --- a/project/projectmodel.h +++ b/project/projectmodel.h @@ -1,369 +1,371 @@ /* This file is part of KDevelop Copyright 2005 Roberto Raggi Copyright 2007 Andreas Pakulat Copyright 2007 Aleix Pol This library 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 library 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 Library General Public License for more details. You should have received a copy of the GNU Library General Public License along with this library; see the file COPYING.LIB. If not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #ifndef KDEVPROJECTMODEL_H #define KDEVPROJECTMODEL_H #include #include "projectexport.h" #include #include template struct QPair; template class QList; namespace KDevelop { class IProject; class ProjectFolderItem; class ProjectBuildFolderItem; class ProjectFileItem; class ProjectTargetItem; class ProjectExecutableTargetItem; class ProjectLibraryTargetItem; class ProjectModel; class KDEVPLATFORMPROJECT_EXPORT ProjectVisitor { public: ProjectVisitor(); virtual ~ProjectVisitor(); virtual void visit( IProject* ); virtual void visit( ProjectBuildFolderItem* ); virtual void visit( ProjectExecutableTargetItem* ); virtual void visit( ProjectFolderItem* ); virtual void visit( ProjectFileItem* ); virtual void visit( ProjectLibraryTargetItem* ); }; /** * Interface that allows a developer to implement the three basic types of * items you would see in a multi-project * \li Folder * \li Project * \li Custom Target * \li Library Target * \li Executable Target * \li File */ class KDEVPLATFORMPROJECT_EXPORT ProjectBaseItem { public: ProjectBaseItem( IProject*, const QString &name, ProjectBaseItem *parent = 0 ); virtual ~ProjectBaseItem(); enum ProjectItemType { BaseItem = 0 /** item is a base item */, BuildFolder = 1 /** item is a buildable folder */, Folder = 2 /** item is a folder */, ExecutableTarget = 3 /** item is an executable target */, LibraryTarget = 4 /** item is a library target */, Target = 5 /** item is a target */, File = 6 /** item is a file */, CustomProjectItemType = 100 /** type which should be used as base for custom types */ }; enum RenameStatus { RenameOk = 0, ExistingItemSameName = 1, ProjectManagerRenameFailed = 2, InvalidNewName = 3 }; /** @returns Returns the project that the item belongs to. */ IProject* project() const; /** @returns If this item is a folder, it returns a pointer to the folder, otherwise returns a 0 pointer. */ virtual ProjectFolderItem *folder() const; /** @returns If this item is a target, it returns a pointer to the target, otherwise returns a 0 pointer. */ virtual ProjectTargetItem *target() const; /** @returns If this item is a file, it returns a pointer to the file, otherwise returns a 0 pointer. */ virtual ProjectFileItem *file() const; /** @returns If this item is a file, it returns a pointer to the file, otherwise returns a 0 pointer. */ virtual ProjectExecutableTargetItem *executable() const; /** @returns Returns a list of the folders that have this object as the parent. */ QList folderList() const; /** @returns Returns a list of the targets that have this object as the parent. */ QList targetList() const; /** @returns Returns a list of the files that have this object as the parent. */ QList fileList() const; virtual bool lessThan( const KDevelop::ProjectBaseItem* ) const; /** @returns the @p row item in the list of children of this item or 0 if there is no such child. */ ProjectBaseItem* child( int row ) const; /** @returns the list of children of this item. */ QList children() const; /** @returns a valid QModelIndex for usage with the model API for this item. */ QModelIndex index() const; /** @returns The parent item if this item has one, else it return 0. */ virtual ProjectBaseItem* parent() const; /** @returns the displayed text of this item. */ QString text() const; /** @returns the row in the list of children of this items parent, or -1. */ int row() const; /** * Allows to change the displayed text of this item. * @param text the new text */ void setText( const QString& text ); /** @returns the number of children of this item, or 0 if there are none. */ int rowCount() const; /** @returns the model to which this item belongs, or 0 if its not associated to a model. */ ProjectModel* model() const; /** * Adds a new child item to this item. */ void appendRow( ProjectBaseItem* item ); /** * Removes and deletes the item at the given @p row if there is one. */ void removeRow( int row ); /** * Removes and deletes the @p count items after the given @p row if there is one. */ void removeRows( int row, int count ); /** * Returns and removes the item at the given @p row if there is one. */ ProjectBaseItem* takeRow( int row ); /** @returns RTTI info, allows to know the type of item */ virtual int type() const; /** @returns a string to pass to KIcon as icon-name suitable to represent this item. */ virtual QString iconName() const; /** * Set the url of this item. * Note this function never renames the item in the project manager or on the filesystem, * it only changes the url and possibly the text nothing else. */ virtual void setUrl( const KUrl& ); /** Get the url of this item (if any) */ KUrl url() const; /** * Renames the item to the new name. * @returns status information wether the renaming succeeded. */ virtual RenameStatus rename( const QString& newname ); /** * Default flags: Qt::ItemIsEnabled | Qt::ItemIsSelectable * * @returns the flags supported by the item */ virtual Qt::ItemFlags flags(); /** * Sets what flags should be returned by ::flags() method. */ void setFlags(Qt::ItemFlags flags); protected: class ProjectBaseItemPrivate* const d_ptr; ProjectBaseItem( ProjectBaseItemPrivate& dd ); void setRow( int row ); void setModel( ProjectModel* model ); private: Q_DECLARE_PRIVATE(ProjectBaseItem) friend class ProjectModel; }; /** * Implementation of the ProjectBaseItem interface that is specific to a * folder */ class KDEVPLATFORMPROJECT_EXPORT ProjectFolderItem: public ProjectBaseItem { public: ProjectFolderItem( IProject*, const KUrl &dir, ProjectBaseItem *parent = 0 ); virtual ~ProjectFolderItem(); virtual void setUrl(const KUrl& ); virtual ProjectFolderItem *folder() const; ///Reimplemented from QStandardItem virtual int type() const; /** Get the folder name, equal to url().fileName() but faster (precomputed) */ QString folderName() const; /** @returns Returns whether this folder directly contains the specified file or folder. */ bool hasFileOrFolder(const QString& name) const; virtual QString iconName() const; virtual RenameStatus rename(const QString& newname); + + void propagateRename( const KUrl& newBase ) const; }; /** * Folder which contains buildable targets as part of a buildable project */ class KDEVPLATFORMPROJECT_EXPORT ProjectBuildFolderItem: public ProjectFolderItem { public: ProjectBuildFolderItem( IProject*, const KUrl &dir, ProjectBaseItem *parent = 0 ); ///Reimplemented from QStandardItem virtual int type() const; virtual QString iconName() const; }; /** * Object which represents a target in a build system. * * This object contains all properties specific to a target. */ class KDEVPLATFORMPROJECT_EXPORT ProjectTargetItem: public ProjectBaseItem { public: ProjectTargetItem( IProject*, const QString &name, ProjectBaseItem *parent = 0 ); ///Reimplemented from QStandardItem virtual int type() const; virtual ProjectTargetItem *target() const; virtual QString iconName() const; }; /** * Object which represents an executable target in a build system. * * This object contains all properties specific to an executable. */ class KDEVPLATFORMPROJECT_EXPORT ProjectExecutableTargetItem: public ProjectTargetItem { public: ProjectExecutableTargetItem( IProject*, const QString &name, ProjectBaseItem *parent = 0 ); virtual ProjectExecutableTargetItem *executable() const; virtual int type() const; virtual KUrl builtUrl() const=0; virtual KUrl installedUrl() const=0; }; /** * Object which represents a library target in a build system. * * This object contains all properties specific to a library. */ class KDEVPLATFORMPROJECT_EXPORT ProjectLibraryTargetItem: public ProjectTargetItem { public: ProjectLibraryTargetItem(IProject* project, const QString &name, ProjectBaseItem *parent = 0 ); virtual int type() const; }; /** * Object which represents a file. */ class KDEVPLATFORMPROJECT_EXPORT ProjectFileItem: public ProjectBaseItem { public: ProjectFileItem( IProject*, const KUrl& file, ProjectBaseItem *parent = 0 ); ~ProjectFileItem(); ///Reimplemented from QStandardItem virtual int type() const; virtual ProjectFileItem *file() const; /** Get the file name, equal to url().fileName() but faster (precomputed) */ QString fileName() const; virtual void setUrl( const KUrl& ); virtual QString iconName() const; virtual RenameStatus rename(const QString& newname); }; /** * Class providing some convenience methods for accessing the project model * @todo: maybe switch to QAbstractItemModel, would make the implementation * for at least the checkbox-behaviour easier */ class KDEVPLATFORMPROJECT_EXPORT ProjectModel: public QAbstractItemModel { Q_OBJECT public: ProjectModel( QObject *parent = 0 ); virtual ~ProjectModel(); void resetModel(); void clear(); void appendRow( ProjectBaseItem* item ); void removeRow( int row ); ProjectBaseItem* takeRow( int row ); QModelIndex pathToIndex(const QStringList& tofetch) const; QStringList pathFromIndex(const QModelIndex& index) const; QModelIndex indexFromItem( const ProjectBaseItem* item ) const; ProjectBaseItem* itemFromIndex( const QModelIndex& ) const; virtual int columnCount( const QModelIndex& parent = QModelIndex() ) const; virtual QVariant data( const QModelIndex& index, int role = Qt::DisplayRole ) const; virtual QModelIndex parent( const QModelIndex& child ) const; virtual int rowCount( const QModelIndex& parent = QModelIndex() ) const; virtual QModelIndex index(int row, int column, const QModelIndex& parent = QModelIndex()) const; virtual bool hasChildren(const QModelIndex& parent = QModelIndex()) const; virtual bool setData(const QModelIndex& index, const QVariant& value, int role = Qt::EditRole); virtual bool insertColumns(int column, int count, const QModelIndex& parent = QModelIndex()); virtual bool insertRows(int row, int count, const QModelIndex& parent = QModelIndex()); virtual Qt::ItemFlags flags(const QModelIndex& index) const; private: class ProjectModelPrivate* const d; friend class ProjectBaseItem; }; KDEVPLATFORMPROJECT_EXPORT QStringList joinProjectBasePath( const QStringList& partialpath, KDevelop::ProjectBaseItem* item ); KDEVPLATFORMPROJECT_EXPORT QStringList removeProjectBasePath( const QStringList& fullpath, KDevelop::ProjectBaseItem* item ); } #endif // KDEVPROJECTMODEL_H