Compare commits

..

54 Commits

Author SHA1 Message Date
sledgehammer999
da0b276d5f Bump to 4.3.3 2021-01-19 00:47:04 +02:00
sledgehammer999
2d73bc9e7d Update Changelog 2021-01-19 00:46:29 +02:00
Chocobo1
fdd54fe568 Simplify code for checking free disk space
`QStorageInfo::bytesAvailable()` is guaranteed to return `-1` for an
invalid path.
https://doc.qt.io/qt-5/qstorageinfo.html#bytesAvailable
2021-01-19 00:45:13 +02:00
Chocobo1
e5ce24e55e Improve detection of file extension string 2021-01-19 00:45:06 +02:00
sledgehammer999
d90349709b Sync translations from Transifex and run lupdate 2021-01-17 23:24:02 +02:00
Vladimir Golovnev (Glassez)
adb0fe6582 WebUI: Correctly represent torrent content structure 2021-01-17 22:50:40 +02:00
Chocobo1
5ed81580c9 Add README.md to searchengine folder 2021-01-17 22:50:39 +02:00
Chocobo1
86d6fb86d7 Unify "github actions" artifacts naming scheme 2021-01-17 22:50:38 +02:00
Chocobo1
ddec247d4f Migrate away from deprecated Qt functions
`QString QDateTime::toString(Qt::DateFormat format = Qt::TextDate)` will
be removed in Qt6.
2021-01-17 22:50:37 +02:00
Chocobo1
d431ecbe00 Disable clang "range loop analysis" compiler warning
See: https://github.com/qbittorrent/qBittorrent/pull/13915#issuecomment-739449084
2021-01-17 22:50:36 +02:00
Chocobo1
be929ed88c Set source character sets to UTF-8
This suppress warning C4819.
https://docs.microsoft.com/en-us/cpp/build/reference/utf-8-set-source-and-executable-character-sets-to-utf-8?view=msvc-160
2021-01-17 22:50:35 +02:00
Chocobo1
2e1f9bf8be Add script for generating project tarball 2021-01-17 22:50:20 +02:00
lbilli
7fff393b0e On Linux use legacy 'data' directory only as a fallback 2021-01-17 22:47:13 +02:00
sledgehammer999
a669ec49ad Correct copyright attribution
These files were created and edited in their entirety in commit 8db4bde15d
As far as I can tell they were almost entirety rewritten from their original state.
The old copyright attribution is restored and the new author is added too.
2021-01-17 22:47:11 +02:00
Vladimir Golovnev (Glassez)
1880082017 Remove redundant suffix from TorrentHandle class
Originally, it was just a wrapper for libtorrent::torrent_handle class, so it mimicked its name.
It was then transformed into a more complex aggregate, but the name was retained (just by inertia).
Unlike libtorrent::torrent_handle class in whose name "handle" means the pattern used,
it does not matter for qBittorrent classes and just eats up space in the source code.
2021-01-17 22:47:00 +02:00
sledgehammer999
0cbd15890a Merge pull request #14170 from sledgehammer999/use_cxx1z
Use c++1z to enable c++17
2021-01-07 13:40:05 +02:00
sledgehammer999
7fe7c6c277 Use c++1z to enable c++17
It increases compatibility with older qt versions.
2021-01-06 21:54:46 +02:00
jagannatharjun
e4c177fec7 Correctly set items flags in TorrentContentModel
Only set editable flag on item's where editing is handled in the delegate

closes #13515
2021-01-06 21:36:40 +02:00
Chocobo1
77f4e6c2cf Generate version header when configuring project
The basic idea is we create a version header template at
"src/base/version.h.in" and the build systems are expected to replace
strings that are enclosed with @ symbols and generate
"src/base/version.h" for other source files to consume/include.
2021-01-06 21:36:39 +02:00
sledgehammer999
4563b11a2e Bump copyright year 2021-01-06 21:36:37 +02:00
Vladimir Golovnev (Glassez)
cb477f9a29 QMake: Raise minimal macOS target version 2021-01-06 21:36:35 +02:00
Vladimir Golovnev (Glassez)
58ac07667e Use single parameter to accept torrent source 2021-01-06 21:36:34 +02:00
Vladimir Golovnev (Glassez)
74bf3af41c Use std::optional<bool> instead of custom TriStateBool 2021-01-06 21:36:33 +02:00
Vladimir Golovnev (Glassez)
9317071122 Change parseBool() to return optional bool value 2021-01-06 21:36:31 +02:00
Vladimir Golovnev (Glassez)
dab32f2090 Use std::optional instead of boost::optional 2021-01-06 21:36:29 +02:00
Vladimir Golovnev (Glassez)
dc464d4d41 Use nested namespaces definition syntax 2021-01-06 21:36:28 +02:00
Chocobo1
e7e3f6a9db Don't use deprecated locale name 2021-01-06 21:36:27 +02:00
Chocobo1
5a1c4e79b3 Revise store/load state operations of Options Dialog 2021-01-06 21:36:26 +02:00
Chocobo1
c6d9ab6810 Remember dialog sizes
This applies to "About Dialog", "Ban List Options Dialog", "Download From URL Dialog", "IP Subnet
Whitelist Options Dialog", "Search Plugin Select Dialog", "Search Plugin Source Dialog",
"Statistics Dialog", "Speed Limit Dialog" and "Torrent Options Dialog".

Also unifies storing the dialog size under the key "Size".
2021-01-06 21:36:24 +02:00
Chocobo1
d7afad835e Revise SettingsStorage store/load value interface 2021-01-06 21:36:22 +02:00
Chocobo1
8608d7b9da Improve load data behavior of SettingsStorage class
Previously it only handle the case of failed lookup, now it discard
invalid values when deserializing the database from disk.
Also checks whether the data is convertible to the intended type.
2021-01-06 21:36:22 +02:00
Vladimir Golovnev (Glassez)
72970602af Reload "missing files" torrent instead of re-checking 2021-01-06 21:36:20 +02:00
Vladimir Golovnev (Glassez)
86579ca87d Extract torrent reloading logic into separate method 2021-01-06 21:36:19 +02:00
Vladimir Golovnev (Glassez)
e55582124c Drop notification about move storage failed 2021-01-06 21:36:17 +02:00
Vladimir Golovnev (Glassez)
bd8b06c607 Drop notification about move storage finished 2021-01-06 21:36:16 +02:00
Chocobo1
230fedf069 Move parsing of TriStateBool to a static class function 2021-01-06 21:36:14 +02:00
thalieht
7bea10f507 Update "Keep top-level folder" in WebUI options 2021-01-06 21:36:13 +02:00
Chocobo1
7cde969b90 Exclude configure script for "trailing newlines" checking 2021-01-06 21:36:12 +02:00
Chocobo1
a3b8f6880b Migrate away from deprecated AC_OUTPUT macro
The `AC_OUTPUT` has two versions, the deprecated one takes arguments and the other not. Check the
following link for equivalent replacement:
https://www.gnu.org/savannah-checkouts/gnu/autoconf/manual/autoconf-2.70/html_node/Obsolete-Macros.html#Obsolete-Macros

Also regenerate the configure script with the latest Autoconf 2.70.
2021-01-06 21:35:33 +02:00
Chocobo1
ad79fc8d43 Migrate away from deprecated std::iterator class 2021-01-06 21:31:51 +02:00
Chocobo1
fb4bf94a56 Use function-pointer based signal-slot connection 2021-01-06 21:31:50 +02:00
Chocobo1
1c184944fd Remove unused define 2021-01-06 21:31:49 +02:00
Chocobo1
ec420f6617 Bump project requirement to C++17 2021-01-06 21:31:47 +02:00
Chocobo1
d908227619 Add a thin layer around SettingsStorage class
This new layer would be handy for saving GUI widget states as they don't
need the value cached and they store/load rarely.
2021-01-06 21:31:45 +02:00
sledgehammer999
ac8167410b Add new languages
* Azerbaijani
* Estonian
2021-01-06 21:31:44 +02:00
Vladimir Golovnev (Glassez)
26ce187b30 Don't call non-existent elements
Fixed a regression where the script tries to access elements that no longer
exist on the page, because they were replaced with others by a previous change.
2021-01-06 21:31:43 +02:00
Vladimir Golovnev (Glassez)
2c4e04e537 Don't call non-existent elements
Fixed a regression where the script tries to access elements that no longer
exist on the page, because they were replaced with others by a previous change.
2021-01-06 21:31:42 +02:00
Vladimir Golovnev (Glassez)
b418f65c2f Improve content file/folder names handling
Move files/folders renaming functions to core classes.
Query file/folder for renaming by its current path.
Add ability to rename content folders from WebAPI/WebUI.
2021-01-06 21:31:41 +02:00
Vladimir Golovnev (Glassez)
dd3a8d5d56 Fix folder name extraction functions
It should return empty string if there is no parent folder.
2021-01-06 21:31:39 +02:00
Chocobo1
49e54a55df Capitalize locale names 2021-01-06 21:31:38 +02:00
thalieht
8cd0a7ae85 Group several torrent options into one dialog
Speed limits, share limits and the new options to disable DHT, PeX, LSD per torrent
2021-01-06 21:31:36 +02:00
thalieht
442f0df613 Save fastresume when setting torrent speed limits 2021-01-06 21:31:35 +02:00
thalieht
f9ee5bdb59 Increase maximum global speed limits from ~1 GiB/s to ~2 GiB/s
Closer to the INT_MAX limit of ~2 Billion when multiplied by 1024 for libtorrent
2021-01-06 21:31:33 +02:00
thalieht
b9602cc6ab Convert existing speed dialog to global + alt global limits only 2021-01-06 21:31:25 +02:00
283 changed files with 78562 additions and 43463 deletions

View File

@@ -72,7 +72,7 @@ jobs:
- name: upload artifact as zip - name: upload artifact as zip
uses: actions/upload-artifact@v2 uses: actions/upload-artifact@v2
with: with:
name: qBittorrent-CI-Ubuntu_${{ matrix.os }}-${{ matrix.qbt_gui }} name: qBittorrent-CI_${{ matrix.os }}-x64_${{ matrix.qbt_gui }}
path: | path: |
build/compile_commands.json build/compile_commands.json
build/target_graph.dot build/target_graph.dot
@@ -151,7 +151,7 @@ jobs:
- name: upload artifact as zip - name: upload artifact as zip
uses: actions/upload-artifact@v2 uses: actions/upload-artifact@v2
with: with:
name: qBittorrent-CI-Windows_x64-static-release name: qBittorrent-CI_Windows-x64
path: | path: |
build/compile_commands.json build/compile_commands.json
build/target_graph.dot build/target_graph.dot
@@ -200,10 +200,10 @@ jobs:
-Value "set(VCPKG_BUILD_TYPE release)","set(VCPKG_OSX_DEPLOYMENT_TARGET 10.15)" -Value "set(VCPKG_BUILD_TYPE release)","set(VCPKG_OSX_DEPLOYMENT_TARGET 10.15)"
# NOTE: Avoids a libtorrent ABI issue. See https://github.com/arvidn/libtorrent/issues/4965 # NOTE: Avoids a libtorrent ABI issue. See https://github.com/arvidn/libtorrent/issues/4965
- name: force AppleClang to compile libtorrent with C++14 - name: force AppleClang to compile libtorrent with C++17
run: | run: |
(Get-Content -path ${{ env.RUNVCPKG_VCPKG_ROOT }}/ports/libtorrent/portfile.cmake).Replace( ` (Get-Content -path ${{ env.RUNVCPKG_VCPKG_ROOT }}/ports/libtorrent/portfile.cmake).Replace( `
'${FEATURE_OPTIONS}', '${FEATURE_OPTIONS} -DCMAKE_CXX_STANDARD=14') ` '${FEATURE_OPTIONS}', '${FEATURE_OPTIONS} -DCMAKE_CXX_STANDARD=17') `
| Set-Content -Path ${{ env.RUNVCPKG_VCPKG_ROOT }}/ports/libtorrent/portfile.cmake | Set-Content -Path ${{ env.RUNVCPKG_VCPKG_ROOT }}/ports/libtorrent/portfile.cmake
- name: install dependencies via vcpkg - name: install dependencies via vcpkg
@@ -236,7 +236,7 @@ jobs:
- name: upload artifact as zip - name: upload artifact as zip
uses: actions/upload-artifact@v2 uses: actions/upload-artifact@v2
with: with:
name: qBittorrent-CI-macOS_x64-static-release_${{ matrix.qbt_gui }} name: qBittorrent-CI_macOS_${{ matrix.qbt_gui }}
path: | path: |
build/compile_commands.json build/compile_commands.json
build/target_graph.dot build/target_graph.dot

View File

@@ -12,6 +12,7 @@ regressions=0
exclusions_nonutf8='(.*(7z|gif|ic(ns|o)|png|qm|zip))' exclusions_nonutf8='(.*(7z|gif|ic(ns|o)|png|qm|zip))'
exclusions_bom='src/base/unicodestrings.h' exclusions_bom='src/base/unicodestrings.h'
exclusions_tw='(*.ts)|src/webui/www/private/scripts/lib/mootools-1.2-more.js' exclusions_tw='(*.ts)|src/webui/www/private/scripts/lib/mootools-1.2-more.js'
exclusions_trailing_newline='configure'
exclusions_no_lf='(*.ts)|(.*svg)|compile_commands.json|src/webui/www/private/scripts/lib/mootools-1.2-(core-yc.js|more.js)' exclusions_no_lf='(*.ts)|(.*svg)|compile_commands.json|src/webui/www/private/scripts/lib/mootools-1.2-(core-yc.js|more.js)'
echo -e "\n*** Detect files not encoded in UTF-8 ***\n" echo -e "\n*** Detect files not encoded in UTF-8 ***\n"
@@ -50,6 +51,7 @@ echo -e "\n*** Detect too many trailing newlines ***\n"
find . -path ./build -prune -false -o -path ./.git -prune -false -o -type f -exec file --mime {} \; | sort \ find . -path ./build -prune -false -o -path ./.git -prune -false -o -type f -exec file --mime {} \; | sort \
| grep -e "charset=us-ascii" -e "charset=utf-8" | cut -d ":" -f 1 \ | grep -e "charset=us-ascii" -e "charset=utf-8" | cut -d ":" -f 1 \
| grep -E -v -e "${exclusions_trailing_newline}" \
| xargs -L1 -I my_input bash -c 'test "$(tail -q -c2 "my_input" | hexdump -C | grep "0a 0a")" && echo "my_input"' \ | xargs -L1 -I my_input bash -c 'test "$(tail -q -c2 "my_input" | hexdump -C | grep "0a 0a")" && echo "my_input"' \
| tee >(echo -e "--> Too many trailing newlines: found" "$(wc -l < /dev/stdin)" "regression(s)\n") \ | tee >(echo -e "--> Too many trailing newlines: found" "$(wc -l < /dev/stdin)" "regression(s)\n") \
| xargs -I my_input -0 bash -c 'echo "my_input"; test "$(echo -n "my_input" | wc -l)" -eq 0' | xargs -I my_input -0 bash -c 'echo "my_input"; test "$(echo -n "my_input" | wc -l)" -eq 0'

1
.gitignore vendored
View File

@@ -4,6 +4,7 @@ src/qbittorrent
src/qbittorrent-nox src/qbittorrent-nox
src/release src/release
src/debug src/debug
src/base/version.h
CMakeLists.txt.user* CMakeLists.txt.user*
qbittorrent.pro.user* qbittorrent.pro.user*
conf.pri conf.pri

View File

@@ -129,7 +129,7 @@ install:
cmake \ cmake \
-DCMAKE_BUILD_TYPE=Release \ -DCMAKE_BUILD_TYPE=Release \
-DCMAKE_CXX_STANDARD=14 \ -DCMAKE_CXX_STANDARD=17 \
-Ddeprecated-functions=OFF \ -Ddeprecated-functions=OFF \
-DOPENSSL_ROOT_DIR="$openssl_root_path" \ -DOPENSSL_ROOT_DIR="$openssl_root_path" \
./ ./
@@ -145,7 +145,7 @@ install:
cmake \ cmake \
-DCMAKE_BUILD_TYPE=Release \ -DCMAKE_BUILD_TYPE=Release \
-DCMAKE_CXX_STANDARD=14 \ -DCMAKE_CXX_STANDARD=17 \
-Ddeprecated-functions=ON \ -Ddeprecated-functions=ON \
-DOPENSSL_ROOT_DIR="$openssl_root_path" \ -DOPENSSL_ROOT_DIR="$openssl_root_path" \
./ ./

View File

@@ -3,7 +3,6 @@ cmake_minimum_required(VERSION 3.16 FATAL_ERROR) # Policies <= CMP0097 default t
list(APPEND CMAKE_MODULE_PATH ${CMAKE_CURRENT_SOURCE_DIR}/cmake/Modules) list(APPEND CMAKE_MODULE_PATH ${CMAKE_CURRENT_SOURCE_DIR}/cmake/Modules)
project(qBittorrent project(qBittorrent
VERSION 4.3.2.0
DESCRIPTION "The qBittorrent BitTorrent client" DESCRIPTION "The qBittorrent BitTorrent client"
HOMEPAGE_URL "https://www.qbittorrent.org/" HOMEPAGE_URL "https://www.qbittorrent.org/"
LANGUAGES CXX LANGUAGES CXX
@@ -51,8 +50,6 @@ elseif (MSVC)
feature_option(MSVC_RUNTIME_DYNAMIC "Use MSVC dynamic runtime library (-MD) instead of static (-MT)" ON) feature_option(MSVC_RUNTIME_DYNAMIC "Use MSVC dynamic runtime library (-MD) instead of static (-MT)" ON)
endif() endif()
set(QBT_VER_STATUS "alpha1" CACHE STRING "Project status version. Should be empty for release builds.")
include(GNUInstallDirs) include(GNUInstallDirs)
add_subdirectory(src) add_subdirectory(src)
add_subdirectory(dist) add_subdirectory(dist)
@@ -62,3 +59,7 @@ if (VERBOSE_CONFIGURE)
else() else()
feature_summary(WHAT ENABLED_FEATURES DISABLED_FEATURES) feature_summary(WHAT ENABLED_FEATURES DISABLED_FEATURES)
endif() endif()
# Generate version header
file(READ "src/base/version.h.in" versionHeader)
file(WRITE "src/base/version.h" "${versionHeader}")

View File

@@ -1,3 +1,21 @@
Tue Jan 19 2021 - sledgehammer999 <sledgehammer999@qbittorrent.org> - v4.3.3
- FEATURE: New languages: Azerbaijani, Estonian
- BUGFIX: Unify global speed dialogs for normal/alternative speeds (thalieht)
- BUGFIX: Increase maximum global speed limits ~2 GiB/s (thalieht)
- BUGFIX: Save fastresume when setting torrent speed limits (thalieht)
- BUGFIX: Group several torrent options into one dialog (thalieht)
- BUGFIX: Capitalize locale names (Chocobo1)
- BUGFIX: Improve content file/folder names handling (glassez)
- BUGFIX: Drop notification about move storage finished or failed (glassez)
- BUGFIX: Reload "missing files" torrent instead of re-checking (glassez)
- BUGFIX: Remember dialog sizes (Chocobo1)
- BUGFIX: Improve detection of file extension string (Chocobo1)
- WEBUI: Don't call non-existent elements (glassez)
- WEBUI: Update "Keep top-level folder" in WebUI options (thalieht)
- MACOS: QMake: Raise minimal macOS target version to 10.14 (glassez)
- LINUX: Use legacy 'data' directory only as a fallback (lbilli)
- OTHER: Bump project requirement to C++17 (Chocobo1)
Sun Dec 27 2020 - sledgehammer999 <sledgehammer999@qbittorrent.org> - v4.3.2 Sun Dec 27 2020 - sledgehammer999 <sledgehammer999@qbittorrent.org> - v4.3.2
- FEATURE: Allow to add root folder to torrent content (glassez) - FEATURE: Allow to add root folder to torrent content (glassez)
- FEATURE: "HTTPS tracker validation" option is available on all platforms with latest libtorrent (Chocobo1) - FEATURE: "HTTPS tracker validation" option is available on all platforms with latest libtorrent (Chocobo1)

19
build_dist.sh Executable file
View File

@@ -0,0 +1,19 @@
#!/bin/sh
# get version numbers
versionSrc="src/base/version.h.in"
versionMajor="$(grep -Po '(?<=QBT_VERSION_MAJOR )\d+' "$versionSrc")"
versionMinor="$(grep -Po '(?<=QBT_VERSION_MINOR )\d+' "$versionSrc")"
versionBugfix="$(grep -Po '(?<=QBT_VERSION_BUGFIX )\d+' "$versionSrc")"
versionBuild="$(grep -Po '(?<=QBT_VERSION_BUILD )\d+' "$versionSrc")"
versionStatus="$(grep -Po '(?<=QBT_VERSION_STATUS ")\w+' "$versionSrc")"
if [ "$versionBuild" != "0" ]; then
projectVersion="$versionMajor.$versionMinor.$versionBugfix.$versionBuild$versionStatus"
else
projectVersion="$versionMajor.$versionMinor.$versionBugfix$versionStatus"
fi
# pack archives
git archive --format=tar --prefix="qbittorrent-$projectVersion/" HEAD | gzip -9 > "qbittorrent-$projectVersion.tar.gz"
git archive --format=tar --prefix="qbittorrent-$projectVersion/" HEAD | xz -9 > "qbittorrent-$projectVersion.tar.xz"

View File

@@ -7,47 +7,16 @@ macro(qbt_common_config)
# treat value specified by the CXX_STANDARD target property as a requirement by default # treat value specified by the CXX_STANDARD target property as a requirement by default
set(CMAKE_CXX_STANDARD_REQUIRED ON) set(CMAKE_CXX_STANDARD_REQUIRED ON)
# these definitions are only needed for calls to
# lt::generate_fingerprint and for the qbittorrent.rc file on Windows
add_library(qbt_version_definitions INTERFACE)
target_compile_definitions(qbt_version_definitions INTERFACE
QBT_VERSION_MAJOR=${qBittorrent_VERSION_MAJOR}
QBT_VERSION_MINOR=${qBittorrent_VERSION_MINOR}
QBT_VERSION_BUGFIX=${qBittorrent_VERSION_PATCH}
QBT_VERSION_BUILD=${qBittorrent_VERSION_TWEAK}
)
add_library(qbt_common_cfg INTERFACE) add_library(qbt_common_cfg INTERFACE)
# Full C++ 14 support is required # Full C++ 17 support is required
# See also https://cmake.org/cmake/help/latest/prop_gbl/CMAKE_CXX_KNOWN_FEATURES.html # See also https://cmake.org/cmake/help/latest/prop_gbl/CMAKE_CXX_KNOWN_FEATURES.html
# for a breakdown of the features that CMake recognizes for each C++ standard # for a breakdown of the features that CMake recognizes for each C++ standard
target_compile_features(qbt_common_cfg INTERFACE target_compile_features(qbt_common_cfg INTERFACE
cxx_std_14 cxx_std_17
cxx_aggregate_default_initializers
cxx_attribute_deprecated
cxx_binary_literals
cxx_contextual_conversions
cxx_decltype_auto
cxx_digit_separators
cxx_generic_lambdas
cxx_lambda_init_captures
cxx_relaxed_constexpr
cxx_return_type_deduction
cxx_variable_templates
) )
set(QBT_PROJECT_VERSION "${qBittorrent_VERSION_MAJOR}.${qBittorrent_VERSION_MINOR}.${qBittorrent_VERSION_PATCH}")
if (NOT ${qBittorrent_VERSION_TWEAK} EQUAL 0)
set(QBT_PROJECT_VERSION "${QBT_PROJECT_VERSION}.${qBittorrent_VERSION_TWEAK}")
endif()
set(QBT_FULL_VERSION "${QBT_PROJECT_VERSION}${QBT_VER_STATUS}")
target_compile_definitions(qbt_common_cfg INTERFACE target_compile_definitions(qbt_common_cfg INTERFACE
QBT_VERSION="v${QBT_FULL_VERSION}"
QBT_VERSION_2="${QBT_FULL_VERSION}"
QT_DEPRECATED_WARNINGS QT_DEPRECATED_WARNINGS
QT_NO_CAST_TO_ASCII QT_NO_CAST_TO_ASCII
QT_NO_CAST_FROM_BYTEARRAY QT_NO_CAST_FROM_BYTEARRAY
@@ -90,6 +59,12 @@ macro(qbt_common_config)
endif() endif()
endif() endif()
if ((CXX_COMPILER_ID STREQUAL "Clang") OR (CXX_COMPILER_ID STREQUAL "AppleClang"))
target_compile_options(qbt_common_cfg INTERFACE
-Wno-range-loop-analysis
)
endif()
if (MINGW) if (MINGW)
target_link_options(qbt_common_cfg INTERFACE $<$<OR:$<CONFIG:Debug>,$<CONFIG:RelWithDebInfo>>:LINKER:--dynamicbase>) target_link_options(qbt_common_cfg INTERFACE $<$<OR:$<CONFIG:Debug>,$<CONFIG:RelWithDebInfo>>:LINKER:--dynamicbase>)
endif() endif()
@@ -101,8 +76,12 @@ macro(qbt_common_config)
endif() endif()
if (MSVC) if (MSVC)
target_compile_options(qbt_common_cfg INTERFACE /guard:cf) target_compile_options(qbt_common_cfg INTERFACE
target_link_options(qbt_common_cfg INTERFACE /guard:cf /guard:cf
/utf-8
)
target_link_options(qbt_common_cfg INTERFACE
/guard:cf
$<$<NOT:$<CONFIG:Debug>>:/OPT:REF /OPT:ICF> $<$<NOT:$<CONFIG:Debug>>:/OPT:REF /OPT:ICF>
# suppress linking warning due to /INCREMENTAL and /OPT:ICF being both ON # suppress linking warning due to /INCREMENTAL and /OPT:ICF being both ON
$<$<CONFIG:RelWithDebInfo>:/INCREMENTAL:NO> $<$<CONFIG:RelWithDebInfo>:/INCREMENTAL:NO>

4906
configure vendored

File diff suppressed because it is too large Load Diff

View File

@@ -1,4 +1,4 @@
AC_INIT([qbittorrent], [v4.3.2], [bugs.qbittorrent.org], [], [https://www.qbittorrent.org/]) AC_INIT([qbittorrent], [v4.3.3], [bugs.qbittorrent.org], [], [https://www.qbittorrent.org/])
AC_CONFIG_AUX_DIR([build-aux]) AC_CONFIG_AUX_DIR([build-aux])
AC_CONFIG_MACRO_DIR([m4]) AC_CONFIG_MACRO_DIR([m4])
: ${CFLAGS=""} : ${CFLAGS=""}
@@ -194,34 +194,34 @@ PKG_CHECK_MODULES(zlib,
[CXXFLAGS="$zlib_CFLAGS $CXXFLAGS" [CXXFLAGS="$zlib_CFLAGS $CXXFLAGS"
LIBS="$zlib_LIBS $LIBS"]) LIBS="$zlib_LIBS $LIBS"])
# Check if already in >= C++14 mode because of the flags returned by one of the above packages # Check if already in >= C++17 mode because of the flags returned by one of the above packages
TMP_CXXFLAGS="$CXXFLAGS" TMP_CXXFLAGS="$CXXFLAGS"
CXXFLAGS="" CXXFLAGS=""
AC_MSG_CHECKING([if compiler defaults to C++14 or later mode]) AC_MSG_CHECKING([if compiler defaults to C++17 or later mode])
AC_COMPILE_IFELSE([DETECT_CPP14_PROGRAM()], AC_COMPILE_IFELSE([DETECT_CPP17_PROGRAM()],
[AC_MSG_RESULT([yes]) [AC_MSG_RESULT([yes])
QBT_CXX14_FOUND="yes"], QBT_CXX17_FOUND="yes"],
[AC_MSG_RESULT([no]) [AC_MSG_RESULT([no])
QBT_CXX14_FOUND="no"]) QBT_CXX17_FOUND="no"])
# In case of no, check if the compiler can support at least C++14 # In case of no, check if the compiler can support at least C++17
# and if yes, enable it leaving a warning to the user # and if yes, enable it leaving a warning to the user
AS_IF([test "x$QBT_CXX14_FOUND" = "xno"], AS_IF([test "x$QBT_CXX17_FOUND" = "xno"],
[AC_MSG_CHECKING([if compiler supports C++14]) [AC_MSG_CHECKING([if compiler supports C++17])
CXXFLAGS="-std=c++14" CXXFLAGS="-std=c++17"
AC_COMPILE_IFELSE([DETECT_CPP14_PROGRAM()], AC_COMPILE_IFELSE([DETECT_CPP17_PROGRAM()],
[AC_MSG_RESULT([yes]) [AC_MSG_RESULT([yes])
AC_MSG_CHECKING([if C++14 is disabled by the set compiler flags]) AC_MSG_CHECKING([if C++17 is disabled by the set compiler flags])
# prepend the flag so it won't override conflicting user defined flags # prepend the flag so it won't override conflicting user defined flags
CXXFLAGS="-std=c++14 $TMP_CXXFLAGS" CXXFLAGS="-std=c++17 $TMP_CXXFLAGS"
AC_COMPILE_IFELSE([DETECT_CPP14_PROGRAM()], AC_COMPILE_IFELSE([DETECT_CPP17_PROGRAM()],
[AC_MSG_RESULT([no]) [AC_MSG_RESULT([no])
QBT_ADD_CONFIG="$QBT_ADD_CONFIG c++14" QBT_ADD_CONFIG="$QBT_ADD_CONFIG c++1z"
AC_MSG_WARN([C++14 mode is now force enabled. The C++ mode should match the mode that other libraries were built with, otherwise you'll likely get linking errors.])], AC_MSG_WARN([C++17 mode is now force enabled. The C++ mode should match the mode that other libraries were built with, otherwise you'll likely get linking errors.])],
[AC_MSG_RESULT([yes]) [AC_MSG_RESULT([yes])
AC_MSG_ERROR([The compiler supports C++14 but the user or a dependency has explicitly enabled a lower mode.])])], AC_MSG_ERROR([The compiler supports C++17 but the user or a dependency has explicitly enabled a lower mode.])])],
[AC_MSG_RESULT([no]) [AC_MSG_RESULT([no])
AC_MSG_ERROR([A compiler supporting C++14 is required.])]) AC_MSG_ERROR([A compiler supporting C++17 is required.])])
]) ])
CXXFLAGS="$TMP_CXXFLAGS" CXXFLAGS="$TMP_CXXFLAGS"
@@ -272,9 +272,13 @@ AC_SUBST(QBT_REMOVE_CONFIG)
AC_SUBST(QBT_ADD_DEFINES) AC_SUBST(QBT_ADD_DEFINES)
AC_SUBST(QBT_REMOVE_DEFINES) AC_SUBST(QBT_REMOVE_DEFINES)
AC_OUTPUT(conf.pri) QBT_CONFIG_FILES="conf.pri"
AS_IF([test "x$enable_systemd" = "xyes"], AS_IF([test "x$enable_systemd" = "xyes"],
[AC_OUTPUT(dist/unix/systemd/qbittorrent-nox@.service)]) [QBT_CONFIG_FILES="$QBT_CONFIG_FILES dist/unix/systemd/qbittorrent-nox@.service"])
AC_CONFIG_FILES(["$QBT_CONFIG_FILES"])
AC_OUTPUT
AC_MSG_NOTICE([Running qmake to generate the makefile...]) AC_MSG_NOTICE([Running qmake to generate the makefile...])
TOPDIR="$(cd "$(dirname "$0")" && pwd)" TOPDIR="$(cd "$(dirname "$0")" && pwd)"

4
dist/mac/Info.plist vendored
View File

@@ -55,7 +55,7 @@
<key>CFBundlePackageType</key> <key>CFBundlePackageType</key>
<string>APPL</string> <string>APPL</string>
<key>CFBundleShortVersionString</key> <key>CFBundleShortVersionString</key>
<string>4.3.2</string> <string>4.3.3</string>
<key>CFBundleExecutable</key> <key>CFBundleExecutable</key>
<string>@EXECUTABLE@</string> <string>@EXECUTABLE@</string>
<key>CFBundleIdentifier</key> <key>CFBundleIdentifier</key>
@@ -67,7 +67,7 @@
<key>NSAppleScriptEnabled</key> <key>NSAppleScriptEnabled</key>
<string>YES</string> <string>YES</string>
<key>NSHumanReadableCopyright</key> <key>NSHumanReadableCopyright</key>
<string>Copyright © 2006-2020 The qBittorrent project</string> <string>Copyright © 2006-2021 The qBittorrent project</string>
<key>UTExportedTypeDeclarations</key> <key>UTExportedTypeDeclarations</key>
<array> <array>
<dict> <dict>

View File

@@ -74,6 +74,6 @@
<url type="translate">https://github.com/qbittorrent/qBittorrent/wiki/How-to-translate-qBittorrent</url> <url type="translate">https://github.com/qbittorrent/qBittorrent/wiki/How-to-translate-qBittorrent</url>
<content_rating type="oars-1.1"/> <content_rating type="oars-1.1"/>
<releases> <releases>
<release version="4.3.2" date="2020-12-27"/> <release version="4.3.3" date="2021-01-19"/>
</releases> </releases>
</component> </component>

View File

@@ -12,6 +12,9 @@ StartupNotify=false
StartupWMClass=qbittorrent StartupWMClass=qbittorrent
Keywords=bittorrent;torrent;magnet;download;p2p; Keywords=bittorrent;torrent;magnet;download;p2p;
# Translations
# Translations # Translations
Comment[oc]=Telecargar e partejar de fichièrs amb BitTorrent Comment[oc]=Telecargar e partejar de fichièrs amb BitTorrent
GenericName[oc]=Client BitTorrent GenericName[oc]=Client BitTorrent
@@ -85,6 +88,9 @@ Name[hr]=qBittorrent
Comment[hu]=Fájlok letöltése és megosztása a BitTorrent hálózaton keresztül Comment[hu]=Fájlok letöltése és megosztása a BitTorrent hálózaton keresztül
GenericName[hu]=BitTorrent kliens GenericName[hu]=BitTorrent kliens
Name[hu]=qBittorrent Name[hu]=qBittorrent
Comment[hy]=Նիշքերի փոխանցում BitTorrent-ի միջոցով
GenericName[hy]=BitTorrent սպասառու
Name[hy]=qBittorrent
Comment[id]=Unduh dan berbagi berkas melalui BitTorrent Comment[id]=Unduh dan berbagi berkas melalui BitTorrent
GenericName[id]=Klien BitTorrent GenericName[id]=Klien BitTorrent
Name[id]=qBittorrent Name[id]=qBittorrent
@@ -100,8 +106,8 @@ Name[ja]=qBittorrent
Comment[ka]=ჩამოტვირთე და გააზიარე ფაილები Bittorrent-ის საშუალებით Comment[ka]=ჩამოტვირთე და გააზიარე ფაილები Bittorrent-ის საშუალებით
GenericName[ka]=BitTorrent კლიენტი GenericName[ka]=BitTorrent კლიენტი
Name[ka]=qBittorrent Name[ka]=qBittorrent
Comment[ko]=비트토트를 통해 파일을 받고 공유합니다 Comment[ko]=비트토트를 통해 파일을 받고 공유합니다
GenericName[ko]=비트토트 클라이언트 GenericName[ko]=비트토트 클라이언트
Name[ko]=qBittorrent Name[ko]=qBittorrent
Comment[zh]=通过 BitTorrent 下载和分享文件 Comment[zh]=通过 BitTorrent 下载和分享文件
GenericName[zh]=BitTorrent 客户端 GenericName[zh]=BitTorrent 客户端
@@ -189,8 +195,8 @@ Name[ms_MY]=qBittorrent
Comment[eo]=Elŝutu kaj kunhavigu dosierojn per BitTorrent Comment[eo]=Elŝutu kaj kunhavigu dosierojn per BitTorrent
GenericName[eo]=BitTorrent-kliento GenericName[eo]=BitTorrent-kliento
Name[eo]=qBittorrent Name[eo]=qBittorrent
Comment[mn_MN]=BitTorrent ашиглан файлуудыг татаж түгээх Comment[mn_MN]=BitTorrent-оор файлуудаа тат, түгээ
GenericName[mn_MN]=BitTorrent үйлчлүүлэгч GenericName[mn_MN]=BitTorrent татагч
Name[mn_MN]=qBittorrent Name[mn_MN]=qBittorrent
Comment[ta]=BitTorrent வழியாக கோப்புகளை பதிவிறக்க மற்றும் பகிர Comment[ta]=BitTorrent வழியாக கோப்புகளை பதிவிறக்க மற்றும் பகிர
GenericName[ta]=BitTorrent வாடிக்கையாளர் GenericName[ta]=BitTorrent வாடிக்கையாளர்

View File

@@ -28,7 +28,7 @@ XPStyle on
!define CSIDL_LOCALAPPDATA '0x1C' ;Local Application Data path !define CSIDL_LOCALAPPDATA '0x1C' ;Local Application Data path
; Program specific ; Program specific
!define PROG_VERSION "4.3.2" !define PROG_VERSION "4.3.3"
!define MUI_FINISHPAGE_RUN !define MUI_FINISHPAGE_RUN
!define MUI_FINISHPAGE_RUN_FUNCTION PageFinishRun !define MUI_FINISHPAGE_RUN_FUNCTION PageFinishRun
@@ -51,7 +51,7 @@ XPStyle on
;Installer Version Information ;Installer Version Information
VIAddVersionKey "ProductName" "qBittorrent" VIAddVersionKey "ProductName" "qBittorrent"
VIAddVersionKey "CompanyName" "The qBittorrent project" VIAddVersionKey "CompanyName" "The qBittorrent project"
VIAddVersionKey "LegalCopyright" "Copyright ©2006-2020 The qBittorrent project" VIAddVersionKey "LegalCopyright" "Copyright ©2006-2021 The qBittorrent project"
VIAddVersionKey "FileDescription" "qBittorrent - A Bittorrent Client" VIAddVersionKey "FileDescription" "qBittorrent - A Bittorrent Client"
VIAddVersionKey "FileVersion" "${PROG_VERSION}" VIAddVersionKey "FileVersion" "${PROG_VERSION}"

View File

@@ -37,15 +37,15 @@ AC_DEFUN([FIND_QTDBUS],
HAVE_QTDBUS=[false]]) HAVE_QTDBUS=[false]])
]) ])
# DETECT_CPP14_PROGRAM() # DETECT_CPP17_PROGRAM()
# Detects if at least C++14 mode is enabled. # Detects if at least C++17 mode is enabled.
# -------------------------------------- # --------------------------------------
AC_DEFUN([DETECT_CPP14_PROGRAM], AC_DEFUN([DETECT_CPP17_PROGRAM],
[AC_LANG_PROGRAM([[ [AC_LANG_PROGRAM([[
#ifndef __cplusplus #ifndef __cplusplus
#error "This is not a C++ compiler" #error "This is not a C++ compiler"
#elif __cplusplus < 201402L #elif __cplusplus < 201703L
#error "This is not a C++14 compiler" #error "This is not a C++17 compiler"
#endif]], #endif]],
[[]]) [[]])
]) ])

View File

@@ -7,6 +7,8 @@ else {
include(conf.pri) include(conf.pri)
} }
QMAKE_MACOSX_DEPLOYMENT_TARGET = 10.14
LIBS += -framework Carbon -framework IOKit -framework AppKit LIBS += -framework Carbon -framework IOKit -framework AppKit
QT_LANG_PATH = ../dist/qt-translations QT_LANG_PATH = ../dist/qt-translations

View File

@@ -4,19 +4,6 @@ SUBDIRS += src
include(version.pri) include(version.pri)
# Make target to create release tarball. Use 'make tarball'
tarball.commands += rm -fR ../$${PROJECT_NAME}-$${PROJECT_VERSION}/ &&
tarball.commands += git clone . ../$${PROJECT_NAME}-$${PROJECT_VERSION} &&
tarball.commands += rm -fR ../$${PROJECT_NAME}-$${PROJECT_VERSION}/.git &&
tarball.commands += rm -f ../$${PROJECT_NAME}-$${PROJECT_VERSION}/.gitignore &&
tarball.commands += cd .. &&
tarball.commands += tar czf $${PROJECT_NAME}-$${PROJECT_VERSION}.tar.gz $${PROJECT_NAME}-$${PROJECT_VERSION} &&
tarball.commands += tar cf $${PROJECT_NAME}-$${PROJECT_VERSION}.tar $${PROJECT_NAME}-$${PROJECT_VERSION} &&
tarball.commands += xz -f $${PROJECT_NAME}-$${PROJECT_VERSION}.tar &&
tarball.commands += rm -fR $${PROJECT_NAME}-$${PROJECT_VERSION}
QMAKE_EXTRA_TARGETS += tarball
# For Qt Creator beautifier # For Qt Creator beautifier
DISTFILES += \ DISTFILES += \
uncrustify.cfg uncrustify.cfg

View File

@@ -61,7 +61,6 @@ target_sources(qbt_app PRIVATE
target_link_libraries(qbt_app PRIVATE target_link_libraries(qbt_app PRIVATE
qbt_base qbt_base
qbt_version_definitions
) )
set_target_properties(qbt_app PROPERTIES RUNTIME_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}") set_target_properties(qbt_app PROPERTIES RUNTIME_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}")

View File

@@ -63,7 +63,7 @@
#include "base/bittorrent/infohash.h" #include "base/bittorrent/infohash.h"
#include "base/bittorrent/session.h" #include "base/bittorrent/session.h"
#include "base/bittorrent/torrenthandle.h" #include "base/bittorrent/torrent.h"
#include "base/exceptions.h" #include "base/exceptions.h"
#include "base/iconprovider.h" #include "base/iconprovider.h"
#include "base/logger.h" #include "base/logger.h"
@@ -81,6 +81,7 @@
#include "base/utils/fs.h" #include "base/utils/fs.h"
#include "base/utils/misc.h" #include "base/utils/misc.h"
#include "base/utils/string.h" #include "base/utils/string.h"
#include "base/version.h"
#include "applicationinstancemanager.h" #include "applicationinstancemanager.h"
#include "filelogger.h" #include "filelogger.h"
@@ -214,7 +215,7 @@ const QBtCommandLineParameters &Application::commandLineArgs() const
bool Application::isFileLoggerEnabled() const bool Application::isFileLoggerEnabled() const
{ {
return settings()->loadValue(KEY_FILELOGGER_ENABLED, true).toBool(); return settings()->loadValue(KEY_FILELOGGER_ENABLED, true);
} }
void Application::setFileLoggerEnabled(const bool value) void Application::setFileLoggerEnabled(const bool value)
@@ -228,8 +229,8 @@ void Application::setFileLoggerEnabled(const bool value)
QString Application::fileLoggerPath() const QString Application::fileLoggerPath() const
{ {
return settings()->loadValue(KEY_FILELOGGER_PATH, return settings()->loadValue(KEY_FILELOGGER_PATH
{specialFolderLocation(SpecialFolder::Data) + LOG_FOLDER}).toString(); , QString {specialFolderLocation(SpecialFolder::Data) + LOG_FOLDER});
} }
void Application::setFileLoggerPath(const QString &path) void Application::setFileLoggerPath(const QString &path)
@@ -241,7 +242,7 @@ void Application::setFileLoggerPath(const QString &path)
bool Application::isFileLoggerBackup() const bool Application::isFileLoggerBackup() const
{ {
return settings()->loadValue(KEY_FILELOGGER_BACKUP, true).toBool(); return settings()->loadValue(KEY_FILELOGGER_BACKUP, true);
} }
void Application::setFileLoggerBackup(const bool value) void Application::setFileLoggerBackup(const bool value)
@@ -253,7 +254,7 @@ void Application::setFileLoggerBackup(const bool value)
bool Application::isFileLoggerDeleteOld() const bool Application::isFileLoggerDeleteOld() const
{ {
return settings()->loadValue(KEY_FILELOGGER_DELETEOLD, true).toBool(); return settings()->loadValue(KEY_FILELOGGER_DELETEOLD, true);
} }
void Application::setFileLoggerDeleteOld(const bool value) void Application::setFileLoggerDeleteOld(const bool value)
@@ -265,7 +266,7 @@ void Application::setFileLoggerDeleteOld(const bool value)
int Application::fileLoggerMaxSize() const int Application::fileLoggerMaxSize() const
{ {
const int val = settings()->loadValue(KEY_FILELOGGER_MAXSIZEBYTES, DEFAULT_FILELOG_SIZE).toInt(); const int val = settings()->loadValue(KEY_FILELOGGER_MAXSIZEBYTES, DEFAULT_FILELOG_SIZE);
return std::min(std::max(val, MIN_FILELOG_SIZE), MAX_FILELOG_SIZE); return std::min(std::max(val, MIN_FILELOG_SIZE), MAX_FILELOG_SIZE);
} }
@@ -279,7 +280,7 @@ void Application::setFileLoggerMaxSize(const int bytes)
int Application::fileLoggerAge() const int Application::fileLoggerAge() const
{ {
const int val = settings()->loadValue(KEY_FILELOGGER_AGE, 1).toInt(); const int val = settings()->loadValue(KEY_FILELOGGER_AGE, 1);
return std::min(std::max(val, 1), 365); return std::min(std::max(val, 1), 365);
} }
@@ -290,7 +291,7 @@ void Application::setFileLoggerAge(const int value)
int Application::fileLoggerAgeType() const int Application::fileLoggerAgeType() const
{ {
const int val = settings()->loadValue(KEY_FILELOGGER_AGETYPE, 1).toInt(); const int val = settings()->loadValue(KEY_FILELOGGER_AGETYPE, 1);
return ((val < 0) || (val > 2)) ? 1 : val; return ((val < 0) || (val > 2)) ? 1 : val;
} }
@@ -310,7 +311,7 @@ void Application::processMessage(const QString &message)
m_paramsQueue.append(params); m_paramsQueue.append(params);
} }
void Application::runExternalProgram(const BitTorrent::TorrentHandle *torrent) const void Application::runExternalProgram(const BitTorrent::Torrent *torrent) const
{ {
QString program = Preferences::instance()->getAutoRunProgram().trimmed(); QString program = Preferences::instance()->getAutoRunProgram().trimmed();
program.replace("%N", torrent->name()); program.replace("%N", torrent->name());
@@ -404,7 +405,7 @@ void Application::runExternalProgram(const BitTorrent::TorrentHandle *torrent) c
#endif #endif
} }
void Application::sendNotificationEmail(const BitTorrent::TorrentHandle *torrent) void Application::sendNotificationEmail(const BitTorrent::Torrent *torrent)
{ {
// Prepare mail content // Prepare mail content
const QString content = tr("Torrent name: %1").arg(torrent->name()) + '\n' const QString content = tr("Torrent name: %1").arg(torrent->name()) + '\n'
@@ -423,7 +424,7 @@ void Application::sendNotificationEmail(const BitTorrent::TorrentHandle *torrent
content); content);
} }
void Application::torrentFinished(BitTorrent::TorrentHandle *const torrent) void Application::torrentFinished(BitTorrent::Torrent *const torrent)
{ {
Preferences *const pref = Preferences::instance(); Preferences *const pref = Preferences::instance();
@@ -505,7 +506,7 @@ void Application::processParams(const QStringList &params)
} }
#endif #endif
BitTorrent::AddTorrentParams torrentParams; BitTorrent::AddTorrentParams torrentParams;
TriStateBool skipTorrentDialog; std::optional<bool> skipTorrentDialog;
for (QString param : params) for (QString param : params)
{ {
@@ -521,7 +522,7 @@ void Application::processParams(const QStringList &params)
if (param.startsWith(QLatin1String("@addPaused="))) if (param.startsWith(QLatin1String("@addPaused=")))
{ {
torrentParams.addPaused = param.midRef(11).toInt() ? TriStateBool::True : TriStateBool::False; torrentParams.addPaused = (param.midRef(11).toInt() != 0);
continue; continue;
} }
@@ -551,7 +552,7 @@ void Application::processParams(const QStringList &params)
if (param.startsWith(QLatin1String("@skipDialog="))) if (param.startsWith(QLatin1String("@skipDialog=")))
{ {
skipTorrentDialog = param.midRef(12).toInt() ? TriStateBool::True : TriStateBool::False; skipTorrentDialog = (param.midRef(12).toInt() != 0);
continue; continue;
} }
@@ -561,9 +562,7 @@ void Application::processParams(const QStringList &params)
// be shown and skipTorrentDialog is undefined. The other is when // be shown and skipTorrentDialog is undefined. The other is when
// skipTorrentDialog is false, meaning that the application setting // skipTorrentDialog is false, meaning that the application setting
// should be overridden. // should be overridden.
const bool showDialogForThisTorrent = const bool showDialogForThisTorrent = !skipTorrentDialog.value_or(!AddNewTorrentDialog::isEnabled());
((AddNewTorrentDialog::isEnabled() && skipTorrentDialog == TriStateBool::Undefined)
|| skipTorrentDialog == TriStateBool::False);
if (showDialogForThisTorrent) if (showDialogForThisTorrent)
AddNewTorrentDialog::show(param, torrentParams, m_window); AddNewTorrentDialog::show(param, torrentParams, m_window);
else else

View File

@@ -59,7 +59,7 @@ class FileLogger;
namespace BitTorrent namespace BitTorrent
{ {
class TorrentHandle; class Torrent;
} }
namespace RSS namespace RSS
@@ -112,7 +112,7 @@ protected:
private slots: private slots:
void processMessage(const QString &message); void processMessage(const QString &message);
void torrentFinished(BitTorrent::TorrentHandle *const torrent); void torrentFinished(BitTorrent::Torrent *const torrent);
void allTorrentsFinished(); void allTorrentsFinished();
void cleanup(); void cleanup();
#if (!defined(DISABLE_GUI) && defined(Q_OS_WIN)) #if (!defined(DISABLE_GUI) && defined(Q_OS_WIN))
@@ -142,6 +142,6 @@ private:
void initializeTranslation(); void initializeTranslation();
void processParams(const QStringList &params); void processParams(const QStringList &params);
void runExternalProgram(const BitTorrent::TorrentHandle *torrent) const; void runExternalProgram(const BitTorrent::Torrent *torrent) const;
void sendNotificationEmail(const BitTorrent::TorrentHandle *torrent); void sendNotificationEmail(const BitTorrent::Torrent *torrent);
}; };

