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