diff --git a/src/base/bittorrent/addtorrentparams.h b/src/base/bittorrent/addtorrentparams.h index 17df907d6..6039df669 100644 --- a/src/base/bittorrent/addtorrentparams.h +++ b/src/base/bittorrent/addtorrentparams.h @@ -54,6 +54,7 @@ namespace BitTorrent bool sequential = false; bool firstLastPiecePriority = false; bool addForced = false; + std::optional addToQueueTop; std::optional addPaused; std::optional stopCondition; PathList filePaths; // used if TorrentInfo is set diff --git a/src/base/bittorrent/loadtorrentparams.h b/src/base/bittorrent/loadtorrentparams.h index ca3d914fb..c59f3590b 100644 --- a/src/base/bittorrent/loadtorrentparams.h +++ b/src/base/bittorrent/loadtorrentparams.h @@ -56,6 +56,8 @@ namespace BitTorrent bool stopped = false; Torrent::StopCondition stopCondition; + bool addToQueueTop = false; // only for new torrents + qreal ratioLimit = Torrent::USE_GLOBAL_RATIO; int seedingTimeLimit = Torrent::USE_GLOBAL_SEEDING_TIME; }; diff --git a/src/base/bittorrent/session.h b/src/base/bittorrent/session.h index f78abccf8..07346ca08 100644 --- a/src/base/bittorrent/session.h +++ b/src/base/bittorrent/session.h @@ -206,6 +206,8 @@ namespace BitTorrent virtual void setLSDEnabled(bool enabled) = 0; virtual bool isPeXEnabled() const = 0; virtual void setPeXEnabled(bool enabled) = 0; + virtual bool isAddTorrentToQueueTop() const = 0; + virtual void setAddTorrentToQueueTop(bool value) = 0; virtual bool isAddTorrentPaused() const = 0; virtual void setAddTorrentPaused(bool value) = 0; virtual Torrent::StopCondition torrentStopCondition() const = 0; diff --git a/src/base/bittorrent/sessionimpl.cpp b/src/base/bittorrent/sessionimpl.cpp index 0c2a6cbb7..1a068f761 100644 --- a/src/base/bittorrent/sessionimpl.cpp +++ b/src/base/bittorrent/sessionimpl.cpp @@ -471,6 +471,7 @@ SessionImpl::SessionImpl(QObject *parent) , m_additionalTrackers(BITTORRENT_SESSION_KEY(u"AdditionalTrackers"_qs)) , m_globalMaxRatio(BITTORRENT_SESSION_KEY(u"GlobalMaxRatio"_qs), -1, [](qreal r) { return r < 0 ? -1. : r;}) , m_globalMaxSeedingMinutes(BITTORRENT_SESSION_KEY(u"GlobalMaxSeedingMinutes"_qs), -1, lowerLimited(-1)) + , m_isAddTorrentToQueueTop(BITTORRENT_SESSION_KEY(u"AddTorrentToTopOfQueue"_qs), false) , m_isAddTorrentPaused(BITTORRENT_SESSION_KEY(u"AddTorrentPaused"_qs), false) , m_torrentStopCondition(BITTORRENT_SESSION_KEY(u"TorrentStopCondition"_qs), Torrent::StopCondition::None) , m_torrentContentLayout(BITTORRENT_SESSION_KEY(u"TorrentContentLayout"_qs), TorrentContentLayout::Original) @@ -1015,6 +1016,16 @@ void SessionImpl::setDisableAutoTMMWhenCategorySavePathChanged(const bool value) m_isDisableAutoTMMWhenCategorySavePathChanged = value; } +bool SessionImpl::isAddTorrentToQueueTop() const +{ + return m_isAddTorrentToQueueTop; +} + +void SessionImpl::setAddTorrentToQueueTop(bool value) +{ + m_isAddTorrentToQueueTop = value; +} + bool SessionImpl::isAddTorrentPaused() const { return m_isAddTorrentPaused; @@ -2534,6 +2545,7 @@ LoadTorrentParams SessionImpl::initLoadTorrentParams(const AddTorrentParams &add loadTorrentParams.operatingMode = (addTorrentParams.addForced ? TorrentOperatingMode::Forced : TorrentOperatingMode::AutoManaged); loadTorrentParams.stopped = addTorrentParams.addPaused.value_or(isAddTorrentPaused()); loadTorrentParams.stopCondition = addTorrentParams.stopCondition.value_or(torrentStopCondition()); + loadTorrentParams.addToQueueTop = addTorrentParams.addToQueueTop.value_or(false); loadTorrentParams.ratioLimit = addTorrentParams.ratioLimit; loadTorrentParams.seedingTimeLimit = addTorrentParams.seedingTimeLimit; @@ -5177,7 +5189,7 @@ void SessionImpl::handleAddTorrentAlerts(const std::vector &alerts) if (const auto loadingTorrentsIter = m_loadingTorrents.find(torrentID) ; loadingTorrentsIter != m_loadingTorrents.end()) { - LoadTorrentParams params = loadingTorrentsIter.value(); + const LoadTorrentParams params = loadingTorrentsIter.value(); m_loadingTorrents.erase(loadingTorrentsIter); Torrent *torrent = createTorrent(alert->handle, params); @@ -5339,6 +5351,9 @@ TorrentImpl *SessionImpl::createTorrent(const lt::torrent_handle &nativeHandle, if (isRestored()) { + if (params.addToQueueTop) + nativeHandle.queue_position_top(); + torrent->saveResumeData(lt::torrent_handle::save_info_dict); // The following is useless for newly added magnet diff --git a/src/base/bittorrent/sessionimpl.h b/src/base/bittorrent/sessionimpl.h index a6de23091..a7d378a3e 100644 --- a/src/base/bittorrent/sessionimpl.h +++ b/src/base/bittorrent/sessionimpl.h @@ -183,6 +183,8 @@ namespace BitTorrent void setLSDEnabled(bool enabled) override; bool isPeXEnabled() const override; void setPeXEnabled(bool enabled) override; + bool isAddTorrentToQueueTop() const override; + void setAddTorrentToQueueTop(bool value) override; bool isAddTorrentPaused() const override; void setAddTorrentPaused(bool value) override; Torrent::StopCondition torrentStopCondition() const override; @@ -629,6 +631,7 @@ namespace BitTorrent CachedSettingValue m_additionalTrackers; CachedSettingValue m_globalMaxRatio; CachedSettingValue m_globalMaxSeedingMinutes; + CachedSettingValue m_isAddTorrentToQueueTop; CachedSettingValue m_isAddTorrentPaused; CachedSettingValue m_torrentStopCondition; CachedSettingValue m_torrentContentLayout; diff --git a/src/base/torrentfileswatcher.cpp b/src/base/torrentfileswatcher.cpp index c89b2a303..be3971f84 100644 --- a/src/base/torrentfileswatcher.cpp +++ b/src/base/torrentfileswatcher.cpp @@ -76,6 +76,7 @@ const QString PARAM_SAVEPATH = u"save_path"_qs; const QString PARAM_USEDOWNLOADPATH = u"use_download_path"_qs; const QString PARAM_DOWNLOADPATH = u"download_path"_qs; const QString PARAM_OPERATINGMODE = u"operating_mode"_qs; +const QString PARAM_QUEUETOP = u"add_to_top_of_queue"_qs; const QString PARAM_STOPPED = u"stopped"_qs; const QString PARAM_SKIPCHECKING = u"skip_checking"_qs; const QString PARAM_CONTENTLAYOUT = u"content_layout"_qs; @@ -140,6 +141,7 @@ namespace params.useDownloadPath = getOptionalBool(jsonObj, PARAM_USEDOWNLOADPATH); params.downloadPath = Path(jsonObj.value(PARAM_DOWNLOADPATH).toString()); params.addForced = (getEnum(jsonObj, PARAM_OPERATINGMODE) == BitTorrent::TorrentOperatingMode::Forced); + params.addToQueueTop = getOptionalBool(jsonObj, PARAM_QUEUETOP); params.addPaused = getOptionalBool(jsonObj, PARAM_STOPPED); params.skipChecking = jsonObj.value(PARAM_SKIPCHECKING).toBool(); params.contentLayout = getOptionalEnum(jsonObj, PARAM_CONTENTLAYOUT); @@ -168,6 +170,8 @@ namespace {PARAM_RATIOLIMIT, params.ratioLimit} }; + if (params.addToQueueTop) + jsonObj[PARAM_QUEUETOP] = *params.addToQueueTop; if (params.addPaused) jsonObj[PARAM_STOPPED] = *params.addPaused; if (params.contentLayout) diff --git a/src/gui/addnewtorrentdialog.cpp b/src/gui/addnewtorrentdialog.cpp index c6049fded..dedd38f54 100644 --- a/src/gui/addnewtorrentdialog.cpp +++ b/src/gui/addnewtorrentdialog.cpp @@ -217,6 +217,7 @@ AddNewTorrentDialog::AddNewTorrentDialog(const BitTorrent::AddTorrentParams &inP m_ui->downloadPath->setDialogCaption(tr("Choose save path")); m_ui->downloadPath->setMaxVisibleItems(20); + m_ui->addToQueueTopCheckBox->setChecked(m_torrentParams.addToQueueTop.value_or(session->isAddTorrentToQueueTop())); m_ui->startTorrentCheckBox->setChecked(!m_torrentParams.addPaused.value_or(session->isAddTorrentPaused())); m_ui->stopConditionComboBox->setToolTip( u"

