| # kio Library API Documentation
Overview | Class Hierarchy | Classes | Classes (annotated) | Members | Source Files

# 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"

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