Skip to content

Commit

Permalink
fix #948, work on label performance
Browse files Browse the repository at this point in the history
  • Loading branch information
martinrotter committed Jun 9, 2023
1 parent a3442c1 commit a35be95
Show file tree
Hide file tree
Showing 12 changed files with 154 additions and 49 deletions.
8 changes: 8 additions & 0 deletions src/librssguard/core/message.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -143,6 +143,14 @@ Message Message::fromSqlRecord(const QSqlRecord& record, bool* result) {
message.m_accountId = record.value(MSG_DB_ACCOUNT_ID_INDEX).toInt();
message.m_customId = record.value(MSG_DB_CUSTOM_ID_INDEX).toString();
message.m_customHash = record.value(MSG_DB_CUSTOM_HASH_INDEX).toString();
message.m_assignedLabelsIds = record.value(MSG_DB_LABELS_IDS)
.toString()
.split('.',
#if QT_VERSION >= 0x050F00 // Qt >= 5.15.0
Qt::SplitBehaviorFlags::SkipEmptyParts);
#else
QString::SplitBehavior::SkipEmptyParts);
#endif

if (result != nullptr) {
*result = true;
Expand Down
2 changes: 2 additions & 0 deletions src/librssguard/core/message.h
Original file line number Diff line number Diff line change
Expand Up @@ -92,6 +92,8 @@ class RSSGUARD_DLLSPEC Message {
QList<Label*> m_assignedLabelsByFilter;
QList<Label*> m_deassignedLabelsByFilter;

QStringList m_assignedLabelsIds;

// Is true if "created" date was obtained directly
// from the feed, otherwise is false
bool m_createdFromFeed = false;
Expand Down
98 changes: 87 additions & 11 deletions src/librssguard/core/messagesmodel.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

#include "core/messagesmodel.h"

#include "3rd-party/boolinq/boolinq.h"
#include "core/messagesmodelcache.h"
#include "database/databasefactory.h"
#include "database/databasequeries.h"
Expand All @@ -24,24 +25,29 @@
MessagesModel::MessagesModel(QObject* parent)
: QSqlQueryModel(parent), m_view(nullptr), m_cache(new MessagesModelCache(this)),
m_messageHighlighter(MessageHighlighter::NoHighlighting), m_customDateFormat(QString()),
m_customTimeFormat(QString()), m_newerArticlesRelativeTime(-1), m_selectedItem(nullptr), m_displayFeedIcons(false),
m_customTimeFormat(QString()), m_newerArticlesRelativeTime(-1), m_selectedItem(nullptr),
m_unreadIconType(MessageUnreadIcon::Dot),
m_multilineListItems(qApp->settings()->value(GROUP(Messages), SETTING(Messages::MultilineArticleList)).toBool()) {
updateFeedIconsDisplay();
updateDateFormat();

setupFonts();
setupIcons();
setupHeaderData();
updateDateFormat();
updateFeedIconsDisplay();
loadMessages(nullptr);
}

MessagesModel::~MessagesModel() {
qDebugNN << LOGSEC_MESSAGEMODEL << "Destroying MessagesModel instance.";
}

#define RAD_COLOR 0, 180, 0

void MessagesModel::setupIcons() {
m_favoriteIcon = qApp->icons()->fromTheme(QSL("mail-mark-important"));
m_readIcon = qApp->icons()->fromTheme(QSL("mail-mark-read"));
m_unreadIcon = qApp->icons()->fromTheme(QSL("mail-mark-unread"));
m_unreadIcon = m_unreadIconType == MessageUnreadIcon::Dot ? generateUnreadIcon()
: qApp->icons()->fromTheme(QSL("mail-mark-unread"));
m_enclosuresIcon = qApp->icons()->fromTheme(QSL("mail-attachment"));

for (int i = int(MSG_SCORE_MIN); i <= int(MSG_SCORE_MAX); i += 10) {
Expand Down Expand Up @@ -82,6 +88,46 @@ QIcon MessagesModel::generateIconForScore(double score) {
return pix;
}

QIcon MessagesModel::generateUnreadIcon() {
QPointF center(64, 64);
qreal radius = 32;

QRadialGradient grad(center, radius);
grad.setColorAt(0.000, QColor(RAD_COLOR, 255));
grad.setColorAt(0.8, QColor(RAD_COLOR, 0.8 * 255));
grad.setColorAt(1.000, QColor(RAD_COLOR, 0.000));

QPen pen;
pen.setWidth(96);
pen.setBrush(grad);

QPixmap pix(128, 128);
pix.fill(Qt::GlobalColor::transparent);

QPainter painter(&pix);
painter.setRenderHint(QPainter::RenderHint::Antialiasing);
painter.setPen(pen);
painter.drawPoint(center);

return QIcon(pix);
}

QString MessagesModel::descriptionOfUnreadIcon(MessageUnreadIcon type) {
switch (type) {
case MessagesModel::MessageUnreadIcon::Dot:
return tr("dot");

case MessagesModel::MessageUnreadIcon::Envelope:
return tr("envelope");

case MessagesModel::MessageUnreadIcon::FeedIcon:
return tr("feed icon");

default:
return QString();
}
}

MessagesView* MessagesModel::view() const {
return m_view;
}
Expand Down Expand Up @@ -166,7 +212,7 @@ bool MessagesModel::setMessageImportantById(int id, RootItem::Importance importa
bool set = setData(index(i, MSG_DB_IMPORTANT_INDEX), int(important));

if (set) {
emit dataChanged(index(i, 0), index(i, MSG_DB_CUSTOM_HASH_INDEX));
emit dataChanged(index(i, 0), index(i, MSG_DB_LABELS_IDS));
}

return set;
Expand Down Expand Up @@ -214,7 +260,8 @@ void MessagesModel::updateDateFormat() {
}

void MessagesModel::updateFeedIconsDisplay() {
m_displayFeedIcons = qApp->settings()->value(GROUP(Messages), SETTING(Messages::DisplayFeedIconsInList)).toBool();
m_unreadIconType =
MessageUnreadIcon(qApp->settings()->value(GROUP(Messages), SETTING(Messages::UnreadIconType)).toInt());
}

void MessagesModel::reloadWholeLayout() {
Expand Down Expand Up @@ -344,6 +391,9 @@ QVariant MessagesModel::data(const QModelIndex& idx, int role) const {

return contents;
}
else if (index_column == MSG_DB_LABELS_IDS) {
return m_cache->containsData(idx.row()) ? m_cache->data(idx) : QSqlQueryModel::data(idx, role);
}
else if (index_column == MSG_DB_AUTHOR_INDEX) {
const QString author_name = QSqlQueryModel::data(idx, role).toString();

Expand Down Expand Up @@ -477,11 +527,13 @@ QVariant MessagesModel::data(const QModelIndex& idx, int role) const {
const int index_column = idx.column();

if (index_column == MSG_DB_READ_INDEX) {
if (m_displayFeedIcons && m_selectedItem != nullptr) {
if (m_unreadIconType == MessageUnreadIcon::FeedIcon && m_selectedItem != nullptr) {
QModelIndex idx_feedid = index(idx.row(), MSG_DB_FEED_CUSTOM_ID_INDEX);
QVariant dta =
m_cache->containsData(idx_feedid.row()) ? m_cache->data(idx_feedid) : QSqlQueryModel::data(idx_feedid);
QString feed_custom_id = dta.toString();

// TODO: Very slow and repeats itself.
auto acc = m_selectedItem->getParentServiceRoot()->feedIconForMessage(feed_custom_id);

if (acc.isNull()) {
Expand All @@ -496,7 +548,12 @@ QVariant MessagesModel::data(const QModelIndex& idx, int role) const {
QVariant dta =
m_cache->containsData(idx_read.row()) ? m_cache->data(idx_read) : QSqlQueryModel::data(idx_read);

return dta.toInt() == 1 ? m_readIcon : m_unreadIcon;
if (m_unreadIconType == MessageUnreadIcon::Dot) {
return dta.toInt() == 1 ? QVariant() : m_unreadIcon;
}
else {
return dta.toInt() == 1 ? m_readIcon : m_unreadIcon;
}
}
}
else if (index_column == MSG_DB_IMPORTANT_INDEX) {
Expand Down Expand Up @@ -529,7 +586,7 @@ QVariant MessagesModel::data(const QModelIndex& idx, int role) const {
}

bool MessagesModel::setMessageRead(int row_index, RootItem::ReadStatus read) {
if (data(row_index, MSG_DB_READ_INDEX, Qt::EditRole).toInt() == int(read)) {
if (data(row_index, MSG_DB_READ_INDEX, Qt::ItemDataRole::EditRole).toInt() == int(read)) {
// Read status is the same is the one currently set.
// In that case, no extra work is needed.
return true;
Expand Down Expand Up @@ -565,13 +622,32 @@ bool MessagesModel::setMessageRead(int row_index, RootItem::ReadStatus read) {

bool MessagesModel::setMessageReadById(int id, RootItem::ReadStatus read) {
for (int i = 0; i < rowCount(); i++) {
int found_id = data(i, MSG_DB_ID_INDEX, Qt::EditRole).toInt();
int found_id = data(i, MSG_DB_ID_INDEX, Qt::ItemDataRole::EditRole).toInt();

if (found_id == id) {
bool set = setData(index(i, MSG_DB_READ_INDEX), int(read));

if (set) {
emit dataChanged(index(i, 0), index(i, MSG_DB_CUSTOM_HASH_INDEX));
emit dataChanged(index(i, 0), index(i, MSG_DB_LABELS_IDS));
}

return set;
}
}

return false;
}

bool MessagesModel::setMessageLabelsById(int id, const QStringList& label_ids) {
for (int i = 0; i < rowCount(); i++) {
int found_id = data(i, MSG_DB_ID_INDEX, Qt::ItemDataRole::EditRole).toInt();

if (found_id == id) {
QString enc_ids = label_ids.isEmpty() ? QSL(".") : QSL(".") + label_ids.join('.') + QSL(".");
bool set = setData(index(i, MSG_DB_LABELS_IDS), enc_ids);

if (set) {
emit dataChanged(index(i, 0), index(i, MSG_DB_LABELS_IDS));
}

return set;
Expand Down
10 changes: 9 additions & 1 deletion src/librssguard/core/messagesmodel.h
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,10 @@ class MessagesModel : public QSqlQueryModel, public MessagesModelSqlLayer {
// for messages.
enum class MessageHighlighter { NoHighlighting = 100, HighlightUnread = 101, HighlightImportant = 102 };

enum class MessageUnreadIcon { Dot = 1, Envelope = 2, FeedIcon = 3 };

Q_ENUM(MessageUnreadIcon)

// Constructors and destructors.
explicit MessagesModel(QObject* parent = nullptr);
virtual ~MessagesModel();
Expand Down Expand Up @@ -74,13 +78,16 @@ class MessagesModel : public QSqlQueryModel, public MessagesModelSqlLayer {
void setView(MessagesView* new_view);

static QIcon generateIconForScore(double score);
static QIcon generateUnreadIcon();
static QString descriptionOfUnreadIcon(MessagesModel::MessageUnreadIcon type);

public slots:

// NOTE: These methods DO NOT actually change data in the DB, just in the model.
// These are particularly used by msg browser.
bool setMessageImportantById(int id, RootItem::Importance important);
bool setMessageReadById(int id, RootItem::ReadStatus read);
bool setMessageLabelsById(int id, const QStringList& label_ids);

private:
void setupHeaderData();
Expand All @@ -105,10 +112,11 @@ class MessagesModel : public QSqlQueryModel, public MessagesModelSqlLayer {
QIcon m_unreadIcon;
QIcon m_enclosuresIcon;
QList<QIcon> m_scoreIcons;
bool m_displayFeedIcons;
MessageUnreadIcon m_unreadIconType;
bool m_multilineListItems;
};

Q_DECLARE_METATYPE(MessagesModel::MessageHighlighter)
Q_DECLARE_METATYPE(MessagesModel::MessageUnreadIcon)

#endif // MESSAGESMODEL_H
4 changes: 4 additions & 0 deletions src/librssguard/gui/feedmessageviewer.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -261,6 +261,10 @@ void FeedMessageViewer::createConnections() {
&MessagePreviewer::markMessageImportant,
m_messagesView->sourceModel(),
&MessagesModel::setMessageImportantById);
connect(m_messagesBrowser,
&MessagePreviewer::setMessageLabelIds,
m_messagesView->sourceModel(),
&MessagesModel::setMessageLabelsById);

connect(m_messagesView, &MessagesView::currentMessageRemoved, this, &FeedMessageViewer::onMessageRemoved);
connect(m_messagesView, &MessagesView::currentMessageChanged, this, &FeedMessageViewer::displayMessage);
Expand Down
25 changes: 6 additions & 19 deletions src/librssguard/gui/messagepreviewer.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -191,10 +191,14 @@ void MessagePreviewer::switchLabel(bool assign) {

if (assign) {
lbl->assignToMessage(m_message);
m_message.m_assignedLabelsIds.append(lbl->customId());
}
else {
lbl->deassignFromMessage(m_message);
m_message.m_assignedLabelsIds.removeOne(lbl->customId());
}

emit setMessageLabelIds(m_message.m_id, m_message.m_assignedLabelsIds);
}

void MessagePreviewer::markMessageAsRead() {
Expand Down Expand Up @@ -276,39 +280,22 @@ void MessagePreviewer::updateLabels(bool only_clear) {

if (m_root.data() != nullptr && !m_root.data()->getParentServiceRoot()->labelsNode()->labels().isEmpty()) {
m_separator = m_toolBar->addSeparator();
QSqlDatabase database = qApp->database()->driver()->connection(metaObject()->className());
auto lbls = m_root.data()->getParentServiceRoot()->labelsNode()->labels();

for (auto* label : lbls) {
/*
LabelButton* btn_label = new LabelButton(this);
btn_label->setLabel(label);
btn_label->setCheckable(true);
btn_label->setIcon(Label::generateIcon(label->color()));
btn_label->setAutoRaise(false);
btn_label->setText();
btn_label->setToolButtonStyle(Qt::ToolButtonStyle(qApp->settings()
->value(GROUP(GUI), SETTING(GUI::ToolbarStyle))
.toInt()));
btn_label->setToolTip(label->title());
btn_label->setChecked();
*/

LabelToolbarAction* act_label = new LabelToolbarAction(this);

act_label->setIcon(Label::generateIcon(label->color()));
act_label->setText(QSL(" ") + label->title());
act_label->setCheckable(true);
act_label->setChecked(DatabaseQueries::isLabelAssignedToMessage(database, label, m_message));
act_label->setChecked(m_message.m_assignedLabelsIds.contains(label->customId()));
act_label->setToolTip(label->title());
act_label->setLabel(label);

m_toolBar->addAction(act_label);
m_btnLabels.append(act_label);

connect(act_label, &QAction::toggled, this, &MessagePreviewer::switchLabel);

m_btnLabels.append(act_label);
}
}
}
Expand Down
1 change: 1 addition & 0 deletions src/librssguard/gui/messagepreviewer.h
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,7 @@ class MessagePreviewer : public QWidget {
signals:
void markMessageRead(int id, RootItem::ReadStatus read);
void markMessageImportant(int id, RootItem::Importance important);
void setMessageLabelIds(int id, const QStringList& ids);

private:
void createConnections();
Expand Down
21 changes: 16 additions & 5 deletions src/librssguard/gui/settings/settingsfeedsmessages.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@

#include <QFontDialog>
#include <QLocale>
#include <QMetaEnum>
#include <QStringList>

SettingsFeedsMessages::SettingsFeedsMessages(Settings* settings, QWidget* parent)
Expand Down Expand Up @@ -65,7 +66,9 @@ SettingsFeedsMessages::SettingsFeedsMessages(Settings* settings, QWidget* parent
connect(m_ui->m_cbHideCountsIfNoUnread, &QCheckBox::toggled, this, &SettingsFeedsMessages::dirtifySettings);
connect(m_ui->m_checkAutoUpdate, &QCheckBox::toggled, this, &SettingsFeedsMessages::dirtifySettings);
connect(m_ui->m_checkAutoUpdateOnlyUnfocused, &QCheckBox::toggled, this, &SettingsFeedsMessages::dirtifySettings);
connect(m_ui->m_checkDisplayFeedIcons, &QCheckBox::toggled, this, &SettingsFeedsMessages::dirtifySettings);
connect(m_ui->m_cmbUnreadIconType, &QComboBox::currentIndexChanged, this, &SettingsFeedsMessages::dirtifySettings);
connect(m_ui->m_cmbUnreadIconType, &QComboBox::currentIndexChanged, this, &SettingsFeedsMessages::requireRestart);

connect(m_ui->m_checkKeppMessagesInTheMiddle, &QCheckBox::toggled, this, &SettingsFeedsMessages::dirtifySettings);
connect(m_ui->m_cbArticleViewerAlwaysVisible, &QCheckBox::toggled, this, &SettingsFeedsMessages::dirtifySettings);
connect(m_ui->m_checkMessagesDateTimeFormat, &QCheckBox::toggled, this, &SettingsFeedsMessages::dirtifySettings);
Expand Down Expand Up @@ -181,6 +184,14 @@ SettingsFeedsMessages::SettingsFeedsMessages(Settings* settings, QWidget* parent
}

m_ui->m_spinRelativeArticleTime->setValue(-1);

QMetaEnum enumer = QMetaEnum::fromType<MessagesModel::MessageUnreadIcon>();

for (int i = 0; i < enumer.keyCount(); i++) {
auto en = MessagesModel::MessageUnreadIcon(enumer.value(i));

m_ui->m_cmbUnreadIconType->addItem(MessagesModel::descriptionOfUnreadIcon(en), int(en));
}
}

SettingsFeedsMessages::~SettingsFeedsMessages() {
Expand Down Expand Up @@ -227,8 +238,9 @@ void SettingsFeedsMessages::loadSettings() {
->setChecked(settings()->value(GROUP(Feeds), SETTING(Feeds::OnlyBasicShortcutsInLists)).toBool());
m_ui->m_cbHideCountsIfNoUnread
->setChecked(settings()->value(GROUP(Feeds), SETTING(Feeds::HideCountsIfNoUnread)).toBool());
m_ui->m_checkDisplayFeedIcons
->setChecked(settings()->value(GROUP(Messages), SETTING(Messages::DisplayFeedIconsInList)).toBool());
m_ui->m_cmbUnreadIconType
->setCurrentIndex(m_ui->m_cmbUnreadIconType
->findData(settings()->value(GROUP(Messages), SETTING(Messages::UnreadIconType)).toInt()));
m_ui->m_checkBringToForegroundAfterMsgOpened
->setChecked(settings()
->value(GROUP(Messages), SETTING(Messages::BringAppToFrontAfterMessageOpenedExternally))
Expand Down Expand Up @@ -316,7 +328,7 @@ void SettingsFeedsMessages::saveSettings() {
settings()->setValue(GROUP(Feeds), Feeds::OnlyBasicShortcutsInLists, m_ui->m_cbListsRestrictedShortcuts->isChecked());

settings()->setValue(GROUP(Feeds), Feeds::HideCountsIfNoUnread, m_ui->m_cbHideCountsIfNoUnread->isChecked());
settings()->setValue(GROUP(Messages), Messages::DisplayFeedIconsInList, m_ui->m_checkDisplayFeedIcons->isChecked());
settings()->setValue(GROUP(Messages), Messages::UnreadIconType, m_ui->m_cmbUnreadIconType->currentData().toInt());
settings()->setValue(GROUP(Messages),
Messages::BringAppToFrontAfterMessageOpenedExternally,
m_ui->m_checkBringToForegroundAfterMsgOpened->isChecked());
Expand Down Expand Up @@ -368,7 +380,6 @@ void SettingsFeedsMessages::saveSettings() {
qApp->feedReader()->feedsModel()->reloadWholeLayout();

qApp->feedReader()->messagesModel()->updateDateFormat();
qApp->feedReader()->messagesModel()->updateFeedIconsDisplay();
qApp->feedReader()->messagesModel()->reloadWholeLayout();

onEndSaveSettings();
Expand Down
Loading

0 comments on commit a35be95

Please sign in to comment.