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-2005 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., 51 Franklin Street, Fifth Floor, 00019 Boston, MA 02110-1301, USA. 00020 */ 00021 00022 #include "kdirlister.h" 00023 00024 #include <tqregexp.h> 00025 #include <tqptrlist.h> 00026 #include <tqtimer.h> 00027 #include <tqeventloop.h> 00028 00029 #include <tdeapplication.h> 00030 #include <kdebug.h> 00031 #include <tdelocale.h> 00032 #include <tdeio/job.h> 00033 #include <tdemessagebox.h> 00034 #include <tdeglobal.h> 00035 #include <tdeglobalsettings.h> 00036 #include <kstaticdeleter.h> 00037 #include <kprotocolinfo.h> 00038 00039 #include "kdirlister_p.h" 00040 00041 #include <assert.h> 00042 #include <unistd.h> 00043 00044 KDirListerCache* KDirListerCache::s_pSelf = 0; 00045 static KStaticDeleter<KDirListerCache> sd_KDirListerCache; 00046 00047 // Enable this to get printDebug() called often, to see the contents of the cache 00048 //#define DEBUG_CACHE 00049 00050 // Make really sure it doesn't get activated in the final build 00051 #ifdef NDEBUG 00052 #undef DEBUG_CACHE 00053 #endif 00054 00055 KDirListerCache::KDirListerCache( int maxCount ) 00056 : itemsCached( maxCount ) 00057 { 00058 kdDebug(7004) << "+KDirListerCache" << endl; 00059 00060 itemsInUse.setAutoDelete( false ); 00061 itemsCached.setAutoDelete( true ); 00062 urlsCurrentlyListed.setAutoDelete( true ); 00063 urlsCurrentlyHeld.setAutoDelete( true ); 00064 pendingUpdates.setAutoDelete( true ); 00065 00066 connect( kdirwatch, TQT_SIGNAL( dirty( const KURL& ) ), 00067 this, TQT_SLOT( slotFileDirty( const KURL& ) ) ); 00068 connect( kdirwatch, TQT_SIGNAL( created( const TQString& ) ), 00069 this, TQT_SLOT( slotFileCreated( const TQString& ) ) ); 00070 connect( kdirwatch, TQT_SIGNAL( deleted( const TQString& ) ), 00071 this, TQT_SLOT( slotFileDeleted( const TQString& ) ) ); 00072 } 00073 00074 KDirListerCache::~KDirListerCache() 00075 { 00076 kdDebug(7004) << "-KDirListerCache" << endl; 00077 00078 itemsInUse.setAutoDelete( true ); 00079 itemsInUse.clear(); 00080 itemsCached.clear(); 00081 urlsCurrentlyListed.clear(); 00082 urlsCurrentlyHeld.clear(); 00083 00084 if ( KDirWatch::exists() ) 00085 kdirwatch->disconnect( this ); 00086 } 00087 00088 // setting _reload to true will emit the old files and 00089 // call updateDirectory 00090 bool KDirListerCache::listDir( KDirLister *lister, const KURL& _u, 00091 bool _keep, bool _reload ) 00092 { 00093 // like this we don't have to worry about trailing slashes any further 00094 KURL _url = _u; 00095 _url.cleanPath(); // kill consecutive slashes 00096 _url.adjustPath(-1); 00097 TQString urlStr = _url.url(); 00098 TQString urlReferenceStr = _url.internalReferenceURL(); 00099 00100 if ( !lister->validURL( _url ) ) { 00101 return false; 00102 } 00103 00104 #ifdef DEBUG_CACHE 00105 printDebug(); 00106 #endif 00107 kdDebug(7004) << k_funcinfo << lister << " url=" << _url 00108 << " keep=" << _keep << " reload=" << _reload << endl; 00109 00110 if ( !_keep ) 00111 { 00112 // stop any running jobs for lister 00113 stop( lister ); 00114 00115 // clear our internal list for lister 00116 forgetDirs( lister ); 00117 00118 lister->d->rootFileItem = 0; 00119 } 00120 else if ( lister->d->lstDirs.find( _url ) != lister->d->lstDirs.end() ) 00121 { 00122 // stop the job listing _url for this lister 00123 stop( lister, _url ); 00124 00125 // clear _url for lister 00126 forgetDirs( lister, _url, true ); 00127 00128 if ( lister->d->url == _url ) 00129 lister->d->rootFileItem = 0; 00130 } 00131 00132 lister->d->lstDirs.append( _url ); 00133 00134 if ( lister->d->url.isEmpty() || !_keep ) // set toplevel URL only if not set yet 00135 lister->d->url = _url; 00136 00137 DirItem *itemU = itemsInUse[urlStr + ":" + urlReferenceStr]; 00138 DirItem *itemC; 00139 00140 if ( !urlsCurrentlyListed[urlStr + ":" + urlReferenceStr] ) 00141 { 00142 // if there is an update running for _url already we get into 00143 // the following case - it will just be restarted by updateDirectory(). 00144 00145 if ( itemU ) 00146 { 00147 kdDebug(7004) << "listDir: Entry already in use: " << _url << endl; 00148 00149 bool oldState = lister->d->complete; 00150 lister->d->complete = false; 00151 00152 emit lister->started( _url ); 00153 00154 if ( !lister->d->rootFileItem && lister->d->url == _url ) { 00155 lister->d->rootFileItem = itemU->rootItem; 00156 } 00157 00158 lister->addNewItems( *(itemU->lstItems) ); 00159 lister->emitItems(); 00160 00161 // _url is already in use, so there is already an entry in urlsCurrentlyHeld 00162 assert( urlsCurrentlyHeld[urlStr + ":" + urlReferenceStr] ); 00163 urlsCurrentlyHeld[urlStr + ":" + urlReferenceStr]->append( lister ); 00164 00165 lister->d->complete = oldState; 00166 00167 lister->emitCompleted( _url ); 00168 if ( lister->d->complete ) { 00169 emit lister->completed(); 00170 } 00171 00172 if ( _reload || !itemU->complete ) { 00173 updateDirectory( _url ); 00174 } 00175 } 00176 else if ( !_reload && (itemC = itemsCached.take( urlStr )) ) 00177 { 00178 kdDebug(7004) << "listDir: Entry in cache: " << _url << endl; 00179 00180 itemC->decAutoUpdate(); 00181 itemsInUse.insert( urlStr + ":" + urlReferenceStr, itemC ); 00182 itemU = itemC; 00183 00184 bool oldState = lister->d->complete; 00185 lister->d->complete = false; 00186 00187 emit lister->started( _url ); 00188 00189 if ( !lister->d->rootFileItem && lister->d->url == _url ) { 00190 lister->d->rootFileItem = itemC->rootItem; 00191 } 00192 00193 lister->addNewItems( *(itemC->lstItems) ); 00194 lister->emitItems(); 00195 00196 Q_ASSERT( !urlsCurrentlyHeld[urlStr + ":" + urlReferenceStr] ); 00197 TQPtrList<KDirLister> *list = new TQPtrList<KDirLister>; 00198 list->append( lister ); 00199 urlsCurrentlyHeld.insert( urlStr + ":" + urlReferenceStr, list ); 00200 00201 lister->d->complete = oldState; 00202 00203 lister->emitCompleted( _url ); 00204 if ( lister->d->complete ) { 00205 emit lister->completed(); 00206 } 00207 00208 if ( !itemC->complete ) { 00209 updateDirectory( _url ); 00210 } 00211 } 00212 else // dir not in cache or _reload is true 00213 { 00214 kdDebug(7004) << "listDir: Entry not in cache or reloaded: " << _url << endl; 00215 00216 TQPtrList<KDirLister> *list = new TQPtrList<KDirLister>; 00217 list->append( lister ); 00218 urlsCurrentlyListed.insert( urlStr + ":" + urlReferenceStr, list ); 00219 00220 itemsCached.remove( urlStr ); 00221 itemU = new DirItem( _url ); 00222 itemsInUse.insert( urlStr + ":" + urlReferenceStr, itemU ); 00223 00224 // // we have a limit of MAX_JOBS_PER_LISTER concurrently running jobs 00225 // if ( lister->numJobs() >= MAX_JOBS_PER_LISTER ) 00226 // { 00227 // lstPendingUpdates.append( _url ); 00228 // } 00229 // else 00230 // { 00231 00232 if ( lister->d->url == _url ) { 00233 lister->d->rootFileItem = 0; 00234 } 00235 00236 TDEIO::ListJob* job = TDEIO::listDir( _url, false /* no default GUI */ ); 00237 jobs.insert( job, TQValueList<TDEIO::UDSEntry>() ); 00238 00239 lister->jobStarted( job ); 00240 lister->connectJob( job ); 00241 00242 if ( lister->d->window ) { 00243 job->setWindow( lister->d->window ); 00244 } 00245 00246 connect( job, TQT_SIGNAL( entries( TDEIO::Job *, const TDEIO::UDSEntryList & ) ), 00247 this, TQT_SLOT( slotEntries( TDEIO::Job *, const TDEIO::UDSEntryList & ) ) ); 00248 connect( job, TQT_SIGNAL( result( TDEIO::Job * ) ), 00249 this, TQT_SLOT( slotResult( TDEIO::Job * ) ) ); 00250 connect( job, TQT_SIGNAL( redirection( TDEIO::Job *, const KURL & ) ), 00251 this, TQT_SLOT( slotRedirection( TDEIO::Job *, const KURL & ) ) ); 00252 00253 emit lister->started( _url ); 00254 00255 // } 00256 } 00257 } 00258 else 00259 { 00260 kdDebug(7004) << "listDir: Entry currently being listed: " << _url << endl; 00261 00262 emit lister->started( _url ); 00263 00264 urlsCurrentlyListed[urlStr + ":" + urlReferenceStr]->append( lister ); 00265 00266 TDEIO::ListJob *job = jobForUrl( urlStr + ":" + urlReferenceStr ); 00267 Q_ASSERT( job ); 00268 00269 lister->jobStarted( job ); 00270 lister->connectJob( job ); 00271 00272 Q_ASSERT( itemU ); 00273 00274 if ( !lister->d->rootFileItem && lister->d->url == _url ) { 00275 lister->d->rootFileItem = itemU->rootItem; 00276 } 00277 00278 lister->addNewItems( *(itemU->lstItems) ); 00279 lister->emitItems(); 00280 } 00281 00282 // automatic updating of directories 00283 if ( lister->d->autoUpdate ) { 00284 itemU->incAutoUpdate(); 00285 } 00286 00287 return true; 00288 } 00289 00290 bool KDirListerCache::validURL( const KDirLister *lister, const KURL& url ) const 00291 { 00292 if ( !url.isValid() ) 00293 { 00294 if ( lister->d->autoErrorHandling ) 00295 { 00296 TQString tmp = i18n("Malformed URL\n%1").arg( url.prettyURL() ); 00297 KMessageBox::error( lister->d->errorParent, tmp ); 00298 } 00299 return false; 00300 } 00301 00302 if ( !KProtocolInfo::supportsListing( url ) ) 00303 { 00304 if ( lister->d->autoErrorHandling ) 00305 { 00306 // TODO: this message should be changed during next string unfreeze! 00307 TQString tmp = i18n("Malformed URL\n%1").arg( url.prettyURL() ); 00308 KMessageBox::error( lister->d->errorParent, tmp ); 00309 } 00310 return false; 00311 } 00312 00313 return true; 00314 } 00315 00316 void KDirListerCache::stop( KDirLister *lister ) 00317 { 00318 #ifdef DEBUG_CACHE 00319 printDebug(); 00320 #endif 00321 kdDebug(7004) << k_funcinfo << "lister: " << lister << endl; 00322 bool stopped = false; 00323 00324 TQDictIterator< TQPtrList<KDirLister> > it( urlsCurrentlyListed ); 00325 TQPtrList<KDirLister> *listers; 00326 int curIndex; 00327 while ( (listers = it.current()) ) 00328 { 00329 curIndex = listers->findRef( lister ); 00330 if ( curIndex > -1 ) 00331 { 00332 // lister is listing url 00333 TQString url = it.currentKey(); 00334 KDirLister* curLister = listers->at( curIndex ); 00335 00336 //kdDebug(7004) << k_funcinfo << " found lister in list - for " << url << endl; 00337 bool ret = listers->removeRef( lister ); 00338 Q_ASSERT( ret ); 00339 00340 TDEIO::ListJob *job = jobForUrl( url ); 00341 if ( job ) { 00342 lister->jobDone( job ); 00343 } 00344 00345 // move lister to urlsCurrentlyHeld 00346 TQPtrList<KDirLister> *holders = urlsCurrentlyHeld[url]; 00347 if ( !holders ) 00348 { 00349 holders = new TQPtrList<KDirLister>; 00350 urlsCurrentlyHeld.insert( url, holders ); 00351 } 00352 00353 holders->append( lister ); 00354 00355 emit lister->canceled( curLister->d->url ); 00356 00357 //kdDebug(7004) << k_funcinfo << "remaining list: " << listers->count() << " listers" << endl; 00358 00359 if ( listers->isEmpty() ) 00360 { 00361 // kill the job since it isn't used any more 00362 if ( job ) { 00363 killJob( job ); 00364 } 00365 00366 urlsCurrentlyListed.remove( url ); 00367 } 00368 00369 stopped = true; 00370 } 00371 else 00372 ++it; 00373 } 00374 00375 if ( stopped ) 00376 { 00377 emit lister->canceled(); 00378 lister->d->complete = true; 00379 } 00380 00381 // this is wrong if there is still an update running! 00382 //Q_ASSERT( lister->d->complete ); 00383 } 00384 00385 void KDirListerCache::stop( KDirLister *lister, const KURL& _u ) 00386 { 00387 TQString urlStr( _u.url(-1) ); 00388 TQString urlReferenceStr = _u.internalReferenceURL(); 00389 KURL _url( urlStr ); 00390 00391 // TODO: consider to stop all the "child jobs" of _url as well 00392 kdDebug(7004) << k_funcinfo << lister << " url=" << _url << endl; 00393 00394 TQPtrList<KDirLister> *listers = urlsCurrentlyListed[urlStr + ":" + urlReferenceStr]; 00395 if ( !listers || !listers->removeRef( lister ) ) 00396 return; 00397 00398 // move lister to urlsCurrentlyHeld 00399 TQPtrList<KDirLister> *holders = urlsCurrentlyHeld[urlStr + ":" + urlReferenceStr]; 00400 if ( !holders ) 00401 { 00402 holders = new TQPtrList<KDirLister>; 00403 urlsCurrentlyHeld.insert( urlStr + ":" + urlReferenceStr, holders ); 00404 } 00405 00406 holders->append( lister ); 00407 00408 00409 TDEIO::ListJob *job = jobForUrl( urlStr + ":" + urlReferenceStr ); 00410 if ( job ) { 00411 lister->jobDone( job ); 00412 } 00413 00414 emit lister->canceled( _url ); 00415 00416 if ( listers->isEmpty() ) 00417 { 00418 // kill the job since it isn't used any more 00419 if ( job ) 00420 killJob( job ); 00421 00422 urlsCurrentlyListed.remove( urlStr + ":" + urlReferenceStr ); 00423 } 00424 00425 if ( lister->numJobs() == 0 ) 00426 { 00427 lister->d->complete = true; 00428 00429 // we killed the last job for lister 00430 emit lister->canceled(); 00431 } 00432 } 00433 00434 void KDirListerCache::setAutoUpdate( KDirLister *lister, bool enable ) 00435 { 00436 // IMPORTANT: this method does not check for the current autoUpdate state! 00437 00438 for ( KURL::List::Iterator it = lister->d->lstDirs.begin(); 00439 it != lister->d->lstDirs.end(); ++it ) 00440 { 00441 if ( enable ) { 00442 itemsInUse[(*it).url() + ":" + (*it).internalReferenceURL()]->incAutoUpdate(); 00443 } 00444 else { 00445 itemsInUse[(*it).url() + ":" + (*it).internalReferenceURL()]->decAutoUpdate(); 00446 } 00447 } 00448 } 00449 00450 void KDirListerCache::forgetDirs( KDirLister *lister ) 00451 { 00452 kdDebug(7004) << k_funcinfo << lister << endl; 00453 00454 emit lister->clear(); 00455 00456 // forgetDirs() will modify lstDirs, make a copy first 00457 KURL::List lstDirsCopy = lister->d->lstDirs; 00458 for ( KURL::List::Iterator it = lstDirsCopy.begin(); 00459 it != lstDirsCopy.end(); ++it ) 00460 { 00461 forgetDirs( lister, *it, false ); 00462 } 00463 } 00464 00465 void KDirListerCache::forgetDirs( KDirLister *lister, const KURL& _url, bool notify ) 00466 { 00467 kdDebug(7004) << k_funcinfo << lister << " _url: " << _url << endl; 00468 00469 KURL url( _url ); 00470 url.adjustPath( -1 ); 00471 TQString urlStr = url.url(); 00472 TQString urlReferenceStr = url.internalReferenceURL(); 00473 TQPtrList<KDirLister> *holders = urlsCurrentlyHeld[urlStr + ":" + urlReferenceStr]; 00474 //Q_ASSERT( holders ); 00475 if ( holders ) 00476 { 00477 holders->removeRef( lister ); 00478 } 00479 00480 // remove the dir from lister->d->lstDirs so that it doesn't contain things 00481 // that itemsInUse doesn't. When emitting the canceled signals lstDirs must 00482 // not contain anything that itemsInUse does not contain. (otherwise it 00483 // might crash in findByName()). 00484 lister->d->lstDirs.remove( lister->d->lstDirs.find( url ) ); 00485 00486 DirItem *item = itemsInUse[urlStr + ":" + urlReferenceStr]; 00487 00488 if ( holders && holders->isEmpty() ) 00489 { 00490 urlsCurrentlyHeld.remove( urlStr + ":" + urlReferenceStr ); // this deletes the (empty) holders list 00491 if ( !urlsCurrentlyListed[urlStr + ":" + urlReferenceStr] ) 00492 { 00493 // item not in use anymore -> move into cache if complete 00494 itemsInUse.remove( urlStr + ":" + urlReferenceStr ); 00495 00496 // this job is a running update 00497 TDEIO::ListJob *job = jobForUrl( urlStr + ":" + urlReferenceStr ); 00498 if ( job ) 00499 { 00500 lister->jobDone( job ); 00501 killJob( job ); 00502 kdDebug(7004) << k_funcinfo << "Killing update job for " << urlStr << endl; 00503 00504 emit lister->canceled( url ); 00505 if ( lister->numJobs() == 0 ) 00506 { 00507 lister->d->complete = true; 00508 emit lister->canceled(); 00509 } 00510 } 00511 00512 if ( notify ) 00513 emit lister->clear( url ); 00514 00515 if ( item && item->complete ) 00516 { 00517 kdDebug(7004) << k_funcinfo << lister << " item moved into cache: " << url << endl; 00518 itemsCached.insert( urlStr, item ); // TODO: may return false!! 00519 00520 // Should we forget the dir for good, or keep a watch on it? 00521 // Generally keep a watch, except when it would prevent 00522 // unmounting a removable device (#37780) 00523 const bool isLocal = item->url.isLocalFile(); 00524 const bool isManuallyMounted = isLocal && TDEIO::manually_mounted( item->url.path() ); 00525 bool containsManuallyMounted = false; 00526 if ( !isManuallyMounted && item->lstItems && isLocal ) 00527 { 00528 // Look for a manually-mounted directory inside 00529 // If there's one, we can't keep a watch either, FAM would prevent unmounting the CDROM 00530 // I hope this isn't too slow (manually_mounted caches the last device so most 00531 // of the time this is just a stat per subdir) 00532 KFileItemListIterator kit( *item->lstItems ); 00533 for ( ; kit.current() && !containsManuallyMounted; ++kit ) 00534 if ( (*kit)->isDir() && TDEIO::manually_mounted( (*kit)->url().path() ) ) 00535 containsManuallyMounted = true; 00536 } 00537 00538 if ( isManuallyMounted || containsManuallyMounted ) 00539 { 00540 kdDebug(7004) << "Not adding a watch on " << item->url << " because it " << 00541 ( isManuallyMounted ? "is manually mounted" : "contains a manually mounted subdir" ) << endl; 00542 item->complete = false; // set to "dirty" 00543 } 00544 else 00545 item->incAutoUpdate(); // keep watch 00546 } 00547 else 00548 { 00549 delete item; 00550 item = 0; 00551 } 00552 } 00553 } 00554 00555 if ( item && lister->d->autoUpdate ) 00556 item->decAutoUpdate(); 00557 } 00558 00559 void KDirListerCache::updateDirectory( const KURL& _dir ) 00560 { 00561 kdDebug(7004) << k_funcinfo << _dir << endl; 00562 00563 TQString urlStr = _dir.url(-1); 00564 TQString urlReferenceStr = _dir.internalReferenceURL(); 00565 if ( !checkUpdate( _dir, -1 ) ) { 00566 return; 00567 } 00568 00569 // A job can be running to 00570 // - only list a new directory: the listers are in urlsCurrentlyListed 00571 // - only update a directory: the listers are in urlsCurrentlyHeld 00572 // - update a currently running listing: the listers are in urlsCurrentlyListed 00573 // and urlsCurrentlyHeld 00574 00575 TQPtrList<KDirLister> *listers = urlsCurrentlyListed[urlStr + ":" + urlReferenceStr]; 00576 TQPtrList<KDirLister> *holders = urlsCurrentlyHeld[urlStr + ":" + urlReferenceStr]; 00577 00578 // restart the job for _dir if it is running already 00579 bool killed = false; 00580 TQWidget *window = 0; 00581 TDEIO::ListJob *job = jobForUrl( urlStr + ":" + urlReferenceStr ); 00582 if ( job ) 00583 { 00584 window = job->window(); 00585 00586 killJob( job ); 00587 killed = true; 00588 00589 if ( listers ) { 00590 for ( KDirLister *kdl = listers->first(); kdl; kdl = listers->next() ) { 00591 kdl->jobDone( job ); 00592 } 00593 } 00594 00595 if ( holders ) { 00596 for ( KDirLister *kdl = holders->first(); kdl; kdl = holders->next() ) { 00597 kdl->jobDone( job ); 00598 } 00599 } 00600 } 00601 kdDebug(7004) << k_funcinfo << "Killed = " << killed << endl; 00602 00603 // we don't need to emit canceled signals since we only replaced the job, 00604 // the listing is continuing. 00605 00606 Q_ASSERT( !listers || (listers && killed) ); 00607 00608 job = TDEIO::listDir( _dir, false /* no default GUI */ ); 00609 jobs.insert( job, TQValueList<TDEIO::UDSEntry>() ); 00610 00611 connect( job, TQT_SIGNAL(entries( TDEIO::Job *, const TDEIO::UDSEntryList & )), 00612 this, TQT_SLOT(slotUpdateEntries( TDEIO::Job *, const TDEIO::UDSEntryList & )) ); 00613 connect( job, TQT_SIGNAL(result( TDEIO::Job * )), 00614 this, TQT_SLOT(slotUpdateResult( TDEIO::Job * )) ); 00615 00616 kdDebug(7004) << k_funcinfo << "update started in " << _dir << endl; 00617 00618 if ( listers ) { 00619 for ( KDirLister *kdl = listers->first(); kdl; kdl = listers->next() ) { 00620 kdl->jobStarted( job ); 00621 } 00622 } 00623 00624 if ( holders ) 00625 { 00626 if ( !killed ) 00627 { 00628 bool first = true; 00629 for ( KDirLister *kdl = holders->first(); kdl; kdl = holders->next() ) 00630 { 00631 kdl->jobStarted( job ); 00632 if ( first && kdl->d->window ) 00633 { 00634 first = false; 00635 job->setWindow( kdl->d->window ); 00636 } 00637 emit kdl->started( _dir ); 00638 } 00639 } 00640 else 00641 { 00642 job->setWindow( window ); 00643 00644 for ( KDirLister *kdl = holders->first(); kdl; kdl = holders->next() ) { 00645 kdl->jobStarted( job ); 00646 } 00647 } 00648 } 00649 } 00650 00651 bool KDirListerCache::checkUpdate( const KURL& _dir, int truncationMode ) 00652 { 00653 if ( !itemsInUse[_dir.url(truncationMode) + ":" + _dir.internalReferenceURL()] ) 00654 { 00655 DirItem *item = itemsCached[_dir.url(truncationMode)]; 00656 if ( item && item->complete ) 00657 { 00658 item->complete = false; 00659 item->decAutoUpdate(); 00660 // Hmm, this debug output might include login/password from the _dir URL. 00661 //kdDebug(7004) << k_funcinfo << "directory " << _dir << " not in use, marked dirty." << endl; 00662 } 00663 //else 00664 //kdDebug(7004) << k_funcinfo << "aborted, directory " << _dir << " not in cache." << endl; 00665 00666 return false; 00667 } 00668 else 00669 return true; 00670 } 00671 00672 KFileItemList *KDirListerCache::itemsForDir( const KURL &_dir ) const 00673 { 00674 TQString urlStr = _dir.url(-1); 00675 TQString urlReferenceStr = _dir.internalReferenceURL(); 00676 DirItem *item = itemsInUse[ urlStr + ":" + urlReferenceStr ]; 00677 if ( !item ) { 00678 item = itemsCached[ urlStr ]; 00679 } 00680 return item ? item->lstItems : 0; 00681 } 00682 00683 KFileItem *KDirListerCache::findByName( const KDirLister *lister, const TQString& _name ) const 00684 { 00685 Q_ASSERT( lister ); 00686 00687 for ( KURL::List::Iterator it = lister->d->lstDirs.begin(); 00688 it != lister->d->lstDirs.end(); ++it ) 00689 { 00690 KFileItemListIterator kit( *itemsInUse[(*it).url() + ":" + (*it).internalReferenceURL()]->lstItems ); 00691 for ( ; kit.current(); ++kit ) 00692 if ( (*kit)->name() == _name ) 00693 return (*kit); 00694 } 00695 00696 return 0L; 00697 } 00698 00699 KFileItem *KDirListerCache::findByURL( const KDirLister *lister, const KURL& _u ) const 00700 { 00701 KURL _url = _u; 00702 _url.adjustPath(-1); 00703 00704 KURL parentDir( _url ); 00705 parentDir.setPath( parentDir.directory() ); 00706 00707 // If lister is set, check that it contains this dir 00708 if ( lister && !lister->d->lstDirs.contains( parentDir ) ) 00709 return 0L; 00710 00711 KFileItemList *itemList = itemsForDir( parentDir ); 00712 if ( itemList ) 00713 { 00714 KFileItemListIterator kit( *itemList ); 00715 for ( ; kit.current(); ++kit ) 00716 if ( (*kit)->url() == _url ) 00717 return (*kit); 00718 } 00719 return 0L; 00720 } 00721 00722 void KDirListerCache::FilesAdded( const KURL &dir ) 00723 { 00724 kdDebug(7004) << k_funcinfo << dir << endl; 00725 updateDirectory( dir ); 00726 } 00727 00728 void KDirListerCache::FilesRemoved( const KURL::List &fileList ) 00729 { 00730 kdDebug(7004) << k_funcinfo << endl; 00731 KURL::List::ConstIterator it = fileList.begin(); 00732 for ( ; it != fileList.end() ; ++it ) 00733 { 00734 // emit the deleteItem signal if this file was shown in any view 00735 KFileItem *fileitem = 0L; 00736 KURL parentDir( *it ); 00737 parentDir.setPath( parentDir.directory() ); 00738 KFileItemList *lstItems = itemsForDir( parentDir ); 00739 if ( lstItems ) 00740 { 00741 KFileItem *fit = lstItems->first(); 00742 for ( ; fit; fit = lstItems->next() ) 00743 if ( fit->url() == *it ) { 00744 fileitem = fit; 00745 lstItems->take(); // remove fileitem from list 00746 break; 00747 } 00748 } 00749 00750 // Tell the views about it before deleting the KFileItems. They might need the subdirs' 00751 // file items (see the dirtree). 00752 if ( fileitem ) 00753 { 00754 TQPtrList<KDirLister> *listers = urlsCurrentlyHeld[parentDir.url() + ":" + parentDir.internalReferenceURL()]; 00755 if ( listers ) { 00756 for ( KDirLister *kdl = listers->first(); kdl; kdl = listers->next() ) { 00757 kdl->emitDeleteItem( fileitem ); 00758 } 00759 } 00760 } 00761 00762 // If we found a fileitem, we can test if it's a dir. If not, we'll go to deleteDir just in case. 00763 if ( !fileitem || fileitem->isDir() ) 00764 { 00765 // in case of a dir, check if we have any known children, there's much to do in that case 00766 // (stopping jobs, removing dirs from cache etc.) 00767 deleteDir( *it ); 00768 } 00769 00770 // now remove the item itself 00771 delete fileitem; 00772 } 00773 } 00774 00775 void KDirListerCache::FilesChanged( const KURL::List &fileList ) 00776 { 00777 KURL::List dirsToUpdate; 00778 kdDebug(7004) << k_funcinfo << "only half implemented" << endl; 00779 KURL::List::ConstIterator it = fileList.begin(); 00780 for ( ; it != fileList.end() ; ++it ) 00781 { 00782 if ( ( *it ).isLocalFile() ) 00783 { 00784 kdDebug(7004) << "KDirListerCache::FilesChanged " << *it << endl; 00785 KFileItem *fileitem = findByURL( 0, *it ); 00786 if ( fileitem ) 00787 { 00788 // we need to refresh the item, because e.g. the permissions can have changed. 00789 aboutToRefreshItem( fileitem ); 00790 fileitem->refresh(); 00791 emitRefreshItem( fileitem ); 00792 } 00793 else { 00794 kdDebug(7004) << "item not found" << endl; 00795 } 00796 } else { 00797 // For remote files, refresh() won't be able to figure out the new information. 00798 // Let's update the dir. 00799 KURL dir( *it ); 00800 dir.setPath( dir.directory( true ) ); 00801 if ( dirsToUpdate.find( dir ) == dirsToUpdate.end() ) { 00802 dirsToUpdate.prepend( dir ); 00803 } 00804 } 00805 } 00806 00807 KURL::List::ConstIterator itdir = dirsToUpdate.begin(); 00808 for ( ; itdir != dirsToUpdate.end() ; ++itdir ) { 00809 updateDirectory( *itdir ); 00810 } 00811 // ## TODO problems with current jobs listing/updating that dir 00812 // ( see kde-2.2.2's kdirlister ) 00813 } 00814 00815 void KDirListerCache::FileRenamed( const KURL &src, const KURL &dst ) 00816 { 00817 kdDebug(7004) << k_funcinfo << src.prettyURL() << " -> " << dst.prettyURL() << endl; 00818 #ifdef DEBUG_CACHE 00819 printDebug(); 00820 #endif 00821 00822 // Somehow this should only be called if src is a dir. But how could we know if it is? 00823 // (Note that looking into itemsInUse isn't good enough. One could rename a subdir in a view.) 00824 renameDir( src, dst ); 00825 00826 // Now update the KFileItem representing that file or dir (not exclusive with the above!) 00827 KURL oldurl( src ); 00828 oldurl.adjustPath( -1 ); 00829 KFileItem *fileitem = findByURL( 0, oldurl ); 00830 if ( fileitem ) 00831 { 00832 if ( !fileitem->isLocalFile() && !fileitem->localPath().isEmpty() ) // it uses UDS_LOCAL_PATH? ouch, needs an update then 00833 FilesChanged( src ); 00834 else 00835 { 00836 aboutToRefreshItem( fileitem ); 00837 fileitem->setURL( dst ); 00838 fileitem->refreshMimeType(); 00839 emitRefreshItem( fileitem ); 00840 } 00841 } 00842 #ifdef DEBUG_CACHE 00843 printDebug(); 00844 #endif 00845 } 00846 00847 void KDirListerCache::aboutToRefreshItem( KFileItem *fileitem ) 00848 { 00849 // Look whether this item was shown in any view, i.e. held by any dirlister 00850 KURL parentDir( fileitem->url() ); 00851 parentDir.setPath( parentDir.directory() ); 00852 TQString parentDirURL = parentDir.url(); 00853 TQString parentDirReferenceURL = parentDir.internalReferenceURL(); 00854 TQPtrList<KDirLister> *listers = urlsCurrentlyHeld[parentDirURL + ":" + parentDirReferenceURL]; 00855 if ( listers ) 00856 for ( KDirLister *kdl = listers->first(); kdl; kdl = listers->next() ) 00857 kdl->aboutToRefreshItem( fileitem ); 00858 00859 // Also look in urlsCurrentlyListed, in case the user manages to rename during a listing 00860 listers = urlsCurrentlyListed[parentDirURL + ":" + parentDirReferenceURL]; 00861 if ( listers ) 00862 for ( KDirLister *kdl = listers->first(); kdl; kdl = listers->next() ) 00863 kdl->aboutToRefreshItem( fileitem ); 00864 } 00865 00866 void KDirListerCache::emitRefreshItem( KFileItem *fileitem ) 00867 { 00868 // Look whether this item was shown in any view, i.e. held by any dirlister 00869 KURL parentDir( fileitem->url() ); 00870 parentDir.setPath( parentDir.directory() ); 00871 TQString parentDirURL = parentDir.url(); 00872 TQString parentDirReferenceURL = parentDir.internalReferenceURL(); 00873 TQPtrList<KDirLister> *listers = urlsCurrentlyHeld[parentDirURL + ":" + parentDirReferenceURL]; 00874 if ( listers ) 00875 for ( KDirLister *kdl = listers->first(); kdl; kdl = listers->next() ) 00876 { 00877 kdl->addRefreshItem( fileitem ); 00878 kdl->emitItems(); 00879 } 00880 00881 // Also look in urlsCurrentlyListed, in case the user manages to rename during a listing 00882 listers = urlsCurrentlyListed[parentDirURL + ":" + parentDirReferenceURL]; 00883 if ( listers ) 00884 for ( KDirLister *kdl = listers->first(); kdl; kdl = listers->next() ) 00885 { 00886 kdl->addRefreshItem( fileitem ); 00887 kdl->emitItems(); 00888 } 00889 } 00890 00891 KDirListerCache* KDirListerCache::self() 00892 { 00893 if ( !s_pSelf ) 00894 s_pSelf = sd_KDirListerCache.setObject( s_pSelf, new KDirListerCache ); 00895 00896 return s_pSelf; 00897 } 00898 00899 bool KDirListerCache::exists() 00900 { 00901 return s_pSelf != 0; 00902 } 00903 00904 00905 // private slots 00906 00907 // _file can also be a directory being currently held! 00908 void KDirListerCache::slotFileDirty( const KURL& _url ) 00909 { 00910 kdDebug(7004) << k_funcinfo << _url << endl; 00911 00912 if ( !pendingUpdates[_url.path()] ) 00913 { 00914 KURL dir; 00915 dir.setPath( _url.path() ); 00916 dir.setInternalReferenceURL(_url.internalReferenceURL()); 00917 if ( checkUpdate( dir, -1 ) ) { 00918 updateDirectory( _url ); 00919 } 00920 00921 // the parent directory of _url.path() 00922 dir.setPath( dir.directory() ); 00923 dir.setInternalReferenceURL(_url.internalReferenceURL()); 00924 if ( checkUpdate( dir ) ) 00925 { 00926 // Nice hack to save memory: use the qt object name to store the filename 00927 TQTimer *timer = new TQTimer( this, _url.path().utf8() ); 00928 connect( timer, TQT_SIGNAL(timeout()), this, TQT_SLOT(slotFileDirtyDelayed()) ); 00929 pendingUpdates.insert( _url.path(), timer ); 00930 timer->start( 500, true ); 00931 } 00932 } 00933 } 00934 00935 // delayed updating of files, FAM is flooding us with events 00936 void KDirListerCache::slotFileDirtyDelayed() 00937 { 00938 TQString file = TQString::fromUtf8( TQT_TQOBJECT_CONST(sender())->name() ); 00939 00940 kdDebug(7004) << k_funcinfo << file << endl; 00941 00942 // TODO: do it better: don't always create/delete the TQTimer but reuse it. 00943 // Delete the timer after the parent directory is removed from the cache. 00944 pendingUpdates.remove( file ); 00945 00946 KURL u; 00947 u.setPath( file ); 00948 KFileItem *item = findByURL( 0, u ); // search all items 00949 if ( item ) 00950 { 00951 // we need to refresh the item, because e.g. the permissions can have changed. 00952 aboutToRefreshItem( item ); 00953 item->refresh(); 00954 emitRefreshItem( item ); 00955 } 00956 } 00957 00958 void KDirListerCache::slotFileCreated( const TQString& _file ) 00959 { 00960 kdDebug(7004) << k_funcinfo << _file << endl; 00961 // XXX: how to avoid a complete rescan here? 00962 KURL u; 00963 u.setPath( _file ); 00964 u.setPath( u.directory() ); 00965 FilesAdded( u ); 00966 } 00967 00968 void KDirListerCache::slotFileDeleted( const TQString& _file ) 00969 { 00970 kdDebug(7004) << k_funcinfo << _file << endl; 00971 KURL u; 00972 u.setPath( _file ); 00973 FilesRemoved( u ); 00974 } 00975 00976 void KDirListerCache::slotEntries( TDEIO::Job *job, const TDEIO::UDSEntryList &entries ) 00977 { 00978 KURL url = joburl( static_cast<TDEIO::ListJob *>(job) ); 00979 url.adjustPath(-1); 00980 TQString urlStr = url.url(); 00981 TQString urlReferenceStr = url.internalReferenceURL(); 00982 00983 kdDebug(7004) << k_funcinfo << "new entries for " << url << endl; 00984 00985 DirItem *dir = itemsInUse[urlStr + ":" + urlReferenceStr]; 00986 Q_ASSERT( dir ); 00987 00988 TQPtrList<KDirLister> *listers = urlsCurrentlyListed[urlStr + ":" + urlReferenceStr]; 00989 Q_ASSERT( listers ); 00990 Q_ASSERT( !listers->isEmpty() ); 00991 00992 // check if anyone wants the mimetypes immediately 00993 bool delayedMimeTypes = true; 00994 for ( KDirLister *kdl = listers->first(); kdl; kdl = listers->next() ) { 00995 delayedMimeTypes = delayedMimeTypes && kdl->d->delayedMimeTypes; 00996 } 00997 00998 // avoid creating these QStrings again and again 00999 static const TQString& dot = TDEGlobal::staticQString("."); 01000 static const TQString& dotdot = TDEGlobal::staticQString(".."); 01001 01002 TDEIO::UDSEntryListConstIterator it = entries.begin(); 01003 TDEIO::UDSEntryListConstIterator end = entries.end(); 01004 01005 for ( ; it != end; ++it ) 01006 { 01007 TQString name; 01008 01009 // find out about the name 01010 TDEIO::UDSEntry::ConstIterator entit = (*it).begin(); 01011 for( ; entit != (*it).end(); ++entit ) { 01012 if ( (*entit).m_uds == TDEIO::UDS_NAME ) { 01013 name = (*entit).m_str; 01014 break; 01015 } 01016 } 01017 01018 Q_ASSERT( !name.isEmpty() ); 01019 if ( name.isEmpty() ) { 01020 continue; 01021 } 01022 01023 if ( name == dot ) 01024 { 01025 Q_ASSERT( !dir->rootItem ); 01026 dir->rootItem = new KFileItem( *it, url, delayedMimeTypes, true ); 01027 01028 for ( KDirLister *kdl = listers->first(); kdl; kdl = listers->next() ) { 01029 if ( !kdl->d->rootFileItem && kdl->d->url == url ) { 01030 kdl->d->rootFileItem = dir->rootItem; 01031 } 01032 } 01033 } 01034 else if ( name != dotdot ) 01035 { 01036 KFileItem* item = new KFileItem( *it, url, delayedMimeTypes, true ); 01037 Q_ASSERT( item ); 01038 01039 //kdDebug(7004)<< "Adding item: " << item->url() << endl; 01040 dir->lstItems->append( item ); 01041 01042 for ( KDirLister *kdl = listers->first(); kdl; kdl = listers->next() ) { 01043 kdl->addNewItem( item ); 01044 } 01045 } 01046 } 01047 01048 for ( KDirLister *kdl = listers->first(); kdl; kdl = listers->next() ) { 01049 kdl->emitItems(); 01050 } 01051 } 01052 01053 void KDirListerCache::slotResult( TDEIO::Job *j ) 01054 { 01055 Q_ASSERT( j ); 01056 TDEIO::ListJob *job = static_cast<TDEIO::ListJob *>( j ); 01057 jobs.remove( job ); 01058 01059 KURL jobUrl = joburl( job ); 01060 jobUrl.adjustPath(-1); // need remove trailing slashes again, in case of redirections 01061 TQString jobUrlStr = jobUrl.url(); 01062 TQString jobReferenceUrlStr = jobUrl.internalReferenceURL(); 01063 01064 kdDebug(7004) << k_funcinfo << "finished listing " << jobUrl << endl; 01065 #ifdef DEBUG_CACHE 01066 printDebug(); 01067 #endif 01068 01069 TQPtrList<KDirLister> *listers = urlsCurrentlyListed.take( jobUrlStr + ":" + jobReferenceUrlStr ); 01070 Q_ASSERT( listers ); 01071 01072 // move the directory to the held directories, do it before emitting 01073 // the signals to make sure it exists in KDirListerCache in case someone 01074 // calls listDir during the signal emission 01075 Q_ASSERT( !urlsCurrentlyHeld[jobUrlStr + ":" + jobReferenceUrlStr] ); 01076 urlsCurrentlyHeld.insert( jobUrlStr + ":" + jobReferenceUrlStr, listers ); 01077 01078 KDirLister *kdl; 01079 01080 if ( job->error() ) 01081 { 01082 for ( kdl = listers->first(); kdl; kdl = listers->next() ) 01083 { 01084 kdl->jobDone( job ); 01085 kdl->handleError( job ); 01086 emit kdl->canceled( jobUrl ); 01087 if ( kdl->numJobs() == 0 ) 01088 { 01089 kdl->d->complete = true; 01090 emit kdl->canceled(); 01091 } 01092 } 01093 } 01094 else 01095 { 01096 DirItem *dir = itemsInUse[jobUrlStr + ":" + jobReferenceUrlStr]; 01097 Q_ASSERT( dir ); 01098 dir->complete = true; 01099 01100 for ( kdl = listers->first(); kdl; kdl = listers->next() ) 01101 { 01102 kdl->jobDone( job ); 01103 kdl->emitCompleted( jobUrl ); 01104 if ( kdl->numJobs() == 0 ) 01105 { 01106 kdl->d->complete = true; 01107 emit kdl->completed(); 01108 } 01109 } 01110 } 01111 01112 // TODO: hmm, if there was an error and job is a parent of one or more 01113 // of the pending urls we should cancel it/them as well 01114 processPendingUpdates(); 01115 01116 #ifdef DEBUG_CACHE 01117 printDebug(); 01118 #endif 01119 } 01120 01121 void KDirListerCache::slotRedirection( TDEIO::Job *j, const KURL& url ) 01122 { 01123 Q_ASSERT( j ); 01124 TDEIO::ListJob *job = static_cast<TDEIO::ListJob *>( j ); 01125 01126 KURL oldUrl = job->url(); // here we really need the old url! 01127 KURL newUrl = url; 01128 01129 // strip trailing slashes 01130 oldUrl.adjustPath(-1); 01131 newUrl.adjustPath(-1); 01132 01133 if ( oldUrl == newUrl ) 01134 { 01135 kdDebug(7004) << k_funcinfo << "New redirection url same as old, giving up." << endl; 01136 return; 01137 } 01138 01139 kdDebug(7004) << k_funcinfo << oldUrl.prettyURL() << " -> " << newUrl.prettyURL() << endl; 01140 01141 #ifdef DEBUG_CACHE 01142 printDebug(); 01143 #endif 01144 01145 // I don't think there can be dirItems that are childs of oldUrl. 01146 // Am I wrong here? And even if so, we don't need to delete them, right? 01147 // DF: redirection happens before listDir emits any item. Makes little sense otherwise. 01148 01149 // oldUrl cannot be in itemsCached because only completed items are moved there 01150 DirItem *dir = itemsInUse.take( oldUrl.url() + ":" + oldUrl.internalReferenceURL() ); 01151 Q_ASSERT( dir ); 01152 01153 TQPtrList<KDirLister> *listers = urlsCurrentlyListed.take( oldUrl.url() + ":" + oldUrl.internalReferenceURL() ); 01154 Q_ASSERT( listers ); 01155 Q_ASSERT( !listers->isEmpty() ); 01156 01157 for ( KDirLister *kdl = listers->first(); kdl; kdl = listers->next() ) 01158 { 01159 // TODO: put in own method? 01160 if ( kdl->d->url.equals( oldUrl, true ) ) 01161 { 01162 kdl->d->rootFileItem = 0; 01163 kdl->d->url = newUrl; 01164 } 01165 01166 *kdl->d->lstDirs.find( oldUrl ) = newUrl; 01167 01168 if ( kdl->d->lstDirs.count() == 1 ) 01169 { 01170 emit kdl->clear(); 01171 emit kdl->redirection( newUrl ); 01172 emit kdl->redirection( oldUrl, newUrl ); 01173 } 01174 else 01175 { 01176 emit kdl->clear( oldUrl ); 01177 emit kdl->redirection( oldUrl, newUrl ); 01178 } 01179 } 01180 01181 // when a lister was stopped before the job emits the redirection signal, the old url will 01182 // also be in urlsCurrentlyHeld 01183 TQPtrList<KDirLister> *holders = urlsCurrentlyHeld.take( oldUrl.url() + ":" + oldUrl.internalReferenceURL() ); 01184 if ( holders ) 01185 { 01186 Q_ASSERT( !holders->isEmpty() ); 01187 01188 for ( KDirLister *kdl = holders->first(); kdl; kdl = holders->next() ) 01189 { 01190 kdl->jobStarted( job ); 01191 01192 // do it like when starting a new list-job that will redirect later 01193 emit kdl->started( oldUrl ); 01194 01195 // TODO: maybe don't emit started if there's an update running for newUrl already? 01196 01197 if ( kdl->d->url.equals( oldUrl, true ) ) 01198 { 01199 kdl->d->rootFileItem = 0; 01200 kdl->d->url = newUrl; 01201 } 01202 01203 *kdl->d->lstDirs.find( oldUrl ) = newUrl; 01204 01205 if ( kdl->d->lstDirs.count() == 1 ) 01206 { 01207 emit kdl->clear(); 01208 emit kdl->redirection( newUrl ); 01209 emit kdl->redirection( oldUrl, newUrl ); 01210 } 01211 else 01212 { 01213 emit kdl->clear( oldUrl ); 01214 emit kdl->redirection( oldUrl, newUrl ); 01215 } 01216 } 01217 } 01218 01219 DirItem *newDir = itemsInUse[newUrl.url() + ":" + newUrl.internalReferenceURL()]; 01220 if ( newDir ) 01221 { 01222 kdDebug(7004) << "slotRedirection: " << newUrl.url() << " already in use" << endl; 01223 01224 // only in this case there can newUrl already be in urlsCurrentlyListed or urlsCurrentlyHeld 01225 delete dir; 01226 01227 // get the job if one's running for newUrl already (can be a list-job or an update-job), but 01228 // do not return this 'job', which would happen because of the use of redirectionURL() 01229 TDEIO::ListJob *oldJob = jobForUrl( newUrl.url() + ":" + newUrl.internalReferenceURL(), job ); 01230 01231 // listers of newUrl with oldJob: forget about the oldJob and use the already running one 01232 // which will be converted to an updateJob 01233 TQPtrList<KDirLister> *curListers = urlsCurrentlyListed[newUrl.url() + ":" + newUrl.internalReferenceURL()]; 01234 if ( curListers ) 01235 { 01236 kdDebug(7004) << "slotRedirection: and it is currently listed" << endl; 01237 01238 Q_ASSERT( oldJob ); // ?! 01239 01240 for ( KDirLister *kdl = curListers->first(); kdl; kdl = curListers->next() ) // listers of newUrl 01241 { 01242 kdl->jobDone( oldJob ); 01243 01244 kdl->jobStarted( job ); 01245 kdl->connectJob( job ); 01246 } 01247 01248 // append listers of oldUrl with newJob to listers of newUrl with oldJob 01249 for ( KDirLister *kdl = listers->first(); kdl; kdl = listers->next() ) 01250 curListers->append( kdl ); 01251 } 01252 else { 01253 urlsCurrentlyListed.insert( newUrl.url() + ":" + newUrl.internalReferenceURL(), listers ); 01254 } 01255 01256 if ( oldJob ) // kill the old job, be it a list-job or an update-job 01257 killJob( oldJob ); 01258 01259 // holders of newUrl: use the already running job which will be converted to an updateJob 01260 TQPtrList<KDirLister> *curHolders = urlsCurrentlyHeld[newUrl.url() + ":" + newUrl.internalReferenceURL()]; 01261 if ( curHolders ) 01262 { 01263 kdDebug(7004) << "slotRedirection: and it is currently held." << endl; 01264 01265 for ( KDirLister *kdl = curHolders->first(); kdl; kdl = curHolders->next() ) // holders of newUrl 01266 { 01267 kdl->jobStarted( job ); 01268 emit kdl->started( newUrl ); 01269 } 01270 01271 // append holders of oldUrl to holders of newUrl 01272 if ( holders ) 01273 for ( KDirLister *kdl = holders->first(); kdl; kdl = holders->next() ) 01274 curHolders->append( kdl ); 01275 } 01276 else if ( holders ) 01277 urlsCurrentlyHeld.insert( newUrl.url() + ":" + newUrl.internalReferenceURL(), holders ); 01278 01279 01280 // emit old items: listers, holders. NOT: newUrlListers/newUrlHolders, they already have them listed 01281 // TODO: make this a separate method? 01282 for ( KDirLister *kdl = listers->first(); kdl; kdl = listers->next() ) 01283 { 01284 if ( !kdl->d->rootFileItem && kdl->d->url == newUrl ) 01285 kdl->d->rootFileItem = newDir->rootItem; 01286 01287 kdl->addNewItems( *(newDir->lstItems) ); 01288 kdl->emitItems(); 01289 } 01290 01291 if ( holders ) 01292 { 01293 for ( KDirLister *kdl = holders->first(); kdl; kdl = holders->next() ) 01294 { 01295 if ( !kdl->d->rootFileItem && kdl->d->url == newUrl ) 01296 kdl->d->rootFileItem = newDir->rootItem; 01297 01298 kdl->addNewItems( *(newDir->lstItems) ); 01299 kdl->emitItems(); 01300 } 01301 } 01302 } 01303 else if ( (newDir = itemsCached.take( newUrl.url() )) ) 01304 { 01305 kdDebug(7004) << "slotRedirection: " << newUrl.url() << " is unused, but already in the cache." << endl; 01306 01307 delete dir; 01308 itemsInUse.insert( newUrl.url() + ":" + newUrl.internalReferenceURL(), newDir ); 01309 urlsCurrentlyListed.insert( newUrl.url() + ":" + newUrl.internalReferenceURL(), listers ); 01310 if ( holders ) 01311 urlsCurrentlyHeld.insert( newUrl.url() + ":" + newUrl.internalReferenceURL(), holders ); 01312 01313 // emit old items: listers, holders 01314 for ( KDirLister *kdl = listers->first(); kdl; kdl = listers->next() ) 01315 { 01316 if ( !kdl->d->rootFileItem && kdl->d->url == newUrl ) 01317 kdl->d->rootFileItem = newDir->rootItem; 01318 01319 kdl->addNewItems( *(newDir->lstItems) ); 01320 kdl->emitItems(); 01321 } 01322 01323 if ( holders ) 01324 { 01325 for ( KDirLister *kdl = holders->first(); kdl; kdl = holders->next() ) 01326 { 01327 if ( !kdl->d->rootFileItem && kdl->d->url == newUrl ) 01328 kdl->d->rootFileItem = newDir->rootItem; 01329 01330 kdl->addNewItems( *(newDir->lstItems) ); 01331 kdl->emitItems(); 01332 } 01333 } 01334 } 01335 else 01336 { 01337 kdDebug(7004) << "slotRedirection: " << newUrl.url() << " has not been listed yet." << endl; 01338 01339 delete dir->rootItem; 01340 dir->rootItem = 0; 01341 dir->lstItems->clear(); 01342 dir->redirect( newUrl ); 01343 itemsInUse.insert( newUrl.url() + ":" + newUrl.internalReferenceURL(), dir ); 01344 urlsCurrentlyListed.insert( newUrl.url() + ":" + newUrl.internalReferenceURL(), listers ); 01345 01346 if ( holders ) 01347 urlsCurrentlyHeld.insert( newUrl.url() + ":" + newUrl.internalReferenceURL(), holders ); 01348 else 01349 { 01350 #ifdef DEBUG_CACHE 01351 printDebug(); 01352 #endif 01353 return; // only in this case the job doesn't need to be converted, 01354 } 01355 } 01356 01357 // make the job an update job 01358 job->disconnect( this ); 01359 01360 connect( job, TQT_SIGNAL(entries( TDEIO::Job *, const TDEIO::UDSEntryList & )), 01361 this, TQT_SLOT(slotUpdateEntries( TDEIO::Job *, const TDEIO::UDSEntryList & )) ); 01362 connect( job, TQT_SIGNAL(result( TDEIO::Job * )), 01363 this, TQT_SLOT(slotUpdateResult( TDEIO::Job * )) ); 01364 01365 // FIXME: autoUpdate-Counts!! 01366 01367 #ifdef DEBUG_CACHE 01368 printDebug(); 01369 #endif 01370 } 01371 01372 void KDirListerCache::renameDir( const KURL &oldUrl, const KURL &newUrl ) 01373 { 01374 kdDebug(7004) << k_funcinfo << oldUrl.prettyURL() << " -> " << newUrl.prettyURL() << endl; 01375 TQString oldUrlStr = oldUrl.url(-1); 01376 TQString newUrlStr = newUrl.url(-1); 01377 01378 // Not enough. Also need to look at any child dir, even sub-sub-sub-dir. 01379 //DirItem *dir = itemsInUse.take( oldUrlStr ); 01380 //emitRedirections( oldUrl, url ); 01381 01382 // Look at all dirs being listed/shown 01383 TQDictIterator<DirItem> itu( itemsInUse ); 01384 bool goNext; 01385 while ( itu.current() ) 01386 { 01387 goNext = true; 01388 DirItem *dir = itu.current(); 01389 TQString oldDirURLIndep = itu.currentKey(); 01390 oldDirURLIndep.truncate(oldDirURLIndep.length() - (dir->url.internalReferenceURL().length()+strlen(":"))); 01391 KURL oldDirUrl ( oldDirURLIndep ); 01392 //kdDebug(7004) << "itemInUse: " << oldDirUrl.prettyURL() << endl; 01393 // Check if this dir is oldUrl, or a subfolder of it 01394 if ( oldUrl.isParentOf( oldDirUrl ) ) 01395 { 01396 // TODO should use KURL::cleanpath like isParentOf does 01397 TQString relPath = oldDirUrl.path().mid( oldUrl.path().length() ); 01398 01399 KURL newDirUrl( newUrl ); // take new base 01400 if ( !relPath.isEmpty() ) { 01401 newDirUrl.addPath( relPath ); // add unchanged relative path 01402 } 01403 //kdDebug(7004) << "KDirListerCache::renameDir new url=" << newDirUrl.prettyURL() << endl; 01404 01405 // Update URL in dir item and in itemsInUse 01406 dir->redirect( newDirUrl ); 01407 itemsInUse.remove( itu.currentKey() ); // implies ++itu 01408 itemsInUse.insert( newDirUrl.url(-1), dir ); 01409 goNext = false; // because of the implied ++itu above 01410 if ( dir->lstItems ) 01411 { 01412 // Rename all items under that dir 01413 KFileItemListIterator kit( *dir->lstItems ); 01414 for ( ; kit.current(); ++kit ) 01415 { 01416 KURL oldItemUrl = (*kit)->url(); 01417 TQString oldItemUrlStr( oldItemUrl.url(-1) ); 01418 KURL newItemUrl( oldItemUrl ); 01419 newItemUrl.setPath( newDirUrl.path() ); 01420 newItemUrl.addPath( oldItemUrl.fileName() ); 01421 kdDebug(7004) << "KDirListerCache::renameDir renaming " << oldItemUrlStr << " to " << newItemUrl.url() << endl; 01422 (*kit)->setURL( newItemUrl ); 01423 } 01424 } 01425 emitRedirections( oldDirUrl, newDirUrl ); 01426 } 01427 if ( goNext ) 01428 ++itu; 01429 } 01430 01431 // Is oldUrl a directory in the cache? 01432 // Remove any child of oldUrl from the cache - even if the renamed dir itself isn't in it! 01433 removeDirFromCache( oldUrl ); 01434 // TODO rename, instead. 01435 } 01436 01437 void KDirListerCache::emitRedirections( const KURL &oldUrl, const KURL &url ) 01438 { 01439 kdDebug(7004) << k_funcinfo << oldUrl.prettyURL() << " -> " << url.prettyURL() << endl; 01440 TQString oldUrlStr = oldUrl.url(-1); 01441 TQString urlStr = url.url(-1); 01442 TQString oldReferenceUrlStr = oldUrl.internalReferenceURL(); 01443 TQString urlReferenceStr = url.internalReferenceURL(); 01444 01445 TDEIO::ListJob *job = jobForUrl( oldUrlStr + ":" + oldReferenceUrlStr ); 01446 if ( job ) 01447 killJob( job ); 01448 01449 // Check if we were listing this dir. Need to abort and restart with new name in that case. 01450 TQPtrList<KDirLister> *listers = urlsCurrentlyListed.take( oldUrlStr + ":" + oldReferenceUrlStr ); 01451 if ( listers ) 01452 { 01453 // Tell the world that the job listing the old url is dead. 01454 for ( KDirLister *kdl = listers->first(); kdl; kdl = listers->next() ) 01455 { 01456 if ( job ) 01457 kdl->jobDone( job ); 01458 01459 emit kdl->canceled( oldUrl ); 01460 } 01461 01462 urlsCurrentlyListed.insert( urlStr + ":" + urlReferenceStr, listers ); 01463 } 01464 01465 // Check if we are currently displaying this directory (odds opposite wrt above) 01466 // Update urlsCurrentlyHeld dict with new URL 01467 TQPtrList<KDirLister> *holders = urlsCurrentlyHeld.take( oldUrlStr + ":" + oldReferenceUrlStr ); 01468 if ( holders ) 01469 { 01470 if ( job ) 01471 for ( KDirLister *kdl = holders->first(); kdl; kdl = holders->next() ) 01472 kdl->jobDone( job ); 01473 01474 urlsCurrentlyHeld.insert( urlStr + ":" + urlReferenceStr, holders ); 01475 } 01476 01477 if ( listers ) 01478 { 01479 updateDirectory( url ); 01480 01481 // Tell the world about the new url 01482 for ( KDirLister *kdl = listers->first(); kdl; kdl = listers->next() ) 01483 emit kdl->started( url ); 01484 } 01485 01486 if ( holders ) 01487 { 01488 // And notify the dirlisters of the redirection 01489 for ( KDirLister *kdl = holders->first(); kdl; kdl = holders->next() ) 01490 { 01491 *kdl->d->lstDirs.find( oldUrl ) = url; 01492 01493 if ( kdl->d->lstDirs.count() == 1 ) 01494 emit kdl->redirection( url ); 01495 01496 emit kdl->redirection( oldUrl, url ); 01497 } 01498 } 01499 } 01500 01501 void KDirListerCache::removeDirFromCache( const KURL& dir ) 01502 { 01503 kdDebug(7004) << "KDirListerCache::removeDirFromCache " << dir.prettyURL() << endl; 01504 TQCacheIterator<DirItem> itc( itemsCached ); 01505 while ( itc.current() ) 01506 { 01507 if ( dir.isParentOf( KURL( itc.currentKey() ) ) ) 01508 itemsCached.remove( itc.currentKey() ); 01509 else 01510 ++itc; 01511 } 01512 } 01513 01514 void KDirListerCache::slotUpdateEntries( TDEIO::Job* job, const TDEIO::UDSEntryList& list ) 01515 { 01516 jobs[static_cast<TDEIO::ListJob*>(job)] += list; 01517 } 01518 01519 void KDirListerCache::slotUpdateResult( TDEIO::Job * j ) 01520 { 01521 Q_ASSERT( j ); 01522 TDEIO::ListJob *job = static_cast<TDEIO::ListJob *>( j ); 01523 01524 KURL jobUrl = joburl( job ); 01525 jobUrl.adjustPath(-1); // need remove trailing slashes again, in case of redirections 01526 TQString jobUrlStr = jobUrl.url(); 01527 TQString jobReferenceUrlStr = jobUrl.internalReferenceURL(); 01528 01529 kdDebug(7004) << k_funcinfo << "finished update " << jobUrl << endl; 01530 01531 KDirLister *kdl; 01532 01533 TQPtrList<KDirLister> *listers = urlsCurrentlyHeld[jobUrlStr + ":" + jobReferenceUrlStr]; 01534 TQPtrList<KDirLister> *tmpLst = urlsCurrentlyListed.take( jobUrlStr + ":" + jobReferenceUrlStr ); 01535 01536 if ( tmpLst ) 01537 { 01538 if ( listers ) 01539 for ( kdl = tmpLst->first(); kdl; kdl = tmpLst->next() ) 01540 { 01541 Q_ASSERT( listers->containsRef( kdl ) == 0 ); 01542 listers->append( kdl ); 01543 } 01544 else 01545 { 01546 listers = tmpLst; 01547 urlsCurrentlyHeld.insert( jobUrlStr + ":" + jobReferenceUrlStr, listers ); 01548 } 01549 } 01550 01551 // once we are updating dirs that are only in the cache this will fail! 01552 Q_ASSERT( listers ); 01553 01554 if ( job->error() ) 01555 { 01556 for ( kdl = listers->first(); kdl; kdl = listers->next() ) 01557 { 01558 kdl->jobDone( job ); 01559 01560 //don't bother the user 01561 //kdl->handleError( job ); 01562 01563 emit kdl->canceled( jobUrl ); 01564 if ( kdl->numJobs() == 0 ) 01565 { 01566 kdl->d->complete = true; 01567 emit kdl->canceled(); 01568 } 01569 } 01570 01571 jobs.remove( job ); 01572 01573 // TODO: if job is a parent of one or more 01574 // of the pending urls we should cancel them 01575 processPendingUpdates(); 01576 return; 01577 } 01578 01579 DirItem *dir = itemsInUse[jobUrlStr + ":" + jobReferenceUrlStr]; 01580 dir->complete = true; 01581 01582 01583 // check if anyone wants the mimetypes immediately 01584 bool delayedMimeTypes = true; 01585 for ( kdl = listers->first(); kdl; kdl = listers->next() ) { 01586 delayedMimeTypes = delayedMimeTypes && kdl->d->delayedMimeTypes; 01587 } 01588 01589 // should be enough to get reasonable speed in most cases 01590 TQDict<KFileItem> fileItems( 9973 ); 01591 01592 KFileItemListIterator kit ( *(dir->lstItems) ); 01593 01594 // Unmark all items in url 01595 for ( ; kit.current(); ++kit ) 01596 { 01597 (*kit)->unmark(); 01598 if (!((*kit)->listerURL().isEmpty())) { 01599 fileItems.insert( (*kit)->listerURL().url(), *kit ); 01600 } 01601 else { 01602 fileItems.insert( (*kit)->url().url(), *kit ); 01603 } 01604 } 01605 01606 static const TQString& dot = TDEGlobal::staticQString("."); 01607 static const TQString& dotdot = TDEGlobal::staticQString(".."); 01608 01609 KFileItem *item = 0, *tmp; 01610 01611 TQValueList<TDEIO::UDSEntry> buf = jobs[job]; 01612 TQValueListIterator<TDEIO::UDSEntry> it = buf.begin(); 01613 for ( ; it != buf.end(); ++it ) 01614 { 01615 // Form the complete url 01616 if ( !item ) { 01617 item = new KFileItem( *it, jobUrl, delayedMimeTypes, true ); 01618 } 01619 else { 01620 item->setUDSEntry( *it, jobUrl, delayedMimeTypes, true ); 01621 } 01622 01623 // Find out about the name 01624 TQString name = item->name(); 01625 Q_ASSERT( !name.isEmpty() ); 01626 01627 // we duplicate the check for dotdot here, to avoid iterating over 01628 // all items again and checking in matchesFilter() that way. 01629 if ( name.isEmpty() || name == dotdot ) { 01630 continue; 01631 } 01632 01633 if ( name == dot ) 01634 { 01635 // if the update was started before finishing the original listing 01636 // there is no root item yet 01637 if ( !dir->rootItem ) 01638 { 01639 dir->rootItem = item; 01640 item = 0; 01641 01642 for ( KDirLister *kdl = listers->first(); kdl; kdl = listers->next() ) { 01643 if ( !kdl->d->rootFileItem && kdl->d->url == jobUrl ) { 01644 kdl->d->rootFileItem = dir->rootItem; 01645 } 01646 } 01647 } 01648 01649 continue; 01650 } 01651 01652 // Find this item 01653 if ( (tmp = fileItems[item->url().url()]) ) 01654 { 01655 tmp->mark(); 01656 01657 // check if something changed for this file 01658 if ( !tmp->cmp( *item ) ) 01659 { 01660 for ( kdl = listers->first(); kdl; kdl = listers->next() ) { 01661 kdl->aboutToRefreshItem( tmp ); 01662 } 01663 01664 //kdDebug(7004) << "slotUpdateResult: file changed: " << tmp->name() << endl; 01665 tmp->assign( *item ); 01666 01667 for ( kdl = listers->first(); kdl; kdl = listers->next() ) { 01668 kdl->addRefreshItem( tmp ); 01669 } 01670 } 01671 } 01672 else // this is a new file 01673 { 01674 //kdDebug(7004) << "slotUpdateResult: new file: " << name << endl; 01675 01676 item->mark(); 01677 dir->lstItems->append( item ); 01678 01679 for ( kdl = listers->first(); kdl; kdl = listers->next() ) { 01680 kdl->addNewItem( item ); 01681 } 01682 01683 // item used, we need a new one for the next iteration 01684 item = 0; 01685 } 01686 } 01687 01688 if ( item ) { 01689 delete item; 01690 } 01691 01692 jobs.remove( job ); 01693 01694 deleteUnmarkedItems( listers, dir->lstItems ); 01695 01696 for ( kdl = listers->first(); kdl; kdl = listers->next() ) 01697 { 01698 kdl->emitItems(); 01699 01700 kdl->jobDone( job ); 01701 01702 kdl->emitCompleted( jobUrl ); 01703 if ( kdl->numJobs() == 0 ) 01704 { 01705 kdl->d->complete = true; 01706 emit kdl->completed(); 01707 } 01708 } 01709 01710 // TODO: hmm, if there was an error and job is a parent of one or more 01711 // of the pending urls we should cancel it/them as well 01712 processPendingUpdates(); 01713 } 01714 01715 // private 01716 01717 TDEIO::ListJob *KDirListerCache::jobForUrl( const TQString& url, TDEIO::ListJob *not_job ) 01718 { 01719 TDEIO::ListJob *job; 01720 TQMap< TDEIO::ListJob *, TQValueList<TDEIO::UDSEntry> >::Iterator it = jobs.begin(); 01721 while ( it != jobs.end() ) 01722 { 01723 job = it.key(); 01724 KURL itjoburl = joburl( job ); 01725 if ( ((itjoburl.url(-1) + ":" + itjoburl.internalReferenceURL()) == url) && (job != not_job) ) { 01726 return job; 01727 } 01728 ++it; 01729 } 01730 return 0; 01731 } 01732 01733 const KURL& KDirListerCache::joburl( TDEIO::ListJob *job ) 01734 { 01735 if ( job->redirectionURL().isValid() ) { 01736 return job->redirectionURL(); 01737 } 01738 else { 01739 return job->url(); 01740 } 01741 } 01742 01743 void KDirListerCache::killJob( TDEIO::ListJob *job ) 01744 { 01745 jobs.remove( job ); 01746 job->disconnect( this ); 01747 job->kill(); 01748 } 01749 01750 void KDirListerCache::deleteUnmarkedItems( TQPtrList<KDirLister> *listers, KFileItemList *lstItems ) 01751 { 01752 // Find all unmarked items and delete them 01753 KFileItem* item; 01754 lstItems->first(); 01755 while ( (item = lstItems->current()) ) 01756 if ( !item->isMarked() ) 01757 { 01758 //kdDebug() << k_funcinfo << item->name() << endl; 01759 for ( KDirLister *kdl = listers->first(); kdl; kdl = listers->next() ) { 01760 kdl->emitDeleteItem( item ); 01761 } 01762 01763 if ( item->isDir() ) { 01764 deleteDir( item->url() ); 01765 } 01766 01767 // finally actually delete the item 01768 lstItems->take(); 01769 delete item; 01770 } 01771 else 01772 lstItems->next(); 01773 } 01774 01775 void KDirListerCache::deleteDir( const KURL& dirUrl ) 01776 { 01777 //kdDebug() << k_funcinfo << dirUrl.prettyURL() << endl; 01778 // unregister and remove the childs of the deleted item. 01779 // Idea: tell all the KDirListers that they should forget the dir 01780 // and then remove it from the cache. 01781 01782 TQDictIterator<DirItem> itu( itemsInUse ); 01783 while ( itu.current() ) 01784 { 01785 TQString deletedUrlIndep = itu.currentKey(); 01786 deletedUrlIndep.truncate(deletedUrlIndep.length() - ((*itu)->url.internalReferenceURL().length()+strlen(":"))); 01787 KURL deletedUrl( deletedUrlIndep ); 01788 if ( dirUrl.isParentOf( deletedUrl ) ) 01789 { 01790 // stop all jobs for deletedUrl 01791 01792 TQPtrList<KDirLister> *kdls = urlsCurrentlyListed[deletedUrl.url() + ":" + deletedUrl.internalReferenceURL()]; 01793 if ( kdls ) // yeah, I lack good names 01794 { 01795 // we need a copy because stop modifies the list 01796 kdls = new TQPtrList<KDirLister>( *kdls ); 01797 for ( KDirLister *kdl = kdls->first(); kdl; kdl = kdls->next() ) 01798 stop( kdl, deletedUrl ); 01799 01800 delete kdls; 01801 } 01802 01803 // tell listers holding deletedUrl to forget about it 01804 // this will stop running updates for deletedUrl as well 01805 01806 kdls = urlsCurrentlyHeld[deletedUrl.url() + ":" + deletedUrl.internalReferenceURL()]; 01807 if ( kdls ) 01808 { 01809 // we need a copy because forgetDirs modifies the list 01810 kdls = new TQPtrList<KDirLister>( *kdls ); 01811 01812 for ( KDirLister *kdl = kdls->first(); kdl; kdl = kdls->next() ) 01813 { 01814 // lister's root is the deleted item 01815 if ( kdl->d->url == deletedUrl ) 01816 { 01817 // tell the view first. It might need the subdirs' items (which forgetDirs will delete) 01818 if ( kdl->d->rootFileItem ) 01819 emit kdl->deleteItem( kdl->d->rootFileItem ); 01820 forgetDirs( kdl ); 01821 kdl->d->rootFileItem = 0; 01822 } 01823 else 01824 { 01825 bool treeview = kdl->d->lstDirs.count() > 1; 01826 if ( !treeview ) 01827 emit kdl->clear(); 01828 01829 forgetDirs( kdl, deletedUrl, treeview ); 01830 } 01831 } 01832 01833 delete kdls; 01834 } 01835 01836 // delete the entry for deletedUrl - should not be needed, it's in 01837 // items cached now 01838 01839 DirItem *dir = itemsInUse.take( deletedUrl.url() + ":" + deletedUrl.internalReferenceURL() ); 01840 Q_ASSERT( !dir ); 01841 if ( !dir ) // take didn't find it - move on 01842 ++itu; 01843 } 01844 else 01845 ++itu; 01846 } 01847 01848 // remove the children from the cache 01849 removeDirFromCache( dirUrl ); 01850 } 01851 01852 void KDirListerCache::processPendingUpdates() 01853 { 01854 // TODO 01855 } 01856 01857 #ifndef NDEBUG 01858 void KDirListerCache::printDebug() 01859 { 01860 kdDebug(7004) << "Items in use: " << endl; 01861 TQDictIterator<DirItem> itu( itemsInUse ); 01862 for ( ; itu.current() ; ++itu ) { 01863 kdDebug(7004) << " " << itu.currentKey() << " URL: " << itu.current()->url 01864 << " rootItem: " << ( itu.current()->rootItem ? itu.current()->rootItem->url() : KURL() ) 01865 << " autoUpdates refcount: " << itu.current()->autoUpdates 01866 << " complete: " << itu.current()->complete 01867 << ( itu.current()->lstItems ? TQString(" with %1 items.").arg(itu.current()->lstItems->count()) : TQString(" lstItems=NULL") ) << endl; 01868 } 01869 01870 kdDebug(7004) << "urlsCurrentlyHeld: " << endl; 01871 TQDictIterator< TQPtrList<KDirLister> > it( urlsCurrentlyHeld ); 01872 for ( ; it.current() ; ++it ) 01873 { 01874 TQString list; 01875 for ( TQPtrListIterator<KDirLister> listit( *it.current() ); listit.current(); ++listit ) 01876 list += " 0x" + TQString::number( (long)listit.current(), 16 ); 01877 kdDebug(7004) << " " << it.currentKey() << " " << it.current()->count() << " listers: " << list << endl; 01878 } 01879 01880 kdDebug(7004) << "urlsCurrentlyListed: " << endl; 01881 TQDictIterator< TQPtrList<KDirLister> > it2( urlsCurrentlyListed ); 01882 for ( ; it2.current() ; ++it2 ) 01883 { 01884 TQString list; 01885 for ( TQPtrListIterator<KDirLister> listit( *it2.current() ); listit.current(); ++listit ) 01886 list += " 0x" + TQString::number( (long)listit.current(), 16 ); 01887 kdDebug(7004) << " " << it2.currentKey() << " " << it2.current()->count() << " listers: " << list << endl; 01888 } 01889 01890 TQMap< TDEIO::ListJob *, TQValueList<TDEIO::UDSEntry> >::Iterator jit = jobs.begin(); 01891 kdDebug(7004) << "Jobs: " << endl; 01892 for ( ; jit != jobs.end() ; ++jit ) 01893 kdDebug(7004) << " " << jit.key() << " listing " << joburl( jit.key() ).prettyURL() << ": " << (*jit).count() << " entries." << endl; 01894 01895 kdDebug(7004) << "Items in cache: " << endl; 01896 TQCacheIterator<DirItem> itc( itemsCached ); 01897 for ( ; itc.current() ; ++itc ) 01898 kdDebug(7004) << " " << itc.currentKey() << " rootItem: " 01899 << ( itc.current()->rootItem ? itc.current()->rootItem->url().prettyURL() : TQString("NULL") ) 01900 << ( itc.current()->lstItems ? TQString(" with %1 items.").arg(itc.current()->lstItems->count()) : TQString(" lstItems=NULL") ) << endl; 01901 } 01902 #endif 01903 01904 /*********************** -- The new KDirLister -- ************************/ 01905 01906 01907 KDirLister::KDirLister( bool _delayedMimeTypes ) 01908 { 01909 kdDebug(7003) << "+KDirLister" << endl; 01910 01911 d = new KDirListerPrivate; 01912 01913 d->complete = true; 01914 d->delayedMimeTypes = _delayedMimeTypes; 01915 01916 setAutoUpdate( true ); 01917 setDirOnlyMode( false ); 01918 setShowingDotFiles( false ); 01919 01920 setAutoErrorHandlingEnabled( true, 0 ); 01921 } 01922 01923 KDirLister::~KDirLister() 01924 { 01925 kdDebug(7003) << "-KDirLister" << endl; 01926 01927 if ( KDirListerCache::exists() ) 01928 { 01929 // Stop all running jobs 01930 stop(); 01931 s_pCache->forgetDirs( this ); 01932 } 01933 01934 delete d; 01935 } 01936 01937 bool KDirLister::openURL( const KURL& _url, bool _keep, bool _reload ) 01938 { 01939 kdDebug(7003) << k_funcinfo << _url.prettyURL() 01940 << " keep=" << _keep << " reload=" << _reload << endl; 01941 01942 // emit the current changes made to avoid an inconsistent treeview 01943 if ( d->changes != NONE && _keep ) { 01944 emitChanges(); 01945 } 01946 01947 d->changes = NONE; 01948 01949 // If a local path is available, monitor that instead of the given remote URL... 01950 if (!_url.isLocalFile()) { 01951 TDEIO::LocalURLJob* localURLJob = TDEIO::localURL(_url); 01952 if (localURLJob) { 01953 d->openURL_url[localURLJob] = _url; 01954 d->openURL_keep[localURLJob] = _keep; 01955 d->openURL_reload[localURLJob] = _reload; 01956 connect(localURLJob, TQT_SIGNAL(localURL(TDEIO::LocalURLJob*, const KURL&, bool)), this, TQT_SLOT(slotOpenURLGotLocalURL(TDEIO::LocalURLJob*, const KURL&, bool))); 01957 connect(localURLJob, TQT_SIGNAL(destroyed()), this, TQT_SLOT(slotLocalURLKIODestroyed())); 01958 } 01959 return true; 01960 } 01961 else { 01962 return s_pCache->listDir( this, _url, _keep, _reload ); 01963 } 01964 } 01965 01966 void KDirLister::slotOpenURLGotLocalURL(TDEIO::LocalURLJob *job, const KURL& url, bool isLocal) { 01967 KURL realURL = d->openURL_url[job]; 01968 if (isLocal) { 01969 realURL = url; 01970 realURL.setInternalReferenceURL(d->openURL_url[job].url()); 01971 d->m_referenceURLMap[d->openURL_url[job].url()] = url.path(); 01972 } 01973 s_pCache->listDir( this, realURL, d->openURL_keep[job], d->openURL_reload[job] ); 01974 d->openURL_url.remove(job); 01975 d->openURL_keep.remove(job); 01976 d->openURL_reload.remove(job); 01977 } 01978 01979 void KDirLister::slotLocalURLKIODestroyed() { 01980 TDEIO::LocalURLJob* terminatedJob = const_cast<TDEIO::LocalURLJob*>(static_cast<const TDEIO::LocalURLJob*>(sender())); 01981 01982 if (d->openURL_url.contains(terminatedJob)) { 01983 s_pCache->listDir( this, d->openURL_url[terminatedJob], d->openURL_keep[terminatedJob], d->openURL_reload[terminatedJob] ); 01984 d->openURL_url.remove(terminatedJob); 01985 d->openURL_keep.remove(terminatedJob); 01986 d->openURL_reload.remove(terminatedJob); 01987 } 01988 } 01989 01990 void KDirLister::stop() 01991 { 01992 kdDebug(7003) << k_funcinfo << endl; 01993 s_pCache->stop( this ); 01994 d->m_referenceURLMap.clear(); 01995 } 01996 01997 void KDirLister::stop( const KURL& _url ) 01998 { 01999 kdDebug(7003) << k_funcinfo << _url.prettyURL() << endl; 02000 s_pCache->stop( this, _url ); 02001 d->m_referenceURLMap.remove(_url.url()); 02002 } 02003 02004 bool KDirLister::autoUpdate() const 02005 { 02006 return d->autoUpdate; 02007 } 02008 02009 void KDirLister::setAutoUpdate( bool _enable ) 02010 { 02011 if ( d->autoUpdate == _enable ) 02012 return; 02013 02014 d->autoUpdate = _enable; 02015 s_pCache->setAutoUpdate( this, _enable ); 02016 } 02017 02018 bool KDirLister::showingDotFiles() const 02019 { 02020 return d->isShowingDotFiles; 02021 } 02022 02023 void KDirLister::setShowingDotFiles( bool _showDotFiles ) 02024 { 02025 if ( d->isShowingDotFiles == _showDotFiles ) 02026 return; 02027 02028 d->isShowingDotFiles = _showDotFiles; 02029 d->changes ^= DOT_FILES; 02030 } 02031 02032 bool KDirLister::dirOnlyMode() const 02033 { 02034 return d->dirOnlyMode; 02035 } 02036 02037 void KDirLister::setDirOnlyMode( bool _dirsOnly ) 02038 { 02039 if ( d->dirOnlyMode == _dirsOnly ) 02040 return; 02041 02042 d->dirOnlyMode = _dirsOnly; 02043 d->changes ^= DIR_ONLY_MODE; 02044 } 02045 02046 bool KDirLister::autoErrorHandlingEnabled() const 02047 { 02048 return d->autoErrorHandling; 02049 } 02050 02051 void KDirLister::setAutoErrorHandlingEnabled( bool enable, TQWidget* parent ) 02052 { 02053 d->autoErrorHandling = enable; 02054 d->errorParent = parent; 02055 } 02056 02057 const KURL& KDirLister::url() const 02058 { 02059 return d->url; 02060 } 02061 02062 const KURL::List& KDirLister::directories() const 02063 { 02064 return d->lstDirs; 02065 } 02066 02067 void KDirLister::emitChanges() 02068 { 02069 if ( d->changes == NONE ) 02070 return; 02071 02072 static const TQString& dot = TDEGlobal::staticQString("."); 02073 static const TQString& dotdot = TDEGlobal::staticQString(".."); 02074 02075 for ( KURL::List::Iterator it = d->lstDirs.begin(); 02076 it != d->lstDirs.end(); ++it ) 02077 { 02078 KFileItemListIterator kit( *s_pCache->itemsForDir( *it ) ); 02079 for ( ; kit.current(); ++kit ) 02080 { 02081 if ( (*kit)->text() == dot || (*kit)->text() == dotdot ) 02082 continue; 02083 02084 bool oldMime = true, newMime = true; 02085 02086 if ( d->changes & MIME_FILTER ) 02087 { 02088 oldMime = doMimeFilter( (*kit)->mimetype(), d->oldMimeFilter ) 02089 && doMimeExcludeFilter( (*kit)->mimetype(), d->oldMimeExcludeFilter ); 02090 newMime = doMimeFilter( (*kit)->mimetype(), d->mimeFilter ) 02091 && doMimeExcludeFilter( (*kit)->mimetype(), d->mimeExcludeFilter ); 02092 02093 if ( oldMime && !newMime ) 02094 { 02095 emit deleteItem( *kit ); 02096 continue; 02097 } 02098 } 02099 02100 if ( d->changes & DIR_ONLY_MODE ) 02101 { 02102 // the lister switched to dirOnlyMode 02103 if ( d->dirOnlyMode ) 02104 { 02105 if ( !(*kit)->isDir() ) 02106 emit deleteItem( *kit ); 02107 } 02108 else if ( !(*kit)->isDir() ) { 02109 addNewItem( *kit ); 02110 } 02111 02112 continue; 02113 } 02114 02115 if ( (*kit)->isHidden() ) 02116 { 02117 if ( d->changes & DOT_FILES ) 02118 { 02119 // the lister switched to dot files mode 02120 if ( d->isShowingDotFiles ) { 02121 addNewItem( *kit ); 02122 } 02123 else { 02124 emit deleteItem( *kit ); 02125 } 02126 02127 continue; 02128 } 02129 } 02130 else if ( d->changes & NAME_FILTER ) 02131 { 02132 bool oldName = (*kit)->isDir() || 02133 d->oldFilters.isEmpty() || 02134 doNameFilter( (*kit)->text(), d->oldFilters ); 02135 02136 bool newName = (*kit)->isDir() || 02137 d->lstFilters.isEmpty() || 02138 doNameFilter( (*kit)->text(), d->lstFilters ); 02139 02140 if ( oldName && !newName ) 02141 { 02142 emit deleteItem( *kit ); 02143 continue; 02144 } 02145 else if ( !oldName && newName ) { 02146 addNewItem( *kit ); 02147 } 02148 } 02149 02150 if ( (d->changes & MIME_FILTER) && !oldMime && newMime ) { 02151 addNewItem( *kit ); 02152 } 02153 } 02154 02155 emitItems(); 02156 } 02157 02158 d->changes = NONE; 02159 } 02160 02161 void KDirLister::updateDirectory( const KURL& _u ) 02162 { 02163 s_pCache->updateDirectory( _u ); 02164 } 02165 02166 bool KDirLister::isFinished() const 02167 { 02168 return d->complete; 02169 } 02170 02171 KFileItem *KDirLister::rootItem() const 02172 { 02173 return d->rootFileItem; 02174 } 02175 02176 KFileItem *KDirLister::findByURL( const KURL& _url ) const 02177 { 02178 return s_pCache->findByURL( this, _url ); 02179 } 02180 02181 KFileItem *KDirLister::findByName( const TQString& _name ) const 02182 { 02183 return s_pCache->findByName( this, _name ); 02184 } 02185 02186 #ifndef KDE_NO_COMPAT 02187 KFileItem *KDirLister::find( const KURL& _url ) const 02188 { 02189 return findByURL( _url ); 02190 } 02191 #endif 02192 02193 02194 // ================ public filter methods ================ // 02195 02196 void KDirLister::setNameFilter( const TQString& nameFilter ) 02197 { 02198 if ( !(d->changes & NAME_FILTER) ) 02199 { 02200 d->oldFilters = d->lstFilters; 02201 d->lstFilters.setAutoDelete( false ); 02202 } 02203 02204 d->lstFilters.clear(); 02205 d->lstFilters.setAutoDelete( true ); 02206 02207 d->nameFilter = nameFilter; 02208 02209 // Split on white space 02210 TQStringList list = TQStringList::split( ' ', nameFilter ); 02211 for ( TQStringList::Iterator it = list.begin(); it != list.end(); ++it ) 02212 d->lstFilters.append( new TQRegExp(*it, false, true ) ); 02213 02214 d->changes |= NAME_FILTER; 02215 } 02216 02217 const TQString& KDirLister::nameFilter() const 02218 { 02219 return d->nameFilter; 02220 } 02221 02222 void KDirLister::setMimeFilter( const TQStringList& mimeFilter ) 02223 { 02224 if ( !(d->changes & MIME_FILTER) ) 02225 d->oldMimeFilter = d->mimeFilter; 02226 02227 if ( mimeFilter.find("all/allfiles") != mimeFilter.end() || 02228 mimeFilter.find("all/all") != mimeFilter.end() ) 02229 d->mimeFilter.clear(); 02230 else 02231 d->mimeFilter = mimeFilter; 02232 02233 d->changes |= MIME_FILTER; 02234 } 02235 02236 void KDirLister::setMimeExcludeFilter( const TQStringList& mimeExcludeFilter ) 02237 { 02238 if ( !(d->changes & MIME_FILTER) ) 02239 d->oldMimeExcludeFilter = d->mimeExcludeFilter; 02240 02241 d->mimeExcludeFilter = mimeExcludeFilter; 02242 d->changes |= MIME_FILTER; 02243 } 02244 02245 02246 void KDirLister::clearMimeFilter() 02247 { 02248 if ( !(d->changes & MIME_FILTER) ) 02249 { 02250 d->oldMimeFilter = d->mimeFilter; 02251 d->oldMimeExcludeFilter = d->mimeExcludeFilter; 02252 } 02253 d->mimeFilter.clear(); 02254 d->mimeExcludeFilter.clear(); 02255 d->changes |= MIME_FILTER; 02256 } 02257 02258 const TQStringList& KDirLister::mimeFilters() const 02259 { 02260 return d->mimeFilter; 02261 } 02262 02263 bool KDirLister::matchesFilter( const TQString& name ) const 02264 { 02265 return doNameFilter( name, d->lstFilters ); 02266 } 02267 02268 bool KDirLister::matchesMimeFilter( const TQString& mime ) const 02269 { 02270 return doMimeFilter( mime, d->mimeFilter ) && doMimeExcludeFilter(mime,d->mimeExcludeFilter); 02271 } 02272 02273 // ================ protected methods ================ // 02274 02275 bool KDirLister::matchesFilter( const KFileItem *item ) const 02276 { 02277 Q_ASSERT( item ); 02278 static const TQString& dotdot = TDEGlobal::staticQString(".."); 02279 02280 if ( item->text() == dotdot ) 02281 return false; 02282 02283 if ( !d->isShowingDotFiles && item->isHidden() ) 02284 return false; 02285 02286 if ( item->isDir() || d->lstFilters.isEmpty() ) 02287 return true; 02288 02289 return matchesFilter( item->text() ); 02290 } 02291 02292 bool KDirLister::matchesMimeFilter( const KFileItem *item ) const 02293 { 02294 Q_ASSERT( item ); 02295 // Don't lose time determining the mimetype if there is no filter 02296 if ( d->mimeFilter.isEmpty() && d->mimeExcludeFilter.isEmpty() ) 02297 return true; 02298 return matchesMimeFilter( item->mimetype() ); 02299 } 02300 02301 bool KDirLister::doNameFilter( const TQString& name, const TQPtrList<TQRegExp>& filters ) const 02302 { 02303 for ( TQPtrListIterator<TQRegExp> it( filters ); it.current(); ++it ) 02304 if ( it.current()->exactMatch( name ) ) 02305 return true; 02306 02307 return false; 02308 } 02309 02310 bool KDirLister::doMimeFilter( const TQString& mime, const TQStringList& filters ) const 02311 { 02312 if ( filters.isEmpty() ) 02313 return true; 02314 02315 KMimeType::Ptr mimeptr = KMimeType::mimeType(mime); 02316 //kdDebug(7004) << "doMimeFilter: investigating: "<<mimeptr->name()<<endl; 02317 TQStringList::ConstIterator it = filters.begin(); 02318 for ( ; it != filters.end(); ++it ) 02319 if ( mimeptr->is(*it) ) 02320 return true; 02321 //else kdDebug(7004) << "doMimeFilter: compared without result to "<<*it<<endl; 02322 02323 02324 return false; 02325 } 02326 02327 bool KDirLister::doMimeExcludeFilter( const TQString& mime, const TQStringList& filters ) const 02328 { 02329 if ( filters.isEmpty() ) 02330 return true; 02331 02332 TQStringList::ConstIterator it = filters.begin(); 02333 for ( ; it != filters.end(); ++it ) 02334 if ( (*it) == mime ) 02335 return false; 02336 02337 return true; 02338 } 02339 02340 02341 bool KDirLister::validURL( const KURL& _url ) const 02342 { 02343 return s_pCache->validURL( this, _url ); 02344 } 02345 02346 void KDirLister::handleError( TDEIO::Job *job ) 02347 { 02348 if ( d->autoErrorHandling ) { 02349 job->showErrorDialog( d->errorParent ); 02350 } 02351 } 02352 02353 02354 // ================= private methods ================= // 02355 02356 void KDirLister::addNewItem( const KFileItem *item ) 02357 { 02358 if ( ( d->dirOnlyMode && !item->isDir() ) || !matchesFilter( item ) ) { 02359 return; // No reason to continue... bailing out here prevents a mimetype scan. 02360 } 02361 02362 if ((item->url().internalReferenceURL() != "") 02363 && (d->m_referenceURLMap.contains(item->url().internalReferenceURL()))) { 02364 // Likely a media:/ tdeioslave URL or similar 02365 // Rewrite the URL to ensure that the user remains within the media:/ tree! 02366 TQString itemPath = item->url().path(); 02367 if (itemPath.startsWith(d->m_referenceURLMap[item->url().internalReferenceURL()])) { 02368 itemPath = itemPath.remove(0, d->m_referenceURLMap[item->url().internalReferenceURL()].length()); 02369 TQString newPath = item->url().internalReferenceURL(); 02370 if (!newPath.endsWith("/")) newPath = newPath + "/"; 02371 while (itemPath.startsWith("/")) itemPath = itemPath.remove(0,1); 02372 while (itemPath.endsWith("/")) itemPath.truncate(itemPath.length()-1); 02373 newPath = newPath + itemPath; 02374 const_cast<KFileItem*>(item)->setListerURL(item->url()); 02375 const_cast<KFileItem*>(item)->setURL(newPath); 02376 } 02377 } 02378 02379 if ( matchesMimeFilter( item ) ) 02380 { 02381 if ( !d->lstNewItems ) { 02382 d->lstNewItems = new KFileItemList; 02383 } 02384 02385 d->lstNewItems->append( item ); // items not filtered 02386 } 02387 else 02388 { 02389 if ( !d->lstMimeFilteredItems ) { 02390 d->lstMimeFilteredItems = new KFileItemList; 02391 } 02392 02393 d->lstMimeFilteredItems->append( item ); // only filtered by mime 02394 } 02395 } 02396 02397 void KDirLister::addNewItems( const KFileItemList& items ) 02398 { 02399 // TODO: make this faster - test if we have a filter at all first 02400 // DF: was this profiled? The matchesFoo() functions should be fast, w/o filters... 02401 // Of course if there is no filter and we can do a range-insertion instead of a loop, that might be good. 02402 // But that's for Qt4, not possible with TQPtrList. 02403 for ( KFileItemListIterator kit( items ); kit.current(); ++kit ) { 02404 addNewItem( *kit ); 02405 } 02406 } 02407 02408 void KDirLister::aboutToRefreshItem( const KFileItem *item ) 02409 { 02410 // The code here follows the logic in addNewItem 02411 if ( ( d->dirOnlyMode && !item->isDir() ) || !matchesFilter( item ) ) 02412 d->refreshItemWasFiltered = true; 02413 else if ( !matchesMimeFilter( item ) ) 02414 d->refreshItemWasFiltered = true; 02415 else 02416 d->refreshItemWasFiltered = false; 02417 } 02418 02419 void KDirLister::addRefreshItem( const KFileItem *item ) 02420 { 02421 bool isExcluded = (d->dirOnlyMode && !item->isDir()) || !matchesFilter( item ); 02422 02423 if ((item->url().internalReferenceURL() != "") 02424 && (d->m_referenceURLMap.contains(item->url().internalReferenceURL()))) { 02425 // Likely a media:/ tdeioslave URL or similar 02426 // Rewrite the URL to ensure that the user remains within the media:/ tree! 02427 TQString itemPath = item->url().path(); 02428 if (itemPath.startsWith(d->m_referenceURLMap[item->url().internalReferenceURL()])) { 02429 itemPath = itemPath.remove(0, d->m_referenceURLMap[item->url().internalReferenceURL()].length()); 02430 TQString newPath = item->url().internalReferenceURL(); 02431 if (!newPath.endsWith("/")) newPath = newPath + "/"; 02432 while (itemPath.startsWith("/")) itemPath = itemPath.remove(0,1); 02433 while (itemPath.endsWith("/")) itemPath.truncate(itemPath.length()-1); 02434 newPath = newPath + itemPath; 02435 const_cast<KFileItem*>(item)->setListerURL(item->url()); 02436 const_cast<KFileItem*>(item)->setURL(newPath); 02437 } 02438 } 02439 02440 if ( !isExcluded && matchesMimeFilter( item ) ) 02441 { 02442 if ( d->refreshItemWasFiltered ) 02443 { 02444 if ( !d->lstNewItems ) { 02445 d->lstNewItems = new KFileItemList; 02446 } 02447 02448 d->lstNewItems->append( item ); 02449 } 02450 else 02451 { 02452 if ( !d->lstRefreshItems ) { 02453 d->lstRefreshItems = new KFileItemList; 02454 } 02455 02456 d->lstRefreshItems->append( item ); 02457 } 02458 } 02459 else if ( !d->refreshItemWasFiltered ) 02460 { 02461 if ( !d->lstRemoveItems ) { 02462 d->lstRemoveItems = new KFileItemList; 02463 } 02464 02465 // notify the user that the mimetype of a file changed that doesn't match 02466 // a filter or does match an exclude filter 02467 d->lstRemoveItems->append( item ); 02468 } 02469 } 02470 02471 void KDirLister::emitItems() 02472 { 02473 KFileItemList *tmpNew = d->lstNewItems; 02474 d->lstNewItems = 0; 02475 02476 KFileItemList *tmpMime = d->lstMimeFilteredItems; 02477 d->lstMimeFilteredItems = 0; 02478 02479 KFileItemList *tmpRefresh = d->lstRefreshItems; 02480 d->lstRefreshItems = 0; 02481 02482 KFileItemList *tmpRemove = d->lstRemoveItems; 02483 d->lstRemoveItems = 0; 02484 02485 if ( tmpNew ) 02486 { 02487 // For historical reasons, items with different protocols and/or prefixes must be emitted separately 02488 TQString protocol; 02489 TQString prefix; 02490 TQString prevProtocol; 02491 TQString prevPrefix; 02492 KFileItemList emitList; 02493 for ( KFileItemListIterator kit( *tmpNew ); kit.current(); ++kit ) 02494 { 02495 KFileItem *item = *kit; 02496 protocol = item->url().protocol(); 02497 prefix = TQStringList::split("/", item->url().path())[0]; 02498 if ((protocol != prevProtocol) || (prefix != prevPrefix)) { 02499 if (emitList.count() > 0) { 02500 emit newItems( emitList ); 02501 emitList.clear(); 02502 } 02503 } 02504 emitList.append(item); 02505 prevProtocol = protocol; 02506 prevPrefix = prefix; 02507 } 02508 02509 if (emitList.count() > 0) { 02510 emit newItems( emitList ); 02511 } 02512 delete tmpNew; 02513 } 02514 02515 if ( tmpMime ) 02516 { 02517 emit itemsFilteredByMime( *tmpMime ); 02518 delete tmpMime; 02519 } 02520 02521 if ( tmpRefresh ) 02522 { 02523 emit refreshItems( *tmpRefresh ); 02524 delete tmpRefresh; 02525 } 02526 02527 if ( tmpRemove ) 02528 { 02529 for ( KFileItem *tmp = tmpRemove->first(); tmp; tmp = tmpRemove->next() ) { 02530 emit deleteItem( tmp ); 02531 } 02532 delete tmpRemove; 02533 } 02534 } 02535 02536 void KDirLister::emitDeleteItem( KFileItem *item ) 02537 { 02538 if ( ( d->dirOnlyMode && !item->isDir() ) || !matchesFilter( item ) ) { 02539 return; // No reason to continue... bailing out here prevents a mimetype scan. 02540 } 02541 02542 if ( matchesMimeFilter( item ) ) { 02543 emit deleteItem( item ); 02544 } 02545 } 02546 02547 02548 // ================ private slots ================ // 02549 02550 void KDirLister::slotInfoMessage( TDEIO::Job *, const TQString& message ) 02551 { 02552 emit infoMessage( message ); 02553 } 02554 02555 void KDirLister::slotPercent( TDEIO::Job *job, unsigned long pcnt ) 02556 { 02557 d->jobData[static_cast<TDEIO::ListJob *>(job)].percent = pcnt; 02558 02559 int result = 0; 02560 02561 TDEIO::filesize_t size = 0; 02562 02563 TQMap< TDEIO::ListJob *, KDirListerPrivate::JobData >::Iterator dataIt = d->jobData.begin(); 02564 while ( dataIt != d->jobData.end() ) 02565 { 02566 result += (*dataIt).percent * (*dataIt).totalSize; 02567 size += (*dataIt).totalSize; 02568 ++dataIt; 02569 } 02570 02571 if ( size != 0 ) 02572 result /= size; 02573 else 02574 result = 100; 02575 emit percent( result ); 02576 } 02577 02578 void KDirLister::slotTotalSize( TDEIO::Job *job, TDEIO::filesize_t size ) 02579 { 02580 d->jobData[static_cast<TDEIO::ListJob *>(job)].totalSize = size; 02581 02582 TDEIO::filesize_t result = 0; 02583 TQMap< TDEIO::ListJob *, KDirListerPrivate::JobData >::Iterator dataIt = d->jobData.begin(); 02584 while ( dataIt != d->jobData.end() ) 02585 { 02586 result += (*dataIt).totalSize; 02587 ++dataIt; 02588 } 02589 02590 emit totalSize( result ); 02591 } 02592 02593 void KDirLister::slotProcessedSize( TDEIO::Job *job, TDEIO::filesize_t size ) 02594 { 02595 d->jobData[static_cast<TDEIO::ListJob *>(job)].processedSize = size; 02596 02597 TDEIO::filesize_t result = 0; 02598 TQMap< TDEIO::ListJob *, KDirListerPrivate::JobData >::Iterator dataIt = d->jobData.begin(); 02599 while ( dataIt != d->jobData.end() ) 02600 { 02601 result += (*dataIt).processedSize; 02602 ++dataIt; 02603 } 02604 02605 emit processedSize( result ); 02606 } 02607 02608 void KDirLister::slotSpeed( TDEIO::Job *job, unsigned long spd ) 02609 { 02610 d->jobData[static_cast<TDEIO::ListJob *>(job)].speed = spd; 02611 02612 int result = 0; 02613 TQMap< TDEIO::ListJob *, KDirListerPrivate::JobData >::Iterator dataIt = d->jobData.begin(); 02614 while ( dataIt != d->jobData.end() ) 02615 { 02616 result += (*dataIt).speed; 02617 ++dataIt; 02618 } 02619 02620 emit speed( result ); 02621 } 02622 02623 uint KDirLister::numJobs() 02624 { 02625 return d->jobData.count(); 02626 } 02627 02628 void KDirLister::jobDone( TDEIO::ListJob *job ) 02629 { 02630 d->jobData.remove( job ); 02631 } 02632 02633 void KDirLister::jobStarted( TDEIO::ListJob *job ) 02634 { 02635 KDirListerPrivate::JobData jobData; 02636 jobData.speed = 0; 02637 jobData.percent = 0; 02638 jobData.processedSize = 0; 02639 jobData.totalSize = 0; 02640 02641 d->jobData.insert( job, jobData ); 02642 d->complete = false; 02643 } 02644 02645 void KDirLister::connectJob( TDEIO::ListJob *job ) 02646 { 02647 connect( job, TQT_SIGNAL(infoMessage( TDEIO::Job *, const TQString& )), 02648 this, TQT_SLOT(slotInfoMessage( TDEIO::Job *, const TQString& )) ); 02649 connect( job, TQT_SIGNAL(percent( TDEIO::Job *, unsigned long )), 02650 this, TQT_SLOT(slotPercent( TDEIO::Job *, unsigned long )) ); 02651 connect( job, TQT_SIGNAL(totalSize( TDEIO::Job *, TDEIO::filesize_t )), 02652 this, TQT_SLOT(slotTotalSize( TDEIO::Job *, TDEIO::filesize_t )) ); 02653 connect( job, TQT_SIGNAL(processedSize( TDEIO::Job *, TDEIO::filesize_t )), 02654 this, TQT_SLOT(slotProcessedSize( TDEIO::Job *, TDEIO::filesize_t )) ); 02655 connect( job, TQT_SIGNAL(speed( TDEIO::Job *, unsigned long )), 02656 this, TQT_SLOT(slotSpeed( TDEIO::Job *, unsigned long )) ); 02657 } 02658 02659 void KDirLister::emitCompleted( const KURL& _url ) 02660 { 02661 KURL emitURL = _url; 02662 02663 if ((_url.internalReferenceURL() != "") 02664 && (d->m_referenceURLMap.contains(_url.internalReferenceURL()))) { 02665 // Likely a media:/ tdeioslave URL or similar 02666 // Rewrite the URL to ensure that the user remains within the media:/ tree! 02667 TQString itemPath = _url.path(); 02668 if (itemPath.startsWith(d->m_referenceURLMap[_url.internalReferenceURL()])) { 02669 itemPath = itemPath.remove(0, d->m_referenceURLMap[_url.internalReferenceURL()].length()); 02670 TQString newPath = _url.internalReferenceURL(); 02671 if (!newPath.endsWith("/")) newPath = newPath + "/"; 02672 while (itemPath.startsWith("/")) itemPath = itemPath.remove(0,1); 02673 while (itemPath.endsWith("/")) itemPath.truncate(itemPath.length()-1); 02674 newPath = newPath + itemPath; 02675 emitURL = newPath; 02676 } 02677 } 02678 02679 emit completed( emitURL ); 02680 } 02681 02682 void KDirLister::setMainWindow( TQWidget *window ) 02683 { 02684 d->window = window; 02685 } 02686 02687 TQWidget *KDirLister::mainWindow() 02688 { 02689 return d->window; 02690 } 02691 02692 KFileItemList KDirLister::items( WhichItems which ) const 02693 { 02694 return itemsForDir( url(), which ); 02695 } 02696 02697 KFileItemList KDirLister::itemsForDir( const KURL& dir, WhichItems which ) const 02698 { 02699 KFileItemList result; 02700 KFileItemList *allItems = s_pCache->itemsForDir( dir ); 02701 if ( !allItems ) { 02702 return result; 02703 } 02704 02705 if ( which == AllItems ) { 02706 result = *allItems; // shallow copy 02707 } 02708 else // only items passing the filters 02709 { 02710 for ( KFileItemListIterator kit( *allItems ); kit.current(); ++kit ) 02711 { 02712 KFileItem *item = *kit; 02713 bool isExcluded = (d->dirOnlyMode && !item->isDir()) || !matchesFilter( item ); 02714 if ( !isExcluded && matchesMimeFilter( item ) ) { 02715 result.append( item ); 02716 } 02717 } 02718 } 02719 02720 return result; 02721 } 02722 02723 // to keep BC changes 02724 02725 void KDirLister::virtual_hook( int, void * ) 02726 { /*BASE::virtual_hook( id, data );*/ } 02727 02728 #include "kdirlister.moc" 02729 #include "kdirlister_p.moc"