summaryrefslogtreecommitdiffstats
path: root/tdeio/tdeio/kdirlister.cpp
diff options
context:
space:
mode:
authorTimothy Pearson <kb9vqf@pearsoncomputing.net>2013-01-27 01:04:16 -0600
committerTimothy Pearson <kb9vqf@pearsoncomputing.net>2013-01-27 01:04:16 -0600
commit5159cd2beb2e87806a5b54e9991b7895285c9d3e (patch)
tree9b70e8be47a390f8f4d56ead812ab0c9dad88709 /tdeio/tdeio/kdirlister.cpp
parentc17cb900dcf52b8bd6dc300d4f103392900ec2b4 (diff)
downloadtdelibs-5159cd2beb2e87806a5b54e9991b7895285c9d3e.tar.gz
tdelibs-5159cd2beb2e87806a5b54e9991b7895285c9d3e.zip
Rename a number of libraries and executables to avoid conflicts with KDE4
Diffstat (limited to 'tdeio/tdeio/kdirlister.cpp')
-rw-r--r--tdeio/tdeio/kdirlister.cpp2538
1 files changed, 2538 insertions, 0 deletions
diff --git a/tdeio/tdeio/kdirlister.cpp b/tdeio/tdeio/kdirlister.cpp
new file mode 100644
index 000000000..0d3498aa7
--- /dev/null
+++ b/tdeio/tdeio/kdirlister.cpp
@@ -0,0 +1,2538 @@
+/* This file is part of the KDE project
+ Copyright (C) 1998, 1999 Torben Weis <weis@kde.org>
+ 2000 Carsten Pfeiffer <pfeiffer@kde.org>
+ 2001-2005 Michael Brade <brade@kde.org>
+
+ 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 "kdirlister.h"
+
+#include <tqregexp.h>
+#include <tqptrlist.h>
+#include <tqtimer.h>
+#include <tqeventloop.h>
+
+#include <kapplication.h>
+#include <kdebug.h>
+#include <klocale.h>
+#include <tdeio/job.h>
+#include <kmessagebox.h>
+#include <kglobal.h>
+#include <kglobalsettings.h>
+#include <kstaticdeleter.h>
+#include <kprotocolinfo.h>
+
+#include "kdirlister_p.h"
+
+#include <assert.h>
+#include <unistd.h>
+
+KDirListerCache* KDirListerCache::s_pSelf = 0;
+static KStaticDeleter<KDirListerCache> sd_KDirListerCache;
+
+// Enable this to get printDebug() called often, to see the contents of the cache
+//#define DEBUG_CACHE
+
+// Make really sure it doesn't get activated in the final build
+#ifdef NDEBUG
+#undef DEBUG_CACHE
+#endif
+
+KDirListerCache::KDirListerCache( int maxCount )
+ : itemsCached( maxCount )
+{
+ kdDebug(7004) << "+KDirListerCache" << endl;
+
+ itemsInUse.setAutoDelete( false );
+ itemsCached.setAutoDelete( true );
+ urlsCurrentlyListed.setAutoDelete( true );
+ urlsCurrentlyHeld.setAutoDelete( true );
+ pendingUpdates.setAutoDelete( true );
+
+ connect( kdirwatch, TQT_SIGNAL( dirty( const TQString& ) ),
+ this, TQT_SLOT( slotFileDirty( const TQString& ) ) );
+ connect( kdirwatch, TQT_SIGNAL( created( const TQString& ) ),
+ this, TQT_SLOT( slotFileCreated( const TQString& ) ) );
+ connect( kdirwatch, TQT_SIGNAL( deleted( const TQString& ) ),
+ this, TQT_SLOT( slotFileDeleted( const TQString& ) ) );
+}
+
+KDirListerCache::~KDirListerCache()
+{
+ kdDebug(7004) << "-KDirListerCache" << endl;
+
+ itemsInUse.setAutoDelete( true );
+ itemsInUse.clear();
+ itemsCached.clear();
+ urlsCurrentlyListed.clear();
+ urlsCurrentlyHeld.clear();
+
+ if ( KDirWatch::exists() )
+ kdirwatch->disconnect( this );
+}
+
+// setting _reload to true will emit the old files and
+// call updateDirectory
+bool KDirListerCache::listDir( KDirLister *lister, const KURL& _u,
+ bool _keep, bool _reload )
+{
+ // like this we don't have to worry about trailing slashes any further
+ KURL _url = _u;
+ _url.cleanPath(); // kill consecutive slashes
+ _url.adjustPath(-1);
+ TQString urlStr = _url.url();
+
+ if ( !lister->validURL( _url ) )
+ return false;
+
+#ifdef DEBUG_CACHE
+ printDebug();
+#endif
+ kdDebug(7004) << k_funcinfo << lister << " url=" << _url
+ << " keep=" << _keep << " reload=" << _reload << endl;
+
+ if ( !_keep )
+ {
+ // stop any running jobs for lister
+ stop( lister );
+
+ // clear our internal list for lister
+ forgetDirs( lister );
+
+ lister->d->rootFileItem = 0;
+ }
+ else if ( lister->d->lstDirs.find( _url ) != lister->d->lstDirs.end() )
+ {
+ // stop the job listing _url for this lister
+ stop( lister, _url );
+
+ // clear _url for lister
+ forgetDirs( lister, _url, true );
+
+ if ( lister->d->url == _url )
+ lister->d->rootFileItem = 0;
+ }
+
+ lister->d->lstDirs.append( _url );
+
+ if ( lister->d->url.isEmpty() || !_keep ) // set toplevel URL only if not set yet
+ lister->d->url = _url;
+
+ DirItem *itemU = itemsInUse[urlStr];
+ DirItem *itemC;
+
+ if ( !urlsCurrentlyListed[urlStr] )
+ {
+ // if there is an update running for _url already we get into
+ // the following case - it will just be restarted by updateDirectory().
+
+ if ( itemU )
+ {
+ kdDebug(7004) << "listDir: Entry already in use: " << _url << endl;
+
+ bool oldState = lister->d->complete;
+ lister->d->complete = false;
+
+ emit lister->started( _url );
+
+ if ( !lister->d->rootFileItem && lister->d->url == _url )
+ lister->d->rootFileItem = itemU->rootItem;
+
+ lister->addNewItems( *(itemU->lstItems) );
+ lister->emitItems();
+
+ // _url is already in use, so there is already an entry in urlsCurrentlyHeld
+ assert( urlsCurrentlyHeld[urlStr] );
+ urlsCurrentlyHeld[urlStr]->append( lister );
+
+ lister->d->complete = oldState;
+
+ emit lister->completed( _url );
+ if ( lister->d->complete )
+ emit lister->completed();
+
+ if ( _reload || !itemU->complete )
+ updateDirectory( _url );
+ }
+ else if ( !_reload && (itemC = itemsCached.take( urlStr )) )
+ {
+ kdDebug(7004) << "listDir: Entry in cache: " << _url << endl;
+
+ itemC->decAutoUpdate();
+ itemsInUse.insert( urlStr, itemC );
+ itemU = itemC;
+
+ bool oldState = lister->d->complete;
+ lister->d->complete = false;
+
+ emit lister->started( _url );
+
+ if ( !lister->d->rootFileItem && lister->d->url == _url )
+ lister->d->rootFileItem = itemC->rootItem;
+
+ lister->addNewItems( *(itemC->lstItems) );
+ lister->emitItems();
+
+ Q_ASSERT( !urlsCurrentlyHeld[urlStr] );
+ TQPtrList<KDirLister> *list = new TQPtrList<KDirLister>;
+ list->append( lister );
+ urlsCurrentlyHeld.insert( urlStr, list );
+
+ lister->d->complete = oldState;
+
+ emit lister->completed( _url );
+ if ( lister->d->complete )
+ emit lister->completed();
+
+ if ( !itemC->complete )
+ updateDirectory( _url );
+ }
+ else // dir not in cache or _reload is true
+ {
+ kdDebug(7004) << "listDir: Entry not in cache or reloaded: " << _url << endl;
+
+ TQPtrList<KDirLister> *list = new TQPtrList<KDirLister>;
+ list->append( lister );
+ urlsCurrentlyListed.insert( urlStr, list );
+
+ itemsCached.remove( urlStr );
+ itemU = new DirItem( _url );
+ itemsInUse.insert( urlStr, itemU );
+
+// // we have a limit of MAX_JOBS_PER_LISTER concurrently running jobs
+// if ( lister->numJobs() >= MAX_JOBS_PER_LISTER )
+// {
+// lstPendingUpdates.append( _url );
+// }
+// else
+// {
+
+ if ( lister->d->url == _url )
+ lister->d->rootFileItem = 0;
+
+ TDEIO::ListJob* job = TDEIO::listDir( _url, false /* no default GUI */ );
+ jobs.insert( job, TQValueList<TDEIO::UDSEntry>() );
+
+ lister->jobStarted( job );
+ lister->connectJob( job );
+
+ if ( lister->d->window )
+ job->setWindow( lister->d->window );
+
+ connect( job, TQT_SIGNAL( entries( TDEIO::Job *, const TDEIO::UDSEntryList & ) ),
+ this, TQT_SLOT( slotEntries( TDEIO::Job *, const TDEIO::UDSEntryList & ) ) );
+ connect( job, TQT_SIGNAL( result( TDEIO::Job * ) ),
+ this, TQT_SLOT( slotResult( TDEIO::Job * ) ) );
+ connect( job, TQT_SIGNAL( redirection( TDEIO::Job *, const KURL & ) ),
+ this, TQT_SLOT( slotRedirection( TDEIO::Job *, const KURL & ) ) );
+
+ emit lister->started( _url );
+
+// }
+ }
+ }
+ else
+ {
+ kdDebug(7004) << "listDir: Entry currently being listed: " << _url << endl;
+
+ emit lister->started( _url );
+
+ urlsCurrentlyListed[urlStr]->append( lister );
+
+ TDEIO::ListJob *job = jobForUrl( urlStr );
+ Q_ASSERT( job );
+
+ lister->jobStarted( job );
+ lister->connectJob( job );
+
+ Q_ASSERT( itemU );
+
+ if ( !lister->d->rootFileItem && lister->d->url == _url )
+ lister->d->rootFileItem = itemU->rootItem;
+
+ lister->addNewItems( *(itemU->lstItems) );
+ lister->emitItems();
+ }
+
+ // automatic updating of directories
+ if ( lister->d->autoUpdate )
+ itemU->incAutoUpdate();
+
+ return true;
+}
+
+bool KDirListerCache::validURL( const KDirLister *lister, const KURL& url ) const
+{
+ if ( !url.isValid() )
+ {
+ if ( lister->d->autoErrorHandling )
+ {
+ TQString tmp = i18n("Malformed URL\n%1").arg( url.prettyURL() );
+ KMessageBox::error( lister->d->errorParent, tmp );
+ }
+ return false;
+ }
+
+ if ( !KProtocolInfo::supportsListing( url ) )
+ {
+ if ( lister->d->autoErrorHandling )
+ {
+ // TODO: this message should be changed during next string unfreeze!
+ TQString tmp = i18n("Malformed URL\n%1").arg( url.prettyURL() );
+ KMessageBox::error( lister->d->errorParent, tmp );
+ }
+ return false;
+ }
+
+ return true;
+}
+
+void KDirListerCache::stop( KDirLister *lister )
+{
+#ifdef DEBUG_CACHE
+ printDebug();
+#endif
+ kdDebug(7004) << k_funcinfo << "lister: " << lister << endl;
+ bool stopped = false;
+
+ TQDictIterator< TQPtrList<KDirLister> > it( urlsCurrentlyListed );
+ TQPtrList<KDirLister> *listers;
+ while ( (listers = it.current()) )
+ {
+ if ( listers->findRef( lister ) > -1 )
+ {
+ // lister is listing url
+ TQString url = it.currentKey();
+
+ //kdDebug(7004) << k_funcinfo << " found lister in list - for " << url << endl;
+ bool ret = listers->removeRef( lister );
+ Q_ASSERT( ret );
+
+ TDEIO::ListJob *job = jobForUrl( url );
+ if ( job )
+ lister->jobDone( job );
+
+ // move lister to urlsCurrentlyHeld
+ TQPtrList<KDirLister> *holders = urlsCurrentlyHeld[url];
+ if ( !holders )
+ {
+ holders = new TQPtrList<KDirLister>;
+ urlsCurrentlyHeld.insert( url, holders );
+ }
+
+ holders->append( lister );
+
+ emit lister->canceled( KURL( url ) );
+
+ //kdDebug(7004) << k_funcinfo << "remaining list: " << listers->count() << " listers" << endl;
+
+ if ( listers->isEmpty() )
+ {
+ // kill the job since it isn't used any more
+ if ( job )
+ killJob( job );
+
+ urlsCurrentlyListed.remove( url );
+ }
+
+ stopped = true;
+ }
+ else
+ ++it;
+ }
+
+ if ( stopped )
+ {
+ emit lister->canceled();
+ lister->d->complete = true;
+ }
+
+ // this is wrong if there is still an update running!
+ //Q_ASSERT( lister->d->complete );
+}
+
+void KDirListerCache::stop( KDirLister *lister, const KURL& _u )
+{
+ TQString urlStr( _u.url(-1) );
+ KURL _url( urlStr );
+
+ // TODO: consider to stop all the "child jobs" of _url as well
+ kdDebug(7004) << k_funcinfo << lister << " url=" << _url << endl;
+
+ TQPtrList<KDirLister> *listers = urlsCurrentlyListed[urlStr];
+ if ( !listers || !listers->removeRef( lister ) )
+ return;
+
+ // move lister to urlsCurrentlyHeld
+ TQPtrList<KDirLister> *holders = urlsCurrentlyHeld[urlStr];
+ if ( !holders )
+ {
+ holders = new TQPtrList<KDirLister>;
+ urlsCurrentlyHeld.insert( urlStr, holders );
+ }
+
+ holders->append( lister );
+
+
+ TDEIO::ListJob *job = jobForUrl( urlStr );
+ if ( job )
+ lister->jobDone( job );
+
+ emit lister->canceled( _url );
+
+ if ( listers->isEmpty() )
+ {
+ // kill the job since it isn't used any more
+ if ( job )
+ killJob( job );
+
+ urlsCurrentlyListed.remove( urlStr );
+ }
+
+ if ( lister->numJobs() == 0 )
+ {
+ lister->d->complete = true;
+
+ // we killed the last job for lister
+ emit lister->canceled();
+ }
+}
+
+void KDirListerCache::setAutoUpdate( KDirLister *lister, bool enable )
+{
+ // IMPORTANT: this method does not check for the current autoUpdate state!
+
+ for ( KURL::List::Iterator it = lister->d->lstDirs.begin();
+ it != lister->d->lstDirs.end(); ++it )
+ {
+ if ( enable )
+ itemsInUse[(*it).url()]->incAutoUpdate();
+ else
+ itemsInUse[(*it).url()]->decAutoUpdate();
+ }
+}
+
+void KDirListerCache::forgetDirs( KDirLister *lister )
+{
+ kdDebug(7004) << k_funcinfo << lister << endl;
+
+ emit lister->clear();
+
+ // forgetDirs() will modify lstDirs, make a copy first
+ KURL::List lstDirsCopy = lister->d->lstDirs;
+ for ( KURL::List::Iterator it = lstDirsCopy.begin();
+ it != lstDirsCopy.end(); ++it )
+ {
+ forgetDirs( lister, *it, false );
+ }
+}
+
+void KDirListerCache::forgetDirs( KDirLister *lister, const KURL& _url, bool notify )
+{
+ kdDebug(7004) << k_funcinfo << lister << " _url: " << _url << endl;
+
+ KURL url( _url );
+ url.adjustPath( -1 );
+ TQString urlStr = url.url();
+ TQPtrList<KDirLister> *holders = urlsCurrentlyHeld[urlStr];
+ //Q_ASSERT( holders );
+ if ( holders )
+ {
+ holders->removeRef( lister );
+ }
+
+ // remove the dir from lister->d->lstDirs so that it doesn't contain things
+ // that itemsInUse doesn't. When emitting the canceled signals lstDirs must
+ // not contain anything that itemsInUse does not contain. (otherwise it
+ // might crash in findByName()).
+ lister->d->lstDirs.remove( lister->d->lstDirs.find( url ) );
+
+ DirItem *item = itemsInUse[urlStr];
+
+ if ( holders && holders->isEmpty() )
+ {
+ urlsCurrentlyHeld.remove( urlStr ); // this deletes the (empty) holders list
+ if ( !urlsCurrentlyListed[urlStr] )
+ {
+ // item not in use anymore -> move into cache if complete
+ itemsInUse.remove( urlStr );
+
+ // this job is a running update
+ TDEIO::ListJob *job = jobForUrl( urlStr );
+ if ( job )
+ {
+ lister->jobDone( job );
+ killJob( job );
+ kdDebug(7004) << k_funcinfo << "Killing update job for " << urlStr << endl;
+
+ emit lister->canceled( url );
+ if ( lister->numJobs() == 0 )
+ {
+ lister->d->complete = true;
+ emit lister->canceled();
+ }
+ }
+
+ if ( notify )
+ emit lister->clear( url );
+
+ if ( item && item->complete )
+ {
+ kdDebug(7004) << k_funcinfo << lister << " item moved into cache: " << url << endl;
+ itemsCached.insert( urlStr, item ); // TODO: may return false!!
+
+ // Should we forget the dir for good, or keep a watch on it?
+ // Generally keep a watch, except when it would prevent
+ // unmounting a removable device (#37780)
+ const bool isLocal = item->url.isLocalFile();
+ const bool isManuallyMounted = isLocal && TDEIO::manually_mounted( item->url.path() );
+ bool containsManuallyMounted = false;
+ if ( !isManuallyMounted && item->lstItems && isLocal )
+ {
+ // Look for a manually-mounted directory inside
+ // If there's one, we can't keep a watch either, FAM would prevent unmounting the CDROM
+ // I hope this isn't too slow (manually_mounted caches the last device so most
+ // of the time this is just a stat per subdir)
+ KFileItemListIterator kit( *item->lstItems );
+ for ( ; kit.current() && !containsManuallyMounted; ++kit )
+ if ( (*kit)->isDir() && TDEIO::manually_mounted( (*kit)->url().path() ) )
+ containsManuallyMounted = true;
+ }
+
+ if ( isManuallyMounted || containsManuallyMounted )
+ {
+ kdDebug(7004) << "Not adding a watch on " << item->url << " because it " <<
+ ( isManuallyMounted ? "is manually mounted" : "contains a manually mounted subdir" ) << endl;
+ item->complete = false; // set to "dirty"
+ }
+ else
+ item->incAutoUpdate(); // keep watch
+ }
+ else
+ {
+ delete item;
+ item = 0;
+ }
+ }
+ }
+
+ if ( item && lister->d->autoUpdate )
+ item->decAutoUpdate();
+}
+
+void KDirListerCache::updateDirectory( const KURL& _dir )
+{
+ kdDebug(7004) << k_funcinfo << _dir << endl;
+
+ TQString urlStr = _dir.url(-1);
+ if ( !checkUpdate( urlStr ) )
+ return;
+
+ // A job can be running to
+ // - only list a new directory: the listers are in urlsCurrentlyListed
+ // - only update a directory: the listers are in urlsCurrentlyHeld
+ // - update a currently running listing: the listers are in urlsCurrentlyListed
+ // and urlsCurrentlyHeld
+
+ TQPtrList<KDirLister> *listers = urlsCurrentlyListed[urlStr];
+ TQPtrList<KDirLister> *holders = urlsCurrentlyHeld[urlStr];
+
+ // restart the job for _dir if it is running already
+ bool killed = false;
+ TQWidget *window = 0;
+ TDEIO::ListJob *job = jobForUrl( urlStr );
+ if ( job )
+ {
+ window = job->window();
+
+ killJob( job );
+ killed = true;
+
+ if ( listers )
+ for ( KDirLister *kdl = listers->first(); kdl; kdl = listers->next() )
+ kdl->jobDone( job );
+
+ if ( holders )
+ for ( KDirLister *kdl = holders->first(); kdl; kdl = holders->next() )
+ kdl->jobDone( job );
+ }
+ kdDebug(7004) << k_funcinfo << "Killed = " << killed << endl;
+
+ // we don't need to emit canceled signals since we only replaced the job,
+ // the listing is continuing.
+
+ Q_ASSERT( !listers || (listers && killed) );
+
+ job = TDEIO::listDir( _dir, false /* no default GUI */ );
+ jobs.insert( job, TQValueList<TDEIO::UDSEntry>() );
+
+ connect( job, TQT_SIGNAL(entries( TDEIO::Job *, const TDEIO::UDSEntryList & )),
+ this, TQT_SLOT(slotUpdateEntries( TDEIO::Job *, const TDEIO::UDSEntryList & )) );
+ connect( job, TQT_SIGNAL(result( TDEIO::Job * )),
+ this, TQT_SLOT(slotUpdateResult( TDEIO::Job * )) );
+
+ kdDebug(7004) << k_funcinfo << "update started in " << _dir << endl;
+
+ if ( listers )
+ for ( KDirLister *kdl = listers->first(); kdl; kdl = listers->next() )
+ kdl->jobStarted( job );
+
+ if ( holders )
+ {
+ if ( !killed )
+ {
+ bool first = true;
+ for ( KDirLister *kdl = holders->first(); kdl; kdl = holders->next() )
+ {
+ kdl->jobStarted( job );
+ if ( first && kdl->d->window )
+ {
+ first = false;
+ job->setWindow( kdl->d->window );
+ }
+ emit kdl->started( _dir );
+ }
+ }
+ else
+ {
+ job->setWindow( window );
+
+ for ( KDirLister *kdl = holders->first(); kdl; kdl = holders->next() )
+ kdl->jobStarted( job );
+ }
+ }
+}
+
+bool KDirListerCache::checkUpdate( const TQString& _dir )
+{
+ if ( !itemsInUse[_dir] )
+ {
+ DirItem *item = itemsCached[_dir];
+ if ( item && item->complete )
+ {
+ item->complete = false;
+ item->decAutoUpdate();
+ // Hmm, this debug output might include login/password from the _dir URL.
+ //kdDebug(7004) << k_funcinfo << "directory " << _dir << " not in use, marked dirty." << endl;
+ }
+ //else
+ //kdDebug(7004) << k_funcinfo << "aborted, directory " << _dir << " not in cache." << endl;
+
+ return false;
+ }
+ else
+ return true;
+}
+
+KFileItemList *KDirListerCache::itemsForDir( const KURL &_dir ) const
+{
+ TQString urlStr = _dir.url(-1);
+ DirItem *item = itemsInUse[ urlStr ];
+ if ( !item )
+ item = itemsCached[ urlStr ];
+ return item ? item->lstItems : 0;
+}
+
+KFileItem *KDirListerCache::findByName( const KDirLister *lister, const TQString& _name ) const
+{
+ Q_ASSERT( lister );
+
+ for ( KURL::List::Iterator it = lister->d->lstDirs.begin();
+ it != lister->d->lstDirs.end(); ++it )
+ {
+ KFileItemListIterator kit( *itemsInUse[(*it).url()]->lstItems );
+ for ( ; kit.current(); ++kit )
+ if ( (*kit)->name() == _name )
+ return (*kit);
+ }
+
+ return 0L;
+}
+
+KFileItem *KDirListerCache::findByURL( const KDirLister *lister, const KURL& _u ) const
+{
+ KURL _url = _u;
+ _url.adjustPath(-1);
+
+ KURL parentDir( _url );
+ parentDir.setPath( parentDir.directory() );
+
+ // If lister is set, check that it contains this dir
+ if ( lister && !lister->d->lstDirs.contains( parentDir ) )
+ return 0L;
+
+ KFileItemList *itemList = itemsForDir( parentDir );
+ if ( itemList )
+ {
+ KFileItemListIterator kit( *itemList );
+ for ( ; kit.current(); ++kit )
+ if ( (*kit)->url() == _url )
+ return (*kit);
+ }
+ return 0L;
+}
+
+void KDirListerCache::FilesAdded( const KURL &dir )
+{
+ kdDebug(7004) << k_funcinfo << dir << endl;
+ updateDirectory( dir );
+}
+
+void KDirListerCache::FilesRemoved( const KURL::List &fileList )
+{
+ kdDebug(7004) << k_funcinfo << endl;
+ KURL::List::ConstIterator it = fileList.begin();
+ for ( ; it != fileList.end() ; ++it )
+ {
+ // emit the deleteItem signal if this file was shown in any view
+ KFileItem *fileitem = 0L;
+ KURL parentDir( *it );
+ parentDir.setPath( parentDir.directory() );
+ KFileItemList *lstItems = itemsForDir( parentDir );
+ if ( lstItems )
+ {
+ KFileItem *fit = lstItems->first();
+ for ( ; fit; fit = lstItems->next() )
+ if ( fit->url() == *it ) {
+ fileitem = fit;
+ lstItems->take(); // remove fileitem from list
+ break;
+ }
+ }
+
+ // Tell the views about it before deleting the KFileItems. They might need the subdirs'
+ // file items (see the dirtree).
+ if ( fileitem )
+ {
+ TQPtrList<KDirLister> *listers = urlsCurrentlyHeld[parentDir.url()];
+ if ( listers )
+ for ( KDirLister *kdl = listers->first(); kdl; kdl = listers->next() )
+ kdl->emitDeleteItem( fileitem );
+ }
+
+ // If we found a fileitem, we can test if it's a dir. If not, we'll go to deleteDir just in case.
+ if ( !fileitem || fileitem->isDir() )
+ {
+ // in case of a dir, check if we have any known children, there's much to do in that case
+ // (stopping jobs, removing dirs from cache etc.)
+ deleteDir( *it );
+ }
+
+ // now remove the item itself
+ delete fileitem;
+ }
+}
+
+void KDirListerCache::FilesChanged( const KURL::List &fileList )
+{
+ KURL::List dirsToUpdate;
+ kdDebug(7004) << k_funcinfo << "only half implemented" << endl;
+ KURL::List::ConstIterator it = fileList.begin();
+ for ( ; it != fileList.end() ; ++it )
+ {
+ if ( ( *it ).isLocalFile() )
+ {
+ kdDebug(7004) << "KDirListerCache::FilesChanged " << *it << endl;
+ KFileItem *fileitem = findByURL( 0, *it );
+ if ( fileitem )
+ {
+ // we need to refresh the item, because e.g. the permissions can have changed.
+ aboutToRefreshItem( fileitem );
+ fileitem->refresh();
+ emitRefreshItem( fileitem );
+ }
+ else
+ kdDebug(7004) << "item not found" << endl;
+ } else {
+ // For remote files, refresh() won't be able to figure out the new information.
+ // Let's update the dir.
+ KURL dir( *it );
+ dir.setPath( dir.directory( true ) );
+ if ( dirsToUpdate.find( dir ) == dirsToUpdate.end() )
+ dirsToUpdate.prepend( dir );
+ }
+ }
+
+ KURL::List::ConstIterator itdir = dirsToUpdate.begin();
+ for ( ; itdir != dirsToUpdate.end() ; ++itdir )
+ updateDirectory( *itdir );
+ // ## TODO problems with current jobs listing/updating that dir
+ // ( see kde-2.2.2's kdirlister )
+}
+
+void KDirListerCache::FileRenamed( const KURL &src, const KURL &dst )
+{
+ kdDebug(7004) << k_funcinfo << src.prettyURL() << " -> " << dst.prettyURL() << endl;
+#ifdef DEBUG_CACHE
+ printDebug();
+#endif
+
+ // Somehow this should only be called if src is a dir. But how could we know if it is?
+ // (Note that looking into itemsInUse isn't good enough. One could rename a subdir in a view.)
+ renameDir( src, dst );
+
+ // Now update the KFileItem representing that file or dir (not exclusive with the above!)
+ KURL oldurl( src );
+ oldurl.adjustPath( -1 );
+ KFileItem *fileitem = findByURL( 0, oldurl );
+ if ( fileitem )
+ {
+ if ( !fileitem->isLocalFile() && !fileitem->localPath().isEmpty() ) // it uses UDS_LOCAL_PATH? ouch, needs an update then
+ FilesChanged( src );
+ else
+ {
+ aboutToRefreshItem( fileitem );
+ fileitem->setURL( dst );
+ fileitem->refreshMimeType();
+ emitRefreshItem( fileitem );
+ }
+ }
+#ifdef DEBUG_CACHE
+ printDebug();
+#endif
+}
+
+void KDirListerCache::aboutToRefreshItem( KFileItem *fileitem )
+{
+ // Look whether this item was shown in any view, i.e. held by any dirlister
+ KURL parentDir( fileitem->url() );
+ parentDir.setPath( parentDir.directory() );
+ TQString parentDirURL = parentDir.url();
+ TQPtrList<KDirLister> *listers = urlsCurrentlyHeld[parentDirURL];
+ if ( listers )
+ for ( KDirLister *kdl = listers->first(); kdl; kdl = listers->next() )
+ kdl->aboutToRefreshItem( fileitem );
+
+ // Also look in urlsCurrentlyListed, in case the user manages to rename during a listing
+ listers = urlsCurrentlyListed[parentDirURL];
+ if ( listers )
+ for ( KDirLister *kdl = listers->first(); kdl; kdl = listers->next() )
+ kdl->aboutToRefreshItem( fileitem );
+}
+
+void KDirListerCache::emitRefreshItem( KFileItem *fileitem )
+{
+ // Look whether this item was shown in any view, i.e. held by any dirlister
+ KURL parentDir( fileitem->url() );
+ parentDir.setPath( parentDir.directory() );
+ TQString parentDirURL = parentDir.url();
+ TQPtrList<KDirLister> *listers = urlsCurrentlyHeld[parentDirURL];
+ if ( listers )
+ for ( KDirLister *kdl = listers->first(); kdl; kdl = listers->next() )
+ {
+ kdl->addRefreshItem( fileitem );
+ kdl->emitItems();
+ }
+
+ // Also look in urlsCurrentlyListed, in case the user manages to rename during a listing
+ listers = urlsCurrentlyListed[parentDirURL];
+ if ( listers )
+ for ( KDirLister *kdl = listers->first(); kdl; kdl = listers->next() )
+ {
+ kdl->addRefreshItem( fileitem );
+ kdl->emitItems();
+ }
+}
+
+KDirListerCache* KDirListerCache::self()
+{
+ if ( !s_pSelf )
+ s_pSelf = sd_KDirListerCache.setObject( s_pSelf, new KDirListerCache );
+
+ return s_pSelf;
+}
+
+bool KDirListerCache::exists()
+{
+ return s_pSelf != 0;
+}
+
+
+// private slots
+
+// _file can also be a directory being currently held!
+void KDirListerCache::slotFileDirty( const TQString& _file )
+{
+ kdDebug(7004) << k_funcinfo << _file << endl;
+
+ if ( !pendingUpdates[_file] )
+ {
+ KURL dir;
+ dir.setPath( _file );
+ if ( checkUpdate( dir.url(-1) ) )
+ updateDirectory( dir );
+
+ // the parent directory of _file
+ dir.setPath( dir.directory() );
+ if ( checkUpdate( dir.url() ) )
+ {
+ // Nice hack to save memory: use the qt object name to store the filename
+ TQTimer *timer = new TQTimer( this, _file.utf8() );
+ connect( timer, TQT_SIGNAL(timeout()), this, TQT_SLOT(slotFileDirtyDelayed()) );
+ pendingUpdates.insert( _file, timer );
+ timer->start( 500, true );
+ }
+ }
+}
+
+// delayed updating of files, FAM is flooding us with events
+void KDirListerCache::slotFileDirtyDelayed()
+{
+ TQString file = TQString::fromUtf8( TQT_TQOBJECT_CONST(sender())->name() );
+
+ kdDebug(7004) << k_funcinfo << file << endl;
+
+ // TODO: do it better: don't always create/delete the TQTimer but reuse it.
+ // Delete the timer after the parent directory is removed from the cache.
+ pendingUpdates.remove( file );
+
+ KURL u;
+ u.setPath( file );
+ KFileItem *item = findByURL( 0, u ); // search all items
+ if ( item )
+ {
+ // we need to refresh the item, because e.g. the permissions can have changed.
+ aboutToRefreshItem( item );
+ item->refresh();
+ emitRefreshItem( item );
+ }
+}
+
+void KDirListerCache::slotFileCreated( const TQString& _file )
+{
+ kdDebug(7004) << k_funcinfo << _file << endl;
+ // XXX: how to avoid a complete rescan here?
+ KURL u;
+ u.setPath( _file );
+ u.setPath( u.directory() );
+ FilesAdded( u );
+}
+
+void KDirListerCache::slotFileDeleted( const TQString& _file )
+{
+ kdDebug(7004) << k_funcinfo << _file << endl;
+ KURL u;
+ u.setPath( _file );
+ FilesRemoved( u );
+}
+
+void KDirListerCache::slotEntries( TDEIO::Job *job, const TDEIO::UDSEntryList &entries )
+{
+ KURL url = joburl( static_cast<TDEIO::ListJob *>(job) );
+ url.adjustPath(-1);
+ TQString urlStr = url.url();
+
+ kdDebug(7004) << k_funcinfo << "new entries for " << url << endl;
+
+ DirItem *dir = itemsInUse[urlStr];
+ Q_ASSERT( dir );
+
+ TQPtrList<KDirLister> *listers = urlsCurrentlyListed[urlStr];
+ Q_ASSERT( listers );
+ Q_ASSERT( !listers->isEmpty() );
+
+ // check if anyone wants the mimetypes immediately
+ bool delayedMimeTypes = true;
+ for ( KDirLister *kdl = listers->first(); kdl; kdl = listers->next() )
+ delayedMimeTypes = delayedMimeTypes && kdl->d->delayedMimeTypes;
+
+ // avoid creating these QStrings again and again
+ static const TQString& dot = TDEGlobal::staticQString(".");
+ static const TQString& dotdot = TDEGlobal::staticQString("..");
+
+ TDEIO::UDSEntryListConstIterator it = entries.begin();
+ TDEIO::UDSEntryListConstIterator end = entries.end();
+
+ for ( ; it != end; ++it )
+ {
+ TQString name;
+
+ // find out about the name
+ TDEIO::UDSEntry::ConstIterator entit = (*it).begin();
+ for( ; entit != (*it).end(); ++entit )
+ if ( (*entit).m_uds == TDEIO::UDS_NAME )
+ {
+ name = (*entit).m_str;
+ break;
+ }
+
+ Q_ASSERT( !name.isEmpty() );
+ if ( name.isEmpty() )
+ continue;
+
+ if ( name == dot )
+ {
+ Q_ASSERT( !dir->rootItem );
+ dir->rootItem = new KFileItem( *it, url, delayedMimeTypes, true );
+
+ for ( KDirLister *kdl = listers->first(); kdl; kdl = listers->next() )
+ if ( !kdl->d->rootFileItem && kdl->d->url == url )
+ kdl->d->rootFileItem = dir->rootItem;
+ }
+ else if ( name != dotdot )
+ {
+ KFileItem* item = new KFileItem( *it, url, delayedMimeTypes, true );
+ Q_ASSERT( item );
+
+ //kdDebug(7004)<< "Adding item: " << item->url() << endl;
+ dir->lstItems->append( item );
+
+ for ( KDirLister *kdl = listers->first(); kdl; kdl = listers->next() )
+ kdl->addNewItem( item );
+ }
+ }
+
+ for ( KDirLister *kdl = listers->first(); kdl; kdl = listers->next() )
+ kdl->emitItems();
+}
+
+void KDirListerCache::slotResult( TDEIO::Job *j )
+{
+ Q_ASSERT( j );
+ TDEIO::ListJob *job = static_cast<TDEIO::ListJob *>( j );
+ jobs.remove( job );
+
+ KURL jobUrl = joburl( job );
+ jobUrl.adjustPath(-1); // need remove trailing slashes again, in case of redirections
+ TQString jobUrlStr = jobUrl.url();
+
+ kdDebug(7004) << k_funcinfo << "finished listing " << jobUrl << endl;
+#ifdef DEBUG_CACHE
+ printDebug();
+#endif
+
+ TQPtrList<KDirLister> *listers = urlsCurrentlyListed.take( jobUrlStr );
+ Q_ASSERT( listers );
+
+ // move the directory to the held directories, do it before emitting
+ // the signals to make sure it exists in KDirListerCache in case someone
+ // calls listDir during the signal emission
+ Q_ASSERT( !urlsCurrentlyHeld[jobUrlStr] );
+ urlsCurrentlyHeld.insert( jobUrlStr, listers );
+
+ KDirLister *kdl;
+
+ if ( job->error() )
+ {
+ for ( kdl = listers->first(); kdl; kdl = listers->next() )
+ {
+ kdl->jobDone( job );
+ kdl->handleError( job );
+ emit kdl->canceled( jobUrl );
+ if ( kdl->numJobs() == 0 )
+ {
+ kdl->d->complete = true;
+ emit kdl->canceled();
+ }
+ }
+ }
+ else
+ {
+ DirItem *dir = itemsInUse[jobUrlStr];
+ Q_ASSERT( dir );
+ dir->complete = true;
+
+ for ( kdl = listers->first(); kdl; kdl = listers->next() )
+ {
+ kdl->jobDone( job );
+ emit kdl->completed( jobUrl );
+ if ( kdl->numJobs() == 0 )
+ {
+ kdl->d->complete = true;
+ emit kdl->completed();
+ }
+ }
+ }
+
+ // TODO: hmm, if there was an error and job is a parent of one or more
+ // of the pending urls we should cancel it/them as well
+ processPendingUpdates();
+
+#ifdef DEBUG_CACHE
+ printDebug();
+#endif
+}
+
+void KDirListerCache::slotRedirection( TDEIO::Job *j, const KURL& url )
+{
+ Q_ASSERT( j );
+ TDEIO::ListJob *job = static_cast<TDEIO::ListJob *>( j );
+
+ KURL oldUrl = job->url(); // here we really need the old url!
+ KURL newUrl = url;
+
+ // strip trailing slashes
+ oldUrl.adjustPath(-1);
+ newUrl.adjustPath(-1);
+
+ if ( oldUrl == newUrl )
+ {
+ kdDebug(7004) << k_funcinfo << "New redirection url same as old, giving up." << endl;
+ return;
+ }
+
+ kdDebug(7004) << k_funcinfo << oldUrl.prettyURL() << " -> " << newUrl.prettyURL() << endl;
+
+#ifdef DEBUG_CACHE
+ printDebug();
+#endif
+
+ // I don't think there can be dirItems that are childs of oldUrl.
+ // Am I wrong here? And even if so, we don't need to delete them, right?
+ // DF: redirection happens before listDir emits any item. Makes little sense otherwise.
+
+ // oldUrl cannot be in itemsCached because only completed items are moved there
+ DirItem *dir = itemsInUse.take( oldUrl.url() );
+ Q_ASSERT( dir );
+
+ TQPtrList<KDirLister> *listers = urlsCurrentlyListed.take( oldUrl.url() );
+ Q_ASSERT( listers );
+ Q_ASSERT( !listers->isEmpty() );
+
+ for ( KDirLister *kdl = listers->first(); kdl; kdl = listers->next() )
+ {
+ // TODO: put in own method?
+ if ( kdl->d->url.equals( oldUrl, true ) )
+ {
+ kdl->d->rootFileItem = 0;
+ kdl->d->url = newUrl;
+ }
+
+ *kdl->d->lstDirs.find( oldUrl ) = newUrl;
+
+ if ( kdl->d->lstDirs.count() == 1 )
+ {
+ emit kdl->clear();
+ emit kdl->redirection( newUrl );
+ emit kdl->redirection( oldUrl, newUrl );
+ }
+ else
+ {
+ emit kdl->clear( oldUrl );
+ emit kdl->redirection( oldUrl, newUrl );
+ }
+ }
+
+ // when a lister was stopped before the job emits the redirection signal, the old url will
+ // also be in urlsCurrentlyHeld
+ TQPtrList<KDirLister> *holders = urlsCurrentlyHeld.take( oldUrl.url() );
+ if ( holders )
+ {
+ Q_ASSERT( !holders->isEmpty() );
+
+ for ( KDirLister *kdl = holders->first(); kdl; kdl = holders->next() )
+ {
+ kdl->jobStarted( job );
+
+ // do it like when starting a new list-job that will redirect later
+ emit kdl->started( oldUrl );
+
+ // TODO: maybe don't emit started if there's an update running for newUrl already?
+
+ if ( kdl->d->url.equals( oldUrl, true ) )
+ {
+ kdl->d->rootFileItem = 0;
+ kdl->d->url = newUrl;
+ }
+
+ *kdl->d->lstDirs.find( oldUrl ) = newUrl;
+
+ if ( kdl->d->lstDirs.count() == 1 )
+ {
+ emit kdl->clear();
+ emit kdl->redirection( newUrl );
+ emit kdl->redirection( oldUrl, newUrl );
+ }
+ else
+ {
+ emit kdl->clear( oldUrl );
+ emit kdl->redirection( oldUrl, newUrl );
+ }
+ }
+ }
+
+ DirItem *newDir = itemsInUse[newUrl.url()];
+ if ( newDir )
+ {
+ kdDebug(7004) << "slotRedirection: " << newUrl.url() << " already in use" << endl;
+
+ // only in this case there can newUrl already be in urlsCurrentlyListed or urlsCurrentlyHeld
+ delete dir;
+
+ // get the job if one's running for newUrl already (can be a list-job or an update-job), but
+ // do not return this 'job', which would happen because of the use of redirectionURL()
+ TDEIO::ListJob *oldJob = jobForUrl( newUrl.url(), job );
+
+ // listers of newUrl with oldJob: forget about the oldJob and use the already running one
+ // which will be converted to an updateJob
+ TQPtrList<KDirLister> *curListers = urlsCurrentlyListed[newUrl.url()];
+ if ( curListers )
+ {
+ kdDebug(7004) << "slotRedirection: and it is currently listed" << endl;
+
+ Q_ASSERT( oldJob ); // ?!
+
+ for ( KDirLister *kdl = curListers->first(); kdl; kdl = curListers->next() ) // listers of newUrl
+ {
+ kdl->jobDone( oldJob );
+
+ kdl->jobStarted( job );
+ kdl->connectJob( job );
+ }
+
+ // append listers of oldUrl with newJob to listers of newUrl with oldJob
+ for ( KDirLister *kdl = listers->first(); kdl; kdl = listers->next() )
+ curListers->append( kdl );
+ }
+ else
+ urlsCurrentlyListed.insert( newUrl.url(), listers );
+
+ if ( oldJob ) // kill the old job, be it a list-job or an update-job
+ killJob( oldJob );
+
+ // holders of newUrl: use the already running job which will be converted to an updateJob
+ TQPtrList<KDirLister> *curHolders = urlsCurrentlyHeld[newUrl.url()];
+ if ( curHolders )
+ {
+ kdDebug(7004) << "slotRedirection: and it is currently held." << endl;
+
+ for ( KDirLister *kdl = curHolders->first(); kdl; kdl = curHolders->next() ) // holders of newUrl
+ {
+ kdl->jobStarted( job );
+ emit kdl->started( newUrl );
+ }
+
+ // append holders of oldUrl to holders of newUrl
+ if ( holders )
+ for ( KDirLister *kdl = holders->first(); kdl; kdl = holders->next() )
+ curHolders->append( kdl );
+ }
+ else if ( holders )
+ urlsCurrentlyHeld.insert( newUrl.url(), holders );
+
+
+ // emit old items: listers, holders. NOT: newUrlListers/newUrlHolders, they already have them listed
+ // TODO: make this a separate method?
+ for ( KDirLister *kdl = listers->first(); kdl; kdl = listers->next() )
+ {
+ if ( !kdl->d->rootFileItem && kdl->d->url == newUrl )
+ kdl->d->rootFileItem = newDir->rootItem;
+
+ kdl->addNewItems( *(newDir->lstItems) );
+ kdl->emitItems();
+ }
+
+ if ( holders )
+ {
+ for ( KDirLister *kdl = holders->first(); kdl; kdl = holders->next() )
+ {
+ if ( !kdl->d->rootFileItem && kdl->d->url == newUrl )
+ kdl->d->rootFileItem = newDir->rootItem;
+
+ kdl->addNewItems( *(newDir->lstItems) );
+ kdl->emitItems();
+ }
+ }
+ }
+ else if ( (newDir = itemsCached.take( newUrl.url() )) )
+ {
+ kdDebug(7004) << "slotRedirection: " << newUrl.url() << " is unused, but already in the cache." << endl;
+
+ delete dir;
+ itemsInUse.insert( newUrl.url(), newDir );
+ urlsCurrentlyListed.insert( newUrl.url(), listers );
+ if ( holders )
+ urlsCurrentlyHeld.insert( newUrl.url(), holders );
+
+ // emit old items: listers, holders
+ for ( KDirLister *kdl = listers->first(); kdl; kdl = listers->next() )
+ {
+ if ( !kdl->d->rootFileItem && kdl->d->url == newUrl )
+ kdl->d->rootFileItem = newDir->rootItem;
+
+ kdl->addNewItems( *(newDir->lstItems) );
+ kdl->emitItems();
+ }
+
+ if ( holders )
+ {
+ for ( KDirLister *kdl = holders->first(); kdl; kdl = holders->next() )
+ {
+ if ( !kdl->d->rootFileItem && kdl->d->url == newUrl )
+ kdl->d->rootFileItem = newDir->rootItem;
+
+ kdl->addNewItems( *(newDir->lstItems) );
+ kdl->emitItems();
+ }
+ }
+ }
+ else
+ {
+ kdDebug(7004) << "slotRedirection: " << newUrl.url() << " has not been listed yet." << endl;
+
+ delete dir->rootItem;
+ dir->rootItem = 0;
+ dir->lstItems->clear();
+ dir->redirect( newUrl );
+ itemsInUse.insert( newUrl.url(), dir );
+ urlsCurrentlyListed.insert( newUrl.url(), listers );
+
+ if ( holders )
+ urlsCurrentlyHeld.insert( newUrl.url(), holders );
+ else
+ {
+#ifdef DEBUG_CACHE
+ printDebug();
+#endif
+ return; // only in this case the job doesn't need to be converted,
+ }
+ }
+
+ // make the job an update job
+ job->disconnect( this );
+
+ connect( job, TQT_SIGNAL(entries( TDEIO::Job *, const TDEIO::UDSEntryList & )),
+ this, TQT_SLOT(slotUpdateEntries( TDEIO::Job *, const TDEIO::UDSEntryList & )) );
+ connect( job, TQT_SIGNAL(result( TDEIO::Job * )),
+ this, TQT_SLOT(slotUpdateResult( TDEIO::Job * )) );
+
+ // FIXME: autoUpdate-Counts!!
+
+#ifdef DEBUG_CACHE
+ printDebug();
+#endif
+}
+
+void KDirListerCache::renameDir( const KURL &oldUrl, const KURL &newUrl )
+{
+ kdDebug(7004) << k_funcinfo << oldUrl.prettyURL() << " -> " << newUrl.prettyURL() << endl;
+ TQString oldUrlStr = oldUrl.url(-1);
+ TQString newUrlStr = newUrl.url(-1);
+
+ // Not enough. Also need to look at any child dir, even sub-sub-sub-dir.
+ //DirItem *dir = itemsInUse.take( oldUrlStr );
+ //emitRedirections( oldUrl, url );
+
+ // Look at all dirs being listed/shown
+ TQDictIterator<DirItem> itu( itemsInUse );
+ bool goNext;
+ while ( itu.current() )
+ {
+ goNext = true;
+ DirItem *dir = itu.current();
+ KURL oldDirUrl ( itu.currentKey() );
+ //kdDebug(7004) << "itemInUse: " << oldDirUrl.prettyURL() << endl;
+ // Check if this dir is oldUrl, or a subfolder of it
+ if ( oldUrl.isParentOf( oldDirUrl ) )
+ {
+ // TODO should use KURL::cleanpath like isParentOf does
+ TQString relPath = oldDirUrl.path().mid( oldUrl.path().length() );
+
+ KURL newDirUrl( newUrl ); // take new base
+ if ( !relPath.isEmpty() )
+ newDirUrl.addPath( relPath ); // add unchanged relative path
+ //kdDebug(7004) << "KDirListerCache::renameDir new url=" << newDirUrl.prettyURL() << endl;
+
+ // Update URL in dir item and in itemsInUse
+ dir->redirect( newDirUrl );
+ itemsInUse.remove( itu.currentKey() ); // implies ++itu
+ itemsInUse.insert( newDirUrl.url(-1), dir );
+ goNext = false; // because of the implied ++itu above
+ if ( dir->lstItems )
+ {
+ // Rename all items under that dir
+ KFileItemListIterator kit( *dir->lstItems );
+ for ( ; kit.current(); ++kit )
+ {
+ KURL oldItemUrl = (*kit)->url();
+ TQString oldItemUrlStr( oldItemUrl.url(-1) );
+ KURL newItemUrl( oldItemUrl );
+ newItemUrl.setPath( newDirUrl.path() );
+ newItemUrl.addPath( oldItemUrl.fileName() );
+ kdDebug(7004) << "KDirListerCache::renameDir renaming " << oldItemUrlStr << " to " << newItemUrl.url() << endl;
+ (*kit)->setURL( newItemUrl );
+ }
+ }
+ emitRedirections( oldDirUrl, newDirUrl );
+ }
+ if ( goNext )
+ ++itu;
+ }
+
+ // Is oldUrl a directory in the cache?
+ // Remove any child of oldUrl from the cache - even if the renamed dir itself isn't in it!
+ removeDirFromCache( oldUrl );
+ // TODO rename, instead.
+}
+
+void KDirListerCache::emitRedirections( const KURL &oldUrl, const KURL &url )
+{
+ kdDebug(7004) << k_funcinfo << oldUrl.prettyURL() << " -> " << url.prettyURL() << endl;
+ TQString oldUrlStr = oldUrl.url(-1);
+ TQString urlStr = url.url(-1);
+
+ TDEIO::ListJob *job = jobForUrl( oldUrlStr );
+ if ( job )
+ killJob( job );
+
+ // Check if we were listing this dir. Need to abort and restart with new name in that case.
+ TQPtrList<KDirLister> *listers = urlsCurrentlyListed.take( oldUrlStr );
+ if ( listers )
+ {
+ // Tell the world that the job listing the old url is dead.
+ for ( KDirLister *kdl = listers->first(); kdl; kdl = listers->next() )
+ {
+ if ( job )
+ kdl->jobDone( job );
+
+ emit kdl->canceled( oldUrl );
+ }
+
+ urlsCurrentlyListed.insert( urlStr, listers );
+ }
+
+ // Check if we are currently displaying this directory (odds opposite wrt above)
+ // Update urlsCurrentlyHeld dict with new URL
+ TQPtrList<KDirLister> *holders = urlsCurrentlyHeld.take( oldUrlStr );
+ if ( holders )
+ {
+ if ( job )
+ for ( KDirLister *kdl = holders->first(); kdl; kdl = holders->next() )
+ kdl->jobDone( job );
+
+ urlsCurrentlyHeld.insert( urlStr, holders );
+ }
+
+ if ( listers )
+ {
+ updateDirectory( url );
+
+ // Tell the world about the new url
+ for ( KDirLister *kdl = listers->first(); kdl; kdl = listers->next() )
+ emit kdl->started( url );
+ }
+
+ if ( holders )
+ {
+ // And notify the dirlisters of the redirection
+ for ( KDirLister *kdl = holders->first(); kdl; kdl = holders->next() )
+ {
+ *kdl->d->lstDirs.find( oldUrl ) = url;
+
+ if ( kdl->d->lstDirs.count() == 1 )
+ emit kdl->redirection( url );
+
+ emit kdl->redirection( oldUrl, url );
+ }
+ }
+}
+
+void KDirListerCache::removeDirFromCache( const KURL& dir )
+{
+ kdDebug(7004) << "KDirListerCache::removeDirFromCache " << dir.prettyURL() << endl;
+ TQCacheIterator<DirItem> itc( itemsCached );
+ while ( itc.current() )
+ {
+ if ( dir.isParentOf( KURL( itc.currentKey() ) ) )
+ itemsCached.remove( itc.currentKey() );
+ else
+ ++itc;
+ }
+}
+
+void KDirListerCache::slotUpdateEntries( TDEIO::Job* job, const TDEIO::UDSEntryList& list )
+{
+ jobs[static_cast<TDEIO::ListJob*>(job)] += list;
+}
+
+void KDirListerCache::slotUpdateResult( TDEIO::Job * j )
+{
+ Q_ASSERT( j );
+ TDEIO::ListJob *job = static_cast<TDEIO::ListJob *>( j );
+
+ KURL jobUrl = joburl( job );
+ jobUrl.adjustPath(-1); // need remove trailing slashes again, in case of redirections
+ TQString jobUrlStr = jobUrl.url();
+
+ kdDebug(7004) << k_funcinfo << "finished update " << jobUrl << endl;
+
+ KDirLister *kdl;
+
+ TQPtrList<KDirLister> *listers = urlsCurrentlyHeld[jobUrlStr];
+ TQPtrList<KDirLister> *tmpLst = urlsCurrentlyListed.take( jobUrlStr );
+
+ if ( tmpLst )
+ {
+ if ( listers )
+ for ( kdl = tmpLst->first(); kdl; kdl = tmpLst->next() )
+ {
+ Q_ASSERT( listers->containsRef( kdl ) == 0 );
+ listers->append( kdl );
+ }
+ else
+ {
+ listers = tmpLst;
+ urlsCurrentlyHeld.insert( jobUrlStr, listers );
+ }
+ }
+
+ // once we are updating dirs that are only in the cache this will fail!
+ Q_ASSERT( listers );
+
+ if ( job->error() )
+ {
+ for ( kdl = listers->first(); kdl; kdl = listers->next() )
+ {
+ kdl->jobDone( job );
+
+ //don't bother the user
+ //kdl->handleError( job );
+
+ emit kdl->canceled( jobUrl );
+ if ( kdl->numJobs() == 0 )
+ {
+ kdl->d->complete = true;
+ emit kdl->canceled();
+ }
+ }
+
+ jobs.remove( job );
+
+ // TODO: if job is a parent of one or more
+ // of the pending urls we should cancel them
+ processPendingUpdates();
+ return;
+ }
+
+ DirItem *dir = itemsInUse[jobUrlStr];
+ dir->complete = true;
+
+
+ // check if anyone wants the mimetypes immediately
+ bool delayedMimeTypes = true;
+ for ( kdl = listers->first(); kdl; kdl = listers->next() )
+ delayedMimeTypes = delayedMimeTypes && kdl->d->delayedMimeTypes;
+
+ // should be enough to get reasonable speed in most cases
+ TQDict<KFileItem> fileItems( 9973 );
+
+ KFileItemListIterator kit ( *(dir->lstItems) );
+
+ // Unmark all items in url
+ for ( ; kit.current(); ++kit )
+ {
+ (*kit)->unmark();
+ fileItems.insert( (*kit)->url().url(), *kit );
+ }
+
+ static const TQString& dot = TDEGlobal::staticQString(".");
+ static const TQString& dotdot = TDEGlobal::staticQString("..");
+
+ KFileItem *item = 0, *tmp;
+
+ TQValueList<TDEIO::UDSEntry> buf = jobs[job];
+ TQValueListIterator<TDEIO::UDSEntry> it = buf.begin();
+ for ( ; it != buf.end(); ++it )
+ {
+ // Form the complete url
+ if ( !item )
+ item = new KFileItem( *it, jobUrl, delayedMimeTypes, true );
+ else
+ item->setUDSEntry( *it, jobUrl, delayedMimeTypes, true );
+
+ // Find out about the name
+ TQString name = item->name();
+ Q_ASSERT( !name.isEmpty() );
+
+ // we duplicate the check for dotdot here, to avoid iterating over
+ // all items again and checking in matchesFilter() that way.
+ if ( name.isEmpty() || name == dotdot )
+ continue;
+
+ if ( name == dot )
+ {
+ // if the update was started before finishing the original listing
+ // there is no root item yet
+ if ( !dir->rootItem )
+ {
+ dir->rootItem = item;
+ item = 0;
+
+ for ( KDirLister *kdl = listers->first(); kdl; kdl = listers->next() )
+ if ( !kdl->d->rootFileItem && kdl->d->url == jobUrl )
+ kdl->d->rootFileItem = dir->rootItem;
+ }
+
+ continue;
+ }
+
+ // Find this item
+ if ( (tmp = fileItems[item->url().url()]) )
+ {
+ tmp->mark();
+
+ // check if something changed for this file
+ if ( !tmp->cmp( *item ) )
+ {
+ for ( kdl = listers->first(); kdl; kdl = listers->next() )
+ kdl->aboutToRefreshItem( tmp );
+
+ //kdDebug(7004) << "slotUpdateResult: file changed: " << tmp->name() << endl;
+ tmp->assign( *item );
+
+ for ( kdl = listers->first(); kdl; kdl = listers->next() )
+ kdl->addRefreshItem( tmp );
+ }
+ }
+ else // this is a new file
+ {
+ //kdDebug(7004) << "slotUpdateResult: new file: " << name << endl;
+
+ item->mark();
+ dir->lstItems->append( item );
+
+ for ( kdl = listers->first(); kdl; kdl = listers->next() )
+ kdl->addNewItem( item );
+
+ // item used, we need a new one for the next iteration
+ item = 0;
+ }
+ }
+
+ if ( item )
+ delete item;
+
+ jobs.remove( job );
+
+ deleteUnmarkedItems( listers, dir->lstItems );
+
+ for ( kdl = listers->first(); kdl; kdl = listers->next() )
+ {
+ kdl->emitItems();
+
+ kdl->jobDone( job );
+
+ emit kdl->completed( jobUrl );
+ if ( kdl->numJobs() == 0 )
+ {
+ kdl->d->complete = true;
+ emit kdl->completed();
+ }
+ }
+
+ // TODO: hmm, if there was an error and job is a parent of one or more
+ // of the pending urls we should cancel it/them as well
+ processPendingUpdates();
+}
+
+// private
+
+TDEIO::ListJob *KDirListerCache::jobForUrl( const TQString& url, TDEIO::ListJob *not_job )
+{
+ TDEIO::ListJob *job;
+ TQMap< TDEIO::ListJob *, TQValueList<TDEIO::UDSEntry> >::Iterator it = jobs.begin();
+ while ( it != jobs.end() )
+ {
+ job = it.key();
+ if ( joburl( job ).url(-1) == url && job != not_job )
+ return job;
+ ++it;
+ }
+ return 0;
+}
+
+const KURL& KDirListerCache::joburl( TDEIO::ListJob *job )
+{
+ if ( job->redirectionURL().isValid() )
+ return job->redirectionURL();
+ else
+ return job->url();
+}
+
+void KDirListerCache::killJob( TDEIO::ListJob *job )
+{
+ jobs.remove( job );
+ job->disconnect( this );
+ job->kill();
+}
+
+void KDirListerCache::deleteUnmarkedItems( TQPtrList<KDirLister> *listers, KFileItemList *lstItems )
+{
+ // Find all unmarked items and delete them
+ KFileItem* item;
+ lstItems->first();
+ while ( (item = lstItems->current()) )
+ if ( !item->isMarked() )
+ {
+ //kdDebug() << k_funcinfo << item->name() << endl;
+ for ( KDirLister *kdl = listers->first(); kdl; kdl = listers->next() )
+ kdl->emitDeleteItem( item );
+
+ if ( item->isDir() )
+ deleteDir( item->url() );
+
+ // finally actually delete the item
+ lstItems->take();
+ delete item;
+ }
+ else
+ lstItems->next();
+}
+
+void KDirListerCache::deleteDir( const KURL& dirUrl )
+{
+ //kdDebug() << k_funcinfo << dirUrl.prettyURL() << endl;
+ // unregister and remove the childs of the deleted item.
+ // Idea: tell all the KDirListers that they should forget the dir
+ // and then remove it from the cache.
+
+ TQDictIterator<DirItem> itu( itemsInUse );
+ while ( itu.current() )
+ {
+ KURL deletedUrl( itu.currentKey() );
+ if ( dirUrl.isParentOf( deletedUrl ) )
+ {
+ // stop all jobs for deletedUrl
+
+ TQPtrList<KDirLister> *kdls = urlsCurrentlyListed[deletedUrl.url()];
+ if ( kdls ) // yeah, I lack good names
+ {
+ // we need a copy because stop modifies the list
+ kdls = new TQPtrList<KDirLister>( *kdls );
+ for ( KDirLister *kdl = kdls->first(); kdl; kdl = kdls->next() )
+ stop( kdl, deletedUrl );
+
+ delete kdls;
+ }
+
+ // tell listers holding deletedUrl to forget about it
+ // this will stop running updates for deletedUrl as well
+
+ kdls = urlsCurrentlyHeld[deletedUrl.url()];
+ if ( kdls )
+ {
+ // we need a copy because forgetDirs modifies the list
+ kdls = new TQPtrList<KDirLister>( *kdls );
+
+ for ( KDirLister *kdl = kdls->first(); kdl; kdl = kdls->next() )
+ {
+ // lister's root is the deleted item
+ if ( kdl->d->url == deletedUrl )
+ {
+ // tell the view first. It might need the subdirs' items (which forgetDirs will delete)
+ if ( kdl->d->rootFileItem )
+ emit kdl->deleteItem( kdl->d->rootFileItem );
+ forgetDirs( kdl );
+ kdl->d->rootFileItem = 0;
+ }
+ else
+ {
+ bool treeview = kdl->d->lstDirs.count() > 1;
+ if ( !treeview )
+ emit kdl->clear();
+
+ forgetDirs( kdl, deletedUrl, treeview );
+ }
+ }
+
+ delete kdls;
+ }
+
+ // delete the entry for deletedUrl - should not be needed, it's in
+ // items cached now
+
+ DirItem *dir = itemsInUse.take( deletedUrl.url() );
+ Q_ASSERT( !dir );
+ if ( !dir ) // take didn't find it - move on
+ ++itu;
+ }
+ else
+ ++itu;
+ }
+
+ // remove the children from the cache
+ removeDirFromCache( dirUrl );
+}
+
+void KDirListerCache::processPendingUpdates()
+{
+ // TODO
+}
+
+#ifndef NDEBUG
+void KDirListerCache::printDebug()
+{
+ kdDebug(7004) << "Items in use: " << endl;
+ TQDictIterator<DirItem> itu( itemsInUse );
+ for ( ; itu.current() ; ++itu ) {
+ kdDebug(7004) << " " << itu.currentKey() << " URL: " << itu.current()->url
+ << " rootItem: " << ( itu.current()->rootItem ? itu.current()->rootItem->url() : KURL() )
+ << " autoUpdates refcount: " << itu.current()->autoUpdates
+ << " complete: " << itu.current()->complete
+ << ( itu.current()->lstItems ? TQString(" with %1 items.").arg(itu.current()->lstItems->count()) : TQString(" lstItems=NULL") ) << endl;
+ }
+
+ kdDebug(7004) << "urlsCurrentlyHeld: " << endl;
+ TQDictIterator< TQPtrList<KDirLister> > it( urlsCurrentlyHeld );
+ for ( ; it.current() ; ++it )
+ {
+ TQString list;
+ for ( TQPtrListIterator<KDirLister> listit( *it.current() ); listit.current(); ++listit )
+ list += " 0x" + TQString::number( (long)listit.current(), 16 );
+ kdDebug(7004) << " " << it.currentKey() << " " << it.current()->count() << " listers: " << list << endl;
+ }
+
+ kdDebug(7004) << "urlsCurrentlyListed: " << endl;
+ TQDictIterator< TQPtrList<KDirLister> > it2( urlsCurrentlyListed );
+ for ( ; it2.current() ; ++it2 )
+ {
+ TQString list;
+ for ( TQPtrListIterator<KDirLister> listit( *it2.current() ); listit.current(); ++listit )
+ list += " 0x" + TQString::number( (long)listit.current(), 16 );
+ kdDebug(7004) << " " << it2.currentKey() << " " << it2.current()->count() << " listers: " << list << endl;
+ }
+
+ TQMap< TDEIO::ListJob *, TQValueList<TDEIO::UDSEntry> >::Iterator jit = jobs.begin();
+ kdDebug(7004) << "Jobs: " << endl;
+ for ( ; jit != jobs.end() ; ++jit )
+ kdDebug(7004) << " " << jit.key() << " listing " << joburl( jit.key() ).prettyURL() << ": " << (*jit).count() << " entries." << endl;
+
+ kdDebug(7004) << "Items in cache: " << endl;
+ TQCacheIterator<DirItem> itc( itemsCached );
+ for ( ; itc.current() ; ++itc )
+ kdDebug(7004) << " " << itc.currentKey() << " rootItem: "
+ << ( itc.current()->rootItem ? itc.current()->rootItem->url().prettyURL() : TQString("NULL") )
+ << ( itc.current()->lstItems ? TQString(" with %1 items.").arg(itc.current()->lstItems->count()) : TQString(" lstItems=NULL") ) << endl;
+}
+#endif
+
+/*********************** -- The new KDirLister -- ************************/
+
+
+KDirLister::KDirLister( bool _delayedMimeTypes )
+{
+ kdDebug(7003) << "+KDirLister" << endl;
+
+ d = new KDirListerPrivate;
+
+ d->complete = true;
+ d->delayedMimeTypes = _delayedMimeTypes;
+
+ setAutoUpdate( true );
+ setDirOnlyMode( false );
+ setShowingDotFiles( false );
+
+ setAutoErrorHandlingEnabled( true, 0 );
+}
+
+KDirLister::~KDirLister()
+{
+ kdDebug(7003) << "-KDirLister" << endl;
+
+ if ( KDirListerCache::exists() )
+ {
+ // Stop all running jobs
+ stop();
+ s_pCache->forgetDirs( this );
+ }
+
+ delete d;
+}
+
+bool KDirLister::openURL( const KURL& _url, bool _keep, bool _reload )
+{
+ kdDebug(7003) << k_funcinfo << _url.prettyURL()
+ << " keep=" << _keep << " reload=" << _reload << endl;
+
+ // emit the current changes made to avoid an inconsistent treeview
+ if ( d->changes != NONE && _keep )
+ emitChanges();
+
+ d->changes = NONE;
+
+ // If a local path is available, monitor that instead of the given remote URL...
+ KURL realURL = _url;
+ if (!realURL.isLocalFile()) {
+ TDEIO::LocalURLJob* localURLJob = TDEIO::localURL(_url);
+ if (localURLJob) {
+ connect(localURLJob, TQT_SIGNAL(localURL(TDEIO::Job*, const KURL&, bool)), this, TQT_SLOT(slotLocalURL(TDEIO::Job*, const KURL&, bool)));
+ connect(localURLJob, TQT_SIGNAL(destroyed()), this, TQT_SLOT(slotLocalURLKIODestroyed()));
+ d->localURLSlotFired = false;
+ while (!d->localURLSlotFired) {
+ tqApp->eventLoop()->processEvents(TQEventLoop::ExcludeUserInput);
+ usleep(1000);
+ }
+ if (d->localURLResultIsLocal) {
+ realURL = d->localURLResultURL;
+ }
+ }
+ }
+
+ return s_pCache->listDir( this, realURL, _keep, _reload );
+}
+
+void KDirLister::slotLocalURL(TDEIO::Job *job, const KURL& url, bool isLocal) {
+ d->localURLSlotFired = true;
+ d->localURLResultURL = url;
+ d->localURLResultIsLocal = isLocal;
+}
+
+void KDirLister::slotLocalURLKIODestroyed() {
+ if (!d->localURLSlotFired) {
+ d->localURLSlotFired = true;
+ d->localURLResultURL = KURL();
+ d->localURLResultIsLocal = false;
+ }
+}
+
+void KDirLister::stop()
+{
+ kdDebug(7003) << k_funcinfo << endl;
+ s_pCache->stop( this );
+}
+
+void KDirLister::stop( const KURL& _url )
+{
+ kdDebug(7003) << k_funcinfo << _url.prettyURL() << endl;
+ s_pCache->stop( this, _url );
+}
+
+bool KDirLister::autoUpdate() const
+{
+ return d->autoUpdate;
+}
+
+void KDirLister::setAutoUpdate( bool _enable )
+{
+ if ( d->autoUpdate == _enable )
+ return;
+
+ d->autoUpdate = _enable;
+ s_pCache->setAutoUpdate( this, _enable );
+}
+
+bool KDirLister::showingDotFiles() const
+{
+ return d->isShowingDotFiles;
+}
+
+void KDirLister::setShowingDotFiles( bool _showDotFiles )
+{
+ if ( d->isShowingDotFiles == _showDotFiles )
+ return;
+
+ d->isShowingDotFiles = _showDotFiles;
+ d->changes ^= DOT_FILES;
+}
+
+bool KDirLister::dirOnlyMode() const
+{
+ return d->dirOnlyMode;
+}
+
+void KDirLister::setDirOnlyMode( bool _dirsOnly )
+{
+ if ( d->dirOnlyMode == _dirsOnly )
+ return;
+
+ d->dirOnlyMode = _dirsOnly;
+ d->changes ^= DIR_ONLY_MODE;
+}
+
+bool KDirLister::autoErrorHandlingEnabled() const
+{
+ return d->autoErrorHandling;
+}
+
+void KDirLister::setAutoErrorHandlingEnabled( bool enable, TQWidget* parent )
+{
+ d->autoErrorHandling = enable;
+ d->errorParent = parent;
+}
+
+const KURL& KDirLister::url() const
+{
+ return d->url;
+}
+
+const KURL::List& KDirLister::directories() const
+{
+ return d->lstDirs;
+}
+
+void KDirLister::emitChanges()
+{
+ if ( d->changes == NONE )
+ return;
+
+ static const TQString& dot = TDEGlobal::staticQString(".");
+ static const TQString& dotdot = TDEGlobal::staticQString("..");
+
+ for ( KURL::List::Iterator it = d->lstDirs.begin();
+ it != d->lstDirs.end(); ++it )
+ {
+ KFileItemListIterator kit( *s_pCache->itemsForDir( *it ) );
+ for ( ; kit.current(); ++kit )
+ {
+ if ( (*kit)->text() == dot || (*kit)->text() == dotdot )
+ continue;
+
+ bool oldMime = true, newMime = true;
+
+ if ( d->changes & MIME_FILTER )
+ {
+ oldMime = doMimeFilter( (*kit)->mimetype(), d->oldMimeFilter )
+ && doMimeExcludeFilter( (*kit)->mimetype(), d->oldMimeExcludeFilter );
+ newMime = doMimeFilter( (*kit)->mimetype(), d->mimeFilter )
+ && doMimeExcludeFilter( (*kit)->mimetype(), d->mimeExcludeFilter );
+
+ if ( oldMime && !newMime )
+ {
+ emit deleteItem( *kit );
+ continue;
+ }
+ }
+
+ if ( d->changes & DIR_ONLY_MODE )
+ {
+ // the lister switched to dirOnlyMode
+ if ( d->dirOnlyMode )
+ {
+ if ( !(*kit)->isDir() )
+ emit deleteItem( *kit );
+ }
+ else if ( !(*kit)->isDir() )
+ addNewItem( *kit );
+
+ continue;
+ }
+
+ if ( (*kit)->isHidden() )
+ {
+ if ( d->changes & DOT_FILES )
+ {
+ // the lister switched to dot files mode
+ if ( d->isShowingDotFiles )
+ addNewItem( *kit );
+ else
+ emit deleteItem( *kit );
+
+ continue;
+ }
+ }
+ else if ( d->changes & NAME_FILTER )
+ {
+ bool oldName = (*kit)->isDir() ||
+ d->oldFilters.isEmpty() ||
+ doNameFilter( (*kit)->text(), d->oldFilters );
+
+ bool newName = (*kit)->isDir() ||
+ d->lstFilters.isEmpty() ||
+ doNameFilter( (*kit)->text(), d->lstFilters );
+
+ if ( oldName && !newName )
+ {
+ emit deleteItem( *kit );
+ continue;
+ }
+ else if ( !oldName && newName )
+ addNewItem( *kit );
+ }
+
+ if ( (d->changes & MIME_FILTER) && !oldMime && newMime )
+ addNewItem( *kit );
+ }
+
+ emitItems();
+ }
+
+ d->changes = NONE;
+}
+
+void KDirLister::updateDirectory( const KURL& _u )
+{
+ s_pCache->updateDirectory( _u );
+}
+
+bool KDirLister::isFinished() const
+{
+ return d->complete;
+}
+
+KFileItem *KDirLister::rootItem() const
+{
+ return d->rootFileItem;
+}
+
+KFileItem *KDirLister::findByURL( const KURL& _url ) const
+{
+ return s_pCache->findByURL( this, _url );
+}
+
+KFileItem *KDirLister::findByName( const TQString& _name ) const
+{
+ return s_pCache->findByName( this, _name );
+}
+
+#ifndef KDE_NO_COMPAT
+KFileItem *KDirLister::find( const KURL& _url ) const
+{
+ return findByURL( _url );
+}
+#endif
+
+
+// ================ public filter methods ================ //
+
+void KDirLister::setNameFilter( const TQString& nameFilter )
+{
+ if ( !(d->changes & NAME_FILTER) )
+ {
+ d->oldFilters = d->lstFilters;
+ d->lstFilters.setAutoDelete( false );
+ }
+
+ d->lstFilters.clear();
+ d->lstFilters.setAutoDelete( true );
+
+ d->nameFilter = nameFilter;
+
+ // Split on white space
+ TQStringList list = TQStringList::split( ' ', nameFilter );
+ for ( TQStringList::Iterator it = list.begin(); it != list.end(); ++it )
+ d->lstFilters.append( new TQRegExp(*it, false, true ) );
+
+ d->changes |= NAME_FILTER;
+}
+
+const TQString& KDirLister::nameFilter() const
+{
+ return d->nameFilter;
+}
+
+void KDirLister::setMimeFilter( const TQStringList& mimeFilter )
+{
+ if ( !(d->changes & MIME_FILTER) )
+ d->oldMimeFilter = d->mimeFilter;
+
+ if ( mimeFilter.find("all/allfiles") != mimeFilter.end() ||
+ mimeFilter.find("all/all") != mimeFilter.end() )
+ d->mimeFilter.clear();
+ else
+ d->mimeFilter = mimeFilter;
+
+ d->changes |= MIME_FILTER;
+}
+
+void KDirLister::setMimeExcludeFilter( const TQStringList& mimeExcludeFilter )
+{
+ if ( !(d->changes & MIME_FILTER) )
+ d->oldMimeExcludeFilter = d->mimeExcludeFilter;
+
+ d->mimeExcludeFilter = mimeExcludeFilter;
+ d->changes |= MIME_FILTER;
+}
+
+
+void KDirLister::clearMimeFilter()
+{
+ if ( !(d->changes & MIME_FILTER) )
+ {
+ d->oldMimeFilter = d->mimeFilter;
+ d->oldMimeExcludeFilter = d->mimeExcludeFilter;
+ }
+ d->mimeFilter.clear();
+ d->mimeExcludeFilter.clear();
+ d->changes |= MIME_FILTER;
+}
+
+const TQStringList& KDirLister::mimeFilters() const
+{
+ return d->mimeFilter;
+}
+
+bool KDirLister::matchesFilter( const TQString& name ) const
+{
+ return doNameFilter( name, d->lstFilters );
+}
+
+bool KDirLister::matchesMimeFilter( const TQString& mime ) const
+{
+ return doMimeFilter( mime, d->mimeFilter ) && doMimeExcludeFilter(mime,d->mimeExcludeFilter);
+}
+
+// ================ protected methods ================ //
+
+bool KDirLister::matchesFilter( const KFileItem *item ) const
+{
+ Q_ASSERT( item );
+ static const TQString& dotdot = TDEGlobal::staticQString("..");
+
+ if ( item->text() == dotdot )
+ return false;
+
+ if ( !d->isShowingDotFiles && item->isHidden() )
+ return false;
+
+ if ( item->isDir() || d->lstFilters.isEmpty() )
+ return true;
+
+ return matchesFilter( item->text() );
+}
+
+bool KDirLister::matchesMimeFilter( const KFileItem *item ) const
+{
+ Q_ASSERT( item );
+ // Don't lose time determining the mimetype if there is no filter
+ if ( d->mimeFilter.isEmpty() && d->mimeExcludeFilter.isEmpty() )
+ return true;
+ return matchesMimeFilter( item->mimetype() );
+}
+
+bool KDirLister::doNameFilter( const TQString& name, const TQPtrList<TQRegExp>& filters ) const
+{
+ for ( TQPtrListIterator<TQRegExp> it( filters ); it.current(); ++it )
+ if ( it.current()->exactMatch( name ) )
+ return true;
+
+ return false;
+}
+
+bool KDirLister::doMimeFilter( const TQString& mime, const TQStringList& filters ) const
+{
+ if ( filters.isEmpty() )
+ return true;
+
+ KMimeType::Ptr mimeptr = KMimeType::mimeType(mime);
+ //kdDebug(7004) << "doMimeFilter: investigating: "<<mimeptr->name()<<endl;
+ TQStringList::ConstIterator it = filters.begin();
+ for ( ; it != filters.end(); ++it )
+ if ( mimeptr->is(*it) )
+ return true;
+ //else kdDebug(7004) << "doMimeFilter: compared without result to "<<*it<<endl;
+
+
+ return false;
+}
+
+bool KDirLister::doMimeExcludeFilter( const TQString& mime, const TQStringList& filters ) const
+{
+ if ( filters.isEmpty() )
+ return true;
+
+ TQStringList::ConstIterator it = filters.begin();
+ for ( ; it != filters.end(); ++it )
+ if ( (*it) == mime )
+ return false;
+
+ return true;
+}
+
+
+bool KDirLister::validURL( const KURL& _url ) const
+{
+ return s_pCache->validURL( this, _url );
+}
+
+void KDirLister::handleError( TDEIO::Job *job )
+{
+ if ( d->autoErrorHandling )
+ job->showErrorDialog( d->errorParent );
+}
+
+
+// ================= private methods ================= //
+
+void KDirLister::addNewItem( const KFileItem *item )
+{
+ if ( ( d->dirOnlyMode && !item->isDir() ) || !matchesFilter( item ) )
+ return; // No reason to continue... bailing out here prevents a mimetype scan.
+
+ if ( matchesMimeFilter( item ) )
+ {
+ if ( !d->lstNewItems )
+ d->lstNewItems = new KFileItemList;
+
+ d->lstNewItems->append( item ); // items not filtered
+ }
+ else
+ {
+ if ( !d->lstMimeFilteredItems )
+ d->lstMimeFilteredItems = new KFileItemList;
+
+ d->lstMimeFilteredItems->append( item ); // only filtered by mime
+ }
+}
+
+void KDirLister::addNewItems( const KFileItemList& items )
+{
+ // TODO: make this faster - test if we have a filter at all first
+ // DF: was this profiled? The matchesFoo() functions should be fast, w/o filters...
+ // Of course if there is no filter and we can do a range-insertion instead of a loop, that might be good.
+ // But that's for Qt4, not possible with TQPtrList.
+ for ( KFileItemListIterator kit( items ); kit.current(); ++kit )
+ addNewItem( *kit );
+}
+
+void KDirLister::aboutToRefreshItem( const KFileItem *item )
+{
+ // The code here follows the logic in addNewItem
+ if ( ( d->dirOnlyMode && !item->isDir() ) || !matchesFilter( item ) )
+ d->refreshItemWasFiltered = true;
+ else if ( !matchesMimeFilter( item ) )
+ d->refreshItemWasFiltered = true;
+ else
+ d->refreshItemWasFiltered = false;
+}
+
+void KDirLister::addRefreshItem( const KFileItem *item )
+{
+ bool isExcluded = (d->dirOnlyMode && !item->isDir()) || !matchesFilter( item );
+
+ if ( !isExcluded && matchesMimeFilter( item ) )
+ {
+ if ( d->refreshItemWasFiltered )
+ {
+ if ( !d->lstNewItems )
+ d->lstNewItems = new KFileItemList;
+
+ d->lstNewItems->append( item );
+ }
+ else
+ {
+ if ( !d->lstRefreshItems )
+ d->lstRefreshItems = new KFileItemList;
+
+ d->lstRefreshItems->append( item );
+ }
+ }
+ else if ( !d->refreshItemWasFiltered )
+ {
+ if ( !d->lstRemoveItems )
+ d->lstRemoveItems = new KFileItemList;
+
+ // notify the user that the mimetype of a file changed that doesn't match
+ // a filter or does match an exclude filter
+ d->lstRemoveItems->append( item );
+ }
+}
+
+void KDirLister::emitItems()
+{
+ KFileItemList *tmpNew = d->lstNewItems;
+ d->lstNewItems = 0;
+
+ KFileItemList *tmpMime = d->lstMimeFilteredItems;
+ d->lstMimeFilteredItems = 0;
+
+ KFileItemList *tmpRefresh = d->lstRefreshItems;
+ d->lstRefreshItems = 0;
+
+ KFileItemList *tmpRemove = d->lstRemoveItems;
+ d->lstRemoveItems = 0;
+
+ if ( tmpNew )
+ {
+ emit newItems( *tmpNew );
+ delete tmpNew;
+ }
+
+ if ( tmpMime )
+ {
+ emit itemsFilteredByMime( *tmpMime );
+ delete tmpMime;
+ }
+
+ if ( tmpRefresh )
+ {
+ emit refreshItems( *tmpRefresh );
+ delete tmpRefresh;
+ }
+
+ if ( tmpRemove )
+ {
+ for ( KFileItem *tmp = tmpRemove->first(); tmp; tmp = tmpRemove->next() )
+ emit deleteItem( tmp );
+ delete tmpRemove;
+ }
+}
+
+void KDirLister::emitDeleteItem( KFileItem *item )
+{
+ if ( ( d->dirOnlyMode && !item->isDir() ) || !matchesFilter( item ) )
+ return; // No reason to continue... bailing out here prevents a mimetype scan.
+ if ( matchesMimeFilter( item ) )
+ emit deleteItem( item );
+}
+
+
+// ================ private slots ================ //
+
+void KDirLister::slotInfoMessage( TDEIO::Job *, const TQString& message )
+{
+ emit infoMessage( message );
+}
+
+void KDirLister::slotPercent( TDEIO::Job *job, unsigned long pcnt )
+{
+ d->jobData[static_cast<TDEIO::ListJob *>(job)].percent = pcnt;
+
+ int result = 0;
+
+ TDEIO::filesize_t size = 0;
+
+ TQMap< TDEIO::ListJob *, KDirListerPrivate::JobData >::Iterator dataIt = d->jobData.begin();
+ while ( dataIt != d->jobData.end() )
+ {
+ result += (*dataIt).percent * (*dataIt).totalSize;
+ size += (*dataIt).totalSize;
+ ++dataIt;
+ }
+
+ if ( size != 0 )
+ result /= size;
+ else
+ result = 100;
+ emit percent( result );
+}
+
+void KDirLister::slotTotalSize( TDEIO::Job *job, TDEIO::filesize_t size )
+{
+ d->jobData[static_cast<TDEIO::ListJob *>(job)].totalSize = size;
+
+ TDEIO::filesize_t result = 0;
+ TQMap< TDEIO::ListJob *, KDirListerPrivate::JobData >::Iterator dataIt = d->jobData.begin();
+ while ( dataIt != d->jobData.end() )
+ {
+ result += (*dataIt).totalSize;
+ ++dataIt;
+ }
+
+ emit totalSize( result );
+}
+
+void KDirLister::slotProcessedSize( TDEIO::Job *job, TDEIO::filesize_t size )
+{
+ d->jobData[static_cast<TDEIO::ListJob *>(job)].processedSize = size;
+
+ TDEIO::filesize_t result = 0;
+ TQMap< TDEIO::ListJob *, KDirListerPrivate::JobData >::Iterator dataIt = d->jobData.begin();
+ while ( dataIt != d->jobData.end() )
+ {
+ result += (*dataIt).processedSize;
+ ++dataIt;
+ }
+
+ emit processedSize( result );
+}
+
+void KDirLister::slotSpeed( TDEIO::Job *job, unsigned long spd )
+{
+ d->jobData[static_cast<TDEIO::ListJob *>(job)].speed = spd;
+
+ int result = 0;
+ TQMap< TDEIO::ListJob *, KDirListerPrivate::JobData >::Iterator dataIt = d->jobData.begin();
+ while ( dataIt != d->jobData.end() )
+ {
+ result += (*dataIt).speed;
+ ++dataIt;
+ }
+
+ emit speed( result );
+}
+
+uint KDirLister::numJobs()
+{
+ return d->jobData.count();
+}
+
+void KDirLister::jobDone( TDEIO::ListJob *job )
+{
+ d->jobData.remove( job );
+}
+
+void KDirLister::jobStarted( TDEIO::ListJob *job )
+{
+ KDirListerPrivate::JobData jobData;
+ jobData.speed = 0;
+ jobData.percent = 0;
+ jobData.processedSize = 0;
+ jobData.totalSize = 0;
+
+ d->jobData.insert( job, jobData );
+ d->complete = false;
+}
+
+void KDirLister::connectJob( TDEIO::ListJob *job )
+{
+ connect( job, TQT_SIGNAL(infoMessage( TDEIO::Job *, const TQString& )),
+ this, TQT_SLOT(slotInfoMessage( TDEIO::Job *, const TQString& )) );
+ connect( job, TQT_SIGNAL(percent( TDEIO::Job *, unsigned long )),
+ this, TQT_SLOT(slotPercent( TDEIO::Job *, unsigned long )) );
+ connect( job, TQT_SIGNAL(totalSize( TDEIO::Job *, TDEIO::filesize_t )),
+ this, TQT_SLOT(slotTotalSize( TDEIO::Job *, TDEIO::filesize_t )) );
+ connect( job, TQT_SIGNAL(processedSize( TDEIO::Job *, TDEIO::filesize_t )),
+ this, TQT_SLOT(slotProcessedSize( TDEIO::Job *, TDEIO::filesize_t )) );
+ connect( job, TQT_SIGNAL(speed( TDEIO::Job *, unsigned long )),
+ this, TQT_SLOT(slotSpeed( TDEIO::Job *, unsigned long )) );
+}
+
+void KDirLister::setMainWindow( TQWidget *window )
+{
+ d->window = window;
+}
+
+TQWidget *KDirLister::mainWindow()
+{
+ return d->window;
+}
+
+KFileItemList KDirLister::items( WhichItems which ) const
+{
+ return itemsForDir( url(), which );
+}
+
+KFileItemList KDirLister::itemsForDir( const KURL& dir, WhichItems which ) const
+{
+ KFileItemList result;
+ KFileItemList *allItems = s_pCache->itemsForDir( dir );
+ if ( !allItems )
+ return result;
+
+ if ( which == AllItems )
+ result = *allItems; // shallow copy
+ else // only items passing the filters
+ {
+ for ( KFileItemListIterator kit( *allItems ); kit.current(); ++kit )
+ {
+ KFileItem *item = *kit;
+ bool isExcluded = (d->dirOnlyMode && !item->isDir()) || !matchesFilter( item );
+ if ( !isExcluded && matchesMimeFilter( item ) )
+ result.append( item );
+ }
+ }
+
+ return result;
+}
+
+// to keep BC changes
+
+void KDirLister::virtual_hook( int, void * )
+{ /*BASE::virtual_hook( id, data );*/ }
+
+#include "kdirlister.moc"
+#include "kdirlister_p.moc"