X-Git-Url: https://cloud.milkyroute.net/gitweb/dolphin.git/blobdiff_plain/51b978f7fd7ed02b509f34f2579bf016f78bc5e0..4b70446c17dff6646c11966670bcbe145d07c685:/src/kitemviews/kfileitemmodelrolesupdater.cpp diff --git a/src/kitemviews/kfileitemmodelrolesupdater.cpp b/src/kitemviews/kfileitemmodelrolesupdater.cpp index eaaab6bc0..0865d40e7 100644 --- a/src/kitemviews/kfileitemmodelrolesupdater.cpp +++ b/src/kitemviews/kfileitemmodelrolesupdater.cpp @@ -24,13 +24,13 @@ #include #include #include -#include #include #include #include #include #include "private/kpixmapmodifier.h" +#include "private/kdirectorycontentscounter.h" #include #include @@ -40,18 +40,11 @@ #include -#ifdef HAVE_NEPOMUK - #include "private/knepomukrolesprovider.h" - #include - #include -#endif - -// Required includes for subItemsCount(): -#ifdef Q_WS_WIN - #include -#else - #include - #include +#ifdef HAVE_BALOO + #include "private/kbaloorolesprovider.h" + #include + #include + #include #endif // #define KFILEITEMMODELROLESUPDATER_DEBUG @@ -89,19 +82,15 @@ KFileItemModelRolesUpdater::KFileItemModelRolesUpdater(KFileItemModel* model, QO m_resolvableRoles(), m_enabledPlugins(), m_pendingSortRoleItems(), - m_hasUnknownIcons(false), - m_firstIndexWithoutIcon(0), m_pendingIndexes(), m_pendingPreviewItems(), m_previewJob(), m_recentlyChangedItemsTimer(0), m_recentlyChangedItems(), m_changedItems(), - m_dirWatcher(0), - m_watchedDirs() - #ifdef HAVE_NEPOMUK - , m_nepomukResourceWatcher(0), - m_nepomukUriItems() + m_directoryContentsCounter(0) + #ifdef HAVE_BALOO + , m_balooFileMonitor(0) #endif { Q_ASSERT(model); @@ -133,14 +122,13 @@ KFileItemModelRolesUpdater::KFileItemModelRolesUpdater(KFileItemModel* model, QO m_resolvableRoles.insert("size"); m_resolvableRoles.insert("type"); m_resolvableRoles.insert("isExpandable"); -#ifdef HAVE_NEPOMUK - m_resolvableRoles += KNepomukRolesProvider::instance().roles(); +#ifdef HAVE_BALOO + m_resolvableRoles += KBalooRolesProvider::instance().roles(); #endif - // When folders are expandable or the item-count is shown for folders, it is necessary - // to watch the number of items of the sub-folder to be able to react on changes. - m_dirWatcher = new KDirWatch(this); - connect(m_dirWatcher, SIGNAL(dirty(QString)), this, SLOT(slotDirWatchDirty(QString))); + m_directoryContentsCounter = new KDirectoryContentsCounter(m_model, this); + connect(m_directoryContentsCounter, SIGNAL(result(QString,int)), + this, SLOT(slotDirectoryContentsCountReceived(QString,int))); } KFileItemModelRolesUpdater::~KFileItemModelRolesUpdater() @@ -274,34 +262,29 @@ void KFileItemModelRolesUpdater::setRoles(const QSet& roles) if (m_roles != roles) { m_roles = roles; -#ifdef HAVE_NEPOMUK - if (Nepomuk2::ResourceManager::instance()->initialized()) { - // Check whether there is at least one role that must be resolved - // with the help of Nepomuk. If this is the case, a (quite expensive) - // resolving will be done in KFileItemModelRolesUpdater::rolesData() and - // the role gets watched for changes. - const KNepomukRolesProvider& rolesProvider = KNepomukRolesProvider::instance(); - bool hasNepomukRole = false; - QSetIterator it(roles); - while (it.hasNext()) { - const QByteArray& role = it.next(); - if (rolesProvider.roles().contains(role)) { - hasNepomukRole = true; - break; - } +#ifdef HAVE_BALOO + // Check whether there is at least one role that must be resolved + // with the help of Baloo. If this is the case, a (quite expensive) + // resolving will be done in KFileItemModelRolesUpdater::rolesData() and + // the role gets watched for changes. + const KBalooRolesProvider& rolesProvider = KBalooRolesProvider::instance(); + bool hasBalooRole = false; + QSetIterator it(roles); + while (it.hasNext()) { + const QByteArray& role = it.next(); + if (rolesProvider.roles().contains(role)) { + hasBalooRole = true; + break; } + } - if (hasNepomukRole && !m_nepomukResourceWatcher) { - Q_ASSERT(m_nepomukUriItems.isEmpty()); - - m_nepomukResourceWatcher = new Nepomuk2::ResourceWatcher(this); - connect(m_nepomukResourceWatcher, SIGNAL(propertyChanged(Nepomuk2::Resource,Nepomuk2::Types::Property,QVariantList,QVariantList)), - this, SLOT(applyChangedNepomukRoles(Nepomuk2::Resource))); - } else if (!hasNepomukRole && m_nepomukResourceWatcher) { - delete m_nepomukResourceWatcher; - m_nepomukResourceWatcher = 0; - m_nepomukUriItems.clear(); - } + if (hasBalooRole && !m_balooFileMonitor) { + m_balooFileMonitor = new Baloo::FileMonitor(this); + connect(m_balooFileMonitor, SIGNAL(fileMetaDataChanged(QString)), + this, SLOT(applyChangedBalooRoles(QString))); + } else if (!hasBalooRole && m_balooFileMonitor) { + delete m_balooFileMonitor; + m_balooFileMonitor = 0; } #endif @@ -333,10 +316,6 @@ void KFileItemModelRolesUpdater::slotItemsInserted(const KItemRangeList& itemRan QElapsedTimer timer; timer.start(); - const int firstInsertedIndex = itemRanges.first().index; - m_firstIndexWithoutIcon = qMin(m_firstIndexWithoutIcon, firstInsertedIndex); - m_hasUnknownIcons = true; - // Determine the sort role synchronously for as many items as possible. if (m_resolvableRoles.contains(m_model->sortRole())) { int insertedCount = 0; @@ -373,54 +352,19 @@ void KFileItemModelRolesUpdater::slotItemsRemoved(const KItemRangeList& itemRang const bool allItemsRemoved = (m_model->count() == 0); - if (m_hasUnknownIcons) { - const int firstRemovedIndex = itemRanges.first().index; - m_firstIndexWithoutIcon = qMin(m_firstIndexWithoutIcon, firstRemovedIndex); - } - - if (!m_watchedDirs.isEmpty()) { - // Don't let KDirWatch watch for removed items +#ifdef HAVE_BALOO + if (m_balooFileMonitor) { + // Don't let the FileWatcher watch for removed items if (allItemsRemoved) { - foreach (const QString& path, m_watchedDirs) { - m_dirWatcher->removeDir(path); - } - m_watchedDirs.clear(); + m_balooFileMonitor->clear(); } else { - QMutableSetIterator it(m_watchedDirs); - while (it.hasNext()) { - const QString& path = it.next(); - if (m_model->index(KUrl(path)) < 0) { - m_dirWatcher->removeDir(path); - it.remove(); - } - } - } - } - -#ifdef HAVE_NEPOMUK - if (m_nepomukResourceWatcher) { - // Don't let the ResourceWatcher watch for removed items - if (allItemsRemoved) { - m_nepomukResourceWatcher->setResources(QList()); - m_nepomukResourceWatcher->stop(); - m_nepomukUriItems.clear(); - } else { - QList newResources; - const QList oldResources = m_nepomukResourceWatcher->resources(); - foreach (const Nepomuk2::Resource& resource, oldResources) { - const QUrl uri = resource.uri(); - const KUrl itemUrl = m_nepomukUriItems.value(uri); + QStringList newFileList; + foreach (const QString& itemUrl, m_balooFileMonitor->files()) { if (m_model->index(itemUrl) >= 0) { - newResources.append(resource); - } else { - m_nepomukUriItems.remove(uri); + newFileList.append(itemUrl); } } - m_nepomukResourceWatcher->setResources(newResources); - if (newResources.isEmpty()) { - Q_ASSERT(m_nepomukUriItems.isEmpty()); - m_nepomukResourceWatcher->stop(); - } + m_balooFileMonitor->setFiles(newFileList); } } #endif @@ -459,11 +403,6 @@ void KFileItemModelRolesUpdater::slotItemsMoved(const KItemRange& itemRange, QLi Q_UNUSED(itemRange); Q_UNUSED(movedToIndexes); - if (m_hasUnknownIcons) { - const int firstMovedIndex = itemRange.index; - m_firstIndexWithoutIcon = qMin(m_firstIndexWithoutIcon, firstMovedIndex); - } - // The visible items might have changed. startUpdating(); } @@ -586,6 +525,22 @@ void KFileItemModelRolesUpdater::slotGotPreview(const KFileItem& item, const QPi } QHash data = rolesData(item); + + const QStringList overlays = data["iconOverlays"].toStringList(); + // Strangely KFileItem::overlays() returns empty string-values, so + // we need to check first whether an overlay must be drawn at all. + // It is more efficient to do it here, as KIconLoader::drawOverlays() + // assumes that an overlay will be drawn and has some additional + // setup time. + foreach (const QString& overlay, overlays) { + if (!overlay.isEmpty()) { + // There is at least one overlay, draw all overlays above m_pixmap + // and cancel the check + KIconLoader::global()->drawOverlays(overlays, scaledPixmap, KIconLoader::Desktop); + break; + } + } + data.insert("iconPixmap", scaledPixmap); disconnect(m_model, SIGNAL(itemsChanged(KItemRangeList,QSet)), @@ -616,7 +571,7 @@ void KFileItemModelRolesUpdater::slotPreviewFailed(const KFileItem& item) connect(m_model, SIGNAL(itemsChanged(KItemRangeList,QSet)), this, SLOT(slotItemsChanged(KItemRangeList,QSet))); - applyResolvedRoles(item, ResolveAll); + applyResolvedRoles(index, ResolveAll); m_finishedItems.insert(item); } } @@ -693,7 +648,7 @@ void KFileItemModelRolesUpdater::resolveNextPendingRoles() continue; } - applyResolvedRoles(item, ResolveAll); + applyResolvedRoles(index, ResolveAll); m_finishedItems.insert(item); m_changedItems.remove(item); break; @@ -737,14 +692,9 @@ void KFileItemModelRolesUpdater::resolveRecentlyChangedItems() updateChangedItems(); } -void KFileItemModelRolesUpdater::applyChangedNepomukRoles(const Nepomuk2::Resource& resource) +void KFileItemModelRolesUpdater::applyChangedBalooRoles(const QString& itemUrl) { -#ifdef HAVE_NEPOMUK - if (!Nepomuk2::ResourceManager::instance()->initialized()) { - return; - } - - const KUrl itemUrl = m_nepomukUriItems.value(resource.uri()); +#ifdef HAVE_BALOO const KFileItem item = m_model->fileItem(itemUrl); if (item.isNull()) { @@ -753,10 +703,34 @@ void KFileItemModelRolesUpdater::applyChangedNepomukRoles(const Nepomuk2::Resour return; } - QHash data = rolesData(item); + Baloo::FileFetchJob* job = new Baloo::FileFetchJob(item.localPath()); + connect(job, SIGNAL(finished(KJob*)), this, SLOT(applyChangedBalooRolesJobFinished(KJob*))); + job->setProperty("item", QVariant::fromValue(item)); + job->start(); +#else +#ifndef Q_CC_MSVC + Q_UNUSED(itemUrl); +#endif +#endif +} + +void KFileItemModelRolesUpdater::applyChangedBalooRolesJobFinished(KJob* kjob) +{ +#ifdef HAVE_BALOO + const KFileItem item = kjob->property("item").value(); + + const KBalooRolesProvider& rolesProvider = KBalooRolesProvider::instance(); + QHash data; + + foreach (const QByteArray& role, rolesProvider.roles()) { + // Overwrite all the role values with an empty QVariant, because the roles + // provider doesn't overwrite it when the property value list is empty. + // See bug 322348 + data.insert(role, QVariant()); + } - const KNepomukRolesProvider& rolesProvider = KNepomukRolesProvider::instance(); - QHashIterator it(rolesProvider.roleValues(resource, m_roles)); + Baloo::FileFetchJob* job = static_cast(kjob); + QHashIterator it(rolesProvider.roleValues(job->file(), m_roles)); while (it.hasNext()) { it.next(); data.insert(it.key(), it.value()); @@ -768,14 +742,10 @@ void KFileItemModelRolesUpdater::applyChangedNepomukRoles(const Nepomuk2::Resour m_model->setData(index, data); connect(m_model, SIGNAL(itemsChanged(KItemRangeList,QSet)), this, SLOT(slotItemsChanged(KItemRangeList,QSet))); -#else -#ifndef Q_CC_MSVC - Q_UNUSED(resource); -#endif #endif } -void KFileItemModelRolesUpdater::slotDirWatchDirty(const QString& path) +void KFileItemModelRolesUpdater::slotDirectoryContentsCountReceived(const QString& path, int count) { const bool getSizeRole = m_roles.contains("size"); const bool getIsExpandableRole = m_roles.contains("isExpandable"); @@ -783,16 +753,8 @@ void KFileItemModelRolesUpdater::slotDirWatchDirty(const QString& path) if (getSizeRole || getIsExpandableRole) { const int index = m_model->index(KUrl(path)); if (index >= 0) { - if (!m_model->fileItem(index).isDir()) { - // If INotify is used, KDirWatch issues the dirty() signal - // also for changed files inside the directory, even if we - // don't enable this behavior explicitly (see bug 309740). - return; - } - QHash data; - const int count = subItemsCount(path); if (getSizeRole) { data.insert("size", count); } @@ -800,9 +762,11 @@ void KFileItemModelRolesUpdater::slotDirWatchDirty(const QString& path) data.insert("isExpandable", count > 0); } - // Note that we do not block the itemsChanged signal here. - // This ensures that a new preview will be generated. + disconnect(m_model, SIGNAL(itemsChanged(KItemRangeList,QSet)), + this, SLOT(slotItemsChanged(KItemRangeList,QSet))); m_model->setData(index, data); + connect(m_model, SIGNAL(itemsChanged(KItemRangeList,QSet)), + this, SLOT(slotItemsChanged(KItemRangeList,QSet))); } } } @@ -829,13 +793,6 @@ void KFileItemModelRolesUpdater::startUpdating() // Determine the icons for the visible items synchronously. updateVisibleIcons(); - // Try to do at least a fast icon loading (without determining the - // mime type) for all items, to reduce the risk that the user sees - // "unknown" icons when scrolling. - if (m_hasUnknownIcons) { - updateAllIconsFast(MaxBlockTimeout - timer.elapsed()); - } - // A detailed update of the items in and near the visible area // only makes sense if sorting is finished. if (m_state == ResolvingSortRole) { @@ -883,62 +840,12 @@ void KFileItemModelRolesUpdater::updateVisibleIcons() // Try to determine the final icons for all visible items. int index; for (index = m_firstVisibleIndex; index <= lastVisibleIndex && timer.elapsed() < MaxBlockTimeout; ++index) { - const KFileItem item = m_model->fileItem(index); - applyResolvedRoles(item, ResolveFast); - } - - if (index > lastVisibleIndex) { - return; - } - - // If this didn't work before MaxBlockTimeout was reached, at least - // prevent that the user sees 'unknown' icons. - disconnect(m_model, SIGNAL(itemsChanged(KItemRangeList,QSet)), - this, SLOT(slotItemsChanged(KItemRangeList,QSet))); - - while (index <= lastVisibleIndex) { - if (!m_model->data(index).contains("iconName")) { - const KFileItem item = m_model->fileItem(index); - QHash data; - data.insert("iconName", item.iconName()); - m_model->setData(index, data); - } - ++index; + applyResolvedRoles(index, ResolveFast); } - connect(m_model, SIGNAL(itemsChanged(KItemRangeList,QSet)), - this, SLOT(slotItemsChanged(KItemRangeList,QSet))); -} - -void KFileItemModelRolesUpdater::updateAllIconsFast(int timeout) -{ - if (timeout <= 0) { - return; - } - - QElapsedTimer timer; - timer.start(); - - disconnect(m_model, SIGNAL(itemsChanged(KItemRangeList,QSet)), - this, SLOT(slotItemsChanged(KItemRangeList,QSet))); - - const int count = m_model->count(); - while (m_firstIndexWithoutIcon < count && timer.elapsed() < timeout) { - if (!m_model->data(m_firstIndexWithoutIcon).contains("iconName")) { - const KFileItem item = m_model->fileItem(m_firstIndexWithoutIcon); - QHash data; - data.insert("iconName", item.iconName()); - m_model->setData(m_firstIndexWithoutIcon, data); - } - ++m_firstIndexWithoutIcon; - } - - if (m_firstIndexWithoutIcon == count) { - m_hasUnknownIcons = false; - } - - connect(m_model, SIGNAL(itemsChanged(KItemRangeList,QSet)), - this, SLOT(slotItemsChanged(KItemRangeList,QSet))); + // KFileItemListView::initializeItemListWidget(KItemListWidget*) will load + // preliminary icons (i.e., without mime type determination) for the + // remaining items. } void KFileItemModelRolesUpdater::startPreviewJob() @@ -1085,9 +992,9 @@ void KFileItemModelRolesUpdater::applySortRole(int index) data.insert("type", item.mimeComment()); } else if (m_model->sortRole() == "size" && item.isLocalFile() && item.isDir()) { const QString path = item.localPath(); - data.insert("size", subItemsCount(path)); + data.insert("size", m_directoryContentsCounter->countDirectoryContentsSynchronously(path)); } else { - // Probably the sort role is a Nepomuk role - just determine all roles. + // Probably the sort role is a baloo role - just determine all roles. data = rolesData(item); } @@ -1106,27 +1013,20 @@ void KFileItemModelRolesUpdater::applySortProgressToModel() m_model->emitSortProgress(resolvedCount); } -bool KFileItemModelRolesUpdater::applyResolvedRoles(const KFileItem& item, ResolveHint hint) +bool KFileItemModelRolesUpdater::applyResolvedRoles(int index, ResolveHint hint) { - if (item.isNull()) { - return false; - } - + const KFileItem item = m_model->fileItem(index); const bool resolveAll = (hint == ResolveAll); bool iconChanged = false; if (!item.isMimeTypeKnown() || !item.isFinalIconKnown()) { item.determineMimeType(); iconChanged = true; - } else { - const int index = m_model->index(item); - if (!m_model->data(index).contains("iconName")) { - iconChanged = true; - } + } else if (!m_model->data(index).contains("iconName")) { + iconChanged = true; } if (iconChanged || resolveAll || m_clearPreviews) { - const int index = m_model->index(item); if (index < 0) { return false; } @@ -1153,7 +1053,7 @@ bool KFileItemModelRolesUpdater::applyResolvedRoles(const KFileItem& item, Resol return false; } -QHash KFileItemModelRolesUpdater::rolesData(const KFileItem& item) const +QHash KFileItemModelRolesUpdater::rolesData(const KFileItem& item) { QHash data; @@ -1162,19 +1062,10 @@ QHash KFileItemModelRolesUpdater::rolesData(const KFileIte if ((getSizeRole || getIsExpandableRole) && item.isDir()) { if (item.isLocalFile()) { + // Tell m_directoryContentsCounter that we want to count the items + // inside the directory. The result will be received in slotDirectoryContentsCountReceived. const QString path = item.localPath(); - const int count = subItemsCount(path); - if (getSizeRole) { - data.insert("size", count); - } - if (getIsExpandableRole) { - data.insert("isExpandable", count > 0); - } - - if (!m_dirWatcher->contains(path)) { - m_dirWatcher->addDir(path); - m_watchedDirs.insert(path); - } + m_directoryContentsCounter->addDirectory(path); } else if (getSizeRole) { data.insert("size", -1); // -1 indicates an unknown number of items } @@ -1186,93 +1077,15 @@ QHash KFileItemModelRolesUpdater::rolesData(const KFileIte data.insert("iconOverlays", item.overlays()); -#ifdef HAVE_NEPOMUK - if (m_nepomukResourceWatcher) { - const KNepomukRolesProvider& rolesProvider = KNepomukRolesProvider::instance(); - Nepomuk2::Resource resource(item.nepomukUri()); - QHashIterator it(rolesProvider.roleValues(resource, m_roles)); - while (it.hasNext()) { - it.next(); - data.insert(it.key(), it.value()); - } - - QUrl uri = resource.uri(); - if (uri.isEmpty()) { - // TODO: Is there another way to explicitly create a resource? - // We need a resource to be able to track it for changes. - resource.setRating(0); - uri = resource.uri(); - } - if (!uri.isEmpty() && !m_nepomukUriItems.contains(uri)) { - m_nepomukResourceWatcher->addResource(resource); - - if (m_nepomukUriItems.isEmpty()) { - m_nepomukResourceWatcher->start(); - } - - m_nepomukUriItems.insert(uri, item.url()); - } +#ifdef HAVE_BALOO + if (m_balooFileMonitor) { + m_balooFileMonitor->addFile(item.localPath()); + applyChangedBalooRoles(item.localPath()); } #endif - return data; } -int KFileItemModelRolesUpdater::subItemsCount(const QString& path) const -{ - const bool countHiddenFiles = m_model->showHiddenFiles(); - const bool showFoldersOnly = m_model->showDirectoriesOnly(); - -#ifdef Q_WS_WIN - QDir dir(path); - QDir::Filters filters = QDir::NoDotAndDotDot | QDir::System; - if (countHiddenFiles) { - filters |= QDir::Hidden; - } - if (showFoldersOnly) { - filters |= QDir::Dirs; - } else { - filters |= QDir::AllEntries; - } - return dir.entryList(filters).count(); -#else - // Taken from kdelibs/kio/kio/kdirmodel.cpp - // Copyright (C) 2006 David Faure - - int count = -1; - DIR* dir = ::opendir(QFile::encodeName(path)); - if (dir) { // krazy:exclude=syscalls - count = 0; - struct dirent *dirEntry = 0; - while ((dirEntry = ::readdir(dir))) { - if (dirEntry->d_name[0] == '.') { - if (dirEntry->d_name[1] == '\0' || !countHiddenFiles) { - // Skip "." or hidden files - continue; - } - if (dirEntry->d_name[1] == '.' && dirEntry->d_name[2] == '\0') { - // Skip ".." - continue; - } - } - - // If only directories are counted, consider an unknown file type and links also - // as directory instead of trying to do an expensive stat() - // (see bugs 292642 and 299997). - const bool countEntry = !showFoldersOnly || - dirEntry->d_type == DT_DIR || - dirEntry->d_type == DT_LNK || - dirEntry->d_type == DT_UNKNOWN; - if (countEntry) { - ++count; - } - } - ::closedir(dir); - } - return count; -#endif -} - void KFileItemModelRolesUpdater::updateAllPreviews() { if (m_state == Paused) {