mirror of
https://github.com/qbittorrent/qBittorrent.git
synced 2026-01-02 21:52:32 -06:00
@@ -588,6 +588,7 @@ void AdvancedSettings::loadAdvancedSettings()
|
||||
m_comboBoxDiskIOType.addItem(tr("Default"), QVariant::fromValue(BitTorrent::DiskIOType::Default));
|
||||
m_comboBoxDiskIOType.addItem(tr("Memory mapped files"), QVariant::fromValue(BitTorrent::DiskIOType::MMap));
|
||||
m_comboBoxDiskIOType.addItem(tr("POSIX-compliant"), QVariant::fromValue(BitTorrent::DiskIOType::Posix));
|
||||
m_comboBoxDiskIOType.addItem(tr("Simple pread/pwrite"), QVariant::fromValue(BitTorrent::DiskIOType::SimplePreadPwrite));
|
||||
m_comboBoxDiskIOType.setCurrentIndex(m_comboBoxDiskIOType.findData(QVariant::fromValue(session->diskIOType())));
|
||||
addRow(DISK_IO_TYPE, tr("Disk IO type (requires restart)") + u' ' + makeLink(u"https://www.libtorrent.org/single-page-ref.html#default-disk-io-constructor", u"(?)")
|
||||
, &m_comboBoxDiskIOType);
|
||||
|
||||
@@ -175,7 +175,8 @@ void GUIAddTorrentManager::onMetadataDownloaded(const BitTorrent::TorrentInfo &m
|
||||
}
|
||||
}
|
||||
|
||||
bool GUIAddTorrentManager::processTorrent(const QString &source, const BitTorrent::TorrentDescriptor &torrentDescr, const BitTorrent::AddTorrentParams ¶ms)
|
||||
bool GUIAddTorrentManager::processTorrent(const QString &source
|
||||
, const BitTorrent::TorrentDescriptor &torrentDescr, const BitTorrent::AddTorrentParams ¶ms)
|
||||
{
|
||||
const bool hasMetadata = torrentDescr.info().has_value();
|
||||
const BitTorrent::InfoHash infoHash = torrentDescr.infoHash();
|
||||
@@ -183,32 +184,39 @@ bool GUIAddTorrentManager::processTorrent(const QString &source, const BitTorren
|
||||
// Prevent showing the dialog if download is already present
|
||||
if (BitTorrent::Torrent *torrent = btSession()->findTorrent(infoHash))
|
||||
{
|
||||
if (hasMetadata)
|
||||
if (Preferences::instance()->confirmMergeTrackers())
|
||||
{
|
||||
// Trying to set metadata to existing torrent in case if it has none
|
||||
torrent->setMetadata(*torrentDescr.info());
|
||||
}
|
||||
if (hasMetadata)
|
||||
{
|
||||
// Trying to set metadata to existing torrent in case if it has none
|
||||
torrent->setMetadata(*torrentDescr.info());
|
||||
}
|
||||
|
||||
if (torrent->isPrivate() || (hasMetadata && torrentDescr.info()->isPrivate()))
|
||||
{
|
||||
handleDuplicateTorrent(source, torrent, tr("Trackers cannot be merged because it is a private torrent"));
|
||||
const bool isPrivate = torrent->isPrivate() || (hasMetadata && torrentDescr.info()->isPrivate());
|
||||
const QString dialogCaption = tr("Torrent is already present");
|
||||
if (isPrivate)
|
||||
{
|
||||
// We cannot merge trackers for private torrent but we still notify user
|
||||
// about duplicate torrent if confirmation dialog is enabled.
|
||||
RaisedMessageBox::warning(app()->mainWindow(), dialogCaption
|
||||
, tr("Trackers cannot be merged because it is a private torrent."));
|
||||
}
|
||||
else
|
||||
{
|
||||
const bool mergeTrackers = btSession()->isMergeTrackersEnabled();
|
||||
const QMessageBox::StandardButton btn = RaisedMessageBox::question(app()->mainWindow(), dialogCaption
|
||||
, tr("Torrent '%1' is already in the transfer list. Do you want to merge trackers from new source?").arg(torrent->name())
|
||||
, (QMessageBox::Yes | QMessageBox::No), (mergeTrackers ? QMessageBox::Yes : QMessageBox::No));
|
||||
if (btn == QMessageBox::Yes)
|
||||
{
|
||||
torrent->addTrackers(torrentDescr.trackers());
|
||||
torrent->addUrlSeeds(torrentDescr.urlSeeds());
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
bool mergeTrackers = btSession()->isMergeTrackersEnabled();
|
||||
if (Preferences::instance()->confirmMergeTrackers())
|
||||
{
|
||||
const QMessageBox::StandardButton btn = RaisedMessageBox::question(app()->mainWindow(), tr("Torrent is already present")
|
||||
, tr("Torrent '%1' is already in the transfer list. Do you want to merge trackers from new source?").arg(torrent->name())
|
||||
, (QMessageBox::Yes | QMessageBox::No), QMessageBox::Yes);
|
||||
mergeTrackers = (btn == QMessageBox::Yes);
|
||||
}
|
||||
|
||||
if (mergeTrackers)
|
||||
{
|
||||
torrent->addTrackers(torrentDescr.trackers());
|
||||
torrent->addUrlSeeds(torrentDescr.urlSeeds());
|
||||
}
|
||||
handleDuplicateTorrent(source, torrentDescr, torrent);
|
||||
}
|
||||
|
||||
return false;
|
||||
|
||||
@@ -30,6 +30,7 @@
|
||||
|
||||
#include "optionsdialog.h"
|
||||
|
||||
#include <algorithm>
|
||||
#include <chrono>
|
||||
#include <cstdlib>
|
||||
#include <limits>
|
||||
@@ -44,6 +45,10 @@
|
||||
#include <QSystemTrayIcon>
|
||||
#include <QTranslator>
|
||||
|
||||
#ifdef Q_OS_WIN
|
||||
#include <QStyleFactory>
|
||||
#endif
|
||||
|
||||
#include "base/bittorrent/session.h"
|
||||
#include "base/bittorrent/sharelimitaction.h"
|
||||
#include "base/exceptions.h"
|
||||
@@ -56,6 +61,7 @@
|
||||
#include "base/rss/rss_session.h"
|
||||
#include "base/torrentfileguard.h"
|
||||
#include "base/torrentfileswatcher.h"
|
||||
#include "base/utils/compare.h"
|
||||
#include "base/utils/io.h"
|
||||
#include "base/utils/misc.h"
|
||||
#include "base/utils/net.h"
|
||||
@@ -236,6 +242,8 @@ void OptionsDialog::loadBehaviorTabOptions()
|
||||
initializeLanguageCombo();
|
||||
setLocale(pref->getLocale());
|
||||
|
||||
initializeStyleCombo();
|
||||
|
||||
m_ui->checkUseCustomTheme->setChecked(Preferences::instance()->useCustomUITheme());
|
||||
m_ui->customThemeFilePath->setSelectedPath(Preferences::instance()->customUIThemePath());
|
||||
m_ui->customThemeFilePath->setMode(FileSystemPathEdit::Mode::FileOpen);
|
||||
@@ -345,7 +353,11 @@ void OptionsDialog::loadBehaviorTabOptions()
|
||||
|
||||
m_ui->checkBoxPerformanceWarning->setChecked(session->isPerformanceWarningEnabled());
|
||||
|
||||
connect(m_ui->comboI18n, qComboBoxCurrentIndexChanged, this, &ThisType::enableApplyButton);
|
||||
connect(m_ui->comboLanguage, qComboBoxCurrentIndexChanged, this, &ThisType::enableApplyButton);
|
||||
|
||||
#ifdef Q_OS_WIN
|
||||
connect(m_ui->comboStyle, qComboBoxCurrentIndexChanged, this, &ThisType::enableApplyButton);
|
||||
#endif
|
||||
|
||||
#if (defined(Q_OS_UNIX) && !defined(Q_OS_MACOS))
|
||||
connect(m_ui->checkUseSystemIcon, &QAbstractButton::toggled, this, &ThisType::enableApplyButton);
|
||||
@@ -443,6 +455,13 @@ void OptionsDialog::saveBehaviorTabOptions() const
|
||||
}
|
||||
pref->setLocale(locale);
|
||||
|
||||
#ifdef Q_OS_WIN
|
||||
if (const QVariant systemStyle = m_ui->comboStyle->currentData(); systemStyle.isValid())
|
||||
pref->setStyle(systemStyle.toString());
|
||||
else
|
||||
pref->setStyle(m_ui->comboStyle->currentText());
|
||||
#endif
|
||||
|
||||
#if (defined(Q_OS_UNIX) && !defined(Q_OS_MACOS))
|
||||
pref->useSystemIcons(m_ui->checkUseSystemIcon->isChecked());
|
||||
#endif
|
||||
@@ -1387,7 +1406,7 @@ void OptionsDialog::initializeLanguageCombo()
|
||||
for (const QString &langFile : langFiles)
|
||||
{
|
||||
const QString langCode = QStringView(langFile).sliced(12).chopped(3).toString(); // remove "qbittorrent_" and ".qm"
|
||||
m_ui->comboI18n->addItem(Utils::Misc::languageToLocalizedString(langCode), langCode);
|
||||
m_ui->comboLanguage->addItem(Utils::Misc::languageToLocalizedString(langCode), langCode);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1672,6 +1691,33 @@ bool OptionsDialog::isSplashScreenDisabled() const
|
||||
return !m_ui->checkShowSplash->isChecked();
|
||||
}
|
||||
|
||||
void OptionsDialog::initializeStyleCombo()
|
||||
{
|
||||
#ifdef Q_OS_WIN
|
||||
m_ui->labelStyleHint->setText(tr("%1 is recommended for best compatibility with Windows dark mode"
|
||||
, "Fusion is recommended for best compatibility with Windows dark mode").arg(u"Fusion"_s));
|
||||
m_ui->comboStyle->addItem(tr("System", "System default Qt style"), u"system"_s);
|
||||
m_ui->comboStyle->setItemData(0, tr("Let Qt decide the style for this system"), Qt::ToolTipRole);
|
||||
m_ui->comboStyle->insertSeparator(1);
|
||||
|
||||
QStringList styleNames = QStyleFactory::keys();
|
||||
std::sort(styleNames.begin(), styleNames.end(), Utils::Compare::NaturalLessThan<Qt::CaseInsensitive>());
|
||||
m_ui->comboStyle->addItems(styleNames);
|
||||
const QString prefStyleName = Preferences::instance()->getStyle();
|
||||
const QString selectedStyleName = prefStyleName.isEmpty() ? QApplication::style()->name() : prefStyleName;
|
||||
|
||||
if (selectedStyleName.compare(u"system"_s, Qt::CaseInsensitive) != 0)
|
||||
m_ui->comboStyle->setCurrentText(selectedStyleName);
|
||||
#else
|
||||
m_ui->labelStyle->hide();
|
||||
m_ui->comboStyle->hide();
|
||||
m_ui->labelStyleHint->hide();
|
||||
m_ui->UISettingsBoxLayout->removeWidget(m_ui->labelStyle);
|
||||
m_ui->UISettingsBoxLayout->removeWidget(m_ui->comboStyle);
|
||||
m_ui->UISettingsBoxLayout->removeWidget(m_ui->labelStyleHint);
|
||||
#endif
|
||||
}
|
||||
|
||||
#ifdef Q_OS_WIN
|
||||
bool OptionsDialog::WinStartup() const
|
||||
{
|
||||
@@ -1721,7 +1767,7 @@ QString OptionsDialog::getProxyPassword() const
|
||||
// Locale Settings
|
||||
QString OptionsDialog::getLocale() const
|
||||
{
|
||||
return m_ui->comboI18n->itemData(m_ui->comboI18n->currentIndex(), Qt::UserRole).toString();
|
||||
return m_ui->comboLanguage->itemData(m_ui->comboLanguage->currentIndex(), Qt::UserRole).toString();
|
||||
}
|
||||
|
||||
void OptionsDialog::setLocale(const QString &localeStr)
|
||||
@@ -1746,7 +1792,7 @@ void OptionsDialog::setLocale(const QString &localeStr)
|
||||
name = locale.name();
|
||||
}
|
||||
// Attempt to find exact match
|
||||
int index = m_ui->comboI18n->findData(name, Qt::UserRole);
|
||||
int index = m_ui->comboLanguage->findData(name, Qt::UserRole);
|
||||
if (index < 0)
|
||||
{
|
||||
//Attempt to find a language match without a country
|
||||
@@ -1754,16 +1800,16 @@ void OptionsDialog::setLocale(const QString &localeStr)
|
||||
if (pos > -1)
|
||||
{
|
||||
QString lang = name.left(pos);
|
||||
index = m_ui->comboI18n->findData(lang, Qt::UserRole);
|
||||
index = m_ui->comboLanguage->findData(lang, Qt::UserRole);
|
||||
}
|
||||
}
|
||||
if (index < 0)
|
||||
{
|
||||
// Unrecognized, use US English
|
||||
index = m_ui->comboI18n->findData(u"en"_s, Qt::UserRole);
|
||||
index = m_ui->comboLanguage->findData(u"en"_s, Qt::UserRole);
|
||||
Q_ASSERT(index >= 0);
|
||||
}
|
||||
m_ui->comboI18n->setCurrentIndex(index);
|
||||
m_ui->comboLanguage->setCurrentIndex(index);
|
||||
}
|
||||
|
||||
Path OptionsDialog::getTorrentExportDir() const
|
||||
@@ -1869,7 +1915,7 @@ Path OptionsDialog::getFilter() const
|
||||
void OptionsDialog::webUIHttpsCertChanged(const Path &path)
|
||||
{
|
||||
const auto readResult = Utils::IO::readFile(path, Utils::Net::MAX_SSL_FILE_SIZE);
|
||||
const bool isCertValid = !Utils::SSLKey::load(readResult.value_or(QByteArray())).isNull();
|
||||
const bool isCertValid = Utils::Net::isSSLCertificatesValid(readResult.value_or(QByteArray()));
|
||||
|
||||
m_ui->textWebUIHttpsCert->setSelectedPath(path);
|
||||
m_ui->lblSslCertStatus->setPixmap(UIThemeManager::instance()->getScaledPixmap(
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
/*
|
||||
* Bittorrent Client using Qt and libtorrent.
|
||||
* Copyright (C) 2023 Vladimir Golovnev <glassez@yandex.ru>
|
||||
* Copyright (C) 2023-2024 Vladimir Golovnev <glassez@yandex.ru>
|
||||
* Copyright (C) 2006 Christophe Dumez <chris@qbittorrent.org>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
@@ -143,6 +143,7 @@ private:
|
||||
|
||||
// General options
|
||||
void initializeLanguageCombo();
|
||||
void initializeStyleCombo();
|
||||
QString getLocale() const;
|
||||
bool isSplashScreenDisabled() const;
|
||||
#ifdef Q_OS_WIN
|
||||
|
||||
@@ -132,9 +132,9 @@
|
||||
<property name="title">
|
||||
<string>Interface</string>
|
||||
</property>
|
||||
<layout class="QGridLayout" name="gridLayout_81">
|
||||
<layout class="QGridLayout" name="UISettingsBoxLayout">
|
||||
<item row="0" column="0" colspan="3">
|
||||
<widget class="QLabel" name="label_15">
|
||||
<widget class="QLabel" name="labelRestartRequired">
|
||||
<property name="font">
|
||||
<font>
|
||||
<italic>true</italic>
|
||||
@@ -146,17 +146,17 @@
|
||||
</widget>
|
||||
</item>
|
||||
<item row="1" column="0">
|
||||
<widget class="QLabel" name="label_9">
|
||||
<widget class="QLabel" name="labelLanguage">
|
||||
<property name="text">
|
||||
<string>Language:</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="1" column="1">
|
||||
<widget class="QComboBox" name="comboI18n"/>
|
||||
<widget class="QComboBox" name="comboLanguage"/>
|
||||
</item>
|
||||
<item row="1" column="2">
|
||||
<spacer name="horizontalSpacer_111">
|
||||
<spacer name="spacerLanguage">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Horizontal</enum>
|
||||
</property>
|
||||
@@ -168,7 +168,26 @@
|
||||
</property>
|
||||
</spacer>
|
||||
</item>
|
||||
<item row="2" column="0" colspan="3">
|
||||
<item row="2" column="0">
|
||||
<widget class="QLabel" name="labelStyle">
|
||||
<property name="text">
|
||||
<string>Style:</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="2" column="1">
|
||||
<widget class="QComboBox" name="comboStyle"/>
|
||||
</item>
|
||||
<item row="2" column="2">
|
||||
<widget class="QLabel" name="labelStyleHint">
|
||||
<property name="font">
|
||||
<font>
|
||||
<italic>true</italic>
|
||||
</font>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="3" column="0" colspan="3">
|
||||
<widget class="QGroupBox" name="checkUseCustomTheme">
|
||||
<property name="title">
|
||||
<string>Use custom UI Theme</string>
|
||||
@@ -190,14 +209,14 @@
|
||||
</layout>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="3" column="0" colspan="2">
|
||||
<item row="4" column="0" colspan="2">
|
||||
<widget class="QCheckBox" name="checkUseSystemIcon">
|
||||
<property name="text">
|
||||
<string>Use icons from system theme</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="4" column="0" colspan="2">
|
||||
<item row="5" column="0" colspan="2">
|
||||
<widget class="QPushButton" name="buttonCustomizeUITheme">
|
||||
<property name="text">
|
||||
<string>Customize UI Theme...</string>
|
||||
@@ -3881,7 +3900,7 @@ Use ';' to split multiple entries. Can use wildcard '*'.</string>
|
||||
</customwidgets>
|
||||
<tabstops>
|
||||
<tabstop>tabOption</tabstop>
|
||||
<tabstop>comboI18n</tabstop>
|
||||
<tabstop>comboLanguage</tabstop>
|
||||
<tabstop>checkUseCustomTheme</tabstop>
|
||||
<tabstop>customThemeFilePath</tabstop>
|
||||
<tabstop>checkAddStopped</tabstop>
|
||||
|
||||
@@ -42,7 +42,6 @@
|
||||
#include "base/indexrange.h"
|
||||
#include "base/path.h"
|
||||
#include "base/utils/misc.h"
|
||||
#include "gui/uithememanager.h"
|
||||
|
||||
namespace
|
||||
{
|
||||
@@ -119,13 +118,7 @@ PiecesBar::PiecesBar(QWidget *parent)
|
||||
: QWidget(parent)
|
||||
{
|
||||
setMouseTracking(true);
|
||||
|
||||
updateColorsImpl();
|
||||
connect(UIThemeManager::instance(), &UIThemeManager::themeChanged, this, [this]
|
||||
{
|
||||
updateColors();
|
||||
redraw();
|
||||
});
|
||||
}
|
||||
|
||||
void PiecesBar::setTorrent(const BitTorrent::Torrent *torrent)
|
||||
@@ -143,12 +136,19 @@ void PiecesBar::clear()
|
||||
|
||||
bool PiecesBar::event(QEvent *e)
|
||||
{
|
||||
if (e->type() == QEvent::ToolTip)
|
||||
const QEvent::Type eventType = e->type();
|
||||
if (eventType == QEvent::ToolTip)
|
||||
{
|
||||
showToolTip(static_cast<QHelpEvent *>(e));
|
||||
return true;
|
||||
}
|
||||
|
||||
if (eventType == QEvent::PaletteChange)
|
||||
{
|
||||
updateColors();
|
||||
redraw();
|
||||
}
|
||||
|
||||
return base::event(e);
|
||||
}
|
||||
|
||||
|
||||
@@ -126,6 +126,8 @@ RSSWidget::RSSWidget(IGUIApplication *app, QWidget *parent)
|
||||
, this, &RSSWidget::handleSessionProcessingStateChanged);
|
||||
connect(RSS::Session::instance()->rootFolder(), &RSS::Folder::unreadCountChanged
|
||||
, this, &RSSWidget::handleUnreadCountChanged);
|
||||
|
||||
m_ui->textBrowser->installEventFilter(this);
|
||||
}
|
||||
|
||||
RSSWidget::~RSSWidget()
|
||||
@@ -494,60 +496,11 @@ void RSSWidget::handleCurrentArticleItemChanged(QListWidgetItem *currentItem, QL
|
||||
article->markAsRead();
|
||||
}
|
||||
|
||||
if (!currentItem) return;
|
||||
if (!currentItem)
|
||||
return;
|
||||
|
||||
auto *article = m_articleListWidget->getRSSArticle(currentItem);
|
||||
Q_ASSERT(article);
|
||||
|
||||
const QString highlightedBaseColor = m_ui->textBrowser->palette().color(QPalette::Highlight).name();
|
||||
const QString highlightedBaseTextColor = m_ui->textBrowser->palette().color(QPalette::HighlightedText).name();
|
||||
const QString alternateBaseColor = m_ui->textBrowser->palette().color(QPalette::AlternateBase).name();
|
||||
|
||||
QString html =
|
||||
u"<div style='border: 2px solid red; margin-left: 5px; margin-right: 5px; margin-bottom: 5px;'>" +
|
||||
u"<div style='background-color: \"%1\"; font-weight: bold; color: \"%2\";'>%3</div>"_s.arg(highlightedBaseColor, highlightedBaseTextColor, article->title());
|
||||
if (article->date().isValid())
|
||||
html += u"<div style='background-color: \"%1\";'><b>%2</b>%3</div>"_s.arg(alternateBaseColor, tr("Date: "), QLocale::system().toString(article->date().toLocalTime()));
|
||||
if (m_feedListWidget->currentItem() == m_feedListWidget->stickyUnreadItem())
|
||||
html += u"<div style='background-color: \"%1\";'><b>%2</b>%3</div>"_s.arg(alternateBaseColor, tr("Feed: "), article->feed()->title());
|
||||
if (!article->author().isEmpty())
|
||||
html += u"<div style='background-color: \"%1\";'><b>%2</b>%3</div>"_s.arg(alternateBaseColor, tr("Author: "), article->author());
|
||||
html += u"</div>"
|
||||
u"<div style='margin-left: 5px; margin-right: 5px;'>";
|
||||
if (Qt::mightBeRichText(article->description()))
|
||||
{
|
||||
html += article->description();
|
||||
}
|
||||
else
|
||||
{
|
||||
QString description = article->description();
|
||||
QRegularExpression rx;
|
||||
// If description is plain text, replace BBCode tags with HTML and wrap everything in <pre></pre> so it looks nice
|
||||
rx.setPatternOptions(QRegularExpression::InvertedGreedinessOption
|
||||
| QRegularExpression::CaseInsensitiveOption);
|
||||
|
||||
rx.setPattern(u"\\[img\\](.+)\\[/img\\]"_s);
|
||||
description = description.replace(rx, u"<img src=\"\\1\">"_s);
|
||||
|
||||
rx.setPattern(u"\\[url=(\")?(.+)\\1\\]"_s);
|
||||
description = description.replace(rx, u"<a href=\"\\2\">"_s);
|
||||
description = description.replace(u"[/url]"_s, u"</a>"_s, Qt::CaseInsensitive);
|
||||
|
||||
rx.setPattern(u"\\[(/)?([bius])\\]"_s);
|
||||
description = description.replace(rx, u"<\\1\\2>"_s);
|
||||
|
||||
rx.setPattern(u"\\[color=(\")?(.+)\\1\\]"_s);
|
||||
description = description.replace(rx, u"<span style=\"color:\\2\">"_s);
|
||||
description = description.replace(u"[/color]"_s, u"</span>"_s, Qt::CaseInsensitive);
|
||||
|
||||
rx.setPattern(u"\\[size=(\")?(.+)\\d\\1\\]"_s);
|
||||
description = description.replace(rx, u"<span style=\"font-size:\\2px\">"_s);
|
||||
description = description.replace(u"[/size]"_s, u"</span>"_s, Qt::CaseInsensitive);
|
||||
|
||||
html += u"<pre>" + description + u"</pre>";
|
||||
}
|
||||
html += u"</div>";
|
||||
m_ui->textBrowser->setHtml(html);
|
||||
renderArticle(article);
|
||||
}
|
||||
|
||||
void RSSWidget::saveSlidersPosition()
|
||||
@@ -590,3 +543,73 @@ void RSSWidget::handleUnreadCountChanged()
|
||||
{
|
||||
emit unreadCountUpdated(RSS::Session::instance()->rootFolder()->unreadCount());
|
||||
}
|
||||
|
||||
bool RSSWidget::eventFilter(QObject *obj, QEvent *event)
|
||||
{
|
||||
if ((obj == m_ui->textBrowser) && (event->type() == QEvent::PaletteChange))
|
||||
{
|
||||
QListWidgetItem *currentItem = m_articleListWidget->currentItem();
|
||||
if (currentItem)
|
||||
{
|
||||
const RSS::Article *article = m_articleListWidget->getRSSArticle(currentItem);
|
||||
renderArticle(article);
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
void RSSWidget::renderArticle(const RSS::Article *article) const
|
||||
{
|
||||
Q_ASSERT(article);
|
||||
|
||||
const QString highlightedBaseColor = m_ui->textBrowser->palette().color(QPalette::Active, QPalette::Highlight).name();
|
||||
const QString highlightedBaseTextColor = m_ui->textBrowser->palette().color(QPalette::Active, QPalette::HighlightedText).name();
|
||||
const QString alternateBaseColor = m_ui->textBrowser->palette().color(QPalette::Active, QPalette::AlternateBase).name();
|
||||
|
||||
QString html =
|
||||
u"<div style='border: 2px solid red; margin-left: 5px; margin-right: 5px; margin-bottom: 5px;'>" +
|
||||
u"<div style='background-color: \"%1\"; font-weight: bold; color: \"%2\";'>%3</div>"_s.arg(highlightedBaseColor, highlightedBaseTextColor, article->title());
|
||||
if (article->date().isValid())
|
||||
html += u"<div style='background-color: \"%1\";'><b>%2</b>%3</div>"_s.arg(alternateBaseColor, tr("Date: "), QLocale::system().toString(article->date().toLocalTime()));
|
||||
if (m_feedListWidget->currentItem() == m_feedListWidget->stickyUnreadItem())
|
||||
html += u"<div style='background-color: \"%1\";'><b>%2</b>%3</div>"_s.arg(alternateBaseColor, tr("Feed: "), article->feed()->title());
|
||||
if (!article->author().isEmpty())
|
||||
html += u"<div style='background-color: \"%1\";'><b>%2</b>%3</div>"_s.arg(alternateBaseColor, tr("Author: "), article->author());
|
||||
html += u"</div>"
|
||||
u"<div style='margin-left: 5px; margin-right: 5px;'>";
|
||||
if (Qt::mightBeRichText(article->description()))
|
||||
{
|
||||
html += article->description();
|
||||
}
|
||||
else
|
||||
{
|
||||
QString description = article->description();
|
||||
QRegularExpression rx;
|
||||
// If description is plain text, replace BBCode tags with HTML and wrap everything in <pre></pre> so it looks nice
|
||||
rx.setPatternOptions(QRegularExpression::InvertedGreedinessOption
|
||||
| QRegularExpression::CaseInsensitiveOption);
|
||||
|
||||
rx.setPattern(u"\\[img\\](.+)\\[/img\\]"_s);
|
||||
description = description.replace(rx, u"<img src=\"\\1\">"_s);
|
||||
|
||||
rx.setPattern(u"\\[url=(\")?(.+)\\1\\]"_s);
|
||||
description = description.replace(rx, u"<a href=\"\\2\">"_s);
|
||||
description = description.replace(u"[/url]"_s, u"</a>"_s, Qt::CaseInsensitive);
|
||||
|
||||
rx.setPattern(u"\\[(/)?([bius])\\]"_s);
|
||||
description = description.replace(rx, u"<\\1\\2>"_s);
|
||||
|
||||
rx.setPattern(u"\\[color=(\")?(.+)\\1\\]"_s);
|
||||
description = description.replace(rx, u"<span style=\"color:\\2\">"_s);
|
||||
description = description.replace(u"[/color]"_s, u"</span>"_s, Qt::CaseInsensitive);
|
||||
|
||||
rx.setPattern(u"\\[size=(\")?(.+)\\d\\1\\]"_s);
|
||||
description = description.replace(rx, u"<span style=\"font-size:\\2px\">"_s);
|
||||
description = description.replace(u"[/size]"_s, u"</span>"_s, Qt::CaseInsensitive);
|
||||
|
||||
html += u"<pre>" + description + u"</pre>";
|
||||
}
|
||||
html += u"</div>";
|
||||
m_ui->textBrowser->setHtml(html);
|
||||
}
|
||||
|
||||
@@ -40,6 +40,11 @@ class QTreeWidgetItem;
|
||||
class ArticleListWidget;
|
||||
class FeedListWidget;
|
||||
|
||||
namespace RSS
|
||||
{
|
||||
class Article;
|
||||
}
|
||||
|
||||
namespace Ui
|
||||
{
|
||||
class RSSWidget;
|
||||
@@ -85,6 +90,9 @@ private slots:
|
||||
void handleUnreadCountChanged();
|
||||
|
||||
private:
|
||||
bool eventFilter(QObject *obj, QEvent *event) override;
|
||||
void renderArticle(const RSS::Article *article) const;
|
||||
|
||||
Ui::RSSWidget *m_ui = nullptr;
|
||||
ArticleListWidget *m_articleListWidget = nullptr;
|
||||
FeedListWidget *m_feedListWidget = nullptr;
|
||||
|
||||
@@ -84,11 +84,7 @@ TorrentCreatorDialog::TorrentCreatorDialog(QWidget *parent, const Path &defaultP
|
||||
m_ui->setupUi(this);
|
||||
|
||||
m_ui->comboPieceSize->addItem(tr("Auto"), 0);
|
||||
#ifdef QBT_USES_LIBTORRENT2
|
||||
for (int i = 4; i <= 18; ++i)
|
||||
#else
|
||||
for (int i = 4; i <= 17; ++i)
|
||||
#endif
|
||||
{
|
||||
const int size = 1024 << i;
|
||||
const QString displaySize = Utils::Misc::friendlyUnit(size, false, 0);
|
||||
|
||||
@@ -80,6 +80,14 @@ UIThemeManager::UIThemeManager()
|
||||
, m_useSystemIcons {Preferences::instance()->useSystemIcons()}
|
||||
#endif
|
||||
{
|
||||
#ifdef Q_OS_WIN
|
||||
if (const QString styleName = Preferences::instance()->getStyle(); styleName.compare(u"system", Qt::CaseInsensitive) != 0)
|
||||
{
|
||||
if (!QApplication::setStyle(styleName.isEmpty() ? u"Fusion"_s : styleName))
|
||||
LogMsg(tr("Set app style failed. Unknown style: \"%1\"").arg(styleName), Log::WARNING);
|
||||
}
|
||||
#endif
|
||||
|
||||
// NOTE: Qt::QueuedConnection can be omitted as soon as support for Qt 6.5 is dropped
|
||||
connect(QApplication::styleHints(), &QStyleHints::colorSchemeChanged, this, &UIThemeManager::onColorSchemeChanged, Qt::QueuedConnection);
|
||||
|
||||
|
||||
Reference in New Issue
Block a user