1 /************************************************************************
2 **
3 **  Copyright (C) 2015-2019 Kevin B. Hendricks, Stratford Ontario Canada
4 **  Copyright (C) 2009-2011 Strahinja Markovic  <strahinja.markovic@gmail.com>
5 **
6 **  This file is part of Sigil.
7 **
8 **  Sigil is free software: you can redistribute it and/or modify
9 **  it under the terms of the GNU General Public License as published by
10 **  the Free Software Foundation, either version 3 of the License, or
11 **  (at your option) any later version.
12 **
13 **  Sigil is distributed in the hope that it will be useful,
14 **  but WITHOUT ANY WARRANTY; without even the implied warranty of
15 **  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16 **  GNU General Public License for more details.
17 **
18 **  You should have received a copy of the GNU General Public License
19 **  along with Sigil.  If not, see <http://www.gnu.org/licenses/>.
20 **
21 *************************************************************************/
22 
23 #include "MainUI/OPFModelItem.h"
24 
25 // Reimplementation of QStandardItem to support sorting alphanumerically
AlphanumericItem()26 AlphanumericItem::AlphanumericItem() : QStandardItem()
27 {
28 }
29 
AlphanumericItem(const QIcon icon,const QString text)30 AlphanumericItem::AlphanumericItem(const QIcon icon, const QString text) : QStandardItem(icon, text)
31 {
32 }
33 
34 // Override standard sort operator to allow sorting alphanumerically case-sensitive
operator <(const QStandardItem & item) const35 bool AlphanumericItem::operator<(const QStandardItem &item) const
36 {
37     if (model()->sortRole() == READING_ORDER_ROLE) {
38         return data(READING_ORDER_ROLE).toInt() < item.data(READING_ORDER_ROLE).toInt();
39     } else if (model()->sortRole() != ALPHANUMERIC_ORDER_ROLE) {
40         return text().compare(item.text()) < 0;
41     }
42 
43     QString s1 = data(ALPHANUMERIC_ORDER_ROLE).toString();
44     QString s2 = item.data(ALPHANUMERIC_ORDER_ROLE).toString();
45 
46     if (s1 == NULL || s2 == NULL) {
47         return false;
48     }
49 
50     int len1 = s1.length();
51     int len2 = s2.length();
52     int marker1 = 0;
53     int marker2 = 0;
54     int result  = 0;
55 
56     // Loop through both strings with separate markers
57     while (marker1 < len1 && marker2 < len2) {
58         QChar ch1 = s1[marker1];
59         QChar ch2 = s2[marker2];
60         QString space1(s1);
61         QString space2(s2);
62         int loc1 = 0;
63         int loc2 = 0;
64 
65         // Loop over first string at marker collecting consecutive digits (or non-digits)
66         do {
67             space1[loc1++] = ch1;
68             marker1++;
69 
70             if (marker1 < len1) {
71                 ch1 = s1[marker1];
72             } else {
73                 break;
74             }
75         } while (ch1.isDigit() == space1[0].isDigit());
76 
77         // Loop over second string at marker collecting consecutive digits (or non-digits)
78         do {
79             space2[loc2++] = ch2;
80             marker2++;
81 
82             if (marker2 < len2) {
83                 ch2 = s2[marker2];
84             } else {
85                 break;
86             }
87         } while (ch2.isDigit() == space2[0].isDigit());
88 
89         QString str1 = space1.left(loc1);
90         QString str2 = space2.left(loc2);
91 
92         // If we collected numbers, compare them numerically
93         if (space1[0].isDigit() && space2[0].isDigit()) {
94             int n1 = str1.toInt();
95             int n2 = str2.toInt();
96             result = n1 - n2;
97         } else {
98             result = str1.compare(str2);
99         }
100 
101         if (result != 0) {
102             return result < 0;
103         }
104     }
105 
106     return len1 < len2;
107 }
108