connect(m_view, SIGNAL(startedPathLoading(KUrl)), this, SLOT(slotStartedPathLoading()));
connect(m_view, SIGNAL(finishedPathLoading(KUrl)), this, SLOT(slotFinishedPathLoading()));
connect(m_view, SIGNAL(itemCountChanged()), this, SLOT(delayedStatusBarUpdate()));
- connect(m_view, SIGNAL(pathLoadingProgress(int)), this, SLOT(updateProgress(int)));
+ connect(m_view, SIGNAL(pathLoadingProgress(int)), this, SLOT(updateLoadingProgress(int)));
+ connect(m_view, SIGNAL(sortProgress(int)), this, SLOT(updateSortProgress(int)));
connect(m_view, SIGNAL(infoMessage(QString)), this, SLOT(showInfoMessage(QString)));
connect(m_view, SIGNAL(errorMessage(QString)), this, SLOT(showErrorMessage(QString)));
connect(m_view, SIGNAL(urlIsFileError(KUrl)), this, SLOT(openFile(KUrl)));
}
}
-void DolphinViewContainer::updateProgress(int percent)
+void DolphinViewContainer::updateLoadingProgress(int percent)
{
if (m_statusBar->progressText().isEmpty()) {
m_statusBar->setProgressText(i18nc("@info:progress", "Loading folder..."));
m_statusBar->setProgress(percent);
}
+void DolphinViewContainer::updateSortProgress(int percent)
+{
+ if (m_statusBar->progressText().isEmpty()) {
+ m_statusBar->setProgressText(i18nc("@info:progress", "Sorting..."));
+ }
+ m_statusBar->setProgress(percent);
+}
+
void DolphinViewContainer::slotStartedPathLoading()
{
if (isSearchUrl(url())) {
// Trigger an undetermined progress indication. The progress
// information in percent will be triggered by the percent() signal
// of the directory lister later.
- updateProgress(-1);
+ updateLoadingProgress(-1);
}
}
*/
void updateStatusBar();
- void updateProgress(int percent);
+ void updateLoadingProgress(int percent);
+
+ void updateSortProgress(int percent);
/**
* Updates the statusbar to show an undetermined progress with the correct
m_naturalSorting(KGlobalSettings::naturalSorting()),
m_sortFoldersFirst(true),
m_sortRole(NameRole),
+ m_sortProgressPercent(-1),
m_roles(),
m_caseSensitivity(Qt::CaseInsensitive),
m_itemData(),
return;
}
+ if (m_sortRole == TypeRole) {
+ // Try to resolve the MIME-types synchronously to prevent a reordering of
+ // the items when sorting by type (per default MIME-types are resolved
+ // asynchronously by KFileItemModelRolesUpdater).
+ determineMimeTypes(items, 200);
+ }
+
#ifdef KFILEITEMMODEL_DEBUG
QElapsedTimer timer;
timer.start();
return items;
}
+void KFileItemModel::emitSortProgress(int resolvedCount)
+{
+ // Be tolerant against a resolvedCount with a wrong range.
+ // Although there should not be a case where KFileItemModelRolesUpdater
+ // (= caller) provides a wrong range, it is important to emit
+ // a useful progress information even if there is an unexpected
+ // implementation issue.
+
+ const int itemCount = count();
+ if (resolvedCount >= itemCount) {
+ m_sortProgressPercent = -1;
+ if (m_resortAllItemsTimer->isActive()) {
+ m_resortAllItemsTimer->stop();
+ resortAllItems();
+ }
+
+ emit sortProgress(100);
+ } else if (itemCount > 0) {
+ resolvedCount = qBound(0, resolvedCount, itemCount);
+
+ const int progress = resolvedCount * 100 / itemCount;
+ if (m_sortProgressPercent != progress) {
+ m_sortProgressPercent = progress;
+ emit sortProgress(progress);
+ }
+ }
+}
+
const KFileItemModel::RoleInfoMap* KFileItemModel::rolesInfoMap(int& count)
{
static const RoleInfoMap rolesInfoMap[] = {
return rolesInfoMap;
}
+void KFileItemModel::determineMimeTypes(const KFileItemList& items, int timeout)
+{
+ QElapsedTimer timer;
+ timer.start();
+ foreach (KFileItem item, items) {
+ item.determineMimeType();
+ if (timer.elapsed() > timeout) {
+ // Don't block the user interface, let the remaining items
+ // be resolved asynchronously.
+ return;
+ }
+ }
+}
+
#include "kfileitemmodel.moc"
*/
void loadingCompleted();
+ /**
+ * Is emitted if the sort-role gets resolved asynchronously and provides
+ * the progress-information of the sorting in percent. It is assured
+ * that the last sortProgress-signal contains 100 as value.
+ */
+ void sortProgress(int percent);
+
protected:
virtual void onGroupedSortingChanged(bool current);
virtual void onSortRoleChanged(const QByteArray& current, const QByteArray& previous);
*/
KFileItemList childItems(const KFileItem& item) const;
+ /**
+ * Is invoked by KFileItemModelRolesUpdater and results in emitting the
+ * sortProgress signal with a percent-value of the progress.
+ */
+ void emitSortProgress(int resolvedCount);
+
/**
* Maps the QByteArray-roles to RoleTypes and provides translation- and
* group-contexts.
*/
static const RoleInfoMap* rolesInfoMap(int& count);
+ /**
+ * Determines the MIME-types of all items that can be done within
+ * the given timeout.
+ */
+ static void determineMimeTypes(const KFileItemList& items, int timeout);
+
private:
QWeakPointer<KDirLister> m_dirLister;
bool m_sortFoldersFirst;
RoleType m_sortRole;
+ int m_sortProgressPercent; // Value of sortProgress() signal
QSet<QByteArray> m_roles;
Qt::CaseSensitivity m_caseSensitivity;
QSet<KUrl> m_urlsToExpand;
friend class KFileItemModelSortAlgorithm; // Accesses lessThan() method
+ friend class KFileItemModelRolesUpdater; // Accesses emitSortProgress() method
friend class KFileItemModelTest; // For unit testing
};
m_previewShown(false),
m_enlargeSmallPreviews(true),
m_clearPreviews(false),
+ m_sortProgress(-1),
m_model(model),
m_iconSize(),
m_firstVisibleIndex(0),
this, SLOT(slotItemsRemoved(KItemRangeList)));
connect(m_model, SIGNAL(itemsChanged(KItemRangeList,QSet<QByteArray>)),
this, SLOT(slotItemsChanged(KItemRangeList,QSet<QByteArray>)));
+ connect(m_model, SIGNAL(sortRoleChanged(QByteArray,QByteArray)),
+ this, SLOT(slotSortRoleChanged(QByteArray,QByteArray)));
// 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->setInterval(1000);
m_changedItemsTimer->setSingleShot(true);
connect(m_changedItemsTimer, SIGNAL(timeout()), this, SLOT(resolveChangedItems()));
+
+ m_resolvableRoles.insert("size");
+ m_resolvableRoles.insert("type");
+ m_resolvableRoles.insert("isExpandable");
+#ifdef HAVE_NEPOMUK
+ m_resolvableRoles += KNepomukRolesProvider::instance().roles();
+#endif
}
KFileItemModelRolesUpdater::~KFileItemModelRolesUpdater()
QSetIterator<QByteArray> it(roles);
while (it.hasNext()) {
const QByteArray& role = it.next();
- if (rolesProvider.isNepomukRole(role)) {
+ if (rolesProvider.roles().contains(role)) {
hasNepomukRole = true;
break;
}
}
#endif
+ updateSortProgress();
+
if (m_paused) {
m_rolesChangedDuringPausing = true;
} else {
m_changedItemsTimer->start();
}
+void KFileItemModelRolesUpdater::slotSortRoleChanged(const QByteArray& current,
+ const QByteArray& previous)
+{
+ Q_UNUSED(current);
+ Q_UNUSED(previous);
+ updateSortProgress();
+}
+
void KFileItemModelRolesUpdater::slotGotPreview(const KFileItem& item, const QPixmap& pixmap)
{
m_pendingVisibleItems.remove(item);
m_model->setData(index, data);
connect(m_model, SIGNAL(itemsChanged(KItemRangeList,QSet<QByteArray>)),
this, SLOT(slotItemsChanged(KItemRangeList,QSet<QByteArray>)));
+
+ applySortProgressToModel();
}
void KFileItemModelRolesUpdater::slotPreviewFailed(const KFileItem& item)
m_clearPreviews = true;
applyResolvedRoles(item, ResolveAll);
m_clearPreviews = clearPreviews;
+
+ applySortProgressToModel();
}
void KFileItemModelRolesUpdater::slotPreviewJobFinished(KJob* job)
m_clearPreviews = false;
}
+ applySortProgressToModel();
+
#ifdef KFILEITEMMODELROLESUPDATER_DEBUG
static int callCount = 0;
++callCount;
{
int resolvedCount = 0;
- const bool hasSlowRoles = m_previewShown
- || m_roles.contains("size")
- || m_roles.contains("type")
- || m_roles.contains("isExpandable");
+ bool hasSlowRoles = m_previewShown;
+ if (!hasSlowRoles) {
+ QSetIterator<QByteArray> it(m_roles);
+ while (it.hasNext()) {
+ if (m_resolvableRoles.contains(it.next())) {
+ hasSlowRoles = true;
+ break;
+ }
+ }
+ }
+
const ResolveHint resolveHint = hasSlowRoles ? ResolveFast : ResolveAll;
// Resolving the MIME type can be expensive. Assure that not more than MaxBlockTimeout ms are
QSetIterator<KFileItem> 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()
+ // All roles will be resolved by applyResolvedRoles()
m_pendingVisibleItems.remove(item);
}
+ applyResolvedRoles(item, resolveHint);
++resolvedCount;
if (timer.elapsed() > MaxBlockTimeout) {
}
kDebug() << "[TIME] Resolved pending roles:" << timer.elapsed();
#endif
+
+ applySortProgressToModel();
}
void KFileItemModelRolesUpdater::resetPendingRoles()
resolvePendingRoles();
}
+void KFileItemModelRolesUpdater::applySortProgressToModel()
+{
+ if (m_sortProgress < 0) {
+ return;
+ }
+
+ // Inform the model about the progress of the resolved items,
+ // so that it can give an indication when the sorting has been finished.
+ const int resolvedCount = m_model->count()
+ - m_pendingVisibleItems.count()
+ - m_pendingInvisibleItems.count();
+ if (resolvedCount > 0) {
+ m_model->emitSortProgress(resolvedCount);
+ if (resolvedCount == m_model->count()) {
+ m_sortProgress = -1;
+ }
+ }
+}
+
+void KFileItemModelRolesUpdater::updateSortProgress()
+{
+ const QByteArray sortRole = m_model->sortRole();
+
+ // Optimization if the sorting is done by type: In case if all MIME-types
+ // are known, the types have been resolved already by KFileItemModel and
+ // no sort-progress feedback is required.
+ const bool showProgress = (sortRole == "type")
+ ? hasUnknownMimeTypes()
+ : m_resolvableRoles.contains(sortRole);
+
+ if (m_sortProgress >= 0) {
+ // Mark the current sorting as finished
+ m_model->emitSortProgress(m_model->count());
+ }
+ m_sortProgress = showProgress ? 0 : -1;
+}
+
+bool KFileItemModelRolesUpdater::hasUnknownMimeTypes() const
+{
+ const int count = m_model->count();
+ for (int i = 0; i < count; ++i) {
+ const KFileItem item = m_model->fileItem(i);
+ if (!item.isMimeTypeKnown()) {
+ return true;
+ }
+ }
+
+ return false;
+}
+
bool KFileItemModelRolesUpdater::applyResolvedRoles(const KFileItem& item, ResolveHint hint)
{
if (item.isNull()) {
void slotItemsRemoved(const KItemRangeList& itemRanges);
void slotItemsChanged(const KItemRangeList& itemRanges,
const QSet<QByteArray>& roles);
+ void slotSortRoleChanged(const QByteArray& current,
+ const QByteArray& previous);
/**
* Is invoked after a preview has been received successfully.
void resetPendingRoles();
void sortAndResolveAllRoles();
void sortAndResolvePendingRoles();
+ void applySortProgressToModel();
+
+ /**
+ * Updates m_sortProgress to be 0 if the sort-role
+ * needs to get resolved asynchronously and hence a
+ * progress is required. Otherwise m_sortProgress
+ * will be set to -1 which means that no progress
+ * will be provided.
+ */
+ void updateSortProgress();
+
+ /**
+ * @return True, if at least one item from the model
+ * has an unknown MIME-type.
+ */
+ bool hasUnknownMimeTypes() const;
enum ResolveHint {
ResolveFast,
// during the roles-updater has been paused by setPaused().
bool m_clearPreviews;
+ int m_sortProgress;
+
KFileItemModel* m_model;
QSize m_iconSize;
int m_firstVisibleIndex;
int m_lastVisibleIndex;
QSet<QByteArray> m_roles;
+ QSet<QByteArray> m_resolvableRoles;
QStringList m_enabledPlugins;
QSet<KFileItem> m_pendingVisibleItems;
{
}
-bool KNepomukRolesProvider::isNepomukRole(const QByteArray& role) const
+QSet<QByteArray> KNepomukRolesProvider::roles() const
{
- return m_roles.contains(role);
+ return m_roles;
}
QHash<QByteArray, QVariant> KNepomukRolesProvider::roleValues(const Nepomuk::Resource& resource,
virtual ~KNepomukRolesProvider();
/**
- * @return True if the values of the role can be determined by Nepomuk.
+ * @return Roles that can be provided by KNepomukRolesProvider.
*/
- bool isNepomukRole(const QByteArray& role) const;
+ QSet<QByteArray> roles() const;
/**
* @return Values for the roles \a roles that can be determined from the file
m_progressBar->hide();
m_showProgressBarTimer = new QTimer(this);
- m_showProgressBarTimer->setInterval(1000);
+ m_showProgressBarTimer->setInterval(200);
m_showProgressBarTimer->setSingleShot(true);
connect(m_showProgressBarTimer, SIGNAL(timeout()), this, SLOT(updateProgressInfo()));
KFileItemModel* model = fileItemModel();
if (model) {
connect(model, SIGNAL(loadingCompleted()), this, SLOT(slotLoadingCompleted()));
+ connect(model, SIGNAL(sortProgress(int)), this, SIGNAL(sortProgress(int)));
}
KItemListView* view = controller->view();
*/
void pathLoadingProgress(int percent);
+ void sortProgress(int percent);
+
/**
* Is emitted if the DolphinView::setUrl() is invoked but the URL is not
* a directory.
void hideToolTip();
- //void slotUrlChangeRequested(const KUrl& url);
-
private:
KFileItemModel* fileItemModel() const;