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 == dot )
00859     {
00860       Q_ASSERT( !dir->rootItem );
00861       dir->rootItem = new KFileItem( *it, url, delayedMimeTypes, true  );
00862 
00863       for ( KDirLister *kdl = listers->first(); kdl; kdl = listers->next() )
00864         if ( !kdl->d->rootFileItem && kdl->d->url == url )
00865           kdl->d->rootFileItem = dir->rootItem;
00866     }
00867     else if ( name != dotdot )
00868     {
00869       //kdDebug(7004)<< "Adding " << url.prettyURL() << endl;
00870 
00871       KFileItem* item = new KFileItem( *it, url, delayedMimeTypes, true );
00872       Q_ASSERT( item );
00873 
00874       dir->lstItems->append( item );
00875 
00876       for ( KDirLister *kdl = listers->first(); kdl; kdl = listers->next() )
00877         kdl->addNewItem( item );
00878     }
00879   }
00880 
00881   for ( KDirLister *kdl = listers->first(); kdl; kdl = listers->next() )
00882     kdl->emitItems();
00883 }
00884 
00885 void KDirListerCache::slotResult( KIO::Job* j )
00886 {
00887   Q_ASSERT( j );
00888   KIO::ListJob *job = static_cast<KIO::ListJob *>( j );
00889   jobs.remove( job );
00890 
00891   KURL jobUrl = job->url();
00892   jobUrl.adjustPath(-1);  // need remove trailing slashes again, in case of redirections
00893   QString jobUrlStr = jobUrl.url();
00894 
00895   kdDebug(7004) << k_funcinfo << "finished listing " << jobUrl << endl;
00896 #ifdef DEBUG_CACHE
00897   printDebug();
00898 #endif
00899 
00900   QPtrList<KDirLister> *listers = urlsCurrentlyListed.take( jobUrlStr );
00901   Q_ASSERT( listers );
00902 
00903   KDirLister *kdl;
00904 
00905   if ( job->error() )
00906   {
00907     for ( kdl = listers->first(); kdl; kdl = listers->next() )
00908     {
00909       kdl->handleError( job );
00910       emit kdl->canceled( jobUrl );
00911       if ( --kdl->d->numJobs == 0 )
00912       {
00913         kdl->d->complete = true;
00914         emit kdl->canceled();
00915       }
00916     }
00917   }
00918   else
00919   {
00920     DirItem *dir = itemsInUse[jobUrlStr];
00921     Q_ASSERT( dir );
00922     dir->complete = true;
00923 
00924     for ( kdl = listers->first(); kdl; kdl = listers->next() )
00925     {
00926       emit kdl->completed( jobUrl );
00927       if ( --kdl->d->numJobs == 0 )
00928       {
00929         kdl->d->complete = true;
00930         emit kdl->completed();
00931       }
00932     }
00933   }
00934 
00935   // move the directory to the held directories
00936   Q_ASSERT( !urlsCurrentlyHeld[jobUrlStr] );
00937   urlsCurrentlyHeld.insert( jobUrlStr, listers );
00938 
00939   // TODO: hmm, if there was an error and job is a parent of one or more
00940   // of the pending urls we should cancel it/them as well
00941   processPendingUpdates();
00942 
00943 #ifdef DEBUG_CACHE
00944   printDebug();
00945 #endif
00946 }
00947 
00948 void KDirListerCache::slotRedirection( KIO::Job *job, const KURL &url )
00949 {
00950   Q_ASSERT( job );
00951   KURL oldUrl = static_cast<KIO::ListJob *>( job )->url();
00952 
00953   // strip trailing slashes
00954   oldUrl.adjustPath(-1);
00955   KURL newUrl = url;
00956   newUrl.adjustPath(-1);
00957 
00958   kdDebug(7004) << k_funcinfo << oldUrl.prettyURL() << " -> " << newUrl.prettyURL() << endl;
00959 
00960   // I don't think there can be dirItems that are childs of oldUrl.
00961   // Am I wrong here? And even if so, we don't need to delete them, right?
00962   // DF: redirection happens before listDir emits any item. Makes little sense otherwise.
00963 
00964   DirItem *dir = itemsInUse.take( oldUrl.url() );
00965   Q_ASSERT( dir );
00966 
00967   QPtrList<KDirLister> *listers = urlsCurrentlyListed.take( oldUrl.url() );
00968   Q_ASSERT( listers );
00969   Q_ASSERT( !listers->isEmpty() );
00970 
00971   for ( KDirLister *kdl = listers->first(); kdl; kdl = listers->next() )
00972   {
00973     if ( kdl->d->url.cmp( oldUrl, true ) )
00974     {
00975       kdl->d->rootFileItem = 0;
00976       kdl->d->url = newUrl;
00977     }
00978 
00979     *kdl->d->lstDirs.find( oldUrl ) = newUrl;
00980 
00981     if ( kdl->d->lstDirs.count() == 1 )
00982     {
00983       emit kdl->clear();
00984       emit kdl->redirection( newUrl );
00985       emit kdl->redirection( oldUrl, newUrl );
00986     }
00987     else
00988     {
00989       emit kdl->clear( oldUrl );
00990       emit kdl->redirection( oldUrl, newUrl );
00991     }
00992   }
00993 
00994   delete dir->rootItem;
00995   dir->rootItem = 0;
00996   dir->lstItems->clear();
00997   itemsInUse.insert( newUrl.url(), dir );
00998   urlsCurrentlyListed.insert( newUrl.url(), listers );
00999 }
01000 
01001 void KDirListerCache::renameDir( const KURL &oldUrl, const KURL &newUrl )
01002 {
01003   kdDebug(7004) << k_funcinfo << oldUrl.prettyURL() << " -> " << newUrl.prettyURL() << endl;
01004   QString oldUrlStr = oldUrl.url(-1);
01005   QString newUrlStr = newUrl.url(-1);
01006 
01007   // Not enough. Also need to look at any child dir, even sub-sub-sub-dir.
01008   //DirItem *dir = itemsInUse.take( oldUrlStr );
01009   //emitRedirections( oldUrl, url );
01010 
01011   // Look at all dirs being listed/shown
01012   QDictIterator<DirItem> itu( itemsInUse );
01013   bool goNext;
01014   while ( itu.current() )
01015   {
01016     goNext = true;
01017     DirItem* dir = itu.current();
01018     KURL oldDirUrl = itu.currentKey();
01019     //kdDebug(7004) << "itemInUse: " << oldDirUrl.prettyURL() << endl;
01020     // Check if this dir is oldUrl, or a subfolder of it
01021     if ( oldUrl.isParentOf( oldDirUrl ) )
01022     {
01023       QString relPath = oldDirUrl.path().mid( oldUrl.path().length() ); // ### should use KURL::cleanpath like isParentOf does
01024 
01025       KURL newDirUrl( newUrl ); // take new base
01026       if ( !relPath.isEmpty() )
01027         newDirUrl.addPath( relPath ); // add unchanged relative path
01028       //kdDebug(7004) << "KDirListerCache::renameDir new url=" << newDirUrl.prettyURL() << endl;
01029 
01030       // Update URL in root item and in itemsInUse
01031       if ( dir->rootItem )
01032         dir->rootItem->setURL( newDirUrl );
01033       dir->url = newDirUrl;
01034       itemsInUse.remove( itu.currentKey() ); // implies ++itu
01035       itemsInUse.insert( newDirUrl.url(-1), dir );
01036       goNext = false; // because of the implied ++itu above
01037       if ( dir->lstItems )
01038       {
01039         // Rename all items under that dir
01040         KFileItemListIterator kit( *dir->lstItems );
01041         for ( ; kit.current(); ++kit )
01042         {
01043           KURL oldItemUrl = (*kit)->url();
01044           QString oldItemUrlStr( oldItemUrl.url(-1) );
01045           KURL newItemUrl( oldItemUrl );
01046           newItemUrl.setPath( newDirUrl.path() );
01047           newItemUrl.addPath( oldItemUrl.fileName() );
01048           kdDebug(7004) << "KDirListerCache::renameDir renaming " << oldItemUrlStr << " to " << newItemUrl.url() << endl;
01049           (*kit)->setURL( newItemUrl );
01050         }
01051       }
01052       emitRedirections( oldDirUrl, newDirUrl );
01053     }
01054     if (goNext)
01055       ++itu;
01056   }
01057 
01058   // Is oldUrl a directory in the cache?
01059   // Remove any child of oldUrl from the cache - even if the renamed dir itself isn't in it!
01060   removeDirFromCache( oldUrl );
01061   // TODO rename, instead.
01062 }
01063 
01064 void KDirListerCache::emitRedirections( const KURL &oldUrl, const KURL &url )
01065 {
01066   kdDebug(7004) << k_funcinfo << oldUrl.prettyURL() << " -> " << url.prettyURL() << endl;
01067   QString oldUrlStr = oldUrl.url(-1);
01068   QString urlStr = url.url(-1);
01069   // Check if we were listing this dir. Need to abort and restart with new name in that case.
01070   QPtrList<KDirLister> *listers = urlsCurrentlyListed.take( oldUrlStr );
01071   if ( listers )
01072   {
01073     killJob( oldUrlStr );
01074     urlsCurrentlyListed.insert( urlStr, listers );
01075     updateDirectory( url );
01076     // not sure if we should emit canceled( oldUrl ) and started( dst ),
01077     // updateDirectory won't do it which means we will get a completed without
01078     // a different argument... I'd do this as well.
01079     for ( KDirLister *kdl = listers->first(); kdl; kdl = listers->next() )
01080     {
01081       emit kdl->canceled( oldUrl );
01082       emit kdl->started( url );
01083     }
01084   }
01085 
01086   // Check if we are currently displaying this directory (odds opposite wrt above)
01087   // Update urlsCurrentlyHeld dict with new URL
01088   QPtrList<KDirLister> *holders = urlsCurrentlyHeld.take( oldUrlStr );
01089   if ( holders )
01090   {
01091     urlsCurrentlyHeld.insert( url.url(-1), holders );
01092     // And notify the dirlisters of the redirection
01093     for ( KDirLister *kdl = holders->first(); kdl; kdl = holders->next() )
01094     {
01095       *kdl->d->lstDirs.find( oldUrl ) = url;
01096       if ( kdl->d->lstDirs.count() == 1 )
01097       {
01098         emit kdl->redirection( url );
01099       }
01100       emit kdl->redirection( oldUrl, url );
01101     }
01102   }
01103 }
01104 
01105 void KDirListerCache::removeDirFromCache( const KURL& dir )
01106 {
01107   kdDebug(7004) << "KDirListerCache::removeDirFromCache " << dir.prettyURL() << endl;
01108   QCacheIterator<DirItem> itc( itemsCached );
01109   while ( itc.current() )
01110   {
01111     if ( dir.isParentOf( KURL( itc.currentKey() ) ) )
01112       itemsCached.remove( itc.currentKey() );
01113     else
01114       ++itc;
01115   }
01116 }
01117 
01118 void KDirListerCache::slotUpdateEntries( KIO::Job* job, const KIO::UDSEntryList& list )
01119 {
01120   jobs[static_cast<KIO::ListJob*>(job)] += list;
01121 }
01122 
01123 void KDirListerCache::slotUpdateResult( KIO::Job * j )
01124 {
01125   Q_ASSERT( j );
01126   KIO::ListJob *job = static_cast<KIO::ListJob *>( j );
01127 
01128   KURL jobUrl = job->url();
01129   jobUrl.adjustPath(-1);  // need remove trailing slashes again, in case of redirections
01130   QString jobUrlStr = jobUrl.url();
01131 
01132   kdDebug(7004) << k_funcinfo << "finished update " << jobUrl << endl;
01133 
01134   KDirLister *kdl;
01135 
01136   QPtrList<KDirLister> *listers = urlsCurrentlyHeld[jobUrlStr];
01137   QPtrList<KDirLister> *tmpLst = urlsCurrentlyListed.take( jobUrlStr );
01138 
01139   if ( tmpLst )
01140   {
01141     if ( listers )
01142       for ( kdl = tmpLst->first(); kdl; kdl = tmpLst->next() )
01143       {
01144         Q_ASSERT( listers->containsRef( kdl ) == 0 );
01145         listers->append( kdl );
01146       }
01147     else
01148     {
01149       listers = tmpLst;
01150       urlsCurrentlyHeld.insert( jobUrlStr, listers );
01151     }
01152   }
01153 
01154   // once we are updating dirs that are only in the cache this will fail!
01155   Q_ASSERT( listers );
01156 
01157   if ( job->error() )
01158   {
01159     for ( kdl = listers->first(); kdl; kdl = listers->next() )
01160     {
01161       //don't bother the user
01162       //kdl->handleError( job );
01163 
01164       emit kdl->canceled( jobUrl );
01165       if ( --kdl->d->numJobs == 0 )
01166       {
01167         kdl->d->complete = true;
01168         emit kdl->canceled();
01169       }
01170     }
01171 
01172     jobs.remove( job );
01173 
01174     // TODO: if job is a parent of one or more
01175     // of the pending urls we should cancel them
01176     processPendingUpdates();
01177     return;
01178   }
01179 
01180   DirItem *dir = itemsInUse[jobUrlStr];
01181   dir->complete = true;
01182 
01183 
01184   // check if anyone wants the mimetypes immediately
01185   bool delayedMimeTypes = true;
01186   for ( kdl = listers->first(); kdl; kdl = listers->next() )
01187     delayedMimeTypes &= kdl->d->delayedMimeTypes;
01188 
01189   // should be enough to get reasonable speed in most cases
01190   QDict<KFileItem> fileItems( 9973 );
01191 
01192   KFileItemListIterator kit ( *(dir->lstItems) );
01193 
01194   // Unmark all items in url
01195   for ( ; kit.current(); ++kit )
01196   {
01197     //kdDebug(7004) << "slotUpdateResult : unmarking " << (*kit)->url().prettyURL() << endl;
01198     (*kit)->unmark();
01199     fileItems.insert( (*kit)->url().url(), *kit );
01200   }
01201 
01202   static const QString& dot = KGlobal::staticQString(".");
01203   static const QString& dotdot = KGlobal::staticQString("..");
01204 
01205   KFileItem *item, *tmp;
01206 
01207   QValueList<KIO::UDSEntry> buf = jobs[job];
01208   QValueListIterator<KIO::UDSEntry> it = buf.begin();
01209   for ( ; it != buf.end(); ++it )
01210   {
01211     QString name;
01212 
01213     // Find out about the name
01214     KIO::UDSEntry::Iterator it2 = (*it).begin();
01215     for ( ; it2 != (*it).end(); it2++ )
01216       if ( (*it2).m_uds == KIO::UDS_NAME )
01217       {
01218         name = (*it2).m_str;
01219         break;
01220       }
01221 
01222     Q_ASSERT( !name.isEmpty() );
01223 
01224     // we duplicate the check for dotdot here, to avoid iterating over
01225     // all items again and checking in matchesFilter() that way.
01226     if ( name.isEmpty() || name == dotdot )
01227       continue;
01228 
01229     if ( name == dot )
01230     {
01231       // if the update was started before finishing the original listing
01232       // there is no root item yet
01233       if ( !dir->rootItem )
01234       {
01235         dir->rootItem = new KFileItem( *it, jobUrl, delayedMimeTypes, true  );
01236 
01237         for ( KDirLister *kdl = listers->first(); kdl; kdl = listers->next() )
01238           if ( !kdl->d->rootFileItem && kdl->d->url == jobUrl )
01239             kdl->d->rootFileItem = dir->rootItem;
01240       }
01241 
01242       continue;
01243     }
01244 
01245     // Form the complete url
01246     KURL u( jobUrl );
01247     u.addPath( name );
01248     //kdDebug(7004) << "slotUpdateResult : found " << name << endl;
01249 
01250     // Find this item
01251     bool found = false;
01252     if ( (tmp = fileItems[u.url()]) )
01253     {
01254       tmp->mark();
01255       found = true;
01256     }
01257 
01258     item = new KFileItem( *it, jobUrl, delayedMimeTypes, true  );
01259 
01260     if ( found )
01261     {
01262       // check if something changed for this file
01263       if ( !tmp->cmp( *item ) )
01264       {
01265         //kdDebug(7004) << "slotUpdateResult: file changed: " << tmp->name() << endl;
01266         tmp->assign( *item );
01267 
01268         for ( kdl = listers->first(); kdl; kdl = listers->next() )
01269           kdl->addRefreshItem( tmp );
01270       }
01271       delete item;  // gmbl, this is the most often case... IMPORTANT TODO: speed it up somehow!
01272     }
01273     else // this is a new file
01274     {
01275       //kdDebug(7004) << "slotUpdateResult: new file: " << name << endl;
01276 
01277       item->mark();
01278       dir->lstItems->append( item );
01279 
01280       for ( kdl = listers->first(); kdl; kdl = listers->next() )
01281         kdl->addNewItem( item );
01282     }
01283   }
01284 
01285   jobs.remove( job );
01286 
01287   deleteUnmarkedItems( listers, dir->lstItems );
01288 
01289   for ( kdl = listers->first(); kdl; kdl = listers->next() )
01290   {
01291     kdl->emitItems();
01292 
01293     emit kdl->completed( jobUrl );
01294     if ( --kdl->d->numJobs == 0 )
01295     {
01296       kdl->d->complete = true;
01297       emit kdl->completed();
01298     }
01299   }
01300 
01301   // TODO: hmm, if there was an error and job is a parent of one or more
01302   // of the pending urls we should cancel it/them as well
01303   processPendingUpdates();
01304 }
01305 
01306 // private
01307 
01308 bool KDirListerCache::killJob( const QString& _url )
01309 {
01310   KIO::ListJob *job;
01311   QMap< KIO::ListJob *, QValueList<KIO::UDSEntry> >::Iterator it = jobs.begin();
01312   while ( it != jobs.end() )
01313   {
01314     job = it.key();
01315     if ( job->url().url(-1) == _url )
01316     {
01317       jobs.remove( it );
01318       job->disconnect( this );
01319       job->kill();
01320       return true;
01321     }
01322     ++it;
01323   }
01324   return false;
01325 }
01326 
01327 void KDirListerCache::deleteUnmarkedItems( QPtrList<KDirLister> *listers, KFileItemList *lstItems )
01328 {
01329   // Find all unmarked items and delete them
01330   KFileItem* item;
01331   lstItems->first();
01332   while ( (item = lstItems->current()) )
01333     if ( !item->isMarked() )
01334     {
01335       //kdDebug() << k_funcinfo << item->name() << endl;
01336       for ( KDirLister *kdl = listers->first(); kdl; kdl = listers->next() )
01337         kdl->emitDeleteItem( item );
01338 
01339       if ( item->isDir() )
01340         deleteDir( item->url() );
01341 
01342       // finally actually delete the item
01343       lstItems->take();
01344       delete item;
01345     }
01346     else
01347       lstItems->next();
01348 }
01349 
01350 void KDirListerCache::deleteDir( const KURL& dirUrl )
01351 {
01352   //kdDebug() << k_funcinfo << dirUrl.prettyURL() << endl;
01353   // unregister and remove the childs of the deleted item.
01354   // Idea: tell all the KDirListers that they should forget the dir
01355   //       and then remove it from the cache.
01356 
01357   QDictIterator<DirItem> itu( itemsInUse );
01358   while ( itu.current() )
01359   {
01360     KURL deletedUrl = itu.currentKey();
01361     if ( dirUrl.isParentOf( deletedUrl ) )
01362     {
01363       // stop all jobs for deletedUrl
01364 
01365       QPtrList<KDirLister> *kdls = urlsCurrentlyListed[deletedUrl.url()];
01366       if ( kdls )  // yeah, I lack good names
01367       {
01368         // we need a copy because stop modifies the list
01369         kdls = new QPtrList<KDirLister>( *kdls );
01370         for ( KDirLister *kdl = kdls->first(); kdl; kdl = kdls->next() )
01371           stop( kdl, deletedUrl );
01372 
01373         delete kdls;
01374       }
01375 
01376       // tell listers holding deletedUrl to forget about it
01377       // this will stop running updates for deletedUrl as well
01378 
01379       kdls = urlsCurrentlyHeld[deletedUrl.url()];
01380       if ( kdls )
01381       {
01382         // we need a copy because forgetDirs modifies the list
01383         kdls = new QPtrList<KDirLister>( *kdls );
01384 
01385         for ( KDirLister *kdl = kdls->first(); kdl; kdl = kdls->next() )
01386         {
01387           // lister's root is the deleted item
01388           if ( kdl->d->url == deletedUrl )
01389           {
01390             // tell the view first. It might need the subdirs' items (which forgetDirs will delete)
01391             emit kdl->deleteItem( kdl->d->rootFileItem );
01392             forgetDirs( kdl );
01393             kdl->d->rootFileItem = 0;
01394           }
01395           else
01396           {
01397             bool treeview = kdl->d->lstDirs.count() > 1;
01398             forgetDirs( kdl, deletedUrl, treeview );
01399             if ( !treeview )
01400             {
01401               kdl->d->lstDirs.clear();
01402               emit kdl->clear();
01403             }
01404           }
01405         }
01406 
01407         delete kdls;
01408       }
01409 
01410       // delete the entry for deletedUrl - should not be needed, it's in
01411       // items cached now
01412 
01413       DirItem *dir = itemsInUse.take( deletedUrl.url() );
01414       Q_ASSERT( !dir );
01415     }
01416     else
01417       ++itu;
01418   }
01419 
01420   // remove the children from the cache
01421   removeDirFromCache( dirUrl );
01422 }
01423 
01424 void KDirListerCache::processPendingUpdates()
01425 {
01426   // TODO
01427 }
01428 
01429 #ifndef NDEBUG
01430 void KDirListerCache::printDebug()
01431 {
01432   kdDebug(7004) << "Items in use: " << endl;
01433   QDictIterator<DirItem> itu( itemsInUse );
01434   for ( ; itu.current() ; ++itu ) {
01435       kdDebug(7004) << "   " << itu.currentKey() << "  URL: " << itu.current()->url
01436                     << " rootItem: " << ( itu.current()->rootItem ? itu.current()->rootItem->url() : QString("NULL") )
01437                     << " autoUpdates refcount: " << itu.current()->autoUpdates
01438                     << " complete: " << itu.current()->complete
01439                   << ( itu.current()->lstItems ? QString(" with %1 items.").arg(itu.current()->lstItems->count()) : QString(" lstItems=NULL") ) << endl;
01440   }
01441 
01442   kdDebug(7004) << "urlsCurrentlyHeld: " << endl;
01443   QDictIterator< QPtrList<KDirLister> > it( urlsCurrentlyHeld );
01444   for ( ; it.current() ; ++it )
01445   {
01446     QString list;
01447     for ( QPtrListIterator<KDirLister> listit( *it.current() ); listit.current(); ++listit )
01448       list += " 0x" + QString::number( (long)listit.current(), 16 );
01449     kdDebug(7004) << "   " << it.currentKey() << "  " << it.current()->count() << " listers: " << list << endl;
01450   }
01451 
01452   kdDebug(7004) << "urlsCurrentlyListed: " << endl;
01453   QDictIterator< QPtrList<KDirLister> > it2( urlsCurrentlyListed );
01454   for ( ; it2.current() ; ++it2 )
01455   {
01456     QString list;
01457     for ( QPtrListIterator<KDirLister> listit( *it2.current() ); listit.current(); ++listit )
01458       list += " 0x" + QString::number( (long)listit.current(), 16 );
01459     kdDebug(7004) << "   " << it2.currentKey() << "  " << it2.current()->count() << " listers: " << list << endl;
01460   }
01461 
01462   QMap< KIO::ListJob *, QValueList<KIO::UDSEntry> >::Iterator jit = jobs.begin();
01463   kdDebug(7004) << "Jobs: " << endl;
01464   for ( ; jit != jobs.end() ; ++jit )
01465     kdDebug(7004) << "   " << jit.key() << " listing " << jit.key()->url().prettyURL() << ": " << (*jit).count() << " entries." << endl;
01466 
01467   kdDebug(7004) << "Items in cache: " << endl;
01468   QCacheIterator<DirItem> itc( itemsCached );
01469   for ( ; itc.current() ; ++itc )
01470     kdDebug(7004) << "   " << itc.currentKey() << "  rootItem: "
01471                   << ( itc.current()->rootItem ? itc.current()->rootItem->url().prettyURL() : QString("NULL") )
01472                   << ( itc.current()->lstItems ? QString(" with %1 items.").arg(itc.current()->lstItems->count()) : QString(" lstItems=NULL") ) << endl;
01473 }
01474 #endif
01475 
01476 /*********************** -- The new KDirLister -- ************************/
01477 
01478 
01479 KDirLister::KDirLister( bool _delayedMimeTypes )
01480 {
01481   kdDebug(7003) << "+KDirLister" << endl;
01482 
01483   d = new KDirListerPrivate;
01484 
01485   d->complete = true;
01486   d->delayedMimeTypes = _delayedMimeTypes;
01487 
01488   setAutoUpdate( true );
01489   setDirOnlyMode( false );
01490   setShowingDotFiles( false );
01491 
01492   setAutoErrorHandlingEnabled( true, 0 );
01493 
01494   connect( this, SIGNAL( completed() ), SLOT( slotClearState() ) );
01495   connect( this, SIGNAL( canceled() ), SLOT( slotClearState() ) );
01496   connect( this, SIGNAL( completed( const KURL& ) ), SLOT( slotJobToBeKilled( const KURL& ) ) );
01497   connect( this, SIGNAL( canceled( const KURL& ) ), SLOT( slotJobToBeKilled( const KURL& ) ) );
01498 }
01499 
01500 KDirLister::~KDirLister()
01501 {
01502   kdDebug(7003) << "-KDirLister" << endl;
01503 
01504   // Stop all running jobs
01505   stop();
01506   s_pCache->forgetDirs( this );
01507 
01508   delete d;
01509 }
01510 
01511 bool KDirLister::openURL( const KURL& _url, bool _keep, bool _reload )
01512 {
01513   if ( !validURL( _url ) )
01514     return false;
01515 
01516   kdDebug(7003) << k_funcinfo << _url.prettyURL()
01517                 << " keep=" << _keep << " reload=" << _reload << endl;
01518 
01519   // emit the current changes made to avoid an inconsistent treeview
01520   if ( d->changes != NONE && _keep )
01521     emitChanges();
01522 
01523   d->changes = NONE;
01524 
01525   s_pCache->listDir( this, _url, _keep, _reload );
01526 
01527   return true;
01528 }
01529 
01530 void KDirLister::stop()
01531 {
01532   kdDebug(7003) << k_funcinfo << endl;
01533   s_pCache->stop( this );
01534 }
01535 
01536 void KDirLister::stop( const KURL& _url )
01537 {
01538   kdDebug(7003) << k_funcinfo << _url.prettyURL() << endl;
01539   s_pCache->stop( this, _url );
01540 }
01541 
01542 bool KDirLister::autoUpdate() const
01543 {
01544   return d->autoUpdate;
01545 }
01546 
01547 void KDirLister::setAutoUpdate( bool _enable )
01548 {
01549   if ( d->autoUpdate == _enable )
01550     return;
01551 
01552   d->autoUpdate = _enable;
01553   s_pCache->setAutoUpdate( this, _enable );
01554 }
01555 
01556 bool KDirLister::showingDotFiles() const
01557 {
01558   return d->isShowingDotFiles;
01559 }
01560 
01561 void KDirLister::setShowingDotFiles( bool _showDotFiles )
01562 {
01563   if ( d->isShowingDotFiles == _showDotFiles )
01564     return;
01565 
01566   d->isShowingDotFiles = _showDotFiles;
01567   d->changes ^= DOT_FILES;
01568 }
01569 
01570 bool KDirLister::dirOnlyMode() const
01571 {
01572   return d->dirOnlyMode;
01573 }
01574 
01575 void KDirLister::setDirOnlyMode( bool _dirsOnly )
01576 {
01577   if ( d->dirOnlyMode == _dirsOnly )
01578     return;
01579 
01580   d->dirOnlyMode = _dirsOnly;
01581   d->changes ^= DIR_ONLY_MODE;
01582 }
01583 
01584 bool KDirLister::autoErrorHandlingEnabled() const
01585 {
01586   return d->autoErrorHandling;
01587 }
01588 
01589 void KDirLister::setAutoErrorHandlingEnabled( bool enable, QWidget* parent )
01590 {
01591   d->autoErrorHandling = enable;
01592   d->errorParent = parent;
01593 }
01594 
01595 const KURL& KDirLister::url() const
01596 {
01597   return d->url;
01598 }
01599 
01600 void KDirLister::emitChanges()
01601 {
01602   if ( d->changes == NONE )
01603     return;
01604 
01605   static const QString& dot = KGlobal::staticQString(".");
01606   static const QString& dotdot = KGlobal::staticQString("..");
01607 
01608   for ( KURL::List::Iterator it = d->lstDirs.begin();
01609         it != d->lstDirs.end(); ++it )
01610   {
01611     KFileItemListIterator kit( *s_pCache->itemsForDir( *it ) );
01612     for ( ; kit.current(); ++kit )
01613     {
01614       if ( (*kit)->text() == dot || (*kit)->text() == dotdot )
01615         continue;
01616 
01617       bool oldMime = true, newMime = true;
01618 
01619       if ( d->changes & MIME_FILTER )
01620       {
01621         oldMime = doMimeFilter( (*kit)->mimetype(), d->oldMimeFilter )
01622          && doMimeExcludeFilter( (*kit)->mimetype(), d->oldMimeExcludeFilter );
01623         newMime = doMimeFilter( (*kit)->mimetype(), d->mimeFilter )
01624         && doMimeExcludeFilter( (*kit)->mimetype(), d->mimeExcludeFilter );
01625 
01626         if ( oldMime && !newMime )
01627         {
01628           emit deleteItem( *kit );
01629           continue;
01630         }
01631       }
01632 
01633       if ( d->changes & DIR_ONLY_MODE )
01634       {
01635         // the lister switched to dirOnlyMode
01636         if ( d->dirOnlyMode )
01637         {
01638           if ( !(*kit)->isDir() )
01639             emit deleteItem( *kit );
01640         }
01641         else if ( !(*kit)->isDir() )
01642           addNewItem( *kit );
01643 
01644         continue;
01645       }
01646 
01647       if ( (*kit)->text()[0] == dot )
01648       {
01649         if ( d->changes & DOT_FILES )
01650         {
01651           // the lister switched to dot files mode
01652           if ( d->isShowingDotFiles )
01653             addNewItem( *kit );
01654           else
01655             emit deleteItem( *kit );
01656 
01657           continue;
01658         }
01659       }
01660       else if ( d->changes & NAME_FILTER )
01661       {
01662         bool oldName = (*kit)->isDir() ||
01663                        d->oldFilters.isEmpty() ||
01664                        doNameFilter( (*kit)->text(), d->oldFilters );
01665 
01666         bool newName = (*kit)->isDir() ||
01667                        d->lstFilters.isEmpty() ||
01668                        doNameFilter( (*kit)->text(), d->lstFilters );
01669 
01670         if ( oldName && !newName )
01671         {
01672           emit deleteItem( *kit );
01673           continue;
01674         }
01675         else if ( !oldName && newName )
01676           addNewItem( *kit );
01677       }
01678 
01679       if ( (d->changes & MIME_FILTER) && !oldMime && newMime )
01680         addNewItem( *kit );
01681     }
01682 
01683     emitItems();
01684   }
01685 
01686   d->changes = NONE;
01687 }
01688 
01689 void KDirLister::updateDirectory( const KURL& _u )
01690 {
01691   s_pCache->updateDirectory( _u );
01692 }
01693 
01694 bool KDirLister::isFinished() const
01695 {
01696   return d->complete;
01697 }
01698 
01699 KFileItem* KDirLister::rootItem() const
01700 {
01701   return d->rootFileItem;
01702 }
01703 
01704 KFileItem* KDirLister::findByURL( const KURL& _url ) const
01705 {
01706   return s_pCache->findByURL( this, _url );
01707 }
01708 
01709 KFileItem* KDirLister::findByName( const QString& _name ) const
01710 {
01711   return s_pCache->findByName( this, _name );
01712 }
01713 
01714 #ifndef KDE_NO_COMPAT
01715 KFileItem* KDirLister::find( const KURL& _url ) const
01716 {
01717   return findByURL( _url );
01718 }
01719 #endif
01720 
01721 
01722 // ================ public filter methods ================ //
01723 
01724 void KDirLister::setNameFilter( const QString& nameFilter )
01725 {
01726   if ( !(d->changes & NAME_FILTER) )
01727   {
01728     d->oldFilters = d->lstFilters;
01729     d->lstFilters.setAutoDelete( false );
01730   }
01731 
01732   d->lstFilters.clear();
01733   d->lstFilters.setAutoDelete( true );
01734 
01735   d->nameFilter = nameFilter;
01736 
01737   // Split on white space
01738   QStringList list = QStringList::split( ' ', nameFilter );
01739   for ( QStringList::Iterator it = list.begin(); it != list.end(); ++it )
01740     d->lstFilters.append( new QRegExp(*it, false, true ) );
01741 
01742   d->changes |= NAME_FILTER;
01743 }
01744 
01745 const QString& KDirLister::nameFilter() const
01746 {
01747   return d->nameFilter;
01748 }
01749 
01750 void KDirLister::setMimeFilter( const QStringList& mimeFilter )
01751 {
01752   if ( !(d->changes & MIME_FILTER) )
01753     d->oldMimeFilter = d->mimeFilter;
01754 
01755   d->mimeFilter = mimeFilter;
01756   d->changes |= MIME_FILTER;
01757 }
01758 
01759 void KDirLister::setMimeExcludeFilter( const QStringList& mimeExcludeFilter )
01760 {
01761   if ( !(d->changes & MIME_FILTER) )
01762     d->oldMimeExcludeFilter = d->mimeExcludeFilter;
01763 
01764   d->mimeExcludeFilter = mimeExcludeFilter;
01765   d->changes |= MIME_FILTER;
01766 }
01767 
01768 
01769 void KDirLister::clearMimeFilter()
01770 {
01771   if ( !(d->changes & MIME_FILTER) )
01772   {
01773        d->oldMimeFilter = d->mimeFilter;
01774        d->oldMimeExcludeFilter = d->mimeExcludeFilter;
01775   }
01776   d->mimeFilter.clear();
01777   d->mimeExcludeFilter.clear();
01778   d->changes |= MIME_FILTER;
01779 }
01780 
01781 const QStringList& KDirLister::mimeFilters() const
01782 {
01783   return d->mimeFilter;
01784 }
01785 
01786 bool KDirLister::matchesFilter( const QString& name ) const
01787 {
01788   return doNameFilter( name, d->lstFilters );
01789 }
01790 
01791 bool KDirLister::matchesMimeFilter( const QString& mime ) const
01792 {
01793   return doMimeFilter( mime, d->mimeFilter ) && doMimeExcludeFilter(mime,d->mimeExcludeFilter);
01794 }
01795 
01796 // ================ protected methods ================ //
01797 
01798 bool KDirLister::matchesFilter( const KFileItem *item ) const
01799 {
01800   Q_ASSERT( item );
01801   static const QString& dotdot = KGlobal::staticQString("..");
01802 
01803   if ( item->text() == dotdot )
01804     return false;
01805 
01806   if ( !d->isShowingDotFiles && item->text()[0] == '.' )
01807     return false;
01808 
01809   if ( item->isDir() || d->lstFilters.isEmpty() )
01810     return true;
01811 
01812   return matchesFilter( item->text() );
01813 }
01814 
01815 bool KDirLister::matchesMimeFilter( const KFileItem *item ) const
01816 {
01817   Q_ASSERT( item );
01818   return matchesMimeFilter( item->mimetype() );
01819 }
01820 
01821 bool KDirLister::doNameFilter( const QString& name, const QPtrList<QRegExp>& filters ) const
01822 {
01823   for ( QPtrListIterator<QRegExp> it( filters ); it.current(); ++it )
01824     if ( it.current()->exactMatch( name ) )
01825       return true;
01826 
01827   return false;
01828 }
01829 
01830 bool KDirLister::doMimeFilter( const QString& mime, const QStringList& filters ) const
01831 {
01832   if ( filters.isEmpty() )
01833     return true;
01834 
01835   QStringList::ConstIterator it = filters.begin();
01836   for ( ; it != filters.end(); ++it )
01837     if ( (*it) == mime )
01838       return true;
01839 
01840   return false;
01841 }
01842 
01843 bool KDirLister::doMimeExcludeFilter( const QString& mime, const QStringList& filters ) const
01844 {
01845   if ( filters.isEmpty() )
01846     return true;
01847 
01848   QStringList::ConstIterator it = filters.begin();
01849   for ( ; it != filters.end(); ++it )
01850     if ( (*it) == mime )
01851       return false;
01852 
01853   return true;
01854 }
01855 
01856 
01857 bool KDirLister::validURL( const KURL& _url ) const
01858 {
01859   if ( _url.isMalformed() )
01860   {
01861     if ( d->autoErrorHandling )
01862     {
01863       QString tmp = i18n("Malformed URL\n%1").arg( _url.prettyURL() );
01864       KMessageBox::error( d->errorParent, tmp );
01865     }
01866     return false;
01867   }
01868 
01869   // TODO: verify that this is really a directory?
01870 
01871   return true;
01872 }
01873 
01874 void KDirLister::handleError( KIO::Job *job )
01875 {
01876   if ( d->autoErrorHandling )
01877     job->showErrorDialog( d->errorParent );
01878 }
01879 
01880 
01881 // ================= private methods ================= //
01882 
01883 void KDirLister::addNewItem( const KFileItem *item )
01884 {
01885   bool isNameFilterMatch = (d->dirOnlyMode && !item->isDir()) || !matchesFilter( item );
01886   if (isNameFilterMatch)
01887      return; // No reason to continue... bailing out here prevents a mimetype scan.
01888      
01889   bool isMimeFilterMatch = !matchesMimeFilter( item );
01890 
01891   if ( !isNameFilterMatch && !isMimeFilterMatch )
01892   {
01893     if ( !d->lstNewItems )
01894       d->lstNewItems = new KFileItemList;
01895 
01896     d->lstNewItems->append( item );            // items not filtered
01897   }
01898   else if ( !isNameFilterMatch )
01899   {
01900     if ( !d->lstMimeFilteredItems )
01901       d->lstMimeFilteredItems = new KFileItemList;
01902 
01903     d->lstMimeFilteredItems->append( item );   // only filtered by mime
01904   }
01905 }
01906 
01907 void KDirLister::addNewItems( const KFileItemList& items )
01908 {
01909   // TODO: make this faster - test if we have a filter at all first
01910   for ( KFileItemListIterator kit( items ); kit.current(); ++kit )
01911     addNewItem( *kit );
01912 }
01913 
01914 void KDirLister::addRefreshItem( const KFileItem *item )
01915 {
01916   bool isNameFilterMatch = (d->dirOnlyMode && !item->isDir()) || !matchesFilter( item );
01917   bool isMimeFilterMatch = !matchesMimeFilter( item );
01918 
01919   if ( !isNameFilterMatch && !isMimeFilterMatch )
01920   {
01921     if ( !d->lstRefreshItems )
01922       d->lstRefreshItems = new KFileItemList;
01923 
01924     d->lstRefreshItems->append( item );
01925   }
01926 }
01927 
01928 void KDirLister::emitItems()
01929 {
01930   KFileItemList *tmpNew = d->lstNewItems;
01931   d->lstNewItems = 0;
01932 
01933   KFileItemList *tmpMime = d->lstMimeFilteredItems;
01934   d->lstMimeFilteredItems = 0;
01935 
01936   KFileItemList *tmpRefresh = d->lstRefreshItems;
01937   d->lstRefreshItems = 0;
01938 
01939   if ( tmpNew )
01940   {
01941     emit newItems( *tmpNew );
01942     delete tmpNew;
01943   }
01944 
01945   if ( tmpMime )
01946   {
01947     emit itemsFilteredByMime( *tmpMime );
01948     delete tmpMime;
01949   }
01950 
01951   if ( tmpRefresh )
01952   {
01953     emit refreshItems( *tmpRefresh );
01954     delete tmpRefresh;
01955   }
01956 }
01957 
01958 void KDirLister::emitDeleteItem( KFileItem *item )
01959 {
01960   bool isNameFilterMatch = (d->dirOnlyMode && !item->isDir()) || !matchesFilter( item );
01961   bool isMimeFilterMatch = !matchesMimeFilter( item );
01962 
01963   if ( !isNameFilterMatch && !isMimeFilterMatch )
01964     emit deleteItem( item );
01965 }
01966 
01967 
01968 // ================ private slots ================ //
01969 
01970 void KDirLister::slotInfoMessage( KIO::Job *, const QString& message )
01971 {
01972   emit infoMessage( message );
01973 }
01974 
01975 void KDirLister::slotPercent( KIO::Job *job, unsigned long pcnt )
01976 {
01977   d->jobData[static_cast<KIO::ListJob*>(job)].percent = pcnt;
01978 
01979   int result = 0;
01980 
01981   KIO::filesize_t size = 0;
01982 
01983   QMap< KIO::ListJob *, KDirListerPrivate::JobData >::Iterator dataIt = d->jobData.begin();
01984   while ( dataIt != d->jobData.end() )
01985   {
01986     result += (*dataIt).percent * (*dataIt).totalSize;
01987     size += (*dataIt).totalSize;
01988     ++dataIt;
01989   }
01990 
01991   if ( size != 0 )
01992     result /= size;
01993   else
01994     result = 100;
01995   emit percent( result );
01996 }
01997 
01998 void KDirLister::slotTotalSize( KIO::Job *job, KIO::filesize_t size )
01999 {
02000   d->jobData[static_cast<KIO::ListJob*>(job)].totalSize = size;
02001 
02002   KIO::filesize_t result = 0;
02003   QMap< KIO::ListJob *, KDirListerPrivate::JobData >::Iterator dataIt = d->jobData.begin();
02004   while ( dataIt != d->jobData.end() )
02005   {
02006     result += (*dataIt).totalSize;
02007     ++dataIt;
02008   }
02009 
02010   emit totalSize( result );
02011 }
02012 
02013 void KDirLister::slotProcessedSize( KIO::Job *job, KIO::filesize_t size )
02014 {
02015   d->jobData[static_cast<KIO::ListJob*>(job)].processedSize = size;
02016 
02017   KIO::filesize_t result = 0;
02018   QMap< KIO::ListJob *, KDirListerPrivate::JobData >::Iterator dataIt = d->jobData.begin();
02019   while ( dataIt != d->jobData.end() )
02020   {
02021     result += (*dataIt).processedSize;
02022     ++dataIt;
02023   }
02024 
02025   emit processedSize( result );
02026 }
02027 
02028 void KDirLister::slotSpeed( KIO::Job *job, unsigned long spd )
02029 {
02030   d->jobData[static_cast<KIO::ListJob*>(job)].speed = spd;
02031 
02032   int result = 0;
02033   QMap< KIO::ListJob *, KDirListerPrivate::JobData >::Iterator dataIt = d->jobData.begin();
02034   while ( dataIt != d->jobData.end() )
02035   {
02036     result += (*dataIt).speed;
02037     ++dataIt;
02038   }
02039 
02040   emit speed( result );
02041 }
02042 
02043 void KDirLister::slotJobToBeKilled( const KURL& url )
02044 {
02045   KIO::ListJob *job;
02046   QMap< KIO::ListJob *, KDirListerPrivate::JobData >::Iterator dataIt = d->jobData.begin();
02047   while ( dataIt != d->jobData.end() )
02048   {
02049     job = dataIt.key();
02050     if ( job->url().cmp(url, true) )
02051     {
02052       d->jobData.remove( dataIt );
02053       return;
02054     }
02055     ++dataIt;
02056   }
02057 }
02058 
02059 void KDirLister::slotClearState()
02060 {
02061   d->jobData.clear();
02062 }
02063 
02064 void KDirLister::setMainWindow(QWidget *window)
02065 {
02066   d->window = window;
02067 }
02068 
02069 QWidget *KDirLister::mainWindow()
02070 {
02071   return d->window;
02072 }
02073 
02074 KFileItemList KDirLister::items( WhichItems which ) const
02075 {
02076     return itemsForDir( url(), which );
02077 }
02078 
02079 KFileItemList KDirLister::itemsForDir( const KURL &dir, WhichItems which) const
02080 {
02081     KFileItemList result;
02082     KFileItemList *allItems = s_pCache->itemsForDir( dir );
02083 
02084     if ( which == AllItems )
02085         result = *allItems; // shallow copy
02086         
02087     else // only items passing the filters
02088     {
02089         for ( KFileItemListIterator kit( *allItems ); kit.current(); ++kit )
02090         {
02091             KFileItem *item = *kit;
02092             bool isNameFilterMatch = (d->dirOnlyMode && !item->isDir()) ||
02093                                      !matchesFilter( item );
02094             bool isMimeFilterMatch = !matchesMimeFilter( item );
02095 
02096             if ( !isNameFilterMatch && !isMimeFilterMatch )
02097                 result.append( item );
02098         }
02099     }
02100 
02101     return result;
02102 }
02103 
02104 // to keep BC changes
02105 
02106 void KDirLister::virtual_hook( int, void* )
02107 { /*BASE::virtual_hook( id, data );*/ }
02108 
02109 #include "kdirlister.moc"
02110 #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 Wed Oct 8 12:21:28 2003 by doxygen 1.2.18 written by Dimitri van Heesch, © 1997-2001