" + tr("None") + u" - " + tr("No stop condition is set.") + u"

" + @@ -889,6 +890,7 @@ void AddNewTorrentDialog::accept() if (m_contentModel) m_torrentParams.filePriorities = m_contentModel->model()->getFilePriorities(); + m_torrentParams.addToQueueTop = m_ui->addToQueueTopCheckBox->isChecked(); m_torrentParams.addPaused = !m_ui->startTorrentCheckBox->isChecked(); m_torrentParams.stopCondition = m_ui->stopConditionComboBox->currentData().value(); m_torrentParams.contentLayout = static_cast(m_ui->contentLayoutComboBox->currentIndex()); diff --git a/src/gui/addnewtorrentdialog.ui b/src/gui/addnewtorrentdialog.ui index 3b8926ee9..dac5358b4 100644 --- a/src/gui/addnewtorrentdialog.ui +++ b/src/gui/addnewtorrentdialog.ui @@ -257,6 +257,13 @@ + + + Add to top of queue + + + + Skip hash check diff --git a/src/gui/optionsdialog.cpp b/src/gui/optionsdialog.cpp index b3b14fde6..afa03b70a 100644 --- a/src/gui/optionsdialog.cpp +++ b/src/gui/optionsdialog.cpp @@ -466,6 +466,7 @@ void OptionsDialog::loadDownloadsTabOptions() m_ui->checkAdditionDialogFront->setChecked(AddNewTorrentDialog::isTopLevel()); m_ui->contentLayoutComboBox->setCurrentIndex(static_cast(session->torrentContentLayout())); + m_ui->checkAddToQueueTop->setChecked(session->isAddTorrentToQueueTop()); m_ui->checkStartPaused->setChecked(session->isAddTorrentPaused()); m_ui->stopConditionComboBox->setToolTip( @@ -588,6 +589,7 @@ void OptionsDialog::loadDownloadsTabOptions() connect(m_ui->contentLayoutComboBox, qComboBoxCurrentIndexChanged, this, &ThisType::enableApplyButton); + connect(m_ui->checkAddToQueueTop, &QAbstractButton::toggled, this, &ThisType::enableApplyButton); connect(m_ui->checkStartPaused, &QAbstractButton::toggled, this, &ThisType::enableApplyButton); connect(m_ui->checkStartPaused, &QAbstractButton::toggled, this, [this](const bool checked) { @@ -653,6 +655,7 @@ void OptionsDialog::saveDownloadsTabOptions() const session->setTorrentContentLayout(static_cast(m_ui->contentLayoutComboBox->currentIndex())); + session->setAddTorrentToQueueTop(m_ui->checkAddToQueueTop->isChecked()); session->setAddTorrentPaused(addTorrentsInPause()); session->setTorrentStopCondition(m_ui->stopConditionComboBox->currentData().value()); TorrentFileGuard::setAutoDeleteMode(!m_ui->deleteTorrentBox->isChecked() ? TorrentFileGuard::Never diff --git a/src/gui/optionsdialog.ui b/src/gui/optionsdialog.ui index 029ef056e..2693cef96 100644 --- a/src/gui/optionsdialog.ui +++ b/src/gui/optionsdialog.ui @@ -857,6 +857,16 @@ + + + + The torrent will be added to the top of the download queue + + + Add to top of queue + + + diff --git a/src/gui/watchedfolderoptionsdialog.cpp b/src/gui/watchedfolderoptionsdialog.cpp index 06deb20e1..30b513c68 100644 --- a/src/gui/watchedfolderoptionsdialog.cpp +++ b/src/gui/watchedfolderoptionsdialog.cpp @@ -65,6 +65,7 @@ WatchedFolderOptionsDialog::WatchedFolderOptionsDialog( populateSavePaths(); const BitTorrent::AddTorrentParams &torrentParams = watchedFolderOptions.addTorrentParams; + m_ui->addToQueueTopCheckBox->setChecked(torrentParams.addToQueueTop.value_or(session->isAddTorrentToQueueTop())); m_ui->startTorrentCheckBox->setChecked(!torrentParams.addPaused.value_or(session->isAddTorrentPaused())); m_ui->skipCheckingCheckBox->setChecked(torrentParams.skipChecking); m_ui->comboTTM->setCurrentIndex(torrentParams.useAutoTMM.value_or(!session->isAutoTMMDisabledByDefault())); @@ -116,6 +117,7 @@ TorrentFilesWatcher::WatchedFolderOptions WatchedFolderOptionsDialog::watchedFol } params.useAutoTMM = useAutoTMM; params.category = m_ui->categoryComboBox->currentText(); + params.addToQueueTop = m_ui->addToQueueTopCheckBox->isChecked(); params.addPaused = !m_ui->startTorrentCheckBox->isChecked(); params.skipChecking = m_ui->skipCheckingCheckBox->isChecked(); params.contentLayout = static_cast(m_ui->contentLayoutComboBox->currentIndex()); diff --git a/src/gui/watchedfolderoptionsdialog.ui b/src/gui/watchedfolderoptionsdialog.ui index 8f1d8bc9d..1e14ae385 100644 --- a/src/gui/watchedfolderoptionsdialog.ui +++ b/src/gui/watchedfolderoptionsdialog.ui @@ -204,6 +204,30 @@ + + + + + + Add to top of queue + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + diff --git a/src/webui/api/appcontroller.cpp b/src/webui/api/appcontroller.cpp index e0ddc7d5b..d0097dd61 100644 --- a/src/webui/api/appcontroller.cpp +++ b/src/webui/api/appcontroller.cpp @@ -110,6 +110,7 @@ void AppController::preferencesAction() // Downloads // When adding a torrent data[u"torrent_content_layout"_qs] = Utils::String::fromEnum(session->torrentContentLayout()); + data[u"add_to_top_of_queue"_qs] = session->isAddTorrentToQueueTop(); data[u"start_paused_enabled"_qs] = session->isAddTorrentPaused(); data[u"torrent_stop_condition"_qs] = Utils::String::fromEnum(session->torrentStopCondition()); data[u"auto_delete_mode"_qs] = static_cast(TorrentFileGuard::autoDeleteMode()); @@ -414,6 +415,8 @@ void AppController::setPreferencesAction() // When adding a torrent if (hasKey(u"torrent_content_layout"_qs)) session->setTorrentContentLayout(Utils::String::toEnum(it.value().toString(), BitTorrent::TorrentContentLayout::Original)); + if (hasKey(u"add_to_top_of_queue"_qs)) + session->setAddTorrentToQueueTop(it.value().toBool()); if (hasKey(u"start_paused_enabled"_qs)) session->setAddTorrentPaused(it.value().toBool()); if (hasKey(u"torrent_stop_condition"_qs)) diff --git a/src/webui/api/torrentscontroller.cpp b/src/webui/api/torrentscontroller.cpp index 6ede337e5..b908e97dd 100644 --- a/src/webui/api/torrentscontroller.cpp +++ b/src/webui/api/torrentscontroller.cpp @@ -661,6 +661,7 @@ void TorrentsController::addAction() const bool skipChecking = parseBool(params()[u"skip_checking"_qs]).value_or(false); const bool seqDownload = parseBool(params()[u"sequentialDownload"_qs]).value_or(false); const bool firstLastPiece = parseBool(params()[u"firstLastPiecePrio"_qs]).value_or(false); + const std::optional addToQueueTop = parseBool(params()[u"addToTopOfQueue"_qs]); const std::optional addPaused = parseBool(params()[u"paused"_qs]); const QString savepath = params()[u"savepath"_qs].trimmed(); const QString downloadPath = params()[u"downloadPath"_qs].trimmed(); @@ -706,6 +707,7 @@ void TorrentsController::addAction() addTorrentParams.skipChecking = skipChecking; addTorrentParams.sequential = seqDownload; addTorrentParams.firstLastPiecePriority = firstLastPiece; + addTorrentParams.addToQueueTop = addToQueueTop; addTorrentParams.addPaused = addPaused; addTorrentParams.stopCondition = stopCondition; addTorrentParams.contentLayout = contentLayout;