greatly enhanced RTL customization, ability to setup RTL behavior for individual feeds, inspired by #1653
This commit is contained in:
parent
e54e7ac134
commit
e80db5bc4c
21 changed files with 158 additions and 55 deletions
|
@ -8,6 +8,7 @@
|
||||||
<file>sql/db_update_mysql_5_6.sql</file>
|
<file>sql/db_update_mysql_5_6.sql</file>
|
||||||
<file>sql/db_update_mysql_6_7.sql</file>
|
<file>sql/db_update_mysql_6_7.sql</file>
|
||||||
<file>sql/db_update_mysql_7_8.sql</file>
|
<file>sql/db_update_mysql_7_8.sql</file>
|
||||||
|
<file>sql/db_update_mysql_8_9.sql</file>
|
||||||
|
|
||||||
<file>sql/db_init_sqlite.sql</file>
|
<file>sql/db_init_sqlite.sql</file>
|
||||||
<file>sql/db_update_sqlite_1_2.sql</file>
|
<file>sql/db_update_sqlite_1_2.sql</file>
|
||||||
|
@ -17,5 +18,6 @@
|
||||||
<file>sql/db_update_sqlite_5_6.sql</file>
|
<file>sql/db_update_sqlite_5_6.sql</file>
|
||||||
<file>sql/db_update_sqlite_6_7.sql</file>
|
<file>sql/db_update_sqlite_6_7.sql</file>
|
||||||
<file>sql/db_update_sqlite_7_8.sql</file>
|
<file>sql/db_update_sqlite_7_8.sql</file>
|
||||||
|
<file>sql/db_update_sqlite_8_9.sql</file>
|
||||||
</qresource>
|
</qresource>
|
||||||
</RCC>
|
</RCC>
|
|
@ -43,7 +43,7 @@ CREATE TABLE Feeds (
|
||||||
update_interval INTEGER NOT NULL DEFAULT 900 CHECK (update_interval >= 1),
|
update_interval INTEGER NOT NULL DEFAULT 900 CHECK (update_interval >= 1),
|
||||||
is_off INTEGER NOT NULL DEFAULT 0 CHECK (is_off >= 0 AND is_off <= 1),
|
is_off INTEGER NOT NULL DEFAULT 0 CHECK (is_off >= 0 AND is_off <= 1),
|
||||||
is_quiet INTEGER NOT NULL DEFAULT 0 CHECK (is_quiet >= 0 AND is_quiet <= 1),
|
is_quiet INTEGER NOT NULL DEFAULT 0 CHECK (is_quiet >= 0 AND is_quiet <= 1),
|
||||||
is_rtl INTEGER NOT NULL DEFAULT 0 CHECK (is_rtl >= 0 AND is_rtl <= 1),
|
is_rtl INTEGER NOT NULL DEFAULT 0 CHECK (is_rtl >= 0 AND is_rtl <= 1024),
|
||||||
|
|
||||||
add_any_datetime_articles INTEGER NOT NULL DEFAULT 0 CHECK (add_any_datetime_articles >= 0 AND add_any_datetime_articles <= 1),
|
add_any_datetime_articles INTEGER NOT NULL DEFAULT 0 CHECK (add_any_datetime_articles >= 0 AND add_any_datetime_articles <= 1),
|
||||||
datetime_to_avoid BIGINT NOT NULL DEFAULT 0 CHECK (datetime_to_avoid >= 0),
|
datetime_to_avoid BIGINT NOT NULL DEFAULT 0 CHECK (datetime_to_avoid >= 0),
|
||||||
|
|
7
resources/sql/db_update_mysql_8_9.sql
Normal file
7
resources/sql/db_update_mysql_8_9.sql
Normal file
|
@ -0,0 +1,7 @@
|
||||||
|
USE ##;
|
||||||
|
-- !
|
||||||
|
SET FOREIGN_KEY_CHECKS = 0;
|
||||||
|
-- !
|
||||||
|
!! db_update_sqlite_8_9.sql
|
||||||
|
-- !
|
||||||
|
SET FOREIGN_KEY_CHECKS = 1;
|
40
resources/sql/db_update_sqlite_8_9.sql
Normal file
40
resources/sql/db_update_sqlite_8_9.sql
Normal file
|
@ -0,0 +1,40 @@
|
||||||
|
ALTER TABLE Feeds RENAME TO backup_Feeds;
|
||||||
|
-- !
|
||||||
|
CREATE TABLE Feeds (
|
||||||
|
id $$,
|
||||||
|
ordr INTEGER NOT NULL CHECK (ordr >= 0),
|
||||||
|
title TEXT NOT NULL CHECK (title != ''),
|
||||||
|
description TEXT,
|
||||||
|
date_created BIGINT,
|
||||||
|
icon ^^,
|
||||||
|
category INTEGER NOT NULL CHECK (category >= -1), /* Physical category ID, also root feeds contain -1 here. */
|
||||||
|
source TEXT,
|
||||||
|
update_type INTEGER NOT NULL CHECK (update_type >= 0),
|
||||||
|
update_interval INTEGER NOT NULL DEFAULT 900 CHECK (update_interval >= 1),
|
||||||
|
is_off INTEGER NOT NULL DEFAULT 0 CHECK (is_off >= 0 AND is_off <= 1),
|
||||||
|
is_quiet INTEGER NOT NULL DEFAULT 0 CHECK (is_quiet >= 0 AND is_quiet <= 1),
|
||||||
|
is_rtl INTEGER NOT NULL DEFAULT 0 CHECK (is_rtl >= 0 AND is_rtl <= 1024),
|
||||||
|
|
||||||
|
add_any_datetime_articles INTEGER NOT NULL DEFAULT 0 CHECK (add_any_datetime_articles >= 0 AND add_any_datetime_articles <= 1),
|
||||||
|
datetime_to_avoid BIGINT NOT NULL DEFAULT 0 CHECK (datetime_to_avoid >= 0),
|
||||||
|
|
||||||
|
keep_article_customize INTEGER NOT NULL DEFAULT 0 CHECK (keep_article_customize >= 0 AND keep_article_customize <= 1),
|
||||||
|
keep_article_count INTEGER NOT NULL DEFAULT 0 CHECK (keep_article_count >= 0),
|
||||||
|
keep_unread_articles INTEGER NOT NULL DEFAULT 1 CHECK (keep_unread_articles >= 0 AND keep_unread_articles <= 1),
|
||||||
|
keep_starred_articles INTEGER NOT NULL DEFAULT 1 CHECK (keep_starred_articles >= 0 AND keep_starred_articles <= 1),
|
||||||
|
recycle_articles INTEGER NOT NULL DEFAULT 0 CHECK (recycle_articles >= 0 AND recycle_articles <= 1),
|
||||||
|
|
||||||
|
open_articles INTEGER NOT NULL DEFAULT 0 CHECK (open_articles >= 0 AND open_articles <= 1),
|
||||||
|
account_id INTEGER NOT NULL,
|
||||||
|
custom_id TEXT NOT NULL CHECK (custom_id != ''), /* Custom ID cannot be empty, it must contain either service-specific ID, or Feeds/id. */
|
||||||
|
/* Custom column for (serialized) custom account-specific data. */
|
||||||
|
custom_data TEXT,
|
||||||
|
|
||||||
|
FOREIGN KEY (account_id) REFERENCES Accounts (id) ON DELETE CASCADE
|
||||||
|
);
|
||||||
|
-- !
|
||||||
|
INSERT INTO Feeds (id, ordr, title, description, date_created, icon, category, source, update_type, update_interval, is_off, is_quiet, is_rtl, add_any_datetime_articles, datetime_to_avoid, keep_article_customize, keep_article_count, keep_unread_articles, keep_starred_articles, recycle_articles, open_articles, account_id, custom_id, custom_data)
|
||||||
|
SELECT id, ordr, title, description, date_created, icon, category, source, update_type, update_interval, is_off, is_quiet, is_rtl, add_any_datetime_articles, datetime_to_avoid, keep_article_customize, keep_article_count, keep_unread_articles, keep_starred_articles, recycle_articles, open_articles, account_id, custom_id, custom_data
|
||||||
|
FROM backup_Feeds;
|
||||||
|
-- !
|
||||||
|
DROP TABLE backup_Feeds;
|
|
@ -297,6 +297,7 @@ set(SOURCES
|
||||||
services/abstract/category.h
|
services/abstract/category.h
|
||||||
services/abstract/feed.cpp
|
services/abstract/feed.cpp
|
||||||
services/abstract/feed.h
|
services/abstract/feed.h
|
||||||
|
services/abstract/feedrtlbehavior.h
|
||||||
services/abstract/gui/accountdetails.cpp
|
services/abstract/gui/accountdetails.cpp
|
||||||
services/abstract/gui/accountdetails.h
|
services/abstract/gui/accountdetails.h
|
||||||
services/abstract/gui/authenticationdetails.cpp
|
services/abstract/gui/authenticationdetails.cpp
|
||||||
|
|
|
@ -111,7 +111,8 @@ Message::Message() {
|
||||||
m_categories = QList<MessageCategory>();
|
m_categories = QList<MessageCategory>();
|
||||||
m_accountId = m_id = 0;
|
m_accountId = m_id = 0;
|
||||||
m_score = 0.0;
|
m_score = 0.0;
|
||||||
m_isRead = m_isImportant = m_isDeleted = m_isRtl = false;
|
m_isRead = m_isImportant = m_isDeleted = false;
|
||||||
|
m_rtlBehavior = RtlBehavior::NoRtl;
|
||||||
m_assignedLabels = QList<Label*>();
|
m_assignedLabels = QList<Label*>();
|
||||||
m_assignedLabelsByFilter = QList<Label*>();
|
m_assignedLabelsByFilter = QList<Label*>();
|
||||||
m_deassignedLabelsByFilter = QList<Label*>();
|
m_deassignedLabelsByFilter = QList<Label*>();
|
||||||
|
@ -188,7 +189,7 @@ QJsonObject Message::toJson() const {
|
||||||
obj.insert(QSL("custom_hash"), m_customHash);
|
obj.insert(QSL("custom_hash"), m_customHash);
|
||||||
obj.insert(QSL("feed_custom_id"), m_feedId);
|
obj.insert(QSL("feed_custom_id"), m_feedId);
|
||||||
obj.insert(QSL("feed_title"), m_feedTitle);
|
obj.insert(QSL("feed_title"), m_feedTitle);
|
||||||
obj.insert(QSL("is_rtl"), m_isRtl);
|
obj.insert(QSL("is_rtl"), int(m_rtlBehavior));
|
||||||
obj.insert(QSL("enclosures"), Enclosures::encodeEnclosuresToJson(m_enclosures));
|
obj.insert(QSL("enclosures"), Enclosures::encodeEnclosuresToJson(m_enclosures));
|
||||||
|
|
||||||
return obj;
|
return obj;
|
||||||
|
@ -218,7 +219,7 @@ Message Message::fromSqlRecord(const QSqlRecord& record, bool* result) {
|
||||||
message.m_contents = record.value(MSG_DB_CONTENTS_INDEX).toString();
|
message.m_contents = record.value(MSG_DB_CONTENTS_INDEX).toString();
|
||||||
message.m_enclosures = Enclosures::decodeEnclosuresFromString(record.value(MSG_DB_ENCLOSURES_INDEX).toString());
|
message.m_enclosures = Enclosures::decodeEnclosuresFromString(record.value(MSG_DB_ENCLOSURES_INDEX).toString());
|
||||||
message.m_score = record.value(MSG_DB_SCORE_INDEX).toDouble();
|
message.m_score = record.value(MSG_DB_SCORE_INDEX).toDouble();
|
||||||
message.m_isRtl = record.value(MSG_DB_FEED_IS_RTL_INDEX).toBool();
|
message.m_rtlBehavior = record.value(MSG_DB_FEED_IS_RTL_INDEX).value<RtlBehavior>();
|
||||||
message.m_accountId = record.value(MSG_DB_ACCOUNT_ID_INDEX).toInt();
|
message.m_accountId = record.value(MSG_DB_ACCOUNT_ID_INDEX).toInt();
|
||||||
message.m_customId = record.value(MSG_DB_CUSTOM_ID_INDEX).toString();
|
message.m_customId = record.value(MSG_DB_CUSTOM_ID_INDEX).toString();
|
||||||
message.m_customHash = record.value(MSG_DB_CUSTOM_HASH_INDEX).toString();
|
message.m_customHash = record.value(MSG_DB_CUSTOM_HASH_INDEX).toString();
|
||||||
|
@ -258,7 +259,7 @@ QString Message::generateRawAtomContents(const Message& msg) {
|
||||||
|
|
||||||
QDataStream& operator<<(QDataStream& out, const Message& my_obj) {
|
QDataStream& operator<<(QDataStream& out, const Message& my_obj) {
|
||||||
out << my_obj.m_accountId << my_obj.m_customHash << my_obj.m_customId << my_obj.m_feedId << my_obj.m_id
|
out << my_obj.m_accountId << my_obj.m_customHash << my_obj.m_customId << my_obj.m_feedId << my_obj.m_id
|
||||||
<< my_obj.m_isImportant << my_obj.m_isRead << my_obj.m_isDeleted << my_obj.m_score << my_obj.m_isRtl;
|
<< my_obj.m_isImportant << my_obj.m_isRead << my_obj.m_isDeleted << my_obj.m_score << my_obj.m_rtlBehavior;
|
||||||
|
|
||||||
return out;
|
return out;
|
||||||
}
|
}
|
||||||
|
@ -272,7 +273,7 @@ QDataStream& operator>>(QDataStream& in, Message& my_obj) {
|
||||||
bool is_important;
|
bool is_important;
|
||||||
bool is_read;
|
bool is_read;
|
||||||
bool is_deleted;
|
bool is_deleted;
|
||||||
bool is_rtl;
|
RtlBehavior is_rtl;
|
||||||
double score;
|
double score;
|
||||||
|
|
||||||
in >> account_id >> custom_hash >> custom_id >> feed_id >> id >> is_important >> is_read >> is_deleted >> score >>
|
in >> account_id >> custom_hash >> custom_id >> feed_id >> id >> is_important >> is_read >> is_deleted >> score >>
|
||||||
|
@ -287,7 +288,7 @@ QDataStream& operator>>(QDataStream& in, Message& my_obj) {
|
||||||
my_obj.m_isRead = is_read;
|
my_obj.m_isRead = is_read;
|
||||||
my_obj.m_isDeleted = is_deleted;
|
my_obj.m_isDeleted = is_deleted;
|
||||||
my_obj.m_score = score;
|
my_obj.m_score = score;
|
||||||
my_obj.m_isRtl = is_rtl;
|
my_obj.m_rtlBehavior = is_rtl;
|
||||||
|
|
||||||
return in;
|
return in;
|
||||||
}
|
}
|
||||||
|
|
|
@ -5,6 +5,8 @@
|
||||||
|
|
||||||
// #include "definitions/definitions.h"
|
// #include "definitions/definitions.h"
|
||||||
|
|
||||||
|
#include "services/abstract/feedrtlbehavior.h"
|
||||||
|
|
||||||
#include <QDataStream>
|
#include <QDataStream>
|
||||||
#include <QDateTime>
|
#include <QDateTime>
|
||||||
#include <QSqlRecord>
|
#include <QSqlRecord>
|
||||||
|
@ -84,7 +86,7 @@ class RSSGUARD_DLLSPEC Message {
|
||||||
bool m_isImportant;
|
bool m_isImportant;
|
||||||
bool m_isDeleted;
|
bool m_isDeleted;
|
||||||
double m_score;
|
double m_score;
|
||||||
bool m_isRtl;
|
RtlBehavior m_rtlBehavior;
|
||||||
QList<Enclosure> m_enclosures;
|
QList<Enclosure> m_enclosures;
|
||||||
|
|
||||||
// List of assigned labels.
|
// List of assigned labels.
|
||||||
|
|
|
@ -437,12 +437,15 @@ QVariant MessagesModel::data(const QModelIndex& idx, int role) const {
|
||||||
return Qt::LayoutDirection::LayoutDirectionAuto;
|
return Qt::LayoutDirection::LayoutDirectionAuto;
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
return (m_cache->containsData(idx.row())
|
RtlBehavior rtl_mode =
|
||||||
? m_cache->data(index(idx.row(), MSG_DB_FEED_IS_RTL_INDEX))
|
(m_cache->containsData(idx.row())
|
||||||
: QSqlQueryModel::data(index(idx.row(), MSG_DB_FEED_IS_RTL_INDEX), Qt::ItemDataRole::EditRole))
|
? m_cache->data(index(idx.row(), MSG_DB_FEED_IS_RTL_INDEX))
|
||||||
.toInt() == 0
|
: QSqlQueryModel::data(index(idx.row(), MSG_DB_FEED_IS_RTL_INDEX), Qt::ItemDataRole::EditRole))
|
||||||
? Qt::LayoutDirection::LayoutDirectionAuto
|
.value<RtlBehavior>();
|
||||||
: Qt::LayoutDirection::RightToLeft;
|
|
||||||
|
return (rtl_mode == RtlBehavior::Everywhere || rtl_mode == RtlBehavior::EverywhereExceptFeedList)
|
||||||
|
? Qt::LayoutDirection::RightToLeft
|
||||||
|
: Qt::LayoutDirection::LayoutDirectionAuto;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -2698,7 +2698,7 @@ void DatabaseQueries::createOverwriteFeed(const QSqlDatabase& db, Feed* feed, in
|
||||||
q.bindValue(QSL(":is_off"), feed->isSwitchedOff());
|
q.bindValue(QSL(":is_off"), feed->isSwitchedOff());
|
||||||
q.bindValue(QSL(":is_quiet"), feed->isQuiet());
|
q.bindValue(QSL(":is_quiet"), feed->isQuiet());
|
||||||
q.bindValue(QSL(":open_articles"), feed->openArticlesDirectly());
|
q.bindValue(QSL(":open_articles"), feed->openArticlesDirectly());
|
||||||
q.bindValue(QSL(":is_rtl"), feed->isRtl());
|
q.bindValue(QSL(":is_rtl"), int(feed->rtlBehavior()));
|
||||||
|
|
||||||
const Feed::ArticleIgnoreLimit art = feed->articleIgnoreLimit();
|
const Feed::ArticleIgnoreLimit art = feed->articleIgnoreLimit();
|
||||||
|
|
||||||
|
|
|
@ -385,7 +385,7 @@ Assignment DatabaseQueries::getFeeds(const QSqlDatabase& db,
|
||||||
feed->setAutoUpdateInterval(query.value(FDS_DB_UPDATE_INTERVAL_INDEX).toInt());
|
feed->setAutoUpdateInterval(query.value(FDS_DB_UPDATE_INTERVAL_INDEX).toInt());
|
||||||
feed->setIsSwitchedOff(query.value(FDS_DB_IS_OFF_INDEX).toBool());
|
feed->setIsSwitchedOff(query.value(FDS_DB_IS_OFF_INDEX).toBool());
|
||||||
feed->setIsQuiet(query.value(FDS_DB_IS_QUIET_INDEX).toBool());
|
feed->setIsQuiet(query.value(FDS_DB_IS_QUIET_INDEX).toBool());
|
||||||
feed->setIsRtl(query.value(FDS_DB_IS_RTL_INDEX).toBool());
|
feed->setRtlBehavior(query.value(FDS_DB_IS_RTL_INDEX).value<RtlBehavior>());
|
||||||
|
|
||||||
Feed::ArticleIgnoreLimit art;
|
Feed::ArticleIgnoreLimit art;
|
||||||
|
|
||||||
|
|
|
@ -230,7 +230,7 @@
|
||||||
#define APP_DB_SQLITE_FILE "database.db"
|
#define APP_DB_SQLITE_FILE "database.db"
|
||||||
|
|
||||||
// Keep this in sync with schema versions declared in SQL initialization code.
|
// Keep this in sync with schema versions declared in SQL initialization code.
|
||||||
#define APP_DB_SCHEMA_VERSION "8"
|
#define APP_DB_SCHEMA_VERSION "9"
|
||||||
#define APP_DB_UPDATE_FILE_PATTERN "db_update_%1_%2_%3.sql"
|
#define APP_DB_UPDATE_FILE_PATTERN "db_update_%1_%2_%3.sql"
|
||||||
#define APP_DB_COMMENT_SPLIT "-- !\n"
|
#define APP_DB_COMMENT_SPLIT "-- !\n"
|
||||||
#define APP_DB_INCLUDE_PLACEHOLDER "!!"
|
#define APP_DB_INCLUDE_PLACEHOLDER "!!"
|
||||||
|
|
|
@ -592,19 +592,24 @@ void MessagesView::loadItem(RootItem* item) {
|
||||||
|
|
||||||
if (switch_entire_rtl_list && item != nullptr) {
|
if (switch_entire_rtl_list && item != nullptr) {
|
||||||
if (item->kind() == RootItem::Kind::Feed) {
|
if (item->kind() == RootItem::Kind::Feed) {
|
||||||
setLayoutDirection(item->toFeed()->isRtl() ? Qt::LayoutDirection::RightToLeft : Qt::LayoutDirection::LeftToRight);
|
auto* fd = item->toFeed();
|
||||||
|
setLayoutDirection((fd->rtlBehavior() == RtlBehavior::Everywhere ||
|
||||||
|
fd->rtlBehavior() == RtlBehavior::EverywhereExceptFeedList)
|
||||||
|
? Qt::LayoutDirection::RightToLeft
|
||||||
|
: Qt::LayoutDirection::LayoutDirectionAuto);
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
auto fds = item->getSubTreeFeeds();
|
auto fds = item->getSubTreeFeeds();
|
||||||
bool all_feeds_rtl = !fds.isEmpty() && std::all_of(fds.begin(), fds.end(), [](Feed* fd) {
|
bool all_feeds_rtl = !fds.isEmpty() && std::all_of(fds.begin(), fds.end(), [](Feed* fd) {
|
||||||
return fd->isRtl();
|
return fd->rtlBehavior() == RtlBehavior::Everywhere ||
|
||||||
|
fd->rtlBehavior() == RtlBehavior::EverywhereExceptFeedList;
|
||||||
});
|
});
|
||||||
|
|
||||||
setLayoutDirection(all_feeds_rtl ? Qt::LayoutDirection::RightToLeft : Qt::LayoutDirection::LeftToRight);
|
setLayoutDirection(all_feeds_rtl ? Qt::LayoutDirection::RightToLeft : Qt::LayoutDirection::LayoutDirectionAuto);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
setLayoutDirection(Qt::LayoutDirection::LeftToRight);
|
setLayoutDirection(Qt::LayoutDirection::LayoutDirectionAuto);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Messages are loaded, make sure that previously
|
// Messages are loaded, make sure that previously
|
||||||
|
|
|
@ -369,7 +369,7 @@ void WebBrowser::setFullArticleHtml(const QObject* sndr, const QString& url, con
|
||||||
full_article.m_isImportant = displayed_article.m_isImportant;
|
full_article.m_isImportant = displayed_article.m_isImportant;
|
||||||
full_article.m_isDeleted = displayed_article.m_isDeleted;
|
full_article.m_isDeleted = displayed_article.m_isDeleted;
|
||||||
full_article.m_score = displayed_article.m_score;
|
full_article.m_score = displayed_article.m_score;
|
||||||
full_article.m_isRtl = displayed_article.m_isRtl;
|
full_article.m_rtlBehavior = displayed_article.m_rtlBehavior;
|
||||||
full_article.m_enclosures = displayed_article.m_enclosures;
|
full_article.m_enclosures = displayed_article.m_enclosures;
|
||||||
|
|
||||||
loadMessages({full_article}, m_root);
|
loadMessages({full_article}, m_root);
|
||||||
|
|
|
@ -295,7 +295,11 @@ void TextBrowserViewer::loadMessages(const QList<Message>& messages, RootItem* r
|
||||||
setHtml(html_messages.m_html, html_messages.m_baseUrl);
|
setHtml(html_messages.m_html, html_messages.m_baseUrl);
|
||||||
|
|
||||||
QTextOption op;
|
QTextOption op;
|
||||||
op.setTextDirection(messages.at(0).m_isRtl ? Qt::LayoutDirection::RightToLeft : Qt::LayoutDirection::LeftToRight);
|
op.setTextDirection((messages.at(0).m_rtlBehavior == RtlBehavior::Everywhere ||
|
||||||
|
messages.at(0).m_rtlBehavior == RtlBehavior::EverywhereExceptFeedList ||
|
||||||
|
messages.at(0).m_rtlBehavior == RtlBehavior::OnlyViewer)
|
||||||
|
? Qt::LayoutDirection::RightToLeft
|
||||||
|
: Qt::LayoutDirection::LeftToRight);
|
||||||
document()->setDefaultTextOption(op);
|
document()->setDefaultTextOption(op);
|
||||||
|
|
||||||
emit loadingFinished(true);
|
emit loadingFinished(true);
|
||||||
|
|
|
@ -292,17 +292,21 @@ PreparedHtml SkinFactory::generateHtmlOfArticles(const QList<Message>& messages,
|
||||||
msg_contents = qApp->web()->limitSizeOfHtmlImages(msg_contents, desired_width, forced_img_height);
|
msg_contents = qApp->web()->limitSizeOfHtmlImages(msg_contents, desired_width, forced_img_height);
|
||||||
}
|
}
|
||||||
|
|
||||||
messages_layout.append(single_message_layout.arg(message.m_title,
|
messages_layout
|
||||||
tr("Written by ") + (message.m_author.isEmpty()
|
.append(single_message_layout.arg(message.m_title,
|
||||||
? tr("unknown author")
|
tr("Written by ") +
|
||||||
: message.m_author),
|
(message.m_author.isEmpty() ? tr("unknown author") : message.m_author),
|
||||||
message.m_url,
|
message.m_url,
|
||||||
msg_contents,
|
msg_contents,
|
||||||
msg_date,
|
msg_date,
|
||||||
enclosures,
|
enclosures,
|
||||||
enclosure_images,
|
enclosure_images,
|
||||||
QString::number(message.m_id),
|
QString::number(message.m_id),
|
||||||
message.m_isRtl ? QSL("rtl") : QSL("ltr")));
|
(message.m_rtlBehavior == RtlBehavior::Everywhere ||
|
||||||
|
message.m_rtlBehavior == RtlBehavior::EverywhereExceptFeedList ||
|
||||||
|
message.m_rtlBehavior == RtlBehavior::OnlyViewer)
|
||||||
|
? QSL("rtl")
|
||||||
|
: QSL("ltr")));
|
||||||
}
|
}
|
||||||
|
|
||||||
QString msg_contents =
|
QString msg_contents =
|
||||||
|
|
17
src/librssguard/services/abstract/FeedRtlBehavior.h
Normal file
17
src/librssguard/services/abstract/FeedRtlBehavior.h
Normal file
|
@ -0,0 +1,17 @@
|
||||||
|
// For license of this file, see <project-root-folder>/LICENSE.md.
|
||||||
|
|
||||||
|
#ifndef FEEDRTLBEHAVIOR_H
|
||||||
|
#define FEEDRTLBEHAVIOR_H
|
||||||
|
|
||||||
|
#include <QMetaType>
|
||||||
|
|
||||||
|
enum class RtlBehavior {
|
||||||
|
NoRtl = 0, // The item is not RTL.
|
||||||
|
Everywhere = 1, // RTL is applied everwhere (feed list, article list, article viewer).
|
||||||
|
OnlyViewer = 2, // Use RTL only in article view, but not in article/feed list.
|
||||||
|
EverywhereExceptFeedList = 4 // Use RTL everywhere, but not in the feed list.
|
||||||
|
};
|
||||||
|
|
||||||
|
Q_DECLARE_METATYPE(RtlBehavior)
|
||||||
|
|
||||||
|
#endif // FEEDRTLBEHAVIOR_H
|
|
@ -17,7 +17,8 @@ Feed::Feed(RootItem* parent)
|
||||||
: RootItem(parent), m_source(QString()), m_status(Status::Normal), m_statusString(QString()),
|
: RootItem(parent), m_source(QString()), m_status(Status::Normal), m_statusString(QString()),
|
||||||
m_autoUpdateType(AutoUpdateType::DefaultAutoUpdate), m_autoUpdateInterval(DEFAULT_AUTO_UPDATE_INTERVAL),
|
m_autoUpdateType(AutoUpdateType::DefaultAutoUpdate), m_autoUpdateInterval(DEFAULT_AUTO_UPDATE_INTERVAL),
|
||||||
m_lastUpdated(QDateTime::currentDateTimeUtc()), m_isSwitchedOff(false), m_isQuiet(false),
|
m_lastUpdated(QDateTime::currentDateTimeUtc()), m_isSwitchedOff(false), m_isQuiet(false),
|
||||||
m_openArticlesDirectly(false), m_isRtl(false), m_messageFilters(QList<QPointer<MessageFilter>>()) {
|
m_openArticlesDirectly(false), m_rtlBehavior(RtlBehavior::NoRtl),
|
||||||
|
m_messageFilters(QList<QPointer<MessageFilter>>()) {
|
||||||
setKind(RootItem::Kind::Feed);
|
setKind(RootItem::Kind::Feed);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -40,7 +41,7 @@ Feed::Feed(const Feed& other) : RootItem(other) {
|
||||||
setMessageFilters(other.messageFilters());
|
setMessageFilters(other.messageFilters());
|
||||||
setOpenArticlesDirectly(other.openArticlesDirectly());
|
setOpenArticlesDirectly(other.openArticlesDirectly());
|
||||||
setArticleIgnoreLimit(Feed::ArticleIgnoreLimit(other.articleIgnoreLimit()));
|
setArticleIgnoreLimit(Feed::ArticleIgnoreLimit(other.articleIgnoreLimit()));
|
||||||
setIsRtl(other.isRtl());
|
setRtlBehavior(other.rtlBehavior());
|
||||||
setIsSwitchedOff(other.isSwitchedOff());
|
setIsSwitchedOff(other.isSwitchedOff());
|
||||||
setIsQuiet(other.isQuiet());
|
setIsQuiet(other.isQuiet());
|
||||||
}
|
}
|
||||||
|
@ -78,7 +79,8 @@ QVariant Feed::data(int column, int role) const {
|
||||||
|
|
||||||
case TEXT_DIRECTION_ROLE: {
|
case TEXT_DIRECTION_ROLE: {
|
||||||
if (column == FDS_MODEL_TITLE_INDEX) {
|
if (column == FDS_MODEL_TITLE_INDEX) {
|
||||||
return isRtl() ? Qt::LayoutDirection::RightToLeft : Qt::LayoutDirection::LayoutDirectionAuto;
|
return rtlBehavior() == RtlBehavior::Everywhere ? Qt::LayoutDirection::RightToLeft
|
||||||
|
: Qt::LayoutDirection::LayoutDirectionAuto;
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
return Qt::LayoutDirection::LayoutDirectionAuto;
|
return Qt::LayoutDirection::LayoutDirectionAuto;
|
||||||
|
@ -198,12 +200,12 @@ void Feed::setOpenArticlesDirectly(bool opn) {
|
||||||
m_openArticlesDirectly = opn;
|
m_openArticlesDirectly = opn;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool Feed::isRtl() const {
|
RtlBehavior Feed::rtlBehavior() const {
|
||||||
return m_isRtl;
|
return m_rtlBehavior;
|
||||||
}
|
}
|
||||||
|
|
||||||
void Feed::setIsRtl(bool rtl) {
|
void Feed::setRtlBehavior(RtlBehavior rtl) {
|
||||||
m_isRtl = rtl;
|
m_rtlBehavior = rtl;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool Feed::removeUnwantedArticles(QSqlDatabase& db) {
|
bool Feed::removeUnwantedArticles(QSqlDatabase& db) {
|
||||||
|
|
|
@ -5,6 +5,7 @@
|
||||||
|
|
||||||
#include "core/message.h"
|
#include "core/message.h"
|
||||||
#include "core/messagefilter.h"
|
#include "core/messagefilter.h"
|
||||||
|
#include "services/abstract/feedrtlbehavior.h"
|
||||||
#include "services/abstract/rootitem.h"
|
#include "services/abstract/rootitem.h"
|
||||||
|
|
||||||
#include <QPointer>
|
#include <QPointer>
|
||||||
|
@ -104,8 +105,8 @@ class RSSGUARD_DLLSPEC Feed : public RootItem {
|
||||||
QDateTime lastUpdated() const;
|
QDateTime lastUpdated() const;
|
||||||
void setLastUpdated(const QDateTime& last_updated);
|
void setLastUpdated(const QDateTime& last_updated);
|
||||||
|
|
||||||
bool isRtl() const;
|
RtlBehavior rtlBehavior() const;
|
||||||
void setIsRtl(bool rtl);
|
void setRtlBehavior(RtlBehavior rtl);
|
||||||
|
|
||||||
bool removeUnwantedArticles(QSqlDatabase& db);
|
bool removeUnwantedArticles(QSqlDatabase& db);
|
||||||
|
|
||||||
|
@ -130,7 +131,7 @@ class RSSGUARD_DLLSPEC Feed : public RootItem {
|
||||||
bool m_isSwitchedOff;
|
bool m_isSwitchedOff;
|
||||||
bool m_isQuiet;
|
bool m_isQuiet;
|
||||||
bool m_openArticlesDirectly;
|
bool m_openArticlesDirectly;
|
||||||
bool m_isRtl;
|
RtlBehavior m_rtlBehavior;
|
||||||
|
|
||||||
// NOTE: These are used to filter out older articles
|
// NOTE: These are used to filter out older articles
|
||||||
// than needed. Either absolute value is given (date/time)
|
// than needed. Either absolute value is given (date/time)
|
||||||
|
|
|
@ -61,7 +61,7 @@ void FormFeedDetails::apply() {
|
||||||
}
|
}
|
||||||
|
|
||||||
if (isChangeAllowed(m_ui->m_mcbFeedRtl)) {
|
if (isChangeAllowed(m_ui->m_mcbFeedRtl)) {
|
||||||
fd->setIsRtl(m_ui->m_cbFeedRtl->isChecked());
|
fd->setRtlBehavior(m_ui->m_cmbRtlBehavior->currentData().value<RtlBehavior>());
|
||||||
}
|
}
|
||||||
|
|
||||||
m_ui->m_wdgArticleLimiting->saveFeed(fd, m_isBatchEdit);
|
m_ui->m_wdgArticleLimiting->saveFeed(fd, m_isBatchEdit);
|
||||||
|
@ -127,7 +127,7 @@ void FormFeedDetails::loadFeedData() {
|
||||||
m_ui->m_mcbOpenArticlesAutomatically->addActionWidget(m_ui->m_cbOpenArticlesAutomatically);
|
m_ui->m_mcbOpenArticlesAutomatically->addActionWidget(m_ui->m_cbOpenArticlesAutomatically);
|
||||||
m_ui->m_mcbDisableFeed->addActionWidget(m_ui->m_cbDisableFeed);
|
m_ui->m_mcbDisableFeed->addActionWidget(m_ui->m_cbDisableFeed);
|
||||||
m_ui->m_mcbSuppressFeed->addActionWidget(m_ui->m_cbSuppressFeed);
|
m_ui->m_mcbSuppressFeed->addActionWidget(m_ui->m_cbSuppressFeed);
|
||||||
m_ui->m_mcbFeedRtl->addActionWidget(m_ui->m_cbFeedRtl);
|
m_ui->m_mcbFeedRtl->addActionWidget(m_ui->m_cmbRtlBehavior);
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
// We hide batch selectors.
|
// We hide batch selectors.
|
||||||
|
@ -158,7 +158,7 @@ void FormFeedDetails::loadFeedData() {
|
||||||
->setCurrentIndex(m_ui->m_cmbAutoUpdateType->findData(QVariant::fromValue(int(fd->autoUpdateType()))));
|
->setCurrentIndex(m_ui->m_cmbAutoUpdateType->findData(QVariant::fromValue(int(fd->autoUpdateType()))));
|
||||||
m_ui->m_spinAutoUpdateInterval->setValue(fd->autoUpdateInterval());
|
m_ui->m_spinAutoUpdateInterval->setValue(fd->autoUpdateInterval());
|
||||||
m_ui->m_cbOpenArticlesAutomatically->setChecked(fd->openArticlesDirectly());
|
m_ui->m_cbOpenArticlesAutomatically->setChecked(fd->openArticlesDirectly());
|
||||||
m_ui->m_cbFeedRtl->setChecked(fd->isRtl());
|
m_ui->m_cmbRtlBehavior->setCurrentIndex(m_ui->m_cmbRtlBehavior->findData(QVariant::fromValue(fd->rtlBehavior())));
|
||||||
m_ui->m_cbDisableFeed->setChecked(fd->isSwitchedOff());
|
m_ui->m_cbDisableFeed->setChecked(fd->isSwitchedOff());
|
||||||
m_ui->m_cbSuppressFeed->setChecked(fd->isQuiet());
|
m_ui->m_cbSuppressFeed->setChecked(fd->isQuiet());
|
||||||
|
|
||||||
|
@ -202,10 +202,18 @@ void FormFeedDetails::initialize() {
|
||||||
// Setup auto-update options.
|
// Setup auto-update options.
|
||||||
m_ui->m_spinAutoUpdateInterval->setMode(TimeSpinBox::Mode::MinutesSeconds);
|
m_ui->m_spinAutoUpdateInterval->setMode(TimeSpinBox::Mode::MinutesSeconds);
|
||||||
m_ui->m_spinAutoUpdateInterval->setValue(DEFAULT_AUTO_UPDATE_INTERVAL);
|
m_ui->m_spinAutoUpdateInterval->setValue(DEFAULT_AUTO_UPDATE_INTERVAL);
|
||||||
|
|
||||||
m_ui->m_cmbAutoUpdateType->addItem(tr("Fetch articles using global interval"),
|
m_ui->m_cmbAutoUpdateType->addItem(tr("Fetch articles using global interval"),
|
||||||
QVariant::fromValue(int(Feed::AutoUpdateType::DefaultAutoUpdate)));
|
QVariant::fromValue(int(Feed::AutoUpdateType::DefaultAutoUpdate)));
|
||||||
m_ui->m_cmbAutoUpdateType->addItem(tr("Fetch articles every"),
|
m_ui->m_cmbAutoUpdateType->addItem(tr("Fetch articles every"),
|
||||||
QVariant::fromValue(int(Feed::AutoUpdateType::SpecificAutoUpdate)));
|
QVariant::fromValue(int(Feed::AutoUpdateType::SpecificAutoUpdate)));
|
||||||
m_ui->m_cmbAutoUpdateType->addItem(tr("Disable auto-fetching of articles"),
|
m_ui->m_cmbAutoUpdateType->addItem(tr("Disable auto-fetching of articles"),
|
||||||
QVariant::fromValue(int(Feed::AutoUpdateType::DontAutoUpdate)));
|
QVariant::fromValue(int(Feed::AutoUpdateType::DontAutoUpdate)));
|
||||||
|
|
||||||
|
m_ui->m_cmbRtlBehavior->addItem(tr("Left-to-right"), QVariant::fromValue(int(RtlBehavior::NoRtl)));
|
||||||
|
m_ui->m_cmbRtlBehavior->addItem(tr("Right-to-left (everywhere)"), QVariant::fromValue(int(RtlBehavior::Everywhere)));
|
||||||
|
m_ui->m_cmbRtlBehavior->addItem(tr("Right-to-left (everywhere except feed list)"),
|
||||||
|
QVariant::fromValue(int(RtlBehavior::EverywhereExceptFeedList)));
|
||||||
|
m_ui->m_cmbRtlBehavior->addItem(tr("Right-to-left (only in article viewer)"),
|
||||||
|
QVariant::fromValue(int(RtlBehavior::OnlyViewer)));
|
||||||
}
|
}
|
||||||
|
|
|
@ -131,11 +131,18 @@
|
||||||
<widget class="MultiFeedEditCheckBox" name="m_mcbFeedRtl"/>
|
<widget class="MultiFeedEditCheckBox" name="m_mcbFeedRtl"/>
|
||||||
</item>
|
</item>
|
||||||
<item>
|
<item>
|
||||||
<widget class="QCheckBox" name="m_cbFeedRtl">
|
<layout class="QHBoxLayout" name="horizontalLayout_2">
|
||||||
<property name="text">
|
<item>
|
||||||
<string>Right-to-left layout</string>
|
<widget class="QLabel" name="label">
|
||||||
</property>
|
<property name="text">
|
||||||
</widget>
|
<string>Right-to-left behavior</string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<widget class="QComboBox" name="m_cmbRtlBehavior"/>
|
||||||
|
</item>
|
||||||
|
</layout>
|
||||||
</item>
|
</item>
|
||||||
</layout>
|
</layout>
|
||||||
</item>
|
</item>
|
||||||
|
@ -188,7 +195,6 @@
|
||||||
<tabstop>m_mcbDisableFeed</tabstop>
|
<tabstop>m_mcbDisableFeed</tabstop>
|
||||||
<tabstop>m_cbDisableFeed</tabstop>
|
<tabstop>m_cbDisableFeed</tabstop>
|
||||||
<tabstop>m_mcbFeedRtl</tabstop>
|
<tabstop>m_mcbFeedRtl</tabstop>
|
||||||
<tabstop>m_cbFeedRtl</tabstop>
|
|
||||||
</tabstops>
|
</tabstops>
|
||||||
<resources/>
|
<resources/>
|
||||||
<connections>
|
<connections>
|
||||||
|
|
|
@ -491,7 +491,7 @@ QMap<QString, QVariantMap> ServiceRoot::storeCustomFeedsData() {
|
||||||
feed_custom_data.insert(QSL("is_off"), feed->isSwitchedOff());
|
feed_custom_data.insert(QSL("is_off"), feed->isSwitchedOff());
|
||||||
feed_custom_data.insert(QSL("is_quiet"), feed->isQuiet());
|
feed_custom_data.insert(QSL("is_quiet"), feed->isQuiet());
|
||||||
feed_custom_data.insert(QSL("open_articles_directly"), feed->openArticlesDirectly());
|
feed_custom_data.insert(QSL("open_articles_directly"), feed->openArticlesDirectly());
|
||||||
feed_custom_data.insert(QSL("is_rtl"), feed->isRtl());
|
feed_custom_data.insert(QSL("is_rtl"), QVariant::fromValue(feed->rtlBehavior()));
|
||||||
|
|
||||||
feed_custom_data.insert(QSL("article_limit_ignore"), QVariant::fromValue(feed->articleIgnoreLimit()));
|
feed_custom_data.insert(QSL("article_limit_ignore"), QVariant::fromValue(feed->articleIgnoreLimit()));
|
||||||
|
|
||||||
|
@ -550,7 +550,7 @@ void ServiceRoot::restoreCustomFeedsData(const QMap<QString, QVariantMap>& data,
|
||||||
feed->setIsSwitchedOff(feed_custom_data.value(QSL("is_off")).toBool());
|
feed->setIsSwitchedOff(feed_custom_data.value(QSL("is_off")).toBool());
|
||||||
feed->setIsQuiet(feed_custom_data.value(QSL("is_quiet")).toBool());
|
feed->setIsQuiet(feed_custom_data.value(QSL("is_quiet")).toBool());
|
||||||
feed->setOpenArticlesDirectly(feed_custom_data.value(QSL("open_articles_directly")).toBool());
|
feed->setOpenArticlesDirectly(feed_custom_data.value(QSL("open_articles_directly")).toBool());
|
||||||
feed->setIsRtl(feed_custom_data.value(QSL("is_rtl")).toBool());
|
feed->setRtlBehavior(feed_custom_data.value(QSL("is_rtl")).value<RtlBehavior>());
|
||||||
|
|
||||||
feed
|
feed
|
||||||
->setArticleIgnoreLimit(feed_custom_data.value(QSL("article_limit_ignore")).value<Feed::ArticleIgnoreLimit>());
|
->setArticleIgnoreLimit(feed_custom_data.value(QSL("article_limit_ignore")).value<Feed::ArticleIgnoreLimit>());
|
||||||
|
|
Loading…
Add table
Reference in a new issue