From 88705d0c34911fee2464bab8a050159f68d84d98 Mon Sep 17 00:00:00 2001 From: Nick Shaforostoff Date: Fri, 20 Jul 2007 21:16:50 +0000 Subject: [PATCH] Make use of the newly added KDirSortFilterProxyModel class -- that is, essentially, remove all the code being duplicated :) Make manpart use KEncodingDetector capabilities along the way (it was before) svn path=/trunk/KDE/kdebase/apps/; revision=690382 --- src/CMakeLists.txt | 1 - src/dolphinsortfilterproxymodel.cpp | 326 ++++------------------------ src/dolphinsortfilterproxymodel.h | 42 +++- src/kcategorizedview.cpp | 8 +- src/kcategorizedview_p.h | 4 +- src/ksortfilterproxymodel.cpp | 52 ----- src/ksortfilterproxymodel.h | 61 ------ 7 files changed, 82 insertions(+), 412 deletions(-) delete mode 100644 src/ksortfilterproxymodel.cpp delete mode 100644 src/ksortfilterproxymodel.h diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 2484b3b05..7ff73c560 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -16,7 +16,6 @@ set(dolphinprivate_LIB_SRCS dolphincolumnview.cpp dolphinitemcategorizer.cpp kcategorizedview.cpp - ksortfilterproxymodel.cpp kitemcategorizer.cpp dolphinsettings.cpp viewproperties.cpp diff --git a/src/dolphinsortfilterproxymodel.cpp b/src/dolphinsortfilterproxymodel.cpp index 592b0aa1c..dcb1af0e9 100644 --- a/src/dolphinsortfilterproxymodel.cpp +++ b/src/dolphinsortfilterproxymodel.cpp @@ -50,16 +50,10 @@ static DolphinView::Sorting sortingTypeTable[] = }; DolphinSortFilterProxyModel::DolphinSortFilterProxyModel(QObject* parent) : - KSortFilterProxyModel(parent), + KDirSortFilterProxyModel(parent), m_sorting(DolphinView::SortByName), m_sortOrder(Qt::AscendingOrder) { - setDynamicSortFilter(true); - - // sort by the user visible string for now - setSortRole(DolphinView::SortByName); - setSortCaseSensitivity(Qt::CaseInsensitive); - sort(KDirModel::Name, Qt::AscendingOrder); } DolphinSortFilterProxyModel::~DolphinSortFilterProxyModel() @@ -83,19 +77,7 @@ void DolphinSortFilterProxyModel::sort(int column, Qt::SortOrder sortOrder) m_sorting = sortingForColumn(column); m_sortOrder = sortOrder; setSortRole(m_sorting); - KSortFilterProxyModel::sort(column, sortOrder); -} - -bool DolphinSortFilterProxyModel::hasChildren(const QModelIndex& parent) const -{ - const QModelIndex sourceParent = mapToSource(parent); - return sourceModel()->hasChildren(sourceParent); -} - -bool DolphinSortFilterProxyModel::canFetchMore(const QModelIndex& parent) const -{ - const QModelIndex sourceParent = mapToSource(parent); - return sourceModel()->canFetchMore(sourceParent); + KDirSortFilterProxyModel::sort(column, sortOrder); } DolphinView::Sorting DolphinSortFilterProxyModel::sortingForColumn(int column) @@ -196,27 +178,12 @@ bool DolphinSortFilterProxyModel::lessThanGeneralPurpose(const QModelIndex &left bool DolphinSortFilterProxyModel::lessThan(const QModelIndex& left, const QModelIndex& right) const { +#ifdef HAVE_NEPOMUK KDirModel* dirModel = static_cast(sourceModel()); const KFileItem* leftFileItem = dirModel->itemForIndex(left); const KFileItem* rightFileItem = dirModel->itemForIndex(right); - // If we are sorting by rating, folders and files are citizens of the same - // class. Same if we are sorting by tags. -#ifdef HAVE_NEPOMUK - if ((sortRole() != DolphinView::SortByRating) && - (sortRole() != DolphinView::SortByTags)) - { -#endif - // On our priority, folders go above regular files. - if (leftFileItem->isDir() && !rightFileItem->isDir()) { - return true; - } else if (!leftFileItem->isDir() && rightFileItem->isDir()) { - return false; - } -#ifdef HAVE_NEPOMUK - } -#endif // Hidden elements go before visible ones, if they both are // folders or files. @@ -227,164 +194,60 @@ bool DolphinSortFilterProxyModel::lessThan(const QModelIndex& left, } switch (sortRole()) { - case DolphinView::SortByName: { - // So we are in the same priority, what counts now is their names. - const QVariant leftData = dirModel->data(left, KDirModel::Name); - const QVariant rightData = dirModel->data(right, KDirModel::Name); - const QString leftValueString(leftData.toString()); - const QString rightValueString(rightData.toString()); - - return sortCaseSensitivity() ? - (naturalCompare(leftValueString, rightValueString) < 0) : - (naturalCompare(leftValueString.toLower(), rightValueString.toLower()) < 0); - } - - case DolphinView::SortBySize: { - // If we have two folders, what we have to measure is the number of - // items that contains each other - if (leftFileItem->isDir() && rightFileItem->isDir()) { - QVariant leftValue = dirModel->data(left, KDirModel::ChildCountRole); - int leftCount = leftValue.type() == QVariant::Int ? leftValue.toInt() : KDirModel::ChildCountUnknown; - - QVariant rightValue = dirModel->data(right, KDirModel::ChildCountRole); - int rightCount = rightValue.type() == QVariant::Int ? rightValue.toInt() : KDirModel::ChildCountUnknown; - - // In the case they two have the same child items, we sort them by - // their names. So we have always everything ordered. We also check - // if we are taking in count their cases. - if (leftCount == rightCount) { - return sortCaseSensitivity() ? (naturalCompare(leftFileItem->name(), rightFileItem->name()) < 0) : - (naturalCompare(leftFileItem->name().toLower(), rightFileItem->name().toLower()) < 0); - } - - // If they had different number of items, we sort them depending - // on how many items had each other. - return leftCount < rightCount; - } - - // If what we are measuring is two files and they have the same size, - // sort them by their file names. - if (leftFileItem->size() == rightFileItem->size()) { - return sortCaseSensitivity() ? (naturalCompare(leftFileItem->name(), rightFileItem->name()) < 0) : - (naturalCompare(leftFileItem->name().toLower(), rightFileItem->name().toLower()) < 0); - } - - // If their sizes are different, sort them by their sizes, as expected. - return leftFileItem->size() < rightFileItem->size(); - } - - case DolphinView::SortByDate: { - KDateTime leftTime, rightTime; - leftTime.setTime_t(leftFileItem->time(KIO::UDS_MODIFICATION_TIME)); - rightTime.setTime_t(rightFileItem->time(KIO::UDS_MODIFICATION_TIME)); - - if (leftTime == rightTime) { - return sortCaseSensitivity() ? - (naturalCompare(leftFileItem->name(), rightFileItem->name()) < 0) : - (naturalCompare(leftFileItem->name().toLower(), rightFileItem->name().toLower()) < 0); - } - - return leftTime > rightTime; - } - - case DolphinView::SortByPermissions: { - if (leftFileItem->permissionsString() == rightFileItem->permissionsString()) { - return sortCaseSensitivity() ? - (naturalCompare(leftFileItem->name(), rightFileItem->name()) < 0) : - (naturalCompare(leftFileItem->name().toLower(), rightFileItem->name().toLower()) < 0); - } - - return naturalCompare(leftFileItem->permissionsString(), - rightFileItem->permissionsString()) < 0; - } - - case DolphinView::SortByOwner: { - if (leftFileItem->user() == rightFileItem->user()) { - return sortCaseSensitivity() ? - (naturalCompare(leftFileItem->name(), rightFileItem->name()) < 0) : - (naturalCompare(leftFileItem->name().toLower(), rightFileItem->name().toLower()) < 0); - } - - return naturalCompare(leftFileItem->user(), rightFileItem->user()) < 0; - } + case DolphinView::SortByRating: { + const quint32 leftRating = ratingForIndex(left); + const quint32 rightRating = ratingForIndex(right); + + if (leftRating == rightRating) { + // On our priority, folders go above regular files. + // This checks are needed (don't think it's the same doing it here + // than above). Here we make dirs citizens of first class because + // we know we are on the same category. On the check we do on the + // top of the method we don't know, so we remove that check when we + // are sorting by rating. (ereslibre) + if (leftFileItem->isDir() && !rightFileItem->isDir()) { + return true; + } else if (!leftFileItem->isDir() && rightFileItem->isDir()) { + return false; + } - case DolphinView::SortByGroup: { - if (leftFileItem->group() == rightFileItem->group()) { - return sortCaseSensitivity() ? (naturalCompare(leftFileItem->name(), rightFileItem->name()) < 0) : + return sortCaseSensitivity() ? + (naturalCompare(leftFileItem->name(), rightFileItem->name()) < 0) : (naturalCompare(leftFileItem->name().toLower(), rightFileItem->name().toLower()) < 0); - } - - return naturalCompare(leftFileItem->group(), - rightFileItem->group()) < 0; - } - - case DolphinView::SortByType: { - if (leftFileItem->mimetype() == rightFileItem->mimetype()) { - return sortCaseSensitivity() ? - (naturalCompare(leftFileItem->name(), rightFileItem->name()) < 0) : - (naturalCompare(leftFileItem->name().toLower(), rightFileItem->name().toLower()) < 0); - } - - return naturalCompare(leftFileItem->mimeComment(), - rightFileItem->mimeComment()) < 0; - } - -#ifdef HAVE_NEPOMUK - case DolphinView::SortByRating: { - const quint32 leftRating = ratingForIndex(left); - const quint32 rightRating = ratingForIndex(right); - - if (leftRating == rightRating) { - // On our priority, folders go above regular files. - // This checks are needed (don't think it's the same doing it here - // than above). Here we make dirs citizens of first class because - // we know we are on the same category. On the check we do on the - // top of the method we don't know, so we remove that check when we - // are sorting by rating. (ereslibre) - if (leftFileItem->isDir() && !rightFileItem->isDir()) { - return true; - } else if (!leftFileItem->isDir() && rightFileItem->isDir()) { - return false; } - return sortCaseSensitivity() ? - (naturalCompare(leftFileItem->name(), rightFileItem->name()) < 0) : - (naturalCompare(leftFileItem->name().toLower(), rightFileItem->name().toLower()) < 0); + return leftRating > rightRating; } - return leftRating > rightRating; - } - - case DolphinView::SortByTags: { - const QString leftTags = tagsForIndex(left); - const QString rightTags = tagsForIndex(right); + case DolphinView::SortByTags: { + const QString leftTags = tagsForIndex(left); + const QString rightTags = tagsForIndex(right); + + if (leftTags == rightTags) { + // On our priority, folders go above regular files. + // This checks are needed (don't think it's the same doing it here + // than above). Here we make dirs citizens of first class because + // we know we are on the same category. On the check we do on the + // top of the method we don't know, so we remove that check when we + // are sorting by tags. (ereslibre) + if (leftFileItem->isDir() && !rightFileItem->isDir()) { + return true; + } else if (!leftFileItem->isDir() && rightFileItem->isDir()) { + return false; + } - if (leftTags == rightTags) { - // On our priority, folders go above regular files. - // This checks are needed (don't think it's the same doing it here - // than above). Here we make dirs citizens of first class because - // we know we are on the same category. On the check we do on the - // top of the method we don't know, so we remove that check when we - // are sorting by tags. (ereslibre) - if (leftFileItem->isDir() && !rightFileItem->isDir()) { - return true; - } else if (!leftFileItem->isDir() && rightFileItem->isDir()) { - return false; + return sortCaseSensitivity() ? + (naturalCompare(leftFileItem->name(), rightFileItem->name()) < 0) : + (naturalCompare(leftFileItem->name().toLower(), rightFileItem->name().toLower()) < 0); } - return sortCaseSensitivity() ? - (naturalCompare(leftFileItem->name(), rightFileItem->name()) < 0) : - (naturalCompare(leftFileItem->name().toLower(), rightFileItem->name().toLower()) < 0); + return naturalCompare(leftTags, rightTags) < 0; } - - return naturalCompare(leftTags, rightTags) < 0; } #endif - } - // We have set a SortRole and trust the ProxyModel to do // the right thing for now. - return QSortFilterProxyModel::lessThan(left, right); + return KDirSortFilterProxyModel::lessThan(left, right); } quint32 DolphinSortFilterProxyModel::ratingForIndex(const QModelIndex& index) @@ -432,111 +295,10 @@ QString DolphinSortFilterProxyModel::tagsForIndex(const QModelIndex& index) return tagsString; #else + Q_UNUSED(index); return QString(); #endif } -int DolphinSortFilterProxyModel::naturalCompare(const QString& a, - const QString& b) -{ - // This method chops the input a and b into pieces of - // digits and non-digits (a1.05 becomes a | 1 | . | 05) - // and compares these pieces of a and b to each other - // (first with first, second with second, ...). - // - // This is based on the natural sort order code code by Martin Pool - // http://sourcefrog.net/projects/natsort/ - // Martin Pool agreed to license this under LGPL or GPL. - - const QChar* currA = a.unicode(); // iterator over a - const QChar* currB = b.unicode(); // iterator over b - - if (currA == currB) { - return 0; - } - - const QChar* begSeqA = currA; // beginning of a new character sequence of a - const QChar* begSeqB = currB; - - while (!currA->isNull() && !currB->isNull()) { - // find sequence of characters ending at the first non-character - while (!currA->isNull() && !currA->isDigit()) { - ++currA; - } - - while (!currB->isNull() && !currB->isDigit()) { - ++currB; - } - - // compare these sequences - const QString subA(begSeqA, currA - begSeqA); - const QString subB(begSeqB, currB - begSeqB); - const int cmp = QString::localeAwareCompare(subA, subB); - if (cmp != 0) { - return cmp; - } - - if (currA->isNull() || currB->isNull()) { - break; - } - - // now some digits follow... - if ((*currA == '0') || (*currB == '0')) { - // one digit-sequence starts with 0 -> assume we are in a fraction part - // do left aligned comparison (numbers are considered left aligned) - while (1) { - if (!currA->isDigit() && !currB->isDigit()) { - break; - } else if (!currA->isDigit()) { - return -1; - } else if (!currB->isDigit()) { - return + 1; - } else if (*currA < *currB) { - return -1; - } else if (*currA > *currB) { - return + 1; - } - ++currA; - ++currB; - } - } else { - // No digit-sequence starts with 0 -> assume we are looking at some integer - // do right aligned comparison. - // - // The longest run of digits wins. That aside, the greatest - // value wins, but we can't know that it will until we've scanned - // both numbers to know that they have the same magnitude. - - int weight = 0; - while (1) { - if (!currA->isDigit() && !currB->isDigit()) { - if (weight != 0) { - return weight; - } - break; - } else if (!currA->isDigit()) { - return -1; - } else if (!currB->isDigit()) { - return + 1; - } else if ((*currA < *currB) && (weight == 0)) { - weight = -1; - } else if ((*currA > *currB) && (weight == 0)) { - weight = + 1; - } - ++currA; - ++currB; - } - } - - begSeqA = currA; - begSeqB = currB; - } - - if (currA->isNull() && currB->isNull()) { - return 0; - } - - return currA->isNull() ? -1 : + 1; -} #include "dolphinsortfilterproxymodel.moc" diff --git a/src/dolphinsortfilterproxymodel.h b/src/dolphinsortfilterproxymodel.h index 56ee77dba..ef55bab56 100644 --- a/src/dolphinsortfilterproxymodel.h +++ b/src/dolphinsortfilterproxymodel.h @@ -20,7 +20,7 @@ #ifndef DOLPHINSORTFILTERPROXYMODEL_H #define DOLPHINSORTFILTERPROXYMODEL_H -#include +#include #include #include @@ -39,7 +39,7 @@ * * It is assured that directories are always sorted before files. */ -class LIBDOLPHINPRIVATE_EXPORT DolphinSortFilterProxyModel : public KSortFilterProxyModel +class LIBDOLPHINPRIVATE_EXPORT DolphinSortFilterProxyModel : public KDirSortFilterProxyModel { Q_OBJECT @@ -62,12 +62,6 @@ public: virtual void sort(int column, Qt::SortOrder order = Qt::AscendingOrder); - /** Reimplemented from QAbstractItemModel. Returns true for directories. */ - virtual bool hasChildren(const QModelIndex& parent = QModelIndex()) const; - - /** Reimplemented from QAbstractItemModel. Returns true for empty directories. */ - virtual bool canFetchMore(const QModelIndex& parent) const; - /** * Helper method to get the DolphinView::Sorting type for a given * column \a column. If the column is smaller 0 or greater than the @@ -75,9 +69,39 @@ public: */ static DolphinView::Sorting sortingForColumn(int column); + /** + * This method is essential on the categorized view. + * It will does a "basic" sorting, just for finding out categories, + * and their order. Then over those elements DISORDERED on categories, + * the lessThan method will be applied for each category. + * + * The easy explanation is that not always folders go first. That will depend. + * Imagine we sort by Rating. Categories will be created by 10 stars, + * 9 stars, 8 stars... but a category with only a file with rating 10 + * will go before a category with a folder with rating 8. + * That's the main reason, and that's lessThanGeneralPurpose() method. + * That will go category by category creating sets of elements... + */ virtual bool lessThanGeneralPurpose(const QModelIndex &left, const QModelIndex &right) const; + /** + * Then for each set of elements lessThanCategoryPurpose() will be applied, + * because for each category we wan't first folders and bla bla bla... + * That's the main reason of that method existence. + * + * For that reason, is not that clear that we want ALWAYS folders first. + * On each category, yes, that's true. But that's not true always, + * as I have pointed out on the example before. + */ + bool lessThanCategoryPurpose(const QModelIndex &left, + const QModelIndex &right) const + { + //when we sort inside 1 category its the usual lessThan() + //from KDirSortFilterProxyModel(+nepomuk) + return lessThan(left,right); + } + protected: virtual bool lessThan(const QModelIndex& left, const QModelIndex& right) const; @@ -95,8 +119,6 @@ private: */ static QString tagsForIndex(const QModelIndex& index); - static int naturalCompare(const QString& a, const QString& b); - private: DolphinView::Sorting m_sorting; Qt::SortOrder m_sortOrder; diff --git a/src/kcategorizedview.cpp b/src/kcategorizedview.cpp index d250c42c9..b42d066b5 100644 --- a/src/kcategorizedview.cpp +++ b/src/kcategorizedview.cpp @@ -33,7 +33,7 @@ #include #include "kitemcategorizer.h" -#include "ksortfilterproxymodel.h" +#include "dolphinsortfilterproxymodel.h" class LessThan { @@ -44,7 +44,7 @@ public: CategoryPurpose }; - inline LessThan(const KSortFilterProxyModel *proxyModel, + inline LessThan(const DolphinSortFilterProxyModel *proxyModel, Purpose purpose) : proxyModel(proxyModel) , purpose(purpose) @@ -67,7 +67,7 @@ public: } private: - const KSortFilterProxyModel *proxyModel; + const DolphinSortFilterProxyModel *proxyModel; const Purpose purpose; }; @@ -483,7 +483,7 @@ void KCategorizedView::setModel(QAbstractItemModel *model) QListView::setModel(model); - d->proxyModel = dynamic_cast(model); + d->proxyModel = dynamic_cast(model); if (d->proxyModel) { diff --git a/src/kcategorizedview_p.h b/src/kcategorizedview_p.h index 45d89aa21..4e5a55dba 100644 --- a/src/kcategorizedview_p.h +++ b/src/kcategorizedview_p.h @@ -21,7 +21,7 @@ #ifndef KCATEGORIZEDVIEW_P_H #define KCATEGORIZEDVIEW_P_H -class KSortFilterProxyModel; +class DolphinSortFilterProxyModel; /** * @internal @@ -152,7 +152,7 @@ public: QRect lastSelectionRect; // Attributes for speed reasons - KSortFilterProxyModel *proxyModel; + DolphinSortFilterProxyModel *proxyModel; QModelIndexList sourceModelIndexList; // in source model QModelIndex lastIndex; }; diff --git a/src/ksortfilterproxymodel.cpp b/src/ksortfilterproxymodel.cpp deleted file mode 100644 index 9b08c420f..000000000 --- a/src/ksortfilterproxymodel.cpp +++ /dev/null @@ -1,52 +0,0 @@ -/** - * This file is part of the KDE project - * Copyright (C) 2007 Rafael Fernández López - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Library General Public - * License as published by the Free Software Foundation; either - * version 2 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Library General Public License for more details. - * - * You should have received a copy of the GNU Library General Public License - * along with this library; see the file COPYING.LIB. If not, write to - * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, - * Boston, MA 02110-1301, USA. - */ - -#include "ksortfilterproxymodel.h" - -KSortFilterProxyModel::KSortFilterProxyModel(QObject *parent) - : QSortFilterProxyModel(parent) -{ -} - -KSortFilterProxyModel::~KSortFilterProxyModel() -{ -} - -void KSortFilterProxyModel::sort(int column, Qt::SortOrder order) -{ - QSortFilterProxyModel::sort(column, order); - - m_sortOrder = order; - - emit sortingRoleChanged(); -} - -Qt::SortOrder KSortFilterProxyModel::sortOrder() const -{ - return m_sortOrder; -} - -bool KSortFilterProxyModel::lessThanCategoryPurpose(const QModelIndex &left, - const QModelIndex &right) const -{ - return lessThan(left, right); -} - -#include "ksortfilterproxymodel.moc" diff --git a/src/ksortfilterproxymodel.h b/src/ksortfilterproxymodel.h deleted file mode 100644 index 1c653f67c..000000000 --- a/src/ksortfilterproxymodel.h +++ /dev/null @@ -1,61 +0,0 @@ -/** - * This file is part of the KDE project - * Copyright (C) 2007 Rafael Fernández López - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Library General Public - * License as published by the Free Software Foundation; either - * version 2 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Library General Public License for more details. - * - * You should have received a copy of the GNU Library General Public License - * along with this library; see the file COPYING.LIB. If not, write to - * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, - * Boston, MA 02110-1301, USA. - */ - -#ifndef KSORTFILTERPROXYMODEL_H -#define KSORTFILTERPROXYMODEL_H - -#include - -#include - -/** - * @internal - * - * This class is meant to be used with KListView class - * - * @see KListView - */ -class LIBDOLPHINPRIVATE_EXPORT KSortFilterProxyModel - : public QSortFilterProxyModel -{ - Q_OBJECT - -public: - KSortFilterProxyModel(QObject *parent = 0); - ~KSortFilterProxyModel(); - - virtual void sort(int column, Qt::SortOrder order = Qt::AscendingOrder); - - Qt::SortOrder sortOrder() const; - - virtual bool lessThanGeneralPurpose(const QModelIndex &left, - const QModelIndex &right) const = 0; - - virtual bool lessThanCategoryPurpose(const QModelIndex &left, - const QModelIndex &right) const; - -Q_SIGNALS: - void sortingRoleChanged(); - -private: - Qt::SortOrder m_sortOrder; -}; - -#endif // KSORTFILTERPROXYMODEL_H -- 2.47.3