X-Git-Url: https://cloud.milkyroute.net/gitweb/dolphin.git/blobdiff_plain/bb6dda65002351dfb477e799b2c23cb98a80c6a0..05082aed16cdf7e511d9c97d0cf07e270af493e5:/src/kitemviews/kfileitemmodelrolesupdater.cpp diff --git a/src/kitemviews/kfileitemmodelrolesupdater.cpp b/src/kitemviews/kfileitemmodelrolesupdater.cpp index 65c11e0f5..34165843f 100644 --- a/src/kitemviews/kfileitemmodelrolesupdater.cpp +++ b/src/kitemviews/kfileitemmodelrolesupdater.cpp @@ -33,7 +33,12 @@ #include #include -// Required includes for subDirectoriesCount(): +#ifdef HAVE_NEPOMUK + #include "knepomukrolesprovider_p.h" + #include "knepomukresourcewatcher_p.h" +#endif + +// Required includes for subItemsCount(): #ifdef Q_WS_WIN #include #else @@ -41,7 +46,7 @@ #include #endif -#define KFILEITEMMODELROLESUPDATER_DEBUG +// #define KFILEITEMMODELROLESUPDATER_DEBUG namespace { // Maximum time in ms that the KFileItemModelRolesUpdater @@ -62,6 +67,7 @@ KFileItemModelRolesUpdater::KFileItemModelRolesUpdater(KFileItemModel* model, QO m_iconSizeChangedDuringPausing(false), m_rolesChangedDuringPausing(false), m_previewShown(false), + m_enlargeSmallPreviews(true), m_clearPreviews(false), m_model(model), m_iconSize(), @@ -72,7 +78,13 @@ KFileItemModelRolesUpdater::KFileItemModelRolesUpdater(KFileItemModel* model, QO m_pendingVisibleItems(), m_pendingInvisibleItems(), m_previewJobs(), - m_resolvePendingRolesTimer(0) + m_changedItemsTimer(0), + m_changedItems() + #ifdef HAVE_NEPOMUK + , m_nepomukResourceWatcher(0), + m_nepomukUriItems() + #endif + { Q_ASSERT(model); @@ -89,12 +101,12 @@ KFileItemModelRolesUpdater::KFileItemModelRolesUpdater(KFileItemModel* model, QO connect(m_model, SIGNAL(itemsChanged(KItemRangeList,QSet)), this, SLOT(slotItemsChanged(KItemRangeList,QSet))); - // A timer with a minimal timeout is used to merge several triggerPendingRolesResolving() calls - // to only one call of resolvePendingRoles(). - m_resolvePendingRolesTimer = new QTimer(this); - m_resolvePendingRolesTimer->setInterval(1); - m_resolvePendingRolesTimer->setSingleShot(true); - connect(m_resolvePendingRolesTimer, SIGNAL(timeout()), this, SLOT(resolvePendingRoles())); + // Use a timer to prevent that each call of slotItemsChanged() results in a synchronous + // resolving of the roles. Postpone the resolving until no update has been done for 1 second. + m_changedItemsTimer = new QTimer(this); + m_changedItemsTimer->setInterval(1000); + m_changedItemsTimer->setSingleShot(true); + connect(m_changedItemsTimer, SIGNAL(timeout()), this, SLOT(resolveChangedItems())); } KFileItemModelRolesUpdater::~KFileItemModelRolesUpdater() @@ -144,7 +156,7 @@ void KFileItemModelRolesUpdater::setVisibleIndexRange(int index, int count) } } -void KFileItemModelRolesUpdater::setPreviewShown(bool show) +void KFileItemModelRolesUpdater::setPreviewsShown(bool show) { if (show == m_previewShown) { return; @@ -155,21 +167,37 @@ void KFileItemModelRolesUpdater::setPreviewShown(bool show) m_clearPreviews = true; } - if (m_paused) { - m_previewChangedDuringPausing = true; - } else { - sortAndResolveAllRoles(); - } + updateAllPreviews(); } -bool KFileItemModelRolesUpdater::isPreviewShown() const +bool KFileItemModelRolesUpdater::previewsShown() const { return m_previewShown; } +void KFileItemModelRolesUpdater::setEnlargeSmallPreviews(bool enlarge) +{ + if (enlarge != m_enlargeSmallPreviews) { + m_enlargeSmallPreviews = enlarge; + if (m_previewShown) { + updateAllPreviews(); + } + } +} + +bool KFileItemModelRolesUpdater::enlargeSmallPreviews() const +{ + return m_enlargeSmallPreviews; +} + void KFileItemModelRolesUpdater::setEnabledPlugins(const QStringList& list) { - m_enabledPlugins = list; + if (m_enabledPlugins == list) { + m_enabledPlugins = list; + if (m_previewShown) { + updateAllPreviews(); + } + } } void KFileItemModelRolesUpdater::setPaused(bool paused) @@ -204,25 +232,49 @@ void KFileItemModelRolesUpdater::setPaused(bool paused) void KFileItemModelRolesUpdater::setRoles(const QSet& roles) { - if (roles.count() == m_roles.count()) { - bool isEqual = true; - foreach (const QByteArray& role, roles) { - if (!m_roles.contains(role)) { - isEqual = false; + if (m_roles != roles) { + m_roles = roles; + +#ifdef HAVE_NEPOMUK + // 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.isNepomukRole(role)) { + hasNepomukRole = true; break; } } - if (isEqual) { - return; - } - } - m_roles = roles; + if (hasNepomukRole && !m_nepomukResourceWatcher) { + Q_ASSERT(m_nepomukUriItems.isEmpty()); + + m_nepomukResourceWatcher = new Nepomuk::ResourceWatcher(this); + connect(m_nepomukResourceWatcher, SIGNAL(propertyChanged(Nepomuk::Resource,Nepomuk::Types::Property,QVariantList,QVariantList)), + this, SLOT(applyChangedNepomukRoles(Nepomuk::Resource))); + connect(m_nepomukResourceWatcher, SIGNAL(propertyRemoved(Nepomuk::Resource,Nepomuk::Types::Property,QVariant)), + this, SLOT(applyChangedNepomukRoles(Nepomuk::Resource))); + connect(m_nepomukResourceWatcher, SIGNAL(propertyAdded(Nepomuk::Resource,Nepomuk::Types::Property,QVariant)), + this, SLOT(applyChangedNepomukRoles(Nepomuk::Resource))); + connect(m_nepomukResourceWatcher, SIGNAL(resourceCreated(Nepomuk::Resource,QList)), + this, SLOT(applyChangedNepomukRoles(Nepomuk::Resource))); + } else if (!hasNepomukRole && m_nepomukResourceWatcher) { + delete m_nepomukResourceWatcher; + m_nepomukResourceWatcher = 0; + m_nepomukUriItems.clear(); + } +#endif - if (m_paused) { - m_rolesChangedDuringPausing = true; - } else { - sortAndResolveAllRoles(); + if (m_paused) { + m_rolesChangedDuringPausing = true; + } else { + sortAndResolveAllRoles(); + } } } @@ -243,49 +295,38 @@ QStringList KFileItemModelRolesUpdater::enabledPlugins() const void KFileItemModelRolesUpdater::slotItemsInserted(const KItemRangeList& itemRanges) { - // If no valid index range is given assume that all items are visible. - // A cleanup will be done later as soon as the index range has been set. - const bool hasValidIndexRange = (m_lastVisibleIndex >= 0); - - if (hasValidIndexRange) { - // Move all current pending visible items that are not visible anymore - // to the pending invisible items. - QSetIterator it(m_pendingVisibleItems); - while (it.hasNext()) { - const KFileItem item = it.next(); - const int index = m_model->index(item); - if (index < m_firstVisibleIndex || index > m_lastVisibleIndex) { - m_pendingVisibleItems.remove(item); - m_pendingInvisibleItems.insert(item); - } - } - } - - int rangesCount = 0; + startUpdating(itemRanges); +} - foreach (const KItemRange& range, itemRanges) { - rangesCount += range.count; +void KFileItemModelRolesUpdater::slotItemsRemoved(const KItemRangeList& itemRanges) +{ + Q_UNUSED(itemRanges); - // Add the inserted items to the pending visible and invisible items - const int lastIndex = range.index + range.count - 1; - for (int i = range.index; i <= lastIndex; ++i) { - const KFileItem item = m_model->fileItem(i); - if (!hasValidIndexRange || (i >= m_firstVisibleIndex && i <= m_lastVisibleIndex)) { - m_pendingVisibleItems.insert(item); - } else { - m_pendingInvisibleItems.insert(item); +#ifdef HAVE_NEPOMUK + if (m_nepomukResourceWatcher) { + // Don't let the ResourceWatcher watch for removed items + if (m_model->count() == 0) { + m_nepomukResourceWatcher->setResources(QList()); + m_nepomukUriItems.clear(); + } else { + QList newResources; + const QList oldResources = m_nepomukResourceWatcher->resources(); + foreach (const Nepomuk::Resource& resource, oldResources) { + const QUrl uri = resource.resourceUri(); + const KUrl itemUrl = m_nepomukUriItems.value(uri); + if (m_model->index(itemUrl) >= 0) { + newResources.append(resource); + } else { + m_nepomukUriItems.remove(uri); + } } + m_nepomukResourceWatcher->setResources(newResources); } } +#endif - triggerPendingRolesResolving(rangesCount); -} - -void KFileItemModelRolesUpdater::slotItemsRemoved(const KItemRangeList& itemRanges) -{ - Q_UNUSED(itemRanges); m_firstVisibleIndex = 0; - m_lastVisibleIndex = -1; + m_lastVisibleIndex = -1; if (!hasPendingRoles()) { return; } @@ -294,9 +335,14 @@ void KFileItemModelRolesUpdater::slotItemsRemoved(const KItemRangeList& itemRang // Most probably a directory change is done. Clear all pending items // and also kill all ongoing preview-jobs. resetPendingRoles(); + + m_changedItems.clear(); + m_changedItemsTimer->stop(); } else { // Remove all items from m_pendingVisibleItems and m_pendingInvisibleItems - // that are not part of the model anymore. + // that are not part of the model anymore. The items from m_changedItems + // don't need to be handled here, removed items are just skipped in + // resolveChangedItems(). for (int i = 0; i <= 1; ++i) { QSet& pendingItems = (i == 0) ? m_pendingVisibleItems : m_pendingInvisibleItems; QMutableSetIterator it(pendingItems); @@ -313,9 +359,23 @@ void KFileItemModelRolesUpdater::slotItemsRemoved(const KItemRangeList& itemRang void KFileItemModelRolesUpdater::slotItemsChanged(const KItemRangeList& itemRanges, const QSet& roles) { - Q_UNUSED(itemRanges); Q_UNUSED(roles); - // TODO + + if (m_changedItemsTimer->isActive()) { + // A call of slotItemsChanged() has been done recently. Postpone the resolving + // of the roles until the timer has exceeded. + foreach (const KItemRange& itemRange, itemRanges) { + int index = itemRange.index; + for (int count = itemRange.count; count > 0; --count) { + m_changedItems.insert(m_model->fileItem(index)); + ++index; + } + } + } else { + // No call of slotItemsChanged() has been done recently, resolve the roles now. + startUpdating(itemRanges); + } + m_changedItemsTimer->start(); } void KFileItemModelRolesUpdater::slotGotPreview(const KFileItem& item, const QPixmap& pixmap) @@ -334,7 +394,34 @@ void KFileItemModelRolesUpdater::slotGotPreview(const KFileItem& item, const QPi const int slashIndex = mimeType.indexOf(QLatin1Char('/')); const QString mimeTypeGroup = mimeType.left(slashIndex); if (mimeTypeGroup == QLatin1String("image")) { - KPixmapModifier::applyFrame(scaledPixmap, m_iconSize); + if (m_enlargeSmallPreviews) { + KPixmapModifier::applyFrame(scaledPixmap, m_iconSize); + } else { + // Assure that small previews don't get enlarged. Instead they + // should be shown centered within the frame. + const QSize contentSize = KPixmapModifier::sizeInsideFrame(m_iconSize); + const bool enlargingRequired = scaledPixmap.width() < contentSize.width() && + scaledPixmap.height() < contentSize.height(); + if (enlargingRequired) { + QSize frameSize = scaledPixmap.size(); + frameSize.scale(m_iconSize, Qt::KeepAspectRatio); + + QPixmap largeFrame(frameSize); + largeFrame.fill(Qt::transparent); + + KPixmapModifier::applyFrame(largeFrame, frameSize); + + QPainter painter(&largeFrame); + painter.drawPixmap((largeFrame.width() - scaledPixmap.width()) / 2, + (largeFrame.height() - scaledPixmap.height()) / 2, + scaledPixmap); + scaledPixmap = largeFrame; + } else { + // The image must be shrinked as it is too large to fit into + // the available icon size + KPixmapModifier::applyFrame(scaledPixmap, m_iconSize); + } + } } else { KPixmapModifier::scale(scaledPixmap, m_iconSize); } @@ -375,83 +462,6 @@ void KFileItemModelRolesUpdater::slotPreviewJobFinished(KJob* job) startPreviewJob(visibleItems + m_pendingInvisibleItems.toList()); } -void KFileItemModelRolesUpdater::resolvePendingRoles() -{ - int resolvedCount = 0; - - const bool hasSlowRoles = m_previewShown - || m_roles.contains("size") - || m_roles.contains("type"); - const ResolveHint resolveHint = hasSlowRoles ? ResolveFast : ResolveAll; - - // Resolving the MIME type can be expensive. Assure that not more than MaxBlockTimeout ms are - // spend for resolving them synchronously. Usually this is more than enough to determine - // all visible items, but there are corner cases where this limit gets easily exceeded. - QElapsedTimer timer; - timer.start(); - - // Resolve the MIME type of all visible items - QSetIterator visibleIt(m_pendingVisibleItems); - while (visibleIt.hasNext()) { - const KFileItem item = visibleIt.next(); - applyResolvedRoles(item, resolveHint); - if (!hasSlowRoles) { - Q_ASSERT(!m_pendingInvisibleItems.contains(item)); - // All roles have been resolved already by applyResolvedRoles() - m_pendingVisibleItems.remove(item); - } - ++resolvedCount; - - if (timer.elapsed() > MaxBlockTimeout) { - break; - } - } - - // Resolve the MIME type of the invisible items at least until the timeout - // has been exceeded or the maximum number of items has been reached - KFileItemList invisibleItems; - if (m_lastVisibleIndex >= 0) { - // The visible range is valid, don't care about the order how the MIME - // type of invisible items get resolved - invisibleItems = m_pendingInvisibleItems.toList(); - } else { - // The visible range is temporary invalid (e.g. happens when loading - // a directory) so take care to sort the currently invisible items where - // a part will get visible later - invisibleItems = sortedItems(m_pendingInvisibleItems); - } - - int index = 0; - while (resolvedCount < MaxResolveItemsCount && index < invisibleItems.count() && timer.elapsed() <= MaxBlockTimeout) { - const KFileItem item = invisibleItems.at(index); - applyResolvedRoles(item, resolveHint); - - if (!hasSlowRoles) { - // All roles have been resolved already by applyResolvedRoles() - m_pendingInvisibleItems.remove(item); - } - ++index; - ++resolvedCount; - } - - if (m_previewShown) { - KFileItemList items = sortedItems(m_pendingVisibleItems); - items += invisibleItems; - startPreviewJob(items); - } else { - QTimer::singleShot(0, this, SLOT(resolveNextPendingRoles())); - } - -#ifdef KFILEITEMMODELROLESUPDATER_DEBUG - if (timer.elapsed() > MaxBlockTimeout) { - kDebug() << "Maximum time of" << MaxBlockTimeout - << "ms exceeded, skipping items... Remaining visible:" << m_pendingVisibleItems.count() - << "invisible:" << m_pendingInvisibleItems.count(); - } - kDebug() << "[TIME] Resolved pending roles:" << timer.elapsed(); -#endif -} - void KFileItemModelRolesUpdater::resolveNextPendingRoles() { if (m_paused) { @@ -494,6 +504,92 @@ void KFileItemModelRolesUpdater::resolveNextPendingRoles() #endif } +void KFileItemModelRolesUpdater::resolveChangedItems() +{ + if (m_changedItems.isEmpty()) { + return; + } + + KItemRangeList itemRanges; + + QSetIterator it(m_changedItems); + while (it.hasNext()) { + const KFileItem& item = it.next(); + const int index = m_model->index(item); + if (index >= 0) { + itemRanges.append(KItemRange(index, 1)); + } + } + m_changedItems.clear(); + + startUpdating(itemRanges); +} + +void KFileItemModelRolesUpdater::applyChangedNepomukRoles(const Nepomuk::Resource& resource) +{ +#ifdef HAVE_NEPOMUK + const KUrl itemUrl = m_nepomukUriItems.value(resource.resourceUri()); + const KFileItem item = m_model->fileItem(itemUrl); + QHash data = rolesData(item); + + const KNepomukRolesProvider& rolesProvider = KNepomukRolesProvider::instance(); + QHashIterator it(rolesProvider.roleValues(resource, m_roles)); + while (it.hasNext()) { + it.next(); + data.insert(it.key(), it.value()); + } + + disconnect(m_model, SIGNAL(itemsChanged(KItemRangeList,QSet)), + this, SLOT(slotItemsChanged(KItemRangeList,QSet))); + const int index = m_model->index(item); + m_model->setData(index, data); + connect(m_model, SIGNAL(itemsChanged(KItemRangeList,QSet)), + this, SLOT(slotItemsChanged(KItemRangeList,QSet))); +#else + Q_UNUSED(resource); +#endif +} + +void KFileItemModelRolesUpdater::startUpdating(const KItemRangeList& itemRanges) +{ + // If no valid index range is given assume that all items are visible. + // A cleanup will be done later as soon as the index range has been set. + const bool hasValidIndexRange = (m_lastVisibleIndex >= 0); + + if (hasValidIndexRange) { + // Move all current pending visible items that are not visible anymore + // to the pending invisible items. + QSetIterator it(m_pendingVisibleItems); + while (it.hasNext()) { + const KFileItem item = it.next(); + const int index = m_model->index(item); + if (index < m_firstVisibleIndex || index > m_lastVisibleIndex) { + m_pendingVisibleItems.remove(item); + m_pendingInvisibleItems.insert(item); + } + } + } + + int rangesCount = 0; + + foreach (const KItemRange& range, itemRanges) { + rangesCount += range.count; + + // Add the inserted items to the pending visible and invisible items + const int lastIndex = range.index + range.count - 1; + for (int i = range.index; i <= lastIndex; ++i) { + const KFileItem item = m_model->fileItem(i); + if (!hasValidIndexRange || (i >= m_firstVisibleIndex && i <= m_lastVisibleIndex)) { + m_pendingVisibleItems.insert(item); + } else { + m_pendingInvisibleItems.insert(item); + } + } + } + + resolvePendingRoles(); +} + void KFileItemModelRolesUpdater::startPreviewJob(const KFileItemList& items) { if (items.isEmpty() || m_paused) { @@ -512,7 +608,7 @@ void KFileItemModelRolesUpdater::startPreviewJob(const KFileItemList& items) // worst case) might block the application for several seconds. To prevent such // a blocking the MIME-type of the items will determined until the MaxBlockTimeout // has been reached and only those items will get passed. As soon as the MIME-type - // has been resolved once KIO::filePreview() can already access the resolved + // has been resolved once KIO::PreviewJob() can already access the resolved // MIME-type in a fast way. QElapsedTimer timer; timer.start(); @@ -529,7 +625,8 @@ void KFileItemModelRolesUpdater::startPreviewJob(const KFileItemList& items) break; } } - KJob* job = KIO::filePreview(itemSubSet, cacheSize, &m_enabledPlugins); + KIO::PreviewJob* job = new KIO::PreviewJob(itemSubSet, cacheSize, &m_enabledPlugins); + job->setIgnoreMaximumSize(items.first().isLocalFile()); connect(job, SIGNAL(gotPreview(KFileItem,QPixmap)), this, SLOT(slotGotPreview(KFileItem,QPixmap))); @@ -547,6 +644,84 @@ bool KFileItemModelRolesUpdater::hasPendingRoles() const return !m_pendingVisibleItems.isEmpty() || !m_pendingInvisibleItems.isEmpty(); } +void KFileItemModelRolesUpdater::resolvePendingRoles() +{ + int resolvedCount = 0; + + const bool hasSlowRoles = m_previewShown + || m_roles.contains("size") + || m_roles.contains("type") + || m_roles.contains("isExpandable"); + const ResolveHint resolveHint = hasSlowRoles ? ResolveFast : ResolveAll; + + // Resolving the MIME type can be expensive. Assure that not more than MaxBlockTimeout ms are + // spend for resolving them synchronously. Usually this is more than enough to determine + // all visible items, but there are corner cases where this limit gets easily exceeded. + QElapsedTimer timer; + timer.start(); + + // Resolve the MIME type of all visible items + QSetIterator visibleIt(m_pendingVisibleItems); + while (visibleIt.hasNext()) { + const KFileItem item = visibleIt.next(); + applyResolvedRoles(item, resolveHint); + if (!hasSlowRoles) { + Q_ASSERT(!m_pendingInvisibleItems.contains(item)); + // All roles have been resolved already by applyResolvedRoles() + m_pendingVisibleItems.remove(item); + } + ++resolvedCount; + + if (timer.elapsed() > MaxBlockTimeout) { + break; + } + } + + // Resolve the MIME type of the invisible items at least until the timeout + // has been exceeded or the maximum number of items has been reached + KFileItemList invisibleItems; + if (m_lastVisibleIndex >= 0) { + // The visible range is valid, don't care about the order how the MIME + // type of invisible items get resolved + invisibleItems = m_pendingInvisibleItems.toList(); + } else { + // The visible range is temporary invalid (e.g. happens when loading + // a directory) so take care to sort the currently invisible items where + // a part will get visible later + invisibleItems = sortedItems(m_pendingInvisibleItems); + } + + int index = 0; + while (resolvedCount < MaxResolveItemsCount && index < invisibleItems.count() && timer.elapsed() <= MaxBlockTimeout) { + const KFileItem item = invisibleItems.at(index); + applyResolvedRoles(item, resolveHint); + + if (!hasSlowRoles) { + // All roles have been resolved already by applyResolvedRoles() + m_pendingInvisibleItems.remove(item); + } + ++index; + ++resolvedCount; + } + + if (m_previewShown) { + KFileItemList items = sortedItems(m_pendingVisibleItems); + items += invisibleItems; + startPreviewJob(items); + } else { + QTimer::singleShot(0, this, SLOT(resolveNextPendingRoles())); + } + +#ifdef KFILEITEMMODELROLESUPDATER_DEBUG + if (timer.elapsed() > MaxBlockTimeout) { + kDebug() << "Maximum time of" << MaxBlockTimeout + << "ms exceeded, skipping items... Remaining visible:" << m_pendingVisibleItems.count() + << "invisible:" << m_pendingInvisibleItems.count(); + } + kDebug() << "[TIME] Resolved pending roles:" << timer.elapsed(); +#endif +} + void KFileItemModelRolesUpdater::resetPendingRoles() { m_pendingVisibleItems.clear(); @@ -558,21 +733,6 @@ void KFileItemModelRolesUpdater::resetPendingRoles() Q_ASSERT(m_previewJobs.isEmpty()); } -void KFileItemModelRolesUpdater::triggerPendingRolesResolving(int count) -{ - if (count == m_model->count()) { - // When initially loading a directory a synchronous resolving prevents a minor - // flickering when opening directories. This is also fine from a performance point - // of view as it is assured in resolvePendingRoles() to never block the event-loop - // for more than 200 ms. - resolvePendingRoles(); - } else { - // Items have been added. This can be done in several small steps within one loop - // because of the sorting and hence may not trigger any expensive operation. - m_resolvePendingRolesTimer->start(); - } -} - void KFileItemModelRolesUpdater::sortAndResolveAllRoles() { if (m_paused) { @@ -610,8 +770,7 @@ void KFileItemModelRolesUpdater::sortAndResolveAllRoles() } } - triggerPendingRolesResolving(m_pendingVisibleItems.count() + - m_pendingInvisibleItems.count()); + resolvePendingRoles(); } void KFileItemModelRolesUpdater::sortAndResolvePendingRoles() @@ -650,8 +809,7 @@ void KFileItemModelRolesUpdater::sortAndResolvePendingRoles() } } - triggerPendingRolesResolving(m_pendingVisibleItems.count() + - m_pendingInvisibleItems.count()); + resolvePendingRoles(); } bool KFileItemModelRolesUpdater::applyResolvedRoles(const KFileItem& item, ResolveHint hint) @@ -682,7 +840,7 @@ bool KFileItemModelRolesUpdater::applyResolvedRoles(const KFileItem& item, Resol data.insert("iconName", item.iconName()); if (m_clearPreviews) { - data.insert("iconPixmap", QString()); + data.insert("iconPixmap", QPixmap()); } disconnect(m_model, SIGNAL(itemsChanged(KItemRangeList,QSet)), @@ -700,13 +858,21 @@ QHash KFileItemModelRolesUpdater::rolesData(const KFileIte { QHash data; - if (m_roles.contains("size")) { - if (item.isDir() && item.isLocalFile()) { + const bool getSizeRole = m_roles.contains("size"); + const bool getIsExpandableRole = m_roles.contains("isExpandable"); + + if ((getSizeRole || getIsExpandableRole) && item.isDir()) { + if (item.isLocalFile()) { const QString path = item.localPath(); - const int count = subDirectoriesCount(path); - if (count >= 0) { - data.insert("size", KIO::filesize_t(count)); + const int count = subItemsCount(path); + if (getSizeRole) { + data.insert("size", count); + } + if (getIsExpandableRole) { + data.insert("isExpandable", count > 0); } + } else if (getSizeRole) { + data.insert("size", -1); // -1 indicates an unknown number of items } } @@ -716,6 +882,35 @@ QHash KFileItemModelRolesUpdater::rolesData(const KFileIte data.insert("iconOverlays", item.overlays()); +#ifdef HAVE_NEPOMUK + if (m_nepomukResourceWatcher) { + const KNepomukRolesProvider& rolesProvider = KNepomukRolesProvider::instance(); + Nepomuk::Resource resource(item.url()); + QHashIterator it(rolesProvider.roleValues(resource, m_roles)); + while (it.hasNext()) { + it.next(); + data.insert(it.key(), it.value()); + } + + QUrl uri = resource.resourceUri(); + 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.resourceUri(); + } + if (!uri.isEmpty() && !m_nepomukUriItems.contains(uri)) { + // TODO: Calling stop()/start() is a workaround until + // ResourceWatcher has been fixed. + m_nepomukResourceWatcher->stop(); + m_nepomukResourceWatcher->addResource(resource); + m_nepomukResourceWatcher->start(); + + m_nepomukUriItems.insert(uri, item.url()); + } + } +#endif + return data; } @@ -755,11 +950,23 @@ KFileItemList KFileItemModelRolesUpdater::sortedItems(const QSet& ite return itemList; } -int KFileItemModelRolesUpdater::subDirectoriesCount(const QString& path) +int KFileItemModelRolesUpdater::subItemsCount(const QString& path) const { + const bool countHiddenFiles = m_model->showHiddenFiles(); + const bool showFoldersOnly = m_model->showFoldersOnly(); + #ifdef Q_WS_WIN QDir dir(path); - return dir.entryList(QDir::AllEntries|QDir::NoDotAndDotDot|QDir::System).count(); + 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 @@ -771,8 +978,8 @@ int KFileItemModelRolesUpdater::subDirectoriesCount(const QString& path) struct dirent *dirEntry = 0; while ((dirEntry = ::readdir(dir))) { // krazy:exclude=syscalls if (dirEntry->d_name[0] == '.') { - if (dirEntry->d_name[1] == '\0') { - // Skip "." + if (dirEntry->d_name[1] == '\0' || !countHiddenFiles) { + // Skip "." or hidden files continue; } if (dirEntry->d_name[1] == '.' && dirEntry->d_name[2] == '\0') { @@ -780,7 +987,12 @@ int KFileItemModelRolesUpdater::subDirectoriesCount(const QString& path) continue; } } - ++count; + + // If only directories are counted, consider an unknown file type also + // as directory instead of trying to do an expensive stat() (see bug 292642). + if (!showFoldersOnly || dirEntry->d_type == DT_DIR || dirEntry->d_type == DT_UNKNOWN) { + ++count; + } } ::closedir(dir); } @@ -788,4 +1000,13 @@ int KFileItemModelRolesUpdater::subDirectoriesCount(const QString& path) #endif } +void KFileItemModelRolesUpdater::updateAllPreviews() +{ + if (m_paused) { + m_previewChangedDuringPausing = true; + } else { + sortAndResolveAllRoles(); + } +} + #include "kfileitemmodelrolesupdater.moc"