/****************************************************************************
**
** Copyright (C) 1999-2006 Frank Hemer <frank@hemer.org>,
** Tilo Riemer <riemer@crossvc.com>,
** Wim Delvaux <wim.delvaux@chello.be>,
** Jose Hernandez <joseh@tesco.net>,
** Helmut Koll <HelmutKoll@web.de>,
** Tom Mishima <tmishima@mail.at-m.or.jp>,
** Joerg Preiss <auba@auba.de>
**
**
**----------------------------------------------------------------------------
**
**----------------------------------------------------------------------------
**
** CrossVC is available under two different licenses:
**
** If CrossVC is linked against the GPLed version of Qt
** CrossVC is released under the terms of GPL also.
**
** If CrossVC is linked against a nonGPLed version of Qt
** CrossVC is released under the terms of the
** CrossVC License for non-Unix platforms (CLNU)
**
**
** CrossVC License for non-Unix platforms (CLNU):
**
** Redistribution and use in binary form, without modification,
** are permitted provided that the following conditions are met:
**
** 1. Redistributions in binary form must reproduce the above copyright
** notice, this list of conditions and the following disclaimer in the
** documentation and/or other materials provided with the distribution.
** 2. It is not permitted to distribute the binary package under a name
** different than CrossVC.
** 3. The name of the authors may not be used to endorse or promote
** products derived from this software without specific prior written
** permission.
** 4. The source code is the creative property of the authors.
** Extensions and development under the terms of the Gnu Public License
** are limited to the Unix platform. Any distribution or compilation of
** the source code against libraries licensed other than gpl requires
** the written permission of the authors.
**
**
** THIS SOFTWARE IS PROVIDED BY THE AUTHOR "AS IS" AND ANY EXPRESS OR
** IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
** WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
** ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
** DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
** DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
** GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
** INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
** WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
** NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
** SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
**
**
**
** CrossVC License for Unix platforms:
**
** 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, version 2 of the License.
** 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 version 2 for more details.
**
** You should have received a copy of the GNU General Public License
** along with this program; if not, write to the Free Software Foundation,
** Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
**
*****************************************************************************/
#include <qapplication.h>
#include <qdir.h>
#include <qfile.h>
#include <qfileinfo.h>
#include <qdatetime.h>
#include <qstringlist.h>
#include <qdict.h>
#include <qregexp.h>
#include <qsignal.h>
#include <qpainter.h>
#include <assert.h>
#include "config.h"
#include "directory.h"
#include "CvsDirectory.h"
#include "globals.h"
#include "filesubr.h"
#include "ccvscommand.h"
#include "cvslistview.h"
#include "noncvslistview.h"
#include "cvsignorelistview.h"
#include "pixmapcache.h"
#include "CCvsOutput.h"
#include "LinCVSLog.h"
#define DIRECTORY 123456
//----------------------------------------------------------------------------
void EntryState::setState( EntryStates newState ) {
// printf("\nfile: %s, state: %i, newstate: %i\n",m_fileName.ascii(),m_state,newState);
if (m_state==newState) return;
m_state = newState;
if (newState>myDirectory->get_ES_Max()) myDirectory->set_ES_Max(newState);
else if (newState<myDirectory->get_ES_Max()) myDirectory->calc_ES_Max();
// bubble up
myDirectory->setDirState( newState );
}
//============================================================================
const bool Directory::VIRTUAL = true;
GuardedDir Directory::s_activeDir = NULL;
QObject * Directory::s_control = NULL;
QListView * Directory::s_topView = NULL;
ColorTabWidget * Directory::s_pListView = NULL;
QPopupMenu * Directory::s_fileMenu = NULL;
CvsListView * Directory::s_FileListView = NULL;
NonCvsListView * Directory::s_NonFileListView = NULL;
CvsIgnoreListView * Directory::s_IgnoreFileListView = NULL;
//----------------------------------------------------------------------------
void Directory::initialize( const QObject * control,
QListView * workBench,
ColorTabWidget * listView,
QPopupMenu * menu,
CvsListView * fileListView,
NonCvsListView * nonFileListView,
CvsIgnoreListView * ignoreFileListView) {
s_control = const_cast<QObject *>(control);
s_topView = workBench;
s_pListView = listView;
s_fileMenu = menu;
s_FileListView = fileListView;
s_NonFileListView = nonFileListView;
s_IgnoreFileListView = ignoreFileListView;
}
// helps creating fast hash-tables
const unsigned int Directory::nextPrime( unsigned int i) {
switch( i) {
case 0: return 19;
case 19: return 41;
case 41: return 79;
case 79: return 157;
case 157: return 311;
case 311: return 619;
case 619: return 1249;
case 1249: return 2503;
case 2503: return 4999;
case 4999: return 9973;
default: return i*2+1;
}
}
//----------------------------------------------------------------------------
bool Directory::setEntryState(QString &fileName, EntryStates stateId) {
EntryState *entry;
if (!(entry = m_entries.find(fileName))) return false;
entry->setState(stateId);
if (Debug::g_pLog) {
QString msg = m_fullName+" changing EntryState: ";
msg += fileName;
msg += ", state: "+QString::number(stateId);
Debug::g_pLog->log(Debug::LL_GOSSIP_MONGER, msg);
}
return true;
}
//----------------------------------------------------------------------------
void Directory::removeEntry(QString &fileName) {
m_entries.remove(fileName);
if (Debug::g_pLog) {
QString msg = m_fullName+" removing EntryState: ";
msg += fileName;
Debug::g_pLog->log(Debug::LL_GOSSIP_MONGER, msg);
}
}
//----------------------------------------------------------------------------
void Directory::appendEntry(QString &key, EntryState *entry) {
if (m_entries.size() <= m_entries.count()) m_entries.resize( nextPrime(m_entries.size()));
m_entries.insert(key,entry);
if (entry->state()>m_curStateMax) m_curStateMax=entry->state();
if (Debug::g_pLog) {
QString msg = m_fullName+" appending EntryState: ";
msg += key;
msg += ", state: "+QString::number(entry->state());
Debug::g_pLog->log(Debug::LL_GOSSIP_MONGER, msg);
}
}
//----------------------------------------------------------------------------
//top level dir
Directory::Directory(QStringList)
: DirBase(s_topView),
m_tabIdx(0),
m_pFileListView(NULL),
m_pNonFileListView(NULL),
m_pIgnoreFileListView(NULL),
m_subProjectList(NULL),
m_lastHScrollBarValue(0),
m_lastVScrollBarValue(0)
{
m_topDir = this;
m_isSubProjectRoot = true;
m_virtual = false;
m_pDirectorySuicide = new QSignal(this);
m_pDirectorySuicide->connect(s_control,SLOT(slot_requestDirectorySuicide(const QVariant&)));
m_pFileContentsChanged = new QSignal(this);
m_pFileContentsChanged->connect(s_control,SLOT(setDirMenu()));
}
//----------------------------------------------------------------------------
//subdir
Directory::Directory( QListViewItem * parent,
bool virtualDir)
: DirBase( parent ),
m_tabIdx(0),
m_pFileListView(NULL),
m_pNonFileListView(NULL),
m_pIgnoreFileListView(NULL),
m_subProjectList( NULL),
m_pDirectorySuicide( NULL),
m_lastHScrollBarValue(0),
m_lastVScrollBarValue(0)
{
m_pFileContentsChanged = new QSignal(this);
m_pFileContentsChanged->connect(s_control,SLOT(setDirMenu()));
m_topDir = dyncast_dir(dyncast_dir(parent)->topDir());
m_isSubProjectRoot = false;
m_virtual = virtualDir;
}
//----------------------------------------------------------------------------
Directory::~Directory() {
releaseMonitoredDir(this);
}
//----------------------------------------------------------------------------
const int Directory::checkType(const QString path) {
if (QFileInfo(path+"CVS").exists()) return Cvs;
else return Plain;
}
//----------------------------------------------------------------------------
//top level dir
Directory * Directory::createInstance(const QString& fileName)
{
QString path = fileName;
if(path.length() > 1){//is not root
path += "/";
}
switch(checkType(path)) {
case Cvs: {
return new CvsDirectory(NULL,fileName);
}
case Plain: {
Directory * dir = new Directory(NULL);
s_topView->setUpdatesEnabled(FALSE);
dir->init(fileName);
s_topView->setUpdatesEnabled(TRUE);
s_topView->triggerUpdate();
return dir;
}
default: {
assert(false);
}
}
return 0; // makes the compiler happy
}
//----------------------------------------------------------------------------
//subdir
Directory * Directory::createChildInstance( QListViewItem * parent,
const QString& fileName,
bool virtualDir)
{
QString path = fileName;
if(path.length() > 1){//is not root
path += "/";
}
switch(checkType(path)) {
case Cvs: {
return new CvsDirectory(parent,fileName,virtualDir);
}
case Plain: {
Directory * dir = new Directory(parent,virtualDir);
bool update;
if (update = dir->s_topView->isUpdatesEnabled()) {
dir->s_topView->setUpdatesEnabled(FALSE);
}
dir->init(fileName);
if (update) {
dir->s_topView->setUpdatesEnabled(TRUE);
dir->s_topView->triggerUpdate();
}
return dir;
}
default: {
assert(false);
}
}
return 0; // makes the compiler happy
}
//----------------------------------------------------------------------------
Directory * Directory::createChild( const QString& fileName, bool virtualDir) {
Directory * dir = new Directory(this,virtualDir);
bool update;
if (update = dir->s_topView->isUpdatesEnabled()) {
dir->s_topView->setUpdatesEnabled(FALSE);
}
dir->init(fileName);
if (update) {
dir->s_topView->setUpdatesEnabled(TRUE);
dir->s_topView->triggerUpdate();
}
return dir;
}
//----------------------------------------------------------------------------
int Directory::compare ( QListViewItem * item, int row, bool ascending) const {
int ret = QString::localeAwareCompare(text(row).lower(),item->text(row).lower());
if (ret != 0) return ret;
else return QListViewItem::compare(item,row,ascending);
}
//----------------------------------------------------------------------------
int Directory::rtti() const {
return DIRECTORY;
}
//----------------------------------------------------------------------------
Directory * Directory::parent() const{
if (QListViewItem::parent() && (QListViewItem::parent()->rtti() >= DIRECTORY)) {
return static_cast<Directory*>(QListViewItem::parent());
} else return NULL;
}
//----------------------------------------------------------------------------
Directory * Directory::firstChild() {
QListViewItem * lvi = QListViewItem::firstChild();
while ( lvi && (lvi->rtti() < DIRECTORY) ) {
lvi = lvi->nextSibling();
}
return static_cast<Directory *>(lvi);
}
//----------------------------------------------------------------------------
Directory * Directory::nextSibling() {
QListViewItem * lvi = QListViewItem::nextSibling();
while ( lvi && (lvi->rtti() < DIRECTORY) ) {
lvi = lvi->nextSibling();
}
return static_cast<Directory *>(lvi);
}
//----------------------------------------------------------------------------
Directory * Directory::dyncast_dir(QListViewItem * lvi) {
if ( lvi && (lvi->rtti() >= DIRECTORY) ) return static_cast<Directory *>(lvi);
else return NULL;
}
//----------------------------------------------------------------------------
void Directory::activateItem(bool resetCache, int tab /*=7*/)
{
// qDebug("activateItem("+QString(resetCache ? "true" : "false")+")");
if (static_cast<CvsDirListView*>(s_topView)->validate(s_activeDir)) {
s_activeDir->saveViewPort();
}
bool dirChanged = (this != (DirBase *)s_activeDir);
s_activeDir = this;
CFileListView * lv = static_cast<CFileListView*>(s_pListView->page(m_tabIdx));
assert(lv);
bool update = (lv->isUpdatable());
if (update) lv->setUpdatable(false);
if (tab) {
if (tab & Controled) {
m_pFileListView->clear();
m_pFileListView->setColumnWidth(0,100);
m_pFileListView->setColumnWidth(1,100);
m_pFileListView->setColumnWidth(2,50);
m_pFileListView->setColumnWidth(3,50);
m_pFileListView->setColumnWidth(4,50);
m_pFileListView->setColumnWidth(5,100);
m_pFileListView->setColumnWidth(6,100);
m_pFileListView->setCurAbsPath(m_fullName);
}
if (tab & NonControled) {
m_pNonFileListView->clear();
m_pNonFileListView->setColumnWidth(0,100);
m_pNonFileListView->setColumnWidth(1,100);
m_pNonFileListView->setCurAbsPath(m_fullName);
}
if (tab & Ignored) {
m_pIgnoreFileListView->clear();
m_pIgnoreFileListView->setColumnWidth(0,100);
m_pIgnoreFileListView->setColumnWidth(1,100);
m_pIgnoreFileListView->setCurAbsPath(m_fullName);
}
if (!resetCache) isModified();//reset modified flag to prevent double checking on next checkStatus()
if (!m_disabled) {//don't activate if disabled
qApp->setOverrideCursor(waitCursor); // takes some time on huge dirs
checkAndShowStatus(NULL,false,tab,resetCache);
qApp->restoreOverrideCursor();
}
m_pNonFileListView->signalState();
QListViewItem *item = NULL;
for ( QStringList::Iterator it = m_selectedList.begin(); it != m_selectedList.end(); ++it ) {
item = lv->findItem(*it,0);
if (item) item->setSelected(true);
}
if (item) lv->setCurrentItem(item);
} else {
m_pNonFileListView->signalState();
}
s_pListView->setCurrentPage(m_tabIdx);
if (update) {
m_pFileContentsChanged->setValue(true);
m_pFileContentsChanged->activate();
if (dirChanged) lv->setUpdatable(true);
lv->horizontalScrollBar()->setValue(m_lastHScrollBarValue);
lv->verticalScrollBar()->setValue(m_lastVScrollBarValue);
if (!dirChanged) lv->setUpdatable(true);
}
}
//----------------------------------------------------------------------------
void Directory::saveViewPort() {
m_tabIdx = s_pListView->currentPageIndex();
CFileListView * lv = s_pListView->currentPage();
m_lastHScrollBarValue = lv->horizontalScrollBar()->value();
m_lastVScrollBarValue = lv->verticalScrollBar()->value();
m_selectedList.clear();
QListViewItem * myChild = lv->firstChild();
while(myChild) {
if (myChild->isSelected()) m_selectedList.append(myChild->text(0));
myChild = myChild->nextSibling();
}
}
//----------------------------------------------------------------------------
void Directory::init(const QString& fileName)
{
m_isControlledDir = false;
m_hasControlledSubDir = false;
m_isAnalyzedDir = false;
m_activatingIsNecessary = true;
m_pFileListView = s_FileListView;
m_pNonFileListView = s_NonFileListView;
m_pIgnoreFileListView = s_IgnoreFileListView;
m_fullName = fileName;
m_readable = QDir(m_fullName).isReadable();
m_entries.setAutoDelete(true);
m_entries = QDict<EntryState>(nextPrime(0));
m_ignoreFiles = QDict<bool>(nextPrime(0));
m_ignoreFiles.setAutoDelete(true);
m_nonFiles = QDict<bool>(nextPrime(0));
m_nonFiles.setAutoDelete(true);
m_curState = ES_unknown;
m_port = -1;
m_isAutoUpdate = FALSE;
m_dirTag = QString::null;
setStatusText(fileName);
if(m_fullName.length() == 1) {//root
setText(0, m_fullName);
} else {
setText(0, QFileInfo( m_fullName ).fileName() );
}
// init global state variables
m_curStateMax = ES_probably_up_to_date;
m_curDirStateMax = ES_probably_up_to_date;
//check for CVS/ directory
m_isControlledDir = checkDirForControl();
//check for being a sub project and adapt disabledList
if (m_isSubProjectRoot) {
int au = 0;
QString subProjectName = relativeName();
projectSettings->get(subProjectName,DISABLED,m_disabledList);
projectSettings->get(subProjectName,PAUTOUPDATE,au);
if (AUTOUPDATE && (au>0) ) {
m_isAutoUpdate = true;
m_topDir->setAutoUpdate(true);
}
}
// clear directory
setDirState( ES_probably_up_to_date );
bool dontAnalyze = false;
if (m_virtual) {
m_disabled = false;
setDirState(ES_missing_dir);
dontAnalyze = true;
} else if (!m_readable ) {
m_disabled = true;
dontAnalyze = true;
} else if ( getDisabled(m_fullName) ) {
m_disabled = true;
Directory *hlp = parent();
if (hlp) hlp->setDirState(ES_unknown,true); // reset state in dir-hierarchy
dontAnalyze = true;
}
if (dontAnalyze) {
setDirIcon();
return;
}
QFileInfo fInfo(m_fullName);
if (fInfo.exists()) {
m_lastModTimeOfDir = fInfo.lastModified();
m_lastCallTime = m_lastModTimeOfDir;
}
m_disabled = false;
m_hasDSTBug = hasDSTBug(&m_fullName);
qApp->processEvents(1);
if(!globalStopAction){
if ( !((depth() >= 1) && (ONTHEFLYSCANNING)) ) {
analyzeDirs();
}
if (m_isControlledDir) {
addMonitoredDir(this);
}
}
setDirIcon();
}
//----------------------------------------------------------------------------
void Directory::setOpen( bool open) {
QString removed;
setOpen(open,removed);
}
//----------------------------------------------------------------------------
void Directory::setOpen( bool open, QString &removed) {
bool update;
if (update = s_topView->isUpdatesEnabled()) {
s_topView->setUpdatesEnabled(FALSE);
}
removed = "";
if (ONTHEFLYSCANNING && open) {
QApplication::setOverrideCursor(waitCursor);
Directory * C = firstChild();
while( C ) {
if ( (!C->m_isAnalyzedDir) && (!C->m_disabled)) {
C->analyzeDirs();
if (!C->isControlledTree() && !C->isVirtual() && (C->childCount() == 0) ) {
Directory * tmp = C->nextSibling();
delete C;
C = tmp;
continue;
}
}
C = C->nextSibling();
}
if (!isControlledTree() && !isVirtual() && (childCount() == 0)) {//can't kill myself -- so call cvscontrol to sync with the event loop
Directory * tmp = this;
while (tmp->parent() &&
!(tmp->parent()->isControlledTree()) &&
(tmp->parent()->childCount() == 1) &&
(tmp->parent() != m_topDir) ) {
tmp = tmp->parent();
}
m_topDir->m_pDirectorySuicide->setValue(tmp->fullName());
m_topDir->m_pDirectorySuicide->activate();
removed = tmp->fullName();
}
setStatusText("");
QApplication::restoreOverrideCursor();
}
QListViewItem::setOpen(open);
if (update) {
s_topView->setUpdatesEnabled(TRUE);
s_topView->triggerUpdate();
}
}
//----------------------------------------------------------------------------
DirBase * Directory::topDir() {
return m_topDir;
}
//----------------------------------------------------------------------------
DirBase * Directory::topControlledDir() {
if (!m_isSubProjectRoot) {
Directory * dir = parent();
Q_CHECK_PTR(dir);
return dir->topControlledDir();
} else return this;
}
//----------------------------------------------------------------------------
void Directory::analyzeAll() {
bool tmpScanMode = ONTHEFLYSCANNING;
ONTHEFLYSCANNING = false;
bool update;
if (update = s_topView->isUpdatesEnabled()) {
s_topView->setUpdatesEnabled(FALSE);
}
recAnalyzeAll();
if (update) {
s_topView->setUpdatesEnabled(TRUE);
s_topView->triggerUpdate();
}
ONTHEFLYSCANNING = tmpScanMode;
}
//----------------------------------------------------------------------------
//This must only be called if not in onTheFlyScanning mode!
bool Directory::recAnalyzeAll() {
Directory * C = firstChild();
while( C ) {
bool remove = false;
if ( !C->m_disabled) {
if (!C->m_isAnalyzedDir) {
C->analyzeDirs();
if (!C->isControlledTree()) {
remove = true;
}
} else if (!C->recAnalyzeAll()) {
remove = true;
}
}
if (remove) {
Directory * tmp = C;
C = C->nextSibling();
delete tmp;
continue;
} else C = C->nextSibling();
}
if (!isControlledTree()) return false;
else return true;
}
//----------------------------------------------------------------------------
//used from disableProjectSlot, enableProjectSlot, and rereadProjectOfDir
DirBase * Directory::reloadChild(QString childDir) {
bool update;
if (update = s_topView->isUpdatesEnabled()) {
s_topView->setUpdatesEnabled(FALSE);
}
Directory * C = firstChild();
while( C ) {
if( C->fullName().find(childDir)==0) {
delete C;
C = 0; //paranoia
break;
}
C = C->nextSibling();
}
setDirState( ES_unknown, true);//reset state hierarchy
C = createChildInstance(this, childDir);
if (ONTHEFLYSCANNING && (!C->m_disabled)) {//won't scan otherwise
C->analyzeDirs();
}
if (update) {
s_topView->setUpdatesEnabled(TRUE);
s_topView->triggerUpdate();
}
return C;
}
//----------------------------------------------------------------------------
void Directory::removeChild(QString childDir) {
Directory * C = firstChild();
while( C ) {
if( C->fullName().find(childDir)==0) {
delete C;
break;
}
C = C->nextSibling();
}
setDirState( ES_unknown, true);//reset state hierarchy
}
//----------------------------------------------------------------------------
void Directory::removeChild(DirBase * childDir) {
delete childDir;
childDir = 0;
setDirState( ES_unknown, true);//reset state hierarchy
}
//----------------------------------------------------------------------------
QString Directory::shortName( void ) {
QString R;
int pos = m_fullName.findRev( '/' );
R = m_fullName.mid( pos+1 );
return R;
}
//----------------------------------------------------------------------------
QString Directory::relativeName() {
QString rel;
int pos = m_topDir->m_fullName.findRev( '/');
rel = m_fullName.mid( pos+1);
return rel;
}
/*---------------------------------------------------------------------------*/
/*!
\fn void Directory::paintCell( QPainter *p, const QColorGroup &cg,
int column, int width, int alignment )
\brief Paints a dedicated directory entry with a different color.
\param *p
\param &cg
\param column
\param width
\param alignment
<BR><HR>*/
/*---------------------------------------------------------------------------*/
void Directory::paintCell( QPainter *p, const QColorGroup &cg,
int column, int width, int alignment )
{
QColorGroup colGrp( cg );
QColor c = colGrp.text();
bool translate = false;
if (m_disabled) {
colGrp.setColor( QColorGroup::Text, Qt::gray );
}
if ( m_isSubProjectRoot && (m_topDir != this) ) {
translate = true;
if (isSelected()) {
p->fillRect(0,0,14,height(),colGrp.highlight());
} else {
p->eraseRect(0,0,14,height());
}
p->drawPixmap(2,0,findEmbeddedPixmap("anchor_12x16"));
p->translate(14,0);
}
QListViewItem::paintCell( p, colGrp, column, width, alignment );
colGrp.setColor( QColorGroup::Text, c );
if (translate) p->translate(-14,0);
}
//----------------------------------------------------------------------------
//called after checkout, if it's a part of an existing project, and after UPDATE_DIR_CMD and QUERY_UPDATE_CMD
//returns the first not yet analyzed directory in the hierarchy
//if addVirtual==true, add as virtual dir, itter, don't analyze!
DirBase * Directory::addDir(QString newDir, bool addVirtual) {
if (!m_isAnalyzedDir && !m_virtual ) {//don't add if scanning hasn't reached this depth yet!
return this;
}
if (m_fullName.compare(newDir) == 0) {//I am it ;-)
if (addVirtual) return NULL;
resetDirState();
Directory *myChild = firstChild();
while (myChild) {
Directory *myTmpChild = myChild;
myChild = myChild->nextSibling();
delete myTmpChild;
}
m_isAnalyzedDir = false;//need to rescan!
analyzeDirs();
return NULL;
} else {//It's in one of the subdir's path
Directory *myChild = firstChild();
while(myChild) {
if(newDir.find(myChild->fullName()+"/" ) == 0) {
return myChild->addDir(newDir, addVirtual);
}
myChild = myChild->nextSibling();
}
}
//Not found yet? So it's a new subdir
Directory * item = NULL;
if (!addVirtual) {
item = createChildInstance(this, newDir);
if(item->isControlledTree()) { // fails if dir is disabled
m_hasControlledSubDir = true;
}
else if (!item->m_disabled) {
delete item;
item = 0;
}
calcDirChilds_ES_Max();
if (item && (!item->m_isAnalyzedDir)) {
return item;
} else return NULL;
} else {//virtual dir (query update)
QString newName = newDir;
int pos = newName.find( "/", m_fullName.length()+1);
if (pos > -1) {
newName = newDir.left(pos);
}
item = createChild(newName, true);
item->addDir( newDir, true);//wouldn't itter otherwise cause not analyzed
return item;//item must never be analyzed, it is virtual!
}
}
//----------------------------------------------------------------------------
DirBase * Directory::searchDirOfPath(QString path, bool findVirtual) {
if (!findVirtual && m_virtual) {
return NULL;
}
if (path.compare(m_fullName) == 0) {
return this; //it's my path :-)
}
if (path.find(m_fullName+"/") == 0) {//is subdir
Directory * myChild = firstChild();
Directory * result;
while (myChild) {
if ( (result = dyncast_dir(myChild->searchDirOfPath(path, findVirtual))) ) {
return result;
}
else {
myChild = myChild->nextSibling();
}
}
}
return NULL;
}
//----------------------------------------------------------------------------
//return the deepest valid (not disabled, not virtual) dir in hierarchy
DirBase * Directory::searchLastValidDirOfPath(QString path) {
if (m_disabled || m_virtual) {
return NULL;
}
if (path.compare(m_fullName) == 0) {
return this; //it´s my path :-)
}
if (path.find(m_fullName+"/") == 0) {//is subdir
Directory * myChild = firstChild();
Directory * result;
while (myChild) {
if ( (result = dyncast_dir(myChild->searchLastValidDirOfPath(path))) ) {
return result;
}
else {
myChild = myChild->nextSibling();
}
}
return this;
}
return NULL;
}
//--------------------------------------- STATE -------------------------------------
void Directory::recResetDirState( ) {
if ( m_disabled ) return; // we don't want to scan and change disabled dirs
Directory * D;
m_curState = ES_probably_up_to_date;
setDirIcon();
D = firstChild();
while( D ) {
D->recResetDirState();
D = D->nextSibling();
}
}
//----------------------------------------------------------------------------
void Directory::resetDirState( ) {
// reset from top down
m_topDir->recResetDirState();
}
//----------------------------------------------------------------------------
void Directory::setDirState( EntryStates newState, bool fromChild) {
// printf("\n%s:\nm_curState: %i, newState: %i, m_curStateMax: %i, m_curDirStateMax: %i\n",fullName().ascii(),m_curState,newState,m_curStateMax,m_curDirStateMax);
if ( newState == m_curState ) {
if (fromChild) {//if child state has changed it still must be adapted
if (newState > m_curDirStateMax) m_curDirStateMax = newState;
else if (newState < m_curDirStateMax) calcDirChilds_ES_Max();
}
return;
}
EntryStates nextState;
if( newState > m_curState ) {
// forced or more severe
nextState = newState;
if (fromChild) m_curDirStateMax = newState;
}
else { // still warnlevel required
if (fromChild) calcDirChilds_ES_Max();
EntryStates dirMaxState = m_curDirStateMax;
if ( m_curStateMax > dirMaxState) dirMaxState = m_curStateMax;
nextState = dirMaxState; // set new state
}
// printf("m_curState: %i, newState: %i, m_curStateMax: %i, m_curDirStateMax: %i\n",m_curState,newState,m_curStateMax,m_curDirStateMax);
// only change pix if required
if (m_curState<=ES_up_to_date && nextState<=ES_up_to_date) {
m_curState = nextState;
return; // same level (ok), nothing to be done
}
else if (m_curState>=ES_conflict && nextState>=ES_conflict) {
m_curState = nextState;
return; // same level (problem) nothing to be done
}
else if (m_curState>ES_modified && nextState>ES_modified && m_curState<ES_needs_patch && nextState<ES_needs_patch) {
m_curState = nextState;
return; // same level (uncommitted) nothing to be done
}
else if (m_curState>=ES_needs_patch && nextState>=ES_needs_patch && m_curState<ES_conflict && nextState<ES_conflict) {
m_curState = nextState;
return; // same level (warn) nothing to be done
}
else m_curState = nextState;
// now set the pixmap
setDirIcon();
if( depth() > 0 ) {
// non root -> has directory parent
parent()->setDirState( nextState, true);
}
}
//----------------------------------------------------------------------------
EntryStates Directory::getEntryState(QString fileName) {
EntryState * e = m_entries.find(fileName.stripWhiteSpace());
return (e) ? e->state() : ES_invalid;
}
//----------------------------------------------------------------------------
void Directory::setFilesToUpToDate(QStringList& updateFileList)
{
QString tmp;
while (!updateFileList.isEmpty()) {
tmp = updateFileList.first();
setEntryState(tmp, ES_up_to_date);
updateFileList.remove(tmp);
}
}
//----------------------------------------------------------------------------
void Directory::setDirIcon() {
const char * PMName;
if ( m_disabled) {
PMName = "FolderDisabled16x16";
} else if ( m_virtual) {//virtual folder
PMName = "FolderMissing16x16";
} else if ( m_curState <= ES_up_to_date ) {// all is OK
PMName = (m_isControlledDir) ?
(m_readable) ?
(m_isAutoUpdate) ? "FolderClosedAuto26x16" : "FolderClosed16x16"
: "FolderClosedLocked16x16"
: (m_isAutoUpdate) ? "FolderStatusAuto26x16" : "FolderStatus16x16";
} else if ( m_curState == ES_noncvs) { // noncvs
PMName = (m_isControlledDir) ?
(m_readable) ?
(m_isAutoUpdate) ? "FolderClosedNonCVSAuto26x16" : "FolderClosedNonCVS16x16"
: "FolderClosedLockedNonCVS16x16"
: (m_isAutoUpdate) ? "FolderStatusAuto26x16" : "FolderStatus16x16";
} else if ( m_curState == ES_modified) { // modified
PMName = (m_isControlledDir) ?
(m_readable) ?
(m_isAutoUpdate) ? "FolderClosedModifiedAuto26x16" : "FolderClosedModified16x16"
: "FolderClosedLockedModified16x16"
: (m_isAutoUpdate) ? "FolderStatusAuto26x16" : "FolderStatus16x16";
} else if( m_curState < ES_needs_patch ) { // uncommitted
PMName = (m_isControlledDir) ?
(m_readable) ?
(m_isAutoUpdate) ? "FolderClosedUncommittedAuto26x16" : "FolderClosedUncommitted16x16"
: "FolderClosedLockedUncommitted16x16"
: (m_isAutoUpdate) ? "FolderStatusAuto26x16" : "FolderStatus16x16";
} else if( m_curState < ES_conflict ) { // warn
PMName = (m_isControlledDir) ?
(m_readable) ?
(m_isAutoUpdate) ? "FolderClosedWarnAuto26x16" : "FolderClosedWarn16x16"
: "FolderClosedLockedWarn16x16"
: (m_isAutoUpdate) ? "FolderStatusAuto26x16" : "FolderStatus16x16";
} else { // problem
PMName = (m_isControlledDir) ?
(m_readable) ?
(m_isAutoUpdate) ? "FolderClosedProblemAuto26x16" : "FolderClosedProblem16x16"
: "FolderClosedLockedProblem16x16"
: (m_isAutoUpdate) ? "FolderStatusAuto26x16" : "FolderStatus16x16";
}
setPixmap( 0, findEmbeddedPixmap (PMName));
}
//----------------------------------------------------------------------------
void Directory::setAutoUpdate(bool state) {
m_isAutoUpdate = state;
setDirIcon();
}
//----------------------------------------------------------------------------
void Directory::setCallTime(QDateTime & dateTime) {
m_lastCallTime = dateTime;
Directory * D = firstChild();
while( D ) {
D->setCallTime(dateTime);
D = D->nextSibling();
}
}
//----------------------------------------------------------------------------
//----------------------------------------------------------------------------
void Directory::removeTmpEntries(QString name) {
//remove virtual dirs
Directory *myChild = firstChild();
while(myChild) {
if (myChild->isVirtual()) {
Directory *myTmpChild = myChild;
myChild = myChild->nextSibling();
if (name.isNull() || (name == myTmpChild->shortName()) ) {
delete (myTmpChild);
setDirState(ES_unknown,true);//reset state
}
} else {
myChild = myChild->nextSibling();
}
}
}
//----------------------------------------------------------------------------
void Directory::recRemoveTmpEntries(bool allProjects) {
if (m_disabled) return;
Directory * C = firstChild();
while( C ) {
if (allProjects || (C->topControlledDir() == topControlledDir()) ) C->recRemoveTmpEntries(allProjects);
C = C->nextSibling();
}
removeTmpEntries();
}
//----------------------------------------------------------------------------
void Directory::recGetOpenDirsStringList(QStringList& list) {
if (!isOpen()) return;
else list.append(m_fullName);
Directory * C = firstChild();
while( C ) {
C->recGetOpenDirsStringList(list);
C = C->nextSibling();
}
}
//----------------------------------------------------------------------------
void Directory::setAllToUpToDate() {
//alle entries im eignen verzeichnis auf uptodate setzen
EntriesIterator it(*getEntries());
while(it.current()) {
setAndAppendEntry(it.current()->name, ES_up_to_date);
++it;
}
//jetzt die subdirs...
Directory *myChild = firstChild();
while(myChild) {
myChild->setAllToUpToDate();
myChild = myChild->nextSibling();
}
}
//----------------------------------------------------------------------------
void Directory::set_ES_Max(EntryStates e_state) {
m_curStateMax = e_state;
}
//----------------------------------------------------------------------------
EntryStates Directory::get_ES_Max() {
return m_curStateMax;
}
//----------------------------------------------------------------------------
void Directory::calc_ES_Max() {
if (m_nonFiles.isEmpty()) m_curStateMax = ES_unknown;//set modified state if there are non-cvs-files
else m_curStateMax = ES_noncvs;
QDictIterator<EntryState>it(m_entries);
while(it.current()) {
if (it.current()->state() > m_curStateMax) m_curStateMax = it.current()->state();
++it;
}
}
//----------------------------------------------------------------------------
void Directory::calcDirChilds_ES_Max() {
m_curDirStateMax = ES_unknown;
Directory * C = firstChild();
while( C ) {
if( C->m_curState > m_curDirStateMax) m_curDirStateMax = C->m_curState;
C = C->nextSibling();
}
}
//----------------------------------------------------------------------------
void Directory::setAndAppendEntry(QString &fileName, EntryStates stateId)
{
if(!setEntryState(fileName, stateId)) {
appendEntry(fileName, new EntryState(fileName, stateId, this ));
return;
}
}
//----------------------------------------------------------------------------
bool Directory::recCopyTree(QString src,QString dst, bool deleteSource /*=TRUE*/) {
QDir newDir;
QString dstDir = dst+"/"+src.mid(src.findRev("/"));
if (!newDir.mkdir(dstDir) ) {
qDebug("can't create dir: "+dstDir );
return FALSE;
}
//dirs first
QStringList AllSubDirs;
QDir D( src);
D.setFilter(QDir::Dirs);
AllSubDirs = D.entryList();
// remove . and ..
AllSubDirs.remove( "." );
AllSubDirs.remove( ".." );
QStringList::Iterator fileit; //VC6 does _not_ like it...
for (fileit = AllSubDirs.begin(); fileit != AllSubDirs.end(); fileit++) {
recCopyTree(src+"/"+(*fileit),dstDir,deleteSource);
}
//now the files
QStringList AllFilesInDirectory;
D.setFilter( QDir::Files | QDir::Hidden);
AllFilesInDirectory = D.entryList();
for (fileit = AllFilesInDirectory.begin(); fileit != AllFilesInDirectory.end(); fileit++) {
QString srcName = src+"/"+(*fileit);
QString dstName = dstDir+"/"+(*fileit);
QFileInfo fInfo(srcName);
int permission = 0;
if (fInfo.isReadable()) permission = (permission | READABLE);
if (fInfo.isWritable()) permission = (permission | WRITEABLE);
if (fInfo.isExecutable()) permission = (permission | EXECUTABLE);
if (!copyFile(srcName, dstName, permission, deleteSource) ) {
qDebug("can't copy file: "+srcName+" -> "+dstName);
return FALSE;
}
}
return TRUE;
}
//----------------------------------------------------------------------------
bool Directory::recCopyControlledFiles(QString nextDir, int writeMode /*=Create*/) {//rename to recCopyRegisteredFiles
QDir newDir(nextDir);
if (writeMode==Create) {
if (newDir.exists()) {
qDebug("dir exists: "+nextDir);
return false;
}
if (!newDir.mkdir(nextDir)) {
qDebug("can't create dir: "+nextDir);
return false;
}
} else if (writeMode==Replace) {
if (!newDir.exists()) {
if (!newDir.mkdir(nextDir)) {
qDebug("can't create dir: "+nextDir);
return false;
}
}
} else if (!newDir.exists()) {
qDebug("dir doesn't exists: "+nextDir);
return false;
}
QStringList targetFiles = newDir.entryList(QDir::Files|QDir::Hidden|QDir::System);
Entries * entries = getEntries();
if (entries) {
EntriesIterator it(*entries);
while(it.current()) {
QString source = m_fullName+"/"+it.current()->name;
QString target = nextDir+"/"+it.current()->name;
QFileInfo targetInfo(target);
if ( (writeMode & Create) && targetInfo.exists()) {
qDebug("Create mode and file exists: "+target);
return false;
}
if ( (writeMode & (Overwrite|Replace)) && targetInfo.exists() && !targetInfo.isWritable()) {
QFile targetFile(target);
setPermission(targetFile,READABLE|WRITEABLE|(targetInfo.isExecutable() ? EXECUTABLE : 0));
}
QFileInfo info(source);
if (info.exists()) {
int permission = READABLE;
if (info.isWritable()) permission |= WRITEABLE;
if (info.isExecutable()) permission |= EXECUTABLE;
if (!copyFile(source,target,permission)) {
qDebug("can't copy file: "+source+" -> "+target);
return false;
} else {
QStringList::Iterator iter = targetFiles.find(it.current()->name);
if (iter != targetFiles.end()) {
targetFiles.remove(iter);
}
}
}
++it;
}
}
if (writeMode & Replace) {//remove remaining files
QStringList::Iterator iter = targetFiles.begin();
while (iter!=targetFiles.end()) {
QFile targetFile(*iter);
setPermission(targetFile,WRITEABLE);
if (!newDir.remove(*iter)) {
qDebug("cannot remove file: "+nextDir+"/"+*iter);
}
++iter;
}
}
Directory * child = firstChild();
while( child) {
if ( !(child->m_disabled || child->m_virtual) ) {
if (!child->recCopyControlledFiles(nextDir+"/"+child->shortName(),writeMode)) {
return false;
}
}
child = child->nextSibling();
}
return true;
}
//----------------------------------------------------------------------------
bool Directory::copyFile(QString src, QString dst, int permission, bool deleteSource /*=FALSE*/) {
QFile srcFile( src );
if (srcFile.open( IO_ReadOnly )) {
unsigned int size = srcFile.size();
char * buff = new char[size];
QDataStream srcStream(&srcFile);
srcStream.readRawBytes(buff,size);
QFile dstFile( dst);
if (dstFile.open( IO_WriteOnly )) {
QDataStream dstStream(&dstFile);
dstStream.writeRawBytes(buff,size);
dstFile.close();
} else {
delete buff;
return false;
}
setPermission(dstFile,permission);
delete buff;
srcFile.close();
if (deleteSource) {
setPermission(srcFile,READABLE | WRITEABLE);
return srcFile.remove();
} else {
return true;
}
} else return false;
}
//----------------------------------------------------------------------------
bool Directory::backupFiles(QStringList) {
return false;
}
//----------------------------------------------------------------------------
bool Directory::restoreFiles(QStringList) {
return false;
}
//----------------------------------------------------------------------------
bool Directory::recRemoveNonControlledFiles(QString &filter) {
QDir D( m_fullName);
D.setFilter( QDir::Files | QDir::Hidden);
D.setNameFilter( filter);
QStringList fileList = D.entryList();
Entries * entries = getEntries();
for (QStringList::Iterator fileit = fileList.begin(); fileit != fileList.end(); fileit++) {
Entry * entry = entries->find(*fileit);
if (!entry) {
QString fileName = m_fullName + "/" + (*fileit);
QFile file(fileName);
setPermission(file, READABLE | WRITEABLE);
if (!file.remove()) {
filter = fileName;
return false;
}
}
}
Directory * child = firstChild();
while( child) {
if ( !(child->m_disabled || child->m_virtual) ) {
if (!child->recRemoveNonControlledFiles(filter)) {
return false;
}
}
child = child->nextSibling();
}
return true;
}
//----------------------------------------------------------------------------
//Check and modify the dir state according to non-cvs files,
//use !!!only!!! for this!!!
void Directory::checkNonControlledFilesDirState() {//rename to checkUncontrolledFilesDirState
if (m_nonFiles.isEmpty()) {
if (m_curStateMax == ES_noncvs) {
calc_ES_Max();
setDirState( m_curStateMax);
}
} else if (m_curStateMax < ES_noncvs) {
m_curStateMax = ES_noncvs;
setDirState( ES_noncvs);
}
}
//----------------------------------------------------------------------------
//recursive check for modifications, only detected by a timestamp
//change of the dir or its CVS/Entries file
//if checkCvsFiles is true, also check for a change in each files timestamp
//if modifications are detected, check and set the new dir state
void Directory::recCheckForModifications(bool checkCvsFiles) {
if (m_disabled || m_virtual) return;
qApp->processEvents(1);
if (globalStopAction) return;
Directory * C = firstChild();
while( C ) {
C->recCheckForModifications(checkCvsFiles);
C = C->nextSibling();
}
}
//----------------------------------------------------------------------------
//recursive check for modifications, only detected by a timestamp
//change of the CVS/Entries / CVS/Entries.log file
//if modifications are detected, activateItem
bool Directory::postCallCheck(int) {
return false;
}
//----------------------------------------------------------------------------
void Directory::validateControlledFilesStatus( bool recursive /* = FALSE*/,
bool forceCacheReset /* = FALSE*/,
bool forceEntriesReset /* = FALSE*/) {
if (recursive) {
Directory * C = firstChild();
while( C ) {
C->validateControlledFilesStatus(recursive,forceCacheReset,forceEntriesReset);
C = C->nextSibling();
}
}
}
//----------------------------------------------------------------------------
//Add a single file, only known by its name, and display it
void Directory::checkAndUpdateFileCache(QString& file) {
bool found;
updateFileCacheAndCheckForIgnores(QString::null,file,false,found);
if (isSelected() && (!found) ) {
bool IsDir = false;
bool isWritable = false;
bool isExecutable = false;
QFileInfo info(m_fullName+"/"+file);
IsDir = info.isDir();
isWritable = info.isWritable();
isExecutable = info.isExecutable();
//show non-controlled entries
FileListViewItem * item = new FileListViewItem(m_pNonFileListView,IsDir,FileListViewItem::TextNoCase,FileListViewItem::ModDate);
item->setPixmap(0, findEmbeddedPixmap((IsDir) ?
(isExecutable) ? "FolderStatus16x16" : "FolderClosedLocked16x16" :
(isWritable) ? "FileUnknown16x16" : "FileLocked16x16"));
m_pNonFileListView->signalState();
item->setText(0, file);
QDateTime localDate = info.lastModified();
item->setModifiedDate(1, &localDate, localDate.toString(LookAndFeel::g_dateTimeFormat));
}
}
//----------------------------------------------------------------------------
//Remove a single file, only known by its name, and remove from display if selected
bool Directory::removeNonControlled(QString& file) {
if (m_ignoreFiles.remove(file)) {
if (isSelected()) {
QListViewItem * item = m_pIgnoreFileListView->firstChild();
while (item) {
if (item->text(0) == file) {
QListViewItem * hlp = item;
item = item->nextSibling();
delete hlp;
continue;
} else item = item->nextSibling();
}
}
return true;
} else if (m_nonFiles.remove(file)) {
if (isSelected()) {
QListViewItem * item = m_pNonFileListView->firstChild();
while (item) {
if (item->text(0) == file) {
QListViewItem * hlp = item;
item = item->nextSibling();
delete hlp;
continue;
} else item = item->nextSibling();
}
}
checkNonControlledFilesDirState();
if (isSelected()) {
m_pNonFileListView->signalState();
}
return true;
}
return false;
}
//----------------------------------------------------------------------------
//Main function for checking file state and displaying, used by DirWatch,AnalyzeDir,cvscontrol::checkStatus ...
void Directory::checkAndShowStatus(FileListViewItem *item /* = NULL*/,
bool checkOnly /* =FALSE*/,
int tab /* =Controled|NonControled|Ignored*/,
bool /*resetCache =FALSE*/) {
if(item) {//only one item
qDebug("Directory cannot hold controlled files");
} else { // read entries in directory
if (tab & NonControled) {
QStringList AllFilesInDirectory;
QFile f;
QString line;
QString path = m_fullName;
if(path.length() > 1){//is not root
path += "/";
}
QDir D( path);
D.setFilter( QDir::Files | QDir::Dirs | QDir::Hidden | QDir::System);
AllFilesInDirectory = D.entryList();
// remove . and ..
AllFilesInDirectory.remove( "." );
AllFilesInDirectory.remove( ".." );
// now check the files
for (QStringList::Iterator fileit = AllFilesInDirectory.begin(); fileit != AllFilesInDirectory.end(); fileit++) {
QString name = path + (*fileit);
QFileInfo info(name);
bool IsDir = info.isDir();
if ( IsDir && (checkType(name+"/") != Plain) ) {// Controled directory -> do NOT show
continue;
}
bool isWritable = info.isWritable();
bool isExecutable = info.isExecutable();
bool found;
updateFileCacheAndCheckForIgnores(QString::null,*fileit,false, found);
// stop here if checkOnly because now we know the non-cvs state (dir state was allready set in updateFileCacheAndCheckForIgnores
if (checkOnly) return;
//show non-cvs entries
item = new FileListViewItem(m_pNonFileListView,IsDir,FileListViewItem::TextNoCase,FileListViewItem::ModDate);
item->setPixmap(0, findEmbeddedPixmap( (IsDir) ?
(isExecutable) ? "FolderStatus16x16" : "FolderClosedLocked16x16" :
(isWritable) ? "FileUnknown16x16" : "FileLocked16x16"));
item->setText(0, *fileit);
QDateTime localDate = info.lastModified();
item->setModifiedDate(1, &localDate, localDate.toString(LookAndFeel::g_dateTimeFormat));
}
checkNonControlledFilesDirState();
}
}
}
//----------------------------------------------------------------------------
bool Directory::updateFileCacheAndCheckForIgnores(const QString filesToIgnore, QString& file, bool ignoreCacheReseted, bool& found) {
bool doIgnore = FALSE;
found = FALSE;
if (!ignoreCacheReseted) {
if (m_ignoreFiles.find(file)) {
doIgnore = true;
found = true;
} else if (m_nonFiles.find(file)) {
found = true;
}
}
if (!found) {
//reimplemented old version of ignore scan,
//now using wildcard mode
//this is at about factor 2 faster on lin!!!
QStringList ignf = QStringList::split(" ",filesToIgnore);
QRegExp exp;
exp.setWildcard(true);
for (QStringList::Iterator it = ignf.begin(); it != ignf.end(); it++) {
exp.setPattern(*it);
if ( exp.exactMatch(file) ) {
doIgnore = true;
break;
}
}
if (doIgnore) {
if (m_ignoreFiles.size()<=m_ignoreFiles.count()) {
m_ignoreFiles.resize(nextPrime(m_ignoreFiles.size()));
}
m_ignoreFiles.insert(file,new bool(true));
} else {
if (m_nonFiles.size()<=m_nonFiles.count()) {
m_nonFiles.resize(nextPrime(m_nonFiles.size()));
}
m_nonFiles.insert(file,new bool(true));
checkNonControlledFilesDirState();
}
}
return doIgnore;
}
//----------------------------------------------------------------------------
void Directory::updateDisabledList(QStringList& list) {
m_disabledList = list;
}
//----------------------------------------------------------------------------
void Directory::updateSubProjectList(QStringList& list) {
m_subProjectList = list;
}
//----------------------------------------------------------------------------
bool Directory::getDisabled(QString filename)
{
QStringList* list = dyncast_dir(topControlledDir())->getDisabledList();
QStringList::iterator it = list->find( filename);
if (it != list->end()) {
return true;
} else {
return false;
}
}
//----------------------------------------------------------------------------
void Directory::setAllOpen( ) {
Directory * D = this;
do {
D->setOpen( TRUE );
if( D->depth() == 0 )
// root item
break;
D = D->parent();
} while ( 1 );
}
//----------------------------------------------------------------------------
void Directory::expandAllDir() {
bool update;
if (update = s_topView->isUpdatesEnabled()) {
s_topView->setUpdatesEnabled(FALSE);
}
if (!isOpen()) {
setOpen(true);
}
Directory *myChild = firstChild();
while(myChild) {
myChild->expandAllDir();
myChild = myChild->nextSibling();
}
if (update) {
s_topView->setUpdatesEnabled(TRUE);
s_topView->triggerUpdate();
}
}
//----------------------------------------------------------------------------
void Directory::collapsAllDir() {
Directory *myChild = firstChild();
while(myChild) {
myChild->collapsAllDir();
myChild = myChild->nextSibling();
}
if (isOpen()) {
setOpen(false);
}
}
//----------------------------------------------------------------------------
int Directory::isTreeEmpty() {
if (getEntries()->count()) return 0;
// seems to contain NO regular CVS files
Directory * C = firstChild();
while( C ) {
if( ! C->isTreeEmpty() )
return 0;
C = C->nextSibling();
}
// no entry found
return 1;
}
//----------------------------------------------------------------------------
void Directory::afterCall( int, CvsBuffer*, bool) {
}
//----------------------------------------------------------------------------
bool Directory::hasDisabled() {
if (m_disabled) return TRUE;
Directory * C = firstChild();
while( C ) {
if (C->hasDisabled()) {
return TRUE;
}
C = C->nextSibling();
}
return FALSE;
}
/**
* Executes a self contained command on the directory structure beginning
* with the current item. The target item (and NOT the command) is
* responsible for making sure that recursive commands are applied to all
* child items.
*
* @param CvsCommand
* command to execute of the directory structure
* @return
* true on success. Otherwise false.
*/
bool Directory::execute(CCvsCommand &cmd)
{
if (m_disabled) return FALSE;
if (!cmd.isRecursive()) {
return cmd.execute(*this);
} else {
if (ONTHEFLYSCANNING) analyzeAll();
return recExecute(cmd);
}
}
/**
* Undo the changes made by previously executing the given command.
*
* @param CvsCommand
* command to undo
* @return
* true on success. Otherwise false.
*/
bool Directory::unexecute(CCvsCommand &cmd)
{
if (m_disabled) return FALSE;
if (!cmd.isRecursive()) {
return cmd.unexecute(*this);
} else {
if (ONTHEFLYSCANNING) analyzeAll();
return recUnexecute(cmd);
}
}
//----------------------------------------------------------------------------
bool Directory::recExecute(CCvsCommand &cmd) {
bool retVal = TRUE;
Directory * C = firstChild();
while( C ) {
if (!C->m_disabled && !C->m_isSubProjectRoot) {
if (!C->recExecute(cmd)) retVal = FALSE;
} else {
retVal = FALSE;
}
C = C->nextSibling();
}
if (!cmd.execute(*this)) retVal = FALSE;
return retVal;
}
//----------------------------------------------------------------------------
bool Directory::recUnexecute(CCvsCommand &cmd) {
bool retVal = TRUE;
Directory * C = firstChild();
while( C ) {
if (!C->m_disabled && !C->m_isSubProjectRoot) {
if (!C->recUnexecute(cmd)) retVal = FALSE;
} else {
retVal = FALSE;
}
C = C->nextSibling();
}
if (!cmd.unexecute(*this)) retVal = FALSE;
return retVal;
}
//----------------------------------------------------------------------------
void Directory::setStatusText( const QString & txt, int ms) {
((CvsDirListView*)s_topView)->setStatusBarText( txt, ms);
}
//----------------------------------------------------------------------------
QStringList Directory::getSelectedFiles() {
QStringList names;
FileListViewItem * item = s_pListView->currentFirstChild();
while (item) {
if ( item->isSelected() ) {
names.append( item->text(0).stripWhiteSpace());
}
item = item->nextSibling();
}
return names;
}
//----------------------------------------------------------------------------
QString Directory::getFirstSelectedFile() {
FileListViewItem * item = s_pListView->currentFirstChild();
while (item) {
if ( item->isSelected() ) {
return item->text(0).stripWhiteSpace();
}
item = item->nextSibling();
}
return QString::null;
}
//======================================= virtual methods =========================================================
bool Directory::analyzeDirs() {
if (m_isAnalyzedDir) {//don't analyze twice on setOpen()
return m_hasControlledSubDir;
}
// qDebug("analyzing: "+m_fullName+", depth: "+QString::number(depth()));
QDir myDir(m_fullName);
myDir.setFilter( QDir::Dirs | QDir::Hidden);
QStringList subDirList = myDir.entryList();
QString path = m_fullName;
QString curSubDirName;
QFileInfo fileInfo;
Directory *item;
//is the current dir or the parent dir -- ignore it
subDirList.remove(".");
subDirList.remove("..");
if(!subDirList.isEmpty()) {//has subdirs
if(m_fullName.length() > 1){//is not root
path += "/";
}
for(unsigned int i = 0; i < subDirList.count(); i++) {
if(globalStopAction) break; //cancel this action
curSubDirName = subDirList[i];
fileInfo.setFile(path + curSubDirName);
//ignore symlinks
if( fileInfo.isSymLink()) continue;
//ignore non-cvs dirs
if (!bSCANNONCVS && (depth() >= 1)) continue;
if(fileInfo.isReadable() && fileInfo.isExecutable()) {//is a dir and readable
//at the moment lacks a test for enough mem
m_isAnalyzedDir = true;//no need to analyze again in onthefly mode
item = Directory::createChildInstance(this, path + curSubDirName);
if(item->isControlledTree()) { // fails if dir is disabled and returns true even if
// there are dirs in between that have no CVS dir
m_hasControlledSubDir = true;
}
else if (item->isDisabled()) continue;
else if (ONTHEFLYSCANNING && !item->isAnalyzed()) continue;//don't know yet if there are cvs dirs somewhere in depth
else {
delete item;
item = 0; // paranoia
}
}
}
calcDirChilds_ES_Max();
} else {//has no subdirs
m_isAnalyzedDir = true;//no need to analyze again in onthefly mode
}
if (m_hasControlledSubDir) {
// check and set FolderState and therewith initialize caches
checkAndShowStatus(NULL,true);
return true;
} else {
return false;
}
}
syntax highlighted by Code2HTML, v. 0.9.1