kio Library API Documentation

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, 2002 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., 59 Temple Place - Suite 330,
00019    Boston, MA 02111-1307, USA.
00020 */
00021 
00022 #include "kdirlister.h"
00023 
00024 #include <qregexp.h>
00025 #include <qptrlist.h>
00026 #include <qtimer.h>
00027 
00028 #include <kapplication.h>
00029 #include <kdebug.h>
00030 #include <klocale.h>
00031 #include <kio/job.h>
00032 #include <kmessagebox.h>
00033 #include <kglobal.h>
00034 #include <kglobalsettings.h>
00035 #include <kstaticdeleter.h>
00036 
00037 #include "kdirlister_p.h"
00038 
00039 #include <assert.h>
00040 
00041 KDirListerCache* KDirListerCache::s_pSelf = 0;
00042 static KStaticDeleter<KDirListerCache> sd_KDirListerCache;
00043 
00044 // Enable this to get printDebug() called often, to see the contents of the cache
00045 //#define DEBUG_CACHE
00046 
00047 // Make really sure it doesn't get activated in the final build
00048 #ifdef NDEBUG
00049 #undef DEBUG_CACHE
00050 #endif
00051 
00052 KDirListerCache::KDirListerCache( int maxCount )
00053   : itemsCached( maxCount )
00054 {
00055   kdDebug(7004) << "+KDirListerCache" << endl;
00056 
00057   itemsInUse.setAutoDelete( false );
00058   itemsCached.setAutoDelete( true );
00059   urlsCurrentlyListed.setAutoDelete( true );
00060   urlsCurrentlyHeld.setAutoDelete( true );
00061   pendingUpdates.setAutoDelete( true );
00062 
00063   connect( kdirwatch, SIGNAL( dirty( const QString& ) ),
00064            this, SLOT( slotFileDirty( const QString& ) ) );
00065   connect( kdirwatch, SIGNAL( created( const QString& ) ),
00066            this, SLOT( slotFileCreated( const QString& ) ) );
00067   connect( kdirwatch, SIGNAL( deleted( const QString& ) ),
00068            this, SLOT( slotFileDeleted( const QString& ) ) );
00069 }
00070 
00071 KDirListerCache::~KDirListerCache()
00072 {
00073   kdDebug(7004) << "-KDirListerCache" << endl;
00074 
00075   itemsInUse.setAutoDelete( true );
00076   itemsInUse.clear();
00077   itemsCached.clear();
00078   urlsCurrentlyListed.clear();
00079   urlsCurrentlyHeld.clear();
00080 
00081   if ( KDirWatch::exists() )
00082     kdirwatch->disconnect( this );
00083 }
00084 
00085 // setting _reload to true will emit the old files and
00086 // call updateDirectory
00087 void KDirListerCache::listDir( KDirLister* lister, const KURL& _u,
00088                                bool _keep, bool _reload )
00089 {
00090   // like this we don't have to worry about trailing slashes any further
00091   KURL _url = _u;
00092   _url.cleanPath(); // kill consecutive slashes
00093   _url.adjustPath(-1);
00094   QString urlStr = _url.url();
00095 
00096 #ifdef DEBUG_CACHE
00097   printDebug();
00098 #endif
00099   kdDebug(7004) << k_funcinfo << lister << " url=" << _url
00100                 << " keep=" << _keep << " reload=" << _reload << endl;
00101 
00102   if ( !_keep )
00103   {
00104     // stop any running jobs for lister
00105     stop( lister );
00106 
00107     // clear our internal list for lister
00108     forgetDirs( lister );
00109 
00110     lister->d->rootFileItem = 0;
00111   }
00112   else if ( lister->d->lstDirs.contains( _url ) )
00113   {
00114     // stop the job listing _url for this lister
00115     stop( lister, _url );
00116 
00117     // clear _url for lister
00118     forgetDirs( lister, _url, true );
00119 
00120     if ( lister->d->url == _url )
00121       lister->d->rootFileItem = 0;
00122   }
00123 
00124   lister->d->lstDirs.append( _url );
00125 
00126   if ( lister->d->url.isEmpty() || !_keep ) // set toplevel URL only if not set yet
00127     lister->d->url = _url;
00128 
00129   DirItem *itemU = itemsInUse[urlStr];
00130   DirItem *itemC;
00131 
00132   if ( !urlsCurrentlyListed[urlStr] )
00133   {
00134     // if there is an update running for _url already we get into
00135     // the following case - it will just be restarted by updateDirectory().
00136 
00137     if ( itemU )
00138     {
00139       kdDebug(7004) << "listDir: Entry already in use: " << _url << endl;
00140 
00141       bool oldState = lister->d->complete;
00142       lister->d->complete = false;
00143 
00144       emit lister->started( _url );
00145 
00146       if ( !lister->d->rootFileItem && lister->d->url == _url )
00147         lister->d->rootFileItem = itemU->rootItem;
00148 
00149       lister->addNewItems( *(itemU->lstItems) );
00150       lister->emitItems();
00151 
00152       lister->d->complete = oldState;
00153 
00154       emit lister->completed( _url );
00155       if ( lister->d->complete )
00156         emit lister->completed();
00157 
00158       // _url is already in use, so there is already an entry in urlsCurrentlyHeld
00159       assert( urlsCurrentlyHeld[urlStr] );
00160       urlsCurrentlyHeld[urlStr]->append( lister );
00161 
00162       if ( _reload || !itemU->complete )
00163         updateDirectory( _url );
00164     }
00165     else if ( !_reload && (itemC = itemsCached.take( urlStr )) )
00166     {
00167       kdDebug(7004) << "listDir: Entry in cache: " << _url << endl;
00168 
00169       itemC->decAutoUpdate();
00170       itemsInUse.insert( urlStr, itemC );
00171       itemU = itemC;
00172 
00173       bool oldState = lister->d->complete;
00174       lister->d->complete = false;
00175 
00176       emit lister->started( _url );
00177 
00178       if ( !lister->d->rootFileItem && lister->d->url == _url )
00179         lister->d->rootFileItem = itemC->rootItem;
00180 
00181       lister->addNewItems( *(itemC->lstItems) );
00182       lister->emitItems();
00183 
00184       lister->d->complete = oldState;
00185 
00186       emit lister->completed( _url );
00187       if ( lister->d->complete )
00188         emit lister->completed();
00189 
00190       Q_ASSERT( !urlsCurrentlyHeld[urlStr] );
00191       QPtrList<KDirLister> *list = new QPtrList<KDirLister>;
00192       list->append( lister );
00193       urlsCurrentlyHeld.insert( urlStr, list );
00194 
00195       if ( !itemC->complete )
00196         updateDirectory( _url );
00197     }
00198     else  // dir not in cache or _reload is true
00199     {
00200       kdDebug(7004) << "listDir: Entry not in cache or reloaded: " << _url << endl;
00201 
00202       QPtrList<KDirLister> *list = new QPtrList<KDirLister>;
00203       list->append( lister );
00204       urlsCurrentlyListed.insert( urlStr, list );
00205 
00206       itemsCached.remove( urlStr );
00207       itemU = new DirItem( _url );
00208       itemsInUse.insert( urlStr, itemU );
00209 
00210 //        // we have a limit of MAX_JOBS_PER_LISTER concurrently running jobs
00211 //        if ( lister->numJobs() >= MAX_JOBS_PER_LISTER )
00212 //        {
00213 //          lstPendingUpdates.append( _url );
00214 //        }
00215 //        else
00216 //        {
00217 
00218       if ( lister->d->url == _url )
00219         lister->d->rootFileItem = 0;
00220 
00221       lister->d->complete = false;
00222 
00223       KIO::ListJob* job = KIO::listDir( _url, false /* no default GUI */ );
00224       lister->jobStarted(job);
00225       jobs.insert( job, QValueList<KIO::UDSEntry>() );
00226 
00227       if (lister->d->window)
00228         job->setWindow(lister->d->window);
00229 
00230       connect( job, SIGNAL( entries( KIO::Job *, const KIO::UDSEntryList & ) ),
00231                this, SLOT( slotEntries( KIO::Job *, const KIO::UDSEntryList & ) ) );
00232       connect( job, SIGNAL( result( KIO::Job * ) ),
00233                this, SLOT( slotResult( KIO::Job * ) ) );
00234       connect( job, SIGNAL( redirection( KIO::Job *, const KURL & ) ),
00235                this, SLOT( slotRedirection( KIO::Job *, const KURL & ) ) );
00236 
00237       connect( job, SIGNAL( infoMessage( KIO::Job *, const QString& ) ),
00238                lister, SLOT( slotInfoMessage( KIO::Job *, const QString& ) ) );
00239       connect( job, SIGNAL( percent( KIO::Job *, unsigned long ) ),
00240                lister, SLOT( slotPercent( KIO::Job *, unsigned long ) ) );
00241       connect( job, SIGNAL( totalSize( KIO::Job *, KIO::filesize_t ) ),
00242                lister, SLOT( slotTotalSize( KIO::Job *, KIO::filesize_t ) ) );
00243       connect( job, SIGNAL( processedSize( KIO::Job *, KIO::filesize_t ) ),
00244                lister, SLOT( slotProcessedSize( KIO::Job *, KIO::filesize_t ) ) );
00245       connect( job, SIGNAL( speed( KIO::Job *, unsigned long ) ),
00246                lister, SLOT( slotSpeed( KIO::Job *, unsigned long ) ) );
00247 
00248       emit lister->started( _url );
00249 
00250 //        }
00251     }
00252   }
00253   else
00254   {
00255     kdDebug(7004) << k_funcinfo << "Entry currently being listed: " << _url << endl;
00256 
00257     emit lister->started( _url );
00258 
00259     lister->d->complete = false;
00260     urlsCurrentlyListed[urlStr]->append( lister );
00261 
00262     KIO::ListJob *job = jobForUrl(urlStr);
00263     Q_ASSERT(job);
00264 
00265     lister->jobStarted(job);
00266     connect( job, SIGNAL( infoMessage( KIO::Job *, const QString& ) ),
00267              lister, SLOT( slotInfoMessage( KIO::Job *, const QString& ) ) );
00268     connect( job, SIGNAL( percent( KIO::Job *, unsigned long ) ),
00269              lister, SLOT( slotPercent( KIO::Job *, unsigned long ) ) );
00270     connect( job, SIGNAL( totalSize( KIO::Job *, KIO::filesize_t ) ),
00271              lister, SLOT( slotTotalSize( KIO::Job *, KIO::filesize_t ) ) );
00272     connect( job, SIGNAL( processedSize( KIO::Job *, KIO::filesize_t ) ),
00273              lister, SLOT( slotProcessedSize( KIO::Job *, KIO::filesize_t ) ) );
00274     connect( job, SIGNAL( speed( KIO::Job *, unsigned long ) ),
00275              lister, SLOT( slotSpeed( KIO::Job *, unsigned long ) ) );
00276 
00277     Q_ASSERT( itemU );
00278 
00279     if ( !lister->d->rootFileItem && lister->d->url == _url )
00280       lister->d->rootFileItem = itemU->rootItem;
00281 
00282     lister->addNewItems( *(itemU->lstItems) );
00283     lister->emitItems();
00284   }
00285 
00286   // automatic updating of directories
00287   if ( lister->d->autoUpdate )
00288     itemU->incAutoUpdate();
00289 }
00290 
00291 void KDirListerCache::stop( KDirLister *lister )
00292 {
00293 #ifdef DEBUG_CACHE
00294   printDebug();
00295 #endif
00296   kdDebug(7004) << k_funcinfo << "lister: " << lister << endl;
00297   bool stopped = false;
00298 
00299   QDictIterator< QPtrList<KDirLister> > it( urlsCurrentlyListed );
00300   QPtrList<KDirLister> *listers;
00301   while ( (listers = it.current()) )
00302   {
00303     if ( listers->findRef( lister ) > -1 )
00304     {
00305       // lister is listing url
00306       QString url = it.currentKey();
00307 
00308       //kdDebug(7004) << k_funcinfo << " found lister in list - for " << url << endl;
00309       bool ret = listers->removeRef( lister );
00310       Q_ASSERT(ret);
00311       KIO::ListJob *job = jobForUrl(url);
00312       lister->jobDone(job);
00313 
00314       // move lister to urlsCurrentlyHeld
00315       QPtrList<KDirLister> *holders = urlsCurrentlyHeld[url];
00316       if ( !holders )
00317       {
00318         holders = new QPtrList<KDirLister>;
00319         holders->append( lister );
00320         urlsCurrentlyHeld.insert( url, holders );
00321       }
00322       else
00323         holders->append( lister );
00324 
00325       emit lister->canceled( KURL( url ) );
00326 
00327       //kdDebug(7004) << "KDirListerCache::stop(lister) remaining list: " << listers->count() << " listers" << endl;
00328       //kill the job if it isn't used any more
00329       if ( listers->isEmpty() )
00330       {
00331         killJob( job );
00332         urlsCurrentlyListed.remove( url );
00333       }
00334 
00335       stopped = true;
00336     }
00337     else
00338       ++it;
00339   }
00340 
00341   if ( stopped )
00342   {
00343     emit lister->canceled();
00344     lister->d->complete = true;
00345   }
00346 
00347   // this is wrong if there is still an update running!
00348   //Q_ASSERT( lister->d->complete );
00349 }
00350 
00351 void KDirListerCache::stop( KDirLister *lister, const KURL& _u )
00352 {
00353   QString urlStr( _u.url(-1) );
00354   KURL _url( urlStr );
00355 
00356   // TODO: consider to stop all the "child jobs" of _url as well
00357   kdDebug(7004) << k_funcinfo << lister << " url=" << _url << endl;
00358 
00359   kdDebug(7004) << "removing listed from urlsCurrentlyListed" << endl;
00360   QPtrList<KDirLister> *listers = urlsCurrentlyListed[urlStr];
00361   if ( !listers || !listers->removeRef( lister ) )
00362     return;
00363 
00364   // move lister to urlsCurrentlyHeld
00365   QPtrList<KDirLister> *holders = urlsCurrentlyHeld[urlStr];
00366   if ( !holders )
00367   {
00368     holders = new QPtrList<KDirLister>;
00369     holders->append( lister );
00370     urlsCurrentlyHeld.insert( urlStr, holders );
00371   }
00372   else
00373     holders->append( lister );
00374 
00375   KIO::ListJob *job = jobForUrl(urlStr);
00376   lister->jobDone(job);
00377   emit lister->canceled( _url );
00378 
00379   if ( listers->isEmpty() )   // kill the job
00380   {
00381     killJob( job );
00382     urlsCurrentlyListed.remove( urlStr );
00383   }
00384 
00385   if ( lister->numJobs() == 0 )
00386   {
00387     lister->d->complete = true;
00388 
00389     // we killed the last job for lister
00390     emit lister->canceled();
00391   }
00392 }
00393 
00394 void KDirListerCache::setAutoUpdate( KDirLister *lister, bool enable )
00395 {
00396   // IMPORTANT: this method does not check for the current autoUpdate state!
00397 
00398   for ( KURL::List::Iterator it = lister->d->lstDirs.begin();
00399         it != lister->d->lstDirs.end(); ++it )
00400   {
00401     if ( enable )
00402       itemsInUse[(*it).url()]->incAutoUpdate();
00403     else
00404       itemsInUse[(*it).url()]->decAutoUpdate();
00405   }
00406 }
00407 
00408 void KDirListerCache::forgetDirs( KDirLister *lister )
00409 {
00410   kdDebug(7004) << k_funcinfo << lister << endl;
00411 
00412   // clear lister->d->lstDirs before calling forgetDirs(), so that
00413   // it doesn't contain things that itemsInUse doesn't. When emitting
00414   // the canceled signals, lstDirs must not contain anything that
00415   // itemsInUse does not contain. (otherwise it might crash in findByName()).
00416   KURL::List lstDirsCopy = lister->d->lstDirs;
00417   lister->d->lstDirs.clear();
00418 
00419   for ( KURL::List::Iterator it = lstDirsCopy.begin();
00420         it != lstDirsCopy.end(); ++it )
00421   {
00422     forgetDirs( lister, *it, false );
00423   }
00424 
00425   emit lister->clear();
00426 }
00427 
00428 void KDirListerCache::forgetDirs( KDirLister *lister, const KURL& _url, bool notify )
00429 {
00430   kdDebug(7004) << k_funcinfo << lister << " _url: " << _url << endl;
00431 
00432   KURL url( _url );
00433   url.adjustPath( -1 );
00434   QString urlStr = url.url();
00435   QPtrList<KDirLister> *holders = urlsCurrentlyHeld[urlStr];
00436   Q_ASSERT( holders );
00437   holders->removeRef( lister );
00438 
00439   DirItem *item = itemsInUse[urlStr];
00440   Q_ASSERT( item );
00441 
00442   if ( holders->isEmpty() )
00443   {
00444     urlsCurrentlyHeld.remove( urlStr ); // this deletes the (empty) holders list
00445     if ( !urlsCurrentlyListed[urlStr] )
00446     {
00447       // item not in use anymore -> move into cache if complete
00448       itemsInUse.remove( urlStr );
00449 
00450       // this job is a running update
00451       KIO::ListJob *job = jobForUrl(urlStr);
00452       if (job)
00453       {
00454         lister->jobDone(job);
00455         killJob( job );
00456         kdDebug(7004) << k_funcinfo << "Killing update job for " << urlStr << endl;
00457 
00458         emit lister->canceled( url );
00459         if ( lister->numJobs() == 0 )
00460         {
00461           lister->d->complete = true;
00462           emit lister->canceled();
00463         }
00464       }
00465 
00466       if ( notify )
00467       {
00468         lister->d->lstDirs.remove( url );
00469         emit lister->clear( url );
00470       }
00471 
00472       if ( item->complete )
00473       {
00474         kdDebug(7004) << k_funcinfo << lister << " item moved into cache: " << url << endl;
00475         itemsCached.insert( urlStr, item ); // TODO: may return false!!
00476 
00477         // watch cached directories if not manually mounted, otherwise set to "dirty"
00478         if ( !KIO::manually_mounted( item->url.directory( false ) + item->url.fileName() ) )
00479           item->incAutoUpdate();
00480         else
00481           item->complete = false;
00482       }
00483       else {
00484         delete item;
00485         item = 0;
00486       }
00487     }
00488   }
00489 
00490   if ( item && lister->d->autoUpdate )
00491     item->decAutoUpdate();
00492 }
00493 
00494 void KDirListerCache::updateDirectory( const KURL& _dir )
00495 {
00496   kdDebug(7004) << k_funcinfo << _dir << endl;
00497 
00498   QString urlStr = _dir.url(-1);
00499   if ( !checkUpdate( urlStr ) )
00500     return;
00501 
00502   // A job can be running to
00503   //   - only list a new directory: the listers are in urlsCurrentlyListed
00504   //   - only update a directory: the listers are in urlsCurrentlyHeld
00505   //   - update a currently running listing: the listers are in urlsCurrently
00506 
00507   QPtrList<KDirLister> *listers = urlsCurrentlyListed[urlStr];
00508   QPtrList<KDirLister> *holders = urlsCurrentlyHeld[urlStr];
00509   // restart the job for _dir if it is running already
00510   bool killed = false;
00511   KIO::ListJob *job = jobForUrl(urlStr);
00512   if (job)
00513   {
00514      killed = true;
00515      killJob( job );
00516      if (listers)
00517         for ( KDirLister *kdl = listers->first(); kdl; kdl = listers->next() )
00518            kdl->jobDone(job);
00519      if (holders)
00520         for ( KDirLister *kdl = holders->first(); kdl; kdl = holders->next() )
00521            kdl->jobDone(job);
00522   }
00523   kdDebug(7004) << k_funcinfo << "Killed = " << killed << endl;
00524 
00525   // we don't need to emit canceled signals since we only replaced the job,
00526   // the listing is continuing.
00527 
00528   Q_ASSERT( !listers || ( listers && killed ) );
00529 
00530   job = KIO::listDir( _dir, false /* no default GUI */ );
00531   jobs.insert( job, QValueList<KIO::UDSEntry>() );
00532 
00533   connect( job, SIGNAL( entries( KIO::Job *, const KIO::UDSEntryList & ) ),
00534            this, SLOT( slotUpdateEntries( KIO::Job *, const KIO::UDSEntryList & ) ) );
00535   connect( job, SIGNAL( result( KIO::Job * ) ),
00536            this, SLOT( slotUpdateResult( KIO::Job * ) ) );
00537 
00538   kdDebug(7004) << k_funcinfo << "update started in " << _dir << endl;
00539 
00540   if (listers)
00541      for ( KDirLister *kdl = listers->first(); kdl; kdl = listers->next() )
00542         kdl->jobStarted(job);
00543 
00544   if (holders)
00545   {
00546      if ( killed )
00547      {
00548         bool first = true;
00549         for ( KDirLister *kdl = holders->first(); kdl; kdl = holders->next() )
00550         {
00551            kdl->jobStarted(job);
00552            kdl->d->complete = false;
00553            if (first && kdl->d->window)
00554            {
00555               first = false;
00556               job->setWindow(kdl->d->window);
00557            }
00558            emit kdl->started( _dir );
00559         }
00560      }
00561      else
00562      {
00563         for ( KDirLister *kdl = holders->first(); kdl; kdl = holders->next() )
00564            kdl->jobStarted(job);
00565      }
00566   }
00567 }
00568 
00569 bool KDirListerCache::checkUpdate( const QString& _dir )
00570 {
00571   if ( !itemsInUse[_dir] )
00572   {
00573     DirItem *item = itemsCached[_dir];
00574     if ( item && item->complete )
00575     {
00576       item->complete = false;
00577       item->decAutoUpdate();
00578       // Hmm, this debug output might include login/password from the _dir URL.
00579       //kdDebug(7004) << k_funcinfo << "directory " << _dir << " not in use, marked dirty." << endl;
00580     }
00581     //else
00582       //kdDebug(7004) << k_funcinfo << "aborted, directory " << _dir << " not in cache." << endl;
00583 
00584     return false;
00585   }
00586   else
00587     return true;
00588 }
00589 
00590 KFileItemList* KDirListerCache::itemsForDir( const KURL &_dir ) const
00591 {
00592   QString urlStr = _dir.url(-1);
00593   DirItem *item = itemsInUse[ urlStr ];
00594   if ( !item )
00595     item = itemsCached[ urlStr ];
00596   return item ? item->lstItems : 0;
00597 }
00598 
00599 KFileItem* KDirListerCache::findByName( const KDirLister *lister, const QString& _name ) const
00600 {
00601   Q_ASSERT( lister );
00602 
00603   for ( KURL::List::Iterator it = lister->d->lstDirs.begin();
00604         it != lister->d->lstDirs.end(); ++it )
00605   {
00606     KFileItemListIterator kit( *itemsInUse[(*it).url()]->lstItems );
00607     for ( ; kit.current(); ++kit )
00608       if ( (*kit)->name() == _name )
00609         return (*kit);
00610   }
00611 
00612   return 0L;
00613 }
00614 
00615 KFileItem* KDirListerCache::findByURL( const KDirLister *lister, const KURL& _u ) const
00616 {
00617   KURL _url = _u;
00618   _url.adjustPath(-1);
00619 
00620   KURL parentDir( _url );
00621   parentDir.setPath( parentDir.directory() );
00622 
00623   // If lister is set, check that it contains this dir
00624   if ( lister && !lister->d->lstDirs.contains( parentDir ) )
00625       return 0L;
00626 
00627   KFileItemList* itemList = itemsForDir( parentDir );
00628   if ( itemList )
00629   {
00630     KFileItemListIterator kit( *itemList );
00631     for ( ; kit.current(); ++kit )
00632       if ( (*kit)->url() == _url )
00633         return (*kit);
00634   }
00635   return 0L;
00636 }
00637 
00638 void KDirListerCache::FilesAdded( const KURL &dir )
00639 {
00640   kdDebug(7004) << k_funcinfo << dir << endl;
00641   updateDirectory( dir );
00642 }
00643 
00644 void KDirListerCache::FilesRemoved( const KURL::List &fileList )
00645 {
00646   kdDebug(7004) << k_funcinfo << endl;
00647   KURL::List::ConstIterator it = fileList.begin();
00648   for ( ; it != fileList.end() ; ++it )
00649   {
00650     // emit the deleteItem signal if this file was shown in any view
00651     KFileItem* fileitem = 0L;
00652     KURL parentDir( *it );
00653     parentDir.setPath( parentDir.directory() );
00654     KFileItemList* lstItems = itemsForDir( parentDir );
00655     if ( lstItems )
00656     {
00657       KFileItem* fit = lstItems->first();
00658       for ( ; fit; fit = lstItems->next() )
00659         if ( fit->url() == *it ) {
00660           fileitem = fit;
00661           lstItems->take(); // remove fileitem from list
00662           break;
00663         }
00664     }
00665 
00666     // Tell the views about it before deleting the KFileItems. They might need the subdirs'
00667     // file items (see the dirtree).
00668     if ( fileitem )
00669     {
00670       QPtrList<KDirLister> *listers = urlsCurrentlyHeld[parentDir.url()];
00671       if ( listers )
00672         for ( KDirLister *kdl = listers->first(); kdl; kdl = listers->next() )
00673           kdl->emitDeleteItem( fileitem );
00674     }
00675 
00676     // If we found a fileitem, we can test if it's a dir. If not, we'll go to deleteDir just in case.
00677     if ( !fileitem || fileitem->isDir() )
00678     {
00679       // in case of a dir, check if we have any known children, there's much to do in that case
00680       // (stopping jobs, removing dirs from cache etc.)
00681       deleteDir( *it );
00682     }
00683 
00684     // now remove the item itself
00685     delete fileitem;
00686   }
00687 }
00688 
00689 void KDirListerCache::FilesChanged( const KURL::List &fileList )
00690 {
00691   KURL::List dirsToUpdate;
00692   kdDebug(7004) << k_funcinfo << "only half implemented" << endl;
00693   KURL::List::ConstIterator it = fileList.begin();
00694   for ( ; it != fileList.end() ; ++it )
00695   {
00696     if ( ( *it ).isLocalFile() )
00697     {
00698       kdDebug(7004) << "KDirListerCache::FilesChanged " << *it << endl;
00699       KFileItem* fileitem = findByURL( 0, *it );
00700       if ( fileitem )
00701       {
00702           // we need to refresh the item, because e.g. the permissions can have changed.
00703           fileitem->refresh();
00704           emitRefreshItem( fileitem );
00705       }
00706       else
00707           kdDebug(7004) << "item not found" << endl;
00708     } else {
00709       // For remote files, refresh() won't be able to figure out the new information.
00710       // Let's update the dir.
00711       KURL dir( *it );
00712       dir.setPath( dir.directory(-1) );
00713       if ( dirsToUpdate.find( dir ) == dirsToUpdate.end() )
00714         dirsToUpdate.prepend( dir );
00715     }
00716   }
00717 
00718   KURL::List::ConstIterator itdir = dirsToUpdate.begin();
00719   for ( ; itdir != dirsToUpdate.end() ; ++itdir )
00720     updateDirectory( *itdir );
00721   // ## TODO problems with current jobs listing/updating that dir
00722   // ( see kde-2.2.2's kdirlister )
00723 }
00724 
00725 void KDirListerCache::FileRenamed( const KURL &src, const KURL &dst )
00726 {
00727   kdDebug(7004) << k_funcinfo << src.prettyURL() << " -> " << dst.prettyURL() << endl;
00728 #ifdef DEBUG_CACHE
00729   printDebug();
00730 #endif
00731 
00732   // Somehow this should only be called if src is a dir. But how could we know if it is?
00733   // (Note that looking into itemsInUse isn't good enough. One could rename a subdir in a view.)
00734   renameDir( src, dst );
00735 
00736   // Now update the KFileItem representing that file or dir (not exclusive with the above!)
00737   KURL oldurl( src );
00738   oldurl.adjustPath( -1 );
00739   KFileItem* fileitem = findByURL( 0, oldurl );
00740   if ( fileitem )
00741   {
00742     fileitem->setURL( dst );
00743     fileitem->refreshMimeType();
00744 
00745     emitRefreshItem( fileitem );
00746   }
00747 #ifdef DEBUG_CACHE
00748   printDebug();
00749 #endif
00750 }
00751 
00752 void KDirListerCache::emitRefreshItem( KFileItem* fileitem )
00753 {
00754   // Look whether this item was shown in any view, i.e. held by any dirlister
00755   KURL parentDir( fileitem->url() );
00756   parentDir.setPath( parentDir.directory() );
00757   QString parentDirURL = parentDir.url();
00758   QPtrList<KDirLister> *listers = urlsCurrentlyHeld[parentDirURL];
00759   if ( listers )
00760     for ( KDirLister *kdl = listers->first(); kdl; kdl = listers->next() )
00761     {
00762       kdl->addRefreshItem( fileitem );
00763       kdl->emitItems();
00764     }
00765 
00766   // Also look in urlsCurrentlyListed, in case the user manages to rename during a listing
00767   listers = urlsCurrentlyListed[parentDirURL];
00768   if ( listers )
00769     for ( KDirLister *kdl = listers->first(); kdl; kdl = listers->next() )
00770     {
00771       kdl->addRefreshItem( fileitem );
00772       kdl->emitItems();
00773     }
00774 }
00775 
00776 KDirListerCache* KDirListerCache::self()
00777 {
00778   if ( !s_pSelf )
00779     s_pSelf = sd_KDirListerCache.setObject( s_pSelf, new KDirListerCache );
00780 
00781   return s_pSelf;
00782 }
00783 
00784 // private slots
00785 
00786 // _file can also be a directory being currently held!
00787 void KDirListerCache::slotFileDirty( const QString& _file )
00788 {
00789   kdDebug(7004) << k_funcinfo << _file << endl;
00790 
00791   if ( !pendingUpdates[_file] )
00792   {
00793     KURL dir = KURL( _file );
00794     if ( checkUpdate( dir.url(-1) ) )
00795       updateDirectory( dir );
00796 
00797     // the parent directory of _file
00798     dir.setPath( dir.directory() );
00799     if ( checkUpdate( dir.url() ) )
00800     {
00801       // Nice hack to save memory: use the qt object name to store the filename
00802       QTimer *timer = new QTimer( this, _file.utf8() );
00803       connect( timer, SIGNAL(timeout()), this, SLOT(slotFileDirtyDelayed()) );
00804       pendingUpdates.insert( _file, timer );
00805       timer->start( 500, true );
00806     }
00807   }
00808 }
00809 
00810 // delayed updating of files, FAM is flooding us with events
00811 void KDirListerCache::slotFileDirtyDelayed()
00812 {
00813   QString file = QString::fromUtf8( sender()->name() );
00814 
00815   kdDebug(7004) << k_funcinfo << file << endl;
00816 
00817   // TODO: do it better: don't always create/delete the QTimer but reuse it.
00818   // Delete the timer after the parent directory is removed from the cache.
00819   pendingUpdates.remove( file );
00820 
00821   KURL u;
00822   u.setPath( file );
00823   KFileItem *item = findByURL( 0, u ); // search all items
00824   if ( item )
00825   {
00826     // we need to refresh the item, because e.g. the permissions can have changed.
00827     item->refresh();
00828     emitRefreshItem( item );
00829   }
00830 }
00831 
00832 void KDirListerCache::slotFileCreated( const QString& _file )
00833 {
00834   kdDebug(7004) << k_funcinfo << _file << endl;
00835   // XXX: how to avoid a complete rescan here?
00836   KURL u;
00837   u.setPath( _file );
00838   u.setPath( u.directory() );
00839   FilesAdded( u );
00840 }
00841 
00842 void KDirListerCache::slotFileDeleted( const QString& _file )
00843 {
00844   kdDebug(7004) << k_funcinfo << _file << endl;
00845   KURL u;
00846   u.setPath( _file );
00847   FilesRemoved( u );
00848 }
00849 
00850 void KDirListerCache::slotEntries( KIO::Job *job, const KIO::UDSEntryList &entries )
00851 {
00852   KURL url = static_cast<KIO::ListJob *>(job)->url();
00853   url.adjustPath(-1);
00854   QString urlStr = url.url();
00855 
00856   kdDebug(7004) << k_funcinfo << "new entries for " << url << endl;
00857 
00858   DirItem *dir = itemsInUse[urlStr];
00859   Q_ASSERT( dir );
00860 
00861   QPtrList<KDirLister> *listers = urlsCurrentlyListed[urlStr];
00862   Q_ASSERT( listers );
00863   Q_ASSERT( !listers->isEmpty() );
00864 
00865   // check if anyone wants the mimetypes immediately
00866   bool delayedMimeTypes = true;
00867   for ( KDirLister *kdl = listers->first(); kdl; kdl = listers->next() )
00868     delayedMimeTypes &= kdl->d->delayedMimeTypes;
00869 
00870   // avoid creating these QStrings again and again
00871   static const QString& dot = KGlobal::staticQString(".");
00872   static const QString& dotdot = KGlobal::staticQString("..");
00873 
00874   KIO::UDSEntryListConstIterator it = entries.begin();
00875   KIO::UDSEntryListConstIterator end = entries.end();
00876 
00877   for ( ; it != end; ++it )
00878   {
00879     QString name;
00880 
00881     // find out about the name
00882     KIO::UDSEntry::ConstIterator entit = (*it).begin();
00883     for( ; entit != (*it).end(); ++entit )
00884       if ( (*entit).m_uds == KIO::UDS_NAME )
00885       {
00886         name = (*entit).m_str;
00887         break;
00888       }
00889 
00890     Q_ASSERT( !name.isEmpty() );
00891     if ( name.isEmpty() )
00892       continue;
00893 
00894     if ( name == dot )
00895     {
00896       Q_ASSERT( !dir->rootItem );
00897       dir->rootItem = new KFileItem( *it, url, delayedMimeTypes, true  );
00898 
00899       for ( KDirLister *kdl = listers->first(); kdl; kdl = listers->next() )
00900         if ( !kdl->d->rootFileItem && kdl->d->url == url )
00901           kdl->d->rootFileItem = dir->rootItem;
00902     }
00903     else if ( name != dotdot )
00904     {
00905       KFileItem* item = new KFileItem( *it, url, delayedMimeTypes, true );
00906       Q_ASSERT( item );
00907 
00908       //kdDebug(7004)<< "Adding item: " << item->url() << endl;
00909       dir->lstItems->append( item );
00910 
00911       for ( KDirLister *kdl = listers->first(); kdl; kdl = listers->next() )
00912         kdl->addNewItem( item );
00913     }
00914   }
00915 
00916   for ( KDirLister *kdl = listers->first(); kdl; kdl = listers->next() )
00917     kdl->emitItems();
00918 }
00919 
00920 void KDirListerCache::slotResult( KIO::Job* j )
00921 {
00922   Q_ASSERT( j );
00923   KIO::ListJob *job = static_cast<KIO::ListJob *>( j );
00924   jobs.remove( job );
00925 
00926   KURL jobUrl = job->url();
00927   jobUrl.adjustPath(-1);  // need remove trailing slashes again, in case of redirections
00928   QString jobUrlStr = jobUrl.url();
00929 
00930   kdDebug(7004) << k_funcinfo << "finished listing " << jobUrl << endl;
00931 #ifdef DEBUG_CACHE
00932   printDebug();
00933 #endif
00934 
00935   QPtrList<KDirLister> *listers = urlsCurrentlyListed.take( jobUrlStr );
00936   Q_ASSERT( listers );
00937 
00938   // move the directory to the held directories, do it before emitting
00939   // the signals to make sure it exists in KDirListerCache in case someone
00940   // calls listDir during the signal emission
00941   Q_ASSERT( !urlsCurrentlyHeld[jobUrlStr] );
00942   urlsCurrentlyHeld.insert( jobUrlStr, listers );
00943 
00944   KDirLister *kdl;
00945 
00946   if ( job->error() )
00947   {
00948     for ( kdl = listers->first(); kdl; kdl = listers->next() )
00949     {
00950       kdl->jobDone(job);
00951       kdl->handleError( job );
00952       emit kdl->canceled( jobUrl );
00953       if ( kdl->numJobs() == 0 )
00954       {
00955         kdl->d->complete = true;
00956         emit kdl->canceled();
00957       }
00958     }
00959   }
00960   else
00961   {
00962     DirItem *dir = itemsInUse[jobUrlStr];
00963     Q_ASSERT( dir );
00964     dir->complete = true;
00965 
00966     for ( kdl = listers->first(); kdl; kdl = listers->next() )
00967     {
00968       kdl->jobDone(job);
00969       emit kdl->completed( jobUrl );
00970       if ( kdl->numJobs() == 0 )
00971       {
00972         kdl->d->complete = true;
00973         emit kdl->completed();
00974       }
00975     }
00976   }
00977 
00978   // TODO: hmm, if there was an error and job is a parent of one or more
00979   // of the pending urls we should cancel it/them as well
00980   processPendingUpdates();
00981 
00982 #ifdef DEBUG_CACHE
00983   printDebug();
00984 #endif
00985 }
00986 
00987 void KDirListerCache::slotRedirection( KIO::Job *job, const KURL &url )
00988 {
00989   Q_ASSERT( job );
00990   KURL oldUrl = static_cast<KIO::ListJob *>( job )->url();
00991 
00992   // strip trailing slashes
00993   oldUrl.adjustPath(-1);
00994   KURL newUrl = url;
00995   newUrl.adjustPath(-1);
00996 
00997   kdDebug(7004) << k_funcinfo << oldUrl.prettyURL() << " -> " << newUrl.prettyURL() << endl;
00998 
00999   // I don't think there can be dirItems that are childs of oldUrl.
01000   // Am I wrong here? And even if so, we don't need to delete them, right?
01001   // DF: redirection happens before listDir emits any item. Makes little sense otherwise.
01002 
01003   DirItem *dir = itemsInUse.take( oldUrl.url() );
01004   Q_ASSERT( dir );
01005 
01006   QPtrList<KDirLister> *listers = urlsCurrentlyListed.take( oldUrl.url() );
01007   Q_ASSERT( listers );
01008   Q_ASSERT( !listers->isEmpty() );
01009 
01010   for ( KDirLister *kdl = listers->first(); kdl; kdl = listers->next() )
01011   {
01012     if ( kdl->d->url.equals( oldUrl, true ) )
01013     {
01014       kdl->d->rootFileItem = 0;
01015       kdl->d->url = newUrl;
01016     }
01017 
01018     *kdl->d->lstDirs.find( oldUrl ) = newUrl;
01019 
01020     if ( kdl->d->lstDirs.count() == 1 )
01021     {
01022       emit kdl->clear();
01023       emit kdl->redirection( newUrl );
01024       emit kdl->redirection( oldUrl, newUrl );
01025     }
01026     else
01027     {
01028       emit kdl->clear( oldUrl );
01029       emit kdl->redirection( oldUrl, newUrl );
01030     }
01031   }
01032 
01033   delete dir->rootItem;
01034   dir->rootItem = 0;
01035   dir->lstItems->clear();
01036   itemsInUse.insert( newUrl.url(), dir );
01037   urlsCurrentlyListed.insert( newUrl.url(), listers );
01038 }
01039 
01040 void KDirListerCache::renameDir( const KURL &oldUrl, const KURL &newUrl )
01041 {
01042   kdDebug(7004) << k_funcinfo << oldUrl.prettyURL() << " -> " << newUrl.prettyURL() << endl;
01043   QString oldUrlStr = oldUrl.url(-1);
01044   QString newUrlStr = newUrl.url(-1);
01045 
01046   // Not enough. Also need to look at any child dir, even sub-sub-sub-dir.
01047   //DirItem *dir = itemsInUse.take( oldUrlStr );
01048   //emitRedirections( oldUrl, url );
01049 
01050   // Look at all dirs being listed/shown
01051   QDictIterator<DirItem> itu( itemsInUse );
01052   bool goNext;
01053   while ( itu.current() )
01054   {
01055     goNext = true;
01056     DirItem* dir = itu.current();
01057     KURL oldDirUrl ( itu.currentKey() );
01058     //kdDebug(7004) << "itemInUse: " << oldDirUrl.prettyURL() << endl;
01059     // Check if this dir is oldUrl, or a subfolder of it
01060     if ( oldUrl.isParentOf( oldDirUrl ) )
01061     {
01062       QString relPath = oldDirUrl.path().mid( oldUrl.path().length() ); // ### should use KURL::cleanpath like isParentOf does
01063 
01064       KURL newDirUrl( newUrl ); // take new base
01065       if ( !relPath.isEmpty() )
01066         newDirUrl.addPath( relPath ); // add unchanged relative path
01067       //kdDebug(7004) << "KDirListerCache::renameDir new url=" << newDirUrl.prettyURL() << endl;
01068 
01069       // Update URL in root item and in itemsInUse
01070       if ( dir->rootItem )
01071         dir->rootItem->setURL( newDirUrl );
01072       dir->url = newDirUrl;
01073       itemsInUse.remove( itu.currentKey() ); // implies ++itu
01074       itemsInUse.insert( newDirUrl.url(-1), dir );
01075       goNext = false; // because of the implied ++itu above
01076       if ( dir->lstItems )
01077       {
01078         // Rename all items under that dir
01079         KFileItemListIterator kit( *dir->lstItems );
01080         for ( ; kit.current(); ++kit )
01081         {
01082           KURL oldItemUrl = (*kit)->url();
01083           QString oldItemUrlStr( oldItemUrl.url(-1) );
01084           KURL newItemUrl( oldItemUrl );
01085           newItemUrl.setPath( newDirUrl.path() );
01086           newItemUrl.addPath( oldItemUrl.fileName() );
01087           kdDebug(7004) << "KDirListerCache::renameDir renaming " << oldItemUrlStr << " to " << newItemUrl.url() << endl;
01088           (*kit)->setURL( newItemUrl );
01089         }
01090       }
01091       emitRedirections( oldDirUrl, newDirUrl );
01092     }
01093     if (goNext)
01094       ++itu;
01095   }
01096 
01097   // Is oldUrl a directory in the cache?
01098   // Remove any child of oldUrl from the cache - even if the renamed dir itself isn't in it!
01099   removeDirFromCache( oldUrl );
01100   // TODO rename, instead.
01101 }
01102 
01103 void KDirListerCache::emitRedirections( const KURL &oldUrl, const KURL &url )
01104 {
01105   kdDebug(7004) << k_funcinfo << oldUrl.prettyURL() << " -> " << url.prettyURL() << endl;
01106   QString oldUrlStr = oldUrl.url(-1);
01107   QString urlStr = url.url(-1);
01108 
01109   KIO::ListJob *job = jobForUrl(oldUrlStr);
01110   if (job)
01111      killJob( job );
01112 
01113   // Check if we were listing this dir. Need to abort and restart with new name in that case.
01114   QPtrList<KDirLister> *listers = urlsCurrentlyListed.take( oldUrlStr );
01115   if ( listers )
01116   {
01117     // Tell the world that the job listing the old url is dead.
01118     for ( KDirLister *kdl = listers->first(); kdl; kdl = listers->next() )
01119     {
01120        kdl->jobDone(job);
01121        emit kdl->canceled( oldUrl );
01122     }
01123 
01124     urlsCurrentlyListed.insert( urlStr, listers );
01125   }
01126 
01127   // Check if we are currently displaying this directory (odds opposite wrt above)
01128   // Update urlsCurrentlyHeld dict with new URL
01129   QPtrList<KDirLister> *holders = urlsCurrentlyHeld.take( oldUrlStr );
01130   if ( holders )
01131   {
01132     for ( KDirLister *kdl = holders->first(); kdl; kdl = holders->next() )
01133     {
01134        kdl->jobDone(job);
01135     }
01136     urlsCurrentlyHeld.insert( urlStr, holders );
01137   }
01138 
01139   if (listers)
01140   {
01141     updateDirectory( url );
01142 
01143     // Tell the world about the new url
01144     for ( KDirLister *kdl = listers->first(); kdl; kdl = listers->next() )
01145     {
01146       emit kdl->started( url );
01147     }
01148   }
01149 
01150   if (holders)
01151   {
01152     // And notify the dirlisters of the redirection
01153     for ( KDirLister *kdl = holders->first(); kdl; kdl = holders->next() )
01154     {
01155       *kdl->d->lstDirs.find( oldUrl ) = url;
01156       if ( kdl->d->lstDirs.count() == 1 )
01157       {
01158         emit kdl->redirection( url );
01159       }
01160       emit kdl->redirection( oldUrl, url );
01161     }
01162   }
01163 }
01164 
01165 void KDirListerCache::removeDirFromCache( const KURL& dir )
01166 {
01167   kdDebug(7004) << "KDirListerCache::removeDirFromCache " << dir.prettyURL() << endl;
01168   QCacheIterator<DirItem> itc( itemsCached );
01169   while ( itc.current() )
01170   {
01171     if ( dir.isParentOf( KURL( itc.currentKey() ) ) )
01172       itemsCached.remove( itc.currentKey() );
01173     else
01174       ++itc;
01175   }
01176 }
01177 
01178 void KDirListerCache::slotUpdateEntries( KIO::Job* job, const KIO::UDSEntryList& list )
01179 {
01180   jobs[static_cast<KIO::ListJob*>(job)] += list;
01181 }
01182 
01183 void KDirListerCache::slotUpdateResult( KIO::Job * j )
01184 {
01185   Q_ASSERT( j );
01186   KIO::ListJob *job = static_cast<KIO::ListJob *>( j );
01187 
01188   KURL jobUrl = job->url();
01189   jobUrl.adjustPath(-1);  // need remove trailing slashes again, in case of redirections
01190   QString jobUrlStr = jobUrl.url();
01191 
01192   kdDebug(7004) << k_funcinfo << "finished update " << jobUrl << endl;
01193 
01194   KDirLister *kdl;
01195 
01196   QPtrList<KDirLister> *listers = urlsCurrentlyHeld[jobUrlStr];
01197   QPtrList<KDirLister> *tmpLst = urlsCurrentlyListed.take( jobUrlStr );
01198 
01199   if ( tmpLst )
01200   {
01201     if ( listers )
01202       for ( kdl = tmpLst->first(); kdl; kdl = tmpLst->next() )
01203       {
01204         Q_ASSERT( listers->containsRef( kdl ) == 0 );
01205         listers->append( kdl );
01206       }
01207     else
01208     {
01209       listers = tmpLst;
01210       urlsCurrentlyHeld.insert( jobUrlStr, listers );
01211     }
01212   }
01213 
01214   // once we are updating dirs that are only in the cache this will fail!
01215   Q_ASSERT( listers );
01216 
01217   if ( job->error() )
01218   {
01219     for ( kdl = listers->first(); kdl; kdl = listers->next() )
01220     {
01221       kdl->jobDone(job);
01222       //don't bother the user
01223       //kdl->handleError( job );
01224 
01225       emit kdl->canceled( jobUrl );
01226       if ( kdl->numJobs() == 0 )
01227       {
01228         kdl->d->complete = true;
01229         emit kdl->canceled();
01230       }
01231     }
01232 
01233     jobs.remove( job );
01234 
01235     // TODO: if job is a parent of one or more
01236     // of the pending urls we should cancel them
01237     processPendingUpdates();
01238     return;
01239   }
01240 
01241   DirItem *dir = itemsInUse[jobUrlStr];
01242   dir->complete = true;
01243 
01244 
01245   // check if anyone wants the mimetypes immediately
01246   bool delayedMimeTypes = true;
01247   for ( kdl = listers->first(); kdl; kdl = listers->next() )
01248     delayedMimeTypes &= kdl->d->delayedMimeTypes;
01249 
01250   // should be enough to get reasonable speed in most cases
01251   QDict<KFileItem> fileItems( 9973 );
01252 
01253   KFileItemListIterator kit ( *(dir->lstItems) );
01254 
01255   // Unmark all items in url
01256   for ( ; kit.current(); ++kit )
01257   {
01258     (*kit)->unmark();
01259     fileItems.insert( (*kit)->url().url(), *kit );
01260   }
01261 
01262   static const QString& dot = KGlobal::staticQString(".");
01263   static const QString& dotdot = KGlobal::staticQString("..");
01264 
01265   KFileItem *item, *tmp;
01266 
01267   QValueList<KIO::UDSEntry> buf = jobs[job];
01268   QValueListIterator<KIO::UDSEntry> it = buf.begin();
01269   for ( ; it != buf.end(); ++it )
01270   {
01271     QString name;
01272 
01273     // Find out about the name
01274     KIO::UDSEntry::Iterator it2 = (*it).begin();
01275     for ( ; it2 != (*it).end(); it2++ )
01276       if ( (*it2).m_uds == KIO::UDS_NAME )
01277       {
01278         name = (*it2).m_str;
01279         break;
01280       }
01281 
01282     Q_ASSERT( !name.isEmpty() );
01283 
01284     // we duplicate the check for dotdot here, to avoid iterating over
01285     // all items again and checking in matchesFilter() that way.
01286     if ( name.isEmpty() || name == dotdot )
01287       continue;
01288 
01289     if ( name == dot )
01290     {
01291       // if the update was started before finishing the original listing
01292       // there is no root item yet
01293       if ( !dir->rootItem )
01294       {
01295         dir->rootItem = new KFileItem( *it, jobUrl, delayedMimeTypes, true  );
01296 
01297         for ( KDirLister *kdl = listers->first(); kdl; kdl = listers->next() )
01298           if ( !kdl->d->rootFileItem && kdl->d->url == jobUrl )
01299             kdl->d->rootFileItem = dir->rootItem;
01300       }
01301 
01302       continue;
01303     }
01304 
01305     // Form the complete url
01306     item = new KFileItem( *it, jobUrl, delayedMimeTypes, true  );
01307 
01308     QString url = item->url().url();
01309     //kdDebug(7004) << "slotUpdateResult : look for " << url << endl;
01310 
01311     // Find this item
01312     if ( (tmp = fileItems[url]) )
01313     {
01314       tmp->mark();
01315 
01316       // check if something changed for this file
01317       if ( !tmp->cmp( *item ) )
01318       {
01319         //kdDebug(7004) << "slotUpdateResult: file changed: " << tmp->name() << endl;
01320         tmp->assign( *item );
01321 
01322         for ( kdl = listers->first(); kdl; kdl = listers->next() )
01323           kdl->addRefreshItem( tmp );
01324       }
01325       delete item;  // gmbl, this is the most often case... IMPORTANT TODO: speed it up somehow!
01326     }
01327     else // this is a new file
01328     {
01329       //kdDebug(7004) << "slotUpdateResult: new file: " << name << endl;
01330 
01331       item->mark();
01332       dir->lstItems->append( item );
01333 
01334       for ( kdl = listers->first(); kdl; kdl = listers->next() )
01335         kdl->addNewItem( item );
01336     }
01337   }
01338 
01339   jobs.remove( job );
01340 
01341   deleteUnmarkedItems( listers, dir->lstItems );
01342 
01343   for ( kdl = listers->first(); kdl; kdl = listers->next() )
01344   {
01345     kdl->emitItems();
01346 
01347     kdl->jobDone(job);
01348 
01349     emit kdl->completed( jobUrl );
01350     if ( kdl->numJobs() == 0 )
01351     {
01352       kdl->d->complete = true;
01353       emit kdl->completed();
01354     }
01355   }
01356 
01357   // TODO: hmm, if there was an error and job is a parent of one or more
01358   // of the pending urls we should cancel it/them as well
01359   processPendingUpdates();
01360 }
01361 
01362 // private
01363 
01364 KIO::ListJob *KDirListerCache::jobForUrl(const QString& _url)
01365 {
01366   KIO::ListJob *job;
01367   QMap< KIO::ListJob *, QValueList<KIO::UDSEntry> >::Iterator it = jobs.begin();
01368   while ( it != jobs.end() )
01369   {
01370     job = it.key();
01371     if ( job->url().url(-1) == _url )
01372     {
01373        return job;
01374     }
01375     ++it;
01376   }
01377   return 0;
01378 }
01379 
01380 void KDirListerCache::killJob( KIO::ListJob *job)
01381 {
01382   jobs.remove( job );
01383   job->disconnect( this );
01384   job->kill();
01385 }
01386 
01387 void KDirListerCache::deleteUnmarkedItems( QPtrList<KDirLister> *listers, KFileItemList *lstItems )
01388 {
01389   // Find all unmarked items and delete them
01390   KFileItem* item;
01391   lstItems->first();
01392   while ( (item = lstItems->current()) )
01393     if ( !item->isMarked() )
01394     {
01395       //kdDebug() << k_funcinfo << item->name() << endl;
01396       for ( KDirLister *kdl = listers->first(); kdl; kdl = listers->next() )
01397         kdl->emitDeleteItem( item );
01398 
01399       if ( item->isDir() )
01400         deleteDir( item->url() );
01401 
01402       // finally actually delete the item
01403       lstItems->take();
01404       delete item;
01405     }
01406     else
01407       lstItems->next();
01408 }
01409 
01410 void KDirListerCache::deleteDir( const KURL& dirUrl )
01411 {
01412   //kdDebug() << k_funcinfo << dirUrl.prettyURL() << endl;
01413   // unregister and remove the childs of the deleted item.
01414   // Idea: tell all the KDirListers that they should forget the dir
01415   //       and then remove it from the cache.
01416 
01417   QDictIterator<DirItem> itu( itemsInUse );
01418   while ( itu.current() )
01419   {
01420     KURL deletedUrl ( itu.currentKey() );
01421     if ( dirUrl.isParentOf( deletedUrl ) )
01422     {
01423       // stop all jobs for deletedUrl
01424 
01425       QPtrList<KDirLister> *kdls = urlsCurrentlyListed[deletedUrl.url()];
01426       if ( kdls )  // yeah, I lack good names
01427       {
01428         // we need a copy because stop modifies the list
01429         kdls = new QPtrList<KDirLister>( *kdls );
01430         for ( KDirLister *kdl = kdls->first(); kdl; kdl = kdls->next() )
01431           stop( kdl, deletedUrl );
01432 
01433         delete kdls;
01434       }
01435 
01436       // tell listers holding deletedUrl to forget about it
01437       // this will stop running updates for deletedUrl as well
01438 
01439       kdls = urlsCurrentlyHeld[deletedUrl.url()];
01440       if ( kdls )
01441       {
01442         // we need a copy because forgetDirs modifies the list
01443         kdls = new QPtrList<KDirLister>( *kdls );
01444 
01445         for ( KDirLister *kdl = kdls->first(); kdl; kdl = kdls->next() )
01446         {
01447           // lister's root is the deleted item
01448           if ( kdl->d->url == deletedUrl )
01449           {
01450             // tell the view first. It might need the subdirs' items (which forgetDirs will delete)
01451             if ( kdl->d->rootFileItem )
01452               emit kdl->deleteItem( kdl->d->rootFileItem );
01453             forgetDirs( kdl );
01454             kdl->d->rootFileItem = 0;
01455           }
01456           else
01457           {
01458             bool treeview = kdl->d->lstDirs.count() > 1;
01459             forgetDirs( kdl, deletedUrl, treeview );
01460             if ( !treeview )
01461             {
01462               kdl->d->lstDirs.clear();
01463               emit kdl->clear();
01464             }
01465           }
01466         }
01467 
01468         delete kdls;
01469       }
01470 
01471       // delete the entry for deletedUrl - should not be needed, it's in
01472       // items cached now
01473 
01474       DirItem *dir = itemsInUse.take( deletedUrl.url() );
01475       Q_ASSERT( !dir );
01476       if ( !dir ) // take didn't find it - move on
01477           ++itu;
01478     }
01479     else
01480       ++itu;
01481   }
01482 
01483   // remove the children from the cache
01484   removeDirFromCache( dirUrl );
01485 }
01486 
01487 void KDirListerCache::processPendingUpdates()
01488 {
01489   // TODO
01490 }
01491 
01492 #ifndef NDEBUG
01493 void KDirListerCache::printDebug()
01494 {
01495   kdDebug(7004) << "Items in use: " << endl;
01496   QDictIterator<DirItem> itu( itemsInUse );
01497   for ( ; itu.current() ; ++itu ) {
01498       kdDebug(7004) << "   " << itu.currentKey() << "  URL: " << itu.current()->url
01499                     << " rootItem: " << ( itu.current()->rootItem ? itu.current()->rootItem->url() : KURL() )
01500                     << " autoUpdates refcount: " << itu.current()->autoUpdates
01501                     << " complete: " << itu.current()->complete
01502                   << ( itu.current()->lstItems ? QString(" with %1 items.").arg(itu.current()->lstItems->count()) : QString(" lstItems=NULL") ) << endl;
01503   }
01504 
01505   kdDebug(7004) << "urlsCurrentlyHeld: " << endl;
01506   QDictIterator< QPtrList<KDirLister> > it( urlsCurrentlyHeld );
01507   for ( ; it.current() ; ++it )
01508   {
01509     QString list;
01510     for ( QPtrListIterator<KDirLister> listit( *it.current() ); listit.current(); ++listit )
01511       list += " 0x" + QString::number( (long)listit.current(), 16 );
01512     kdDebug(7004) << "   " << it.currentKey() << "  " << it.current()->count() << " listers: " << list << endl;
01513   }
01514 
01515   kdDebug(7004) << "urlsCurrentlyListed: " << endl;
01516   QDictIterator< QPtrList<KDirLister> > it2( urlsCurrentlyListed );
01517   for ( ; it2.current() ; ++it2 )
01518   {
01519     QString list;
01520     for ( QPtrListIterator<KDirLister> listit( *it2.current() ); listit.current(); ++listit )
01521       list += " 0x" + QString::number( (long)listit.current(), 16 );
01522     kdDebug(7004) << "   " << it2.currentKey() << "  " << it2.current()->count() << " listers: " << list << endl;
01523   }
01524 
01525   QMap< KIO::ListJob *, QValueList<KIO::UDSEntry> >::Iterator jit = jobs.begin();
01526   kdDebug(7004) << "Jobs: " << endl;
01527   for ( ; jit != jobs.end() ; ++jit )
01528     kdDebug(7004) << "   " << jit.key() << " listing " << jit.key()->url().prettyURL() << ": " << (*jit).count() << " entries." << endl;
01529 
01530   kdDebug(7004) << "Items in cache: " << endl;
01531   QCacheIterator<DirItem> itc( itemsCached );
01532   for ( ; itc.current() ; ++itc )
01533     kdDebug(7004) << "   " << itc.currentKey() << "  rootItem: "
01534                   << ( itc.current()->rootItem ? itc.current()->rootItem->url().prettyURL() : QString("NULL") )
01535                   << ( itc.current()->lstItems ? QString(" with %1 items.").arg(itc.current()->lstItems->count()) : QString(" lstItems=NULL") ) << endl;
01536 }
01537 #endif
01538 
01539 /*********************** -- The new KDirLister -- ************************/
01540 
01541 
01542 KDirLister::KDirLister( bool _delayedMimeTypes )
01543 {
01544   kdDebug(7003) << "+KDirLister" << endl;
01545 
01546   d = new KDirListerPrivate;
01547 
01548   d->complete = true;
01549   d->delayedMimeTypes = _delayedMimeTypes;
01550 
01551   setAutoUpdate( true );
01552   setDirOnlyMode( false );
01553   setShowingDotFiles( false );
01554 
01555   setAutoErrorHandlingEnabled( true, 0 );
01556 }
01557 
01558 KDirLister::~KDirLister()
01559 {
01560   kdDebug(7003) << "-KDirLister" << endl;
01561 
01562   // Stop all running jobs
01563   stop();
01564   s_pCache->forgetDirs( this );
01565 
01566   delete d;
01567 }
01568 
01569 bool KDirLister::openURL( const KURL& _url, bool _keep, bool _reload )
01570 {
01571   if ( !validURL( _url ) )
01572     return false;
01573 
01574   kdDebug(7003) << k_funcinfo << _url.prettyURL()
01575                 << " keep=" << _keep << " reload=" << _reload << endl;
01576 
01577   // emit the current changes made to avoid an inconsistent treeview
01578   if ( d->changes != NONE && _keep )
01579     emitChanges();
01580 
01581   d->changes = NONE;
01582 
01583   s_pCache->listDir( this, _url, _keep, _reload );
01584 
01585   return true;
01586 }
01587 
01588 void KDirLister::stop()
01589 {
01590   kdDebug(7003) << k_funcinfo << endl;
01591   s_pCache->stop( this );
01592 }
01593 
01594 void KDirLister::stop( const KURL& _url )
01595 {
01596   kdDebug(7003) << k_funcinfo << _url.prettyURL() << endl;
01597   s_pCache->stop( this, _url );
01598 }
01599 
01600 bool KDirLister::autoUpdate() const
01601 {
01602   return d->autoUpdate;
01603 }
01604 
01605 void KDirLister::setAutoUpdate( bool _enable )
01606 {
01607   if ( d->autoUpdate == _enable )
01608     return;
01609 
01610   d->autoUpdate = _enable;
01611   s_pCache->setAutoUpdate( this, _enable );
01612 }
01613 
01614 bool KDirLister::showingDotFiles() const
01615 {
01616   return d->isShowingDotFiles;
01617 }
01618 
01619 void KDirLister::setShowingDotFiles( bool _showDotFiles )
01620 {
01621   if ( d->isShowingDotFiles == _showDotFiles )
01622     return;
01623 
01624   d->isShowingDotFiles = _showDotFiles;
01625   d->changes ^= DOT_FILES;
01626 }
01627 
01628 bool KDirLister::dirOnlyMode() const
01629 {
01630   return d->dirOnlyMode;
01631 }
01632 
01633 void KDirLister::setDirOnlyMode( bool _dirsOnly )
01634 {
01635   if ( d->dirOnlyMode == _dirsOnly )
01636     return;
01637 
01638   d->dirOnlyMode = _dirsOnly;
01639   d->changes ^= DIR_ONLY_MODE;
01640 }
01641 
01642 bool KDirLister::autoErrorHandlingEnabled() const
01643 {
01644   return d->autoErrorHandling;
01645 }
01646 
01647 void KDirLister::setAutoErrorHandlingEnabled( bool enable, QWidget* parent )
01648 {
01649   d->autoErrorHandling = enable;
01650   d->errorParent = parent;
01651 }
01652 
01653 const KURL& KDirLister::url() const
01654 {
01655   return d->url;
01656 }
01657 
01658 void KDirLister::emitChanges()
01659 {
01660   if ( d->changes == NONE )
01661     return;
01662 
01663   static const QString& dot = KGlobal::staticQString(".");
01664   static const QString& dotdot = KGlobal::staticQString("..");
01665 
01666   for ( KURL::List::Iterator it = d->lstDirs.begin();
01667         it != d->lstDirs.end(); ++it )
01668   {
01669     KFileItemListIterator kit( *s_pCache->itemsForDir( *it ) );
01670     for ( ; kit.current(); ++kit )
01671     {
01672       if ( (*kit)->text() == dot || (*kit)->text() == dotdot )
01673         continue;
01674 
01675       bool oldMime = true, newMime = true;
01676 
01677       if ( d->changes & MIME_FILTER )
01678       {
01679         oldMime = doMimeFilter( (*kit)->mimetype(), d->oldMimeFilter )
01680          && doMimeExcludeFilter( (*kit)->mimetype(), d->oldMimeExcludeFilter );
01681         newMime = doMimeFilter( (*kit)->mimetype(), d->mimeFilter )
01682         && doMimeExcludeFilter( (*kit)->mimetype(), d->mimeExcludeFilter );
01683 
01684         if ( oldMime && !newMime )
01685         {
01686           emit deleteItem( *kit );
01687           continue;
01688         }
01689       }
01690 
01691       if ( d->changes & DIR_ONLY_MODE )
01692       {
01693         // the lister switched to dirOnlyMode
01694         if ( d->dirOnlyMode )
01695         {
01696           if ( !(*kit)->isDir() )
01697             emit deleteItem( *kit );
01698         }
01699         else if ( !(*kit)->isDir() )
01700           addNewItem( *kit );
01701 
01702         continue;
01703       }
01704 
01705       if ( (*kit)->text()[0] == dot )
01706       {
01707         if ( d->changes & DOT_FILES )
01708         {
01709           // the lister switched to dot files mode
01710           if ( d->isShowingDotFiles )
01711             addNewItem( *kit );
01712           else
01713             emit deleteItem( *kit );
01714 
01715           continue;
01716         }
01717       }
01718       else if ( d->changes & NAME_FILTER )
01719       {
01720         bool oldName = (*kit)->isDir() ||
01721                        d->oldFilters.isEmpty() ||
01722                        doNameFilter( (*kit)->text(), d->oldFilters );
01723 
01724         bool newName = (*kit)->isDir() ||
01725                        d->lstFilters.isEmpty() ||
01726                        doNameFilter( (*kit)->text(), d->lstFilters );
01727 
01728         if ( oldName && !newName )
01729         {
01730           emit deleteItem( *kit );
01731           continue;
01732         }
01733         else if ( !oldName && newName )
01734           addNewItem( *kit );
01735       }
01736 
01737       if ( (d->changes & MIME_FILTER) && !oldMime && newMime )
01738         addNewItem( *kit );
01739     }
01740 
01741     emitItems();
01742   }
01743 
01744   d->changes = NONE;
01745 }
01746 
01747 void KDirLister::updateDirectory( const KURL& _u )
01748 {
01749   s_pCache->updateDirectory( _u );
01750 }
01751 
01752 bool KDirLister::isFinished() const
01753 {
01754   return d->complete;
01755 }
01756 
01757 KFileItem* KDirLister::rootItem() const
01758 {
01759   return d->rootFileItem;
01760 }
01761 
01762 KFileItem* KDirLister::findByURL( const KURL& _url ) const
01763 {
01764   return s_pCache->findByURL( this, _url );
01765 }
01766 
01767 KFileItem* KDirLister::findByName( const QString& _name ) const
01768 {
01769   return s_pCache->findByName( this, _name );
01770 }
01771 
01772 #ifndef KDE_NO_COMPAT
01773 KFileItem* KDirLister::find( const KURL& _url ) const
01774 {
01775   return findByURL( _url );
01776 }
01777 #endif
01778 
01779 
01780 // ================ public filter methods ================ //
01781 
01782 void KDirLister::setNameFilter( const QString& nameFilter )
01783 {
01784   if ( !(d->changes & NAME_FILTER) )
01785   {
01786     d->oldFilters = d->lstFilters;
01787     d->lstFilters.setAutoDelete( false );
01788   }
01789 
01790   d->lstFilters.clear();
01791   d->lstFilters.setAutoDelete( true );
01792 
01793   d->nameFilter = nameFilter;
01794 
01795   // Split on white space
01796   QStringList list = QStringList::split( ' ', nameFilter );
01797   for ( QStringList::Iterator it = list.begin(); it != list.end(); ++it )
01798     d->lstFilters.append( new QRegExp(*it, false, true ) );
01799 
01800   d->changes |= NAME_FILTER;
01801 }
01802 
01803 const QString& KDirLister::nameFilter() const
01804 {
01805   return d->nameFilter;
01806 }
01807 
01808 void KDirLister::setMimeFilter( const QStringList& mimeFilter )
01809 {
01810   if ( !(d->changes & MIME_FILTER) )
01811     d->oldMimeFilter = d->mimeFilter;
01812 
01813   if (mimeFilter.find ("all/allfiles") != mimeFilter.end () ||
01814       mimeFilter.find ("all/all") != mimeFilter.end ())
01815     d->mimeFilter.clear ();
01816   else
01817     d->mimeFilter = mimeFilter;
01818 
01819   d->changes |= MIME_FILTER;
01820 }
01821 
01822 void KDirLister::setMimeExcludeFilter( const QStringList& mimeExcludeFilter )
01823 {
01824   if ( !(d->changes & MIME_FILTER) )
01825     d->oldMimeExcludeFilter = d->mimeExcludeFilter;
01826 
01827   d->mimeExcludeFilter = mimeExcludeFilter;
01828   d->changes |= MIME_FILTER;
01829 }
01830 
01831 
01832 void KDirLister::clearMimeFilter()
01833 {
01834   if ( !(d->changes & MIME_FILTER) )
01835   {
01836        d->oldMimeFilter = d->mimeFilter;
01837        d->oldMimeExcludeFilter = d->mimeExcludeFilter;
01838   }
01839   d->mimeFilter.clear();
01840   d->mimeExcludeFilter.clear();
01841   d->changes |= MIME_FILTER;
01842 }
01843 
01844 const QStringList& KDirLister::mimeFilters() const
01845 {
01846   return d->mimeFilter;
01847 }
01848 
01849 bool KDirLister::matchesFilter( const QString& name ) const
01850 {
01851   return doNameFilter( name, d->lstFilters );
01852 }
01853 
01854 bool KDirLister::matchesMimeFilter( const QString& mime ) const
01855 {
01856   return doMimeFilter( mime, d->mimeFilter ) && doMimeExcludeFilter(mime,d->mimeExcludeFilter);
01857 }
01858 
01859 // ================ protected methods ================ //
01860 
01861 bool KDirLister::matchesFilter( const KFileItem *item ) const
01862 {
01863   Q_ASSERT( item );
01864   static const QString& dotdot = KGlobal::staticQString("..");
01865 
01866   if ( item->text() == dotdot )
01867     return false;
01868 
01869   if ( !d->isShowingDotFiles && item->text()[0] == '.' )
01870     return false;
01871 
01872   if ( item->isDir() || d->lstFilters.isEmpty() )
01873     return true;
01874 
01875   return matchesFilter( item->text() );
01876 }
01877 
01878 bool KDirLister::matchesMimeFilter( const KFileItem *item ) const
01879 {
01880   Q_ASSERT( item );
01881   return matchesMimeFilter( item->mimetype() );
01882 }
01883 
01884 bool KDirLister::doNameFilter( const QString& name, const QPtrList<QRegExp>& filters ) const
01885 {
01886   for ( QPtrListIterator<QRegExp> it( filters ); it.current(); ++it )
01887     if ( it.current()->exactMatch( name ) )
01888       return true;
01889 
01890   return false;
01891 }
01892 
01893 bool KDirLister::doMimeFilter( const QString& mime, const QStringList& filters ) const
01894 {
01895   if ( filters.isEmpty() )
01896     return true;
01897 
01898   KMimeType::Ptr mimeptr = KMimeType::mimeType(mime);
01899   QStringList::ConstIterator it = filters.begin();
01900   for ( ; it != filters.end(); ++it )
01901     if ( mimeptr->is(*it) )
01902       return true;
01903 
01904   return false;
01905 }
01906 
01907 bool KDirLister::doMimeExcludeFilter( const QString& mime, const QStringList& filters ) const
01908 {
01909   if ( filters.isEmpty() )
01910     return true;
01911 
01912   QStringList::ConstIterator it = filters.begin();
01913   for ( ; it != filters.end(); ++it )
01914     if ( (*it) == mime )
01915       return false;
01916 
01917   return true;
01918 }
01919 
01920 
01921 bool KDirLister::validURL( const KURL& _url ) const
01922 {
01923   if ( !_url.isValid() )
01924   {
01925     if ( d->autoErrorHandling )
01926     {
01927       QString tmp = i18n("Malformed URL\n%1").arg( _url.prettyURL() );
01928       KMessageBox::error( d->errorParent, tmp );
01929     }
01930     return false;
01931   }
01932 
01933   // TODO: verify that this is really a directory?
01934 
01935   return true;
01936 }
01937 
01938 void KDirLister::handleError( KIO::Job *job )
01939 {
01940   if ( d->autoErrorHandling )
01941     job->showErrorDialog( d->errorParent );
01942 }
01943 
01944 
01945 // ================= private methods ================= //
01946 
01947 void KDirLister::addNewItem( const KFileItem *item )
01948 {
01949   bool isNameFilterMatch = (d->dirOnlyMode && !item->isDir()) || !matchesFilter( item );
01950   if (isNameFilterMatch)
01951      return; // No reason to continue... bailing out here prevents a mimetype scan.
01952 
01953   bool isMimeFilterMatch = !matchesMimeFilter( item );
01954 
01955   if ( !isNameFilterMatch && !isMimeFilterMatch )
01956   {
01957     if ( !d->lstNewItems )
01958       d->lstNewItems = new KFileItemList;
01959 
01960     d->lstNewItems->append( item );            // items not filtered
01961   }
01962   else if ( !isNameFilterMatch )
01963   {
01964     if ( !d->lstMimeFilteredItems )
01965       d->lstMimeFilteredItems = new KFileItemList;
01966 
01967     d->lstMimeFilteredItems->append( item );   // only filtered by mime
01968   }
01969 }
01970 
01971 void KDirLister::addNewItems( const KFileItemList& items )
01972 {
01973   // TODO: make this faster - test if we have a filter at all first
01974   for ( KFileItemListIterator kit( items ); kit.current(); ++kit )
01975     addNewItem( *kit );
01976 }
01977 
01978 void KDirLister::addRefreshItem( const KFileItem *item )
01979 {
01980   bool isNameFilterMatch = (d->dirOnlyMode && !item->isDir()) || !matchesFilter( item );
01981   bool isMimeFilterMatch = !matchesMimeFilter( item );
01982 
01983   if ( !isNameFilterMatch && !isMimeFilterMatch )
01984   {
01985     if ( !d->lstRefreshItems )
01986       d->lstRefreshItems = new KFileItemList;
01987 
01988     d->lstRefreshItems->append( item );
01989   } else {
01990     if ( !d->lstRemoveItems )
01991       d->lstRemoveItems = new KFileItemList;
01992 
01993       d->lstRemoveItems->append( item );//notify the user that the mimetype of a file changed, which doesn't match a filter or does match an exclude  filter
01994   }
01995 }
01996 
01997 void KDirLister::emitItems()
01998 {
01999   KFileItemList *tmpNew = d->lstNewItems;
02000   d->lstNewItems = 0;
02001 
02002   KFileItemList *tmpMime = d->lstMimeFilteredItems;
02003   d->lstMimeFilteredItems = 0;
02004 
02005   KFileItemList *tmpRefresh = d->lstRefreshItems;
02006   d->lstRefreshItems = 0;
02007 
02008   KFileItemList *tmpRemove = d->lstRemoveItems;
02009   d->lstRemoveItems = 0;
02010 
02011   if ( tmpNew )
02012   {
02013     emit newItems( *tmpNew );
02014     delete tmpNew;
02015   }
02016 
02017   if ( tmpMime )
02018   {
02019     emit itemsFilteredByMime( *tmpMime );
02020     delete tmpMime;
02021   }
02022 
02023   if ( tmpRefresh )
02024   {
02025     emit refreshItems( *tmpRefresh );
02026     delete tmpRefresh;
02027   }
02028 
02029   if ( tmpRemove )
02030   {
02031     for (KFileItem *tmp=tmpRemove->first(); tmp;tmp=tmpRemove->next())
02032         emit deleteItem( tmp);
02033     delete tmpRemove;
02034   }
02035 }
02036 
02037 void KDirLister::emitDeleteItem( KFileItem *item )
02038 {
02039   bool isNameFilterMatch = (d->dirOnlyMode && !item->isDir()) || !matchesFilter( item );
02040   bool isMimeFilterMatch = !matchesMimeFilter( item );
02041 
02042   if ( !isNameFilterMatch && !isMimeFilterMatch )
02043     emit deleteItem( item );
02044 }
02045 
02046 
02047 // ================ private slots ================ //
02048 
02049 void KDirLister::slotInfoMessage( KIO::Job *, const QString& message )
02050 {
02051   emit infoMessage( message );
02052 }
02053 
02054 void KDirLister::slotPercent( KIO::Job *job, unsigned long pcnt )
02055 {
02056   d->jobData[static_cast<KIO::ListJob*>(job)].percent = pcnt;
02057 
02058   int result = 0;
02059 
02060   KIO::filesize_t size = 0;
02061 
02062   QMap< KIO::ListJob *, KDirListerPrivate::JobData >::Iterator dataIt = d->jobData.begin();
02063   while ( dataIt != d->jobData.end() )
02064   {
02065     result += (*dataIt).percent * (*dataIt).totalSize;
02066     size += (*dataIt).totalSize;
02067     ++dataIt;
02068   }
02069 
02070   if ( size != 0 )
02071     result /= size;
02072   else
02073     result = 100;
02074   emit percent( result );
02075 }
02076 
02077 void KDirLister::slotTotalSize( KIO::Job *job, KIO::filesize_t size )
02078 {
02079   d->jobData[static_cast<KIO::ListJob*>(job)].totalSize = size;
02080 
02081   KIO::filesize_t result = 0;
02082   QMap< KIO::ListJob *, KDirListerPrivate::JobData >::Iterator dataIt = d->jobData.begin();
02083   while ( dataIt != d->jobData.end() )
02084   {
02085     result += (*dataIt).totalSize;
02086     ++dataIt;
02087   }
02088 
02089   emit totalSize( result );
02090 }
02091 
02092 void KDirLister::slotProcessedSize( KIO::Job *job, KIO::filesize_t size )
02093 {
02094   d->jobData[static_cast<KIO::ListJob*>(job)].processedSize = size;
02095 
02096   KIO::filesize_t result = 0;
02097   QMap< KIO::ListJob *, KDirListerPrivate::JobData >::Iterator dataIt = d->jobData.begin();
02098   while ( dataIt != d->jobData.end() )
02099   {
02100     result += (*dataIt).processedSize;
02101     ++dataIt;
02102   }
02103 
02104   emit processedSize( result );
02105 }
02106 
02107 void KDirLister::slotSpeed( KIO::Job *job, unsigned long spd )
02108 {
02109   d->jobData[static_cast<KIO::ListJob*>(job)].speed = spd;
02110 
02111   int result = 0;
02112   QMap< KIO::ListJob *, KDirListerPrivate::JobData >::Iterator dataIt = d->jobData.begin();
02113   while ( dataIt != d->jobData.end() )
02114   {
02115     result += (*dataIt).speed;
02116     ++dataIt;
02117   }
02118 
02119   emit speed( result );
02120 }
02121 
02122 uint KDirLister::numJobs()
02123 {
02124   return d->jobData.count();
02125 }
02126 
02127 void KDirLister::jobDone(KIO::ListJob *job)
02128 {
02129   if (job)
02130      d->jobData.remove(job);
02131 }
02132 
02133 void KDirLister::jobStarted(KIO::ListJob *job)
02134 {
02135   KDirListerPrivate::JobData jobData;
02136   jobData.speed = 0;
02137   jobData.percent = 0;
02138   jobData.processedSize = 0;
02139   jobData.totalSize = 0;
02140 
02141   d->jobData.insert(job, jobData);
02142 }
02143 
02144 void KDirLister::setMainWindow(QWidget *window)
02145 {
02146   d->window = window;
02147 }
02148 
02149 QWidget *KDirLister::mainWindow()
02150 {
02151   return d->window;
02152 }
02153 
02154 KFileItemList KDirLister::items( WhichItems which ) const
02155 {
02156     return itemsForDir( url(), which );
02157 }
02158 
02159 KFileItemList KDirLister::itemsForDir( const KURL &dir, WhichItems which) const
02160 {
02161     KFileItemList result;
02162     KFileItemList *allItems = s_pCache->itemsForDir( dir );
02163 
02164     if ( which == AllItems )
02165         result = *allItems; // shallow copy
02166 
02167     else // only items passing the filters
02168     {
02169         for ( KFileItemListIterator kit( *allItems ); kit.current(); ++kit )
02170         {
02171             KFileItem *item = *kit;
02172             bool isNameFilterMatch = (d->dirOnlyMode && !item->isDir()) ||
02173                                      !matchesFilter( item );
02174             bool isMimeFilterMatch = !matchesMimeFilter( item );
02175 
02176             if ( !isNameFilterMatch && !isMimeFilterMatch )
02177                 result.append( item );
02178         }
02179     }
02180 
02181     return result;
02182 }
02183 
02184 // to keep BC changes
02185 
02186 void KDirLister::virtual_hook( int, void* )
02187 { /*BASE::virtual_hook( id, data );*/ }
02188 
02189 #include "kdirlister.moc"
02190 #include "kdirlister_p.moc"
KDE Logo
This file is part of the documentation for kio Library Version 3.2.0.
Documentation copyright © 1996-2004 the KDE developers.
Generated on Wed Feb 4 12:35:03 2004 by doxygen 1.2.18 written by Dimitri van Heesch, © 1997-2003