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 #include <kprotocolinfo.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
00046
00047
00048
00049 #ifdef NDEBUG
00050 #undef DEBUG_CACHE
00051 #endif
00052
00053 KDirListerCache::KDirListerCache( int maxCount )
00054 : itemsCached( maxCount )
00055 {
00056 kdDebug(7004) << "+KDirListerCache" << endl;
00057
00058 itemsInUse.setAutoDelete( false );
00059 itemsCached.setAutoDelete( true );
00060 urlsCurrentlyListed.setAutoDelete( true );
00061 urlsCurrentlyHeld.setAutoDelete( true );
00062 pendingUpdates.setAutoDelete( true );
00063
00064 connect( kdirwatch, SIGNAL( dirty( const QString& ) ),
00065 this, SLOT( slotFileDirty( const QString& ) ) );
00066 connect( kdirwatch, SIGNAL( created( const QString& ) ),
00067 this, SLOT( slotFileCreated( const QString& ) ) );
00068 connect( kdirwatch, SIGNAL( deleted( const QString& ) ),
00069 this, SLOT( slotFileDeleted( const QString& ) ) );
00070 }
00071
00072 KDirListerCache::~KDirListerCache()
00073 {
00074 kdDebug(7004) << "-KDirListerCache" << endl;
00075
00076 itemsInUse.setAutoDelete( true );
00077 itemsInUse.clear();
00078 itemsCached.clear();
00079 urlsCurrentlyListed.clear();
00080 urlsCurrentlyHeld.clear();
00081
00082 if ( KDirWatch::exists() )
00083 kdirwatch->disconnect( this );
00084 }
00085
00086
00087
00088 bool KDirListerCache::listDir( KDirLister *lister, const KURL& _u,
00089 bool _keep, bool _reload )
00090 {
00091
00092 KURL _url = _u;
00093 _url.cleanPath();
00094 _url.adjustPath(-1);
00095 QString urlStr = _url.url();
00096
00097 if ( !lister->validURL( _url ) )
00098 return false;
00099
00100 #ifdef DEBUG_CACHE
00101 printDebug();
00102 #endif
00103 kdDebug(7004) << k_funcinfo << lister << " url=" << _url
00104 << " keep=" << _keep << " reload=" << _reload << endl;
00105
00106 if ( !_keep )
00107 {
00108
00109 stop( lister );
00110
00111
00112 forgetDirs( lister );
00113
00114 lister->d->rootFileItem = 0;
00115 }
00116 else if ( lister->d->lstDirs.find( _url ) != lister->d->lstDirs.end() )
00117 {
00118
00119 stop( lister, _url );
00120
00121
00122 forgetDirs( lister, _url, true );
00123
00124 if ( lister->d->url == _url )
00125 lister->d->rootFileItem = 0;
00126 }
00127
00128 lister->d->lstDirs.append( _url );
00129
00130 if ( lister->d->url.isEmpty() || !_keep )
00131 lister->d->url = _url;
00132
00133 DirItem *itemU = itemsInUse[urlStr];
00134 DirItem *itemC;
00135
00136 if ( !urlsCurrentlyListed[urlStr] )
00137 {
00138
00139
00140
00141 if ( itemU )
00142 {
00143 kdDebug(7004) << "listDir: Entry already in use: " << _url << endl;
00144
00145 bool oldState = lister->d->complete;
00146 lister->d->complete = false;
00147
00148 emit lister->started( _url );
00149
00150 if ( !lister->d->rootFileItem && lister->d->url == _url )
00151 lister->d->rootFileItem = itemU->rootItem;
00152
00153 lister->addNewItems( *(itemU->lstItems) );
00154 lister->emitItems();
00155
00156
00157 assert( urlsCurrentlyHeld[urlStr] );
00158 urlsCurrentlyHeld[urlStr]->append( lister );
00159
00160 lister->d->complete = oldState;
00161
00162 emit lister->completed( _url );
00163 if ( lister->d->complete )
00164 emit lister->completed();
00165
00166 if ( _reload || !itemU->complete )
00167 updateDirectory( _url );
00168 }
00169 else if ( !_reload && (itemC = itemsCached.take( urlStr )) )
00170 {
00171 kdDebug(7004) << "listDir: Entry in cache: " << _url << endl;
00172
00173 itemC->decAutoUpdate();
00174 itemsInUse.insert( urlStr, itemC );
00175 itemU = itemC;
00176
00177 bool oldState = lister->d->complete;
00178 lister->d->complete = false;
00179
00180 emit lister->started( _url );
00181
00182 if ( !lister->d->rootFileItem && lister->d->url == _url )
00183 lister->d->rootFileItem = itemC->rootItem;
00184
00185 lister->addNewItems( *(itemC->lstItems) );
00186 lister->emitItems();
00187
00188 Q_ASSERT( !urlsCurrentlyHeld[urlStr] );
00189 QPtrList<KDirLister> *list = new QPtrList<KDirLister>;
00190 list->append( lister );
00191 urlsCurrentlyHeld.insert( urlStr, list );
00192
00193 lister->d->complete = oldState;
00194
00195 emit lister->completed( _url );
00196 if ( lister->d->complete )
00197 emit lister->completed();
00198
00199 if ( !itemC->complete )
00200 updateDirectory( _url );
00201 }
00202 else
00203 {
00204 kdDebug(7004) << "listDir: Entry not in cache or reloaded: " << _url << endl;
00205
00206 QPtrList<KDirLister> *list = new QPtrList<KDirLister>;
00207 list->append( lister );
00208 urlsCurrentlyListed.insert( urlStr, list );
00209
00210 itemsCached.remove( urlStr );
00211 itemU = new DirItem( _url );
00212 itemsInUse.insert( urlStr, itemU );
00213
00214
00215
00216
00217
00218
00219
00220
00221
00222 if ( lister->d->url == _url )
00223 lister->d->rootFileItem = 0;
00224
00225 KIO::ListJob* job = KIO::listDir( _url, false );
00226 jobs.insert( job, QValueList<KIO::UDSEntry>() );
00227
00228 lister->jobStarted( job );
00229 lister->connectJob( job );
00230
00231 if ( lister->d->window )
00232 job->setWindow( lister->d->window );
00233
00234 connect( job, SIGNAL( entries( KIO::Job *, const KIO::UDSEntryList & ) ),
00235 this, SLOT( slotEntries( KIO::Job *, const KIO::UDSEntryList & ) ) );
00236 connect( job, SIGNAL( result( KIO::Job * ) ),
00237 this, SLOT( slotResult( KIO::Job * ) ) );
00238 connect( job, SIGNAL( redirection( KIO::Job *, const KURL & ) ),
00239 this, SLOT( slotRedirection( KIO::Job *, const KURL & ) ) );
00240
00241 emit lister->started( _url );
00242
00243
00244 }
00245 }
00246 else
00247 {
00248 kdDebug(7004) << "listDir: Entry currently being listed: " << _url << endl;
00249
00250 emit lister->started( _url );
00251
00252 urlsCurrentlyListed[urlStr]->append( lister );
00253
00254 KIO::ListJob *job = jobForUrl( urlStr );
00255 Q_ASSERT( job );
00256
00257 lister->jobStarted( job );
00258 lister->connectJob( job );
00259
00260 Q_ASSERT( itemU );
00261
00262 if ( !lister->d->rootFileItem && lister->d->url == _url )
00263 lister->d->rootFileItem = itemU->rootItem;
00264
00265 lister->addNewItems( *(itemU->lstItems) );
00266 lister->emitItems();
00267 }
00268
00269
00270 if ( lister->d->autoUpdate )
00271 itemU->incAutoUpdate();
00272
00273 return true;
00274 }
00275
00276 bool KDirListerCache::validURL( const KDirLister *lister, const KURL& url ) const
00277 {
00278 if ( !url.isValid() )
00279 {
00280 if ( lister->d->autoErrorHandling )
00281 {
00282 QString tmp = i18n("Malformed URL\n%1").arg( url.prettyURL() );
00283 KMessageBox::error( lister->d->errorParent, tmp );
00284 }
00285 return false;
00286 }
00287
00288 if ( !KProtocolInfo::supportsListing( url ) )
00289 {
00290 if ( lister->d->autoErrorHandling )
00291 {
00292
00293 QString tmp = i18n("Malformed URL\n%1").arg( url.prettyURL() );
00294 KMessageBox::error( lister->d->errorParent, tmp );
00295 }
00296 return false;
00297 }
00298
00299 return true;
00300 }
00301
00302 void KDirListerCache::stop( KDirLister *lister )
00303 {
00304 #ifdef DEBUG_CACHE
00305 printDebug();
00306 #endif
00307 kdDebug(7004) << k_funcinfo << "lister: " << lister << endl;
00308 bool stopped = false;
00309
00310 QDictIterator< QPtrList<KDirLister> > it( urlsCurrentlyListed );
00311 QPtrList<KDirLister> *listers;
00312 while ( (listers = it.current()) )
00313 {
00314 if ( listers->findRef( lister ) > -1 )
00315 {
00316
00317 QString url = it.currentKey();
00318
00319
00320 bool ret = listers->removeRef( lister );
00321 Q_ASSERT( ret );
00322
00323 KIO::ListJob *job = jobForUrl( url );
00324 if ( job )
00325 lister->jobDone( job );
00326
00327
00328 QPtrList<KDirLister> *holders = urlsCurrentlyHeld[url];
00329 if ( !holders )
00330 {
00331 holders = new QPtrList<KDirLister>;
00332 urlsCurrentlyHeld.insert( url, holders );
00333 }
00334
00335 holders->append( lister );
00336
00337 emit lister->canceled( KURL( url ) );
00338
00339
00340
00341 if ( listers->isEmpty() )
00342 {
00343
00344 if ( job )
00345 killJob( job );
00346
00347 urlsCurrentlyListed.remove( url );
00348 }
00349
00350 stopped = true;
00351 }
00352 else
00353 ++it;
00354 }
00355
00356 if ( stopped )
00357 {
00358 emit lister->canceled();
00359 lister->d->complete = true;
00360 }
00361
00362
00363
00364 }
00365
00366 void KDirListerCache::stop( KDirLister *lister, const KURL& _u )
00367 {
00368 QString urlStr( _u.url(-1) );
00369 KURL _url( urlStr );
00370
00371
00372 kdDebug(7004) << k_funcinfo << lister << " url=" << _url << endl;
00373
00374 QPtrList<KDirLister> *listers = urlsCurrentlyListed[urlStr];
00375 if ( !listers || !listers->removeRef( lister ) )
00376 return;
00377
00378
00379 QPtrList<KDirLister> *holders = urlsCurrentlyHeld[urlStr];
00380 if ( !holders )
00381 {
00382 holders = new QPtrList<KDirLister>;
00383 urlsCurrentlyHeld.insert( urlStr, holders );
00384 }
00385
00386 holders->append( lister );
00387
00388
00389 KIO::ListJob *job = jobForUrl( urlStr );
00390 if ( job )
00391 lister->jobDone( job );
00392
00393 emit lister->canceled( _url );
00394
00395 if ( listers->isEmpty() )
00396 {
00397
00398 if ( job )
00399 killJob( job );
00400
00401 urlsCurrentlyListed.remove( urlStr );
00402 }
00403
00404 if ( lister->numJobs() == 0 )
00405 {
00406 lister->d->complete = true;
00407
00408
00409 emit lister->canceled();
00410 }
00411 }
00412
00413 void KDirListerCache::setAutoUpdate( KDirLister *lister, bool enable )
00414 {
00415
00416
00417 for ( KURL::List::Iterator it = lister->d->lstDirs.begin();
00418 it != lister->d->lstDirs.end(); ++it )
00419 {
00420 if ( enable )
00421 itemsInUse[(*it).url()]->incAutoUpdate();
00422 else
00423 itemsInUse[(*it).url()]->decAutoUpdate();
00424 }
00425 }
00426
00427 void KDirListerCache::forgetDirs( KDirLister *lister )
00428 {
00429 kdDebug(7004) << k_funcinfo << lister << endl;
00430
00431 emit lister->clear();
00432
00433
00434 KURL::List lstDirsCopy = lister->d->lstDirs;
00435 for ( KURL::List::Iterator it = lstDirsCopy.begin();
00436 it != lstDirsCopy.end(); ++it )
00437 {
00438 forgetDirs( lister, *it, false );
00439 }
00440 }
00441
00442 void KDirListerCache::forgetDirs( KDirLister *lister, const KURL& _url, bool notify )
00443 {
00444 kdDebug(7004) << k_funcinfo << lister << " _url: " << _url << endl;
00445
00446 KURL url( _url );
00447 url.adjustPath( -1 );
00448 QString urlStr = url.url();
00449 QPtrList<KDirLister> *holders = urlsCurrentlyHeld[urlStr];
00450 Q_ASSERT( holders );
00451 holders->removeRef( lister );
00452
00453
00454
00455
00456
00457 lister->d->lstDirs.remove( lister->d->lstDirs.find( url ) );
00458
00459 DirItem *item = itemsInUse[urlStr];
00460 Q_ASSERT( item );
00461
00462 if ( holders->isEmpty() )
00463 {
00464 urlsCurrentlyHeld.remove( urlStr );
00465 if ( !urlsCurrentlyListed[urlStr] )
00466 {
00467
00468 itemsInUse.remove( urlStr );
00469
00470
00471 KIO::ListJob *job = jobForUrl( urlStr );
00472 if ( job )
00473 {
00474 lister->jobDone( job );
00475 killJob( job );
00476 kdDebug(7004) << k_funcinfo << "Killing update job for " << urlStr << endl;
00477
00478 emit lister->canceled( url );
00479 if ( lister->numJobs() == 0 )
00480 {
00481 lister->d->complete = true;
00482 emit lister->canceled();
00483 }
00484 }
00485
00486 if ( notify )
00487 emit lister->clear( url );
00488
00489 if ( item->complete )
00490 {
00491 kdDebug(7004) << k_funcinfo << lister << " item moved into cache: " << url << endl;
00492 itemsCached.insert( urlStr, item );
00493
00494
00495
00496
00497 const bool isLocal = item->url.isLocalFile();
00498 const bool isManuallyMounted = isLocal && KIO::manually_mounted( item->url.path() );
00499 bool containsManuallyMounted = false;
00500 if ( !isManuallyMounted && item->lstItems && isLocal )
00501 {
00502
00503
00504
00505
00506 KFileItemListIterator kit( *item->lstItems );
00507 for ( ; kit.current() && !containsManuallyMounted; ++kit )
00508 if ( (*kit)->isDir() && KIO::manually_mounted( (*kit)->url().path() ) )
00509 containsManuallyMounted = true;
00510 }
00511
00512 if ( isManuallyMounted || containsManuallyMounted )
00513 {
00514 kdDebug(7004) << "Not adding a watch on " << item->url << " because it " <<
00515 ( isManuallyMounted ? "is manually mounted" : "contains a manually mounted subdir" ) << endl;
00516 item->complete = false;
00517 }
00518 else
00519 item->incAutoUpdate();
00520 }
00521 else
00522 {
00523 delete item;
00524 item = 0;
00525 }
00526 }
00527 }
00528
00529 if ( item && lister->d->autoUpdate )
00530 item->decAutoUpdate();
00531 }
00532
00533 void KDirListerCache::updateDirectory( const KURL& _dir )
00534 {
00535 kdDebug(7004) << k_funcinfo << _dir << endl;
00536
00537 QString urlStr = _dir.url(-1);
00538 if ( !checkUpdate( urlStr ) )
00539 return;
00540
00541
00542
00543
00544
00545
00546
00547 QPtrList<KDirLister> *listers = urlsCurrentlyListed[urlStr];
00548 QPtrList<KDirLister> *holders = urlsCurrentlyHeld[urlStr];
00549
00550
00551 bool killed = false;
00552 QWidget *window = 0;
00553 KIO::ListJob *job = jobForUrl( urlStr );
00554 if ( job )
00555 {
00556 window = job->window();
00557
00558 killJob( job );
00559 killed = true;
00560
00561 if ( listers )
00562 for ( KDirLister *kdl = listers->first(); kdl; kdl = listers->next() )
00563 kdl->jobDone( job );
00564
00565 if ( holders )
00566 for ( KDirLister *kdl = holders->first(); kdl; kdl = holders->next() )
00567 kdl->jobDone( job );
00568 }
00569 kdDebug(7004) << k_funcinfo << "Killed = " << killed << endl;
00570
00571
00572
00573
00574 Q_ASSERT( !listers || (listers && killed) );
00575
00576 job = KIO::listDir( _dir, false );
00577 jobs.insert( job, QValueList<KIO::UDSEntry>() );
00578
00579 connect( job, SIGNAL(entries( KIO::Job *, const KIO::UDSEntryList & )),
00580 this, SLOT(slotUpdateEntries( KIO::Job *, const KIO::UDSEntryList & )) );
00581 connect( job, SIGNAL(result( KIO::Job * )),
00582 this, SLOT(slotUpdateResult( KIO::Job * )) );
00583
00584 kdDebug(7004) << k_funcinfo << "update started in " << _dir << endl;
00585
00586 if ( listers )
00587 for ( KDirLister *kdl = listers->first(); kdl; kdl = listers->next() )
00588 kdl->jobStarted( job );
00589
00590 if ( holders )
00591 {
00592 if ( !killed )
00593 {
00594 bool first = true;
00595 for ( KDirLister *kdl = holders->first(); kdl; kdl = holders->next() )
00596 {
00597 kdl->jobStarted( job );
00598 if ( first && kdl->d->window )
00599 {
00600 first = false;
00601 job->setWindow( kdl->d->window );
00602 }
00603 emit kdl->started( _dir );
00604 }
00605 }
00606 else
00607 {
00608 job->setWindow( window );
00609
00610 for ( KDirLister *kdl = holders->first(); kdl; kdl = holders->next() )
00611 kdl->jobStarted( job );
00612 }
00613 }
00614 }
00615
00616 bool KDirListerCache::checkUpdate( const QString& _dir )
00617 {
00618 if ( !itemsInUse[_dir] )
00619 {
00620 DirItem *item = itemsCached[_dir];
00621 if ( item && item->complete )
00622 {
00623 item->complete = false;
00624 item->decAutoUpdate();
00625
00626
00627 }
00628
00629
00630
00631 return false;
00632 }
00633 else
00634 return true;
00635 }
00636
00637 KFileItemList *KDirListerCache::itemsForDir( const KURL &_dir ) const
00638 {
00639 QString urlStr = _dir.url(-1);
00640 DirItem *item = itemsInUse[ urlStr ];
00641 if ( !item )
00642 item = itemsCached[ urlStr ];
00643 return item ? item->lstItems : 0;
00644 }
00645
00646 KFileItem *KDirListerCache::findByName( const KDirLister *lister, const QString& _name ) const
00647 {
00648 Q_ASSERT( lister );
00649
00650 for ( KURL::List::Iterator it = lister->d->lstDirs.begin();
00651 it != lister->d->lstDirs.end(); ++it )
00652 {
00653 KFileItemListIterator kit( *itemsInUse[(*it).url()]->lstItems );
00654 for ( ; kit.current(); ++kit )
00655 if ( (*kit)->name() == _name )
00656 return (*kit);
00657 }
00658
00659 return 0L;
00660 }
00661
00662 KFileItem *KDirListerCache::findByURL( const KDirLister *lister, const KURL& _u ) const
00663 {
00664 KURL _url = _u;
00665 _url.adjustPath(-1);
00666
00667 KURL parentDir( _url );
00668 parentDir.setPath( parentDir.directory() );
00669
00670
00671 if ( lister && !lister->d->lstDirs.contains( parentDir ) )
00672 return 0L;
00673
00674 KFileItemList *itemList = itemsForDir( parentDir );
00675 if ( itemList )
00676 {
00677 KFileItemListIterator kit( *itemList );
00678 for ( ; kit.current(); ++kit )
00679 if ( (*kit)->url() == _url )
00680 return (*kit);
00681 }
00682 return 0L;
00683 }
00684
00685 void KDirListerCache::FilesAdded( const KURL &dir )
00686 {
00687 kdDebug(7004) << k_funcinfo << dir << endl;
00688 updateDirectory( dir );
00689 }
00690
00691 void KDirListerCache::FilesRemoved( const KURL::List &fileList )
00692 {
00693 kdDebug(7004) << k_funcinfo << endl;
00694 KURL::List::ConstIterator it = fileList.begin();
00695 for ( ; it != fileList.end() ; ++it )
00696 {
00697
00698 KFileItem *fileitem = 0L;
00699 KURL parentDir( *it );
00700 parentDir.setPath( parentDir.directory() );
00701 KFileItemList *lstItems = itemsForDir( parentDir );
00702 if ( lstItems )
00703 {
00704 KFileItem *fit = lstItems->first();
00705 for ( ; fit; fit = lstItems->next() )
00706 if ( fit->url() == *it ) {
00707 fileitem = fit;
00708 lstItems->take();
00709 break;
00710 }
00711 }
00712
00713
00714
00715 if ( fileitem )
00716 {
00717 QPtrList<KDirLister> *listers = urlsCurrentlyHeld[parentDir.url()];
00718 if ( listers )
00719 for ( KDirLister *kdl = listers->first(); kdl; kdl = listers->next() )
00720 kdl->emitDeleteItem( fileitem );
00721 }
00722
00723
00724 if ( !fileitem || fileitem->isDir() )
00725 {
00726
00727
00728 deleteDir( *it );
00729 }
00730
00731
00732 delete fileitem;
00733 }
00734 }
00735
00736 void KDirListerCache::FilesChanged( const KURL::List &fileList )
00737 {
00738 KURL::List dirsToUpdate;
00739 kdDebug(7004) << k_funcinfo << "only half implemented" << endl;
00740 KURL::List::ConstIterator it = fileList.begin();
00741 for ( ; it != fileList.end() ; ++it )
00742 {
00743 if ( ( *it ).isLocalFile() )
00744 {
00745 kdDebug(7004) << "KDirListerCache::FilesChanged " << *it << endl;
00746 KFileItem *fileitem = findByURL( 0, *it );
00747 if ( fileitem )
00748 {
00749
00750 aboutToRefreshItem( fileitem );
00751 fileitem->refresh();
00752 emitRefreshItem( fileitem );
00753 }
00754 else
00755 kdDebug(7004) << "item not found" << endl;
00756 } else {
00757
00758
00759 KURL dir( *it );
00760 dir.setPath( dir.directory( true ) );
00761 if ( dirsToUpdate.find( dir ) == dirsToUpdate.end() )
00762 dirsToUpdate.prepend( dir );
00763 }
00764 }
00765
00766 KURL::List::ConstIterator itdir = dirsToUpdate.begin();
00767 for ( ; itdir != dirsToUpdate.end() ; ++itdir )
00768 updateDirectory( *itdir );
00769
00770
00771 }
00772
00773 void KDirListerCache::FileRenamed( const KURL &src, const KURL &dst )
00774 {
00775 kdDebug(7004) << k_funcinfo << src.prettyURL() << " -> " << dst.prettyURL() << endl;
00776 #ifdef DEBUG_CACHE
00777 printDebug();
00778 #endif
00779
00780
00781
00782 renameDir( src, dst );
00783
00784
00785 KURL oldurl( src );
00786 oldurl.adjustPath( -1 );
00787 KFileItem *fileitem = findByURL( 0, oldurl );
00788 if ( fileitem )
00789 {
00790 if ( !fileitem->isLocalFile() && !fileitem->localPath().isEmpty() )
00791 FilesChanged( src );
00792 else
00793 {
00794 aboutToRefreshItem( fileitem );
00795 fileitem->setURL( dst );
00796 fileitem->refreshMimeType();
00797 emitRefreshItem( fileitem );
00798 }
00799 }
00800 #ifdef DEBUG_CACHE
00801 printDebug();
00802 #endif
00803 }
00804
00805 void KDirListerCache::aboutToRefreshItem( KFileItem *fileitem )
00806 {
00807
00808 KURL parentDir( fileitem->url() );
00809 parentDir.setPath( parentDir.directory() );
00810 QString parentDirURL = parentDir.url();
00811 QPtrList<KDirLister> *listers = urlsCurrentlyHeld[parentDirURL];
00812 if ( listers )
00813 for ( KDirLister *kdl = listers->first(); kdl; kdl = listers->next() )
00814 kdl->aboutToRefreshItem( fileitem );
00815
00816
00817 listers = urlsCurrentlyListed[parentDirURL];
00818 if ( listers )
00819 for ( KDirLister *kdl = listers->first(); kdl; kdl = listers->next() )
00820 kdl->aboutToRefreshItem( fileitem );
00821 }
00822
00823 void KDirListerCache::emitRefreshItem( KFileItem *fileitem )
00824 {
00825
00826 KURL parentDir( fileitem->url() );
00827 parentDir.setPath( parentDir.directory() );
00828 QString parentDirURL = parentDir.url();
00829 QPtrList<KDirLister> *listers = urlsCurrentlyHeld[parentDirURL];
00830 if ( listers )
00831 for ( KDirLister *kdl = listers->first(); kdl; kdl = listers->next() )
00832 {
00833 kdl->addRefreshItem( fileitem );
00834 kdl->emitItems();
00835 }
00836
00837
00838 listers = urlsCurrentlyListed[parentDirURL];
00839 if ( listers )
00840 for ( KDirLister *kdl = listers->first(); kdl; kdl = listers->next() )
00841 {
00842 kdl->addRefreshItem( fileitem );
00843 kdl->emitItems();
00844 }
00845 }
00846
00847 KDirListerCache* KDirListerCache::self()
00848 {
00849 if ( !s_pSelf )
00850 s_pSelf = sd_KDirListerCache.setObject( s_pSelf, new KDirListerCache );
00851
00852 return s_pSelf;
00853 }
00854
00855 bool KDirListerCache::exists()
00856 {
00857 return s_pSelf != 0;
00858 }
00859
00860
00861
00862
00863
00864 void KDirListerCache::slotFileDirty( const QString& _file )
00865 {
00866 kdDebug(7004) << k_funcinfo << _file << endl;
00867
00868 if ( !pendingUpdates[_file] )
00869 {
00870 KURL dir;
00871 dir.setPath( _file );
00872 if ( checkUpdate( dir.url(-1) ) )
00873 updateDirectory( dir );
00874
00875
00876 dir.setPath( dir.directory() );
00877 if ( checkUpdate( dir.url() ) )
00878 {
00879
00880 QTimer *timer = new QTimer( this, _file.utf8() );
00881 connect( timer, SIGNAL(timeout()), this, SLOT(slotFileDirtyDelayed()) );
00882 pendingUpdates.insert( _file, timer );
00883 timer->start( 500, true );
00884 }
00885 }
00886 }
00887
00888
00889 void KDirListerCache::slotFileDirtyDelayed()
00890 {
00891 QString file = QString::fromUtf8( sender()->name() );
00892
00893 kdDebug(7004) << k_funcinfo << file << endl;
00894
00895
00896
00897 pendingUpdates.remove( file );
00898
00899 KURL u;
00900 u.setPath( file );
00901 KFileItem *item = findByURL( 0, u );
00902 if ( item )
00903 {
00904
00905 aboutToRefreshItem( item );
00906 item->refresh();
00907 emitRefreshItem( item );
00908 }
00909 }
00910
00911 void KDirListerCache::slotFileCreated( const QString& _file )
00912 {
00913 kdDebug(7004) << k_funcinfo << _file << endl;
00914
00915 KURL u;
00916 u.setPath( _file );
00917 u.setPath( u.directory() );
00918 FilesAdded( u );
00919 }
00920
00921 void KDirListerCache::slotFileDeleted( const QString& _file )
00922 {
00923 kdDebug(7004) << k_funcinfo << _file << endl;
00924 KURL u;
00925 u.setPath( _file );
00926 FilesRemoved( u );
00927 }
00928
00929 void KDirListerCache::slotEntries( KIO::Job *job, const KIO::UDSEntryList &entries )
00930 {
00931 KURL url = joburl( static_cast<KIO::ListJob *>(job) );
00932 url.adjustPath(-1);
00933 QString urlStr = url.url();
00934
00935 kdDebug(7004) << k_funcinfo << "new entries for " << url << endl;
00936
00937 DirItem *dir = itemsInUse[urlStr];
00938 Q_ASSERT( dir );
00939
00940 QPtrList<KDirLister> *listers = urlsCurrentlyListed[urlStr];
00941 Q_ASSERT( listers );
00942 Q_ASSERT( !listers->isEmpty() );
00943
00944
00945 bool delayedMimeTypes = true;
00946 for ( KDirLister *kdl = listers->first(); kdl; kdl = listers->next() )
00947 delayedMimeTypes = delayedMimeTypes && kdl->d->delayedMimeTypes;
00948
00949
00950 static const QString& dot = KGlobal::staticQString(".");
00951 static const QString& dotdot = KGlobal::staticQString("..");
00952
00953 KIO::UDSEntryListConstIterator it = entries.begin();
00954 KIO::UDSEntryListConstIterator end = entries.end();
00955
00956 for ( ; it != end; ++it )
00957 {
00958 QString name;
00959
00960
00961 KIO::UDSEntry::ConstIterator entit = (*it).begin();
00962 for( ; entit != (*it).end(); ++entit )
00963 if ( (*entit).m_uds == KIO::UDS_NAME )
00964 {
00965 name = (*entit).m_str;
00966 break;
00967 }
00968
00969 Q_ASSERT( !name.isEmpty() );
00970 if ( name.isEmpty() )
00971 continue;
00972
00973 if ( name == dot )
00974 {
00975 Q_ASSERT( !dir->rootItem );
00976 dir->rootItem = new KFileItem( *it, url, delayedMimeTypes, true );
00977
00978 for ( KDirLister *kdl = listers->first(); kdl; kdl = listers->next() )
00979 if ( !kdl->d->rootFileItem && kdl->d->url == url )
00980 kdl->d->rootFileItem = dir->rootItem;
00981 }
00982 else if ( name != dotdot )
00983 {
00984 KFileItem* item = new KFileItem( *it, url, delayedMimeTypes, true );
00985 Q_ASSERT( item );
00986
00987
00988 dir->lstItems->append( item );
00989
00990 for ( KDirLister *kdl = listers->first(); kdl; kdl = listers->next() )
00991 kdl->addNewItem( item );
00992 }
00993 }
00994
00995 for ( KDirLister *kdl = listers->first(); kdl; kdl = listers->next() )
00996 kdl->emitItems();
00997 }
00998
00999 void KDirListerCache::slotResult( KIO::Job *j )
01000 {
01001 Q_ASSERT( j );
01002 KIO::ListJob *job = static_cast<KIO::ListJob *>( j );
01003 jobs.remove( job );
01004
01005 KURL jobUrl = joburl( job );
01006 jobUrl.adjustPath(-1);
01007 QString jobUrlStr = jobUrl.url();
01008
01009 kdDebug(7004) << k_funcinfo << "finished listing " << jobUrl << endl;
01010 #ifdef DEBUG_CACHE
01011 printDebug();
01012 #endif
01013
01014 QPtrList<KDirLister> *listers = urlsCurrentlyListed.take( jobUrlStr );
01015 Q_ASSERT( listers );
01016
01017
01018
01019
01020 Q_ASSERT( !urlsCurrentlyHeld[jobUrlStr] );
01021 urlsCurrentlyHeld.insert( jobUrlStr, listers );
01022
01023 KDirLister *kdl;
01024
01025 if ( job->error() )
01026 {
01027 for ( kdl = listers->first(); kdl; kdl = listers->next() )
01028 {
01029 kdl->jobDone( job );
01030 kdl->handleError( job );
01031 emit kdl->canceled( jobUrl );
01032 if ( kdl->numJobs() == 0 )
01033 {
01034 kdl->d->complete = true;
01035 emit kdl->canceled();
01036 }
01037 }
01038 }
01039 else
01040 {
01041 DirItem *dir = itemsInUse[jobUrlStr];
01042 Q_ASSERT( dir );
01043 dir->complete = true;
01044
01045 for ( kdl = listers->first(); kdl; kdl = listers->next() )
01046 {
01047 kdl->jobDone( job );
01048 emit kdl->completed( jobUrl );
01049 if ( kdl->numJobs() == 0 )
01050 {
01051 kdl->d->complete = true;
01052 emit kdl->completed();
01053 }
01054 }
01055 }
01056
01057
01058
01059 processPendingUpdates();
01060
01061 #ifdef DEBUG_CACHE
01062 printDebug();
01063 #endif
01064 }
01065
01066 void KDirListerCache::slotRedirection( KIO::Job *j, const KURL& url )
01067 {
01068 Q_ASSERT( j );
01069 KIO::ListJob *job = static_cast<KIO::ListJob *>( j );
01070
01071 KURL oldUrl = job->url();
01072 KURL newUrl = url;
01073
01074
01075 oldUrl.adjustPath(-1);
01076 newUrl.adjustPath(-1);
01077
01078 if ( oldUrl == newUrl )
01079 {
01080 kdDebug(7004) << k_funcinfo << "New redirection url same as old, giving up." << endl;
01081 return;
01082 }
01083
01084 kdDebug(7004) << k_funcinfo << oldUrl.prettyURL() << " -> " << newUrl.prettyURL() << endl;
01085
01086 #ifdef DEBUG_CACHE
01087 printDebug();
01088 #endif
01089
01090
01091
01092
01093
01094
01095 DirItem *dir = itemsInUse.take( oldUrl.url() );
01096 Q_ASSERT( dir );
01097
01098 QPtrList<KDirLister> *listers = urlsCurrentlyListed.take( oldUrl.url() );
01099 Q_ASSERT( listers );
01100 Q_ASSERT( !listers->isEmpty() );
01101
01102 for ( KDirLister *kdl = listers->first(); kdl; kdl = listers->next() )
01103 {
01104
01105 if ( kdl->d->url.equals( oldUrl, true ) )
01106 {
01107 kdl->d->rootFileItem = 0;
01108 kdl->d->url = newUrl;
01109 }
01110
01111 *kdl->d->lstDirs.find( oldUrl ) = newUrl;
01112
01113 if ( kdl->d->lstDirs.count() == 1 )
01114 {
01115 emit kdl->clear();
01116 emit kdl->redirection( newUrl );
01117 emit kdl->redirection( oldUrl, newUrl );
01118 }
01119 else
01120 {
01121 emit kdl->clear( oldUrl );
01122 emit kdl->redirection( oldUrl, newUrl );
01123 }
01124 }
01125
01126
01127
01128 QPtrList<KDirLister> *holders = urlsCurrentlyHeld.take( oldUrl.url() );
01129 if ( holders )
01130 {
01131 Q_ASSERT( !holders->isEmpty() );
01132
01133 for ( KDirLister *kdl = holders->first(); kdl; kdl = holders->next() )
01134 {
01135 kdl->jobStarted( job );
01136
01137
01138 emit kdl->started( oldUrl );
01139
01140
01141
01142 if ( kdl->d->url.equals( oldUrl, true ) )
01143 {
01144 kdl->d->rootFileItem = 0;
01145 kdl->d->url = newUrl;
01146 }
01147
01148 *kdl->d->lstDirs.find( oldUrl ) = newUrl;
01149
01150 if ( kdl->d->lstDirs.count() == 1 )
01151 {
01152 emit kdl->clear();
01153 emit kdl->redirection( newUrl );
01154 emit kdl->redirection( oldUrl, newUrl );
01155 }
01156 else
01157 {
01158 emit kdl->clear( oldUrl );
01159 emit kdl->redirection( oldUrl, newUrl );
01160 }
01161 }
01162 }
01163
01164 DirItem *newDir = itemsInUse[newUrl.url()];
01165 if ( newDir )
01166 {
01167 kdDebug(7004) << "slotRedirection: " << newUrl.url() << " already in use" << endl;
01168
01169
01170 delete dir;
01171
01172
01173
01174 KIO::ListJob *oldJob = jobForUrl( newUrl.url(), job );
01175
01176
01177
01178 QPtrList<KDirLister> *curListers = urlsCurrentlyListed[newUrl.url()];
01179 if ( curListers )
01180 {
01181 kdDebug(7004) << "slotRedirection: and it is currently listed" << endl;
01182
01183 Q_ASSERT( oldJob );
01184
01185 for ( KDirLister *kdl = curListers->first(); kdl; kdl = curListers->next() )
01186 {
01187 kdl->jobDone( oldJob );
01188
01189 kdl->jobStarted( job );
01190 kdl->connectJob( job );
01191 }
01192
01193
01194 for ( KDirLister *kdl = listers->first(); kdl; kdl = listers->next() )
01195 curListers->append( kdl );
01196 }
01197 else
01198 urlsCurrentlyListed.insert( newUrl.url(), listers );
01199
01200 if ( oldJob )
01201 killJob( oldJob );
01202
01203
01204 QPtrList<KDirLister> *curHolders = urlsCurrentlyHeld[newUrl.url()];
01205 if ( curHolders )
01206 {
01207 kdDebug(7004) << "slotRedirection: and it is currently held." << endl;
01208
01209 for ( KDirLister *kdl = curHolders->first(); kdl; kdl = curHolders->next() )
01210 {
01211 kdl->jobStarted( job );
01212 emit kdl->started( newUrl );
01213 }
01214
01215
01216 if ( holders )
01217 for ( KDirLister *kdl = holders->first(); kdl; kdl = holders->next() )
01218 curHolders->append( kdl );
01219 }
01220 else if ( holders )
01221 urlsCurrentlyHeld.insert( newUrl.url(), holders );
01222
01223
01224
01225
01226 for ( KDirLister *kdl = listers->first(); kdl; kdl = listers->next() )
01227 {
01228 if ( !kdl->d->rootFileItem && kdl->d->url == newUrl )
01229 kdl->d->rootFileItem = newDir->rootItem;
01230
01231 kdl->addNewItems( *(newDir->lstItems) );
01232 kdl->emitItems();
01233 }
01234
01235 if ( holders )
01236 {
01237 for ( KDirLister *kdl = holders->first(); kdl; kdl = holders->next() )
01238 {
01239 if ( !kdl->d->rootFileItem && kdl->d->url == newUrl )
01240 kdl->d->rootFileItem = newDir->rootItem;
01241
01242 kdl->addNewItems( *(newDir->lstItems) );
01243 kdl->emitItems();
01244 }
01245 }
01246 }
01247 else if ( (newDir = itemsCached.take( newUrl.url() )) )
01248 {
01249 kdDebug(7004) << "slotRedirection: " << newUrl.url() << " is unused, but already in the cache." << endl;
01250
01251 delete dir;
01252 itemsInUse.insert( newUrl.url(), newDir );
01253 urlsCurrentlyListed.insert( newUrl.url(), listers );
01254 if ( holders )
01255 urlsCurrentlyHeld.insert( newUrl.url(), holders );
01256
01257
01258 for ( KDirLister *kdl = listers->first(); kdl; kdl = listers->next() )
01259 {
01260 if ( !kdl->d->rootFileItem && kdl->d->url == newUrl )
01261 kdl->d->rootFileItem = newDir->rootItem;
01262
01263 kdl->addNewItems( *(newDir->lstItems) );
01264 kdl->emitItems();
01265 }
01266
01267 if ( holders )
01268 {
01269 for ( KDirLister *kdl = holders->first(); kdl; kdl = holders->next() )
01270 {
01271 if ( !kdl->d->rootFileItem && kdl->d->url == newUrl )
01272 kdl->d->rootFileItem = newDir->rootItem;
01273
01274 kdl->addNewItems( *(newDir->lstItems) );
01275 kdl->emitItems();
01276 }
01277 }
01278 }
01279 else
01280 {
01281 kdDebug(7004) << "slotRedirection: " << newUrl.url() << " has not been listed yet." << endl;
01282
01283 delete dir->rootItem;
01284 dir->rootItem = 0;
01285 dir->lstItems->clear();
01286 dir->redirect( newUrl );
01287 itemsInUse.insert( newUrl.url(), dir );
01288 url