Git commit 2aaaafd99d7ddd8a0e0b77db1886b843e79fb2c8 by Stephane Mankowski.
Committed on 02/04/2015 at 20:42.
Pushed by smankowski into branch 'master'.

BUG:345719
Enhance fast search/filter on lists

M  +8    -5    doc/index.docbook
M  +1    -1    skgbasegui/skgfilteredtableview.ui
M  +94   -34   skgbasegui/skgsortfilterproxymodel.cpp
M  +3    -0    skgbasegui/skgsortfilterproxymodel.h

http://commits.kde.org/skrooge/2aaaafd99d7ddd8a0e0b77db1886b843e79fb2c8

diff --git a/doc/index.docbook b/doc/index.docbook
index 20d3c88..96eec8b 100644
--- a/doc/index.docbook
+++ b/doc/index.docbook
@@ -588,16 +588,19 @@
                <listitem><para>If you want to search only on one column, you 
must prefix your word by the column name like: col1:word.</para></listitem>
                <listitem><para>If you want to use the character ":" in value, 
you must specify the column name like this: col1:value:rest.</para></listitem>
                <listitem><para>If you want to search for a phrase or something 
that contains spaces, you must put it in quotes, like: "yes, this is a 
phrase".</para></listitem>
+               <listitem><para>You can also use operator "&lt;" and 
"&gt;".</para></listitem>
            </itemizedlist>
          <para>
            Some examples are better to explain:
          </para>
            <itemizedlist>
-             <listitem><para>+val1 +val2 => Keep lines containing val1 OR 
val2</para></listitem>
-             <listitem><para>+val1 -val2 => Keep lines containing val1 but NOT 
val2</para></listitem>
-             <listitem><para>"abc def" => Keep lines containing the sentense 
"abc def"</para></listitem>
-             <listitem><para>abc:def => Keep lines having a column name 
starting by abc and containing def</para></listitem>
-             <listitem><para>:abc:def => Keep lines containing 
"abc:def"</para></listitem>
+             <listitem><para>+val1 +val2 =&gt; Keep lines containing val1 OR 
val2</para></listitem>
+             <listitem><para>+val1 -val2 =&gt; Keep lines containing val1 but 
NOT val2</para></listitem>
+             <listitem><para>"abc def" =&gt; Keep lines containing the 
sentense "abc def"</para></listitem>
+             <listitem><para>abc:def =&gt; Keep lines having a column name 
starting by abc and containing def</para></listitem>
+             <listitem><para>:abc:def =&gt; Keep lines containing 
"abc:def"</para></listitem>
+             <listitem><para>Date&gt;2015-03-01 =&gt; Keep lines where Date 
attribute is greater than 2015-03-01</para></listitem>
+             <listitem><para>Amount&lt;10 =&gt;Keep lines where Amount 
attribute is less than 10</para></listitem>
            </itemizedlist>
        </tip>
        </sect3>
diff --git a/skgbasegui/skgfilteredtableview.ui 
b/skgbasegui/skgfilteredtableview.ui
index c225272..a3670ed 100644
--- a/skgbasegui/skgfilteredtableview.ui
+++ b/skgbasegui/skgfilteredtableview.ui
@@ -101,7 +101,7 @@
         <enum>Qt::WheelFocus</enum>
        </property>
        <property name="toolTip">
-        <string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;Searching is 
case-insensitive. So table, Table, and TABLE are all the same.&lt;br/&gt;If you 
just put a word or series of words in the search box, the application will 
filter the table to keep all lines having these words (logical operator AND). 
&lt;br/&gt;If you want to add (logical operator OR) some line, you must prefix 
your word by &amp;quot;+&amp;quot;.&lt;br/&gt;If you want to remove (logical 
operator NOT) some line, you must prefix your word by 
&amp;quot;-&amp;quot;.&lt;br/&gt;If you want to search only on one column, you 
must prefix your word by the column name like: col1:word.&lt;/p&gt;&lt;p&gt;If 
you want to use the character &amp;quot;:&amp;quot; in value, you must specify 
the column name like this: col1:value:rest.&lt;br/&gt;If you want to search for 
a phrase or something that contains spaces, you must put it in quotes, like: 
&amp;quot;yes, this is a phrase&amp;quot;.&lt;/p&gt;&lt;p&gt;&lt;span 
style=&quot; font-weight:600; text-decoration: 
underline;&quot;&gt;Examples:&lt;/span&gt;&lt;br/&gt;+val1 +val2 =&amp;gt; Keep 
lines containing val1 OR val2&lt;br/&gt;+val1 -val2 =&amp;gt; Keep lines 
containing val1 but NOT val2&lt;br/&gt;&amp;quot;abc def&amp;quot; =&amp;gt; 
Keep lines containing the sentense &amp;quot;abc def&amp;quot; 
&lt;br/&gt;abc:def =&amp;gt; Keep lines having a column name starting by abc 
and containing def&lt;br/&gt;:abc:def =&amp;gt; Keep lines containing 
&amp;quot;abc:def&amp;quot;&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
+        <string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;Searching is 
case-insensitive. So table, Table, and TABLE are all the same.&lt;br/&gt;If you 
just put a word or series of words in the search box, the application will 
filter the table to keep all lines having these words (logical operator AND). 
&lt;br/&gt;If you want to add (logical operator OR) some line, you must prefix 
your word by &amp;quot;+&amp;quot;.&lt;br/&gt;If you want to remove (logical 
operator NOT) some line, you must prefix your word by 
&amp;quot;-&amp;quot;.&lt;br/&gt;If you want to search only on one column, you 
must prefix your word by the column name like: col1:word.&lt;br/&gt;If you want 
to use the character &amp;quot;:&amp;quot; in value, you must specify the 
column name like this: col1:value:rest.&lt;br/&gt;If you want to search for a 
phrase or something that contains spaces, you must put it in quotes, like: 
&amp;quot;yes, this is a phrase&amp;quot;.&lt;/p&gt;&lt;p&gt;You can also use 
operator &amp;quot;&amp;lt;&amp;quot; and 
&amp;quot;&amp;gt;&amp;quot;.&lt;/p&gt;&lt;p&gt;&lt;span style=&quot; 
font-weight:600; text-decoration: 
underline;&quot;&gt;Examples:&lt;/span&gt;&lt;br/&gt;+val1 +val2 =&amp;gt; Keep 
lines containing val1 OR val2&lt;br/&gt;+val1 -val2 =&amp;gt; Keep lines 
containing val1 but NOT val2&lt;br/&gt;&amp;quot;abc def&amp;quot; =&amp;gt; 
Keep lines containing the sentense &amp;quot;abc def&amp;quot; 
&lt;br/&gt;abc:def =&amp;gt; Keep lines having a column name starting by abc 
and containing def&lt;br/&gt;:abc:def =&amp;gt; Keep lines containing 
&amp;quot;abc:def&amp;quot;&lt;br/&gt;Date&amp;gt;2015-03-01 =&amp;gt; Keep 
lines where Date attribute is greater than 
2015-03-01&lt;br/&gt;Amount&amp;lt;10 =&amp;gt;Keep lines where Amount 
attribute is less than 10&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
        </property>
       </widget>
      </item>
diff --git a/skgbasegui/skgsortfilterproxymodel.cpp 
b/skgbasegui/skgsortfilterproxymodel.cpp
index 9c12558..f00d9e5 100644
--- a/skgbasegui/skgsortfilterproxymodel.cpp
+++ b/skgbasegui/skgsortfilterproxymodel.cpp
@@ -125,42 +125,82 @@ bool SKGSortFilterProxyModel::lessThan(const QModelIndex& 
left,
         } else {
             // For better performances, and avoid too many calls to 
QAbstractItemModel::data
             // return QSortFilterProxyModel::lessThan(left, right);
-            switch (leftData.userType()) {
-            case QVariant::Invalid:
-                return (rightData.type() != QVariant::Invalid);
-            case QVariant::Int:
-                return leftData.toInt() < rightData.toInt();
-            case QVariant::UInt:
-                return leftData.toUInt() < rightData.toUInt();
-            case QVariant::LongLong:
-                return leftData.toLongLong() < rightData.toLongLong();
-            case QVariant::ULongLong:
-                return leftData.toULongLong() < rightData.toULongLong();
-            case QMetaType::Float:
-                return leftData.toFloat() < rightData.toFloat();
-            case QVariant::Double:
-                return leftData.toDouble() < rightData.toDouble();
-            case QVariant::Char:
-                return leftData.toChar() < rightData.toChar();
-            case QVariant::Date:
-                return leftData.toDate() < rightData.toDate();
-            case QVariant::Time:
-                return leftData.toTime() < rightData.toTime();
-            case QVariant::DateTime:
-                return leftData.toDateTime() < rightData.toDateTime();
-            case QVariant::String:
-            default:
-                if (this->isSortLocaleAware()) {
-                    return 
leftData.toString().localeAwareCompare(rightData.toString()) < 0;
-                } else {
-                    return leftData.toString().compare(rightData.toString(), 
this->sortCaseSensitivity()) < 0;
-                }
-            }
+            return lessThan(leftData, rightData);
         }
     }
     return false;
 }
 
+bool SKGSortFilterProxyModel::lessThan(const QVariant& iLeftData, const 
QVariant& iRightData) const
+{
+    switch (iLeftData.userType()) {
+    case QVariant::Invalid:
+        return (iRightData.type() != QVariant::Invalid);
+    case QVariant::Int:
+        return iLeftData.toInt() < iRightData.toInt();
+    case QVariant::UInt:
+        return iLeftData.toUInt() < iRightData.toUInt();
+    case QVariant::LongLong:
+        return iLeftData.toLongLong() < iRightData.toLongLong();
+    case QVariant::ULongLong:
+        return iLeftData.toULongLong() < iRightData.toULongLong();
+    case QMetaType::Float:
+        return iLeftData.toFloat() < iRightData.toFloat();
+    case QVariant::Double:
+        return iLeftData.toDouble() < iRightData.toDouble();
+    case QVariant::Char:
+        return iLeftData.toChar() < iRightData.toChar();
+    case QVariant::Date:
+        return iLeftData.toDate() < iRightData.toDate();
+    case QVariant::Time:
+        return iLeftData.toTime() < iRightData.toTime();
+    case QVariant::DateTime:
+        return iLeftData.toDateTime() < iRightData.toDateTime();
+    case QVariant::String:
+    default:
+        if (this->isSortLocaleAware()) {
+            return 
iLeftData.toString().localeAwareCompare(iRightData.toString()) < 0;
+        } else {
+            return iLeftData.toString().compare(iRightData.toString(), 
this->sortCaseSensitivity()) < 0;
+        }
+    }
+}
+
+bool SKGSortFilterProxyModel::moreThan(const QVariant& iLeftData, const 
QVariant& iRightData) const
+{
+    switch (iLeftData.userType()) {
+    case QVariant::Invalid:
+        return (iRightData.type() != QVariant::Invalid);
+    case QVariant::Int:
+        return iLeftData.toInt() > iRightData.toInt();
+    case QVariant::UInt:
+        return iLeftData.toUInt() > iRightData.toUInt();
+    case QVariant::LongLong:
+        return iLeftData.toLongLong() > iRightData.toLongLong();
+    case QVariant::ULongLong:
+        return iLeftData.toULongLong() > iRightData.toULongLong();
+    case QMetaType::Float:
+        return iLeftData.toFloat() > iRightData.toFloat();
+    case QVariant::Double:
+        return iLeftData.toDouble() > iRightData.toDouble();
+    case QVariant::Char:
+        return iLeftData.toChar() > iRightData.toChar();
+    case QVariant::Date:
+        return iLeftData.toDate() > iRightData.toDate();
+    case QVariant::Time:
+        return iLeftData.toTime() > iRightData.toTime();
+    case QVariant::DateTime:
+        return iLeftData.toDateTime() > iRightData.toDateTime();
+    case QVariant::String:
+    default:
+        if (this->isSortLocaleAware()) {
+            return 
iLeftData.toString().localeAwareCompare(iRightData.toString()) < 0;
+        } else {
+            return iLeftData.toString().compare(iRightData.toString(), 
this->sortCaseSensitivity()) > 0;
+        }
+    }
+}
+
 bool SKGSortFilterProxyModel::filterAcceptsRow(int source_row, const 
QModelIndex& source_parent) const
 {
     _SKGTRACEINFUNC(10);
@@ -214,11 +254,22 @@ bool SKGSortFilterProxyModel::filterAcceptsRowWords(int 
source_row, const QModel
         for (int w = 0; output && w < nbwords; ++w) {
             QString word = iWords.at(w);
             QString att;
+            QChar op = ':';
 
             // Check if the word follows the format attribut:value
             int pos = word.indexOf(':');
+            int pos2 = word.indexOf('<');
+            int pos3 = word.indexOf('>');
+            if (pos2 != -1 && (pos2 < pos || pos == -1)) {
+                pos = pos2;
+            }
+            if (pos3 != -1 && (pos3 < pos || pos == -1)) {
+                pos = pos3;
+            }
+
             if (pos != -1) {
                 att = word.left(pos);
+                op = word[pos];
                 word = word.right(word.count() - pos - 1);
             }
 
@@ -230,10 +281,19 @@ bool SKGSortFilterProxyModel::filterAcceptsRowWords(int 
source_row, const QModel
                 if (index0.isValid()) {
                     // Check if the header validates the attribut
                     if (att.isEmpty() || model->headerData(i, 
Qt::Horizontal).toString().startsWith(att, Qt::CaseInsensitive)) {
+
                         // Check if the value validate the attribute
-                        output = model->data(index0).toString().contains(word 
, Qt::CaseInsensitive);
-                        if (!output) {
-                            output = model->data(index0, 
Qt::UserRole).toString().contains(word , Qt::CaseInsensitive);
+                        if (op == ':') {
+                            output = 
model->data(index0).toString().contains(word , Qt::CaseInsensitive);
+                            if (!output) {
+                                output = model->data(index0, 
Qt::UserRole).toString().contains(word , Qt::CaseInsensitive);
+                            }
+                        } else if (op == '<') {
+                            QVariant var = model->data(index0, Qt::UserRole);
+                            output = lessThan(var, QVariant(word));
+                        } else if (op == '>') {
+                            QVariant var = model->data(index0, Qt::UserRole);
+                            output = moreThan(var, QVariant(word));
                         }
                     }
                 }
diff --git a/skgbasegui/skgsortfilterproxymodel.h 
b/skgbasegui/skgsortfilterproxymodel.h
index 864e754..6a39643 100644
--- a/skgbasegui/skgsortfilterproxymodel.h
+++ b/skgbasegui/skgsortfilterproxymodel.h
@@ -84,6 +84,9 @@ protected:
 private:
     bool filterAcceptsRowWords(int source_row, const QModelIndex& 
source_parent, const QStringList& iWords) const;
 
+    bool lessThan(const QVariant& iLeftData, const QVariant& iRightData) const;
+    bool moreThan(const QVariant& iLeftData, const QVariant& iRightData) const;
+
     SKGSortFilterProxyModelPrivate* const d;
 };
 

Reply via email to