kio Library API Documentation

kdirlister.cpp

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