View File

@@ -254,13 +254,13 @@ namespace
return padUsageText(fullParameter() + QLatin1String("=<true|false>")); return padUsageText(fullParameter() + QLatin1String("=<true|false>"));
} }
TriStateBool value(const QString &arg) const std::optional<bool> value(const QString &arg) const
{ {
QStringList parts = arg.split(QLatin1Char('=')); QStringList parts = arg.split(QLatin1Char('='));
if (parts.size() == 1) if (parts.size() == 1)
{ {
return TriStateBool(m_defaultValue); return m_defaultValue;
} }
if (parts.size() == 2) if (parts.size() == 2)
{ {
@@ -268,11 +268,11 @@ namespace
if ((val.toUpper() == QLatin1String("TRUE")) || (val == QLatin1String("1"))) if ((val.toUpper() == QLatin1String("TRUE")) || (val == QLatin1String("1")))
{ {
return TriStateBool::True; return true;
} }
if ((val.toUpper() == QLatin1String("FALSE")) || (val == QLatin1String("0"))) if ((val.toUpper() == QLatin1String("FALSE")) || (val == QLatin1String("0")))
{ {
return TriStateBool::False; return false;
} }
} }
@@ -282,30 +282,30 @@ namespace
.arg(fullParameter(), QLatin1String("<true|false>"))); .arg(fullParameter(), QLatin1String("<true|false>")));
} }
TriStateBool value(const QProcessEnvironment &env) const std::optional<bool> value(const QProcessEnvironment &env) const
{ {
const QString val = env.value(envVarName(), "-1"); const QString val = env.value(envVarName(), "-1");
if (val.isEmpty()) if (val.isEmpty())
{ {
return TriStateBool(m_defaultValue); return m_defaultValue;
} }
if (val == QLatin1String("-1")) if (val == QLatin1String("-1"))
{ {
return TriStateBool::Undefined; return std::nullopt;
} }
if ((val.toUpper() == QLatin1String("TRUE")) || (val == QLatin1String("1"))) if ((val.toUpper() == QLatin1String("TRUE")) || (val == QLatin1String("1")))
{ {
return TriStateBool::True; return true;
} }
if ((val.toUpper() == QLatin1String("FALSE")) || (val == QLatin1String("0"))) if ((val.toUpper() == QLatin1String("FALSE")) || (val == QLatin1String("0")))
{ {
return TriStateBool::False; return false;
} }
qDebug() << QObject::tr("Expected %1 in environment variable '%2', but got '%3'") qDebug() << QObject::tr("Expected %1 in environment variable '%2', but got '%3'")
.arg(QLatin1String("true|false"), envVarName(), val); .arg(QLatin1String("true|false"), envVarName(), val);
return TriStateBool::Undefined; return std::nullopt;
} }
bool m_defaultValue; bool m_defaultValue;
@@ -374,14 +374,8 @@ QStringList QBtCommandLineParameters::paramList() const
if (!savePath.isEmpty()) if (!savePath.isEmpty())
result.append(QLatin1String("@savePath=") + savePath); result.append(QLatin1String("@savePath=") + savePath);
if (addPaused == TriStateBool::True) if (addPaused.has_value())
{ result.append(*addPaused ? QLatin1String {"@addPaused=1"} : QLatin1String {"@addPaused=0"});
result.append(QLatin1String("@addPaused=1"));
}
else if (addPaused == TriStateBool::False)
{
result.append(QLatin1String("@addPaused=0"));
}
if (skipChecking) if (skipChecking)
result.append(QLatin1String("@skipChecking")); result.append(QLatin1String("@skipChecking"));
@@ -395,14 +389,8 @@ QStringList QBtCommandLineParameters::paramList() const
if (firstLastPiecePriority) if (firstLastPiecePriority)
result.append(QLatin1String("@firstLastPiecePriority")); result.append(QLatin1String("@firstLastPiecePriority"));
if (skipDialog == TriStateBool::True) if (skipDialog.has_value())
{ result.append(*skipDialog ? QLatin1String {"@skipDialog=1"} : QLatin1String {"@skipDialog=0"});
result.append(QLatin1String("@skipDialog=1"));
}
else if (skipDialog == TriStateBool::False)
{
result.append(QLatin1String("@skipDialog=0"));
}
result += torrents; result += torrents;
return result; return result;

View File

@@ -30,13 +30,12 @@
#pragma once #pragma once
#include <optional>
#include <stdexcept> #include <stdexcept>
#include <QString> #include <QString>
#include <QStringList> #include <QStringList>
#include "base/tristatebool.h"
class QProcessEnvironment; class QProcessEnvironment;
struct QBtCommandLineParameters struct QBtCommandLineParameters
@@ -55,8 +54,8 @@ struct QBtCommandLineParameters
bool shouldDaemonize; bool shouldDaemonize;
#endif #endif
int webUiPort; int webUiPort;
TriStateBool addPaused; std::optional<bool> addPaused;
TriStateBool skipDialog; std::optional<bool> skipDialog;
QStringList torrents; QStringList torrents;
QString profileDir; QString profileDir;
QString configurationName; QString configurationName;

View File

@@ -78,6 +78,7 @@ Q_IMPORT_PLUGIN(QICOPlugin)
#include "base/preferences.h" #include "base/preferences.h"
#include "base/profile.h" #include "base/profile.h"
#include "base/version.h"
#include "application.h" #include "application.h"
#include "cmdoptions.h" #include "cmdoptions.h"
#include "upgrade.h" #include "upgrade.h"

View File

@@ -152,7 +152,7 @@ bool QtLocalPeer::isClient()
#endif #endif
if (!res) if (!res)
qWarning("QtSingleCoreApplication: listen on local socket failed, %s", qPrintable(server->errorString())); qWarning("QtSingleCoreApplication: listen on local socket failed, %s", qPrintable(server->errorString()));
QObject::connect(server, SIGNAL(newConnection()), SLOT(receiveConnection())); connect(server, &QLocalServer::newConnection, this, &QtLocalPeer::receiveConnection);
return false; return false;
} }

View File

@@ -32,6 +32,7 @@
#include <QString> #include <QString>
#include "base/utils/misc.h" #include "base/utils/misc.h"
#include "base/version.h"
#include "ui_stacktracedialog.h" #include "ui_stacktracedialog.h"
StacktraceDialog::StacktraceDialog(QWidget *parent) StacktraceDialog::StacktraceDialog(QWidget *parent)

View File

@@ -46,8 +46,8 @@ namespace
const auto migrate = [](const QString &oldKey, const QString &newKey, const QString &savePath) const auto migrate = [](const QString &oldKey, const QString &newKey, const QString &savePath)
{ {
SettingsStorage *settingsStorage {SettingsStorage::instance()}; SettingsStorage *settingsStorage {SettingsStorage::instance()};
const QByteArray oldData {settingsStorage->loadValue(oldKey).toByteArray()}; const auto oldData {settingsStorage->loadValue<QByteArray>(oldKey)};
const QString newData {settingsStorage->loadValue(newKey).toString()}; const auto newData {settingsStorage->loadValue<QString>(newKey)};
const QString errorMsgFormat {QObject::tr("Migrate preferences failed: WebUI https, file: \"%1\", error: \"%2\"")}; const QString errorMsgFormat {QObject::tr("Migrate preferences failed: WebUI https, file: \"%1\", error: \"%2\"")};
if (!newData.isEmpty() || oldData.isEmpty()) if (!newData.isEmpty() || oldData.isEmpty())
@@ -89,8 +89,8 @@ namespace
const QString newKey {QLatin1String {"BitTorrent/Session/TorrentContentLayout"}}; const QString newKey {QLatin1String {"BitTorrent/Session/TorrentContentLayout"}};
SettingsStorage *settingsStorage {SettingsStorage::instance()}; SettingsStorage *settingsStorage {SettingsStorage::instance()};
const QVariant oldData {settingsStorage->loadValue(oldKey)}; const auto oldData {settingsStorage->loadValue<QVariant>(oldKey)};
const QString newData {settingsStorage->loadValue(newKey).toString()}; const auto newData {settingsStorage->loadValue<QString>(newKey)};
if (!newData.isEmpty() || !oldData.isValid()) if (!newData.isEmpty() || !oldData.isValid())
return; return;
@@ -128,7 +128,7 @@ void handleChangedDefaults(const DefaultPreferencesMode mode)
SettingsStorage *settingsStorage {SettingsStorage::instance()}; SettingsStorage *settingsStorage {SettingsStorage::instance()};
for (auto it = changedDefaults.cbegin(); it != changedDefaults.cend(); ++it) for (auto it = changedDefaults.cbegin(); it != changedDefaults.cend(); ++it)
{ {
if (settingsStorage->loadValue(it->name).isNull()) if (settingsStorage->loadValue<QVariant>(it->name).isNull())
settingsStorage->storeValue(it->name, (mode == DefaultPreferencesMode::Legacy ? it->legacy : it->current)); settingsStorage->storeValue(it->name, (mode == DefaultPreferencesMode::Legacy ? it->legacy : it->current));
} }
} }

View File

