mirror of
https://github.com/qbittorrent/qBittorrent
synced 2025-08-20 21:33:27 -07:00
commit
76a3aba7e0
21 changed files with 251 additions and 68 deletions
13
.github/workflows/ci_ubuntu.yaml
vendored
13
.github/workflows/ci_ubuntu.yaml
vendored
|
@ -138,16 +138,15 @@ jobs:
|
|||
|
||||
- name: Install AppImage
|
||||
run: |
|
||||
sudo apt install libfuse2
|
||||
curl \
|
||||
-L \
|
||||
-Z \
|
||||
-O https://github.com/linuxdeploy/linuxdeploy/releases/download/continuous/linuxdeploy-static-x86_64.AppImage \
|
||||
-O https://github.com/linuxdeploy/linuxdeploy-plugin-qt/releases/download/continuous/linuxdeploy-plugin-qt-static-x86_64.AppImage \
|
||||
-O https://github.com/linuxdeploy/linuxdeploy/releases/download/continuous/linuxdeploy-x86_64.AppImage \
|
||||
-O https://github.com/linuxdeploy/linuxdeploy-plugin-qt/releases/download/continuous/linuxdeploy-plugin-qt-x86_64.AppImage \
|
||||
-O https://github.com/linuxdeploy/linuxdeploy-plugin-appimage/releases/download/continuous/linuxdeploy-plugin-appimage-x86_64.AppImage
|
||||
chmod +x \
|
||||
linuxdeploy-static-x86_64.AppImage \
|
||||
linuxdeploy-plugin-qt-static-x86_64.AppImage \
|
||||
linuxdeploy-x86_64.AppImage \
|
||||
linuxdeploy-plugin-qt-x86_64.AppImage \
|
||||
linuxdeploy-plugin-appimage-x86_64.AppImage
|
||||
|
||||
- name: Prepare files for AppImage
|
||||
|
@ -160,12 +159,12 @@ jobs:
|
|||
|
||||
- name: Package AppImage
|
||||
run: |
|
||||
./linuxdeploy-static-x86_64.AppImage --appdir qbittorrent --plugin qt
|
||||
./linuxdeploy-x86_64.AppImage --appdir qbittorrent --plugin qt
|
||||
rm qbittorrent/apprun-hooks/*
|
||||
cp .github/workflows/helper/appimage/export_vars.sh qbittorrent/apprun-hooks/export_vars.sh
|
||||
NO_APPSTREAM=1 \
|
||||
OUTPUT=upload/qbittorrent-CI_Ubuntu_x86_64.AppImage \
|
||||
./linuxdeploy-static-x86_64.AppImage --appdir qbittorrent --output appimage
|
||||
./linuxdeploy-x86_64.AppImage --appdir qbittorrent --output appimage
|
||||
|
||||
- name: Upload build artifacts
|
||||
uses: actions/upload-artifact@v4
|
||||
|
|
12
dist/windows/installer-translations/swedish.nsh
vendored
12
dist/windows/installer-translations/swedish.nsh
vendored
|
@ -7,21 +7,21 @@ LangString inst_desktop ${LANG_SWEDISH} "Skapa skrivbordsgenväg"
|
|||
;LangString inst_startmenu ${LANG_ENGLISH} "Create Start Menu Shortcut"
|
||||
LangString inst_startmenu ${LANG_SWEDISH} "Skapa startmenygenväg"
|
||||
;LangString inst_startup ${LANG_ENGLISH} "Start qBittorrent on Windows start up"
|
||||
LangString inst_startup ${LANG_SWEDISH} "Starta qBittorrent vid Windows start"
|
||||
LangString inst_startup ${LANG_SWEDISH} "Starta qBittorrent vid Windows-uppstart"
|
||||
;LangString inst_torrent ${LANG_ENGLISH} "Open .torrent files with qBittorrent"
|
||||
LangString inst_torrent ${LANG_SWEDISH} "Öppna .torrent-filer med qBittorrent"
|
||||
;LangString inst_magnet ${LANG_ENGLISH} "Open magnet links with qBittorrent"
|
||||
LangString inst_magnet ${LANG_SWEDISH} "Öppna magnetlänkar med qBittorrent"
|
||||
;LangString inst_firewall ${LANG_ENGLISH} "Add Windows Firewall rule"
|
||||
LangString inst_firewall ${LANG_SWEDISH} "Lägg till Windows-brandväggregel"
|
||||
LangString inst_firewall ${LANG_SWEDISH} "Lägg till Windows-brandväggsregel"
|
||||
;LangString inst_pathlimit ${LANG_ENGLISH} "Disable Windows path length limit (260 character MAX_PATH limitation, requires Windows 10 1607 or later)"
|
||||
LangString inst_pathlimit ${LANG_SWEDISH} "Inaktivera gränsen för Windows-sökvägslängd (260 tecken MAX_PATH-begränsning, kräver Windows 10 1607 eller senare)"
|
||||
;LangString inst_firewallinfo ${LANG_ENGLISH} "Adding Windows Firewall rule"
|
||||
LangString inst_firewallinfo ${LANG_SWEDISH} "Lägger till Windows-brandväggregel"
|
||||
LangString inst_firewallinfo ${LANG_SWEDISH} "Lägger till Windows-brandväggsregel"
|
||||
;LangString inst_warning ${LANG_ENGLISH} "qBittorrent is running. Please close the application before installing."
|
||||
LangString inst_warning ${LANG_SWEDISH} "qBittorrent körs. Vänligen stäng programmet innan du installerar."
|
||||
LangString inst_warning ${LANG_SWEDISH} "qBittorrent körs. Stäng programmet innan du installerar."
|
||||
;LangString inst_uninstall_question ${LANG_ENGLISH} "Current version will be uninstalled. User settings and torrents will remain intact."
|
||||
LangString inst_uninstall_question ${LANG_SWEDISH} "Nuvarande version avinstalleras. Användarinställningar och torrenter kommer att förbli intakta."
|
||||
LangString inst_uninstall_question ${LANG_SWEDISH} "Aktuell version avinstalleras. Användarinställningar och torrenter kommer att förbli intakta."
|
||||
;LangString inst_unist ${LANG_ENGLISH} "Uninstalling previous version."
|
||||
LangString inst_unist ${LANG_SWEDISH} "Avinstallerar tidigare version."
|
||||
;LangString launch_qbt ${LANG_ENGLISH} "Launch qBittorrent."
|
||||
|
@ -53,7 +53,7 @@ LangString remove_firewallinfo ${LANG_SWEDISH} "Tar bort Windows-brandväggsrege
|
|||
;LangString remove_cache ${LANG_ENGLISH} "Remove torrents and cached data"
|
||||
LangString remove_cache ${LANG_SWEDISH} "Ta bort torrenter och cachade data"
|
||||
;LangString uninst_warning ${LANG_ENGLISH} "qBittorrent is running. Please close the application before uninstalling."
|
||||
LangString uninst_warning ${LANG_SWEDISH} "qBittorrent körs. Vänligen stäng programmet innan du avinstallerar."
|
||||
LangString uninst_warning ${LANG_SWEDISH} "qBittorrent körs. Stäng programmet innan du avinstallerar."
|
||||
;LangString uninst_tor_warn ${LANG_ENGLISH} "Not removing .torrent association. It is associated with:"
|
||||
LangString uninst_tor_warn ${LANG_SWEDISH} "Tar inte bort .torrent-association. Den är associerad med:"
|
||||
;LangString uninst_mag_warn ${LANG_ENGLISH} "Not removing magnet association. It is associated with:"
|
||||
|
|
|
@ -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 ¶ms)
|
||||
{
|
||||
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;
|
||||
|
|
|
@ -30,8 +30,10 @@
|
|||
#pragma once
|
||||
|
||||
#include <QByteArray>
|
||||
#include <QHash>
|
||||
#include <QHostAddress>
|
||||
#include <QList>
|
||||
#include <QMap>
|
||||
#include <QString>
|
||||
|
||||
#include "base/global.h"
|
||||
|
|
|
@ -287,6 +287,8 @@ if (CMAKE_SYSTEM_NAME STREQUAL "Darwin")
|
|||
macosdockbadge/badger.mm
|
||||
macosdockbadge/badgeview.h
|
||||
macosdockbadge/badgeview.mm
|
||||
macosshiftclickhandler.h
|
||||
macosshiftclickhandler.cpp
|
||||
macutilities.h
|
||||
macutilities.mm
|
||||
)
|
||||
|
|
73
src/gui/macosshiftclickhandler.cpp
Normal file
73
src/gui/macosshiftclickhandler.cpp
Normal file
|
@ -0,0 +1,73 @@
|
|||
/*
|
||||
* Bittorrent Client using Qt and libtorrent.
|
||||
* Copyright (C) 2025 Luke Memet (lukemmtt)
|
||||
*
|
||||
* 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 "macosshiftclickhandler.h"
|
||||
|
||||
#include <QMouseEvent>
|
||||
#include <QTreeView>
|
||||
|
||||
MacOSShiftClickHandler::MacOSShiftClickHandler(QTreeView *treeView)
|
||||
: QObject(treeView)
|
||||
, m_treeView {treeView}
|
||||
{
|
||||
treeView->installEventFilter(this);
|
||||
}
|
||||
|
||||
bool MacOSShiftClickHandler::eventFilter(QObject *watched, QEvent *event)
|
||||
{
|
||||
if ((watched == m_treeView) && (event->type() == QEvent::MouseButtonPress))
|
||||
{
|
||||
const auto *mouseEvent = static_cast<QMouseEvent *>(event);
|
||||
if (mouseEvent->button() != Qt::LeftButton)
|
||||
return false;
|
||||
|
||||
const QModelIndex clickedIndex = m_treeView->indexAt(mouseEvent->position().toPoint());
|
||||
if (!clickedIndex.isValid())
|
||||
return false;
|
||||
|
||||
const Qt::KeyboardModifiers modifiers = mouseEvent->modifiers();
|
||||
const bool shiftPressed = modifiers.testFlag(Qt::ShiftModifier);
|
||||
|
||||
if (shiftPressed && m_lastClickedIndex.isValid())
|
||||
{
|
||||
const QItemSelection selection(m_lastClickedIndex, clickedIndex);
|
||||
const bool commandPressed = modifiers.testFlag(Qt::ControlModifier);
|
||||
if (commandPressed)
|
||||
m_treeView->selectionModel()->select(selection, (QItemSelectionModel::Select | QItemSelectionModel::Rows));
|
||||
else
|
||||
m_treeView->selectionModel()->select(selection, (QItemSelectionModel::ClearAndSelect | QItemSelectionModel::Rows));
|
||||
m_treeView->selectionModel()->setCurrentIndex(clickedIndex, QItemSelectionModel::NoUpdate);
|
||||
return true;
|
||||
}
|
||||
|
||||
if (!modifiers.testFlags(Qt::AltModifier | Qt::MetaModifier))
|
||||
m_lastClickedIndex = clickedIndex;
|
||||
}
|
||||
|
||||
return QObject::eventFilter(watched, event);
|
||||
}
|
50
src/gui/macosshiftclickhandler.h
Normal file
50
src/gui/macosshiftclickhandler.h
Normal file
|
@ -0,0 +1,50 @@
|
|||
/*
|
||||
* Bittorrent Client using Qt and libtorrent.
|
||||
* Copyright (C) 2025 Luke Memet (lukemmtt)
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <QObject>
|
||||
#include <QPersistentModelIndex>
|
||||
|
||||
class QTreeView;
|
||||
|
||||
// Workaround for QTBUG-115838: Shift-click range selection not working properly on macOS
|
||||
class MacOSShiftClickHandler final : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
Q_DISABLE_COPY_MOVE(MacOSShiftClickHandler)
|
||||
|
||||
public:
|
||||
explicit MacOSShiftClickHandler(QTreeView *treeView);
|
||||
|
||||
private:
|
||||
bool eventFilter(QObject *watched, QEvent *event) override;
|
||||
|
||||
QTreeView *m_treeView = nullptr;
|
||||
QPersistentModelIndex m_lastClickedIndex;
|
||||
};
|
|
@ -74,6 +74,7 @@
|
|||
#include "utils.h"
|
||||
|
||||
#ifdef Q_OS_MACOS
|
||||
#include "macosshiftclickhandler.h"
|
||||
#include "macutilities.h"
|
||||
#endif
|
||||
|
||||
|
@ -158,6 +159,7 @@ TransferListWidget::TransferListWidget(IGUIApplication *app, QWidget *parent)
|
|||
setDropIndicatorShown(true);
|
||||
#if defined(Q_OS_MACOS)
|
||||
setAttribute(Qt::WA_MacShowFocusRect, false);
|
||||
new MacOSShiftClickHandler(this);
|
||||
#endif
|
||||
header()->setFirstSectionMovable(true);
|
||||
header()->setStretchLastSection(false);
|
||||
|
|
|
@ -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, {{}, {}}}
|
||||
};
|
||||
}
|
||||
|
||||
|
|
|
@ -49,7 +49,7 @@ void RSSController::addFolderAction()
|
|||
{
|
||||
requireParams({u"path"_s});
|
||||
|
||||
const QString path = params()[u"path"_s].trimmed();
|
||||
const QString path = params()[u"path"_s];
|
||||
const nonstd::expected<void, QString> result = RSS::Session::instance()->addFolder(path);
|
||||
if (!result)
|
||||
throw APIError(APIErrorType::Conflict, result.error());
|
||||
|
@ -59,8 +59,8 @@ void RSSController::addFeedAction()
|
|||
{
|
||||
requireParams({u"url"_s, u"path"_s});
|
||||
|
||||
const QString url = params()[u"url"_s].trimmed();
|
||||
const QString path = params()[u"path"_s].trimmed();
|
||||
const QString url = params()[u"url"_s];
|
||||
const QString path = params()[u"path"_s];
|
||||
const nonstd::expected<void, QString> result = RSS::Session::instance()->addFeed(url, (path.isEmpty() ? url : path));
|
||||
if (!result)
|
||||
throw APIError(APIErrorType::Conflict, result.error());
|
||||
|
@ -70,8 +70,8 @@ void RSSController::setFeedURLAction()
|
|||
{
|
||||
requireParams({u"path"_s, u"url"_s});
|
||||
|
||||
const QString path = params()[u"path"_s].trimmed();
|
||||
const QString url = params()[u"url"_s].trimmed();
|
||||
const QString path = params()[u"path"_s];
|
||||
const QString url = params()[u"url"_s];
|
||||
const nonstd::expected<void, QString> result = RSS::Session::instance()->setFeedURL(path, url);
|
||||
if (!result)
|
||||
throw APIError(APIErrorType::Conflict, result.error());
|
||||
|
@ -81,7 +81,7 @@ void RSSController::removeItemAction()
|
|||
{
|
||||
requireParams({u"path"_s});
|
||||
|
||||
const QString path = params()[u"path"_s].trimmed();
|
||||
const QString path = params()[u"path"_s];
|
||||
const nonstd::expected<void, QString> result = RSS::Session::instance()->removeItem(path);
|
||||
if (!result)
|
||||
throw APIError(APIErrorType::Conflict, result.error());
|
||||
|
@ -91,8 +91,8 @@ void RSSController::moveItemAction()
|
|||
{
|
||||
requireParams({u"itemPath"_s, u"destPath"_s});
|
||||
|
||||
const QString itemPath = params()[u"itemPath"_s].trimmed();
|
||||
const QString destPath = params()[u"destPath"_s].trimmed();
|
||||
const QString itemPath = params()[u"itemPath"_s];
|
||||
const QString destPath = params()[u"destPath"_s];
|
||||
const nonstd::expected<void, QString> result = RSS::Session::instance()->moveItem(itemPath, destPath);
|
||||
if (!result)
|
||||
throw APIError(APIErrorType::Conflict, result.error());
|
||||
|
@ -146,8 +146,8 @@ void RSSController::setRuleAction()
|
|||
{
|
||||
requireParams({u"ruleName"_s, u"ruleDef"_s});
|
||||
|
||||
const QString ruleName {params()[u"ruleName"_s].trimmed()};
|
||||
const QByteArray ruleDef {params()[u"ruleDef"_s].trimmed().toUtf8()};
|
||||
const QString ruleName {params()[u"ruleName"_s]};
|
||||
const QByteArray ruleDef {params()[u"ruleDef"_s].toUtf8()};
|
||||
|
||||
const auto jsonObj = QJsonDocument::fromJson(ruleDef).object();
|
||||
RSS::AutoDownloader::instance()->setRule(RSS::AutoDownloadRule::fromJsonObject(jsonObj, ruleName));
|
||||
|
@ -157,8 +157,8 @@ void RSSController::renameRuleAction()
|
|||
{
|
||||
requireParams({u"ruleName"_s, u"newRuleName"_s});
|
||||
|
||||
const QString ruleName {params()[u"ruleName"_s].trimmed()};
|
||||
const QString newRuleName {params()[u"newRuleName"_s].trimmed()};
|
||||
const QString ruleName {params()[u"ruleName"_s]};
|
||||
const QString newRuleName {params()[u"newRuleName"_s]};
|
||||
|
||||
RSS::AutoDownloader::instance()->renameRule(ruleName, newRuleName);
|
||||
}
|
||||
|
@ -167,7 +167,7 @@ void RSSController::removeRuleAction()
|
|||
{
|
||||
requireParams({u"ruleName"_s});
|
||||
|
||||
const QString ruleName {params()[u"ruleName"_s].trimmed()};
|
||||
const QString ruleName {params()[u"ruleName"_s]};
|
||||
RSS::AutoDownloader::instance()->removeRule(ruleName);
|
||||
}
|
||||
|
||||
|
|
|
@ -100,6 +100,7 @@ ol {
|
|||
.dynamicTableDiv,
|
||||
.mochaContentWrapper,
|
||||
.panel,
|
||||
.scrollableMenu,
|
||||
#rssDetailsView {
|
||||
scrollbar-width: thin;
|
||||
}
|
||||
|
|
|
@ -21,7 +21,7 @@
|
|||
} = window.MUI.Windows.instances["multiRenamePage"];
|
||||
|
||||
const bulkRenameFilesContextMenu = new window.qBittorrent.ContextMenu.ContextMenu({
|
||||
targets: "#bulkRenameFilesTableDiv tr",
|
||||
targets: "#bulkRenameFilesTableDiv tbody tr",
|
||||
menu: "multiRenameFilesMenu",
|
||||
actions: {
|
||||
ToggleSelection: (element, ref) => {
|
||||
|
|
|
@ -294,6 +294,7 @@ window.qBittorrent.DynamicTable ??= (() => {
|
|||
this.updateTableHeaders();
|
||||
this.tableBody.replaceChildren();
|
||||
this.updateTable(true);
|
||||
this.reselectRows(this.selectedRowsIds());
|
||||
}
|
||||
if (this.currentHeaderAction === "drag") {
|
||||
resetElementBorderStyle(el);
|
||||
|
@ -750,10 +751,7 @@ window.qBittorrent.DynamicTable ??= (() => {
|
|||
reselectRows: function(rowIds) {
|
||||
this.deselectAll();
|
||||
this.selectedRows = rowIds.slice();
|
||||
for (const tr of this.getTrs()) {
|
||||
if (rowIds.includes(tr.rowId))
|
||||
tr.classList.add("selected");
|
||||
}
|
||||
this.setRowClass();
|
||||
},
|
||||
|
||||
setRowClass: function() {
|
||||
|
@ -1752,7 +1750,7 @@ window.qBittorrent.DynamicTable ??= (() => {
|
|||
td.append(span);
|
||||
}
|
||||
|
||||
span.style.backgroundImage = `url('images/flags/${country_code ?? "xx"}.svg')`;
|
||||
span.style.backgroundImage = `url('images/flags/${country_code || "xx"}.svg')`;
|
||||
span.textContent = country;
|
||||
td.title = country;
|
||||
};
|
||||
|
@ -2058,7 +2056,11 @@ window.qBittorrent.DynamicTable ??= (() => {
|
|||
break;
|
||||
}
|
||||
|
||||
td.className = statusClass;
|
||||
for (const c of [...td.classList]) {
|
||||
if (c.startsWith("tracker"))
|
||||
td.classList.remove(c);
|
||||
}
|
||||
td.classList.add(statusClass);
|
||||
td.textContent = status;
|
||||
td.title = status;
|
||||
};
|
||||
|
|
|
@ -575,7 +575,7 @@ window.qBittorrent.PropFiles ??= (() => {
|
|||
};
|
||||
|
||||
const torrentFilesContextMenu = new window.qBittorrent.ContextMenu.ContextMenu({
|
||||
targets: "#torrentFilesTableDiv tr",
|
||||
targets: "#torrentFilesTableDiv tbody tr",
|
||||
menu: "torrentFilesMenu",
|
||||
actions: {
|
||||
Rename: (element, ref) => {
|
||||
|
|
|
@ -196,7 +196,7 @@ window.qBittorrent.PropTrackers ??= (() => {
|
|||
if (current_hash.length === 0)
|
||||
return;
|
||||
|
||||
const trackerUrl = encodeURIComponent(element.childNodes[1].textContent);
|
||||
const trackerUrl = encodeURIComponent(torrentTrackersTable.selectedRowsIds()[0]);
|
||||
new MochaUI.Window({
|
||||
id: "trackersPage",
|
||||
icon: "images/qbittorrent-tray.svg",
|
||||
|
|
|
@ -97,8 +97,8 @@ window.qBittorrent.Search ??= (() => {
|
|||
}
|
||||
},
|
||||
offsets: {
|
||||
x: -15,
|
||||
y: -53
|
||||
x: 2,
|
||||
y: -60
|
||||
},
|
||||
onShow: function() {
|
||||
setActiveTab(this.options.element);
|
||||
|
@ -109,7 +109,7 @@ window.qBittorrent.Search ??= (() => {
|
|||
// load "Search in" preference from local storage
|
||||
$("searchInTorrentName").value = (LocalPreferences.get("search_in_filter") === "names") ? "names" : "everywhere";
|
||||
const searchResultsTableContextMenu = new window.qBittorrent.ContextMenu.ContextMenu({
|
||||
targets: "#searchResultsTableDiv tr",
|
||||
targets: "#searchResultsTableDiv tbody tr",
|
||||
menu: "searchResultsTableMenu",
|
||||
actions: {
|
||||
Download: downloadSearchTorrent,
|
||||
|
@ -184,7 +184,10 @@ window.qBittorrent.Search ??= (() => {
|
|||
closeTabElem.src = "images/application-exit.svg";
|
||||
closeTabElem.width = "10";
|
||||
closeTabElem.height = "10";
|
||||
closeTabElem.addEventListener("click", function(e) { qBittorrent.Search.closeSearchTab(this); });
|
||||
closeTabElem.addEventListener("click", function(e) {
|
||||
e.stopPropagation();
|
||||
closeSearchTab(this);
|
||||
});
|
||||
|
||||
tabElem.prepend(closeTabElem);
|
||||
tabElem.appendChild(getStatusIconElement("QBT_TR(Searching...)QBT_TR[CONTEXT=SearchJobWidget]", "images/queued.svg"));
|
||||
|
|
|
@ -98,7 +98,7 @@
|
|||
}
|
||||
},
|
||||
offsets: {
|
||||
x: -15,
|
||||
x: 0,
|
||||
y: 2
|
||||
},
|
||||
onShow: function() {
|
||||
|
|
|
@ -206,7 +206,7 @@
|
|||
});
|
||||
|
||||
const logTableContextMenu = new window.qBittorrent.ContextMenu.ContextMenu({
|
||||
targets: ":is(#logMessageView, #logPeerView) tr",
|
||||
targets: ":is(#logMessageTableDiv, #logPeerTableDiv) tbody tr",
|
||||
menu: "logTableMenu",
|
||||
actions: {
|
||||
Clear: () => {
|
||||
|
|
|
@ -218,7 +218,7 @@
|
|||
$("rssFetchingDisabled").classList.remove("invisible");
|
||||
|
||||
const rssFeedContextMenu = new window.qBittorrent.ContextMenu.RssFeedContextMenu({
|
||||
targets: "#rssFeedTableDiv tr",
|
||||
targets: "#rssFeedTableDiv tbody tr",
|
||||
menu: "rssFeedMenu",
|
||||
actions: {
|
||||
update: (el) => {
|
||||
|
@ -288,7 +288,7 @@
|
|||
rssFeedTable.setup("rssFeedTableDiv", "rssFeedFixedHeaderDiv", rssFeedContextMenu);
|
||||
|
||||
const rssArticleContextMenu = new window.qBittorrent.ContextMenu.RssArticleContextMenu({
|
||||
targets: "#rssArticleTableDiv tr",
|
||||
targets: "#rssArticleTableDiv tbody tr",
|
||||
menu: "rssArticleMenu",
|
||||
actions: {
|
||||
Download: (el) => {
|
||||
|
|
|
@ -94,7 +94,7 @@
|
|||
const setup = () => {
|
||||
searchPluginsTable = new window.qBittorrent.DynamicTable.SearchPluginsTable();
|
||||
searchPluginsTableContextMenu = new window.qBittorrent.ContextMenu.SearchPluginsTableContextMenu({
|
||||
targets: "#searchPluginsTableDiv tr",
|
||||
targets: "#searchPluginsTableDiv tbody tr",
|
||||
menu: "searchPluginsTableMenu",
|
||||
actions: {
|
||||
Enabled: enablePlugin,
|
||||
|
|
|
@ -29,7 +29,7 @@
|
|||
|
||||
// create a context menu
|
||||
const contextMenu = new window.qBittorrent.ContextMenu.TorrentsTableContextMenu({
|
||||
targets: "#torrentsTableDiv tr",
|
||||
targets: "#torrentsTableDiv tbody tr",
|
||||
menu: "torrentsTableMenu",
|
||||
actions: {
|
||||
start: (element, ref) => {
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue