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