diff --git a/src/base/bittorrent/torrenthandle.h b/src/base/bittorrent/torrenthandle.h index 76234af08..e753e2bb7 100644 --- a/src/base/bittorrent/torrenthandle.h +++ b/src/base/bittorrent/torrenthandle.h @@ -240,6 +240,9 @@ namespace BitTorrent virtual int downloadLimit() const = 0; virtual int uploadLimit() const = 0; virtual bool superSeeding() const = 0; + virtual bool isDHTDisabled() const = 0; + virtual bool isPEXDisabled() const = 0; + virtual bool isLSDDisabled() const = 0; virtual QVector peers() const = 0; virtual QBitArray pieces() const = 0; virtual QBitArray downloadingPieces() const = 0; @@ -279,6 +282,9 @@ namespace BitTorrent virtual void setUploadLimit(int limit) = 0; virtual void setDownloadLimit(int limit) = 0; virtual void setSuperSeeding(bool enable) = 0; + virtual void setDHTDisabled(bool disable) = 0; + virtual void setPEXDisabled(bool disable) = 0; + virtual void setLSDDisabled(bool disable) = 0; virtual void flushCache() const = 0; virtual void addTrackers(const QVector &trackers) = 0; virtual void replaceTrackers(const QVector &trackers) = 0; diff --git a/src/base/bittorrent/torrenthandleimpl.cpp b/src/base/bittorrent/torrenthandleimpl.cpp index 8db5a485e..8bca5d3e7 100644 --- a/src/base/bittorrent/torrenthandleimpl.cpp +++ b/src/base/bittorrent/torrenthandleimpl.cpp @@ -1028,6 +1028,21 @@ bool TorrentHandleImpl::superSeeding() const return static_cast(m_nativeStatus.flags & lt::torrent_flags::super_seeding); } +bool TorrentHandleImpl::isDHTDisabled() const +{ + return static_cast(m_nativeStatus.flags & lt::torrent_flags::disable_dht); +} + +bool TorrentHandleImpl::isPEXDisabled() const +{ + return static_cast(m_nativeStatus.flags & lt::torrent_flags::disable_pex); +} + +bool TorrentHandleImpl::isLSDDisabled() const +{ + return static_cast(m_nativeStatus.flags & lt::torrent_flags::disable_lsd); +} + QVector TorrentHandleImpl::peers() const { std::vector nativePeers; @@ -1966,10 +1981,50 @@ void TorrentHandleImpl::setDownloadLimit(const int limit) void TorrentHandleImpl::setSuperSeeding(const bool enable) { + if (enable == superSeeding()) + return; + if (enable) m_nativeHandle.set_flags(lt::torrent_flags::super_seeding); else m_nativeHandle.unset_flags(lt::torrent_flags::super_seeding); + saveResumeData(); +} + +void TorrentHandleImpl::setDHTDisabled(const bool disable) +{ + if (disable == isDHTDisabled()) + return; + + if (disable) + m_nativeHandle.set_flags(lt::torrent_flags::disable_dht); + else + m_nativeHandle.unset_flags(lt::torrent_flags::disable_dht); + saveResumeData(); +} + +void TorrentHandleImpl::setPEXDisabled(const bool disable) +{ + if (disable == isPEXDisabled()) + return; + + if (disable) + m_nativeHandle.set_flags(lt::torrent_flags::disable_pex); + else + m_nativeHandle.unset_flags(lt::torrent_flags::disable_pex); + saveResumeData(); +} + +void TorrentHandleImpl::setLSDDisabled(const bool disable) +{ + if (disable == isLSDDisabled()) + return; + + if (disable) + m_nativeHandle.set_flags(lt::torrent_flags::disable_lsd); + else + m_nativeHandle.unset_flags(lt::torrent_flags::disable_lsd); + saveResumeData(); } void TorrentHandleImpl::flushCache() const diff --git a/src/base/bittorrent/torrenthandleimpl.h b/src/base/bittorrent/torrenthandleimpl.h index ddbf953fa..5b7ca48d2 100644 --- a/src/base/bittorrent/torrenthandleimpl.h +++ b/src/base/bittorrent/torrenthandleimpl.h @@ -192,6 +192,9 @@ namespace BitTorrent int downloadLimit() const override; int uploadLimit() const override; bool superSeeding() const override; + bool isDHTDisabled() const override; + bool isPEXDisabled() const override; + bool isLSDDisabled() const override; QVector peers() const override; QBitArray pieces() const override; QBitArray downloadingPieces() const override; @@ -225,6 +228,9 @@ namespace BitTorrent void setUploadLimit(int limit) override; void setDownloadLimit(int limit) override; void setSuperSeeding(bool enable) override; + void setDHTDisabled(bool disable) override; + void setPEXDisabled(bool disable) override; + void setLSDDisabled(bool disable) override; void flushCache() const override; void addTrackers(const QVector &trackers) override; void replaceTrackers(const QVector &trackers) override; diff --git a/src/base/unicodestrings.h b/src/base/unicodestrings.h index 493890c86..e855fe9d5 100644 --- a/src/base/unicodestrings.h +++ b/src/base/unicodestrings.h @@ -38,6 +38,7 @@ // See issue #3059 for more details (https://github.com/qbittorrent/qBittorrent/issues/3059). const char C_COPYRIGHT[] = "©"; +const char C_INEQUALITY[] = "≠"; const char C_INFINITY[] = "∞"; const char C_NON_BREAKING_SPACE[] = " "; const char C_THIN_SPACE[] = " "; diff --git a/src/gui/CMakeLists.txt b/src/gui/CMakeLists.txt index 1169cb51d..bafec9458 100644 --- a/src/gui/CMakeLists.txt +++ b/src/gui/CMakeLists.txt @@ -67,6 +67,7 @@ add_library(qbt_gui STATIC torrentcontentmodelitem.h torrentcontenttreeview.h torrentcreatordialog.h + torrentoptionsdialog.h trackerentriesdialog.h transferlistdelegate.h transferlistfilterswidget.h @@ -76,7 +77,6 @@ add_library(qbt_gui STATIC tristateaction.h tristatewidget.h uithememanager.h - updownratiodialog.h utils.h # sources @@ -147,6 +147,7 @@ add_library(qbt_gui STATIC torrentcontentmodelitem.cpp torrentcontenttreeview.cpp torrentcreatordialog.cpp + torrentoptionsdialog.cpp trackerentriesdialog.cpp transferlistdelegate.cpp transferlistfilterswidget.cpp @@ -156,7 +157,6 @@ add_library(qbt_gui STATIC tristateaction.cpp tristatewidget.cpp uithememanager.cpp - updownratiodialog.cpp utils.cpp # forms @@ -186,8 +186,8 @@ add_library(qbt_gui STATIC statsdialog.ui torrentcategorydialog.ui torrentcreatordialog.ui + torrentoptionsdialog.ui trackerentriesdialog.ui - updownratiodialog.ui ) target_sources(qbt_gui INTERFACE about.qrc) diff --git a/src/gui/gui.pri b/src/gui/gui.pri index aa33bacc1..5f2ecec09 100644 --- a/src/gui/gui.pri +++ b/src/gui/gui.pri @@ -68,6 +68,7 @@ HEADERS += \ $$PWD/torrentcontentmodelitem.h \ $$PWD/torrentcontenttreeview.h \ $$PWD/torrentcreatordialog.h \ + $$PWD/torrentoptionsdialog.h \ $$PWD/trackerentriesdialog.h \ $$PWD/transferlistdelegate.h \ $$PWD/transferlistfilterswidget.h \ @@ -77,7 +78,6 @@ HEADERS += \ $$PWD/tristateaction.h \ $$PWD/tristatewidget.h \ $$PWD/uithememanager.h \ - $$PWD/updownratiodialog.h \ $$PWD/utils.h SOURCES += \ @@ -148,6 +148,7 @@ SOURCES += \ $$PWD/torrentcontentmodelitem.cpp \ $$PWD/torrentcontenttreeview.cpp \ $$PWD/torrentcreatordialog.cpp \ + $$PWD/torrentoptionsdialog.cpp \ $$PWD/trackerentriesdialog.cpp \ $$PWD/transferlistdelegate.cpp \ $$PWD/transferlistfilterswidget.cpp \ @@ -157,7 +158,6 @@ SOURCES += \ $$PWD/tristateaction.cpp \ $$PWD/tristatewidget.cpp \ $$PWD/uithememanager.cpp \ - $$PWD/updownratiodialog.cpp \ $$PWD/utils.cpp win32|macx { @@ -207,7 +207,7 @@ FORMS += \ $$PWD/statsdialog.ui \ $$PWD/torrentcategorydialog.ui \ $$PWD/torrentcreatordialog.ui \ - $$PWD/trackerentriesdialog.ui \ - $$PWD/updownratiodialog.ui + $$PWD/torrentoptionsdialog.ui \ + $$PWD/trackerentriesdialog.ui RESOURCES += $$PWD/about.qrc diff --git a/src/gui/properties/trackerlistwidget.cpp b/src/gui/properties/trackerlistwidget.cpp index ea33606c4..ce0193b5c 100644 --- a/src/gui/properties/trackerlistwidget.cpp +++ b/src/gui/properties/trackerlistwidget.cpp @@ -283,26 +283,34 @@ void TrackerListWidget::clear() void TrackerListWidget::loadStickyItems(const BitTorrent::TorrentHandle *torrent) { - QString working = tr("Working"); - QString disabled = tr("Disabled"); + const QString working {tr("Working")}; + const QString disabled {tr("Disabled")}; + const QString torrentDisabled {tr("Disabled for this torrent")}; + const auto *session = BitTorrent::Session::instance(); // load DHT information - if (BitTorrent::Session::instance()->isDHTEnabled() && !torrent->isPrivate()) - m_DHTItem->setText(COL_STATUS, working); - else + if (torrent->isPrivate() || torrent->isDHTDisabled()) + m_DHTItem->setText(COL_STATUS, torrentDisabled); + else if (!session->isDHTEnabled()) m_DHTItem->setText(COL_STATUS, disabled); + else + m_DHTItem->setText(COL_STATUS, working); // Load PeX Information - if (BitTorrent::Session::instance()->isPeXEnabled() && !torrent->isPrivate()) - m_PEXItem->setText(COL_STATUS, working); - else + if (torrent->isPrivate() || torrent->isPEXDisabled()) + m_PEXItem->setText(COL_STATUS, torrentDisabled); + else if (!session->isPeXEnabled()) m_PEXItem->setText(COL_STATUS, disabled); + else + m_PEXItem->setText(COL_STATUS, working); // Load LSD Information - if (BitTorrent::Session::instance()->isLSDEnabled() && !torrent->isPrivate()) - m_LSDItem->setText(COL_STATUS, working); - else + if (torrent->isPrivate() || torrent->isLSDDisabled()) + m_LSDItem->setText(COL_STATUS, torrentDisabled); + else if (!session->isLSDEnabled()) m_LSDItem->setText(COL_STATUS, disabled); + else + m_LSDItem->setText(COL_STATUS, working); if (torrent->isPrivate()) { diff --git a/src/gui/torrentoptionsdialog.cpp b/src/gui/torrentoptionsdialog.cpp new file mode 100644 index 000000000..b80122573 --- /dev/null +++ b/src/gui/torrentoptionsdialog.cpp @@ -0,0 +1,368 @@ +/* + * Bittorrent Client using Qt and libtorrent. + * Copyright (C) 2006 Christophe Dumez + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * In addition, as a special exception, the copyright holders give permission to + * link this program with the OpenSSL project's "OpenSSL" library (or with + * modified versions of it that use the same license as the "OpenSSL" library), + * and distribute the linked executables. You must obey the GNU General Public + * License in all respects for all of the code used other than "OpenSSL". If you + * modify file(s), you may extend this exception to your version of the file(s), + * but you are not obligated to do so. If you do not wish to do so, delete this + * exception statement from your version. + */ + +#include "torrentoptionsdialog.h" + +#include +#include + +#include "base/bittorrent/infohash.h" +#include "base/bittorrent/session.h" +#include "base/bittorrent/torrenthandle.h" +#include "base/global.h" +#include "base/unicodestrings.h" +#include "ui_torrentoptionsdialog.h" +#include "utils.h" + +namespace +{ + const int MIXED_SHARE_LIMITS = -9; + + void updateSliderValue(QSlider *slider, const int value) + { + if (value > slider->maximum()) + slider->setMaximum(value); + slider->setValue(value); + } +} + +TorrentOptionsDialog::TorrentOptionsDialog(QWidget *parent, const QVector &torrents) + : QDialog {parent} + , m_ui {new Ui::TorrentOptionsDialog} +{ + m_ui->setupUi(this); + + Q_ASSERT(!torrents.empty()); + const auto *session = BitTorrent::Session::instance(); + bool allSameUpLimit = true, allSameDownLimit = true, allSameRatio = true, allSameSeedingTime = true + , allTorrentsArePrivate = true, allSameDHT = true, allSamePEX = true, allSameLSD = true; + + const int firstTorrentUpLimit = qMax(0, torrents[0]->uploadLimit()); + const int firstTorrentDownLimit = qMax(0, torrents[0]->downloadLimit()); + + const qreal firstTorrentRatio = torrents[0]->ratioLimit(); + const int firstTorrentSeedingTime = torrents[0]->seedingTimeLimit(); + + const bool isFirstTorrentDHTDisabled = torrents[0]->isDHTDisabled(); + const bool isFirstTorrentPEXDisabled = torrents[0]->isPEXDisabled(); + const bool isFirstTorrentLSDDisabled = torrents[0]->isLSDDisabled(); + + m_torrentHashes.reserve(torrents.size()); + for (const BitTorrent::TorrentHandle *torrent : torrents) + { + m_torrentHashes << torrent->hash(); + if (allSameUpLimit) + { + if (qMax(0, torrent->uploadLimit()) != firstTorrentUpLimit) + allSameUpLimit = false; + } + if (allSameDownLimit) + { + if (qMax(0, torrent->downloadLimit()) != firstTorrentDownLimit) + allSameDownLimit = false; + } + if (allSameRatio) + { + if (torrent->ratioLimit() != firstTorrentRatio) + allSameRatio = false; + } + if (allSameSeedingTime) + { + if (torrent->seedingTimeLimit() != firstTorrentSeedingTime) + allSameSeedingTime = false; + } + if (allTorrentsArePrivate) + { + if (!torrent->isPrivate()) + allTorrentsArePrivate = false; + } + if (allSameDHT) + { + if (torrent->isDHTDisabled() != isFirstTorrentDHTDisabled) + { + m_ui->checkDisableDHT->setCheckState(Qt::PartiallyChecked); + allSameDHT = false; + } + } + if (allSamePEX) + { + if (torrent->isPEXDisabled() != isFirstTorrentPEXDisabled) + { + m_ui->checkDisablePEX->setCheckState(Qt::PartiallyChecked); + allSamePEX = false; + } + } + if (allSameLSD) + { + if (torrent->isLSDDisabled() != isFirstTorrentLSDDisabled) + { + m_ui->checkDisableLSD->setCheckState(Qt::PartiallyChecked); + allSameLSD = false; + } + } + } + + const bool isAltLimitEnabled = session->isAltGlobalSpeedLimitEnabled(); + const int globalUploadLimit = isAltLimitEnabled + ? (session->altGlobalUploadSpeedLimit() / 1024) + : (session->globalUploadSpeedLimit() / 1024); + const int globalDownloadLimit = isAltLimitEnabled + ? (session->altGlobalDownloadSpeedLimit() / 1024) + : (session->globalDownloadSpeedLimit() / 1024); + + const int uploadVal = qMax(0, (firstTorrentUpLimit / 1024)); + const int downloadVal = qMax(0, (firstTorrentDownLimit / 1024)); + int maxUpload = (globalUploadLimit <= 0) ? 10000 : globalUploadLimit; + int maxDownload = (globalDownloadLimit <= 0) ? 10000 : globalDownloadLimit; + + // This can happen for example if global rate limit is lower than torrent rate limit. + if (uploadVal > maxUpload) + maxUpload = uploadVal; + if (downloadVal > maxDownload) + maxDownload = downloadVal; + + m_ui->sliderUploadLimit->setMaximum(maxUpload); + m_ui->sliderUploadLimit->setValue(allSameUpLimit ? uploadVal : (maxUpload / 2)); + if (allSameUpLimit) + { + m_ui->spinUploadLimit->setValue(uploadVal); + } + else + { + m_ui->spinUploadLimit->setSpecialValueText(QString::fromUtf8(C_INEQUALITY)); + m_ui->spinUploadLimit->setMinimum(-1); + m_ui->spinUploadLimit->setValue(-1); + connect(m_ui->spinUploadLimit, qOverload(&QSpinBox::valueChanged) + , this, &TorrentOptionsDialog::handleUpSpeedLimitChanged); + } + + m_ui->sliderDownloadLimit->setMaximum(maxDownload); + m_ui->sliderDownloadLimit->setValue(allSameDownLimit ? downloadVal : (maxDownload / 2)); + if (allSameDownLimit) + { + m_ui->spinDownloadLimit->setValue(downloadVal); + } + else + { + m_ui->spinDownloadLimit->setSpecialValueText(QString::fromUtf8(C_INEQUALITY)); + m_ui->spinDownloadLimit->setMinimum(-1); + m_ui->spinDownloadLimit->setValue(-1); + connect(m_ui->spinDownloadLimit, qOverload(&QSpinBox::valueChanged) + , this, &TorrentOptionsDialog::handleDownSpeedLimitChanged); + } + + const bool useGlobalValue = allSameRatio && allSameSeedingTime + && (firstTorrentRatio == BitTorrent::TorrentHandle::USE_GLOBAL_RATIO) + && (firstTorrentSeedingTime == BitTorrent::TorrentHandle::USE_GLOBAL_SEEDING_TIME); + + if (!allSameRatio || !allSameSeedingTime) + { + m_ui->radioUseGlobalShareLimits->setChecked(false); + m_ui->radioNoLimit->setChecked(false); + m_ui->radioTorrentLimit->setChecked(false); + } + else if (useGlobalValue) + { + m_ui->radioUseGlobalShareLimits->setChecked(true); + } + else if ((firstTorrentRatio == BitTorrent::TorrentHandle::NO_RATIO_LIMIT) + && (firstTorrentSeedingTime == BitTorrent::TorrentHandle::NO_SEEDING_TIME_LIMIT)) + { + m_ui->radioNoLimit->setChecked(true); + } + else + { + m_ui->radioTorrentLimit->setChecked(true); + if (firstTorrentRatio >= 0) + m_ui->checkMaxRatio->setChecked(true); + if (firstTorrentSeedingTime >= 0) + m_ui->checkMaxTime->setChecked(true); + } + + const qreal maxRatio = (allSameRatio && (firstTorrentRatio >= 0)) + ? firstTorrentRatio : session->globalMaxRatio(); + const int maxSeedingTime = (allSameSeedingTime && (firstTorrentSeedingTime >= 0)) + ? firstTorrentSeedingTime : session->globalMaxSeedingMinutes(); + m_ui->spinRatioLimit->setValue(maxRatio); + m_ui->spinTimeLimit->setValue(maxSeedingTime); + handleRatioTypeChanged(); + + if (!allTorrentsArePrivate) + { + if (m_ui->checkDisableDHT->checkState() != Qt::PartiallyChecked) + m_ui->checkDisableDHT->setChecked(isFirstTorrentDHTDisabled); + if (m_ui->checkDisablePEX->checkState() != Qt::PartiallyChecked) + m_ui->checkDisablePEX->setChecked(isFirstTorrentPEXDisabled); + if (m_ui->checkDisableLSD->checkState() != Qt::PartiallyChecked) + m_ui->checkDisableLSD->setChecked(isFirstTorrentLSDDisabled); + } + else + { + m_ui->checkDisableDHT->setChecked(true); + m_ui->checkDisableDHT->setEnabled(false); + m_ui->checkDisablePEX->setChecked(true); + m_ui->checkDisablePEX->setEnabled(false); + m_ui->checkDisableLSD->setChecked(true); + m_ui->checkDisableLSD->setEnabled(false); + } + + const QString privateTorrentsTooltip = tr("Not applicable to private torrents"); + m_ui->checkDisableDHT->setToolTip(privateTorrentsTooltip); + m_ui->checkDisablePEX->setToolTip(privateTorrentsTooltip); + m_ui->checkDisableLSD->setToolTip(privateTorrentsTooltip); + + m_initialValues = + { + getRatio(), + getSeedingTime(), + m_ui->spinUploadLimit->value(), + m_ui->spinDownloadLimit->value(), + m_ui->checkDisableDHT->checkState(), + m_ui->checkDisablePEX->checkState(), + m_ui->checkDisableLSD->checkState() + }; + + // Sync up/down speed limit sliders with their corresponding spinboxes + connect(m_ui->sliderUploadLimit, &QSlider::valueChanged, m_ui->spinUploadLimit, &QSpinBox::setValue); + connect(m_ui->sliderDownloadLimit, &QSlider::valueChanged, m_ui->spinDownloadLimit, &QSpinBox::setValue); + connect(m_ui->spinUploadLimit, qOverload(&QSpinBox::valueChanged) + , this, [this](const int value) { updateSliderValue(m_ui->sliderUploadLimit, value); }); + connect(m_ui->spinDownloadLimit, qOverload(&QSpinBox::valueChanged) + , this, [this](const int value) { updateSliderValue(m_ui->sliderDownloadLimit, value); }); + + connect(m_ui->checkMaxRatio, &QCheckBox::toggled, m_ui->spinRatioLimit, &QDoubleSpinBox::setEnabled); + connect(m_ui->checkMaxTime, &QCheckBox::toggled, m_ui->spinTimeLimit, &QSpinBox::setEnabled); + +#if (QT_VERSION >= QT_VERSION_CHECK(5, 15, 0)) + connect(m_ui->buttonGroup, &QButtonGroup::idClicked, this, &TorrentOptionsDialog::handleRatioTypeChanged); +#else + connect(m_ui->buttonGroup, qOverload(&QButtonGroup::buttonClicked) + , this, &TorrentOptionsDialog::handleRatioTypeChanged); +#endif + + Utils::Gui::resize(this); +} + +TorrentOptionsDialog::~TorrentOptionsDialog() +{ + delete m_ui; +} + +void TorrentOptionsDialog::accept() +{ + if (m_ui->radioTorrentLimit->isChecked() && !m_ui->checkMaxRatio->isChecked() && !m_ui->checkMaxTime->isChecked()) + { + QMessageBox::critical(this, tr("No share limit method selected"), tr("Please select a limit method first")); + return; + } + + const auto *session = BitTorrent::Session::instance(); + for (const BitTorrent::InfoHash &hash : asConst(m_torrentHashes)) + { + BitTorrent::TorrentHandle *torrent = session->findTorrent(hash); + if (!torrent) continue; + + if (m_initialValues.upSpeedLimit != m_ui->spinUploadLimit->value()) + torrent->setUploadLimit(m_ui->spinUploadLimit->value() * 1024); + if (m_initialValues.downSpeedLimit != m_ui->spinDownloadLimit->value()) + torrent->setDownloadLimit(m_ui->spinDownloadLimit->value() * 1024); + + const qreal ratioLimit = getRatio(); + if (m_initialValues.ratio != ratioLimit) + torrent->setRatioLimit(ratioLimit); + + const int seedingTimeLimit = getSeedingTime(); + if (m_initialValues.seedingTime != seedingTimeLimit) + torrent->setSeedingTimeLimit(seedingTimeLimit); + + if (!torrent->isPrivate()) + { + if (m_initialValues.disableDHT != m_ui->checkDisableDHT->checkState()) + torrent->setDHTDisabled(m_ui->checkDisableDHT->isChecked()); + if (m_initialValues.disablePEX != m_ui->checkDisablePEX->checkState()) + torrent->setPEXDisabled(m_ui->checkDisablePEX->isChecked()); + if (m_initialValues.disableLSD != m_ui->checkDisableLSD->checkState()) + torrent->setLSDDisabled(m_ui->checkDisableLSD->isChecked()); + } + } + + QDialog::accept(); +} + +qreal TorrentOptionsDialog::getRatio() const +{ + if (m_ui->buttonGroup->checkedId() == -1) // No radio button is selected + return MIXED_SHARE_LIMITS; + + if (m_ui->radioUseGlobalShareLimits->isChecked()) + return BitTorrent::TorrentHandle::USE_GLOBAL_RATIO; + + if (m_ui->radioNoLimit->isChecked() || !m_ui->checkMaxRatio->isChecked()) + return BitTorrent::TorrentHandle::NO_RATIO_LIMIT; + + return m_ui->spinRatioLimit->value(); +} + +int TorrentOptionsDialog::getSeedingTime() const +{ + if (m_ui->buttonGroup->checkedId() == -1) // No radio button is selected + return MIXED_SHARE_LIMITS; + + if (m_ui->radioUseGlobalShareLimits->isChecked()) + return BitTorrent::TorrentHandle::USE_GLOBAL_SEEDING_TIME; + + if (m_ui->radioNoLimit->isChecked() || !m_ui->checkMaxTime->isChecked()) + return BitTorrent::TorrentHandle::NO_SEEDING_TIME_LIMIT; + + return m_ui->spinTimeLimit->value(); +} + +void TorrentOptionsDialog::handleRatioTypeChanged() +{ + m_ui->checkMaxRatio->setEnabled(m_ui->radioTorrentLimit->isChecked()); + m_ui->checkMaxTime->setEnabled(m_ui->radioTorrentLimit->isChecked()); + + m_ui->spinRatioLimit->setEnabled(m_ui->radioTorrentLimit->isChecked() && m_ui->checkMaxRatio->isChecked()); + m_ui->spinTimeLimit->setEnabled(m_ui->radioTorrentLimit->isChecked() && m_ui->checkMaxTime->isChecked()); +} + +void TorrentOptionsDialog::handleUpSpeedLimitChanged() +{ + m_ui->spinUploadLimit->setMinimum(0); + m_ui->spinUploadLimit->setSpecialValueText(QString::fromUtf8(C_INFINITY)); + disconnect(m_ui->spinUploadLimit, qOverload(&QSpinBox::valueChanged) + , this, &TorrentOptionsDialog::handleUpSpeedLimitChanged); +} + +void TorrentOptionsDialog::handleDownSpeedLimitChanged() +{ + m_ui->spinDownloadLimit->setMinimum(0); + m_ui->spinDownloadLimit->setSpecialValueText(QString::fromUtf8(C_INFINITY)); + disconnect(m_ui->spinDownloadLimit, qOverload(&QSpinBox::valueChanged) + , this, &TorrentOptionsDialog::handleDownSpeedLimitChanged); +} diff --git a/src/gui/updownratiodialog.h b/src/gui/torrentoptionsdialog.h similarity index 65% rename from src/gui/updownratiodialog.h rename to src/gui/torrentoptionsdialog.h index af55c0d45..ac64a9e5f 100644 --- a/src/gui/updownratiodialog.h +++ b/src/gui/torrentoptionsdialog.h @@ -1,7 +1,7 @@ /* * Bittorrent Client using Qt and libtorrent. - * Copyright (C) 2011 Christian Kandeler - * Copyright (C) 2011 Christophe Dumez + * Copyright (C) 2006 Christophe Dumez + * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 @@ -30,33 +30,48 @@ #include +namespace BitTorrent +{ + class InfoHash; + class TorrentHandle; +} + namespace Ui { - class UpDownRatioDialog; + class TorrentOptionsDialog; } -class UpDownRatioDialog final : public QDialog +class TorrentOptionsDialog final : public QDialog { Q_OBJECT public: - UpDownRatioDialog(bool useDefault, qreal initialValue, qreal maxValue, - int initialTimeValue, int maxTimeValue, - QWidget *parent = nullptr); - ~UpDownRatioDialog(); - - bool useDefault() const; - qreal ratio() const; - int seedingTime() const; + explicit TorrentOptionsDialog(QWidget *parent, const QVector &torrents); + ~TorrentOptionsDialog() override; public slots: void accept() override; private slots: + void handleUpSpeedLimitChanged(); + void handleDownSpeedLimitChanged(); + void handleRatioTypeChanged(); - void enableRatioSpin(); - void enableTimeSpin(); private: - Ui::UpDownRatioDialog *m_ui; + qreal getRatio() const; + int getSeedingTime() const; + + QVector m_torrentHashes; + Ui::TorrentOptionsDialog *m_ui; + struct + { + qreal ratio; + int seedingTime; + int upSpeedLimit; + int downSpeedLimit; + Qt::CheckState disableDHT; + Qt::CheckState disablePEX; + Qt::CheckState disableLSD; + } m_initialValues; }; diff --git a/src/gui/torrentoptionsdialog.ui b/src/gui/torrentoptionsdialog.ui new file mode 100644 index 000000000..b033d5c92 --- /dev/null +++ b/src/gui/torrentoptionsdialog.ui @@ -0,0 +1,278 @@ + + + TorrentOptionsDialog + + + + 0 + 0 + 390 + 450 + + + + Torrent Options + + + + + + Torrent speed limits + + + + + + Download: + + + + + + + + + + KiB/s + + + 2000000 + + + + + + + + + + KiB/s + + + 2000000 + + + + + + + These will not exceed the global limits + + + + + + + Upload: + + + + + + + Qt::Horizontal + + + + + + + Qt::Horizontal + + + + + + + + + + Torrent share limits + + + + + + Use global share limit + + + buttonGroup + + + + + + + Set no share limit + + + buttonGroup + + + + + + + + + Set share limit to + + + buttonGroup + + + + + + + minutes + + + + + + + 9999.000000000000000 + + + 0.050000000000000 + + + 1.000000000000000 + + + + + + + 525600 + + + 1440 + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + ratio + + + + + + + + + + + + + + Disable DHT for this torrent + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + Disable PeX for this torrent + + + + + + + Disable LSD for this torrent + + + + + + + + + Qt::Vertical + + + + 20 + 0 + + + + + + + + QDialogButtonBox::Cancel|QDialogButtonBox::Ok + + + + + + + + + buttonBox + rejected() + TorrentOptionsDialog + reject() + + + 221 + 73 + + + 221 + 82 + + + + + buttonBox + accepted() + TorrentOptionsDialog + accept() + + + 277 + 59 + + + 343 + 80 + + + + + + + + diff --git a/src/gui/transferlistwidget.cpp b/src/gui/transferlistwidget.cpp index 908732d42..798756c0a 100644 --- a/src/gui/transferlistwidget.cpp +++ b/src/gui/transferlistwidget.cpp @@ -62,13 +62,13 @@ #include "previewselectdialog.h" #include "speedlimitdialog.h" #include "torrentcategorydialog.h" +#include "torrentoptionsdialog.h" #include "trackerentriesdialog.h" #include "transferlistdelegate.h" #include "transferlistmodel.h" #include "transferlistsortmodel.h" #include "tristateaction.h" #include "uithememanager.h" -#include "updownratiodialog.h" #include "utils.h" #ifdef Q_OS_MACOS @@ -551,84 +551,13 @@ void TransferListWidget::previewSelectedTorrents() } } -void TransferListWidget::setSpeedLimitsSelectedTorrents() +void TransferListWidget::setTorrentOptions() { - const QVector torrentsList = getSelectedTorrents(); - if (torrentsList.empty()) return; + const QVector selectedTorrents = getSelectedTorrents(); + if (selectedTorrents.empty()) return; - int oldUploadLimit = torrentsList.first()->uploadLimit(); - int oldDownloadLimit = torrentsList.first()->downloadLimit(); - - for (const BitTorrent::TorrentHandle *torrent : torrentsList) - { - if (torrent->uploadLimit() != oldUploadLimit) - { - oldUploadLimit = -1; - break; - } - } - - for (const BitTorrent::TorrentHandle *torrent : torrentsList) - { - if (torrent->downloadLimit() != oldDownloadLimit) - { - oldDownloadLimit = -1; - break; - } - } - - const BitTorrent::Session *session = BitTorrent::Session::instance(); - const bool isAltLimitEnabled = session->isAltGlobalSpeedLimitEnabled(); - OldSpeedLimits oldSpeedLimits = { - oldUploadLimit, - oldDownloadLimit, - isAltLimitEnabled ? session->altGlobalUploadSpeedLimit() : session->globalUploadSpeedLimit(), - isAltLimitEnabled ? session->altGlobalDownloadSpeedLimit() : session->globalDownloadSpeedLimit(), - }; - NewSpeedLimits newSpeedLimits; - const bool ok = SpeedLimitDialog::askNewSpeedLimits(this, oldSpeedLimits, newSpeedLimits); - if (!ok) return; - - for (BitTorrent::TorrentHandle *const torrent : torrentsList) { - torrent->setUploadLimit(newSpeedLimits.uploadLimit); - torrent->setDownloadLimit(newSpeedLimits.downloadLimit); - } -} - -void TransferListWidget::setMaxRatioSelectedTorrents() -{ - const QVector torrents = getSelectedTorrents(); - if (torrents.isEmpty()) return; - - qreal currentMaxRatio = BitTorrent::Session::instance()->globalMaxRatio(); - if (torrents.count() == 1) - currentMaxRatio = torrents[0]->maxRatio(); - - int currentMaxSeedingTime = BitTorrent::Session::instance()->globalMaxSeedingMinutes(); - if (torrents.count() == 1) - currentMaxSeedingTime = torrents[0]->maxSeedingTime(); - - bool useGlobalValue = true; - if (torrents.count() == 1) - useGlobalValue = (torrents[0]->ratioLimit() == BitTorrent::TorrentHandle::USE_GLOBAL_RATIO) - && (torrents[0]->seedingTimeLimit() == BitTorrent::TorrentHandle::USE_GLOBAL_SEEDING_TIME); - - auto dialog = new UpDownRatioDialog(useGlobalValue, currentMaxRatio, BitTorrent::TorrentHandle::MAX_RATIO, - currentMaxSeedingTime, BitTorrent::TorrentHandle::MAX_SEEDING_TIME, this); + auto dialog = new TorrentOptionsDialog {this, selectedTorrents}; dialog->setAttribute(Qt::WA_DeleteOnClose); - connect(dialog, &QDialog::accepted, this, [dialog, torrents]() - { - for (BitTorrent::TorrentHandle *const torrent : torrents) - { - const qreal ratio = (dialog->useDefault() - ? BitTorrent::TorrentHandle::USE_GLOBAL_RATIO : dialog->ratio()); - torrent->setRatioLimit(ratio); - - const int seedingTime = (dialog->useDefault() - ? BitTorrent::TorrentHandle::USE_GLOBAL_SEEDING_TIME : dialog->seedingTime()); - torrent->setSeedingTimeLimit(seedingTime); - } - }); dialog->open(); } @@ -879,10 +808,8 @@ void TransferListWidget::displayListMenu(const QPoint &) connect(actionDelete, &QAction::triggered, this, &TransferListWidget::softDeleteSelectedTorrents); auto *actionPreviewFile = new QAction(UIThemeManager::instance()->getIcon("view-preview"), tr("Preview file..."), listMenu); connect(actionPreviewFile, &QAction::triggered, this, &TransferListWidget::previewSelectedTorrents); - auto *actionSetMaxRatio = new QAction(UIThemeManager::instance()->getIcon(QLatin1String("ratio")), tr("Limit share ratio..."), listMenu); - connect(actionSetMaxRatio, &QAction::triggered, this, &TransferListWidget::setMaxRatioSelectedTorrents); - auto *actionSetSpeedLimits = new QAction(UIThemeManager::instance()->getIcon("speedometer"), tr("Limit speed rates..."), listMenu); - connect(actionSetSpeedLimits, &QAction::triggered, this, &TransferListWidget::setSpeedLimitsSelectedTorrents); + auto *actionTorrentOptions = new QAction(UIThemeManager::instance()->getIcon("configure"), tr("Torrent options..."), listMenu); + connect(actionTorrentOptions, &QAction::triggered, this, &TransferListWidget::setTorrentOptions); auto *actionOpenDestinationFolder = new QAction(UIThemeManager::instance()->getIcon("inode-directory"), tr("Open destination folder"), listMenu); connect(actionOpenDestinationFolder, &QAction::triggered, this, &TransferListWidget::openSelectedTorrentsFolder); auto *actionIncreaseQueuePos = new QAction(UIThemeManager::instance()->getIcon("go-up"), tr("Move up", "i.e. move up in the queue"), listMenu); @@ -1112,8 +1039,7 @@ void TransferListWidget::displayListMenu(const QPoint &) listMenu->addAction(actionAutoTMM); listMenu->addSeparator(); - listMenu->addAction(actionSetSpeedLimits); - listMenu->addAction(actionSetMaxRatio); + listMenu->addAction(actionTorrentOptions); if (!oneNotSeed && oneHasMetadata) { actionSuperSeedingMode->setCheckState(allSameSuperSeeding diff --git a/src/gui/transferlistwidget.h b/src/gui/transferlistwidget.h index e9ae74db3..1380a7514 100644 --- a/src/gui/transferlistwidget.h +++ b/src/gui/transferlistwidget.h @@ -79,8 +79,7 @@ public slots: void openSelectedTorrentsFolder() const; void recheckSelectedTorrents(); void reannounceSelectedTorrents(); - void setSpeedLimitsSelectedTorrents(); - void setMaxRatioSelectedTorrents(); + void setTorrentOptions(); void previewSelectedTorrents(); void hideQueuePosColumn(bool hide); void displayDLHoSMenu(const QPoint&); diff --git a/src/gui/updownratiodialog.cpp b/src/gui/updownratiodialog.cpp deleted file mode 100644 index fe75dbdb0..000000000 --- a/src/gui/updownratiodialog.cpp +++ /dev/null @@ -1,137 +0,0 @@ -/* - * Bittorrent Client using Qt and libtorrent. - * Copyright (C) 2011 Christian Kandeler - * Copyright (C) 2011 Christophe Dumez - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version 2 - * of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - * - * In addition, as a special exception, the copyright holders give permission to - * link this program with the OpenSSL project's "OpenSSL" library (or with - * modified versions of it that use the same license as the "OpenSSL" library), - * and distribute the linked executables. You must obey the GNU General Public - * License in all respects for all of the code used other than "OpenSSL". If you - * modify file(s), you may extend this exception to your version of the file(s), - * but you are not obligated to do so. If you do not wish to do so, delete this - * exception statement from your version. - */ - -#include "updownratiodialog.h" - -#include - -#include "base/bittorrent/session.h" -#include "ui_updownratiodialog.h" -#include "utils.h" - -UpDownRatioDialog::UpDownRatioDialog(bool useDefault, qreal initialRatioValue, - qreal maxRatioValue, int initialTimeValue, - int maxTimeValue, QWidget *parent) - : QDialog(parent) - , m_ui(new Ui::UpDownRatioDialog) -{ - m_ui->setupUi(this); - - if (useDefault) - { - m_ui->useDefaultButton->setChecked(true); - } - else if ((initialRatioValue == -1.) && (initialTimeValue == -1)) - { - m_ui->noLimitButton->setChecked(true); - initialRatioValue = BitTorrent::Session::instance()->globalMaxRatio(); - initialTimeValue = BitTorrent::Session::instance()->globalMaxSeedingMinutes(); - } - else - { - m_ui->torrentLimitButton->setChecked(true); - - if (initialRatioValue >= 0) - m_ui->checkMaxRatio->setChecked(true); - - if (initialTimeValue >= 0) - m_ui->checkMaxTime->setChecked(true); - } - - m_ui->ratioSpinBox->setMinimum(0); - m_ui->ratioSpinBox->setMaximum(maxRatioValue); - m_ui->ratioSpinBox->setValue(initialRatioValue); - - m_ui->timeSpinBox->setMinimum(0); - m_ui->timeSpinBox->setMaximum(maxTimeValue); - m_ui->timeSpinBox->setValue(initialTimeValue); - -#if (QT_VERSION >= QT_VERSION_CHECK(5, 15, 0)) - connect(m_ui->buttonGroup, &QButtonGroup::idClicked - , this, &UpDownRatioDialog::handleRatioTypeChanged); -#else - connect(m_ui->buttonGroup, qOverload(&QButtonGroup::buttonClicked) - , this, &UpDownRatioDialog::handleRatioTypeChanged); -#endif - connect(m_ui->checkMaxRatio, &QCheckBox::toggled, this, &UpDownRatioDialog::enableRatioSpin); - connect(m_ui->checkMaxTime, &QCheckBox::toggled, this, &UpDownRatioDialog::enableTimeSpin); - - handleRatioTypeChanged(); - - Utils::Gui::resize(this); -} - -void UpDownRatioDialog::accept() -{ - if (m_ui->torrentLimitButton->isChecked() && !m_ui->checkMaxRatio->isChecked() && !m_ui->checkMaxTime->isChecked()) - QMessageBox::critical(this, tr("No share limit method selected"), - tr("Please select a limit method first")); - else - QDialog::accept(); -} - -bool UpDownRatioDialog::useDefault() const -{ - return m_ui->useDefaultButton->isChecked(); -} - -qreal UpDownRatioDialog::ratio() const -{ - return (m_ui->noLimitButton->isChecked() || !m_ui->checkMaxRatio->isChecked()) ? -1. : m_ui->ratioSpinBox->value(); -} - -int UpDownRatioDialog::seedingTime() const -{ - return (m_ui->noLimitButton->isChecked() || !m_ui->checkMaxTime->isChecked()) ? -1 : m_ui->timeSpinBox->value(); -} - -void UpDownRatioDialog::handleRatioTypeChanged() -{ - // ui->ratioSpinBox->setEnabled(ui->torrentLimitButton->isChecked()); - m_ui->checkMaxRatio->setEnabled(m_ui->torrentLimitButton->isChecked()); - m_ui->checkMaxTime->setEnabled(m_ui->torrentLimitButton->isChecked()); - - m_ui->ratioSpinBox->setEnabled(m_ui->torrentLimitButton->isChecked() && m_ui->checkMaxRatio->isChecked()); - m_ui->timeSpinBox->setEnabled(m_ui->torrentLimitButton->isChecked() && m_ui->checkMaxTime->isChecked()); -} - -void UpDownRatioDialog::enableRatioSpin() -{ - m_ui->ratioSpinBox->setEnabled(m_ui->checkMaxRatio->isChecked()); -} - -void UpDownRatioDialog::enableTimeSpin() -{ - m_ui->timeSpinBox->setEnabled(m_ui->checkMaxTime->isChecked()); -} - -UpDownRatioDialog::~UpDownRatioDialog() -{ - delete m_ui; -} diff --git a/src/gui/updownratiodialog.ui b/src/gui/updownratiodialog.ui deleted file mode 100644 index edfef4312..000000000 --- a/src/gui/updownratiodialog.ui +++ /dev/null @@ -1,177 +0,0 @@ - - - UpDownRatioDialog - - - - 0 - 0 - 399 - 195 - - - - Torrent Upload/Download Ratio Limiting - - - - - - Use global share limit - - - buttonGroup - - - - - - - Set no share limit - - - buttonGroup - - - - - - - - - Set share limit to - - - buttonGroup - - - - - - - 9998.000000000000000 - - - 0.050000000000000 - - - 1.000000000000000 - - - - - - - - 0 - 0 - - - - 0 - - - 525600.000000000000000 - - - 1.000000000000000 - - - 1440.000000000000000 - - - - - - - Qt::Horizontal - - - - 40 - 20 - - - - - - - - ratio - - - - - - - minutes - - - - - - - - - Qt::Vertical - - - - 20 - 40 - - - - - - - - Qt::Horizontal - - - QDialogButtonBox::Cancel|QDialogButtonBox::Ok - - - - - - - - - buttonBox - accepted() - UpDownRatioDialog - accept() - - - 248 - 254 - - - 157 - 274 - - - - - buttonBox - rejected() - UpDownRatioDialog - reject() - - - 316 - 260 - - - 286 - 274 - - - - - - - - -