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