2 * Bittorrent Client using Qt and libtorrent.
3 * Copyright (C) 2024 Vladimir Golovnev <glassez@yandex.ru>
4 * Copyright (C) 2020 thalieht
5 * Copyright (C) 2011 Christian Kandeler
6 * Copyright (C) 2011 Christophe Dumez <chris@qbittorrent.org>
8 * This program is free software; you can redistribute it and/or
9 * modify it under the terms of the GNU General Public License
10 * as published by the Free Software Foundation; either version 2
11 * of the License, or (at your option) any later version.
13 * This program is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 * GNU General Public License for more details.
18 * You should have received a copy of the GNU General Public License
19 * along with this program; if not, write to the Free Software
20 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
22 * In addition, as a special exception, the copyright holders give permission to
23 * link this program with the OpenSSL project's "OpenSSL" library (or with
24 * modified versions of it that use the same license as the "OpenSSL" library),
25 * and distribute the linked executables. You must obey the GNU General Public
26 * License in all respects for all of the code used other than "OpenSSL". If you
27 * modify file(s), you may extend this exception to your version of the file(s),
28 * but you are not obligated to do so. If you do not wish to do so, delete this
29 * exception statement from your version.
32 #include "torrentoptionsdialog.h"
37 #include <QMessageBox>
40 #include "base/bittorrent/infohash.h"
41 #include "base/bittorrent/session.h"
42 #include "base/bittorrent/torrent.h"
43 #include "base/global.h"
44 #include "base/unicodestrings.h"
45 #include "base/utils/fs.h"
46 #include "ui_torrentoptionsdialog.h"
49 #define SETTINGS_KEY(name) u"TorrentOptionsDialog/" name
53 void updateSliderValue(QSlider
*slider
, const int value
)
55 if (value
> slider
->maximum())
56 slider
->setMaximum(value
);
57 slider
->setValue(value
);
61 TorrentOptionsDialog::TorrentOptionsDialog(QWidget
*parent
, const QList
<BitTorrent::Torrent
*> &torrents
)
63 , m_ui
{new Ui::TorrentOptionsDialog
}
64 , m_storeDialogSize
{SETTINGS_KEY(u
"Size"_s
)}
65 , m_currentCategoriesString
{u
"--%1--"_s
.arg(tr("Currently used categories"))}
67 Q_ASSERT(!torrents
.empty());
71 connect(m_ui
->buttonBox
, &QDialogButtonBox::accepted
, this, &QDialog::accept
);
72 connect(m_ui
->buttonBox
, &QDialogButtonBox::rejected
, this, &QDialog::reject
);
74 m_ui
->savePath
->setMode(FileSystemPathEdit::Mode::DirectorySave
);
75 m_ui
->savePath
->setDialogCaption(tr("Choose save path"));
76 m_ui
->downloadPath
->setMode(FileSystemPathEdit::Mode::DirectorySave
);
77 m_ui
->downloadPath
->setDialogCaption(tr("Choose save path"));
79 const auto *session
= BitTorrent::Session::instance();
80 bool allSameUpLimit
= true;
81 bool allSameDownLimit
= true;
82 bool allSameRatio
= true;
83 bool allSameSeedingTime
= true;
84 bool allSameInactiveSeedingTime
= true;
85 bool allSameShareLimitAction
= true;
86 bool allTorrentsArePrivate
= true;
87 bool allSameDHT
= true;
88 bool allSamePEX
= true;
89 bool allSameLSD
= true;
90 bool allSameSequential
= true;
91 bool allSameFirstLastPieces
= true;
92 bool allSameAutoTMM
= true;
93 bool allSameSavePath
= true;
94 bool allSameDownloadPath
= true;
96 const bool isFirstTorrentAutoTMMEnabled
= torrents
[0]->isAutoTMMEnabled();
97 const Path firstTorrentSavePath
= torrents
[0]->savePath();
98 const Path firstTorrentDownloadPath
= torrents
[0]->downloadPath();
99 const QString firstTorrentCategory
= torrents
[0]->category();
101 const int firstTorrentUpLimit
= std::max(0, torrents
[0]->uploadLimit());
102 const int firstTorrentDownLimit
= std::max(0, torrents
[0]->downloadLimit());
104 const qreal firstTorrentRatio
= torrents
[0]->ratioLimit();
105 const int firstTorrentSeedingTime
= torrents
[0]->seedingTimeLimit();
106 const int firstTorrentInactiveSeedingTime
= torrents
[0]->inactiveSeedingTimeLimit();
107 const BitTorrent::ShareLimitAction firstTorrentShareLimitAction
= torrents
[0]->shareLimitAction();
109 const bool isFirstTorrentDHTDisabled
= torrents
[0]->isDHTDisabled();
110 const bool isFirstTorrentPEXDisabled
= torrents
[0]->isPEXDisabled();
111 const bool isFirstTorrentLSDDisabled
= torrents
[0]->isLSDDisabled();
112 const bool isFirstTorrentSequentialEnabled
= torrents
[0]->isSequentialDownload();
113 const bool isFirstTorrentFirstLastPiecesEnabled
= torrents
[0]->hasFirstLastPiecePriority();
115 m_torrentIDs
.reserve(torrents
.size());
116 for (const BitTorrent::Torrent
*torrent
: torrents
)
118 m_torrentIDs
<< torrent
->id();
122 if (torrent
->isAutoTMMEnabled() != isFirstTorrentAutoTMMEnabled
)
123 allSameAutoTMM
= false;
127 if (torrent
->savePath() != firstTorrentSavePath
)
128 allSameSavePath
= false;
130 if (allSameDownloadPath
)
132 if (torrent
->downloadPath() != firstTorrentDownloadPath
)
133 allSameDownloadPath
= false;
135 if (m_allSameCategory
)
137 if (torrent
->category() != firstTorrentCategory
)
138 m_allSameCategory
= false;
142 if (std::max(0, torrent
->uploadLimit()) != firstTorrentUpLimit
)
143 allSameUpLimit
= false;
145 if (allSameDownLimit
)
147 if (std::max(0, torrent
->downloadLimit()) != firstTorrentDownLimit
)
148 allSameDownLimit
= false;
152 if (torrent
->ratioLimit() != firstTorrentRatio
)
153 allSameRatio
= false;
155 if (allSameSeedingTime
)
157 if (torrent
->seedingTimeLimit() != firstTorrentSeedingTime
)
158 allSameSeedingTime
= false;
160 if (allSameInactiveSeedingTime
)
162 if (torrent
->inactiveSeedingTimeLimit() != firstTorrentInactiveSeedingTime
)
163 allSameInactiveSeedingTime
= false;
165 if (allSameShareLimitAction
)
167 if (torrent
->shareLimitAction() != firstTorrentShareLimitAction
)
168 allSameShareLimitAction
= false;
170 if (allTorrentsArePrivate
)
172 if (!torrent
->isPrivate())
173 allTorrentsArePrivate
= false;
177 if (torrent
->isDHTDisabled() != isFirstTorrentDHTDisabled
)
182 if (torrent
->isPEXDisabled() != isFirstTorrentPEXDisabled
)
187 if (torrent
->isLSDDisabled() != isFirstTorrentLSDDisabled
)
190 if (allSameSequential
)
192 if (torrent
->isSequentialDownload() != isFirstTorrentSequentialEnabled
)
193 allSameSequential
= false;
195 if (allSameFirstLastPieces
)
197 if (torrent
->hasFirstLastPiecePriority() != isFirstTorrentFirstLastPiecesEnabled
)
198 allSameFirstLastPieces
= false;
203 m_ui
->checkAutoTMM
->setChecked(isFirstTorrentAutoTMMEnabled
);
205 m_ui
->checkAutoTMM
->setCheckState(Qt::PartiallyChecked
);
208 m_ui
->savePath
->setSelectedPath(firstTorrentSavePath
);
210 if (allSameDownloadPath
)
212 m_ui
->downloadPath
->setSelectedPath(firstTorrentDownloadPath
);
213 m_ui
->checkUseDownloadPath
->setChecked(!firstTorrentDownloadPath
.isEmpty());
217 m_ui
->checkUseDownloadPath
->setCheckState(Qt::PartiallyChecked
);
220 if (!m_allSameCategory
)
222 m_ui
->comboCategory
->addItem(m_currentCategoriesString
);
223 m_ui
->comboCategory
->clearEditText();
224 m_ui
->comboCategory
->lineEdit()->setPlaceholderText(m_currentCategoriesString
);
226 else if (!firstTorrentCategory
.isEmpty())
228 m_ui
->comboCategory
->setCurrentText(firstTorrentCategory
);
229 m_ui
->comboCategory
->addItem(firstTorrentCategory
);
231 m_ui
->comboCategory
->addItem(QString());
233 m_categories
= session
->categories();
234 std::sort(m_categories
.begin(), m_categories
.end(), Utils::Compare::NaturalLessThan
<Qt::CaseInsensitive
>());
235 for (const QString
&category
: asConst(m_categories
))
237 if (m_allSameCategory
&& (category
== firstTorrentCategory
))
240 m_ui
->comboCategory
->addItem(category
);
243 const bool isAltLimitEnabled
= session
->isAltGlobalSpeedLimitEnabled();
244 const int globalUploadLimit
= isAltLimitEnabled
245 ? (session
->altGlobalUploadSpeedLimit() / 1024)
246 : (session
->globalUploadSpeedLimit() / 1024);
247 const int globalDownloadLimit
= isAltLimitEnabled
248 ? (session
->altGlobalDownloadSpeedLimit() / 1024)
249 : (session
->globalDownloadSpeedLimit() / 1024);
251 const int uploadVal
= std::max(0, (firstTorrentUpLimit
/ 1024));
252 const int downloadVal
= std::max(0, (firstTorrentDownLimit
/ 1024));
253 int maxUpload
= (globalUploadLimit
<= 0) ? 10000 : globalUploadLimit
;
254 int maxDownload
= (globalDownloadLimit
<= 0) ? 10000 : globalDownloadLimit
;
256 // This can happen for example if global rate limit is lower than torrent rate limit.
257 if (uploadVal
> maxUpload
)
258 maxUpload
= uploadVal
;
259 if (downloadVal
> maxDownload
)
260 maxDownload
= downloadVal
;
262 m_ui
->sliderUploadLimit
->setMaximum(maxUpload
);
263 m_ui
->sliderUploadLimit
->setValue(allSameUpLimit
? uploadVal
: (maxUpload
/ 2));
266 m_ui
->spinUploadLimit
->setValue(uploadVal
);
270 m_ui
->spinUploadLimit
->setSpecialValueText(C_INEQUALITY
);
271 m_ui
->spinUploadLimit
->setMinimum(-1);
272 m_ui
->spinUploadLimit
->setValue(-1);
273 connect(m_ui
->spinUploadLimit
, qOverload
<int>(&QSpinBox::valueChanged
)
274 , this, &TorrentOptionsDialog::handleUpSpeedLimitChanged
);
277 m_ui
->sliderDownloadLimit
->setMaximum(maxDownload
);
278 m_ui
->sliderDownloadLimit
->setValue(allSameDownLimit
? downloadVal
: (maxDownload
/ 2));
279 if (allSameDownLimit
)
281 m_ui
->spinDownloadLimit
->setValue(downloadVal
);
285 m_ui
->spinDownloadLimit
->setSpecialValueText(C_INEQUALITY
);
286 m_ui
->spinDownloadLimit
->setMinimum(-1);
287 m_ui
->spinDownloadLimit
->setValue(-1);
288 connect(m_ui
->spinDownloadLimit
, qOverload
<int>(&QSpinBox::valueChanged
)
289 , this, &TorrentOptionsDialog::handleDownSpeedLimitChanged
);
292 m_ui
->torrentShareLimitsWidget
->setDefaultLimits(session
->globalMaxRatio(), session
->globalMaxSeedingMinutes(), session
->globalMaxInactiveSeedingMinutes());
294 m_ui
->torrentShareLimitsWidget
->setRatioLimit(firstTorrentRatio
);
295 if (allSameSeedingTime
)
296 m_ui
->torrentShareLimitsWidget
->setSeedingTimeLimit(firstTorrentSeedingTime
);
297 if (allSameInactiveSeedingTime
)
298 m_ui
->torrentShareLimitsWidget
->setInactiveSeedingTimeLimit(firstTorrentInactiveSeedingTime
);
299 if (allSameShareLimitAction
)
300 m_ui
->torrentShareLimitsWidget
->setShareLimitAction(firstTorrentShareLimitAction
);
302 if (!allTorrentsArePrivate
)
305 m_ui
->checkDisableDHT
->setChecked(isFirstTorrentDHTDisabled
);
307 m_ui
->checkDisableDHT
->setCheckState(Qt::PartiallyChecked
);
310 m_ui
->checkDisablePEX
->setChecked(isFirstTorrentPEXDisabled
);
312 m_ui
->checkDisablePEX
->setCheckState(Qt::PartiallyChecked
);
315 m_ui
->checkDisableLSD
->setChecked(isFirstTorrentLSDDisabled
);
317 m_ui
->checkDisableLSD
->setCheckState(Qt::PartiallyChecked
);
321 m_ui
->checkDisableDHT
->setChecked(true);
322 m_ui
->checkDisableDHT
->setEnabled(false);
323 m_ui
->checkDisablePEX
->setChecked(true);
324 m_ui
->checkDisablePEX
->setEnabled(false);
325 m_ui
->checkDisableLSD
->setChecked(true);
326 m_ui
->checkDisableLSD
->setEnabled(false);
329 const QString privateTorrentsTooltip
= tr("Not applicable to private torrents");
330 m_ui
->checkDisableDHT
->setToolTip(privateTorrentsTooltip
);
331 m_ui
->checkDisablePEX
->setToolTip(privateTorrentsTooltip
);
332 m_ui
->checkDisableLSD
->setToolTip(privateTorrentsTooltip
);
334 if (allSameSequential
)
335 m_ui
->checkSequential
->setChecked(isFirstTorrentSequentialEnabled
);
337 m_ui
->checkSequential
->setCheckState(Qt::PartiallyChecked
);
339 if (allSameFirstLastPieces
)
340 m_ui
->checkFirstLastPieces
->setChecked(isFirstTorrentFirstLastPiecesEnabled
);
342 m_ui
->checkFirstLastPieces
->setCheckState(Qt::PartiallyChecked
);
346 .savePath
= m_ui
->savePath
->selectedPath(),
347 .downloadPath
= m_ui
->downloadPath
->selectedPath(),
348 .category
= m_ui
->comboCategory
->currentText(),
349 .ratio
= m_ui
->torrentShareLimitsWidget
->ratioLimit(),
350 .seedingTime
= m_ui
->torrentShareLimitsWidget
->seedingTimeLimit(),
351 .inactiveSeedingTime
= m_ui
->torrentShareLimitsWidget
->inactiveSeedingTimeLimit(),
352 .shareLimitAction
= m_ui
->torrentShareLimitsWidget
->shareLimitAction(),
353 .upSpeedLimit
= m_ui
->spinUploadLimit
->value(),
354 .downSpeedLimit
= m_ui
->spinDownloadLimit
->value(),
355 .autoTMM
= m_ui
->checkAutoTMM
->checkState(),
356 .useDownloadPath
= m_ui
->checkUseDownloadPath
->checkState(),
357 .disableDHT
= m_ui
->checkDisableDHT
->checkState(),
358 .disablePEX
= m_ui
->checkDisablePEX
->checkState(),
359 .disableLSD
= m_ui
->checkDisableLSD
->checkState(),
360 .sequential
= m_ui
->checkSequential
->checkState(),
361 .firstLastPieces
= m_ui
->checkFirstLastPieces
->checkState()
364 // Needs to be called after the initial values struct is initialized
366 handleUseDownloadPathChanged();
368 connect(m_ui
->checkAutoTMM
, &QCheckBox::clicked
, this, &TorrentOptionsDialog::handleTMMChanged
);
369 connect(m_ui
->checkUseDownloadPath
, &QCheckBox::clicked
, this, &TorrentOptionsDialog::handleUseDownloadPathChanged
);
370 connect(m_ui
->comboCategory
, &QComboBox::activated
, this, &TorrentOptionsDialog::handleCategoryChanged
);
372 // Sync up/down speed limit sliders with their corresponding spinboxes
373 connect(m_ui
->sliderUploadLimit
, &QSlider::valueChanged
, m_ui
->spinUploadLimit
, &QSpinBox::setValue
);
374 connect(m_ui
->sliderDownloadLimit
, &QSlider::valueChanged
, m_ui
->spinDownloadLimit
, &QSpinBox::setValue
);
375 connect(m_ui
->spinUploadLimit
, qOverload
<int>(&QSpinBox::valueChanged
)
376 , this, [this](const int value
) { updateSliderValue(m_ui
->sliderUploadLimit
, value
); });
377 connect(m_ui
->spinDownloadLimit
, qOverload
<int>(&QSpinBox::valueChanged
)
378 , this, [this](const int value
) { updateSliderValue(m_ui
->sliderDownloadLimit
, value
); });
380 if (const QSize dialogSize
= m_storeDialogSize
; dialogSize
.isValid())
384 TorrentOptionsDialog::~TorrentOptionsDialog()
386 m_storeDialogSize
= size();
390 void TorrentOptionsDialog::accept()
392 auto *session
= BitTorrent::Session::instance();
393 for (const BitTorrent::TorrentID
&id
: asConst(m_torrentIDs
))
395 BitTorrent::Torrent
*torrent
= session
->getTorrent(id
);
396 if (!torrent
) continue;
398 if (m_initialValues
.autoTMM
!= m_ui
->checkAutoTMM
->checkState())
399 torrent
->setAutoTMMEnabled(m_ui
->checkAutoTMM
->isChecked());
401 if (m_ui
->checkAutoTMM
->checkState() == Qt::Unchecked
)
403 const Path savePath
= m_ui
->savePath
->selectedPath();
404 if (m_initialValues
.savePath
!= savePath
)
405 torrent
->setSavePath(savePath
);
407 const Qt::CheckState useDownloadPathState
= m_ui
->checkUseDownloadPath
->checkState();
408 if (useDownloadPathState
== Qt::Checked
)
410 const Path downloadPath
= m_ui
->downloadPath
->selectedPath();
411 if (m_initialValues
.downloadPath
!= downloadPath
)
412 torrent
->setDownloadPath(downloadPath
);
414 else if (useDownloadPathState
== Qt::Unchecked
)
416 torrent
->setDownloadPath({});
420 const QString category
= m_ui
->comboCategory
->currentText();
421 // index 0 is always the current category
422 if ((m_initialValues
.category
!= category
) || (m_ui
->comboCategory
->currentIndex() != 0))
424 if (!m_categories
.contains(category
))
425 session
->addCategory(category
);
427 torrent
->setCategory(category
);
430 if (m_initialValues
.upSpeedLimit
!= m_ui
->spinUploadLimit
->value())
431 torrent
->setUploadLimit(m_ui
->spinUploadLimit
->value() * 1024);
432 if (m_initialValues
.downSpeedLimit
!= m_ui
->spinDownloadLimit
->value())
433 torrent
->setDownloadLimit(m_ui
->spinDownloadLimit
->value() * 1024);
435 if (const std::optional
<qreal
> ratioLimit
= m_ui
->torrentShareLimitsWidget
->ratioLimit();
436 m_initialValues
.ratio
!= ratioLimit
)
438 torrent
->setRatioLimit(ratioLimit
.value());
441 if (const std::optional
<int> seedingTimeLimit
= m_ui
->torrentShareLimitsWidget
->seedingTimeLimit();
442 m_initialValues
.seedingTime
!= seedingTimeLimit
)
444 torrent
->setSeedingTimeLimit(seedingTimeLimit
.value());
447 if (const std::optional
<int> inactiveSeedingTimeLimit
= m_ui
->torrentShareLimitsWidget
->inactiveSeedingTimeLimit();
448 m_initialValues
.inactiveSeedingTime
!= inactiveSeedingTimeLimit
)
450 torrent
->setInactiveSeedingTimeLimit(inactiveSeedingTimeLimit
.value());
453 if (const std::optional
<BitTorrent::ShareLimitAction
> shareLimitAction
= m_ui
->torrentShareLimitsWidget
->shareLimitAction();
454 m_initialValues
.shareLimitAction
!= shareLimitAction
)
456 torrent
->setShareLimitAction(shareLimitAction
.value());
459 if (!torrent
->isPrivate())
461 if (m_initialValues
.disableDHT
!= m_ui
->checkDisableDHT
->checkState())
462 torrent
->setDHTDisabled(m_ui
->checkDisableDHT
->isChecked());
463 if (m_initialValues
.disablePEX
!= m_ui
->checkDisablePEX
->checkState())
464 torrent
->setPEXDisabled(m_ui
->checkDisablePEX
->isChecked());
465 if (m_initialValues
.disableLSD
!= m_ui
->checkDisableLSD
->checkState())
466 torrent
->setLSDDisabled(m_ui
->checkDisableLSD
->isChecked());
469 if (m_initialValues
.sequential
!= m_ui
->checkSequential
->checkState())
470 torrent
->setSequentialDownload(m_ui
->checkSequential
->isChecked());
471 if (m_initialValues
.firstLastPieces
!= m_ui
->checkFirstLastPieces
->checkState())
472 torrent
->setFirstLastPiecePriority(m_ui
->checkFirstLastPieces
->isChecked());
478 void TorrentOptionsDialog::handleCategoryChanged([[maybe_unused
]] const int index
)
480 if (m_ui
->checkAutoTMM
->checkState() == Qt::Checked
)
482 if (!m_allSameCategory
&& (m_ui
->comboCategory
->currentIndex() == 0))
484 m_ui
->savePath
->setSelectedPath({});
488 const Path savePath
= BitTorrent::Session::instance()->categorySavePath(m_ui
->comboCategory
->currentText());
489 m_ui
->savePath
->setSelectedPath(savePath
);
490 const Path downloadPath
= BitTorrent::Session::instance()->categoryDownloadPath(m_ui
->comboCategory
->currentText());
491 m_ui
->downloadPath
->setSelectedPath(downloadPath
);
492 m_ui
->checkUseDownloadPath
->setChecked(!downloadPath
.isEmpty());
496 if (!m_allSameCategory
&& (m_ui
->comboCategory
->currentIndex() == 0))
498 m_ui
->comboCategory
->clearEditText();
499 m_ui
->comboCategory
->lineEdit()->setPlaceholderText(m_currentCategoriesString
);
503 m_ui
->comboCategory
->lineEdit()->setPlaceholderText(QString());
507 void TorrentOptionsDialog::handleTMMChanged()
509 if (m_ui
->checkAutoTMM
->checkState() == Qt::Unchecked
)
511 m_ui
->groupBoxSavePath
->setEnabled(true);
512 m_ui
->savePath
->setSelectedPath(m_initialValues
.savePath
);
513 m_ui
->downloadPath
->setSelectedPath(m_initialValues
.downloadPath
);
514 m_ui
->checkUseDownloadPath
->setCheckState(m_initialValues
.useDownloadPath
);
518 m_ui
->groupBoxSavePath
->setEnabled(false);
519 if (m_ui
->checkAutoTMM
->checkState() == Qt::Checked
)
521 if (!m_allSameCategory
&& (m_ui
->comboCategory
->currentIndex() == 0))
523 m_ui
->savePath
->setSelectedPath({});
524 m_ui
->downloadPath
->setSelectedPath({});
525 m_ui
->checkUseDownloadPath
->setCheckState(Qt::PartiallyChecked
);
529 const Path savePath
= BitTorrent::Session::instance()->categorySavePath(m_ui
->comboCategory
->currentText());
530 m_ui
->savePath
->setSelectedPath(savePath
);
531 const Path downloadPath
= BitTorrent::Session::instance()->categoryDownloadPath(m_ui
->comboCategory
->currentText());
532 m_ui
->downloadPath
->setSelectedPath(downloadPath
);
533 m_ui
->checkUseDownloadPath
->setChecked(!downloadPath
.isEmpty());
536 else // partially checked
538 m_ui
->savePath
->setSelectedPath({});
539 m_ui
->downloadPath
->setSelectedPath({});
540 m_ui
->checkUseDownloadPath
->setCheckState(Qt::PartiallyChecked
);
545 void TorrentOptionsDialog::handleUseDownloadPathChanged()
547 const bool isChecked
= m_ui
->checkUseDownloadPath
->checkState() == Qt::Checked
;
548 m_ui
->downloadPath
->setEnabled(isChecked
);
549 if (isChecked
&& m_ui
->downloadPath
->selectedPath().isEmpty())
550 m_ui
->downloadPath
->setSelectedPath(BitTorrent::Session::instance()->downloadPath());
553 void TorrentOptionsDialog::handleUpSpeedLimitChanged()
555 m_ui
->spinUploadLimit
->setMinimum(0);
556 m_ui
->spinUploadLimit
->setSpecialValueText(C_INFINITY
);
557 disconnect(m_ui
->spinUploadLimit
, qOverload
<int>(&QSpinBox::valueChanged
)
558 , this, &TorrentOptionsDialog::handleUpSpeedLimitChanged
);
561 void TorrentOptionsDialog::handleDownSpeedLimitChanged()
563 m_ui
->spinDownloadLimit
->setMinimum(0);
564 m_ui
->spinDownloadLimit
->setSpecialValueText(C_INFINITY
);
565 disconnect(m_ui
->spinDownloadLimit
, qOverload
<int>(&QSpinBox::valueChanged
)
566 , this, &TorrentOptionsDialog::handleDownSpeedLimitChanged
);