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