diff options
Diffstat (limited to 'parts/fileview/filetreewidget.cpp')
-rw-r--r-- | parts/fileview/filetreewidget.cpp | 387 |
1 files changed, 387 insertions, 0 deletions
diff --git a/parts/fileview/filetreewidget.cpp b/parts/fileview/filetreewidget.cpp new file mode 100644 index 00000000..e0d7538b --- /dev/null +++ b/parts/fileview/filetreewidget.cpp @@ -0,0 +1,387 @@ +/*************************************************************************** + * Copyright (C) 2001-2002 by Bernd Gehrmann * + * [email protected] * + * Copyright (C) 2003 by Mario Scalas (VCS Support) * + * [email protected] * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + * * + ***************************************************************************/ + +#include "filetreewidget.h" + +#include <qheader.h> +#include <qpainter.h> +#include <qregexp.h> +#include <qstringlist.h> +#include <qcolor.h> + +#include <kdebug.h> +#include <klocale.h> +#include <kpopupmenu.h> +#include <kfileitem.h> +#include <kurl.h> +#include <kaction.h> + +#include "kdevcore.h" +#include "kdevproject.h" +#include "kdevpartcontroller.h" +#include "kdevmainwindow.h" +#include "kdevversioncontrol.h" +#include "domutil.h" +#include "urlutil.h" + +#include "fileviewpart.h" +#include "fileitemfactory.h" +#include "vcsfiletreewidgetimpl.h" +#include "stdfiletreewidgetimpl.h" + +using namespace filetreeview; + +/////////////////////////////////////////////////////////////////////////////// +// class FileTreeViewItem +/////////////////////////////////////////////////////////////////////////////// + +#include <kdeversion.h> + +/////////////////////////////////////////////////////////////////////////////// +// class FileTreeWidget +/////////////////////////////////////////////////////////////////////////////// + +FileTreeWidget::FileTreeWidget( FileViewPart *part, QWidget *parent, KDevVCSFileInfoProvider *infoProvider ) + : KFileTreeView( parent, "filetreewidget" ), m_part( part ), m_rootBranch( 0 ) +{ + kdDebug(9017) << "Requested FileTree for: " << projectDirectory() << endl; + if (versionControl() && infoProvider) + kdDebug(9017) << "Valid VCS directory: " << versionControl()->isValidDirectory( projectDirectory() ) << endl; + + if (infoProvider && versionControl() && versionControl()->isValidDirectory( projectDirectory() )) + m_impl = new VCSFileTreeWidgetImpl( this, infoProvider ); + else + m_impl = new StdFileTreeWidgetImpl( this ); + + //setResizeMode( QListView::LastColumn ); + setSorting( 0 ); + setAllColumnsShowFocus( true ); + setSelectionMode( QListView::Extended ); // Enable multiple items selection by use of Ctrl/Shift + setDragEnabled( false ); + + // Slot connections + connect( this, SIGNAL(executed(QListViewItem*)), this, SLOT(slotItemExecuted(QListViewItem*)) ); + connect( this, SIGNAL(returnPressed(QListViewItem*)), this, SLOT(slotItemExecuted(QListViewItem*)) ); + connect( this, SIGNAL(contextMenu(KListView*, QListViewItem*, const QPoint&)), + this, SLOT(slotContextMenu(KListView*, QListViewItem*, const QPoint&)) ); + // Intercepts KDevelop core signals and VCS notifications (if available) + connect( m_part->project(), SIGNAL( activeDirectoryChanged( const QString&, const QString& ) ), + this, SLOT( changeActiveDirectory( const QString&, const QString& ) ) ); + connect( m_part->project(), SIGNAL( addedFilesToProject( const QStringList & ) ), + this, SLOT( addProjectFiles( const QStringList & ) ) ); + connect( m_part->project(), SIGNAL( removedFilesFromProject( const QStringList & ) ), + this, SLOT( removeProjectFiles( const QStringList & ) ) ); + // Safeguard against VCS plug-in unloading at run-time + connect( m_impl, SIGNAL(implementationInvalidated()), this, SLOT(slotImplementationInvalidated()) ); + + // Hide pattern for files + QDomDocument &dom = *m_part->projectDom(); + QString defaultHidePattern = "*.o,*.lo,CVS"; + QString hidePattern = DomUtil::readEntry( dom, "/kdevfileview/tree/hidepatterns", defaultHidePattern ); + m_hidePatterns = QStringList::split( ",", hidePattern ); +} + +/////////////////////////////////////////////////////////////////////////////// + +FileTreeWidget::~FileTreeWidget() +{ + kdDebug(9017) << "FileTreeWidget::~FileTreeWidget()" << endl; + + QDomDocument &dom = *m_part->projectDom(); + DomUtil::writeEntry( dom, "/kdevfileview/tree/hidepatterns", hidePatterns() ); + +// delete m_impl; +} + +/////////////////////////////////////////////////////////////////////////////// + +void FileTreeWidget::openDirectory( const QString& dirName ) +{ + kdDebug(9017) << "FileTreeWidget::openDirectory(): " + dirName << endl; + + // if we're reloading + if (m_rootBranch) + { + disconnect( m_rootBranch, SIGNAL(populateFinished(KFileTreeViewItem*)), this, SLOT(finishPopulate(KFileTreeViewItem*)) ); + removeBranch( m_rootBranch ); + m_projectFiles.clear(); + } + + addProjectFiles( m_part->project()->allFiles(), true ); + + KURL url = KURL::fromPathOrURL( dirName ); + const QPixmap& pix = KMimeType::mimeType("inode/directory")->pixmap( KIcon::Small ); + + // this is a bit odd, but the order of these calls seems to be important + //FileTreeBranch *b = new FileTreeBranch( this, url, url.prettyURL(), pix ); + FileTreeBranchItem *b = m_impl->branchItemFactory()->makeBranchItem( this, url, url.prettyURL(), pix ); + b->setChildRecurse( false ); + m_rootBranch = addBranch( b ); + m_rootBranch->setOpen( true ); + connect( m_rootBranch, SIGNAL(populateFinished(KFileTreeViewItem*)), this, SLOT(finishPopulate(KFileTreeViewItem*)) ); +} + +/////////////////////////////////////////////////////////////////////////////// + +bool FileTreeWidget::shouldBeShown( KFileTreeViewItem* item ) +{ + FileTreeViewItem * i = static_cast<FileTreeViewItem *>( item ); + return ( i->isDir() || ( (m_impl->showNonProjectFiles() || i->isProjectFile() ) + && !matchesHidePattern( i->url().fileName() ) ) ) ; +} + +/////////////////////////////////////////////////////////////////////////////// + +bool FileTreeWidget::matchesHidePattern(const QString &fileName) +{ + QStringList::ConstIterator it; + for (it = m_hidePatterns.begin(); it != m_hidePatterns.end(); ++it) { + QRegExp re(*it, true, true); + if (re.search(fileName) == 0 && (uint)re.matchedLength() == fileName.length()) + return true; + } + + return false; +} + +/////////////////////////////////////////////////////////////////////////////// + +void FileTreeWidget::hideOrShow() +{ + // This is called the first time the tree branch is expanded + FileTreeViewItem* item = static_cast<FileTreeViewItem*>(firstChild()); + if( !item ) + return; + + // Need to skip the root item (which is the sub-directory) + // i.e. "/home/devmario/src/kdevelop/parts/cvsservice" + item = static_cast<FileTreeViewItem*>( item->firstChild() ); + // Now fill the sub-tree + while (item) + { + item->hideOrShow(); + item = static_cast<FileTreeViewItem*>(item->nextSibling()); + } +} + +void FileTreeWidget::finishPopulate(KFileTreeViewItem* item) +{ + if( item == firstChild() ) + { + changeActiveDirectory( "", m_part->project()->activeDirectory() ); + } +} + +/////////////////////////////////////////////////////////////////////////////// + +void FileTreeWidget::slotItemExecuted( QListViewItem* item ) +{ + if (!item) + return; + + KFileTreeViewItem* ftitem = static_cast<KFileTreeViewItem*>(item); + + if (ftitem->isDir()) + return; + + m_part->partController()->editDocument( ftitem->url() ); +} + +/////////////////////////////////////////////////////////////////////////////// + +void FileTreeWidget::slotContextMenu( KListView *, QListViewItem* item, const QPoint &p ) +{ + kdDebug(9017) << "FileTreeWidget::slotContextMenu(...)" << endl; + + KPopupMenu popup( i18n("File Tree"), this ); + + // If an item is selected, fill the file context with selected files' list + if (item) + { + m_impl->fillPopupMenu( &popup, item ); + FileContext context( m_impl->selectedPathUrls() ); + m_part->core()->fillContextMenu( &popup, &context ); + } + + + popup.exec( p ); +} + +/////////////////////////////////////////////////////////////////////////////// + +QString FileTreeWidget::projectDirectory() +{ + return m_part->project()->projectDirectory(); +} + +/////////////////////////////////////////////////////////////////////////////// + +/** + * @brief Test whether given file (or a directory) is part of this project. + * + * @param fileName or directory to test for presence. + */ +bool FileTreeWidget::isInProject(const QString &fileName) const +{ + return m_projectFiles.contains(fileName); +} + +/////////////////////////////////////////////////////////////////////////////// + +/** + * @brief Add a bunch of files to this project. + * + * Whenever we load a project or user chooses to add a bunch of files using UI, + * we end in this method. + * We merge the list of files already in the project (if any) with the incoming set. + * + * @param fileList + * @param constructing + * + * @see m_projectFiles + */ +void FileTreeWidget::addProjectFiles( QStringList const & fileList, bool constructing ) +{ + kdDebug(9017) << "files added to project: " << fileList << endl; + + QStringList::ConstIterator it; + for ( it = fileList.begin(); it != fileList.end(); ++it ) + { + if( (*it).isEmpty() ) + continue; + kdDebug(9017) << "adding file: " << *it << endl; + const QString file = projectDirectory() + "/" + ( *it ); + if ( !m_projectFiles.contains( file ) ) + { + // We got a new file to add to this project. + // Ensure all the parent directories are part of the project set, too. + QStringList paths = QStringList::split( "/", *it); + paths.pop_back(); + while( !paths.isEmpty() ) + { + // We are adding the directories from longest (the one containing our file), + // to the shortest, measured from root directory of our project. + // Whenever we find out that a directory is already recorded as part of our project, + // we may stop adding, because its parent directories were already added - + // in some previous addition. + QString joinedPaths = paths.join("/"); + if( m_projectFiles.contains( joinedPaths ) ) + break; + m_projectFiles.insert( projectDirectory() + "/" + joinedPaths, true ); + paths.pop_back(); + } + m_projectFiles.insert( file, false ); +// kdDebug(9017) << "file added: " << file << endl; + } + + if ( !constructing ) + { + FileTreeViewItem* item = static_cast<FileTreeViewItem*>(firstChild()); + if( item ) + { + item->setProjectFile( file, true ); + } + } + } +} + +/////////////////////////////////////////////////////////////////////////////// + +void FileTreeWidget::removeProjectFiles( QStringList const & fileList ) +{ + kdDebug(9017) << "files removed from project: " << fileList.count() << endl; + + QStringList::ConstIterator it; + for ( it = fileList.begin(); it != fileList.end(); ++it ) + { + QString file = m_part->project()->projectDirectory() + "/" + ( *it ); + m_projectFiles.remove( file ); + kdDebug(9017) << "file removed: " << file << endl; + + FileTreeViewItem* item = static_cast<FileTreeViewItem*>(firstChild()); + if( item ) + { + item->setProjectFile( file, false ); + } + } +} + +void FileTreeWidget::changeActiveDirectory( const QString& olddir, const QString& newdir ) +{ + FileTreeViewItem* item = static_cast<FileTreeViewItem*>(firstChild()); + if( item ) + { + item->changeActiveDir( projectDirectory() + "/" + olddir, projectDirectory() + "/" + newdir ); + } +} + +/////////////////////////////////////////////////////////////////////////////// + +void FileTreeWidget::applyHidePatterns( const QString &hidePatterns ) +{ + m_hidePatterns = QStringList::split( ",", hidePatterns ); + hideOrShow(); +} + +/////////////////////////////////////////////////////////////////////////////// + +QString FileTreeWidget::hidePatterns() const +{ + return m_hidePatterns.join( "," ); +} + +/////////////////////////////////////////////////////////////////////////////// + +KDevVersionControl *FileTreeWidget::versionControl() const +{ + if (part() && part()->versionControl()) + return part()->versionControl(); + else + return 0; +} + +/////////////////////////////////////////////////////////////////////////////// + +bool FileTreeWidget::showNonProjectFiles() const +{ + return m_impl->showNonProjectFiles(); +} + +/////////////////////////////////////////////////////////////////////////////// + +void FileTreeWidget::slotImplementationInvalidated() +{ + kdDebug(9017) << "FileTreeWidget::slotImplementationInvalidated()" << endl; + + // Destroy old implementation, create the simpler default impl. and + // reload list view + // remove old branch + removeBranch( m_rootBranch ); + m_rootBranch = 0; // avoid openDirectory() trying to release the branch + + // Restore a clean situation for an eventual new & different implementation + /** \FIXME this for-loop should really go in ~FileTreeViewWidgetImpl() but + * it crashes there: here it works :-/ + */ + for (int i=columns()-1; i>=0; --i) + { + kdDebug(9017) << "Removing column: " << i << endl; + removeColumn( i ); + } + + delete m_impl; + m_impl = new StdFileTreeWidgetImpl( this ); + openDirectory( projectDirectory() ); +} + +#include "filetreewidget.moc" |