diff --git a/src/librssguard/core/messagesmodel.cpp b/src/librssguard/core/messagesmodel.cpp index 3d4f9221c..49a8c8513 100644 --- a/src/librssguard/core/messagesmodel.cpp +++ b/src/librssguard/core/messagesmodel.cpp @@ -431,14 +431,20 @@ QVariant MessagesModel::data(const QModelIndex& idx, int role) const { index_column != MSG_DB_AUTHOR_INDEX) { return Qt::LayoutDirection::LayoutDirectionAuto; } - else { - return (m_cache->containsData(idx.row()) - ? m_cache->data(index(idx.row(), MSG_DB_FEED_IS_RTL_INDEX)) - : QSqlQueryModel::data(index(idx.row(), MSG_DB_FEED_IS_RTL_INDEX), Qt::ItemDataRole::EditRole)) - .toInt() == 0 - ? Qt::LayoutDirection::LayoutDirectionAuto - : Qt::LayoutDirection::RightToLeft; - } + + int isFeedRtl = (m_cache->containsData(idx.row()) + ? m_cache->data(index(idx.row(), MSG_DB_FEED_IS_RTL_INDEX)) + : QSqlQueryModel::data(index(idx.row(), MSG_DB_FEED_IS_RTL_INDEX), Qt::ItemDataRole::EditRole)).toInt(); + + bool m_isSwitchEntireTableview = qApp->settings()->value(GROUP(GUI), SETTING(GUI::SwitchRtlEntireTableview)).toBool(); + + if (isFeedRtl == 0 && m_isSwitchEntireTableview) + return Qt::LayoutDirection::LayoutDirectionAuto; + else if (isFeedRtl == 0) + return Qt::LayoutDirection::LayoutDirectionAuto; + else + return Qt::LayoutDirection::RightToLeft; + } case LOWER_TITLE_ROLE: diff --git a/src/librssguard/gui/messagesview.cpp b/src/librssguard/gui/messagesview.cpp index 4a2b36cc1..d4869ddac 100644 --- a/src/librssguard/gui/messagesview.cpp +++ b/src/librssguard/gui/messagesview.cpp @@ -349,6 +349,7 @@ void MessagesView::initializeContextMenu() { m_contextMenu = new QMenu(tr("Context menu for articles"), this); } + m_contextMenu->setLayoutDirection(Qt::LayoutDirection::LeftToRight); m_contextMenu->clear(); QList selected_messages; @@ -504,8 +505,10 @@ void MessagesView::selectionChanged(const QItemSelection& selected, const QItemS // Set this message as read only if current item // wasn't changed by "mark selected messages unread" action. if (!m_processingRightMouseButton) { - m_sourceModel->setMessageRead(mapped_current_index.row(), RootItem::ReadStatus::Read); - message.m_isRead = true; + if (qApp->settings()->value(GROUP(Messages), SETTING(Messages::MarkMessageReadOnSelectionChange)).toBool()) { + m_sourceModel->setMessageRead(mapped_current_index.row(), RootItem::ReadStatus::Read); + message.m_isRead = true; + } } emit currentMessageChanged(message, m_sourceModel->loadedItem()); @@ -534,25 +537,51 @@ void MessagesView::loadItem(RootItem* item) { sort(col, ord, false, true, false, true); m_sourceModel->loadMessages(item); - /* - if (item->kind() == RootItem::Kind::Feed) { - if (item->toFeed()->isRtl()) { - setLayoutDirection(Qt::LayoutDirection::RightToLeft); - } - else { - setLayoutDirection(Qt::LayoutDirection::LeftToRight); + // Handle the direction of messages and their Tableview. + if (item != nullptr) { + + Qt::LayoutDirection direction = Qt::LayoutDirection::LayoutDirectionAuto; + + // Check if the current item is a category and if all child items and grandchildren are RTL feeds. + if (item->kind() == RootItem::Kind::Category) { + const QList childItemsList = collectChildAndGrandchildFeeds(item); + + const bool areAllChildrenRtl = std::all_of(childItemsList.begin(), childItemsList.end(), [](RootItem* childItem) { + return childItem->kind() == RootItem::Kind::Feed && childItem->toFeed()->isRtl(); + }); + + // Set layout direction based on RTL status of child items and current item. + if (areAllChildrenRtl && qApp->settings()->value(GROUP(GUI), SETTING(GUI::SwitchRtlEntireTableview)).toBool()) + direction = Qt::LayoutDirection::RightToLeft; + + } else if (item->kind() == RootItem::Kind::Feed) { + if (item->toFeed()->isRtl() && qApp->settings()->value(GROUP(GUI), SETTING(GUI::SwitchRtlEntireTableview)).toBool()) + direction = Qt::LayoutDirection::RightToLeft; } + + setLayoutDirection(direction); } - else { - setLayoutDirection(Qt::LayoutDirection::LeftToRight); - } - */ // Messages are loaded, make sure that previously // active message is not shown in browser. emit currentMessageRemoved(m_sourceModel->loadedItem()); } +QList MessagesView::collectChildAndGrandchildFeeds(RootItem* item) { + QList childItemsList; + + for (RootItem *childItem : item->childItems()) { + if (childItem->kind() == RootItem::Kind::Category) { + QList recursiveList = collectChildAndGrandchildFeeds(childItem); + childItemsList.append(recursiveList); + } else { + childItemsList.append(childItem); + } + } + + return childItemsList; +} + void MessagesView::changeFilter(MessagesProxyModel::MessageListFilter filter) { m_proxyModel->setMessageListFilter(filter); reloadSelections(); diff --git a/src/librssguard/gui/messagesview.h b/src/librssguard/gui/messagesview.h index 85546ab03..bee65759a 100644 --- a/src/librssguard/gui/messagesview.h +++ b/src/librssguard/gui/messagesview.h @@ -40,6 +40,9 @@ class MessagesView : public BaseTreeView { // Loads un-deleted messages from selected feeds. void loadItem(RootItem* item); + // Allow to recursively collects all child & grandchild feeds of the given RootItem. + QList collectChildAndGrandchildFeeds(RootItem* item); + // Message manipulators. #if defined(ENABLE_MEDIAPLAYER) void playSelectedArticleInMediaPlayer(); diff --git a/src/librssguard/gui/settings/settingsfeedsmessages.cpp b/src/librssguard/gui/settings/settingsfeedsmessages.cpp index 88382ea20..59a627a66 100644 --- a/src/librssguard/gui/settings/settingsfeedsmessages.cpp +++ b/src/librssguard/gui/settings/settingsfeedsmessages.cpp @@ -78,6 +78,12 @@ SettingsFeedsMessages::SettingsFeedsMessages(Settings* settings, QWidget* parent connect(m_ui->m_checkAutoUpdate, &QCheckBox::toggled, this, &SettingsFeedsMessages::dirtifySettings); connect(m_ui->m_cbUpdateFeedListDuringFetching, &QCheckBox::toggled, this, &SettingsFeedsMessages::dirtifySettings); connect(m_ui->m_checkAutoUpdateOnlyUnfocused, &QCheckBox::toggled, this, &SettingsFeedsMessages::dirtifySettings); + + connect(m_ui->m_checkSwitchRtlEntireTableview, &QCheckBox::toggled, this, &SettingsFeedsMessages::dirtifySettings); + connect(m_ui->m_checkApplyRtlFeedsTitles, &QCheckBox::toggled, this, &SettingsFeedsMessages::dirtifySettings); + + connect(m_ui->m_checkMarkMessageReadOnSelectionChange, &QCheckBox::toggled, this, &SettingsFeedsMessages::dirtifySettings); + connect(m_ui->m_cmbUnreadIconType, QOverload::of(&QComboBox::currentIndexChanged), this, @@ -281,6 +287,8 @@ 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_checkSwitchRtlEntireTableview + ->setChecked(settings()->value(GROUP(GUI), SETTING(GUI::SwitchRtlEntireTableview)).toBool()); m_ui->m_cmbUnreadIconType ->setCurrentIndex(m_ui->m_cmbUnreadIconType ->findData(settings()->value(GROUP(Messages), SETTING(Messages::UnreadIconType)).toInt())); @@ -290,6 +298,8 @@ void SettingsFeedsMessages::loadSettings() { .toBool()); m_ui->m_checkKeppMessagesInTheMiddle ->setChecked(settings()->value(GROUP(Messages), SETTING(Messages::KeepCursorInCenter)).toBool()); + m_ui->m_checkMarkMessageReadOnSelectionChange + ->setChecked(settings()->value(GROUP(Messages), SETTING(Messages::MarkMessageReadOnSelectionChange)).toBool()); m_ui->m_checkRemoveReadMessagesOnExit ->setChecked(settings()->value(GROUP(Messages), SETTING(Messages::ClearReadOnExit)).toBool()); m_ui->m_checkAutoUpdate->setChecked(settings()->value(GROUP(Feeds), SETTING(Feeds::AutoUpdateEnabled)).toBool()); @@ -317,6 +327,8 @@ void SettingsFeedsMessages::loadSettings() { m_ui->m_cmbCountsFeedList->setEditText(settings()->value(GROUP(Feeds), SETTING(Feeds::CountFormat)).toString()); m_ui->m_checkShowTooltips ->setChecked(settings()->value(GROUP(Feeds), SETTING(Feeds::EnableTooltipsFeedsMessages)).toBool()); + m_ui->m_checkApplyRtlFeedsTitles + ->setChecked(settings()->value(GROUP(Feeds), SETTING(Feeds::ApplyRtlToFeedsTitles)).toBool()); m_ui->m_cmbIgnoreContentsChanges ->setChecked(settings()->value(GROUP(Messages), SETTING(Messages::IgnoreContentsChanges)).toBool()); m_ui->m_checkMultilineArticleList @@ -391,6 +403,8 @@ void SettingsFeedsMessages::saveSettings() { settings()->setValue(GROUP(Feeds), Feeds::HideCountsIfNoUnread, m_ui->m_cbHideCountsIfNoUnread->isChecked()); settings()->setValue(GROUP(Messages), Messages::UnreadIconType, m_ui->m_cmbUnreadIconType->currentData().toInt()); + settings()->setValue(GROUP(GUI), GUI::SwitchRtlEntireTableview, m_ui->m_checkSwitchRtlEntireTableview->isChecked()); + // Make registry hack to make "show app window after external viewer called" feature // work more reliably on Windows 10+. #if defined(Q_OS_WIN) @@ -415,6 +429,7 @@ void SettingsFeedsMessages::saveSettings() { settings()->setValue(GROUP(Messages), Messages::KeepCursorInCenter, m_ui->m_checkKeppMessagesInTheMiddle->isChecked()); + settings()->setValue(GROUP(Messages), Messages::MarkMessageReadOnSelectionChange, m_ui->m_checkMarkMessageReadOnSelectionChange->isChecked()); settings()->setValue(GROUP(Messages), Messages::ClearReadOnExit, m_ui->m_checkRemoveReadMessagesOnExit->isChecked()); settings()->setValue(GROUP(Feeds), Feeds::AutoUpdateEnabled, m_ui->m_checkAutoUpdate->isChecked()); settings()->setValue(GROUP(Feeds), Feeds::AutoUpdateOnlyUnfocused, m_ui->m_checkAutoUpdateOnlyUnfocused->isChecked()); @@ -443,6 +458,7 @@ void SettingsFeedsMessages::saveSettings() { settings()->setValue(GROUP(Feeds), Feeds::FeedsUpdateStartupDelay, m_ui->m_spinStartupUpdateDelay->value()); settings()->setValue(GROUP(Feeds), Feeds::CountFormat, m_ui->m_cmbCountsFeedList->currentText()); settings()->setValue(GROUP(Feeds), Feeds::EnableTooltipsFeedsMessages, m_ui->m_checkShowTooltips->isChecked()); + settings()->setValue(GROUP(Feeds), Feeds::ApplyRtlToFeedsTitles, m_ui->m_checkApplyRtlFeedsTitles->isChecked()); settings()->setValue(GROUP(Messages), Messages::IgnoreContentsChanges, m_ui->m_cmbIgnoreContentsChanges->isChecked()); settings()->setValue(GROUP(Messages), Messages::MultilineArticleList, m_ui->m_checkMultilineArticleList->isChecked()); settings()->setValue(GROUP(Messages), diff --git a/src/librssguard/gui/settings/settingsfeedsmessages.ui b/src/librssguard/gui/settings/settingsfeedsmessages.ui index c44c58982..b8dbab0e0 100644 --- a/src/librssguard/gui/settings/settingsfeedsmessages.ui +++ b/src/librssguard/gui/settings/settingsfeedsmessages.ui @@ -14,7 +14,7 @@ - 0 + 3 @@ -266,6 +266,13 @@ + + + + Apply RTL mode to feeds titles + + + @@ -281,34 +288,41 @@ + + + Mark article as read on mouse click or on keyboard up/down press + + + + Remove all read articles from all feeds on application exit - + Ignore changes in article body when new articles are being fetched - + Fixup date/time of articles which are in the future - + Bring application window to front once article is opened in external web browser - + Internal article viewer @@ -407,14 +421,14 @@ - + Keep article viewer always visible - + Use legacy article formatting @@ -650,6 +664,22 @@ + + + + RTL behaviour + + + + + + Switch messages tableview direction + + + + + + @@ -690,6 +720,8 @@ m_cbUpdateFeedListDuringFetching m_cbListsRestrictedShortcuts m_checkShowTooltips + m_checkApplyRtlFeedsTitles + m_checkMarkMessageReadOnSelectionChange m_checkRemoveReadMessagesOnExit m_cbArticleViewerAlwaysVisible m_cmbIgnoreContentsChanges @@ -712,6 +744,7 @@ m_tabFeedsMessages m_gbFeedListFont m_gbArticleListFont + m_checkSwitchRtlEntireTableview diff --git a/src/librssguard/miscellaneous/settings.cpp b/src/librssguard/miscellaneous/settings.cpp index 68fa2cf0c..3fca72534 100644 --- a/src/librssguard/miscellaneous/settings.cpp +++ b/src/librssguard/miscellaneous/settings.cpp @@ -95,6 +95,9 @@ DVALUE(char*) Feeds::CountFormatDef = "(%unread)"; DKEY Feeds::EnableTooltipsFeedsMessages = "show_tooltips"; DVALUE(bool) Feeds::EnableTooltipsFeedsMessagesDef = true; +DKEY Feeds::ApplyRtlToFeedsTitles = "apply_rtl_to_feeds_titles"; +DVALUE(bool) Feeds::ApplyRtlToFeedsTitlesDef = false; + DKEY Feeds::AutoUpdateInterval = "auto_update_interval"; DVALUE(int) Feeds::AutoUpdateIntervalDef = DEFAULT_AUTO_UPDATE_INTERVAL; @@ -214,6 +217,9 @@ DVALUE(bool) Messages::UseCustomTimeDef = false; DKEY Messages::CustomTimeFormat = "custom_time_format"; DVALUE(QString) Messages::CustomTimeFormatDef = {}; +DKEY Messages::MarkMessageReadOnSelectionChange = "mark_message_read_on_selection_change"; +DVALUE(bool) Messages::MarkMessageReadOnSelectionChangeDef = false; + DKEY Messages::ClearReadOnExit = "clear_read_on_exit"; DVALUE(bool) Messages::ClearReadOnExitDef = false; @@ -270,6 +276,9 @@ DVALUE(int) GUI::ToolbarIconSizeDef = 0; DKEY GUI::ToolbarStyle = "toolbar_style"; DVALUE(Qt::ToolButtonStyle) GUI::ToolbarStyleDef = Qt::ToolButtonIconOnly; +DKEY GUI::SwitchRtlEntireTableview = "switch_rtl_entire_tableview"; +DVALUE(bool) GUI::SwitchRtlEntireTableviewDef = true; + DKEY GUI::HeightRowMessages = "height_row_messages"; DVALUE(int) GUI::HeightRowMessagesDef = -1; diff --git a/src/librssguard/miscellaneous/settings.h b/src/librssguard/miscellaneous/settings.h index e88d8d5ca..a75f8e7cd 100644 --- a/src/librssguard/miscellaneous/settings.h +++ b/src/librssguard/miscellaneous/settings.h @@ -93,6 +93,9 @@ namespace Feeds { KEY EnableTooltipsFeedsMessages; VALUE(bool) EnableTooltipsFeedsMessagesDef; + KEY ApplyRtlToFeedsTitles; + VALUE(bool) ApplyRtlToFeedsTitlesDef; + KEY AutoUpdateInterval; VALUE(int) AutoUpdateIntervalDef; @@ -160,6 +163,9 @@ namespace Messages { KEY HoursToAvoidArticle; VALUE(int) HoursToAvoidArticleDef; + KEY MarkMessageReadOnSelectionChange; + VALUE(bool) MarkMessageReadOnSelectionChangeDef; + KEY LimitDoNotRemoveUnread; VALUE(bool) LimitDoNotRemoveUnreadDef; @@ -374,6 +380,9 @@ namespace GUI { KEY DefaultSortColumnFeeds; VALUE(int) DefaultSortColumnFeedsDef; + KEY SwitchRtlEntireTableview; + VALUE(bool) SwitchRtlEntireTableviewDef; + KEY HeightRowMessages; VALUE(int) HeightRowMessagesDef; diff --git a/src/librssguard/services/abstract/feed.cpp b/src/librssguard/services/abstract/feed.cpp index 21c76cfab..77cc0db36 100644 --- a/src/librssguard/services/abstract/feed.cpp +++ b/src/librssguard/services/abstract/feed.cpp @@ -78,7 +78,8 @@ QVariant Feed::data(int column, int role) const { case TEXT_DIRECTION_ROLE: { if (column == FDS_MODEL_TITLE_INDEX) { - return isRtl() ? Qt::LayoutDirection::RightToLeft : Qt::LayoutDirection::LayoutDirectionAuto; + const bool m_areRtlFeedsTitlesApplied = qApp->settings()->value(GROUP(Feeds), SETTING(Feeds::ApplyRtlToFeedsTitles)).toBool(); + return isRtl() && m_areRtlFeedsTitlesApplied ? Qt::LayoutDirection::RightToLeft : Qt::LayoutDirection::LayoutDirectionAuto; } else { return Qt::LayoutDirection::LayoutDirectionAuto;