00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023 #include "kdirlister.h"
00024 #include "kdirlister_p.h"
00025
00026 #include <QtCore/QRegExp>
00027
00028 #include <kdebug.h>
00029 #include <kde_file.h>
00030 #include <klocale.h>
00031 #include <kio/job.h>
00032 #include <kio/jobuidelegate.h>
00033 #include <kmessagebox.h>
00034 #include <kglobal.h>
00035 #include <kglobalsettings.h>
00036 #include "kprotocolmanager.h"
00037 #include "kmountpoint.h"
00038 #include <sys/stat.h>
00039
00040 #include <assert.h>
00041 #include <QFile>
00042
00043
00044
00045
00046
00047 #ifdef NDEBUG
00048 #undef DEBUG_CACHE
00049 #endif
00050
00051 K_GLOBAL_STATIC(KDirListerCache, kDirListerCache)
00052
00053 KDirListerCache::KDirListerCache()
00054 : itemsCached( 10 )
00055 {
00056
00057
00058 connect( &pendingUpdateTimer, SIGNAL(timeout()), this, SLOT(processPendingUpdates()) );
00059 pendingUpdateTimer.setSingleShot( true );
00060
00061 connect( KDirWatch::self(), SIGNAL( dirty( const QString& ) ),
00062 this, SLOT( slotFileDirty( const QString& ) ) );
00063 connect( KDirWatch::self(), SIGNAL( created( const QString& ) ),
00064 this, SLOT( slotFileCreated( const QString& ) ) );
00065 connect( KDirWatch::self(), SIGNAL( deleted( const QString& ) ),
00066 this, SLOT( slotFileDeleted( const QString& ) ) );
00067
00068 kdirnotify = new org::kde::KDirNotify(QString(), QString(), QDBusConnection::sessionBus(), this);
00069 connect(kdirnotify, SIGNAL(FileRenamed(QString,QString)), SLOT(slotFileRenamed(QString,QString)));
00070 connect(kdirnotify, SIGNAL(FilesAdded(QString)), SLOT(slotFilesAdded(QString)));
00071 connect(kdirnotify, SIGNAL(FilesChanged(QStringList)), SLOT(slotFilesChanged(QStringList)));
00072 connect(kdirnotify, SIGNAL(FilesRemoved(QStringList)), SLOT(slotFilesRemoved(QStringList)));
00073
00074
00075
00076 qAddPostRoutine(kDirListerCache.destroy);
00077 }
00078
00079 KDirListerCache::~KDirListerCache()
00080 {
00081
00082
00083 qDeleteAll(itemsInUse);
00084 itemsInUse.clear();
00085
00086 itemsCached.clear();
00087 directoryData.clear();
00088
00089 if ( KDirWatch::exists() )
00090 KDirWatch::self()->disconnect( this );
00091 }
00092
00093
00094
00095 bool KDirListerCache::listDir( KDirLister *lister, const KUrl& _u,
00096 bool _keep, bool _reload )
00097 {
00098
00099 KUrl _url(_u);
00100 _url.cleanPath();
00101
00102 if (!_url.host().isEmpty() && KProtocolInfo::protocolClass(_url.protocol()) == ":local") {
00103
00104 _url.setHost(QString());
00105 if (_keep == false)
00106 emit lister->redirection(_url);
00107 }
00108
00109 _url.adjustPath(KUrl::RemoveTrailingSlash);
00110 const QString urlStr = _url.url();
00111
00112 if (!validUrl(lister, _url)) {
00113 kDebug(7004) << lister << "url=" << _url << "not a valid url";
00114 return false;
00115 }
00116
00117 #ifdef DEBUG_CACHE
00118 printDebug();
00119 #endif
00120
00121
00122 if (!_keep) {
00123
00124 stop(lister, true );
00125
00126
00127 forgetDirs(lister);
00128
00129 lister->d->rootFileItem = KFileItem();
00130 } else if (lister->d->lstDirs.contains(_url)) {
00131
00132 stop(lister, _url, true );
00133
00134
00135
00136
00137 lister->d->lstDirs.removeAll(_url);
00138
00139
00140 forgetDirs(lister, _url, true);
00141
00142 if (lister->d->url == _url)
00143 lister->d->rootFileItem = KFileItem();
00144 }
00145
00146 lister->d->complete = false;
00147
00148 lister->d->lstDirs.append(_url);
00149
00150 if (lister->d->url.isEmpty() || !_keep)
00151 lister->d->url = _url;
00152
00153 DirItem *itemU = itemsInUse.value(urlStr);
00154
00155 KDirListerCacheDirectoryData& dirData = directoryData[urlStr];
00156
00157 if (dirData.listersCurrentlyListing.isEmpty()) {
00158
00159
00160
00161 dirData.listersCurrentlyListing.append(lister);
00162
00163 DirItem *itemFromCache;
00164 if (itemU || (!_reload && (itemFromCache = itemsCached.take(urlStr)) ) ) {
00165 if (itemU) {
00166 kDebug(7004) << "Entry already in use:" << _url;
00167
00168 } else {
00169 kDebug(7004) << "Entry in cache:" << _url;
00170 itemFromCache->decAutoUpdate();
00171 itemsInUse.insert(urlStr, itemFromCache);
00172 itemU = itemFromCache;
00173 }
00174
00175 emit lister->started(_url);
00176
00177
00178
00179 new KDirLister::Private::CachedItemsJob(lister, itemU->lstItems, itemU->rootItem, _url, _reload);
00180
00181 } else {
00182
00183 if (_reload) {
00184 kDebug(7004) << "Reloading directory:" << _url;
00185 itemsCached.remove(urlStr);
00186 } else {
00187 kDebug(7004) << "Listing directory:" << _url;
00188 }
00189
00190 itemU = new DirItem(_url);
00191 itemsInUse.insert(urlStr, itemU);
00192
00193
00194
00195
00196
00197
00198
00199 {
00200 KIO::ListJob* job = KIO::listDir(_url, KIO::HideProgressInfo);
00201 runningListJobs.insert(job, KIO::UDSEntryList());
00202
00203 lister->d->jobStarted(job);
00204 lister->d->connectJob(job);
00205
00206 if (lister->d->window)
00207 job->ui()->setWindow(lister->d->window);
00208
00209 connect(job, SIGNAL(entries(KIO::Job *, KIO::UDSEntryList)),
00210 this, SLOT(slotEntries(KIO::Job *, KIO::UDSEntryList)));
00211 connect(job, SIGNAL(result(KJob *)),
00212 this, SLOT(slotResult(KJob *)));
00213 connect(job, SIGNAL(redirection(KIO::Job *,KUrl)),
00214 this, SLOT(slotRedirection(KIO::Job *,KUrl)));
00215
00216 emit lister->started(_url);
00217 }
00218 }
00219 } else {
00220
00221 kDebug(7004) << "Entry currently being listed:" << _url << "by" << dirData.listersCurrentlyListing;
00222 #ifdef DEBUG_CACHE
00223 printDebug();
00224 #endif
00225
00226 emit lister->started( _url );
00227
00228
00229 Q_ASSERT(!dirData.listersCurrentlyListing.contains(lister));
00230 dirData.listersCurrentlyListing.append( lister );
00231
00232 KIO::ListJob *job = jobForUrl( urlStr );
00233
00234 if( job ) {
00235 lister->d->jobStarted( job );
00236 lister->d->connectJob( job );
00237 }
00238 Q_ASSERT( itemU );
00239
00240
00241
00242
00243 new KDirLister::Private::CachedItemsJob(lister, itemU->lstItems, itemU->rootItem, _url, _reload);
00244
00245 #ifdef DEBUG_CACHE
00246 printDebug();
00247 #endif
00248 }
00249
00250
00251 if (lister->d->autoUpdate)
00252 itemU->incAutoUpdate();
00253
00254 return true;
00255 }
00256
00257 void KDirLister::Private::CachedItemsJob::done()
00258 {
00259
00260 Q_ASSERT(m_lister->d->m_cachedItemsJob == this);
00261 kDirListerCache->emitItemsFromCache(m_lister, m_items, m_rootItem, m_url, m_reload, m_emitCompleted);
00262 emitResult();
00263 }
00264
00265 void KDirListerCache::emitItemsFromCache(KDirLister* lister, const KFileItemList& items, const KFileItem& rootItem, const KUrl& _url, bool _reload, bool _emitCompleted)
00266 {
00267 lister->d->m_cachedItemsJob = 0;
00268
00269 const QString urlStr = _url.url();
00270 DirItem *itemU = kDirListerCache->itemsInUse.value(urlStr);
00271 Q_ASSERT(itemU);
00272
00273 KDirLister::Private* kdl = lister->d;
00274
00275 kdl->complete = false;
00276
00277 if ( kdl->rootFileItem.isNull() && kdl->url == _url )
00278 kdl->rootFileItem = rootItem;
00279
00280
00281 kdl->addNewItems(_url, items);
00282 kdl->emitItems();
00283
00284 KDirListerCacheDirectoryData& dirData = directoryData[urlStr];
00285 Q_ASSERT(dirData.listersCurrentlyListing.contains(lister));
00286
00287
00288
00289
00290
00291 if (_emitCompleted && jobForUrl( urlStr ) == 0) {
00292
00293 Q_ASSERT(!dirData.listersCurrentlyHolding.contains(lister));
00294 dirData.listersCurrentlyHolding.append( lister );
00295 dirData.listersCurrentlyListing.removeAll( lister );
00296
00297 kdl->complete = true;
00298 emit lister->completed( _url );
00299 emit lister->completed();
00300
00301 if ( _reload || !itemU->complete ) {
00302 updateDirectory( _url );
00303 }
00304 }
00305 }
00306
00307 bool KDirListerCache::validUrl( const KDirLister *lister, const KUrl& url ) const
00308 {
00309 if ( !url.isValid() )
00310 {
00311 if ( lister->d->autoErrorHandling )
00312 {
00313 QString tmp = i18n("Malformed URL\n%1", url.prettyUrl() );
00314 KMessageBox::error( lister->d->errorParent, tmp );
00315 }
00316 return false;
00317 }
00318
00319 if ( !KProtocolManager::supportsListing( url ) )
00320 {
00321 if ( lister->d->autoErrorHandling )
00322 {
00323 QString tmp = i18n("URL cannot be listed\n%1", url.prettyUrl() );
00324 KMessageBox::error( lister->d->errorParent, tmp );
00325 }
00326 return false;
00327 }
00328
00329 return true;
00330 }
00331
00332 void KDirListerCache::stop( KDirLister *lister, bool silent )
00333 {
00334 #ifdef DEBUG_CACHE
00335
00336 #endif
00337
00338 bool stopped = false;
00339
00340 QHash<QString,KDirListerCacheDirectoryData>::iterator dirit = directoryData.begin();
00341 const QHash<QString,KDirListerCacheDirectoryData>::iterator dirend = directoryData.end();
00342 for( ; dirit != dirend ; ++dirit ) {
00343 KDirListerCacheDirectoryData& dirData = dirit.value();
00344 if ( dirData.listersCurrentlyListing.removeAll(lister) ) {
00345
00346 const QString url = dirit.key();
00347
00348
00349 stopLister(lister, url, dirData, silent);
00350 stopped = true;
00351 }
00352 }
00353
00354 if (lister->d->m_cachedItemsJob) {
00355 delete lister->d->m_cachedItemsJob;
00356 lister->d->m_cachedItemsJob = 0;
00357 stopped = true;
00358 }
00359
00360 if ( stopped ) {
00361 if (!silent) {
00362 emit lister->canceled();
00363 }
00364 lister->d->complete = true;
00365 }
00366
00367
00368
00369 }
00370
00371 void KDirListerCache::stop(KDirLister *lister, const KUrl& _u, bool silent)
00372 {
00373 KUrl url(_u);
00374 url.adjustPath( KUrl::RemoveTrailingSlash );
00375 const QString urlStr = url.url();
00376
00377 if (lister->d->m_cachedItemsJob && lister->d->m_cachedItemsJob->url() == url) {
00378 delete lister->d->m_cachedItemsJob;
00379 lister->d->m_cachedItemsJob = 0;
00380 }
00381
00382
00383 kDebug(7004) << lister << " url=" << url;
00384
00385 QHash<QString,KDirListerCacheDirectoryData>::iterator dirit = directoryData.find(urlStr);
00386 if (dirit == directoryData.end())
00387 return;
00388 KDirListerCacheDirectoryData& dirData = dirit.value();
00389 if ( dirData.listersCurrentlyListing.removeAll(lister) ) {
00390
00391 stopLister(lister, urlStr, dirData, silent);
00392
00393 if ( lister->d->numJobs() == 0 ) {
00394 lister->d->complete = true;
00395
00396 if (!silent) {
00397 emit lister->canceled();
00398 }
00399 }
00400 }
00401 }
00402
00403
00404 void KDirListerCache::stopLister(KDirLister* lister, const QString& url, KDirListerCacheDirectoryData& dirData, bool silent)
00405 {
00406
00407
00408
00409
00410
00411 dirData.listersCurrentlyHolding.append(lister);
00412
00413 if (!silent)
00414 emit lister->canceled(KUrl(url));
00415 }
00416
00417 void KDirListerCache::setAutoUpdate( KDirLister *lister, bool enable )
00418 {
00419
00420
00421 for ( KUrl::List::const_iterator it = lister->d->lstDirs.constBegin();
00422 it != lister->d->lstDirs.constEnd(); ++it ) {
00423 DirItem* dirItem = itemsInUse.value((*it).url());
00424 Q_ASSERT(dirItem);
00425 if ( enable )
00426 dirItem->incAutoUpdate();
00427 else
00428 dirItem->decAutoUpdate();
00429 }
00430 }
00431
00432 void KDirListerCache::forgetDirs( KDirLister *lister )
00433 {
00434
00435
00436 emit lister->clear();
00437
00438
00439
00440
00441 const KUrl::List lstDirsCopy = lister->d->lstDirs;
00442 lister->d->lstDirs.clear();
00443
00444 for ( KUrl::List::const_iterator it = lstDirsCopy.begin();
00445 it != lstDirsCopy.end(); ++it ) {
00446 forgetDirs( lister, *it, false );
00447 }
00448 }
00449
00450 static bool manually_mounted(const QString& path, const KMountPoint::List& possibleMountPoints)
00451 {
00452 KMountPoint::Ptr mp = possibleMountPoints.findByPath(path);
00453 if (!mp)
00454 return true;
00455 const bool supermount = mp->mountType() == "supermount";
00456 if (supermount) {
00457 return true;
00458 }
00459
00460 return mp->mountOptions().contains("noauto");
00461 }
00462
00463
00464 void KDirListerCache::forgetDirs( KDirLister *lister, const KUrl& _url, bool notify )
00465 {
00466
00467
00468 KUrl url( _url );
00469 url.adjustPath( KUrl::RemoveTrailingSlash );
00470 const QString urlStr = url.url();
00471
00472 DirectoryDataHash::iterator dit = directoryData.find(urlStr);
00473 if (dit == directoryData.end())
00474 return;
00475 KDirListerCacheDirectoryData& dirData = *dit;
00476 dirData.listersCurrentlyHolding.removeAll(lister);
00477
00478
00479 KIO::ListJob *job = jobForUrl(urlStr);
00480 if (job)
00481 lister->d->jobDone(job);
00482
00483 DirItem *item = itemsInUse.value(urlStr);
00484 Q_ASSERT(item);
00485
00486 if ( dirData.listersCurrentlyHolding.isEmpty() && dirData.listersCurrentlyListing.isEmpty() ) {
00487
00488 directoryData.erase(dit);
00489 itemsInUse.remove( urlStr );
00490
00491
00492 if ( job ) {
00493 killJob( job );
00494 kDebug(7004) << "Killing update job for " << urlStr;
00495
00496
00497
00498
00499
00500 if ( lister->d->numJobs() == 0 ) {
00501 lister->d->complete = true;
00502
00503 }
00504 }
00505
00506 if ( notify ) {
00507 lister->d->lstDirs.removeAll( url );
00508 emit lister->clear( url );
00509 }
00510
00511 if ( item->complete ) {
00512 kDebug(7004) << lister << " item moved into cache: " << url;
00513 itemsCached.insert( urlStr, item );
00514
00515 const KMountPoint::List possibleMountPoints = KMountPoint::possibleMountPoints(KMountPoint::NeedMountOptions);
00516
00517
00518
00519
00520 const bool isLocal = item->url.isLocalFile();
00521 bool isManuallyMounted = false;
00522 bool containsManuallyMounted = false;
00523 if (isLocal) {
00524 isManuallyMounted = manually_mounted( item->url.path(), possibleMountPoints );
00525 if ( !isManuallyMounted ) {
00526
00527
00528
00529 KFileItemList::const_iterator kit = item->lstItems.constBegin();
00530 KFileItemList::const_iterator kend = item->lstItems.constEnd();
00531 for ( ; kit != kend && !containsManuallyMounted; ++kit )
00532 if ( (*kit).isDir() && manually_mounted((*kit).url().path(), possibleMountPoints) )
00533 containsManuallyMounted = true;
00534 }
00535 }
00536
00537 if ( isManuallyMounted || containsManuallyMounted )
00538 {
00539 kDebug(7004) << "Not adding a watch on " << item->url << " because it " <<
00540 ( isManuallyMounted ? "is manually mounted" : "contains a manually mounted subdir" );
00541 item->complete = false;
00542 }
00543 else
00544 item->incAutoUpdate();
00545 }
00546 else
00547 {
00548 delete item;
00549 item = 0;
00550 }
00551 }
00552
00553 if ( item && lister->d->autoUpdate )
00554 item->decAutoUpdate();
00555 }
00556
00557 void KDirListerCache::updateDirectory( const KUrl& _dir )
00558 {
00559 kDebug(7004) << _dir;
00560
00561 QString urlStr = _dir.url(KUrl::RemoveTrailingSlash);
00562 if ( !checkUpdate( urlStr ) )
00563 return;
00564
00565
00566
00567
00568
00569
00570 KDirListerCacheDirectoryData& dirData = directoryData[urlStr];
00571 QList<KDirLister *> listers = dirData.listersCurrentlyListing;
00572 QList<KDirLister *> holders = dirData.listersCurrentlyHolding;
00573
00574
00575 bool killed = false;
00576 QWidget *window = 0;
00577 KIO::ListJob *job = jobForUrl( urlStr );
00578 if (job) {
00579 window = job->ui()->window();
00580
00581 killJob( job );
00582 killed = true;
00583
00584 foreach ( KDirLister *kdl, listers )
00585 kdl->d->jobDone( job );
00586
00587 foreach ( KDirLister *kdl, holders )
00588 kdl->d->jobDone( job );
00589 } else {
00590
00591
00592 Q_FOREACH(KDirLister *kdl, listers) {
00593 if (kdl->d->m_cachedItemsJob) {
00594 KDirLister::Private::CachedItemsJob* job = kdl->d->m_cachedItemsJob;
00595 job->setEmitCompleted(false);
00596 job->done();
00597 delete job;
00598 killed = true;
00599 }
00600 }
00601 }
00602
00603
00604
00605
00606
00607
00608
00609 Q_ASSERT( listers.isEmpty() || killed );
00610
00611 job = KIO::listDir( _dir, KIO::HideProgressInfo );
00612 runningListJobs.insert( job, KIO::UDSEntryList() );
00613
00614 connect( job, SIGNAL(entries( KIO::Job *, const KIO::UDSEntryList & )),
00615 this, SLOT(slotUpdateEntries( KIO::Job *, const KIO::UDSEntryList & )) );
00616 connect( job, SIGNAL(result( KJob * )),
00617 this, SLOT(slotUpdateResult( KJob * )) );
00618
00619 kDebug(7004) << "update started in" << _dir;
00620
00621 foreach ( KDirLister *kdl, listers ) {
00622 kdl->d->jobStarted( job );
00623 }
00624
00625 if ( !holders.isEmpty() ) {
00626 if ( !killed ) {
00627 bool first = true;
00628 foreach ( KDirLister *kdl, holders ) {
00629 kdl->d->jobStarted( job );
00630 if ( first && kdl->d->window ) {
00631 first = false;
00632 job->ui()->setWindow( kdl->d->window );
00633 }
00634 emit kdl->started( _dir );
00635 }
00636 } else {
00637 job->ui()->setWindow( window );
00638
00639 foreach ( KDirLister *kdl, holders ) {
00640 kdl->d->jobStarted( job );
00641 }
00642 }
00643 }
00644 }
00645
00646 bool KDirListerCache::checkUpdate( const QString& _dir )
00647 {
00648 if ( !itemsInUse.contains(_dir) )
00649 {
00650 DirItem *item = itemsCached[_dir];
00651 if ( item && item->complete )
00652 {
00653 item->complete = false;
00654 item->decAutoUpdate();
00655
00656
00657 }
00658
00659
00660
00661 return false;
00662 }
00663 else
00664 return true;
00665 }
00666
00667 KFileItem KDirListerCache::itemForUrl( const KUrl& url ) const
00668 {
00669 KFileItem *item = findByUrl( 0, url );
00670 if (item) {
00671 return *item;
00672 } else {
00673 return KFileItem();
00674 }
00675 }
00676
00677 KDirListerCache::DirItem *KDirListerCache::dirItemForUrl(const KUrl& dir) const
00678 {
00679 const QString urlStr = dir.url(KUrl::RemoveTrailingSlash);
00680 DirItem *item = itemsInUse.value(urlStr);
00681 if ( !item )
00682 item = itemsCached[urlStr];
00683 return item;
00684 }
00685
00686 KFileItemList *KDirListerCache::itemsForDir(const KUrl& dir) const
00687 {
00688 DirItem *item = dirItemForUrl(dir);
00689 return item ? &item->lstItems : 0;
00690 }
00691
00692 KFileItem KDirListerCache::findByName( const KDirLister *lister, const QString& _name ) const
00693 {
00694 Q_ASSERT(lister);
00695
00696 for (KUrl::List::const_iterator it = lister->d->lstDirs.constBegin();
00697 it != lister->d->lstDirs.constEnd(); ++it) {
00698 DirItem* dirItem = itemsInUse.value((*it).url());
00699 Q_ASSERT(dirItem);
00700 const KFileItem item = dirItem->lstItems.findByName(_name);
00701 if (!item.isNull())
00702 return item;
00703 }
00704
00705 return KFileItem();
00706 }
00707
00708 KFileItem *KDirListerCache::findByUrl( const KDirLister *lister, const KUrl& _u ) const
00709 {
00710 KUrl url(_u);
00711 url.adjustPath(KUrl::RemoveTrailingSlash);
00712
00713
00714 DirItem* dirItem = dirItemForUrl(url);
00715 if (dirItem && !dirItem->rootItem.isNull() && dirItem->rootItem.url() == url) {
00716
00717 if (!lister || lister->d->lstDirs.contains(url))
00718 return &dirItem->rootItem;
00719 }
00720
00721 KUrl parentDir(url);
00722 parentDir.setPath( parentDir.directory() );
00723
00724
00725 if (lister && !lister->d->lstDirs.contains(parentDir))
00726 return 0;
00727
00728 dirItem = dirItemForUrl(parentDir);
00729 if (dirItem) {
00730 KFileItemList::iterator it = dirItem->lstItems.begin();
00731 const KFileItemList::iterator end = dirItem->lstItems.end();
00732 for (; it != end ; ++it) {
00733 if ((*it).url() == url) {
00734 return &*it;
00735 }
00736 }
00737 }
00738
00739 return 0;
00740 }
00741
00742 void KDirListerCache::slotFilesAdded( const QString &dir )
00743 {
00744 kDebug(7004) << dir;
00745 updateDirectory( KUrl(dir) );
00746 }
00747
00748 void KDirListerCache::slotFilesRemoved( const QStringList &fileList )
00749 {
00750 kDebug(7004) << fileList.count();
00751
00752 QMap<QString, KFileItemList> removedItemsByDir;
00753 QStringList deletedSubdirs;
00754
00755 for (QStringList::const_iterator it = fileList.begin(); it != fileList.end() ; ++it) {
00756 KUrl url(*it);
00757 DirItem* dirItem = dirItemForUrl(url);
00758 if (dirItem) {
00759 deletedSubdirs.append(*it);
00760 if (!dirItem->rootItem.isNull()) {
00761 removedItemsByDir[*it].append(dirItem->rootItem);
00762 }
00763 }
00764
00765 KUrl parentDir(url);
00766 parentDir.setPath(parentDir.directory());
00767 dirItem = dirItemForUrl(parentDir);
00768 if (!dirItem)
00769 continue;
00770 for (KFileItemList::iterator fit = dirItem->lstItems.begin(), fend = dirItem->lstItems.end(); fit != fend ; ++fit) {
00771 if ((*fit).url() == url) {
00772 const KFileItem fileitem = *fit;
00773 removedItemsByDir[parentDir.url()].append(fileitem);
00774
00775 if (fileitem.isNull() || fileitem.isDir()) {
00776 deletedSubdirs.append(*it);
00777 }
00778 dirItem->lstItems.erase(fit);
00779 break;
00780 }
00781 }
00782 }
00783
00784 QMap<QString, KFileItemList>::const_iterator rit = removedItemsByDir.constBegin();
00785 for(; rit != removedItemsByDir.constEnd(); ++rit) {
00786
00787
00788 DirectoryDataHash::const_iterator dit = directoryData.constFind(rit.key());
00789 if (dit != directoryData.constEnd()) {
00790 itemsDeleted((*dit).listersCurrentlyHolding, rit.value());
00791 }
00792 }
00793
00794 Q_FOREACH(const QString& url, deletedSubdirs) {
00795
00796
00797 deleteDir(url);
00798 }
00799 }
00800
00801 void KDirListerCache::slotFilesChanged( const QStringList &fileList )
00802 {
00803
00804 KUrl::List dirsToUpdate;
00805 QStringList::const_iterator it = fileList.begin();
00806 for (; it != fileList.end() ; ++it) {
00807 KUrl url( *it );
00808 KFileItem *fileitem = findByUrl(0, url);
00809 if (!fileitem) {
00810 kDebug(7004) << "item not found for" << url;
00811 continue;
00812 }
00813 if (url.isLocalFile()) {
00814
00815 aboutToRefreshItem(*fileitem);
00816 KFileItem oldItem = *fileitem;
00817 fileitem->refresh();
00818 emitRefreshItem(oldItem, *fileitem);
00819 } else {
00820 pendingRemoteUpdates.insert(fileitem);
00821
00822
00823 KUrl dir(url);
00824 dir.setPath(dir.directory());
00825 if (!dirsToUpdate.contains(dir))
00826 dirsToUpdate.prepend(dir);
00827 }
00828 }
00829
00830 KUrl::List::const_iterator itdir = dirsToUpdate.constBegin();
00831 for (; itdir != dirsToUpdate.constEnd() ; ++itdir)
00832 updateDirectory( *itdir );
00833
00834
00835 }
00836
00837 void KDirListerCache::slotFileRenamed( const QString &_src, const QString &_dst )
00838 {
00839 KUrl src( _src );
00840 KUrl dst( _dst );
00841 kDebug(7004) << src << "->" << dst;
00842 #ifdef DEBUG_CACHE
00843 printDebug();
00844 #endif
00845
00846 KUrl oldurl( src );
00847 oldurl.adjustPath( KUrl::RemoveTrailingSlash );
00848 KFileItem *fileitem = findByUrl( 0, oldurl );
00849
00850
00851
00852
00853
00854 bool nameOnly = fileitem && !fileitem->entry().stringValue( KIO::UDSEntry::UDS_URL ).isEmpty();
00855 nameOnly &= src.directory( KUrl::IgnoreTrailingSlash | KUrl::AppendTrailingSlash ) ==
00856 dst.directory( KUrl::IgnoreTrailingSlash | KUrl::AppendTrailingSlash );
00857
00858
00859
00860
00861 if( !nameOnly ) {
00862 renameDir( src, dst );
00863
00864
00865 fileitem = findByUrl( 0, oldurl );
00866 }
00867
00868
00869 if ( fileitem )
00870 {
00871 if ( !fileitem->isLocalFile() && !fileitem->localPath().isEmpty() )
00872 slotFilesChanged( QStringList() << src.url() );
00873 else
00874 {
00875 aboutToRefreshItem( *fileitem );
00876 const KFileItem oldItem = *fileitem;
00877 if( nameOnly )
00878 fileitem->setName( dst.fileName() );
00879 else
00880 fileitem->setUrl( dst );
00881 fileitem->refreshMimeType();
00882 fileitem->determineMimeType();
00883 emitRefreshItem( oldItem, *fileitem );
00884 }
00885 }
00886 #ifdef DEBUG_CACHE
00887 printDebug();
00888 #endif
00889 }
00890
00891 void KDirListerCache::aboutToRefreshItem( const KFileItem& fileitem )
00892 {
00893
00894 KUrl parentDir( fileitem.url() );
00895 parentDir.setPath( parentDir.directory() );
00896 const QString parentDirURL = parentDir.url();
00897
00898 DirectoryDataHash::iterator dit = directoryData.find(parentDirURL);
00899 if (dit == directoryData.end())
00900 return;
00901
00902 foreach (KDirLister *kdl, (*dit).listersCurrentlyHolding)
00903 kdl->d->aboutToRefreshItem( fileitem );
00904
00905
00906 foreach (KDirLister *kdl, (*dit).listersCurrentlyListing)
00907 kdl->d->aboutToRefreshItem( fileitem );
00908 }
00909
00910 void KDirListerCache::emitRefreshItem(const KFileItem& oldItem, const KFileItem& fileitem )
00911 {
00912
00913 KUrl parentDir( oldItem.url() );
00914 parentDir.setPath( parentDir.directory() );
00915 QString parentDirURL = parentDir.url();
00916 DirectoryDataHash::iterator dit = directoryData.find(parentDirURL);
00917 QList<KDirLister *> listers;
00918
00919 if (dit != directoryData.end())
00920 listers += (*dit).listersCurrentlyHolding + (*dit).listersCurrentlyListing;
00921 if (oldItem.isDir()) {
00922
00923 dit = directoryData.find(oldItem.url().url());
00924 if (dit != directoryData.end())
00925 listers += (*dit).listersCurrentlyHolding + (*dit).listersCurrentlyListing;
00926 }
00927 Q_FOREACH(KDirLister *kdl, listers) {
00928
00929 if (oldItem.isDir() && kdl->d->rootFileItem == oldItem) {
00930 kdl->d->rootFileItem = fileitem;
00931 }
00932 KUrl directoryUrl(oldItem.url());
00933 directoryUrl.setPath(directoryUrl.directory());
00934 kdl->d->addRefreshItem(directoryUrl, oldItem, fileitem);
00935 kdl->d->emitItems();
00936 }
00937 }
00938
00939
00940
00941
00942
00943 void KDirListerCache::slotFileDirty( const QString& path )
00944 {
00945 kDebug(7004) << path;
00946
00947 KDE_struct_stat buff;
00948 if ( KDE_stat( QFile::encodeName(path), &buff ) != 0 )
00949 return;
00950 const bool isDir = S_ISDIR(buff.st_mode);
00951 KUrl url(path);
00952
00953 if (isDir) {
00954
00955 updateDirectory(url);
00956 } else {
00957
00958 const QString urlStr = url.url(KUrl::RemoveTrailingSlash);
00959 if (!pendingUpdates.contains(urlStr)) {
00960 KUrl dir(url);
00961 dir.setPath(dir.directory());
00962 if (checkUpdate(dir.url())) {
00963 pendingUpdates.insert(urlStr);
00964 if (!pendingUpdateTimer.isActive())
00965 pendingUpdateTimer.start( 500 );
00966 }
00967 }
00968 }
00969 }
00970
00971 void KDirListerCache::slotFileCreated( const QString& path )
00972 {
00973 kDebug(7004) << path;
00974
00975 KUrl u( path );
00976 u.setPath( u.directory() );
00977 updateDirectory( u );
00978 }
00979
00980 void KDirListerCache::slotFileDeleted( const QString& path )
00981 {
00982 kDebug(7004) << path;
00983 KUrl u( path );
00984 slotFilesRemoved( QStringList() << u.url() );
00985 }
00986
00987 void KDirListerCache::slotEntries( KIO::Job *job, const KIO::UDSEntryList &entries )
00988 {
00989 KUrl url(joburl( static_cast<KIO::ListJob *>(job) ));
00990 url.adjustPath(KUrl::RemoveTrailingSlash);
00991 QString urlStr = url.url();
00992
00993
00994
00995 DirItem *dir = itemsInUse.value(urlStr);
00996 Q_ASSERT( dir );
00997
00998 DirectoryDataHash::iterator dit = directoryData.find(urlStr);
00999 Q_ASSERT(dit != directoryData.end());
01000 KDirListerCacheDirectoryData& dirData = *dit;
01001 Q_ASSERT( !dirData.listersCurrentlyListing.isEmpty() );
01002
01003
01004 bool delayedMimeTypes = true;
01005 foreach ( KDirLister *kdl, dirData.listersCurrentlyListing )
01006 delayedMimeTypes &= kdl->d->delayedMimeTypes;
01007
01008 KIO::UDSEntryList::const_iterator it = entries.begin();
01009 const KIO::UDSEntryList::const_iterator end = entries.end();
01010 for ( ; it != end; ++it )
01011 {
01012 const QString name = (*it).stringValue( KIO::UDSEntry::UDS_NAME );
01013
01014 Q_ASSERT( !name.isEmpty() );
01015 if ( name.isEmpty() )
01016 continue;
01017
01018 if ( name == "." )
01019 {
01020 Q_ASSERT( dir->rootItem.isNull() );
01021
01022
01023
01024
01025
01026
01027 dir->rootItem = itemForUrl(url);
01028 if (dir->rootItem.isNull())
01029 dir->rootItem = KFileItem( *it, url, delayedMimeTypes, true );
01030
01031 foreach ( KDirLister *kdl, dirData.listersCurrentlyListing )
01032 if ( kdl->d->rootFileItem.isNull() && kdl->d->url == url )
01033 kdl->d->rootFileItem = dir->rootItem;
01034 }
01035 else if ( name != ".." )
01036 {
01037 KFileItem item( *it, url, delayedMimeTypes, true );
01038
01039
01040 dir->lstItems.append( item );
01041
01042 foreach ( KDirLister *kdl, dirData.listersCurrentlyListing )
01043 kdl->d->addNewItem(url, item);
01044 }
01045 }
01046
01047 foreach ( KDirLister *kdl, dirData.listersCurrentlyListing )
01048 kdl->d->emitItems();
01049 }
01050
01051 void KDirListerCache::slotResult( KJob *j )
01052 {
01053 Q_ASSERT( j );
01054 KIO::ListJob *job = static_cast<KIO::ListJob *>( j );
01055 runningListJobs.remove( job );
01056
01057 KUrl jobUrl(joburl( job ));
01058 jobUrl.adjustPath(KUrl::RemoveTrailingSlash);
01059 QString jobUrlStr = jobUrl.url();
01060
01061 kDebug(7004) << "finished listing" << jobUrl;
01062 #ifdef DEBUG_CACHE
01063 printDebug();
01064 #endif
01065
01066 DirectoryDataHash::iterator dit = directoryData.find(jobUrlStr);
01067 Q_ASSERT(dit != directoryData.end());
01068 KDirListerCacheDirectoryData& dirData = *dit;
01069 Q_ASSERT( !dirData.listersCurrentlyListing.isEmpty() );
01070 QList<KDirLister *> listers = dirData.listersCurrentlyListing;
01071
01072
01073
01074
01075 Q_ASSERT( dirData.listersCurrentlyHolding.isEmpty() );
01076 dirData.moveListersWithoutCachedItemsJob();
01077
01078 if ( job->error() )
01079 {
01080 foreach ( KDirLister *kdl, listers )
01081 {
01082 kdl->d->jobDone( job );
01083 kdl->handleError( job );
01084 emit kdl->canceled( jobUrl );
01085 if ( kdl->d->numJobs() == 0 )
01086 {
01087 kdl->d->complete = true;
01088 emit kdl->canceled();
01089 }
01090 }
01091 }
01092 else
01093 {
01094 DirItem *dir = itemsInUse.value(jobUrlStr);
01095 Q_ASSERT( dir );
01096 dir->complete = true;
01097
01098 foreach ( KDirLister* kdl, listers )
01099 {
01100 kdl->d->jobDone( job );
01101 emit kdl->completed( jobUrl );
01102 if ( kdl->d->numJobs() == 0 )
01103 {
01104 kdl->d->complete = true;
01105 emit kdl->completed();
01106 }
01107 }
01108 }
01109
01110
01111
01112 processPendingUpdates();
01113
01114 #ifdef DEBUG_CACHE
01115 printDebug();
01116 #endif
01117 }
01118
01119 void KDirListerCache::slotRedirection( KIO::Job *j, const KUrl& url )
01120 {
01121 Q_ASSERT( j );
01122 KIO::ListJob *job = static_cast<KIO::ListJob *>( j );
01123
01124 KUrl oldUrl(job->url());
01125 KUrl newUrl(url);
01126
01127
01128 oldUrl.adjustPath(KUrl::RemoveTrailingSlash);
01129 newUrl.adjustPath(KUrl::RemoveTrailingSlash);
01130
01131 if ( oldUrl == newUrl ) {
01132 kDebug(7004) << "New redirection url same as old, giving up.";
01133 return;
01134 }
01135
01136 const QString oldUrlStr = oldUrl.url();
01137 const QString newUrlStr = newUrl.url();
01138
01139 kDebug(7004) << oldUrl << "->" << newUrl;
01140
01141 #ifdef DEBUG_CACHE
01142 printDebug();
01143 #endif
01144
01145
01146
01147
01148
01149
01150 DirItem *dir = itemsInUse.take(oldUrlStr);
01151 Q_ASSERT( dir );
01152
01153 DirectoryDataHash::iterator dit = directoryData.find(oldUrlStr);
01154 Q_ASSERT(dit != directoryData.end());
01155 KDirListerCacheDirectoryData oldDirData = *dit;
01156 directoryData.erase(dit);
01157 Q_ASSERT( !oldDirData.listersCurrentlyListing.isEmpty() );
01158 const QList<KDirLister *> listers = oldDirData.listersCurrentlyListing;
01159 Q_ASSERT( !listers.isEmpty() );
01160
01161 foreach ( KDirLister *kdl, listers ) {
01162 kdl->d->redirect(oldUrlStr, newUrl);
01163 }
01164
01165
01166
01167 const QList<KDirLister *> holders = oldDirData.listersCurrentlyHolding;
01168 foreach ( KDirLister *kdl, holders ) {
01169 kdl->d->jobStarted( job );
01170
01171
01172 emit kdl->started( oldUrl );
01173
01174 kdl->d->redirect(oldUrl, newUrl);
01175 }
01176
01177 DirItem *newDir = itemsInUse.value(newUrlStr);
01178 if ( newDir ) {
01179 kDebug(7004) << newUrl << "already in use";
01180
01181
01182 delete dir;
01183
01184
01185
01186 KIO::ListJob *oldJob = jobForUrl( newUrlStr, job );
01187
01188
01189
01190 KDirListerCacheDirectoryData& newDirData = directoryData[newUrlStr];
01191
01192 QList<KDirLister *>& curListers = newDirData.listersCurrentlyListing;
01193 if ( !curListers.isEmpty() ) {
01194 kDebug(7004) << "and it is currently listed";
01195
01196 Q_ASSERT( oldJob );
01197
01198 foreach ( KDirLister *kdl, curListers ) {
01199 kdl->d->jobDone( oldJob );
01200
01201 kdl->d->jobStarted( job );
01202 kdl->d->connectJob( job );
01203 }
01204
01205
01206 foreach ( KDirLister *kdl, listers )
01207 curListers.append( kdl );
01208 } else {
01209 curListers = listers;
01210 }
01211
01212 if ( oldJob )
01213 killJob( oldJob );
01214
01215
01216 QList<KDirLister *>& curHolders = newDirData.listersCurrentlyHolding;
01217 if ( !curHolders.isEmpty() ) {
01218 kDebug(7004) << "and it is currently held.";
01219
01220 foreach ( KDirLister *kdl, curHolders ) {
01221 kdl->d->jobStarted( job );
01222 emit kdl->started( newUrl );
01223 }
01224
01225
01226 foreach ( KDirLister *kdl, holders )
01227 curHolders.append( kdl );
01228 } else {
01229 curHolders = holders;
01230 }
01231
01232
01233
01234
01235 foreach ( KDirLister *kdl, listers + holders ) {
01236 if ( kdl->d->rootFileItem.isNull() && kdl->d->url == newUrl )
01237 kdl->d->rootFileItem = newDir->rootItem;
01238
01239 kdl->d->addNewItems(newUrl, newDir->lstItems);
01240 kdl->d->emitItems();
01241 }
01242 } else if ( (newDir = itemsCached.take( newUrlStr )) ) {
01243 kDebug(7004) << newUrl << "is unused, but already in the cache.";
01244
01245 delete dir;
01246 itemsInUse.insert( newUrlStr, newDir );
01247 KDirListerCacheDirectoryData& newDirData = directoryData[newUrlStr];
01248 newDirData.listersCurrentlyListing = listers;
01249 newDirData.listersCurrentlyHolding = holders;
01250
01251
01252 foreach ( KDirLister *kdl, listers + holders ) {
01253 if ( kdl->d->rootFileItem.isNull() && kdl->d->url == newUrl )
01254 kdl->d->rootFileItem = newDir->rootItem;
01255
01256 kdl->d->addNewItems(newUrl, newDir->lstItems);
01257 kdl->d->emitItems();
01258 }
01259 } else {
01260 kDebug(7004) << newUrl << "has not been listed yet.";
01261
01262 dir->rootItem = KFileItem();
01263 dir->lstItems.clear();
01264 dir->redirect( newUrl );
01265 itemsInUse.insert( newUrlStr, dir );
01266 KDirListerCacheDirectoryData& newDirData = directoryData[newUrlStr];
01267 newDirData.listersCurrentlyListing = listers;
01268 newDirData.listersCurrentlyHolding = holders;
01269
01270 if ( holders.isEmpty() ) {
01271 #ifdef DEBUG_CACHE
01272 printDebug();
01273 #endif
01274 return;
01275 }
01276 }
01277
01278
01279 job->disconnect( this );
01280
01281 connect( job, SIGNAL(entries( KIO::Job *, const KIO::UDSEntryList & )),
01282 this, SLOT(slotUpdateEntries( KIO::Job *, const KIO::UDSEntryList & )) );
01283 connect( job, SIGNAL(result( KJob * )),
01284 this, SLOT(slotUpdateResult( KJob * )) );
01285
01286
01287
01288 #ifdef DEBUG_CACHE
01289 printDebug();
01290 #endif
01291 }
01292
01293 struct KDirListerCache::ItemInUseChange
01294 {
01295 ItemInUseChange(const QString& old, const QString& newU, DirItem* di)
01296 : oldUrl(old), newUrl(newU), dirItem(di) {}
01297 QString oldUrl;
01298 QString newUrl;
01299 DirItem* dirItem;
01300 };
01301
01302 void KDirListerCache::renameDir( const KUrl &oldUrl, const KUrl &newUrl )
01303 {
01304 kDebug(7004) << oldUrl << "->" << newUrl;
01305 const QString oldUrlStr = oldUrl.url(KUrl::RemoveTrailingSlash);
01306 const QString newUrlStr = newUrl.url(KUrl::RemoveTrailingSlash);
01307
01308
01309
01310
01311
01312 QLinkedList<ItemInUseChange> itemsToChange;
01313
01314
01315 QHash<QString, DirItem *>::iterator itu = itemsInUse.begin();
01316 const QHash<QString, DirItem *>::iterator ituend = itemsInUse.end();
01317 for (; itu != ituend ; ++itu) {
01318 DirItem *dir = itu.value();
01319 KUrl oldDirUrl ( itu.key() );
01320
01321
01322 if ( oldUrl.isParentOf( oldDirUrl ) ) {
01323
01324 QString relPath = oldDirUrl.path().mid( oldUrl.path().length() );
01325
01326 KUrl newDirUrl( newUrl );
01327 if ( !relPath.isEmpty() )
01328 newDirUrl.addPath( relPath );
01329
01330
01331
01332 dir->redirect( newDirUrl );
01333
01334 itemsToChange.append(ItemInUseChange(oldDirUrl.url(KUrl::RemoveTrailingSlash),
01335 newDirUrl.url(KUrl::RemoveTrailingSlash),
01336 dir));
01337
01338
01339 for ( KFileItemList::iterator kit = dir->lstItems.begin(), kend = dir->lstItems.end();
01340 kit != kend ; ++kit )
01341 {
01342 aboutToRefreshItem(*kit);
01343 const KFileItem oldItem = *kit;
01344
01345 const KUrl oldItemUrl ((*kit).url());
01346 const QString oldItemUrlStr( oldItemUrl.url(KUrl::RemoveTrailingSlash) );
01347 KUrl newItemUrl( oldItemUrl );
01348 newItemUrl.setPath( newDirUrl.path() );
01349 newItemUrl.addPath( oldItemUrl.fileName() );
01350 kDebug(7004) << "renaming" << oldItemUrl << "to" << newItemUrl;
01351 (*kit).setUrl(newItemUrl);
01352
01353 emitRefreshItem(oldItem, *kit);
01354 }
01355 emitRedirections( oldDirUrl, newDirUrl );
01356 }
01357 }
01358
01359
01360
01361 foreach(const ItemInUseChange& i, itemsToChange) {
01362 itemsInUse.remove(i.oldUrl);
01363 itemsInUse.insert(i.newUrl, i.dirItem);
01364 }
01365
01366
01367
01368 removeDirFromCache( oldUrl );
01369
01370 }
01371
01372
01373 void KDirListerCache::emitRedirections( const KUrl &oldUrl, const KUrl &newUrl )
01374 {
01375 kDebug(7004) << oldUrl << "->" << newUrl;
01376 const QString oldUrlStr = oldUrl.url(KUrl::RemoveTrailingSlash);
01377 const QString newUrlStr = newUrl.url(KUrl::RemoveTrailingSlash);
01378
01379 KIO::ListJob *job = jobForUrl( oldUrlStr );
01380 if ( job )
01381 killJob( job );
01382
01383
01384 DirectoryDataHash::iterator dit = directoryData.find(oldUrlStr);
01385 if ( dit == directoryData.end() )
01386 return;
01387 const QList<KDirLister *> listers = (*dit).listersCurrentlyListing;
01388 const QList<KDirLister *> holders = (*dit).listersCurrentlyHolding;
01389
01390 KDirListerCacheDirectoryData& newDirData = directoryData[newUrlStr];
01391
01392
01393 foreach ( KDirLister *kdl, listers ) {
01394 if ( job )
01395 kdl->d->jobDone( job );
01396
01397 emit kdl->canceled( oldUrl );
01398 }
01399 newDirData.listersCurrentlyListing += listers;
01400
01401
01402 foreach ( KDirLister *kdl, holders ) {
01403 if ( job )
01404 kdl->d->jobDone( job );
01405 }
01406 newDirData.listersCurrentlyHolding += holders;
01407 directoryData.erase(dit);
01408
01409 if ( !listers.isEmpty() ) {
01410 updateDirectory( newUrl );
01411
01412
01413 foreach ( KDirLister *kdl, listers )
01414 emit kdl->started( newUrl );
01415 }
01416
01417
01418 foreach ( KDirLister *kdl, holders ) {
01419
01420 KUrl::List& lstDirs = kdl->d->lstDirs;
01421 lstDirs[ lstDirs.indexOf( oldUrl ) ] = newUrl;
01422
01423 if ( lstDirs.count() == 1 )
01424 emit kdl->redirection( newUrl );
01425
01426 emit kdl->redirection( oldUrl, newUrl );
01427 }
01428 }
01429
01430 void KDirListerCache::removeDirFromCache( const KUrl& dir )
01431 {
01432 kDebug(7004) << dir;
01433 const QList<QString> cachedDirs = itemsCached.keys();
01434 foreach(const QString& cachedDir, cachedDirs) {
01435 if ( dir.isParentOf( KUrl( cachedDir ) ) )
01436 itemsCached.remove( cachedDir );
01437 }
01438 }
01439
01440 void KDirListerCache::slotUpdateEntries( KIO::Job* job, const KIO::UDSEntryList& list )
01441 {
01442 runningListJobs[static_cast<KIO::ListJob*>(job)] += list;
01443 }
01444
01445 void KDirListerCache::slotUpdateResult( KJob * j )
01446 {
01447 Q_ASSERT( j );
01448 KIO::ListJob *job = static_cast<KIO::ListJob *>( j );
01449
01450 KUrl jobUrl (joburl( job ));
01451 jobUrl.adjustPath(KUrl::RemoveTrailingSlash);
01452 QString jobUrlStr (jobUrl.url());
01453
01454 kDebug(7004) << "finished update" << jobUrl;
01455
01456 KDirListerCacheDirectoryData& dirData = directoryData[jobUrlStr];
01457
01458
01459 dirData.moveListersWithoutCachedItemsJob();
01460 QList<KDirLister *> listers = dirData.listersCurrentlyHolding;
01461 listers += dirData.listersCurrentlyListing;
01462
01463
01464 Q_ASSERT( !listers.isEmpty() );
01465
01466 if ( job->error() ) {
01467 foreach ( KDirLister* kdl, listers ) {
01468 kdl->d->jobDone( job );
01469
01470
01471
01472
01473 emit kdl->canceled( jobUrl );
01474 if ( kdl->d->numJobs() == 0 ) {
01475 kdl->d->complete = true;
01476 emit kdl->canceled();
01477 }
01478 }
01479
01480 runningListJobs.remove( job );
01481
01482
01483
01484 processPendingUpdates();
01485 return;
01486 }
01487
01488 DirItem *dir = itemsInUse.value(jobUrlStr, 0);
01489 Q_ASSERT(dir);
01490 dir->complete = true;
01491
01492
01493
01494 bool delayedMimeTypes = true;
01495 foreach ( KDirLister *kdl, listers )
01496 delayedMimeTypes &= kdl->d->delayedMimeTypes;
01497
01498 QHash<QString, KFileItem*> fileItems;
01499
01500
01501 for ( KFileItemList::iterator kit = dir->lstItems.begin(), kend = dir->lstItems.end() ; kit != kend ; ++kit )
01502 {
01503 (*kit).unmark();
01504 fileItems.insert( (*kit).name(), &*kit );
01505 }
01506
01507 const KIO::UDSEntryList& buf = runningListJobs.value( job );
01508 KIO::UDSEntryList::const_iterator it = buf.constBegin();
01509 const KIO::UDSEntryList::const_iterator end = buf.constEnd();
01510 for ( ; it != end; ++it )
01511 {
01512
01513 KFileItem item( *it, jobUrl, delayedMimeTypes, true );
01514
01515 const QString name = item.name();
01516 Q_ASSERT( !name.isEmpty() );
01517
01518
01519
01520 if ( name.isEmpty() || name == ".." )
01521 continue;
01522
01523 if ( name == "." )
01524 {
01525
01526
01527 if ( dir->rootItem.isNull() )
01528 {
01529 dir->rootItem = item;
01530
01531 foreach ( KDirLister *kdl, listers )
01532 if ( kdl->d->rootFileItem.isNull() && kdl->d->url == jobUrl )
01533 kdl->d->rootFileItem = dir->rootItem;
01534 }
01535 continue;
01536 }
01537
01538
01539 if (KFileItem* tmp = fileItems.value(item.name()))
01540 {
01541 QSet<KFileItem*>::iterator pru_it = pendingRemoteUpdates.find(tmp);
01542 const bool inPendingRemoteUpdates = (pru_it != pendingRemoteUpdates.end());
01543
01544
01545 if (!tmp->cmp( item ) || inPendingRemoteUpdates) {
01546
01547 if (inPendingRemoteUpdates) {
01548 pendingRemoteUpdates.erase(pru_it);
01549 }
01550 foreach ( KDirLister *kdl, listers )
01551 kdl->d->aboutToRefreshItem( *tmp );
01552
01553
01554
01555 const KFileItem oldItem = *tmp;
01556 *tmp = item;
01557 foreach ( KDirLister *kdl, listers )
01558 kdl->d->addRefreshItem(jobUrl, oldItem, *tmp);
01559 }
01560 tmp->mark();
01561 }
01562 else
01563 {
01564
01565
01566 KFileItem pitem(item);
01567 pitem.mark();
01568 dir->lstItems.append( pitem );
01569
01570 foreach ( KDirLister *kdl, listers )
01571 kdl->d->addNewItem(jobUrl, pitem);
01572 }
01573 }
01574
01575 runningListJobs.remove( job );
01576
01577 deleteUnmarkedItems( listers, dir->lstItems );
01578
01579 foreach ( KDirLister *kdl, listers ) {
01580 kdl->d->emitItems();
01581
01582 kdl->d->jobDone( job );
01583
01584 emit kdl->completed( jobUrl );
01585 if ( kdl->d->numJobs() == 0 )
01586 {
01587 kdl->d->complete = true;
01588 emit kdl->completed();
01589 }
01590 }
01591
01592
01593
01594 processPendingUpdates();
01595 }
01596
01597
01598
01599 KIO::ListJob *KDirListerCache::jobForUrl( const QString& url, KIO::ListJob *not_job )
01600 {
01601 QMap< KIO::ListJob *, KIO::UDSEntryList >::const_iterator it = runningListJobs.constBegin();
01602 while ( it != runningListJobs.constEnd() )
01603 {
01604 KIO::ListJob *job = it.key();
01605 if ( joburl( job ).url(KUrl::RemoveTrailingSlash) == url && job != not_job )
01606 return job;
01607 ++it;
01608 }
01609 return 0;
01610 }
01611
01612 const KUrl& KDirListerCache::joburl( KIO::ListJob *job )
01613 {
01614 if ( job->redirectionUrl().isValid() )
01615 return job->redirectionUrl();
01616 else
01617 return job->url();
01618 }
01619
01620 void KDirListerCache::killJob( KIO::ListJob *job )
01621 {
01622 runningListJobs.remove( job );
01623 job->disconnect( this );
01624 job->kill();
01625 }
01626
01627 void KDirListerCache::deleteUnmarkedItems( const QList<KDirLister *>& listers, KFileItemList &lstItems )
01628 {
01629 KFileItemList deletedItems;
01630
01631 QMutableListIterator<KFileItem> kit(lstItems);
01632 while (kit.hasNext()) {
01633 const KFileItem item = kit.next();
01634 if (!item.isMarked()) {
01635
01636 deletedItems.append(item);
01637 kit.remove();
01638 }
01639 }
01640 if (!deletedItems.isEmpty())
01641 itemsDeleted(listers, deletedItems);
01642 }
01643
01644 void KDirListerCache::itemsDeleted(const QList<KDirLister *>& listers, const KFileItemList& deletedItems)
01645 {
01646 Q_FOREACH(KDirLister *kdl, listers) {
01647 kdl->d->emitItemsDeleted(deletedItems);
01648 }
01649
01650 Q_FOREACH(const KFileItem& item, deletedItems) {
01651 if (item.isDir())
01652 deleteDir(item.url());
01653 }
01654 }
01655
01656 void KDirListerCache::deleteDir( const KUrl& dirUrl )
01657 {
01658
01659
01660
01661
01662
01663
01664 KUrl::List affectedItems;
01665
01666 QHash<QString, DirItem *>::iterator itu = itemsInUse.begin();
01667 const QHash<QString, DirItem *>::iterator ituend = itemsInUse.end();
01668 for ( ; itu != ituend; ++itu ) {
01669 const KUrl deletedUrl( itu.key() );
01670 if ( dirUrl.isParentOf( deletedUrl ) ) {
01671 affectedItems.append(deletedUrl);
01672 }
01673 }
01674
01675 foreach(const KUrl& deletedUrl, affectedItems) {
01676 const QString deletedUrlStr = deletedUrl.url();
01677
01678 DirectoryDataHash::iterator dit = directoryData.find(deletedUrlStr);
01679 if (dit != directoryData.end()) {
01680
01681 QList<KDirLister *> listers = (*dit).listersCurrentlyListing;
01682 foreach ( KDirLister *kdl, listers )
01683 stop( kdl, deletedUrl );
01684
01685
01686
01687
01688 QList<KDirLister *> holders = (*dit).listersCurrentlyHolding;
01689 foreach ( KDirLister *kdl, holders ) {
01690
01691 if ( kdl->d->url == deletedUrl )
01692 {
01693
01694 if ( !kdl->d->rootFileItem.isNull() ) {
01695 emit kdl->deleteItem( kdl->d->rootFileItem );
01696 emit kdl->itemsDeleted(KFileItemList() << kdl->d->rootFileItem);
01697 }
01698 forgetDirs( kdl );
01699 kdl->d->rootFileItem = KFileItem();
01700 }
01701 else
01702 {
01703 const bool treeview = kdl->d->lstDirs.count() > 1;
01704 if ( !treeview )
01705 {
01706 emit kdl->clear();
01707 kdl->d->lstDirs.clear();
01708 }
01709 else
01710 kdl->d->lstDirs.removeAll( deletedUrl );
01711
01712 forgetDirs( kdl, deletedUrl, treeview );
01713 }
01714 }
01715 }
01716
01717
01718
01719 int count = itemsInUse.remove( deletedUrlStr );
01720 Q_ASSERT( count == 0 );
01721 Q_UNUSED( count );
01722 }
01723
01724
01725 removeDirFromCache( dirUrl );
01726 }
01727
01728
01729 void KDirListerCache::processPendingUpdates()
01730 {
01731 foreach(const QString& file, pendingUpdates) {
01732 kDebug(7004) << file;
01733 KUrl u(file);
01734 KFileItem *item = findByUrl( 0, u );
01735 if ( item ) {
01736
01737 aboutToRefreshItem( *item );
01738 KFileItem oldItem = *item;
01739 item->refresh();
01740 emitRefreshItem( oldItem, *item );
01741 }
01742 }
01743 pendingUpdates.clear();
01744 }
01745
01746 #ifndef NDEBUG
01747 void KDirListerCache::printDebug()
01748 {
01749 kDebug(7004) << "Items in use:";
01750 QHash<QString, DirItem *>::const_iterator itu = itemsInUse.constBegin();
01751 const QHash<QString, DirItem *>::const_iterator ituend = itemsInUse.constEnd();
01752 for ( ; itu != ituend ; ++itu ) {
01753 kDebug(7004) << " " << itu.key() << "URL:" << itu.value()->url
01754 << "rootItem:" << ( !itu.value()->rootItem.isNull() ? itu.value()->rootItem.url() : KUrl() )
01755 << "autoUpdates refcount:" << itu.value()->autoUpdates
01756 << "complete:" << itu.value()->complete
01757 << QString("with %1 items.").arg(itu.value()->lstItems.count());
01758 }
01759
01760 kDebug(7004) << "Directory data:";
01761 DirectoryDataHash::const_iterator dit = directoryData.constBegin();
01762 for ( ; dit != directoryData.constEnd(); ++dit )
01763 {
01764 QString list;
01765 foreach ( KDirLister* listit, (*dit).listersCurrentlyListing )
01766 list += " 0x" + QString::number( (qlonglong)listit, 16 );
01767 kDebug(7004) << " " << dit.key() << (*dit).listersCurrentlyListing.count() << "listers:" << list;
01768 foreach ( KDirLister* listit, (*dit).listersCurrentlyListing ) {
01769 if (listit->d->m_cachedItemsJob) {
01770 kDebug(7004) << " Lister" << listit << "has CachedItemsJob" << listit->d->m_cachedItemsJob;
01771 }
01772 }
01773
01774 list.clear();
01775 foreach ( KDirLister* listit, (*dit).listersCurrentlyHolding )
01776 list += " 0x" + QString::number( (qlonglong)listit, 16 );
01777 kDebug(7004) << " " << dit.key() << (*dit).listersCurrentlyHolding.count() << "holders:" << list;
01778 }
01779
01780 QMap< KIO::ListJob *, KIO::UDSEntryList >::Iterator jit = runningListJobs.begin();
01781 kDebug(7004) << "Jobs:";
01782 for ( ; jit != runningListJobs.end() ; ++jit )
01783 kDebug(7004) << " " << jit.key() << "listing" << joburl( jit.key() ) << ":" << (*jit).count() << "entries.";
01784
01785 kDebug(7004) << "Items in cache:";
01786 const QList<QString> cachedDirs = itemsCached.keys();
01787 foreach(const QString& cachedDir, cachedDirs) {
01788 DirItem* dirItem = itemsCached.object(cachedDir);
01789 kDebug(7004) << " " << cachedDir << "rootItem:"
01790 << (!dirItem->rootItem.isNull() ? dirItem->rootItem.url().prettyUrl() : QString("NULL") )
01791 << "with" << dirItem->lstItems.count() << "items.";
01792 }
01793 }
01794 #endif
01795
01796
01797 KDirLister::KDirLister( QObject* parent )
01798 : QObject(parent), d(new Private(this))
01799 {
01800
01801
01802 d->complete = true;
01803
01804 setAutoUpdate( true );
01805 setDirOnlyMode( false );
01806 setShowingDotFiles( false );
01807
01808 setAutoErrorHandlingEnabled( true, 0 );
01809 }
01810
01811 KDirLister::~KDirLister()
01812 {
01813
01814
01815
01816 if (!kDirListerCache.isDestroyed()) {
01817 stop();
01818 kDirListerCache->forgetDirs( this );
01819 }
01820
01821 delete d;
01822 }
01823
01824 bool KDirLister::openUrl( const KUrl& _url, OpenUrlFlags _flags )
01825 {
01826
01827 if (d->hasPendingChanges && (_flags & Keep))
01828 emitChanges();
01829
01830 d->hasPendingChanges = false;
01831
01832 return kDirListerCache->listDir( this, _url, _flags & Keep, _flags & Reload );
01833 }
01834
01835 void KDirLister::stop()
01836 {
01837 kDirListerCache->stop( this );
01838 }
01839
01840 void KDirLister::stop( const KUrl& _url )
01841 {
01842 kDirListerCache->stop( this, _url );
01843 }
01844
01845 bool KDirLister::autoUpdate() const
01846 {
01847 return d->autoUpdate;
01848 }
01849
01850 void KDirLister::setAutoUpdate( bool _enable )
01851 {
01852 if ( d->autoUpdate == _enable )
01853 return;
01854
01855 d->autoUpdate = _enable;
01856 kDirListerCache->setAutoUpdate( this, _enable );
01857 }
01858
01859 bool KDirLister::showingDotFiles() const
01860 {
01861 return d->settings.isShowingDotFiles;
01862 }
01863
01864 void KDirLister::setShowingDotFiles( bool _showDotFiles )
01865 {
01866 if ( d->settings.isShowingDotFiles == _showDotFiles )
01867 return;
01868
01869 d->prepareForSettingsChange();
01870 d->settings.isShowingDotFiles = _showDotFiles;
01871 }
01872
01873 bool KDirLister::dirOnlyMode() const
01874 {
01875 return d->settings.dirOnlyMode;
01876 }
01877
01878 void KDirLister::setDirOnlyMode( bool _dirsOnly )
01879 {
01880 if ( d->settings.dirOnlyMode == _dirsOnly )
01881 return;
01882
01883 d->prepareForSettingsChange();
01884 d->settings.dirOnlyMode = _dirsOnly;
01885 }
01886
01887 bool KDirLister::autoErrorHandlingEnabled() const
01888 {
01889 return d->autoErrorHandling;
01890 }
01891
01892 void KDirLister::setAutoErrorHandlingEnabled( bool enable, QWidget* parent )
01893 {
01894 d->autoErrorHandling = enable;
01895 d->errorParent = parent;
01896 }
01897
01898 KUrl KDirLister::url() const
01899 {
01900 return d->url;
01901 }
01902
01903 KUrl::List KDirLister::directories() const
01904 {
01905 return d->lstDirs;
01906 }
01907
01908 void KDirLister::emitChanges()
01909 {
01910 d->emitChanges();
01911 }
01912
01913 void KDirLister::Private::emitChanges()
01914 {
01915 if (!hasPendingChanges)
01916 return;
01917
01918
01919
01920 hasPendingChanges = false;
01921
01922 const Private::FilterSettings newSettings = settings;
01923 settings = oldSettings;
01924
01925
01926 Q_FOREACH(const KUrl& dir, lstDirs) {
01927 KFileItemList* itemList = kDirListerCache->itemsForDir(dir);
01928 KFileItemList::iterator kit = itemList->begin();
01929 const KFileItemList::iterator kend = itemList->end();
01930 for (; kit != kend; ++kit) {
01931 if (isItemVisible(*kit) && m_parent->matchesMimeFilter(*kit))
01932 (*kit).mark();
01933 else
01934 (*kit).unmark();
01935 }
01936 }
01937
01938 settings = newSettings;
01939
01940 Q_FOREACH(const KUrl& dir, lstDirs) {
01941 KFileItemList deletedItems;
01942
01943 KFileItemList* itemList = kDirListerCache->itemsForDir(dir);
01944 KFileItemList::iterator kit = itemList->begin();
01945 const KFileItemList::iterator kend = itemList->end();
01946 for (; kit != kend; ++kit) {
01947 KFileItem& item = *kit;
01948 const QString text = item.text();
01949 if (text == "." || text == "..")
01950 continue;
01951 const bool nowVisible = isItemVisible(item) && m_parent->matchesMimeFilter(item);
01952 if (nowVisible && !item.isMarked())
01953 addNewItem(dir, item);
01954 else if (!nowVisible && item.isMarked())
01955 deletedItems.append(*kit);
01956 }
01957 if (!deletedItems.isEmpty()) {
01958 emit m_parent->itemsDeleted(deletedItems);
01959
01960 Q_FOREACH(const KFileItem& item, deletedItems)
01961 emit m_parent->deleteItem(item);
01962 }
01963 emitItems();
01964 }
01965 oldSettings = settings;
01966 }
01967
01968 void KDirLister::updateDirectory( const KUrl& _u )
01969 {
01970 kDirListerCache->updateDirectory( _u );
01971 }
01972
01973 bool KDirLister::isFinished() const
01974 {
01975 return d->complete;
01976 }
01977
01978 KFileItem KDirLister::rootItem() const
01979 {
01980 return d->rootFileItem;
01981 }
01982
01983 KFileItem KDirLister::findByUrl( const KUrl& _url ) const
01984 {
01985 KFileItem *item = kDirListerCache->findByUrl( this, _url );
01986 if (item) {
01987 return *item;
01988 } else {
01989 return KFileItem();
01990 }
01991 }
01992
01993 KFileItem KDirLister::findByName( const QString& _name ) const
01994 {
01995 return kDirListerCache->findByName( this, _name );
01996 }
01997
01998
01999
02000
02001 void KDirLister::setNameFilter( const QString& nameFilter )
02002 {
02003 if (d->nameFilter == nameFilter)
02004 return;
02005
02006 d->prepareForSettingsChange();
02007
02008 d->settings.lstFilters.clear();
02009 d->nameFilter = nameFilter;
02010
02011 const QStringList list = nameFilter.split( ' ', QString::SkipEmptyParts );
02012 for (QStringList::const_iterator it = list.begin(); it != list.end(); ++it)
02013 d->settings.lstFilters.append(QRegExp(*it, Qt::CaseInsensitive, QRegExp::Wildcard));
02014 }
02015
02016 QString KDirLister::nameFilter() const
02017 {
02018 return d->nameFilter;
02019 }
02020
02021 void KDirLister::setMimeFilter( const QStringList& mimeFilter )
02022 {
02023 if (d->settings.mimeFilter == mimeFilter)
02024 return;
02025
02026 d->prepareForSettingsChange();
02027 if (mimeFilter.contains("application/octet-stream"))
02028 d->settings.mimeFilter.clear();
02029 else
02030 d->settings.mimeFilter = mimeFilter;
02031 }
02032
02033 void KDirLister::setMimeExcludeFilter( const QStringList& mimeExcludeFilter )
02034 {
02035 if (d->settings.mimeExcludeFilter == mimeExcludeFilter)
02036 return;
02037
02038 d->prepareForSettingsChange();
02039 d->settings.mimeExcludeFilter = mimeExcludeFilter;
02040 }
02041
02042
02043 void KDirLister::clearMimeFilter()
02044 {
02045 d->prepareForSettingsChange();
02046 d->settings.mimeFilter.clear();
02047 d->settings.mimeExcludeFilter.clear();
02048 }
02049
02050 QStringList KDirLister::mimeFilters() const
02051 {
02052 return d->settings.mimeFilter;
02053 }
02054
02055 bool KDirLister::matchesFilter( const QString& name ) const
02056 {
02057 return doNameFilter(name, d->settings.lstFilters);
02058 }
02059
02060 bool KDirLister::matchesMimeFilter( const QString& mime ) const
02061 {
02062 return doMimeFilter(mime, d->settings.mimeFilter) &&
02063 d->doMimeExcludeFilter(mime, d->settings.mimeExcludeFilter);
02064 }
02065
02066
02067
02068 bool KDirLister::matchesFilter( const KFileItem& item ) const
02069 {
02070 Q_ASSERT( !item.isNull() );
02071
02072 if ( item.text() == ".." )
02073 return false;
02074
02075 if ( !d->settings.isShowingDotFiles && item.isHidden() )
02076 return false;
02077
02078 if ( item.isDir() || d->settings.lstFilters.isEmpty() )
02079 return true;
02080
02081 return matchesFilter( item.text() );
02082 }
02083
02084 bool KDirLister::matchesMimeFilter( const KFileItem& item ) const
02085 {
02086 Q_ASSERT(!item.isNull());
02087
02088 if (d->settings.mimeFilter.isEmpty() && d->settings.mimeExcludeFilter.isEmpty())
02089 return true;
02090 return matchesMimeFilter(item.mimetype());
02091 }
02092
02093 bool KDirLister::doNameFilter( const QString& name, const QList<QRegExp>& filters ) const
02094 {
02095 for ( QList<QRegExp>::const_iterator it = filters.begin(); it != filters.end(); ++it )
02096 if ( (*it).exactMatch( name ) )
02097 return true;
02098
02099 return false;
02100 }
02101
02102 bool KDirLister::doMimeFilter( const QString& mime, const QStringList& filters ) const
02103 {
02104 if ( filters.isEmpty() )
02105 return true;
02106
02107 const KMimeType::Ptr mimeptr = KMimeType::mimeType(mime);
02108 if ( !mimeptr )
02109 return false;
02110
02111
02112 QStringList::const_iterator it = filters.begin();
02113 for ( ; it != filters.end(); ++it )
02114 if ( mimeptr->is(*it) )
02115 return true;
02116
02117
02118 return false;
02119 }
02120
02121 bool KDirLister::Private::doMimeExcludeFilter( const QString& mime, const QStringList& filters ) const
02122 {
02123 if ( filters.isEmpty() )
02124 return true;
02125
02126 QStringList::const_iterator it = filters.begin();
02127 for ( ; it != filters.end(); ++it )
02128 if ( (*it) == mime )
02129 return false;
02130
02131 return true;
02132 }
02133
02134 void KDirLister::handleError( KIO::Job *job )
02135 {
02136 if ( d->autoErrorHandling )
02137 job->uiDelegate()->showErrorMessage();
02138 }
02139
02140
02141
02142
02143 void KDirLister::Private::addNewItem(const KUrl& directoryUrl, const KFileItem &item)
02144 {
02145 if (!isItemVisible(item))
02146 return;
02147
02148 if ( m_parent->matchesMimeFilter( item ) )
02149 {
02150 if ( !lstNewItems )
02151 {
02152 lstNewItems = new NewItemsHash;
02153 }
02154
02155 Q_ASSERT( !item.isNull() );
02156 (*lstNewItems)[directoryUrl].append( item );
02157 }
02158 else
02159 {
02160 if ( !lstMimeFilteredItems ) {
02161 lstMimeFilteredItems = new KFileItemList;
02162 }
02163
02164 Q_ASSERT( !item.isNull() );
02165 lstMimeFilteredItems->append( item );
02166 }
02167 }
02168
02169 void KDirLister::Private::addNewItems(const KUrl& directoryUrl, const KFileItemList& items)
02170 {
02171
02172
02173
02174 KFileItemList::const_iterator kit = items.begin();
02175 const KFileItemList::const_iterator kend = items.end();
02176 for ( ; kit != kend; ++kit )
02177 addNewItem(directoryUrl, *kit);
02178 }
02179
02180 void KDirLister::Private::aboutToRefreshItem( const KFileItem &item )
02181 {
02182 refreshItemWasFiltered = !isItemVisible(item) || !m_parent->matchesMimeFilter(item);
02183 }
02184
02185 void KDirLister::Private::addRefreshItem(const KUrl& directoryUrl, const KFileItem& oldItem, const KFileItem& item)
02186 {
02187 if (isItemVisible(item) && m_parent->matchesMimeFilter(item)) {
02188 if ( refreshItemWasFiltered )
02189 {
02190 if ( !lstNewItems ) {
02191 lstNewItems = new NewItemsHash;
02192 }
02193
02194 Q_ASSERT( !item.isNull() );
02195 (*lstNewItems)[directoryUrl].append( item );
02196 }
02197 else
02198 {
02199 if ( !lstRefreshItems ) {
02200 lstRefreshItems = new QList<QPair<KFileItem,KFileItem> >;
02201 }
02202
02203 Q_ASSERT( !item.isNull() );
02204 lstRefreshItems->append( qMakePair(oldItem, item) );
02205 }
02206 }
02207 else if ( !refreshItemWasFiltered )
02208 {
02209 if ( !lstRemoveItems ) {
02210 lstRemoveItems = new KFileItemList;
02211 }
02212
02213
02214
02215
02216 Q_ASSERT(!oldItem.isNull());
02217 lstRemoveItems->append(oldItem);
02218 }
02219 }
02220
02221 void KDirLister::Private::emitItems()
02222 {
02223 NewItemsHash *tmpNew = lstNewItems;
02224 lstNewItems = 0;
02225
02226 KFileItemList *tmpMime = lstMimeFilteredItems;
02227 lstMimeFilteredItems = 0;
02228
02229 QList<QPair<KFileItem, KFileItem> > *tmpRefresh = lstRefreshItems;
02230 lstRefreshItems = 0;
02231
02232 KFileItemList *tmpRemove = lstRemoveItems;
02233 lstRemoveItems = 0;
02234
02235 if (tmpNew) {
02236 QHashIterator<KUrl, KFileItemList> it(*tmpNew);
02237 while (it.hasNext()) {
02238 it.next();
02239 emit m_parent->itemsAdded(it.key(), it.value());
02240 emit m_parent->newItems(it.value());
02241 }
02242 delete tmpNew;
02243 }
02244
02245 if ( tmpMime )
02246 {
02247 emit m_parent->itemsFilteredByMime( *tmpMime );
02248 delete tmpMime;
02249 }
02250
02251 if ( tmpRefresh )
02252 {
02253 emit m_parent->refreshItems( *tmpRefresh );
02254 delete tmpRefresh;
02255 }
02256
02257 if ( tmpRemove )
02258 {
02259 emit m_parent->itemsDeleted( *tmpRemove );
02260 delete tmpRemove;
02261 }
02262 }
02263
02264 void KDirLister::Private::emitDeleteItem( const KFileItem &item )
02265 {
02266 if (isItemVisible(item) && m_parent->matchesMimeFilter(item)) {
02267 emit m_parent->deleteItem(item);
02268 }
02269 }
02270
02271 bool KDirLister::Private::isItemVisible(const KFileItem& item) const
02272 {
02273
02274
02275
02276 return (!settings.dirOnlyMode || item.isDir())
02277 && m_parent->matchesFilter(item);
02278 }
02279
02280 void KDirLister::Private::emitItemsDeleted(const KFileItemList &_items)
02281 {
02282 KFileItemList items = _items;
02283 QMutableListIterator<KFileItem> it(items);
02284 while (it.hasNext()) {
02285 const KFileItem& item = it.next();
02286 if (isItemVisible(item) && m_parent->matchesMimeFilter(item)) {
02287
02288 emit m_parent->deleteItem(item);
02289 } else {
02290 it.remove();
02291 }
02292 }
02293 if (!items.isEmpty())
02294 emit m_parent->itemsDeleted(items);
02295 }
02296
02297
02298
02299 void KDirLister::Private::_k_slotInfoMessage( KJob *, const QString& message )
02300 {
02301 emit m_parent->infoMessage( message );
02302 }
02303
02304 void KDirLister::Private::_k_slotPercent( KJob *job, unsigned long pcnt )
02305 {
02306 jobData[static_cast<KIO::ListJob *>(job)].percent = pcnt;
02307
02308 int result = 0;
02309
02310 KIO::filesize_t size = 0;
02311
02312 QMap< KIO::ListJob *, Private::JobData >::Iterator dataIt = jobData.begin();
02313 while ( dataIt != jobData.end() )
02314 {
02315 result += (*dataIt).percent * (*dataIt).totalSize;
02316 size += (*dataIt).totalSize;
02317 ++dataIt;
02318 }
02319
02320 if ( size != 0 )
02321 result /= size;
02322 else
02323 result = 100;
02324 emit m_parent->percent( result );
02325 }
02326
02327 void KDirLister::Private::_k_slotTotalSize( KJob *job, qulonglong size )
02328 {
02329 jobData[static_cast<KIO::ListJob *>(job)].totalSize = size;
02330
02331 KIO::filesize_t result = 0;
02332 QMap< KIO::ListJob *, Private::JobData >::Iterator dataIt = jobData.begin();
02333 while ( dataIt != jobData.end() )
02334 {
02335 result += (*dataIt).totalSize;
02336 ++dataIt;
02337 }
02338
02339 emit m_parent->totalSize( result );
02340 }
02341
02342 void KDirLister::Private::_k_slotProcessedSize( KJob *job, qulonglong size )
02343 {
02344 jobData[static_cast<KIO::ListJob *>(job)].processedSize = size;
02345
02346 KIO::filesize_t result = 0;
02347 QMap< KIO::ListJob *, Private::JobData >::Iterator dataIt = jobData.begin();
02348 while ( dataIt != jobData.end() )
02349 {
02350 result += (*dataIt).processedSize;
02351 ++dataIt;
02352 }
02353
02354 emit m_parent->processedSize( result );
02355 }
02356
02357 void KDirLister::Private::_k_slotSpeed( KJob *job, unsigned long spd )
02358 {
02359 jobData[static_cast<KIO::ListJob *>(job)].speed = spd;
02360
02361 int result = 0;
02362 QMap< KIO::ListJob *, Private::JobData >::Iterator dataIt = jobData.begin();
02363 while ( dataIt != jobData.end() )
02364 {
02365 result += (*dataIt).speed;
02366 ++dataIt;
02367 }
02368
02369 emit m_parent->speed( result );
02370 }
02371
02372 uint KDirLister::Private::numJobs()
02373 {
02374 #ifdef DEBUG_CACHE
02375
02376 qDebug() << m_parent << "numJobs:" << jobData.count();
02377 QMapIterator<KIO::ListJob *, JobData> it(jobData);
02378 while (it.hasNext()) {
02379 it.next();
02380 qDebug() << (void*)it.key();
02381 qDebug() << it.key();
02382 }
02383 #endif
02384
02385 return jobData.count();
02386 }
02387
02388 void KDirLister::Private::jobDone( KIO::ListJob *job )
02389 {
02390 jobData.remove( job );
02391 }
02392
02393 void KDirLister::Private::jobStarted( KIO::ListJob *job )
02394 {
02395 Private::JobData data;
02396 data.speed = 0;
02397 data.percent = 0;
02398 data.processedSize = 0;
02399 data.totalSize = 0;
02400
02401 jobData.insert( job, data );
02402 complete = false;
02403 }
02404
02405 void KDirLister::Private::connectJob( KIO::ListJob *job )
02406 {
02407 m_parent->connect( job, SIGNAL(infoMessage( KJob *, const QString&, const QString& )),
02408 m_parent, SLOT(_k_slotInfoMessage( KJob *, const QString& )) );
02409 m_parent->connect( job, SIGNAL(percent( KJob *, unsigned long )),
02410 m_parent, SLOT(_k_slotPercent( KJob *, unsigned long )) );
02411 m_parent->connect( job, SIGNAL(totalSize( KJob *, qulonglong )),
02412 m_parent, SLOT(_k_slotTotalSize( KJob *, qulonglong )) );
02413 m_parent->connect( job, SIGNAL(processedSize( KJob *, qulonglong )),
02414 m_parent, SLOT(_k_slotProcessedSize( KJob *, qulonglong )) );
02415 m_parent->connect( job, SIGNAL(speed( KJob *, unsigned long )),
02416 m_parent, SLOT(_k_slotSpeed( KJob *, unsigned long )) );
02417 }
02418
02419 void KDirLister::setMainWindow( QWidget *window )
02420 {
02421 d->window = window;
02422 }
02423
02424 QWidget *KDirLister::mainWindow()
02425 {
02426 return d->window;
02427 }
02428
02429 KFileItemList KDirLister::items( WhichItems which ) const
02430 {
02431 return itemsForDir( url(), which );
02432 }
02433
02434 KFileItemList KDirLister::itemsForDir( const KUrl& dir, WhichItems which ) const
02435 {
02436 KFileItemList *allItems = kDirListerCache->itemsForDir( dir );
02437 if ( !allItems )
02438 return KFileItemList();
02439
02440 if ( which == AllItems )
02441 return *allItems;
02442 else
02443 {
02444 KFileItemList result;
02445 KFileItemList::const_iterator kit = allItems->constBegin();
02446 const KFileItemList::const_iterator kend = allItems->constEnd();
02447 for ( ; kit != kend; ++kit )
02448 {
02449 const KFileItem& item = *kit;
02450 if (d->isItemVisible(item) && matchesMimeFilter(item)) {
02451 result.append(item);
02452 }
02453 }
02454 return result;
02455 }
02456 }
02457
02458 bool KDirLister::delayedMimeTypes() const
02459 {
02460 return d->delayedMimeTypes;
02461 }
02462
02463 void KDirLister::setDelayedMimeTypes( bool delayedMimeTypes )
02464 {
02465 d->delayedMimeTypes = delayedMimeTypes;
02466 }
02467
02468
02469 void KDirLister::Private::redirect( const KUrl& oldUrl, const KUrl& newUrl )
02470 {
02471 if ( url.equals( oldUrl, KUrl::CompareWithoutTrailingSlash ) ) {
02472 rootFileItem = KFileItem();
02473 url = newUrl;
02474 }
02475
02476 const int idx = lstDirs.indexOf( oldUrl );
02477 if (idx == -1) {
02478 kWarning(7004) << "Unexpected redirection from" << oldUrl << "to" << newUrl
02479 << "but this dirlister is currently listing" << lstDirs;
02480 } else {
02481 lstDirs[ idx ] = newUrl;
02482 }
02483
02484 if ( lstDirs.count() == 1 ) {
02485 emit m_parent->clear();
02486 emit m_parent->redirection( newUrl );
02487 emit m_parent->redirection( oldUrl, newUrl );
02488 } else {
02489 emit m_parent->clear( oldUrl );
02490 emit m_parent->redirection( oldUrl, newUrl );
02491 }
02492 }
02493
02494 void KDirListerCacheDirectoryData::moveListersWithoutCachedItemsJob()
02495 {
02496
02497
02498
02499
02500
02501 QMutableListIterator<KDirLister *> lister_it(listersCurrentlyListing);
02502 while (lister_it.hasNext()) {
02503 KDirLister* kdl = lister_it.next();
02504 if (!kdl->d->m_cachedItemsJob) {
02505
02506
02507
02508 Q_ASSERT(!listersCurrentlyHolding.contains(kdl));
02509 if (!listersCurrentlyHolding.contains(kdl)) {
02510 listersCurrentlyHolding.append(kdl);
02511 }
02512 lister_it.remove();
02513 }
02514 }
02515 }
02516
02517 KFileItem KDirLister::cachedItemForUrl(const KUrl& url)
02518 {
02519 return kDirListerCache->itemForUrl(url);
02520 }
02521
02522 #include "kdirlister.moc"
02523 #include "kdirlister_p.moc"