|
|
|
/***************************************************************************
|
|
|
|
* Copyright (C) 2003 by Mario Scalas *
|
|
|
|
* mario.scalas@libero.it *
|
|
|
|
* *
|
|
|
|
* 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 <tqpainter.h>
|
|
|
|
#include <tqheader.h>
|
|
|
|
#include <tqpopupmenu.h>
|
|
|
|
#include <kxmlguiclient.h>
|
|
|
|
#include <tdeaction.h>
|
|
|
|
#include <tdelocale.h>
|
|
|
|
#include <kdebug.h>
|
|
|
|
#include <tdeversion.h>
|
|
|
|
|
|
|
|
//#include <kdevproject.h>
|
|
|
|
#include <urlutil.h>
|
|
|
|
#include <domutil.h>
|
|
|
|
|
|
|
|
#include "fileviewpart.h"
|
|
|
|
#include "filetreewidget.h"
|
|
|
|
#include "fileitemfactory.h"
|
|
|
|
#include "vcsfiletreewidgetimpl.h"
|
|
|
|
#include "vcscolorsconfigwidget.h"
|
|
|
|
|
|
|
|
using namespace filetreeview;
|
|
|
|
|
|
|
|
///////////////////////////////////////////////////////////////////////////////
|
|
|
|
// class VCSFileTreeViewItem
|
|
|
|
///////////////////////////////////////////////////////////////////////////////
|
|
|
|
|
|
|
|
#define FILENAME_COLUMN 0
|
|
|
|
#define STATUS_COLUMN 1
|
|
|
|
#define WORKREVISION_COLUMN 2
|
|
|
|
#define REPOREVISION_COLUMN 3
|
|
|
|
|
|
|
|
class VCSFileTreeViewItem : public filetreeview::FileTreeViewItem
|
|
|
|
{
|
|
|
|
public:
|
|
|
|
VCSFileTreeViewItem( KFileTreeViewItem* parent, KFileItem* item, KFileTreeBranch* branch, bool pf )
|
|
|
|
: FileTreeViewItem( parent, item, branch, pf ), m_statusColor( &FileViewPart::vcsColors.unknown ) {}
|
|
|
|
VCSFileTreeViewItem( KFileTreeView* parent, KFileItem* item, KFileTreeBranch* branch )
|
|
|
|
: FileTreeViewItem( parent, item, branch ), m_statusColor( &FileViewPart::vcsColors.unknown ) {}
|
|
|
|
virtual void paintCell( TQPainter *p, const TQColorGroup &cg, int column, int width, int alignment )
|
|
|
|
{
|
|
|
|
// paint cell in a different color depending on VCS state
|
|
|
|
TQColorGroup mycg( cg );
|
|
|
|
mycg.setColor( TQColorGroup::Base, *m_statusColor );
|
|
|
|
FileTreeViewItem::paintCell( p, mycg, column, width, alignment );
|
|
|
|
}
|
|
|
|
void setVCSInfo( const VCSFileInfo &info );
|
|
|
|
|
|
|
|
TQString fileName() const { return text( FILENAME_COLUMN ); }
|
|
|
|
TQString workingRev() const { return text( WORKREVISION_COLUMN ); }
|
|
|
|
TQString repositoryRev() const { return text( REPOREVISION_COLUMN ); }
|
|
|
|
TQString status() const { return text( STATUS_COLUMN ); }
|
|
|
|
void setFileName( const TQString &p ) { setText( FILENAME_COLUMN, p ); }
|
|
|
|
void setWorkingRev( const TQString &p ) { setText( WORKREVISION_COLUMN, p ); }
|
|
|
|
void setRepositoryRev( const TQString &p ) { setText( REPOREVISION_COLUMN, p ); }
|
|
|
|
void setStatus( const VCSFileInfo::FileState status );
|
|
|
|
|
|
|
|
private:
|
|
|
|
TQColor *m_statusColor; // cached
|
|
|
|
};
|
|
|
|
|
|
|
|
///////////////////////////////////////////////////////////////////////////////
|
|
|
|
|
|
|
|
void VCSFileTreeViewItem::setVCSInfo( const VCSFileInfo &info )
|
|
|
|
{
|
|
|
|
//setFileName( info.fileName );
|
|
|
|
setRepositoryRev( info.repoRevision );
|
|
|
|
setWorkingRev( info.workRevision );
|
|
|
|
setStatus( info.state );
|
|
|
|
}
|
|
|
|
|
|
|
|
///////////////////////////////////////////////////////////////////////////////
|
|
|
|
|
|
|
|
void VCSFileTreeViewItem::setStatus( const VCSFileInfo::FileState status )
|
|
|
|
{
|
|
|
|
setText( STATUS_COLUMN, VCSFileInfo::state2String( status ) );
|
|
|
|
// Update color too
|
|
|
|
switch (status)
|
|
|
|
{
|
|
|
|
case VCSFileInfo::Added:
|
|
|
|
m_statusColor = &FileViewPart::vcsColors.added;
|
|
|
|
break;
|
|
|
|
case VCSFileInfo::Uptodate:
|
|
|
|
m_statusColor = &FileViewPart::vcsColors.updated;
|
|
|
|
break;
|
|
|
|
case VCSFileInfo::Modified:
|
|
|
|
m_statusColor = &FileViewPart::vcsColors.modified;
|
|
|
|
break;
|
|
|
|
case VCSFileInfo::Conflict:
|
|
|
|
m_statusColor = &FileViewPart::vcsColors.conflict;
|
|
|
|
break;
|
|
|
|
case VCSFileInfo::Sticky:
|
|
|
|
m_statusColor = &FileViewPart::vcsColors.sticky;
|
|
|
|
break;
|
|
|
|
case VCSFileInfo::NeedsCheckout:
|
|
|
|
m_statusColor = &FileViewPart::vcsColors.needsCheckout;
|
|
|
|
break;
|
|
|
|
case VCSFileInfo::NeedsPatch:
|
|
|
|
m_statusColor = &FileViewPart::vcsColors.needsPatch;
|
|
|
|
break;
|
|
|
|
case VCSFileInfo::Unknown:
|
|
|
|
m_statusColor = &FileViewPart::vcsColors.unknown;
|
|
|
|
break;
|
|
|
|
case VCSFileInfo::Directory:
|
|
|
|
default:
|
|
|
|
// No color change
|
|
|
|
m_statusColor = &FileViewPart::vcsColors.defaultColor;
|
|
|
|
//kdDebug() << "MyFileTreeViewItem::paintCell(): Unknown color!" << endl;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
///////////////////////////////////////////////////////////////////////////////
|
|
|
|
// class VCSFileTreeBranchItem
|
|
|
|
///////////////////////////////////////////////////////////////////////////////
|
|
|
|
|
|
|
|
class VCSFileTreeBranchItem : public filetreeview::FileTreeBranchItem
|
|
|
|
{
|
|
|
|
public:
|
|
|
|
VCSFileTreeBranchItem( KFileTreeView* view, const KURL& url, const TQString& name, const TQPixmap& pix,
|
|
|
|
KDevVCSFileInfoProvider *vcsInfoProvider )
|
|
|
|
: FileTreeBranchItem( view, url, name, pix ), m_vcsInfoProvider( vcsInfoProvider ) {}
|
|
|
|
// virtual ~VCSFileTreeBranchItem() {}
|
|
|
|
virtual KFileTreeViewItem* createTreeViewItem( KFileTreeViewItem* parent, KFileItem* fileItem );
|
|
|
|
|
|
|
|
private:
|
|
|
|
KDevVCSFileInfoProvider *m_vcsInfoProvider;
|
|
|
|
};
|
|
|
|
|
|
|
|
///////////////////////////////////////////////////////////////////////////////
|
|
|
|
|
|
|
|
KFileTreeViewItem* VCSFileTreeBranchItem::createTreeViewItem( KFileTreeViewItem* parent, KFileItem* fileItem )
|
|
|
|
{
|
|
|
|
// kdDebug(9017) << "MyFileTreeBranch::createTreeViewItem(): " + fileItem->url().path() << endl;
|
|
|
|
if (!parent || !fileItem)
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
FileTreeWidget *lv = static_cast<filetreeview::FileTreeViewItem*>( parent )->listView();
|
|
|
|
const KURL fileURL = fileItem->url();
|
|
|
|
const bool isDirectory = lv->isInProject( fileURL.path() );
|
|
|
|
|
|
|
|
VCSFileTreeViewItem *newItem = new VCSFileTreeViewItem( parent, fileItem, this, isDirectory );
|
|
|
|
|
|
|
|
// TQString fileName = fileURL.fileName();
|
|
|
|
// TQString dirName = URLUtil::extractPathNameRelative( lv->projectDirectory(), fileURL.directory() );
|
|
|
|
|
|
|
|
// const VCSFileInfoMap &vcsFiles = *m_vcsInfoProvider->status( dirName );
|
|
|
|
// kdDebug(9017) << "Dir has " << vcsFiles.count() << " registered files!" << endl;
|
|
|
|
// if (vcsFiles.contains( fileName ))
|
|
|
|
// newItem->setVCSInfo( vcsFiles[ fileName ] );
|
|
|
|
// else
|
|
|
|
// kdDebug(9017) << "!!!No VCS info for this file!!!" << endl;
|
|
|
|
return newItem;
|
|
|
|
}
|
|
|
|
|
|
|
|
///////////////////////////////////////////////////////////////////////////////
|
|
|
|
// class VCSFileItemFactory
|
|
|
|
///////////////////////////////////////////////////////////////////////////////
|
|
|
|
|
|
|
|
class VCSBranchItemFactory : public filetreeview::BranchItemFactory
|
|
|
|
{
|
|
|
|
public:
|
|
|
|
VCSBranchItemFactory( KDevVCSFileInfoProvider *vcsInfoProvider ) : m_vcsInfoProvider( vcsInfoProvider ) {}
|
|
|
|
virtual filetreeview::FileTreeBranchItem *makeBranchItem( KFileTreeView* view, const KURL& url, const TQString& name, const TQPixmap& pix )
|
|
|
|
{
|
|
|
|
return new VCSFileTreeBranchItem( view, url, name, pix, m_vcsInfoProvider );
|
|
|
|
}
|
|
|
|
private:
|
|
|
|
KDevVCSFileInfoProvider *m_vcsInfoProvider;
|
|
|
|
};
|
|
|
|
|
|
|
|
///////////////////////////////////////////////////////////////////////////////
|
|
|
|
// class VCSFileTreeWidgetImpl
|
|
|
|
///////////////////////////////////////////////////////////////////////////////
|
|
|
|
|
|
|
|
VCSFileTreeWidgetImpl::VCSFileTreeWidgetImpl( FileTreeWidget *parent, KDevVCSFileInfoProvider *infoProvider )
|
|
|
|
: FileTreeViewWidgetImpl( parent, "vcsfiletreewidgetimpl" ),
|
|
|
|
m_actionToggleShowVCSFields( 0 ), m_actionSyncWithRepository( 0 ), m_vcsInfoProvider( infoProvider ),
|
|
|
|
m_isSyncingWithRepository( false ), m_vcsStatusRequestedItem( 0 )
|
|
|
|
{
|
|
|
|
kdDebug(9017) << "VCSFileTreeWidgetImpl::VCSFileTreeWidgetImpl()" << endl;
|
|
|
|
|
|
|
|
Q_ASSERT( m_vcsInfoProvider );
|
|
|
|
setBranchItemFactory( new VCSBranchItemFactory( m_vcsInfoProvider ) );
|
|
|
|
|
|
|
|
// Update the #define order on top if you change this order!
|
|
|
|
parent->addColumn( "Filename" );
|
|
|
|
parent->addColumn( "Status" );
|
|
|
|
parent->addColumn( "Work" );
|
|
|
|
parent->addColumn( "Repo" );
|
|
|
|
|
|
|
|
connect( m_vcsInfoProvider, TQT_SIGNAL(statusReady(const VCSFileInfoMap&, void *)),
|
|
|
|
this, TQT_SLOT(vcsDirStatusReady(const VCSFileInfoMap&, void*)) );
|
|
|
|
// Harakiri itself if the infoProvider object is destroyed since we cannot work anymore :-(
|
|
|
|
connect( m_vcsInfoProvider, TQT_SIGNAL(destroyed()), TQT_SIGNAL(implementationInvalidated()) );
|
|
|
|
|
|
|
|
m_actionToggleShowVCSFields = new TDEToggleAction( i18n("Show VCS Fields"), TDEShortcut(),
|
|
|
|
this, "actiontoggleshowvcsfieldstoggleaction" );
|
|
|
|
m_actionToggleShowVCSFields->setCheckedState(i18n("Hide VCS Fields"));
|
|
|
|
TQString aboutAction = i18n("<b>Show VCS fields</b><p>Shows <b>Revision</b> and <b>Timestamp</b> for each file contained in VCS repository.");
|
|
|
|
m_actionToggleShowVCSFields->setWhatsThis( aboutAction );
|
|
|
|
connect( m_actionToggleShowVCSFields, TQT_SIGNAL(toggled(bool)), this, TQT_SLOT(slotToggleShowVCSFields(bool)) );
|
|
|
|
|
|
|
|
m_actionSyncWithRepository = new TDEAction( i18n( "Sync with Repository"), TDEShortcut(),
|
|
|
|
this, TQT_SLOT(slotSyncWithRepository()), this, "actionsyncwithrepository" );
|
|
|
|
aboutAction = i18n("<b>Sync with repository</b><p>Synchronize file status with remote repository.");
|
|
|
|
m_actionSyncWithRepository->setWhatsThis( aboutAction );
|
|
|
|
|
|
|
|
TQDomDocument &dom = projectDom();
|
|
|
|
m_actionToggleShowVCSFields->setChecked( DomUtil::readBoolEntry(dom, "/kdevfileview/tree/showvcsfields") );
|
|
|
|
slotToggleShowVCSFields( showVCSFields() ); // show or hide fields depending on read settings
|
|
|
|
connect( parent, TQT_SIGNAL(expanded(TQListViewItem*)), this, TQT_SLOT(slotDirectoryExpanded(TQListViewItem*)));
|
|
|
|
}
|
|
|
|
|
|
|
|
///////////////////////////////////////////////////////////////////////////////
|
|
|
|
|
|
|
|
VCSFileTreeWidgetImpl::~VCSFileTreeWidgetImpl()
|
|
|
|
{
|
|
|
|
kdDebug(9017) << "VCSFileTreeWidgetImpl::~VCSFileTreeWidgetImpl()" << endl;
|
|
|
|
|
|
|
|
TQDomDocument &dom = projectDom();
|
|
|
|
DomUtil::writeBoolEntry( dom, "/kdevfileview/tree/showvcsfields", showVCSFields() );
|
|
|
|
}
|
|
|
|
|
|
|
|
///////////////////////////////////////////////////////////////////////////////
|
|
|
|
|
|
|
|
bool VCSFileTreeWidgetImpl::canReloadTree() const
|
|
|
|
{
|
|
|
|
return !m_isSyncingWithRepository;
|
|
|
|
}
|
|
|
|
|
|
|
|
///////////////////////////////////////////////////////////////////////////////
|
|
|
|
|
|
|
|
void VCSFileTreeWidgetImpl::fillPopupMenu( TQPopupMenu *popupMenu, TQListViewItem *item ) const
|
|
|
|
{
|
|
|
|
FileTreeViewWidgetImpl::fillPopupMenu( popupMenu, item );
|
|
|
|
|
|
|
|
// Submenu for visualization options
|
|
|
|
m_actionToggleShowVCSFields->plug( popupMenu );
|
|
|
|
// Give a change for syncing status with remote repository: a file info provider must
|
|
|
|
// be available and the item must be a project directory
|
|
|
|
FileTreeViewItem *fileItem = static_cast<FileTreeViewItem *>( item );
|
|
|
|
if (fileItem->isDir())
|
|
|
|
{
|
|
|
|
m_vcsStatusRequestedItem = fileItem;
|
|
|
|
popupMenu->insertSeparator();
|
|
|
|
m_actionSyncWithRepository->plug( popupMenu );
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
///////////////////////////////////////////////////////////////////////////////
|
|
|
|
|
|
|
|
void VCSFileTreeWidgetImpl::slotToggleShowVCSFields( bool checked )
|
|
|
|
{
|
|
|
|
kdDebug(9017) << "VCSFileTreeWidgetImpl::slotToggleShowVCSFields()" << endl;
|
|
|
|
|
|
|
|
if (checked)
|
|
|
|
{
|
|
|
|
setColumnWidth( 0, contentsWidth() / 2 ); // "Filename"
|
|
|
|
setColumnWidth( 1, contentsWidth() / 4 ); // "status"
|
|
|
|
setColumnWidth( 2, contentsWidth() / 5 ); // "work revision"
|
|
|
|
setColumnWidth( 3, contentsWidth() / 5 ); // "repository revision"
|
|
|
|
header()->show();
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
setColumnWidth( 3 ,0 ); // Hide columns
|
|
|
|
setColumnWidth( 2 ,0 );
|
|
|
|
setColumnWidth( 1, 0 );
|
|
|
|
setColumnWidth( 0, contentsWidth() ); // Make the "Filename" column to occupy all the row
|
|
|
|
header()->hide();
|
|
|
|
}
|
|
|
|
|
|
|
|
triggerUpdate();
|
|
|
|
}
|
|
|
|
|
|
|
|
///////////////////////////////////////////////////////////////////////////////
|
|
|
|
|
|
|
|
bool VCSFileTreeWidgetImpl::showVCSFields() const
|
|
|
|
{
|
|
|
|
return m_actionToggleShowVCSFields->isChecked();
|
|
|
|
}
|
|
|
|
|
|
|
|
///////////////////////////////////////////////////////////////////////////////
|
|
|
|
|
|
|
|
void VCSFileTreeWidgetImpl::vcsDirStatusReady( const VCSFileInfoMap &modifiedFiles, void *callerData )
|
|
|
|
{
|
|
|
|
kdDebug(9017) << "VCSFileTreeWidgetImpl::vcsDirStatusReady(const VCSFileInfoMap &, void*)" << endl;
|
|
|
|
|
|
|
|
VCSFileTreeViewItem *item = static_cast<VCSFileTreeViewItem*>( callerData );
|
|
|
|
// Q_ASSERT( item ); // this must _not_ fail!
|
|
|
|
if( !item ){
|
|
|
|
kdDebug(9017) << "static_cast<VCSFileTreeViewItem*>( callerData ) failed" << endl;
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
// Update vcs file info for all childs in this tree folder ...
|
|
|
|
item = static_cast<VCSFileTreeViewItem*>( item->firstChild() );
|
|
|
|
while (item)
|
|
|
|
{
|
|
|
|
const TQString fileName = item->fileName();
|
|
|
|
kdDebug(9017) << "Widget item filename is: " << fileName << endl;
|
|
|
|
if (modifiedFiles.contains( fileName ))
|
|
|
|
{
|
|
|
|
const VCSFileInfo &vcsInfo = modifiedFiles[ fileName ];
|
|
|
|
kdDebug(9017) << "Nice! Found info for this file: " << vcsInfo.toString() << endl;
|
|
|
|
item->setVCSInfo( modifiedFiles[ fileName ] );
|
|
|
|
}
|
|
|
|
else
|
|
|
|
kdDebug(9017) << "Map does not contain anything useful about this file ;-( " << fileName << endl;
|
|
|
|
item = static_cast<VCSFileTreeViewItem*>( item->nextSibling() );
|
|
|
|
}
|
|
|
|
triggerUpdate();
|
|
|
|
|
|
|
|
m_isSyncingWithRepository = false;
|
|
|
|
}
|
|
|
|
|
|
|
|
///////////////////////////////////////////////////////////////////////////////
|
|
|
|
|
|
|
|
void VCSFileTreeWidgetImpl::slotSyncWithRepository()
|
|
|
|
{
|
|
|
|
kdDebug(9017) << "VCSFileTreeWidgetImpl::slotSyncWithRepository()" << endl;
|
|
|
|
const VCSFileTreeViewItem *myFileItem = static_cast<VCSFileTreeViewItem *>( m_vcsStatusRequestedItem );
|
|
|
|
const TQString relDirPath = URLUtil::extractPathNameRelative( projectDirectory(), myFileItem->fileItem()->url().path() );
|
|
|
|
kdDebug(9017) << "VCS Info requested for: " << relDirPath << endl;
|
|
|
|
m_vcsInfoProvider->requestStatus( relDirPath, m_vcsStatusRequestedItem );
|
|
|
|
m_isSyncingWithRepository = true;
|
|
|
|
}
|
|
|
|
|
|
|
|
///////////////////////////////////////////////////////////////////////////////
|
|
|
|
|
|
|
|
void VCSFileTreeWidgetImpl::slotDirectoryExpanded( TQListViewItem* aItem )
|
|
|
|
{
|
|
|
|
VCSFileTreeViewItem *item = static_cast<VCSFileTreeViewItem *>( aItem );
|
|
|
|
if( !item ) return;
|
|
|
|
|
|
|
|
const TQString relDirPath = URLUtil::extractPathNameRelative( projectDirectory(), item->fileItem()->url().path() );
|
|
|
|
kdDebug(9017) << "ASync VCS Info requested for: " << relDirPath << endl;
|
|
|
|
m_vcsInfoProvider->requestStatus( relDirPath, item, false, false );
|
|
|
|
|
|
|
|
// m_isSyncingWithRepository = true;
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
#include "vcsfiletreewidgetimpl.moc"
|