mirror of
https://github.com/qbittorrent/qBittorrent.git
synced 2024-11-29 05:48:47 +03:00
commit
f9a2b02a8d
7 changed files with 102 additions and 10 deletions
|
@ -2711,8 +2711,39 @@ bool SessionImpl::addTorrent_impl(const TorrentDescriptor &source, const AddTorr
|
||||||
if (m_loadingTorrents.contains(id) || (infoHash.isHybrid() && m_loadingTorrents.contains(altID)))
|
if (m_loadingTorrents.contains(id) || (infoHash.isHybrid() && m_loadingTorrents.contains(altID)))
|
||||||
return false;
|
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;
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
// It looks illogical that we don't just use an existing handle,
|
// It looks illogical that we don't just use an existing handle,
|
||||||
// but as previous experience has shown, it actually creates unnecessary
|
// but as previous experience has shown, it actually creates unnecessary
|
||||||
|
|
|
@ -43,7 +43,6 @@ class QSslSocket;
|
||||||
#else
|
#else
|
||||||
class QTcpSocket;
|
class QTcpSocket;
|
||||||
#endif
|
#endif
|
||||||
class QTextCodec;
|
|
||||||
|
|
||||||
namespace Net
|
namespace Net
|
||||||
{
|
{
|
||||||
|
|
|
@ -195,10 +195,8 @@ void PiecesBar::paintEvent(QPaintEvent *)
|
||||||
|
|
||||||
if (!m_highlightedRegion.isNull())
|
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)};
|
QRect targetHighlightRect {m_highlightedRegion.adjusted(borderWidth, borderWidth, borderWidth, height() - 2 * borderWidth)};
|
||||||
painter.fillRect(targetHighlightRect, highlightColor);
|
painter.fillRect(targetHighlightRect, highlightedPieceColor());
|
||||||
}
|
}
|
||||||
|
|
||||||
QPainterPath border;
|
QPainterPath border;
|
||||||
|
@ -231,6 +229,13 @@ QColor PiecesBar::pieceColor() const
|
||||||
return palette().color(QPalette::Active, QPalette::Highlight);
|
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
|
QColor PiecesBar::colorBoxBorderColor() const
|
||||||
{
|
{
|
||||||
return palette().color(QPalette::Active, QPalette::ToolTipText);
|
return palette().color(QPalette::Active, QPalette::ToolTipText);
|
||||||
|
|
|
@ -68,7 +68,9 @@ protected:
|
||||||
QColor backgroundColor() const;
|
QColor backgroundColor() const;
|
||||||
QColor borderColor() const;
|
QColor borderColor() const;
|
||||||
QColor pieceColor() const;
|
QColor pieceColor() const;
|
||||||
|
QColor highlightedPieceColor() const;
|
||||||
QColor colorBoxBorderColor() const;
|
QColor colorBoxBorderColor() const;
|
||||||
|
|
||||||
const QVector<QRgb> &pieceColors() const;
|
const QVector<QRgb> &pieceColors() const;
|
||||||
|
|
||||||
// mix two colors by light model, ratio <0, 1>
|
// mix two colors by light model, ratio <0, 1>
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
/*
|
/*
|
||||||
* Bittorrent Client using Qt and libtorrent.
|
* Bittorrent Client using Qt and libtorrent.
|
||||||
* Copyright (C) 2018 Vladimir Golovnev <glassez@yandex.ru>
|
* Copyright (C) 2018-2024 Vladimir Golovnev <glassez@yandex.ru>
|
||||||
* Copyright (C) 2006 Christophe Dumez <chris@qbittorrent.org>
|
* Copyright (C) 2006 Christophe Dumez <chris@qbittorrent.org>
|
||||||
*
|
*
|
||||||
* This program is free software; you can redistribute it and/or
|
* This program is free software; you can redistribute it and/or
|
||||||
|
@ -50,6 +50,19 @@
|
||||||
#include "searchsortmodel.h"
|
#include "searchsortmodel.h"
|
||||||
#include "ui_searchjobwidget.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)
|
SearchJobWidget::SearchJobWidget(SearchHandler *searchHandler, IGUIApplication *app, QWidget *parent)
|
||||||
: GUIApplicationComponent(app, parent)
|
: GUIApplicationComponent(app, parent)
|
||||||
, m_ui {new Ui::SearchJobWidget}
|
, m_ui {new Ui::SearchJobWidget}
|
||||||
|
@ -158,6 +171,8 @@ SearchJobWidget::SearchJobWidget(SearchHandler *searchHandler, IGUIApplication *
|
||||||
connect(this, &QObject::destroyed, searchHandler, &QObject::deleteLater);
|
connect(this, &QObject::destroyed, searchHandler, &QObject::deleteLater);
|
||||||
|
|
||||||
setStatusTip(statusText(m_status));
|
setStatusTip(statusText(m_status));
|
||||||
|
|
||||||
|
connect(UIThemeManager::instance(), &UIThemeManager::themeChanged, this, &SearchJobWidget::onUIThemeChanged);
|
||||||
}
|
}
|
||||||
|
|
||||||
SearchJobWidget::~SearchJobWidget()
|
SearchJobWidget::~SearchJobWidget()
|
||||||
|
@ -179,9 +194,31 @@ QHeaderView *SearchJobWidget::header() const
|
||||||
// Set the color of a row in data model
|
// Set the color of a row in data model
|
||||||
void SearchJobWidget::setRowColor(int row, const QColor &color)
|
void SearchJobWidget::setRowColor(int row, const QColor &color)
|
||||||
{
|
{
|
||||||
m_proxyModel->setDynamicSortFilter(false);
|
|
||||||
for (int i = 0; i < m_proxyModel->columnCount(); ++i)
|
for (int i = 0; i < m_proxyModel->columnCount(); ++i)
|
||||||
m_proxyModel->setData(m_proxyModel->index(row, i), color, Qt::ForegroundRole);
|
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);
|
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); });
|
, this, [this, option](const QString &source) { addTorrentToSession(source, option); });
|
||||||
connect(downloadHandler, &SearchDownloadHandler::downloadFinished, downloadHandler, &SearchDownloadHandler::deleteLater);
|
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)
|
void SearchJobWidget::addTorrentToSession(const QString &source, const AddTorrentOption option)
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
/*
|
/*
|
||||||
* Bittorrent Client using Qt and libtorrent.
|
* Bittorrent Client using Qt and libtorrent.
|
||||||
* Copyright (C) 2018 Vladimir Golovnev <glassez@yandex.ru>
|
* Copyright (C) 2018-2024 Vladimir Golovnev <glassez@yandex.ru>
|
||||||
* Copyright (C) 2006 Christophe Dumez <chris@qbittorrent.org>
|
* Copyright (C) 2006 Christophe Dumez <chris@qbittorrent.org>
|
||||||
*
|
*
|
||||||
* This program is free software; you can redistribute it and/or
|
* This program is free software; you can redistribute it and/or
|
||||||
|
@ -113,8 +113,10 @@ private:
|
||||||
void fillFilterComboBoxes();
|
void fillFilterComboBoxes();
|
||||||
NameFilteringMode filteringMode() const;
|
NameFilteringMode filteringMode() const;
|
||||||
QHeaderView *header() const;
|
QHeaderView *header() const;
|
||||||
void setRowColor(int row, const QColor &color);
|
|
||||||
int visibleColumnsCount() const;
|
int visibleColumnsCount() const;
|
||||||
|
void setRowColor(int row, const QColor &color);
|
||||||
|
void setRowVisited(int row);
|
||||||
|
void onUIThemeChanged();
|
||||||
|
|
||||||
void downloadTorrents(AddTorrentOption option = AddTorrentOption::Default);
|
void downloadTorrents(AddTorrentOption option = AddTorrentOption::Default);
|
||||||
void openTorrentPages() const;
|
void openTorrentPages() const;
|
||||||
|
|
|
@ -70,6 +70,13 @@
|
||||||
<option value="FilesChecked">QBT_TR(Files checked)QBT_TR[CONTEXT=OptionsDialog]</option>
|
<option value="FilesChecked">QBT_TR(Files checked)QBT_TR[CONTEXT=OptionsDialog]</option>
|
||||||
</select>
|
</select>
|
||||||
</div>
|
</div>
|
||||||
|
<fieldset class="settings">
|
||||||
|
<legend>QBT_TR(When duplicate torrent is being added)QBT_TR[CONTEXT=OptionsDialog]</legend>
|
||||||
|
<div class="formRow">
|
||||||
|
<input type="checkbox" id="mergeTrackersInput">
|
||||||
|
<label for="mergeTrackersInput">QBT_TR(Merge trackers to existing torrent)QBT_TR[CONTEXT=OptionsDialog]</label>
|
||||||
|
</div>
|
||||||
|
</fieldset>
|
||||||
<div class="formRow">
|
<div class="formRow">
|
||||||
<input type="checkbox" id="deletetorrentfileafter_checkbox" />
|
<input type="checkbox" id="deletetorrentfileafter_checkbox" />
|
||||||
<label for="deletetorrentfileafter_checkbox">QBT_TR(Delete .torrent files afterwards)QBT_TR[CONTEXT=OptionsDialog]</label>
|
<label for="deletetorrentfileafter_checkbox">QBT_TR(Delete .torrent files afterwards)QBT_TR[CONTEXT=OptionsDialog]</label>
|
||||||
|
@ -145,6 +152,10 @@
|
||||||
<input type="checkbox" id="use_subcategories_checkbox" />
|
<input type="checkbox" id="use_subcategories_checkbox" />
|
||||||
<label for="use_subcategories_checkbox">QBT_TR(Use Subcategories)QBT_TR[CONTEXT=OptionsDialog]</label>
|
<label for="use_subcategories_checkbox">QBT_TR(Use Subcategories)QBT_TR[CONTEXT=OptionsDialog]</label>
|
||||||
</div>
|
</div>
|
||||||
|
<div class="formRow">
|
||||||
|
<input type="checkbox" id="categoryPathsManualModeCheckbox" title="QBT_TR(Resolve relative Save Path against appropriate Category path instead of Default one)QBT_TR[CONTEXT=OptionsDialog]">
|
||||||
|
<label for="categoryPathsManualModeCheckbox">QBT_TR(Use Category paths in Manual Mode)QBT_TR[CONTEXT=OptionsDialog]</label>
|
||||||
|
</div>
|
||||||
<table>
|
<table>
|
||||||
<tr>
|
<tr>
|
||||||
<td>
|
<td>
|
||||||
|
@ -2033,6 +2044,7 @@ Use ';' to split multiple entries. Can use wildcard '*'.)QBT_TR[CONTEXT=OptionsD
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
$("stopConditionSelect").getChildren("option")[index].selected = true;
|
$("stopConditionSelect").getChildren("option")[index].selected = true;
|
||||||
|
$("mergeTrackersInput").setProperty("checked", pref.merge_trackers);
|
||||||
$("deletetorrentfileafter_checkbox").setProperty("checked", pref.auto_delete_mode);
|
$("deletetorrentfileafter_checkbox").setProperty("checked", pref.auto_delete_mode);
|
||||||
|
|
||||||
$("preallocateall_checkbox").setProperty("checked", pref.preallocate_all);
|
$("preallocateall_checkbox").setProperty("checked", pref.preallocate_all);
|
||||||
|
@ -2045,6 +2057,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);
|
$("save_path_changed_tmm_combobox").setProperty("value", pref.save_path_changed_tmm_enabled);
|
||||||
$("category_changed_tmm_combobox").setProperty("value", pref.category_changed_tmm_enabled);
|
$("category_changed_tmm_combobox").setProperty("value", pref.category_changed_tmm_enabled);
|
||||||
$("use_subcategories_checkbox").setProperty("checked", pref.use_subcategories);
|
$("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);
|
$("savepath_text").setProperty("value", pref.save_path);
|
||||||
$("temppath_checkbox").setProperty("checked", pref.temp_path_enabled);
|
$("temppath_checkbox").setProperty("checked", pref.temp_path_enabled);
|
||||||
$("temppath_text").setProperty("value", pref.temp_path);
|
$("temppath_text").setProperty("value", pref.temp_path);
|
||||||
|
@ -2417,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_to_top_of_queue"] = $("addToTopOfQueueCheckbox").getProperty("checked");
|
||||||
settings["add_stopped_enabled"] = $("dontstartdownloads_checkbox").getProperty("checked");
|
settings["add_stopped_enabled"] = $("dontstartdownloads_checkbox").getProperty("checked");
|
||||||
settings["torrent_stop_condition"] = $("stopConditionSelect").getSelected()[0].getProperty("value");
|
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["auto_delete_mode"] = Number($("deletetorrentfileafter_checkbox").getProperty("checked"));
|
||||||
|
|
||||||
settings["preallocate_all"] = $("preallocateall_checkbox").getProperty("checked");
|
settings["preallocate_all"] = $("preallocateall_checkbox").getProperty("checked");
|
||||||
|
@ -2429,6 +2443,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["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["category_changed_tmm_enabled"] = ($("category_changed_tmm_combobox").getProperty("value") === "true");
|
||||||
settings["use_subcategories"] = $("use_subcategories_checkbox").getProperty("checked");
|
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["save_path"] = $("savepath_text").getProperty("value");
|
||||||
settings["temp_path_enabled"] = $("temppath_checkbox").getProperty("checked");
|
settings["temp_path_enabled"] = $("temppath_checkbox").getProperty("checked");
|
||||||
settings["temp_path"] = $("temppath_text").getProperty("value");
|
settings["temp_path"] = $("temppath_text").getProperty("value");
|
||||||
|
|
Loading…
Reference in a new issue