Commit 7aac4752 authored by Peter Penz's avatar Peter Penz
Browse files

Do a natural sorting of items (thanks to Dominic Battre and Martin Pool for...

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
parent ab62eb85
/***************************************************************************
* 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; }
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment