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 "<" and ">".</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 => 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>Date>2015-03-01 => Keep lines where Date attribute is greater than 2015-03-01</para></listitem> + <listitem><para>Amount<10 =>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><html><head/><body><p>Searching is case-insensitive. So table, Table, and TABLE are all the same.<br/>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). <br/>If you want to add (logical operator OR) some line, you must prefix your word by &quot;+&quot;.<br/>If you want to remove (logical operator NOT) some line, you must prefix your word by &quot;-&quot;.<br/>If you want to search only on one column, you must prefix your word by the column name like: col1:word.</p><p>If you want to use the character &quot;:&quot; in value, you must specify the column name like this: col1:value:rest.<br/>If you want to search for a phrase or something that contains spaces, you must put it in quotes, like: &quot;yes, this is a phrase&quot;.</p><p><span style=" font-weight:600; text-decoration: underline;">Examples:</span><br/>+val1 +val2 =&gt; Keep lines containing val1 OR val2<br/>+val1 -val2 =&gt; Keep lines containing val1 but NOT val2<br/>&quot;abc def&quot; =&gt; Keep lines containing the sentense &quot;abc def&quot; <br/>abc:def =&gt; Keep lines having a column name starting by abc and containing def<br/>:abc:def =&gt; Keep lines containing &quot;abc:def&quot;</p></body></html></string> + <string><html><head/><body><p>Searching is case-insensitive. So table, Table, and TABLE are all the same.<br/>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). <br/>If you want to add (logical operator OR) some line, you must prefix your word by &quot;+&quot;.<br/>If you want to remove (logical operator NOT) some line, you must prefix your word by &quot;-&quot;.<br/>If you want to search only on one column, you must prefix your word by the column name like: col1:word.<br/>If you want to use the character &quot;:&quot; in value, you must specify the column name like this: col1:value:rest.<br/>If you want to search for a phrase or something that contains spaces, you must put it in quotes, like: &quot;yes, this is a phrase&quot;.</p><p>You can also use operator &quot;&lt;&quot; and &quot;&gt;&quot;.</p><p><span style=" font-weight:600; text-decoration: underline;">Examples:</span><br/>+val1 +val2 =&gt; Keep lines containing val1 OR val2<br/>+val1 -val2 =&gt; Keep lines containing val1 but NOT val2<br/>&quot;abc def&quot; =&gt; Keep lines containing the sentense &quot;abc def&quot; <br/>abc:def =&gt; Keep lines having a column name starting by abc and containing def<br/>:abc:def =&gt; Keep lines containing &quot;abc:def&quot;<br/>Date&gt;2015-03-01 =&gt; Keep lines where Date attribute is greater than 2015-03-01<br/>Amount&lt;10 =&gt;Keep lines where Amount attribute is less than 10</p></body></html></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; };