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