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