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 dir->redirect( newUrl );
01040 itemsInUse.insert( newUrl.url(), dir );
01041 urlsCurrentlyListed.insert( newUrl.url(), listers );
01042 }
01043
01044 void KDirListerCache::renameDir( const KURL &oldUrl, const KURL &newUrl )
01045 {
01046 kdDebug(7004) << k_funcinfo << oldUrl.prettyURL() << " -> " << newUrl.prettyURL() << endl;
01047 QString oldUrlStr = oldUrl.url(-1);
01048 QString newUrlStr = newUrl.url(-1);
01049
01050
01051
01052
01053
01054
01055 QDictIterator<DirItem> itu( itemsInUse );
01056 bool goNext;
01057 while ( itu.current() )
01058 {
01059 goNext = true;
01060 DirItem* dir = itu.current();
01061 KURL oldDirUrl ( itu.currentKey() );
01062
01063
01064 if ( oldUrl.isParentOf( oldDirUrl ) )
01065 {
01066 QString relPath = oldDirUrl.path().mid( oldUrl.path().length() );
01067
01068 KURL newDirUrl( newUrl );
01069 if ( !relPath.isEmpty() )
01070 newDirUrl.addPath( relPath );
01071
01072
01073
01074 dir->redirect( newDirUrl );
01075 itemsInUse.remove( itu.currentKey() );
01076 itemsInUse.insert( newDirUrl.url(-1), dir );
01077 goNext = false;
01078 if ( dir->lstItems )
01079 {
01080
01081 KFileItemListIterator kit( *dir->lstItems );
01082 for ( ; kit.current(); ++kit )
01083 {
01084 KURL oldItemUrl = (*kit)->url();
01085 QString oldItemUrlStr( oldItemUrl.url(-1) );
01086 KURL newItemUrl( oldItemUrl );
01087 newItemUrl.setPath( newDirUrl.path() );
01088 newItemUrl.addPath( oldItemUrl.fileName() );
01089 kdDebug(7004) << "KDirListerCache::renameDir renaming " << oldItemUrlStr << " to " << newItemUrl.url() << endl;
01090 (*kit)->setURL( newItemUrl );
01091 }
01092 }
01093 emitRedirections( oldDirUrl, newDirUrl );
01094 }
01095 if (goNext)
01096 ++itu;
01097 }
01098
01099
01100
01101 removeDirFromCache( oldUrl );
01102
01103 }
01104
01105 void KDirListerCache::emitRedirections( const KURL &oldUrl, const KURL &url )
01106 {
01107 kdDebug(7004) << k_funcinfo << oldUrl.prettyURL() << " -> " << url.prettyURL() << endl;
01108 QString oldUrlStr = oldUrl.url(-1);
01109 QString urlStr = url.url(-1);
01110
01111 KIO::ListJob *job = jobForUrl(oldUrlStr);
01112 if (job)
01113 killJob( job );
01114
01115
01116 QPtrList<KDirLister> *listers = urlsCurrentlyListed.take( oldUrlStr );
01117 if ( listers )
01118 {
01119
01120 for ( KDirLister *kdl = listers->first(); kdl; kdl = listers->next() )
01121 {
01122 kdl->jobDone(job);
01123 emit kdl->canceled( oldUrl );
01124 }
01125
01126 urlsCurrentlyListed.insert( urlStr, listers );
01127 }
01128
01129
01130
01131 QPtrList<KDirLister> *holders = urlsCurrentlyHeld.take( oldUrlStr );
01132 if ( holders )
01133 {
01134 for ( KDirLister *kdl = holders->first(); kdl; kdl = holders->next() )
01135 {
01136 kdl->jobDone(job);
01137 }
01138 urlsCurrentlyHeld.insert( urlStr, holders );
01139 }
01140
01141 if (listers)
01142 {
01143 updateDirectory( url );
01144
01145
01146 for ( KDirLister *kdl = listers->first(); kdl; kdl = listers->next() )
01147 {
01148 emit kdl->started( url );
01149 }
01150 }
01151
01152 if (holders)
01153 {
01154
01155 for ( KDirLister *kdl = holders->first(); kdl; kdl = holders->next() )
01156 {
01157 *kdl->d->lstDirs.find( oldUrl ) = url;
01158 if ( kdl->d->lstDirs.count() == 1 )
01159 {
01160 emit kdl->redirection( url );
01161 }
01162 emit kdl->redirection( oldUrl, url );
01163 }
01164 }
01165 }
01166
01167 void KDirListerCache::removeDirFromCache( const KURL& dir )
01168 {
01169 kdDebug(7004) << "KDirListerCache::removeDirFromCache " << dir.prettyURL() << endl;
01170 QCacheIterator<DirItem> itc( itemsCached );
01171 while ( itc.current() )
01172 {
01173 if ( dir.isParentOf( KURL( itc.currentKey() ) ) )
01174 itemsCached.remove( itc.currentKey() );
01175 else
01176 ++itc;
01177 }
01178 }
01179
01180 void KDirListerCache::slotUpdateEntries( KIO::Job* job, const KIO::UDSEntryList& list )
01181 {
01182 jobs[static_cast<KIO::ListJob*>(job)] += list;
01183 }
01184
01185 void KDirListerCache::slotUpdateResult( KIO::Job * j )
01186 {
01187 Q_ASSERT( j );
01188 KIO::ListJob *job = static_cast<KIO::ListJob *>( j );
01189
01190 KURL jobUrl = job->url();
01191 jobUrl.adjustPath(-1);
01192 QString jobUrlStr = jobUrl.url();
01193
01194 kdDebug(7004) << k_funcinfo << "finished update " << jobUrl << endl;
01195
01196 KDirLister *kdl;
01197
01198 QPtrList<KDirLister> *listers = urlsCurrentlyHeld[jobUrlStr];
01199 QPtrList<KDirLister> *tmpLst = urlsCurrentlyListed.take( jobUrlStr );
01200
01201 if ( tmpLst )
01202 {
01203 if ( listers )
01204 for ( kdl = tmpLst->first(); kdl; kdl = tmpLst->next() )
01205 {
01206 Q_ASSERT( listers->containsRef( kdl ) == 0 );
01207 listers->append( kdl );
01208 }
01209 else
01210 {
01211 listers = tmpLst;
01212 urlsCurrentlyHeld.insert( jobUrlStr, listers );
01213 }
01214 }
01215
01216
01217 Q_ASSERT( listers );
01218
01219 if ( job->error() )
01220 {
01221 for ( kdl = listers->first(); kdl; kdl = listers->next() )
01222 {
01223 kdl->jobDone(job);
01224
01225
01226
01227 emit kdl->canceled( jobUrl );
01228 if ( kdl->numJobs() == 0 )
01229 {
01230 kdl->d->complete = true;
01231 emit kdl->canceled();
01232 }
01233 }
01234
01235 jobs.remove( job );
01236
01237
01238
01239 processPendingUpdates();
01240 return;
01241 }
01242
01243 DirItem *dir = itemsInUse[jobUrlStr];
01244 dir->complete = true;
01245
01246
01247
01248 bool delayedMimeTypes = true;
01249 for ( kdl = listers->first(); kdl; kdl = listers->next() )
01250 delayedMimeTypes &= kdl->d->delayedMimeTypes;
01251
01252
01253 QDict<KFileItem> fileItems( 9973 );
01254
01255 KFileItemListIterator kit ( *(dir->lstItems) );
01256
01257
01258 for ( ; kit.current(); ++kit )
01259 {
01260 (*kit)->unmark();
01261 fileItems.insert( (*kit)->url().url(), *kit );
01262 }
01263
01264 static const QString& dot = KGlobal::staticQString(".");
01265 static const QString& dotdot = KGlobal::staticQString("..");
01266
01267 KFileItem *item, *tmp;
01268
01269 QValueList<KIO::UDSEntry> buf = jobs[job];
01270 QValueListIterator<KIO::UDSEntry> it = buf.begin();
01271 for ( ; it != buf.end(); ++it )
01272 {
01273 QString name;
01274
01275
01276 KIO::UDSEntry::Iterator it2 = (*it).begin();
01277 for ( ; it2 != (*it).end(); it2++ )
01278 if ( (*it2).m_uds == KIO::UDS_NAME )
01279 {
01280 name = (*it2).m_str;
01281 break;
01282 }
01283
01284 Q_ASSERT( !name.isEmpty() );
01285
01286
01287
01288 if ( name.isEmpty() || name == dotdot )
01289 continue;
01290
01291 if ( name == dot )
01292 {
01293
01294
01295 if ( !dir->rootItem )
01296 {
01297 dir->rootItem = new KFileItem( *it, jobUrl, delayedMimeTypes, true );
01298
01299 for ( KDirLister *kdl = listers->first(); kdl; kdl = listers->next() )
01300 if ( !kdl->d->rootFileItem && kdl->d->url == jobUrl )
01301 kdl->d->rootFileItem = dir->rootItem;
01302 }
01303
01304 continue;
01305 }
01306
01307
01308 item = new KFileItem( *it, jobUrl, delayedMimeTypes, true );
01309
01310 QString url = item->url().url();
01311
01312
01313
01314 if ( (tmp = fileItems[url]) )
01315 {
01316 tmp->mark();
01317
01318
01319 if ( !tmp->cmp( *item ) )
01320 {
01321
01322 tmp->assign( *item );
01323
01324 for ( kdl = listers->first(); kdl; kdl = listers->next() )
01325 kdl->addRefreshItem( tmp );
01326 }
01327 delete item;
01328 }
01329 else
01330 {
01331
01332
01333 item->mark();
01334 dir->lstItems->append( item );
01335
01336 for ( kdl = listers->first(); kdl; kdl = listers->next() )
01337 kdl->addNewItem( item );
01338 }
01339 }
01340
01341 jobs.remove( job );
01342
01343 deleteUnmarkedItems( listers, dir->lstItems );
01344
01345 for ( kdl = listers->first(); kdl; kdl = listers->next() )
01346 {
01347 kdl->emitItems();
01348
01349 kdl->jobDone(job);
01350
01351 emit kdl->completed( jobUrl );
01352 if ( kdl->numJobs() == 0 )
01353 {
01354 kdl->d->complete = true;
01355 emit kdl->completed();
01356 }
01357 }
01358
01359
01360
01361 processPendingUpdates();
01362 }
01363
01364
01365
01366 KIO::ListJob *KDirListerCache::jobForUrl(const QString& _url)
01367 {
01368 KIO::ListJob *job;
01369 QMap< KIO::ListJob *, QValueList<KIO::UDSEntry> >::Iterator it = jobs.begin();
01370 while ( it != jobs.end() )
01371 {
01372 job = it.key();
01373 if ( job->url().url(-1) == _url )
01374 {
01375 return job;
01376 }
01377 ++it;
01378 }
01379 return 0;
01380 }
01381
01382 void KDirListerCache::killJob( KIO::ListJob *job )
01383 {
01384 jobs.remove( job );
01385 job->disconnect( this );
01386 job->kill();
01387 }
01388
01389 void KDirListerCache::deleteUnmarkedItems( QPtrList<KDirLister> *listers, KFileItemList *lstItems )
01390 {
01391
01392 KFileItem* item;
01393 lstItems->first();
01394 while ( (item = lstItems->current()) )
01395 if ( !item->isMarked() )
01396 {
01397
01398 for ( KDirLister *kdl = listers->first(); kdl; kdl = listers->next() )
01399 kdl->emitDeleteItem( item );
01400
01401 if ( item->isDir() )
01402 deleteDir( item->url() );
01403
01404
01405 lstItems->take();
01406 delete item;
01407 }
01408 else
01409 lstItems->next();
01410 }
01411
01412 void KDirListerCache::deleteDir( const KURL& dirUrl )
01413 {
01414
01415
01416
01417
01418
01419 QDictIterator<DirItem> itu( itemsInUse );
01420 while ( itu.current() )
01421 {
01422 KURL deletedUrl( itu.currentKey() );
01423 if ( dirUrl.isParentOf( deletedUrl ) )
01424 {
01425
01426
01427 QPtrList<KDirLister> *kdls = urlsCurrentlyListed[deletedUrl.url()];
01428 if ( kdls )
01429 {
01430
01431 kdls = new QPtrList<KDirLister>( *kdls );
01432 for ( KDirLister *kdl = kdls->first(); kdl; kdl = kdls->next() )
01433 stop( kdl, deletedUrl );
01434
01435 delete kdls;
01436 }
01437
01438
01439
01440
01441 kdls = urlsCurrentlyHeld[deletedUrl.url()];
01442 if ( kdls )
01443 {
01444
01445 kdls = new QPtrList<KDirLister>( *kdls );
01446
01447 for ( KDirLister *kdl = kdls->first(); kdl; kdl = kdls->next() )
01448 {
01449
01450 if ( kdl->d->url == deletedUrl )
01451 {
01452
01453 if ( kdl->d->rootFileItem )
01454 emit kdl->deleteItem( kdl->d->rootFileItem );
01455 forgetDirs( kdl );
01456 kdl->d->rootFileItem = 0;
01457 }
01458 else
01459 {
01460 bool treeview = kdl->d->lstDirs.count() > 1;
01461 if ( !treeview )
01462 {
01463 emit kdl->clear();
01464 kdl->d->lstDirs.clear();
01465 }
01466 else
01467 kdl->d->lstDirs.remove( kdl->d->lstDirs.find( deletedUrl ) );
01468
01469 forgetDirs( kdl, deletedUrl, treeview );
01470 }
01471 }
01472
01473 delete kdls;
01474 }
01475
01476
01477
01478
01479 DirItem *dir = itemsInUse.take( deletedUrl.url() );
01480 Q_ASSERT( !dir );
01481 if ( !dir )
01482 ++itu;
01483 }
01484 else
01485 ++itu;
01486 }
01487
01488
01489 removeDirFromCache( dirUrl );
01490 }
01491
01492 void KDirListerCache::processPendingUpdates()
01493 {
01494
01495 }
01496
01497 #ifndef NDEBUG
01498 void KDirListerCache::printDebug()
01499 {
01500 kdDebug(7004) << "Items in use: " << endl;
01501 QDictIterator<DirItem> itu( itemsInUse );
01502 for ( ; itu.current() ; ++itu ) {
01503 kdDebug(7004) << " " << itu.currentKey() << " URL: " << itu.current()->url
01504 << " rootItem: " << ( itu.current()->rootItem ? itu.current()->rootItem->url() : KURL() )
01505 << " autoUpdates refcount: " << itu.current()->autoUpdates
01506 << " complete: " << itu.current()->complete
01507 << ( itu.current()->lstItems ? QString(" with %1 items.").arg(itu.current()->lstItems->count()) : QString(" lstItems=NULL") ) << endl;
01508 }
01509
01510 kdDebug(7004) << "urlsCurrentlyHeld: " << endl;
01511 QDictIterator< QPtrList<KDirLister> > it( urlsCurrentlyHeld );
01512 for ( ; it.current() ; ++it )
01513 {
01514 QString list;
01515 for ( QPtrListIterator<KDirLister> listit( *it.current() ); listit.current(); ++listit )
01516 list += " 0x" + QString::number( (long)listit.current(), 16 );
01517 kdDebug(7004) << " " << it.currentKey() << " " << it.current()->count() << " listers: " << list << endl;
01518 }
01519
01520 kdDebug(7004) << "urlsCurrentlyListed: " << endl;
01521 QDictIterator< QPtrList<KDirLister> > it2( urlsCurrentlyListed );
01522 for ( ; it2.current() ; ++it2 )
01523 {
01524 QString list;
01525 for ( QPtrListIterator<KDirLister> listit( *it2.current() ); listit.current(); ++listit )
01526 list += " 0x" + QString::number( (long)listit.current(), 16 );
01527 kdDebug(7004) << " " << it2.currentKey() << " " << it2.current()->count() << " listers: " << list << endl;
01528 }
01529
01530 QMap< KIO::ListJob *, QValueList<KIO::UDSEntry> >::Iterator jit = jobs.begin();
01531 kdDebug(7004) << "Jobs: " << endl;
01532 for ( ; jit != jobs.end() ; ++jit )
01533 kdDebug(7004) << " " << jit.key() << " listing " << jit.key()->url().prettyURL() << ": " << (*jit).count() << " entries." << endl;
01534
01535 kdDebug(7004) << "Items in cache: " << endl;
01536 QCacheIterator<DirItem> itc( itemsCached );
01537 for ( ; itc.current() ; ++itc )
01538 kdDebug(7004) << " " << itc.currentKey() << " rootItem: "
01539 << ( itc.current()->rootItem ? itc.current()->rootItem->url().prettyURL() : QString("NULL") )
01540 << ( itc.current()->lstItems ? QString(" with %1 items.").arg(itc.current()->lstItems->count()) : QString(" lstItems=NULL") ) << endl;
01541 }
01542 #endif
01543
01544
01545
01546
01547 KDirLister::KDirLister( bool _delayedMimeTypes )
01548 {
01549 kdDebug(7003) << "+KDirLister" << endl;
01550
01551 d = new KDirListerPrivate;
01552
01553 d->complete = true;
01554 d->delayedMimeTypes = _delayedMimeTypes;
01555
01556 setAutoUpdate( true );
01557 setDirOnlyMode( false );
01558 setShowingDotFiles( false );
01559
01560 setAutoErrorHandlingEnabled( true, 0 );
01561 }
01562
01563 KDirLister::~KDirLister()
01564 {
01565 kdDebug(7003) << "-KDirLister" << endl;
01566
01567
01568 stop();
01569 s_pCache->forgetDirs( this );
01570
01571 delete d;
01572 }
01573
01574 bool KDirLister::openURL( const KURL& _url, bool _keep, bool _reload )
01575 {
01576 if ( !validURL( _url ) )
01577 return false;
01578
01579 kdDebug(7003) << k_funcinfo << _url.prettyURL()
01580 << " keep=" << _keep << " reload=" << _reload << endl;
01581
01582
01583 if ( d->changes != NONE && _keep )
01584 emitChanges();
01585
01586 d->changes = NONE;
01587
01588 s_pCache->listDir( this, _url, _keep, _reload );
01589
01590 return true;
01591 }
01592
01593 void KDirLister::stop()
01594 {
01595 kdDebug(7003) << k_funcinfo << endl;
01596 s_pCache->stop( this );
01597 }
01598
01599 void KDirLister::stop( const KURL& _url )
01600 {
01601 kdDebug(7003) << k_funcinfo << _url.prettyURL() << endl;
01602 s_pCache->stop( this, _url );
01603 }
01604
01605 bool KDirLister::autoUpdate() const
01606 {
01607 return d->autoUpdate;
01608 }
01609
01610 void KDirLister::setAutoUpdate( bool _enable )
01611 {
01612 if ( d->autoUpdate == _enable )
01613 return;
01614
01615 d->autoUpdate = _enable;
01616 s_pCache->setAutoUpdate( this, _enable );
01617 }
01618
01619 bool KDirLister::showingDotFiles() const
01620 {
01621 return d->isShowingDotFiles;
01622 }
01623
01624 void KDirLister::setShowingDotFiles( bool _showDotFiles )
01625 {
01626 if ( d->isShowingDotFiles == _showDotFiles )
01627 return;
01628
01629 d->isShowingDotFiles = _showDotFiles;
01630 d->changes ^= DOT_FILES;
01631 }
01632
01633 bool KDirLister::dirOnlyMode() const
01634 {
01635 return d->dirOnlyMode;
01636 }
01637
01638 void KDirLister::setDirOnlyMode( bool _dirsOnly )
01639 {
01640 if ( d->dirOnlyMode == _dirsOnly )
01641 return;
01642
01643 d->dirOnlyMode = _dirsOnly;
01644 d->changes ^= DIR_ONLY_MODE;
01645 }
01646
01647 bool KDirLister::autoErrorHandlingEnabled() const
01648 {
01649 return d->autoErrorHandling;
01650 }
01651
01652 void KDirLister::setAutoErrorHandlingEnabled( bool enable, QWidget* parent )
01653 {
01654 d->autoErrorHandling = enable;
01655 d->errorParent = parent;
01656 }
01657
01658 const KURL& KDirLister::url() const
01659 {
01660 return d->url;
01661 }
01662
01663 void KDirLister::emitChanges()
01664 {
01665 if ( d->changes == NONE )
01666 return;
01667
01668 static const QString& dot = KGlobal::staticQString(".");
01669 static const QString& dotdot = KGlobal::staticQString("..");
01670
01671 for ( KURL::List::Iterator it = d->lstDirs.begin();
01672 it != d->lstDirs.end(); ++it )
01673 {
01674 KFileItemListIterator kit( *s_pCache->itemsForDir( *it ) );
01675 for ( ; kit.current(); ++kit )
01676 {
01677 if ( (*kit)->text() == dot || (*kit)->text() == dotdot )
01678 continue;
01679
01680 bool oldMime = true, newMime = true;
01681
01682 if ( d->changes & MIME_FILTER )
01683 {
01684 oldMime = doMimeFilter( (*kit)->mimetype(), d->oldMimeFilter )
01685 && doMimeExcludeFilter( (*kit)->mimetype(), d->oldMimeExcludeFilter );
01686 newMime = doMimeFilter( (*kit)->mimetype(), d->mimeFilter )
01687 && doMimeExcludeFilter( (*kit)->mimetype(), d->mimeExcludeFilter );
01688
01689 if ( oldMime && !newMime )
01690 {
01691 emit deleteItem( *kit );
01692 continue;
01693 }
01694 }
01695
01696 if ( d->changes & DIR_ONLY_MODE )
01697 {
01698
01699 if ( d->dirOnlyMode )
01700 {
01701 if ( !(*kit)->isDir() )
01702 emit deleteItem( *kit );
01703 }
01704 else if ( !(*kit)->isDir() )
01705 addNewItem( *kit );
01706
01707 continue;
01708 }
01709
01710 if ( (*kit)->isHidden() )
01711 {
01712 if ( d->changes & DOT_FILES )
01713 {
01714
01715 if ( d->isShowingDotFiles )
01716 addNewItem( *kit );
01717 else
01718 emit deleteItem( *kit );
01719
01720 continue;
01721 }
01722 }
01723 else if ( d->changes & NAME_FILTER )
01724 {
01725 bool oldName = (*kit)->isDir() ||
01726 d->oldFilters.isEmpty() ||
01727 doNameFilter( (*kit)->text(), d->oldFilters );
01728
01729 bool newName = (*kit)->isDir() ||
01730 d->lstFilters.isEmpty() ||
01731 doNameFilter( (*kit)->text(), d->lstFilters );
01732
01733 if ( oldName && !newName )
01734 {
01735 emit deleteItem( *kit );
01736 continue;
01737 }
01738 else if ( !oldName && newName )
01739 addNewItem( *kit );
01740 }
01741
01742 if ( (d->changes & MIME_FILTER) && !oldMime && newMime )
01743 addNewItem( *kit );
01744 }
01745
01746 emitItems();
01747 }
01748
01749 d->changes = NONE;
01750 }
01751
01752 void KDirLister::updateDirectory( const KURL& _u )
01753 {
01754 s_pCache->updateDirectory( _u );
01755 }
01756
01757 bool KDirLister::isFinished() const
01758 {
01759 return d->complete;
01760 }
01761
01762 KFileItem* KDirLister::rootItem() const
01763 {
01764 return d->rootFileItem;
01765 }
01766
01767 KFileItem* KDirLister::findByURL( const KURL& _url ) const
01768 {
01769 return s_pCache->findByURL( this, _url );
01770 }
01771
01772 KFileItem* KDirLister::findByName( const QString& _name ) const
01773 {
01774 return s_pCache->findByName( this, _name );
01775 }
01776
01777 #ifndef KDE_NO_COMPAT
01778 KFileItem* KDirLister::find( const KURL& _url ) const
01779 {
01780 return findByURL( _url );
01781 }
01782 #endif
01783
01784
01785
01786
01787 void KDirLister::setNameFilter( const QString& nameFilter )
01788 {
01789 if ( !(d->changes & NAME_FILTER) )
01790 {
01791 d->oldFilters = d->lstFilters;
01792 d->lstFilters.setAutoDelete( false );
01793 }
01794
01795 d->lstFilters.clear();
01796 d->lstFilters.setAutoDelete( true );
01797
01798 d->nameFilter = nameFilter;
01799
01800
01801 QStringList list = QStringList::split( ' ', nameFilter );
01802 for ( QStringList::Iterator it = list.begin(); it != list.end(); ++it )
01803 d->lstFilters.append( new QRegExp(*it, false, true ) );
01804
01805 d->changes |= NAME_FILTER;
01806 }
01807
01808 const QString& KDirLister::nameFilter() const
01809 {
01810 return d->nameFilter;
01811 }
01812
01813 void KDirLister::setMimeFilter( const QStringList& mimeFilter )
01814 {
01815 if ( !(d->changes & MIME_FILTER) )
01816 d->oldMimeFilter = d->mimeFilter;
01817
01818 if (mimeFilter.find ("all/allfiles") != mimeFilter.end () ||
01819 mimeFilter.find ("all/all") != mimeFilter.end ())
01820 d->mimeFilter.clear ();
01821 else
01822 d->mimeFilter = mimeFilter;
01823
01824 d->changes |= MIME_FILTER;
01825 }
01826
01827 void KDirLister::setMimeExcludeFilter( const QStringList& mimeExcludeFilter )
01828 {
01829 if ( !(d->changes & MIME_FILTER) )
01830 d->oldMimeExcludeFilter = d->mimeExcludeFilter;
01831
01832 d->mimeExcludeFilter = mimeExcludeFilter;
01833 d->changes |= MIME_FILTER;
01834 }
01835
01836
01837 void KDirLister::clearMimeFilter()
01838 {
01839 if ( !(d->changes & MIME_FILTER) )
01840 {
01841 d->oldMimeFilter = d->mimeFilter;
01842 d->oldMimeExcludeFilter = d->mimeExcludeFilter;
01843 }
01844 d->mimeFilter.clear();
01845 d->mimeExcludeFilter.clear();
01846 d->changes |= MIME_FILTER;
01847 }
01848
01849 const QStringList& KDirLister::mimeFilters() const
01850 {
01851 return d->mimeFilter;
01852 }
01853
01854 bool KDirLister::matchesFilter( const QString& name ) const
01855 {
01856 return doNameFilter( name, d->lstFilters );
01857 }
01858
01859 bool KDirLister::matchesMimeFilter( const QString& mime ) const
01860 {
01861 return doMimeFilter( mime, d->mimeFilter ) && doMimeExcludeFilter(mime,d->mimeExcludeFilter);
01862 }
01863
01864
01865
01866 bool KDirLister::matchesFilter( const KFileItem *item ) const
01867 {
01868 Q_ASSERT( item );
01869 static const QString& dotdot = KGlobal::staticQString("..");
01870
01871 if ( item->text() == dotdot )
01872 return false;
01873
01874 if ( !d->isShowingDotFiles && item->text()[0] == '.' )
01875 return false;
01876
01877 if ( item->isDir() || d->lstFilters.isEmpty() )
01878 return true;
01879
01880 return matchesFilter( item->text() );
01881 }
01882
01883 bool KDirLister::matchesMimeFilter( const KFileItem *item ) const
01884 {
01885 Q_ASSERT( item );
01886 return matchesMimeFilter( item->mimetype() );
01887 }
01888
01889 bool KDirLister::doNameFilter( const QString& name, const QPtrList<QRegExp>& filters ) const
01890 {
01891 for ( QPtrListIterator<QRegExp> it( filters ); it.current(); ++it )
01892 if ( it.current()->exactMatch( name ) )
01893 return true;
01894
01895 return false;
01896 }
01897
01898 bool KDirLister::doMimeFilter( const QString& mime, const QStringList& filters ) const
01899 {
01900 if ( filters.isEmpty() )
01901 return true;
01902
01903 KMimeType::Ptr mimeptr = KMimeType::mimeType(mime);
01904 QStringList::ConstIterator it = filters.begin();
01905 for ( ; it != filters.end(); ++it )
01906 if ( mimeptr->is(*it) )
01907 return true;
01908
01909 return false;
01910 }
01911
01912 bool KDirLister::doMimeExcludeFilter( const QString& mime, const QStringList& filters ) const
01913 {
01914 if ( filters.isEmpty() )
01915 return true;
01916
01917 QStringList::ConstIterator it = filters.begin();
01918 for ( ; it != filters.end(); ++it )
01919 if ( (*it) == mime )
01920 return false;
01921
01922 return true;
01923 }
01924
01925
01926 bool KDirLister::validURL( const KURL& _url ) const
01927 {
01928 if ( !_url.isValid() )
01929 {
01930 if ( d->autoErrorHandling )
01931 {
01932 QString tmp = i18n("Malformed URL\n%1").arg( _url.prettyURL() );
01933 KMessageBox::error( d->errorParent, tmp );
01934 }
01935 return false;
01936 }
01937
01938
01939
01940 return true;
01941 }
01942
01943 void KDirLister::handleError( KIO::Job *job )
01944 {
01945 if ( d->autoErrorHandling )
01946 job->showErrorDialog( d->errorParent );
01947 }
01948
01949
01950
01951
01952 void KDirLister::addNewItem( const KFileItem *item )
01953 {
01954 bool isNameFilterMatch = (d->dirOnlyMode && !item->isDir()) || !matchesFilter( item );
01955 if (isNameFilterMatch)
01956 return;
01957
01958 bool isMimeFilterMatch = !matchesMimeFilter( item );
01959
01960 if ( !isNameFilterMatch && !isMimeFilterMatch )
01961 {
01962 if ( !d->lstNewItems )
01963 d->lstNewItems = new KFileItemList;
01964
01965 d->lstNewItems->append( item );
01966 }
01967 else if ( !isNameFilterMatch )
01968 {
01969 if ( !d->lstMimeFilteredItems )
01970 d->lstMimeFilteredItems = new KFileItemList;
01971
01972 d->lstMimeFilteredItems->append( item );
01973 }
01974 }
01975
01976 void KDirLister::addNewItems( const KFileItemList& items )
01977 {
01978
01979 for ( KFileItemListIterator kit( items ); kit.current(); ++kit )
01980 addNewItem( *kit );
01981 }
01982
01983 void KDirLister::addRefreshItem( const KFileItem *item )
01984 {
01985 bool isNameFilterMatch = (d->dirOnlyMode && !item->isDir()) || !matchesFilter( item );
01986 bool isMimeFilterMatch = !matchesMimeFilter( item );
01987
01988 if ( !isNameFilterMatch && !isMimeFilterMatch )
01989 {
01990 if ( !d->lstRefreshItems )
01991 d->lstRefreshItems = new KFileItemList;
01992
01993 d->lstRefreshItems->append( item );
01994 } else {
01995 if ( !d->lstRemoveItems )
01996 d->lstRemoveItems = new KFileItemList;
01997
01998 d->lstRemoveItems->append( item );
01999 }
02000 }
02001
02002 void KDirLister::emitItems()
02003 {
02004 KFileItemList *tmpNew = d->lstNewItems;
02005 d->lstNewItems = 0;
02006
02007 KFileItemList *tmpMime = d->lstMimeFilteredItems;
02008 d->lstMimeFilteredItems = 0;
02009
02010 KFileItemList *tmpRefresh = d->lstRefreshItems;
02011 d->lstRefreshItems = 0;
02012
02013 KFileItemList *tmpRemove = d->lstRemoveItems;
02014 d->lstRemoveItems = 0;
02015
02016 if ( tmpNew )
02017 {
02018 emit newItems( *tmpNew );
02019 delete tmpNew;
02020 }
02021
02022 if ( tmpMime )
02023 {
02024 emit itemsFilteredByMime( *tmpMime );
02025 delete tmpMime;
02026 }
02027
02028 if ( tmpRefresh )
02029 {
02030 emit refreshItems( *tmpRefresh );
02031 delete tmpRefresh;
02032 }
02033
02034 if ( tmpRemove )
02035 {
02036 for ( KFileItem *tmp = tmpRemove->first(); tmp; tmp = tmpRemove->next() )
02037 emit deleteItem( tmp );
02038 delete tmpRemove;
02039 }
02040 }
02041
02042 void KDirLister::emitDeleteItem( KFileItem *item )
02043 {
02044 bool isNameFilterMatch = (d->dirOnlyMode && !item->isDir()) || !matchesFilter( item );
02045 bool isMimeFilterMatch = !matchesMimeFilter( item );
02046
02047 if ( !isNameFilterMatch && !isMimeFilterMatch )
02048 emit deleteItem( item );
02049 }
02050
02051
02052
02053
02054 void KDirLister::slotInfoMessage( KIO::Job *, const QString& message )
02055 {
02056 emit infoMessage( message );
02057 }
02058
02059 void KDirLister::slotPercent( KIO::Job *job, unsigned long pcnt )
02060 {
02061 d->jobData[static_cast<KIO::ListJob*>(job)].percent = pcnt;
02062
02063 int result = 0;
02064
02065 KIO::filesize_t size = 0;
02066
02067 QMap< KIO::ListJob *, KDirListerPrivate::JobData >::Iterator dataIt = d->jobData.begin();
02068 while ( dataIt != d->jobData.end() )
02069 {
02070 result += (*dataIt).percent * (*dataIt).totalSize;
02071 size += (*dataIt).totalSize;
02072 ++dataIt;
02073 }
02074
02075 if ( size != 0 )
02076 result /= size;
02077 else
02078 result = 100;
02079 emit percent( result );
02080 }
02081
02082 void KDirLister::slotTotalSize( KIO::Job *job, KIO::filesize_t size )
02083 {
02084 d->jobData[static_cast<KIO::ListJob*>(job)].totalSize = size;
02085
02086 KIO::filesize_t result = 0;
02087 QMap< KIO::ListJob *, KDirListerPrivate::JobData >::Iterator dataIt = d->jobData.begin();
02088 while ( dataIt != d->jobData.end() )
02089 {
02090 result += (*dataIt).totalSize;
02091 ++dataIt;
02092 }
02093
02094 emit totalSize( result );
02095 }
02096
02097 void KDirLister::slotProcessedSize( KIO::Job *job, KIO::filesize_t size )
02098 {
02099 d->jobData[static_cast<KIO::ListJob*>(job)].processedSize = size;
02100
02101 KIO::filesize_t result = 0;
02102 QMap< KIO::ListJob *, KDirListerPrivate::JobData >::Iterator dataIt = d->jobData.begin();
02103 while ( dataIt != d->jobData.end() )
02104 {
02105 result += (*dataIt).processedSize;
02106 ++dataIt;
02107 }
02108
02109 emit processedSize( result );
02110 }
02111
02112 void KDirLister::slotSpeed( KIO::Job *job, unsigned long spd )
02113 {
02114 d->jobData[static_cast<KIO::ListJob*>(job)].speed = spd;
02115
02116 int result = 0;
02117 QMap< KIO::ListJob *, KDirListerPrivate::JobData >::Iterator dataIt = d->jobData.begin();
02118 while ( dataIt != d->jobData.end() )
02119 {
02120 result += (*dataIt).speed;
02121 ++dataIt;
02122 }
02123
02124 emit speed( result );
02125 }
02126
02127 uint KDirLister::numJobs()
02128 {
02129 return d->jobData.count();
02130 }
02131
02132 void KDirLister::jobDone(KIO::ListJob *job)
02133 {
02134 if (job)
02135 d->jobData.remove(job);
02136 }
02137
02138 void KDirLister::jobStarted(KIO::ListJob *job)
02139 {
02140 KDirListerPrivate::JobData jobData;
02141 jobData.speed = 0;
02142 jobData.percent = 0;
02143 jobData.processedSize = 0;
02144 jobData.totalSize = 0;
02145
02146 d->jobData.insert(job, jobData);
02147 }
02148
02149 void KDirLister::setMainWindow(QWidget *window)
02150 {
02151 d->window = window;
02152 }
02153
02154 QWidget *KDirLister::mainWindow()
02155 {
02156 return d->window;
02157 }
02158
02159 KFileItemList KDirLister::items( WhichItems which ) const
02160 {
02161 return itemsForDir( url(), which );
02162 }
02163
02164 KFileItemList KDirLister::itemsForDir( const KURL &dir, WhichItems which) const
02165 {
02166 KFileItemList result;
02167 KFileItemList *allItems = s_pCache->itemsForDir( dir );
02168 if ( !allItems )
02169 return result;
02170
02171 if ( which == AllItems )
02172 result = *allItems;
02173
02174 else
02175 {
02176 for ( KFileItemListIterator kit( *allItems ); kit.current(); ++kit )
02177 {
02178 KFileItem *item = *kit;
02179 bool isNameFilterMatch = (d->dirOnlyMode && !item->isDir()) ||
02180 !matchesFilter( item );
02181 bool isMimeFilterMatch = !matchesMimeFilter( item );
02182
02183 if ( !isNameFilterMatch && !isMimeFilterMatch )
02184 result.append( item );
02185 }
02186 }
02187
02188 return result;
02189 }
02190
02191
02192
02193 void KDirLister::virtual_hook( int, void* )
02194 { }
02195
02196 #include "kdirlister.moc"
02197 #include "kdirlister_p.moc"