• Skip to content
  • Skip to link menu
Trinity API Reference
  • Trinity API Reference
  • tdeio/tdeio
 

tdeio/tdeio

kdirlister.cpp

00001 /* This file is part of the KDE project
00002    Copyright (C) 1998, 1999 Torben Weis <weis@kde.org>
00003                  2000 Carsten Pfeiffer <pfeiffer@kde.org>
00004                  2001-2005 Michael Brade <brade@kde.org>
00005 
00006    This library is free software; you can redistribute it and/or
00007    modify it under the terms of the GNU Library General Public
00008    License as published by the Free Software Foundation; either
00009    version 2 of the License, or (at your option) any later version.
00010 
00011    This library is distributed in the hope that it will be useful,
00012    but WITHOUT ANY WARRANTY; without even the implied warranty of
00013    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00014    Library General Public License for more details.
00015 
00016    You should have received a copy of the GNU Library General Public License
00017    along with this library; see the file COPYING.LIB.  If not, write to
00018    the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
00019    Boston, MA 02110-1301, USA.
00020 */
00021 
00022 #include "kdirlister.h"
00023 
00024 #include <tqregexp.h>
00025 #include <tqptrlist.h>
00026 #include <tqtimer.h>
00027 #include <tqeventloop.h>
00028 
00029 #include <tdeapplication.h>
00030 #include <kdebug.h>
00031 #include <tdelocale.h>
00032 #include <tdeio/job.h>
00033 #include <tdemessagebox.h>
00034 #include <tdeglobal.h>
00035 #include <tdeglobalsettings.h>
00036 #include <kstaticdeleter.h>
00037 #include <kprotocolinfo.h>
00038 
00039 #include "kdirlister_p.h"
00040 
00041 #include <assert.h>
00042 #include <unistd.h>
00043 
00044 KDirListerCache* KDirListerCache::s_pSelf = 0;
00045 static KStaticDeleter<KDirListerCache> sd_KDirListerCache;
00046 
00047 // Enable this to get printDebug() called often, to see the contents of the cache
00048 //#define DEBUG_CACHE
00049 
00050 // Make really sure it doesn't get activated in the final build
00051 #ifdef NDEBUG
00052 #undef DEBUG_CACHE
00053 #endif
00054 
00055 KDirListerCache::KDirListerCache( int maxCount )
00056   : itemsCached( maxCount )
00057 {
00058   kdDebug(7004) << "+KDirListerCache" << endl;
00059 
00060   itemsInUse.setAutoDelete( false );
00061   itemsCached.setAutoDelete( true );
00062   urlsCurrentlyListed.setAutoDelete( true );
00063   urlsCurrentlyHeld.setAutoDelete( true );
00064   pendingUpdates.setAutoDelete( true );
00065 
00066   connect( kdirwatch, TQT_SIGNAL( dirty( const KURL& ) ),
00067            this, TQT_SLOT( slotFileDirty( const KURL& ) ) );
00068   connect( kdirwatch, TQT_SIGNAL( created( const TQString& ) ),
00069            this, TQT_SLOT( slotFileCreated( const TQString& ) ) );
00070   connect( kdirwatch, TQT_SIGNAL( deleted( const TQString& ) ),
00071            this, TQT_SLOT( slotFileDeleted( const TQString& ) ) );
00072 }
00073 
00074 KDirListerCache::~KDirListerCache()
00075 {
00076   kdDebug(7004) << "-KDirListerCache" << endl;
00077 
00078   itemsInUse.setAutoDelete( true );
00079   itemsInUse.clear();
00080   itemsCached.clear();
00081   urlsCurrentlyListed.clear();
00082   urlsCurrentlyHeld.clear();
00083 
00084   if ( KDirWatch::exists() )
00085     kdirwatch->disconnect( this );
00086 }
00087 
00088 // setting _reload to true will emit the old files and
00089 // call updateDirectory
00090 bool KDirListerCache::listDir( KDirLister *lister, const KURL& _u,
00091                                bool _keep, bool _reload )
00092 {
00093   // like this we don't have to worry about trailing slashes any further
00094   KURL _url = _u;
00095   _url.cleanPath(); // kill consecutive slashes
00096   _url.adjustPath(-1);
00097   TQString urlStr = _url.url();
00098   TQString urlReferenceStr = _url.internalReferenceURL();
00099 
00100   if ( !lister->validURL( _url ) ) {
00101     return false;
00102   }
00103 
00104 #ifdef DEBUG_CACHE
00105   printDebug();
00106 #endif
00107   kdDebug(7004) << k_funcinfo << lister << " url=" << _url
00108                 << " keep=" << _keep << " reload=" << _reload << endl;
00109 
00110   if ( !_keep )
00111   {
00112     // stop any running jobs for lister
00113     stop( lister );
00114 
00115     // clear our internal list for lister
00116     forgetDirs( lister );
00117 
00118     lister->d->rootFileItem = 0;
00119   }
00120   else if ( lister->d->lstDirs.find( _url ) != lister->d->lstDirs.end() )
00121   {
00122     // stop the job listing _url for this lister
00123     stop( lister, _url );
00124 
00125     // clear _url for lister
00126     forgetDirs( lister, _url, true );
00127 
00128     if ( lister->d->url == _url )
00129       lister->d->rootFileItem = 0;
00130   }
00131 
00132   lister->d->lstDirs.append( _url );
00133 
00134   if ( lister->d->url.isEmpty() || !_keep ) // set toplevel URL only if not set yet
00135     lister->d->url = _url;
00136 
00137   DirItem *itemU = itemsInUse[urlStr + ":" + urlReferenceStr];
00138   DirItem *itemC;
00139 
00140   if ( !urlsCurrentlyListed[urlStr + ":" + urlReferenceStr] )
00141   {
00142     // if there is an update running for _url already we get into
00143     // the following case - it will just be restarted by updateDirectory().
00144 
00145     if ( itemU )
00146     {
00147       kdDebug(7004) << "listDir: Entry already in use: " << _url << endl;
00148 
00149       bool oldState = lister->d->complete;
00150       lister->d->complete = false;
00151 
00152       emit lister->started( _url );
00153 
00154       if ( !lister->d->rootFileItem && lister->d->url == _url ) {
00155         lister->d->rootFileItem = itemU->rootItem;
00156       }
00157 
00158       lister->addNewItems( *(itemU->lstItems) );
00159       lister->emitItems();
00160 
00161       // _url is already in use, so there is already an entry in urlsCurrentlyHeld
00162       assert( urlsCurrentlyHeld[urlStr + ":" + urlReferenceStr] );
00163       urlsCurrentlyHeld[urlStr + ":" + urlReferenceStr]->append( lister );
00164 
00165       lister->d->complete = oldState;
00166 
00167       lister->emitCompleted( _url );
00168       if ( lister->d->complete ) {
00169         emit lister->completed();
00170       }
00171 
00172       if ( _reload || !itemU->complete ) {
00173         updateDirectory( _url );
00174       }
00175     }
00176     else if ( !_reload && (itemC = itemsCached.take( urlStr )) )
00177     {
00178       kdDebug(7004) << "listDir: Entry in cache: " << _url << endl;
00179 
00180       itemC->decAutoUpdate();
00181       itemsInUse.insert( urlStr + ":" + urlReferenceStr, itemC );
00182       itemU = itemC;
00183 
00184       bool oldState = lister->d->complete;
00185       lister->d->complete = false;
00186 
00187       emit lister->started( _url );
00188 
00189       if ( !lister->d->rootFileItem && lister->d->url == _url ) {
00190         lister->d->rootFileItem = itemC->rootItem;
00191       }
00192 
00193       lister->addNewItems( *(itemC->lstItems) );
00194       lister->emitItems();
00195 
00196       Q_ASSERT( !urlsCurrentlyHeld[urlStr + ":" + urlReferenceStr] );
00197       TQPtrList<KDirLister> *list = new TQPtrList<KDirLister>;
00198       list->append( lister );
00199       urlsCurrentlyHeld.insert( urlStr + ":" + urlReferenceStr, list );
00200 
00201       lister->d->complete = oldState;
00202 
00203       lister->emitCompleted( _url );
00204       if ( lister->d->complete ) {
00205         emit lister->completed();
00206       }
00207 
00208       if ( !itemC->complete ) {
00209         updateDirectory( _url );
00210       }
00211     }
00212     else  // dir not in cache or _reload is true
00213     {
00214       kdDebug(7004) << "listDir: Entry not in cache or reloaded: " << _url << endl;
00215 
00216       TQPtrList<KDirLister> *list = new TQPtrList<KDirLister>;
00217       list->append( lister );
00218       urlsCurrentlyListed.insert( urlStr + ":" + urlReferenceStr, list );
00219 
00220       itemsCached.remove( urlStr );
00221       itemU = new DirItem( _url );
00222       itemsInUse.insert( urlStr + ":" + urlReferenceStr, itemU );
00223 
00224 //        // we have a limit of MAX_JOBS_PER_LISTER concurrently running jobs
00225 //        if ( lister->numJobs() >= MAX_JOBS_PER_LISTER )
00226 //        {
00227 //          lstPendingUpdates.append( _url );
00228 //        }
00229 //        else
00230 //        {
00231 
00232       if ( lister->d->url == _url ) {
00233         lister->d->rootFileItem = 0;
00234       }
00235 
00236       TDEIO::ListJob* job = TDEIO::listDir( _url, false /* no default GUI */ );
00237       jobs.insert( job, TQValueList<TDEIO::UDSEntry>() );
00238 
00239       lister->jobStarted( job );
00240       lister->connectJob( job );
00241 
00242       if ( lister->d->window ) {
00243         job->setWindow( lister->d->window );
00244       }
00245 
00246       connect( job, TQT_SIGNAL( entries( TDEIO::Job *, const TDEIO::UDSEntryList & ) ),
00247                this, TQT_SLOT( slotEntries( TDEIO::Job *, const TDEIO::UDSEntryList & ) ) );
00248       connect( job, TQT_SIGNAL( result( TDEIO::Job * ) ),
00249                this, TQT_SLOT( slotResult( TDEIO::Job * ) ) );
00250       connect( job, TQT_SIGNAL( redirection( TDEIO::Job *, const KURL & ) ),
00251                this, TQT_SLOT( slotRedirection( TDEIO::Job *, const KURL & ) ) );
00252 
00253       emit lister->started( _url );
00254 
00255 //        }
00256     }
00257   }
00258   else
00259   {
00260     kdDebug(7004) << "listDir: Entry currently being listed: " << _url << endl;
00261 
00262     emit lister->started( _url );
00263 
00264     urlsCurrentlyListed[urlStr + ":" + urlReferenceStr]->append( lister );
00265 
00266     TDEIO::ListJob *job = jobForUrl( urlStr + ":" + urlReferenceStr );
00267     Q_ASSERT( job );
00268 
00269     lister->jobStarted( job );
00270     lister->connectJob( job );
00271 
00272     Q_ASSERT( itemU );
00273 
00274     if ( !lister->d->rootFileItem && lister->d->url == _url ) {
00275       lister->d->rootFileItem = itemU->rootItem;
00276     }
00277 
00278     lister->addNewItems( *(itemU->lstItems) );
00279     lister->emitItems();
00280   }
00281 
00282   // automatic updating of directories
00283   if ( lister->d->autoUpdate ) {
00284     itemU->incAutoUpdate();
00285   }
00286 
00287   return true;
00288 }
00289 
00290 bool KDirListerCache::validURL( const KDirLister *lister, const KURL& url ) const
00291 {
00292   if ( !url.isValid() )
00293   {
00294     if ( lister->d->autoErrorHandling )
00295     {
00296       TQString tmp = i18n("Malformed URL\n%1").arg( url.prettyURL() );
00297       KMessageBox::error( lister->d->errorParent, tmp );
00298     }
00299     return false;
00300   }
00301 
00302   if ( !KProtocolInfo::supportsListing( url ) )
00303   {
00304     if ( lister->d->autoErrorHandling )
00305     {
00306       // TODO: this message should be changed during next string unfreeze!
00307       TQString tmp = i18n("Malformed URL\n%1").arg( url.prettyURL() );
00308       KMessageBox::error( lister->d->errorParent, tmp );
00309     }
00310     return false;
00311   }
00312 
00313   return true;
00314 }
00315 
00316 void KDirListerCache::stop( KDirLister *lister )
00317 {
00318 #ifdef DEBUG_CACHE
00319   printDebug();
00320 #endif
00321   kdDebug(7004) << k_funcinfo << "lister: " << lister << endl;
00322   bool stopped = false;
00323 
00324   TQDictIterator< TQPtrList<KDirLister> > it( urlsCurrentlyListed );
00325   TQPtrList<KDirLister> *listers;
00326   int curIndex;
00327   while ( (listers = it.current()) )
00328   {
00329     curIndex = listers->findRef( lister );
00330     if ( curIndex > -1 )
00331     {
00332       // lister is listing url
00333       TQString url = it.currentKey();
00334       KDirLister* curLister = listers->at( curIndex );
00335 
00336       //kdDebug(7004) << k_funcinfo << " found lister in list - for " << url << endl;
00337       bool ret = listers->removeRef( lister );
00338       Q_ASSERT( ret );
00339 
00340       TDEIO::ListJob *job = jobForUrl( url );
00341       if ( job ) {
00342         lister->jobDone( job );
00343       }
00344 
00345       // move lister to urlsCurrentlyHeld
00346       TQPtrList<KDirLister> *holders = urlsCurrentlyHeld[url];
00347       if ( !holders )
00348       {
00349         holders = new TQPtrList<KDirLister>;
00350         urlsCurrentlyHeld.insert( url, holders );
00351       }
00352 
00353       holders->append( lister );
00354 
00355       emit lister->canceled( curLister->d->url );
00356 
00357       //kdDebug(7004) << k_funcinfo << "remaining list: " << listers->count() << " listers" << endl;
00358 
00359       if ( listers->isEmpty() )
00360       {
00361         // kill the job since it isn't used any more
00362         if ( job ) {
00363           killJob( job );
00364         }
00365 
00366         urlsCurrentlyListed.remove( url );
00367       }
00368 
00369       stopped = true;
00370     }
00371     else
00372       ++it;
00373   }
00374 
00375   if ( stopped )
00376   {
00377     emit lister->canceled();
00378     lister->d->complete = true;
00379   }
00380 
00381   // this is wrong if there is still an update running!
00382   //Q_ASSERT( lister->d->complete );
00383 }
00384 
00385 void KDirListerCache::stop( KDirLister *lister, const KURL& _u )
00386 {
00387   TQString urlStr( _u.url(-1) );
00388   TQString urlReferenceStr = _u.internalReferenceURL();
00389   KURL _url( urlStr );
00390 
00391   // TODO: consider to stop all the "child jobs" of _url as well
00392   kdDebug(7004) << k_funcinfo << lister << " url=" << _url << endl;
00393 
00394   TQPtrList<KDirLister> *listers = urlsCurrentlyListed[urlStr + ":" + urlReferenceStr];
00395   if ( !listers || !listers->removeRef( lister ) )
00396     return;
00397 
00398   // move lister to urlsCurrentlyHeld
00399   TQPtrList<KDirLister> *holders = urlsCurrentlyHeld[urlStr + ":" + urlReferenceStr];
00400   if ( !holders )
00401   {
00402     holders = new TQPtrList<KDirLister>;
00403     urlsCurrentlyHeld.insert( urlStr + ":" + urlReferenceStr, holders );
00404   }
00405 
00406   holders->append( lister );
00407 
00408 
00409   TDEIO::ListJob *job = jobForUrl( urlStr + ":" + urlReferenceStr );
00410   if ( job ) {
00411     lister->jobDone( job );
00412   }
00413 
00414   emit lister->canceled( _url );
00415 
00416   if ( listers->isEmpty() )
00417   {
00418     // kill the job since it isn't used any more
00419     if ( job )
00420       killJob( job );
00421 
00422     urlsCurrentlyListed.remove( urlStr + ":" + urlReferenceStr );
00423   }
00424 
00425   if ( lister->numJobs() == 0 )
00426   {
00427     lister->d->complete = true;
00428 
00429     // we killed the last job for lister
00430     emit lister->canceled();
00431   }
00432 }
00433 
00434 void KDirListerCache::setAutoUpdate( KDirLister *lister, bool enable )
00435 {
00436   // IMPORTANT: this method does not check for the current autoUpdate state!
00437 
00438   for ( KURL::List::Iterator it = lister->d->lstDirs.begin();
00439         it != lister->d->lstDirs.end(); ++it )
00440   {
00441     if ( enable ) {
00442       itemsInUse[(*it).url() + ":" + (*it).internalReferenceURL()]->incAutoUpdate();
00443     }
00444     else {
00445       itemsInUse[(*it).url() + ":" + (*it).internalReferenceURL()]->decAutoUpdate();
00446     }
00447   }
00448 }
00449 
00450 void KDirListerCache::forgetDirs( KDirLister *lister )
00451 {
00452   kdDebug(7004) << k_funcinfo << lister << endl;
00453 
00454   emit lister->clear();
00455 
00456   // forgetDirs() will modify lstDirs, make a copy first
00457   KURL::List lstDirsCopy = lister->d->lstDirs;
00458   for ( KURL::List::Iterator it = lstDirsCopy.begin();
00459         it != lstDirsCopy.end(); ++it )
00460   {
00461     forgetDirs( lister, *it, false );
00462   }
00463 }
00464 
00465 void KDirListerCache::forgetDirs( KDirLister *lister, const KURL& _url, bool notify )
00466 {
00467   kdDebug(7004) << k_funcinfo << lister << " _url: " << _url << endl;
00468 
00469   KURL url( _url );
00470   url.adjustPath( -1 );
00471   TQString urlStr = url.url();
00472   TQString urlReferenceStr = url.internalReferenceURL();
00473   TQPtrList<KDirLister> *holders = urlsCurrentlyHeld[urlStr + ":" + urlReferenceStr];
00474   //Q_ASSERT( holders );
00475   if ( holders )
00476   {
00477     holders->removeRef( lister );
00478   }
00479 
00480   // remove the dir from lister->d->lstDirs so that it doesn't contain things
00481   // that itemsInUse doesn't. When emitting the canceled signals lstDirs must
00482   // not contain anything that itemsInUse does not contain. (otherwise it 
00483   // might crash in findByName()).
00484   lister->d->lstDirs.remove( lister->d->lstDirs.find( url ) );
00485 
00486   DirItem *item = itemsInUse[urlStr + ":" + urlReferenceStr];
00487 
00488   if ( holders && holders->isEmpty() )
00489   {
00490     urlsCurrentlyHeld.remove( urlStr + ":" + urlReferenceStr ); // this deletes the (empty) holders list
00491     if ( !urlsCurrentlyListed[urlStr + ":" + urlReferenceStr] )
00492     {
00493       // item not in use anymore -> move into cache if complete
00494       itemsInUse.remove( urlStr + ":" + urlReferenceStr );
00495 
00496       // this job is a running update
00497       TDEIO::ListJob *job = jobForUrl( urlStr + ":" + urlReferenceStr );
00498       if ( job )
00499       {
00500         lister->jobDone( job );
00501         killJob( job );
00502         kdDebug(7004) << k_funcinfo << "Killing update job for " << urlStr << endl;
00503 
00504         emit lister->canceled( url );
00505         if ( lister->numJobs() == 0 )
00506         {
00507           lister->d->complete = true;
00508           emit lister->canceled();
00509         }
00510       }
00511 
00512       if ( notify )
00513         emit lister->clear( url );
00514 
00515       if ( item && item->complete )
00516       {
00517         kdDebug(7004) << k_funcinfo << lister << " item moved into cache: " << url << endl;
00518         itemsCached.insert( urlStr, item ); // TODO: may return false!!
00519 
00520         // Should we forget the dir for good, or keep a watch on it?
00521         // Generally keep a watch, except when it would prevent
00522         // unmounting a removable device (#37780)
00523         const bool isLocal = item->url.isLocalFile();
00524         const bool isManuallyMounted = isLocal && TDEIO::manually_mounted( item->url.path() );
00525         bool containsManuallyMounted = false;
00526         if ( !isManuallyMounted && item->lstItems && isLocal ) 
00527         {
00528           // Look for a manually-mounted directory inside
00529           // If there's one, we can't keep a watch either, FAM would prevent unmounting the CDROM
00530           // I hope this isn't too slow (manually_mounted caches the last device so most
00531           // of the time this is just a stat per subdir)
00532           KFileItemListIterator kit( *item->lstItems );
00533           for ( ; kit.current() && !containsManuallyMounted; ++kit )
00534             if ( (*kit)->isDir() && TDEIO::manually_mounted( (*kit)->url().path() ) )
00535               containsManuallyMounted = true;
00536         }
00537 
00538         if ( isManuallyMounted || containsManuallyMounted ) 
00539         {
00540           kdDebug(7004) << "Not adding a watch on " << item->url << " because it " <<
00541             ( isManuallyMounted ? "is manually mounted" : "contains a manually mounted subdir" ) << endl;
00542           item->complete = false; // set to "dirty"
00543         }
00544         else
00545           item->incAutoUpdate(); // keep watch
00546       }
00547       else
00548       {
00549         delete item;
00550         item = 0;
00551       }
00552     }
00553   }
00554 
00555   if ( item && lister->d->autoUpdate )
00556     item->decAutoUpdate();
00557 }
00558 
00559 void KDirListerCache::updateDirectory( const KURL& _dir )
00560 {
00561   kdDebug(7004) << k_funcinfo << _dir << endl;
00562 
00563   TQString urlStr = _dir.url(-1);
00564   TQString urlReferenceStr = _dir.internalReferenceURL();
00565   if ( !checkUpdate( _dir, -1 ) ) {
00566     return;
00567   }
00568 
00569   // A job can be running to
00570   //   - only list a new directory: the listers are in urlsCurrentlyListed
00571   //   - only update a directory: the listers are in urlsCurrentlyHeld
00572   //   - update a currently running listing: the listers are in urlsCurrentlyListed
00573   //     and urlsCurrentlyHeld
00574 
00575   TQPtrList<KDirLister> *listers = urlsCurrentlyListed[urlStr + ":" + urlReferenceStr];
00576   TQPtrList<KDirLister> *holders = urlsCurrentlyHeld[urlStr + ":" + urlReferenceStr];
00577 
00578   // restart the job for _dir if it is running already
00579   bool killed = false;
00580   TQWidget *window = 0;
00581   TDEIO::ListJob *job = jobForUrl( urlStr + ":" + urlReferenceStr );
00582   if ( job )
00583   {
00584      window = job->window();
00585 
00586      killJob( job );
00587      killed = true;
00588 
00589      if ( listers ) {
00590         for ( KDirLister *kdl = listers->first(); kdl; kdl = listers->next() ) {
00591            kdl->jobDone( job );
00592         }
00593      }
00594 
00595      if ( holders ) {
00596         for ( KDirLister *kdl = holders->first(); kdl; kdl = holders->next() ) {
00597            kdl->jobDone( job );
00598         }
00599      }
00600   }
00601   kdDebug(7004) << k_funcinfo << "Killed = " << killed << endl;
00602 
00603   // we don't need to emit canceled signals since we only replaced the job,
00604   // the listing is continuing.
00605 
00606   Q_ASSERT( !listers || (listers && killed) );
00607 
00608   job = TDEIO::listDir( _dir, false /* no default GUI */ );
00609   jobs.insert( job, TQValueList<TDEIO::UDSEntry>() );
00610 
00611   connect( job, TQT_SIGNAL(entries( TDEIO::Job *, const TDEIO::UDSEntryList & )),
00612            this, TQT_SLOT(slotUpdateEntries( TDEIO::Job *, const TDEIO::UDSEntryList & )) );
00613   connect( job, TQT_SIGNAL(result( TDEIO::Job * )),
00614            this, TQT_SLOT(slotUpdateResult( TDEIO::Job * )) );
00615 
00616   kdDebug(7004) << k_funcinfo << "update started in " << _dir << endl;
00617 
00618   if ( listers ) {
00619      for ( KDirLister *kdl = listers->first(); kdl; kdl = listers->next() ) {
00620         kdl->jobStarted( job );
00621      }
00622   }
00623 
00624   if ( holders )
00625   {
00626      if ( !killed )
00627      {
00628         bool first = true;
00629         for ( KDirLister *kdl = holders->first(); kdl; kdl = holders->next() )
00630         {
00631            kdl->jobStarted( job );
00632            if ( first && kdl->d->window )
00633            {
00634               first = false;
00635               job->setWindow( kdl->d->window );
00636            }
00637            emit kdl->started( _dir );
00638         }
00639      }
00640      else
00641      {
00642         job->setWindow( window );
00643 
00644         for ( KDirLister *kdl = holders->first(); kdl; kdl = holders->next() ) {
00645            kdl->jobStarted( job );
00646         }
00647      }
00648   }
00649 }
00650 
00651 bool KDirListerCache::checkUpdate( const KURL& _dir, int truncationMode )
00652 {
00653   if ( !itemsInUse[_dir.url(truncationMode) + ":" + _dir.internalReferenceURL()] )
00654   {
00655     DirItem *item = itemsCached[_dir.url(truncationMode)];
00656     if ( item && item->complete )
00657     {
00658       item->complete = false;
00659       item->decAutoUpdate();
00660       // Hmm, this debug output might include login/password from the _dir URL.
00661       //kdDebug(7004) << k_funcinfo << "directory " << _dir << " not in use, marked dirty." << endl;
00662     }
00663     //else
00664       //kdDebug(7004) << k_funcinfo << "aborted, directory " << _dir << " not in cache." << endl;
00665 
00666     return false;
00667   }
00668   else
00669     return true;
00670 }
00671 
00672 KFileItemList *KDirListerCache::itemsForDir( const KURL &_dir ) const
00673 {
00674   TQString urlStr = _dir.url(-1);
00675   TQString urlReferenceStr = _dir.internalReferenceURL();
00676   DirItem *item = itemsInUse[ urlStr + ":" + urlReferenceStr ];
00677   if ( !item ) {
00678     item = itemsCached[ urlStr ];
00679   }
00680   return item ? item->lstItems : 0;
00681 }
00682 
00683 KFileItem *KDirListerCache::findByName( const KDirLister *lister, const TQString& _name ) const
00684 {
00685   Q_ASSERT( lister );
00686 
00687   for ( KURL::List::Iterator it = lister->d->lstDirs.begin();
00688         it != lister->d->lstDirs.end(); ++it )
00689   {
00690     KFileItemListIterator kit( *itemsInUse[(*it).url() + ":" + (*it).internalReferenceURL()]->lstItems );
00691     for ( ; kit.current(); ++kit )
00692       if ( (*kit)->name() == _name )
00693         return (*kit);
00694   }
00695 
00696   return 0L;
00697 }
00698 
00699 KFileItem *KDirListerCache::findByURL( const KDirLister *lister, const KURL& _u ) const
00700 {
00701   KURL _url = _u;
00702   _url.adjustPath(-1);
00703 
00704   KURL parentDir( _url );
00705   parentDir.setPath( parentDir.directory() );
00706 
00707   // If lister is set, check that it contains this dir
00708   if ( lister && !lister->d->lstDirs.contains( parentDir ) )
00709       return 0L;
00710 
00711   KFileItemList *itemList = itemsForDir( parentDir );
00712   if ( itemList )
00713   {
00714     KFileItemListIterator kit( *itemList );
00715     for ( ; kit.current(); ++kit )
00716       if ( (*kit)->url() == _url )
00717         return (*kit);
00718   }
00719   return 0L;
00720 }
00721 
00722 void KDirListerCache::FilesAdded( const KURL &dir )
00723 {
00724   kdDebug(7004) << k_funcinfo << dir << endl;
00725   updateDirectory( dir );
00726 }
00727 
00728 void KDirListerCache::FilesRemoved( const KURL::List &fileList )
00729 {
00730   kdDebug(7004) << k_funcinfo << endl;
00731   KURL::List::ConstIterator it = fileList.begin();
00732   for ( ; it != fileList.end() ; ++it )
00733   {
00734     // emit the deleteItem signal if this file was shown in any view
00735     KFileItem *fileitem = 0L;
00736     KURL parentDir( *it );
00737     parentDir.setPath( parentDir.directory() );
00738     KFileItemList *lstItems = itemsForDir( parentDir );
00739     if ( lstItems )
00740     {
00741       KFileItem *fit = lstItems->first();
00742       for ( ; fit; fit = lstItems->next() )
00743         if ( fit->url() == *it ) {
00744           fileitem = fit;
00745           lstItems->take(); // remove fileitem from list
00746           break;
00747         }
00748     }
00749 
00750     // Tell the views about it before deleting the KFileItems. They might need the subdirs'
00751     // file items (see the dirtree).
00752     if ( fileitem )
00753     {
00754       TQPtrList<KDirLister> *listers = urlsCurrentlyHeld[parentDir.url() + ":" + parentDir.internalReferenceURL()];
00755       if ( listers ) {
00756         for ( KDirLister *kdl = listers->first(); kdl; kdl = listers->next() ) {
00757           kdl->emitDeleteItem( fileitem );
00758         }
00759       }
00760     }
00761 
00762     // If we found a fileitem, we can test if it's a dir. If not, we'll go to deleteDir just in case.
00763     if ( !fileitem || fileitem->isDir() )
00764     {
00765       // in case of a dir, check if we have any known children, there's much to do in that case
00766       // (stopping jobs, removing dirs from cache etc.)
00767       deleteDir( *it );
00768     }
00769 
00770     // now remove the item itself
00771     delete fileitem;
00772   }
00773 }
00774 
00775 void KDirListerCache::FilesChanged( const KURL::List &fileList )
00776 {
00777   KURL::List dirsToUpdate;
00778   kdDebug(7004) << k_funcinfo << "only half implemented" << endl;
00779   KURL::List::ConstIterator it = fileList.begin();
00780   for ( ; it != fileList.end() ; ++it )
00781   {
00782     if ( ( *it ).isLocalFile() )
00783     {
00784       kdDebug(7004) << "KDirListerCache::FilesChanged " << *it << endl;
00785       KFileItem *fileitem = findByURL( 0, *it );
00786       if ( fileitem )
00787       {
00788           // we need to refresh the item, because e.g. the permissions can have changed.
00789           aboutToRefreshItem( fileitem );
00790           fileitem->refresh();
00791           emitRefreshItem( fileitem );
00792       }
00793       else {
00794           kdDebug(7004) << "item not found" << endl;
00795       }
00796     } else {
00797       // For remote files, refresh() won't be able to figure out the new information.
00798       // Let's update the dir.
00799       KURL dir( *it );
00800       dir.setPath( dir.directory( true ) );
00801       if ( dirsToUpdate.find( dir ) == dirsToUpdate.end() ) {
00802         dirsToUpdate.prepend( dir );
00803       }
00804     }
00805   }
00806 
00807   KURL::List::ConstIterator itdir = dirsToUpdate.begin();
00808   for ( ; itdir != dirsToUpdate.end() ; ++itdir ) {
00809     updateDirectory( *itdir );
00810   }
00811   // ## TODO problems with current jobs listing/updating that dir
00812   // ( see kde-2.2.2's kdirlister )
00813 }
00814 
00815 void KDirListerCache::FileRenamed( const KURL &src, const KURL &dst )
00816 {
00817   kdDebug(7004) << k_funcinfo << src.prettyURL() << " -> " << dst.prettyURL() << endl;
00818 #ifdef DEBUG_CACHE
00819   printDebug();
00820 #endif
00821 
00822   // Somehow this should only be called if src is a dir. But how could we know if it is?
00823   // (Note that looking into itemsInUse isn't good enough. One could rename a subdir in a view.)
00824   renameDir( src, dst );
00825 
00826   // Now update the KFileItem representing that file or dir (not exclusive with the above!)
00827   KURL oldurl( src );
00828   oldurl.adjustPath( -1 );
00829   KFileItem *fileitem = findByURL( 0, oldurl );
00830   if ( fileitem )
00831   {
00832     if ( !fileitem->isLocalFile() && !fileitem->localPath().isEmpty() ) // it uses UDS_LOCAL_PATH? ouch, needs an update then
00833         FilesChanged( src );
00834     else
00835     {
00836         aboutToRefreshItem( fileitem );
00837         fileitem->setURL( dst );
00838         fileitem->refreshMimeType();
00839         emitRefreshItem( fileitem );
00840     }
00841   }
00842 #ifdef DEBUG_CACHE
00843   printDebug();
00844 #endif
00845 }
00846 
00847 void KDirListerCache::aboutToRefreshItem( KFileItem *fileitem )
00848 {
00849   // Look whether this item was shown in any view, i.e. held by any dirlister
00850   KURL parentDir( fileitem->url() );
00851   parentDir.setPath( parentDir.directory() );
00852   TQString parentDirURL = parentDir.url();
00853   TQString parentDirReferenceURL = parentDir.internalReferenceURL();
00854   TQPtrList<KDirLister> *listers = urlsCurrentlyHeld[parentDirURL + ":" + parentDirReferenceURL];
00855   if ( listers )
00856     for ( KDirLister *kdl = listers->first(); kdl; kdl = listers->next() )
00857       kdl->aboutToRefreshItem( fileitem );
00858 
00859   // Also look in urlsCurrentlyListed, in case the user manages to rename during a listing
00860   listers = urlsCurrentlyListed[parentDirURL + ":" + parentDirReferenceURL];
00861   if ( listers )
00862     for ( KDirLister *kdl = listers->first(); kdl; kdl = listers->next() )
00863       kdl->aboutToRefreshItem( fileitem );
00864 }
00865 
00866 void KDirListerCache::emitRefreshItem( KFileItem *fileitem )
00867 {
00868   // Look whether this item was shown in any view, i.e. held by any dirlister
00869   KURL parentDir( fileitem->url() );
00870   parentDir.setPath( parentDir.directory() );
00871   TQString parentDirURL = parentDir.url();
00872   TQString parentDirReferenceURL = parentDir.internalReferenceURL();
00873   TQPtrList<KDirLister> *listers = urlsCurrentlyHeld[parentDirURL + ":" + parentDirReferenceURL];
00874   if ( listers )
00875     for ( KDirLister *kdl = listers->first(); kdl; kdl = listers->next() )
00876     {
00877       kdl->addRefreshItem( fileitem );
00878       kdl->emitItems();
00879     }
00880 
00881   // Also look in urlsCurrentlyListed, in case the user manages to rename during a listing
00882   listers = urlsCurrentlyListed[parentDirURL + ":" + parentDirReferenceURL];
00883   if ( listers )
00884     for ( KDirLister *kdl = listers->first(); kdl; kdl = listers->next() )
00885     {
00886       kdl->addRefreshItem( fileitem );
00887       kdl->emitItems();
00888     }
00889 }
00890 
00891 KDirListerCache* KDirListerCache::self()
00892 {
00893   if ( !s_pSelf )
00894     s_pSelf = sd_KDirListerCache.setObject( s_pSelf, new KDirListerCache );
00895 
00896   return s_pSelf;
00897 }
00898 
00899 bool KDirListerCache::exists()
00900 {
00901   return s_pSelf != 0;
00902 }
00903  
00904 
00905 // private slots
00906 
00907 // _file can also be a directory being currently held!
00908 void KDirListerCache::slotFileDirty( const KURL& _url )
00909 {
00910   kdDebug(7004) << k_funcinfo << _url << endl;
00911 
00912   if ( !pendingUpdates[_url.path()] )
00913   {
00914     KURL dir;
00915     dir.setPath( _url.path() );
00916     dir.setInternalReferenceURL(_url.internalReferenceURL());
00917     if ( checkUpdate( dir, -1 ) ) {
00918       updateDirectory( _url );
00919     }
00920 
00921     // the parent directory of _url.path()
00922     dir.setPath( dir.directory() );
00923     dir.setInternalReferenceURL(_url.internalReferenceURL());
00924     if ( checkUpdate( dir ) )
00925     {
00926       // Nice hack to save memory: use the qt object name to store the filename
00927       TQTimer *timer = new TQTimer( this, _url.path().utf8() );
00928       connect( timer, TQT_SIGNAL(timeout()), this, TQT_SLOT(slotFileDirtyDelayed()) );
00929       pendingUpdates.insert( _url.path(), timer );
00930       timer->start( 500, true );
00931     }
00932   }
00933 }
00934 
00935 // delayed updating of files, FAM is flooding us with events
00936 void KDirListerCache::slotFileDirtyDelayed()
00937 {
00938   TQString file = TQString::fromUtf8( TQT_TQOBJECT_CONST(sender())->name() );
00939 
00940   kdDebug(7004) << k_funcinfo << file << endl;
00941 
00942   // TODO: do it better: don't always create/delete the TQTimer but reuse it.
00943   // Delete the timer after the parent directory is removed from the cache.
00944   pendingUpdates.remove( file );
00945 
00946   KURL u;
00947   u.setPath( file );
00948   KFileItem *item = findByURL( 0, u ); // search all items
00949   if ( item )
00950   {
00951     // we need to refresh the item, because e.g. the permissions can have changed.
00952     aboutToRefreshItem( item );
00953     item->refresh();
00954     emitRefreshItem( item );
00955   }
00956 }
00957 
00958 void KDirListerCache::slotFileCreated( const TQString& _file )
00959 {
00960   kdDebug(7004) << k_funcinfo << _file << endl;
00961   // XXX: how to avoid a complete rescan here?
00962   KURL u;
00963   u.setPath( _file );
00964   u.setPath( u.directory() );
00965   FilesAdded( u );
00966 }
00967 
00968 void KDirListerCache::slotFileDeleted( const TQString& _file )
00969 {
00970   kdDebug(7004) << k_funcinfo << _file << endl;
00971   KURL u;
00972   u.setPath( _file );
00973   FilesRemoved( u );
00974 }
00975 
00976 void KDirListerCache::slotEntries( TDEIO::Job *job, const TDEIO::UDSEntryList &entries )
00977 {
00978   KURL url = joburl( static_cast<TDEIO::ListJob *>(job) );
00979   url.adjustPath(-1);
00980   TQString urlStr = url.url();
00981   TQString urlReferenceStr = url.internalReferenceURL();
00982 
00983   kdDebug(7004) << k_funcinfo << "new entries for " << url << endl;
00984 
00985   DirItem *dir = itemsInUse[urlStr + ":" + urlReferenceStr];
00986   Q_ASSERT( dir );
00987 
00988   TQPtrList<KDirLister> *listers = urlsCurrentlyListed[urlStr + ":" + urlReferenceStr];
00989   Q_ASSERT( listers );
00990   Q_ASSERT( !listers->isEmpty() );
00991 
00992   // check if anyone wants the mimetypes immediately
00993   bool delayedMimeTypes = true;
00994   for ( KDirLister *kdl = listers->first(); kdl; kdl = listers->next() ) {
00995     delayedMimeTypes = delayedMimeTypes && kdl->d->delayedMimeTypes;
00996   }
00997 
00998   // avoid creating these QStrings again and again
00999   static const TQString& dot = TDEGlobal::staticQString(".");
01000   static const TQString& dotdot = TDEGlobal::staticQString("..");
01001 
01002   TDEIO::UDSEntryListConstIterator it = entries.begin();
01003   TDEIO::UDSEntryListConstIterator end = entries.end();
01004 
01005   for ( ; it != end; ++it )
01006   {
01007     TQString name;
01008 
01009     // find out about the name
01010     TDEIO::UDSEntry::ConstIterator entit = (*it).begin();
01011     for( ; entit != (*it).end(); ++entit ) {
01012       if ( (*entit).m_uds == TDEIO::UDS_NAME ) {
01013         name = (*entit).m_str;
01014         break;
01015       }
01016     }
01017 
01018     Q_ASSERT( !name.isEmpty() );
01019     if ( name.isEmpty() ) {
01020       continue;
01021     }
01022 
01023     if ( name == dot )
01024     {
01025       Q_ASSERT( !dir->rootItem );
01026       dir->rootItem = new KFileItem( *it, url, delayedMimeTypes, true  );
01027 
01028       for ( KDirLister *kdl = listers->first(); kdl; kdl = listers->next() ) {
01029         if ( !kdl->d->rootFileItem && kdl->d->url == url ) {
01030           kdl->d->rootFileItem = dir->rootItem;
01031         }
01032       }
01033     }
01034     else if ( name != dotdot )
01035     {
01036       KFileItem* item = new KFileItem( *it, url, delayedMimeTypes, true );
01037       Q_ASSERT( item );
01038 
01039       //kdDebug(7004)<< "Adding item: " << item->url() << endl;
01040       dir->lstItems->append( item );
01041 
01042       for ( KDirLister *kdl = listers->first(); kdl; kdl = listers->next() ) {
01043         kdl->addNewItem( item );
01044       }
01045     }
01046   }
01047 
01048   for ( KDirLister *kdl = listers->first(); kdl; kdl = listers->next() ) {
01049     kdl->emitItems();
01050   }
01051 }
01052 
01053 void KDirListerCache::slotResult( TDEIO::Job *j )
01054 {
01055   Q_ASSERT( j );
01056   TDEIO::ListJob *job = static_cast<TDEIO::ListJob *>( j );
01057   jobs.remove( job );
01058 
01059   KURL jobUrl = joburl( job );
01060   jobUrl.adjustPath(-1);  // need remove trailing slashes again, in case of redirections
01061   TQString jobUrlStr = jobUrl.url();
01062   TQString jobReferenceUrlStr = jobUrl.internalReferenceURL();
01063 
01064   kdDebug(7004) << k_funcinfo << "finished listing " << jobUrl << endl;
01065 #ifdef DEBUG_CACHE
01066   printDebug();
01067 #endif
01068 
01069   TQPtrList<KDirLister> *listers = urlsCurrentlyListed.take( jobUrlStr + ":" + jobReferenceUrlStr );
01070   Q_ASSERT( listers );
01071 
01072   // move the directory to the held directories, do it before emitting
01073   // the signals to make sure it exists in KDirListerCache in case someone
01074   // calls listDir during the signal emission
01075   Q_ASSERT( !urlsCurrentlyHeld[jobUrlStr + ":" + jobReferenceUrlStr] );
01076   urlsCurrentlyHeld.insert( jobUrlStr + ":" + jobReferenceUrlStr, listers );
01077 
01078   KDirLister *kdl;
01079 
01080   if ( job->error() )
01081   {
01082     for ( kdl = listers->first(); kdl; kdl = listers->next() )
01083     {
01084       kdl->jobDone( job );
01085       kdl->handleError( job );
01086       emit kdl->canceled( jobUrl );
01087       if ( kdl->numJobs() == 0 )
01088       {
01089         kdl->d->complete = true;
01090         emit kdl->canceled();
01091       }
01092     }
01093   }
01094   else
01095   {
01096     DirItem *dir = itemsInUse[jobUrlStr + ":" + jobReferenceUrlStr];
01097     Q_ASSERT( dir );
01098     dir->complete = true;
01099 
01100     for ( kdl = listers->first(); kdl; kdl = listers->next() )
01101     {
01102       kdl->jobDone( job );
01103       kdl->emitCompleted( jobUrl );
01104       if ( kdl->numJobs() == 0 )
01105       {
01106         kdl->d->complete = true;
01107         emit kdl->completed();
01108       }
01109     }
01110   }
01111 
01112   // TODO: hmm, if there was an error and job is a parent of one or more
01113   // of the pending urls we should cancel it/them as well
01114   processPendingUpdates();
01115 
01116 #ifdef DEBUG_CACHE
01117   printDebug();
01118 #endif
01119 }
01120 
01121 void KDirListerCache::slotRedirection( TDEIO::Job *j, const KURL& url )
01122 {
01123   Q_ASSERT( j );
01124   TDEIO::ListJob *job = static_cast<TDEIO::ListJob *>( j );
01125 
01126   KURL oldUrl = job->url();  // here we really need the old url!
01127   KURL newUrl = url;
01128 
01129   // strip trailing slashes
01130   oldUrl.adjustPath(-1);
01131   newUrl.adjustPath(-1);
01132 
01133   if ( oldUrl == newUrl )
01134   {
01135     kdDebug(7004) << k_funcinfo << "New redirection url same as old, giving up." << endl;
01136     return;
01137   }
01138 
01139   kdDebug(7004) << k_funcinfo << oldUrl.prettyURL() << " -> " << newUrl.prettyURL() << endl;
01140 
01141 #ifdef DEBUG_CACHE
01142   printDebug();
01143 #endif
01144 
01145   // I don't think there can be dirItems that are childs of oldUrl.
01146   // Am I wrong here? And even if so, we don't need to delete them, right?
01147   // DF: redirection happens before listDir emits any item. Makes little sense otherwise.
01148 
01149   // oldUrl cannot be in itemsCached because only completed items are moved there
01150   DirItem *dir = itemsInUse.take( oldUrl.url() + ":" + oldUrl.internalReferenceURL() );
01151   Q_ASSERT( dir );
01152 
01153   TQPtrList<KDirLister> *listers = urlsCurrentlyListed.take( oldUrl.url() + ":" + oldUrl.internalReferenceURL() );
01154   Q_ASSERT( listers );
01155   Q_ASSERT( !listers->isEmpty() );
01156 
01157   for ( KDirLister *kdl = listers->first(); kdl; kdl = listers->next() )
01158   {
01159     // TODO: put in own method?
01160     if ( kdl->d->url.equals( oldUrl, true ) )
01161     {
01162       kdl->d->rootFileItem = 0;
01163       kdl->d->url = newUrl;
01164     }
01165 
01166     *kdl->d->lstDirs.find( oldUrl ) = newUrl;
01167 
01168     if ( kdl->d->lstDirs.count() == 1 )
01169     {
01170       emit kdl->clear();
01171       emit kdl->redirection( newUrl );
01172       emit kdl->redirection( oldUrl, newUrl );
01173     }
01174     else
01175     {
01176       emit kdl->clear( oldUrl );
01177       emit kdl->redirection( oldUrl, newUrl );
01178     }
01179   }
01180 
01181   // when a lister was stopped before the job emits the redirection signal, the old url will
01182   // also be in urlsCurrentlyHeld
01183   TQPtrList<KDirLister> *holders = urlsCurrentlyHeld.take( oldUrl.url() + ":" + oldUrl.internalReferenceURL() );
01184   if ( holders )
01185   {
01186     Q_ASSERT( !holders->isEmpty() );
01187 
01188     for ( KDirLister *kdl = holders->first(); kdl; kdl = holders->next() )
01189     {
01190       kdl->jobStarted( job );
01191       
01192       // do it like when starting a new list-job that will redirect later
01193       emit kdl->started( oldUrl );
01194 
01195       // TODO: maybe don't emit started if there's an update running for newUrl already?
01196 
01197       if ( kdl->d->url.equals( oldUrl, true ) )
01198       {
01199         kdl->d->rootFileItem = 0;
01200         kdl->d->url = newUrl;
01201       }
01202 
01203       *kdl->d->lstDirs.find( oldUrl ) = newUrl;
01204 
01205       if ( kdl->d->lstDirs.count() == 1 )
01206       {
01207         emit kdl->clear();
01208         emit kdl->redirection( newUrl );
01209         emit kdl->redirection( oldUrl, newUrl );
01210       }
01211       else
01212       {
01213         emit kdl->clear( oldUrl );
01214         emit kdl->redirection( oldUrl, newUrl );
01215       }
01216     }
01217   }
01218 
01219   DirItem *newDir = itemsInUse[newUrl.url() + ":" + newUrl.internalReferenceURL()];
01220   if ( newDir )
01221   {
01222     kdDebug(7004) << "slotRedirection: " << newUrl.url() << " already in use" << endl;
01223     
01224     // only in this case there can newUrl already be in urlsCurrentlyListed or urlsCurrentlyHeld
01225     delete dir;
01226 
01227     // get the job if one's running for newUrl already (can be a list-job or an update-job), but
01228     // do not return this 'job', which would happen because of the use of redirectionURL()
01229     TDEIO::ListJob *oldJob = jobForUrl( newUrl.url() + ":" + newUrl.internalReferenceURL(), job );
01230 
01231     // listers of newUrl with oldJob: forget about the oldJob and use the already running one
01232     // which will be converted to an updateJob
01233     TQPtrList<KDirLister> *curListers = urlsCurrentlyListed[newUrl.url() + ":" + newUrl.internalReferenceURL()];
01234     if ( curListers )
01235     {
01236       kdDebug(7004) << "slotRedirection: and it is currently listed" << endl;
01237 
01238       Q_ASSERT( oldJob );  // ?!
01239 
01240       for ( KDirLister *kdl = curListers->first(); kdl; kdl = curListers->next() )  // listers of newUrl
01241       {
01242         kdl->jobDone( oldJob );
01243 
01244         kdl->jobStarted( job );
01245         kdl->connectJob( job );
01246       }
01247 
01248       // append listers of oldUrl with newJob to listers of newUrl with oldJob
01249       for ( KDirLister *kdl = listers->first(); kdl; kdl = listers->next() )
01250         curListers->append( kdl );
01251     }
01252     else {
01253       urlsCurrentlyListed.insert( newUrl.url() + ":" + newUrl.internalReferenceURL(), listers );
01254     }
01255 
01256     if ( oldJob )         // kill the old job, be it a list-job or an update-job
01257       killJob( oldJob );
01258 
01259     // holders of newUrl: use the already running job which will be converted to an updateJob
01260     TQPtrList<KDirLister> *curHolders = urlsCurrentlyHeld[newUrl.url() + ":" + newUrl.internalReferenceURL()];
01261     if ( curHolders )
01262     {
01263       kdDebug(7004) << "slotRedirection: and it is currently held." << endl;
01264 
01265       for ( KDirLister *kdl = curHolders->first(); kdl; kdl = curHolders->next() )  // holders of newUrl
01266       {
01267         kdl->jobStarted( job );
01268         emit kdl->started( newUrl );
01269       }
01270 
01271       // append holders of oldUrl to holders of newUrl
01272       if ( holders )
01273         for ( KDirLister *kdl = holders->first(); kdl; kdl = holders->next() )
01274           curHolders->append( kdl );
01275     }
01276     else if ( holders )
01277       urlsCurrentlyHeld.insert( newUrl.url() + ":" + newUrl.internalReferenceURL(), holders );
01278 
01279     
01280     // emit old items: listers, holders. NOT: newUrlListers/newUrlHolders, they already have them listed
01281     // TODO: make this a separate method?
01282     for ( KDirLister *kdl = listers->first(); kdl; kdl = listers->next() )
01283     {
01284       if ( !kdl->d->rootFileItem && kdl->d->url == newUrl )
01285         kdl->d->rootFileItem = newDir->rootItem;
01286 
01287       kdl->addNewItems( *(newDir->lstItems) );
01288       kdl->emitItems();
01289     }
01290 
01291     if ( holders )
01292     {
01293       for ( KDirLister *kdl = holders->first(); kdl; kdl = holders->next() )
01294       {
01295         if ( !kdl->d->rootFileItem && kdl->d->url == newUrl )
01296           kdl->d->rootFileItem = newDir->rootItem;
01297 
01298         kdl->addNewItems( *(newDir->lstItems) );
01299         kdl->emitItems();
01300       }
01301     }
01302   }
01303   else if ( (newDir = itemsCached.take( newUrl.url() )) )
01304   {
01305     kdDebug(7004) << "slotRedirection: " << newUrl.url() << " is unused, but already in the cache." << endl;
01306 
01307     delete dir;
01308     itemsInUse.insert( newUrl.url() + ":" + newUrl.internalReferenceURL(), newDir );
01309     urlsCurrentlyListed.insert( newUrl.url() + ":" + newUrl.internalReferenceURL(), listers );
01310     if ( holders )
01311       urlsCurrentlyHeld.insert( newUrl.url() + ":" + newUrl.internalReferenceURL(), holders );
01312 
01313     // emit old items: listers, holders
01314     for ( KDirLister *kdl = listers->first(); kdl; kdl = listers->next() )
01315     {
01316       if ( !kdl->d->rootFileItem && kdl->d->url == newUrl )
01317         kdl->d->rootFileItem = newDir->rootItem;
01318 
01319       kdl->addNewItems( *(newDir->lstItems) );
01320       kdl->emitItems();
01321     }
01322 
01323     if ( holders )
01324     {
01325       for ( KDirLister *kdl = holders->first(); kdl; kdl = holders->next() )
01326       {
01327         if ( !kdl->d->rootFileItem && kdl->d->url == newUrl )
01328           kdl->d->rootFileItem = newDir->rootItem;
01329 
01330         kdl->addNewItems( *(newDir->lstItems) );
01331         kdl->emitItems();
01332       }
01333     }
01334   }
01335   else
01336   {
01337     kdDebug(7004) << "slotRedirection: " << newUrl.url() << " has not been listed yet." << endl;
01338 
01339     delete dir->rootItem;
01340     dir->rootItem = 0;
01341     dir->lstItems->clear();
01342     dir->redirect( newUrl );
01343     itemsInUse.insert( newUrl.url() + ":" + newUrl.internalReferenceURL(), dir );
01344     urlsCurrentlyListed.insert( newUrl.url() + ":" + newUrl.internalReferenceURL(), listers );
01345 
01346     if ( holders )
01347       urlsCurrentlyHeld.insert( newUrl.url() + ":" + newUrl.internalReferenceURL(), holders );
01348     else
01349     {
01350 #ifdef DEBUG_CACHE
01351       printDebug();
01352 #endif
01353       return; // only in this case the job doesn't need to be converted, 
01354     }
01355   }
01356 
01357   // make the job an update job
01358   job->disconnect( this );
01359     
01360   connect( job, TQT_SIGNAL(entries( TDEIO::Job *, const TDEIO::UDSEntryList & )),
01361            this, TQT_SLOT(slotUpdateEntries( TDEIO::Job *, const TDEIO::UDSEntryList & )) );
01362   connect( job, TQT_SIGNAL(result( TDEIO::Job * )),
01363            this, TQT_SLOT(slotUpdateResult( TDEIO::Job * )) );
01364 
01365   // FIXME: autoUpdate-Counts!!
01366 
01367 #ifdef DEBUG_CACHE
01368   printDebug();
01369 #endif
01370 }
01371 
01372 void KDirListerCache::renameDir( const KURL &oldUrl, const KURL &newUrl )
01373 {
01374   kdDebug(7004) << k_funcinfo << oldUrl.prettyURL() << " -> " << newUrl.prettyURL() << endl;
01375   TQString oldUrlStr = oldUrl.url(-1);
01376   TQString newUrlStr = newUrl.url(-1);
01377 
01378   // Not enough. Also need to look at any child dir, even sub-sub-sub-dir.
01379   //DirItem *dir = itemsInUse.take( oldUrlStr );
01380   //emitRedirections( oldUrl, url );
01381 
01382   // Look at all dirs being listed/shown
01383   TQDictIterator<DirItem> itu( itemsInUse );
01384   bool goNext;
01385   while ( itu.current() )
01386   {
01387     goNext = true;
01388     DirItem *dir = itu.current();
01389     TQString oldDirURLIndep = itu.currentKey();
01390     oldDirURLIndep.truncate(oldDirURLIndep.length() - (dir->url.internalReferenceURL().length()+strlen(":")));
01391     KURL oldDirUrl ( oldDirURLIndep );
01392     //kdDebug(7004) << "itemInUse: " << oldDirUrl.prettyURL() << endl;
01393     // Check if this dir is oldUrl, or a subfolder of it
01394     if ( oldUrl.isParentOf( oldDirUrl ) )
01395     {
01396       // TODO should use KURL::cleanpath like isParentOf does
01397       TQString relPath = oldDirUrl.path().mid( oldUrl.path().length() );
01398 
01399       KURL newDirUrl( newUrl ); // take new base
01400       if ( !relPath.isEmpty() ) {
01401         newDirUrl.addPath( relPath ); // add unchanged relative path
01402       }
01403       //kdDebug(7004) << "KDirListerCache::renameDir new url=" << newDirUrl.prettyURL() << endl;
01404 
01405       // Update URL in dir item and in itemsInUse
01406       dir->redirect( newDirUrl );
01407       itemsInUse.remove( itu.currentKey() ); // implies ++itu
01408       itemsInUse.insert( newDirUrl.url(-1), dir );
01409       goNext = false; // because of the implied ++itu above
01410       if ( dir->lstItems )
01411       {
01412         // Rename all items under that dir
01413         KFileItemListIterator kit( *dir->lstItems );
01414         for ( ; kit.current(); ++kit )
01415         {
01416           KURL oldItemUrl = (*kit)->url();
01417           TQString oldItemUrlStr( oldItemUrl.url(-1) );
01418           KURL newItemUrl( oldItemUrl );
01419           newItemUrl.setPath( newDirUrl.path() );
01420           newItemUrl.addPath( oldItemUrl.fileName() );
01421           kdDebug(7004) << "KDirListerCache::renameDir renaming " << oldItemUrlStr << " to " << newItemUrl.url() << endl;
01422           (*kit)->setURL( newItemUrl );
01423         }
01424       }
01425       emitRedirections( oldDirUrl, newDirUrl );
01426     }
01427     if ( goNext )
01428       ++itu;
01429   }
01430 
01431   // Is oldUrl a directory in the cache?
01432   // Remove any child of oldUrl from the cache - even if the renamed dir itself isn't in it!
01433   removeDirFromCache( oldUrl );
01434   // TODO rename, instead.
01435 }
01436 
01437 void KDirListerCache::emitRedirections( const KURL &oldUrl, const KURL &url )
01438 {
01439   kdDebug(7004) << k_funcinfo << oldUrl.prettyURL() << " -> " << url.prettyURL() << endl;
01440   TQString oldUrlStr = oldUrl.url(-1);
01441   TQString urlStr = url.url(-1);
01442   TQString oldReferenceUrlStr = oldUrl.internalReferenceURL();
01443   TQString urlReferenceStr = url.internalReferenceURL();
01444 
01445   TDEIO::ListJob *job = jobForUrl( oldUrlStr + ":" + oldReferenceUrlStr );
01446   if ( job )
01447     killJob( job );
01448 
01449   // Check if we were listing this dir. Need to abort and restart with new name in that case.
01450   TQPtrList<KDirLister> *listers = urlsCurrentlyListed.take( oldUrlStr + ":" + oldReferenceUrlStr );
01451   if ( listers )
01452   {
01453     // Tell the world that the job listing the old url is dead.
01454     for ( KDirLister *kdl = listers->first(); kdl; kdl = listers->next() )
01455     {
01456       if ( job )
01457         kdl->jobDone( job );
01458 
01459       emit kdl->canceled( oldUrl );
01460     }
01461 
01462     urlsCurrentlyListed.insert( urlStr + ":" + urlReferenceStr, listers );
01463   }
01464 
01465   // Check if we are currently displaying this directory (odds opposite wrt above)
01466   // Update urlsCurrentlyHeld dict with new URL
01467   TQPtrList<KDirLister> *holders = urlsCurrentlyHeld.take( oldUrlStr + ":" + oldReferenceUrlStr );
01468   if ( holders )
01469   {
01470     if ( job )
01471       for ( KDirLister *kdl = holders->first(); kdl; kdl = holders->next() )
01472         kdl->jobDone( job );
01473 
01474     urlsCurrentlyHeld.insert( urlStr + ":" + urlReferenceStr, holders );
01475   }
01476 
01477   if ( listers )
01478   {
01479     updateDirectory( url );
01480 
01481     // Tell the world about the new url
01482     for ( KDirLister *kdl = listers->first(); kdl; kdl = listers->next() )
01483       emit kdl->started( url );
01484   }
01485 
01486   if ( holders )
01487   {
01488     // And notify the dirlisters of the redirection
01489     for ( KDirLister *kdl = holders->first(); kdl; kdl = holders->next() )
01490     {
01491       *kdl->d->lstDirs.find( oldUrl ) = url;
01492 
01493       if ( kdl->d->lstDirs.count() == 1 )
01494         emit kdl->redirection( url );
01495 
01496       emit kdl->redirection( oldUrl, url );
01497     }
01498   }
01499 }
01500 
01501 void KDirListerCache::removeDirFromCache( const KURL& dir )
01502 {
01503   kdDebug(7004) << "KDirListerCache::removeDirFromCache " << dir.prettyURL() << endl;
01504   TQCacheIterator<DirItem> itc( itemsCached );
01505   while ( itc.current() )
01506   {
01507     if ( dir.isParentOf( KURL( itc.currentKey() ) ) )
01508       itemsCached.remove( itc.currentKey() );
01509     else
01510       ++itc;
01511   }
01512 }
01513 
01514 void KDirListerCache::slotUpdateEntries( TDEIO::Job* job, const TDEIO::UDSEntryList& list )
01515 {
01516   jobs[static_cast<TDEIO::ListJob*>(job)] += list;
01517 }
01518 
01519 void KDirListerCache::slotUpdateResult( TDEIO::Job * j )
01520 {
01521   Q_ASSERT( j );
01522   TDEIO::ListJob *job = static_cast<TDEIO::ListJob *>( j );
01523 
01524   KURL jobUrl = joburl( job );
01525   jobUrl.adjustPath(-1);  // need remove trailing slashes again, in case of redirections
01526   TQString jobUrlStr = jobUrl.url();
01527   TQString jobReferenceUrlStr = jobUrl.internalReferenceURL();
01528 
01529   kdDebug(7004) << k_funcinfo << "finished update " << jobUrl << endl;
01530 
01531   KDirLister *kdl;
01532 
01533   TQPtrList<KDirLister> *listers = urlsCurrentlyHeld[jobUrlStr + ":" + jobReferenceUrlStr];
01534   TQPtrList<KDirLister> *tmpLst = urlsCurrentlyListed.take( jobUrlStr + ":" + jobReferenceUrlStr );
01535 
01536   if ( tmpLst )
01537   {
01538     if ( listers )
01539       for ( kdl = tmpLst->first(); kdl; kdl = tmpLst->next() )
01540       {
01541         Q_ASSERT( listers->containsRef( kdl ) == 0 );
01542         listers->append( kdl );
01543       }
01544     else
01545     {
01546       listers = tmpLst;
01547       urlsCurrentlyHeld.insert( jobUrlStr + ":" + jobReferenceUrlStr, listers );
01548     }
01549   }
01550 
01551   // once we are updating dirs that are only in the cache this will fail!
01552   Q_ASSERT( listers );
01553 
01554   if ( job->error() )
01555   {
01556     for ( kdl = listers->first(); kdl; kdl = listers->next() )
01557     {
01558       kdl->jobDone( job );
01559 
01560       //don't bother the user
01561       //kdl->handleError( job );
01562 
01563       emit kdl->canceled( jobUrl );
01564       if ( kdl->numJobs() == 0 )
01565       {
01566         kdl->d->complete = true;
01567         emit kdl->canceled();
01568       }
01569     }
01570 
01571     jobs.remove( job );
01572 
01573     // TODO: if job is a parent of one or more
01574     // of the pending urls we should cancel them
01575     processPendingUpdates();
01576     return;
01577   }
01578 
01579   DirItem *dir = itemsInUse[jobUrlStr + ":" + jobReferenceUrlStr];
01580   dir->complete = true;
01581 
01582 
01583   // check if anyone wants the mimetypes immediately
01584   bool delayedMimeTypes = true;
01585   for ( kdl = listers->first(); kdl; kdl = listers->next() ) {
01586     delayedMimeTypes = delayedMimeTypes && kdl->d->delayedMimeTypes;
01587   }
01588 
01589   // should be enough to get reasonable speed in most cases
01590   TQDict<KFileItem> fileItems( 9973 );
01591 
01592   KFileItemListIterator kit ( *(dir->lstItems) );
01593 
01594   // Unmark all items in url
01595   for ( ; kit.current(); ++kit )
01596   {
01597     (*kit)->unmark();
01598     if (!((*kit)->listerURL().isEmpty())) {
01599       fileItems.insert( (*kit)->listerURL().url(), *kit );
01600     }
01601     else {
01602       fileItems.insert( (*kit)->url().url(), *kit );
01603     }
01604   }
01605 
01606   static const TQString& dot = TDEGlobal::staticQString(".");
01607   static const TQString& dotdot = TDEGlobal::staticQString("..");
01608 
01609   KFileItem *item = 0, *tmp;
01610 
01611   TQValueList<TDEIO::UDSEntry> buf = jobs[job];
01612   TQValueListIterator<TDEIO::UDSEntry> it = buf.begin();
01613   for ( ; it != buf.end(); ++it )
01614   {
01615     // Form the complete url
01616     if ( !item ) {
01617       item = new KFileItem( *it, jobUrl, delayedMimeTypes, true );
01618     }
01619     else {
01620       item->setUDSEntry( *it, jobUrl, delayedMimeTypes, true );
01621     }
01622 
01623     // Find out about the name
01624     TQString name = item->name();
01625     Q_ASSERT( !name.isEmpty() );
01626 
01627     // we duplicate the check for dotdot here, to avoid iterating over
01628     // all items again and checking in matchesFilter() that way.
01629     if ( name.isEmpty() || name == dotdot ) {
01630       continue;
01631     }
01632 
01633     if ( name == dot )
01634     {
01635       // if the update was started before finishing the original listing
01636       // there is no root item yet
01637       if ( !dir->rootItem )
01638       {
01639         dir->rootItem = item;
01640         item = 0;
01641 
01642         for ( KDirLister *kdl = listers->first(); kdl; kdl = listers->next() ) {
01643           if ( !kdl->d->rootFileItem && kdl->d->url == jobUrl ) {
01644             kdl->d->rootFileItem = dir->rootItem;
01645           }
01646         }
01647       }
01648 
01649       continue;
01650     }
01651 
01652     // Find this item
01653     if ( (tmp = fileItems[item->url().url()]) )
01654     {
01655       tmp->mark();
01656 
01657       // check if something changed for this file
01658       if ( !tmp->cmp( *item ) )
01659       {
01660         for ( kdl = listers->first(); kdl; kdl = listers->next() ) {
01661           kdl->aboutToRefreshItem( tmp );
01662         }
01663 
01664         //kdDebug(7004) << "slotUpdateResult: file changed: " << tmp->name() << endl;
01665         tmp->assign( *item );
01666 
01667         for ( kdl = listers->first(); kdl; kdl = listers->next() ) {
01668           kdl->addRefreshItem( tmp );
01669         }
01670       }
01671     }
01672     else // this is a new file
01673     {
01674       //kdDebug(7004) << "slotUpdateResult: new file: " << name << endl;
01675 
01676       item->mark();
01677       dir->lstItems->append( item );
01678 
01679       for ( kdl = listers->first(); kdl; kdl = listers->next() ) {
01680         kdl->addNewItem( item );
01681       }
01682 
01683       // item used, we need a new one for the next iteration
01684       item = 0;
01685     }
01686   }
01687 
01688   if ( item ) {
01689     delete item;
01690   }
01691 
01692   jobs.remove( job );
01693 
01694   deleteUnmarkedItems( listers, dir->lstItems );
01695 
01696   for ( kdl = listers->first(); kdl; kdl = listers->next() )
01697   {
01698     kdl->emitItems();
01699 
01700     kdl->jobDone( job );
01701 
01702     kdl->emitCompleted( jobUrl );
01703     if ( kdl->numJobs() == 0 )
01704     {
01705       kdl->d->complete = true;
01706       emit kdl->completed();
01707     }
01708   }
01709 
01710   // TODO: hmm, if there was an error and job is a parent of one or more
01711   // of the pending urls we should cancel it/them as well
01712   processPendingUpdates();
01713 }
01714 
01715 // private
01716 
01717 TDEIO::ListJob *KDirListerCache::jobForUrl( const TQString& url, TDEIO::ListJob *not_job )
01718 {
01719   TDEIO::ListJob *job;
01720   TQMap< TDEIO::ListJob *, TQValueList<TDEIO::UDSEntry> >::Iterator it = jobs.begin();
01721   while ( it != jobs.end() )
01722   {
01723     job = it.key();
01724     KURL itjoburl = joburl( job );
01725     if ( ((itjoburl.url(-1) + ":" + itjoburl.internalReferenceURL()) == url) && (job != not_job) ) {
01726        return job;
01727     }
01728     ++it;
01729   }
01730   return 0;
01731 }
01732 
01733 const KURL& KDirListerCache::joburl( TDEIO::ListJob *job )
01734 {
01735   if ( job->redirectionURL().isValid() ) {
01736      return job->redirectionURL();
01737   }
01738   else {
01739      return job->url();
01740   }
01741 }
01742 
01743 void KDirListerCache::killJob( TDEIO::ListJob *job )
01744 {
01745   jobs.remove( job );
01746   job->disconnect( this );
01747   job->kill();
01748 }
01749 
01750 void KDirListerCache::deleteUnmarkedItems( TQPtrList<KDirLister> *listers, KFileItemList *lstItems )
01751 {
01752   // Find all unmarked items and delete them
01753   KFileItem* item;
01754   lstItems->first();
01755   while ( (item = lstItems->current()) )
01756     if ( !item->isMarked() )
01757     {
01758       //kdDebug() << k_funcinfo << item->name() << endl;
01759       for ( KDirLister *kdl = listers->first(); kdl; kdl = listers->next() ) {
01760         kdl->emitDeleteItem( item );
01761       }
01762 
01763       if ( item->isDir() ) {
01764         deleteDir( item->url() );
01765       }
01766 
01767       // finally actually delete the item
01768       lstItems->take();
01769       delete item;
01770     }
01771     else
01772       lstItems->next();
01773 }
01774 
01775 void KDirListerCache::deleteDir( const KURL& dirUrl )
01776 {
01777   //kdDebug() << k_funcinfo << dirUrl.prettyURL() << endl;
01778   // unregister and remove the childs of the deleted item.
01779   // Idea: tell all the KDirListers that they should forget the dir
01780   //       and then remove it from the cache.
01781 
01782   TQDictIterator<DirItem> itu( itemsInUse );
01783   while ( itu.current() )
01784   {
01785     TQString deletedUrlIndep = itu.currentKey();
01786     deletedUrlIndep.truncate(deletedUrlIndep.length() - ((*itu)->url.internalReferenceURL().length()+strlen(":")));
01787     KURL deletedUrl( deletedUrlIndep );
01788     if ( dirUrl.isParentOf( deletedUrl ) )
01789     {
01790       // stop all jobs for deletedUrl
01791 
01792       TQPtrList<KDirLister> *kdls = urlsCurrentlyListed[deletedUrl.url() + ":" + deletedUrl.internalReferenceURL()];
01793       if ( kdls )  // yeah, I lack good names
01794       {
01795         // we need a copy because stop modifies the list
01796         kdls = new TQPtrList<KDirLister>( *kdls );
01797         for ( KDirLister *kdl = kdls->first(); kdl; kdl = kdls->next() )
01798           stop( kdl, deletedUrl );
01799 
01800         delete kdls;
01801       }
01802 
01803       // tell listers holding deletedUrl to forget about it
01804       // this will stop running updates for deletedUrl as well
01805 
01806       kdls = urlsCurrentlyHeld[deletedUrl.url() + ":" + deletedUrl.internalReferenceURL()];
01807       if ( kdls )
01808       {
01809         // we need a copy because forgetDirs modifies the list
01810         kdls = new TQPtrList<KDirLister>( *kdls );
01811 
01812         for ( KDirLister *kdl = kdls->first(); kdl; kdl = kdls->next() )
01813         {
01814           // lister's root is the deleted item
01815           if ( kdl->d->url == deletedUrl )
01816           {
01817             // tell the view first. It might need the subdirs' items (which forgetDirs will delete)
01818             if ( kdl->d->rootFileItem )
01819               emit kdl->deleteItem( kdl->d->rootFileItem );
01820             forgetDirs( kdl );
01821             kdl->d->rootFileItem = 0;
01822           }
01823           else
01824           {
01825             bool treeview = kdl->d->lstDirs.count() > 1;
01826             if ( !treeview )
01827               emit kdl->clear();
01828 
01829             forgetDirs( kdl, deletedUrl, treeview );
01830           }
01831         }
01832 
01833         delete kdls;
01834       }
01835 
01836       // delete the entry for deletedUrl - should not be needed, it's in
01837       // items cached now
01838 
01839       DirItem *dir = itemsInUse.take( deletedUrl.url() + ":" + deletedUrl.internalReferenceURL() );
01840       Q_ASSERT( !dir );
01841       if ( !dir ) // take didn't find it - move on
01842           ++itu;
01843     }
01844     else
01845       ++itu;
01846   }
01847 
01848   // remove the children from the cache
01849   removeDirFromCache( dirUrl );
01850 }
01851 
01852 void KDirListerCache::processPendingUpdates()
01853 {
01854   // TODO
01855 }
01856 
01857 #ifndef NDEBUG
01858 void KDirListerCache::printDebug()
01859 {
01860   kdDebug(7004) << "Items in use: " << endl;
01861   TQDictIterator<DirItem> itu( itemsInUse );
01862   for ( ; itu.current() ; ++itu ) {
01863       kdDebug(7004) << "   " << itu.currentKey() << "  URL: " << itu.current()->url
01864                     << " rootItem: " << ( itu.current()->rootItem ? itu.current()->rootItem->url() : KURL() )
01865                     << " autoUpdates refcount: " << itu.current()->autoUpdates
01866                     << " complete: " << itu.current()->complete
01867                   << ( itu.current()->lstItems ? TQString(" with %1 items.").arg(itu.current()->lstItems->count()) : TQString(" lstItems=NULL") ) << endl;
01868   }
01869 
01870   kdDebug(7004) << "urlsCurrentlyHeld: " << endl;
01871   TQDictIterator< TQPtrList<KDirLister> > it( urlsCurrentlyHeld );
01872   for ( ; it.current() ; ++it )
01873   {
01874     TQString list;
01875     for ( TQPtrListIterator<KDirLister> listit( *it.current() ); listit.current(); ++listit )
01876       list += " 0x" + TQString::number( (long)listit.current(), 16 );
01877     kdDebug(7004) << "   " << it.currentKey() << "  " << it.current()->count() << " listers: " << list << endl;
01878   }
01879 
01880   kdDebug(7004) << "urlsCurrentlyListed: " << endl;
01881   TQDictIterator< TQPtrList<KDirLister> > it2( urlsCurrentlyListed );
01882   for ( ; it2.current() ; ++it2 )
01883   {
01884     TQString list;
01885     for ( TQPtrListIterator<KDirLister> listit( *it2.current() ); listit.current(); ++listit )
01886       list += " 0x" + TQString::number( (long)listit.current(), 16 );
01887     kdDebug(7004) << "   " << it2.currentKey() << "  " << it2.current()->count() << " listers: " << list << endl;
01888   }
01889 
01890   TQMap< TDEIO::ListJob *, TQValueList<TDEIO::UDSEntry> >::Iterator jit = jobs.begin();
01891   kdDebug(7004) << "Jobs: " << endl;
01892   for ( ; jit != jobs.end() ; ++jit )
01893     kdDebug(7004) << "   " << jit.key() << " listing " << joburl( jit.key() ).prettyURL() << ": " << (*jit).count() << " entries." << endl;
01894 
01895   kdDebug(7004) << "Items in cache: " << endl;
01896   TQCacheIterator<DirItem> itc( itemsCached );
01897   for ( ; itc.current() ; ++itc )
01898     kdDebug(7004) << "   " << itc.currentKey() << "  rootItem: "
01899                   << ( itc.current()->rootItem ? itc.current()->rootItem->url().prettyURL() : TQString("NULL") )
01900                   << ( itc.current()->lstItems ? TQString(" with %1 items.").arg(itc.current()->lstItems->count()) : TQString(" lstItems=NULL") ) << endl;
01901 }
01902 #endif
01903 
01904 /*********************** -- The new KDirLister -- ************************/
01905 
01906 
01907 KDirLister::KDirLister( bool _delayedMimeTypes )
01908 {
01909   kdDebug(7003) << "+KDirLister" << endl;
01910 
01911   d = new KDirListerPrivate;
01912 
01913   d->complete = true;
01914   d->delayedMimeTypes = _delayedMimeTypes;
01915 
01916   setAutoUpdate( true );
01917   setDirOnlyMode( false );
01918   setShowingDotFiles( false );
01919 
01920   setAutoErrorHandlingEnabled( true, 0 );
01921 }
01922 
01923 KDirLister::~KDirLister()
01924 {
01925   kdDebug(7003) << "-KDirLister" << endl;
01926 
01927   if ( KDirListerCache::exists() )
01928   {
01929     // Stop all running jobs
01930     stop();
01931     s_pCache->forgetDirs( this );
01932   }
01933 
01934   delete d;
01935 }
01936 
01937 bool KDirLister::openURL( const KURL& _url, bool _keep, bool _reload )
01938 {
01939   kdDebug(7003) << k_funcinfo << _url.prettyURL()
01940                 << " keep=" << _keep << " reload=" << _reload << endl;
01941 
01942   // emit the current changes made to avoid an inconsistent treeview
01943   if ( d->changes != NONE && _keep ) {
01944     emitChanges();
01945   }
01946 
01947   d->changes = NONE;
01948 
01949   // If a local path is available, monitor that instead of the given remote URL...
01950   if (!_url.isLocalFile()) {
01951       TDEIO::LocalURLJob* localURLJob = TDEIO::localURL(_url);
01952       if (localURLJob) {
01953           d->openURL_url[localURLJob] = _url;
01954           d->openURL_keep[localURLJob] = _keep;
01955           d->openURL_reload[localURLJob] = _reload;
01956           connect(localURLJob, TQT_SIGNAL(localURL(TDEIO::LocalURLJob*, const KURL&, bool)), this, TQT_SLOT(slotOpenURLGotLocalURL(TDEIO::LocalURLJob*, const KURL&, bool)));
01957           connect(localURLJob, TQT_SIGNAL(destroyed()), this, TQT_SLOT(slotLocalURLKIODestroyed()));
01958       }
01959       return true;
01960   }
01961   else {
01962       return s_pCache->listDir( this, _url, _keep, _reload );
01963   }
01964 }
01965 
01966 void KDirLister::slotOpenURLGotLocalURL(TDEIO::LocalURLJob *job, const KURL& url, bool isLocal) {
01967   KURL realURL = d->openURL_url[job];
01968   if (isLocal) {
01969       realURL = url;
01970       realURL.setInternalReferenceURL(d->openURL_url[job].url());
01971       d->m_referenceURLMap[d->openURL_url[job].url()] = url.path();
01972   }
01973   s_pCache->listDir( this, realURL, d->openURL_keep[job], d->openURL_reload[job] );
01974   d->openURL_url.remove(job);
01975   d->openURL_keep.remove(job);
01976   d->openURL_reload.remove(job);
01977 }
01978 
01979 void KDirLister::slotLocalURLKIODestroyed() {
01980   TDEIO::LocalURLJob* terminatedJob = const_cast<TDEIO::LocalURLJob*>(static_cast<const TDEIO::LocalURLJob*>(sender()));
01981 
01982   if (d->openURL_url.contains(terminatedJob)) {
01983       s_pCache->listDir( this, d->openURL_url[terminatedJob], d->openURL_keep[terminatedJob], d->openURL_reload[terminatedJob] );
01984       d->openURL_url.remove(terminatedJob);
01985       d->openURL_keep.remove(terminatedJob);
01986       d->openURL_reload.remove(terminatedJob);
01987   }
01988 }
01989 
01990 void KDirLister::stop()
01991 {
01992   kdDebug(7003) << k_funcinfo << endl;
01993   s_pCache->stop( this );
01994   d->m_referenceURLMap.clear();
01995 }
01996 
01997 void KDirLister::stop( const KURL& _url )
01998 {
01999   kdDebug(7003) << k_funcinfo << _url.prettyURL() << endl;
02000   s_pCache->stop( this, _url );
02001   d->m_referenceURLMap.remove(_url.url());
02002 }
02003 
02004 bool KDirLister::autoUpdate() const
02005 {
02006   return d->autoUpdate;
02007 }
02008 
02009 void KDirLister::setAutoUpdate( bool _enable )
02010 {
02011   if ( d->autoUpdate == _enable )
02012     return;
02013 
02014   d->autoUpdate = _enable;
02015   s_pCache->setAutoUpdate( this, _enable );
02016 }
02017 
02018 bool KDirLister::showingDotFiles() const
02019 {
02020   return d->isShowingDotFiles;
02021 }
02022 
02023 void KDirLister::setShowingDotFiles( bool _showDotFiles )
02024 {
02025   if ( d->isShowingDotFiles == _showDotFiles )
02026     return;
02027 
02028   d->isShowingDotFiles = _showDotFiles;
02029   d->changes ^= DOT_FILES;
02030 }
02031 
02032 bool KDirLister::dirOnlyMode() const
02033 {
02034   return d->dirOnlyMode;
02035 }
02036 
02037 void KDirLister::setDirOnlyMode( bool _dirsOnly )
02038 {
02039   if ( d->dirOnlyMode == _dirsOnly )
02040     return;
02041 
02042   d->dirOnlyMode = _dirsOnly;
02043   d->changes ^= DIR_ONLY_MODE;
02044 }
02045 
02046 bool KDirLister::autoErrorHandlingEnabled() const
02047 {
02048   return d->autoErrorHandling;
02049 }
02050 
02051 void KDirLister::setAutoErrorHandlingEnabled( bool enable, TQWidget* parent )
02052 {
02053   d->autoErrorHandling = enable;
02054   d->errorParent = parent;
02055 }
02056 
02057 const KURL& KDirLister::url() const
02058 {
02059   return d->url;
02060 }
02061 
02062 const KURL::List& KDirLister::directories() const
02063 {
02064   return d->lstDirs;
02065 }
02066 
02067 void KDirLister::emitChanges()
02068 {
02069   if ( d->changes == NONE )
02070     return;
02071 
02072   static const TQString& dot = TDEGlobal::staticQString(".");
02073   static const TQString& dotdot = TDEGlobal::staticQString("..");
02074 
02075   for ( KURL::List::Iterator it = d->lstDirs.begin();
02076         it != d->lstDirs.end(); ++it )
02077   {
02078     KFileItemListIterator kit( *s_pCache->itemsForDir( *it ) );
02079     for ( ; kit.current(); ++kit )
02080     {
02081       if ( (*kit)->text() == dot || (*kit)->text() == dotdot )
02082         continue;
02083 
02084       bool oldMime = true, newMime = true;
02085 
02086       if ( d->changes & MIME_FILTER )
02087       {
02088         oldMime = doMimeFilter( (*kit)->mimetype(), d->oldMimeFilter )
02089                 && doMimeExcludeFilter( (*kit)->mimetype(), d->oldMimeExcludeFilter );
02090         newMime = doMimeFilter( (*kit)->mimetype(), d->mimeFilter )
02091                 && doMimeExcludeFilter( (*kit)->mimetype(), d->mimeExcludeFilter );
02092 
02093         if ( oldMime && !newMime )
02094         {
02095           emit deleteItem( *kit );
02096           continue;
02097         }
02098       }
02099 
02100       if ( d->changes & DIR_ONLY_MODE )
02101       {
02102         // the lister switched to dirOnlyMode
02103         if ( d->dirOnlyMode )
02104         {
02105           if ( !(*kit)->isDir() )
02106             emit deleteItem( *kit );
02107         }
02108         else if ( !(*kit)->isDir() ) {
02109           addNewItem( *kit );
02110         }
02111 
02112         continue;
02113       }
02114 
02115       if ( (*kit)->isHidden() )
02116       {
02117         if ( d->changes & DOT_FILES )
02118         {
02119           // the lister switched to dot files mode
02120           if ( d->isShowingDotFiles ) {
02121             addNewItem( *kit );
02122           }
02123           else {
02124             emit deleteItem( *kit );
02125           }
02126 
02127           continue;
02128         }
02129       }
02130       else if ( d->changes & NAME_FILTER )
02131       {
02132         bool oldName = (*kit)->isDir() ||
02133                        d->oldFilters.isEmpty() ||
02134                        doNameFilter( (*kit)->text(), d->oldFilters );
02135 
02136         bool newName = (*kit)->isDir() ||
02137                        d->lstFilters.isEmpty() ||
02138                        doNameFilter( (*kit)->text(), d->lstFilters );
02139 
02140         if ( oldName && !newName )
02141         {
02142           emit deleteItem( *kit );
02143           continue;
02144         }
02145         else if ( !oldName && newName ) {
02146           addNewItem( *kit );
02147         }
02148       }
02149 
02150       if ( (d->changes & MIME_FILTER) && !oldMime && newMime ) {
02151         addNewItem( *kit );
02152       }
02153     }
02154 
02155     emitItems();
02156   }
02157 
02158   d->changes = NONE;
02159 }
02160 
02161 void KDirLister::updateDirectory( const KURL& _u )
02162 {
02163   s_pCache->updateDirectory( _u );
02164 }
02165 
02166 bool KDirLister::isFinished() const
02167 {
02168   return d->complete;
02169 }
02170 
02171 KFileItem *KDirLister::rootItem() const
02172 {
02173   return d->rootFileItem;
02174 }
02175 
02176 KFileItem *KDirLister::findByURL( const KURL& _url ) const
02177 {
02178   return s_pCache->findByURL( this, _url );
02179 }
02180 
02181 KFileItem *KDirLister::findByName( const TQString& _name ) const
02182 {
02183   return s_pCache->findByName( this, _name );
02184 }
02185 
02186 #ifndef KDE_NO_COMPAT
02187 KFileItem *KDirLister::find( const KURL& _url ) const
02188 {
02189   return findByURL( _url );
02190 }
02191 #endif
02192 
02193 
02194 // ================ public filter methods ================ //
02195 
02196 void KDirLister::setNameFilter( const TQString& nameFilter )
02197 {
02198   if ( !(d->changes & NAME_FILTER) )
02199   {
02200     d->oldFilters = d->lstFilters;
02201     d->lstFilters.setAutoDelete( false );
02202   }
02203 
02204   d->lstFilters.clear();
02205   d->lstFilters.setAutoDelete( true );
02206 
02207   d->nameFilter = nameFilter;
02208 
02209   // Split on white space
02210   TQStringList list = TQStringList::split( ' ', nameFilter );
02211   for ( TQStringList::Iterator it = list.begin(); it != list.end(); ++it )
02212     d->lstFilters.append( new TQRegExp(*it, false, true ) );
02213 
02214   d->changes |= NAME_FILTER;
02215 }
02216 
02217 const TQString& KDirLister::nameFilter() const
02218 {
02219   return d->nameFilter;
02220 }
02221 
02222 void KDirLister::setMimeFilter( const TQStringList& mimeFilter )
02223 {
02224   if ( !(d->changes & MIME_FILTER) )
02225     d->oldMimeFilter = d->mimeFilter;
02226 
02227   if ( mimeFilter.find("all/allfiles") != mimeFilter.end() || 
02228        mimeFilter.find("all/all") != mimeFilter.end() )
02229     d->mimeFilter.clear();
02230   else
02231     d->mimeFilter = mimeFilter;
02232 
02233   d->changes |= MIME_FILTER;
02234 }
02235 
02236 void KDirLister::setMimeExcludeFilter( const TQStringList& mimeExcludeFilter )
02237 {
02238   if ( !(d->changes & MIME_FILTER) )
02239     d->oldMimeExcludeFilter = d->mimeExcludeFilter;
02240 
02241   d->mimeExcludeFilter = mimeExcludeFilter;
02242   d->changes |= MIME_FILTER;
02243 }
02244 
02245 
02246 void KDirLister::clearMimeFilter()
02247 {
02248   if ( !(d->changes & MIME_FILTER) )
02249   {
02250     d->oldMimeFilter = d->mimeFilter;
02251     d->oldMimeExcludeFilter = d->mimeExcludeFilter;
02252   }
02253   d->mimeFilter.clear();
02254   d->mimeExcludeFilter.clear();
02255   d->changes |= MIME_FILTER;
02256 }
02257 
02258 const TQStringList& KDirLister::mimeFilters() const
02259 {
02260   return d->mimeFilter;
02261 }
02262 
02263 bool KDirLister::matchesFilter( const TQString& name ) const
02264 {
02265   return doNameFilter( name, d->lstFilters );
02266 }
02267 
02268 bool KDirLister::matchesMimeFilter( const TQString& mime ) const
02269 {
02270   return doMimeFilter( mime, d->mimeFilter ) && doMimeExcludeFilter(mime,d->mimeExcludeFilter);
02271 }
02272 
02273 // ================ protected methods ================ //
02274 
02275 bool KDirLister::matchesFilter( const KFileItem *item ) const
02276 {
02277   Q_ASSERT( item );
02278   static const TQString& dotdot = TDEGlobal::staticQString("..");
02279 
02280   if ( item->text() == dotdot )
02281     return false;
02282 
02283   if ( !d->isShowingDotFiles && item->isHidden() )
02284     return false;
02285 
02286   if ( item->isDir() || d->lstFilters.isEmpty() )
02287     return true;
02288 
02289   return matchesFilter( item->text() );
02290 }
02291 
02292 bool KDirLister::matchesMimeFilter( const KFileItem *item ) const
02293 {
02294   Q_ASSERT( item );
02295   // Don't lose time determining the mimetype if there is no filter
02296   if ( d->mimeFilter.isEmpty() && d->mimeExcludeFilter.isEmpty() )
02297       return true;
02298   return matchesMimeFilter( item->mimetype() );
02299 }
02300 
02301 bool KDirLister::doNameFilter( const TQString& name, const TQPtrList<TQRegExp>& filters ) const
02302 {
02303   for ( TQPtrListIterator<TQRegExp> it( filters ); it.current(); ++it )
02304     if ( it.current()->exactMatch( name ) )
02305       return true;
02306 
02307   return false;
02308 }
02309 
02310 bool KDirLister::doMimeFilter( const TQString& mime, const TQStringList& filters ) const
02311 {
02312   if ( filters.isEmpty() )
02313     return true;
02314 
02315   KMimeType::Ptr mimeptr = KMimeType::mimeType(mime);
02316   //kdDebug(7004) << "doMimeFilter: investigating: "<<mimeptr->name()<<endl;
02317   TQStringList::ConstIterator it = filters.begin();
02318   for ( ; it != filters.end(); ++it )
02319     if ( mimeptr->is(*it) )
02320       return true;
02321     //else   kdDebug(7004) << "doMimeFilter: compared without result to  "<<*it<<endl;
02322 
02323 
02324   return false;
02325 }
02326 
02327 bool KDirLister::doMimeExcludeFilter( const TQString& mime, const TQStringList& filters ) const
02328 {
02329   if ( filters.isEmpty() )
02330     return true;
02331 
02332   TQStringList::ConstIterator it = filters.begin();
02333   for ( ; it != filters.end(); ++it )
02334     if ( (*it) == mime )
02335       return false;
02336 
02337   return true;
02338 }
02339 
02340 
02341 bool KDirLister::validURL( const KURL& _url ) const
02342 {
02343   return s_pCache->validURL( this, _url );
02344 }
02345 
02346 void KDirLister::handleError( TDEIO::Job *job )
02347 {
02348   if ( d->autoErrorHandling ) {
02349     job->showErrorDialog( d->errorParent );
02350   }
02351 }
02352 
02353 
02354 // ================= private methods ================= //
02355 
02356 void KDirLister::addNewItem( const KFileItem *item )
02357 {
02358   if ( ( d->dirOnlyMode && !item->isDir() ) || !matchesFilter( item ) ) {
02359     return; // No reason to continue... bailing out here prevents a mimetype scan.
02360   }
02361 
02362   if ((item->url().internalReferenceURL() != "")
02363       && (d->m_referenceURLMap.contains(item->url().internalReferenceURL()))) {
02364     // Likely a media:/ tdeioslave URL or similar
02365     // Rewrite the URL to ensure that the user remains within the media:/ tree!
02366     TQString itemPath = item->url().path();
02367     if (itemPath.startsWith(d->m_referenceURLMap[item->url().internalReferenceURL()])) {
02368       itemPath = itemPath.remove(0, d->m_referenceURLMap[item->url().internalReferenceURL()].length());
02369       TQString newPath = item->url().internalReferenceURL();
02370       if (!newPath.endsWith("/")) newPath = newPath + "/";
02371       while (itemPath.startsWith("/")) itemPath = itemPath.remove(0,1);
02372       while (itemPath.endsWith("/")) itemPath.truncate(itemPath.length()-1);
02373       newPath = newPath + itemPath;
02374       const_cast<KFileItem*>(item)->setListerURL(item->url());
02375       const_cast<KFileItem*>(item)->setURL(newPath);
02376     }
02377   }
02378 
02379   if ( matchesMimeFilter( item ) )
02380   {
02381     if ( !d->lstNewItems ) {
02382       d->lstNewItems = new KFileItemList;
02383     }
02384 
02385     d->lstNewItems->append( item );            // items not filtered
02386   }
02387   else
02388   {
02389     if ( !d->lstMimeFilteredItems ) {
02390       d->lstMimeFilteredItems = new KFileItemList;
02391     }
02392 
02393     d->lstMimeFilteredItems->append( item );   // only filtered by mime
02394   }
02395 }
02396 
02397 void KDirLister::addNewItems( const KFileItemList& items )
02398 {
02399   // TODO: make this faster - test if we have a filter at all first
02400   // DF: was this profiled? The matchesFoo() functions should be fast, w/o filters...
02401   // Of course if there is no filter and we can do a range-insertion instead of a loop, that might be good.
02402   // But that's for Qt4, not possible with TQPtrList.
02403   for ( KFileItemListIterator kit( items ); kit.current(); ++kit ) {
02404     addNewItem( *kit );
02405   }
02406 }
02407 
02408 void KDirLister::aboutToRefreshItem( const KFileItem *item )
02409 {
02410   // The code here follows the logic in addNewItem
02411   if ( ( d->dirOnlyMode && !item->isDir() ) || !matchesFilter( item ) )
02412     d->refreshItemWasFiltered = true;
02413   else if ( !matchesMimeFilter( item ) )
02414     d->refreshItemWasFiltered = true;
02415   else
02416     d->refreshItemWasFiltered = false;
02417 }
02418 
02419 void KDirLister::addRefreshItem( const KFileItem *item )
02420 {
02421   bool isExcluded = (d->dirOnlyMode && !item->isDir()) || !matchesFilter( item );
02422 
02423   if ((item->url().internalReferenceURL() != "")
02424       && (d->m_referenceURLMap.contains(item->url().internalReferenceURL()))) {
02425     // Likely a media:/ tdeioslave URL or similar
02426     // Rewrite the URL to ensure that the user remains within the media:/ tree!
02427     TQString itemPath = item->url().path();
02428     if (itemPath.startsWith(d->m_referenceURLMap[item->url().internalReferenceURL()])) {
02429       itemPath = itemPath.remove(0, d->m_referenceURLMap[item->url().internalReferenceURL()].length());
02430       TQString newPath = item->url().internalReferenceURL();
02431       if (!newPath.endsWith("/")) newPath = newPath + "/";
02432       while (itemPath.startsWith("/")) itemPath = itemPath.remove(0,1);
02433       while (itemPath.endsWith("/")) itemPath.truncate(itemPath.length()-1);
02434       newPath = newPath + itemPath;
02435       const_cast<KFileItem*>(item)->setListerURL(item->url());
02436       const_cast<KFileItem*>(item)->setURL(newPath);
02437     }
02438   }
02439 
02440   if ( !isExcluded && matchesMimeFilter( item ) )
02441   {
02442     if ( d->refreshItemWasFiltered )
02443     {
02444       if ( !d->lstNewItems ) {
02445         d->lstNewItems = new KFileItemList;
02446       }
02447 
02448       d->lstNewItems->append( item );
02449     }
02450     else
02451     {
02452       if ( !d->lstRefreshItems ) {
02453         d->lstRefreshItems = new KFileItemList;
02454       }
02455 
02456       d->lstRefreshItems->append( item );
02457     }
02458   }
02459   else if ( !d->refreshItemWasFiltered )
02460   {
02461     if ( !d->lstRemoveItems ) {
02462       d->lstRemoveItems = new KFileItemList;
02463     }
02464 
02465     // notify the user that the mimetype of a file changed that doesn't match
02466     // a filter or does match an exclude filter
02467     d->lstRemoveItems->append( item );
02468   }
02469 }
02470 
02471 void KDirLister::emitItems()
02472 {
02473   KFileItemList *tmpNew = d->lstNewItems;
02474   d->lstNewItems = 0;
02475 
02476   KFileItemList *tmpMime = d->lstMimeFilteredItems;
02477   d->lstMimeFilteredItems = 0;
02478 
02479   KFileItemList *tmpRefresh = d->lstRefreshItems;
02480   d->lstRefreshItems = 0;
02481 
02482   KFileItemList *tmpRemove = d->lstRemoveItems;
02483   d->lstRemoveItems = 0;
02484 
02485   if ( tmpNew )
02486   {
02487     // For historical reasons, items with different protocols and/or prefixes must be emitted separately
02488     TQString protocol;
02489     TQString prefix;
02490     TQString prevProtocol;
02491     TQString prevPrefix;
02492     KFileItemList emitList;
02493     for ( KFileItemListIterator kit( *tmpNew ); kit.current(); ++kit )
02494     {
02495       KFileItem *item = *kit;
02496       protocol = item->url().protocol();
02497       prefix = TQStringList::split("/", item->url().path())[0];
02498       if ((protocol != prevProtocol) || (prefix != prevPrefix)) {
02499         if (emitList.count() > 0) {
02500           emit newItems( emitList );
02501           emitList.clear();
02502         }
02503       }
02504       emitList.append(item);
02505       prevProtocol = protocol;
02506       prevPrefix = prefix;
02507     }
02508 
02509     if (emitList.count() > 0) {
02510       emit newItems( emitList );
02511     }
02512     delete tmpNew;
02513   }
02514 
02515   if ( tmpMime )
02516   {
02517     emit itemsFilteredByMime( *tmpMime );
02518     delete tmpMime;
02519   }
02520 
02521   if ( tmpRefresh )
02522   {
02523     emit refreshItems( *tmpRefresh );
02524     delete tmpRefresh;
02525   }
02526 
02527   if ( tmpRemove )
02528   {
02529     for ( KFileItem *tmp = tmpRemove->first(); tmp; tmp = tmpRemove->next() ) {
02530       emit deleteItem( tmp );
02531     }
02532     delete tmpRemove;
02533   }
02534 }
02535 
02536 void KDirLister::emitDeleteItem( KFileItem *item )
02537 {
02538   if ( ( d->dirOnlyMode && !item->isDir() ) || !matchesFilter( item ) ) {
02539     return; // No reason to continue... bailing out here prevents a mimetype scan.
02540   }
02541 
02542   if ( matchesMimeFilter( item ) ) {
02543     emit deleteItem( item );
02544   }
02545 }
02546 
02547 
02548 // ================ private slots ================ //
02549 
02550 void KDirLister::slotInfoMessage( TDEIO::Job *, const TQString& message )
02551 {
02552   emit infoMessage( message );
02553 }
02554 
02555 void KDirLister::slotPercent( TDEIO::Job *job, unsigned long pcnt )
02556 {
02557   d->jobData[static_cast<TDEIO::ListJob *>(job)].percent = pcnt;
02558 
02559   int result = 0;
02560 
02561   TDEIO::filesize_t size = 0;
02562 
02563   TQMap< TDEIO::ListJob *, KDirListerPrivate::JobData >::Iterator dataIt = d->jobData.begin();
02564   while ( dataIt != d->jobData.end() )
02565   {
02566     result += (*dataIt).percent * (*dataIt).totalSize;
02567     size += (*dataIt).totalSize;
02568     ++dataIt;
02569   }
02570 
02571   if ( size != 0 )
02572     result /= size;
02573   else
02574     result = 100;
02575   emit percent( result );
02576 }
02577 
02578 void KDirLister::slotTotalSize( TDEIO::Job *job, TDEIO::filesize_t size )
02579 {
02580   d->jobData[static_cast<TDEIO::ListJob *>(job)].totalSize = size;
02581 
02582   TDEIO::filesize_t result = 0;
02583   TQMap< TDEIO::ListJob *, KDirListerPrivate::JobData >::Iterator dataIt = d->jobData.begin();
02584   while ( dataIt != d->jobData.end() )
02585   {
02586     result += (*dataIt).totalSize;
02587     ++dataIt;
02588   }
02589 
02590   emit totalSize( result );
02591 }
02592 
02593 void KDirLister::slotProcessedSize( TDEIO::Job *job, TDEIO::filesize_t size )
02594 {
02595   d->jobData[static_cast<TDEIO::ListJob *>(job)].processedSize = size;
02596 
02597   TDEIO::filesize_t result = 0;
02598   TQMap< TDEIO::ListJob *, KDirListerPrivate::JobData >::Iterator dataIt = d->jobData.begin();
02599   while ( dataIt != d->jobData.end() )
02600   {
02601     result += (*dataIt).processedSize;
02602     ++dataIt;
02603   }
02604 
02605   emit processedSize( result );
02606 }
02607 
02608 void KDirLister::slotSpeed( TDEIO::Job *job, unsigned long spd )
02609 {
02610   d->jobData[static_cast<TDEIO::ListJob *>(job)].speed = spd;
02611 
02612   int result = 0;
02613   TQMap< TDEIO::ListJob *, KDirListerPrivate::JobData >::Iterator dataIt = d->jobData.begin();
02614   while ( dataIt != d->jobData.end() )
02615   {
02616     result += (*dataIt).speed;
02617     ++dataIt;
02618   }
02619 
02620   emit speed( result );
02621 }
02622 
02623 uint KDirLister::numJobs()
02624 {
02625   return d->jobData.count();
02626 }
02627 
02628 void KDirLister::jobDone( TDEIO::ListJob *job )
02629 {
02630   d->jobData.remove( job );
02631 }
02632 
02633 void KDirLister::jobStarted( TDEIO::ListJob *job )
02634 {
02635   KDirListerPrivate::JobData jobData;
02636   jobData.speed = 0;
02637   jobData.percent = 0;
02638   jobData.processedSize = 0;
02639   jobData.totalSize = 0;
02640 
02641   d->jobData.insert( job, jobData );
02642   d->complete = false;
02643 }
02644 
02645 void KDirLister::connectJob( TDEIO::ListJob *job )
02646 {
02647   connect( job, TQT_SIGNAL(infoMessage( TDEIO::Job *, const TQString& )),
02648            this, TQT_SLOT(slotInfoMessage( TDEIO::Job *, const TQString& )) );
02649   connect( job, TQT_SIGNAL(percent( TDEIO::Job *, unsigned long )),
02650            this, TQT_SLOT(slotPercent( TDEIO::Job *, unsigned long )) );
02651   connect( job, TQT_SIGNAL(totalSize( TDEIO::Job *, TDEIO::filesize_t )),
02652            this, TQT_SLOT(slotTotalSize( TDEIO::Job *, TDEIO::filesize_t )) );
02653   connect( job, TQT_SIGNAL(processedSize( TDEIO::Job *, TDEIO::filesize_t )),
02654            this, TQT_SLOT(slotProcessedSize( TDEIO::Job *, TDEIO::filesize_t )) );
02655   connect( job, TQT_SIGNAL(speed( TDEIO::Job *, unsigned long )),
02656            this, TQT_SLOT(slotSpeed( TDEIO::Job *, unsigned long )) );
02657 }
02658 
02659 void KDirLister::emitCompleted( const KURL& _url )
02660 {
02661   KURL emitURL = _url;
02662 
02663   if ((_url.internalReferenceURL() != "")
02664       && (d->m_referenceURLMap.contains(_url.internalReferenceURL()))) {
02665     // Likely a media:/ tdeioslave URL or similar
02666     // Rewrite the URL to ensure that the user remains within the media:/ tree!
02667     TQString itemPath = _url.path();
02668     if (itemPath.startsWith(d->m_referenceURLMap[_url.internalReferenceURL()])) {
02669       itemPath = itemPath.remove(0, d->m_referenceURLMap[_url.internalReferenceURL()].length());
02670       TQString newPath = _url.internalReferenceURL();
02671       if (!newPath.endsWith("/")) newPath = newPath + "/";
02672       while (itemPath.startsWith("/")) itemPath = itemPath.remove(0,1);
02673       while (itemPath.endsWith("/")) itemPath.truncate(itemPath.length()-1);
02674       newPath = newPath + itemPath;
02675       emitURL = newPath;
02676     }
02677   }
02678 
02679   emit completed( emitURL );
02680 }
02681 
02682 void KDirLister::setMainWindow( TQWidget *window )
02683 {
02684   d->window = window;
02685 }
02686 
02687 TQWidget *KDirLister::mainWindow()
02688 {
02689   return d->window;
02690 }
02691 
02692 KFileItemList KDirLister::items( WhichItems which ) const
02693 {
02694     return itemsForDir( url(), which );
02695 }
02696 
02697 KFileItemList KDirLister::itemsForDir( const KURL& dir, WhichItems which ) const
02698 {
02699     KFileItemList result;
02700     KFileItemList *allItems = s_pCache->itemsForDir( dir );
02701     if ( !allItems ) {
02702         return result;
02703     }
02704 
02705     if ( which == AllItems ) {
02706         result = *allItems; // shallow copy
02707     }
02708     else // only items passing the filters
02709     {
02710         for ( KFileItemListIterator kit( *allItems ); kit.current(); ++kit )
02711         {
02712             KFileItem *item = *kit;
02713             bool isExcluded = (d->dirOnlyMode && !item->isDir()) || !matchesFilter( item );
02714             if ( !isExcluded && matchesMimeFilter( item ) ) {
02715                 result.append( item );
02716             }
02717         }
02718     }
02719 
02720     return result;
02721 }
02722 
02723 // to keep BC changes
02724 
02725 void KDirLister::virtual_hook( int, void * )
02726 { /*BASE::virtual_hook( id, data );*/ }
02727 
02728 #include "kdirlister.moc"
02729 #include "kdirlister_p.moc"

tdeio/tdeio

Skip menu "tdeio/tdeio"
  • Main Page
  • Modules
  • Namespace List
  • Class Hierarchy
  • Alphabetical List
  • Class List
  • File List
  • Namespace Members
  • Class Members
  • Related Pages

tdeio/tdeio

Skip menu "tdeio/tdeio"
  • arts
  • dcop
  • dnssd
  • interfaces
  •   kspeech
  •     interface
  •     library
  •   tdetexteditor
  • kate
  • kded
  • kdoctools
  • kimgio
  • kjs
  • libtdemid
  • libtdescreensaver
  • tdeabc
  • tdecmshell
  • tdecore
  • tdefx
  • tdehtml
  • tdeinit
  • tdeio
  •   bookmarks
  •   httpfilter
  •   kpasswdserver
  •   kssl
  •   tdefile
  •   tdeio
  •   tdeioexec
  • tdeioslave
  •   http
  • tdemdi
  •   tdemdi
  • tdenewstuff
  • tdeparts
  • tdeprint
  • tderandr
  • tderesources
  • tdespell2
  • tdesu
  • tdeui
  • tdeunittest
  • tdeutils
  • tdewallet
Generated for tdeio/tdeio by doxygen 1.6.3
This website is maintained by Timothy Pearson.