This commit is contained in:
Martin Rotter 2014-10-29 16:38:23 +01:00
parent 57e05f34d8
commit f645917e77
7 changed files with 101 additions and 11 deletions

View File

@ -9,6 +9,7 @@ Fixed:
Added: Added:
<ul> <ul>
<li>Inline searching in feed/message list is now case insensitive and more polished (bug report #84).</li>
<li>Items in feed list (categories and feeds) now can be re-arranged via drag-drop functionality (issue report #91).</li> <li>Items in feed list (categories and feeds) now can be re-arranged via drag-drop functionality (issue report #91).</li>
<li>Tray icon now displays blue number of unread messages if any of those messages is newly downloaded from online feed (enhancement #87).</li> <li>Tray icon now displays blue number of unread messages if any of those messages is newly downloaded from online feed (enhancement #87).</li>
<li>Fixed issue request #95: items are now permanently hidden (not deleted from database) when "deleted" from recycle bin.</li> <li>Fixed issue request #95: items are now permanently hidden (not deleted from database) when "deleted" from recycle bin.</li>

View File

@ -42,6 +42,95 @@ FeedsProxyModel::~FeedsProxyModel() {
qDebug("Destroying FeedsProxyModel instance"); 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 { bool FeedsProxyModel::lessThan(const QModelIndex &left, const QModelIndex &right) const {
if (left.isValid() && right.isValid()) { if (left.isValid() && right.isValid()) {
// Make necessary castings. // Make necessary castings.

View File

@ -36,6 +36,8 @@ class FeedsProxyModel : public QSortFilterProxyModel {
return m_sourceModel; return m_sourceModel;
} }
QModelIndexList match(const QModelIndex &start, int role, const QVariant &value, int hits, Qt::MatchFlags flags) const;
// Maps list of indexes. // Maps list of indexes.
QModelIndexList mapListToSource(const QModelIndexList &indexes); QModelIndexList mapListToSource(const QModelIndexList &indexes);

View File

@ -68,7 +68,7 @@ QModelIndexList MessagesProxyModel::match(const QModelIndex &start, int role,
const QVariant &entered_value, int hits, Qt::MatchFlags flags) const { const QVariant &entered_value, int hits, Qt::MatchFlags flags) const {
QModelIndexList result; QModelIndexList result;
uint match_type = flags & 0x0F; uint match_type = flags & 0x0F;
Qt::CaseSensitivity case_sensitivity = Qt::CaseSensitive; Qt::CaseSensitivity case_sensitivity = Qt::CaseInsensitive;
bool wrap = flags & Qt::MatchWrap; bool wrap = flags & Qt::MatchWrap;
bool all_hits = (hits == -1); bool all_hits = (hits == -1);
QString entered_text; QString entered_text;
@ -83,14 +83,7 @@ QModelIndexList MessagesProxyModel::match(const QModelIndex &start, int role,
continue; continue;
} }
QVariant item_value; QVariant item_value = m_sourceModel->data(mapToSource(idx).row(), MSG_DB_TITLE_INDEX, role);
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 based matching. // QVariant based matching.
if (match_type == Qt::MatchExactly) { if (match_type == Qt::MatchExactly) {

View File

@ -74,7 +74,6 @@
#define FILTER_RIGHT_MARGIN 5 #define FILTER_RIGHT_MARGIN 5
#define FEEDS_VIEW_INDENTATION 10 #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 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_NAME_SETTINGS "config"

View File

@ -535,6 +535,7 @@ void FeedsView::selectNextItem() {
if (index_next.isValid()) { if (index_next.isValid()) {
setCurrentIndex(index_next); setCurrentIndex(index_next);
selectionModel()->select(index_next, QItemSelectionModel::Select | QItemSelectionModel::Rows); selectionModel()->select(index_next, QItemSelectionModel::Select | QItemSelectionModel::Rows);
setFocus();
} }
} }
@ -550,6 +551,7 @@ void FeedsView::selectPreviousItem() {
if (index_previous.isValid()) { if (index_previous.isValid()) {
setCurrentIndex(index_previous); setCurrentIndex(index_previous);
selectionModel()->select(index_previous, QItemSelectionModel::Select | QItemSelectionModel::Rows); selectionModel()->select(index_previous, QItemSelectionModel::Select | QItemSelectionModel::Rows);
setFocus();
} }
} }

View File

@ -59,6 +59,8 @@ void MessagesView::createConnections() {
} }
void MessagesView::keyboardSearch(const QString &search) { 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); setSelectionMode(QAbstractItemView::SingleSelection);
QTreeView::keyboardSearch(search); QTreeView::keyboardSearch(search);
setSelectionMode(QAbstractItemView::ExtendedSelection); setSelectionMode(QAbstractItemView::ExtendedSelection);
@ -432,6 +434,7 @@ void MessagesView::selectNextItem() {
if (index_next.isValid()) { if (index_next.isValid()) {
setCurrentIndex(index_next); setCurrentIndex(index_next);
selectionModel()->select(index_next, QItemSelectionModel::Select | QItemSelectionModel::Rows); selectionModel()->select(index_next, QItemSelectionModel::Select | QItemSelectionModel::Rows);
setFocus();
} }
} }
@ -441,6 +444,7 @@ void MessagesView::selectPreviousItem() {
if (index_previous.isValid()) { if (index_previous.isValid()) {
setCurrentIndex(index_previous); setCurrentIndex(index_previous);
selectionModel()->select(index_previous, QItemSelectionModel::Select | QItemSelectionModel::Rows); selectionModel()->select(index_previous, QItemSelectionModel::Select | QItemSelectionModel::Rows);
setFocus();
} }
} }