Fixed #84.
This commit is contained in:
parent
57e05f34d8
commit
f645917e77
@ -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>
|
||||||
|
@ -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.
|
||||||
|
@ -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);
|
||||||
|
|
||||||
|
@ -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) {
|
||||||
|
@ -74,8 +74,7 @@
|
|||||||
#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"
|
||||||
#define BACKUP_SUFFIX_SETTINGS ".ini.backup"
|
#define BACKUP_SUFFIX_SETTINGS ".ini.backup"
|
||||||
|
@ -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();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -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();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user