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