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