mirror of
https://invent.kde.org/system/dolphin
synced 2024-07-04 17:30:55 +00:00
Do a natural sorting of items (thanks to Dominic Battre and Martin Pool for the patch!). This means that items like:
item_10.png item_1.png item_2.png are sorted like item_1.png item_2.png item_10.png TODO: corresponding to Ellen directory items should always be ordered as first items (have to go work now -> weekend task :-)) svn path=/trunk/playground/utils/dolphin/; revision=622241
This commit is contained in:
parent
b8572433e2
commit
7954282089
|
@ -1,39 +1,40 @@
|
|||
/***************************************************************************
|
||||
* Copyright (C) 2006 by Peter Penz <peter.penz@gmx.at> *
|
||||
* Copyright (C) 2006 by Gregor Kališnik <gregor@podnapisi.net> *
|
||||
* *
|
||||
* This program is free software; you can redistribute it and/or modify *
|
||||
* it under the terms of the GNU General Public License as published by *
|
||||
* the Free Software Foundation; either version 2 of the License, or *
|
||||
* (at your option) any later version. *
|
||||
* *
|
||||
* This program 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 General Public License for more details. *
|
||||
* *
|
||||
* You should have received a copy of the GNU General Public License *
|
||||
* along with this program; if not, write to the *
|
||||
* Free Software Foundation, Inc., *
|
||||
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA *
|
||||
***************************************************************************/
|
||||
* Copyright (C) 2006 by Peter Penz <peter.penz@gmx.at> *
|
||||
* Copyright (C) 2006 by Dominic Battre <dominic battre de> *
|
||||
* Copyright (C) 2006 by Martin Pool <mbp canonical com> *
|
||||
* *
|
||||
* This program is free software; you can redistribute it and/or modify *
|
||||
* it under the terms of the GNU General Public License as published by *
|
||||
* the Free Software Foundation; either version 2 of the License, or *
|
||||
* (at your option) any later version. *
|
||||
* *
|
||||
* This program 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 General Public License for more details. *
|
||||
* *
|
||||
* You should have received a copy of the GNU General Public License *
|
||||
* along with this program; if not, write to the *
|
||||
* Free Software Foundation, Inc., *
|
||||
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA *
|
||||
***************************************************************************/
|
||||
|
||||
#include "dolphinsortfilterproxymodel.h"
|
||||
|
||||
#include <kdirmodel.h>
|
||||
#include <kfileitem.h>
|
||||
|
||||
static const int dolphin_map_size = 3;
|
||||
static int dolphin_view_to_dir_model_column[] = {
|
||||
/* SortByName */ KDirModel::Name,
|
||||
/* SortBySize */ KDirModel::Size,
|
||||
/* SortByDate */ KDirModel::ModifiedTime
|
||||
static const int dolphinMapSize = 3;
|
||||
static int dolphinViewToDirModelColumn[] = {
|
||||
KDirModel::Name, // DolphinView::SortByName
|
||||
KDirModel::Size, // DolphinView::SortBySize
|
||||
KDirModel::ModifiedTime // DolphinView::SortByDate
|
||||
};
|
||||
|
||||
static DolphinView::Sorting dir_model_column_to_dolphin_view[] = {
|
||||
/* KDirModel::Name */ DolphinView::SortByName,
|
||||
/* KDirModel::Size */ DolphinView::SortBySize,
|
||||
/* KDirModel::ModifiedTime */ DolphinView::SortByDate
|
||||
static DolphinView::Sorting dirModelColumnToDolphinView[] = {
|
||||
DolphinView::SortByName, // KDirModel::Name
|
||||
DolphinView::SortBySize, // KDirModel::Size
|
||||
DolphinView::SortByDate // KDirModel::ModifiedTime
|
||||
};
|
||||
|
||||
|
||||
|
@ -42,9 +43,7 @@ DolphinSortFilterProxyModel::DolphinSortFilterProxyModel(QObject* parent) :
|
|||
{
|
||||
setDynamicSortFilter(true);
|
||||
|
||||
/*
|
||||
* sort by the user visible string for now
|
||||
*/
|
||||
// sort by the user visible string for now
|
||||
setSortRole(Qt::DisplayRole);
|
||||
setSortCaseSensitivity(Qt::CaseInsensitive);
|
||||
sort(KDirModel::Name, Qt::Ascending);
|
||||
|
@ -54,48 +53,161 @@ DolphinSortFilterProxyModel::~DolphinSortFilterProxyModel()
|
|||
{
|
||||
}
|
||||
|
||||
/*
|
||||
* Update the sort column by mapping DolpginView::Sorting to
|
||||
* KDirModel::ModelColumns.
|
||||
* We will keep the sortOrder
|
||||
*/
|
||||
void DolphinSortFilterProxyModel::setSorting(DolphinView::Sorting sorting)
|
||||
{
|
||||
Q_ASSERT( static_cast<int>(sorting) >= 0 && static_cast<int>(sorting) <= dolphin_map_size );
|
||||
sort(dolphin_view_to_dir_model_column[static_cast<int>(sorting)],
|
||||
// Update the sort column by mapping DolpginView::Sorting to
|
||||
// KDirModel::ModelColumns. We will keep the sortOrder.
|
||||
Q_ASSERT(static_cast<int>(sorting) >= 0 && static_cast<int>(sorting) <= dolphinMapSize);
|
||||
sort(dolphinViewToDirModelColumn[static_cast<int>(sorting)],
|
||||
m_sortOrder );
|
||||
}
|
||||
|
||||
/**
|
||||
* @reimplemented, @internal
|
||||
*
|
||||
* If the view 'forces' sorting order to change we will
|
||||
* notice now.
|
||||
*/
|
||||
void DolphinSortFilterProxyModel::sort(int column, Qt::SortOrder sortOrder)
|
||||
{
|
||||
m_sortOrder = sortOrder;
|
||||
m_sorting = column >= 0 && column <= dolphin_map_size ?
|
||||
dir_model_column_to_dolphin_view[column] :
|
||||
DolphinView::SortByName;
|
||||
m_sorting = (column >= 0) && (column <= dolphinMapSize) ?
|
||||
dirModelColumnToDolphinView[column] :
|
||||
DolphinView::SortByName;
|
||||
QSortFilterProxyModel::sort(column,sortOrder);
|
||||
}
|
||||
|
||||
/*
|
||||
* change the sort order by keeping the current column
|
||||
*/
|
||||
void DolphinSortFilterProxyModel::setSortOrder(Qt::SortOrder sortOrder)
|
||||
{
|
||||
sort(dolphin_view_to_dir_model_column[m_sorting], sortOrder);
|
||||
// change the sort order by keeping the current column
|
||||
sort(dolphinViewToDirModelColumn[m_sorting], sortOrder);
|
||||
}
|
||||
|
||||
static int 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 sub_a(begSeqA, currA - begSeqA);
|
||||
const QString sub_b(begSeqB, currB - begSeqB);
|
||||
int cmp = QString::localeAwareCompare(sub_a, sub_b);
|
||||
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 aligend)
|
||||
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, so we
|
||||
// remember it in 'weight'.
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
|
||||
bool DolphinSortFilterProxyModel::lessThan(const QModelIndex& left,
|
||||
const QModelIndex& right) const
|
||||
{
|
||||
/*
|
||||
* We have set a SortRole and trust the ProxyModel to do
|
||||
* the right thing for now
|
||||
*/
|
||||
|
||||
QVariant leftData = sourceModel()->data(left, sortRole());
|
||||
QVariant rightData = sourceModel()->data(right, sortRole());
|
||||
|
||||
if (leftData.type() == QVariant::String && rightData.type() == QVariant::String) {
|
||||
const QString left = leftData.toString();
|
||||
const QString right = rightData.toString();
|
||||
|
||||
return sortCaseSensitivity() ? (naturalCompare(left, right) < 0) :
|
||||
(naturalCompare(left.toLower(), right.toLower()) < 0);
|
||||
}
|
||||
|
||||
// We have set a SortRole and trust the ProxyModel to do
|
||||
// the right thing for now.
|
||||
return QSortFilterProxyModel::lessThan(left,right);
|
||||
}
|
||||
|
||||
|
|
|
@ -27,8 +27,14 @@
|
|||
* @brief Acts as proxy model for KDirModel to sort and filter
|
||||
* KFileItems.
|
||||
*
|
||||
* TODO: implementation does not work yet (the method lessThan is
|
||||
* not invoked)
|
||||
* A natural sorting is done. This means that items like:
|
||||
* - item_10.png
|
||||
* - item_1.png
|
||||
* - item_2.png
|
||||
* are sorted like
|
||||
* - item_1.png
|
||||
* - item_2.png
|
||||
* - item_10.png
|
||||
*/
|
||||
class DolphinSortFilterProxyModel : public QSortFilterProxyModel
|
||||
{
|
||||
|
@ -41,7 +47,13 @@ public:
|
|||
void setSorting(DolphinView::Sorting sorting);
|
||||
DolphinView::Sorting sorting() const { return m_sorting; }
|
||||
|
||||
virtual void sort (int column,
|
||||
/**
|
||||
* @reimplemented, @internal
|
||||
*
|
||||
* If the view 'forces' sorting order to change we will
|
||||
* notice now.
|
||||
*/
|
||||
virtual void sort (int column,
|
||||
Qt::SortOrder order = Qt::AscendingOrder);
|
||||
void setSortOrder(Qt::SortOrder sortOrder);
|
||||
Qt::SortOrder sortOrder() const { return m_sortOrder; }
|
||||
|
|
Loading…
Reference in New Issue
Block a user