diff --git a/.github/workflows/ci_macos.yaml b/.github/workflows/ci_macos.yaml
index 5719960c9..4b2709516 100644
--- a/.github/workflows/ci_macos.yaml
+++ b/.github/workflows/ci_macos.yaml
@@ -49,6 +49,7 @@ jobs:
- name: Setup ccache
uses: Chocobo1/setup-ccache-action@v1
with:
+ store_cache: ${{ startsWith(github.ref, 'refs/heads/') }}
update_packager_index: false
- name: Install boost
@@ -66,6 +67,7 @@ jobs:
version: ${{ matrix.qt_version }}
archives: qtbase qtdeclarative qtsvg qttools
# Not sure why Qt made a hard dependency on qtdeclarative, try removing it when Qt > 6.4.0
+ cache: true
- name: Install libtorrent
run: |
diff --git a/.github/workflows/ci_ubuntu.yaml b/.github/workflows/ci_ubuntu.yaml
index fcb7a58ce..313275b07 100644
--- a/.github/workflows/ci_ubuntu.yaml
+++ b/.github/workflows/ci_ubuntu.yaml
@@ -39,6 +39,7 @@ jobs:
- name: Setup ccache
uses: Chocobo1/setup-ccache-action@v1
with:
+ store_cache: ${{ startsWith(github.ref, 'refs/heads/') }}
update_packager_index: false
ccache_options: |
max_size=2G
@@ -48,6 +49,7 @@ jobs:
with:
version: ${{ matrix.qt_version }}
archives: icu qtbase qtsvg qttools
+ cache: true
- name: Install libtorrent
run: |
@@ -117,6 +119,8 @@ jobs:
- name: Run CodeQL analysis
uses: github/codeql-action/analyze@v2
if: startsWith(matrix.libt_version, 2) && (matrix.qbt_gui == 'GUI=ON') && startsWith(matrix.qt_version, 6)
+ with:
+ category: ${{ github.base_ref || github.ref_name }}
- name: Prepare build artifacts
run: |
diff --git a/.github/workflows/ci_windows.yaml b/.github/workflows/ci_windows.yaml
index f7e310f60..e6aeb4bd6 100644
--- a/.github/workflows/ci_windows.yaml
+++ b/.github/workflows/ci_windows.yaml
@@ -22,6 +22,7 @@ jobs:
env:
boost_path: "${{ github.workspace }}/../boost"
libtorrent_path: "${{ github.workspace }}/libtorrent"
+ vpkg_triplet_path: "${{ github.workspace }}/../triplets_overlay"
steps:
- name: Checkout repository
@@ -42,29 +43,32 @@ jobs:
vcpkgDirectory: C:/vcpkg
doNotUpdateVcpkg: true # the preinstalled vcpkg is updated regularly
- - name: Install dependencies from vcpkg
+ - name: Install dependencies with vcpkg
run: |
- # tell vcpkg to only build Release variants of the dependencies
+ # create our own triplet
New-Item `
- -Path "${{ github.workspace }}" `
- -Name "triplets_overlay" `
- -ItemType Directory
- Copy-Item `
- "${{ env.RUNVCPKG_VCPKG_ROOT }}/triplets/x64-windows-static.cmake" `
- "${{ github.workspace }}/triplets_overlay/x64-windows-static-release.cmake"
+ -Force `
+ -ItemType File `
+ -Path "${{ env.vpkg_triplet_path }}/x64-windows-static-md-release.cmake"
Add-Content `
- "${{ github.workspace }}/triplets_overlay/x64-windows-static-release.cmake" `
- -Value "set(VCPKG_BUILD_TYPE release)"
+ -Path "${{ env.vpkg_triplet_path }}/x64-windows-static-md-release.cmake" `
+ -Value @("set(VCPKG_TARGET_ARCHITECTURE x64)",
+ "set(VCPKG_LIBRARY_LINKAGE static)",
+ "set(VCPKG_CRT_LINKAGE dynamic)",
+ "set(VCPKG_BUILD_TYPE release)",
+ "set(VCPKG_C_FLAGS /guard:cf)",
+ "set(VCPKG_CXX_FLAGS /guard:cf)",
+ "set(VCPKG_LINKER_FLAGS /guard:cf)")
# clear buildtrees after each package installation to reduce disk space requirements
$packages = `
- "openssl:x64-windows-static-release",
- "zlib:x64-windows-static-release"
+ "openssl:x64-windows-static-md-release",
+ "zlib:x64-windows-static-md-release"
${{ env.RUNVCPKG_VCPKG_ROOT }}/vcpkg.exe upgrade `
- --overlay-triplets="${{ github.workspace }}/triplets_overlay" `
- --no-dry-run
+ --no-dry-run `
+ --overlay-triplets="${{ env.vpkg_triplet_path }}"
${{ env.RUNVCPKG_VCPKG_ROOT }}/vcpkg.exe install `
- --overlay-triplets="${{ github.workspace }}/triplets_overlay" `
--clean-after-build `
+ --overlay-triplets="${{ env.vpkg_triplet_path }}" `
$packages
- name: Install boost
@@ -81,6 +85,7 @@ jobs:
with:
version: "6.5.0"
archives: qtbase qtsvg qttools
+ cache: true
- name: Install libtorrent
run: |
@@ -90,37 +95,38 @@ jobs:
--recurse-submodules `
https://github.com/arvidn/libtorrent.git
cd libtorrent
+ $env:CXXFLAGS+=" /guard:cf"
+ $env:LDFLAGS+=" /guard:cf"
cmake `
-B build `
-G "Ninja" `
-DCMAKE_BUILD_TYPE=RelWithDebInfo `
- -DCMAKE_CXX_FLAGS=/guard:cf `
-DCMAKE_EXPORT_COMPILE_COMMANDS=ON `
-DCMAKE_INSTALL_PREFIX="${{ env.libtorrent_path }}" `
-DCMAKE_TOOLCHAIN_FILE="${{ env.RUNVCPKG_VCPKG_ROOT }}/scripts/buildsystems/vcpkg.cmake" `
-DBOOST_ROOT="${{ env.boost_path }}" `
-DBUILD_SHARED_LIBS=OFF `
-Ddeprecated-functions=OFF `
- -Dstatic_runtime=ON `
- -DVCPKG_TARGET_TRIPLET=x64-windows-static-release
+ -Dstatic_runtime=OFF `
+ -DVCPKG_TARGET_TRIPLET=x64-windows-static-md-release
cmake --build build
cmake --install build
- name: Build qBittorrent
run: |
+ $env:CXXFLAGS+=" /WX"
cmake `
-B build `
-G "Ninja" `
-DCMAKE_BUILD_TYPE=RelWithDebInfo `
- -DCMAKE_CXX_FLAGS="/WX" `
-DCMAKE_EXPORT_COMPILE_COMMANDS=ON `
-DCMAKE_TOOLCHAIN_FILE="${{ env.RUNVCPKG_VCPKG_ROOT }}/scripts/buildsystems/vcpkg.cmake" `
-DBOOST_ROOT="${{ env.boost_path }}" `
-DLibtorrentRasterbar_DIR="${{ env.libtorrent_path }}/lib/cmake/LibtorrentRasterbar" `
- -DMSVC_RUNTIME_DYNAMIC=OFF `
+ -DMSVC_RUNTIME_DYNAMIC=ON `
-DQT6=ON `
-DTESTING=ON `
- -DVCPKG_TARGET_TRIPLET=x64-windows-static-release `
+ -DVCPKG_TARGET_TRIPLET=x64-windows-static-md-release `
-DVERBOSE_CONFIGURE=ON `
--graphviz=build/target_graph.dot
cmake --build build --target qbt_update_translations
diff --git a/.tx/config b/.tx/config
index 95d5b1afa..287c2319a 100644
--- a/.tx/config
+++ b/.tx/config
@@ -1,7 +1,7 @@
[main]
host = https://www.transifex.com
-[o:sledgehammer999:p:qbittorrent:r:qbittorrent_master]
+[o:sledgehammer999:p:qbittorrent:r:qbittorrent_v46x]
file_filter = src/lang/qbittorrent_.ts
source_file = src/lang/qbittorrent_en.ts
source_lang = en
@@ -9,7 +9,7 @@ type = QT
minimum_perc = 23
lang_map = pt: pt_PT, zh: zh_CN
-[o:sledgehammer999:p:qbittorrent:r:qbittorrent_webui]
+[o:sledgehammer999:p:qbittorrent:r:qbittorrent_webui_v46x]
file_filter = src/webui/www/translations/webui_.ts
source_file = src/webui/www/translations/webui_en.ts
source_lang = en
diff --git a/CMakeLists.txt b/CMakeLists.txt
index 9a2712e62..9c833f90b 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -30,16 +30,21 @@ feature_option(STACKTRACE "Enable stacktrace support" ON)
feature_option(TESTING "Build internal testing suite" OFF)
feature_option(VERBOSE_CONFIGURE "Show information about PACKAGES_FOUND and PACKAGES_NOT_FOUND in the configure output (only useful for debugging the CMake build scripts)" OFF)
-if (CMAKE_SYSTEM_NAME STREQUAL "Linux")
+if (CMAKE_SYSTEM_NAME STREQUAL "Linux" OR CMAKE_SYSTEM_NAME STREQUAL "FreeBSD")
feature_option_dependent(DBUS
- "Enable support for notifications and power-management features via D-Bus on Linux"
+ "Enable support for notifications and power-management features via D-Bus"
ON "GUI" OFF
)
+endif()
+
+if (CMAKE_SYSTEM_NAME STREQUAL "Linux")
feature_option_dependent(SYSTEMD
"Install systemd service file. Target directory is overridable with `SYSTEMD_SERVICES_INSTALL_DIR` variable"
OFF "NOT GUI" OFF
)
-elseif (MSVC)
+endif()
+
+if (MSVC)
feature_option(MSVC_RUNTIME_DYNAMIC "Use MSVC dynamic runtime library (-MD) instead of static (-MT)" ON)
endif()
diff --git a/Changelog b/Changelog
index 5163569ef..33b62e606 100644
--- a/Changelog
+++ b/Changelog
@@ -1,3 +1,94 @@
+Mon Nov 27th 2023 - sledgehammer999 - v4.6.2
+ - BUGFIX: Do not apply share limit if the previous one was applied (glassez)
+ - BUGFIX: Show Add new torrent dialog on main window screen (glassez)
+ - WEBUI: Fix JS memory leak (brvphoenix)
+ - WEBUI: Disable stdout buffering for qbt-nox (Chocobo1)
+ - WINDOWS: NSIS: Display correct Minimum Windows OS requirement (xavier2k6)
+ - WINDOWS: NSIS: Add Hebrew translation (avivmu)
+ - LINUX: WAYLAND: Fix parent widget of "Lock qBittorrent" submenu (Vlad Zahorodnii)
+
+Mon Nov 20th 2023 - sledgehammer999 - v4.6.1
+ - FEATURE: Add option to enable previous Add new torrent dialog behavior (glassez)
+ - BUGFIX: Prevent crash due to race condition when adding magnet link (glassez)
+ - BUGFIX: Fix Enter key behavior when add new torrent (glassez)
+ - BUGFIX: Add missing main window icon (iomezk)
+ - BUGFIX: Update size of selected files when selection is changed (glassez)
+ - BUGFIX: Correctly handle changing save path of torrent w/o metadata (glassez)
+ - BUGFIX: Use appropriate icon for "moving" torrents in transfer list (xavier2k6)
+ - WEBUI: Drop WebUI default credentials (glassez)
+ - WEBUI: Add I2P settings to WebUI (thalieht)
+ - WEBUI: Fix duplicate scrollbar on Transfer List (AgentConDier)
+ - WEBUI: Fix .torrent file upload on iPadOS (Vitaly Cheptsov)
+ - WEBUI: Fix incorrect subcategory sorting (Bartu Özen)
+ - WEBUI: Correctly set save path in RSS rules (glassez)
+ - WEBUI: Allow to request torrents count via WebAPI (glassez)
+ - WEBUI: Improve performance of getting torrent numbers via WebAPI (Chocobo1)
+ - WEBUI: Improve free disk space checking for WebAPI (glassez)
+ - WINDOWS: NSIS: Fixed typo in the installer's hungarian translation (MartinKing01)
+ - LINUX: Fix invisible tray icon with Qt5 in Linux (thalieht)
+ - MACOS: Remove "Physical memory (RAM) usage limit" option (Chocobo1)
+
+Sun Oct 22nd 2023 - sledgehammer999 - v4.6.0
+ - FEATURE: Add (experimental) I2P support (glassez)
+ - FEATURE: Provide UI editor for the default theme (glassez)
+ - FEATURE: Various UI theming improvements (glassez)
+ - FEATURE: Implement torrent tags editing dialog (glassez)
+ - FEATURE: Revamp "Watched folder options" and "Automated RSS downloader" dialog (glassez)
+ - FEATURE: Allow to use another icons in dark mode (glassez)
+ - FEATURE: Allow to add new torrents to queue top (glassez)
+ - FEATURE: Allow to filter torrent list by save path (Tom)
+ - FEATURE: Expose 'socket send/receive buffer size' options (Chocobo1)
+ - FEATURE: Expose 'max torrent file size' setting (Chocobo1)
+ - FEATURE: Expose 'bdecode limits' settings (Chocobo1)
+ - FEATURE: Add options to adjust behavior of merging trackers to existing torrent (glassez)
+ - FEATURE: Add option to stop seeding when torrent has been inactive (Christopher)
+ - FEATURE: Allow to use proxy per subsystem (glassez)
+ - FEATURE: Expand the scope of "Proxy hostname lookup" option (glassez)
+ - FEATURE: Add shortcut for "Ban peer permanently" function (Luka Čelebić)
+ - FEATURE: Add option to auto hide zero status filters (glassez)
+ - FEATURE: Allow to disable confirmation of Pause/Resume All (glassez)
+ - FEATURE: Add alternative shortcut CTRL+E for CTRL+F (Luka Čelebić)
+ - FEATURE: Show filtered port numbers in logs (Hanabishi)
+ - FEATURE: Add button to copy library versions to clipboard (Chocobo1)
+ - BUGFIX: Ensure ongoing storage moving job will be completed when shutting down (Chocobo1)
+ - BUGFIX: Refactored many areas to call non UI blocking code (glassez)
+ - BUGFIX: Various improvements to the SQLite backend (glassez)
+ - BUGFIX: Improve startup window state handling (glassez)
+ - BUGFIX: Use tray icon from system theme only if option is set (glassez)
+ - BUGFIX: Inhibit system sleep while torrents are moving (Sentox6)
+ - BUGFIX: Use hostname instead of domain name in tracker filter list (tearfur)
+ - BUGFIX: Visually validate input path in torrent creator dialog (Chocobo1)
+ - BUGFIX: Disable symlink resolving in Torrent creator (Ignat Loskutov)
+ - BUGFIX: Change default value for `file pool size` and `stop tracker timeout` settings (stalkerok)
+ - BUGFIX: Log when duplicate torrents are being added (glassez)
+ - BUGFIX: Inhibit suspend instead of screen idle (axet)
+ - BUGFIX: Ensure file name is valid when exporting torrents (glassez)
+ - BUGFIX: Open "Save path" if torrent has no metadata (Xu Chao)
+ - BUGFIX: Prevent torrent starting unexpectedly edge case with magnet (Xu Chao)
+ - BUGFIX: Better ergonomics of the "Add new torrent" dialog (Xu Chao, glassez)
+ - WEBUI: Add log viewer (brvphoenix)
+ - WEBUI: WebAPI: Allow to specify session cookie name (glassez)
+ - WEBUI: Improve sync API performance (glassez)
+ - WEBUI: Add filelog settings (brvphoenix)
+ - WEBUI: Add multi-file renaming (loligans)
+ - WEBUI: Add "Add to top of queue" option (thalieht)
+ - WEBUI: Implement subcategories (Bartu Özen)
+ - WEBUI: Set "SameSite=None" if CSRF Protection is disabled (七海千秋)
+ - WEBUI: Show only hosts in tracker filter list (ttys3)
+ - WEBUI: Set Connection status and Speed limits tooltips (Raymond Ha)
+ - WEBUI: set Cross Origin Opener Policy to `same-origin` (Chocobo1)
+ - WEBUI: Fix response for HTTP HEAD method (Chocobo1)
+ - WEBUI: Preserve the network interfaces when connection is down (Fabricio Silva)
+ - WEBUI: Add "Add Tags" field for RSS rules (Matic Babnik)
+ - WEBUI: Fix missing error icon (Trim21)
+ - RSS: Add "Rename rule" button to RSS Downloader (BallsOfSpaghetti)
+ - RSS: Allow to edit RSS feed URL (glassez)
+ - RSS: Allow to assign priority to RSS download rule (glassez)
+ - SEARCH: Use python isolate mode (Chocobo1)
+ - SEARCH: Bump python version minimum requirement to 3.7.0 (Chocobo1)
+ - OTHER: Enable DBUS cmake option on FreeBSD (yuri@FreeBSD)
+ - OTHER: Numerous code improvements and refactorings (glassez, Chocobo1)
+
Unreleased - sledgehammer999 - v4.5.0
- FEATURE: Add `Auto resize columns` functionality (Chocobo1)
- FEATURE: Allow to use Category paths in `Manual` mode (glassez)
diff --git a/configure b/configure
index 773548c5d..6da002afc 100755
--- a/configure
+++ b/configure
@@ -1,6 +1,6 @@
#! /bin/sh
# Guess values for system-dependent variables and create Makefiles.
-# Generated by GNU Autoconf 2.71 for qbittorrent v4.6.0beta2.
+# Generated by GNU Autoconf 2.71 for qbittorrent v4.6.2.
#
# Report bugs to .
#
@@ -611,8 +611,8 @@ MAKEFLAGS=
# Identity of this package.
PACKAGE_NAME='qbittorrent'
PACKAGE_TARNAME='qbittorrent'
-PACKAGE_VERSION='v4.6.0beta2'
-PACKAGE_STRING='qbittorrent v4.6.0beta2'
+PACKAGE_VERSION='v4.6.2'
+PACKAGE_STRING='qbittorrent v4.6.2'
PACKAGE_BUGREPORT='bugs.qbittorrent.org'
PACKAGE_URL='https://www.qbittorrent.org/'
@@ -1329,7 +1329,7 @@ if test "$ac_init_help" = "long"; then
# Omit some internal or obsolete options to make the list less imposing.
# This message is too long to be a string in the A/UX 3.1 sh.
cat <<_ACEOF
-\`configure' configures qbittorrent v4.6.0beta2 to adapt to many kinds of systems.
+\`configure' configures qbittorrent v4.6.2 to adapt to many kinds of systems.
Usage: $0 [OPTION]... [VAR=VALUE]...
@@ -1400,7 +1400,7 @@ fi
if test -n "$ac_init_help"; then
case $ac_init_help in
- short | recursive ) echo "Configuration of qbittorrent v4.6.0beta2:";;
+ short | recursive ) echo "Configuration of qbittorrent v4.6.2:";;
esac
cat <<\_ACEOF
@@ -1533,7 +1533,7 @@ fi
test -n "$ac_init_help" && exit $ac_status
if $ac_init_version; then
cat <<\_ACEOF
-qbittorrent configure v4.6.0beta2
+qbittorrent configure v4.6.2
generated by GNU Autoconf 2.71
Copyright (C) 2021 Free Software Foundation, Inc.
@@ -1648,7 +1648,7 @@ cat >config.log <<_ACEOF
This file contains any messages produced by compilers while
running configure, to aid debugging if configure makes a mistake.
-It was created by qbittorrent $as_me v4.6.0beta2, which was
+It was created by qbittorrent $as_me v4.6.2, which was
generated by GNU Autoconf 2.71. Invocation command line was
$ $0$ac_configure_args_raw
@@ -4779,7 +4779,7 @@ fi
# Define the identity of the package.
PACKAGE='qbittorrent'
- VERSION='v4.6.0beta2'
+ VERSION='v4.6.2'
printf "%s\n" "#define PACKAGE \"$PACKAGE\"" >>confdefs.h
@@ -7237,7 +7237,7 @@ cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1
# report actual input values of CONFIG_FILES etc. instead of their
# values after options handling.
ac_log="
-This file was extended by qbittorrent $as_me v4.6.0beta2, which was
+This file was extended by qbittorrent $as_me v4.6.2, which was
generated by GNU Autoconf 2.71. Invocation command line was
CONFIG_FILES = $CONFIG_FILES
@@ -7297,7 +7297,7 @@ ac_cs_config_escaped=`printf "%s\n" "$ac_cs_config" | sed "s/^ //; s/'/'\\\\\\\\
cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1
ac_cs_config='$ac_cs_config_escaped'
ac_cs_version="\\
-qbittorrent config.status v4.6.0beta2
+qbittorrent config.status v4.6.2
configured by $0, generated by GNU Autoconf 2.71,
with options \\"\$ac_cs_config\\"
diff --git a/configure.ac b/configure.ac
index f05e7120c..214c24518 100644
--- a/configure.ac
+++ b/configure.ac
@@ -1,4 +1,4 @@
-AC_INIT([qbittorrent], [v4.6.0beta2], [bugs.qbittorrent.org], [], [https://www.qbittorrent.org/])
+AC_INIT([qbittorrent], [v4.6.2], [bugs.qbittorrent.org], [], [https://www.qbittorrent.org/])
AC_CONFIG_AUX_DIR([build-aux])
AC_CONFIG_MACRO_DIR([m4])
: ${CFLAGS=""}
diff --git a/dist/mac/Info.plist b/dist/mac/Info.plist
index f3d55f614..736796fe7 100644
--- a/dist/mac/Info.plist
+++ b/dist/mac/Info.plist
@@ -55,7 +55,7 @@
CFBundlePackageType
APPL
CFBundleShortVersionString
- 4.5.0
+ 4.6.2
CFBundleExecutable
${EXECUTABLE_NAME}
CFBundleIdentifier
@@ -67,7 +67,7 @@
NSAppleScriptEnabled
YES
NSHumanReadableCopyright
- Copyright © 2006-2022 The qBittorrent project
+ Copyright © 2006-2023 The qBittorrent project
UTExportedTypeDeclarations
diff --git a/dist/unix/org.qbittorrent.qBittorrent.appdata.xml b/dist/unix/org.qbittorrent.qBittorrent.appdata.xml
index e56ffc716..38f58afd2 100644
--- a/dist/unix/org.qbittorrent.qBittorrent.appdata.xml
+++ b/dist/unix/org.qbittorrent.qBittorrent.appdata.xml
@@ -74,6 +74,6 @@
https://github.com/qbittorrent/qBittorrent/wiki/How-to-translate-qBittorrent
-
+
diff --git a/dist/unix/org.qbittorrent.qBittorrent.desktop b/dist/unix/org.qbittorrent.qBittorrent.desktop
index cb9e814cb..59f396ce9 100644
--- a/dist/unix/org.qbittorrent.qBittorrent.desktop
+++ b/dist/unix/org.qbittorrent.qBittorrent.desktop
@@ -14,216 +14,216 @@ Keywords=bittorrent;torrent;magnet;download;p2p;
SingleMainWindow=true
# Translations
-Comment[af]=Aflaai en deel lêers oor BitTorrent
GenericName[af]=BitTorrent kliënt
+Comment[af]=Aflaai en deel lêers oor BitTorrent
Name[af]=qBittorrent
-Comment[ar]=نزّل وشارك الملفات عبر كيوبتتورنت
GenericName[ar]=عميل بتتورنت
+Comment[ar]=نزّل وشارك الملفات عبر كيوبتتورنت
Name[ar]=qBittorrent
-Comment[be]=Спампоўванне і раздача файлаў праз пратакол BitTorrent
GenericName[be]=Кліент BitTorrent
+Comment[be]=Спампоўванне і раздача файлаў праз пратакол BitTorrent
Name[be]=qBittorrent
-Comment[bg]=Сваляне и споделяне на файлове чрез BitTorrent
GenericName[bg]=BitTorrent клиент
+Comment[bg]=Сваляне и споделяне на файлове чрез BitTorrent
Name[bg]=qBittorrent
-Comment[bn]=বিটটরেন্টে ফাইল ডাউনলোড এবং শেয়ার করুন
GenericName[bn]=বিটটরেন্ট ক্লায়েন্ট
+Comment[bn]=বিটটরেন্টে ফাইল ডাউনলোড এবং শেয়ার করুন
Name[bn]=qBittorrent
-Comment[zh]=通过 BitTorrent 下载和分享文件
GenericName[zh]=BitTorrent 客户端
+Comment[zh]=通过 BitTorrent 下载和分享文件
Name[zh]=qBittorrent
-Comment[bs]=Preuzmi i dijeli datoteke preko BitTorrent-a
GenericName[bs]=BitTorrent klijent
+Comment[bs]=Preuzmi i dijeli datoteke preko BitTorrent-a
Name[bs]=qBittorrent
-Comment[ca]=Baixeu i compartiu fitxers amb el BitTorrent
GenericName[ca]=Client de BitTorrent
+Comment[ca]=Baixeu i compartiu fitxers amb el BitTorrent
Name[ca]=qBittorrent
-Comment[cs]=Stahování a sdílení souborů přes síť BitTorrent
GenericName[cs]=BitTorrent klient
+Comment[cs]=Stahování a sdílení souborů přes síť BitTorrent
Name[cs]=qBittorrent
-Comment[da]=Download og del filer over BitTorrent
GenericName[da]=BitTorrent-klient
+Comment[da]=Download og del filer over BitTorrent
Name[da]=qBittorrent
-Comment[de]=Über BitTorrent Dateien herunterladen und teilen
GenericName[de]=BitTorrent Client
+Comment[de]=Über BitTorrent Dateien herunterladen und teilen
Name[de]=qBittorrent
-Comment[el]=Κάντε λήψη και μοιραστείτε αρχεία μέσω BitTorrent
GenericName[el]=BitTorrent client
+Comment[el]=Κάντε λήψη και μοιραστείτε αρχεία μέσω BitTorrent
Name[el]=qBittorrent
-Comment[en_GB]=Download and share files over BitTorrent
GenericName[en_GB]=BitTorrent client
+Comment[en_GB]=Download and share files over BitTorrent
Name[en_GB]=qBittorrent
-Comment[es]=Descargue y comparta archivos por BitTorrent
GenericName[es]=Cliente BitTorrent
+Comment[es]=Descargue y comparta archivos por BitTorrent
Name[es]=qBittorrent
-Comment[et]=Lae alla ja jaga faile üle BitTorrenti
GenericName[et]=BitTorrent klient
+Comment[et]=Lae alla ja jaga faile üle BitTorrenti
Name[et]=qBittorrent
-Comment[eu]=Jeitsi eta elkarbanatu agiriak BitTorrent bidez
GenericName[eu]=BitTorrent bezeroa
+Comment[eu]=Jeitsi eta elkarbanatu agiriak BitTorrent bidez
Name[eu]=qBittorrent
-Comment[fa]=دانلود و به اشتراک گذاری فایل های بوسیله بیت تورنت
GenericName[fa]=بیت تورنت نسخه کلاینت
+Comment[fa]=دانلود و به اشتراک گذاری فایل های بوسیله بیت تورنت
Name[fa]=qBittorrent
-Comment[fi]=Lataa ja jaa tiedostoja BitTorrentia käyttäen
GenericName[fi]=BitTorrent-asiakasohjelma
+Comment[fi]=Lataa ja jaa tiedostoja BitTorrentia käyttäen
Name[fi]=qBittorrent
-Comment[fr]=Télécharger et partager des fichiers sur BitTorrent
GenericName[fr]=Client BitTorrent
+Comment[fr]=Télécharger et partager des fichiers sur BitTorrent
Name[fr]=qBittorrent
-Comment[gl]=Descargar e compartir ficheiros co protocolo BitTorrent
GenericName[gl]=Cliente BitTorrent
+Comment[gl]=Descargar e compartir ficheiros co protocolo BitTorrent
Name[gl]=qBittorrent
-Comment[gu]=બિટ્ટોરેંટ પર ફાઈલો ડાઉનલોડ અને શેર કરો
GenericName[gu]=બિટ્ટોરેંટ ક્લાયન્ટ
+Comment[gu]=બિટ્ટોરેંટ પર ફાઈલો ડાઉનલોડ અને શેર કરો
Name[gu]=qBittorrent
-Comment[he]=הורד ושתף קבצים על גבי ביטורנט
GenericName[he]=לקוח ביטורנט
+Comment[he]=הורד ושתף קבצים על גבי ביטורנט
Name[he]=qBittorrent
-Comment[hr]=Preuzmite i dijelite datoteke putem BitTorrenta
GenericName[hr]=BitTorrent klijent
+Comment[hr]=Preuzmite i dijelite datoteke putem BitTorrenta
Name[hr]=qBittorrent
-Comment[hu]=Fájlok letöltése és megosztása a BitTorrent hálózaton keresztül
GenericName[hu]=BitTorrent kliens
+Comment[hu]=Fájlok letöltése és megosztása a BitTorrent hálózaton keresztül
Name[hu]=qBittorrent
-Comment[hy]=Նիշքերի փոխանցում BitTorrent-ի միջոցով
GenericName[hy]=BitTorrent սպասառու
+Comment[hy]=Նիշքերի փոխանցում BitTorrent-ի միջոցով
Name[hy]=qBittorrent
-Comment[id]=Unduh dan berbagi berkas melalui BitTorrent
GenericName[id]=Klien BitTorrent
+Comment[id]=Unduh dan berbagi berkas melalui BitTorrent
Name[id]=qBittorrent
-Comment[is]=Sækja og deila skrám yfir BitTorrent
GenericName[is]=BitTorrent biðlarar
+Comment[is]=Sækja og deila skrám yfir BitTorrent
Name[is]=qBittorrent
-Comment[it]=Scarica e condividi file tramite BitTorrent
GenericName[it]=Client BitTorrent
+Comment[it]=Scarica e condividi file tramite BitTorrent
Name[it]=qBittorrent
-Comment[ja]=BitTorrentでファイルのダウンロードと共有
GenericName[ja]=BitTorrentクライアント
+Comment[ja]=BitTorrentでファイルのダウンロードと共有
Name[ja]=qBittorrent
-Comment[ka]=გადმოტვირთეთ და გააზიარეთ ფაილები BitTorrent-ის საშუალებით
GenericName[ka]=BitTorrent კლიენტი
+Comment[ka]=გადმოტვირთეთ და გააზიარეთ ფაილები BitTorrent-ის საშუალებით
Name[ka]=qBittorrent
-Comment[ko]=BitTorrent를 통한 파일 내려받기 및 공유
GenericName[ko]=BitTorrent 클라이언트
+Comment[ko]=BitTorrent를 통한 파일 내려받기 및 공유
Name[ko]=qBittorrent
-Comment[lt]=Atsisiųskite bei dalinkitės failais BitTorrent tinkle
GenericName[lt]=BitTorrent klientas
+Comment[lt]=Atsisiųskite bei dalinkitės failais BitTorrent tinkle
Name[lt]=qBittorrent
-Comment[mk]=Превземајте и споделувајте фајлови преку BitTorrent
GenericName[mk]=BitTorrent клиент
+Comment[mk]=Превземајте и споделувајте фајлови преку BitTorrent
Name[mk]=qBittorrent
-Comment[my]=တောရန့်ဖြင့်ဖိုင်များဒေါင်းလုဒ်ဆွဲရန်နှင့်မျှဝေရန်
GenericName[my]=တောရန့်စီမံခန့်ခွဲသည့်အရာ
+Comment[my]=တောရန့်ဖြင့်ဖိုင်များဒေါင်းလုဒ်ဆွဲရန်နှင့်မျှဝေရန်
Name[my]=qBittorrent
-Comment[nb]=Last ned og del filer over BitTorrent
GenericName[nb]=BitTorrent-klient
+Comment[nb]=Last ned og del filer over BitTorrent
Name[nb]=qBittorrent
-Comment[nl]=Bestanden downloaden en delen via BitTorrent
GenericName[nl]=BitTorrent-client
+Comment[nl]=Bestanden downloaden en delen via BitTorrent
Name[nl]=qBittorrent
-Comment[pl]=Pobieraj i dziel się plikami przez BitTorrent
GenericName[pl]=Klient BitTorrent
+Comment[pl]=Pobieraj i dziel się plikami przez BitTorrent
Name[pl]=qBittorrent
-Comment[pt]=Transferir e partilhar ficheiros por BitTorrent
GenericName[pt]=Cliente BitTorrent
+Comment[pt]=Transferir e partilhar ficheiros por BitTorrent
Name[pt]=qBittorrent
-Comment[pt_BR]=Baixe e compartilhe arquivos pelo BitTorrent
GenericName[pt_BR]=Cliente BitTorrent
+Comment[pt_BR]=Baixe e compartilhe arquivos pelo BitTorrent
Name[pt_BR]=qBittorrent
-Comment[ro]=Descărcați și partajați fișiere prin BitTorrent
GenericName[ro]=Client BitTorrent
+Comment[ro]=Descărcați și partajați fișiere prin BitTorrent
Name[ro]=qBittorrent
-Comment[ru]=Обмен файлами по сети БитТоррент
GenericName[ru]=Клиент сети БитТоррент
+Comment[ru]=Обмен файлами по сети БитТоррент
Name[ru]=qBittorrent
-Comment[sk]=Sťahovanie a zdieľanie súborov prostredníctvom siete BitTorrent
GenericName[sk]=Klient siete BitTorrent
+Comment[sk]=Sťahovanie a zdieľanie súborov prostredníctvom siete BitTorrent
Name[sk]=qBittorrent
-Comment[sl]=Prenesite in delite datoteke preko BitTorrenta
GenericName[sl]=BitTorrent odjemalec
+Comment[sl]=Prenesite in delite datoteke preko BitTorrenta
Name[sl]=qBittorrent
Name[sq]=qBittorrent
-Comment[sr]=Преузимајте и делите фајлове преко BitTorrent протокола
GenericName[sr]=BitTorrent-клијент
+Comment[sr]=Преузимајте и делите фајлове преко BitTorrent протокола
Name[sr]=qBittorrent
-Comment[sr@latin]=Preuzimanje i deljenje fajlova preko BitTorrent-a
GenericName[sr@latin]=BitTorrent klijent
+Comment[sr@latin]=Preuzimanje i deljenje fajlova preko BitTorrent-a
Name[sr@latin]=qBittorrent
-Comment[sv]=Hämta och dela filer över BitTorrent
GenericName[sv]=BitTorrent-klient
+Comment[sv]=Hämta och dela filer över BitTorrent
Name[sv]=qBittorrent
-Comment[ta]=BitTorrent வழியாக கோப்புகளை பதிவிறக்க மற்றும் பகிர
GenericName[ta]=BitTorrent வாடிக்கையாளர்
+Comment[ta]=BitTorrent வழியாக கோப்புகளை பதிவிறக்க மற்றும் பகிர
Name[ta]=qBittorrent
-Comment[te]=క్యు బిట్ టొరెంట్ తో ఫైల్స్ దిగుమతి చేసుకోండి , పంచుకోండి
GenericName[te]=క్యు బిట్ టొరెంట్ క్లయింట్
+Comment[te]=క్యు బిట్ టొరెంట్ తో ఫైల్స్ దిగుమతి చేసుకోండి , పంచుకోండి
Name[te]=qBittorrent
-Comment[th]=ดาวน์โหลดและแชร์ไฟล์ผ่าน BitTorrent
GenericName[th]=โปรแกรมบิททอเร้นท์
+Comment[th]=ดาวน์โหลดและแชร์ไฟล์ผ่าน BitTorrent
Name[th]=qBittorrent
-Comment[tr]=Dosyaları BitTorrent üzerinden indirin ve paylaşın
GenericName[tr]=BitTorrent istemcisi
+Comment[tr]=Dosyaları BitTorrent üzerinden indirin ve paylaşın
Name[tr]=qBittorrent
-Comment[ur]=BitTorrent پر فائلوں کو ڈاؤن لوڈ کریں اور اشتراک کریں
GenericName[ur]=قیو بٹ ٹورنٹ کلائنٹ
+Comment[ur]=BitTorrent پر فائلوں کو ڈاؤن لوڈ کریں اور اشتراک کریں
Name[ur]=qBittorrent
-Comment[uk]=Завантажуйте та поширюйте файли через BitTorrent
GenericName[uk]=BitTorrent-клієнт
+Comment[uk]=Завантажуйте та поширюйте файли через BitTorrent
Name[uk]=qBittorrent
-Comment[vi]=Tải xuống và chia sẻ tệp qua BitTorrent
GenericName[vi]=Máy khách BitTorrent
+Comment[vi]=Tải xuống và chia sẻ tệp qua BitTorrent
Name[vi]=qBittorrent
-Comment[zh_HK]=經由BitTorrent下載並分享檔案
GenericName[zh_HK]=BitTorrent用戶端
+Comment[zh_HK]=經由BitTorrent下載並分享檔案
Name[zh_HK]=qBittorrent
-Comment[zh_TW]=經由 BitTorrent 下載並分享檔案
GenericName[zh_TW]=BitTorrent 用戶端
+Comment[zh_TW]=使用 BitTorrent 下載並分享檔案
Name[zh_TW]=qBittorrent
-Comment[eo]=Elŝutu kaj kunhavigu dosierojn per BitTorrent
GenericName[eo]=BitTorrent-kliento
+Comment[eo]=Elŝutu kaj kunhavigu dosierojn per BitTorrent
Name[eo]=qBittorrent
-Comment[kk]=BitTorrent арқылы файл жүктеу және бөлісу
GenericName[kk]=BitTorrent клиенті
+Comment[kk]=BitTorrent арқылы файл жүктеу және бөлісу
Name[kk]=qBittorrent
-Comment[en_AU]=Download and share files over BitTorrent
GenericName[en_AU]=BitTorrent client
+Comment[en_AU]=Download and share files over BitTorrent
Name[en_AU]=qBittorrent
Name[rm]=qBittorrent
Name[jv]=qBittorrent
-Comment[oc]=Telecargar e partejar de fichièrs amb BitTorrent
GenericName[oc]=Client BitTorrent
+Comment[oc]=Telecargar e partejar de fichièrs amb BitTorrent
Name[oc]=qBittorrent
Name[ug]=qBittorrent
Name[yi]=qBittorrent
-Comment[nqo]=ߞߐߕߐ߯ߘߐ ߟߎ߬ ߟߊߖߌ߰ ߞߊ߬ ߓߊ߲߫ ߞߵߊ߬ߟߎ߬ ߘߐߕߟߊ߫ ߓߌߙߏߙߍ߲ߕ ߞߊ߲߬
GenericName[nqo]=ߓߌߙߏߙߍ߲ߕ ߕߣߐ߬ߓߐ߬ߟߊ
+Comment[nqo]=ߞߐߕߐ߯ߘߐ ߟߎ߬ ߟߊߖߌ߰ ߞߊ߬ ߓߊ߲߫ ߞߵߊ߬ߟߎ߬ ߘߐߕߟߊ߫ ߓߌߙߏߙߍ߲ߕ ߞߊ߲߬
Name[nqo]=qBittorrent
-Comment[uz@Latn]=BitTorrent orqali fayllarni yuklab olish va baham ko‘rish
GenericName[uz@Latn]=BitTorrent mijozi
+Comment[uz@Latn]=BitTorrent orqali fayllarni yuklab olish va baham ko‘rish
Name[uz@Latn]=qBittorrent
-Comment[ltg]=Atsasyuteit i daleit failus ar BitTorrent
GenericName[ltg]=BitTorrent klients
+Comment[ltg]=Atsasyuteit i daleit failus ar BitTorrent
Name[ltg]=qBittorrent
-Comment[hi_IN]=BitTorrent द्वारा फाइल डाउनलोड व सहभाजन
GenericName[hi_IN]=Bittorrent साधन
+Comment[hi_IN]=BitTorrent द्वारा फाइल डाउनलोड व सहभाजन
Name[hi_IN]=qBittorrent
-Comment[az@latin]=Faylları BitTorrent vasitəsilə endirin və paylaşın
GenericName[az@latin]=BitTorrent client
+Comment[az@latin]=Faylları BitTorrent vasitəsilə endirin və paylaşın
Name[az@latin]=qBittorrent
-Comment[lv_LV]=Lejupielādēt un koplietot failus ar BitTorrent
GenericName[lv_LV]=BitTorrent klients
+Comment[lv_LV]=Lejupielādēt un koplietot failus ar BitTorrent
Name[lv_LV]=qBittorrent
-Comment[ms_MY]=Muat turun dan kongsi fail melalui BitTorrent
GenericName[ms_MY]=Klien BitTorrent
+Comment[ms_MY]=Muat turun dan kongsi fail melalui BitTorrent
Name[ms_MY]=qBittorrent
-Comment[mn_MN]=BitTorrent-оор файлуудаа тат, түгээ
GenericName[mn_MN]=BitTorrent татагч
+Comment[mn_MN]=BitTorrent-оор файлуудаа тат, түгээ
Name[mn_MN]=qBittorrent
-Comment[ne_NP]=फाइलहरू डाउनलोड गर्नुहोस् र BitTorrent मा साझा गर्नुहोस्
GenericName[ne_NP]=BitTorrent क्लाइन्ट
+Comment[ne_NP]=फाइलहरू डाउनलोड गर्नुहोस् र BitTorrent मा साझा गर्नुहोस्
Name[ne_NP]=qBittorrent
-Comment[pt_PT]=Transferir e partilhar ficheiros por BitTorrent
GenericName[pt_PT]=Cliente BitTorrent
+Comment[pt_PT]=Transferir e partilhar ficheiros por BitTorrent
Name[pt_PT]=qBittorrent
Name[si_LK]=qBittorrent
diff --git a/dist/windows/config.nsi b/dist/windows/config.nsi
index 3342e2b6c..edfeea8cb 100644
--- a/dist/windows/config.nsi
+++ b/dist/windows/config.nsi
@@ -25,7 +25,7 @@
; 4.5.1.3 -> good
; 4.5.1.3.2 -> bad
; 4.5.0beta -> bad
-!define /ifndef QBT_VERSION "4.5.0"
+!define /ifndef QBT_VERSION "4.6.2"
; Option that controls the installer's window name
; If set, its value will be used like this:
@@ -112,7 +112,7 @@ OutFile "qbittorrent_${QBT_INSTALLER_FILENAME}_setup.exe"
;Installer Version Information
VIAddVersionKey "ProductName" "qBittorrent"
VIAddVersionKey "CompanyName" "The qBittorrent project"
-VIAddVersionKey "LegalCopyright" "Copyright ©2006-2022 The qBittorrent project"
+VIAddVersionKey "LegalCopyright" "Copyright ©2006-2023 The qBittorrent project"
VIAddVersionKey "FileDescription" "qBittorrent - A Bittorrent Client"
VIAddVersionKey "FileVersion" "${QBT_VERSION}"
diff --git a/dist/windows/installer-translations/afrikaans.nsi b/dist/windows/installer-translations/afrikaans.nsi
index c46d5e2dd..4473df4d9 100644
--- a/dist/windows/installer-translations/afrikaans.nsi
+++ b/dist/windows/installer-translations/afrikaans.nsi
@@ -30,8 +30,8 @@ LangString launch_qbt ${LANG_AFRIKAANS} "Launch qBittorrent."
LangString inst_requires_64bit ${LANG_AFRIKAANS} "This installer works only in 64-bit Windows versions."
;LangString inst_requires_win7 ${LANG_ENGLISH} "This qBittorrent version requires at least Windows 7."
LangString inst_requires_win7 ${LANG_AFRIKAANS} "This qBittorrent version requires at least Windows 7."
-;LangString inst_requires_win10 ${LANG_ENGLISH} "This installer requires at least Windows 10 1809."
-LangString inst_requires_win10 ${LANG_AFRIKAANS} "This installer requires at least Windows 10 1809."
+;LangString inst_requires_win10 ${LANG_ENGLISH} "This installer requires at least Windows 10 (1809) / Windows Server 2019."
+LangString inst_requires_win10 ${LANG_AFRIKAANS} "This installer requires at least Windows 10 (1809) / Windows Server 2019."
;LangString inst_uninstall_link_description ${LANG_ENGLISH} "Uninstall qBittorrent"
LangString inst_uninstall_link_description ${LANG_AFRIKAANS} "Uninstall qBittorrent"
diff --git a/dist/windows/installer-translations/albanian.nsi b/dist/windows/installer-translations/albanian.nsi
index 649734e65..535e48be3 100644
--- a/dist/windows/installer-translations/albanian.nsi
+++ b/dist/windows/installer-translations/albanian.nsi
@@ -30,8 +30,8 @@ LangString launch_qbt ${LANG_ALBANIAN} "Launch qBittorrent."
LangString inst_requires_64bit ${LANG_ALBANIAN} "This installer works only in 64-bit Windows versions."
;LangString inst_requires_win7 ${LANG_ENGLISH} "This qBittorrent version requires at least Windows 7."
LangString inst_requires_win7 ${LANG_ALBANIAN} "This qBittorrent version requires at least Windows 7."
-;LangString inst_requires_win10 ${LANG_ENGLISH} "This installer requires at least Windows 10 1809."
-LangString inst_requires_win10 ${LANG_ALBANIAN} "This installer requires at least Windows 10 1809."
+;LangString inst_requires_win10 ${LANG_ENGLISH} "This installer requires at least Windows 10 (1809) / Windows Server 2019."
+LangString inst_requires_win10 ${LANG_ALBANIAN} "This installer requires at least Windows 10 (1809) / Windows Server 2019."
;LangString inst_uninstall_link_description ${LANG_ENGLISH} "Uninstall qBittorrent"
LangString inst_uninstall_link_description ${LANG_ALBANIAN} "Uninstall qBittorrent"
diff --git a/dist/windows/installer-translations/arabic.nsi b/dist/windows/installer-translations/arabic.nsi
index ce6bb15f3..272c836f6 100644
--- a/dist/windows/installer-translations/arabic.nsi
+++ b/dist/windows/installer-translations/arabic.nsi
@@ -30,8 +30,8 @@ LangString launch_qbt ${LANG_ARABIC} "تشغيل البرنامج"
LangString inst_requires_64bit ${LANG_ARABIC} "هذا المثبت يعمل فقط في نسخ ويندوز 64 بت"
;LangString inst_requires_win7 ${LANG_ENGLISH} "This qBittorrent version requires at least Windows 7."
LangString inst_requires_win7 ${LANG_ARABIC} "This qBittorrent version requires at least Windows 7."
-;LangString inst_requires_win10 ${LANG_ENGLISH} "This installer requires at least Windows 10 1809."
-LangString inst_requires_win10 ${LANG_ARABIC} "This installer requires at least Windows 10 1809."
+;LangString inst_requires_win10 ${LANG_ENGLISH} "This installer requires at least Windows 10 (1809) / Windows Server 2019."
+LangString inst_requires_win10 ${LANG_ARABIC} "This installer requires at least Windows 10 (1809) / Windows Server 2019."
;LangString inst_uninstall_link_description ${LANG_ENGLISH} "Uninstall qBittorrent"
LangString inst_uninstall_link_description ${LANG_ARABIC} "Uninstall qBittorrent"
diff --git a/dist/windows/installer-translations/basque.nsi b/dist/windows/installer-translations/basque.nsi
index fd41ecc9a..697e70e7c 100644
--- a/dist/windows/installer-translations/basque.nsi
+++ b/dist/windows/installer-translations/basque.nsi
@@ -30,8 +30,8 @@ LangString launch_qbt ${LANG_BASQUE} "Abiarazi qBittorrent."
LangString inst_requires_64bit ${LANG_BASQUE} "This installer works only in 64-bit Windows versions."
;LangString inst_requires_win7 ${LANG_ENGLISH} "This qBittorrent version requires at least Windows 7."
LangString inst_requires_win7 ${LANG_BASQUE} "This qBittorrent version requires at least Windows 7."
-;LangString inst_requires_win10 ${LANG_ENGLISH} "This installer requires at least Windows 10 1809."
-LangString inst_requires_win10 ${LANG_BASQUE} "This installer requires at least Windows 10 1809."
+;LangString inst_requires_win10 ${LANG_ENGLISH} "This installer requires at least Windows 10 (1809) / Windows Server 2019."
+LangString inst_requires_win10 ${LANG_BASQUE} "This installer requires at least Windows 10 (1809) / Windows Server 2019."
;LangString inst_uninstall_link_description ${LANG_ENGLISH} "Uninstall qBittorrent"
LangString inst_uninstall_link_description ${LANG_BASQUE} "Uninstall qBittorrent"
diff --git a/dist/windows/installer-translations/belarusian.nsi b/dist/windows/installer-translations/belarusian.nsi
index 09c075040..60b47ba66 100644
--- a/dist/windows/installer-translations/belarusian.nsi
+++ b/dist/windows/installer-translations/belarusian.nsi
@@ -30,8 +30,8 @@ LangString launch_qbt ${LANG_BELARUSIAN} "Launch qBittorrent."
LangString inst_requires_64bit ${LANG_BELARUSIAN} "This installer works only in 64-bit Windows versions."
;LangString inst_requires_win7 ${LANG_ENGLISH} "This qBittorrent version requires at least Windows 7."
LangString inst_requires_win7 ${LANG_BELARUSIAN} "This qBittorrent version requires at least Windows 7."
-;LangString inst_requires_win10 ${LANG_ENGLISH} "This installer requires at least Windows 10 1809."
-LangString inst_requires_win10 ${LANG_BELARUSIAN} "This installer requires at least Windows 10 1809."
+;LangString inst_requires_win10 ${LANG_ENGLISH} "This installer requires at least Windows 10 (1809) / Windows Server 2019."
+LangString inst_requires_win10 ${LANG_BELARUSIAN} "This installer requires at least Windows 10 (1809) / Windows Server 2019."
;LangString inst_uninstall_link_description ${LANG_ENGLISH} "Uninstall qBittorrent"
LangString inst_uninstall_link_description ${LANG_BELARUSIAN} "Uninstall qBittorrent"
diff --git a/dist/windows/installer-translations/bosnian.nsi b/dist/windows/installer-translations/bosnian.nsi
index c32eeccd0..4abff45fb 100644
--- a/dist/windows/installer-translations/bosnian.nsi
+++ b/dist/windows/installer-translations/bosnian.nsi
@@ -30,8 +30,8 @@ LangString launch_qbt ${LANG_BOSNIAN} "Launch qBittorrent."
LangString inst_requires_64bit ${LANG_BOSNIAN} "This installer works only in 64-bit Windows versions."
;LangString inst_requires_win7 ${LANG_ENGLISH} "This qBittorrent version requires at least Windows 7."
LangString inst_requires_win7 ${LANG_BOSNIAN} "This qBittorrent version requires at least Windows 7."
-;LangString inst_requires_win10 ${LANG_ENGLISH} "This installer requires at least Windows 10 1809."
-LangString inst_requires_win10 ${LANG_BOSNIAN} "This installer requires at least Windows 10 1809."
+;LangString inst_requires_win10 ${LANG_ENGLISH} "This installer requires at least Windows 10 (1809) / Windows Server 2019."
+LangString inst_requires_win10 ${LANG_BOSNIAN} "This installer requires at least Windows 10 (1809) / Windows Server 2019."
;LangString inst_uninstall_link_description ${LANG_ENGLISH} "Uninstall qBittorrent"
LangString inst_uninstall_link_description ${LANG_BOSNIAN} "Uninstall qBittorrent"
diff --git a/dist/windows/installer-translations/breton.nsi b/dist/windows/installer-translations/breton.nsi
index dbfaac2bc..31755264a 100644
--- a/dist/windows/installer-translations/breton.nsi
+++ b/dist/windows/installer-translations/breton.nsi
@@ -30,8 +30,8 @@ LangString launch_qbt ${LANG_BRETON} "Launch qBittorrent."
LangString inst_requires_64bit ${LANG_BRETON} "This installer works only in 64-bit Windows versions."
;LangString inst_requires_win7 ${LANG_ENGLISH} "This qBittorrent version requires at least Windows 7."
LangString inst_requires_win7 ${LANG_BRETON} "This qBittorrent version requires at least Windows 7."
-;LangString inst_requires_win10 ${LANG_ENGLISH} "This installer requires at least Windows 10 1809."
-LangString inst_requires_win10 ${LANG_BRETON} "This installer requires at least Windows 10 1809."
+;LangString inst_requires_win10 ${LANG_ENGLISH} "This installer requires at least Windows 10 (1809) / Windows Server 2019."
+LangString inst_requires_win10 ${LANG_BRETON} "This installer requires at least Windows 10 (1809) / Windows Server 2019."
;LangString inst_uninstall_link_description ${LANG_ENGLISH} "Uninstall qBittorrent"
LangString inst_uninstall_link_description ${LANG_BRETON} "Uninstall qBittorrent"
diff --git a/dist/windows/installer-translations/bulgarian.nsi b/dist/windows/installer-translations/bulgarian.nsi
index 4ab6e9e21..a1a955b14 100644
--- a/dist/windows/installer-translations/bulgarian.nsi
+++ b/dist/windows/installer-translations/bulgarian.nsi
@@ -30,8 +30,8 @@ LangString launch_qbt ${LANG_BULGARIAN} "Launch qBittorrent."
LangString inst_requires_64bit ${LANG_BULGARIAN} "This installer works only in 64-bit Windows versions."
;LangString inst_requires_win7 ${LANG_ENGLISH} "This qBittorrent version requires at least Windows 7."
LangString inst_requires_win7 ${LANG_BULGARIAN} "This qBittorrent version requires at least Windows 7."
-;LangString inst_requires_win10 ${LANG_ENGLISH} "This installer requires at least Windows 10 1809."
-LangString inst_requires_win10 ${LANG_BULGARIAN} "This installer requires at least Windows 10 1809."
+;LangString inst_requires_win10 ${LANG_ENGLISH} "This installer requires at least Windows 10 (1809) / Windows Server 2019."
+LangString inst_requires_win10 ${LANG_BULGARIAN} "This installer requires at least Windows 10 (1809) / Windows Server 2019."
;LangString inst_uninstall_link_description ${LANG_ENGLISH} "Uninstall qBittorrent"
LangString inst_uninstall_link_description ${LANG_BULGARIAN} "Uninstall qBittorrent"
diff --git a/dist/windows/installer-translations/catalan.nsi b/dist/windows/installer-translations/catalan.nsi
index ff0ea3406..4ab34c3b1 100644
--- a/dist/windows/installer-translations/catalan.nsi
+++ b/dist/windows/installer-translations/catalan.nsi
@@ -30,8 +30,8 @@ LangString launch_qbt ${LANG_CATALAN} "Launch qBittorrent."
LangString inst_requires_64bit ${LANG_CATALAN} "This installer works only in 64-bit Windows versions."
;LangString inst_requires_win7 ${LANG_ENGLISH} "This qBittorrent version requires at least Windows 7."
LangString inst_requires_win7 ${LANG_CATALAN} "This qBittorrent version requires at least Windows 7."
-;LangString inst_requires_win10 ${LANG_ENGLISH} "This installer requires at least Windows 10 1809."
-LangString inst_requires_win10 ${LANG_CATALAN} "This installer requires at least Windows 10 1809."
+;LangString inst_requires_win10 ${LANG_ENGLISH} "This installer requires at least Windows 10 (1809) / Windows Server 2019."
+LangString inst_requires_win10 ${LANG_CATALAN} "This installer requires at least Windows 10 (1809) / Windows Server 2019."
;LangString inst_uninstall_link_description ${LANG_ENGLISH} "Uninstall qBittorrent"
LangString inst_uninstall_link_description ${LANG_CATALAN} "Uninstall qBittorrent"
diff --git a/dist/windows/installer-translations/croatian.nsi b/dist/windows/installer-translations/croatian.nsi
index 3b4eb8738..481bf373f 100644
--- a/dist/windows/installer-translations/croatian.nsi
+++ b/dist/windows/installer-translations/croatian.nsi
@@ -30,8 +30,8 @@ LangString launch_qbt ${LANG_CROATIAN} "Pokreni qBittorrent."
LangString inst_requires_64bit ${LANG_CROATIAN} "This installer works only in 64-bit Windows versions."
;LangString inst_requires_win7 ${LANG_ENGLISH} "This qBittorrent version requires at least Windows 7."
LangString inst_requires_win7 ${LANG_CROATIAN} "This qBittorrent version requires at least Windows 7."
-;LangString inst_requires_win10 ${LANG_ENGLISH} "This installer requires at least Windows 10 1809."
-LangString inst_requires_win10 ${LANG_CROATIAN} "This installer requires at least Windows 10 1809."
+;LangString inst_requires_win10 ${LANG_ENGLISH} "This installer requires at least Windows 10 (1809) / Windows Server 2019."
+LangString inst_requires_win10 ${LANG_CROATIAN} "This installer requires at least Windows 10 (1809) / Windows Server 2019."
;LangString inst_uninstall_link_description ${LANG_ENGLISH} "Uninstall qBittorrent"
LangString inst_uninstall_link_description ${LANG_CROATIAN} "Uninstall qBittorrent"
diff --git a/dist/windows/installer-translations/czech.nsi b/dist/windows/installer-translations/czech.nsi
index ed7cb8e41..8fc42480f 100644
--- a/dist/windows/installer-translations/czech.nsi
+++ b/dist/windows/installer-translations/czech.nsi
@@ -30,8 +30,8 @@ LangString launch_qbt ${LANG_CZECH} "Spustit qBittorrent."
LangString inst_requires_64bit ${LANG_CZECH} "Tento instalátor funguje pouze v 64-bit Windows."
;LangString inst_requires_win7 ${LANG_ENGLISH} "This qBittorrent version requires at least Windows 7."
LangString inst_requires_win7 ${LANG_CZECH} "Tato verze qBittorrent vyžaduje minimálně Windows 7."
-;LangString inst_requires_win10 ${LANG_ENGLISH} "This installer requires at least Windows 10 1809."
-LangString inst_requires_win10 ${LANG_CZECH} "This installer requires at least Windows 10 1809."
+;LangString inst_requires_win10 ${LANG_ENGLISH} "This installer requires at least Windows 10 (1809) / Windows Server 2019."
+LangString inst_requires_win10 ${LANG_CZECH} "This installer requires at least Windows 10 (1809) / Windows Server 2019."
;LangString inst_uninstall_link_description ${LANG_ENGLISH} "Uninstall qBittorrent"
LangString inst_uninstall_link_description ${LANG_CZECH} "Uninstall qBittorrent"
diff --git a/dist/windows/installer-translations/danish.nsi b/dist/windows/installer-translations/danish.nsi
index 8b5f11d53..aad04f0ed 100644
--- a/dist/windows/installer-translations/danish.nsi
+++ b/dist/windows/installer-translations/danish.nsi
@@ -30,8 +30,8 @@ LangString launch_qbt ${LANG_DANISH} "Start qBittorrent."
LangString inst_requires_64bit ${LANG_DANISH} "Installationsprogrammet virker kun i Windows-versioner som er 64-bit."
;LangString inst_requires_win7 ${LANG_ENGLISH} "This qBittorrent version requires at least Windows 7."
LangString inst_requires_win7 ${LANG_DANISH} "qBittorrent-versionen kræver mindst Windows 7."
-;LangString inst_requires_win10 ${LANG_ENGLISH} "This installer requires at least Windows 10 1809."
-LangString inst_requires_win10 ${LANG_DANISH} "This installer requires at least Windows 10 1809."
+;LangString inst_requires_win10 ${LANG_ENGLISH} "This installer requires at least Windows 10 (1809) / Windows Server 2019."
+LangString inst_requires_win10 ${LANG_DANISH} "This installer requires at least Windows 10 (1809) / Windows Server 2019."
;LangString inst_uninstall_link_description ${LANG_ENGLISH} "Uninstall qBittorrent"
LangString inst_uninstall_link_description ${LANG_DANISH} "Afinstaller qBittorrent"
diff --git a/dist/windows/installer-translations/dutch.nsi b/dist/windows/installer-translations/dutch.nsi
index 6a73ec17f..507f219e0 100644
--- a/dist/windows/installer-translations/dutch.nsi
+++ b/dist/windows/installer-translations/dutch.nsi
@@ -30,8 +30,8 @@ LangString launch_qbt ${LANG_DUTCH} "qBittorrent starten."
LangString inst_requires_64bit ${LANG_DUTCH} "Dit installatieprogramma werkt alleen in 64-bit Windows-versies."
;LangString inst_requires_win7 ${LANG_ENGLISH} "This qBittorrent version requires at least Windows 7."
LangString inst_requires_win7 ${LANG_DUTCH} "Deze versie van qBittorrent vereist ten minste Windows 7."
-;LangString inst_requires_win10 ${LANG_ENGLISH} "This installer requires at least Windows 10 1809."
-LangString inst_requires_win10 ${LANG_DUTCH} "Dit installatieprogramma vereist ten minste Windows 10 1809."
+;LangString inst_requires_win10 ${LANG_ENGLISH} "This installer requires at least Windows 10 (1809) / Windows Server 2019."
+LangString inst_requires_win10 ${LANG_DUTCH} "Dit installatieprogramma vereist ten minste Windows 10 (1809) / Windows Server 2019."
;LangString inst_uninstall_link_description ${LANG_ENGLISH} "Uninstall qBittorrent"
LangString inst_uninstall_link_description ${LANG_DUTCH} "qBittorrent verwijderen"
diff --git a/dist/windows/installer-translations/english.nsi b/dist/windows/installer-translations/english.nsi
index fecf97c8f..3450d9f9d 100644
--- a/dist/windows/installer-translations/english.nsi
+++ b/dist/windows/installer-translations/english.nsi
@@ -30,8 +30,8 @@ LangString launch_qbt ${LANG_ENGLISH} "Launch qBittorrent."
LangString inst_requires_64bit ${LANG_ENGLISH} "This installer works only in 64-bit Windows versions."
;LangString inst_requires_win7 ${LANG_ENGLISH} "This qBittorrent version requires at least Windows 7."
LangString inst_requires_win7 ${LANG_ENGLISH} "This qBittorrent version requires at least Windows 7."
-;LangString inst_requires_win10 ${LANG_ENGLISH} "This installer requires at least Windows 10 1809."
-LangString inst_requires_win10 ${LANG_ENGLISH} "This installer requires at least Windows 10 1809."
+;LangString inst_requires_win10 ${LANG_ENGLISH} "This installer requires at least Windows 10 (1809) / Windows Server 2019."
+LangString inst_requires_win10 ${LANG_ENGLISH} "This installer requires at least Windows 10 (1809) / Windows Server 2019."
;LangString inst_uninstall_link_description ${LANG_ENGLISH} "Uninstall qBittorrent"
LangString inst_uninstall_link_description ${LANG_ENGLISH} "Uninstall qBittorrent"
diff --git a/dist/windows/installer-translations/esperanto.nsi b/dist/windows/installer-translations/esperanto.nsi
index a9db79867..cbc02f334 100644
--- a/dist/windows/installer-translations/esperanto.nsi
+++ b/dist/windows/installer-translations/esperanto.nsi
@@ -30,8 +30,8 @@ LangString launch_qbt ${LANG_ESPERANTO} "Launch qBittorrent."
LangString inst_requires_64bit ${LANG_ESPERANTO} "This installer works only in 64-bit Windows versions."
;LangString inst_requires_win7 ${LANG_ENGLISH} "This qBittorrent version requires at least Windows 7."
LangString inst_requires_win7 ${LANG_ESPERANTO} "This qBittorrent version requires at least Windows 7."
-;LangString inst_requires_win10 ${LANG_ENGLISH} "This installer requires at least Windows 10 1809."
-LangString inst_requires_win10 ${LANG_ESPERANTO} "This installer requires at least Windows 10 1809."
+;LangString inst_requires_win10 ${LANG_ENGLISH} "This installer requires at least Windows 10 (1809) / Windows Server 2019."
+LangString inst_requires_win10 ${LANG_ESPERANTO} "This installer requires at least Windows 10 (1809) / Windows Server 2019."
;LangString inst_uninstall_link_description ${LANG_ENGLISH} "Uninstall qBittorrent"
LangString inst_uninstall_link_description ${LANG_ESPERANTO} "Uninstall qBittorrent"
diff --git a/dist/windows/installer-translations/estonian.nsi b/dist/windows/installer-translations/estonian.nsi
index 42ab103a4..2d8250730 100644
--- a/dist/windows/installer-translations/estonian.nsi
+++ b/dist/windows/installer-translations/estonian.nsi
@@ -30,8 +30,8 @@ LangString launch_qbt ${LANG_ESTONIAN} "Käivita qBittorrent."
LangString inst_requires_64bit ${LANG_ESTONIAN} "See installer töötab ainult 64-bit Windowsi versioonides."
;LangString inst_requires_win7 ${LANG_ENGLISH} "This qBittorrent version requires at least Windows 7."
LangString inst_requires_win7 ${LANG_ESTONIAN} "Selle qBittorrenti versiooni jaoks on vajalik vähemalt Windows 7."
-;LangString inst_requires_win10 ${LANG_ENGLISH} "This installer requires at least Windows 10 1809."
-LangString inst_requires_win10 ${LANG_ESTONIAN} "Selle installeri jaoks on vajalik vähemalt Windows 10 1809."
+;LangString inst_requires_win10 ${LANG_ENGLISH} "This installer requires at least Windows 10 (1809) / Windows Server 2019."
+LangString inst_requires_win10 ${LANG_ESTONIAN} "Selle installeri jaoks on vajalik vähemalt Windows 10 (1809) / Windows Server 2019."
;LangString inst_uninstall_link_description ${LANG_ENGLISH} "Uninstall qBittorrent"
LangString inst_uninstall_link_description ${LANG_ESTONIAN} "Desinstalli qBittorrent"
diff --git a/dist/windows/installer-translations/farsi.nsi b/dist/windows/installer-translations/farsi.nsi
index 7ebc11e9b..819ccc1fd 100644
--- a/dist/windows/installer-translations/farsi.nsi
+++ b/dist/windows/installer-translations/farsi.nsi
@@ -30,8 +30,8 @@ LangString launch_qbt ${LANG_FARSI} "Launch qBittorrent."
LangString inst_requires_64bit ${LANG_FARSI} "This installer works only in 64-bit Windows versions."
;LangString inst_requires_win7 ${LANG_ENGLISH} "This qBittorrent version requires at least Windows 7."
LangString inst_requires_win7 ${LANG_FARSI} "This qBittorrent version requires at least Windows 7."
-;LangString inst_requires_win10 ${LANG_ENGLISH} "This installer requires at least Windows 10 1809."
-LangString inst_requires_win10 ${LANG_FARSI} "This installer requires at least Windows 10 1809."
+;LangString inst_requires_win10 ${LANG_ENGLISH} "This installer requires at least Windows 10 (1809) / Windows Server 2019."
+LangString inst_requires_win10 ${LANG_FARSI} "This installer requires at least Windows 10 (1809) / Windows Server 2019."
;LangString inst_uninstall_link_description ${LANG_ENGLISH} "Uninstall qBittorrent"
LangString inst_uninstall_link_description ${LANG_FARSI} "Uninstall qBittorrent"
diff --git a/dist/windows/installer-translations/finnish.nsi b/dist/windows/installer-translations/finnish.nsi
index 8cb9f80c1..cf8815275 100644
--- a/dist/windows/installer-translations/finnish.nsi
+++ b/dist/windows/installer-translations/finnish.nsi
@@ -30,8 +30,8 @@ LangString launch_qbt ${LANG_FINNISH} "Käynnistä qBittorrent."
LangString inst_requires_64bit ${LANG_FINNISH} "Tämä asennusohjelma toimii vain 64-bittisellä Windowsin versiolla."
;LangString inst_requires_win7 ${LANG_ENGLISH} "This qBittorrent version requires at least Windows 7."
LangString inst_requires_win7 ${LANG_FINNISH} "Tämä qBittorrent versio tarvitsee vähintään Windows 7:n."
-;LangString inst_requires_win10 ${LANG_ENGLISH} "This installer requires at least Windows 10 1809."
-LangString inst_requires_win10 ${LANG_FINNISH} "This installer requires at least Windows 10 1809."
+;LangString inst_requires_win10 ${LANG_ENGLISH} "This installer requires at least Windows 10 (1809) / Windows Server 2019."
+LangString inst_requires_win10 ${LANG_FINNISH} "This installer requires at least Windows 10 (1809) / Windows Server 2019."
;LangString inst_uninstall_link_description ${LANG_ENGLISH} "Uninstall qBittorrent"
LangString inst_uninstall_link_description ${LANG_FINNISH} "Uninstall qBittorrent"
diff --git a/dist/windows/installer-translations/french.nsi b/dist/windows/installer-translations/french.nsi
index a7f9ae947..3685f8d7a 100644
--- a/dist/windows/installer-translations/french.nsi
+++ b/dist/windows/installer-translations/french.nsi
@@ -7,7 +7,7 @@ LangString inst_desktop ${LANG_FRENCH} "Créer un Raccourci sur le Bureau"
;LangString inst_startmenu ${LANG_ENGLISH} "Create Start Menu Shortcut"
LangString inst_startmenu ${LANG_FRENCH} "Créer un Raccourci dans le Menu Démarrer"
;LangString inst_startup ${LANG_ENGLISH} "Start qBittorrent on Windows start up"
-LangString inst_startup ${LANG_FRENCH} "Démarrez qBittorrent au démarrage de Windows"
+LangString inst_startup ${LANG_FRENCH} "Démarrer qBittorrent au démarrage de Windows"
;LangString inst_torrent ${LANG_ENGLISH} "Open .torrent files with qBittorrent"
LangString inst_torrent ${LANG_FRENCH} "Ouvrir les fichiers .torrent avec qBittorrent"
;LangString inst_magnet ${LANG_ENGLISH} "Open magnet links with qBittorrent"
@@ -15,7 +15,7 @@ LangString inst_magnet ${LANG_FRENCH} "Ouvrir les liens magnet avec qBittorrent"
;LangString inst_firewall ${LANG_ENGLISH} "Add Windows Firewall rule"
LangString inst_firewall ${LANG_FRENCH} "Ajouter une règle au Pare-Feu de Windows"
;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_FRENCH} "Désactiver la limite de taille du chemin de Windows (limitation de MAX_PATH 260 caractères, nécessite Windows 10 1607 ou plus)"
+LangString inst_pathlimit ${LANG_FRENCH} "Désactiver la limite de taille des chemins de Windows (limite MAX_PATH de 260 caractères, nécessite Windows 10 1607 ou plus)"
;LangString inst_firewallinfo ${LANG_ENGLISH} "Adding Windows Firewall rule"
LangString inst_firewallinfo ${LANG_FRENCH} "Ajout d'une règle au Pare-Feu de Windows"
;LangString inst_warning ${LANG_ENGLISH} "qBittorrent is running. Please close the application before installing."
@@ -30,8 +30,8 @@ LangString launch_qbt ${LANG_FRENCH} "Lancer qBittorrent."
LangString inst_requires_64bit ${LANG_FRENCH} "Cet installateur ne fonctionne que dans les versions 64 bits de Windows."
;LangString inst_requires_win7 ${LANG_ENGLISH} "This qBittorrent version requires at least Windows 7."
LangString inst_requires_win7 ${LANG_FRENCH} "Cette version de qBittorrent nécessite au moins Windows 7."
-;LangString inst_requires_win10 ${LANG_ENGLISH} "This installer requires at least Windows 10 1809."
-LangString inst_requires_win10 ${LANG_FRENCH} "This installer requires at least Windows 10 1809."
+;LangString inst_requires_win10 ${LANG_ENGLISH} "This installer requires at least Windows 10 (1809) / Windows Server 2019."
+LangString inst_requires_win10 ${LANG_FRENCH} "Cet installateur nécessite au moins Windows 10 (1809) / Windows Server 2019."
;LangString inst_uninstall_link_description ${LANG_ENGLISH} "Uninstall qBittorrent"
LangString inst_uninstall_link_description ${LANG_FRENCH} "Désinstaller qBittorrent"
@@ -53,9 +53,9 @@ LangString remove_firewall ${LANG_FRENCH} "Supprimer la règle du Pare-Feu de Wi
;LangString remove_firewallinfo ${LANG_ENGLISH} "Removing Windows Firewall rule"
LangString remove_firewallinfo ${LANG_FRENCH} "Suppression de la règle du Pare-Feu de Windows"
;LangString remove_cache ${LANG_ENGLISH} "Remove torrents and cached data"
-LangString remove_cache ${LANG_FRENCH} "Supprimer les torrents et données cachées"
+LangString remove_cache ${LANG_FRENCH} "Supprimer les torrents et données en cache"
;LangString uninst_warning ${LANG_ENGLISH} "qBittorrent is running. Please close the application before uninstalling."
-LangString uninst_warning ${LANG_FRENCH} "qBittorrent est en cours d'exécution. Veuillez fermer l'application avant la désinstallation."
+LangString uninst_warning ${LANG_FRENCH} "qBittorrent est en cours d'exécution. Fermez l'application avant de la désinstaller."
;LangString uninst_tor_warn ${LANG_ENGLISH} "Not removing .torrent association. It is associated with:"
LangString uninst_tor_warn ${LANG_FRENCH} "Ne peut pas supprimer l'association du .torrent. Elle est associée avec :"
;LangString uninst_mag_warn ${LANG_ENGLISH} "Not removing magnet association. It is associated with:"
diff --git a/dist/windows/installer-translations/galician.nsi b/dist/windows/installer-translations/galician.nsi
index 402084f34..35abdf15c 100644
--- a/dist/windows/installer-translations/galician.nsi
+++ b/dist/windows/installer-translations/galician.nsi
@@ -30,8 +30,8 @@ LangString launch_qbt ${LANG_GALICIAN} "Iniciar qBittorrent."
LangString inst_requires_64bit ${LANG_GALICIAN} "This installer works only in 64-bit Windows versions."
;LangString inst_requires_win7 ${LANG_ENGLISH} "This qBittorrent version requires at least Windows 7."
LangString inst_requires_win7 ${LANG_GALICIAN} "This qBittorrent version requires at least Windows 7."
-;LangString inst_requires_win10 ${LANG_ENGLISH} "This installer requires at least Windows 10 1809."
-LangString inst_requires_win10 ${LANG_GALICIAN} "This installer requires at least Windows 10 1809."
+;LangString inst_requires_win10 ${LANG_ENGLISH} "This installer requires at least Windows 10 (1809) / Windows Server 2019."
+LangString inst_requires_win10 ${LANG_GALICIAN} "This installer requires at least Windows 10 (1809) / Windows Server 2019."
;LangString inst_uninstall_link_description ${LANG_ENGLISH} "Uninstall qBittorrent"
LangString inst_uninstall_link_description ${LANG_GALICIAN} "Uninstall qBittorrent"
diff --git a/dist/windows/installer-translations/german.nsi b/dist/windows/installer-translations/german.nsi
index fd7fbe946..957d76d05 100644
--- a/dist/windows/installer-translations/german.nsi
+++ b/dist/windows/installer-translations/german.nsi
@@ -30,8 +30,8 @@ LangString launch_qbt ${LANG_GERMAN} "Starte qBittorrent."
LangString inst_requires_64bit ${LANG_GERMAN} "Diese Installation funktioniert nur mit einer 64-bit Version von Windows."
;LangString inst_requires_win7 ${LANG_ENGLISH} "This qBittorrent version requires at least Windows 7."
LangString inst_requires_win7 ${LANG_GERMAN} "Diese Version von qBittorrent erfordert mindestens Windows 7."
-;LangString inst_requires_win10 ${LANG_ENGLISH} "This installer requires at least Windows 10 1809."
-LangString inst_requires_win10 ${LANG_GERMAN} "Diese Installation erfordert mindestens Windows 10 1809."
+;LangString inst_requires_win10 ${LANG_ENGLISH} "This installer requires at least Windows 10 (1809) / Windows Server 2019."
+LangString inst_requires_win10 ${LANG_GERMAN} "Diese Installation erfordert mindestens Windows 10 (1809) / Windows Server 2019."
;LangString inst_uninstall_link_description ${LANG_ENGLISH} "Uninstall qBittorrent"
LangString inst_uninstall_link_description ${LANG_GERMAN} "qBittorrent deinstallieren"
diff --git a/dist/windows/installer-translations/greek.nsi b/dist/windows/installer-translations/greek.nsi
index b79b62e82..798ea87de 100644
--- a/dist/windows/installer-translations/greek.nsi
+++ b/dist/windows/installer-translations/greek.nsi
@@ -30,8 +30,8 @@ LangString launch_qbt ${LANG_GREEK} "Εκκίνηση του qBittorrent."
LangString inst_requires_64bit ${LANG_GREEK} "Αυτό το αρχείο εγκατάστασης λειτουργεί μόνο σε 64-bit εκδόσεις των Windows."
;LangString inst_requires_win7 ${LANG_ENGLISH} "This qBittorrent version requires at least Windows 7."
LangString inst_requires_win7 ${LANG_GREEK} "This qBittorrent version requires at least Windows 7."
-;LangString inst_requires_win10 ${LANG_ENGLISH} "This installer requires at least Windows 10 1809."
-LangString inst_requires_win10 ${LANG_GREEK} "This installer requires at least Windows 10 1809."
+;LangString inst_requires_win10 ${LANG_ENGLISH} "This installer requires at least Windows 10 (1809) / Windows Server 2019."
+LangString inst_requires_win10 ${LANG_GREEK} "This installer requires at least Windows 10 (1809) / Windows Server 2019."
;LangString inst_uninstall_link_description ${LANG_ENGLISH} "Uninstall qBittorrent"
LangString inst_uninstall_link_description ${LANG_GREEK} "Uninstall qBittorrent"
diff --git a/dist/windows/installer-translations/hebrew.nsi b/dist/windows/installer-translations/hebrew.nsi
index b50b44dde..6a5b126d0 100644
--- a/dist/windows/installer-translations/hebrew.nsi
+++ b/dist/windows/installer-translations/hebrew.nsi
@@ -1,39 +1,37 @@
;Installer strings
;LangString inst_qbt_req ${LANG_ENGLISH} "qBittorrent (required)"
-LangString inst_qbt_req ${LANG_HEBREW} "qBittorrent (required)"
+LangString inst_qbt_req ${LANG_HEBREW} "qBittorrent (נדרש)"
;LangString inst_desktop ${LANG_ENGLISH} "Create Desktop Shortcut"
-LangString inst_desktop ${LANG_HEBREW} "Create Desktop Shortcut"
+LangString inst_desktop ${LANG_HEBREW} "צור קיצור דרך בשולחן עבודה"
;LangString inst_startmenu ${LANG_ENGLISH} "Create Start Menu Shortcut"
-LangString inst_startmenu ${LANG_HEBREW} "Create Start Menu Shortcut"
+LangString inst_startmenu ${LANG_HEBREW} "צור קיצור דרך ב-Start Menu"
;LangString inst_startup ${LANG_ENGLISH} "Start qBittorrent on Windows start up"
-LangString inst_startup ${LANG_HEBREW} "Start qBittorrent on Windows start up"
+LangString inst_startup ${LANG_HEBREW} "התחל את qBittorrent עם עליית Windows"
;LangString inst_torrent ${LANG_ENGLISH} "Open .torrent files with qBittorrent"
-LangString inst_torrent ${LANG_HEBREW} "Open .torrent files with qBittorrent"
+LangString inst_torrent ${LANG_HEBREW} "פתח קבצי .torrent עם qBittorrent"
;LangString inst_magnet ${LANG_ENGLISH} "Open magnet links with qBittorrent"
-LangString inst_magnet ${LANG_HEBREW} "Open magnet links with qBittorrent"
+LangString inst_magnet ${LANG_HEBREW} "פתח קישורי מגנט עם qBittorrent"
;LangString inst_firewall ${LANG_ENGLISH} "Add Windows Firewall rule"
-LangString inst_firewall ${LANG_HEBREW} "Add Windows Firewall rule"
+LangString inst_firewall ${LANG_HEBREW} "הוסף כלל חומת האש של Windows"
;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_HEBREW} "Disable Windows path length limit (260 character MAX_PATH limitation, requires Windows 10 1607 or later)"
+LangString inst_pathlimit ${LANG_HEBREW} "השבת את מגבלת אורך הנתיב של Windows (הגבלת MAX_PATH של 260 תווים, דורשת Windows 10 1607 ואילך)"
;LangString inst_firewallinfo ${LANG_ENGLISH} "Adding Windows Firewall rule"
-LangString inst_firewallinfo ${LANG_HEBREW} "Adding Windows Firewall rule"
+LangString inst_firewallinfo ${LANG_HEBREW} "מוסיף כלל חומת האש של Windows"
;LangString inst_warning ${LANG_ENGLISH} "qBittorrent is running. Please close the application before installing."
-LangString inst_warning ${LANG_HEBREW} "qBittorrent is running. Please close the application before installing."
+LangString inst_warning ${LANG_HEBREW} "qBittorrent פועל. אנא סגור את האפליקציה לפני ההתקנה."
;LangString inst_uninstall_question ${LANG_ENGLISH} "Current version will be uninstalled. User settings and torrents will remain intact."
-LangString inst_uninstall_question ${LANG_HEBREW} "Current version will be uninstalled. User settings and torrents will remain intact."
+LangString inst_uninstall_question ${LANG_HEBREW} "הגרסה הנוכחית תוסר. הגדרות המשתמש והטורנטים יישארו ללא שינוי."
;LangString inst_unist ${LANG_ENGLISH} "Uninstalling previous version."
-LangString inst_unist ${LANG_HEBREW} "Uninstalling previous version."
+LangString inst_unist ${LANG_HEBREW} "מסיר את ההתקנה של הגרסה הקודמת."
;LangString launch_qbt ${LANG_ENGLISH} "Launch qBittorrent."
-LangString launch_qbt ${LANG_HEBREW} "Launch qBittorrent."
+LangString launch_qbt ${LANG_HEBREW} "הפעל את qBittorrent."
;LangString inst_requires_64bit ${LANG_ENGLISH} "This installer works only in 64-bit Windows versions."
-LangString inst_requires_64bit ${LANG_HEBREW} "This installer works only in 64-bit Windows versions."
-;LangString inst_requires_win7 ${LANG_ENGLISH} "This qBittorrent version requires at least Windows 7."
-LangString inst_requires_win7 ${LANG_HEBREW} "This qBittorrent version requires at least Windows 7."
-;LangString inst_requires_win10 ${LANG_ENGLISH} "This installer requires at least Windows 10 1809."
-LangString inst_requires_win10 ${LANG_HEBREW} "This installer requires at least Windows 10 1809."
+LangString inst_requires_64bit ${LANG_HEBREW} "התקנה זו עובדת רק בגירסאות 64 סיביות של Windows."
+;LangString inst_requires_win10 ${LANG_ENGLISH} "This installer requires at least Windows 10 (1809) / Windows Server 2019."
+LangString inst_requires_win10 ${LANG_HEBREW} "התקנה זו דורשת לפחות Windows 10 (1809) / Windows Server 2019."
;LangString inst_uninstall_link_description ${LANG_ENGLISH} "Uninstall qBittorrent"
-LangString inst_uninstall_link_description ${LANG_HEBREW} "Uninstall qBittorrent"
+LangString inst_uninstall_link_description ${LANG_HEBREW} "הסר את ההתקנה של qBittorrent"
;------------------------------------
;Uninstaller strings
diff --git a/dist/windows/installer-translations/hungarian.nsi b/dist/windows/installer-translations/hungarian.nsi
index 756da4cc3..6536c3a85 100644
--- a/dist/windows/installer-translations/hungarian.nsi
+++ b/dist/windows/installer-translations/hungarian.nsi
@@ -19,7 +19,7 @@ LangString inst_pathlimit ${LANG_HUNGARIAN} "A Windows elérési útvonalak hoss
;LangString inst_firewallinfo ${LANG_ENGLISH} "Adding Windows Firewall rule"
LangString inst_firewallinfo ${LANG_HUNGARIAN} "Windows Tűzfal szabály hozzáadása folyamatban"
;LangString inst_warning ${LANG_ENGLISH} "qBittorrent is running. Please close the application before installing."
-LangString inst_warning ${LANG_HUNGARIAN} "A qBittorrent fut. Kérem zárjba be az alkalmazást a telepítés előtt."
+LangString inst_warning ${LANG_HUNGARIAN} "A qBittorrent fut. Kérem zárja be az alkalmazást a telepítés előtt."
;LangString inst_uninstall_question ${LANG_ENGLISH} "Current version will be uninstalled. User settings and torrents will remain intact."
LangString inst_uninstall_question ${LANG_HUNGARIAN} "A jelenlegi verzió el lesz távolítva. A felhasználói beállítások és a torrentek megmaradnak."
;LangString inst_unist ${LANG_ENGLISH} "Uninstalling previous version."
@@ -30,8 +30,8 @@ LangString launch_qbt ${LANG_HUNGARIAN} "qBittorrent indítása."
LangString inst_requires_64bit ${LANG_HUNGARIAN} "A telepítő csak 64-bites Windows verziókon működik."
;LangString inst_requires_win7 ${LANG_ENGLISH} "This qBittorrent version requires at least Windows 7."
LangString inst_requires_win7 ${LANG_HUNGARIAN} "A qBittorrent ezen verziójához minimum Windows 7 szükséges."
-;LangString inst_requires_win10 ${LANG_ENGLISH} "This installer requires at least Windows 10 1809."
-LangString inst_requires_win10 ${LANG_HUNGARIAN} "This installer requires at least Windows 10 1809."
+;LangString inst_requires_win10 ${LANG_ENGLISH} "This installer requires at least Windows 10 (1809) / Windows Server 2019."
+LangString inst_requires_win10 ${LANG_HUNGARIAN} "This installer requires at least Windows 10 (1809) / Windows Server 2019."
;LangString inst_uninstall_link_description ${LANG_ENGLISH} "Uninstall qBittorrent"
LangString inst_uninstall_link_description ${LANG_HUNGARIAN} "qBittorrent eltávolítása"
diff --git a/dist/windows/installer-translations/icelandic.nsi b/dist/windows/installer-translations/icelandic.nsi
index 50457fd0a..b4d93fcdf 100644
--- a/dist/windows/installer-translations/icelandic.nsi
+++ b/dist/windows/installer-translations/icelandic.nsi
@@ -30,8 +30,8 @@ LangString launch_qbt ${LANG_ICELANDIC} "Launch qBittorrent."
LangString inst_requires_64bit ${LANG_ICELANDIC} "This installer works only in 64-bit Windows versions."
;LangString inst_requires_win7 ${LANG_ENGLISH} "This qBittorrent version requires at least Windows 7."
LangString inst_requires_win7 ${LANG_ICELANDIC} "This qBittorrent version requires at least Windows 7."
-;LangString inst_requires_win10 ${LANG_ENGLISH} "This installer requires at least Windows 10 1809."
-LangString inst_requires_win10 ${LANG_ICELANDIC} "This installer requires at least Windows 10 1809."
+;LangString inst_requires_win10 ${LANG_ENGLISH} "This installer requires at least Windows 10 (1809) / Windows Server 2019."
+LangString inst_requires_win10 ${LANG_ICELANDIC} "This installer requires at least Windows 10 (1809) / Windows Server 2019."
;LangString inst_uninstall_link_description ${LANG_ENGLISH} "Uninstall qBittorrent"
LangString inst_uninstall_link_description ${LANG_ICELANDIC} "Uninstall qBittorrent"
diff --git a/dist/windows/installer-translations/indonesian.nsi b/dist/windows/installer-translations/indonesian.nsi
index 6b31ee330..cf8343119 100644
--- a/dist/windows/installer-translations/indonesian.nsi
+++ b/dist/windows/installer-translations/indonesian.nsi
@@ -30,8 +30,8 @@ LangString launch_qbt ${LANG_INDONESIAN} "Buka qBittorrent."
LangString inst_requires_64bit ${LANG_INDONESIAN} "Aplikasi ini hanya berjalan pada versi Windows 64-bit."
;LangString inst_requires_win7 ${LANG_ENGLISH} "This qBittorrent version requires at least Windows 7."
LangString inst_requires_win7 ${LANG_INDONESIAN} "Versi qBittorrent ini membutuhkan setidaknya Windows 7."
-;LangString inst_requires_win10 ${LANG_ENGLISH} "This installer requires at least Windows 10 1809."
-LangString inst_requires_win10 ${LANG_INDONESIAN} "Penginstal ini membutuhkan setidaknya Windows 10 1809."
+;LangString inst_requires_win10 ${LANG_ENGLISH} "This installer requires at least Windows 10 (1809) / Windows Server 2019."
+LangString inst_requires_win10 ${LANG_INDONESIAN} "Penginstal ini membutuhkan setidaknya Windows 10 (1809) / Windows Server 2019."
;LangString inst_uninstall_link_description ${LANG_ENGLISH} "Uninstall qBittorrent"
LangString inst_uninstall_link_description ${LANG_INDONESIAN} "Hapus qBittorrent"
diff --git a/dist/windows/installer-translations/irish.nsi b/dist/windows/installer-translations/irish.nsi
index f4fd14c79..1468f896c 100644
--- a/dist/windows/installer-translations/irish.nsi
+++ b/dist/windows/installer-translations/irish.nsi
@@ -30,8 +30,8 @@ LangString launch_qbt ${LANG_IRISH} "Launch qBittorrent."
LangString inst_requires_64bit ${LANG_IRISH} "This installer works only in 64-bit Windows versions."
;LangString inst_requires_win7 ${LANG_ENGLISH} "This qBittorrent version requires at least Windows 7."
LangString inst_requires_win7 ${LANG_IRISH} "This qBittorrent version requires at least Windows 7."
-;LangString inst_requires_win10 ${LANG_ENGLISH} "This installer requires at least Windows 10 1809."
-LangString inst_requires_win10 ${LANG_IRISH} "This installer requires at least Windows 10 1809."
+;LangString inst_requires_win10 ${LANG_ENGLISH} "This installer requires at least Windows 10 (1809) / Windows Server 2019."
+LangString inst_requires_win10 ${LANG_IRISH} "This installer requires at least Windows 10 (1809) / Windows Server 2019."
;LangString inst_uninstall_link_description ${LANG_ENGLISH} "Uninstall qBittorrent"
LangString inst_uninstall_link_description ${LANG_IRISH} "Uninstall qBittorrent"
diff --git a/dist/windows/installer-translations/italian.nsi b/dist/windows/installer-translations/italian.nsi
index 0361259f6..78c143c59 100644
--- a/dist/windows/installer-translations/italian.nsi
+++ b/dist/windows/installer-translations/italian.nsi
@@ -30,8 +30,8 @@ LangString launch_qbt ${LANG_ITALIAN} "Esegui qBittorrent."
LangString inst_requires_64bit ${LANG_ITALIAN} "Questo installer funziona solo con versioni di Windows a 64bit."
;LangString inst_requires_win7 ${LANG_ENGLISH} "This qBittorrent version requires at least Windows 7."
LangString inst_requires_win7 ${LANG_ITALIAN} "Questa versione di qBittorrent richiede Windows 7 o versioni successive."
-;LangString inst_requires_win10 ${LANG_ENGLISH} "This installer requires at least Windows 10 1809."
-LangString inst_requires_win10 ${LANG_ITALIAN} "This installer requires at least Windows 10 1809."
+;LangString inst_requires_win10 ${LANG_ENGLISH} "This installer requires at least Windows 10 (1809) / Windows Server 2019."
+LangString inst_requires_win10 ${LANG_ITALIAN} "This installer requires at least Windows 10 (1809) / Windows Server 2019."
;LangString inst_uninstall_link_description ${LANG_ENGLISH} "Uninstall qBittorrent"
LangString inst_uninstall_link_description ${LANG_ITALIAN} "Disinstalla qBittorrent"
diff --git a/dist/windows/installer-translations/japanese.nsi b/dist/windows/installer-translations/japanese.nsi
index 37f273479..7f7eeacff 100644
--- a/dist/windows/installer-translations/japanese.nsi
+++ b/dist/windows/installer-translations/japanese.nsi
@@ -30,8 +30,8 @@ LangString launch_qbt ${LANG_JAPANESE} "qBittorrent を起動"
LangString inst_requires_64bit ${LANG_JAPANESE} "このインストーラは 64 ビット版の Windows でのみ実行できます。"
;LangString inst_requires_win7 ${LANG_ENGLISH} "This qBittorrent version requires at least Windows 7."
LangString inst_requires_win7 ${LANG_JAPANESE} "このバージョンの qBittorrent には Windows 7 以降が必要です。"
-;LangString inst_requires_win10 ${LANG_ENGLISH} "This installer requires at least Windows 10 1809."
-LangString inst_requires_win10 ${LANG_JAPANESE} "このインストーラの実行には Windows 10 1809 以降が必要です。"
+;LangString inst_requires_win10 ${LANG_ENGLISH} "This installer requires at least Windows 10 (1809) / Windows Server 2019."
+LangString inst_requires_win10 ${LANG_JAPANESE} "このインストーラの実行には Windows 10 (1809) / Windows Server 2019 以降が必要です。"
;LangString inst_uninstall_link_description ${LANG_ENGLISH} "Uninstall qBittorrent"
LangString inst_uninstall_link_description ${LANG_JAPANESE} "qBittorrent をアンインストール"
diff --git a/dist/windows/installer-translations/korean.nsi b/dist/windows/installer-translations/korean.nsi
index d3f5cd469..36f605cff 100644
--- a/dist/windows/installer-translations/korean.nsi
+++ b/dist/windows/installer-translations/korean.nsi
@@ -30,8 +30,8 @@ LangString launch_qbt ${LANG_KOREAN} "qBittorrent를 실행합니다."
LangString inst_requires_64bit ${LANG_KOREAN} "이 설치 프로그램은 64비트 Windows 버전에서만 작동합니다."
;LangString inst_requires_win7 ${LANG_ENGLISH} "This qBittorrent version requires at least Windows 7."
LangString inst_requires_win7 ${LANG_KOREAN} "이 qBittorrent 버전에는 Windows 7 이상이 필요합니다."
-;LangString inst_requires_win10 ${LANG_ENGLISH} "This installer requires at least Windows 10 1809."
-LangString inst_requires_win10 ${LANG_KOREAN} "This installer requires at least Windows 10 1809."
+;LangString inst_requires_win10 ${LANG_ENGLISH} "This installer requires at least Windows 10 (1809) / Windows Server 2019."
+LangString inst_requires_win10 ${LANG_KOREAN} "This installer requires at least Windows 10 (1809) / Windows Server 2019."
;LangString inst_uninstall_link_description ${LANG_ENGLISH} "Uninstall qBittorrent"
LangString inst_uninstall_link_description ${LANG_KOREAN} "qBittorrent 제거"
diff --git a/dist/windows/installer-translations/kurdish.nsi b/dist/windows/installer-translations/kurdish.nsi
index 36fb8b4d0..d876f8389 100644
--- a/dist/windows/installer-translations/kurdish.nsi
+++ b/dist/windows/installer-translations/kurdish.nsi
@@ -30,8 +30,8 @@ LangString launch_qbt ${LANG_KURDISH} "Launch qBittorrent."
LangString inst_requires_64bit ${LANG_KURDISH} "This installer works only in 64-bit Windows versions."
;LangString inst_requires_win7 ${LANG_ENGLISH} "This qBittorrent version requires at least Windows 7."
LangString inst_requires_win7 ${LANG_KURDISH} "This qBittorrent version requires at least Windows 7."
-;LangString inst_requires_win10 ${LANG_ENGLISH} "This installer requires at least Windows 10 1809."
-LangString inst_requires_win10 ${LANG_KURDISH} "This installer requires at least Windows 10 1809."
+;LangString inst_requires_win10 ${LANG_ENGLISH} "This installer requires at least Windows 10 (1809) / Windows Server 2019."
+LangString inst_requires_win10 ${LANG_KURDISH} "This installer requires at least Windows 10 (1809) / Windows Server 2019."
;LangString inst_uninstall_link_description ${LANG_ENGLISH} "Uninstall qBittorrent"
LangString inst_uninstall_link_description ${LANG_KURDISH} "Uninstall qBittorrent"
diff --git a/dist/windows/installer-translations/latvian.nsi b/dist/windows/installer-translations/latvian.nsi
index 622779db6..e4ef707c6 100644
--- a/dist/windows/installer-translations/latvian.nsi
+++ b/dist/windows/installer-translations/latvian.nsi
@@ -30,8 +30,8 @@ LangString launch_qbt ${LANG_LATVIAN} "Palaist qBittorrent."
LangString inst_requires_64bit ${LANG_LATVIAN} "Šī instalēšanas programma darbojas tikai 64 bitu Windows versijās."
;LangString inst_requires_win7 ${LANG_ENGLISH} "This qBittorrent version requires at least Windows 7."
LangString inst_requires_win7 ${LANG_LATVIAN} "Šai qBittorrent versijai ir nepieciešama vismaz Windows 7."
-;LangString inst_requires_win10 ${LANG_ENGLISH} "This installer requires at least Windows 10 1809."
-LangString inst_requires_win10 ${LANG_LATVIAN} "This installer requires at least Windows 10 1809."
+;LangString inst_requires_win10 ${LANG_ENGLISH} "This installer requires at least Windows 10 (1809) / Windows Server 2019."
+LangString inst_requires_win10 ${LANG_LATVIAN} "This installer requires at least Windows 10 (1809) / Windows Server 2019."
;LangString inst_uninstall_link_description ${LANG_ENGLISH} "Uninstall qBittorrent"
LangString inst_uninstall_link_description ${LANG_LATVIAN} "Atinstalēt qBittorrent"
diff --git a/dist/windows/installer-translations/lithuanian.nsi b/dist/windows/installer-translations/lithuanian.nsi
index 7fdcdbe50..c4ed2bea0 100644
--- a/dist/windows/installer-translations/lithuanian.nsi
+++ b/dist/windows/installer-translations/lithuanian.nsi
@@ -30,8 +30,8 @@ LangString launch_qbt ${LANG_LITHUANIAN} "Paleisti qBittorrent."
LangString inst_requires_64bit ${LANG_LITHUANIAN} "Šis įdiegėjas veikia tik su 64 bitų Windows versija."
;LangString inst_requires_win7 ${LANG_ENGLISH} "This qBittorrent version requires at least Windows 7."
LangString inst_requires_win7 ${LANG_LITHUANIAN} "Ši qBittorent versija reikalauja bent Windows 7."
-;LangString inst_requires_win10 ${LANG_ENGLISH} "This installer requires at least Windows 10 1809."
-LangString inst_requires_win10 ${LANG_LITHUANIAN} "Šis įdiegėjas reikalauja bent Windows 10 1809."
+;LangString inst_requires_win10 ${LANG_ENGLISH} "This installer requires at least Windows 10 (1809) / Windows Server 2019."
+LangString inst_requires_win10 ${LANG_LITHUANIAN} "Šis įdiegėjas reikalauja bent Windows 10 (1809) / Windows Server 2019."
;LangString inst_uninstall_link_description ${LANG_ENGLISH} "Uninstall qBittorrent"
LangString inst_uninstall_link_description ${LANG_LITHUANIAN} "Pašalinti qBittorrent"
diff --git a/dist/windows/installer-translations/luxembourgish.nsi b/dist/windows/installer-translations/luxembourgish.nsi
index 9b5a24509..766d68533 100644
--- a/dist/windows/installer-translations/luxembourgish.nsi
+++ b/dist/windows/installer-translations/luxembourgish.nsi
@@ -30,8 +30,8 @@ LangString launch_qbt ${LANG_LUXEMBOURGISH} "Launch qBittorrent."
LangString inst_requires_64bit ${LANG_LUXEMBOURGISH} "This installer works only in 64-bit Windows versions."
;LangString inst_requires_win7 ${LANG_ENGLISH} "This qBittorrent version requires at least Windows 7."
LangString inst_requires_win7 ${LANG_LUXEMBOURGISH} "This qBittorrent version requires at least Windows 7."
-;LangString inst_requires_win10 ${LANG_ENGLISH} "This installer requires at least Windows 10 1809."
-LangString inst_requires_win10 ${LANG_LUXEMBOURGISH} "This installer requires at least Windows 10 1809."
+;LangString inst_requires_win10 ${LANG_ENGLISH} "This installer requires at least Windows 10 (1809) / Windows Server 2019."
+LangString inst_requires_win10 ${LANG_LUXEMBOURGISH} "This installer requires at least Windows 10 (1809) / Windows Server 2019."
;LangString inst_uninstall_link_description ${LANG_ENGLISH} "Uninstall qBittorrent"
LangString inst_uninstall_link_description ${LANG_LUXEMBOURGISH} "Uninstall qBittorrent"
diff --git a/dist/windows/installer-translations/macedonian.nsi b/dist/windows/installer-translations/macedonian.nsi
index 7a635d612..424c86b2f 100644
--- a/dist/windows/installer-translations/macedonian.nsi
+++ b/dist/windows/installer-translations/macedonian.nsi
@@ -30,8 +30,8 @@ LangString launch_qbt ${LANG_MACEDONIAN} "Launch qBittorrent."
LangString inst_requires_64bit ${LANG_MACEDONIAN} "This installer works only in 64-bit Windows versions."
;LangString inst_requires_win7 ${LANG_ENGLISH} "This qBittorrent version requires at least Windows 7."
LangString inst_requires_win7 ${LANG_MACEDONIAN} "This qBittorrent version requires at least Windows 7."
-;LangString inst_requires_win10 ${LANG_ENGLISH} "This installer requires at least Windows 10 1809."
-LangString inst_requires_win10 ${LANG_MACEDONIAN} "This installer requires at least Windows 10 1809."
+;LangString inst_requires_win10 ${LANG_ENGLISH} "This installer requires at least Windows 10 (1809) / Windows Server 2019."
+LangString inst_requires_win10 ${LANG_MACEDONIAN} "This installer requires at least Windows 10 (1809) / Windows Server 2019."
;LangString inst_uninstall_link_description ${LANG_ENGLISH} "Uninstall qBittorrent"
LangString inst_uninstall_link_description ${LANG_MACEDONIAN} "Uninstall qBittorrent"
diff --git a/dist/windows/installer-translations/malay.nsi b/dist/windows/installer-translations/malay.nsi
index 10cbca020..e3cd5ebee 100644
--- a/dist/windows/installer-translations/malay.nsi
+++ b/dist/windows/installer-translations/malay.nsi
@@ -30,8 +30,8 @@ LangString launch_qbt ${LANG_MALAY} "Launch qBittorrent."
LangString inst_requires_64bit ${LANG_MALAY} "This installer works only in 64-bit Windows versions."
;LangString inst_requires_win7 ${LANG_ENGLISH} "This qBittorrent version requires at least Windows 7."
LangString inst_requires_win7 ${LANG_MALAY} "This qBittorrent version requires at least Windows 7."
-;LangString inst_requires_win10 ${LANG_ENGLISH} "This installer requires at least Windows 10 1809."
-LangString inst_requires_win10 ${LANG_MALAY} "This installer requires at least Windows 10 1809."
+;LangString inst_requires_win10 ${LANG_ENGLISH} "This installer requires at least Windows 10 (1809) / Windows Server 2019."
+LangString inst_requires_win10 ${LANG_MALAY} "This installer requires at least Windows 10 (1809) / Windows Server 2019."
;LangString inst_uninstall_link_description ${LANG_ENGLISH} "Uninstall qBittorrent"
LangString inst_uninstall_link_description ${LANG_MALAY} "Uninstall qBittorrent"
diff --git a/dist/windows/installer-translations/mongolian.nsi b/dist/windows/installer-translations/mongolian.nsi
index ba0a0e179..794d027d1 100644
--- a/dist/windows/installer-translations/mongolian.nsi
+++ b/dist/windows/installer-translations/mongolian.nsi
@@ -30,8 +30,8 @@ LangString launch_qbt ${LANG_MONGOLIAN} "Launch qBittorrent."
LangString inst_requires_64bit ${LANG_MONGOLIAN} "This installer works only in 64-bit Windows versions."
;LangString inst_requires_win7 ${LANG_ENGLISH} "This qBittorrent version requires at least Windows 7."
LangString inst_requires_win7 ${LANG_MONGOLIAN} "This qBittorrent version requires at least Windows 7."
-;LangString inst_requires_win10 ${LANG_ENGLISH} "This installer requires at least Windows 10 1809."
-LangString inst_requires_win10 ${LANG_MONGOLIAN} "This installer requires at least Windows 10 1809."
+;LangString inst_requires_win10 ${LANG_ENGLISH} "This installer requires at least Windows 10 (1809) / Windows Server 2019."
+LangString inst_requires_win10 ${LANG_MONGOLIAN} "This installer requires at least Windows 10 (1809) / Windows Server 2019."
;LangString inst_uninstall_link_description ${LANG_ENGLISH} "Uninstall qBittorrent"
LangString inst_uninstall_link_description ${LANG_MONGOLIAN} "Uninstall qBittorrent"
diff --git a/dist/windows/installer-translations/norwegian.nsi b/dist/windows/installer-translations/norwegian.nsi
index d8a3e17c1..b65e110c1 100644
--- a/dist/windows/installer-translations/norwegian.nsi
+++ b/dist/windows/installer-translations/norwegian.nsi
@@ -30,8 +30,8 @@ LangString launch_qbt ${LANG_NORWEGIAN} "Sett i gang qBittorrent."
LangString inst_requires_64bit ${LANG_NORWEGIAN} "This installer works only in 64-bit Windows versions."
;LangString inst_requires_win7 ${LANG_ENGLISH} "This qBittorrent version requires at least Windows 7."
LangString inst_requires_win7 ${LANG_NORWEGIAN} "This qBittorrent version requires at least Windows 7."
-;LangString inst_requires_win10 ${LANG_ENGLISH} "This installer requires at least Windows 10 1809."
-LangString inst_requires_win10 ${LANG_NORWEGIAN} "This installer requires at least Windows 10 1809."
+;LangString inst_requires_win10 ${LANG_ENGLISH} "This installer requires at least Windows 10 (1809) / Windows Server 2019."
+LangString inst_requires_win10 ${LANG_NORWEGIAN} "This installer requires at least Windows 10 (1809) / Windows Server 2019."
;LangString inst_uninstall_link_description ${LANG_ENGLISH} "Uninstall qBittorrent"
LangString inst_uninstall_link_description ${LANG_NORWEGIAN} "Uninstall qBittorrent"
diff --git a/dist/windows/installer-translations/norwegiannynorsk.nsi b/dist/windows/installer-translations/norwegiannynorsk.nsi
index 008ea3c01..daf0475d6 100644
--- a/dist/windows/installer-translations/norwegiannynorsk.nsi
+++ b/dist/windows/installer-translations/norwegiannynorsk.nsi
@@ -30,8 +30,8 @@ LangString launch_qbt ${LANG_NORWEGIANNYNORSK} "Launch qBittorrent."
LangString inst_requires_64bit ${LANG_NORWEGIANNYNORSK} "This installer works only in 64-bit Windows versions."
;LangString inst_requires_win7 ${LANG_ENGLISH} "This qBittorrent version requires at least Windows 7."
LangString inst_requires_win7 ${LANG_NORWEGIANNYNORSK} "This qBittorrent version requires at least Windows 7."
-;LangString inst_requires_win10 ${LANG_ENGLISH} "This installer requires at least Windows 10 1809."
-LangString inst_requires_win10 ${LANG_NORWEGIANNYNORSK} "This installer requires at least Windows 10 1809."
+;LangString inst_requires_win10 ${LANG_ENGLISH} "This installer requires at least Windows 10 (1809) / Windows Server 2019."
+LangString inst_requires_win10 ${LANG_NORWEGIANNYNORSK} "This installer requires at least Windows 10 (1809) / Windows Server 2019."
;LangString inst_uninstall_link_description ${LANG_ENGLISH} "Uninstall qBittorrent"
LangString inst_uninstall_link_description ${LANG_NORWEGIANNYNORSK} "Uninstall qBittorrent"
diff --git a/dist/windows/installer-translations/polish.nsi b/dist/windows/installer-translations/polish.nsi
index 6c09dcc63..a1731137e 100644
--- a/dist/windows/installer-translations/polish.nsi
+++ b/dist/windows/installer-translations/polish.nsi
@@ -30,8 +30,8 @@ LangString launch_qbt ${LANG_POLISH} "Uruchom qBittorrent."
LangString inst_requires_64bit ${LANG_POLISH} "Ten instalator działa tylko w 64-bitowych wersjach systemu Windows."
;LangString inst_requires_win7 ${LANG_ENGLISH} "This qBittorrent version requires at least Windows 7."
LangString inst_requires_win7 ${LANG_POLISH} "Ta wersja qBittorrent wymaga co najmniej systemu Windows 7."
-;LangString inst_requires_win10 ${LANG_ENGLISH} "This installer requires at least Windows 10 1809."
-LangString inst_requires_win10 ${LANG_POLISH} "This installer requires at least Windows 10 1809."
+;LangString inst_requires_win10 ${LANG_ENGLISH} "This installer requires at least Windows 10 (1809) / Windows Server 2019."
+LangString inst_requires_win10 ${LANG_POLISH} "This installer requires at least Windows 10 (1809) / Windows Server 2019."
;LangString inst_uninstall_link_description ${LANG_ENGLISH} "Uninstall qBittorrent"
LangString inst_uninstall_link_description ${LANG_POLISH} "Odinstaluj qBittorrent"
diff --git a/dist/windows/installer-translations/portuguese.nsi b/dist/windows/installer-translations/portuguese.nsi
index 0148d7ba9..ea9d45f03 100644
--- a/dist/windows/installer-translations/portuguese.nsi
+++ b/dist/windows/installer-translations/portuguese.nsi
@@ -30,8 +30,8 @@ LangString launch_qbt ${LANG_PORTUGUESE} "Iniciar qBittorrent."
LangString inst_requires_64bit ${LANG_PORTUGUESE} "Este instalador funciona apenas em versões Windows de 64 bits."
;LangString inst_requires_win7 ${LANG_ENGLISH} "This qBittorrent version requires at least Windows 7."
LangString inst_requires_win7 ${LANG_PORTUGUESE} "Esta versão qBittorrent requer pelo menos o Windows 7."
-;LangString inst_requires_win10 ${LANG_ENGLISH} "This installer requires at least Windows 10 1809."
-LangString inst_requires_win10 ${LANG_PORTUGUESE} "This installer requires at least Windows 10 1809."
+;LangString inst_requires_win10 ${LANG_ENGLISH} "This installer requires at least Windows 10 (1809) / Windows Server 2019."
+LangString inst_requires_win10 ${LANG_PORTUGUESE} "This installer requires at least Windows 10 (1809) / Windows Server 2019."
;LangString inst_uninstall_link_description ${LANG_ENGLISH} "Uninstall qBittorrent"
LangString inst_uninstall_link_description ${LANG_PORTUGUESE} "Desinstalar qBittorrent"
diff --git a/dist/windows/installer-translations/portugueseBR.nsi b/dist/windows/installer-translations/portugueseBR.nsi
index 83eb2a7bd..ba1438fa4 100644
--- a/dist/windows/installer-translations/portugueseBR.nsi
+++ b/dist/windows/installer-translations/portugueseBR.nsi
@@ -30,8 +30,8 @@ LangString launch_qbt ${LANG_PORTUGUESEBR} "Executar o qBittorrent."
LangString inst_requires_64bit ${LANG_PORTUGUESEBR} "Este instalador só funciona nas versões 64 bits do Windows."
;LangString inst_requires_win7 ${LANG_ENGLISH} "This qBittorrent version requires at least Windows 7."
LangString inst_requires_win7 ${LANG_PORTUGUESEBR} "Esta versão do qBittorrent requer no mínimo o Windows 7."
-;LangString inst_requires_win10 ${LANG_ENGLISH} "This installer requires at least Windows 10 1809."
-LangString inst_requires_win10 ${LANG_PORTUGUESEBR} "Este instalador requer no mínimo o Windows 10 1809."
+;LangString inst_requires_win10 ${LANG_ENGLISH} "This installer requires at least Windows 10 (1809) / Windows Server 2019."
+LangString inst_requires_win10 ${LANG_PORTUGUESEBR} "Este instalador requer no mínimo o Windows 10 (1809) / Windows Server 2019."
;LangString inst_uninstall_link_description ${LANG_ENGLISH} "Uninstall qBittorrent"
LangString inst_uninstall_link_description ${LANG_PORTUGUESEBR} "Desinstalar o qBittorrent"
diff --git a/dist/windows/installer-translations/romanian.nsi b/dist/windows/installer-translations/romanian.nsi
index e52eba970..ac6d9d21e 100644
--- a/dist/windows/installer-translations/romanian.nsi
+++ b/dist/windows/installer-translations/romanian.nsi
@@ -1,62 +1,62 @@
;Installer strings
;LangString inst_qbt_req ${LANG_ENGLISH} "qBittorrent (required)"
-LangString inst_qbt_req ${LANG_ROMANIAN} "qBittorrent (required)"
+LangString inst_qbt_req ${LANG_ROMANIAN} "qBittorrent (obligatoriu)"
;LangString inst_desktop ${LANG_ENGLISH} "Create Desktop Shortcut"
-LangString inst_desktop ${LANG_ROMANIAN} "Create Desktop Shortcut"
+LangString inst_desktop ${LANG_ROMANIAN} "Creați o comandă rapidă pe Desktop"
;LangString inst_startmenu ${LANG_ENGLISH} "Create Start Menu Shortcut"
-LangString inst_startmenu ${LANG_ROMANIAN} "Create Start Menu Shortcut"
+LangString inst_startmenu ${LANG_ROMANIAN} "Creați o comandă rapidă în meniul Start"
;LangString inst_startup ${LANG_ENGLISH} "Start qBittorrent on Windows start up"
-LangString inst_startup ${LANG_ROMANIAN} "Start qBittorrent on Windows start up"
+LangString inst_startup ${LANG_ROMANIAN} "Porniți qBittorrent la pornirea Windows"
;LangString inst_torrent ${LANG_ENGLISH} "Open .torrent files with qBittorrent"
-LangString inst_torrent ${LANG_ROMANIAN} "Open .torrent files with qBittorrent"
+LangString inst_torrent ${LANG_ROMANIAN} "Deschideți fișierele .torrent cu qBittorrent"
;LangString inst_magnet ${LANG_ENGLISH} "Open magnet links with qBittorrent"
-LangString inst_magnet ${LANG_ROMANIAN} "Open magnet links with qBittorrent"
+LangString inst_magnet ${LANG_ROMANIAN} "Deschideți linkurile magnet cu qBittorrent"
;LangString inst_firewall ${LANG_ENGLISH} "Add Windows Firewall rule"
-LangString inst_firewall ${LANG_ROMANIAN} "Add Windows Firewall rule"
+LangString inst_firewall ${LANG_ROMANIAN} "Adăugați regula Windows Firewall"
;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_ROMANIAN} "Disable Windows path length limit (260 character MAX_PATH limitation, requires Windows 10 1607 or later)"
+LangString inst_pathlimit ${LANG_ROMANIAN} "Dezactivați limita de lungime a căii Windows (260 de caractere limită MAX_PATH, necesită Windows 10 1607 sau o versiune ulterioară)"
;LangString inst_firewallinfo ${LANG_ENGLISH} "Adding Windows Firewall rule"
-LangString inst_firewallinfo ${LANG_ROMANIAN} "Adding Windows Firewall rule"
+LangString inst_firewallinfo ${LANG_ROMANIAN} "Adăugarea regulii Windows Firewall"
;LangString inst_warning ${LANG_ENGLISH} "qBittorrent is running. Please close the application before installing."
-LangString inst_warning ${LANG_ROMANIAN} "qBittorrent is running. Please close the application before installing."
+LangString inst_warning ${LANG_ROMANIAN} "qBittorrent rulează. Vă rugăm să închideți aplicația înainte de instalare."
;LangString inst_uninstall_question ${LANG_ENGLISH} "Current version will be uninstalled. User settings and torrents will remain intact."
-LangString inst_uninstall_question ${LANG_ROMANIAN} "Current version will be uninstalled. User settings and torrents will remain intact."
+LangString inst_uninstall_question ${LANG_ROMANIAN} "Versiunea actuală va fi dezinstalată. Setările utilizatorului și torrentele vor rămâne intacte."
;LangString inst_unist ${LANG_ENGLISH} "Uninstalling previous version."
-LangString inst_unist ${LANG_ROMANIAN} "Uninstalling previous version."
+LangString inst_unist ${LANG_ROMANIAN} "Se dezinstalează versiunea anterioară."
;LangString launch_qbt ${LANG_ENGLISH} "Launch qBittorrent."
-LangString launch_qbt ${LANG_ROMANIAN} "Launch qBittorrent."
+LangString launch_qbt ${LANG_ROMANIAN} "Lansați qBittorrent."
;LangString inst_requires_64bit ${LANG_ENGLISH} "This installer works only in 64-bit Windows versions."
-LangString inst_requires_64bit ${LANG_ROMANIAN} "This installer works only in 64-bit Windows versions."
+LangString inst_requires_64bit ${LANG_ROMANIAN} "Acest program de instalare funcționează doar pe versiunile Windows pe 64 de biți."
;LangString inst_requires_win7 ${LANG_ENGLISH} "This qBittorrent version requires at least Windows 7."
-LangString inst_requires_win7 ${LANG_ROMANIAN} "This qBittorrent version requires at least Windows 7."
-;LangString inst_requires_win10 ${LANG_ENGLISH} "This installer requires at least Windows 10 1809."
-LangString inst_requires_win10 ${LANG_ROMANIAN} "This installer requires at least Windows 10 1809."
+LangString inst_requires_win7 ${LANG_ROMANIAN} "Această versiune de qBittorrent necesită cel puțin Windows 7."
+;LangString inst_requires_win10 ${LANG_ENGLISH} "This installer requires at least Windows 10 (1809) / Windows Server 2019."
+LangString inst_requires_win10 ${LANG_ROMANIAN} "Acest program de instalare necesită cel puțin Windows 10 (1809) / Windows Server 2019."
;LangString inst_uninstall_link_description ${LANG_ENGLISH} "Uninstall qBittorrent"
-LangString inst_uninstall_link_description ${LANG_ROMANIAN} "Uninstall qBittorrent"
+LangString inst_uninstall_link_description ${LANG_ROMANIAN} "Dezinstalați qBittorrent"
;------------------------------------
;Uninstaller strings
;LangString remove_files ${LANG_ENGLISH} "Remove files"
-LangString remove_files ${LANG_ROMANIAN} "Remove files"
+LangString remove_files ${LANG_ROMANIAN} "Eliminați fișierele"
;LangString remove_shortcuts ${LANG_ENGLISH} "Remove shortcuts"
-LangString remove_shortcuts ${LANG_ROMANIAN} "Remove shortcuts"
+LangString remove_shortcuts ${LANG_ROMANIAN} "Eliminați comenzile rapide"
;LangString remove_associations ${LANG_ENGLISH} "Remove file associations"
-LangString remove_associations ${LANG_ROMANIAN} "Remove file associations"
+LangString remove_associations ${LANG_ROMANIAN} "Eliminați asocierile de fișiere"
;LangString remove_registry ${LANG_ENGLISH} "Remove registry keys"
-LangString remove_registry ${LANG_ROMANIAN} "Remove registry keys"
+LangString remove_registry ${LANG_ROMANIAN} "Eliminați cheile din registru"
;LangString remove_conf ${LANG_ENGLISH} "Remove configuration files"
-LangString remove_conf ${LANG_ROMANIAN} "Remove configuration files"
+LangString remove_conf ${LANG_ROMANIAN} "Eliminați fișierele de configurare"
;LangString remove_firewall ${LANG_ENGLISH} "Remove Windows Firewall rule"
-LangString remove_firewall ${LANG_ROMANIAN} "Remove Windows Firewall rule"
+LangString remove_firewall ${LANG_ROMANIAN} "Eliminați regula Windows Firewall"
;LangString remove_firewallinfo ${LANG_ENGLISH} "Removing Windows Firewall rule"
-LangString remove_firewallinfo ${LANG_ROMANIAN} "Removing Windows Firewall rule"
+LangString remove_firewallinfo ${LANG_ROMANIAN} "Se elimină regula Windows Firewall"
;LangString remove_cache ${LANG_ENGLISH} "Remove torrents and cached data"
-LangString remove_cache ${LANG_ROMANIAN} "Remove torrents and cached data"
+LangString remove_cache ${LANG_ROMANIAN} "Eliminați torrentele și datele din cache"
;LangString uninst_warning ${LANG_ENGLISH} "qBittorrent is running. Please close the application before uninstalling."
-LangString uninst_warning ${LANG_ROMANIAN} "qBittorrent is running. Please close the application before uninstalling."
+LangString uninst_warning ${LANG_ROMANIAN} "qBittorrent rulează. Vă rugăm să închideți aplicația înainte de a o dezinstala."
;LangString uninst_tor_warn ${LANG_ENGLISH} "Not removing .torrent association. It is associated with:"
-LangString uninst_tor_warn ${LANG_ROMANIAN} "Not removing .torrent association. It is associated with:"
+LangString uninst_tor_warn ${LANG_ROMANIAN} "Nu se elimină asocierea .torrent. Este asociat cu:"
;LangString uninst_mag_warn ${LANG_ENGLISH} "Not removing magnet association. It is associated with:"
-LangString uninst_mag_warn ${LANG_ROMANIAN} "Not removing magnet association. It is associated with:"
+LangString uninst_mag_warn ${LANG_ROMANIAN} "Nu se elimină asocierea magnet. Este asociat cu:"
diff --git a/dist/windows/installer-translations/russian.nsi b/dist/windows/installer-translations/russian.nsi
index 153080353..f231eb69a 100644
--- a/dist/windows/installer-translations/russian.nsi
+++ b/dist/windows/installer-translations/russian.nsi
@@ -30,8 +30,8 @@ LangString launch_qbt ${LANG_RUSSIAN} "Запустить qBittorrent."
LangString inst_requires_64bit ${LANG_RUSSIAN} "Этот установщик работает только на 64-битных версиях Windows."
;LangString inst_requires_win7 ${LANG_ENGLISH} "This qBittorrent version requires at least Windows 7."
LangString inst_requires_win7 ${LANG_RUSSIAN} "Для работы этой версии qBittorrent требуется Windows 7 или выше."
-;LangString inst_requires_win10 ${LANG_ENGLISH} "This installer requires at least Windows 10 1809."
-LangString inst_requires_win10 ${LANG_RUSSIAN} "Для работы этого установщика требуется Windows 10 1809 или выше."
+;LangString inst_requires_win10 ${LANG_ENGLISH} "This installer requires at least Windows 10 (1809) / Windows Server 2019."
+LangString inst_requires_win10 ${LANG_RUSSIAN} "Для работы этого установщика требуется Windows 10 (1809) / Windows Server 2019 или выше."
;LangString inst_uninstall_link_description ${LANG_ENGLISH} "Uninstall qBittorrent"
LangString inst_uninstall_link_description ${LANG_RUSSIAN} "Удалить qBittorrent"
diff --git a/dist/windows/installer-translations/serbian.nsi b/dist/windows/installer-translations/serbian.nsi
index 406aa63bf..72774d355 100644
--- a/dist/windows/installer-translations/serbian.nsi
+++ b/dist/windows/installer-translations/serbian.nsi
@@ -30,8 +30,8 @@ LangString launch_qbt ${LANG_SERBIAN} "Launch qBittorrent."
LangString inst_requires_64bit ${LANG_SERBIAN} "This installer works only in 64-bit Windows versions."
;LangString inst_requires_win7 ${LANG_ENGLISH} "This qBittorrent version requires at least Windows 7."
LangString inst_requires_win7 ${LANG_SERBIAN} "This qBittorrent version requires at least Windows 7."
-;LangString inst_requires_win10 ${LANG_ENGLISH} "This installer requires at least Windows 10 1809."
-LangString inst_requires_win10 ${LANG_SERBIAN} "This installer requires at least Windows 10 1809."
+;LangString inst_requires_win10 ${LANG_ENGLISH} "This installer requires at least Windows 10 (1809) / Windows Server 2019."
+LangString inst_requires_win10 ${LANG_SERBIAN} "This installer requires at least Windows 10 (1809) / Windows Server 2019."
;LangString inst_uninstall_link_description ${LANG_ENGLISH} "Uninstall qBittorrent"
LangString inst_uninstall_link_description ${LANG_SERBIAN} "Uninstall qBittorrent"
diff --git a/dist/windows/installer-translations/serbianlatin.nsi b/dist/windows/installer-translations/serbianlatin.nsi
index f31b2c190..282fbc6b1 100644
--- a/dist/windows/installer-translations/serbianlatin.nsi
+++ b/dist/windows/installer-translations/serbianlatin.nsi
@@ -30,8 +30,8 @@ LangString launch_qbt ${LANG_SERBIANLATIN} "Launch qBittorrent."
LangString inst_requires_64bit ${LANG_SERBIANLATIN} "This installer works only in 64-bit Windows versions."
;LangString inst_requires_win7 ${LANG_ENGLISH} "This qBittorrent version requires at least Windows 7."
LangString inst_requires_win7 ${LANG_SERBIANLATIN} "This qBittorrent version requires at least Windows 7."
-;LangString inst_requires_win10 ${LANG_ENGLISH} "This installer requires at least Windows 10 1809."
-LangString inst_requires_win10 ${LANG_SERBIANLATIN} "This installer requires at least Windows 10 1809."
+;LangString inst_requires_win10 ${LANG_ENGLISH} "This installer requires at least Windows 10 (1809) / Windows Server 2019."
+LangString inst_requires_win10 ${LANG_SERBIANLATIN} "This installer requires at least Windows 10 (1809) / Windows Server 2019."
;LangString inst_uninstall_link_description ${LANG_ENGLISH} "Uninstall qBittorrent"
LangString inst_uninstall_link_description ${LANG_SERBIANLATIN} "Uninstall qBittorrent"
diff --git a/dist/windows/installer-translations/simpchinese.nsi b/dist/windows/installer-translations/simpchinese.nsi
index da9e803d8..9459dab3b 100644
--- a/dist/windows/installer-translations/simpchinese.nsi
+++ b/dist/windows/installer-translations/simpchinese.nsi
@@ -30,8 +30,8 @@ LangString launch_qbt ${LANG_SIMPCHINESE} "启动 qBittorrent。"
LangString inst_requires_64bit ${LANG_SIMPCHINESE} "此安装程序仅支持 64 位 Windows 系统。"
;LangString inst_requires_win7 ${LANG_ENGLISH} "This qBittorrent version requires at least Windows 7."
LangString inst_requires_win7 ${LANG_SIMPCHINESE} "这个版本的 qBittorrent 仅支持 Windows 7 及更新的系统。"
-;LangString inst_requires_win10 ${LANG_ENGLISH} "This installer requires at least Windows 10 1809."
-LangString inst_requires_win10 ${LANG_SIMPCHINESE} "This installer requires at least Windows 10 1809."
+;LangString inst_requires_win10 ${LANG_ENGLISH} "This installer requires at least Windows 10 (1809) / Windows Server 2019."
+LangString inst_requires_win10 ${LANG_SIMPCHINESE} "This installer requires at least Windows 10 (1809) / Windows Server 2019."
;LangString inst_uninstall_link_description ${LANG_ENGLISH} "Uninstall qBittorrent"
LangString inst_uninstall_link_description ${LANG_SIMPCHINESE} "卸载 qBittorrent"
diff --git a/dist/windows/installer-translations/slovak.nsi b/dist/windows/installer-translations/slovak.nsi
index 66876ba14..b3a97a739 100644
--- a/dist/windows/installer-translations/slovak.nsi
+++ b/dist/windows/installer-translations/slovak.nsi
@@ -30,8 +30,8 @@ LangString launch_qbt ${LANG_SLOVAK} "Spustiť qBittorrent."
LangString inst_requires_64bit ${LANG_SLOVAK} "Táto inštalácia funguje iba na 64-bitových verziách Windowsu."
;LangString inst_requires_win7 ${LANG_ENGLISH} "This qBittorrent version requires at least Windows 7."
LangString inst_requires_win7 ${LANG_SLOVAK} "Táto qBittorrent verzia vyžaduje aspoň Windows 7."
-;LangString inst_requires_win10 ${LANG_ENGLISH} "This installer requires at least Windows 10 1809."
-LangString inst_requires_win10 ${LANG_SLOVAK} "Tento inštalátor vyžaduje aspoň Windows 10 1809."
+;LangString inst_requires_win10 ${LANG_ENGLISH} "This installer requires at least Windows 10 (1809) / Windows Server 2019."
+LangString inst_requires_win10 ${LANG_SLOVAK} "Tento inštalátor vyžaduje aspoň Windows 10 (1809) / Windows Server 2019."
;LangString inst_uninstall_link_description ${LANG_ENGLISH} "Uninstall qBittorrent"
LangString inst_uninstall_link_description ${LANG_SLOVAK} "Odinštalovať qBittorrent"
diff --git a/dist/windows/installer-translations/slovenian.nsi b/dist/windows/installer-translations/slovenian.nsi
index 2dcd9ccac..af319a487 100644
--- a/dist/windows/installer-translations/slovenian.nsi
+++ b/dist/windows/installer-translations/slovenian.nsi
@@ -30,8 +30,8 @@ LangString launch_qbt ${LANG_SLOVENIAN} "Launch qBittorrent."
LangString inst_requires_64bit ${LANG_SLOVENIAN} "This installer works only in 64-bit Windows versions."
;LangString inst_requires_win7 ${LANG_ENGLISH} "This qBittorrent version requires at least Windows 7."
LangString inst_requires_win7 ${LANG_SLOVENIAN} "This qBittorrent version requires at least Windows 7."
-;LangString inst_requires_win10 ${LANG_ENGLISH} "This installer requires at least Windows 10 1809."
-LangString inst_requires_win10 ${LANG_SLOVENIAN} "This installer requires at least Windows 10 1809."
+;LangString inst_requires_win10 ${LANG_ENGLISH} "This installer requires at least Windows 10 (1809) / Windows Server 2019."
+LangString inst_requires_win10 ${LANG_SLOVENIAN} "This installer requires at least Windows 10 (1809) / Windows Server 2019."
;LangString inst_uninstall_link_description ${LANG_ENGLISH} "Uninstall qBittorrent"
LangString inst_uninstall_link_description ${LANG_SLOVENIAN} "Uninstall qBittorrent"
diff --git a/dist/windows/installer-translations/spanish.nsi b/dist/windows/installer-translations/spanish.nsi
index 7efe0844d..b0c842617 100644
--- a/dist/windows/installer-translations/spanish.nsi
+++ b/dist/windows/installer-translations/spanish.nsi
@@ -30,8 +30,8 @@ LangString launch_qbt ${LANG_SPANISH} "Iniciar qBittorrent."
LangString inst_requires_64bit ${LANG_SPANISH} "Este instalador solo funciona en versiones de 64-bit de Windows."
;LangString inst_requires_win7 ${LANG_ENGLISH} "This qBittorrent version requires at least Windows 7."
LangString inst_requires_win7 ${LANG_SPANISH} "Esta versión de qBittorrent requiere Windows 7 o superior."
-;LangString inst_requires_win10 ${LANG_ENGLISH} "This installer requires at least Windows 10 1809."
-LangString inst_requires_win10 ${LANG_SPANISH} "This installer requires at least Windows 10 1809."
+;LangString inst_requires_win10 ${LANG_ENGLISH} "This installer requires at least Windows 10 (1809) / Windows Server 2019."
+LangString inst_requires_win10 ${LANG_SPANISH} "This installer requires at least Windows 10 (1809) / Windows Server 2019."
;LangString inst_uninstall_link_description ${LANG_ENGLISH} "Uninstall qBittorrent"
LangString inst_uninstall_link_description ${LANG_SPANISH} "Desinstalar qBittorrent"
diff --git a/dist/windows/installer-translations/spanishinternational.nsi b/dist/windows/installer-translations/spanishinternational.nsi
index 7cdd146fa..7927c00b9 100644
--- a/dist/windows/installer-translations/spanishinternational.nsi
+++ b/dist/windows/installer-translations/spanishinternational.nsi
@@ -30,8 +30,8 @@ LangString launch_qbt ${LANG_SPANISHINTERNATIONAL} "Iniciar qBittorrent."
LangString inst_requires_64bit ${LANG_SPANISHINTERNATIONAL} "Este instalador solo funciona en versiones de 64-bit de Windows."
;LangString inst_requires_win7 ${LANG_ENGLISH} "This qBittorrent version requires at least Windows 7."
LangString inst_requires_win7 ${LANG_SPANISHINTERNATIONAL} "Esta versión de qBittorrent requiere Windows 7 o superior."
-;LangString inst_requires_win10 ${LANG_ENGLISH} "This installer requires at least Windows 10 1809."
-LangString inst_requires_win10 ${LANG_SPANISHINTERNATIONAL} "This installer requires at least Windows 10 1809."
+;LangString inst_requires_win10 ${LANG_ENGLISH} "This installer requires at least Windows 10 (1809) / Windows Server 2019."
+LangString inst_requires_win10 ${LANG_SPANISHINTERNATIONAL} "This installer requires at least Windows 10 (1809) / Windows Server 2019."
;LangString inst_uninstall_link_description ${LANG_ENGLISH} "Uninstall qBittorrent"
LangString inst_uninstall_link_description ${LANG_SPANISHINTERNATIONAL} "Desinstalar qBittorrent"
diff --git a/dist/windows/installer-translations/swedish.nsi b/dist/windows/installer-translations/swedish.nsi
index f471141bf..3b8032c23 100644
--- a/dist/windows/installer-translations/swedish.nsi
+++ b/dist/windows/installer-translations/swedish.nsi
@@ -30,8 +30,8 @@ LangString launch_qbt ${LANG_SWEDISH} "Kör qBittorrent."
LangString inst_requires_64bit ${LANG_SWEDISH} "Det här installationsprogrammet fungerar endast i 64-bitars Windows-versioner."
;LangString inst_requires_win7 ${LANG_ENGLISH} "This qBittorrent version requires at least Windows 7."
LangString inst_requires_win7 ${LANG_SWEDISH} "Den här qBittorrent-versionen kräver minst Windows 7."
-;LangString inst_requires_win10 ${LANG_ENGLISH} "This installer requires at least Windows 10 1809."
-LangString inst_requires_win10 ${LANG_SWEDISH} "Det här installationsprogrammet kräver minst Windows 10 1809."
+;LangString inst_requires_win10 ${LANG_ENGLISH} "This installer requires at least Windows 10 (1809) / Windows Server 2019."
+LangString inst_requires_win10 ${LANG_SWEDISH} "Det här installationsprogrammet kräver minst Windows 10 (1809) / Windows Server 2019."
;LangString inst_uninstall_link_description ${LANG_ENGLISH} "Uninstall qBittorrent"
LangString inst_uninstall_link_description ${LANG_SWEDISH} "Avinstallera qBittorrent"
diff --git a/dist/windows/installer-translations/thai.nsi b/dist/windows/installer-translations/thai.nsi
index c48bef13e..4eac8fc9c 100644
--- a/dist/windows/installer-translations/thai.nsi
+++ b/dist/windows/installer-translations/thai.nsi
@@ -30,8 +30,8 @@ LangString launch_qbt ${LANG_THAI} "Launch qBittorrent."
LangString inst_requires_64bit ${LANG_THAI} "This installer works only in 64-bit Windows versions."
;LangString inst_requires_win7 ${LANG_ENGLISH} "This qBittorrent version requires at least Windows 7."
LangString inst_requires_win7 ${LANG_THAI} "This qBittorrent version requires at least Windows 7."
-;LangString inst_requires_win10 ${LANG_ENGLISH} "This installer requires at least Windows 10 1809."
-LangString inst_requires_win10 ${LANG_THAI} "This installer requires at least Windows 10 1809."
+;LangString inst_requires_win10 ${LANG_ENGLISH} "This installer requires at least Windows 10 (1809) / Windows Server 2019."
+LangString inst_requires_win10 ${LANG_THAI} "This installer requires at least Windows 10 (1809) / Windows Server 2019."
;LangString inst_uninstall_link_description ${LANG_ENGLISH} "Uninstall qBittorrent"
LangString inst_uninstall_link_description ${LANG_THAI} "Uninstall qBittorrent"
diff --git a/dist/windows/installer-translations/tradchinese.nsi b/dist/windows/installer-translations/tradchinese.nsi
index 500d61917..d66abb388 100644
--- a/dist/windows/installer-translations/tradchinese.nsi
+++ b/dist/windows/installer-translations/tradchinese.nsi
@@ -30,8 +30,8 @@ LangString launch_qbt ${LANG_TRADCHINESE} "啟動 qBittorrent"
LangString inst_requires_64bit ${LANG_TRADCHINESE} "此安裝程式僅支援 64 位元版本的 Windows。"
;LangString inst_requires_win7 ${LANG_ENGLISH} "This qBittorrent version requires at least Windows 7."
LangString inst_requires_win7 ${LANG_TRADCHINESE} "此 qBittorrent 版本僅支援 Windows 7 以上的系統。"
-;LangString inst_requires_win10 ${LANG_ENGLISH} "This installer requires at least Windows 10 1809."
-LangString inst_requires_win10 ${LANG_TRADCHINESE} "This installer requires at least Windows 10 1809."
+;LangString inst_requires_win10 ${LANG_ENGLISH} "This installer requires at least Windows 10 (1809) / Windows Server 2019."
+LangString inst_requires_win10 ${LANG_TRADCHINESE} "This installer requires at least Windows 10 (1809) / Windows Server 2019."
;LangString inst_uninstall_link_description ${LANG_ENGLISH} "Uninstall qBittorrent"
LangString inst_uninstall_link_description ${LANG_TRADCHINESE} "移除 qBittorrent"
diff --git a/dist/windows/installer-translations/turkish.nsi b/dist/windows/installer-translations/turkish.nsi
index 63dc0b306..e7733a25f 100644
--- a/dist/windows/installer-translations/turkish.nsi
+++ b/dist/windows/installer-translations/turkish.nsi
@@ -30,8 +30,8 @@ LangString launch_qbt ${LANG_TURKISH} "qBittorrent'i başlat."
LangString inst_requires_64bit ${LANG_TURKISH} "Bu yükleyici sadece 64-bit Windows sürümlerinde çalışır."
;LangString inst_requires_win7 ${LANG_ENGLISH} "This qBittorrent version requires at least Windows 7."
LangString inst_requires_win7 ${LANG_TURKISH} "Bu qBittorrent sürümü en az Windows 7 gerektirir."
-;LangString inst_requires_win10 ${LANG_ENGLISH} "This installer requires at least Windows 10 1809."
-LangString inst_requires_win10 ${LANG_TURKISH} "Bu yükleyici en az Windows 10 1809 gerektirir."
+;LangString inst_requires_win10 ${LANG_ENGLISH} "This installer requires at least Windows 10 (1809) / Windows Server 2019."
+LangString inst_requires_win10 ${LANG_TURKISH} "Bu yükleyici en az Windows 10 (1809) / Windows Server 2019 gerektirir."
;LangString inst_uninstall_link_description ${LANG_ENGLISH} "Uninstall qBittorrent"
LangString inst_uninstall_link_description ${LANG_TURKISH} "qBittorrent'i kaldır"
diff --git a/dist/windows/installer-translations/ukrainian.nsi b/dist/windows/installer-translations/ukrainian.nsi
index 6d5377fd4..533e24dec 100644
--- a/dist/windows/installer-translations/ukrainian.nsi
+++ b/dist/windows/installer-translations/ukrainian.nsi
@@ -30,8 +30,8 @@ LangString launch_qbt ${LANG_UKRAINIAN} "Запустити qBittorrent."
LangString inst_requires_64bit ${LANG_UKRAINIAN} "Ця програма установки працює тільки в 64-розрядних версіях Windows."
;LangString inst_requires_win7 ${LANG_ENGLISH} "This qBittorrent version requires at least Windows 7."
LangString inst_requires_win7 ${LANG_UKRAINIAN} "This qBittorrent version requires at least Windows 7."
-;LangString inst_requires_win10 ${LANG_ENGLISH} "This installer requires at least Windows 10 1809."
-LangString inst_requires_win10 ${LANG_UKRAINIAN} "This installer requires at least Windows 10 1809."
+;LangString inst_requires_win10 ${LANG_ENGLISH} "This installer requires at least Windows 10 (1809) / Windows Server 2019."
+LangString inst_requires_win10 ${LANG_UKRAINIAN} "This installer requires at least Windows 10 (1809) / Windows Server 2019."
;LangString inst_uninstall_link_description ${LANG_ENGLISH} "Uninstall qBittorrent"
LangString inst_uninstall_link_description ${LANG_UKRAINIAN} "Uninstall qBittorrent"
diff --git a/dist/windows/installer-translations/uzbek.nsi b/dist/windows/installer-translations/uzbek.nsi
index 3b9fc1e08..671402075 100644
--- a/dist/windows/installer-translations/uzbek.nsi
+++ b/dist/windows/installer-translations/uzbek.nsi
@@ -30,8 +30,8 @@ LangString launch_qbt ${LANG_UZBEK} "qBittorrent ishga tushirilsin."
LangString inst_requires_64bit ${LANG_UZBEK} "Bu oʻrnatuvchi faqat Windows 64-bit versiyalarda ishlaydi."
;LangString inst_requires_win7 ${LANG_ENGLISH} "This qBittorrent version requires at least Windows 7."
LangString inst_requires_win7 ${LANG_UZBEK} "qBittorrent bu versiyasi kamida Windows 7 talab qiladi."
-;LangString inst_requires_win10 ${LANG_ENGLISH} "This installer requires at least Windows 10 1809."
-LangString inst_requires_win10 ${LANG_UZBEK} "Bu oʻrnatuvchi kamida Windows 10 1809 talab qiladi."
+;LangString inst_requires_win10 ${LANG_ENGLISH} "This installer requires at least Windows 10 (1809) / Windows Server 2019."
+LangString inst_requires_win10 ${LANG_UZBEK} "Bu oʻrnatuvchi kamida Windows 10 (1809) / Windows Server 2019 talab qiladi."
;LangString inst_uninstall_link_description ${LANG_ENGLISH} "Uninstall qBittorrent"
LangString inst_uninstall_link_description ${LANG_UZBEK} "qBittorrent oʻchirilsin"
diff --git a/dist/windows/installer-translations/welsh.nsi b/dist/windows/installer-translations/welsh.nsi
index ede9f37f3..efb37c554 100644
--- a/dist/windows/installer-translations/welsh.nsi
+++ b/dist/windows/installer-translations/welsh.nsi
@@ -30,8 +30,8 @@ LangString launch_qbt ${LANG_WELSH} "Launch qBittorrent."
LangString inst_requires_64bit ${LANG_WELSH} "This installer works only in 64-bit Windows versions."
;LangString inst_requires_win7 ${LANG_ENGLISH} "This qBittorrent version requires at least Windows 7."
LangString inst_requires_win7 ${LANG_WELSH} "This qBittorrent version requires at least Windows 7."
-;LangString inst_requires_win10 ${LANG_ENGLISH} "This installer requires at least Windows 10 1809."
-LangString inst_requires_win10 ${LANG_WELSH} "This installer requires at least Windows 10 1809."
+;LangString inst_requires_win10 ${LANG_ENGLISH} "This installer requires at least Windows 10 (1809) / Windows Server 2019."
+LangString inst_requires_win10 ${LANG_WELSH} "This installer requires at least Windows 10 (1809) / Windows Server 2019."
;LangString inst_uninstall_link_description ${LANG_ENGLISH} "Uninstall qBittorrent"
LangString inst_uninstall_link_description ${LANG_WELSH} "Uninstall qBittorrent"
diff --git a/dist/windows/installer.nsi b/dist/windows/installer.nsi
index 14edd1f1f..8f9311c4d 100644
--- a/dist/windows/installer.nsi
+++ b/dist/windows/installer.nsi
@@ -109,7 +109,7 @@ Section $(inst_torrent) ;"Open .torrent files with qBittorrent"
!insertmacro UAC_AsUser_Call Function inst_torrent_user ${UAC_SYNCREGISTERS}|${UAC_SYNCOUTDIR}|${UAC_SYNCINSTDIR}
- System::Call 'Shell32::SHChangeNotify(i ${SHCNE_ASSOCCHANGED}, i ${SHCNF_IDLIST}, i 0, i 0)'
+ System::Call 'Shell32::SHChangeNotify(i ${SHCNE_ASSOCCHANGED}, i ${SHCNF_IDLIST}, p 0, p 0)'
SectionEnd
@@ -142,7 +142,7 @@ Section $(inst_magnet) ;"Open magnet links with qBittorrent"
!insertmacro UAC_AsUser_Call Function inst_magnet_user ${UAC_SYNCREGISTERS}|${UAC_SYNCOUTDIR}|${UAC_SYNCINSTDIR}
- System::Call 'Shell32::SHChangeNotify(i ${SHCNE_ASSOCCHANGED}, i ${SHCNF_IDLIST}, i 0, i 0)'
+ System::Call 'Shell32::SHChangeNotify(i ${SHCNE_ASSOCCHANGED}, i ${SHCNF_IDLIST}, p 0, p 0)'
SectionEnd
@@ -183,7 +183,7 @@ Function .onInit
Abort
${EndIf}
!else
- ${IfNot} ${AtLeastWaaS} 1809 ; Windows 10 1809. Min supported version by Qt6
+ ${IfNot} ${AtLeastWaaS} 1809 ; Windows 10 (1809) / Windows Server 2019. Min supported version by Qt6
MessageBox MB_OK|MB_ICONEXCLAMATION $(inst_requires_win10)
Abort
${EndIf}
diff --git a/dist/windows/uninstaller.nsi b/dist/windows/uninstaller.nsi
index 64dee7dea..72a13749d 100644
--- a/dist/windows/uninstaller.nsi
+++ b/dist/windows/uninstaller.nsi
@@ -26,17 +26,17 @@ Section "un.$(remove_associations)" ;"un.Remove file associations"
DetailPrint "$(uninst_tor_warn) $0"
DeleteRegValue HKLM "Software\Classes\.torrent" ""
DeleteRegKey /ifempty HKLM "Software\Classes\.torrent"
-
torrent_end:
+
ReadRegStr $0 HKLM "Software\Classes\magnet\shell\open\command" ""
StrCmp $0 '"$INSTDIR\qbittorrent.exe" "%1"' 0 magnet_end
DetailPrint "$(uninst_mag_warn) $0"
DeleteRegKey HKLM "Software\Classes\magnet"
-
magnet_end:
+
!insertmacro UAC_AsUser_Call Function un.remove_associations_user ${UAC_SYNCREGISTERS}|${UAC_SYNCOUTDIR}|${UAC_SYNCINSTDIR}
- System::Call 'Shell32::SHChangeNotify(i ${SHCNE_ASSOCCHANGED}, i ${SHCNF_IDLIST}, i 0, i 0)'
+ System::Call 'Shell32::SHChangeNotify(i ${SHCNE_ASSOCCHANGED}, i ${SHCNF_IDLIST}, p 0, p 0)'
SectionEnd
Function un.remove_associations_user
@@ -45,13 +45,12 @@ Function un.remove_associations_user
DetailPrint "$(uninst_tor_warn) $0"
DeleteRegValue HKCU "Software\Classes\.torrent" ""
DeleteRegKey /ifempty HKCU "Software\Classes\.torrent"
-
torrent_end:
+
ReadRegStr $0 HKCU "Software\Classes\magnet\shell\open\command" ""
StrCmp $0 '"$INSTDIR\qbittorrent.exe" "%1"' 0 magnet_end
DetailPrint "$(uninst_mag_warn) $0"
DeleteRegKey HKCU "Software\Classes\magnet"
-
magnet_end:
FunctionEnd
@@ -62,7 +61,7 @@ Section "un.$(remove_registry)" ;"un.Remove registry keys"
DeleteRegKey HKLM "Software\qBittorrent"
DeleteRegKey HKLM "Software\Classes\qBittorrent"
- System::Call 'Shell32::SHChangeNotify(i ${SHCNE_ASSOCCHANGED}, i ${SHCNF_IDLIST}, i 0, i 0)'
+ System::Call 'Shell32::SHChangeNotify(i ${SHCNE_ASSOCCHANGED}, i ${SHCNF_IDLIST}, p 0, p 0)'
SectionEnd
Section "un.$(remove_firewall)" ;
diff --git a/src/app/application.cpp b/src/app/application.cpp
index 6abe0bdaa..e22f2f670 100644
--- a/src/app/application.cpp
+++ b/src/app/application.cpp
@@ -96,12 +96,18 @@
#include "gui/mainwindow.h"
#include "gui/shutdownconfirmdialog.h"
#include "gui/uithememanager.h"
-#include "gui/utils.h"
#include "gui/windowstate.h"
+
+#ifdef Q_OS_WIN
+#include "base/utils/os.h"
+#endif // Q_OS_WIN
#endif // DISABLE_GUI
#ifndef DISABLE_WEBUI
#include "webui/webui.h"
+#ifdef DISABLE_GUI
+#include "base/utils/password.h"
+#endif
#endif
namespace
@@ -306,8 +312,8 @@ Application::Application(int &argc, char **argv)
if (isFileLoggerEnabled())
m_fileLogger = new FileLogger(fileLoggerPath(), isFileLoggerBackup(), fileLoggerMaxSize(), isFileLoggerDeleteOld(), fileLoggerAge(), static_cast(fileLoggerAgeType()));
- if (m_commandLineArgs.webUiPort > 0) // it will be -1 when user did not set any value
- Preferences::instance()->setWebUiPort(m_commandLineArgs.webUiPort);
+ if (m_commandLineArgs.webUIPort > 0) // it will be -1 when user did not set any value
+ Preferences::instance()->setWebUIPort(m_commandLineArgs.webUIPort);
if (m_commandLineArgs.torrentingPort > 0) // it will be -1 when user did not set any value
{
@@ -371,7 +377,7 @@ void Application::setMemoryWorkingSetLimit(const int size)
return;
m_storeMemoryWorkingSetLimit = size;
-#ifdef QBT_USES_LIBTORRENT2
+#if defined(QBT_USES_LIBTORRENT2) && !defined(Q_OS_MACOS)
applyMemoryWorkingSetLimit();
#endif
}
@@ -763,14 +769,13 @@ void Application::processParams(const QBtCommandLineParameters ¶ms)
}
int Application::exec()
-try
{
#if !defined(DISABLE_WEBUI) && defined(DISABLE_GUI)
const QString loadingStr = tr("WebUI will be started shortly after internal preparations. Please wait...");
printf("%s\n", qUtf8Printable(loadingStr));
#endif
-#ifdef QBT_USES_LIBTORRENT2
+#if defined(QBT_USES_LIBTORRENT2) && !defined(Q_OS_MACOS)
applyMemoryWorkingSetLimit();
#endif
@@ -878,14 +883,14 @@ try
delete m_startupProgressDialog;
#ifdef Q_OS_WIN
auto *pref = Preferences::instance();
- if (!pref->neverCheckFileAssoc() && (!Preferences::isTorrentFileAssocSet() || !Preferences::isMagnetLinkAssocSet()))
+ if (!pref->neverCheckFileAssoc() && (!Utils::OS::isTorrentFileAssocSet() || !Utils::OS::isMagnetLinkAssocSet()))
{
if (QMessageBox::question(m_window, tr("Torrent file association")
, tr("qBittorrent is not the default application for opening torrent files or Magnet links.\nDo you want to make qBittorrent the default application for these?")
, QMessageBox::Yes | QMessageBox::No, QMessageBox::Yes) == QMessageBox::Yes)
{
- pref->setTorrentFileAssoc(true);
- pref->setMagnetLinkAssoc(true);
+ Utils::OS::setTorrentFileAssoc(true);
+ Utils::OS::setMagnetLinkAssoc(true);
}
else
{
@@ -896,25 +901,28 @@ try
#endif // DISABLE_GUI
#ifndef DISABLE_WEBUI
+#ifndef DISABLE_GUI
m_webui = new WebUI(this);
-#ifdef DISABLE_GUI
+#else
+ const Preferences *pref = Preferences::instance();
+ const QString tempPassword = pref->getWebUIPassword().isEmpty()
+ ? Utils::Password::generate() : QString();
+ m_webui = new WebUI(this, (!tempPassword.isEmpty() ? Utils::Password::PBKDF2::generate(tempPassword) : QByteArray()));
if (m_webui->isErrored())
QCoreApplication::exit(EXIT_FAILURE);
connect(m_webui, &WebUI::fatalError, this, []() { QCoreApplication::exit(EXIT_FAILURE); });
- const Preferences *pref = Preferences::instance();
-
- const auto scheme = pref->isWebUiHttpsEnabled() ? u"https"_s : u"http"_s;
- const auto url = u"%1://localhost:%2\n"_s.arg(scheme, QString::number(pref->getWebUiPort()));
+ const auto scheme = pref->isWebUIHttpsEnabled() ? u"https"_s : u"http"_s;
+ const auto url = u"%1://localhost:%2\n"_s.arg(scheme, QString::number(pref->getWebUIPort()));
const QString mesg = u"\n******** %1 ********\n"_s.arg(tr("Information"))
+ tr("To control qBittorrent, access the WebUI at: %1").arg(url);
printf("%s\n", qUtf8Printable(mesg));
- if (pref->getWebUIPassword() == QByteArrayLiteral("ARQ77eY1NUZaQsuDHbIMCA==:0WMRkYTUWVT9wVvdDtHAjU9b3b7uB8NR1Gur2hmQCvCDpm39Q+PsJRJPaCU51dEiz+dTzh8qbPsL8WkFljQYFQ=="))
+ if (!tempPassword.isEmpty())
{
- const QString warning = tr("The Web UI administrator username is: %1").arg(pref->getWebUiUsername()) + u'\n'
- + tr("The Web UI administrator password has not been changed from the default: %1").arg(u"adminadmin"_s) + u'\n'
- + tr("This is a security risk, please change your password in program preferences.") + u'\n';
+ const QString warning = tr("The WebUI administrator username is: %1").arg(pref->getWebUIUsername()) + u'\n'
+ + tr("The WebUI administrator password was not set. A temporary password is provided for this session: %1").arg(tempPassword) + u'\n'
+ + tr("You should set your own password in program preferences.") + u'\n';
printf("%s", qUtf8Printable(warning));
}
#endif // DISABLE_GUI
@@ -932,21 +940,6 @@ try
return BaseApplication::exec();
}
-catch (const RuntimeError &err)
-{
-#ifdef DISABLE_GUI
- fprintf(stderr, "%s", qPrintable(err.message()));
-#else
- QMessageBox msgBox;
- msgBox.setIcon(QMessageBox::Critical);
- msgBox.setText(QCoreApplication::translate("Application", "Application failed to start."));
- msgBox.setInformativeText(err.message());
- msgBox.show(); // Need to be shown or to moveToCenter does not work
- msgBox.move(Utils::Gui::screenCenter(&msgBox));
- msgBox.exec();
-#endif
- return EXIT_FAILURE;
-}
bool Application::isRunning()
{
@@ -1092,7 +1085,7 @@ void Application::shutdownCleanup(QSessionManager &manager)
}
#endif
-#ifdef QBT_USES_LIBTORRENT2
+#if defined(QBT_USES_LIBTORRENT2) && !defined(Q_OS_MACOS)
void Application::applyMemoryWorkingSetLimit() const
{
const size_t MiB = 1024 * 1024;
@@ -1312,3 +1305,10 @@ void Application::cleanup()
Utils::Misc::shutdownComputer(m_shutdownAct);
}
}
+
+#ifndef DISABLE_WEBUI
+WebUI *Application::webUI() const
+{
+ return m_webui;
+}
+#endif
diff --git a/src/app/application.h b/src/app/application.h
index ee69f5afc..6d73c8c9a 100644
--- a/src/app/application.h
+++ b/src/app/application.h
@@ -149,12 +149,16 @@ private slots:
#endif
private:
+#ifndef DISABLE_WEBUI
+ WebUI *webUI() const override;
+#endif
+
void initializeTranslation();
void processParams(const QBtCommandLineParameters ¶ms);
void runExternalProgram(const QString &programTemplate, const BitTorrent::Torrent *torrent) const;
void sendNotificationEmail(const BitTorrent::Torrent *torrent);
-#ifdef QBT_USES_LIBTORRENT2
+#if defined(QBT_USES_LIBTORRENT2) && !defined(Q_OS_MACOS)
void applyMemoryWorkingSetLimit() const;
#endif
diff --git a/src/app/cmdoptions.cpp b/src/app/cmdoptions.cpp
index 0b993c3a6..6601f1edc 100644
--- a/src/app/cmdoptions.cpp
+++ b/src/app/cmdoptions.cpp
@@ -349,7 +349,7 @@ QBtCommandLineParameters::QBtCommandLineParameters(const QProcessEnvironment &en
#elif !defined(Q_OS_WIN)
, shouldDaemonize(DAEMON_OPTION.value(env))
#endif
- , webUiPort(WEBUI_PORT_OPTION.value(env, -1))
+ , webUIPort(WEBUI_PORT_OPTION.value(env, -1))
, torrentingPort(TORRENTING_PORT_OPTION.value(env, -1))
, skipDialog(SKIP_DIALOG_OPTION.value(env))
, profileDir(PROFILE_OPTION.value(env))
@@ -373,7 +373,7 @@ QBtCommandLineParameters parseCommandLine(const QStringList &args)
if ((arg.startsWith(u"--") && !arg.endsWith(u".torrent"))
|| (arg.startsWith(u'-') && (arg.size() == 2)))
- {
+ {
// Parse known parameters
if (arg == SHOW_HELP_OPTION)
{
@@ -387,8 +387,8 @@ QBtCommandLineParameters parseCommandLine(const QStringList &args)
#endif
else if (arg == WEBUI_PORT_OPTION)
{
- result.webUiPort = WEBUI_PORT_OPTION.value(arg);
- if ((result.webUiPort < 1) || (result.webUiPort > 65535))
+ result.webUIPort = WEBUI_PORT_OPTION.value(arg);
+ if ((result.webUIPort < 1) || (result.webUIPort > 65535))
throw CommandLineParameterError(QCoreApplication::translate("CMD Options", "%1 must specify a valid port (1 to 65535).")
.arg(u"--webui-port"_s));
}
@@ -509,7 +509,7 @@ QString makeUsage(const QString &prgName)
#endif
+ SHOW_HELP_OPTION.usage() + wrapText(QCoreApplication::translate("CMD Options", "Display this help message and exit")) + u'\n'
+ WEBUI_PORT_OPTION.usage(QCoreApplication::translate("CMD Options", "port"))
- + wrapText(QCoreApplication::translate("CMD Options", "Change the Web UI port"))
+ + wrapText(QCoreApplication::translate("CMD Options", "Change the WebUI port"))
+ u'\n'
+ TORRENTING_PORT_OPTION.usage(QCoreApplication::translate("CMD Options", "port"))
+ wrapText(QCoreApplication::translate("CMD Options", "Change the torrenting port"))
diff --git a/src/app/cmdoptions.h b/src/app/cmdoptions.h
index 8817f4708..1c133c413 100644
--- a/src/app/cmdoptions.h
+++ b/src/app/cmdoptions.h
@@ -53,7 +53,7 @@ struct QBtCommandLineParameters
#elif !defined(Q_OS_WIN)
bool shouldDaemonize = false;
#endif
- int webUiPort = -1;
+ int webUIPort = -1;
int torrentingPort = -1;
std::optional skipDialog;
Path profileDir;
diff --git a/src/app/main.cpp b/src/app/main.cpp
index 1e95075f4..31e744732 100644
--- a/src/app/main.cpp
+++ b/src/app/main.cpp
@@ -46,7 +46,7 @@
#endif
#include
-#include
+#include
#include
#ifndef DISABLE_GUI
@@ -86,6 +86,7 @@ using namespace std::chrono_literals;
void displayVersion();
bool userAgreesWithLegalNotice();
void displayBadArgMessage(const QString &message);
+void displayErrorMessage(const QString &message);
#ifndef DISABLE_GUI
void showSplashScreen();
@@ -98,6 +99,10 @@ void adjustFileDescriptorLimit();
// Main
int main(int argc, char *argv[])
{
+#ifdef DISABLE_GUI
+ setvbuf(stdout, nullptr, _IONBF, 0);
+#endif
+
#ifdef Q_OS_UNIX
adjustFileDescriptorLimit();
#endif
@@ -114,10 +119,12 @@ int main(int argc, char *argv[])
Application::setHighDpiScaleFactorRoundingPolicy(Qt::HighDpiScaleFactorRoundingPolicy::PassThrough);
#endif
+ // `app` must be declared out of try block to allow display message box in case of exception
+ std::unique_ptr app;
try
{
// Create Application
- auto app = std::make_unique(argc, argv);
+ app = std::make_unique(argc, argv);
#ifdef Q_OS_WIN
// QCoreApplication::applicationDirPath() needs an Application object instantiated first
@@ -268,7 +275,7 @@ int main(int argc, char *argv[])
}
catch (const RuntimeError &er)
{
- qDebug() << er.message();
+ displayErrorMessage(er.message());
return EXIT_FAILURE;
}
}
@@ -311,6 +318,30 @@ void displayBadArgMessage(const QString &message)
#endif
}
+void displayErrorMessage(const QString &message)
+{
+#ifndef DISABLE_GUI
+ if (QApplication::instance())
+ {
+ QMessageBox msgBox;
+ msgBox.setIcon(QMessageBox::Critical);
+ msgBox.setText(QCoreApplication::translate("Main", "An unrecoverable error occurred."));
+ msgBox.setInformativeText(message);
+ msgBox.show(); // Need to be shown or to moveToCenter does not work
+ msgBox.move(Utils::Gui::screenCenter(&msgBox));
+ msgBox.exec();
+ }
+ else
+ {
+ const QString errMsg = QCoreApplication::translate("Main", "qBittorrent has encountered an unrecoverable error.") + u'\n' + message + u'\n';
+ fprintf(stderr, "%s", qUtf8Printable(errMsg));
+ }
+#else
+ const QString errMsg = QCoreApplication::translate("Main", "qBittorrent has encountered an unrecoverable error.") + u'\n' + message + u'\n';
+ fprintf(stderr, "%s", qUtf8Printable(errMsg));
+#endif
+}
+
bool userAgreesWithLegalNotice()
{
Preferences *const pref = Preferences::instance();
diff --git a/src/app/signalhandler.cpp b/src/app/signalhandler.cpp
index 36d24bcec..be70f254d 100644
--- a/src/app/signalhandler.cpp
+++ b/src/app/signalhandler.cpp
@@ -43,6 +43,7 @@
#endif
#include
+#include
#include "base/version.h"
@@ -89,7 +90,7 @@ namespace
const char *msgs[] = {"Catching signal: ", sysSigName[signum], "\nExiting cleanly\n"};
std::for_each(std::begin(msgs), std::end(msgs), safePrint);
signal(signum, SIG_DFL);
- QCoreApplication::exit(); // unsafe, but exit anyway
+ QMetaObject::invokeMethod(qApp, [] { QCoreApplication::exit(); }, Qt::QueuedConnection); // unsafe, but exit anyway
}
#ifdef STACKTRACE
diff --git a/src/base/CMakeLists.txt b/src/base/CMakeLists.txt
index 2403c2e11..36825a283 100644
--- a/src/base/CMakeLists.txt
+++ b/src/base/CMakeLists.txt
@@ -99,6 +99,7 @@ add_library(qbt_base STATIC
utils/io.h
utils/misc.h
utils/net.h
+ utils/os.h
utils/password.h
utils/random.h
utils/string.h
@@ -184,6 +185,7 @@ add_library(qbt_base STATIC
utils/io.cpp
utils/misc.cpp
utils/net.cpp
+ utils/os.cpp
utils/password.cpp
utils/random.cpp
utils/string.cpp
diff --git a/src/base/base.pri b/src/base/base.pri
index e6fd1ca3b..7c1d3af57 100644
--- a/src/base/base.pri
+++ b/src/base/base.pri
@@ -99,6 +99,7 @@ HEADERS += \
$$PWD/utils/io.h \
$$PWD/utils/misc.h \
$$PWD/utils/net.h \
+ $$PWD/utils/os.h \
$$PWD/utils/password.h \
$$PWD/utils/random.h \
$$PWD/utils/string.h \
@@ -184,6 +185,7 @@ SOURCES += \
$$PWD/utils/io.cpp \
$$PWD/utils/misc.cpp \
$$PWD/utils/net.cpp \
+ $$PWD/utils/os.cpp \
$$PWD/utils/password.cpp \
$$PWD/utils/random.cpp \
$$PWD/utils/string.cpp \
diff --git a/src/base/bittorrent/dbresumedatastorage.cpp b/src/base/bittorrent/dbresumedatastorage.cpp
index cd360aef0..784c493f2 100644
--- a/src/base/bittorrent/dbresumedatastorage.cpp
+++ b/src/base/bittorrent/dbresumedatastorage.cpp
@@ -288,7 +288,7 @@ namespace BitTorrent
Q_DISABLE_COPY_MOVE(Worker)
public:
- Worker(const Path &dbPath, QReadWriteLock &dbLock);
+ Worker(const Path &dbPath, QReadWriteLock &dbLock, QObject *parent = nullptr);
void run() override;
void requestInterruption();
@@ -332,7 +332,7 @@ BitTorrent::DBResumeDataStorage::DBResumeDataStorage(const Path &dbPath, QObject
updateDB(dbVersion);
}
- m_asyncWorker = new Worker(dbPath, m_dbLock);
+ m_asyncWorker = new Worker(dbPath, m_dbLock, this);
m_asyncWorker->start();
}
@@ -611,10 +611,15 @@ void BitTorrent::DBResumeDataStorage::updateDB(const int fromVersion) const
if (fromVersion <= 4)
{
- const auto alterTableTorrentsQuery = u"ALTER TABLE %1 ADD %2"_s
- .arg(quoted(DB_TABLE_TORRENTS), makeColumnDefinition(DB_COLUMN_INACTIVE_SEEDING_TIME_LIMIT, "INTEGER NOT NULL DEFAULT -2"));
- if (!query.exec(alterTableTorrentsQuery))
- throw RuntimeError(query.lastError().text());
+ const auto testQuery = u"SELECT COUNT(%1) FROM %2;"_s
+ .arg(quoted(DB_COLUMN_INACTIVE_SEEDING_TIME_LIMIT.name), quoted(DB_TABLE_TORRENTS));
+ if (!query.exec(testQuery))
+ {
+ const auto alterTableTorrentsQuery = u"ALTER TABLE %1 ADD %2"_s
+ .arg(quoted(DB_TABLE_TORRENTS), makeColumnDefinition(DB_COLUMN_INACTIVE_SEEDING_TIME_LIMIT, "INTEGER NOT NULL DEFAULT -2"));
+ if (!query.exec(alterTableTorrentsQuery))
+ throw RuntimeError(query.lastError().text());
+ }
}
const QString updateMetaVersionQuery = makeUpdateStatement(DB_TABLE_META, {DB_COLUMN_NAME, DB_COLUMN_VALUE});
@@ -653,8 +658,9 @@ void BitTorrent::DBResumeDataStorage::enableWALMode() const
throw RuntimeError(tr("WAL mode is probably unsupported due to filesystem limitations."));
}
-BitTorrent::DBResumeDataStorage::Worker::Worker(const Path &dbPath, QReadWriteLock &dbLock)
- : m_path {dbPath}
+BitTorrent::DBResumeDataStorage::Worker::Worker(const Path &dbPath, QReadWriteLock &dbLock, QObject *parent)
+ : QThread(parent)
+ , m_path {dbPath}
, m_dbLock {dbLock}
{
}
diff --git a/src/base/bittorrent/sessionimpl.cpp b/src/base/bittorrent/sessionimpl.cpp
index e021a5453..725ad7735 100644
--- a/src/base/bittorrent/sessionimpl.cpp
+++ b/src/base/bittorrent/sessionimpl.cpp
@@ -2227,6 +2227,8 @@ void SessionImpl::processShareLimits()
torrent->setSuperSeeding(true);
LogMsg(u"%1 %2 %3"_s.arg(description, tr("Super seeding enabled."), torrentName));
}
+
+ continue;
}
}
}
@@ -2435,6 +2437,11 @@ bool SessionImpl::cancelDownloadMetadata(const TorrentID &id)
return false;
const lt::torrent_handle nativeHandle = downloadedMetadataIter.value();
+ m_downloadedMetadata.erase(downloadedMetadataIter);
+
+ if (!nativeHandle.is_valid())
+ return true;
+
#ifdef QBT_USES_LIBTORRENT2
const InfoHash infoHash {nativeHandle.info_hashes()};
if (infoHash.isHybrid())
@@ -2445,7 +2452,7 @@ bool SessionImpl::cancelDownloadMetadata(const TorrentID &id)
m_downloadedMetadata.remove((altID == downloadedMetadataIter.key()) ? id : altID);
}
#endif
- m_downloadedMetadata.erase(downloadedMetadataIter);
+
m_nativeSession->remove_torrent(nativeHandle, lt::session::delete_files);
return true;
}
@@ -2950,7 +2957,7 @@ bool SessionImpl::addTorrent_impl(const std::variant &so
}
void SessionImpl::findIncompleteFiles(const TorrentInfo &torrentInfo, const Path &savePath
- , const Path &downloadPath, const PathList &filePaths) const
+ , const Path &downloadPath, const PathList &filePaths) const
{
Q_ASSERT(filePaths.isEmpty() || (filePaths.size() == torrentInfo.filesCount()));
@@ -3143,8 +3150,16 @@ void SessionImpl::generateResumeData()
void SessionImpl::saveResumeData()
{
for (const TorrentImpl *torrent : asConst(m_torrents))
- torrent->nativeHandle().save_resume_data(lt::torrent_handle::only_if_modified);
- m_numResumeData += m_torrents.size();
+ {
+ // When the session is terminated due to unrecoverable error
+ // some of the torrent handles can be corrupted
+ try
+ {
+ torrent->nativeHandle().save_resume_data(lt::torrent_handle::only_if_modified);
+ ++m_numResumeData;
+ }
+ catch (const std::exception &) {}
+ }
// clear queued storage move jobs except the current ongoing one
if (m_moveStorageQueue.size() > 1)
@@ -5547,10 +5562,13 @@ void SessionImpl::handleAlert(const lt::alert *a)
dispatchTorrentAlert(static_cast(a));
break;
case lt::state_update_alert::alert_type:
- handleStateUpdateAlert(static_cast(a));
+ handleStateUpdateAlert(static_cast(a));
+ break;
+ case lt::session_error_alert::alert_type:
+ handleSessionErrorAlert(static_cast(a));
break;
case lt::session_stats_alert::alert_type:
- handleSessionStatsAlert(static_cast(a));
+ handleSessionStatsAlert(static_cast(a));
break;
case lt::tracker_announce_alert::alert_type:
case lt::tracker_error_alert::alert_type:
@@ -5559,56 +5577,59 @@ void SessionImpl::handleAlert(const lt::alert *a)
handleTrackerAlert(static_cast(a));
break;
case lt::file_error_alert::alert_type:
- handleFileErrorAlert(static_cast(a));
+ handleFileErrorAlert(static_cast(a));
break;
case lt::add_torrent_alert::alert_type:
// handled separately
break;
case lt::torrent_removed_alert::alert_type:
- handleTorrentRemovedAlert(static_cast(a));
+ handleTorrentRemovedAlert(static_cast(a));
break;
case lt::torrent_deleted_alert::alert_type:
- handleTorrentDeletedAlert(static_cast(a));
+ handleTorrentDeletedAlert(static_cast(a));
break;
case lt::torrent_delete_failed_alert::alert_type:
- handleTorrentDeleteFailedAlert(static_cast(a));
+ handleTorrentDeleteFailedAlert(static_cast(a));
break;
case lt::portmap_error_alert::alert_type:
- handlePortmapWarningAlert(static_cast(a));
+ handlePortmapWarningAlert(static_cast(a));
break;
case lt::portmap_alert::alert_type:
- handlePortmapAlert(static_cast(a));
+ handlePortmapAlert(static_cast(a));
break;
case lt::peer_blocked_alert::alert_type:
- handlePeerBlockedAlert(static_cast(a));
+ handlePeerBlockedAlert(static_cast(a));
break;
case lt::peer_ban_alert::alert_type:
- handlePeerBanAlert(static_cast(a));
+ handlePeerBanAlert(static_cast(a));
break;
case lt::url_seed_alert::alert_type:
- handleUrlSeedAlert(static_cast(a));
+ handleUrlSeedAlert(static_cast(a));
break;
case lt::listen_succeeded_alert::alert_type:
- handleListenSucceededAlert(static_cast(a));
+ handleListenSucceededAlert(static_cast(a));
break;
case lt::listen_failed_alert::alert_type:
- handleListenFailedAlert(static_cast(a));
+ handleListenFailedAlert(static_cast(a));
break;
case lt::external_ip_alert::alert_type:
- handleExternalIPAlert(static_cast(a));
+ handleExternalIPAlert(static_cast(a));
break;
case lt::alerts_dropped_alert::alert_type:
handleAlertsDroppedAlert(static_cast(a));
break;
case lt::storage_moved_alert::alert_type:
- handleStorageMovedAlert(static_cast(a));
+ handleStorageMovedAlert(static_cast(a));
break;
case lt::storage_moved_failed_alert::alert_type:
- handleStorageMovedFailedAlert(static_cast(a));
+ handleStorageMovedFailedAlert(static_cast(a));
break;
case lt::socks5_alert::alert_type:
handleSocks5Alert(static_cast(a));
break;
+ case lt::i2p_alert::alert_type:
+ handleI2PAlert(static_cast(a));
+ break;
#ifdef QBT_USES_LIBTORRENT2
case lt::torrent_conflict_alert::alert_type:
handleTorrentConflictAlert(static_cast(a));
@@ -5915,6 +5936,12 @@ void SessionImpl::handleExternalIPAlert(const lt::external_ip_alert *p)
}
}
+void SessionImpl::handleSessionErrorAlert(const lt::session_error_alert *p) const
+{
+ LogMsg(tr("BitTorrent session encountered a serious error. Reason: \"%1\"")
+ .arg(QString::fromStdString(p->message())), Log::CRITICAL);
+}
+
void SessionImpl::handleSessionStatsAlert(const lt::session_stats_alert *p)
{
if (m_refreshEnqueued)
@@ -6109,6 +6136,15 @@ void SessionImpl::handleSocks5Alert(const lt::socks5_alert *p) const
}
}
+void SessionImpl::handleI2PAlert(const lt::i2p_alert *p) const
+{
+ if (p->error)
+ {
+ LogMsg(tr("I2P error. Message: \"%1\".")
+ .arg(QString::fromStdString(p->message())), Log::WARNING);
+ }
+}
+
void SessionImpl::handleTrackerAlert(const lt::tracker_alert *a)
{
TorrentImpl *torrent = m_torrents.value(a->handle.info_hash());
diff --git a/src/base/bittorrent/sessionimpl.h b/src/base/bittorrent/sessionimpl.h
index f75879019..a8c1f967b 100644
--- a/src/base/bittorrent/sessionimpl.h
+++ b/src/base/bittorrent/sessionimpl.h
@@ -564,11 +564,13 @@ namespace BitTorrent
void handleListenSucceededAlert(const lt::listen_succeeded_alert *p);
void handleListenFailedAlert(const lt::listen_failed_alert *p);
void handleExternalIPAlert(const lt::external_ip_alert *p);
+ void handleSessionErrorAlert(const lt::session_error_alert *p) const;
void handleSessionStatsAlert(const lt::session_stats_alert *p);
void handleAlertsDroppedAlert(const lt::alerts_dropped_alert *p) const;
void handleStorageMovedAlert(const lt::storage_moved_alert *p);
void handleStorageMovedFailedAlert(const lt::storage_moved_failed_alert *p);
void handleSocks5Alert(const lt::socks5_alert *p) const;
+ void handleI2PAlert(const lt::i2p_alert *p) const;
void handleTrackerAlert(const lt::tracker_alert *a);
#ifdef QBT_USES_LIBTORRENT2
void handleTorrentConflictAlert(const lt::torrent_conflict_alert *a);
diff --git a/src/base/bittorrent/torrentimpl.cpp b/src/base/bittorrent/torrentimpl.cpp
index 86a4e1147..7cab602d7 100644
--- a/src/base/bittorrent/torrentimpl.cpp
+++ b/src/base/bittorrent/torrentimpl.cpp
@@ -51,6 +51,7 @@
#include
#include
+#include "base/exceptions.h"
#include "base/global.h"
#include "base/logger.h"
#include "base/preferences.h"
@@ -599,6 +600,9 @@ void TorrentImpl::replaceTrackers(QVector trackers)
{
// TODO: use std::erase_if() in C++20
trackers.erase(std::remove_if(trackers.begin(), trackers.end(), [](const TrackerEntry &entry) { return entry.url.isEmpty(); }), trackers.end());
+ // Filter out duplicate trackers
+ const auto uniqueTrackers = QSet(trackers.cbegin(), trackers.cend());
+ trackers = QVector(uniqueTrackers.cbegin(), uniqueTrackers.cend());
std::sort(trackers.begin(), trackers.end()
, [](const TrackerEntry &lhs, const TrackerEntry &rhs) { return lhs.tier < rhs.tier; });
@@ -1602,7 +1606,8 @@ void TorrentImpl::applyFirstLastPiecePriority(const bool enabled)
void TorrentImpl::fileSearchFinished(const Path &savePath, const PathList &fileNames)
{
- endReceivedMetadataHandling(savePath, fileNames);
+ if (m_maintenanceJob == MaintenanceJob::HandleMetadata)
+ endReceivedMetadataHandling(savePath, fileNames);
}
TrackerEntry TorrentImpl::updateTrackerEntry(const lt::announce_entry &announceEntry, const QMap &updateInfo)
@@ -1635,7 +1640,13 @@ std::shared_ptr TorrentImpl::nativeTorrentInfo()
void TorrentImpl::endReceivedMetadataHandling(const Path &savePath, const PathList &fileNames)
{
+ Q_ASSERT(m_maintenanceJob == MaintenanceJob::HandleMetadata);
+ if (Q_UNLIKELY(m_maintenanceJob != MaintenanceJob::HandleMetadata))
+ return;
+
Q_ASSERT(m_filePaths.isEmpty());
+ if (Q_UNLIKELY(!m_filePaths.isEmpty()))
+ m_filePaths.clear();
lt::add_torrent_params &p = m_ltAddTorrentParams;
@@ -1644,7 +1655,7 @@ void TorrentImpl::endReceivedMetadataHandling(const Path &savePath, const PathLi
m_filePriorities.reserve(filesCount());
const auto nativeIndexes = m_torrentInfo.nativeIndexes();
p.file_priorities = resized(p.file_priorities, metadata->files().num_files()
- , LT::toNative(p.file_priorities.empty() ? DownloadPriority::Normal : DownloadPriority::Ignored));
+ , LT::toNative(p.file_priorities.empty() ? DownloadPriority::Normal : DownloadPriority::Ignored));
m_completedFiles.fill(static_cast(p.flags & lt::torrent_flags::seed_mode), filesCount());
m_filesProgress.resize(filesCount());
@@ -1694,6 +1705,7 @@ void TorrentImpl::endReceivedMetadataHandling(const Path &savePath, const PathLi
}
void TorrentImpl::reload()
+try
{
m_completedFiles.fill(false);
m_filesProgress.fill(0);
@@ -1736,6 +1748,11 @@ void TorrentImpl::reload()
updateState();
}
+catch (const lt::system_error &err)
+{
+ throw RuntimeError(tr("Failed to reload torrent. Torrent: %1. Reason: %2")
+ .arg(id().toString(), QString::fromLocal8Bit(err.what())));
+}
void TorrentImpl::pause()
{
@@ -1794,6 +1811,7 @@ void TorrentImpl::moveStorage(const Path &newPath, const MoveStorageContext cont
{
if (!hasMetadata())
{
+ m_savePath = newPath;
m_session->handleTorrentSavePathChanged(this);
return;
}
diff --git a/src/base/interfaces/iapplication.h b/src/base/interfaces/iapplication.h
index 3942fd9d0..a020692f8 100644
--- a/src/base/interfaces/iapplication.h
+++ b/src/base/interfaces/iapplication.h
@@ -36,6 +36,7 @@
class QString;
class Path;
+class WebUI;
struct QBtCommandLineParameters;
#ifdef Q_OS_WIN
@@ -83,4 +84,8 @@ public:
virtual MemoryPriority processMemoryPriority() const = 0;
virtual void setProcessMemoryPriority(MemoryPriority priority) = 0;
#endif
+
+#ifndef DISABLE_WEBUI
+ virtual WebUI *webUI() const = 0;
+#endif
};
diff --git a/src/base/net/downloadmanager.cpp b/src/base/net/downloadmanager.cpp
index 7669af79f..ea57d15cf 100644
--- a/src/base/net/downloadmanager.cpp
+++ b/src/base/net/downloadmanager.cpp
@@ -62,11 +62,10 @@ public:
{
const QDateTime now = QDateTime::currentDateTime();
QList cookies = Preferences::instance()->getNetworkCookies();
- for (const QNetworkCookie &cookie : asConst(Preferences::instance()->getNetworkCookies()))
+ cookies.erase(std::remove_if(cookies.begin(), cookies.end(), [&now](const QNetworkCookie &cookie)
{
- if (cookie.isSessionCookie() || (cookie.expirationDate() <= now))
- cookies.removeAll(cookie);
- }
+ return cookie.isSessionCookie() || (cookie.expirationDate() <= now);
+ }), cookies.end());
setAllCookies(cookies);
}
@@ -75,11 +74,10 @@ public:
{
const QDateTime now = QDateTime::currentDateTime();
QList cookies = allCookies();
- for (const QNetworkCookie &cookie : asConst(allCookies()))
+ cookies.erase(std::remove_if(cookies.begin(), cookies.end(), [&now](const QNetworkCookie &cookie)
{
- if (cookie.isSessionCookie() || (cookie.expirationDate() <= now))
- cookies.removeAll(cookie);
- }
+ return cookie.isSessionCookie() || (cookie.expirationDate() <= now);
+ }), cookies.end());
Preferences::instance()->setNetworkCookies(cookies);
}
@@ -91,11 +89,10 @@ public:
{
const QDateTime now = QDateTime::currentDateTime();
QList cookies = QNetworkCookieJar::cookiesForUrl(url);
- for (const QNetworkCookie &cookie : asConst(QNetworkCookieJar::cookiesForUrl(url)))
+ cookies.erase(std::remove_if(cookies.begin(), cookies.end(), [&now](const QNetworkCookie &cookie)
{
- if (!cookie.isSessionCookie() && (cookie.expirationDate() <= now))
- cookies.removeAll(cookie);
- }
+ return !cookie.isSessionCookie() && (cookie.expirationDate() <= now);
+ }), cookies.end());
return cookies;
}
@@ -104,11 +101,10 @@ public:
{
const QDateTime now = QDateTime::currentDateTime();
QList cookies = cookieList;
- for (const QNetworkCookie &cookie : cookieList)
+ cookies.erase(std::remove_if(cookies.begin(), cookies.end(), [&now](const QNetworkCookie &cookie)
{
- if (!cookie.isSessionCookie() && (cookie.expirationDate() <= now))
- cookies.removeAll(cookie);
- }
+ return !cookie.isSessionCookie() && (cookie.expirationDate() <= now);
+ }), cookies.end());
return QNetworkCookieJar::setCookiesFromUrl(cookies, url);
}
diff --git a/src/base/preferences.cpp b/src/base/preferences.cpp
index 331983640..4555247fb 100644
--- a/src/base/preferences.cpp
+++ b/src/base/preferences.cpp
@@ -31,13 +31,6 @@
#include
-#ifdef Q_OS_MACOS
-#include
-#endif
-#ifdef Q_OS_WIN
-#include
-#endif
-
#include
#include
#include
@@ -47,10 +40,6 @@
#include
#include
-#ifdef Q_OS_WIN
-#include
-#endif
-
#include "algorithm.h"
#include "global.h"
#include "path.h"
@@ -639,7 +628,7 @@ void Preferences::setSearchEnabled(const bool enabled)
setValue(u"Preferences/Search/SearchEnabled"_s, enabled);
}
-bool Preferences::isWebUiEnabled() const
+bool Preferences::isWebUIEnabled() const
{
#ifdef DISABLE_GUI
const bool defaultValue = true;
@@ -649,41 +638,41 @@ bool Preferences::isWebUiEnabled() const
return value(u"Preferences/WebUI/Enabled"_s, defaultValue);
}
-void Preferences::setWebUiEnabled(const bool enabled)
+void Preferences::setWebUIEnabled(const bool enabled)
{
- if (enabled == isWebUiEnabled())
+ if (enabled == isWebUIEnabled())
return;
setValue(u"Preferences/WebUI/Enabled"_s, enabled);
}
-bool Preferences::isWebUiLocalAuthEnabled() const
+bool Preferences::isWebUILocalAuthEnabled() const
{
return value(u"Preferences/WebUI/LocalHostAuth"_s, true);
}
-void Preferences::setWebUiLocalAuthEnabled(const bool enabled)
+void Preferences::setWebUILocalAuthEnabled(const bool enabled)
{
- if (enabled == isWebUiLocalAuthEnabled())
+ if (enabled == isWebUILocalAuthEnabled())
return;
setValue(u"Preferences/WebUI/LocalHostAuth"_s, enabled);
}
-bool Preferences::isWebUiAuthSubnetWhitelistEnabled() const
+bool Preferences::isWebUIAuthSubnetWhitelistEnabled() const
{
return value(u"Preferences/WebUI/AuthSubnetWhitelistEnabled"_s, false);
}
-void Preferences::setWebUiAuthSubnetWhitelistEnabled(const bool enabled)
+void Preferences::setWebUIAuthSubnetWhitelistEnabled(const bool enabled)
{
- if (enabled == isWebUiAuthSubnetWhitelistEnabled())
+ if (enabled == isWebUIAuthSubnetWhitelistEnabled())
return;
setValue(u"Preferences/WebUI/AuthSubnetWhitelistEnabled"_s, enabled);
}
-QVector Preferences::getWebUiAuthSubnetWhitelist() const
+QVector Preferences::getWebUIAuthSubnetWhitelist() const
{
const auto subnets = value(u"Preferences/WebUI/AuthSubnetWhitelist"_s);
@@ -700,7 +689,7 @@ QVector Preferences::getWebUiAuthSubnetWhitelist() const
return ret;
}
-void Preferences::setWebUiAuthSubnetWhitelist(QStringList subnets)
+void Preferences::setWebUIAuthSubnetWhitelist(QStringList subnets)
{
Algorithm::removeIf(subnets, [](const QString &subnet)
{
@@ -723,27 +712,27 @@ void Preferences::setServerDomains(const QString &str)
setValue(u"Preferences/WebUI/ServerDomains"_s, str);
}
-QString Preferences::getWebUiAddress() const
+QString Preferences::getWebUIAddress() const
{
return value(u"Preferences/WebUI/Address"_s, u"*"_s).trimmed();
}
-void Preferences::setWebUiAddress(const QString &addr)
+void Preferences::setWebUIAddress(const QString &addr)
{
- if (addr == getWebUiAddress())
+ if (addr == getWebUIAddress())
return;
setValue(u"Preferences/WebUI/Address"_s, addr.trimmed());
}
-quint16 Preferences::getWebUiPort() const
+quint16 Preferences::getWebUIPort() const
{
return value(u"Preferences/WebUI/Port"_s, 8080);
}
-void Preferences::setWebUiPort(const quint16 port)
+void Preferences::setWebUIPort(const quint16 port)
{
- if (port == getWebUiPort())
+ if (port == getWebUIPort())
return;
// cast to `int` type so it will show human readable unit in configuration file
@@ -763,14 +752,14 @@ void Preferences::setUPnPForWebUIPort(const bool enabled)
setValue(u"Preferences/WebUI/UseUPnP"_s, enabled);
}
-QString Preferences::getWebUiUsername() const
+QString Preferences::getWebUIUsername() const
{
return value(u"Preferences/WebUI/Username"_s, u"admin"_s);
}
-void Preferences::setWebUiUsername(const QString &username)
+void Preferences::setWebUIUsername(const QString &username)
{
- if (username == getWebUiUsername())
+ if (username == getWebUIUsername())
return;
setValue(u"Preferences/WebUI/Username"_s, username);
@@ -778,9 +767,7 @@ void Preferences::setWebUiUsername(const QString &username)
QByteArray Preferences::getWebUIPassword() const
{
- // default: adminadmin
- const auto defaultValue = QByteArrayLiteral("ARQ77eY1NUZaQsuDHbIMCA==:0WMRkYTUWVT9wVvdDtHAjU9b3b7uB8NR1Gur2hmQCvCDpm39Q+PsJRJPaCU51dEiz+dTzh8qbPsL8WkFljQYFQ==");
- return value(u"Preferences/WebUI/Password_PBKDF2"_s, defaultValue);
+ return value(u"Preferences/WebUI/Password_PBKDF2"_s);
}
void Preferences::setWebUIPassword(const QByteArray &password)
@@ -843,40 +830,40 @@ void Preferences::setWebAPISessionCookieName(const QString &cookieName)
setValue(u"WebAPI/SessionCookieName"_s, cookieName);
}
-bool Preferences::isWebUiClickjackingProtectionEnabled() const
+bool Preferences::isWebUIClickjackingProtectionEnabled() const
{
return value(u"Preferences/WebUI/ClickjackingProtection"_s, true);
}
-void Preferences::setWebUiClickjackingProtectionEnabled(const bool enabled)
+void Preferences::setWebUIClickjackingProtectionEnabled(const bool enabled)
{
- if (enabled == isWebUiClickjackingProtectionEnabled())
+ if (enabled == isWebUIClickjackingProtectionEnabled())
return;
setValue(u"Preferences/WebUI/ClickjackingProtection"_s, enabled);
}
-bool Preferences::isWebUiCSRFProtectionEnabled() const
+bool Preferences::isWebUICSRFProtectionEnabled() const
{
return value(u"Preferences/WebUI/CSRFProtection"_s, true);
}
-void Preferences::setWebUiCSRFProtectionEnabled(const bool enabled)
+void Preferences::setWebUICSRFProtectionEnabled(const bool enabled)
{
- if (enabled == isWebUiCSRFProtectionEnabled())
+ if (enabled == isWebUICSRFProtectionEnabled())
return;
setValue(u"Preferences/WebUI/CSRFProtection"_s, enabled);
}
-bool Preferences::isWebUiSecureCookieEnabled() const
+bool Preferences::isWebUISecureCookieEnabled() const
{
return value(u"Preferences/WebUI/SecureCookie"_s, true);
}
-void Preferences::setWebUiSecureCookieEnabled(const bool enabled)
+void Preferences::setWebUISecureCookieEnabled(const bool enabled)
{
- if (enabled == isWebUiSecureCookieEnabled())
+ if (enabled == isWebUISecureCookieEnabled())
return;
setValue(u"Preferences/WebUI/SecureCookie"_s, enabled);
@@ -895,14 +882,14 @@ void Preferences::setWebUIHostHeaderValidationEnabled(const bool enabled)
setValue(u"Preferences/WebUI/HostHeaderValidation"_s, enabled);
}
-bool Preferences::isWebUiHttpsEnabled() const
+bool Preferences::isWebUIHttpsEnabled() const
{
return value(u"Preferences/WebUI/HTTPS/Enabled"_s, false);
}
-void Preferences::setWebUiHttpsEnabled(const bool enabled)
+void Preferences::setWebUIHttpsEnabled(const bool enabled)
{
- if (enabled == isWebUiHttpsEnabled())
+ if (enabled == isWebUIHttpsEnabled())
return;
setValue(u"Preferences/WebUI/HTTPS/Enabled"_s, enabled);
@@ -934,27 +921,27 @@ void Preferences::setWebUIHttpsKeyPath(const Path &path)
setValue(u"Preferences/WebUI/HTTPS/KeyPath"_s, path);
}
-bool Preferences::isAltWebUiEnabled() const
+bool Preferences::isAltWebUIEnabled() const
{
return value(u"Preferences/WebUI/AlternativeUIEnabled"_s, false);
}
-void Preferences::setAltWebUiEnabled(const bool enabled)
+void Preferences::setAltWebUIEnabled(const bool enabled)
{
- if (enabled == isAltWebUiEnabled())
+ if (enabled == isAltWebUIEnabled())
return;
setValue(u"Preferences/WebUI/AlternativeUIEnabled"_s, enabled);
}
-Path Preferences::getWebUiRootFolder() const
+Path Preferences::getWebUIRootFolder() const
{
return value(u"Preferences/WebUI/RootFolder"_s);
}
-void Preferences::setWebUiRootFolder(const Path &path)
+void Preferences::setWebUIRootFolder(const Path &path)
{
- if (path == getWebUiRootFolder())
+ if (path == getWebUIRootFolder())
return;
setValue(u"Preferences/WebUI/RootFolder"_s, path);
@@ -1316,144 +1303,8 @@ void Preferences::setNeverCheckFileAssoc(const bool check)
setValue(u"Preferences/Win32/NeverCheckFileAssocation"_s, check);
}
-
-bool Preferences::isTorrentFileAssocSet()
-{
- const QSettings settings(u"HKEY_CURRENT_USER\\Software\\Classes"_s, QSettings::NativeFormat);
- if (settings.value(u".torrent/Default"_s).toString() != u"qBittorrent")
- {
- qDebug(".torrent != qBittorrent");
- return false;
- }
-
- return true;
-}
-
-void Preferences::setTorrentFileAssoc(const bool set)
-{
- QSettings settings(u"HKEY_CURRENT_USER\\Software\\Classes"_s, QSettings::NativeFormat);
-
- // .Torrent association
- if (set)
- {
- const QString oldProgId = settings.value(u".torrent/Default"_s).toString();
- if (!oldProgId.isEmpty() && (oldProgId != u"qBittorrent"))
- settings.setValue((u".torrent/OpenWithProgids/" + oldProgId), QString());
- settings.setValue(u".torrent/Default"_s, u"qBittorrent"_s);
- }
- else if (isTorrentFileAssocSet())
- {
- settings.setValue(u".torrent/Default"_s, QString());
- }
-
- SHChangeNotify(SHCNE_ASSOCCHANGED, SHCNF_IDLIST, 0, 0);
-}
-
-bool Preferences::isMagnetLinkAssocSet()
-{
- const QSettings settings(u"HKEY_CURRENT_USER\\Software\\Classes"_s, QSettings::NativeFormat);
-
- // Check magnet link assoc
- const QString shellCommand = settings.value(u"magnet/shell/open/command/Default"_s, QString()).toString();
-
- const QRegularExpressionMatch exeRegMatch = QRegularExpression(u"\"([^\"]+)\".*"_s).match(shellCommand);
- if (!exeRegMatch.hasMatch())
- return false;
-
- const Path assocExe {exeRegMatch.captured(1)};
- if (assocExe != Path(qApp->applicationFilePath()))
- return false;
-
- return true;
-}
-
-void Preferences::setMagnetLinkAssoc(const bool set)
-{
- QSettings settings(u"HKEY_CURRENT_USER\\Software\\Classes"_s, QSettings::NativeFormat);
-
- // Magnet association
- if (set)
- {
- const QString applicationFilePath = Path(qApp->applicationFilePath()).toString();
- const QString commandStr = u'"' + applicationFilePath + u"\" \"%1\"";
- const QString iconStr = u'"' + applicationFilePath + u"\",1";
-
- settings.setValue(u"magnet/Default"_s, u"URL:Magnet link"_s);
- settings.setValue(u"magnet/Content Type"_s, u"application/x-magnet"_s);
- settings.setValue(u"magnet/URL Protocol"_s, QString());
- settings.setValue(u"magnet/DefaultIcon/Default"_s, iconStr);
- settings.setValue(u"magnet/shell/Default"_s, u"open"_s);
- settings.setValue(u"magnet/shell/open/command/Default"_s, commandStr);
- }
- else if (isMagnetLinkAssocSet())
- {
- settings.remove(u"magnet"_s);
- }
-
- SHChangeNotify(SHCNE_ASSOCCHANGED, SHCNF_IDLIST, 0, 0);
-}
#endif // Q_OS_WIN
-#ifdef Q_OS_MACOS
-namespace
-{
- const CFStringRef torrentExtension = CFSTR("torrent");
- const CFStringRef magnetUrlScheme = CFSTR("magnet");
-}
-
-bool Preferences::isTorrentFileAssocSet()
-{
- bool isSet = false;
- const CFStringRef torrentId = UTTypeCreatePreferredIdentifierForTag(kUTTagClassFilenameExtension, torrentExtension, NULL);
- if (torrentId != NULL)
- {
- const CFStringRef defaultHandlerId = LSCopyDefaultRoleHandlerForContentType(torrentId, kLSRolesViewer);
- if (defaultHandlerId != NULL)
- {
- const CFStringRef myBundleId = CFBundleGetIdentifier(CFBundleGetMainBundle());
- isSet = CFStringCompare(myBundleId, defaultHandlerId, 0) == kCFCompareEqualTo;
- CFRelease(defaultHandlerId);
- }
- CFRelease(torrentId);
- }
- return isSet;
-}
-
-void Preferences::setTorrentFileAssoc()
-{
- if (isTorrentFileAssocSet())
- return;
- const CFStringRef torrentId = UTTypeCreatePreferredIdentifierForTag(kUTTagClassFilenameExtension, torrentExtension, NULL);
- if (torrentId != NULL)
- {
- const CFStringRef myBundleId = CFBundleGetIdentifier(CFBundleGetMainBundle());
- LSSetDefaultRoleHandlerForContentType(torrentId, kLSRolesViewer, myBundleId);
- CFRelease(torrentId);
- }
-}
-
-bool Preferences::isMagnetLinkAssocSet()
-{
- bool isSet = false;
- const CFStringRef defaultHandlerId = LSCopyDefaultHandlerForURLScheme(magnetUrlScheme);
- if (defaultHandlerId != NULL)
- {
- const CFStringRef myBundleId = CFBundleGetIdentifier(CFBundleGetMainBundle());
- isSet = CFStringCompare(myBundleId, defaultHandlerId, 0) == kCFCompareEqualTo;
- CFRelease(defaultHandlerId);
- }
- return isSet;
-}
-
-void Preferences::setMagnetLinkAssoc()
-{
- if (isMagnetLinkAssocSet())
- return;
- const CFStringRef myBundleId = CFBundleGetIdentifier(CFBundleGetMainBundle());
- LSSetDefaultHandlerForURLScheme(magnetUrlScheme, myBundleId);
-}
-#endif // Q_OS_MACOS
-
int Preferences::getTrackerPort() const
{
return value(u"Preferences/Advanced/trackerPort"_s, 9000);
diff --git a/src/base/preferences.h b/src/base/preferences.h
index 9f17eabb5..fe19d930e 100644
--- a/src/base/preferences.h
+++ b/src/base/preferences.h
@@ -169,26 +169,26 @@ public:
void setSearchEnabled(bool enabled);
// HTTP Server
- bool isWebUiEnabled() const;
- void setWebUiEnabled(bool enabled);
+ bool isWebUIEnabled() const;
+ void setWebUIEnabled(bool enabled);
QString getServerDomains() const;
void setServerDomains(const QString &str);
- QString getWebUiAddress() const;
- void setWebUiAddress(const QString &addr);
- quint16 getWebUiPort() const;
- void setWebUiPort(quint16 port);
+ QString getWebUIAddress() const;
+ void setWebUIAddress(const QString &addr);
+ quint16 getWebUIPort() const;
+ void setWebUIPort(quint16 port);
bool useUPnPForWebUIPort() const;
void setUPnPForWebUIPort(bool enabled);
// Authentication
- bool isWebUiLocalAuthEnabled() const;
- void setWebUiLocalAuthEnabled(bool enabled);
- bool isWebUiAuthSubnetWhitelistEnabled() const;
- void setWebUiAuthSubnetWhitelistEnabled(bool enabled);
- QVector getWebUiAuthSubnetWhitelist() const;
- void setWebUiAuthSubnetWhitelist(QStringList subnets);
- QString getWebUiUsername() const;
- void setWebUiUsername(const QString &username);
+ bool isWebUILocalAuthEnabled() const;
+ void setWebUILocalAuthEnabled(bool enabled);
+ bool isWebUIAuthSubnetWhitelistEnabled() const;
+ void setWebUIAuthSubnetWhitelistEnabled(bool enabled);
+ QVector getWebUIAuthSubnetWhitelist() const;
+ void setWebUIAuthSubnetWhitelist(QStringList subnets);
+ QString getWebUIUsername() const;
+ void setWebUIUsername(const QString &username);
QByteArray getWebUIPassword() const;
void setWebUIPassword(const QByteArray &password);
int getWebUIMaxAuthFailCount() const;
@@ -201,26 +201,26 @@ public:
void setWebAPISessionCookieName(const QString &cookieName);
// WebUI security
- bool isWebUiClickjackingProtectionEnabled() const;
- void setWebUiClickjackingProtectionEnabled(bool enabled);
- bool isWebUiCSRFProtectionEnabled() const;
- void setWebUiCSRFProtectionEnabled(bool enabled);
- bool isWebUiSecureCookieEnabled () const;
- void setWebUiSecureCookieEnabled(bool enabled);
+ bool isWebUIClickjackingProtectionEnabled() const;
+ void setWebUIClickjackingProtectionEnabled(bool enabled);
+ bool isWebUICSRFProtectionEnabled() const;
+ void setWebUICSRFProtectionEnabled(bool enabled);
+ bool isWebUISecureCookieEnabled () const;
+ void setWebUISecureCookieEnabled(bool enabled);
bool isWebUIHostHeaderValidationEnabled() const;
void setWebUIHostHeaderValidationEnabled(bool enabled);
// HTTPS
- bool isWebUiHttpsEnabled() const;
- void setWebUiHttpsEnabled(bool enabled);
+ bool isWebUIHttpsEnabled() const;
+ void setWebUIHttpsEnabled(bool enabled);
Path getWebUIHttpsCertificatePath() const;
void setWebUIHttpsCertificatePath(const Path &path);
Path getWebUIHttpsKeyPath() const;
void setWebUIHttpsKeyPath(const Path &path);
- bool isAltWebUiEnabled() const;
- void setAltWebUiEnabled(bool enabled);
- Path getWebUiRootFolder() const;
- void setWebUiRootFolder(const Path &path);
+ bool isAltWebUIEnabled() const;
+ void setAltWebUIEnabled(bool enabled);
+ Path getWebUIRootFolder() const;
+ void setWebUIRootFolder(const Path &path);
// WebUI custom HTTP headers
bool isWebUICustomHTTPHeadersEnabled() const;
@@ -290,17 +290,8 @@ public:
#ifdef Q_OS_WIN
bool neverCheckFileAssoc() const;
void setNeverCheckFileAssoc(bool check = true);
- static bool isTorrentFileAssocSet();
- static void setTorrentFileAssoc(bool set);
- static bool isMagnetLinkAssocSet();
- static void setMagnetLinkAssoc(bool set);
-#endif
-#ifdef Q_OS_MACOS
- static bool isTorrentFileAssocSet();
- static void setTorrentFileAssoc();
- static bool isMagnetLinkAssocSet();
- static void setMagnetLinkAssoc();
#endif
+
int getTrackerPort() const;
void setTrackerPort(int port);
bool isTrackerPortForwardingEnabled() const;
diff --git a/src/base/rss/feed_serializer.cpp b/src/base/rss/feed_serializer.cpp
index 062360ba7..ce097c41c 100644
--- a/src/base/rss/feed_serializer.cpp
+++ b/src/base/rss/feed_serializer.cpp
@@ -45,8 +45,7 @@ const int ARTICLEDATALIST_TYPEID = qRegisterMetaType>();
void RSS::Private::FeedSerializer::load(const Path &dataFileName, const QString &url)
{
- const int fileMaxSize = 10 * 1024 * 1024;
- const auto readResult = Utils::IO::readFile(dataFileName, fileMaxSize);
+ const auto readResult = Utils::IO::readFile(dataFileName, -1);
if (!readResult)
{
if (readResult.error().status == Utils::IO::ReadError::NotExist)
diff --git a/src/base/rss/rss_session.cpp b/src/base/rss/rss_session.cpp
index 6de5c26d7..ec4959eeb 100644
--- a/src/base/rss/rss_session.cpp
+++ b/src/base/rss/rss_session.cpp
@@ -271,6 +271,7 @@ void Session::load()
if (readResult.error().status == Utils::IO::ReadError::NotExist)
{
loadLegacy();
+ store(); // convert to new format
return;
}
@@ -294,10 +295,11 @@ void Session::load()
return;
}
- loadFolder(jsonDoc.object(), rootFolder());
+ if (loadFolder(jsonDoc.object(), rootFolder()))
+ store(); // convert to updated format
}
-void Session::loadFolder(const QJsonObject &jsonObj, Folder *folder)
+bool Session::loadFolder(const QJsonObject &jsonObj, Folder *folder)
{
bool updated = false;
for (const QString &key : asConst(jsonObj.keys()))
@@ -353,7 +355,8 @@ void Session::loadFolder(const QJsonObject &jsonObj, Folder *folder)
}
else
{
- loadFolder(valObj, addSubfolder(key, folder));
+ if (loadFolder(valObj, addSubfolder(key, folder)))
+ updated = true;
}
}
else
@@ -363,8 +366,7 @@ void Session::loadFolder(const QJsonObject &jsonObj, Folder *folder)
}
}
- if (updated)
- store(); // convert to updated format
+ return updated;
}
void Session::loadLegacy()
@@ -394,8 +396,6 @@ void Session::loadLegacy()
addFeed(feedUrl, feedPath);
++i;
}
-
- store(); // convert to new format
}
void Session::store()
diff --git a/src/base/rss/rss_session.h b/src/base/rss/rss_session.h
index 79c920066..9fee14c1e 100644
--- a/src/base/rss/rss_session.h
+++ b/src/base/rss/rss_session.h
@@ -149,7 +149,7 @@ namespace RSS
private:
QUuid generateUID() const;
void load();
- void loadFolder(const QJsonObject &jsonObj, Folder *folder);
+ bool loadFolder(const QJsonObject &jsonObj, Folder *folder);
void loadLegacy();
void store();
nonstd::expected prepareItemDest(const QString &path);
diff --git a/src/base/torrentfileswatcher.cpp b/src/base/torrentfileswatcher.cpp
index 7015a293d..66ec9a566 100644
--- a/src/base/torrentfileswatcher.cpp
+++ b/src/base/torrentfileswatcher.cpp
@@ -92,7 +92,7 @@ class TorrentFilesWatcher::Worker final : public QObject
Q_DISABLE_COPY_MOVE(Worker)
public:
- Worker();
+ Worker(QFileSystemWatcher *watcher);
public slots:
void setWatchedFolder(const Path &path, const TorrentFilesWatcher::WatchedFolderOptions &options);
@@ -141,24 +141,10 @@ TorrentFilesWatcher *TorrentFilesWatcher::instance()
}
TorrentFilesWatcher::TorrentFilesWatcher(QObject *parent)
- : QObject {parent}
+ : QObject(parent)
, m_ioThread {new QThread}
+ , m_asyncWorker {new TorrentFilesWatcher::Worker(new QFileSystemWatcher(this))}
{
- const auto *btSession = BitTorrent::Session::instance();
- if (btSession->isRestored())
- initWorker();
- else
- connect(btSession, &BitTorrent::Session::restored, this, &TorrentFilesWatcher::initWorker);
-
- load();
-}
-
-void TorrentFilesWatcher::initWorker()
-{
- Q_ASSERT(!m_asyncWorker);
-
- m_asyncWorker = new TorrentFilesWatcher::Worker;
-
connect(m_asyncWorker, &TorrentFilesWatcher::Worker::magnetFound, this, &TorrentFilesWatcher::onMagnetFound);
connect(m_asyncWorker, &TorrentFilesWatcher::Worker::torrentFound, this, &TorrentFilesWatcher::onTorrentFound);
@@ -166,13 +152,7 @@ void TorrentFilesWatcher::initWorker()
connect(m_ioThread.get(), &QThread::finished, m_asyncWorker, &QObject::deleteLater);
m_ioThread->start();
- for (auto it = m_watchedFolders.cbegin(); it != m_watchedFolders.cend(); ++it)
- {
- QMetaObject::invokeMethod(m_asyncWorker, [this, path = it.key(), options = it.value()]()
- {
- m_asyncWorker->setWatchedFolder(path, options);
- });
- }
+ load();
}
void TorrentFilesWatcher::load()
@@ -303,13 +283,10 @@ void TorrentFilesWatcher::doSetWatchedFolder(const Path &path, const WatchedFold
m_watchedFolders[path] = options;
- if (m_asyncWorker)
+ QMetaObject::invokeMethod(m_asyncWorker, [this, path, options]
{
- QMetaObject::invokeMethod(m_asyncWorker, [this, path, options]()
- {
- m_asyncWorker->setWatchedFolder(path, options);
- });
- }
+ m_asyncWorker->setWatchedFolder(path, options);
+ });
emit watchedFolderSet(path, options);
}
@@ -344,8 +321,8 @@ void TorrentFilesWatcher::onTorrentFound(const BitTorrent::TorrentInfo &torrentI
BitTorrent::Session::instance()->addTorrent(torrentInfo, addTorrentParams);
}
-TorrentFilesWatcher::Worker::Worker()
- : m_watcher {new QFileSystemWatcher(this)}
+TorrentFilesWatcher::Worker::Worker(QFileSystemWatcher *watcher)
+ : m_watcher {watcher}
, m_watchTimer {new QTimer(this)}
, m_retryTorrentTimer {new QTimer(this)}
{
diff --git a/src/base/torrentfileswatcher.h b/src/base/torrentfileswatcher.h
index be7f42ce9..9142679f3 100644
--- a/src/base/torrentfileswatcher.h
+++ b/src/base/torrentfileswatcher.h
@@ -78,7 +78,6 @@ private slots:
private:
explicit TorrentFilesWatcher(QObject *parent = nullptr);
- void initWorker();
void load();
void loadLegacy();
void store() const;
diff --git a/src/base/utils/io.cpp b/src/base/utils/io.cpp
index 902297d6d..afe4c4deb 100644
--- a/src/base/utils/io.cpp
+++ b/src/base/utils/io.cpp
@@ -28,6 +28,8 @@
#include "io.h"
+#include
+
#include
#include
@@ -89,11 +91,20 @@ nonstd::expected Utils::IO::readFile(const Pat
return nonstd::make_unexpected(ReadError {ReadError::ExceedSize, message});
}
-#if (QT_VERSION >= QT_VERSION_CHECK(6, 5, 0))
- QByteArray ret {fileSize, Qt::Uninitialized};
+#if (QT_VERSION >= QT_VERSION_CHECK(6, 0, 0))
+ using ByteArraySizeType = qsizetype;
#else
- QByteArray ret {static_cast(fileSize), Qt::Uninitialized};
+ using ByteArraySizeType = int;
#endif
+ if ((fileSize < std::numeric_limits::min())
+ || (fileSize > std::numeric_limits::max()))
+ {
+ const QString message = QCoreApplication::translate("Utils::IO", "File size exceeds data size limit. File: \"%1\". File size: %2. Array limit: %3")
+ .arg(file.fileName(), QString::number(fileSize), QString::number(std::numeric_limits::max()));
+ return nonstd::make_unexpected(ReadError {ReadError::ExceedSize, message});
+ }
+
+ QByteArray ret {static_cast(fileSize), Qt::Uninitialized};
const qint64 actualSize = file.read(ret.data(), fileSize);
if (actualSize < 0)
diff --git a/src/base/utils/misc.cpp b/src/base/utils/misc.cpp
index a39355e23..9ca0cdf24 100644
--- a/src/base/utils/misc.cpp
+++ b/src/base/utils/misc.cpp
@@ -611,4 +611,4 @@ Path Utils::Misc::windowsSystemPath()
}();
return path;
}
-#endif
+#endif // Q_OS_WIN
diff --git a/src/base/utils/os.cpp b/src/base/utils/os.cpp
new file mode 100644
index 000000000..8ee374e3d
--- /dev/null
+++ b/src/base/utils/os.cpp
@@ -0,0 +1,194 @@
+/*
+ * Bittorrent Client using Qt and libtorrent.
+ * Copyright (C) 2023 Mike Tzou (Chocobo1)
+ * Copyright (C) 2014 sledgehammer999
+ * 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 "os.h"
+
+#ifdef Q_OS_MACOS
+#include
+#endif // Q_OS_MACOS
+
+#ifdef Q_OS_WIN
+#include
+#endif // Q_OS_WIN
+
+#include
+
+#ifdef Q_OS_WIN
+#include
+#include
+#include
+#endif // Q_OS_WIN
+
+#include "base/global.h"
+#include "base/path.h"
+
+#ifdef Q_OS_MACOS
+namespace
+{
+ const CFStringRef torrentExtension = CFSTR("torrent");
+ const CFStringRef magnetUrlScheme = CFSTR("magnet");
+}
+
+bool Utils::OS::isTorrentFileAssocSet()
+{
+ bool isSet = false;
+ const CFStringRef torrentId = ::UTTypeCreatePreferredIdentifierForTag(kUTTagClassFilenameExtension, torrentExtension, NULL);
+ if (torrentId != NULL)
+ {
+ const CFStringRef defaultHandlerId = ::LSCopyDefaultRoleHandlerForContentType(torrentId, kLSRolesViewer);
+ if (defaultHandlerId != NULL)
+ {
+ const CFStringRef myBundleId = ::CFBundleGetIdentifier(::CFBundleGetMainBundle());
+ if (myBundleId != NULL)
+ isSet = ::CFStringCompare(myBundleId, defaultHandlerId, 0) == kCFCompareEqualTo;
+ ::CFRelease(defaultHandlerId);
+ }
+ ::CFRelease(torrentId);
+ }
+ return isSet;
+}
+
+void Utils::OS::setTorrentFileAssoc()
+{
+ if (isTorrentFileAssocSet())
+ return;
+
+ const CFStringRef torrentId = ::UTTypeCreatePreferredIdentifierForTag(kUTTagClassFilenameExtension, torrentExtension, NULL);
+ if (torrentId != NULL)
+ {
+ const CFStringRef myBundleId = ::CFBundleGetIdentifier(::CFBundleGetMainBundle());
+ if (myBundleId != NULL)
+ ::LSSetDefaultRoleHandlerForContentType(torrentId, kLSRolesViewer, myBundleId);
+ ::CFRelease(torrentId);
+ }
+}
+
+bool Utils::OS::isMagnetLinkAssocSet()
+{
+ bool isSet = false;
+ const CFStringRef defaultHandlerId = ::LSCopyDefaultHandlerForURLScheme(magnetUrlScheme);
+ if (defaultHandlerId != NULL)
+ {
+ const CFStringRef myBundleId = ::CFBundleGetIdentifier(::CFBundleGetMainBundle());
+ if (myBundleId != NULL)
+ isSet = ::CFStringCompare(myBundleId, defaultHandlerId, 0) == kCFCompareEqualTo;
+ ::CFRelease(defaultHandlerId);
+ }
+ return isSet;
+}
+
+void Utils::OS::setMagnetLinkAssoc()
+{
+ if (isMagnetLinkAssocSet())
+ return;
+
+ const CFStringRef myBundleId = ::CFBundleGetIdentifier(::CFBundleGetMainBundle());
+ if (myBundleId != NULL)
+ ::LSSetDefaultHandlerForURLScheme(magnetUrlScheme, myBundleId);
+}
+#endif // Q_OS_MACOS
+
+#ifdef Q_OS_WIN
+bool Utils::OS::isTorrentFileAssocSet()
+{
+ const QSettings settings(u"HKEY_CURRENT_USER\\Software\\Classes"_s, QSettings::NativeFormat);
+ return settings.value(u".torrent/Default"_s).toString() == u"qBittorrent";
+}
+
+void Utils::OS::setTorrentFileAssoc(const bool set)
+{
+ if (set == isTorrentFileAssocSet())
+ return;
+
+ QSettings settings(u"HKEY_CURRENT_USER\\Software\\Classes"_s, QSettings::NativeFormat);
+
+ if (set)
+ {
+ const QString oldProgId = settings.value(u".torrent/Default"_s).toString();
+ if (!oldProgId.isEmpty() && (oldProgId != u"qBittorrent"))
+ settings.setValue((u".torrent/OpenWithProgids/" + oldProgId), QString());
+
+ settings.setValue(u".torrent/Default"_s, u"qBittorrent"_s);
+ settings.setValue(u".torrent/Content Type"_s, u"application/x-bittorrent"_s);
+ }
+ else
+ {
+ settings.setValue(u".torrent/Default"_s, QString());
+ }
+
+ ::SHChangeNotify(SHCNE_ASSOCCHANGED, SHCNF_IDLIST, nullptr, nullptr);
+}
+
+bool Utils::OS::isMagnetLinkAssocSet()
+{
+ const QSettings settings(u"HKEY_CURRENT_USER\\Software\\Classes"_s, QSettings::NativeFormat);
+ const QString shellCommand = settings.value(u"magnet/shell/open/command/Default"_s).toString();
+
+ const QRegularExpressionMatch exeRegMatch = QRegularExpression(u"\"([^\"]+)\".*"_s).match(shellCommand);
+ if (!exeRegMatch.hasMatch())
+ return false;
+
+ const Path assocExe {exeRegMatch.captured(1)};
+ if (assocExe != Path(qApp->applicationFilePath()))
+ return false;
+
+ return true;
+}
+
+void Utils::OS::setMagnetLinkAssoc(const bool set)
+{
+ if (set == isMagnetLinkAssocSet())
+ return;
+
+ QSettings settings(u"HKEY_CURRENT_USER\\Software\\Classes"_s, QSettings::NativeFormat);
+
+ if (set)
+ {
+ const QString applicationFilePath = Path(qApp->applicationFilePath()).toString();
+ const QString commandStr = u'"' + applicationFilePath + u"\" \"%1\"";
+ const QString iconStr = u'"' + applicationFilePath + u"\",1";
+
+ settings.setValue(u"magnet/Default"_s, u"URL:Magnet link"_s);
+ settings.setValue(u"magnet/Content Type"_s, u"application/x-magnet"_s);
+ settings.setValue(u"magnet/DefaultIcon/Default"_s, iconStr);
+ settings.setValue(u"magnet/shell/Default"_s, u"open"_s);
+ settings.setValue(u"magnet/shell/open/command/Default"_s, commandStr);
+ settings.setValue(u"magnet/URL Protocol"_s, QString());
+ }
+ else
+ {
+ // only wipe values that are specific to qbt
+ settings.setValue(u"magnet/DefaultIcon/Default"_s, QString());
+ settings.setValue(u"magnet/shell/open/command/Default"_s, QString());
+ }
+
+ ::SHChangeNotify(SHCNE_ASSOCCHANGED, SHCNF_IDLIST, nullptr, nullptr);
+}
+#endif // Q_OS_WIN
diff --git a/src/base/utils/os.h b/src/base/utils/os.h
new file mode 100644
index 000000000..66b899977
--- /dev/null
+++ b/src/base/utils/os.h
@@ -0,0 +1,50 @@
+/*
+ * Bittorrent Client using Qt and libtorrent.
+ * Copyright (C) 2023 Mike Tzou (Chocobo1)
+ * Copyright (C) 2014 sledgehammer999
+ * 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.
+ */
+
+#pragma once
+
+#include
+
+namespace Utils::OS
+{
+#ifdef Q_OS_MACOS
+ bool isTorrentFileAssocSet();
+ void setTorrentFileAssoc();
+ bool isMagnetLinkAssocSet();
+ void setMagnetLinkAssoc();
+#endif // Q_OS_MACOS
+
+#ifdef Q_OS_WIN
+ bool isTorrentFileAssocSet();
+ void setTorrentFileAssoc(bool set);
+ bool isMagnetLinkAssocSet();
+ void setMagnetLinkAssoc(bool set);
+#endif // Q_OS_WIN
+}
diff --git a/src/base/utils/password.cpp b/src/base/utils/password.cpp
index 0351aff64..4ed8989ad 100644
--- a/src/base/utils/password.cpp
+++ b/src/base/utils/password.cpp
@@ -1,5 +1,6 @@
/*
* Bittorrent Client using Qt and libtorrent.
+ * Copyright (C) 2023 Vladimir Golovnev
* Copyright (C) 2018 Mike Tzou (Chocobo1)
*
* This program is free software; you can redistribute it and/or
@@ -36,6 +37,7 @@
#include
#include
+#include "base/global.h"
#include "bytearray.h"
#include "random.h"
@@ -65,6 +67,21 @@ bool Utils::Password::slowEquals(const QByteArray &a, const QByteArray &b)
return (diff == 0);
}
+QString Utils::Password::generate()
+{
+ const QString alphanum = u"23456789ABCDEFGHIJKLMNPQRSTUVWXYZabcdefghjkmnpqrstuvwxyz"_s;
+ const int passwordLength = 9;
+ QString pass;
+ pass.reserve(passwordLength);
+ while (pass.length() < passwordLength)
+ {
+ const auto num = Utils::Random::rand(0, (alphanum.size() - 1));
+ pass.append(alphanum[num]);
+ }
+
+ return pass;
+}
+
QByteArray Utils::Password::PBKDF2::generate(const QString &password)
{
return generate(password.toUtf8());
@@ -72,9 +89,8 @@ QByteArray Utils::Password::PBKDF2::generate(const QString &password)
QByteArray Utils::Password::PBKDF2::generate(const QByteArray &password)
{
- const std::array salt
- {{Random::rand(), Random::rand()
- , Random::rand(), Random::rand()}};
+ const std::array salt {
+ {Random::rand(), Random::rand(), Random::rand(), Random::rand()}};
std::array outBuf {};
const int hmacResult = PKCS5_PBKDF2_HMAC(password.constData(), password.size()
diff --git a/src/base/utils/password.h b/src/base/utils/password.h
index 3ad6d8578..b656731e9 100644
--- a/src/base/utils/password.h
+++ b/src/base/utils/password.h
@@ -1,5 +1,6 @@
/*
* Bittorrent Client using Qt and libtorrent.
+ * Copyright (C) 2023 Vladimir Golovnev
* Copyright (C) 2018 Mike Tzou (Chocobo1)
*
* This program is free software; you can redistribute it and/or
@@ -37,6 +38,8 @@ namespace Utils::Password
// Taken from https://crackstation.net/hashing-security.htm
bool slowEquals(const QByteArray &a, const QByteArray &b);
+ QString generate();
+
namespace PBKDF2
{
QByteArray generate(const QString &password);
diff --git a/src/base/version.h.in b/src/base/version.h.in
index 5c177f66e..523239f0d 100644
--- a/src/base/version.h.in
+++ b/src/base/version.h.in
@@ -30,9 +30,9 @@
#define QBT_VERSION_MAJOR 4
#define QBT_VERSION_MINOR 6
-#define QBT_VERSION_BUGFIX 0
+#define QBT_VERSION_BUGFIX 2
#define QBT_VERSION_BUILD 0
-#define QBT_VERSION_STATUS "beta2" // Should be empty for stable releases!
+#define QBT_VERSION_STATUS "" // Should be empty for stable releases!
#define QBT__STRINGIFY(x) #x
#define QBT_STRINGIFY(x) QBT__STRINGIFY(x)
diff --git a/src/gui/aboutdialog.cpp b/src/gui/aboutdialog.cpp
index 27193a674..66622deb5 100644
--- a/src/gui/aboutdialog.cpp
+++ b/src/gui/aboutdialog.cpp
@@ -28,6 +28,8 @@
#include "aboutdialog.h"
+#include
+
#include "base/global.h"
#include "base/path.h"
#include "base/unicodestrings.h"
@@ -65,7 +67,7 @@ AboutDialog::AboutDialog(QWidget *parent)
u"
"_s
.arg(tr("An advanced BitTorrent client programmed in C++, based on Qt toolkit and libtorrent-rasterbar.")
.replace(u"C++"_s, u"C\u2060+\u2060+"_s) // make C++ non-breaking
- , tr("Copyright %1 2006-2022 The qBittorrent project").arg(C_COPYRIGHT)
+ , tr("Copyright %1 2006-2023 The qBittorrent project").arg(C_COPYRIGHT)
, tr("Home Page:")
, tr("Forum:")
, tr("Bug Tracker:"));
@@ -74,22 +76,19 @@ AboutDialog::AboutDialog(QWidget *parent)
m_ui->labelMascot->setPixmap(Utils::Gui::scaledPixmap(Path(u":/icons/mascot.png"_s), this));
// Thanks
- if (const auto readResult = Utils::IO::readFile(Path(u":/thanks.html"_s), -1, QIODevice::Text)
- ; readResult)
+ if (const auto readResult = Utils::IO::readFile(Path(u":/thanks.html"_s), -1, QIODevice::Text))
{
m_ui->textBrowserThanks->setHtml(QString::fromUtf8(readResult.value()));
}
// Translation
- if (const auto readResult = Utils::IO::readFile(Path(u":/translators.html"_s), -1, QIODevice::Text)
- ; readResult)
+ if (const auto readResult = Utils::IO::readFile(Path(u":/translators.html"_s), -1, QIODevice::Text))
{
m_ui->textBrowserTranslation->setHtml(QString::fromUtf8(readResult.value()));
}
// License
- if (const auto readResult = Utils::IO::readFile(Path(u":/gpl.html"_s), -1, QIODevice::Text)
- ; readResult)
+ if (const auto readResult = Utils::IO::readFile(Path(u":/gpl.html"_s), -1, QIODevice::Text))
{
m_ui->textBrowserLicense->setHtml(QString::fromUtf8(readResult.value()));
}
@@ -101,6 +100,8 @@ AboutDialog::AboutDialog(QWidget *parent)
m_ui->labelOpensslVer->setText(Utils::Misc::opensslVersionString());
m_ui->labelZlibVer->setText(Utils::Misc::zlibVersionString());
+ connect(m_ui->btnCopyToClipboard, &QAbstractButton::clicked, this, &AboutDialog::copyVersionsToClipboard);
+
const QString DBIPText = u""
u"%1 (https://db-ip.com/)"
u"
"_s
@@ -117,3 +118,14 @@ AboutDialog::~AboutDialog()
m_storeDialogSize = size();
delete m_ui;
}
+
+void AboutDialog::copyVersionsToClipboard() const
+{
+ const QString versions = u"%1 %2\n%3 %4\n%5 %6\n%7 %8\n%9 %10\n"_s
+ .arg(m_ui->labelQt->text(), m_ui->labelQtVer->text()
+ , m_ui->labelLibt->text(), m_ui->labelLibtVer->text()
+ , m_ui->labelBoost->text(), m_ui->labelBoostVer->text()
+ , m_ui->labelOpenssl->text(), m_ui->labelOpensslVer->text()
+ , m_ui->labelZlib->text(), m_ui->labelZlibVer->text());
+ qApp->clipboard()->setText(versions);
+}
diff --git a/src/gui/aboutdialog.h b/src/gui/aboutdialog.h
index 2ac58617b..804933822 100644
--- a/src/gui/aboutdialog.h
+++ b/src/gui/aboutdialog.h
@@ -47,6 +47,8 @@ public:
~AboutDialog() override;
private:
+ void copyVersionsToClipboard() const;
+
Ui::AboutDialog *m_ui = nullptr;
SettingValue m_storeDialogSize;
};
diff --git a/src/gui/aboutdialog.ui b/src/gui/aboutdialog.ui
index 8b64e880d..abb6fd5c0 100644
--- a/src/gui/aboutdialog.ui
+++ b/src/gui/aboutdialog.ui
@@ -25,6 +25,9 @@
qBittorrent
+
+ Qt::LinksAccessibleByMouse|Qt::TextSelectableByKeyboard|Qt::TextSelectableByMouse
+
-
@@ -281,12 +284,12 @@
-
-
- true
-
QTextEdit::NoWrap
+
+ true
+
@@ -323,11 +326,35 @@
-
-
-
- qBittorrent was built with the following libraries:
-
-
+
+
-
+
+
+ qBittorrent was built with the following libraries:
+
+
+
+ -
+
+
+ Qt::Horizontal
+
+
+
+ 40
+ 20
+
+
+
+
+ -
+
+
+ Copy to clipboard
+
+
+
+
-
@@ -359,7 +386,7 @@
-
-
+
Qt:
@@ -372,7 +399,7 @@
-
-
+
Libtorrent:
@@ -385,7 +412,7 @@
-
-
+
Boost:
@@ -425,7 +452,7 @@
-
-
+
OpenSSL:
@@ -445,7 +472,7 @@
-
-
+
zlib:
diff --git a/src/gui/addnewtorrentdialog.cpp b/src/gui/addnewtorrentdialog.cpp
index cf0ee4aaa..e9331a654 100644
--- a/src/gui/addnewtorrentdialog.cpp
+++ b/src/gui/addnewtorrentdialog.cpp
@@ -30,6 +30,7 @@
#include "addnewtorrentdialog.h"
#include
+#include
#include
#include
@@ -38,6 +39,7 @@
#include
#include
#include
+#include
#include
#include
#include
@@ -69,6 +71,7 @@ namespace
#define SETTINGS_KEY(name) u"AddNewTorrentDialog/" name
const QString KEY_ENABLED = SETTINGS_KEY(u"Enabled"_s);
const QString KEY_TOPLEVEL = SETTINGS_KEY(u"TopLevel"_s);
+ const QString KEY_ATTACHED = SETTINGS_KEY(u"Attached"_s);
const QString KEY_SAVEPATHHISTORY = SETTINGS_KEY(u"SavePathHistory"_s);
const QString KEY_DOWNLOADPATHHISTORY = SETTINGS_KEY(u"DownloadPathHistory"_s);
const QString KEY_SAVEPATHHISTORYLENGTH = SETTINGS_KEY(u"SavePathHistoryLength"_s);
@@ -133,6 +136,36 @@ namespace
settings()->storeValue(settingsKey, QStringList(pathList.mid(0, maxLength)));
}
+
+ void adjustDialogGeometry(QWidget *dialog, const QWidget *parentWindow)
+ {
+ // It is preferable to place the dialog in the center of the parent window.
+ // However, if it goes beyond the current screen, then move it so that it fits there
+ // (or, if the dialog is larger than the current screen, at least make sure that
+ // the upper/left coordinates of the dialog are inside it).
+
+ QRect dialogGeometry = dialog->geometry();
+
+ dialogGeometry.moveCenter(parentWindow->geometry().center());
+
+ const QRect screenGeometry = parentWindow->screen()->availableGeometry();
+
+ QPoint delta = screenGeometry.bottomRight() - dialogGeometry.bottomRight();
+ if (delta.x() > 0)
+ delta.setX(0);
+ if (delta.y() > 0)
+ delta.setY(0);
+ dialogGeometry.translate(delta);
+
+ delta = screenGeometry.topLeft() - dialogGeometry.topLeft();
+ if (delta.x() < 0)
+ delta.setX(0);
+ if (delta.y() < 0)
+ delta.setY(0);
+ dialogGeometry.translate(delta);
+
+ dialog->setGeometry(dialogGeometry);
+ }
}
class AddNewTorrentDialog::TorrentContentAdaptor final
@@ -140,10 +173,11 @@ class AddNewTorrentDialog::TorrentContentAdaptor final
{
public:
TorrentContentAdaptor(BitTorrent::TorrentInfo &torrentInfo, PathList &filePaths
- , QVector &filePriorities)
+ , QVector &filePriorities, std::function onFilePrioritiesChanged)
: m_torrentInfo {torrentInfo}
, m_filePaths {filePaths}
, m_filePriorities {filePriorities}
+ , m_onFilePrioritiesChanged {std::move(onFilePrioritiesChanged)}
{
Q_ASSERT(filePaths.isEmpty() || (filePaths.size() == torrentInfo.filesCount()));
@@ -254,6 +288,8 @@ public:
{
Q_ASSERT(priorities.size() == filesCount());
m_filePriorities = priorities;
+ if (m_onFilePrioritiesChanged)
+ m_onFilePrioritiesChanged();
}
Path actualStorageLocation() const override
@@ -274,6 +310,7 @@ private:
BitTorrent::TorrentInfo &m_torrentInfo;
PathList &m_filePaths;
QVector &m_filePriorities;
+ std::function m_onFilePrioritiesChanged;
Path m_originalRootFolder;
BitTorrent::TorrentContentLayout m_currentContentLayout;
};
@@ -330,7 +367,7 @@ AddNewTorrentDialog::AddNewTorrentDialog(const BitTorrent::AddTorrentParams &inP
m_ui->stopConditionComboBox->setItemData(1, QVariant::fromValue(BitTorrent::Torrent::StopCondition::MetadataReceived));
m_ui->stopConditionComboBox->setItemData(2, QVariant::fromValue(BitTorrent::Torrent::StopCondition::FilesChecked));
m_ui->stopConditionComboBox->setCurrentIndex(m_ui->stopConditionComboBox->findData(
- QVariant::fromValue(m_torrentParams.stopCondition.value_or(session->torrentStopCondition()))));
+ QVariant::fromValue(m_torrentParams.stopCondition.value_or(session->torrentStopCondition()))));
m_ui->stopConditionLabel->setEnabled(m_ui->startTorrentCheckBox->isChecked());
m_ui->stopConditionComboBox->setEnabled(m_ui->startTorrentCheckBox->isChecked());
connect(m_ui->startTorrentCheckBox, &QCheckBox::toggled, this, [this](const bool checked)
@@ -351,7 +388,7 @@ AddNewTorrentDialog::AddNewTorrentDialog(const BitTorrent::AddTorrentParams &inP
m_ui->checkBoxRememberLastSavePath->setChecked(m_storeRememberLastSavePath);
m_ui->contentLayoutComboBox->setCurrentIndex(
- static_cast(m_torrentParams.contentLayout.value_or(session->torrentContentLayout())));
+ static_cast(m_torrentParams.contentLayout.value_or(session->torrentContentLayout())));
connect(m_ui->contentLayoutComboBox, &QComboBox::currentIndexChanged, this, &AddNewTorrentDialog::contentLayoutChanged);
m_ui->sequentialCheckBox->setChecked(m_torrentParams.sequential);
@@ -471,6 +508,18 @@ void AddNewTorrentDialog::setSavePathHistoryLength(const int value)
, QStringList(settings()->loadValue(KEY_SAVEPATHHISTORY).mid(0, clampedValue)));
}
+#ifndef Q_OS_MACOS
+void AddNewTorrentDialog::setAttached(const bool value)
+{
+ settings()->storeValue(KEY_ATTACHED, value);
+}
+
+bool AddNewTorrentDialog::isAttached()
+{
+ return settings()->loadValue(KEY_ATTACHED, false);
+}
+#endif
+
void AddNewTorrentDialog::loadState()
{
if (const QSize dialogSize = m_storeDialogSize; dialogSize.isValid())
@@ -489,12 +538,24 @@ void AddNewTorrentDialog::saveState()
void AddNewTorrentDialog::show(const QString &source, const BitTorrent::AddTorrentParams &inParams, QWidget *parent)
{
- auto *dlg = new AddNewTorrentDialog(inParams, parent);
+ const auto *pref = Preferences::instance();
+#ifdef Q_OS_MACOS
+ const bool attached = false;
+#else
+ const bool attached = isAttached();
+#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(inParams, (attached ? parent : nullptr));
+ // Qt::Window is required to avoid showing only two dialog on top (see #12852).
+ // Also improves the general convenience of adding multiple torrents.
+ if (!attached)
+ dlg->setWindowFlags(Qt::Window);
dlg->setAttribute(Qt::WA_DeleteOnClose);
if (Net::DownloadManager::hasSupportedScheme(source))
{
- const auto *pref = Preferences::instance();
// Launch downloader
Net::DownloadManager::instance()->download(
Net::DownloadRequest(source).limit(pref->getTorrentFileSizeLimit())
@@ -509,9 +570,14 @@ void AddNewTorrentDialog::show(const QString &source, const BitTorrent::AddTorre
: dlg->loadTorrentFile(source);
if (isLoaded)
+ {
+ adjustDialogGeometry(dlg, parent);
dlg->QDialog::show();
+ }
else
+ {
delete dlg;
+ }
}
void AddNewTorrentDialog::show(const QString &source, QWidget *parent)
@@ -742,7 +808,7 @@ void AddNewTorrentDialog::contentLayoutChanged()
const auto contentLayout = static_cast(m_ui->contentLayoutComboBox->currentIndex());
m_contentAdaptor->applyContentLayout(contentLayout);
- m_ui->contentTreeView->setContentHandler(m_contentAdaptor); // to cause reloading
+ m_ui->contentTreeView->setContentHandler(m_contentAdaptor.get()); // to cause reloading
}
void AddNewTorrentDialog::saveTorrentFile()
@@ -927,6 +993,9 @@ void AddNewTorrentDialog::updateMetadata(const BitTorrent::TorrentInfo &metadata
// Good to go
m_torrentInfo = metadata;
setMetadataProgressIndicator(true, tr("Parsing metadata..."));
+ const auto stopCondition = m_ui->stopConditionComboBox->currentData().value();
+ if (stopCondition == BitTorrent::Torrent::StopCondition::MetadataReceived)
+ m_ui->startTorrentCheckBox->setChecked(false);
// Update UI
setupTreeview();
@@ -964,7 +1033,8 @@ void AddNewTorrentDialog::setupTreeview()
if (m_torrentParams.filePaths.isEmpty())
m_torrentParams.filePaths = m_torrentInfo.filePaths();
- m_contentAdaptor = new TorrentContentAdaptor(m_torrentInfo, m_torrentParams.filePaths, m_torrentParams.filePriorities);
+ m_contentAdaptor = std::make_unique(m_torrentInfo, m_torrentParams.filePaths
+ , m_torrentParams.filePriorities, [this] { updateDiskSpaceLabel(); });
const auto contentLayout = static_cast(m_ui->contentLayoutComboBox->currentIndex());
m_contentAdaptor->applyContentLayout(contentLayout);
@@ -985,7 +1055,7 @@ void AddNewTorrentDialog::setupTreeview()
m_contentAdaptor->prioritizeFiles(priorities);
}
- m_ui->contentTreeView->setContentHandler(m_contentAdaptor);
+ m_ui->contentTreeView->setContentHandler(m_contentAdaptor.get());
m_filterLine->blockSignals(false);
diff --git a/src/gui/addnewtorrentdialog.h b/src/gui/addnewtorrentdialog.h
index 2a830e14b..910275344 100644
--- a/src/gui/addnewtorrentdialog.h
+++ b/src/gui/addnewtorrentdialog.h
@@ -74,6 +74,10 @@ public:
static void setTopLevel(bool value);
static int savePathHistoryLength();
static void setSavePathHistoryLength(int value);
+#ifndef Q_OS_MACOS
+ static bool isAttached();
+ static void setAttached(bool value);
+#endif
static void show(const QString &source, const BitTorrent::AddTorrentParams &inParams, QWidget *parent);
static void show(const QString &source, QWidget *parent);
@@ -112,7 +116,7 @@ private:
void showEvent(QShowEvent *event) override;
Ui::AddNewTorrentDialog *m_ui = nullptr;
- TorrentContentAdaptor *m_contentAdaptor = nullptr;
+ std::unique_ptr m_contentAdaptor;
BitTorrent::MagnetUri m_magnetURI;
BitTorrent::TorrentInfo m_torrentInfo;
int m_savePathIndex = -1;
diff --git a/src/gui/advancedsettings.cpp b/src/gui/advancedsettings.cpp
index 0d0ce6642..b116f2d4d 100644
--- a/src/gui/advancedsettings.cpp
+++ b/src/gui/advancedsettings.cpp
@@ -63,7 +63,7 @@ namespace
// qBittorrent section
QBITTORRENT_HEADER,
RESUME_DATA_STORAGE,
-#ifdef QBT_USES_LIBTORRENT2
+#if defined(QBT_USES_LIBTORRENT2) && !defined(Q_OS_MACOS)
MEMORY_WORKING_SET_LIMIT,
#endif
#if defined(Q_OS_WIN)
@@ -94,6 +94,7 @@ namespace
ENABLE_SPEED_WIDGET,
#ifndef Q_OS_MACOS
ENABLE_ICONS_IN_MENUS,
+ USE_ATTACHED_ADD_NEW_TORRENT_DIALOG,
#endif
// embedded tracker
TRACKER_STATUS,
@@ -194,7 +195,7 @@ void AdvancedSettings::saveAdvancedSettings() const
BitTorrent::Session *const session = BitTorrent::Session::instance();
session->setResumeDataStorageType(m_comboBoxResumeDataStorage.currentData().value());
-#ifdef QBT_USES_LIBTORRENT2
+#if defined(QBT_USES_LIBTORRENT2) && !defined(Q_OS_MACOS)
// Physical memory (RAM) usage limit
app()->setMemoryWorkingSetLimit(m_spinBoxMemoryWorkingSetLimit.value());
#endif
@@ -310,6 +311,7 @@ void AdvancedSettings::saveAdvancedSettings() const
pref->setSpeedWidgetEnabled(m_checkBoxSpeedWidgetEnabled.isChecked());
#ifndef Q_OS_MACOS
pref->setIconsInMenusEnabled(m_checkBoxIconsInMenusEnabled.isChecked());
+ AddNewTorrentDialog::setAttached(m_checkBoxAttachedAddNewTorrentDialog.isChecked());
#endif
// Tracker
@@ -449,7 +451,7 @@ void AdvancedSettings::loadAdvancedSettings()
m_comboBoxResumeDataStorage.setCurrentIndex(m_comboBoxResumeDataStorage.findData(QVariant::fromValue(session->resumeDataStorageType())));
addRow(RESUME_DATA_STORAGE, tr("Resume data storage type (requires restart)"), &m_comboBoxResumeDataStorage);
-#ifdef QBT_USES_LIBTORRENT2
+#if defined(QBT_USES_LIBTORRENT2) && !defined(Q_OS_MACOS)
// Physical memory (RAM) usage limit
m_spinBoxMemoryWorkingSetLimit.setMinimum(1);
m_spinBoxMemoryWorkingSetLimit.setMaximum(std::numeric_limits::max());
@@ -796,6 +798,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(AddNewTorrentDialog::isAttached());
+ 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());
diff --git a/src/gui/advancedsettings.h b/src/gui/advancedsettings.h
index 1cb869e9e..3622fa787 100644
--- a/src/gui/advancedsettings.h
+++ b/src/gui/advancedsettings.h
@@ -30,6 +30,7 @@
#include
+#include
#include
#include
#include
@@ -88,7 +89,11 @@ private:
QCheckBox m_checkBoxCoalesceRW;
#else
QComboBox m_comboBoxDiskIOType;
- QSpinBox m_spinBoxMemoryWorkingSetLimit, m_spinBoxHashingThreads;
+ QSpinBox m_spinBoxHashingThreads;
+#endif
+
+#if defined(QBT_USES_LIBTORRENT2) && !defined(Q_OS_MACOS)
+ QSpinBox m_spinBoxMemoryWorkingSetLimit;
#endif
#if defined(QBT_USES_LIBTORRENT2) && TORRENT_USE_I2P
@@ -102,6 +107,7 @@ private:
#ifndef Q_OS_MACOS
QCheckBox m_checkBoxIconsInMenusEnabled;
+ QCheckBox m_checkBoxAttachedAddNewTorrentDialog;
#endif
#ifdef QBT_USES_DBUS
diff --git a/src/gui/desktopintegration.cpp b/src/gui/desktopintegration.cpp
index 2be2bc69d..f8a4c85cb 100644
--- a/src/gui/desktopintegration.cpp
+++ b/src/gui/desktopintegration.cpp
@@ -286,17 +286,25 @@ void DesktopIntegration::createTrayIcon()
QIcon DesktopIntegration::getSystrayIcon() const
{
const TrayIcon::Style style = Preferences::instance()->trayIconStyle();
+ QIcon icon;
switch (style)
{
default:
case TrayIcon::Style::Normal:
- return UIThemeManager::instance()->getIcon(u"qbittorrent-tray"_s);
-
+ icon = UIThemeManager::instance()->getIcon(u"qbittorrent-tray"_s);
+ break;
case TrayIcon::Style::MonoDark:
- return UIThemeManager::instance()->getIcon(u"qbittorrent-tray-dark"_s);
-
+ icon = UIThemeManager::instance()->getIcon(u"qbittorrent-tray-dark"_s);
+ break;
case TrayIcon::Style::MonoLight:
- return UIThemeManager::instance()->getIcon(u"qbittorrent-tray-light"_s);
+ icon = UIThemeManager::instance()->getIcon(u"qbittorrent-tray-light"_s);
+ break;
}
+#if ((QT_VERSION < QT_VERSION_CHECK(6, 0, 0)) && defined(Q_OS_UNIX) && !defined(Q_OS_MACOS))
+ // Workaround for invisible tray icon in KDE, https://bugreports.qt.io/browse/QTBUG-53550
+ return {icon.pixmap(32)};
+#else
+ return icon;
+#endif
}
#endif // Q_OS_MACOS
diff --git a/src/gui/ipsubnetwhitelistoptionsdialog.cpp b/src/gui/ipsubnetwhitelistoptionsdialog.cpp
index 78af3610f..11556422c 100644
--- a/src/gui/ipsubnetwhitelistoptionsdialog.cpp
+++ b/src/gui/ipsubnetwhitelistoptionsdialog.cpp
@@ -50,7 +50,7 @@ IPSubnetWhitelistOptionsDialog::IPSubnetWhitelistOptionsDialog(QWidget *parent)
connect(m_ui->buttonBox, &QDialogButtonBox::rejected, this, &QDialog::reject);
QStringList authSubnetWhitelistStringList;
- for (const Utils::Net::Subnet &subnet : asConst(Preferences::instance()->getWebUiAuthSubnetWhitelist()))
+ for (const Utils::Net::Subnet &subnet : asConst(Preferences::instance()->getWebUIAuthSubnetWhitelist()))
authSubnetWhitelistStringList << Utils::Net::subnetToString(subnet);
m_model = new QStringListModel(authSubnetWhitelistStringList, this);
@@ -81,7 +81,7 @@ void IPSubnetWhitelistOptionsDialog::on_buttonBox_accepted()
// Operate on the m_sortFilter to grab the strings in sorted order
for (int i = 0; i < m_sortFilter->rowCount(); ++i)
subnets.append(m_sortFilter->index(i, 0).data().toString());
- Preferences::instance()->setWebUiAuthSubnetWhitelist(subnets);
+ Preferences::instance()->setWebUIAuthSubnetWhitelist(subnets);
QDialog::accept();
}
else
diff --git a/src/gui/lineedit.cpp b/src/gui/lineedit.cpp
index b6ad0af76..f388fab60 100644
--- a/src/gui/lineedit.cpp
+++ b/src/gui/lineedit.cpp
@@ -38,7 +38,7 @@
LineEdit::LineEdit(QWidget *parent)
: QLineEdit(parent)
{
- auto *action = new QAction(UIThemeManager::instance()->getIcon(u"edit-find"_s), QString());
+ auto *action = new QAction(UIThemeManager::instance()->getIcon(u"edit-find"_s), QString(), this);
addAction(action, QLineEdit::LeadingPosition);
setClearButtonEnabled(true);
diff --git a/src/gui/mainwindow.cpp b/src/gui/mainwindow.cpp
index 6ecdc1972..3edf3f74f 100644
--- a/src/gui/mainwindow.cpp
+++ b/src/gui/mainwindow.cpp
@@ -174,7 +174,7 @@ MainWindow::MainWindow(IGUIApplication *app, WindowState initialState)
m_ui->menuLog->setIcon(UIThemeManager::instance()->getIcon(u"help-contents"_s));
m_ui->actionCheckForUpdates->setIcon(UIThemeManager::instance()->getIcon(u"view-refresh"_s));
- auto *lockMenu = new QMenu(this);
+ auto *lockMenu = new QMenu(m_ui->menuView);
lockMenu->addAction(tr("&Set Password"), this, &MainWindow::defineUILockPassword);
lockMenu->addAction(tr("&Clear Password"), this, &MainWindow::clearUILockPassword);
m_ui->actionLock->setMenu(lockMenu);
@@ -455,8 +455,6 @@ MainWindow::MainWindow(IGUIApplication *app, WindowState initialState)
}
#endif
- m_propertiesWidget->readSettings();
-
const bool isFiltersSidebarVisible = pref->isFiltersSidebarVisible();
m_ui->actionShowFiltersSidebar->setChecked(isFiltersSidebarVisible);
if (isFiltersSidebarVisible)
@@ -1092,6 +1090,12 @@ void MainWindow::showEvent(QShowEvent *e)
{
// preparations before showing the window
+ if (m_neverShown)
+ {
+ m_propertiesWidget->readSettings();
+ m_neverShown = false;
+ }
+
if (currentTabWidget() == m_transferListWidget)
m_propertiesWidget->loadDynamicData();
@@ -1178,7 +1182,7 @@ void MainWindow::closeEvent(QCloseEvent *e)
if (!isVisible())
show();
QMessageBox confirmBox(QMessageBox::Question, tr("Exiting qBittorrent"),
- // Split it because the last sentence is used in the Web UI
+ // Split it because the last sentence is used in the WebUI
tr("Some files are currently transferring.") + u'\n' + tr("Are you sure you want to quit qBittorrent?"),
QMessageBox::NoButton, this);
QPushButton *noBtn = confirmBox.addButton(tr("&No"), QMessageBox::NoRole);
diff --git a/src/gui/mainwindow.h b/src/gui/mainwindow.h
index 1c484fe7e..0566c7050 100644
--- a/src/gui/mainwindow.h
+++ b/src/gui/mainwindow.h
@@ -202,6 +202,7 @@ private:
QFileSystemWatcher *m_executableWatcher = nullptr;
// GUI related
bool m_posInitialized = false;
+ bool m_neverShown = true;
QPointer m_tabs;
QPointer m_statusBar;
QPointer m_options;
diff --git a/src/gui/optionsdialog.cpp b/src/gui/optionsdialog.cpp
index d043dfbb6..0c20158f3 100644
--- a/src/gui/optionsdialog.cpp
+++ b/src/gui/optionsdialog.cpp
@@ -69,13 +69,21 @@
#include "utils.h"
#include "watchedfolderoptionsdialog.h"
#include "watchedfoldersmodel.h"
+#include "webui/webui.h"
#ifndef DISABLE_WEBUI
#include "base/net/dnsupdater.h"
#endif
+#if defined Q_OS_MACOS || defined Q_OS_WIN
+#include "base/utils/os.h"
+#endif // defined Q_OS_MACOS || defined Q_OS_WIN
+
#define SETTINGS_KEY(name) u"OptionsDialog/" name
+const int WEBUI_MIN_USERNAME_LENGTH = 3;
+const int WEBUI_MIN_PASSWORD_LENGTH = 6;
+
namespace
{
QStringList translatedWeekdayNames()
@@ -102,6 +110,16 @@ namespace
}
};
+ bool isValidWebUIUsername(const QString &username)
+ {
+ return (username.length() >= WEBUI_MIN_USERNAME_LENGTH);
+ }
+
+ bool isValidWebUIPassword(const QString &password)
+ {
+ return (password.length() >= WEBUI_MIN_PASSWORD_LENGTH);
+ }
+
// Shortcuts for frequently used signals that have more than one overload. They would require
// type casts and that is why we declare required member pointer here instead.
void (QComboBox::*qComboBoxCurrentIndexChanged)(int) = &QComboBox::currentIndexChanged;
@@ -171,7 +189,11 @@ OptionsDialog::OptionsDialog(IGUIApplication *app, QWidget *parent)
// setup apply button
m_applyButton->setEnabled(false);
- connect(m_applyButton, &QPushButton::clicked, this, &OptionsDialog::applySettings);
+ connect(m_applyButton, &QPushButton::clicked, this, [this]
+ {
+ if (applySettings())
+ m_applyButton->setEnabled(false);
+ });
// disable mouse wheel event on widgets to avoid misselection
auto *wheelEventEater = new WheelEventEater(this);
@@ -284,15 +306,15 @@ void OptionsDialog::loadBehaviorTabOptions()
#ifdef Q_OS_WIN
m_ui->checkStartup->setChecked(pref->WinStartup());
- m_ui->checkAssociateTorrents->setChecked(Preferences::isTorrentFileAssocSet());
- m_ui->checkAssociateMagnetLinks->setChecked(Preferences::isMagnetLinkAssocSet());
+ m_ui->checkAssociateTorrents->setChecked(Utils::OS::isTorrentFileAssocSet());
+ m_ui->checkAssociateMagnetLinks->setChecked(Utils::OS::isMagnetLinkAssocSet());
#endif
#ifdef Q_OS_MACOS
m_ui->checkShowSystray->setVisible(false);
- m_ui->checkAssociateTorrents->setChecked(Preferences::isTorrentFileAssocSet());
+ m_ui->checkAssociateTorrents->setChecked(Utils::OS::isTorrentFileAssocSet());
m_ui->checkAssociateTorrents->setEnabled(!m_ui->checkAssociateTorrents->isChecked());
- m_ui->checkAssociateMagnetLinks->setChecked(Preferences::isMagnetLinkAssocSet());
+ m_ui->checkAssociateMagnetLinks->setChecked(Utils::OS::isMagnetLinkAssocSet());
m_ui->checkAssociateMagnetLinks->setEnabled(!m_ui->checkAssociateMagnetLinks->isChecked());
#endif
@@ -433,8 +455,8 @@ void OptionsDialog::saveBehaviorTabOptions() const
#ifdef Q_OS_WIN
pref->setWinStartup(WinStartup());
- Preferences::setTorrentFileAssoc(m_ui->checkAssociateTorrents->isChecked());
- Preferences::setMagnetLinkAssoc(m_ui->checkAssociateMagnetLinks->isChecked());
+ Utils::OS::setTorrentFileAssoc(m_ui->checkAssociateTorrents->isChecked());
+ Utils::OS::setMagnetLinkAssoc(m_ui->checkAssociateMagnetLinks->isChecked());
#endif
#ifndef Q_OS_MACOS
@@ -447,14 +469,14 @@ void OptionsDialog::saveBehaviorTabOptions() const
#ifdef Q_OS_MACOS
if (m_ui->checkAssociateTorrents->isChecked())
{
- Preferences::setTorrentFileAssoc();
- m_ui->checkAssociateTorrents->setChecked(Preferences::isTorrentFileAssocSet());
+ Utils::OS::setTorrentFileAssoc();
+ m_ui->checkAssociateTorrents->setChecked(Utils::OS::isTorrentFileAssocSet());
m_ui->checkAssociateTorrents->setEnabled(!m_ui->checkAssociateTorrents->isChecked());
}
if (m_ui->checkAssociateMagnetLinks->isChecked())
{
- Preferences::setMagnetLinkAssoc();
- m_ui->checkAssociateMagnetLinks->setChecked(Preferences::isMagnetLinkAssocSet());
+ Utils::OS::setMagnetLinkAssoc();
+ m_ui->checkAssociateMagnetLinks->setChecked(Utils::OS::isMagnetLinkAssocSet());
m_ui->checkAssociateMagnetLinks->setEnabled(!m_ui->checkAssociateMagnetLinks->isChecked());
}
#endif
@@ -1207,28 +1229,33 @@ void OptionsDialog::loadWebUITabOptions()
m_ui->textWebUIRootFolder->setMode(FileSystemPathEdit::Mode::DirectoryOpen);
m_ui->textWebUIRootFolder->setDialogCaption(tr("Choose Alternative UI files location"));
- m_ui->checkWebUi->setChecked(pref->isWebUiEnabled());
- m_ui->textWebUiAddress->setText(pref->getWebUiAddress());
- m_ui->spinWebUiPort->setValue(pref->getWebUiPort());
+ if (app()->webUI()->isErrored())
+ m_ui->labelWebUIError->setText(tr("WebUI configuration failed. Reason: %1").arg(app()->webUI()->errorMessage()));
+ else
+ m_ui->labelWebUIError->hide();
+
+ m_ui->checkWebUI->setChecked(pref->isWebUIEnabled());
+ m_ui->textWebUIAddress->setText(pref->getWebUIAddress());
+ m_ui->spinWebUIPort->setValue(pref->getWebUIPort());
m_ui->checkWebUIUPnP->setChecked(pref->useUPnPForWebUIPort());
- m_ui->checkWebUiHttps->setChecked(pref->isWebUiHttpsEnabled());
+ m_ui->checkWebUIHttps->setChecked(pref->isWebUIHttpsEnabled());
webUIHttpsCertChanged(pref->getWebUIHttpsCertificatePath());
webUIHttpsKeyChanged(pref->getWebUIHttpsKeyPath());
- m_ui->textWebUiUsername->setText(pref->getWebUiUsername());
- m_ui->checkBypassLocalAuth->setChecked(!pref->isWebUiLocalAuthEnabled());
- m_ui->checkBypassAuthSubnetWhitelist->setChecked(pref->isWebUiAuthSubnetWhitelistEnabled());
+ m_ui->textWebUIUsername->setText(pref->getWebUIUsername());
+ m_ui->checkBypassLocalAuth->setChecked(!pref->isWebUILocalAuthEnabled());
+ m_ui->checkBypassAuthSubnetWhitelist->setChecked(pref->isWebUIAuthSubnetWhitelistEnabled());
m_ui->IPSubnetWhitelistButton->setEnabled(m_ui->checkBypassAuthSubnetWhitelist->isChecked());
m_ui->spinBanCounter->setValue(pref->getWebUIMaxAuthFailCount());
m_ui->spinBanDuration->setValue(pref->getWebUIBanDuration().count());
m_ui->spinSessionTimeout->setValue(pref->getWebUISessionTimeout());
// Alternative UI
- m_ui->groupAltWebUI->setChecked(pref->isAltWebUiEnabled());
- m_ui->textWebUIRootFolder->setSelectedPath(pref->getWebUiRootFolder());
+ m_ui->groupAltWebUI->setChecked(pref->isAltWebUIEnabled());
+ m_ui->textWebUIRootFolder->setSelectedPath(pref->getWebUIRootFolder());
// Security
- m_ui->checkClickjacking->setChecked(pref->isWebUiClickjackingProtectionEnabled());
- m_ui->checkCSRFProtection->setChecked(pref->isWebUiCSRFProtectionEnabled());
- m_ui->checkSecureCookie->setEnabled(pref->isWebUiHttpsEnabled());
- m_ui->checkSecureCookie->setChecked(pref->isWebUiSecureCookieEnabled());
+ m_ui->checkClickjacking->setChecked(pref->isWebUIClickjackingProtectionEnabled());
+ m_ui->checkCSRFProtection->setChecked(pref->isWebUICSRFProtectionEnabled());
+ m_ui->checkSecureCookie->setEnabled(pref->isWebUIHttpsEnabled());
+ m_ui->checkSecureCookie->setChecked(pref->isWebUISecureCookieEnabled());
m_ui->groupHostHeaderValidation->setChecked(pref->isWebUIHostHeaderValidationEnabled());
m_ui->textServerDomains->setText(pref->getServerDomains());
// Custom HTTP headers
@@ -1244,18 +1271,18 @@ void OptionsDialog::loadWebUITabOptions()
m_ui->DNSUsernameTxt->setText(pref->getDynDNSUsername());
m_ui->DNSPasswordTxt->setText(pref->getDynDNSPassword());
- connect(m_ui->checkWebUi, &QGroupBox::toggled, this, &ThisType::enableApplyButton);
- connect(m_ui->textWebUiAddress, &QLineEdit::textChanged, this, &ThisType::enableApplyButton);
- connect(m_ui->spinWebUiPort, qSpinBoxValueChanged, this, &ThisType::enableApplyButton);
+ connect(m_ui->checkWebUI, &QGroupBox::toggled, this, &ThisType::enableApplyButton);
+ connect(m_ui->textWebUIAddress, &QLineEdit::textChanged, this, &ThisType::enableApplyButton);
+ connect(m_ui->spinWebUIPort, qSpinBoxValueChanged, this, &ThisType::enableApplyButton);
connect(m_ui->checkWebUIUPnP, &QAbstractButton::toggled, this, &ThisType::enableApplyButton);
- connect(m_ui->checkWebUiHttps, &QGroupBox::toggled, this, &ThisType::enableApplyButton);
+ connect(m_ui->checkWebUIHttps, &QGroupBox::toggled, this, &ThisType::enableApplyButton);
connect(m_ui->textWebUIHttpsCert, &FileSystemPathLineEdit::selectedPathChanged, this, &ThisType::enableApplyButton);
connect(m_ui->textWebUIHttpsCert, &FileSystemPathLineEdit::selectedPathChanged, this, &OptionsDialog::webUIHttpsCertChanged);
connect(m_ui->textWebUIHttpsKey, &FileSystemPathLineEdit::selectedPathChanged, this, &ThisType::enableApplyButton);
connect(m_ui->textWebUIHttpsKey, &FileSystemPathLineEdit::selectedPathChanged, this, &OptionsDialog::webUIHttpsKeyChanged);
- connect(m_ui->textWebUiUsername, &QLineEdit::textChanged, this, &ThisType::enableApplyButton);
- connect(m_ui->textWebUiPassword, &QLineEdit::textChanged, this, &ThisType::enableApplyButton);
+ connect(m_ui->textWebUIUsername, &QLineEdit::textChanged, this, &ThisType::enableApplyButton);
+ connect(m_ui->textWebUIPassword, &QLineEdit::textChanged, this, &ThisType::enableApplyButton);
connect(m_ui->checkBypassLocalAuth, &QAbstractButton::toggled, this, &ThisType::enableApplyButton);
connect(m_ui->checkBypassAuthSubnetWhitelist, &QAbstractButton::toggled, this, &ThisType::enableApplyButton);
@@ -1269,7 +1296,7 @@ void OptionsDialog::loadWebUITabOptions()
connect(m_ui->checkClickjacking, &QCheckBox::toggled, this, &ThisType::enableApplyButton);
connect(m_ui->checkCSRFProtection, &QCheckBox::toggled, this, &ThisType::enableApplyButton);
- connect(m_ui->checkWebUiHttps, &QGroupBox::toggled, m_ui->checkSecureCookie, &QWidget::setEnabled);
+ connect(m_ui->checkWebUIHttps, &QGroupBox::toggled, m_ui->checkSecureCookie, &QWidget::setEnabled);
connect(m_ui->checkSecureCookie, &QCheckBox::toggled, this, &ThisType::enableApplyButton);
connect(m_ui->groupHostHeaderValidation, &QGroupBox::toggled, this, &ThisType::enableApplyButton);
connect(m_ui->textServerDomains, &QLineEdit::textChanged, this, &ThisType::enableApplyButton);
@@ -1291,29 +1318,32 @@ void OptionsDialog::saveWebUITabOptions() const
{
auto *pref = Preferences::instance();
- pref->setWebUiEnabled(isWebUiEnabled());
- pref->setWebUiAddress(m_ui->textWebUiAddress->text());
- pref->setWebUiPort(m_ui->spinWebUiPort->value());
+ const bool webUIEnabled = isWebUIEnabled();
+
+ pref->setWebUIEnabled(webUIEnabled);
+ pref->setWebUIAddress(m_ui->textWebUIAddress->text());
+ pref->setWebUIPort(m_ui->spinWebUIPort->value());
pref->setUPnPForWebUIPort(m_ui->checkWebUIUPnP->isChecked());
- pref->setWebUiHttpsEnabled(m_ui->checkWebUiHttps->isChecked());
+ pref->setWebUIHttpsEnabled(m_ui->checkWebUIHttps->isChecked());
pref->setWebUIHttpsCertificatePath(m_ui->textWebUIHttpsCert->selectedPath());
pref->setWebUIHttpsKeyPath(m_ui->textWebUIHttpsKey->selectedPath());
pref->setWebUIMaxAuthFailCount(m_ui->spinBanCounter->value());
pref->setWebUIBanDuration(std::chrono::seconds {m_ui->spinBanDuration->value()});
pref->setWebUISessionTimeout(m_ui->spinSessionTimeout->value());
// Authentication
- pref->setWebUiUsername(webUiUsername());
- if (!webUiPassword().isEmpty())
- pref->setWebUIPassword(Utils::Password::PBKDF2::generate(webUiPassword()));
- pref->setWebUiLocalAuthEnabled(!m_ui->checkBypassLocalAuth->isChecked());
- pref->setWebUiAuthSubnetWhitelistEnabled(m_ui->checkBypassAuthSubnetWhitelist->isChecked());
+ if (const QString username = webUIUsername(); isValidWebUIUsername(username))
+ pref->setWebUIUsername(username);
+ if (const QString password = webUIPassword(); isValidWebUIPassword(password))
+ pref->setWebUIPassword(Utils::Password::PBKDF2::generate(password));
+ pref->setWebUILocalAuthEnabled(!m_ui->checkBypassLocalAuth->isChecked());
+ pref->setWebUIAuthSubnetWhitelistEnabled(m_ui->checkBypassAuthSubnetWhitelist->isChecked());
// Alternative UI
- pref->setAltWebUiEnabled(m_ui->groupAltWebUI->isChecked());
- pref->setWebUiRootFolder(m_ui->textWebUIRootFolder->selectedPath());
+ pref->setAltWebUIEnabled(m_ui->groupAltWebUI->isChecked());
+ pref->setWebUIRootFolder(m_ui->textWebUIRootFolder->selectedPath());
// Security
- pref->setWebUiClickjackingProtectionEnabled(m_ui->checkClickjacking->isChecked());
- pref->setWebUiCSRFProtectionEnabled(m_ui->checkCSRFProtection->isChecked());
- pref->setWebUiSecureCookieEnabled(m_ui->checkSecureCookie->isChecked());
+ pref->setWebUIClickjackingProtectionEnabled(m_ui->checkClickjacking->isChecked());
+ pref->setWebUICSRFProtectionEnabled(m_ui->checkCSRFProtection->isChecked());
+ pref->setWebUISecureCookieEnabled(m_ui->checkSecureCookie->isChecked());
pref->setWebUIHostHeaderValidationEnabled(m_ui->groupHostHeaderValidation->isChecked());
pref->setServerDomains(m_ui->textServerDomains->text());
// Custom HTTP headers
@@ -1513,53 +1543,37 @@ void OptionsDialog::on_buttonBox_accepted()
{
if (m_applyButton->isEnabled())
{
- if (!schedTimesOk())
- {
- m_ui->tabSelection->setCurrentRow(TAB_SPEED);
+ if (!applySettings())
return;
- }
-#ifndef DISABLE_WEBUI
- if (!webUIAuthenticationOk())
- {
- m_ui->tabSelection->setCurrentRow(TAB_WEBUI);
- return;
- }
- if (!isAlternativeWebUIPathValid())
- {
- m_ui->tabSelection->setCurrentRow(TAB_WEBUI);
- return;
- }
-#endif
m_applyButton->setEnabled(false);
- saveOptions();
}
accept();
}
-void OptionsDialog::applySettings()
+bool OptionsDialog::applySettings()
{
if (!schedTimesOk())
{
m_ui->tabSelection->setCurrentRow(TAB_SPEED);
- return;
+ return false;
}
#ifndef DISABLE_WEBUI
- if (!webUIAuthenticationOk())
+ if (isWebUIEnabled() && !webUIAuthenticationOk())
{
m_ui->tabSelection->setCurrentRow(TAB_WEBUI);
- return;
+ return false;
}
if (!isAlternativeWebUIPathValid())
{
m_ui->tabSelection->setCurrentRow(TAB_WEBUI);
- return;
+ return false;
}
#endif
- m_applyButton->setEnabled(false);
saveOptions();
+ return true;
}
void OptionsDialog::on_buttonBox_rejected()
@@ -1855,31 +1869,33 @@ void OptionsDialog::webUIHttpsKeyChanged(const Path &path)
(isKeyValid ? u"security-high"_s : u"security-low"_s), 24));
}
-bool OptionsDialog::isWebUiEnabled() const
+bool OptionsDialog::isWebUIEnabled() const
{
- return m_ui->checkWebUi->isChecked();
+ return m_ui->checkWebUI->isChecked();
}
-QString OptionsDialog::webUiUsername() const
+QString OptionsDialog::webUIUsername() const
{
- return m_ui->textWebUiUsername->text();
+ return m_ui->textWebUIUsername->text();
}
-QString OptionsDialog::webUiPassword() const
+QString OptionsDialog::webUIPassword() const
{
- return m_ui->textWebUiPassword->text();
+ return m_ui->textWebUIPassword->text();
}
bool OptionsDialog::webUIAuthenticationOk()
{
- if (webUiUsername().length() < 3)
+ if (!isValidWebUIUsername(webUIUsername()))
{
- QMessageBox::warning(this, tr("Length Error"), tr("The Web UI username must be at least 3 characters long."));
+ QMessageBox::warning(this, tr("Length Error"), tr("The WebUI username must be at least 3 characters long."));
return false;
}
- if (!webUiPassword().isEmpty() && (webUiPassword().length() < 6))
+
+ const bool dontChangePassword = webUIPassword().isEmpty() && !Preferences::instance()->getWebUIPassword().isEmpty();
+ if (!isValidWebUIPassword(webUIPassword()) && !dontChangePassword)
{
- QMessageBox::warning(this, tr("Length Error"), tr("The Web UI password must be at least 6 characters long."));
+ QMessageBox::warning(this, tr("Length Error"), tr("The WebUI password must be at least 6 characters long."));
return false;
}
return true;
@@ -1889,7 +1905,7 @@ bool OptionsDialog::isAlternativeWebUIPathValid()
{
if (m_ui->groupAltWebUI->isChecked() && m_ui->textWebUIRootFolder->selectedPath().isEmpty())
{
- QMessageBox::warning(this, tr("Location Error"), tr("The alternative Web UI files location cannot be blank."));
+ QMessageBox::warning(this, tr("Location Error"), tr("The alternative WebUI files location cannot be blank."));
return false;
}
return true;
diff --git a/src/gui/optionsdialog.h b/src/gui/optionsdialog.h
index dfb5a75c8..8bcb64744 100644
--- a/src/gui/optionsdialog.h
+++ b/src/gui/optionsdialog.h
@@ -88,7 +88,6 @@ private slots:
void adjustProxyOptions();
void on_buttonBox_accepted();
void on_buttonBox_rejected();
- void applySettings();
void enableApplyButton();
void toggleComboRatioLimitAct();
void changePage(QListWidgetItem *, QListWidgetItem *);
@@ -115,6 +114,7 @@ private:
void showEvent(QShowEvent *e) override;
// Methods
+ bool applySettings();
void saveOptions() const;
void loadBehaviorTabOptions();
@@ -184,9 +184,9 @@ private:
int getMaxActiveTorrents() const;
// WebUI
#ifndef DISABLE_WEBUI
- bool isWebUiEnabled() const;
- QString webUiUsername() const;
- QString webUiPassword() const;
+ bool isWebUIEnabled() const;
+ QString webUIUsername() const;
+ QString webUIPassword() const;
bool webUIAuthenticationOk();
bool isAlternativeWebUIPathValid();
#endif
diff --git a/src/gui/optionsdialog.ui b/src/gui/optionsdialog.ui
index 089cbb849..4f7e826b3 100644
--- a/src/gui/optionsdialog.ui
+++ b/src/gui/optionsdialog.ui
@@ -3223,8 +3223,8 @@ Disable encryption: Only connect to peers without protocol encryption
-
-
+
+
0
@@ -3253,7 +3253,7 @@ Disable encryption: Only connect to peers without protocol encryption
-
-
+
Web User Interface (Remote control)
@@ -3264,17 +3264,29 @@ Disable encryption: Only connect to peers without protocol encryption
false
+
-
+
+
+
+ true
+
+
+
+
+
+
+
-
-
-
+
IP address:
-
-
+
IP address that the Web UI will bind to.
Specify an IPv4 or IPv6 address. You can specify "0.0.0.0" for any IPv4 address,
@@ -3283,14 +3295,14 @@ Specify an IPv4 or IPv6 address. You can specify "0.0.0.0" for any IPv
-
-
+
Port:
-
-
+
1
@@ -3315,7 +3327,7 @@ Specify an IPv4 or IPv6 address. You can specify "0.0.0.0" for any IPv
-
-
+
&Use HTTPS instead of HTTP
@@ -3327,14 +3339,14 @@ Specify an IPv4 or IPv6 address. You can specify "0.0.0.0" for any IPv
-
-
+
Key:
-
-
+
Certificate:
@@ -3366,7 +3378,7 @@ Specify an IPv4 or IPv6 address. You can specify "0.0.0.0" for any IPv
-
-
+
Authentication
@@ -3374,24 +3386,24 @@ Specify an IPv4 or IPv6 address. You can specify "0.0.0.0" for any IPv
-
-
-
+
Username:
-
-
+
-
-
+
Password:
-
-
+
QLineEdit::Password
@@ -3819,13 +3831,13 @@ Use ';' to split multiple entries. Can use wildcard '*'.
stopConditionComboBox
spinPort
checkUPnP
- textWebUiUsername
- checkWebUi
+ textWebUIUsername
+ checkWebUI
textSavePath
scrollArea_7
scrollArea_2
- spinWebUiPort
- textWebUiPassword
+ spinWebUIPort
+ textWebUIPassword
buttonBox
tabSelection
scrollArea
@@ -3915,7 +3927,7 @@ Use ';' to split multiple entries. Can use wildcard '*'.
spinMaxActiveUploads
spinMaxActiveTorrents
checkWebUIUPnP
- checkWebUiHttps
+ checkWebUIHttps
checkBypassLocalAuth
checkBypassAuthSubnetWhitelist
IPSubnetWhitelistButton
diff --git a/src/gui/powermanagement/powermanagement_x11.cpp b/src/gui/powermanagement/powermanagement_x11.cpp
index 55746da55..bfdb9da0b 100644
--- a/src/gui/powermanagement/powermanagement_x11.cpp
+++ b/src/gui/powermanagement/powermanagement_x11.cpp
@@ -105,7 +105,7 @@ void PowerManagementInhibitor::requestBusy()
args << 0u;
args << u"Active torrents are presented"_s;
if (m_useGSM)
- args << 8u;
+ args << 4u;
call.setArguments(args);
QDBusPendingCall pcall = QDBusConnection::sessionBus().asyncCall(call, 1000);
diff --git a/src/gui/previewlistdelegate.cpp b/src/gui/previewlistdelegate.cpp
index 89075bcfb..d89815756 100644
--- a/src/gui/previewlistdelegate.cpp
+++ b/src/gui/previewlistdelegate.cpp
@@ -1,5 +1,6 @@
/*
* Bittorrent Client using Qt and libtorrent.
+ * Copyright (C) 2023 Vladimir Golovnev
* Copyright (C) 2006 Christophe Dumez
*
* This program is free software; you can redistribute it and/or
@@ -30,13 +31,12 @@
#include
#include
-#include
-#include "base/utils/misc.h"
+#include "base/utils/string.h"
#include "previewselectdialog.h"
PreviewListDelegate::PreviewListDelegate(QObject *parent)
- : QItemDelegate(parent)
+ : QStyledItemDelegate(parent)
{
}
@@ -44,15 +44,8 @@ void PreviewListDelegate::paint(QPainter *painter, const QStyleOptionViewItem &o
{
painter->save();
- QStyleOptionViewItem opt = QItemDelegate::setOptions(index, option);
- drawBackground(painter, opt, index);
-
switch (index.column())
{
- case PreviewSelectDialog::SIZE:
- QItemDelegate::drawDisplay(painter, opt, option.rect, Utils::Misc::friendlyUnit(index.data().toLongLong()));
- break;
-
case PreviewSelectDialog::PROGRESS:
{
const qreal progress = (index.data().toReal() * 100);
@@ -65,7 +58,7 @@ void PreviewListDelegate::paint(QPainter *painter, const QStyleOptionViewItem &o
break;
default:
- QItemDelegate::paint(painter, option, index);
+ QStyledItemDelegate::paint(painter, option, index);
break;
}
diff --git a/src/gui/previewlistdelegate.h b/src/gui/previewlistdelegate.h
index ac0daab21..b9fc286f6 100644
--- a/src/gui/previewlistdelegate.h
+++ b/src/gui/previewlistdelegate.h
@@ -1,5 +1,6 @@
/*
* Bittorrent Client using Qt and libtorrent.
+ * Copyright (C) 2023 Vladimir Golovnev
* Copyright (C) 2006 Christophe Dumez
*
* This program is free software; you can redistribute it and/or
@@ -28,11 +29,11 @@
#pragma once
-#include
+#include
#include "progressbarpainter.h"
-class PreviewListDelegate final : public QItemDelegate
+class PreviewListDelegate final : public QStyledItemDelegate
{
Q_OBJECT
Q_DISABLE_COPY_MOVE(PreviewListDelegate)
diff --git a/src/gui/previewselectdialog.cpp b/src/gui/previewselectdialog.cpp
index 21546e081..f79ff54f4 100644
--- a/src/gui/previewselectdialog.cpp
+++ b/src/gui/previewselectdialog.cpp
@@ -1,5 +1,6 @@
/*
* Bittorrent Client using Qt and libtorrent.
+ * Copyright (C) 2023 Vladimir Golovnev
* Copyright (C) 2011 Christophe Dumez
*
* This program is free software; you can redistribute it and/or
@@ -70,16 +71,19 @@ PreviewSelectDialog::PreviewSelectDialog(QWidget *parent, const BitTorrent::Torr
const Preferences *pref = Preferences::instance();
// Preview list
- m_previewListModel = new QStandardItemModel(0, NB_COLUMNS, this);
- m_previewListModel->setHeaderData(NAME, Qt::Horizontal, tr("Name"));
- m_previewListModel->setHeaderData(SIZE, Qt::Horizontal, tr("Size"));
- m_previewListModel->setHeaderData(PROGRESS, Qt::Horizontal, tr("Progress"));
+ auto *previewListModel = new QStandardItemModel(0, NB_COLUMNS, this);
+ previewListModel->setHeaderData(NAME, Qt::Horizontal, tr("Name"));
+ previewListModel->setHeaderData(SIZE, Qt::Horizontal, tr("Size"));
+ previewListModel->setHeaderData(PROGRESS, Qt::Horizontal, tr("Progress"));
m_ui->previewList->setAlternatingRowColors(pref->useAlternatingRowColors());
- m_ui->previewList->setModel(m_previewListModel);
+ m_ui->previewList->setUniformRowHeights(true);
+ m_ui->previewList->setModel(previewListModel);
m_ui->previewList->hideColumn(FILE_INDEX);
- m_listDelegate = new PreviewListDelegate(this);
- m_ui->previewList->setItemDelegate(m_listDelegate);
+
+ auto *listDelegate = new PreviewListDelegate(this);
+ m_ui->previewList->setItemDelegate(listDelegate);
+
// Fill list in
const QVector fp = torrent->filesProgress();
for (int i = 0; i < torrent->filesCount(); ++i)
@@ -87,20 +91,20 @@ PreviewSelectDialog::PreviewSelectDialog(QWidget *parent, const BitTorrent::Torr
const Path filePath = torrent->filePath(i);
if (Utils::Misc::isPreviewable(filePath))
{
- int row = m_previewListModel->rowCount();
- m_previewListModel->insertRow(row);
- m_previewListModel->setData(m_previewListModel->index(row, NAME), filePath.filename());
- m_previewListModel->setData(m_previewListModel->index(row, SIZE), torrent->fileSize(i));
- m_previewListModel->setData(m_previewListModel->index(row, PROGRESS), fp[i]);
- m_previewListModel->setData(m_previewListModel->index(row, FILE_INDEX), i);
+ int row = previewListModel->rowCount();
+ previewListModel->insertRow(row);
+ previewListModel->setData(previewListModel->index(row, NAME), filePath.filename());
+ previewListModel->setData(previewListModel->index(row, SIZE), Utils::Misc::friendlyUnit(torrent->fileSize(i)));
+ previewListModel->setData(previewListModel->index(row, PROGRESS), fp[i]);
+ previewListModel->setData(previewListModel->index(row, FILE_INDEX), i);
}
}
- m_previewListModel->sort(NAME);
+ previewListModel->sort(NAME);
m_ui->previewList->header()->setContextMenuPolicy(Qt::CustomContextMenu);
m_ui->previewList->header()->setFirstSectionMovable(true);
m_ui->previewList->header()->setSortIndicator(0, Qt::AscendingOrder);
- m_ui->previewList->selectionModel()->select(m_previewListModel->index(0, NAME), QItemSelectionModel::Select | QItemSelectionModel::Rows);
+ m_ui->previewList->selectionModel()->select(previewListModel->index(0, NAME), QItemSelectionModel::Select | QItemSelectionModel::Rows);
connect(m_ui->previewList->header(), &QWidget::customContextMenuRequested, this, &PreviewSelectDialog::displayColumnHeaderMenu);
@@ -129,7 +133,7 @@ void PreviewSelectDialog::previewButtonClicked()
// File
if (!path.exists())
{
- const bool isSingleFile = (m_previewListModel->rowCount() == 1);
+ const bool isSingleFile = (m_ui->previewList->model()->rowCount() == 1);
QWidget *parent = isSingleFile ? this->parentWidget() : this;
QMessageBox::critical(parent, tr("Preview impossible")
, tr("Sorry, we can't preview this file: \"%1\".").arg(path.toString()));
@@ -199,6 +203,6 @@ void PreviewSelectDialog::showEvent(QShowEvent *event)
}
// Only one file, no choice
- if (m_previewListModel->rowCount() <= 1)
+ if (m_ui->previewList->model()->rowCount() <= 1)
previewButtonClicked();
}
diff --git a/src/gui/previewselectdialog.h b/src/gui/previewselectdialog.h
index 76a42bad7..7f4a1d985 100644
--- a/src/gui/previewselectdialog.h
+++ b/src/gui/previewselectdialog.h
@@ -1,5 +1,6 @@
/*
* Bittorrent Client using Qt and libtorrent.
+ * Copyright (C) 2023 Vladimir Golovnev
* Copyright (C) 2011 Christophe Dumez
*
* This program is free software; you can redistribute it and/or
@@ -33,8 +34,6 @@
#include "base/path.h"
#include "base/settingvalue.h"
-class QStandardItemModel;
-
namespace BitTorrent
{
class Torrent;
@@ -44,7 +43,6 @@ namespace Ui
{
class PreviewSelectDialog;
}
-class PreviewListDelegate;
class PreviewSelectDialog final : public QDialog
{
@@ -79,8 +77,6 @@ private:
void saveWindowState();
Ui::PreviewSelectDialog *m_ui = nullptr;
- QStandardItemModel *m_previewListModel = nullptr;
- PreviewListDelegate *m_listDelegate = nullptr;
const BitTorrent::Torrent *m_torrent = nullptr;
bool m_headerStateInitialized = false;
diff --git a/src/gui/properties/propertieswidget.cpp b/src/gui/properties/propertieswidget.cpp
index 572da74d9..6b846e2bb 100644
--- a/src/gui/properties/propertieswidget.cpp
+++ b/src/gui/properties/propertieswidget.cpp
@@ -82,6 +82,7 @@ PropertiesWidget::PropertiesWidget(QWidget *parent)
m_ui->contentFilterLayout->insertWidget(3, m_contentFilterLine);
m_ui->filesList->setDoubleClickAction(TorrentContentWidget::DoubleClickAction::Open);
+ m_ui->filesList->setOpenByEnterKey(true);
// SIGNAL/SLOTS
connect(m_ui->selectAllButton, &QPushButton::clicked, m_ui->filesList, &TorrentContentWidget::checkAll);
diff --git a/src/gui/properties/propertieswidget.ui b/src/gui/properties/propertieswidget.ui
index 01123af83..2dcae04c2 100644
--- a/src/gui/properties/propertieswidget.ui
+++ b/src/gui/properties/propertieswidget.ui
@@ -192,7 +192,7 @@
- -
+
-
@@ -382,7 +382,7 @@
- -
+
-
diff --git a/src/gui/torrentcontentwidget.cpp b/src/gui/torrentcontentwidget.cpp
index 594fe76f1..680dfd172 100644
--- a/src/gui/torrentcontentwidget.cpp
+++ b/src/gui/torrentcontentwidget.cpp
@@ -89,10 +89,6 @@ TorrentContentWidget::TorrentContentWidget(QWidget *parent)
const auto *renameFileHotkey = new QShortcut(Qt::Key_F2, this, nullptr, nullptr, Qt::WidgetShortcut);
connect(renameFileHotkey, &QShortcut::activated, this, &TorrentContentWidget::renameSelectedFile);
- const auto *openFileHotkeyReturn = new QShortcut(Qt::Key_Return, this, nullptr, nullptr, Qt::WidgetShortcut);
- connect(openFileHotkeyReturn, &QShortcut::activated, this, &TorrentContentWidget::openSelectedFile);
- const auto *openFileHotkeyEnter = new QShortcut(Qt::Key_Enter, this, nullptr, nullptr, Qt::WidgetShortcut);
- connect(openFileHotkeyEnter, &QShortcut::activated, this, &TorrentContentWidget::openSelectedFile);
connect(model(), &QAbstractItemModel::modelReset, this, &TorrentContentWidget::expandRecursively);
}
@@ -118,6 +114,32 @@ void TorrentContentWidget::refresh()
setUpdatesEnabled(true);
}
+bool TorrentContentWidget::openByEnterKey() const
+{
+ return m_openFileHotkeyEnter;
+}
+
+void TorrentContentWidget::setOpenByEnterKey(const bool value)
+{
+ if (value == openByEnterKey())
+ return;
+
+ if (value)
+ {
+ m_openFileHotkeyReturn = new QShortcut(Qt::Key_Return, this, nullptr, nullptr, Qt::WidgetShortcut);
+ connect(m_openFileHotkeyReturn, &QShortcut::activated, this, &TorrentContentWidget::openSelectedFile);
+ m_openFileHotkeyEnter = new QShortcut(Qt::Key_Enter, this, nullptr, nullptr, Qt::WidgetShortcut);
+ connect(m_openFileHotkeyEnter, &QShortcut::activated, this, &TorrentContentWidget::openSelectedFile);
+ }
+ else
+ {
+ delete m_openFileHotkeyEnter;
+ m_openFileHotkeyEnter = nullptr;
+ delete m_openFileHotkeyReturn;
+ m_openFileHotkeyReturn = nullptr;
+ }
+}
+
TorrentContentWidget::DoubleClickAction TorrentContentWidget::doubleClickAction() const
{
return m_doubleClickAction;
diff --git a/src/gui/torrentcontentwidget.h b/src/gui/torrentcontentwidget.h
index 35620ee42..4baccb883 100644
--- a/src/gui/torrentcontentwidget.h
+++ b/src/gui/torrentcontentwidget.h
@@ -34,6 +34,8 @@
#include "base/bittorrent/downloadpriority.h"
#include "base/pathfwd.h"
+class QShortcut;
+
namespace BitTorrent
{
class Torrent;
@@ -78,6 +80,9 @@ public:
BitTorrent::TorrentContentHandler *contentHandler() const;
void refresh();
+ bool openByEnterKey() const;
+ void setOpenByEnterKey(bool value);
+
DoubleClickAction doubleClickAction() const;
void setDoubleClickAction(DoubleClickAction action);
@@ -118,4 +123,6 @@ private:
TorrentContentFilterModel *m_filterModel;
DoubleClickAction m_doubleClickAction = DoubleClickAction::Rename;
ColumnsVisibilityMode m_columnsVisibilityMode = ColumnsVisibilityMode::Editable;
+ QShortcut *m_openFileHotkeyEnter = nullptr;
+ QShortcut *m_openFileHotkeyReturn = nullptr;
};
diff --git a/src/gui/transferlistmodel.cpp b/src/gui/transferlistmodel.cpp
index 9011a9d6f..c59604b2b 100644
--- a/src/gui/transferlistmodel.cpp
+++ b/src/gui/transferlistmodel.cpp
@@ -117,6 +117,7 @@ TransferListModel::TransferListModel(QObject *parent)
, m_completedIcon {UIThemeManager::instance()->getIcon(u"checked-completed"_s, u"completed"_s)}
, m_downloadingIcon {UIThemeManager::instance()->getIcon(u"downloading"_s)}
, m_errorIcon {UIThemeManager::instance()->getIcon(u"error"_s)}
+ , m_movingIcon {UIThemeManager::instance()->getIcon(u"set-location"_s)}
, m_pausedIcon {UIThemeManager::instance()->getIcon(u"stopped"_s, u"media-playback-pause"_s)}
, m_queuedIcon {UIThemeManager::instance()->getIcon(u"queued"_s)}
, m_stalledDLIcon {UIThemeManager::instance()->getIcon(u"stalledDL"_s)}
@@ -710,8 +711,9 @@ QIcon TransferListModel::getIconByState(const BitTorrent::TorrentState state) co
case BitTorrent::TorrentState::CheckingDownloading:
case BitTorrent::TorrentState::CheckingUploading:
case BitTorrent::TorrentState::CheckingResumeData:
- case BitTorrent::TorrentState::Moving:
return m_checkingIcon;
+ case BitTorrent::TorrentState::Moving:
+ return m_movingIcon;
case BitTorrent::TorrentState::Unknown:
case BitTorrent::TorrentState::MissingFiles:
case BitTorrent::TorrentState::Error:
diff --git a/src/gui/transferlistmodel.h b/src/gui/transferlistmodel.h
index f0d7e8ad1..e2da9f007 100644
--- a/src/gui/transferlistmodel.h
+++ b/src/gui/transferlistmodel.h
@@ -137,6 +137,7 @@ private:
QIcon m_completedIcon;
QIcon m_downloadingIcon;
QIcon m_errorIcon;
+ QIcon m_movingIcon;
QIcon m_pausedIcon;
QIcon m_queuedIcon;
QIcon m_stalledDLIcon;
diff --git a/src/gui/transferlistwidget.cpp b/src/gui/transferlistwidget.cpp
index c46b65a03..38300d05c 100644
--- a/src/gui/transferlistwidget.cpp
+++ b/src/gui/transferlistwidget.cpp
@@ -100,13 +100,15 @@ namespace
void openDestinationFolder(const BitTorrent::Torrent *const torrent)
{
+ const Path contentPath = torrent->contentPath();
+ const Path openedPath = (!contentPath.isEmpty() ? contentPath : torrent->savePath());
#ifdef Q_OS_MACOS
- MacUtils::openFiles({torrent->contentPath()});
+ MacUtils::openFiles({openedPath});
#else
if (torrent->filesCount() == 1)
- Utils::Gui::openFolderSelect(torrent->contentPath());
+ Utils::Gui::openFolderSelect(openedPath);
else
- Utils::Gui::openPath(torrent->contentPath());
+ Utils::Gui::openPath(openedPath);
#endif
}
@@ -253,6 +255,16 @@ QModelIndex TransferListWidget::mapToSource(const QModelIndex &index) const
return index;
}
+QModelIndexList TransferListWidget::mapToSource(const QModelIndexList &indexes) const
+{
+ QModelIndexList result;
+ result.reserve(indexes.size());
+ for (const QModelIndex &index : indexes)
+ result.append(mapToSource(index));
+
+ return result;
+}
+
QModelIndex TransferListWidget::mapFromSource(const QModelIndex &index) const
{
Q_ASSERT(index.isValid());
@@ -263,11 +275,13 @@ QModelIndex TransferListWidget::mapFromSource(const QModelIndex &index) const
void TransferListWidget::torrentDoubleClicked()
{
const QModelIndexList selectedIndexes = selectionModel()->selectedRows();
- if ((selectedIndexes.size() != 1) || !selectedIndexes.first().isValid()) return;
+ if ((selectedIndexes.size() != 1) || !selectedIndexes.first().isValid())
+ return;
const QModelIndex index = m_listModel->index(mapToSource(selectedIndexes.first()).row());
BitTorrent::Torrent *const torrent = m_listModel->torrentHandle(index);
- if (!torrent) return;
+ if (!torrent)
+ return;
int action;
if (torrent->isFinished())
@@ -575,21 +589,22 @@ void TransferListWidget::openSelectedTorrentsFolder() const
for (BitTorrent::Torrent *const torrent : asConst(getSelectedTorrents()))
{
const Path contentPath = torrent->contentPath();
- paths.insert(contentPath);
+ paths.insert(!contentPath.isEmpty() ? contentPath : torrent->savePath());
}
MacUtils::openFiles(PathList(paths.cbegin(), paths.cend()));
#else
for (BitTorrent::Torrent *const torrent : asConst(getSelectedTorrents()))
{
const Path contentPath = torrent->contentPath();
- if (!paths.contains(contentPath))
+ const Path openedPath = (!contentPath.isEmpty() ? contentPath : torrent->savePath());
+ if (!paths.contains(openedPath))
{
if (torrent->filesCount() == 1)
- Utils::Gui::openFolderSelect(contentPath);
+ Utils::Gui::openFolderSelect(openedPath);
else
- Utils::Gui::openPath(contentPath);
+ Utils::Gui::openPath(openedPath);
}
- paths.insert(contentPath);
+ paths.insert(openedPath);
}
#endif // Q_OS_MACOS
}
@@ -806,7 +821,8 @@ void TransferListWidget::exportTorrent()
bool hasError = false;
for (const BitTorrent::Torrent *torrent : torrents)
{
- const Path filePath = savePath / Path(torrent->name() + u".torrent");
+ const QString validName = Utils::Fs::toValidFileName(torrent->name(), u"_"_s);
+ const Path filePath = savePath / Path(validName + u".torrent");
if (filePath.exists())
{
LogMsg(errorMsg.arg(torrent->name(), filePath.toString(), tr("A file with the same name already exists")) , Log::WARNING);
@@ -871,9 +887,13 @@ QStringList TransferListWidget::askTagsForSelection(const QString &dialogTitle)
void TransferListWidget::applyToSelectedTorrents(const std::function &fn)
{
- for (const QModelIndex &index : asConst(selectionModel()->selectedRows()))
+ // Changing the data may affect the layout of the sort/filter model, which in turn may invalidate
+ // the indexes previously obtained from selection model before we process them all.
+ // Therefore, we must map all the selected indexes to source before start processing them.
+ const QModelIndexList sourceRows = mapToSource(selectionModel()->selectedRows());
+ for (const QModelIndex &index : sourceRows)
{
- BitTorrent::Torrent *const torrent = m_listModel->torrentHandle(mapToSource(index));
+ BitTorrent::Torrent *const torrent = m_listModel->torrentHandle(index);
Q_ASSERT(torrent);
fn(torrent);
}
@@ -882,11 +902,13 @@ void TransferListWidget::applyToSelectedTorrents(const std::functionselectedRows();
- if ((selectedIndexes.size() != 1) || !selectedIndexes.first().isValid()) return;
+ if ((selectedIndexes.size() != 1) || !selectedIndexes.first().isValid())
+ return;
const QModelIndex mi = m_listModel->index(mapToSource(selectedIndexes.first()).row(), TransferListModel::TR_NAME);
BitTorrent::Torrent *const torrent = m_listModel->torrentHandle(mi);
- if (!torrent) return;
+ if (!torrent)
+ return;
// Ask for a new Name
bool ok = false;
@@ -901,8 +923,7 @@ void TransferListWidget::renameSelectedTorrent()
void TransferListWidget::setSelectionCategory(const QString &category)
{
- for (const QModelIndex &index : asConst(selectionModel()->selectedRows()))
- m_listModel->setData(m_listModel->index(mapToSource(index).row(), TransferListModel::TR_CATEGORY), category, Qt::DisplayRole);
+ applyToSelectedTorrents([&category](BitTorrent::Torrent *torrent) { torrent->setCategory(category); });
}
void TransferListWidget::addSelectionTag(const QString &tag)
@@ -923,7 +944,8 @@ void TransferListWidget::clearSelectionTags()
void TransferListWidget::displayListMenu()
{
const QModelIndexList selectedIndexes = selectionModel()->selectedRows();
- if (selectedIndexes.isEmpty()) return;
+ if (selectedIndexes.isEmpty())
+ return;
auto *listMenu = new QMenu(this);
listMenu->setAttribute(Qt::WA_DeleteOnClose);
diff --git a/src/gui/transferlistwidget.h b/src/gui/transferlistwidget.h
index 205b21246..ad9b0f37b 100644
--- a/src/gui/transferlistwidget.h
+++ b/src/gui/transferlistwidget.h
@@ -119,6 +119,7 @@ private slots:
private:
void wheelEvent(QWheelEvent *event) override;
QModelIndex mapToSource(const QModelIndex &index) const;
+ QModelIndexList mapToSource(const QModelIndexList &indexes) const;
QModelIndex mapFromSource(const QModelIndex &index) const;
bool loadSettings();
QVector getSelectedTorrents() const;
diff --git a/src/gui/uithemesource.cpp b/src/gui/uithemesource.cpp
index 8565c6414..c4e4ef7f4 100644
--- a/src/gui/uithemesource.cpp
+++ b/src/gui/uithemesource.cpp
@@ -161,13 +161,13 @@ void DefaultThemeSource::loadColors()
return;
}
- const QByteArray configData = readResult.value();
+ const QByteArray &configData = readResult.value();
if (configData.isEmpty())
return;
const QJsonObject config = parseThemeConfig(configData);
- QHash lightModeColorOverrides = colorsFromJSON(config.value(KEY_COLORS_LIGHT).toObject());
+ const QHash lightModeColorOverrides = colorsFromJSON(config.value(KEY_COLORS_LIGHT).toObject());
for (auto overridesIt = lightModeColorOverrides.cbegin(); overridesIt != lightModeColorOverrides.cend(); ++overridesIt)
{
auto it = m_colors.find(overridesIt.key());
@@ -175,7 +175,7 @@ void DefaultThemeSource::loadColors()
it.value().light = overridesIt.value();
}
- QHash darkModeColorOverrides = colorsFromJSON(config.value(KEY_COLORS_DARK).toObject());
+ const QHash darkModeColorOverrides = colorsFromJSON(config.value(KEY_COLORS_DARK).toObject());
for (auto overridesIt = darkModeColorOverrides.cbegin(); overridesIt != darkModeColorOverrides.cend(); ++overridesIt)
{
auto it = m_colors.find(overridesIt.key());
@@ -184,6 +184,12 @@ void DefaultThemeSource::loadColors()
}
}
+CustomThemeSource::CustomThemeSource(const Path &themeRootPath)
+ : m_themeRootPath {themeRootPath}
+{
+ loadColors();
+}
+
QColor CustomThemeSource::getColor(const QString &colorId, const ColorMode colorMode) const
{
if (colorMode == ColorMode::Dark)
@@ -246,6 +252,11 @@ DefaultThemeSource *CustomThemeSource::defaultThemeSource() const
return m_defaultThemeSource.get();
}
+Path CustomThemeSource::themeRootPath() const
+{
+ return m_themeRootPath;
+}
+
void CustomThemeSource::loadColors()
{
const auto readResult = Utils::IO::readFile((themeRootPath() / Path(CONFIG_FILE_NAME)), FILE_MAX_SIZE, QIODevice::Text);
@@ -257,7 +268,7 @@ void CustomThemeSource::loadColors()
return;
}
- const QByteArray configData = readResult.value();
+ const QByteArray &configData = readResult.value();
if (configData.isEmpty())
return;
@@ -267,13 +278,9 @@ void CustomThemeSource::loadColors()
m_darkModeColors.insert(colorsFromJSON(config.value(KEY_COLORS_DARK).toObject()));
}
-Path QRCThemeSource::themeRootPath() const
-{
- return Path(u":/uitheme"_s);
-}
-
FolderThemeSource::FolderThemeSource(const Path &folderPath)
- : m_folder {folderPath}
+ : CustomThemeSource(folderPath)
+ , m_folder {folderPath}
{
}
@@ -285,10 +292,10 @@ QByteArray FolderThemeSource::readStyleSheet()
const QString stylesheetResourcesDir = u":/uitheme"_s;
QByteArray styleSheetData = CustomThemeSource::readStyleSheet();
- return styleSheetData.replace(stylesheetResourcesDir.toUtf8(), themeRootPath().data().toUtf8());
+ return styleSheetData.replace(stylesheetResourcesDir.toUtf8(), m_folder.data().toUtf8());
}
-Path FolderThemeSource::themeRootPath() const
+QRCThemeSource::QRCThemeSource()
+ : CustomThemeSource(Path(u":/uitheme"_s))
{
- return m_folder;
}
diff --git a/src/gui/uithemesource.h b/src/gui/uithemesource.h
index 4969c3cee..5c0920303 100644
--- a/src/gui/uithemesource.h
+++ b/src/gui/uithemesource.h
@@ -84,21 +84,24 @@ public:
QByteArray readStyleSheet() override;
protected:
- virtual Path themeRootPath() const = 0;
+ explicit CustomThemeSource(const Path &themeRootPath);
+
DefaultThemeSource *defaultThemeSource() const;
private:
+ Path themeRootPath() const;
void loadColors();
const std::unique_ptr m_defaultThemeSource = std::make_unique();
+ Path m_themeRootPath;
QHash m_colors;
QHash m_darkModeColors;
};
class QRCThemeSource final : public CustomThemeSource
{
-private:
- Path themeRootPath() const override;
+public:
+ QRCThemeSource();
};
class FolderThemeSource : public CustomThemeSource
@@ -109,7 +112,5 @@ public:
QByteArray readStyleSheet() override;
private:
- Path themeRootPath() const override;
-
const Path m_folder;
};
diff --git a/src/icons/flags/ac.svg b/src/icons/flags/ac.svg
index 1a6d50805..b1ae9ac52 100644
--- a/src/icons/flags/ac.svg
+++ b/src/icons/flags/ac.svg
@@ -1,73 +1,686 @@
diff --git a/src/icons/flags/af.svg b/src/icons/flags/af.svg
index 6e755396f..417dd0476 100644
--- a/src/icons/flags/af.svg
+++ b/src/icons/flags/af.svg
@@ -14,7 +14,7 @@
-
+
@@ -61,7 +61,7 @@
-
+
diff --git a/src/icons/flags/ag.svg b/src/icons/flags/ag.svg
index 875f9753a..250b50126 100644
--- a/src/icons/flags/ag.svg
+++ b/src/icons/flags/ag.svg
@@ -1,14 +1,14 @@
diff --git a/src/icons/flags/ai.svg b/src/icons/flags/ai.svg
index cf91b39b9..81a857d5b 100644
--- a/src/icons/flags/ai.svg
+++ b/src/icons/flags/ai.svg
@@ -1,758 +1,29 @@
-