diff --git a/resources/text/CHANGELOG b/resources/text/CHANGELOG
index f7d5a5f1c..6a305fa67 100644
--- a/resources/text/CHANGELOG
+++ b/resources/text/CHANGELOG
@@ -9,6 +9,7 @@ Fixed:
Added:
+- Inline searching in feed/message list is now case insensitive and more polished (bug report #84).
- Items in feed list (categories and feeds) now can be re-arranged via drag-drop functionality (issue report #91).
- Tray icon now displays blue number of unread messages if any of those messages is newly downloaded from online feed (enhancement #87).
- Fixed issue request #95: items are now permanently hidden (not deleted from database) when "deleted" from recycle bin.
diff --git a/src/core/feedsproxymodel.cpp b/src/core/feedsproxymodel.cpp
index 3d066f419..826ce6d92 100755
--- a/src/core/feedsproxymodel.cpp
+++ b/src/core/feedsproxymodel.cpp
@@ -42,6 +42,95 @@ FeedsProxyModel::~FeedsProxyModel() {
qDebug("Destroying FeedsProxyModel instance");
}
+QModelIndexList FeedsProxyModel::match(const QModelIndex &start, int role, const QVariant &value, int hits, Qt::MatchFlags flags) const {
+ QModelIndexList result;
+ uint matchType = flags & 0x0F;
+ Qt::CaseSensitivity cs = Qt::CaseInsensitive;
+ bool recurse = flags & Qt::MatchRecursive;
+ bool wrap = flags & Qt::MatchWrap;
+ bool allHits = (hits == -1);
+ QString entered_text;
+ QModelIndex p = parent(start);
+ int from = start.row();
+ int to = rowCount(p);
+
+ for (int i = 0; (wrap && i < 2) || (!wrap && i < 1); ++i) {
+ for (int r = from; (r < to) && (allHits || result.count() < hits); ++r) {
+ QModelIndex idx = index(r, start.column(), p);
+
+ if (!idx.isValid()) {
+ continue;
+ }
+
+ QModelIndex mapped_idx = mapToSource(idx);
+ QVariant item_value = m_sourceModel->data(m_sourceModel->index(mapped_idx.row(), FDS_MODEL_TITLE_INDEX, mapped_idx.parent()), role);
+
+ // QVariant based matching.
+ if (matchType == Qt::MatchExactly) {
+ if (value == item_value) {
+ result.append(idx);
+ }
+ }
+ // QString based matching.
+ else {
+ if (entered_text.isEmpty()) {
+ entered_text = value.toString();
+ }
+
+ QString item_text = item_value.toString();
+
+ switch (matchType) {
+ case Qt::MatchRegExp:
+ if (QRegExp(entered_text, cs).exactMatch(item_text)) {
+ result.append(idx);
+ }
+ break;
+
+ case Qt::MatchWildcard:
+ if (QRegExp(entered_text, cs, QRegExp::Wildcard).exactMatch(item_text)) {
+ result.append(idx);
+ }
+ break;
+
+ case Qt::MatchStartsWith:
+ if (item_text.startsWith(entered_text, cs)) {
+ result.append(idx);
+ }
+ break;
+
+ case Qt::MatchEndsWith:
+ if (item_text.endsWith(entered_text, cs)) {
+ result.append(idx);
+ }
+ break;
+
+ case Qt::MatchFixedString:
+ if (item_text.compare(entered_text, cs) == 0) {
+ result.append(idx);
+ }
+ break;
+
+ case Qt::MatchContains:
+ default:
+ if (item_text.contains(entered_text, cs)) {
+ result.append(idx);
+ }
+ break;
+ }
+ }
+
+ if (recurse && hasChildren(idx)) {
+ result += match(index(0, idx.column(), idx), role, (entered_text.isEmpty() ? value : entered_text), (allHits ? -1 : hits - result.count()), flags);
+ }
+ }
+
+ from = 0;
+ to = start.row();
+ }
+
+ return result;
+}
+
bool FeedsProxyModel::lessThan(const QModelIndex &left, const QModelIndex &right) const {
if (left.isValid() && right.isValid()) {
// Make necessary castings.
diff --git a/src/core/feedsproxymodel.h b/src/core/feedsproxymodel.h
index 5bc54dd6d..a0aa10a4a 100755
--- a/src/core/feedsproxymodel.h
+++ b/src/core/feedsproxymodel.h
@@ -36,6 +36,8 @@ class FeedsProxyModel : public QSortFilterProxyModel {
return m_sourceModel;
}
+ QModelIndexList match(const QModelIndex &start, int role, const QVariant &value, int hits, Qt::MatchFlags flags) const;
+
// Maps list of indexes.
QModelIndexList mapListToSource(const QModelIndexList &indexes);
diff --git a/src/core/messagesproxymodel.cpp b/src/core/messagesproxymodel.cpp
index fd8ab02b4..1f0f48ab3 100644
--- a/src/core/messagesproxymodel.cpp
+++ b/src/core/messagesproxymodel.cpp
@@ -68,7 +68,7 @@ QModelIndexList MessagesProxyModel::match(const QModelIndex &start, int role,
const QVariant &entered_value, int hits, Qt::MatchFlags flags) const {
QModelIndexList result;
uint match_type = flags & 0x0F;
- Qt::CaseSensitivity case_sensitivity = Qt::CaseSensitive;
+ Qt::CaseSensitivity case_sensitivity = Qt::CaseInsensitive;
bool wrap = flags & Qt::MatchWrap;
bool all_hits = (hits == -1);
QString entered_text;
@@ -83,14 +83,7 @@ QModelIndexList MessagesProxyModel::match(const QModelIndex &start, int role,
continue;
}
- QVariant item_value;
-
- if (start.column() == MSG_DB_ID_INDEX) {
- item_value = m_sourceModel->data(mapToSource(idx).row(), MSG_DB_TITLE_INDEX);
- }
- else {
- item_value = data(idx, role);
- }
+ QVariant item_value = m_sourceModel->data(mapToSource(idx).row(), MSG_DB_TITLE_INDEX, role);
// QVariant based matching.
if (match_type == Qt::MatchExactly) {
diff --git a/src/definitions/definitions.h.in b/src/definitions/definitions.h.in
index 81d91305c..10912ade4 100755
--- a/src/definitions/definitions.h.in
+++ b/src/definitions/definitions.h.in
@@ -74,8 +74,7 @@
#define FILTER_RIGHT_MARGIN 5
#define FEEDS_VIEW_INDENTATION 10
#define ACCEPT_HEADER_FOR_FEED_DOWNLOADER "application/atom+xml,application/xml;q=0.9,text/xml;q=0.8,*/*;q=0.7"
-
-#define MIME_TYPE_ITEM_POINTER "rssguard/itempointer"
+#define MIME_TYPE_ITEM_POINTER "rssguard/itempointer"
#define BACKUP_NAME_SETTINGS "config"
#define BACKUP_SUFFIX_SETTINGS ".ini.backup"
diff --git a/src/gui/feedsview.cpp b/src/gui/feedsview.cpp
index c35ec6dad..376f420ae 100755
--- a/src/gui/feedsview.cpp
+++ b/src/gui/feedsview.cpp
@@ -535,6 +535,7 @@ void FeedsView::selectNextItem() {
if (index_next.isValid()) {
setCurrentIndex(index_next);
selectionModel()->select(index_next, QItemSelectionModel::Select | QItemSelectionModel::Rows);
+ setFocus();
}
}
@@ -550,6 +551,7 @@ void FeedsView::selectPreviousItem() {
if (index_previous.isValid()) {
setCurrentIndex(index_previous);
selectionModel()->select(index_previous, QItemSelectionModel::Select | QItemSelectionModel::Rows);
+ setFocus();
}
}
diff --git a/src/gui/messagesview.cpp b/src/gui/messagesview.cpp
index 642dd8061..eddf8e93f 100755
--- a/src/gui/messagesview.cpp
+++ b/src/gui/messagesview.cpp
@@ -59,6 +59,8 @@ void MessagesView::createConnections() {
}
void MessagesView::keyboardSearch(const QString &search) {
+ // WARNING: This is quite hacky way how to force selection of next item even
+ // with extended selection enabled.
setSelectionMode(QAbstractItemView::SingleSelection);
QTreeView::keyboardSearch(search);
setSelectionMode(QAbstractItemView::ExtendedSelection);
@@ -432,6 +434,7 @@ void MessagesView::selectNextItem() {
if (index_next.isValid()) {
setCurrentIndex(index_next);
selectionModel()->select(index_next, QItemSelectionModel::Select | QItemSelectionModel::Rows);
+ setFocus();
}
}
@@ -441,6 +444,7 @@ void MessagesView::selectPreviousItem() {
if (index_previous.isValid()) {
setCurrentIndex(index_previous);
selectionModel()->select(index_previous, QItemSelectionModel::Select | QItemSelectionModel::Rows);
+ setFocus();
}
}