From f4125601de02a1e820965b4563b46aed234aa469 Mon Sep 17 00:00:00 2001 From: Vladimir Golovnev Date: Wed, 21 Aug 2024 15:08:14 +0300 Subject: [PATCH 1/5] Refresh search results colors once color scheme is changed * Refresh search results colors once color scheme is changed * Improve color of visited search result items PR #21189. Closes #21187. --- src/gui/search/searchjobwidget.cpp | 44 ++++++++++++++++++++++++++++-- src/gui/search/searchjobwidget.h | 6 ++-- 2 files changed, 45 insertions(+), 5 deletions(-) diff --git a/src/gui/search/searchjobwidget.cpp b/src/gui/search/searchjobwidget.cpp index e8aa99ead..512cd58bc 100644 --- a/src/gui/search/searchjobwidget.cpp +++ b/src/gui/search/searchjobwidget.cpp @@ -1,6 +1,6 @@ /* * Bittorrent Client using Qt and libtorrent. - * Copyright (C) 2018 Vladimir Golovnev + * Copyright (C) 2018-2024 Vladimir Golovnev * Copyright (C) 2006 Christophe Dumez * * This program is free software; you can redistribute it and/or @@ -50,6 +50,19 @@ #include "searchsortmodel.h" #include "ui_searchjobwidget.h" +namespace +{ + enum DataRole + { + LinkVisitedRole = Qt::UserRole + 100 + }; + + QColor visitedRowColor() + { + return QApplication::palette().color(QPalette::Disabled, QPalette::WindowText); + } +} + SearchJobWidget::SearchJobWidget(SearchHandler *searchHandler, IGUIApplication *app, QWidget *parent) : GUIApplicationComponent(app, parent) , m_ui {new Ui::SearchJobWidget} @@ -158,6 +171,8 @@ SearchJobWidget::SearchJobWidget(SearchHandler *searchHandler, IGUIApplication * connect(this, &QObject::destroyed, searchHandler, &QObject::deleteLater); setStatusTip(statusText(m_status)); + + connect(UIThemeManager::instance(), &UIThemeManager::themeChanged, this, &SearchJobWidget::onUIThemeChanged); } SearchJobWidget::~SearchJobWidget() @@ -179,9 +194,31 @@ QHeaderView *SearchJobWidget::header() const // Set the color of a row in data model void SearchJobWidget::setRowColor(int row, const QColor &color) { - m_proxyModel->setDynamicSortFilter(false); for (int i = 0; i < m_proxyModel->columnCount(); ++i) m_proxyModel->setData(m_proxyModel->index(row, i), color, Qt::ForegroundRole); +} + +void SearchJobWidget::setRowVisited(const int row) +{ + m_proxyModel->setDynamicSortFilter(false); + + m_proxyModel->setData(m_proxyModel->index(row, 0), true, LinkVisitedRole); + setRowColor(row, visitedRowColor()); + + m_proxyModel->setDynamicSortFilter(true); +} + +void SearchJobWidget::onUIThemeChanged() +{ + m_proxyModel->setDynamicSortFilter(false); + + for (int row = 0; row < m_proxyModel->rowCount(); ++row) + { + const QVariant userData = m_proxyModel->data(m_proxyModel->index(row, 0), LinkVisitedRole); + const bool isVisited = userData.toBool(); + if (isVisited) + setRowColor(row, visitedRowColor()); + } m_proxyModel->setDynamicSortFilter(true); } @@ -284,7 +321,8 @@ void SearchJobWidget::downloadTorrent(const QModelIndex &rowIndex, const AddTorr , this, [this, option](const QString &source) { addTorrentToSession(source, option); }); connect(downloadHandler, &SearchDownloadHandler::downloadFinished, downloadHandler, &SearchDownloadHandler::deleteLater); } - setRowColor(rowIndex.row(), QApplication::palette().color(QPalette::LinkVisited)); + + setRowVisited(rowIndex.row()); } void SearchJobWidget::addTorrentToSession(const QString &source, const AddTorrentOption option) diff --git a/src/gui/search/searchjobwidget.h b/src/gui/search/searchjobwidget.h index f597c03af..0a84eeb34 100644 --- a/src/gui/search/searchjobwidget.h +++ b/src/gui/search/searchjobwidget.h @@ -1,6 +1,6 @@ /* * Bittorrent Client using Qt and libtorrent. - * Copyright (C) 2018 Vladimir Golovnev + * Copyright (C) 2018-2024 Vladimir Golovnev * Copyright (C) 2006 Christophe Dumez * * This program is free software; you can redistribute it and/or @@ -113,8 +113,10 @@ private: void fillFilterComboBoxes(); NameFilteringMode filteringMode() const; QHeaderView *header() const; - void setRowColor(int row, const QColor &color); int visibleColumnsCount() const; + void setRowColor(int row, const QColor &color); + void setRowVisited(int row); + void onUIThemeChanged(); void downloadTorrents(AddTorrentOption option = AddTorrentOption::Default); void openTorrentPages() const; From 64506f16bd4f88d12b79f711bca46272306c0b73 Mon Sep 17 00:00:00 2001 From: skomerko <168652295+skomerko@users.noreply.github.com> Date: Mon, 26 Aug 2024 12:10:05 +0200 Subject: [PATCH 2/5] WebUI: Provide 'Use Category paths in Manual Mode' option PR #21223. --- src/webui/www/private/views/preferences.html | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/src/webui/www/private/views/preferences.html b/src/webui/www/private/views/preferences.html index 966ab579b..006d62518 100644 --- a/src/webui/www/private/views/preferences.html +++ b/src/webui/www/private/views/preferences.html @@ -145,6 +145,10 @@ +
+ + +
@@ -2045,6 +2049,7 @@ Use ';' to split multiple entries. Can use wildcard '*'.)QBT_TR[CONTEXT=OptionsD $("save_path_changed_tmm_combobox").setProperty("value", pref.save_path_changed_tmm_enabled); $("category_changed_tmm_combobox").setProperty("value", pref.category_changed_tmm_enabled); $("use_subcategories_checkbox").setProperty("checked", pref.use_subcategories); + $("categoryPathsManualModeCheckbox").setProperty("checked", pref.use_category_paths_in_manual_mode); $("savepath_text").setProperty("value", pref.save_path); $("temppath_checkbox").setProperty("checked", pref.temp_path_enabled); $("temppath_text").setProperty("value", pref.temp_path); @@ -2429,6 +2434,7 @@ Use ';' to split multiple entries. Can use wildcard '*'.)QBT_TR[CONTEXT=OptionsD settings["save_path_changed_tmm_enabled"] = ($("save_path_changed_tmm_combobox").getProperty("value") === "true"); settings["category_changed_tmm_enabled"] = ($("category_changed_tmm_combobox").getProperty("value") === "true"); settings["use_subcategories"] = $("use_subcategories_checkbox").getProperty("checked"); + settings["use_category_paths_in_manual_mode"] = $("categoryPathsManualModeCheckbox").getProperty("checked"); settings["save_path"] = $("savepath_text").getProperty("value"); settings["temp_path_enabled"] = $("temppath_checkbox").getProperty("checked"); settings["temp_path"] = $("temppath_text").getProperty("value"); From d4ccf3001c3fad16d84a632149554e02e65698ba Mon Sep 17 00:00:00 2001 From: Prince Gupta <34717789+jagannatharjun@users.noreply.github.com> Date: Mon, 2 Sep 2024 10:41:35 +0530 Subject: [PATCH 3/5] Fix highlighted piece color PR #20971. --- src/gui/properties/piecesbar.cpp | 11 ++++++++--- src/gui/properties/piecesbar.h | 2 ++ 2 files changed, 10 insertions(+), 3 deletions(-) diff --git a/src/gui/properties/piecesbar.cpp b/src/gui/properties/piecesbar.cpp index 065fd26e2..33e04695a 100644 --- a/src/gui/properties/piecesbar.cpp +++ b/src/gui/properties/piecesbar.cpp @@ -195,10 +195,8 @@ void PiecesBar::paintEvent(QPaintEvent *) if (!m_highlightedRegion.isNull()) { - QColor highlightColor {this->palette().color(QPalette::Active, QPalette::Highlight)}; - highlightColor.setAlphaF(0.35f); QRect targetHighlightRect {m_highlightedRegion.adjusted(borderWidth, borderWidth, borderWidth, height() - 2 * borderWidth)}; - painter.fillRect(targetHighlightRect, highlightColor); + painter.fillRect(targetHighlightRect, highlightedPieceColor()); } QPainterPath border; @@ -231,6 +229,13 @@ QColor PiecesBar::pieceColor() const return palette().color(QPalette::Active, QPalette::Highlight); } +QColor PiecesBar::highlightedPieceColor() const +{ + QColor col = palette().color(QPalette::Highlight).darker(); + col.setAlphaF(0.35); + return col; +} + QColor PiecesBar::colorBoxBorderColor() const { return palette().color(QPalette::Active, QPalette::ToolTipText); diff --git a/src/gui/properties/piecesbar.h b/src/gui/properties/piecesbar.h index c7f74d2ba..2474753e6 100644 --- a/src/gui/properties/piecesbar.h +++ b/src/gui/properties/piecesbar.h @@ -68,7 +68,9 @@ protected: QColor backgroundColor() const; QColor borderColor() const; QColor pieceColor() const; + QColor highlightedPieceColor() const; QColor colorBoxBorderColor() const; + const QVector &pieceColors() const; // mix two colors by light model, ratio <0, 1> From 3e96048ee40d04b9b6e8e141df919828d2e0cef7 Mon Sep 17 00:00:00 2001 From: Vladimir Golovnev Date: Fri, 6 Sep 2024 16:28:22 +0300 Subject: [PATCH 4/5] Apply "merge trackers" logic regardless of way the torrent is added PR #21299. --- src/base/bittorrent/sessionimpl.cpp | 33 ++++++++++++++++++++++++++++- src/base/net/smtp.h | 1 - 2 files changed, 32 insertions(+), 2 deletions(-) diff --git a/src/base/bittorrent/sessionimpl.cpp b/src/base/bittorrent/sessionimpl.cpp index 8c21682e8..17c704442 100644 --- a/src/base/bittorrent/sessionimpl.cpp +++ b/src/base/bittorrent/sessionimpl.cpp @@ -2711,8 +2711,39 @@ bool SessionImpl::addTorrent_impl(const TorrentDescriptor &source, const AddTorr if (m_loadingTorrents.contains(id) || (infoHash.isHybrid() && m_loadingTorrents.contains(altID))) return false; - if (findTorrent(infoHash)) + if (Torrent *torrent = findTorrent(infoHash)) + { + // a duplicate torrent is being added + + if (hasMetadata) + { + // Trying to set metadata to existing torrent in case if it has none + torrent->setMetadata(*source.info()); + } + + if (!isMergeTrackersEnabled()) + { + LogMsg(tr("Detected an attempt to add a duplicate torrent. Existing torrent: %1. Result: %2") + .arg(torrent->name(), tr("Merging of trackers is disabled"))); + return false; + } + + const bool isPrivate = torrent->isPrivate() || (hasMetadata && source.info()->isPrivate()); + if (isPrivate) + { + LogMsg(tr("Detected an attempt to add a duplicate torrent. Existing torrent: %1. Result: %2") + .arg(torrent->name(), tr("Trackers cannot be merged because it is a private torrent"))); + return false; + } + + // merge trackers and web seeds + torrent->addTrackers(source.trackers()); + torrent->addUrlSeeds(source.urlSeeds()); + + LogMsg(tr("Detected an attempt to add a duplicate torrent. Existing torrent: %1. Result: %2") + .arg(torrent->name(), tr("Trackers are merged from new source"))); return false; + } // It looks illogical that we don't just use an existing handle, // but as previous experience has shown, it actually creates unnecessary diff --git a/src/base/net/smtp.h b/src/base/net/smtp.h index 28c7cadeb..d58d8322b 100644 --- a/src/base/net/smtp.h +++ b/src/base/net/smtp.h @@ -43,7 +43,6 @@ class QSslSocket; #else class QTcpSocket; #endif -class QTextCodec; namespace Net { From 04f6a565f3904ede2fa90298a57479e6e2577ad5 Mon Sep 17 00:00:00 2001 From: skomerko <168652295+skomerko@users.noreply.github.com> Date: Wed, 11 Sep 2024 18:15:46 +0200 Subject: [PATCH 5/5] WebUI: Provide 'Merge trackers to existing torrent' option PR #21302. --- src/webui/www/private/views/preferences.html | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/src/webui/www/private/views/preferences.html b/src/webui/www/private/views/preferences.html index 006d62518..b46247f25 100644 --- a/src/webui/www/private/views/preferences.html +++ b/src/webui/www/private/views/preferences.html @@ -70,6 +70,13 @@ +
+ QBT_TR(When duplicate torrent is being added)QBT_TR[CONTEXT=OptionsDialog] +
+ + +
+
@@ -2037,6 +2044,7 @@ Use ';' to split multiple entries. Can use wildcard '*'.)QBT_TR[CONTEXT=OptionsD break; } $("stopConditionSelect").getChildren("option")[index].selected = true; + $("mergeTrackersInput").setProperty("checked", pref.merge_trackers); $("deletetorrentfileafter_checkbox").setProperty("checked", pref.auto_delete_mode); $("preallocateall_checkbox").setProperty("checked", pref.preallocate_all); @@ -2422,6 +2430,7 @@ Use ';' to split multiple entries. Can use wildcard '*'.)QBT_TR[CONTEXT=OptionsD settings["add_to_top_of_queue"] = $("addToTopOfQueueCheckbox").getProperty("checked"); settings["add_stopped_enabled"] = $("dontstartdownloads_checkbox").getProperty("checked"); settings["torrent_stop_condition"] = $("stopConditionSelect").getSelected()[0].getProperty("value"); + settings["merge_trackers"] = $("mergeTrackersInput").getProperty("checked"); settings["auto_delete_mode"] = Number($("deletetorrentfileafter_checkbox").getProperty("checked")); settings["preallocate_all"] = $("preallocateall_checkbox").getProperty("checked");