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