@@ -2,6 +2,7 @@ add_library(qbt_base STATIC
# headers # headers
algorithm.h algorithm.h
asyncfilestorage.h asyncfilestorage.h
bittorrent/abstractfilestorage.h
bittorrent/addtorrentparams.h bittorrent/addtorrentparams.h
bittorrent/bandwidthscheduler.h bittorrent/bandwidthscheduler.h
bittorrent/cachestatus.h bittorrent/cachestatus.h
@@ -24,10 +25,10 @@ add_library(qbt_base STATIC
bittorrent/sessionstatus.h bittorrent/sessionstatus.h
bittorrent/speedmonitor.h bittorrent/speedmonitor.h
bittorrent/statistics.h bittorrent/statistics.h
bittorrent/torrent.h
bittorrent/torrentcontentlayout.h bittorrent/torrentcontentlayout.h
bittorrent/torrentcreatorthread.h bittorrent/torrentcreatorthread.h
bittorrent/torrenthandle.h bittorrent/torrentimpl.h
bittorrent/torrenthandleimpl.h
bittorrent/torrentinfo.h bittorrent/torrentinfo.h
bittorrent/tracker.h bittorrent/tracker.h
bittorrent/trackerentry.h bittorrent/trackerentry.h
@@ -72,7 +73,6 @@ add_library(qbt_base STATIC
settingsstorage.h settingsstorage.h
torrentfileguard.h torrentfileguard.h
torrentfilter.h torrentfilter.h
tristatebool.h
types.h types.h
unicodestrings.h unicodestrings.h
utils/bytearray.h utils/bytearray.h
@@ -86,9 +86,11 @@ add_library(qbt_base STATIC
utils/random.h utils/random.h
utils/string.h utils/string.h
utils/version.h utils/version.h
version.h
# sources # sources
asyncfilestorage.cpp asyncfilestorage.cpp
bittorrent/abstractfilestorage.cpp
bittorrent/bandwidthscheduler.cpp bittorrent/bandwidthscheduler.cpp
bittorrent/customstorage.cpp bittorrent/customstorage.cpp
bittorrent/downloadpriority.cpp bittorrent/downloadpriority.cpp
@@ -105,9 +107,9 @@ add_library(qbt_base STATIC
bittorrent/session.cpp bittorrent/session.cpp
bittorrent/speedmonitor.cpp bittorrent/speedmonitor.cpp
bittorrent/statistics.cpp bittorrent/statistics.cpp
bittorrent/torrent.cpp
bittorrent/torrentcreatorthread.cpp bittorrent/torrentcreatorthread.cpp
bittorrent/torrenthandle.cpp bittorrent/torrentimpl.cpp
bittorrent/torrenthandleimpl.cpp
bittorrent/torrentinfo.cpp bittorrent/torrentinfo.cpp
bittorrent/tracker.cpp bittorrent/tracker.cpp
bittorrent/trackerentry.cpp bittorrent/trackerentry.cpp
@@ -148,7 +150,6 @@ add_library(qbt_base STATIC
settingsstorage.cpp settingsstorage.cpp
torrentfileguard.cpp torrentfileguard.cpp
torrentfilter.cpp torrentfilter.cpp
tristatebool.cpp
utils/bytearray.cpp utils/bytearray.cpp
utils/foreignapps.cpp utils/foreignapps.cpp
utils/fs.cpp utils/fs.cpp
@@ -165,7 +166,6 @@ target_link_libraries(qbt_base
PRIVATE PRIVATE
OpenSSL::Crypto OpenSSL::SSL OpenSSL::Crypto OpenSSL::SSL
ZLIB::ZLIB ZLIB::ZLIB
qbt_version_definitions
PUBLIC PUBLIC
LibtorrentRasterbar::torrent-rasterbar LibtorrentRasterbar::torrent-rasterbar
Qt5::Core Qt5::Network Qt5::Xml Qt5::Core Qt5::Network Qt5::Xml

View File

@@ -32,9 +32,6 @@
namespace Algorithm namespace Algorithm
{ {
template <typename ...>
using void_t = void; // replace this with std::void_t in C++17
template <typename T, typename = void> template <typename T, typename = void>
struct HasMappedType struct HasMappedType
: std::false_type : std::false_type
@@ -42,7 +39,7 @@ namespace Algorithm
}; };
template <typename T> template <typename T>
struct HasMappedType<T, void_t<typename T::mapped_type>> struct HasMappedType<T, std::void_t<typename T::mapped_type>>
: std::true_type : std::true_type
{ {
}; };

View File

@@ -1,6 +1,7 @@
HEADERS += \ HEADERS += \
$$PWD/algorithm.h \ $$PWD/algorithm.h \
$$PWD/asyncfilestorage.h \ $$PWD/asyncfilestorage.h \
$$PWD/bittorrent/abstractfilestorage.h \
$$PWD/bittorrent/addtorrentparams.h \ $$PWD/bittorrent/addtorrentparams.h \
$$PWD/bittorrent/bandwidthscheduler.h \ $$PWD/bittorrent/bandwidthscheduler.h \
$$PWD/bittorrent/cachestatus.h \ $$PWD/bittorrent/cachestatus.h \
@@ -23,10 +24,10 @@ HEADERS += \
$$PWD/bittorrent/sessionstatus.h \ $$PWD/bittorrent/sessionstatus.h \
$$PWD/bittorrent/speedmonitor.h \ $$PWD/bittorrent/speedmonitor.h \
$$PWD/bittorrent/statistics.h \ $$PWD/bittorrent/statistics.h \
$$PWD/bittorrent/torrent.h \
$$PWD/bittorrent/torrentcontentlayout.h \ $$PWD/bittorrent/torrentcontentlayout.h \
$$PWD/bittorrent/torrentcreatorthread.h \ $$PWD/bittorrent/torrentcreatorthread.h \
$$PWD/bittorrent/torrenthandle.h \ $$PWD/bittorrent/torrentimpl.h \
$$PWD/bittorrent/torrenthandleimpl.h \
$$PWD/bittorrent/torrentinfo.h \ $$PWD/bittorrent/torrentinfo.h \
$$PWD/bittorrent/tracker.h \ $$PWD/bittorrent/tracker.h \
$$PWD/bittorrent/trackerentry.h \ $$PWD/bittorrent/trackerentry.h \
@@ -72,7 +73,6 @@ HEADERS += \
$$PWD/settingvalue.h \ $$PWD/settingvalue.h \
$$PWD/torrentfileguard.h \ $$PWD/torrentfileguard.h \
$$PWD/torrentfilter.h \ $$PWD/torrentfilter.h \
$$PWD/tristatebool.h \
$$PWD/types.h \ $$PWD/types.h \
$$PWD/unicodestrings.h \ $$PWD/unicodestrings.h \
$$PWD/utils/bytearray.h \ $$PWD/utils/bytearray.h \
@@ -85,10 +85,12 @@ HEADERS += \
$$PWD/utils/password.h \ $$PWD/utils/password.h \
$$PWD/utils/random.h \ $$PWD/utils/random.h \
$$PWD/utils/string.h \ $$PWD/utils/string.h \
$$PWD/utils/version.h $$PWD/utils/version.h \
$$PWD/version.h
SOURCES += \ SOURCES += \
$$PWD/asyncfilestorage.cpp \ $$PWD/asyncfilestorage.cpp \
$$PWD/bittorrent/abstractfilestorage.cpp \
$$PWD/bittorrent/bandwidthscheduler.cpp \ $$PWD/bittorrent/bandwidthscheduler.cpp \
$$PWD/bittorrent/customstorage.cpp \ $$PWD/bittorrent/customstorage.cpp \
$$PWD/bittorrent/downloadpriority.cpp \ $$PWD/bittorrent/downloadpriority.cpp \
@@ -105,9 +107,9 @@ SOURCES += \
$$PWD/bittorrent/session.cpp \ $$PWD/bittorrent/session.cpp \
$$PWD/bittorrent/speedmonitor.cpp \ $$PWD/bittorrent/speedmonitor.cpp \
$$PWD/bittorrent/statistics.cpp \ $$PWD/bittorrent/statistics.cpp \
$$PWD/bittorrent/torrent.cpp \
$$PWD/bittorrent/torrentcreatorthread.cpp \ $$PWD/bittorrent/torrentcreatorthread.cpp \
$$PWD/bittorrent/torrenthandle.cpp \ $$PWD/bittorrent/torrentimpl.cpp \
$$PWD/bittorrent/torrenthandleimpl.cpp \
$$PWD/bittorrent/torrentinfo.cpp \ $$PWD/bittorrent/torrentinfo.cpp \
$$PWD/bittorrent/tracker.cpp \ $$PWD/bittorrent/tracker.cpp \
$$PWD/bittorrent/trackerentry.cpp \ $$PWD/bittorrent/trackerentry.cpp \
@@ -148,7 +150,6 @@ SOURCES += \
$$PWD/settingsstorage.cpp \ $$PWD/settingsstorage.cpp \
$$PWD/torrentfileguard.cpp \ $$PWD/torrentfileguard.cpp \
$$PWD/torrentfilter.cpp \ $$PWD/torrentfilter.cpp \
$$PWD/tristatebool.cpp \
$$PWD/utils/bytearray.cpp \ $$PWD/utils/bytearray.cpp \
$$PWD/utils/foreignapps.cpp \ $$PWD/utils/foreignapps.cpp \
$$PWD/utils/fs.cpp \ $$PWD/utils/fs.cpp \

View File

@@ -0,0 +1,140 @@
/*
* Bittorrent Client using Qt and libtorrent.
* Copyright (C) 2020 Vladimir Golovnev <glassez@yandex.ru>
*
* 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 "abstractfilestorage.h"
#include <QDir>
#include <QHash>
#include <QVector>
#include "base/bittorrent/common.h"
#include "base/exceptions.h"
#include "base/utils/fs.h"
#if defined(Q_OS_WIN)
const Qt::CaseSensitivity CASE_SENSITIVITY {Qt::CaseInsensitive};
#else
const Qt::CaseSensitivity CASE_SENSITIVITY {Qt::CaseSensitive};
#endif
namespace
{
bool areSameFileNames(QString first, QString second)
{
if (first.endsWith(QB_EXT, Qt::CaseInsensitive))
first.chop(QB_EXT.size());
if (second.endsWith(QB_EXT, Qt::CaseInsensitive))
second.chop(QB_EXT.size());
return QString::compare(first, second, CASE_SENSITIVITY) == 0;
}
}
void BitTorrent::AbstractFileStorage::renameFile(const QString &oldPath, const QString &newPath)
{
if (!Utils::Fs::isValidFileSystemName(oldPath, true))
throw RuntimeError {tr("The old path is invalid: '%1'.").arg(oldPath)};
if (!Utils::Fs::isValidFileSystemName(newPath, true))
throw RuntimeError {tr("The new path is invalid: '%1'.").arg(newPath)};
const QString oldFilePath = Utils::Fs::toUniformPath(oldPath);
if (oldFilePath.endsWith(QLatin1Char {'/'}))
throw RuntimeError {tr("Invalid file path: '%1'.").arg(oldFilePath)};
const QString newFilePath = Utils::Fs::toUniformPath(newPath);
if (newFilePath.endsWith(QLatin1Char {'/'}))
throw RuntimeError {tr("Invalid file path: '%1'.").arg(newFilePath)};
if (QDir().isAbsolutePath(newFilePath))
throw RuntimeError {tr("Absolute path isn't allowed: '%1'.").arg(newFilePath)};
int renamingFileIndex = -1;
for (int i = 0; i < filesCount(); ++i)
{
const QString path = filePath(i);
if ((renamingFileIndex < 0) && areSameFileNames(path, oldFilePath))
renamingFileIndex = i;
if (areSameFileNames(path, newFilePath))
throw RuntimeError {tr("The file already exists: '%1'.").arg(newFilePath)};
}
if (renamingFileIndex < 0)
throw RuntimeError {tr("No such file: '%1'.").arg(oldFilePath)};
const auto extAdjusted = [](const QString &path, const bool needExt) -> QString
{
if (path.endsWith(QB_EXT, Qt::CaseInsensitive) == needExt)
return path;
return (needExt ? (path + QB_EXT) : (path.left(path.size() - QB_EXT.size())));
};
renameFile(renamingFileIndex, extAdjusted(newFilePath, filePath(renamingFileIndex).endsWith(QB_EXT, Qt::CaseInsensitive)));
}
void BitTorrent::AbstractFileStorage::renameFolder(const QString &oldPath, const QString &newPath)
{
if (!Utils::Fs::isValidFileSystemName(oldPath, true))
throw RuntimeError {tr("The old path is invalid: '%1'.").arg(oldPath)};
if (!Utils::Fs::isValidFileSystemName(newPath, true))
throw RuntimeError {tr("The new path is invalid: '%1'.").arg(newPath)};
const auto cleanFolderPath = [](const QString &path) -> QString
{
const QString uniformPath = Utils::Fs::toUniformPath(path);
return (uniformPath.endsWith(QLatin1Char {'/'}) ? uniformPath : uniformPath + QLatin1Char {'/'});
};
const QString oldFolderPath = cleanFolderPath(oldPath);
const QString newFolderPath = cleanFolderPath(newPath);
if (QDir().isAbsolutePath(newFolderPath))
throw RuntimeError {tr("Absolute path isn't allowed: '%1'.").arg(newFolderPath)};
QVector<int> renamingFileIndexes;
renamingFileIndexes.reserve(filesCount());
for (int i = 0; i < filesCount(); ++i)
{
const QString path = filePath(i);
if (path.startsWith(oldFolderPath, CASE_SENSITIVITY))
renamingFileIndexes.append(i);
if (path.startsWith(newFolderPath, CASE_SENSITIVITY))
throw RuntimeError {tr("The folder already exists: '%1'.").arg(newFolderPath)};
}
if (renamingFileIndexes.isEmpty())
throw RuntimeError {tr("No such folder: '%1'.").arg(oldFolderPath)};
for (const int index : renamingFileIndexes)
{
const QString newFilePath = newFolderPath + filePath(index).mid(oldFolderPath.size());
renameFile(index, newFilePath);
}
}

View File

@@ -1,7 +1,7 @@
/* /*
* Bittorrent Client using Qt and libtorrent. * Bittorrent Client using Qt and libtorrent.
* Copyright (C) 2011 Christian Kandeler * Copyright (C) 2020 Vladimir Golovnev <glassez@yandex.ru>
* Copyright (C) 2011 Christophe Dumez <chris@qbittorrent.org> *
* This program is free software; you can redistribute it and/or * This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License * modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2 * as published by the Free Software Foundation; either version 2
@@ -28,35 +28,26 @@
#pragma once #pragma once
#include <QDialog> #include <QtGlobal>
#include <QCoreApplication>
namespace Ui class QString;
namespace BitTorrent
{ {
class UpDownRatioDialog; class AbstractFileStorage
{
Q_DECLARE_TR_FUNCTIONS(AbstractFileStorage)
public:
virtual int filesCount() const = 0;
virtual QString filePath(int index) const = 0;
virtual QString fileName(int index) const = 0;
virtual qlonglong fileSize(int index) const = 0;
virtual void renameFile(int index, const QString &name) = 0;
void renameFile(const QString &oldPath, const QString &newPath);
void renameFolder(const QString &oldPath, const QString &newPath);
};
} }
class UpDownRatioDialog final : public QDialog
{
Q_OBJECT
public:
UpDownRatioDialog(bool useDefault, qreal initialValue, qreal maxValue,
int initialTimeValue, int maxTimeValue,
QWidget *parent = nullptr);
~UpDownRatioDialog();
bool useDefault() const;
qreal ratio() const;
int seedingTime() const;
public slots:
void accept() override;
private slots:
void handleRatioTypeChanged();
void enableRatioSpin();
void enableTimeSpin();
private:
Ui::UpDownRatioDialog *m_ui;
};

View File

@@ -28,14 +28,13 @@
#pragma once #pragma once
#include <boost/optional.hpp> #include <optional>
#include <QSet> #include <QSet>
#include <QString> #include <QString>
#include <QVector> #include <QVector>
#include "base/tristatebool.h" #include "torrent.h"
#include "torrenthandle.h"
#include "torrentcontentlayout.h" #include "torrentcontentlayout.h"
namespace BitTorrent namespace BitTorrent
@@ -51,15 +50,15 @@ namespace BitTorrent
bool disableTempPath = false; // e.g. for imported torrents bool disableTempPath = false; // e.g. for imported torrents
bool sequential = false; bool sequential = false;
bool firstLastPiecePriority = false; bool firstLastPiecePriority = false;
TriStateBool addForced; bool addForced = false;
TriStateBool addPaused; std::optional<bool> addPaused;
QVector<DownloadPriority> filePriorities; // used if TorrentInfo is set QVector<DownloadPriority> filePriorities; // used if TorrentInfo is set
bool skipChecking = false; bool skipChecking = false;
boost::optional<BitTorrent::TorrentContentLayout> contentLayout; std::optional<BitTorrent::TorrentContentLayout> contentLayout;
TriStateBool useAutoTMM; std::optional<bool> useAutoTMM;
int uploadLimit = -1; int uploadLimit = -1;
int downloadLimit = -1; int downloadLimit = -1;
int seedingTimeLimit = TorrentHandle::USE_GLOBAL_SEEDING_TIME; int seedingTimeLimit = Torrent::USE_GLOBAL_SEEDING_TIME;
qreal ratioLimit = TorrentHandle::USE_GLOBAL_RATIO; qreal ratioLimit = Torrent::USE_GLOBAL_RATIO;
}; };
} }

View File

@@ -30,5 +30,4 @@
#include <QString> #include <QString>
// TODO: Make it inline in C++17 inline const QString QB_EXT {QStringLiteral(".!qB")};
extern const QString QB_EXT;

View File

@@ -30,9 +30,6 @@
#include <type_traits> #include <type_traits>
template <typename ...>
using void_t = void; // replace this with std::void_t in C++17
template <typename T, typename = void> template <typename T, typename = void>
struct HasUnderlyingType struct HasUnderlyingType
: std::false_type : std::false_type
@@ -40,7 +37,7 @@ struct HasUnderlyingType
}; };
template <typename T> template <typename T>
struct HasUnderlyingType<T, void_t<typename T::underlying_type>> struct HasUnderlyingType<T, std::void_t<typename T::underlying_type>>
: std::true_type : std::true_type
{ {
}; };

View File

@@ -30,14 +30,14 @@
#include <QBitArray> #include <QBitArray>
#include "base/bittorrent/torrenthandle.h" #include "base/bittorrent/torrent.h"
#include "base/net/geoipmanager.h" #include "base/net/geoipmanager.h"
#include "base/unicodestrings.h" #include "base/unicodestrings.h"
#include "peeraddress.h" #include "peeraddress.h"
using namespace BitTorrent; using namespace BitTorrent;
PeerInfo::PeerInfo(const TorrentHandle *torrent, const lt::peer_info &nativeInfo) PeerInfo::PeerInfo(const Torrent *torrent, const lt::peer_info &nativeInfo)
: m_nativeInfo(nativeInfo) : m_nativeInfo(nativeInfo)
{ {
calcRelevance(torrent); calcRelevance(torrent);
@@ -226,7 +226,7 @@ QString PeerInfo::connectionType() const
: QLatin1String {"Web"}; : QLatin1String {"Web"};
} }
void PeerInfo::calcRelevance(const TorrentHandle *torrent) void PeerInfo::calcRelevance(const Torrent *torrent)
{ {
const QBitArray allPieces = torrent->pieces(); const QBitArray allPieces = torrent->pieces();
const QBitArray peerPieces = pieces(); const QBitArray peerPieces = pieces();

View File

@@ -36,7 +36,7 @@ class QBitArray;
namespace BitTorrent namespace BitTorrent
{ {
class TorrentHandle; class Torrent;
struct PeerAddress; struct PeerAddress;
class PeerInfo class PeerInfo
@@ -45,7 +45,7 @@ namespace BitTorrent
public: public:
PeerInfo() = default; PeerInfo() = default;
PeerInfo(const TorrentHandle *torrent, const lt::peer_info &nativeInfo); PeerInfo(const Torrent *torrent, const lt::peer_info &nativeInfo);
bool fromDHT() const; bool fromDHT() const;
bool fromPeX() const; bool fromPeX() const;
@@ -92,7 +92,7 @@ namespace BitTorrent
int downloadingPieceIndex() const; int downloadingPieceIndex() const;
private: private:
void calcRelevance(const TorrentHandle *torrent); void calcRelevance(const Torrent *torrent);
void determineFlags(); void determineFlags();
lt::peer_info m_nativeInfo = {}; lt::peer_info m_nativeInfo = {};

View File

@@ -39,7 +39,7 @@ const QString KEY_ENABLED = QStringLiteral("Network/PortForwardingEnabled");
PortForwarderImpl::PortForwarderImpl(lt::session *provider, QObject *parent) PortForwarderImpl::PortForwarderImpl(lt::session *provider, QObject *parent)
: Net::PortForwarder {parent} : Net::PortForwarder {parent}
, m_active {SettingsStorage::instance()->loadValue(KEY_ENABLED, true).toBool()} , m_active {SettingsStorage::instance()->loadValue(KEY_ENABLED, true)}
, m_provider {provider} , m_provider {provider}
{ {
if (m_active) if (m_active)

View File

@@ -78,13 +78,13 @@
#include "base/profile.h" #include "base/profile.h"
#include "base/torrentfileguard.h" #include "base/torrentfileguard.h"
#include "base/torrentfilter.h" #include "base/torrentfilter.h"
#include "base/tristatebool.h"
#include "base/unicodestrings.h" #include "base/unicodestrings.h"
#include "base/utils/bytearray.h" #include "base/utils/bytearray.h"
#include "base/utils/fs.h" #include "base/utils/fs.h"
#include "base/utils/misc.h" #include "base/utils/misc.h"
#include "base/utils/net.h" #include "base/utils/net.h"
#include "base/utils/random.h" #include "base/utils/random.h"
#include "base/version.h"
#include "bandwidthscheduler.h" #include "bandwidthscheduler.h"
#include "common.h" #include "common.h"
#include "customstorage.h" #include "customstorage.h"
@@ -96,7 +96,7 @@
#include "portforwarderimpl.h" #include "portforwarderimpl.h"
#include "resumedatasavingmanager.h" #include "resumedatasavingmanager.h"
#include "statistics.h" #include "statistics.h"
#include "torrenthandleimpl.h" #include "torrentimpl.h"
#include "tracker.h" #include "tracker.h"
#include "trackerentry.h" #include "trackerentry.h"
@@ -291,9 +291,8 @@ namespace
LowerLimited<T> lowerLimited(T limit, T ret) { return LowerLimited<T>(limit, ret); } LowerLimited<T> lowerLimited(T limit, T ret) { return LowerLimited<T>(limit, ret); }
template <typename T> template <typename T>
std::function<T (const T&)> clampValue(const T lower, const T upper) auto clampValue(const T lower, const T upper)
{ {
// TODO: change return type to `auto` when using C++17
return [lower, upper](const T value) -> T return [lower, upper](const T value) -> T
{ {
if (value < lower) if (value < lower)
@@ -482,7 +481,7 @@ Session::Session(QObject *parent)
m_storedCategories = map_cast(m_categories); m_storedCategories = map_cast(m_categories);
} }
m_tags = List::toSet(m_storedTags.value()); m_tags = List::toSet(m_storedTags.get());
enqueueRefresh(); enqueueRefresh();
updateSeedingLimitTimer(); updateSeedingLimitTimer();
@@ -579,7 +578,7 @@ void Session::setTempPathEnabled(const bool enabled)
if (enabled != isTempPathEnabled()) if (enabled != isTempPathEnabled())
{ {
m_isTempPathEnabled = enabled; m_isTempPathEnabled = enabled;
for (TorrentHandleImpl *const torrent : asConst(m_torrents)) for (TorrentImpl *const torrent : asConst(m_torrents))
torrent->handleTempPathChanged(); torrent->handleTempPathChanged();
} }
} }
@@ -596,7 +595,7 @@ void Session::setAppendExtensionEnabled(const bool enabled)
m_isAppendExtensionEnabled = enabled; m_isAppendExtensionEnabled = enabled;
// append or remove .!qB extension for incomplete files // append or remove .!qB extension for incomplete files
for (TorrentHandleImpl *const torrent : asConst(m_torrents)) for (TorrentImpl *const torrent : asConst(m_torrents))
torrent->handleAppendExtensionToggled(); torrent->handleAppendExtensionToggled();
} }
} }
@@ -749,13 +748,13 @@ bool Session::editCategory(const QString &name, const QString &savePath)
m_storedCategories = map_cast(m_categories); m_storedCategories = map_cast(m_categories);
if (isDisableAutoTMMWhenCategorySavePathChanged()) if (isDisableAutoTMMWhenCategorySavePathChanged())
{ {
for (TorrentHandleImpl *const torrent : asConst(m_torrents)) for (TorrentImpl *const torrent : asConst(m_torrents))
if (torrent->category() == name) if (torrent->category() == name)
torrent->setAutoTMMEnabled(false); torrent->setAutoTMMEnabled(false);
} }
else else
{ {
for (TorrentHandleImpl *const torrent : asConst(m_torrents)) for (TorrentImpl *const torrent : asConst(m_torrents))
if (torrent->category() == name) if (torrent->category() == name)
torrent->handleCategorySavePathChanged(); torrent->handleCategorySavePathChanged();
} }
@@ -765,7 +764,7 @@ bool Session::editCategory(const QString &name, const QString &savePath)
bool Session::removeCategory(const QString &name) bool Session::removeCategory(const QString &name)
{ {
for (TorrentHandleImpl *const torrent : asConst(m_torrents)) for (TorrentImpl *const torrent : asConst(m_torrents))
if (torrent->belongsToCategory(name)) if (torrent->belongsToCategory(name))
torrent->setCategory(""); torrent->setCategory("");
@@ -859,7 +858,7 @@ bool Session::removeTag(const QString &tag)
{ {
if (m_tags.remove(tag)) if (m_tags.remove(tag))
{ {
for (TorrentHandleImpl *const torrent : asConst(m_torrents)) for (TorrentImpl *const torrent : asConst(m_torrents))
torrent->removeTag(tag); torrent->removeTag(tag);
m_storedTags = m_tags.values(); m_storedTags = m_tags.values();
emit tagRemoved(tag); emit tagRemoved(tag);
@@ -1130,7 +1129,7 @@ void Session::initializeNativeSession()
void Session::processBannedIPs(lt::ip_filter &filter) void Session::processBannedIPs(lt::ip_filter &filter)
{ {
// First, import current filter // First, import current filter
for (const QString &ip : asConst(m_bannedIPs.value())) for (const QString &ip : asConst(m_bannedIPs.get()))
{ {
lt::error_code ec; lt::error_code ec;
const lt::address addr = lt::make_address(ip.toLatin1().constData(), ec); const lt::address addr = lt::make_address(ip.toLatin1().constData(), ec);
@@ -1619,16 +1618,16 @@ void Session::processShareLimits()
// We shouldn't iterate over `m_torrents` in the loop below // We shouldn't iterate over `m_torrents` in the loop below
// since `deleteTorrent()` modifies it indirectly // since `deleteTorrent()` modifies it indirectly
const QHash<InfoHash, TorrentHandleImpl *> torrents {m_torrents}; const QHash<InfoHash, TorrentImpl *> torrents {m_torrents};
for (TorrentHandleImpl *const torrent : torrents) for (TorrentImpl *const torrent : torrents)
{ {
if (torrent->isSeed() && !torrent->isForced()) if (torrent->isSeed() && !torrent->isForced())
{ {
if (torrent->ratioLimit() != TorrentHandle::NO_RATIO_LIMIT) if (torrent->ratioLimit() != Torrent::NO_RATIO_LIMIT)
{ {
const qreal ratio = torrent->realRatio(); const qreal ratio = torrent->realRatio();
qreal ratioLimit = torrent->ratioLimit(); qreal ratioLimit = torrent->ratioLimit();
if (ratioLimit == TorrentHandle::USE_GLOBAL_RATIO) if (ratioLimit == Torrent::USE_GLOBAL_RATIO)
// If Global Max Ratio is really set... // If Global Max Ratio is really set...
ratioLimit = globalMaxRatio(); ratioLimit = globalMaxRatio();
@@ -1636,7 +1635,7 @@ void Session::processShareLimits()
{ {
qDebug("Ratio: %f (limit: %f)", ratio, ratioLimit); qDebug("Ratio: %f (limit: %f)", ratio, ratioLimit);
if ((ratio <= TorrentHandle::MAX_RATIO) && (ratio >= ratioLimit)) if ((ratio <= Torrent::MAX_RATIO) && (ratio >= ratioLimit))
{ {
if (m_maxRatioAction == Remove) if (m_maxRatioAction == Remove)
{ {
@@ -1646,7 +1645,7 @@ void Session::processShareLimits()
else if (m_maxRatioAction == DeleteFiles) else if (m_maxRatioAction == DeleteFiles)
{ {
LogMsg(tr("'%1' reached the maximum ratio you set. Removed torrent and its files.").arg(torrent->name())); LogMsg(tr("'%1' reached the maximum ratio you set. Removed torrent and its files.").arg(torrent->name()));
deleteTorrent(torrent->hash(), TorrentAndFiles); deleteTorrent(torrent->hash(), DeleteTorrentAndFiles);
} }
else if ((m_maxRatioAction == Pause) && !torrent->isPaused()) else if ((m_maxRatioAction == Pause) && !torrent->isPaused())
{ {
@@ -1663,11 +1662,11 @@ void Session::processShareLimits()
} }
} }
if (torrent->seedingTimeLimit() != TorrentHandle::NO_SEEDING_TIME_LIMIT) if (torrent->seedingTimeLimit() != Torrent::NO_SEEDING_TIME_LIMIT)
{ {
const qlonglong seedingTimeInMinutes = torrent->seedingTime() / 60; const qlonglong seedingTimeInMinutes = torrent->seedingTime() / 60;
int seedingTimeLimit = torrent->seedingTimeLimit(); int seedingTimeLimit = torrent->seedingTimeLimit();
if (seedingTimeLimit == TorrentHandle::USE_GLOBAL_SEEDING_TIME) if (seedingTimeLimit == Torrent::USE_GLOBAL_SEEDING_TIME)
{ {
// If Global Seeding Time Limit is really set... // If Global Seeding Time Limit is really set...
seedingTimeLimit = globalMaxSeedingMinutes(); seedingTimeLimit = globalMaxSeedingMinutes();
@@ -1675,7 +1674,7 @@ void Session::processShareLimits()
if (seedingTimeLimit >= 0) if (seedingTimeLimit >= 0)
{ {
if ((seedingTimeInMinutes <= TorrentHandle::MAX_SEEDING_TIME) && (seedingTimeInMinutes >= seedingTimeLimit)) if ((seedingTimeInMinutes <= Torrent::MAX_SEEDING_TIME) && (seedingTimeInMinutes >= seedingTimeLimit))
{ {
if (m_maxRatioAction == Remove) if (m_maxRatioAction == Remove)
{ {
@@ -1685,7 +1684,7 @@ void Session::processShareLimits()
else if (m_maxRatioAction == DeleteFiles) else if (m_maxRatioAction == DeleteFiles)
{ {
LogMsg(tr("'%1' reached the maximum seeding time you set. Removed torrent and its files.").arg(torrent->name())); LogMsg(tr("'%1' reached the maximum seeding time you set. Removed torrent and its files.").arg(torrent->name()));
deleteTorrent(torrent->hash(), TorrentAndFiles); deleteTorrent(torrent->hash(), DeleteTorrentAndFiles);
} }
else if ((m_maxRatioAction == Pause) && !torrent->isPaused()) else if ((m_maxRatioAction == Pause) && !torrent->isPaused())
{ {
@@ -1724,7 +1723,7 @@ void Session::handleDownloadFinished(const Net::DownloadResult &result)
void Session::fileSearchFinished(const InfoHash &id, const QString &savePath, const QStringList &fileNames) void Session::fileSearchFinished(const InfoHash &id, const QString &savePath, const QStringList &fileNames)
{ {
TorrentHandleImpl *torrent = m_torrents.value(id); TorrentImpl *torrent = m_torrents.value(id);
if (torrent) if (torrent)
{ {
torrent->fileSearchFinished(savePath, fileNames); torrent->fileSearchFinished(savePath, fileNames);
@@ -1748,14 +1747,14 @@ void Session::fileSearchFinished(const InfoHash &id, const QString &savePath, co
} }
// Return the torrent handle, given its hash // Return the torrent handle, given its hash
TorrentHandle *Session::findTorrent(const InfoHash &hash) const Torrent *Session::findTorrent(const InfoHash &hash) const
{ {
return m_torrents.value(hash); return m_torrents.value(hash);
} }
bool Session::hasActiveTorrents() const bool Session::hasActiveTorrents() const
{ {
return std::any_of(m_torrents.begin(), m_torrents.end(), [](TorrentHandleImpl *torrent) return std::any_of(m_torrents.begin(), m_torrents.end(), [](TorrentImpl *torrent)
{ {
return TorrentFilter::ActiveTorrent.match(torrent); return TorrentFilter::ActiveTorrent.match(torrent);
}); });
@@ -1763,7 +1762,7 @@ bool Session::hasActiveTorrents() const
bool Session::hasUnfinishedTorrents() const bool Session::hasUnfinishedTorrents() const
{ {
return std::any_of(m_torrents.begin(), m_torrents.end(), [](const TorrentHandleImpl *torrent) return std::any_of(m_torrents.begin(), m_torrents.end(), [](const TorrentImpl *torrent)
{ {
return (!torrent->isSeed() && !torrent->isPaused()); return (!torrent->isSeed() && !torrent->isPaused());
}); });
@@ -1771,7 +1770,7 @@ bool Session::hasUnfinishedTorrents() const
bool Session::hasRunningSeed() const bool Session::hasRunningSeed() const
{ {
return std::any_of(m_torrents.begin(), m_torrents.end(), [](const TorrentHandleImpl *torrent) return std::any_of(m_torrents.begin(), m_torrents.end(), [](const TorrentImpl *torrent)
{ {
return (torrent->isSeed() && !torrent->isPaused()); return (torrent->isSeed() && !torrent->isPaused());
}); });
@@ -1800,14 +1799,14 @@ void Session::banIP(const QString &ip)
// and from the disk, if the corresponding deleteOption is chosen // and from the disk, if the corresponding deleteOption is chosen
bool Session::deleteTorrent(const InfoHash &hash, const DeleteOption deleteOption) bool Session::deleteTorrent(const InfoHash &hash, const DeleteOption deleteOption)
{ {
TorrentHandleImpl *const torrent = m_torrents.take(hash); TorrentImpl *const torrent = m_torrents.take(hash);
if (!torrent) return false; if (!torrent) return false;
qDebug("Deleting torrent with hash: %s", qUtf8Printable(torrent->hash())); qDebug("Deleting torrent with hash: %s", qUtf8Printable(torrent->hash()));
emit torrentAboutToBeRemoved(torrent); emit torrentAboutToBeRemoved(torrent);
// Remove it from session // Remove it from session
if (deleteOption == Torrent) if (deleteOption == DeleteTorrent)
{ {
m_removingTorrents[torrent->hash()] = {torrent->name(), "", deleteOption}; m_removingTorrents[torrent->hash()] = {torrent->name(), "", deleteOption};
@@ -1888,7 +1887,7 @@ bool Session::cancelDownloadMetadata(const InfoHash &hash)
void Session::increaseTorrentsQueuePos(const QVector<InfoHash> &hashes) void Session::increaseTorrentsQueuePos(const QVector<InfoHash> &hashes)
{ {
using ElementType = std::pair<int, TorrentHandleImpl *>; using ElementType = std::pair<int, TorrentImpl *>;
std::priority_queue<ElementType std::priority_queue<ElementType
, std::vector<ElementType> , std::vector<ElementType>
, std::greater<ElementType>> torrentQueue; , std::greater<ElementType>> torrentQueue;
@@ -1896,7 +1895,7 @@ void Session::increaseTorrentsQueuePos(const QVector<InfoHash> &hashes)
// Sort torrents by queue position // Sort torrents by queue position
for (const InfoHash &infoHash : hashes) for (const InfoHash &infoHash : hashes)
{ {
TorrentHandleImpl *const torrent = m_torrents.value(infoHash); TorrentImpl *const torrent = m_torrents.value(infoHash);
if (torrent && !torrent->isSeed()) if (torrent && !torrent->isSeed())
torrentQueue.emplace(torrent->queuePosition(), torrent); torrentQueue.emplace(torrent->queuePosition(), torrent);
} }
@@ -1904,7 +1903,7 @@ void Session::increaseTorrentsQueuePos(const QVector<InfoHash> &hashes)
// Increase torrents queue position (starting with the one in the highest queue position) // Increase torrents queue position (starting with the one in the highest queue position)
while (!torrentQueue.empty()) while (!torrentQueue.empty())
{ {
const TorrentHandleImpl *torrent = torrentQueue.top().second; const TorrentImpl *torrent = torrentQueue.top().second;
torrentQueuePositionUp(torrent->nativeHandle()); torrentQueuePositionUp(torrent->nativeHandle());
torrentQueue.pop(); torrentQueue.pop();
} }
@@ -1914,13 +1913,13 @@ void Session::increaseTorrentsQueuePos(const QVector<InfoHash> &hashes)
void Session::decreaseTorrentsQueuePos(const QVector<InfoHash> &hashes) void Session::decreaseTorrentsQueuePos(const QVector<InfoHash> &hashes)
{ {
using ElementType = std::pair<int, TorrentHandleImpl *>; using ElementType = std::pair<int, TorrentImpl *>;
std::priority_queue<ElementType> torrentQueue; std::priority_queue<ElementType> torrentQueue;
// Sort torrents by queue position // Sort torrents by queue position
for (const InfoHash &infoHash : hashes) for (const InfoHash &infoHash : hashes)
{ {
TorrentHandleImpl *const torrent = m_torrents.value(infoHash); TorrentImpl *const torrent = m_torrents.value(infoHash);
if (torrent && !torrent->isSeed()) if (torrent && !torrent->isSeed())
torrentQueue.emplace(torrent->queuePosition(), torrent); torrentQueue.emplace(torrent->queuePosition(), torrent);
} }
@@ -1928,7 +1927,7 @@ void Session::decreaseTorrentsQueuePos(const QVector<InfoHash> &hashes)
// Decrease torrents queue position (starting with the one in the lowest queue position) // Decrease torrents queue position (starting with the one in the lowest queue position)
while (!torrentQueue.empty()) while (!torrentQueue.empty())
{ {
const TorrentHandleImpl *torrent = torrentQueue.top().second; const TorrentImpl *torrent = torrentQueue.top().second;
torrentQueuePositionDown(torrent->nativeHandle()); torrentQueuePositionDown(torrent->nativeHandle());
torrentQueue.pop(); torrentQueue.pop();
} }
@@ -1941,13 +1940,13 @@ void Session::decreaseTorrentsQueuePos(const QVector<InfoHash> &hashes)
void Session::topTorrentsQueuePos(const QVector<InfoHash> &hashes) void Session::topTorrentsQueuePos(const QVector<InfoHash> &hashes)
{ {
using ElementType = std::pair<int, TorrentHandleImpl *>; using ElementType = std::pair<int, TorrentImpl *>;
std::priority_queue<ElementType> torrentQueue; std::priority_queue<ElementType> torrentQueue;
// Sort torrents by queue position // Sort torrents by queue position
for (const InfoHash &infoHash : hashes) for (const InfoHash &infoHash : hashes)
{ {
TorrentHandleImpl *const torrent = m_torrents.value(infoHash); TorrentImpl *const torrent = m_torrents.value(infoHash);
if (torrent && !torrent->isSeed()) if (torrent && !torrent->isSeed())
torrentQueue.emplace(torrent->queuePosition(), torrent); torrentQueue.emplace(torrent->queuePosition(), torrent);
} }
@@ -1955,7 +1954,7 @@ void Session::topTorrentsQueuePos(const QVector<InfoHash> &hashes)
// Top torrents queue position (starting with the one in the lowest queue position) // Top torrents queue position (starting with the one in the lowest queue position)
while (!torrentQueue.empty()) while (!torrentQueue.empty())
{ {
const TorrentHandleImpl *torrent = torrentQueue.top().second; const TorrentImpl *torrent = torrentQueue.top().second;
torrentQueuePositionTop(torrent->nativeHandle()); torrentQueuePositionTop(torrent->nativeHandle());
torrentQueue.pop(); torrentQueue.pop();
} }
@@ -1965,7 +1964,7 @@ void Session::topTorrentsQueuePos(const QVector<InfoHash> &hashes)
void Session::bottomTorrentsQueuePos(const QVector<InfoHash> &hashes) void Session::bottomTorrentsQueuePos(const QVector<InfoHash> &hashes)
{ {
using ElementType = std::pair<int, TorrentHandleImpl *>; using ElementType = std::pair<int, TorrentImpl *>;
std::priority_queue<ElementType std::priority_queue<ElementType
, std::vector<ElementType> , std::vector<ElementType>
, std::greater<ElementType>> torrentQueue; , std::greater<ElementType>> torrentQueue;
@@ -1973,7 +1972,7 @@ void Session::bottomTorrentsQueuePos(const QVector<InfoHash> &hashes)
// Sort torrents by queue position // Sort torrents by queue position
for (const InfoHash &infoHash : hashes) for (const InfoHash &infoHash : hashes)
{ {
TorrentHandleImpl *const torrent = m_torrents.value(infoHash); TorrentImpl *const torrent = m_torrents.value(infoHash);
if (torrent && !torrent->isSeed()) if (torrent && !torrent->isSeed())
torrentQueue.emplace(torrent->queuePosition(), torrent); torrentQueue.emplace(torrent->queuePosition(), torrent);
} }
@@ -1981,7 +1980,7 @@ void Session::bottomTorrentsQueuePos(const QVector<InfoHash> &hashes)
// Bottom torrents queue position (starting with the one in the highest queue position) // Bottom torrents queue position (starting with the one in the highest queue position)
while (!torrentQueue.empty()) while (!torrentQueue.empty())
{ {
const TorrentHandleImpl *torrent = torrentQueue.top().second; const TorrentImpl *torrent = torrentQueue.top().second;
torrentQueuePositionBottom(torrent->nativeHandle()); torrentQueuePositionBottom(torrent->nativeHandle());
torrentQueue.pop(); torrentQueue.pop();
} }
@@ -1992,17 +1991,17 @@ void Session::bottomTorrentsQueuePos(const QVector<InfoHash> &hashes)
saveTorrentsQueue(); saveTorrentsQueue();
} }
void Session::handleTorrentSaveResumeDataRequested(const TorrentHandleImpl *torrent) void Session::handleTorrentSaveResumeDataRequested(const TorrentImpl *torrent)
{ {
qDebug("Saving resume data is requested for torrent '%s'...", qUtf8Printable(torrent->name())); qDebug("Saving resume data is requested for torrent '%s'...", qUtf8Printable(torrent->name()));
++m_numResumeData; ++m_numResumeData;
} }
QVector<TorrentHandle *> Session::torrents() const QVector<Torrent *> Session::torrents() const
{ {
QVector<TorrentHandle *> result; QVector<Torrent *> result;
result.reserve(m_torrents.size()); result.reserve(m_torrents.size());
for (TorrentHandleImpl *torrent : asConst(m_torrents)) for (TorrentImpl *torrent : asConst(m_torrents))
result << torrent; result << torrent;
return result; return result;
@@ -2040,14 +2039,14 @@ bool Session::addTorrent(const MagnetUri &magnetUri, const AddTorrentParams &par
{ {
if (!magnetUri.isValid()) return false; if (!magnetUri.isValid()) return false;
return addTorrent_impl(params, magnetUri); return addTorrent_impl(magnetUri, params);
} }
bool Session::addTorrent(const TorrentInfo &torrentInfo, const AddTorrentParams &params) bool Session::addTorrent(const TorrentInfo &torrentInfo, const AddTorrentParams &params)
{ {
if (!torrentInfo.isValid()) return false; if (!torrentInfo.isValid()) return false;
return addTorrent_impl(params, MagnetUri(), torrentInfo); return addTorrent_impl(torrentInfo, params);
} }
LoadTorrentParams Session::initLoadTorrentParams(const AddTorrentParams &addTorrentParams) LoadTorrentParams Session::initLoadTorrentParams(const AddTorrentParams &addTorrentParams)
@@ -2058,19 +2057,13 @@ LoadTorrentParams Session::initLoadTorrentParams(const AddTorrentParams &addTorr
loadTorrentParams.tags = addTorrentParams.tags; loadTorrentParams.tags = addTorrentParams.tags;
loadTorrentParams.firstLastPiecePriority = addTorrentParams.firstLastPiecePriority; loadTorrentParams.firstLastPiecePriority = addTorrentParams.firstLastPiecePriority;
loadTorrentParams.hasSeedStatus = addTorrentParams.skipChecking; // do not react on 'torrent_finished_alert' when skipping loadTorrentParams.hasSeedStatus = addTorrentParams.skipChecking; // do not react on 'torrent_finished_alert' when skipping
loadTorrentParams.contentLayout = (addTorrentParams.contentLayout loadTorrentParams.contentLayout = addTorrentParams.contentLayout.value_or(torrentContentLayout());
? *addTorrentParams.contentLayout loadTorrentParams.forced = addTorrentParams.addForced;
: torrentContentLayout()); loadTorrentParams.paused = addTorrentParams.addPaused.value_or(isAddTorrentPaused());
loadTorrentParams.forced = (addTorrentParams.addForced == TriStateBool::True);
loadTorrentParams.paused = ((addTorrentParams.addPaused == TriStateBool::Undefined)
? isAddTorrentPaused()
: (addTorrentParams.addPaused == TriStateBool::True));
loadTorrentParams.ratioLimit = addTorrentParams.ratioLimit; loadTorrentParams.ratioLimit = addTorrentParams.ratioLimit;
loadTorrentParams.seedingTimeLimit = addTorrentParams.seedingTimeLimit; loadTorrentParams.seedingTimeLimit = addTorrentParams.seedingTimeLimit;
const bool useAutoTMM = ((addTorrentParams.useAutoTMM == TriStateBool::Undefined) const bool useAutoTMM = addTorrentParams.useAutoTMM.value_or(!isAutoTMMDisabledByDefault());
? !isAutoTMMDisabledByDefault()
: (addTorrentParams.useAutoTMM == TriStateBool::True));
if (useAutoTMM) if (useAutoTMM)
loadTorrentParams.savePath = ""; loadTorrentParams.savePath = "";
else if (addTorrentParams.savePath.trimmed().isEmpty()) else if (addTorrentParams.savePath.trimmed().isEmpty())
@@ -2088,9 +2081,11 @@ LoadTorrentParams Session::initLoadTorrentParams(const AddTorrentParams &addTorr
} }
// Add a torrent to the BitTorrent session // Add a torrent to the BitTorrent session
bool Session::addTorrent_impl(const AddTorrentParams &addTorrentParams, const MagnetUri &magnetUri, TorrentInfo metadata) bool Session::addTorrent_impl(const std::variant<MagnetUri, TorrentInfo> &source, const AddTorrentParams &addTorrentParams)
{ {
const bool hasMetadata = metadata.isValid(); const bool hasMetadata = std::holds_alternative<TorrentInfo>(source);
TorrentInfo metadata = (hasMetadata ? std::get<TorrentInfo>(source) : TorrentInfo {});
const MagnetUri &magnetUri = (hasMetadata ? MagnetUri {} : std::get<MagnetUri>(source));
const InfoHash hash = (hasMetadata ? metadata.hash() : magnetUri.hash()); const InfoHash hash = (hasMetadata ? metadata.hash() : magnetUri.hash());
// It looks illogical that we don't just use an existing handle, // It looks illogical that we don't just use an existing handle,
@@ -2104,7 +2099,7 @@ bool Session::addTorrent_impl(const AddTorrentParams &addTorrentParams, const Ma
if (m_loadingTorrents.contains(hash)) if (m_loadingTorrents.contains(hash))
return false; return false;
TorrentHandleImpl *const torrent = m_torrents.value(hash); TorrentImpl *const torrent = m_torrents.value(hash);
if (torrent) if (torrent)
{ // a duplicate torrent is added { // a duplicate torrent is added
if (torrent->isPrivate() || (hasMetadata && metadata.isPrivate())) if (torrent->isPrivate() || (hasMetadata && metadata.isPrivate()))
@@ -2298,7 +2293,7 @@ bool Session::downloadMetadata(const MagnetUri &magnetUri)
return true; return true;
} }
void Session::exportTorrentFile(const TorrentHandle *torrent, TorrentExportFolder folder) void Session::exportTorrentFile(const Torrent *torrent, TorrentExportFolder folder)
{ {
Q_ASSERT(((folder == TorrentExportFolder::Regular) && !torrentExportDirectory().isEmpty()) || Q_ASSERT(((folder == TorrentExportFolder::Regular) && !torrentExportDirectory().isEmpty()) ||
((folder == TorrentExportFolder::Finished) && !finishedTorrentExportDirectory().isEmpty())); ((folder == TorrentExportFolder::Finished) && !finishedTorrentExportDirectory().isEmpty()));
@@ -2326,7 +2321,7 @@ void Session::exportTorrentFile(const TorrentHandle *torrent, TorrentExportFolde
void Session::generateResumeData() void Session::generateResumeData()
{ {
for (TorrentHandleImpl *const torrent : asConst(m_torrents)) for (TorrentImpl *const torrent : asConst(m_torrents))
{ {
if (!torrent->isValid()) continue; if (!torrent->isValid()) continue;
@@ -2372,7 +2367,7 @@ void Session::saveTorrentsQueue()
{ {
// store hash in textual representation // store hash in textual representation
QMap<int, QString> queue; // Use QMap since it should be ordered by key QMap<int, QString> queue; // Use QMap since it should be ordered by key
for (const TorrentHandleImpl *torrent : asConst(m_torrents)) for (const TorrentImpl *torrent : asConst(m_torrents))
{ {
// We require actual (non-cached) queue position here! // We require actual (non-cached) queue position here!
const int queuePos = static_cast<LTUnderlyingType<lt::queue_position_t>>(torrent->nativeHandle().queue_position()); const int queuePos = static_cast<LTUnderlyingType<lt::queue_position_t>>(torrent->nativeHandle().queue_position());
@@ -2414,10 +2409,10 @@ void Session::setDefaultSavePath(QString path)
m_defaultSavePath = path; m_defaultSavePath = path;
if (isDisableAutoTMMWhenDefaultSavePathChanged()) if (isDisableAutoTMMWhenDefaultSavePathChanged())
for (TorrentHandleImpl *const torrent : asConst(m_torrents)) for (TorrentImpl *const torrent : asConst(m_torrents))
torrent->setAutoTMMEnabled(false); torrent->setAutoTMMEnabled(false);
else else
for (TorrentHandleImpl *const torrent : asConst(m_torrents)) for (TorrentImpl *const torrent : asConst(m_torrents))
torrent->handleCategorySavePathChanged(); torrent->handleCategorySavePathChanged();
} }
@@ -2428,7 +2423,7 @@ void Session::setTempPath(QString path)
m_tempPath = path; m_tempPath = path;
for (TorrentHandleImpl *const torrent : asConst(m_torrents)) for (TorrentImpl *const torrent : asConst(m_torrents))
torrent->handleTempPathChanged(); torrent->handleTempPathChanged();
} }
@@ -3142,7 +3137,7 @@ void Session::setPeerTurnoverInterval(const int val)
int Session::asyncIOThreads() const int Session::asyncIOThreads() const
{ {
return qBound(1, m_asyncIOThreads.value(), 1024); return qBound(1, m_asyncIOThreads.get(), 1024);
} }
void Session::setAsyncIOThreads(const int num) void Session::setAsyncIOThreads(const int num)
@@ -3156,7 +3151,7 @@ void Session::setAsyncIOThreads(const int num)
int Session::hashingThreads() const int Session::hashingThreads() const
{ {
return qBound(1, m_hashingThreads.value(), 1024); return qBound(1, m_hashingThreads.get(), 1024);
} }
void Session::setHashingThreads(const int num) void Session::setHashingThreads(const int num)
@@ -3184,7 +3179,7 @@ void Session::setFilePoolSize(const int size)
int Session::checkingMemUsage() const int Session::checkingMemUsage() const
{ {
return qMax(1, m_checkingMemUsage.value()); return qMax(1, m_checkingMemUsage.get());
} }
void Session::setCheckingMemUsage(int size) void Session::setCheckingMemUsage(int size)
@@ -3201,11 +3196,11 @@ void Session::setCheckingMemUsage(int size)
int Session::diskCacheSize() const int Session::diskCacheSize() const
{ {
#ifdef QBT_APP_64BIT #ifdef QBT_APP_64BIT
return qMin(m_diskCacheSize.value(), 33554431); // 32768GiB return qMin(m_diskCacheSize.get(), 33554431); // 32768GiB
#else #else
// When build as 32bit binary, set the maximum at less than 2GB to prevent crashes // When build as 32bit binary, set the maximum at less than 2GB to prevent crashes
// allocate 1536MiB and leave 512MiB to the rest of program data in RAM // allocate 1536MiB and leave 512MiB to the rest of program data in RAM
return qMin(m_diskCacheSize.value(), 1536); return qMin(m_diskCacheSize.get(), 1536);
#endif #endif
} }
@@ -3737,7 +3732,7 @@ bool Session::isListening() const
MaxRatioAction Session::maxRatioAction() const MaxRatioAction Session::maxRatioAction() const
{ {
return static_cast<MaxRatioAction>(m_maxRatioAction.value()); return static_cast<MaxRatioAction>(m_maxRatioAction.get());
} }
void Session::setMaxRatioAction(const MaxRatioAction act) void Session::setMaxRatioAction(const MaxRatioAction act)
@@ -3756,8 +3751,8 @@ bool Session::isKnownTorrent(const InfoHash &hash) const
void Session::updateSeedingLimitTimer() void Session::updateSeedingLimitTimer()
{ {
if ((globalMaxRatio() == TorrentHandle::NO_RATIO_LIMIT) && !hasPerTorrentRatioLimit() if ((globalMaxRatio() == Torrent::NO_RATIO_LIMIT) && !hasPerTorrentRatioLimit()
&& (globalMaxSeedingMinutes() == TorrentHandle::NO_SEEDING_TIME_LIMIT) && !hasPerTorrentSeedingTimeLimit()) && (globalMaxSeedingMinutes() == Torrent::NO_SEEDING_TIME_LIMIT) && !hasPerTorrentSeedingTimeLimit())
{ {
if (m_seedingLimitTimer->isActive()) if (m_seedingLimitTimer->isActive())
m_seedingLimitTimer->stop(); m_seedingLimitTimer->stop();
@@ -3768,48 +3763,48 @@ void Session::updateSeedingLimitTimer()
} }
} }
void Session::handleTorrentShareLimitChanged(TorrentHandleImpl *const torrent) void Session::handleTorrentShareLimitChanged(TorrentImpl *const torrent)
{ {
torrent->saveResumeData(); torrent->saveResumeData();
updateSeedingLimitTimer(); updateSeedingLimitTimer();
} }
void Session::handleTorrentNameChanged(TorrentHandleImpl *const torrent) void Session::handleTorrentNameChanged(TorrentImpl *const torrent)
{ {
torrent->saveResumeData(); torrent->saveResumeData();
} }
void Session::handleTorrentSavePathChanged(TorrentHandleImpl *const torrent) void Session::handleTorrentSavePathChanged(TorrentImpl *const torrent)
{ {
torrent->saveResumeData(); torrent->saveResumeData();
emit torrentSavePathChanged(torrent); emit torrentSavePathChanged(torrent);
} }
void Session::handleTorrentCategoryChanged(TorrentHandleImpl *const torrent, const QString &oldCategory) void Session::handleTorrentCategoryChanged(TorrentImpl *const torrent, const QString &oldCategory)
{ {
torrent->saveResumeData(); torrent->saveResumeData();
emit torrentCategoryChanged(torrent, oldCategory); emit torrentCategoryChanged(torrent, oldCategory);
} }
void Session::handleTorrentTagAdded(TorrentHandleImpl *const torrent, const QString &tag) void Session::handleTorrentTagAdded(TorrentImpl *const torrent, const QString &tag)
{ {
torrent->saveResumeData(); torrent->saveResumeData();
emit torrentTagAdded(torrent, tag); emit torrentTagAdded(torrent, tag);
} }
void Session::handleTorrentTagRemoved(TorrentHandleImpl *const torrent, const QString &tag) void Session::handleTorrentTagRemoved(TorrentImpl *const torrent, const QString &tag)
{ {
torrent->saveResumeData(); torrent->saveResumeData();
emit torrentTagRemoved(torrent, tag); emit torrentTagRemoved(torrent, tag);
} }
void Session::handleTorrentSavingModeChanged(TorrentHandleImpl *const torrent) void Session::handleTorrentSavingModeChanged(TorrentImpl *const torrent)
{ {
torrent->saveResumeData(); torrent->saveResumeData();
emit torrentSavingModeChanged(torrent); emit torrentSavingModeChanged(torrent);
} }
void Session::handleTorrentTrackersAdded(TorrentHandleImpl *const torrent, const QVector<TrackerEntry> &newTrackers) void Session::handleTorrentTrackersAdded(TorrentImpl *const torrent, const QVector<TrackerEntry> &newTrackers)
{ {
torrent->saveResumeData(); torrent->saveResumeData();
@@ -3821,7 +3816,7 @@ void Session::handleTorrentTrackersAdded(TorrentHandleImpl *const torrent, const
emit trackersChanged(torrent); emit trackersChanged(torrent);
} }
void Session::handleTorrentTrackersRemoved(TorrentHandleImpl *const torrent, const QVector<TrackerEntry> &deletedTrackers) void Session::handleTorrentTrackersRemoved(TorrentImpl *const torrent, const QVector<TrackerEntry> &deletedTrackers)
{ {
torrent->saveResumeData(); torrent->saveResumeData();
@@ -3833,27 +3828,27 @@ void Session::handleTorrentTrackersRemoved(TorrentHandleImpl *const torrent, con
emit trackersChanged(torrent); emit trackersChanged(torrent);
} }
void Session::handleTorrentTrackersChanged(TorrentHandleImpl *const torrent) void Session::handleTorrentTrackersChanged(TorrentImpl *const torrent)
{ {
torrent->saveResumeData(); torrent->saveResumeData();
emit trackersChanged(torrent); emit trackersChanged(torrent);
} }
void Session::handleTorrentUrlSeedsAdded(TorrentHandleImpl *const torrent, const QVector<QUrl> &newUrlSeeds) void Session::handleTorrentUrlSeedsAdded(TorrentImpl *const torrent, const QVector<QUrl> &newUrlSeeds)
{ {
torrent->saveResumeData(); torrent->saveResumeData();
for (const QUrl &newUrlSeed : newUrlSeeds) for (const QUrl &newUrlSeed : newUrlSeeds)
LogMsg(tr("URL seed '%1' was added to torrent '%2'").arg(newUrlSeed.toString(), torrent->name())); LogMsg(tr("URL seed '%1' was added to torrent '%2'").arg(newUrlSeed.toString(), torrent->name()));
} }
void Session::handleTorrentUrlSeedsRemoved(TorrentHandleImpl *const torrent, const QVector<QUrl> &urlSeeds) void Session::handleTorrentUrlSeedsRemoved(TorrentImpl *const torrent, const QVector<QUrl> &urlSeeds)
{ {
torrent->saveResumeData(); torrent->saveResumeData();
for (const QUrl &urlSeed : urlSeeds) for (const QUrl &urlSeed : urlSeeds)
LogMsg(tr("URL seed '%1' was removed from torrent '%2'").arg(urlSeed.toString(), torrent->name())); LogMsg(tr("URL seed '%1' was removed from torrent '%2'").arg(urlSeed.toString(), torrent->name()));
} }
void Session::handleTorrentMetadataReceived(TorrentHandleImpl *const torrent) void Session::handleTorrentMetadataReceived(TorrentImpl *const torrent)
{ {
// Save metadata // Save metadata
const QDir resumeDataDir {m_resumeFolderPath}; const QDir resumeDataDir {m_resumeFolderPath};
@@ -3874,24 +3869,24 @@ void Session::handleTorrentMetadataReceived(TorrentHandleImpl *const torrent)
emit torrentMetadataReceived(torrent); emit torrentMetadataReceived(torrent);
} }
void Session::handleTorrentPaused(TorrentHandleImpl *const torrent) void Session::handleTorrentPaused(TorrentImpl *const torrent)
{ {
torrent->saveResumeData(); torrent->saveResumeData();
emit torrentPaused(torrent); emit torrentPaused(torrent);
} }
void Session::handleTorrentResumed(TorrentHandleImpl *const torrent) void Session::handleTorrentResumed(TorrentImpl *const torrent)
{ {
torrent->saveResumeData(); torrent->saveResumeData();
emit torrentResumed(torrent); emit torrentResumed(torrent);
} }
void Session::handleTorrentChecked(TorrentHandleImpl *const torrent) void Session::handleTorrentChecked(TorrentImpl *const torrent)
{ {
emit torrentFinishedChecking(torrent); emit torrentFinishedChecking(torrent);
} }
void Session::handleTorrentFinished(TorrentHandleImpl *const torrent) void Session::handleTorrentFinished(TorrentImpl *const torrent)
{ {
if (!torrent->hasError() && !torrent->hasMissingFiles()) if (!torrent->hasError() && !torrent->hasMissingFiles())
torrent->saveResumeData(); torrent->saveResumeData();
@@ -3930,7 +3925,7 @@ void Session::handleTorrentFinished(TorrentHandleImpl *const torrent)
emit allTorrentsFinished(); emit allTorrentsFinished();
} }
void Session::handleTorrentResumeDataReady(TorrentHandleImpl *const torrent, const std::shared_ptr<lt::entry> &data) void Session::handleTorrentResumeDataReady(TorrentImpl *const torrent, const std::shared_ptr<lt::entry> &data)
{ {
--m_numResumeData; --m_numResumeData;
@@ -3947,17 +3942,17 @@ void Session::handleTorrentResumeDataReady(TorrentHandleImpl *const torrent, con
#endif #endif
} }
void Session::handleTorrentTrackerReply(TorrentHandleImpl *const torrent, const QString &trackerUrl) void Session::handleTorrentTrackerReply(TorrentImpl *const torrent, const QString &trackerUrl)
{ {
emit trackerSuccess(torrent, trackerUrl); emit trackerSuccess(torrent, trackerUrl);
} }
void Session::handleTorrentTrackerError(TorrentHandleImpl *const torrent, const QString &trackerUrl) void Session::handleTorrentTrackerError(TorrentImpl *const torrent, const QString &trackerUrl)
{ {
emit trackerError(torrent, trackerUrl); emit trackerError(torrent, trackerUrl);
} }
bool Session::addMoveTorrentStorageJob(TorrentHandleImpl *torrent, const QString &newPath, const MoveStorageMode mode) bool Session::addMoveTorrentStorageJob(TorrentImpl *torrent, const QString &newPath, const MoveStorageMode mode)
{ {
Q_ASSERT(torrent); Q_ASSERT(torrent);
@@ -4014,7 +4009,7 @@ bool Session::addMoveTorrentStorageJob(TorrentHandleImpl *torrent, const QString
void Session::moveTorrentStorage(const MoveStorageJob &job) const void Session::moveTorrentStorage(const MoveStorageJob &job) const
{ {
const InfoHash infoHash = job.torrentHandle.info_hash(); const InfoHash infoHash = job.torrentHandle.info_hash();
const TorrentHandleImpl *torrent = m_torrents.value(infoHash); const TorrentImpl *torrent = m_torrents.value(infoHash);
const QString torrentName = (torrent ? torrent->name() : QString {infoHash}); const QString torrentName = (torrent ? torrent->name() : QString {infoHash});
LogMsg(tr("Moving \"%1\" to \"%2\"...").arg(torrentName, job.path)); LogMsg(tr("Moving \"%1\" to \"%2\"...").arg(torrentName, job.path));
@@ -4037,7 +4032,7 @@ void Session::handleMoveTorrentStorageJobFinished()
const bool torrentHasOutstandingJob = (iter != m_moveStorageQueue.cend()); const bool torrentHasOutstandingJob = (iter != m_moveStorageQueue.cend());
TorrentHandleImpl *torrent = m_torrents.value(finishedJob.torrentHandle.info_hash()); TorrentImpl *torrent = m_torrents.value(finishedJob.torrentHandle.info_hash());
if (torrent) if (torrent)
{ {
torrent->handleMoveStorageJobFinished(torrentHasOutstandingJob); torrent->handleMoveStorageJobFinished(torrentHasOutstandingJob);
@@ -4047,19 +4042,19 @@ void Session::handleMoveTorrentStorageJobFinished()
// Last job is completed for torrent that being removing, so actually remove it // Last job is completed for torrent that being removing, so actually remove it
const lt::torrent_handle nativeHandle {finishedJob.torrentHandle}; const lt::torrent_handle nativeHandle {finishedJob.torrentHandle};
const RemovingTorrentData &removingTorrentData = m_removingTorrents[nativeHandle.info_hash()]; const RemovingTorrentData &removingTorrentData = m_removingTorrents[nativeHandle.info_hash()];
if (removingTorrentData.deleteOption == Torrent) if (removingTorrentData.deleteOption == DeleteTorrent)
m_nativeSession->remove_torrent(nativeHandle, lt::session::delete_partfile); m_nativeSession->remove_torrent(nativeHandle, lt::session::delete_partfile);
} }
} }
void Session::handleTorrentTrackerWarning(TorrentHandleImpl *const torrent, const QString &trackerUrl) void Session::handleTorrentTrackerWarning(TorrentImpl *const torrent, const QString &trackerUrl)
{ {
emit trackerWarning(torrent, trackerUrl); emit trackerWarning(torrent, trackerUrl);
} }
bool Session::hasPerTorrentRatioLimit() const bool Session::hasPerTorrentRatioLimit() const
{ {
return std::any_of(m_torrents.cbegin(), m_torrents.cend(), [](const TorrentHandleImpl *torrent) return std::any_of(m_torrents.cbegin(), m_torrents.cend(), [](const TorrentImpl *torrent)
{ {
return (torrent->ratioLimit() >= 0); return (torrent->ratioLimit() >= 0);
}); });
@@ -4067,7 +4062,7 @@ bool Session::hasPerTorrentRatioLimit() const
bool Session::hasPerTorrentSeedingTimeLimit() const bool Session::hasPerTorrentSeedingTimeLimit() const
{ {
return std::any_of(m_torrents.cbegin(), m_torrents.cend(), [](const TorrentHandleImpl *torrent) return std::any_of(m_torrents.cbegin(), m_torrents.cend(), [](const TorrentImpl *torrent)
{ {
return (torrent->seedingTimeLimit() >= 0); return (torrent->seedingTimeLimit() >= 0);
}); });
@@ -4148,7 +4143,7 @@ void Session::disableIPFilter()
void Session::recursiveTorrentDownload(const InfoHash &hash) void Session::recursiveTorrentDownload(const InfoHash &hash)
{ {
TorrentHandleImpl *const torrent = m_torrents.value(hash); TorrentImpl *const torrent = m_torrents.value(hash);
if (!torrent) return; if (!torrent) return;
for (int i = 0; i < torrent->filesCount(); ++i) for (int i = 0; i < torrent->filesCount(); ++i)
@@ -4194,7 +4189,7 @@ bool Session::loadTorrentResumeData(const QByteArray &data, const TorrentInfo &m
Utils::Fs::toUniformPath(fromLTString(root.dict_find_string_value("qBt-savePath")))); Utils::Fs::toUniformPath(fromLTString(root.dict_find_string_value("qBt-savePath"))));
torrentParams.hasSeedStatus = root.dict_find_int_value("qBt-seedStatus"); torrentParams.hasSeedStatus = root.dict_find_int_value("qBt-seedStatus");
torrentParams.firstLastPiecePriority = root.dict_find_int_value("qBt-firstLastPiecePriority"); torrentParams.firstLastPiecePriority = root.dict_find_int_value("qBt-firstLastPiecePriority");
torrentParams.seedingTimeLimit = root.dict_find_int_value("qBt-seedingTimeLimit", TorrentHandle::USE_GLOBAL_SEEDING_TIME); torrentParams.seedingTimeLimit = root.dict_find_int_value("qBt-seedingTimeLimit", Torrent::USE_GLOBAL_SEEDING_TIME);
// TODO: The following code is deprecated. Replace with the commented one after several releases in 4.4.x. // TODO: The following code is deprecated. Replace with the commented one after several releases in 4.4.x.
// === BEGIN DEPRECATED CODE === // // === BEGIN DEPRECATED CODE === //
@@ -4217,7 +4212,7 @@ bool Session::loadTorrentResumeData(const QByteArray &data, const TorrentInfo &m
const lt::string_view ratioLimitString = root.dict_find_string_value("qBt-ratioLimit"); const lt::string_view ratioLimitString = root.dict_find_string_value("qBt-ratioLimit");
if (ratioLimitString.empty()) if (ratioLimitString.empty())
torrentParams.ratioLimit = root.dict_find_int_value("qBt-ratioLimit", TorrentHandle::USE_GLOBAL_RATIO * 1000) / 1000.0; torrentParams.ratioLimit = root.dict_find_int_value("qBt-ratioLimit", Torrent::USE_GLOBAL_RATIO * 1000) / 1000.0;
else else
torrentParams.ratioLimit = fromLTString(ratioLimitString).toDouble(); torrentParams.ratioLimit = fromLTString(ratioLimitString).toDouble();
@@ -4551,7 +4546,7 @@ void Session::handleAlert(const lt::alert *a)
void Session::dispatchTorrentAlert(const lt::alert *a) void Session::dispatchTorrentAlert(const lt::alert *a)
{ {
TorrentHandleImpl *const torrent = m_torrents.value(static_cast<const lt::torrent_alert*>(a)->handle.info_hash()); TorrentImpl *const torrent = m_torrents.value(static_cast<const lt::torrent_alert*>(a)->handle.info_hash());
if (torrent) if (torrent)
{ {
torrent->handleAlert(a); torrent->handleAlert(a);
@@ -4566,13 +4561,13 @@ void Session::dispatchTorrentAlert(const lt::alert *a)
} }
} }
void Session::createTorrentHandle(const lt::torrent_handle &nativeHandle) void Session::createTorrent(const lt::torrent_handle &nativeHandle)
{ {
Q_ASSERT(m_loadingTorrents.contains(nativeHandle.info_hash())); Q_ASSERT(m_loadingTorrents.contains(nativeHandle.info_hash()));
const LoadTorrentParams params = m_loadingTorrents.take(nativeHandle.info_hash()); const LoadTorrentParams params = m_loadingTorrents.take(nativeHandle.info_hash());
auto *const torrent = new TorrentHandleImpl {this, m_nativeSession, nativeHandle, params}; auto *const torrent = new TorrentImpl {this, m_nativeSession, nativeHandle, params};
m_torrents.insert(torrent->hash(), torrent); m_torrents.insert(torrent->hash(), torrent);
const bool hasMetadata = torrent->hasMetadata(); const bool hasMetadata = torrent->hasMetadata();
@@ -4640,7 +4635,7 @@ void Session::handleAddTorrentAlert(const lt::add_torrent_alert *p)
} }
else if (m_loadingTorrents.contains(p->handle.info_hash())) else if (m_loadingTorrents.contains(p->handle.info_hash()))
{ {
createTorrentHandle(p->handle); createTorrent(p->handle);
} }
} }
@@ -4651,7 +4646,7 @@ void Session::handleTorrentRemovedAlert(const lt::torrent_removed_alert *p)
const auto removingTorrentDataIter = m_removingTorrents.find(infoHash); const auto removingTorrentDataIter = m_removingTorrents.find(infoHash);
if (removingTorrentDataIter != m_removingTorrents.end()) if (removingTorrentDataIter != m_removingTorrents.end())
{ {
if (removingTorrentDataIter->deleteOption == Torrent) if (removingTorrentDataIter->deleteOption == DeleteTorrent)
{ {
LogMsg(tr("'%1' was removed from the transfer list.", "'xxx.avi' was removed...").arg(removingTorrentDataIter->name)); LogMsg(tr("'%1' was removed from the transfer list.", "'xxx.avi' was removed...").arg(removingTorrentDataIter->name));
m_removingTorrents.erase(removingTorrentDataIter); m_removingTorrents.erase(removingTorrentDataIter);
@@ -4717,7 +4712,7 @@ void Session::handleMetadataReceivedAlert(const lt::metadata_received_alert *p)
void Session::handleFileErrorAlert(const lt::file_error_alert *p) void Session::handleFileErrorAlert(const lt::file_error_alert *p)
{ {
TorrentHandleImpl *const torrent = m_torrents.value(p->handle.info_hash()); TorrentImpl *const torrent = m_torrents.value(p->handle.info_hash());
if (!torrent) if (!torrent)
return; return;
@@ -4787,7 +4782,7 @@ void Session::handlePeerBanAlert(const lt::peer_ban_alert *p)
void Session::handleUrlSeedAlert(const lt::url_seed_alert *p) void Session::handleUrlSeedAlert(const lt::url_seed_alert *p)
{ {
const TorrentHandleImpl *torrent = m_torrents.value(p->handle.info_hash()); const TorrentImpl *torrent = m_torrents.value(p->handle.info_hash());
if (!torrent) if (!torrent)
return; return;
@@ -4925,13 +4920,10 @@ void Session::handleStorageMovedAlert(const lt::storage_moved_alert *p)
Q_ASSERT(newPath == currentJob.path); Q_ASSERT(newPath == currentJob.path);
const InfoHash infoHash = currentJob.torrentHandle.info_hash(); const InfoHash infoHash = currentJob.torrentHandle.info_hash();
TorrentHandleImpl *torrent = m_torrents.value(infoHash); TorrentImpl *torrent = m_torrents.value(infoHash);
const QString torrentName = (torrent ? torrent->name() : QString {infoHash}); const QString torrentName = (torrent ? torrent->name() : QString {infoHash});
LogMsg(tr("\"%1\" is successfully moved to \"%2\".").arg(torrentName, newPath)); LogMsg(tr("\"%1\" is successfully moved to \"%2\".").arg(torrentName, newPath));
if (torrent)
emit torrentStorageMoveFinished(torrent, newPath);
handleMoveTorrentStorageJobFinished(); handleMoveTorrentStorageJobFinished();
} }
@@ -4943,27 +4935,24 @@ void Session::handleStorageMovedFailedAlert(const lt::storage_moved_failed_alert
Q_ASSERT(currentJob.torrentHandle == p->handle); Q_ASSERT(currentJob.torrentHandle == p->handle);
const InfoHash infoHash = currentJob.torrentHandle.info_hash(); const InfoHash infoHash = currentJob.torrentHandle.info_hash();
TorrentHandleImpl *torrent = m_torrents.value(infoHash); TorrentImpl *torrent = m_torrents.value(infoHash);
const QString torrentName = (torrent ? torrent->name() : QString {infoHash}); const QString torrentName = (torrent ? torrent->name() : QString {infoHash});
const QString currentLocation = QString::fromStdString(p->handle.status(lt::torrent_handle::query_save_path).save_path); const QString currentLocation = QString::fromStdString(p->handle.status(lt::torrent_handle::query_save_path).save_path);
const QString errorMessage = QString::fromStdString(p->message()); const QString errorMessage = QString::fromStdString(p->message());
LogMsg(tr("Failed to move \"%1\" from \"%2\" to \"%3\". Reason: %4.") LogMsg(tr("Failed to move \"%1\" from \"%2\" to \"%3\". Reason: %4.")
.arg(torrentName, currentLocation, currentJob.path, errorMessage), Log::CRITICAL); .arg(torrentName, currentLocation, currentJob.path, errorMessage), Log::CRITICAL);
if (torrent)
emit torrentStorageMoveFailed(torrent, currentJob.path, errorMessage);
handleMoveTorrentStorageJobFinished(); handleMoveTorrentStorageJobFinished();
} }
void Session::handleStateUpdateAlert(const lt::state_update_alert *p) void Session::handleStateUpdateAlert(const lt::state_update_alert *p)
{ {
QVector<TorrentHandle *> updatedTorrents; QVector<Torrent *> updatedTorrents;
updatedTorrents.reserve(p->status.size()); updatedTorrents.reserve(p->status.size());
for (const lt::torrent_status &status : p->status) for (const lt::torrent_status &status : p->status)
{ {
TorrentHandleImpl *const torrent = m_torrents.value(status.info_hash); TorrentImpl *const torrent = m_torrents.value(status.info_hash);
if (!torrent) if (!torrent)
continue; continue;

View File

@@ -30,6 +30,7 @@
#pragma once #pragma once
#include <memory> #include <memory>
#include <variant>
#include <vector> #include <vector>
#include <libtorrent/add_torrent_params.hpp> #include <libtorrent/add_torrent_params.hpp>
@@ -84,8 +85,8 @@ enum MaxRatioAction
enum DeleteOption enum DeleteOption
{ {
Torrent, DeleteTorrent,
TorrentAndFiles DeleteTorrentAndFiles
}; };
enum TorrentExportFolder enum TorrentExportFolder
@@ -103,8 +104,8 @@ namespace BitTorrent
{ {
class InfoHash; class InfoHash;
class MagnetUri; class MagnetUri;
class TorrentHandle; class Torrent;
class TorrentHandleImpl; class TorrentImpl;
class Tracker; class Tracker;
class TrackerEntry; class TrackerEntry;
struct LoadTorrentParams; struct LoadTorrentParams;
@@ -439,8 +440,8 @@ namespace BitTorrent
#endif #endif
void startUpTorrents(); void startUpTorrents();
TorrentHandle *findTorrent(const InfoHash &hash) const; Torrent *findTorrent(const InfoHash &hash) const;
QVector<TorrentHandle *> torrents() const; QVector<Torrent *> torrents() const;
bool hasActiveTorrents() const; bool hasActiveTorrents() const;
bool hasUnfinishedTorrents() const; bool hasUnfinishedTorrents() const;
bool hasRunningSeed() const; bool hasRunningSeed() const;
@@ -459,7 +460,7 @@ namespace BitTorrent
bool addTorrent(const QString &source, const AddTorrentParams &params = AddTorrentParams()); bool addTorrent(const QString &source, const AddTorrentParams &params = AddTorrentParams());
bool addTorrent(const MagnetUri &magnetUri, const AddTorrentParams &params = AddTorrentParams()); bool addTorrent(const MagnetUri &magnetUri, const AddTorrentParams &params = AddTorrentParams());
bool addTorrent(const TorrentInfo &torrentInfo, const AddTorrentParams &params = AddTorrentParams()); bool addTorrent(const TorrentInfo &torrentInfo, const AddTorrentParams &params = AddTorrentParams());
bool deleteTorrent(const InfoHash &hash, DeleteOption deleteOption = Torrent); bool deleteTorrent(const InfoHash &hash, DeleteOption deleteOption = DeleteTorrent);
bool downloadMetadata(const MagnetUri &magnetUri); bool downloadMetadata(const MagnetUri &magnetUri);
bool cancelDownloadMetadata(const InfoHash &hash); bool cancelDownloadMetadata(const InfoHash &hash);
@@ -469,31 +470,31 @@ namespace BitTorrent
void topTorrentsQueuePos(const QVector<InfoHash> &hashes); void topTorrentsQueuePos(const QVector<InfoHash> &hashes);
void bottomTorrentsQueuePos(const QVector<InfoHash> &hashes); void bottomTorrentsQueuePos(const QVector<InfoHash> &hashes);
// TorrentHandle interface // Torrent interface
void handleTorrentSaveResumeDataRequested(const TorrentHandleImpl *torrent); void handleTorrentSaveResumeDataRequested(const TorrentImpl *torrent);
void handleTorrentShareLimitChanged(TorrentHandleImpl *const torrent); void handleTorrentShareLimitChanged(TorrentImpl *const torrent);
void handleTorrentNameChanged(TorrentHandleImpl *const torrent); void handleTorrentNameChanged(TorrentImpl *const torrent);
void handleTorrentSavePathChanged(TorrentHandleImpl *const torrent); void handleTorrentSavePathChanged(TorrentImpl *const torrent);
void handleTorrentCategoryChanged(TorrentHandleImpl *const torrent, const QString &oldCategory); void handleTorrentCategoryChanged(TorrentImpl *const torrent, const QString &oldCategory);
void handleTorrentTagAdded(TorrentHandleImpl *const torrent, const QString &tag); void handleTorrentTagAdded(TorrentImpl *const torrent, const QString &tag);
void handleTorrentTagRemoved(TorrentHandleImpl *const torrent, const QString &tag); void handleTorrentTagRemoved(TorrentImpl *const torrent, const QString &tag);
void handleTorrentSavingModeChanged(TorrentHandleImpl *const torrent); void handleTorrentSavingModeChanged(TorrentImpl *const torrent);
void handleTorrentMetadataReceived(TorrentHandleImpl *const torrent); void handleTorrentMetadataReceived(TorrentImpl *const torrent);
void handleTorrentPaused(TorrentHandleImpl *const torrent); void handleTorrentPaused(TorrentImpl *const torrent);
void handleTorrentResumed(TorrentHandleImpl *const torrent); void handleTorrentResumed(TorrentImpl *const torrent);
void handleTorrentChecked(TorrentHandleImpl *const torrent); void handleTorrentChecked(TorrentImpl *const torrent);
void handleTorrentFinished(TorrentHandleImpl *const torrent); void handleTorrentFinished(TorrentImpl *const torrent);
void handleTorrentTrackersAdded(TorrentHandleImpl *const torrent, const QVector<TrackerEntry> &newTrackers); void handleTorrentTrackersAdded(TorrentImpl *const torrent, const QVector<TrackerEntry> &newTrackers);
void handleTorrentTrackersRemoved(TorrentHandleImpl *const torrent, const QVector<TrackerEntry> &deletedTrackers); void handleTorrentTrackersRemoved(TorrentImpl *const torrent, const QVector<TrackerEntry> &deletedTrackers);
void handleTorrentTrackersChanged(TorrentHandleImpl *const torrent); void handleTorrentTrackersChanged(TorrentImpl *const torrent);
void handleTorrentUrlSeedsAdded(TorrentHandleImpl *const torrent, const QVector<QUrl> &newUrlSeeds); void handleTorrentUrlSeedsAdded(TorrentImpl *const torrent, const QVector<QUrl> &newUrlSeeds);
void handleTorrentUrlSeedsRemoved(TorrentHandleImpl *const torrent, const QVector<QUrl> &urlSeeds); void handleTorrentUrlSeedsRemoved(TorrentImpl *const torrent, const QVector<QUrl> &urlSeeds);
void handleTorrentResumeDataReady(TorrentHandleImpl *const torrent, const std::shared_ptr<lt::entry> &data); void handleTorrentResumeDataReady(TorrentImpl *const torrent, const std::shared_ptr<lt::entry> &data);
void handleTorrentTrackerReply(TorrentHandleImpl *const torrent, const QString &trackerUrl); void handleTorrentTrackerReply(TorrentImpl *const torrent, const QString &trackerUrl);
void handleTorrentTrackerWarning(TorrentHandleImpl *const torrent, const QString &trackerUrl); void handleTorrentTrackerWarning(TorrentImpl *const torrent, const QString &trackerUrl);
void handleTorrentTrackerError(TorrentHandleImpl *const torrent, const QString &trackerUrl); void handleTorrentTrackerError(TorrentImpl *const torrent, const QString &trackerUrl);
bool addMoveTorrentStorageJob(TorrentHandleImpl *torrent, const QString &newPath, MoveStorageMode mode); bool addMoveTorrentStorageJob(TorrentImpl *torrent, const QString &newPath, MoveStorageMode mode);
void findIncompleteFiles(const TorrentInfo &torrentInfo, const QString &savePath) const; void findIncompleteFiles(const TorrentInfo &torrentInfo, const QString &savePath) const;
@@ -503,39 +504,37 @@ namespace BitTorrent
void categoryRemoved(const QString &categoryName); void categoryRemoved(const QString &categoryName);
void downloadFromUrlFailed(const QString &url, const QString &reason); void downloadFromUrlFailed(const QString &url, const QString &reason);
void downloadFromUrlFinished(const QString &url); void downloadFromUrlFinished(const QString &url);
void fullDiskError(TorrentHandle *torrent, const QString &msg); void fullDiskError(Torrent *torrent, const QString &msg);
void IPFilterParsed(bool error, int ruleCount); void IPFilterParsed(bool error, int ruleCount);
void loadTorrentFailed(const QString &error); void loadTorrentFailed(const QString &error);
void metadataDownloaded(const TorrentInfo &info); void metadataDownloaded(const TorrentInfo &info);
void recursiveTorrentDownloadPossible(TorrentHandle *torrent); void recursiveTorrentDownloadPossible(Torrent *torrent);
void speedLimitModeChanged(bool alternative); void speedLimitModeChanged(bool alternative);
void statsUpdated(); void statsUpdated();
void subcategoriesSupportChanged(); void subcategoriesSupportChanged();
void tagAdded(const QString &tag); void tagAdded(const QString &tag);
void tagRemoved(const QString &tag); void tagRemoved(const QString &tag);
void torrentAboutToBeRemoved(TorrentHandle *torrent); void torrentAboutToBeRemoved(Torrent *torrent);
void torrentAdded(TorrentHandle *torrent); void torrentAdded(Torrent *torrent);
void torrentCategoryChanged(TorrentHandle *torrent, const QString &oldCategory); void torrentCategoryChanged(Torrent *torrent, const QString &oldCategory);
void torrentFinished(TorrentHandle *torrent); void torrentFinished(Torrent *torrent);
void torrentFinishedChecking(TorrentHandle *torrent); void torrentFinishedChecking(Torrent *torrent);
void torrentLoaded(TorrentHandle *torrent); void torrentLoaded(Torrent *torrent);
void torrentMetadataReceived(TorrentHandle *torrent); void torrentMetadataReceived(Torrent *torrent);
void torrentPaused(TorrentHandle *torrent); void torrentPaused(Torrent *torrent);
void torrentResumed(TorrentHandle *torrent); void torrentResumed(Torrent *torrent);
void torrentSavePathChanged(TorrentHandle *torrent); void torrentSavePathChanged(Torrent *torrent);
void torrentSavingModeChanged(TorrentHandle *torrent); void torrentSavingModeChanged(Torrent *torrent);
void torrentStorageMoveFailed(TorrentHandle *torrent, const QString &targetPath, const QString &error); void torrentsUpdated(const QVector<Torrent *> &torrents);
void torrentStorageMoveFinished(TorrentHandle *torrent, const QString &newPath); void torrentTagAdded(Torrent *torrent, const QString &tag);
void torrentsUpdated(const QVector<TorrentHandle *> &torrents); void torrentTagRemoved(Torrent *torrent, const QString &tag);
void torrentTagAdded(TorrentHandle *torrent, const QString &tag); void trackerError(Torrent *torrent, const QString &tracker);
void torrentTagRemoved(TorrentHandle *torrent, const QString &tag); void trackerlessStateChanged(Torrent *torrent, bool trackerless);
void trackerError(TorrentHandle *torrent, const QString &tracker); void trackersAdded(Torrent *torrent, const QVector<TrackerEntry> &trackers);
void trackerlessStateChanged(TorrentHandle *torrent, bool trackerless); void trackersChanged(Torrent *torrent);
void trackersAdded(TorrentHandle *torrent, const QVector<TrackerEntry> &trackers); void trackersRemoved(Torrent *torrent, const QVector<TrackerEntry> &trackers);
void trackersChanged(TorrentHandle *torrent); void trackerSuccess(Torrent *torrent, const QString &tracker);
void trackersRemoved(TorrentHandle *torrent, const QVector<TrackerEntry> &trackers); void trackerWarning(Torrent *torrent, const QString &tracker);
void trackerSuccess(TorrentHandle *torrent, const QString &tracker);
void trackerWarning(TorrentHandle *torrent, const QString &tracker);
private slots: private slots:
void configureDeferred(); void configureDeferred();
@@ -602,10 +601,10 @@ namespace BitTorrent
bool loadTorrentResumeData(const QByteArray &data, const TorrentInfo &metadata, LoadTorrentParams &torrentParams); bool loadTorrentResumeData(const QByteArray &data, const TorrentInfo &metadata, LoadTorrentParams &torrentParams);
bool loadTorrent(LoadTorrentParams params); bool loadTorrent(LoadTorrentParams params);
LoadTorrentParams initLoadTorrentParams(const AddTorrentParams &addTorrentParams); LoadTorrentParams initLoadTorrentParams(const AddTorrentParams &addTorrentParams);
bool addTorrent_impl(const AddTorrentParams &addTorrentParams, const MagnetUri &magnetUri, TorrentInfo torrentInfo = TorrentInfo()); bool addTorrent_impl(const std::variant<MagnetUri, TorrentInfo> &source, const AddTorrentParams &addTorrentParams);
void updateSeedingLimitTimer(); void updateSeedingLimitTimer();
void exportTorrentFile(const TorrentHandle *torrent, TorrentExportFolder folder = TorrentExportFolder::Regular); void exportTorrentFile(const Torrent *torrent, TorrentExportFolder folder = TorrentExportFolder::Regular);
void handleAlert(const lt::alert *a); void handleAlert(const lt::alert *a);
void dispatchTorrentAlert(const lt::alert *a); void dispatchTorrentAlert(const lt::alert *a);
@@ -630,7 +629,7 @@ namespace BitTorrent
void handleStorageMovedFailedAlert(const lt::storage_moved_failed_alert *p); void handleStorageMovedFailedAlert(const lt::storage_moved_failed_alert *p);
void handleSocks5Alert(const lt::socks5_alert *p) const; void handleSocks5Alert(const lt::socks5_alert *p) const;
void createTorrentHandle(const lt::torrent_handle &nativeHandle); void createTorrent(const lt::torrent_handle &nativeHandle);
void saveResumeData(); void saveResumeData();
void saveTorrentsQueue(); void saveTorrentsQueue();
@@ -772,7 +771,7 @@ namespace BitTorrent
QSet<InfoHash> m_downloadedMetadata; QSet<InfoHash> m_downloadedMetadata;
QHash<InfoHash, TorrentHandleImpl *> m_torrents; QHash<InfoHash, TorrentImpl *> m_torrents;
QHash<InfoHash, LoadTorrentParams> m_loadingTorrents; QHash<InfoHash, LoadTorrentParams> m_loadingTorrents;
QHash<QString, AddTorrentParams> m_downloadedTorrents; QHash<QString, AddTorrentParams> m_downloadedTorrents;
QHash<InfoHash, RemovingTorrentData> m_removingTorrents; QHash<InfoHash, RemovingTorrentData> m_removingTorrents;

View File

@@ -27,7 +27,7 @@
* exception statement from your version. * exception statement from your version.
*/ */
#include "torrenthandle.h" #include "torrent.h"
#include <type_traits> #include <type_traits>
@@ -40,33 +40,33 @@ namespace BitTorrent
return ::qHash(static_cast<std::underlying_type_t<TorrentState>>(key), seed); return ::qHash(static_cast<std::underlying_type_t<TorrentState>>(key), seed);
} }
// TorrentHandle // Torrent
const qreal TorrentHandle::USE_GLOBAL_RATIO = -2.; const qreal Torrent::USE_GLOBAL_RATIO = -2.;
const qreal TorrentHandle::NO_RATIO_LIMIT = -1.; const qreal Torrent::NO_RATIO_LIMIT = -1.;
const int TorrentHandle::USE_GLOBAL_SEEDING_TIME = -2; const int Torrent::USE_GLOBAL_SEEDING_TIME = -2;
const int TorrentHandle::NO_SEEDING_TIME_LIMIT = -1; const int Torrent::NO_SEEDING_TIME_LIMIT = -1;
const qreal TorrentHandle::MAX_RATIO = 9999.; const qreal Torrent::MAX_RATIO = 9999.;
const int TorrentHandle::MAX_SEEDING_TIME = 525600; const int Torrent::MAX_SEEDING_TIME = 525600;
bool TorrentHandle::isResumed() const bool Torrent::isResumed() const
{ {
return !isPaused(); return !isPaused();
} }
qlonglong TorrentHandle::remainingSize() const qlonglong Torrent::remainingSize() const
{ {
return wantedSize() - completedSize(); return wantedSize() - completedSize();
} }
void TorrentHandle::toggleSequentialDownload() void Torrent::toggleSequentialDownload()
{ {
setSequentialDownload(!isSequentialDownload()); setSequentialDownload(!isSequentialDownload());
} }
void TorrentHandle::toggleFirstLastPiecePriority() void Torrent::toggleFirstLastPiecePriority()
{ {
setFirstLastPiecePriority(!hasFirstLastPiecePriority()); setFirstLastPiecePriority(!hasFirstLastPiecePriority());
} }

View File

@@ -33,6 +33,8 @@
#include <QString> #include <QString>
#include <QtContainerFwd> #include <QtContainerFwd>
#include "abstractfilestorage.h"
class QBitArray; class QBitArray;
class QDateTime; class QDateTime;
class QUrl; class QUrl;
@@ -89,7 +91,7 @@ namespace BitTorrent
uint qHash(TorrentState key, uint seed); uint qHash(TorrentState key, uint seed);
class TorrentHandle class Torrent : public AbstractFileStorage
{ {
public: public:
static const qreal USE_GLOBAL_RATIO; static const qreal USE_GLOBAL_RATIO;
@@ -101,7 +103,7 @@ namespace BitTorrent
static const qreal MAX_RATIO; static const qreal MAX_RATIO;
static const int MAX_SEEDING_TIME; static const int MAX_SEEDING_TIME;
virtual ~TorrentHandle() = default; virtual ~Torrent() = default;
virtual InfoHash hash() const = 0; virtual InfoHash hash() const = 0;
virtual QString name() const = 0; virtual QString name() const = 0;
@@ -177,7 +179,6 @@ namespace BitTorrent
virtual bool removeTag(const QString &tag) = 0; virtual bool removeTag(const QString &tag) = 0;
virtual void removeAllTags() = 0; virtual void removeAllTags() = 0;
virtual int filesCount() const = 0;
virtual int piecesCount() const = 0; virtual int piecesCount() const = 0;
virtual int piecesHave() const = 0; virtual int piecesHave() const = 0;
virtual qreal progress() const = 0; virtual qreal progress() const = 0;
@@ -185,9 +186,6 @@ namespace BitTorrent
virtual qreal ratioLimit() const = 0; virtual qreal ratioLimit() const = 0;
virtual int seedingTimeLimit() const = 0; virtual int seedingTimeLimit() const = 0;
virtual QString filePath(int index) const = 0;
virtual QString fileName(int index) const = 0;
virtual qlonglong fileSize(int index) const = 0;
virtual QStringList absoluteFilePaths() const = 0; virtual QStringList absoluteFilePaths() const = 0;
virtual QVector<DownloadPriority> filePriorities() const = 0; virtual QVector<DownloadPriority> filePriorities() const = 0;
@@ -238,6 +236,9 @@ namespace BitTorrent
virtual int downloadLimit() const = 0; virtual int downloadLimit() const = 0;
virtual int uploadLimit() const = 0; virtual int uploadLimit() const = 0;
virtual bool superSeeding() const = 0; virtual bool superSeeding() const = 0;
virtual bool isDHTDisabled() const = 0;
virtual bool isPEXDisabled() const = 0;
virtual bool isLSDDisabled() const = 0;
virtual QVector<PeerInfo> peers() const = 0; virtual QVector<PeerInfo> peers() const = 0;
virtual QBitArray pieces() const = 0; virtual QBitArray pieces() const = 0;
virtual QBitArray downloadingPieces() const = 0; virtual QBitArray downloadingPieces() const = 0;
@@ -270,13 +271,15 @@ namespace BitTorrent
virtual void forceReannounce(int index = -1) = 0; virtual void forceReannounce(int index = -1) = 0;
virtual void forceDHTAnnounce() = 0; virtual void forceDHTAnnounce() = 0;
virtual void forceRecheck() = 0; virtual void forceRecheck() = 0;
virtual void renameFile(int index, const QString &name) = 0;
virtual void prioritizeFiles(const QVector<DownloadPriority> &priorities) = 0; virtual void prioritizeFiles(const QVector<DownloadPriority> &priorities) = 0;
virtual void setRatioLimit(qreal limit) = 0; virtual void setRatioLimit(qreal limit) = 0;
virtual void setSeedingTimeLimit(int limit) = 0; virtual void setSeedingTimeLimit(int limit) = 0;
virtual void setUploadLimit(int limit) = 0; virtual void setUploadLimit(int limit) = 0;
virtual void setDownloadLimit(int limit) = 0; virtual void setDownloadLimit(int limit) = 0;
virtual void setSuperSeeding(bool enable) = 0; virtual void setSuperSeeding(bool enable) = 0;
virtual void setDHTDisabled(bool disable) = 0;
virtual void setPEXDisabled(bool disable) = 0;
virtual void setLSDDisabled(bool disable) = 0;
virtual void flushCache() const = 0; virtual void flushCache() const = 0;
virtual void addTrackers(const QVector<TrackerEntry> &trackers) = 0; virtual void addTrackers(const QVector<TrackerEntry> &trackers) = 0;
virtual void replaceTrackers(const QVector<TrackerEntry> &trackers) = 0; virtual void replaceTrackers(const QVector<TrackerEntry> &trackers) = 0;

View File

@@ -45,6 +45,7 @@
#include "base/utils/fs.h" #include "base/utils/fs.h"
#include "base/utils/io.h" #include "base/utils/io.h"
#include "base/utils/string.h" #include "base/utils/string.h"
#include "base/version.h"
#include "ltunderlyingtype.h" #include "ltunderlyingtype.h"
namespace namespace

View File

@@ -46,7 +46,7 @@
#include "infohash.h" #include "infohash.h"
#include "speedmonitor.h" #include "speedmonitor.h"
#include "torrenthandle.h" #include "torrent.h"
#include "torrentinfo.h" #include "torrentinfo.h"
namespace BitTorrent namespace BitTorrent
@@ -69,8 +69,8 @@ namespace BitTorrent
bool paused = false; bool paused = false;
qreal ratioLimit = TorrentHandle::USE_GLOBAL_RATIO; qreal ratioLimit = Torrent::USE_GLOBAL_RATIO;
int seedingTimeLimit = TorrentHandle::USE_GLOBAL_SEEDING_TIME; int seedingTimeLimit = Torrent::USE_GLOBAL_SEEDING_TIME;
bool restored = false; // is existing torrent job? bool restored = false; // is existing torrent job?
}; };
@@ -87,15 +87,15 @@ namespace BitTorrent
HandleMetadata HandleMetadata
}; };
class TorrentHandleImpl final : public QObject, public TorrentHandle class TorrentImpl final : public QObject, public Torrent
{ {
Q_DISABLE_COPY(TorrentHandleImpl) Q_DISABLE_COPY(TorrentImpl)
Q_DECLARE_TR_FUNCTIONS(BitTorrent::TorrentHandleImpl) Q_DECLARE_TR_FUNCTIONS(BitTorrent::TorrentImpl)
public: public:
TorrentHandleImpl(Session *session, lt::session *nativeSession TorrentImpl(Session *session, lt::session *nativeSession
, const lt::torrent_handle &nativeHandle, const LoadTorrentParams &params); , const lt::torrent_handle &nativeHandle, const LoadTorrentParams &params);
~TorrentHandleImpl() override; ~TorrentImpl() override;
bool isValid() const; bool isValid() const;
@@ -191,6 +191,9 @@ namespace BitTorrent
int downloadLimit() const override; int downloadLimit() const override;
int uploadLimit() const override; int uploadLimit() const override;
bool superSeeding() const override; bool superSeeding() const override;
bool isDHTDisabled() const override;
bool isPEXDisabled() const override;
bool isLSDDisabled() const override;
QVector<PeerInfo> peers() const override; QVector<PeerInfo> peers() const override;
QBitArray pieces() const override; QBitArray pieces() const override;
QBitArray downloadingPieces() const override; QBitArray downloadingPieces() const override;
@@ -217,13 +220,16 @@ namespace BitTorrent
void forceReannounce(int index = -1) override; void forceReannounce(int index = -1) override;
void forceDHTAnnounce() override; void forceDHTAnnounce() override;
void forceRecheck() override; void forceRecheck() override;
void renameFile(int index, const QString &name) override; void renameFile(int index, const QString &path) override;
void prioritizeFiles(const QVector<DownloadPriority> &priorities) override; void prioritizeFiles(const QVector<DownloadPriority> &priorities) override;
void setRatioLimit(qreal limit) override; void setRatioLimit(qreal limit) override;
void setSeedingTimeLimit(int limit) override; void setSeedingTimeLimit(int limit) override;
void setUploadLimit(int limit) override; void setUploadLimit(int limit) override;
void setDownloadLimit(int limit) override; void setDownloadLimit(int limit) override;
void setSuperSeeding(bool enable) override; void setSuperSeeding(bool enable) override;
void setDHTDisabled(bool disable) override;
void setPEXDisabled(bool disable) override;
void setLSDDisabled(bool disable) override;
void flushCache() const override; void flushCache() const override;
void addTrackers(const QVector<TrackerEntry> &trackers) override; void addTrackers(const QVector<TrackerEntry> &trackers) override;
void replaceTrackers(const QVector<TrackerEntry> &trackers) override; void replaceTrackers(const QVector<TrackerEntry> &trackers) override;
@@ -285,6 +291,7 @@ namespace BitTorrent
void applyFirstLastPiecePriority(bool enabled, const QVector<DownloadPriority> &updatedFilePrio = {}); void applyFirstLastPiecePriority(bool enabled, const QVector<DownloadPriority> &updatedFilePrio = {});
void endReceivedMetadataHandling(const QString &savePath, const QStringList &fileNames); void endReceivedMetadataHandling(const QString &savePath, const QStringList &fileNames);
void reload();
Session *const m_session; Session *const m_session;
lt::session *m_nativeSession; lt::session *m_nativeSession;

View File

@@ -34,6 +34,7 @@
#include <QtContainerFwd> #include <QtContainerFwd>
#include "base/indexrange.h" #include "base/indexrange.h"
#include "abstractfilestorage.h"
#include "torrentcontentlayout.h" #include "torrentcontentlayout.h"
class QByteArray; class QByteArray;
@@ -46,7 +47,7 @@ namespace BitTorrent
class InfoHash; class InfoHash;
class TrackerEntry; class TrackerEntry;
class TorrentInfo class TorrentInfo final : public AbstractFileStorage
{ {
Q_DECLARE_TR_FUNCTIONS(TorrentInfo) Q_DECLARE_TR_FUNCTIONS(TorrentInfo)
@@ -68,15 +69,15 @@ namespace BitTorrent
QString comment() const; QString comment() const;
bool isPrivate() const; bool isPrivate() const;
qlonglong totalSize() const; qlonglong totalSize() const;
int filesCount() const; int filesCount() const override;
int pieceLength() const; int pieceLength() const;
int pieceLength(int index) const; int pieceLength(int index) const;
int piecesCount() const; int piecesCount() const;
QString filePath(int index) const; QString filePath(int index) const override;
QStringList filePaths() const; QStringList filePaths() const;
QString fileName(int index) const; QString fileName(int index) const override;
QString origFilePath(int index) const; QString origFilePath(int index) const;
qlonglong fileSize(int index) const; qlonglong fileSize(int index) const override;
qlonglong fileOffset(int index) const; qlonglong fileOffset(int index) const;
QVector<TrackerEntry> trackers() const; QVector<TrackerEntry> trackers() const;
QVector<QUrl> urlSeeds() const; QVector<QUrl> urlSeeds() const;
@@ -91,7 +92,7 @@ namespace BitTorrent
PieceRange filePieces(const QString &file) const; PieceRange filePieces(const QString &file) const;
PieceRange filePieces(int fileIndex) const; PieceRange filePieces(int fileIndex) const;
void renameFile(int index, const QString &newPath); void renameFile(int index, const QString &newPath) override;
QString rootFolder() const; QString rootFolder() const;
bool hasRootFolder() const; bool hasRootFolder() const;

View File

@@ -37,8 +37,7 @@ class IndexInterval
public: public:
using IndexType = Index; using IndexType = Index;
// TODO: add constexpr when using C++17 constexpr IndexInterval(const IndexType first, const IndexType last)
IndexInterval(const IndexType first, const IndexType last)
: m_first {first} : m_first {first}
, m_last {last} , m_last {last}
{ {

View File

@@ -34,6 +34,7 @@
#include "base/logger.h" #include "base/logger.h"
#include "base/net/downloadmanager.h" #include "base/net/downloadmanager.h"
#include "base/version.h"
using namespace Net; using namespace Net;

View File

@@ -64,15 +64,15 @@ ProxyConfigurationManager *ProxyConfigurationManager::m_instance = nullptr;
ProxyConfigurationManager::ProxyConfigurationManager(QObject *parent) ProxyConfigurationManager::ProxyConfigurationManager(QObject *parent)
: QObject(parent) : QObject(parent)
{ {
m_isProxyOnlyForTorrents = settings()->loadValue(KEY_ONLY_FOR_TORRENTS, false).toBool(); m_isProxyOnlyForTorrents = settings()->loadValue(KEY_ONLY_FOR_TORRENTS, false);
m_config.type = static_cast<ProxyType>( m_config.type = static_cast<ProxyType>(
settings()->loadValue(KEY_TYPE, static_cast<int>(ProxyType::None)).toInt()); settings()->loadValue(KEY_TYPE, static_cast<int>(ProxyType::None)));
if ((m_config.type < ProxyType::None) || (m_config.type > ProxyType::SOCKS4)) if ((m_config.type < ProxyType::None) || (m_config.type > ProxyType::SOCKS4))
m_config.type = ProxyType::None; m_config.type = ProxyType::None;
m_config.ip = settings()->loadValue(KEY_IP, "0.0.0.0").toString(); m_config.ip = settings()->loadValue<QString>(KEY_IP, "0.0.0.0");
m_config.port = static_cast<ushort>(settings()->loadValue(KEY_PORT, 8080).toUInt()); m_config.port = settings()->loadValue<ushort>(KEY_PORT, 8080);
m_config.username = settings()->loadValue(KEY_USERNAME).toString(); m_config.username = settings()->loadValue<QString>(KEY_USERNAME);
m_config.password = settings()->loadValue(KEY_PASSWORD).toString(); m_config.password = settings()->loadValue<QString>(KEY_PASSWORD);
configureProxy(); configureProxy();
} }

View File

@@ -1241,26 +1241,6 @@ void Preferences::setMainLastDir(const QString &path)
setValue("MainWindowLastDir", path); setValue("MainWindowLastDir", path);
} }
QSize Preferences::getPrefSize() const
{
return value("Preferences/State/size").toSize();
}
void Preferences::setPrefSize(const QSize &size)
{
setValue("Preferences/State/size", size);
}
QStringList Preferences::getPrefHSplitterSizes() const
{
return value("Preferences/State/hSplitterSizes").toStringList();
}
void Preferences::setPrefHSplitterSizes(const QStringList &sizes)
{
setValue("Preferences/State/hSplitterSizes", sizes);
}
QByteArray Preferences::getPeerListState() const QByteArray Preferences::getPeerListState() const
{ {
return value("TorrentProperties/Peers/qt5/PeerListState").toByteArray(); return value("TorrentProperties/Peers/qt5/PeerListState").toByteArray();

View File

@@ -329,10 +329,6 @@ public:
void setMainVSplitterState(const QByteArray &state); void setMainVSplitterState(const QByteArray &state);
QString getMainLastDir() const; QString getMainLastDir() const;
void setMainLastDir(const QString &path); void setMainLastDir(const QString &path);
QSize getPrefSize() const;
void setPrefSize(const QSize &size);
QStringList getPrefHSplitterSizes() const;
void setPrefHSplitterSizes(const QStringList &sizes);
QByteArray getPeerListState() const; QByteArray getPeerListState() const;
void setPeerListState(const QByteArray &state); void setPeerListState(const QByteArray &state);
QString getPropSplitterSizes() const; QString getPropSplitterSizes() const;

View File

@@ -83,7 +83,7 @@ QString Private::DefaultProfile::dataLocation() const
const QString dataDir = QStandardPaths::writableLocation(QStandardPaths::GenericDataLocation) const QString dataDir = QStandardPaths::writableLocation(QStandardPaths::GenericDataLocation)
+ QLatin1Char('/') + profileName() + QLatin1Char('/'); + QLatin1Char('/') + profileName() + QLatin1Char('/');
if (QDir(legacyDir).exists()) if (!QDir(dataDir).exists() && QDir(legacyDir).exists())
{ {
qWarning("The legacy data directory '%s' is used. It is recommended to move its content to '%s'", qWarning("The legacy data directory '%s' is used. It is recommended to move its content to '%s'",
qUtf8Printable(legacyDir), qUtf8Printable(dataDir)); qUtf8Printable(legacyDir), qUtf8Printable(dataDir));

View File

@@ -47,7 +47,6 @@
#include "../logger.h" #include "../logger.h"
#include "../profile.h" #include "../profile.h"
#include "../settingsstorage.h" #include "../settingsstorage.h"
#include "../tristatebool.h"
#include "../utils/fs.h" #include "../utils/fs.h"
#include "rss_article.h" #include "rss_article.h"
#include "rss_autodownloadrule.h" #include "rss_autodownloadrule.h"
@@ -105,7 +104,7 @@ QString computeSmartFilterRegex(const QStringList &filters)
} }
AutoDownloader::AutoDownloader() AutoDownloader::AutoDownloader()
: m_processingEnabled(SettingsStorage::instance()->loadValue(SettingsKey_ProcessingEnabled, false).toBool()) : m_processingEnabled(SettingsStorage::instance()->loadValue(SettingsKey_ProcessingEnabled, false))
, m_processingTimer(new QTimer(this)) , m_processingTimer(new QTimer(this))
, m_ioThread(new QThread(this)) , m_ioThread(new QThread(this))
{ {
@@ -290,7 +289,7 @@ void AutoDownloader::importRulesFromLegacyFormat(const QByteArray &data)
QStringList AutoDownloader::smartEpisodeFilters() const QStringList AutoDownloader::smartEpisodeFilters() const
{ {
const QVariant filtersSetting = SettingsStorage::instance()->loadValue(SettingsKey_SmartEpisodeFilter); const auto filtersSetting = SettingsStorage::instance()->loadValue<QVariant>(SettingsKey_SmartEpisodeFilter);
if (filtersSetting.isNull()) if (filtersSetting.isNull())
{ {
@@ -323,7 +322,7 @@ void AutoDownloader::setSmartEpisodeFilters(const QStringList &filters)
bool AutoDownloader::downloadRepacks() const bool AutoDownloader::downloadRepacks() const
{ {
return SettingsStorage::instance()->loadValue(SettingsKey_DownloadRepacks, true).toBool(); return SettingsStorage::instance()->loadValue(SettingsKey_DownloadRepacks, true);
} }
void AutoDownloader::setDownloadRepacks(const bool downloadRepacks) void AutoDownloader::setDownloadRepacks(const bool downloadRepacks)
@@ -398,7 +397,7 @@ void AutoDownloader::processJob(const QSharedPointer<ProcessingJob> &job)
params.addPaused = rule.addPaused(); params.addPaused = rule.addPaused();
params.contentLayout = rule.torrentContentLayout(); params.contentLayout = rule.torrentContentLayout();
if (!rule.savePath().isEmpty()) if (!rule.savePath().isEmpty())
params.useAutoTMM = TriStateBool::False; params.useAutoTMM = false;
const auto torrentURL = job->articleData.value(Article::KeyTorrentURL).toString(); const auto torrentURL = job->articleData.value(Article::KeyTorrentURL).toString();
BitTorrent::Session::instance()->addTorrent(torrentURL, params); BitTorrent::Session::instance()->addTorrent(torrentURL, params);

View File

@@ -42,7 +42,6 @@
#include "base/global.h" #include "base/global.h"
#include "base/preferences.h" #include "base/preferences.h"
#include "base/tristatebool.h"
#include "base/utils/fs.h" #include "base/utils/fs.h"
#include "base/utils/string.h" #include "base/utils/string.h"
#include "rss_article.h" #include "rss_article.h"
@@ -51,56 +50,49 @@
namespace namespace
{ {
TriStateBool jsonValueToTriStateBool(const QJsonValue &jsonVal) std::optional<bool> toOptionalBool(const QJsonValue &jsonVal)
{ {
if (jsonVal.isBool()) if (jsonVal.isBool())
return TriStateBool(jsonVal.toBool()); return jsonVal.toBool();
if (!jsonVal.isNull()) return std::nullopt;
qDebug() << Q_FUNC_INFO << "Incorrect value" << jsonVal.toVariant();
return TriStateBool::Undefined;
} }
QJsonValue triStateBoolToJsonValue(const TriStateBool triStateBool) QJsonValue toJsonValue(const std::optional<bool> boolValue)
{ {
switch (static_cast<signed char>(triStateBool)) return boolValue.has_value() ? *boolValue : QJsonValue {};
{
case 0: return false;
case 1: return true;
default: return {};
}
} }
TriStateBool addPausedLegacyToTriStateBool(const int val) std::optional<bool> addPausedLegacyToOptionalBool(const int val)
{ {
switch (val) switch (val)
{ {
case 1: return TriStateBool::True; // always case 1:
case 2: return TriStateBool::False; // never return true; // always
default: return TriStateBool::Undefined; // default case 2:
return false; // never
default:
return std::nullopt; // default
} }
} }
int triStateBoolToAddPausedLegacy(const TriStateBool triStateBool) int toAddPausedLegacy(const std::optional<bool> boolValue)
{ {
switch (static_cast<signed char>(triStateBool)) if (!boolValue.has_value())
{ return 0; // default
case 0: return 2; // never
case 1: return 1; // always return (*boolValue ? 1 /* always */ : 2 /* never */);
default: return 0; // default
}
} }
boost::optional<BitTorrent::TorrentContentLayout> jsonValueToContentLayout(const QJsonValue &jsonVal) std::optional<BitTorrent::TorrentContentLayout> jsonValueToContentLayout(const QJsonValue &jsonVal)
{ {
const QString str = jsonVal.toString(); const QString str = jsonVal.toString();
if (str.isEmpty()) if (str.isEmpty())
return {}; return std::nullopt;
return Utils::String::toEnum(str, BitTorrent::TorrentContentLayout::Original); return Utils::String::toEnum(str, BitTorrent::TorrentContentLayout::Original);
} }
QJsonValue contentLayoutToJsonValue(const boost::optional<BitTorrent::TorrentContentLayout> contentLayout) QJsonValue contentLayoutToJsonValue(const std::optional<BitTorrent::TorrentContentLayout> contentLayout)
{ {
if (!contentLayout) if (!contentLayout)
return {}; return {};
@@ -142,8 +134,8 @@ namespace RSS
QString savePath; QString savePath;
QString category; QString category;
TriStateBool addPaused = TriStateBool::Undefined; std::optional<bool> addPaused;
boost::optional<BitTorrent::TorrentContentLayout> contentLayout; std::optional<BitTorrent::TorrentContentLayout> contentLayout;
bool smartFilter = false; bool smartFilter = false;
QStringList previouslyMatchedEpisodes; QStringList previouslyMatchedEpisodes;
@@ -477,7 +469,7 @@ QJsonObject AutoDownloadRule::toJsonObject() const
, {Str_AssignedCategory, assignedCategory()} , {Str_AssignedCategory, assignedCategory()}
, {Str_LastMatch, lastMatch().toString(Qt::RFC2822Date)} , {Str_LastMatch, lastMatch().toString(Qt::RFC2822Date)}
, {Str_IgnoreDays, ignoreDays()} , {Str_IgnoreDays, ignoreDays()}
, {Str_AddPaused, triStateBoolToJsonValue(addPaused())} , {Str_AddPaused, toJsonValue(addPaused())}
, {Str_ContentLayout, contentLayoutToJsonValue(torrentContentLayout())} , {Str_ContentLayout, contentLayoutToJsonValue(torrentContentLayout())}
, {Str_SmartFilter, useSmartFilter()} , {Str_SmartFilter, useSmartFilter()}
, {Str_PreviouslyMatched, QJsonArray::fromStringList(previouslyMatchedEpisodes())}}; , {Str_PreviouslyMatched, QJsonArray::fromStringList(previouslyMatchedEpisodes())}};
@@ -494,7 +486,7 @@ AutoDownloadRule AutoDownloadRule::fromJsonObject(const QJsonObject &jsonObj, co
rule.setEnabled(jsonObj.value(Str_Enabled).toBool(true)); rule.setEnabled(jsonObj.value(Str_Enabled).toBool(true));
rule.setSavePath(jsonObj.value(Str_SavePath).toString()); rule.setSavePath(jsonObj.value(Str_SavePath).toString());
rule.setCategory(jsonObj.value(Str_AssignedCategory).toString()); rule.setCategory(jsonObj.value(Str_AssignedCategory).toString());
rule.setAddPaused(jsonValueToTriStateBool(jsonObj.value(Str_AddPaused))); rule.setAddPaused(toOptionalBool(jsonObj.value(Str_AddPaused)));
// TODO: The following code is deprecated. Replace with the commented one after several releases in 4.4.x. // TODO: The following code is deprecated. Replace with the commented one after several releases in 4.4.x.
// === BEGIN DEPRECATED CODE === // // === BEGIN DEPRECATED CODE === //
@@ -504,12 +496,14 @@ AutoDownloadRule AutoDownloadRule::fromJsonObject(const QJsonObject &jsonObj, co
} }
else else
{ {
const TriStateBool createSubfolder = jsonValueToTriStateBool(jsonObj.value(Str_CreateSubfolder)); const std::optional<bool> createSubfolder = toOptionalBool(jsonObj.value(Str_CreateSubfolder));
boost::optional<BitTorrent::TorrentContentLayout> contentLayout; std::optional<BitTorrent::TorrentContentLayout> contentLayout;
if (createSubfolder == TriStateBool::True) if (createSubfolder.has_value())
contentLayout = BitTorrent::TorrentContentLayout::Original; {
else if (createSubfolder == TriStateBool::False) contentLayout = (*createSubfolder
contentLayout = BitTorrent::TorrentContentLayout::NoSubfolder; ? BitTorrent::TorrentContentLayout::Original
: BitTorrent::TorrentContentLayout::NoSubfolder);
}
rule.setTorrentContentLayout(contentLayout); rule.setTorrentContentLayout(contentLayout);
} }
@@ -556,7 +550,7 @@ QVariantHash AutoDownloadRule::toLegacyDict() const
{"enabled", isEnabled()}, {"enabled", isEnabled()},
{"category_assigned", assignedCategory()}, {"category_assigned", assignedCategory()},
{"use_regex", useRegex()}, {"use_regex", useRegex()},
{"add_paused", triStateBoolToAddPausedLegacy(addPaused())}, {"add_paused", toAddPausedLegacy(addPaused())},
{"episode_filter", episodeFilter()}, {"episode_filter", episodeFilter()},
{"last_match", lastMatch()}, {"last_match", lastMatch()},
{"ignore_days", ignoreDays()}}; {"ignore_days", ignoreDays()}};
@@ -574,7 +568,7 @@ AutoDownloadRule AutoDownloadRule::fromLegacyDict(const QVariantHash &dict)
rule.setEnabled(dict.value("enabled", false).toBool()); rule.setEnabled(dict.value("enabled", false).toBool());
rule.setSavePath(dict.value("save_path").toString()); rule.setSavePath(dict.value("save_path").toString());
rule.setCategory(dict.value("category_assigned").toString()); rule.setCategory(dict.value("category_assigned").toString());
rule.setAddPaused(addPausedLegacyToTriStateBool(dict.value("add_paused").toInt())); rule.setAddPaused(addPausedLegacyToOptionalBool(dict.value("add_paused").toInt()));
rule.setLastMatch(dict.value("last_match").toDateTime()); rule.setLastMatch(dict.value("last_match").toDateTime());
rule.setIgnoreDays(dict.value("ignore_days").toInt()); rule.setIgnoreDays(dict.value("ignore_days").toInt());
@@ -639,22 +633,22 @@ void AutoDownloadRule::setSavePath(const QString &savePath)
m_dataPtr->savePath = Utils::Fs::toUniformPath(savePath); m_dataPtr->savePath = Utils::Fs::toUniformPath(savePath);
} }
TriStateBool AutoDownloadRule::addPaused() const std::optional<bool> AutoDownloadRule::addPaused() const
{ {
return m_dataPtr->addPaused; return m_dataPtr->addPaused;
} }
void AutoDownloadRule::setAddPaused(const TriStateBool addPaused) void AutoDownloadRule::setAddPaused(const std::optional<bool> addPaused)
{ {
m_dataPtr->addPaused = addPaused; m_dataPtr->addPaused = addPaused;
} }
boost::optional<BitTorrent::TorrentContentLayout> AutoDownloadRule::torrentContentLayout() const std::optional<BitTorrent::TorrentContentLayout> AutoDownloadRule::torrentContentLayout() const
{ {
return m_dataPtr->contentLayout; return m_dataPtr->contentLayout;
} }
void AutoDownloadRule::setTorrentContentLayout(const boost::optional<BitTorrent::TorrentContentLayout> contentLayout) void AutoDownloadRule::setTorrentContentLayout(const std::optional<BitTorrent::TorrentContentLayout> contentLayout)
{ {
m_dataPtr->contentLayout = contentLayout; m_dataPtr->contentLayout = contentLayout;
} }

View File

@@ -29,7 +29,7 @@
#pragma once #pragma once
#include <boost/optional.hpp> #include <optional>
#include <QSharedDataPointer> #include <QSharedDataPointer>
#include <QVariant> #include <QVariant>
@@ -40,8 +40,6 @@ class QDateTime;
class QJsonObject; class QJsonObject;
class QRegularExpression; class QRegularExpression;
class TriStateBool;
namespace RSS namespace RSS
{ {
struct AutoDownloadRuleData; struct AutoDownloadRuleData;
@@ -81,10 +79,10 @@ namespace RSS
QString savePath() const; QString savePath() const;
void setSavePath(const QString &savePath); void setSavePath(const QString &savePath);
TriStateBool addPaused() const; std::optional<bool> addPaused() const;
void setAddPaused(TriStateBool addPaused); void setAddPaused(std::optional<bool> addPaused);
boost::optional<BitTorrent::TorrentContentLayout> torrentContentLayout() const; std::optional<BitTorrent::TorrentContentLayout> torrentContentLayout() const;
void setTorrentContentLayout(boost::optional<BitTorrent::TorrentContentLayout> contentLayout); void setTorrentContentLayout(std::optional<BitTorrent::TorrentContentLayout> contentLayout);
QString assignedCategory() const; QString assignedCategory() const;
void setCategory(const QString &category); void setCategory(const QString &category);

View File

@@ -63,10 +63,10 @@ using namespace RSS;
QPointer<Session> Session::m_instance = nullptr; QPointer<Session> Session::m_instance = nullptr;
Session::Session() Session::Session()
: m_processingEnabled(SettingsStorage::instance()->loadValue(SettingsKey_ProcessingEnabled, false).toBool()) : m_processingEnabled(SettingsStorage::instance()->loadValue(SettingsKey_ProcessingEnabled, false))
, m_workingThread(new QThread(this)) , m_workingThread(new QThread(this))
, m_refreshInterval(SettingsStorage::instance()->loadValue(SettingsKey_RefreshInterval, 30).toInt()) , m_refreshInterval(SettingsStorage::instance()->loadValue(SettingsKey_RefreshInterval, 30))
, m_maxArticlesPerFeed(SettingsStorage::instance()->loadValue(SettingsKey_MaxArticlesPerFeed, 50).toInt()) , m_maxArticlesPerFeed(SettingsStorage::instance()->loadValue(SettingsKey_MaxArticlesPerFeed, 50))
{ {
Q_ASSERT(!m_instance); // only one instance is allowed Q_ASSERT(!m_instance); // only one instance is allowed
m_instance = this; m_instance = this;
@@ -362,8 +362,8 @@ void Session::loadFolder(const QJsonObject &jsonObj, Folder *folder)
void Session::loadLegacy() void Session::loadLegacy()
{ {
const QStringList legacyFeedPaths = SettingsStorage::instance()->loadValue("Rss/streamList").toStringList(); const auto legacyFeedPaths = SettingsStorage::instance()->loadValue<QStringList>("Rss/streamList");
const QStringList feedAliases = SettingsStorage::instance()->loadValue("Rss/streamAlias").toStringList(); const auto feedAliases = SettingsStorage::instance()->loadValue<QStringList>("Rss/streamAlias");
if (legacyFeedPaths.size() != feedAliases.size()) if (legacyFeedPaths.size() != feedAliases.size())
{ {
Logger::instance()->addMessage("Corrupted RSS list, not loading it.", Log::WARNING); Logger::instance()->addMessage("Corrupted RSS list, not loading it.", Log::WARNING);

View File

@@ -366,12 +366,12 @@ void ScanFoldersModel::addTorrentsToSession(const QStringList &pathList)
if (downloadInWatchFolder(file)) if (downloadInWatchFolder(file))
{ {
params.savePath = QFileInfo(file).dir().path(); params.savePath = QFileInfo(file).dir().path();
params.useAutoTMM = TriStateBool::False; params.useAutoTMM = false;
} }
else if (!downloadInDefaultFolder(file)) else if (!downloadInDefaultFolder(file))
{ {
params.savePath = downloadPathTorrentFolder(file); params.savePath = downloadPathTorrentFolder(file);
params.useAutoTMM = TriStateBool::False; params.useAutoTMM = false;
} }
if (file.endsWith(".magnet", Qt::CaseInsensitive)) if (file.endsWith(".magnet", Qt::CaseInsensitive))

View File

@@ -153,8 +153,7 @@ namespace
SettingsStorage *SettingsStorage::m_instance = nullptr; SettingsStorage *SettingsStorage::m_instance = nullptr;
SettingsStorage::SettingsStorage() SettingsStorage::SettingsStorage()
: m_data{TransactionalSettings(QLatin1String("qBittorrent")).read()} : m_data {TransactionalSettings(QLatin1String("qBittorrent")).read()}
, m_dirty(false)
{ {
m_timer.setSingleShot(true); m_timer.setSingleShot(true);
m_timer.setInterval(5 * 1000); m_timer.setInterval(5 * 1000);
@@ -200,14 +199,14 @@ bool SettingsStorage::save()
return true; return true;
} }
QVariant SettingsStorage::loadValue(const QString &key, const QVariant &defaultValue) const QVariant SettingsStorage::loadValueImpl(const QString &key, const QVariant &defaultValue) const
{ {
const QString realKey = mapKey(key); const QString realKey = mapKey(key);
const QReadLocker locker(&m_lock); const QReadLocker locker(&m_lock);
return m_data.value(realKey, defaultValue); return m_data.value(realKey, defaultValue);
} }
void SettingsStorage::storeValue(const QString &key, const QVariant &value) void SettingsStorage::storeValueImpl(const QString &key, const QVariant &value)
{ {
const QString realKey = mapKey(key); const QString realKey = mapKey(key);
const QWriteLocker locker(&m_lock); const QWriteLocker locker(&m_lock);
@@ -295,7 +294,11 @@ QString TransactionalSettings::deserialize(const QString &name, QVariantHash &da
// or that we don't touch directly in this code (eg disabled by ifdef). This ensures // or that we don't touch directly in this code (eg disabled by ifdef). This ensures
// that they will be copied over when save our settings to disk. // that they will be copied over when save our settings to disk.
for (const QString &key : asConst(settings->allKeys())) for (const QString &key : asConst(settings->allKeys()))
data.insert(key, settings->value(key)); {
const QVariant value = settings->value(key);
if (value.isValid())
data[key] = value;
}
return settings->fileName(); return settings->fileName();
} }

View File

@@ -29,11 +29,15 @@
#pragma once #pragma once
#include <type_traits>
#include <QObject> #include <QObject>
#include <QReadWriteLock> #include <QReadWriteLock>
#include <QTimer> #include <QTimer>
#include <QVariantHash> #include <QVariantHash>
#include "utils/string.h"
class SettingsStorage : public QObject class SettingsStorage : public QObject
{ {
Q_OBJECT Q_OBJECT
@@ -45,18 +49,48 @@ public:
static void freeInstance(); static void freeInstance();
static SettingsStorage *instance(); static SettingsStorage *instance();
QVariant loadValue(const QString &key, const QVariant &defaultValue = {}) const; template <typename T>
void storeValue(const QString &key, const QVariant &value); T loadValue(const QString &key, const T &defaultValue = {}) const
{
if constexpr (std::is_enum_v<T>)
{
const auto value = loadValueImpl(key).toString();
return Utils::String::toEnum(value, defaultValue);
}
else if constexpr (std::is_same_v<T, QVariant>)
{
return loadValueImpl(key, defaultValue);
}
else
{
const QVariant value = loadValueImpl(key);
// check if retrieved value is convertible to T
return value.template canConvert<T>() ? value.template value<T>() : defaultValue;
}
}
template <typename T>
void storeValue(const QString &key, const T &value)
{
if constexpr (std::is_enum_v<T>)
storeValueImpl(key, Utils::String::fromEnum(value));
else
storeValueImpl(key, value);
}
void removeValue(const QString &key); void removeValue(const QString &key);
public slots: public slots:
bool save(); bool save();
private: private:
QVariant loadValueImpl(const QString &key, const QVariant &defaultValue = {}) const;
void storeValueImpl(const QString &key, const QVariant &value);
static SettingsStorage *m_instance; static SettingsStorage *m_instance;
bool m_dirty = false;
QVariantHash m_data; QVariantHash m_data;
bool m_dirty;
QTimer m_timer; QTimer m_timer;
mutable QReadWriteLock m_lock; mutable QReadWriteLock m_lock;
}; };

View File

@@ -28,82 +28,81 @@
#pragma once #pragma once
#include <type_traits>
#include <QMetaEnum>
#include <QString> #include <QString>
#include "settingsstorage.h" #include "settingsstorage.h"
#include "utils/string.h"
// This is a thin/handy wrapper over `SettingsStorage`. Use it when store/load value
// rarely occurs, otherwise use `CachedSettingValue`.
template <typename T>
class SettingValue
{
public:
explicit SettingValue(const char *keyName)
: m_keyName {QLatin1String {keyName}}
{
}
T get(const T &defaultValue = {}) const
{
return SettingsStorage::instance()->loadValue(m_keyName, defaultValue);
}
operator T() const
{
return get();
}
SettingValue<T> &operator=(const T &value)
{
SettingsStorage::instance()->storeValue(m_keyName, value);
return *this;
}
private:
const QString m_keyName;
};
template <typename T> template <typename T>
class CachedSettingValue class CachedSettingValue
{ {
public: public:
explicit CachedSettingValue(const char *keyName, const T &defaultValue = T()) explicit CachedSettingValue(const char *keyName, const T &defaultValue = {})
: m_keyName(QLatin1String(keyName)) : m_setting {keyName}
, m_value(loadValue(defaultValue)) , m_cache {m_setting.get(defaultValue)}
{ {
} }
// The signature of the ProxyFunc should be equivalent to the following: // The signature of the ProxyFunc should be equivalent to the following:
// T proxyFunc(const T &a); // T proxyFunc(const T &a);
template <typename ProxyFunc> template <typename ProxyFunc>
explicit CachedSettingValue(const char *keyName, const T &defaultValue explicit CachedSettingValue(const char *keyName, const T &defaultValue, ProxyFunc &&proxyFunc)
, ProxyFunc &&proxyFunc) : m_setting {keyName}
: m_keyName(QLatin1String(keyName)) , m_cache {proxyFunc(m_setting.get(defaultValue))}
, m_value(proxyFunc(loadValue(defaultValue)))
{ {
} }
T value() const T get() const
{ {
return m_value; return m_cache;
} }
operator T() const operator T() const
{ {
return value(); return get();
} }
CachedSettingValue<T> &operator=(const T &newValue) CachedSettingValue<T> &operator=(const T &value)
{ {
if (m_value == newValue) if (m_cache == value)
return *this; return *this;
m_value = newValue; m_setting = value;
storeValue(m_value); m_cache = value;
return *this; return *this;
} }
private: private:
// regular load/save pair SettingValue<T> m_setting;
template <typename U, typename std::enable_if_t<!std::is_enum<U>::value, int> = 0> T m_cache;
U loadValue(const U &defaultValue)
{
return SettingsStorage::instance()->loadValue(m_keyName, defaultValue).template value<T>();
}
template <typename U, typename std::enable_if_t<!std::is_enum<U>::value, int> = 0>
void storeValue(const U &value)
{
SettingsStorage::instance()->storeValue(m_keyName, value);
}
// load/save pair for an enum
// saves literal value of the enum constant, obtained from QMetaEnum
template <typename U, typename std::enable_if_t<std::is_enum<U>::value, int> = 0>
U loadValue(const U &defaultValue)
{
return Utils::String::toEnum(SettingsStorage::instance()->loadValue(m_keyName).toString(), defaultValue);
}
template <typename U, typename std::enable_if_t<std::is_enum<U>::value, int> = 0>
void storeValue(const U &value)
{
SettingsStorage::instance()->storeValue(m_keyName, Utils::String::fromEnum(value));
}
const QString m_keyName;
T m_value;
}; };

View File

@@ -73,7 +73,7 @@ void TorrentFileGuard::markAsAddedToSession()
TorrentFileGuard::AutoDeleteMode TorrentFileGuard::autoDeleteMode() TorrentFileGuard::AutoDeleteMode TorrentFileGuard::autoDeleteMode()
{ {
return autoDeleteModeSetting(); return autoDeleteModeSetting().get(AutoDeleteMode::Never);
} }
void TorrentFileGuard::setAutoDeleteMode(TorrentFileGuard::AutoDeleteMode mode) void TorrentFileGuard::setAutoDeleteMode(TorrentFileGuard::AutoDeleteMode mode)
@@ -81,8 +81,8 @@ void TorrentFileGuard::setAutoDeleteMode(TorrentFileGuard::AutoDeleteMode mode)
autoDeleteModeSetting() = mode; autoDeleteModeSetting() = mode;
} }
CachedSettingValue<TorrentFileGuard::AutoDeleteMode> &TorrentFileGuard::autoDeleteModeSetting() SettingValue<TorrentFileGuard::AutoDeleteMode> &TorrentFileGuard::autoDeleteModeSetting()
{ {
static CachedSettingValue<AutoDeleteMode> setting("Core/AutoDeleteAddedTorrentFile", AutoDeleteMode::Never); static SettingValue<AutoDeleteMode> setting {"Core/AutoDeleteAddedTorrentFile"};
return setting; return setting;
} }

View File

@@ -31,7 +31,7 @@
#include <QObject> #include <QObject>
#include <QString> #include <QString>
template <typename T> class CachedSettingValue; template <typename T> class SettingValue;
/// Utility class to defer file deletion /// Utility class to defer file deletion
class FileGuard class FileGuard
@@ -75,7 +75,7 @@ public:
private: private:
TorrentFileGuard(const QString &path, AutoDeleteMode mode); TorrentFileGuard(const QString &path, AutoDeleteMode mode);
static CachedSettingValue<AutoDeleteMode> &autoDeleteModeSetting(); static SettingValue<AutoDeleteMode> &autoDeleteModeSetting();
Q_ENUM(AutoDeleteMode) Q_ENUM(AutoDeleteMode)
AutoDeleteMode m_mode; AutoDeleteMode m_mode;

View File

@@ -29,7 +29,7 @@
#include "torrentfilter.h" #include "torrentfilter.h"
#include "bittorrent/infohash.h" #include "bittorrent/infohash.h"
#include "bittorrent/torrenthandle.h" #include "bittorrent/torrent.h"
const QString TorrentFilter::AnyCategory; const QString TorrentFilter::AnyCategory;
const InfoHashSet TorrentFilter::AnyHash {{}}; const InfoHashSet TorrentFilter::AnyHash {{}};
@@ -47,7 +47,7 @@ const TorrentFilter TorrentFilter::StalledUploadingTorrent(TorrentFilter::Stalle
const TorrentFilter TorrentFilter::StalledDownloadingTorrent(TorrentFilter::StalledDownloading); const TorrentFilter TorrentFilter::StalledDownloadingTorrent(TorrentFilter::StalledDownloading);
const TorrentFilter TorrentFilter::ErroredTorrent(TorrentFilter::Errored); const TorrentFilter TorrentFilter::ErroredTorrent(TorrentFilter::Errored);
using BitTorrent::TorrentHandle; using BitTorrent::Torrent;
TorrentFilter::TorrentFilter(const Type type, const InfoHashSet &hashSet, const QString &category, const QString &tag) TorrentFilter::TorrentFilter(const Type type, const InfoHashSet &hashSet, const QString &category, const QString &tag)
: m_type(type) : m_type(type)
@@ -146,14 +146,14 @@ bool TorrentFilter::setTag(const QString &tag)
return false; return false;
} }
bool TorrentFilter::match(const TorrentHandle *const torrent) const bool TorrentFilter::match(const Torrent *const torrent) const
{ {
if (!torrent) return false; if (!torrent) return false;
return (matchState(torrent) && matchHash(torrent) && matchCategory(torrent) && matchTag(torrent)); return (matchState(torrent) && matchHash(torrent) && matchCategory(torrent) && matchTag(torrent));
} }
bool TorrentFilter::matchState(const BitTorrent::TorrentHandle *const torrent) const bool TorrentFilter::matchState(const BitTorrent::Torrent *const torrent) const
{ {
switch (m_type) switch (m_type)
{ {
@@ -187,21 +187,21 @@ bool TorrentFilter::matchState(const BitTorrent::TorrentHandle *const torrent) c
} }
} }
bool TorrentFilter::matchHash(const BitTorrent::TorrentHandle *const torrent) const bool TorrentFilter::matchHash(const BitTorrent::Torrent *const torrent) const
{ {
if (m_hashSet == AnyHash) return true; if (m_hashSet == AnyHash) return true;
return m_hashSet.contains(torrent->hash()); return m_hashSet.contains(torrent->hash());
} }
bool TorrentFilter::matchCategory(const BitTorrent::TorrentHandle *const torrent) const bool TorrentFilter::matchCategory(const BitTorrent::Torrent *const torrent) const
{ {
if (m_category.isNull()) return true; if (m_category.isNull()) return true;
return (torrent->belongsToCategory(m_category)); return (torrent->belongsToCategory(m_category));
} }
bool TorrentFilter::matchTag(const BitTorrent::TorrentHandle *const torrent) const bool TorrentFilter::matchTag(const BitTorrent::Torrent *const torrent) const
{ {
// Empty tag is a special value to indicate we're filtering for untagged torrents. // Empty tag is a special value to indicate we're filtering for untagged torrents.
if (m_tag.isNull()) return true; if (m_tag.isNull()) return true;

View File

@@ -35,7 +35,7 @@
namespace BitTorrent namespace BitTorrent
{ {
class TorrentHandle; class Torrent;
} }
using InfoHashSet = QSet<BitTorrent::InfoHash>; using InfoHashSet = QSet<BitTorrent::InfoHash>;
@@ -88,13 +88,13 @@ public:
bool setCategory(const QString &category); bool setCategory(const QString &category);
bool setTag(const QString &tag); bool setTag(const QString &tag);
bool match(const BitTorrent::TorrentHandle *torrent) const; bool match(const BitTorrent::Torrent *torrent) const;
private: private:
bool matchState(const BitTorrent::TorrentHandle *torrent) const; bool matchState(const BitTorrent::Torrent *torrent) const;
bool matchHash(const BitTorrent::TorrentHandle *torrent) const; bool matchHash(const BitTorrent::Torrent *torrent) const;
bool matchCategory(const BitTorrent::TorrentHandle *torrent) const; bool matchCategory(const BitTorrent::Torrent *torrent) const;
bool matchTag(const BitTorrent::TorrentHandle *torrent) const; bool matchTag(const BitTorrent::Torrent *torrent) const;
Type m_type {All}; Type m_type {All};
QString m_category; QString m_category;

View File

@@ -1,4 +1,4 @@
/* /*
* Bittorrent Client using Qt and libtorrent. * Bittorrent Client using Qt and libtorrent.
* Copyright (C) 2015 Mike Tzou * Copyright (C) 2015 Mike Tzou
* *
@@ -28,16 +28,12 @@
#pragma once #pragma once
// This file must be encoded in "UTF-8 with BOM"
#ifdef _MSC_VER
#pragma execution_character_set("utf-8")
#endif
// Because of the poor handling of UTF-8 characters in MSVC (emits warning C4819), // Because of the poor handling of UTF-8 characters in MSVC (emits warning C4819),
// we put all problematic UTF-8 chars/strings in this file. // we put all problematic UTF-8 chars/strings in this file.
// See issue #3059 for more details (https://github.com/qbittorrent/qBittorrent/issues/3059). // See issue #3059 for more details (https://github.com/qbittorrent/qBittorrent/issues/3059).
const char C_COPYRIGHT[] = "©"; const char C_COPYRIGHT[] = "©";
const char C_INEQUALITY[] = "";
const char C_INFINITY[] = ""; const char C_INFINITY[] = "";
const char C_NON_BREAKING_SPACE[] = " "; const char C_NON_BREAKING_SPACE[] = " ";
const char C_THIN_SPACE[] = ""; const char C_THIN_SPACE[] = "";
@@ -45,6 +41,7 @@ const char C_UTP[] = "μTP";
const char C_LOCALE_ARABIC[] = "عربي"; const char C_LOCALE_ARABIC[] = "عربي";
const char C_LOCALE_ARMENIAN[] = "Հայերեն"; const char C_LOCALE_ARMENIAN[] = "Հայերեն";
const char C_LOCALE_AZERBAIJANI[] = "Azərbaycan dili";
const char C_LOCALE_BASQUE[] = "Euskara"; const char C_LOCALE_BASQUE[] = "Euskara";
const char C_LOCALE_BULGARIAN[] = "Български"; const char C_LOCALE_BULGARIAN[] = "Български";
const char C_LOCALE_BYELORUSSIAN[] = "Беларуская"; const char C_LOCALE_BYELORUSSIAN[] = "Беларуская";
@@ -57,9 +54,10 @@ const char C_LOCALE_CZECH[] = "Čeština";
const char C_LOCALE_DANISH[] = "Dansk"; const char C_LOCALE_DANISH[] = "Dansk";
const char C_LOCALE_DUTCH[] = "Nederlands"; const char C_LOCALE_DUTCH[] = "Nederlands";
const char C_LOCALE_ENGLISH[] = "English"; const char C_LOCALE_ENGLISH[] = "English";
const char C_LOCALE_ENGLISH_AUSTRALIA[] = "English(Australia)"; const char C_LOCALE_ENGLISH_AUSTRALIA[] = "English (Australia)";
const char C_LOCALE_ENGLISH_UNITEDKINGDOM[] = "English(United Kingdom)"; const char C_LOCALE_ENGLISH_UNITEDKINGDOM[] = "English (United Kingdom)";
const char C_LOCALE_ESPERANTO[] = "Esperanto"; const char C_LOCALE_ESPERANTO[] = "Esperanto";
const char C_LOCALE_ESTONIAN[] = "Eesti, eesti keel";
const char C_LOCALE_FINNISH[] = "Suomi"; const char C_LOCALE_FINNISH[] = "Suomi";
const char C_LOCALE_FRENCH[] = "Français"; const char C_LOCALE_FRENCH[] = "Français";
const char C_LOCALE_GALICIAN[] = "Galego"; const char C_LOCALE_GALICIAN[] = "Galego";
@@ -74,8 +72,8 @@ const char C_LOCALE_INDONESIAN[] = "Bahasa Indonesia";
const char C_LOCALE_ITALIAN[] = "Italiano"; const char C_LOCALE_ITALIAN[] = "Italiano";
const char C_LOCALE_JAPANESE[] = "日本語"; const char C_LOCALE_JAPANESE[] = "日本語";
const char C_LOCALE_KOREAN[] = "한글"; const char C_LOCALE_KOREAN[] = "한글";
const char C_LOCALE_LATGALIAN[] = "latgalīšu volūda"; const char C_LOCALE_LATGALIAN[] = "Latgalīšu volūda";
const char C_LOCALE_LATVIAN[] = "latviešu valoda"; const char C_LOCALE_LATVIAN[] = "Latviešu valoda";
const char C_LOCALE_LITHUANIAN[] = "Lietuvių"; const char C_LOCALE_LITHUANIAN[] = "Lietuvių";
const char C_LOCALE_MALAY[] = "بهاس ملايو"; const char C_LOCALE_MALAY[] = "بهاس ملايو";
const char C_LOCALE_NORWEGIAN[] = "Norsk"; const char C_LOCALE_NORWEGIAN[] = "Norsk";
@@ -93,4 +91,4 @@ const char C_LOCALE_SWEDISH[] = "Svenska";
const char C_LOCALE_TURKISH[] = "Türkçe"; const char C_LOCALE_TURKISH[] = "Türkçe";
const char C_LOCALE_UKRAINIAN[] = "Українська"; const char C_LOCALE_UKRAINIAN[] = "Українська";
const char C_LOCALE_UZBEK[] = "أۇزبېك‎"; const char C_LOCALE_UZBEK[] = "أۇزبېك‎";
const char C_LOCALE_VIETNAMESE[] = "tiếng Việt"; const char C_LOCALE_VIETNAMESE[] = "Tiếng Việt";

View File

@@ -33,15 +33,12 @@
class QByteArray; class QByteArray;
namespace Utils namespace Utils::ByteArray
{ {
namespace ByteArray
{
// Mimic QString::splitRef(sep, behavior) // Mimic QString::splitRef(sep, behavior)
QVector<QByteArray> splitToViews(const QByteArray &in, const QByteArray &sep, const QString::SplitBehavior behavior = QString::KeepEmptyParts); QVector<QByteArray> splitToViews(const QByteArray &in, const QByteArray &sep, const QString::SplitBehavior behavior = QString::KeepEmptyParts);
// Mimic QByteArray::mid(pos, len) but instead of returning a full-copy, // Mimic QByteArray::mid(pos, len) but instead of returning a full-copy,
// we only return a partial view // we only return a partial view
const QByteArray midView(const QByteArray &in, int pos, int len = -1); const QByteArray midView(const QByteArray &in, int pos, int len = -1);
}
} }

View File

@@ -33,10 +33,8 @@
#include "base/utils/version.h" #include "base/utils/version.h"
namespace Utils namespace Utils::ForeignApps
{ {
namespace ForeignApps
{
struct PythonInfo struct PythonInfo
{ {
using Version = Utils::Version<quint8, 3, 1>; using Version = Utils::Version<quint8, 3, 1>;
@@ -49,5 +47,4 @@ namespace Utils
}; };
PythonInfo pythonInfo(); PythonInfo pythonInfo();
}
} }

View File

@@ -55,6 +55,7 @@
#include <QDirIterator> #include <QDirIterator>
#include <QFile> #include <QFile>
#include <QFileInfo> #include <QFileInfo>
#include <QMimeDatabase>
#include <QStorageInfo> #include <QStorageInfo>
#include <QRegularExpression> #include <QRegularExpression>
@@ -76,9 +77,14 @@ QString Utils::Fs::toUniformPath(const QString &path)
*/ */
QString Utils::Fs::fileExtension(const QString &filename) QString Utils::Fs::fileExtension(const QString &filename)
{ {
const QString ext = QString(filename).remove(QB_EXT); const QString name = filename.endsWith(QB_EXT)
const int pointIndex = ext.lastIndexOf('.'); #if (QT_VERSION >= QT_VERSION_CHECK(5, 10, 0))
return (pointIndex >= 0) ? ext.mid(pointIndex + 1) : QString(); ? filename.chopped(QB_EXT.length())
#else
? filename.left(filename.length() - QB_EXT.length())
#endif
: filename;
return QMimeDatabase().suffixForFileName(name);
} }
QString Utils::Fs::fileName(const QString &filePath) QString Utils::Fs::fileName(const QString &filePath)
@@ -95,7 +101,7 @@ QString Utils::Fs::folderName(const QString &filePath)
const QString path = toUniformPath(filePath); const QString path = toUniformPath(filePath);
const int slashIndex = path.lastIndexOf('/'); const int slashIndex = path.lastIndexOf('/');
if (slashIndex == -1) if (slashIndex == -1)
return path; return {};
return path.left(slashIndex); return path.left(slashIndex);
} }
@@ -267,8 +273,6 @@ bool Utils::Fs::isValidFileSystemName(const QString &name, const bool allowSepar
qint64 Utils::Fs::freeDiskSpaceOnPath(const QString &path) qint64 Utils::Fs::freeDiskSpaceOnPath(const QString &path)
{ {
if (path.isEmpty()) return -1;
return QStorageInfo(path).bytesAvailable(); return QStorageInfo(path).bytesAvailable();
} }

View File

@@ -34,10 +34,8 @@
#include <QString> #include <QString>
namespace Utils namespace Utils::Fs
{ {
namespace Fs
{
/** /**
* Converts a path to a string suitable for display. * Converts a path to a string suitable for display.
* This function makes sure the directory separator used is consistent * This function makes sure the directory separator used is consistent
@@ -76,5 +74,4 @@ namespace Utils
#if !defined Q_OS_HAIKU #if !defined Q_OS_HAIKU
bool isNetworkFileSystem(const QString &path); bool isNetworkFileSystem(const QString &path);
#endif #endif
}
} }

View File

@@ -31,11 +31,8 @@
class QByteArray; class QByteArray;
namespace Utils namespace Utils::Gzip
{ {
namespace Gzip
{
QByteArray compress(const QByteArray &data, int level = 6, bool *ok = nullptr); QByteArray compress(const QByteArray &data, int level = 6, bool *ok = nullptr);
QByteArray decompress(const QByteArray &data, bool *ok = nullptr); QByteArray decompress(const QByteArray &data, bool *ok = nullptr);
}
} }

View File

@@ -60,18 +60,3 @@ Utils::IO::FileDeviceOutputIterator &Utils::IO::FileDeviceOutputIterator::operat
} }
return *this; return *this;
} }
Utils::IO::FileDeviceOutputIterator &Utils::IO::FileDeviceOutputIterator::operator*()
{
return *this;
}
Utils::IO::FileDeviceOutputIterator &Utils::IO::FileDeviceOutputIterator::operator++()
{
return *this;
}
Utils::IO::FileDeviceOutputIterator &Utils::IO::FileDeviceOutputIterator::operator++(int)
{
return *this;
}

View File

@@ -34,30 +34,44 @@
class QByteArray; class QByteArray;
class QFileDevice; class QFileDevice;
namespace Utils namespace Utils::IO
{ {
namespace IO
{
// A wrapper class that satisfy LegacyOutputIterator requirement // A wrapper class that satisfy LegacyOutputIterator requirement
class FileDeviceOutputIterator class FileDeviceOutputIterator
: public std::iterator<std::output_iterator_tag, void, void, void, void>
{ {
public: public:
// std::iterator_traits
using iterator_category = std::output_iterator_tag;
using difference_type = void;
using value_type = void;
using pointer = void;
using reference = void;
explicit FileDeviceOutputIterator(QFileDevice &device, const int bufferSize = (4 * 1024)); explicit FileDeviceOutputIterator(QFileDevice &device, const int bufferSize = (4 * 1024));
FileDeviceOutputIterator(const FileDeviceOutputIterator &other) = default; FileDeviceOutputIterator(const FileDeviceOutputIterator &other) = default;
~FileDeviceOutputIterator(); ~FileDeviceOutputIterator();
// mimic std::ostream_iterator behavior // mimic std::ostream_iterator behavior
FileDeviceOutputIterator &operator=(char c); FileDeviceOutputIterator &operator=(char c);
// TODO: make these `constexpr` in C++17
FileDeviceOutputIterator &operator*(); constexpr FileDeviceOutputIterator &operator*()
FileDeviceOutputIterator &operator++(); {
FileDeviceOutputIterator &operator++(int); return *this;
}
constexpr FileDeviceOutputIterator &operator++()
{
return *this;
}
constexpr FileDeviceOutputIterator &operator++(int)
{
return *this;
}
private: private:
QFileDevice *m_device; QFileDevice *m_device;
std::shared_ptr<QByteArray> m_buffer; std::shared_ptr<QByteArray> m_buffer;
int m_bufferSize; int m_bufferSize;
}; };
}
} }

View File

@@ -41,10 +41,8 @@ enum class ShutdownDialogAction;
/* Miscellaneous functions that can be useful */ /* Miscellaneous functions that can be useful */
namespace Utils namespace Utils::Misc
{ {
namespace Misc
{
// use binary prefix standards from IEC 60027-2 // use binary prefix standards from IEC 60027-2
// see http://en.wikipedia.org/wiki/Kilobyte // see http://en.wikipedia.org/wiki/Kilobyte
enum class SizeUnit enum class SizeUnit
@@ -105,5 +103,4 @@ namespace Utils
::GetProcAddress(::LoadLibraryW(pathWchar.get()), funcName)); ::GetProcAddress(::LoadLibraryW(pathWchar.get()), funcName));
} }
#endif // Q_OS_WIN #endif // Q_OS_WIN
}
} }

View File

@@ -35,10 +35,8 @@ class QSslCertificate;
class QSslKey; class QSslKey;
class QString; class QString;
namespace Utils namespace Utils::Net
{ {
namespace Net
{
using Subnet = QPair<QHostAddress, int>; using Subnet = QPair<QHostAddress, int>;
bool isValidIP(const QString &ip); bool isValidIP(const QString &ip);
@@ -54,5 +52,4 @@ namespace Utils
bool isSSLCertificatesValid(const QByteArray &data); bool isSSLCertificatesValid(const QByteArray &data);
QSslKey loadSSLKey(const QByteArray &data); QSslKey loadSSLKey(const QByteArray &data);
bool isSSLKeyValid(const QByteArray &data); bool isSSLKeyValid(const QByteArray &data);
}
} }

View File

@@ -31,10 +31,8 @@
class QByteArray; class QByteArray;
class QString; class QString;
namespace Utils namespace Utils::Password
{ {
namespace Password
{
// Implements constant-time comparison to protect against timing attacks // Implements constant-time comparison to protect against timing attacks
// Taken from https://crackstation.net/hashing-security.htm // Taken from https://crackstation.net/hashing-security.htm
bool slowEquals(const QByteArray &a, const QByteArray &b); bool slowEquals(const QByteArray &a, const QByteArray &b);
@@ -47,5 +45,4 @@ namespace Utils
bool verify(const QByteArray &secret, const QString &password); bool verify(const QByteArray &secret, const QString &password);
bool verify(const QByteArray &secret, const QByteArray &password); bool verify(const QByteArray &secret, const QByteArray &password);
} }
}
} }

View File

@@ -31,10 +31,7 @@
#include <cstdint> #include <cstdint>
#include <limits> #include <limits>
namespace Utils namespace Utils::Random
{ {
namespace Random
{
uint32_t rand(uint32_t min = 0, uint32_t max = std::numeric_limits<uint32_t>::max()); uint32_t rand(uint32_t min = 0, uint32_t max = std::numeric_limits<uint32_t>::max());
}
} }

View File

@@ -42,8 +42,6 @@
#include <QThreadStorage> #include <QThreadStorage>
#endif #endif
#include "base/tristatebool.h"
namespace namespace
{ {
class NaturalCompare class NaturalCompare
@@ -192,20 +190,14 @@ QString Utils::String::wildcardToRegex(const QString &pattern)
return qt_regexp_toCanonical(pattern, QRegExp::Wildcard); return qt_regexp_toCanonical(pattern, QRegExp::Wildcard);
} }
bool Utils::String::parseBool(const QString &string, const bool defaultValue) std::optional<bool> Utils::String::parseBool(const QString &string)
{
if (defaultValue)
return (string.compare("false", Qt::CaseInsensitive) == 0) ? false : true;
return (string.compare("true", Qt::CaseInsensitive) == 0) ? true : false;
}
TriStateBool Utils::String::parseTriStateBool(const QString &string)
{ {
if (string.compare("true", Qt::CaseInsensitive) == 0) if (string.compare("true", Qt::CaseInsensitive) == 0)
return TriStateBool::True; return true;
if (string.compare("false", Qt::CaseInsensitive) == 0) if (string.compare("false", Qt::CaseInsensitive) == 0)
return TriStateBool::False; return false;
return TriStateBool::Undefined;
return std::nullopt;
} }
QString Utils::String::join(const QVector<QStringRef> &strings, const QString &separator) QString Utils::String::join(const QVector<QStringRef> &strings, const QString &separator)

View File

@@ -29,6 +29,8 @@
#pragma once #pragma once
#include <optional>
#include <QChar> #include <QChar>
#include <QMetaEnum> #include <QMetaEnum>
#include <QString> #include <QString>
@@ -37,12 +39,8 @@
class QStringRef; class QStringRef;
class TriStateBool; namespace Utils::String
namespace Utils
{ {
namespace String
{
QString fromDouble(double n, int precision); QString fromDouble(double n, int precision);
int naturalCompare(const QString &left, const QString &right, const Qt::CaseSensitivity caseSensitivity); int naturalCompare(const QString &left, const QString &right, const Qt::CaseSensitivity caseSensitivity);
@@ -68,25 +66,24 @@ namespace Utils
return str; return str;
} }
bool parseBool(const QString &string, bool defaultValue); std::optional<bool> parseBool(const QString &string);
TriStateBool parseTriStateBool(const QString &string);
QString join(const QVector<QStringRef> &strings, const QString &separator); QString join(const QVector<QStringRef> &strings, const QString &separator);
template <typename T, typename std::enable_if_t<std::is_enum<T>::value, int> = 0> template <typename T, typename std::enable_if_t<std::is_enum_v<T>, int> = 0>
QString fromEnum(const T &value) QString fromEnum(const T &value)
{ {
static_assert(std::is_same<int, typename std::underlying_type_t<T>>::value, static_assert(std::is_same_v<int, typename std::underlying_type_t<T>>,
"Enumeration underlying type has to be int."); "Enumeration underlying type has to be int.");
const auto metaEnum = QMetaEnum::fromType<T>(); const auto metaEnum = QMetaEnum::fromType<T>();
return QString::fromLatin1(metaEnum.valueToKey(static_cast<int>(value))); return QString::fromLatin1(metaEnum.valueToKey(static_cast<int>(value)));
} }
template <typename T, typename std::enable_if_t<std::is_enum<T>::value, int> = 0> template <typename T, typename std::enable_if_t<std::is_enum_v<T>, int> = 0>
T toEnum(const QString &serializedValue, const T &defaultValue) T toEnum(const QString &serializedValue, const T &defaultValue)
{ {
static_assert(std::is_same<int, typename std::underlying_type_t<T>>::value, static_assert(std::is_same_v<int, typename std::underlying_type_t<T>>,
"Enumeration underlying type has to be int."); "Enumeration underlying type has to be int.");
const auto metaEnum = QMetaEnum::fromType<T>(); const auto metaEnum = QMetaEnum::fromType<T>();
@@ -94,5 +91,4 @@ namespace Utils
const T value = static_cast<T>(metaEnum.keyToValue(serializedValue.toLatin1().constData(), &ok)); const T value = static_cast<T>(metaEnum.keyToValue(serializedValue.toLatin1().constData(), &ok));
return (ok ? value : defaultValue); return (ok ? value : defaultValue);
} }
}
} }

View File

@@ -1,6 +1,6 @@
/* /*
* Bittorrent Client using Qt and libtorrent. * Bittorrent Client using Qt and libtorrent.
* Copyright (C) 2015 Vladimir Golovnev <glassez@yandex.ru> * Copyright (C) 2021 Mike Tzou (Chocobo1)
* *
* This program is free software; you can redistribute it and/or * This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License * modify it under the terms of the GNU General Public License
@@ -26,8 +26,22 @@
* exception statement from your version. * exception statement from your version.
*/ */
#include "tristatebool.h" #pragma once
const TriStateBool TriStateBool::Undefined(-1); #define QBT_VERSION_MAJOR 4
const TriStateBool TriStateBool::False(0); #define QBT_VERSION_MINOR 3
const TriStateBool TriStateBool::True(1); #define QBT_VERSION_BUGFIX 3
#define QBT_VERSION_BUILD 0
#define QBT_VERSION_STATUS "" // Should be empty for stable releases!
#define QBT__STRINGIFY(x) #x
#define QBT_STRINGIFY(x) QBT__STRINGIFY(x)
#if (QBT_VERSION_BUILD != 0)
#define PROJECT_VERSION QBT_STRINGIFY(QBT_VERSION_MAJOR.QBT_VERSION_MINOR.QBT_VERSION_BUGFIX.QBT_VERSION_BUILD) QBT_VERSION_STATUS
#else
#define PROJECT_VERSION QBT_STRINGIFY(QBT_VERSION_MAJOR.QBT_VERSION_MINOR.QBT_VERSION_BUGFIX) QBT_VERSION_STATUS
#endif
#define QBT_VERSION "v" PROJECT_VERSION
#define QBT_VERSION_2 PROJECT_VERSION

View File

@@ -67,6 +67,7 @@ add_library(qbt_gui STATIC
torrentcontentmodelitem.h torrentcontentmodelitem.h
torrentcontenttreeview.h torrentcontenttreeview.h
torrentcreatordialog.h torrentcreatordialog.h
torrentoptionsdialog.h
trackerentriesdialog.h trackerentriesdialog.h
transferlistdelegate.h transferlistdelegate.h
transferlistfilterswidget.h transferlistfilterswidget.h
@@ -76,7 +77,6 @@ add_library(qbt_gui STATIC
tristateaction.h tristateaction.h
tristatewidget.h tristatewidget.h
uithememanager.h uithememanager.h
updownratiodialog.h
utils.h utils.h
# sources # sources
@@ -147,6 +147,7 @@ add_library(qbt_gui STATIC
torrentcontentmodelitem.cpp torrentcontentmodelitem.cpp
torrentcontenttreeview.cpp torrentcontenttreeview.cpp
torrentcreatordialog.cpp torrentcreatordialog.cpp
torrentoptionsdialog.cpp
trackerentriesdialog.cpp trackerentriesdialog.cpp
transferlistdelegate.cpp transferlistdelegate.cpp
transferlistfilterswidget.cpp transferlistfilterswidget.cpp
@@ -156,7 +157,6 @@ add_library(qbt_gui STATIC
tristateaction.cpp tristateaction.cpp
tristatewidget.cpp tristatewidget.cpp
uithememanager.cpp uithememanager.cpp
updownratiodialog.cpp
utils.cpp utils.cpp
# forms # forms
@@ -186,8 +186,8 @@ add_library(qbt_gui STATIC
statsdialog.ui statsdialog.ui
torrentcategorydialog.ui torrentcategorydialog.ui
torrentcreatordialog.ui torrentcreatordialog.ui
torrentoptionsdialog.ui
trackerentriesdialog.ui trackerentriesdialog.ui
updownratiodialog.ui
) )
target_sources(qbt_gui INTERFACE about.qrc) target_sources(qbt_gui INTERFACE about.qrc)

View File

@@ -32,13 +32,17 @@
#include "base/unicodestrings.h" #include "base/unicodestrings.h"
#include "base/utils/misc.h" #include "base/utils/misc.h"
#include "base/version.h"
#include "ui_aboutdialog.h" #include "ui_aboutdialog.h"
#include "uithememanager.h" #include "uithememanager.h"
#include "utils.h" #include "utils.h"
#define SETTINGS_KEY(name) "AboutDialog/" name
AboutDialog::AboutDialog(QWidget *parent) AboutDialog::AboutDialog(QWidget *parent)
: QDialog(parent) : QDialog(parent)
, m_ui(new Ui::AboutDialog) , m_ui(new Ui::AboutDialog)
, m_storeDialogSize(SETTINGS_KEY("Size"))
{ {
m_ui->setupUi(this); m_ui->setupUi(this);
setAttribute(Qt::WA_DeleteOnClose); setAttribute(Qt::WA_DeleteOnClose);
@@ -60,7 +64,7 @@ AboutDialog::AboutDialog(QWidget *parent)
"</table>" "</table>"
"</p>") "</p>")
.arg(tr("An advanced BitTorrent client programmed in C++, based on Qt toolkit and libtorrent-rasterbar.") .arg(tr("An advanced BitTorrent client programmed in C++, based on Qt toolkit and libtorrent-rasterbar.")
, tr("Copyright %1 2006-2020 The qBittorrent project").arg(QString::fromUtf8(C_COPYRIGHT)) , tr("Copyright %1 2006-2021 The qBittorrent project").arg(QString::fromUtf8(C_COPYRIGHT))
, tr("Home Page:") , tr("Home Page:")
, tr("Forum:") , tr("Forum:")
, tr("Bug Tracker:")); , tr("Bug Tracker:"));
@@ -107,11 +111,12 @@ AboutDialog::AboutDialog(QWidget *parent)
"The database is licensed under the Creative Commons Attribution 4.0 International License")); "The database is licensed under the Creative Commons Attribution 4.0 International License"));
m_ui->labelDBIP->setText(DBIPText); m_ui->labelDBIP->setText(DBIPText);
Utils::Gui::resize(this); Utils::Gui::resize(this, m_storeDialogSize);
show(); show();
} }
AboutDialog::~AboutDialog() AboutDialog::~AboutDialog()
{ {
m_storeDialogSize = size();
delete m_ui; delete m_ui;
} }

View File

@@ -30,12 +30,14 @@
#include <QDialog> #include <QDialog>
#include "base/settingvalue.h"
namespace Ui namespace Ui
{ {
class AboutDialog; class AboutDialog;
} }
class AboutDialog : public QDialog class AboutDialog final : public QDialog
{ {
Q_OBJECT Q_OBJECT
Q_DISABLE_COPY(AboutDialog) Q_DISABLE_COPY(AboutDialog)
@@ -46,4 +48,5 @@ public:
private: private:
Ui::AboutDialog *m_ui; Ui::AboutDialog *m_ui;
SettingValue<QSize> m_storeDialogSize;
}; };

View File

@@ -42,7 +42,7 @@
#include "base/bittorrent/infohash.h" #include "base/bittorrent/infohash.h"
#include "base/bittorrent/magneturi.h" #include "base/bittorrent/magneturi.h"
#include "base/bittorrent/session.h" #include "base/bittorrent/session.h"
#include "base/bittorrent/torrenthandle.h" #include "base/bittorrent/torrent.h"
#include "base/exceptions.h" #include "base/exceptions.h"
#include "base/global.h" #include "base/global.h"
#include "base/net/downloadmanager.h" #include "base/net/downloadmanager.h"
@@ -107,12 +107,7 @@ AddNewTorrentDialog::AddNewTorrentDialog(const BitTorrent::AddTorrentParams &inP
const auto *session = BitTorrent::Session::instance(); const auto *session = BitTorrent::Session::instance();
if (m_torrentParams.addPaused == TriStateBool::True) m_ui->startTorrentCheckBox->setChecked(!m_torrentParams.addPaused.value_or(session->isAddTorrentPaused()));
m_ui->startTorrentCheckBox->setChecked(false);
else if (m_torrentParams.addPaused == TriStateBool::False)
m_ui->startTorrentCheckBox->setChecked(true);
else
m_ui->startTorrentCheckBox->setChecked(!session->isAddTorrentPaused());
m_ui->comboTTM->blockSignals(true); // the TreeView size isn't correct if the slot does it job at this point m_ui->comboTTM->blockSignals(true); // the TreeView size isn't correct if the slot does it job at this point
m_ui->comboTTM->setCurrentIndex(!session->isAutoTMMDisabledByDefault()); m_ui->comboTTM->setCurrentIndex(!session->isAutoTMMDisabledByDefault());
@@ -120,11 +115,11 @@ AddNewTorrentDialog::AddNewTorrentDialog(const BitTorrent::AddTorrentParams &inP
populateSavePathComboBox(); populateSavePathComboBox();
connect(m_ui->savePath, &FileSystemPathEdit::selectedPathChanged, this, &AddNewTorrentDialog::onSavePathChanged); connect(m_ui->savePath, &FileSystemPathEdit::selectedPathChanged, this, &AddNewTorrentDialog::onSavePathChanged);
const bool rememberLastSavePath = settings()->loadValue(KEY_REMEMBERLASTSAVEPATH, false).toBool(); const bool rememberLastSavePath = settings()->loadValue(KEY_REMEMBERLASTSAVEPATH, false);
m_ui->checkBoxRememberLastSavePath->setChecked(rememberLastSavePath); m_ui->checkBoxRememberLastSavePath->setChecked(rememberLastSavePath);
m_ui->contentLayoutComboBox->setCurrentIndex( m_ui->contentLayoutComboBox->setCurrentIndex(
static_cast<int>(m_torrentParams.contentLayout ? *m_torrentParams.contentLayout : session->torrentContentLayout())); static_cast<int>(m_torrentParams.contentLayout.value_or(session->torrentContentLayout())));
m_ui->sequentialCheckBox->setChecked(m_torrentParams.sequential); m_ui->sequentialCheckBox->setChecked(m_torrentParams.sequential);
m_ui->firstLastCheckBox->setChecked(m_torrentParams.firstLastPiecePriority); m_ui->firstLastCheckBox->setChecked(m_torrentParams.firstLastPiecePriority);
@@ -135,7 +130,7 @@ AddNewTorrentDialog::AddNewTorrentDialog(const BitTorrent::AddTorrentParams &inP
// Load categories // Load categories
QStringList categories = session->categories().keys(); QStringList categories = session->categories().keys();
std::sort(categories.begin(), categories.end(), Utils::String::naturalLessThan<Qt::CaseInsensitive>); std::sort(categories.begin(), categories.end(), Utils::String::naturalLessThan<Qt::CaseInsensitive>);
QString defaultCategory = settings()->loadValue(KEY_DEFAULTCATEGORY).toString(); auto defaultCategory = settings()->loadValue<QString>(KEY_DEFAULTCATEGORY);
if (!m_torrentParams.category.isEmpty()) if (!m_torrentParams.category.isEmpty())
m_ui->categoryComboBox->addItem(m_torrentParams.category); m_ui->categoryComboBox->addItem(m_torrentParams.category);
@@ -170,7 +165,7 @@ AddNewTorrentDialog::~AddNewTorrentDialog()
bool AddNewTorrentDialog::isEnabled() bool AddNewTorrentDialog::isEnabled()
{ {
return SettingsStorage::instance()->loadValue(KEY_ENABLED, true).toBool(); return SettingsStorage::instance()->loadValue(KEY_ENABLED, true);
} }
void AddNewTorrentDialog::setEnabled(bool value) void AddNewTorrentDialog::setEnabled(bool value)
@@ -180,7 +175,7 @@ void AddNewTorrentDialog::setEnabled(bool value)
bool AddNewTorrentDialog::isTopLevel() bool AddNewTorrentDialog::isTopLevel()
{ {
return SettingsStorage::instance()->loadValue(KEY_TOPLEVEL, true).toBool(); return SettingsStorage::instance()->loadValue(KEY_TOPLEVEL, true);
} }
void AddNewTorrentDialog::setTopLevel(bool value) void AddNewTorrentDialog::setTopLevel(bool value)
@@ -191,7 +186,7 @@ void AddNewTorrentDialog::setTopLevel(bool value)
int AddNewTorrentDialog::savePathHistoryLength() int AddNewTorrentDialog::savePathHistoryLength()
{ {
const int defaultHistoryLength = 8; const int defaultHistoryLength = 8;
const int value = settings()->loadValue(KEY_SAVEPATHHISTORYLENGTH, defaultHistoryLength).toInt(); const int value = settings()->loadValue(KEY_SAVEPATHHISTORYLENGTH, defaultHistoryLength);
return qBound(minPathHistoryLength, value, maxPathHistoryLength); return qBound(minPathHistoryLength, value, maxPathHistoryLength);
} }
@@ -204,14 +199,14 @@ void AddNewTorrentDialog::setSavePathHistoryLength(int value)
settings()->storeValue(KEY_SAVEPATHHISTORYLENGTH, clampedValue); settings()->storeValue(KEY_SAVEPATHHISTORYLENGTH, clampedValue);
settings()->storeValue(KEY_SAVEPATHHISTORY settings()->storeValue(KEY_SAVEPATHHISTORY
, QStringList(settings()->loadValue(KEY_SAVEPATHHISTORY).toStringList().mid(0, clampedValue))); , QStringList(settings()->loadValue<QStringList>(KEY_SAVEPATHHISTORY).mid(0, clampedValue)));
} }
void AddNewTorrentDialog::loadState() void AddNewTorrentDialog::loadState()
{ {
Utils::Gui::resize(this, m_storeDialogSize); Utils::Gui::resize(this, m_storeDialogSize);
m_ui->splitter->restoreState(m_storeSplitterState); m_ui->splitter->restoreState(m_storeSplitterState);
m_headerState = settings()->loadValue(KEY_TREEHEADERSTATE).toByteArray(); m_headerState = settings()->loadValue<QByteArray>(KEY_TREEHEADERSTATE);
} }
void AddNewTorrentDialog::saveState() void AddNewTorrentDialog::saveState()
@@ -280,7 +275,7 @@ bool AddNewTorrentDialog::loadTorrentImpl()
// Prevent showing the dialog if download is already present // Prevent showing the dialog if download is already present
if (BitTorrent::Session::instance()->isKnownTorrent(infoHash)) if (BitTorrent::Session::instance()->isKnownTorrent(infoHash))
{ {
BitTorrent::TorrentHandle *const torrent = BitTorrent::Session::instance()->findTorrent(infoHash); BitTorrent::Torrent *const torrent = BitTorrent::Session::instance()->findTorrent(infoHash);
if (torrent) if (torrent)
{ {
if (torrent->isPrivate() || m_torrentInfo.isPrivate()) if (torrent->isPrivate() || m_torrentInfo.isPrivate())
@@ -321,7 +316,7 @@ bool AddNewTorrentDialog::loadMagnet(const BitTorrent::MagnetUri &magnetUri)
// Prevent showing the dialog if download is already present // Prevent showing the dialog if download is already present
if (BitTorrent::Session::instance()->isKnownTorrent(infoHash)) if (BitTorrent::Session::instance()->isKnownTorrent(infoHash))
{ {
BitTorrent::TorrentHandle *const torrent = BitTorrent::Session::instance()->findTorrent(infoHash); BitTorrent::Torrent *const torrent = BitTorrent::Session::instance()->findTorrent(infoHash);
if (torrent) if (torrent)
{ {
if (torrent->isPrivate()) if (torrent->isPrivate())
@@ -371,7 +366,7 @@ void AddNewTorrentDialog::showEvent(QShowEvent *event)
void AddNewTorrentDialog::saveSavePathHistory() const void AddNewTorrentDialog::saveSavePathHistory() const
{ {
// Get current history // Get current history
QStringList history = settings()->loadValue(KEY_SAVEPATHHISTORY).toStringList(); auto history = settings()->loadValue<QStringList>(KEY_SAVEPATHHISTORY);
QVector<QDir> historyDirs; QVector<QDir> historyDirs;
for (const QString &path : asConst(history)) for (const QString &path : asConst(history))
historyDirs << QDir {path}; historyDirs << QDir {path};
@@ -489,11 +484,11 @@ void AddNewTorrentDialog::populateSavePathComboBox()
m_ui->savePath->clear(); m_ui->savePath->clear();
// Load save path history // Load save path history
const QStringList savePathHistory {settings()->loadValue(KEY_SAVEPATHHISTORY).toStringList()}; const auto savePathHistory {settings()->loadValue<QStringList>(KEY_SAVEPATHHISTORY)};
for (const QString &savePath : savePathHistory) for (const QString &savePath : savePathHistory)
m_ui->savePath->addItem(savePath); m_ui->savePath->addItem(savePath);
const bool rememberLastSavePath {settings()->loadValue(KEY_REMEMBERLASTSAVEPATH, false).toBool()}; const bool rememberLastSavePath {settings()->loadValue(KEY_REMEMBERLASTSAVEPATH, false)};
const QString defSavePath {BitTorrent::Session::instance()->defaultSavePath()}; const QString defSavePath {BitTorrent::Session::instance()->defaultSavePath()};
if (!m_torrentParams.savePath.isEmpty()) if (!m_torrentParams.savePath.isEmpty())
@@ -573,7 +568,7 @@ void AddNewTorrentDialog::accept()
if (m_contentModel) if (m_contentModel)
m_torrentParams.filePriorities = m_contentModel->model()->getFilePriorities(); m_torrentParams.filePriorities = m_contentModel->model()->getFilePriorities();
m_torrentParams.addPaused = TriStateBool(!m_ui->startTorrentCheckBox->isChecked()); m_torrentParams.addPaused = !m_ui->startTorrentCheckBox->isChecked();
m_torrentParams.contentLayout = static_cast<BitTorrent::TorrentContentLayout>(m_ui->contentLayoutComboBox->currentIndex()); m_torrentParams.contentLayout = static_cast<BitTorrent::TorrentContentLayout>(m_ui->contentLayoutComboBox->currentIndex());
m_torrentParams.sequential = m_ui->sequentialCheckBox->isChecked(); m_torrentParams.sequential = m_ui->sequentialCheckBox->isChecked();
@@ -582,13 +577,13 @@ void AddNewTorrentDialog::accept()
QString savePath = m_ui->savePath->selectedPath(); QString savePath = m_ui->savePath->selectedPath();
if (m_ui->comboTTM->currentIndex() != 1) if (m_ui->comboTTM->currentIndex() != 1)
{ // 0 is Manual mode and 1 is Automatic mode. Handle all non 1 values as manual mode. { // 0 is Manual mode and 1 is Automatic mode. Handle all non 1 values as manual mode.
m_torrentParams.useAutoTMM = TriStateBool::False; m_torrentParams.useAutoTMM = false;
m_torrentParams.savePath = savePath; m_torrentParams.savePath = savePath;
saveSavePathHistory(); saveSavePathHistory();
} }
else else
{ {
m_torrentParams.useAutoTMM = TriStateBool::True; m_torrentParams.useAutoTMM = true;
} }
setEnabled(!m_ui->checkBoxNeverShow->isChecked()); setEnabled(!m_ui->checkBoxNeverShow->isChecked());
@@ -660,7 +655,7 @@ void AddNewTorrentDialog::setupTreeview()
// Set torrent information // Set torrent information
m_ui->labelCommentData->setText(Utils::Misc::parseHtmlLinks(m_torrentInfo.comment().toHtmlEscaped())); m_ui->labelCommentData->setText(Utils::Misc::parseHtmlLinks(m_torrentInfo.comment().toHtmlEscaped()));
m_ui->labelDateData->setText(!m_torrentInfo.creationDate().isNull() ? m_torrentInfo.creationDate().toString(Qt::DefaultLocaleShortDate) : tr("Not available")); m_ui->labelDateData->setText(!m_torrentInfo.creationDate().isNull() ? QLocale().toString(m_torrentInfo.creationDate(), QLocale::ShortFormat) : tr("Not available"));
// Prepare content tree // Prepare content tree
m_contentModel = new TorrentContentFilterModel(this); m_contentModel = new TorrentContentFilterModel(this);

View File

@@ -118,6 +118,6 @@ private:
std::unique_ptr<TorrentFileGuard> m_torrentGuard; std::unique_ptr<TorrentFileGuard> m_torrentGuard;
BitTorrent::AddTorrentParams m_torrentParams; BitTorrent::AddTorrentParams m_torrentParams;
CachedSettingValue<QSize> m_storeDialogSize; SettingValue<QSize> m_storeDialogSize;
CachedSettingValue<QByteArray> m_storeSplitterState; SettingValue<QByteArray> m_storeSplitterState;
}; };

View File

@@ -715,12 +715,12 @@ void AdvancedSettings::addRow(const int row, const QString &text, T *widget)
setCellWidget(row, PROPERTY, label); setCellWidget(row, PROPERTY, label);
setCellWidget(row, VALUE, widget); setCellWidget(row, VALUE, widget);
if (std::is_same<T, QCheckBox>::value) if constexpr (std::is_same_v<T, QCheckBox>)
connect(widget, SIGNAL(stateChanged(int)), this, SIGNAL(settingsChanged())); connect(widget, &QCheckBox::stateChanged, this, &AdvancedSettings::settingsChanged);
else if (std::is_same<T, QSpinBox>::value) else if constexpr (std::is_same_v<T, QSpinBox>)
connect(widget, SIGNAL(valueChanged(int)), this, SIGNAL(settingsChanged())); connect(widget, qOverload<int>(&QSpinBox::valueChanged), this, &AdvancedSettings::settingsChanged);
else if (std::is_same<T, QComboBox>::value) else if constexpr (std::is_same_v<T, QComboBox>)
connect(widget, SIGNAL(currentIndexChanged(int)), this, SIGNAL(settingsChanged())); connect(widget, qOverload<int>(&QComboBox::currentIndexChanged), this, &AdvancedSettings::settingsChanged);
else if (std::is_same<T, QLineEdit>::value) else if constexpr (std::is_same_v<T, QLineEdit>)
connect(widget, SIGNAL(textChanged(QString)), this, SIGNAL(settingsChanged())); connect(widget, &QLineEdit::textChanged, this, &AdvancedSettings::settingsChanged);
} }

View File

@@ -28,6 +28,7 @@
#include "autoexpandabledialog.h" #include "autoexpandabledialog.h"
#include "base/utils/fs.h"
#include "ui_autoexpandabledialog.h" #include "ui_autoexpandabledialog.h"
#include "utils.h" #include "utils.h"
@@ -57,12 +58,9 @@ QString AutoExpandableDialog::getText(QWidget *parent, const QString &title, con
d.m_ui->textEdit->selectAll(); d.m_ui->textEdit->selectAll();
if (excludeExtension) if (excludeExtension)
{ {
int lastDotIndex = text.lastIndexOf('.'); const QString extension = Utils::Fs::fileExtension(text);
if ((lastDotIndex > 3) && (text.mid(lastDotIndex - 4, 4).toLower() == ".tar")) if (!extension.isEmpty())
lastDotIndex -= 4; d.m_ui->textEdit->setSelection(0, (text.length() - extension.length() - 1));
// Select file name without extension, except dot files like .gitignore
if (lastDotIndex > 0)
d.m_ui->textEdit->setSelection(0, lastDotIndex);
} }
bool res = d.exec(); bool res = d.exec();

View File

@@ -38,11 +38,13 @@
#include "ui_banlistoptionsdialog.h" #include "ui_banlistoptionsdialog.h"
#include "utils.h" #include "utils.h"
#define SETTINGS_KEY(name) "BanListOptionsDialog/" name
BanListOptionsDialog::BanListOptionsDialog(QWidget *parent) BanListOptionsDialog::BanListOptionsDialog(QWidget *parent)
: QDialog(parent) : QDialog(parent)
, m_ui(new Ui::BanListOptionsDialog) , m_ui(new Ui::BanListOptionsDialog)
, m_storeDialogSize(SETTINGS_KEY("Size"))
, m_model(new QStringListModel(BitTorrent::Session::instance()->bannedIPs(), this)) , m_model(new QStringListModel(BitTorrent::Session::instance()->bannedIPs(), this))
, m_modified(false)
{ {
m_ui->setupUi(this); m_ui->setupUi(this);
@@ -54,11 +56,12 @@ BanListOptionsDialog::BanListOptionsDialog(QWidget *parent)
m_ui->bannedIPList->sortByColumn(0, Qt::AscendingOrder); m_ui->bannedIPList->sortByColumn(0, Qt::AscendingOrder);
m_ui->buttonBanIP->setEnabled(false); m_ui->buttonBanIP->setEnabled(false);
Utils::Gui::resize(this); Utils::Gui::resize(this, m_storeDialogSize);
} }
BanListOptionsDialog::~BanListOptionsDialog() BanListOptionsDialog::~BanListOptionsDialog()
{ {
m_storeDialogSize = size();
delete m_ui; delete m_ui;
} }

View File

@@ -30,6 +30,8 @@
#include <QDialog> #include <QDialog>
#include "base/settingvalue.h"
class QSortFilterProxyModel; class QSortFilterProxyModel;
class QStringListModel; class QStringListModel;
@@ -38,13 +40,14 @@ namespace Ui
class BanListOptionsDialog; class BanListOptionsDialog;
} }
class BanListOptionsDialog : public QDialog class BanListOptionsDialog final : public QDialog
{ {
Q_OBJECT Q_OBJECT
Q_DISABLE_COPY(BanListOptionsDialog)
public: public:
explicit BanListOptionsDialog(QWidget *parent = nullptr); explicit BanListOptionsDialog(QWidget *parent = nullptr);
~BanListOptionsDialog(); ~BanListOptionsDialog() override;
private slots: private slots:
void on_buttonBox_accepted(); void on_buttonBox_accepted();
@@ -54,7 +57,8 @@ private slots:
private: private:
Ui::BanListOptionsDialog *m_ui; Ui::BanListOptionsDialog *m_ui;
SettingValue<QSize> m_storeDialogSize;
QStringListModel *m_model; QStringListModel *m_model;
QSortFilterProxyModel *m_sortFilter; QSortFilterProxyModel *m_sortFilter;
bool m_modified; bool m_modified = false;
}; };

View File

@@ -32,7 +32,7 @@
#include <QIcon> #include <QIcon>
#include "base/bittorrent/session.h" #include "base/bittorrent/session.h"
#include "base/bittorrent/torrenthandle.h" #include "base/bittorrent/torrent.h"
#include "base/global.h" #include "base/global.h"
#include "uithememanager.h" #include "uithememanager.h"
@@ -336,7 +336,7 @@ void CategoryFilterModel::categoryRemoved(const QString &categoryName)
} }
} }
void CategoryFilterModel::torrentAdded(BitTorrent::TorrentHandle *const torrent) void CategoryFilterModel::torrentAdded(BitTorrent::Torrent *const torrent)
{ {
CategoryModelItem *item = findItem(torrent->category()); CategoryModelItem *item = findItem(torrent->category());
Q_ASSERT(item); Q_ASSERT(item);
@@ -345,7 +345,7 @@ void CategoryFilterModel::torrentAdded(BitTorrent::TorrentHandle *const torrent)
m_rootItem->childAt(0)->increaseTorrentsCount(); m_rootItem->childAt(0)->increaseTorrentsCount();
} }
void CategoryFilterModel::torrentAboutToBeRemoved(BitTorrent::TorrentHandle *const torrent) void CategoryFilterModel::torrentAboutToBeRemoved(BitTorrent::Torrent *const torrent)
{ {
CategoryModelItem *item = findItem(torrent->category()); CategoryModelItem *item = findItem(torrent->category());
Q_ASSERT(item); Q_ASSERT(item);
@@ -354,7 +354,7 @@ void CategoryFilterModel::torrentAboutToBeRemoved(BitTorrent::TorrentHandle *con
m_rootItem->childAt(0)->decreaseTorrentsCount(); m_rootItem->childAt(0)->decreaseTorrentsCount();
} }
void CategoryFilterModel::torrentCategoryChanged(BitTorrent::TorrentHandle *const torrent, const QString &oldCategory) void CategoryFilterModel::torrentCategoryChanged(BitTorrent::Torrent *const torrent, const QString &oldCategory)
{ {
QModelIndex i; QModelIndex i;
@@ -403,7 +403,7 @@ void CategoryFilterModel::populate()
m_rootItem->addChild(UID_ALL, new CategoryModelItem(nullptr, tr("All"), torrents.count())); m_rootItem->addChild(UID_ALL, new CategoryModelItem(nullptr, tr("All"), torrents.count()));
// Uncategorized torrents // Uncategorized torrents
using Torrent = BitTorrent::TorrentHandle; using Torrent = BitTorrent::Torrent;
m_rootItem->addChild( m_rootItem->addChild(
UID_UNCATEGORIZED UID_UNCATEGORIZED
, new CategoryModelItem( , new CategoryModelItem(
@@ -411,7 +411,7 @@ void CategoryFilterModel::populate()
, std::count_if(torrents.begin(), torrents.end() , std::count_if(torrents.begin(), torrents.end()
, [](Torrent *torrent) { return torrent->category().isEmpty(); }))); , [](Torrent *torrent) { return torrent->category().isEmpty(); })));
using Torrent = BitTorrent::TorrentHandle; using Torrent = BitTorrent::Torrent;
for (auto i = session->categories().cbegin(); i != session->categories().cend(); ++i) for (auto i = session->categories().cbegin(); i != session->categories().cend(); ++i)
{ {
const QString &category = i.key(); const QString &category = i.key();

View File

@@ -36,7 +36,7 @@ class CategoryModelItem;
namespace BitTorrent namespace BitTorrent
{ {
class TorrentHandle; class Torrent;
} }
class CategoryFilterModel final : public QAbstractItemModel class CategoryFilterModel final : public QAbstractItemModel
@@ -63,9 +63,9 @@ public:
private slots: private slots:
void categoryAdded(const QString &categoryName); void categoryAdded(const QString &categoryName);
void categoryRemoved(const QString &categoryName); void categoryRemoved(const QString &categoryName);
void torrentAdded(BitTorrent::TorrentHandle *const torrent); void torrentAdded(BitTorrent::Torrent *const torrent);
void torrentAboutToBeRemoved(BitTorrent::TorrentHandle *const torrent); void torrentAboutToBeRemoved(BitTorrent::Torrent *const torrent);
void torrentCategoryChanged(BitTorrent::TorrentHandle *const torrent, const QString &oldCategory); void torrentCategoryChanged(BitTorrent::Torrent *const torrent, const QString &oldCategory);
void subcategoriesSupportChanged(); void subcategoriesSupportChanged();
private: private:

View File

@@ -61,9 +61,9 @@ CookiesDialog::CookiesDialog(QWidget *parent)
m_cookiesModel->index(0, 0), m_cookiesModel->index(0, 0),
QItemSelectionModel::ClearAndSelect | QItemSelectionModel::Rows); QItemSelectionModel::ClearAndSelect | QItemSelectionModel::Rows);
Utils::Gui::resize(this, SettingsStorage::instance()->loadValue(KEY_SIZE).toSize()); Utils::Gui::resize(this, SettingsStorage::instance()->loadValue<QSize>(KEY_SIZE));
m_ui->treeView->header()->restoreState( m_ui->treeView->header()->restoreState(
SettingsStorage::instance()->loadValue(KEY_COOKIESVIEWSTATE).toByteArray()); SettingsStorage::instance()->loadValue<QByteArray>(KEY_COOKIESVIEWSTATE));
} }
CookiesDialog::~CookiesDialog() CookiesDialog::~CookiesDialog()

View File

@@ -39,6 +39,8 @@
#include "ui_downloadfromurldialog.h" #include "ui_downloadfromurldialog.h"
#include "utils.h" #include "utils.h"
#define SETTINGS_KEY(name) "DownloadFromURLDialog/" name
namespace namespace
{ {
bool isDownloadable(const QString &str) bool isDownloadable(const QString &str)
@@ -55,6 +57,7 @@ namespace
DownloadFromURLDialog::DownloadFromURLDialog(QWidget *parent) DownloadFromURLDialog::DownloadFromURLDialog(QWidget *parent)
: QDialog(parent) : QDialog(parent)
, m_ui(new Ui::DownloadFromURLDialog) , m_ui(new Ui::DownloadFromURLDialog)
, m_storeDialogSize(SETTINGS_KEY("Size"))
{ {
m_ui->setupUi(this); m_ui->setupUi(this);
setAttribute(Qt::WA_DeleteOnClose); setAttribute(Qt::WA_DeleteOnClose);
@@ -82,12 +85,13 @@ DownloadFromURLDialog::DownloadFromURLDialog(QWidget *parent)
} }
m_ui->textUrls->setText(uniqueURLs.values().join('\n')); m_ui->textUrls->setText(uniqueURLs.values().join('\n'));
Utils::Gui::resize(this); Utils::Gui::resize(this, m_storeDialogSize);
show(); show();
} }
DownloadFromURLDialog::~DownloadFromURLDialog() DownloadFromURLDialog::~DownloadFromURLDialog()
{ {
m_storeDialogSize = size();
delete m_ui; delete m_ui;
} }

View File

@@ -30,19 +30,21 @@
#include <QDialog> #include <QDialog>
#include "base/settingvalue.h"
namespace Ui namespace Ui
{ {
class DownloadFromURLDialog; class DownloadFromURLDialog;
} }
class DownloadFromURLDialog : public QDialog class DownloadFromURLDialog final : public QDialog
{ {
Q_OBJECT Q_OBJECT
Q_DISABLE_COPY(DownloadFromURLDialog) Q_DISABLE_COPY(DownloadFromURLDialog)
public: public:
explicit DownloadFromURLDialog(QWidget *parent); explicit DownloadFromURLDialog(QWidget *parent);
~DownloadFromURLDialog(); ~DownloadFromURLDialog() override;
signals: signals:
void urlsReadyToBeDownloaded(const QStringList &torrentURLs); void urlsReadyToBeDownloaded(const QStringList &torrentURLs);
@@ -52,4 +54,5 @@ private slots:
private: private:
Ui::DownloadFromURLDialog *m_ui; Ui::DownloadFromURLDialog *m_ui;
SettingValue<QSize> m_storeDialogSize;
}; };

View File

@@ -68,6 +68,7 @@ HEADERS += \
$$PWD/torrentcontentmodelitem.h \ $$PWD/torrentcontentmodelitem.h \
$$PWD/torrentcontenttreeview.h \ $$PWD/torrentcontenttreeview.h \
$$PWD/torrentcreatordialog.h \ $$PWD/torrentcreatordialog.h \
$$PWD/torrentoptionsdialog.h \
$$PWD/trackerentriesdialog.h \ $$PWD/trackerentriesdialog.h \
$$PWD/transferlistdelegate.h \ $$PWD/transferlistdelegate.h \
$$PWD/transferlistfilterswidget.h \ $$PWD/transferlistfilterswidget.h \
@@ -77,7 +78,6 @@ HEADERS += \
$$PWD/tristateaction.h \ $$PWD/tristateaction.h \
$$PWD/tristatewidget.h \ $$PWD/tristatewidget.h \
$$PWD/uithememanager.h \ $$PWD/uithememanager.h \
$$PWD/updownratiodialog.h \
$$PWD/utils.h $$PWD/utils.h
SOURCES += \ SOURCES += \
@@ -148,6 +148,7 @@ SOURCES += \
$$PWD/torrentcontentmodelitem.cpp \ $$PWD/torrentcontentmodelitem.cpp \
$$PWD/torrentcontenttreeview.cpp \ $$PWD/torrentcontenttreeview.cpp \
$$PWD/torrentcreatordialog.cpp \ $$PWD/torrentcreatordialog.cpp \
$$PWD/torrentoptionsdialog.cpp \
$$PWD/trackerentriesdialog.cpp \ $$PWD/trackerentriesdialog.cpp \
$$PWD/transferlistdelegate.cpp \ $$PWD/transferlistdelegate.cpp \
$$PWD/transferlistfilterswidget.cpp \ $$PWD/transferlistfilterswidget.cpp \
@@ -157,7 +158,6 @@ SOURCES += \
$$PWD/tristateaction.cpp \ $$PWD/tristateaction.cpp \
$$PWD/tristatewidget.cpp \ $$PWD/tristatewidget.cpp \
$$PWD/uithememanager.cpp \ $$PWD/uithememanager.cpp \
$$PWD/updownratiodialog.cpp \
$$PWD/utils.cpp $$PWD/utils.cpp
win32|macx { win32|macx {
@@ -207,7 +207,7 @@ FORMS += \
$$PWD/statsdialog.ui \ $$PWD/statsdialog.ui \
$$PWD/torrentcategorydialog.ui \ $$PWD/torrentcategorydialog.ui \
$$PWD/torrentcreatordialog.ui \ $$PWD/torrentcreatordialog.ui \
$$PWD/trackerentriesdialog.ui \ $$PWD/torrentoptionsdialog.ui \
$$PWD/updownratiodialog.ui $$PWD/trackerentriesdialog.ui
RESOURCES += $$PWD/about.qrc RESOURCES += $$PWD/about.qrc

View File

@@ -38,10 +38,12 @@
#include "ui_ipsubnetwhitelistoptionsdialog.h" #include "ui_ipsubnetwhitelistoptionsdialog.h"
#include "utils.h" #include "utils.h"
#define SETTINGS_KEY(name) "IPSubnetWhitelistOptionsDialog/" name
IPSubnetWhitelistOptionsDialog::IPSubnetWhitelistOptionsDialog(QWidget *parent) IPSubnetWhitelistOptionsDialog::IPSubnetWhitelistOptionsDialog(QWidget *parent)
: QDialog(parent) : QDialog(parent)
, m_ui(new Ui::IPSubnetWhitelistOptionsDialog) , m_ui(new Ui::IPSubnetWhitelistOptionsDialog)
, m_modified(false) , m_storeDialogSize(SETTINGS_KEY("Size"))
{ {
m_ui->setupUi(this); m_ui->setupUi(this);
@@ -58,11 +60,12 @@ IPSubnetWhitelistOptionsDialog::IPSubnetWhitelistOptionsDialog(QWidget *parent)
m_ui->whitelistedIPSubnetList->sortByColumn(0, Qt::AscendingOrder); m_ui->whitelistedIPSubnetList->sortByColumn(0, Qt::AscendingOrder);
m_ui->buttonWhitelistIPSubnet->setEnabled(false); m_ui->buttonWhitelistIPSubnet->setEnabled(false);
Utils::Gui::resize(this); Utils::Gui::resize(this, m_storeDialogSize);
} }
IPSubnetWhitelistOptionsDialog::~IPSubnetWhitelistOptionsDialog() IPSubnetWhitelistOptionsDialog::~IPSubnetWhitelistOptionsDialog()
{ {
m_storeDialogSize = size();
delete m_ui; delete m_ui;
} }

View File

@@ -30,6 +30,8 @@
#include <QDialog> #include <QDialog>
#include "base/settingvalue.h"
class QSortFilterProxyModel; class QSortFilterProxyModel;
class QStringListModel; class QStringListModel;
@@ -38,14 +40,14 @@ namespace Ui
class IPSubnetWhitelistOptionsDialog; class IPSubnetWhitelistOptionsDialog;
} }
class IPSubnetWhitelistOptionsDialog : public QDialog class IPSubnetWhitelistOptionsDialog final : public QDialog
{ {
Q_OBJECT Q_OBJECT
Q_DISABLE_COPY(IPSubnetWhitelistOptionsDialog) Q_DISABLE_COPY(IPSubnetWhitelistOptionsDialog)
public: public:
explicit IPSubnetWhitelistOptionsDialog(QWidget *parent = nullptr); explicit IPSubnetWhitelistOptionsDialog(QWidget *parent = nullptr);
~IPSubnetWhitelistOptionsDialog(); ~IPSubnetWhitelistOptionsDialog() override;
private slots: private slots:
void on_buttonBox_accepted(); void on_buttonBox_accepted();
@@ -55,7 +57,9 @@ private slots:
private: private:
Ui::IPSubnetWhitelistOptionsDialog *m_ui; Ui::IPSubnetWhitelistOptionsDialog *m_ui;
SettingValue<QSize> m_storeDialogSize;
QStringListModel *m_model; QStringListModel *m_model;
QSortFilterProxyModel *m_sortFilter; QSortFilterProxyModel *m_sortFilter;
bool m_modified; bool m_modified = false;
}; };

View File

@@ -155,7 +155,7 @@ LogMessageModel::LogMessageModel(QObject *parent)
void LogMessageModel::handleNewMessage(const Log::Msg &message) void LogMessageModel::handleNewMessage(const Log::Msg &message)
{ {
const QString time = QDateTime::fromMSecsSinceEpoch(message.timestamp).toString(Qt::SystemLocaleShortDate); const QString time = QLocale::system().toString(QDateTime::fromMSecsSinceEpoch(message.timestamp), QLocale::ShortFormat);
const QString messageText = message.message; const QString messageText = message.message;
const QColor foreground = m_foregroundForMessageTypes[message.type]; const QColor foreground = m_foregroundForMessageTypes[message.type];
@@ -173,7 +173,7 @@ LogPeerModel::LogPeerModel(QObject *parent)
void LogPeerModel::handleNewMessage(const Log::Peer &peer) void LogPeerModel::handleNewMessage(const Log::Peer &peer)
{ {
const QString time = QDateTime::fromMSecsSinceEpoch(peer.timestamp).toString(Qt::SystemLocaleShortDate); const QString time = QLocale::system().toString(QDateTime::fromMSecsSinceEpoch(peer.timestamp), QLocale::ShortFormat);
const QString message = peer.blocked const QString message = peer.blocked
? tr("%1 was blocked. Reason: %2.", "0.0.0.0 was blocked. Reason: reason for blocking.").arg(peer.ip, peer.reason) ? tr("%1 was blocked. Reason: %2.", "0.0.0.0 was blocked. Reason: reason for blocking.").arg(peer.ip, peer.reason)
: tr("%1 was banned", "0.0.0.0 was banned").arg(peer.ip); : tr("%1 was banned", "0.0.0.0 was banned").arg(peer.ip);

View File

@@ -58,7 +58,7 @@
#include "base/bittorrent/session.h" #include "base/bittorrent/session.h"
#include "base/bittorrent/sessionstatus.h" #include "base/bittorrent/sessionstatus.h"
#include "base/bittorrent/torrenthandle.h" #include "base/bittorrent/torrent.h"
#include "base/global.h" #include "base/global.h"
#include "base/logger.h" #include "base/logger.h"
#include "base/net/downloadmanager.h" #include "base/net/downloadmanager.h"
@@ -70,6 +70,7 @@
#include "base/utils/fs.h" #include "base/utils/fs.h"
#include "base/utils/misc.h" #include "base/utils/misc.h"
#include "base/utils/password.h" #include "base/utils/password.h"
#include "base/version.h"
#include "aboutdialog.h" #include "aboutdialog.h"
#include "addnewtorrentdialog.h" #include "addnewtorrentdialog.h"
#include "autoexpandabledialog.h" #include "autoexpandabledialog.h"
@@ -172,10 +173,7 @@ MainWindow::MainWindow(QWidget *parent)
m_ui->actionOpen->setIcon(UIThemeManager::instance()->getIcon("list-add")); m_ui->actionOpen->setIcon(UIThemeManager::instance()->getIcon("list-add"));
m_ui->actionDownloadFromURL->setIcon(UIThemeManager::instance()->getIcon("insert-link")); m_ui->actionDownloadFromURL->setIcon(UIThemeManager::instance()->getIcon("insert-link"));
m_ui->actionSetUploadLimit->setIcon(UIThemeManager::instance()->getIcon("kt-set-max-upload-speed")); m_ui->actionSetGlobalSpeedLimits->setIcon(UIThemeManager::instance()->getIcon("speedometer"));
m_ui->actionSetDownloadLimit->setIcon(UIThemeManager::instance()->getIcon("kt-set-max-download-speed"));
m_ui->actionSetGlobalUploadLimit->setIcon(UIThemeManager::instance()->getIcon("kt-set-max-upload-speed"));
m_ui->actionSetGlobalDownloadLimit->setIcon(UIThemeManager::instance()->getIcon("kt-set-max-download-speed"));
m_ui->actionCreateTorrent->setIcon(UIThemeManager::instance()->getIcon("document-edit")); m_ui->actionCreateTorrent->setIcon(UIThemeManager::instance()->getIcon("document-edit"));
m_ui->actionAbout->setIcon(UIThemeManager::instance()->getIcon("help-about")); m_ui->actionAbout->setIcon(UIThemeManager::instance()->getIcon("help-about"));
m_ui->actionStatistics->setIcon(UIThemeManager::instance()->getIcon("view-statistics")); m_ui->actionStatistics->setIcon(UIThemeManager::instance()->getIcon("view-statistics"));
@@ -211,8 +209,6 @@ MainWindow::MainWindow(QWidget *parent)
connect(BitTorrent::Session::instance(), &BitTorrent::Session::downloadFromUrlFailed, this, &MainWindow::handleDownloadFromUrlFailure); connect(BitTorrent::Session::instance(), &BitTorrent::Session::downloadFromUrlFailed, this, &MainWindow::handleDownloadFromUrlFailure);
connect(BitTorrent::Session::instance(), &BitTorrent::Session::speedLimitModeChanged, this, &MainWindow::updateAltSpeedsBtn); connect(BitTorrent::Session::instance(), &BitTorrent::Session::speedLimitModeChanged, this, &MainWindow::updateAltSpeedsBtn);
connect(BitTorrent::Session::instance(), &BitTorrent::Session::recursiveTorrentDownloadPossible, this, &MainWindow::askRecursiveTorrentDownloadConfirmation); connect(BitTorrent::Session::instance(), &BitTorrent::Session::recursiveTorrentDownloadPossible, this, &MainWindow::askRecursiveTorrentDownloadConfirmation);
connect(BitTorrent::Session::instance(), &BitTorrent::Session::torrentStorageMoveFinished, this, &MainWindow::moveTorrentFinished);
connect(BitTorrent::Session::instance(), &BitTorrent::Session::torrentStorageMoveFailed, this, &MainWindow::moveTorrentFailed);
qDebug("create tabWidget"); qDebug("create tabWidget");
m_tabs = new HidableTabWidget(this); m_tabs = new HidableTabWidget(this);
@@ -264,11 +260,11 @@ MainWindow::MainWindow(QWidget *parent)
connect(BitTorrent::Session::instance(), &BitTorrent::Session::trackerlessStateChanged, m_transferListFiltersWidget, &TransferListFiltersWidget::changeTrackerless); connect(BitTorrent::Session::instance(), &BitTorrent::Session::trackerlessStateChanged, m_transferListFiltersWidget, &TransferListFiltersWidget::changeTrackerless);
connect(BitTorrent::Session::instance(), &BitTorrent::Session::trackerSuccess connect(BitTorrent::Session::instance(), &BitTorrent::Session::trackerSuccess
, m_transferListFiltersWidget, qOverload<const BitTorrent::TorrentHandle *, const QString &>(&TransferListFiltersWidget::trackerSuccess)); , m_transferListFiltersWidget, qOverload<const BitTorrent::Torrent *, const QString &>(&TransferListFiltersWidget::trackerSuccess));
connect(BitTorrent::Session::instance(), &BitTorrent::Session::trackerError connect(BitTorrent::Session::instance(), &BitTorrent::Session::trackerError
, m_transferListFiltersWidget, qOverload<const BitTorrent::TorrentHandle *, const QString &>(&TransferListFiltersWidget::trackerError)); , m_transferListFiltersWidget, qOverload<const BitTorrent::Torrent *, const QString &>(&TransferListFiltersWidget::trackerError));
connect(BitTorrent::Session::instance(), &BitTorrent::Session::trackerWarning connect(BitTorrent::Session::instance(), &BitTorrent::Session::trackerWarning
, m_transferListFiltersWidget, qOverload<const BitTorrent::TorrentHandle *, const QString &>(&TransferListFiltersWidget::trackerWarning)); , m_transferListFiltersWidget, qOverload<const BitTorrent::Torrent *, const QString &>(&TransferListFiltersWidget::trackerWarning));
#ifdef Q_OS_MACOS #ifdef Q_OS_MACOS
// Increase top spacing to avoid tab overlapping // Increase top spacing to avoid tab overlapping
@@ -494,7 +490,7 @@ MainWindow::~MainWindow()
bool MainWindow::isExecutionLogEnabled() const bool MainWindow::isExecutionLogEnabled() const
{ {
return settings()->loadValue(KEY_EXECUTIONLOG_ENABLED, false).toBool(); return settings()->loadValue(KEY_EXECUTIONLOG_ENABLED, false);
} }
void MainWindow::setExecutionLogEnabled(bool value) void MainWindow::setExecutionLogEnabled(bool value)
@@ -506,7 +502,7 @@ int MainWindow::executionLogMsgTypes() const
{ {
// as default value we need all the bits set // as default value we need all the bits set
// -1 is considered the portable way to achieve that // -1 is considered the portable way to achieve that
return settings()->loadValue(KEY_EXECUTIONLOG_TYPES, -1).toInt(); return settings()->loadValue(KEY_EXECUTIONLOG_TYPES, -1);
} }
void MainWindow::setExecutionLogMsgTypes(const int value) void MainWindow::setExecutionLogMsgTypes(const int value)
@@ -517,7 +513,7 @@ void MainWindow::setExecutionLogMsgTypes(const int value)
bool MainWindow::isNotificationsEnabled() const bool MainWindow::isNotificationsEnabled() const
{ {
return settings()->loadValue(KEY_NOTIFICATIONS_ENABLED, true).toBool(); return settings()->loadValue(KEY_NOTIFICATIONS_ENABLED, true);
} }
void MainWindow::setNotificationsEnabled(bool value) void MainWindow::setNotificationsEnabled(bool value)
@@ -527,7 +523,7 @@ void MainWindow::setNotificationsEnabled(bool value)
bool MainWindow::isTorrentAddedNotificationsEnabled() const bool MainWindow::isTorrentAddedNotificationsEnabled() const
{ {
return settings()->loadValue(KEY_NOTIFICATIONS_TORRENTADDED, false).toBool(); return settings()->loadValue(KEY_NOTIFICATIONS_TORRENTADDED, false);
} }
void MainWindow::setTorrentAddedNotificationsEnabled(bool value) void MainWindow::setTorrentAddedNotificationsEnabled(bool value)
@@ -537,7 +533,7 @@ void MainWindow::setTorrentAddedNotificationsEnabled(bool value)
bool MainWindow::isDownloadTrackerFavicon() const bool MainWindow::isDownloadTrackerFavicon() const
{ {
return settings()->loadValue(KEY_DOWNLOAD_TRACKER_FAVICON, false).toBool(); return settings()->loadValue(KEY_DOWNLOAD_TRACKER_FAVICON, false);
} }
void MainWindow::setDownloadTrackerFavicon(bool value) void MainWindow::setDownloadTrackerFavicon(bool value)
@@ -862,30 +858,20 @@ void MainWindow::addTorrentFailed(const QString &error) const
} }
// called when a torrent was added // called when a torrent was added
void MainWindow::torrentNew(BitTorrent::TorrentHandle *const torrent) const void MainWindow::torrentNew(BitTorrent::Torrent *const torrent) const
{ {
if (isTorrentAddedNotificationsEnabled()) if (isTorrentAddedNotificationsEnabled())
showNotificationBaloon(tr("Torrent added"), tr("'%1' was added.", "e.g: xxx.avi was added.").arg(torrent->name())); showNotificationBaloon(tr("Torrent added"), tr("'%1' was added.", "e.g: xxx.avi was added.").arg(torrent->name()));
} }
// called when a torrent has finished // called when a torrent has finished
void MainWindow::finishedTorrent(BitTorrent::TorrentHandle *const torrent) const void MainWindow::finishedTorrent(BitTorrent::Torrent *const torrent) const
{ {
showNotificationBaloon(tr("Download completion"), tr("'%1' has finished downloading.", "e.g: xxx.avi has finished downloading.").arg(torrent->name())); showNotificationBaloon(tr("Download completion"), tr("'%1' has finished downloading.", "e.g: xxx.avi has finished downloading.").arg(torrent->name()));
} }
void MainWindow::moveTorrentFinished(BitTorrent::TorrentHandle *const torrent, const QString &newPath) const
{
showNotificationBaloon(tr("Torrent moving finished"), tr("'%1' has finished moving files to '%2'.").arg(torrent->name(), newPath));
}
void MainWindow::moveTorrentFailed(BitTorrent::TorrentHandle *const torrent, const QString &targetPath, const QString &error) const
{
showNotificationBaloon(tr("Torrent moving failed"), tr("'%1' has failed moving files to '%2'. Reason: %3").arg(torrent->name(), targetPath, error));
}
// Notification when disk is full // Notification when disk is full
void MainWindow::fullDiskError(BitTorrent::TorrentHandle *const torrent, const QString &msg) const void MainWindow::fullDiskError(BitTorrent::Torrent *const torrent, const QString &msg) const
{ {
showNotificationBaloon(tr("I/O Error", "i.e: Input/Output Error") showNotificationBaloon(tr("I/O Error", "i.e: Input/Output Error")
, tr("An I/O error occurred for torrent '%1'.\n Reason: %2" , tr("An I/O error occurred for torrent '%1'.\n Reason: %2"
@@ -975,7 +961,7 @@ void MainWindow::displayExecutionLogTab()
// End of keyboard shortcuts slots // End of keyboard shortcuts slots
void MainWindow::askRecursiveTorrentDownloadConfirmation(BitTorrent::TorrentHandle *const torrent) void MainWindow::askRecursiveTorrentDownloadConfirmation(BitTorrent::Torrent *const torrent)
{ {
Preferences *const pref = Preferences::instance(); Preferences *const pref = Preferences::instance();
if (pref->recursiveDownloadDisabled()) return; if (pref->recursiveDownloadDisabled()) return;
@@ -1008,36 +994,11 @@ void MainWindow::handleDownloadFromUrlFailure(const QString &url, const QString
, tr("Couldn't download file at URL '%1', reason: %2.").arg(url, reason)); , tr("Couldn't download file at URL '%1', reason: %2.").arg(url, reason));
} }
void MainWindow::on_actionSetGlobalUploadLimit_triggered() void MainWindow::on_actionSetGlobalSpeedLimits_triggered()
{ {
qDebug() << Q_FUNC_INFO; auto dialog = new SpeedLimitDialog {this};
dialog->setAttribute(Qt::WA_DeleteOnClose);
BitTorrent::Session *const session = BitTorrent::Session::instance(); dialog->open();
bool ok = false;
const long newLimit = SpeedLimitDialog::askSpeedLimit(
this, &ok, tr("Global Upload Speed Limit"), session->uploadSpeedLimit());
if (ok)
{
qDebug("Setting global upload rate limit to %.1fKb/s", newLimit / 1024.);
session->setUploadSpeedLimit(newLimit);
}
}
void MainWindow::on_actionSetGlobalDownloadLimit_triggered()
{
qDebug() << Q_FUNC_INFO;
BitTorrent::Session *const session = BitTorrent::Session::instance();
bool ok = false;
const long newLimit = SpeedLimitDialog::askSpeedLimit(
this, &ok, tr("Global Download Speed Limit"), session->downloadSpeedLimit());
if (ok)
{
qDebug("Setting global download rate limit to %.1fKb/s", newLimit / 1024.);
session->setDownloadSpeedLimit(newLimit);
}
} }
// Necessary if we want to close the window // Necessary if we want to close the window
@@ -1678,7 +1639,7 @@ void MainWindow::reloadSessionStats()
} }
} }
void MainWindow::reloadTorrentStats(const QVector<BitTorrent::TorrentHandle *> &torrents) void MainWindow::reloadTorrentStats(const QVector<BitTorrent::Torrent *> &torrents)
{ {
if (currentTabWidget() == m_transferListWidget) if (currentTabWidget() == m_transferListWidget)
{ {
@@ -1808,8 +1769,7 @@ QMenu *MainWindow::trayIconMenu()
updateAltSpeedsBtn(isAltBWEnabled); updateAltSpeedsBtn(isAltBWEnabled);
m_ui->actionUseAlternativeSpeedLimits->setChecked(isAltBWEnabled); m_ui->actionUseAlternativeSpeedLimits->setChecked(isAltBWEnabled);
m_trayIconMenu->addAction(m_ui->actionUseAlternativeSpeedLimits); m_trayIconMenu->addAction(m_ui->actionUseAlternativeSpeedLimits);
m_trayIconMenu->addAction(m_ui->actionSetGlobalDownloadLimit); m_trayIconMenu->addAction(m_ui->actionSetGlobalSpeedLimits);
m_trayIconMenu->addAction(m_ui->actionSetGlobalUploadLimit);
m_trayIconMenu->addSeparator(); m_trayIconMenu->addSeparator();
m_trayIconMenu->addAction(m_ui->actionStartAll); m_trayIconMenu->addAction(m_ui->actionStartAll);
m_trayIconMenu->addAction(m_ui->actionPauseAll); m_trayIconMenu->addAction(m_ui->actionPauseAll);

View File

@@ -58,7 +58,7 @@ class TransferListWidget;
namespace BitTorrent namespace BitTorrent
{ {
class TorrentHandle; class Torrent;
} }
namespace Net namespace Net
@@ -110,7 +110,7 @@ private slots:
void balloonClicked(); void balloonClicked();
void writeSettings(); void writeSettings();
void readSettings(); void readSettings();
void fullDiskError(BitTorrent::TorrentHandle *const torrent, const QString &msg) const; void fullDiskError(BitTorrent::Torrent *const torrent, const QString &msg) const;
void handleDownloadFromUrlFailure(const QString &, const QString &) const; void handleDownloadFromUrlFailure(const QString &, const QString &) const;
void tabChanged(int newTab); void tabChanged(int newTab);
bool defineUILockPassword(); bool defineUILockPassword();
@@ -127,14 +127,12 @@ private slots:
void displayExecutionLogTab(); void displayExecutionLogTab();
void focusSearchFilter(); void focusSearchFilter();
void reloadSessionStats(); void reloadSessionStats();
void reloadTorrentStats(const QVector<BitTorrent::TorrentHandle *> &torrents); void reloadTorrentStats(const QVector<BitTorrent::Torrent *> &torrents);
void loadPreferences(bool configureSession = true); void loadPreferences(bool configureSession = true);
void addTorrentFailed(const QString &error) const; void addTorrentFailed(const QString &error) const;
void torrentNew(BitTorrent::TorrentHandle *const torrent) const; void torrentNew(BitTorrent::Torrent *const torrent) const;
void finishedTorrent(BitTorrent::TorrentHandle *const torrent) const; void finishedTorrent(BitTorrent::Torrent *const torrent) const;
void moveTorrentFinished(BitTorrent::TorrentHandle *const torrent, const QString &newPath) const; void askRecursiveTorrentDownloadConfirmation(BitTorrent::Torrent *const torrent);
void moveTorrentFailed(BitTorrent::TorrentHandle *const torrent, const QString &targetPath, const QString &error) const;
void askRecursiveTorrentDownloadConfirmation(BitTorrent::TorrentHandle *const torrent);
void optionsSaved(); void optionsSaved();
#if defined(Q_OS_WIN) || defined(Q_OS_MACOS) #if defined(Q_OS_WIN) || defined(Q_OS_MACOS)
void handleUpdateCheckFinished(bool updateAvailable, QString newVersion, bool invokedByUser); void handleUpdateCheckFinished(bool updateAvailable, QString newVersion, bool invokedByUser);
@@ -171,8 +169,7 @@ private slots:
void on_actionStatistics_triggered(); void on_actionStatistics_triggered();
void on_actionCreateTorrent_triggered(); void on_actionCreateTorrent_triggered();
void on_actionOptions_triggered(); void on_actionOptions_triggered();
void on_actionSetGlobalUploadLimit_triggered(); void on_actionSetGlobalSpeedLimits_triggered();
void on_actionSetGlobalDownloadLimit_triggered();
void on_actionDocumentation_triggered() const; void on_actionDocumentation_triggered() const;
void on_actionOpen_triggered(); void on_actionOpen_triggered();
void on_actionDownloadFromURL_triggered(); void on_actionDownloadFromURL_triggered();

View File

@@ -223,29 +223,14 @@
<string>Torrent &amp;Creator</string> <string>Torrent &amp;Creator</string>
</property> </property>
</action> </action>
<action name="actionSetUploadLimit">
<property name="text">
<string>Set Upload Limit...</string>
</property>
</action>
<action name="actionSetDownloadLimit">
<property name="text">
<string>Set Download Limit...</string>
</property>
</action>
<action name="actionDocumentation"> <action name="actionDocumentation">
<property name="text"> <property name="text">
<string>&amp;Documentation</string> <string>&amp;Documentation</string>
</property> </property>
</action> </action>
<action name="actionSetGlobalDownloadLimit"> <action name="actionSetGlobalSpeedLimits">
<property name="text"> <property name="text">
<string>Set Global Download Limit...</string> <string>Set Global Speed Limits...</string>
</property>
</action>
<action name="actionSetGlobalUploadLimit">
<property name="text">
<string>Set Global Upload Limit...</string>
</property> </property>
</action> </action>
<action name="actionBottomQueuePos"> <action name="actionBottomQueuePos">

View File

@@ -68,6 +68,8 @@
#include "uithememanager.h" #include "uithememanager.h"
#include "utils.h" #include "utils.h"
#define SETTINGS_KEY(name) "OptionsDialog/" name
namespace namespace
{ {
QStringList translatedWeekdayNames() QStringList translatedWeekdayNames()
@@ -88,6 +90,7 @@ namespace
{ {
case QLocale::Arabic: return QString::fromUtf8(C_LOCALE_ARABIC); case QLocale::Arabic: return QString::fromUtf8(C_LOCALE_ARABIC);
case QLocale::Armenian: return QString::fromUtf8(C_LOCALE_ARMENIAN); case QLocale::Armenian: return QString::fromUtf8(C_LOCALE_ARMENIAN);
case QLocale::Azerbaijani: return QString::fromUtf8(C_LOCALE_AZERBAIJANI);
case QLocale::Basque: return QString::fromUtf8(C_LOCALE_BASQUE); case QLocale::Basque: return QString::fromUtf8(C_LOCALE_BASQUE);
case QLocale::Bulgarian: return QString::fromUtf8(C_LOCALE_BULGARIAN); case QLocale::Bulgarian: return QString::fromUtf8(C_LOCALE_BULGARIAN);
case QLocale::Byelorussian: return QString::fromUtf8(C_LOCALE_BYELORUSSIAN); case QLocale::Byelorussian: return QString::fromUtf8(C_LOCALE_BYELORUSSIAN);
@@ -110,6 +113,7 @@ namespace
case QLocale::UnitedKingdom: return QString::fromUtf8(C_LOCALE_ENGLISH_UNITEDKINGDOM); case QLocale::UnitedKingdom: return QString::fromUtf8(C_LOCALE_ENGLISH_UNITEDKINGDOM);
default: return QString::fromUtf8(C_LOCALE_ENGLISH); default: return QString::fromUtf8(C_LOCALE_ENGLISH);
} }
case QLocale::Estonian: return QString::fromUtf8(C_LOCALE_ESTONIAN);
case QLocale::Finnish: return QString::fromUtf8(C_LOCALE_FINNISH); case QLocale::Finnish: return QString::fromUtf8(C_LOCALE_FINNISH);
case QLocale::French: return QString::fromUtf8(C_LOCALE_FRENCH); case QLocale::French: return QString::fromUtf8(C_LOCALE_FRENCH);
case QLocale::Galician: return QString::fromUtf8(C_LOCALE_GALICIAN); case QLocale::Galician: return QString::fromUtf8(C_LOCALE_GALICIAN);
@@ -127,7 +131,7 @@ namespace
case QLocale::Latvian: return QString::fromUtf8(C_LOCALE_LATVIAN); case QLocale::Latvian: return QString::fromUtf8(C_LOCALE_LATVIAN);
case QLocale::Lithuanian: return QString::fromUtf8(C_LOCALE_LITHUANIAN); case QLocale::Lithuanian: return QString::fromUtf8(C_LOCALE_LITHUANIAN);
case QLocale::Malay: return QString::fromUtf8(C_LOCALE_MALAY); case QLocale::Malay: return QString::fromUtf8(C_LOCALE_MALAY);
case QLocale::Norwegian: return QString::fromUtf8(C_LOCALE_NORWEGIAN); case QLocale::NorwegianBokmal: return QString::fromUtf8(C_LOCALE_NORWEGIAN);
case QLocale::Occitan: return QString::fromUtf8(C_LOCALE_OCCITAN); case QLocale::Occitan: return QString::fromUtf8(C_LOCALE_OCCITAN);
case QLocale::Polish: return QString::fromUtf8(C_LOCALE_POLISH); case QLocale::Polish: return QString::fromUtf8(C_LOCALE_POLISH);
case QLocale::Portuguese: case QLocale::Portuguese:
@@ -167,9 +171,10 @@ private:
// Constructor // Constructor
OptionsDialog::OptionsDialog(QWidget *parent) OptionsDialog::OptionsDialog(QWidget *parent)
: QDialog(parent) : QDialog {parent}
, m_refreshingIpFilter(false) , m_ui {new Ui::OptionsDialog}
, m_ui(new Ui::OptionsDialog) , m_storeDialogSize {SETTINGS_KEY("Size")}
, m_storeHSplitterSize {SETTINGS_KEY("HorizontalSplitterSizes")}
{ {
qDebug("-> Constructing Options"); qDebug("-> Constructing Options");
m_ui->setupUi(this); m_ui->setupUi(this);
@@ -563,7 +568,7 @@ OptionsDialog::OptionsDialog(QWidget *parent)
for (QSpinBox *widget : asConst(findChildren<QSpinBox *>())) for (QSpinBox *widget : asConst(findChildren<QSpinBox *>()))
widget->installEventFilter(wheelEventEater); widget->installEventFilter(wheelEventEater);
loadWindowState(); Utils::Gui::resize(this, m_storeDialogSize);
show(); show();
// Have to be called after show(), because splitter width needed // Have to be called after show(), because splitter width needed
loadSplitterState(); loadSplitterState();
@@ -604,7 +609,13 @@ OptionsDialog::~OptionsDialog()
{ {
qDebug("-> destructing Options"); qDebug("-> destructing Options");
saveWindowState(); // save dialog states
m_storeDialogSize = size();
QStringList hSplitterSizes;
for (const int size : asConst(m_ui->hsplitter->sizes()))
hSplitterSizes.append(QString::number(size));
m_storeHSplitterSize = hSplitterSizes;
for (const QString &path : asConst(m_addedScanDirs)) for (const QString &path : asConst(m_addedScanDirs))
ScanFoldersModel::instance()->removePath(path); ScanFoldersModel::instance()->removePath(path);
@@ -619,38 +630,18 @@ void OptionsDialog::changePage(QListWidgetItem *current, QListWidgetItem *previo
m_ui->tabOption->setCurrentIndex(m_ui->tabSelection->row(current)); m_ui->tabOption->setCurrentIndex(m_ui->tabSelection->row(current));
} }
void OptionsDialog::loadWindowState()
{
Utils::Gui::resize(this, Preferences::instance()->getPrefSize());
}
void OptionsDialog::loadSplitterState() void OptionsDialog::loadSplitterState()
{ {
const QStringList sizesStr = Preferences::instance()->getPrefHSplitterSizes();
// width has been modified, use height as width reference instead // width has been modified, use height as width reference instead
const int width = Utils::Gui::scaledSize(this const int width = Utils::Gui::scaledSize(this
, (m_ui->tabSelection->item(TAB_UI)->sizeHint().height() * 2)); , (m_ui->tabSelection->item(TAB_UI)->sizeHint().height() * 2));
QList<int> sizes {width, (m_ui->hsplitter->width() - width)}; const QStringList defaultSizes = {QString::number(width), QString::number(m_ui->hsplitter->width() - width)};
if (sizesStr.size() == 2)
sizes = {sizesStr.first().toInt(), sizesStr.last().toInt()};
m_ui->hsplitter->setSizes(sizes);
}
void OptionsDialog::saveWindowState() const QList<int> splitterSizes;
{ for (const QString &string : asConst(m_storeHSplitterSize.get(defaultSizes)))
Preferences *const pref = Preferences::instance(); splitterSizes.append(string.toInt());
// window size m_ui->hsplitter->setSizes(splitterSizes);
pref->setPrefSize(size());
// Splitter size
const QStringList sizesStr =
{
QString::number(m_ui->hsplitter->sizes().first()),
QString::number(m_ui->hsplitter->sizes().last())
};
pref->setPrefHSplitterSizes(sizesStr);
} }
void OptionsDialog::saveOptions() void OptionsDialog::saveOptions()
@@ -1612,6 +1603,8 @@ void OptionsDialog::setLocale(const QString &localeStr)
QLocale locale(localeStr); QLocale locale(localeStr);
if (locale.language() == QLocale::Uzbek) if (locale.language() == QLocale::Uzbek)
name = "uz@Latn"; name = "uz@Latn";
else if (locale.language() == QLocale::Azerbaijani)
name = "az@latin";
else else
name = locale.name(); name = locale.name();
} }

Some files were not shown because too many files have changed in this diff Show More