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