Backport changes to v5.0.x branch

PR #22336.
This commit is contained in:
Vladimir Golovnev 2025-04-02 11:16:56 +03:00 committed by GitHub
commit a6809efbbb
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
8 changed files with 105 additions and 25 deletions

View file

@ -1,6 +1,6 @@
/*
* Bittorrent Client using Qt and libtorrent.
* Copyright (C) 2015-2024 Vladimir Golovnev <glassez@yandex.ru>
* Copyright (C) 2015-2025 Vladimir Golovnev <glassez@yandex.ru>
* Copyright (C) 2006 Christophe Dumez
*
* This program is free software; you can redistribute it and/or
@ -124,6 +124,28 @@ namespace
const int PIXMAP_CACHE_SIZE = 64 * 1024 * 1024; // 64MiB
#endif
const QString PARAM_ADDSTOPPED = u"@addStopped"_s;
const QString PARAM_CATEGORY = u"@category"_s;
const QString PARAM_FIRSTLASTPIECEPRIORITY = u"@firstLastPiecePriority"_s;
const QString PARAM_SAVEPATH = u"@savePath"_s;
const QString PARAM_SEQUENTIAL = u"@sequential"_s;
const QString PARAM_SKIPCHECKING = u"@skipChecking"_s;
const QString PARAM_SKIPDIALOG = u"@skipDialog"_s;
QString bindParamValue(const QStringView paramName, const QStringView paramValue)
{
return paramName + u'=' + paramValue;
}
std::pair<QStringView, QStringView> parseParam(const QStringView param)
{
const qsizetype sepIndex = param.indexOf(u'=');
if (sepIndex >= 0)
return {param.first(sepIndex), param.sliced(sepIndex + 1)};
return {param, {}};
}
QString serializeParams(const QBtCommandLineParameters &params)
{
QStringList result;
@ -138,85 +160,86 @@ namespace
const BitTorrent::AddTorrentParams &addTorrentParams = params.addTorrentParams;
if (!addTorrentParams.savePath.isEmpty())
result.append(u"@savePath=" + addTorrentParams.savePath.data());
result.append(bindParamValue(PARAM_SAVEPATH, addTorrentParams.savePath.data()));
if (addTorrentParams.addStopped.has_value())
result.append(*addTorrentParams.addStopped ? u"@addStopped=1"_s : u"@addStopped=0"_s);
result.append(bindParamValue(PARAM_ADDSTOPPED, (*addTorrentParams.addStopped ? u"1" : u"0")));
if (addTorrentParams.skipChecking)
result.append(u"@skipChecking"_s);
result.append(PARAM_SKIPCHECKING);
if (!addTorrentParams.category.isEmpty())
result.append(u"@category=" + addTorrentParams.category);
result.append(bindParamValue(PARAM_CATEGORY, addTorrentParams.category));
if (addTorrentParams.sequential)
result.append(u"@sequential"_s);
result.append(PARAM_SEQUENTIAL);
if (addTorrentParams.firstLastPiecePriority)
result.append(u"@firstLastPiecePriority"_s);
result.append(PARAM_FIRSTLASTPIECEPRIORITY);
if (params.skipDialog.has_value())
result.append(*params.skipDialog ? u"@skipDialog=1"_s : u"@skipDialog=0"_s);
result.append(bindParamValue(PARAM_SKIPDIALOG, (*params.skipDialog ? u"1" : u"0")));
result += params.torrentSources;
return result.join(PARAMS_SEPARATOR);
}
QBtCommandLineParameters parseParams(const QString &str)
QBtCommandLineParameters parseParams(const QStringView str)
{
QBtCommandLineParameters parsedParams;
BitTorrent::AddTorrentParams &addTorrentParams = parsedParams.addTorrentParams;
for (QString param : asConst(str.split(PARAMS_SEPARATOR, Qt::SkipEmptyParts)))
for (QStringView param : asConst(str.split(PARAMS_SEPARATOR, Qt::SkipEmptyParts)))
{
param = param.trimmed();
const auto [paramName, paramValue] = parseParam(param);
// Process strings indicating options specified by the user.
if (param.startsWith(u"@savePath="))
if (paramName == PARAM_SAVEPATH)
{
addTorrentParams.savePath = Path(param.mid(10));
addTorrentParams.savePath = Path(paramValue.toString());
continue;
}
if (param.startsWith(u"@addStopped="))
if (paramName == PARAM_ADDSTOPPED)
{
addTorrentParams.addStopped = (QStringView(param).mid(11).toInt() != 0);
addTorrentParams.addStopped = (paramValue.toInt() != 0);
continue;
}
if (param == u"@skipChecking")
if (paramName == PARAM_SKIPCHECKING)
{
addTorrentParams.skipChecking = true;
continue;
}
if (param.startsWith(u"@category="))
if (paramName == PARAM_CATEGORY)
{
addTorrentParams.category = param.mid(10);
addTorrentParams.category = paramValue.toString();
continue;
}
if (param == u"@sequential")
if (paramName == PARAM_SEQUENTIAL)
{
addTorrentParams.sequential = true;
continue;
}
if (param == u"@firstLastPiecePriority")
if (paramName == PARAM_FIRSTLASTPIECEPRIORITY)
{
addTorrentParams.firstLastPiecePriority = true;
continue;
}
if (param.startsWith(u"@skipDialog="))
if (paramName == PARAM_SKIPDIALOG)
{
parsedParams.skipDialog = (QStringView(param).mid(12).toInt() != 0);
parsedParams.skipDialog = (paramValue.toInt() != 0);
continue;
}
parsedParams.torrentSources.append(param);
parsedParams.torrentSources.append(param.toString());
}
return parsedParams;

View file

@ -29,7 +29,10 @@
#pragma once
#include <QByteArray>
#include <QHash>
#include <QHostAddress>
#include <QMap>
#include <QString>
#include <QVector>

View file

@ -2000,6 +2000,19 @@ void Preferences::setAddNewTorrentDialogSavePathHistoryLength(const int value)
setValue(u"AddNewTorrentDialog/SavePathHistoryLength"_s, clampedValue);
}
bool Preferences::isAddNewTorrentDialogAttached() const
{
return value(u"AddNewTorrentDialog/Attached"_s, false);
}
void Preferences::setAddNewTorrentDialogAttached(const bool attached)
{
if (attached == isAddNewTorrentDialogAttached())
return;
setValue(u"AddNewTorrentDialog/Attached"_s, attached);
}
void Preferences::apply()
{
if (SettingsStorage::instance()->save())

View file

@ -423,6 +423,8 @@ public:
void setAddNewTorrentDialogTopLevel(bool value);
int addNewTorrentDialogSavePathHistoryLength() const;
void setAddNewTorrentDialogSavePathHistoryLength(int value);
bool isAddNewTorrentDialogAttached() const;
void setAddNewTorrentDialogAttached(bool attached);
public slots:
void setStatusFilterState(bool checked);

View file

@ -97,6 +97,7 @@ namespace
ENABLE_SPEED_WIDGET,
#ifndef Q_OS_MACOS
ENABLE_ICONS_IN_MENUS,
USE_ATTACHED_ADD_NEW_TORRENT_DIALOG,
#endif
// embedded tracker
TRACKER_STATUS,
@ -323,6 +324,7 @@ void AdvancedSettings::saveAdvancedSettings() const
pref->setSpeedWidgetEnabled(m_checkBoxSpeedWidgetEnabled.isChecked());
#ifndef Q_OS_MACOS
pref->setIconsInMenusEnabled(m_checkBoxIconsInMenusEnabled.isChecked());
pref->setAddNewTorrentDialogAttached(m_checkBoxAttachedAddNewTorrentDialog.isChecked());
#endif
// Tracker
@ -835,6 +837,9 @@ void AdvancedSettings::loadAdvancedSettings()
// Enable icons in menus
m_checkBoxIconsInMenusEnabled.setChecked(pref->iconsInMenusEnabled());
addRow(ENABLE_ICONS_IN_MENUS, tr("Enable icons in menus"), &m_checkBoxIconsInMenusEnabled);
m_checkBoxAttachedAddNewTorrentDialog.setChecked(pref->isAddNewTorrentDialogAttached());
addRow(USE_ATTACHED_ADD_NEW_TORRENT_DIALOG, tr("Attach \"Add new torrent\" dialog to main window"), &m_checkBoxAttachedAddNewTorrentDialog);
#endif
// Tracker State
m_checkBoxTrackerStatus.setChecked(session->isTrackerEnabled());

View file

@ -108,6 +108,7 @@ private:
#ifndef Q_OS_MACOS
QCheckBox m_checkBoxIconsInMenusEnabled;
QCheckBox m_checkBoxAttachedAddNewTorrentDialog;
#endif
#if defined(Q_OS_MACOS) || defined(Q_OS_WIN)

View file

@ -225,12 +225,19 @@ bool GUIAddTorrentManager::processTorrent(const QString &source
if (!hasMetadata)
btSession()->downloadMetadata(torrentDescr);
#ifdef Q_OS_MACOS
const bool attached = false;
#else
const bool attached = Preferences::instance()->isAddNewTorrentDialogAttached();
#endif
// By not setting a parent to the "AddNewTorrentDialog", all those dialogs
// will be displayed on top and will not overlap with the main window.
auto *dlg = new AddNewTorrentDialog(torrentDescr, params, nullptr);
auto *dlg = new AddNewTorrentDialog(torrentDescr, params, (attached ? app()->mainWindow() : nullptr));
// Qt::Window is required to avoid showing only two dialog on top (see #12852).
// Also improves the general convenience of adding multiple torrents.
dlg->setWindowFlags(Qt::Window);
if (!attached)
dlg->setWindowFlags(Qt::Window);
dlg->setAttribute(Qt::WA_DeleteOnClose);
m_dialogs[infoHash] = dlg;

View file

@ -80,7 +80,33 @@ inline QHash<QString, UIThemeColor> defaultUIThemeColors()
{u"TransferList.StoppedUploading"_s, {Color::Primer::Light::doneFg, Color::Primer::Dark::doneFg}},
{u"TransferList.Moving"_s, {Color::Primer::Light::successFg, Color::Primer::Dark::successFg}},
{u"TransferList.MissingFiles"_s, {Color::Primer::Light::dangerFg, Color::Primer::Dark::dangerFg}},
{u"TransferList.Error"_s, {Color::Primer::Light::dangerFg, Color::Primer::Dark::dangerFg}}
{u"TransferList.Error"_s, {Color::Primer::Light::dangerFg, Color::Primer::Dark::dangerFg}},
{u"Palette.Window"_s, {{}, {}}},
{u"Palette.WindowText"_s, {{}, {}}},
{u"Palette.Base"_s, {{}, {}}},
{u"Palette.AlternateBase"_s, {{}, {}}},
{u"Palette.Text"_s, {{}, {}}},
{u"Palette.ToolTipBase"_s, {{}, {}}},
{u"Palette.ToolTipText"_s, {{}, {}}},
{u"Palette.BrightText"_s, {{}, {}}},
{u"Palette.Highlight"_s, {{}, {}}},
{u"Palette.HighlightedText"_s, {{}, {}}},
{u"Palette.Button"_s, {{}, {}}},
{u"Palette.ButtonText"_s, {{}, {}}},
{u"Palette.Link"_s, {{}, {}}},
{u"Palette.LinkVisited"_s, {{}, {}}},
{u"Palette.Light"_s, {{}, {}}},
{u"Palette.Midlight"_s, {{}, {}}},
{u"Palette.Mid"_s, {{}, {}}},
{u"Palette.Dark"_s, {{}, {}}},
{u"Palette.Shadow"_s, {{}, {}}},
{u"Palette.WindowTextDisabled"_s, {{}, {}}},
{u"Palette.TextDisabled"_s, {{}, {}}},
{u"Palette.ToolTipTextDisabled"_s, {{}, {}}},
{u"Palette.BrightTextDisabled"_s, {{}, {}}},
{u"Palette.HighlightedTextDisabled"_s, {{}, {}}},
{u"Palette.ButtonTextDisabled"_s, {{}, {}}}
};
}