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