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