Compare commits

...

53 Commits

Author SHA1 Message Date
sledgehammer999
1d26f4c5f7 Bump to 4.4.0beta2 2021-08-03 23:15:27 +03:00
sledgehammer999
8a09558ed8 Sync translations from Transifex and run lupdate 2021-08-03 23:14:08 +03:00
Daniel Aleksandersen
60b1e692b9 Disconnect comment links fom the WebUI (#15251) 2021-08-03 16:26:04 +08:00
Chocobo1
ce554e6c77 Merge pull request #15229 from Chocobo1/port
Use spinbox special value to represent "Use any available port"
2021-07-30 15:19:08 +08:00
xavier2k6
5d151cca9d GitHub Actions CI: update workflow (#15245)
- update vcpkg to latest commit (includes updated BOOST)
2021-07-30 15:18:38 +08:00
AbeniMatteo
e4730191db Set default file priorities when not specified (#15190) 2021-07-29 12:20:03 +08:00
Chocobo1
49aab492e0 Use spinbox special value to represent "Use any available port"
WebAPI functionality is preserved (deprecated) for now and should be
removed in the future.
2021-07-29 11:50:52 +08:00
Chocobo1
2d4d246268 Remember last viewed page in Options dialog (#15230) 2021-07-28 11:11:00 +08:00
Chocobo1
09e558ae0b Revise checkbox label for "Use any available ports" functionality
Also reorder the checkboxes a bit.
2021-07-27 13:35:18 +08:00
Chocobo1
a3fd6633c4 Use default property for widgets 2021-07-26 12:20:46 +08:00
Vladimir Golovnev
1eb246c98b Merge pull request #15181 from glassez/qt5
Raise minimum Qt version to 5.15.2
2021-07-23 06:22:57 +03:00
Chocobo1
96e0c0df20 Improve handling for magnet URI (#15209)
This add support for magnets URI in v2 hash format.
2021-07-22 13:05:59 +08:00
thalieht
aa8f420681 Recognise v2 info-hashes in clipboard for "Add torrent link" dialog (#15206) 2021-07-20 14:30:37 +03:00
Tom Piccirello
7974b5a95c Support sorting Web UI tables via touch (#15205) 2021-07-19 14:28:04 +08:00
Vladimir Golovnev
ed4570cb4d Store minimal metadata for "restore torrent" purposes (#15191)
We can no longer save valid torrent files in the general case, because
for torrents of version 2, we need a full merkle tree to do it, but if
a torrent is added from magnet link, full merkle tree may not be available
even before the end of downloading all the data. Actually, we don't need
the full torrent file for the purposes of resuming the torrent, so we can
allow libtorrent to produce only a minimal part of the metadata as part
complete resume data, but we still want to store it in a separate file,
so we extract the resulting metadata from the complete resume data before
saving and merge it together before loading.
2021-07-19 07:59:06 +03:00
AbeniMatteo
01d851440b Add "Forced metadata downloading" state (#15185) 2021-07-17 21:33:14 +03:00
AbeniMatteo
e5943b64c1 Add filter "Checking" to side panel (#15166) 2021-07-16 14:08:10 +03:00
scootergrisen
933e56494c Update Danish translation (#15192) 2021-07-16 12:55:05 +08:00
Kristof Mattei
140e73be4e Use the URI's setData to set query data (#15187)
This allows the system to properly encode the '|', instead of passing
the '|' on in the URL, which is not allowed and breaks proxies such as
Authelia.

Then, for the purpose of generalization, I pushed this pattern through
to all places where we join items with a '|'.

This comes with the caveat that when we have individual components which
contain a '|' or any other character that is not allowed per the
HTTP standard, we still like to encode the individual components,
for example in the case of 3 strings, separated by a '|'.
If we don't do this we run into the risk that upon decoding URI finds
'|' in our original strings, which is something we don't want.

For example:
Sender:
````javascript
const arr = ["foo|1", "bar|2"];
const uri = new URI("test.html").setData(arr.join("|"));
````
Then on the receiving window, when it receives the uri and splits it, it
looks like this:
````javascript
const arr = new URI().getData('hashes').split('|');
// arr is now ["foo", "1", "bar", "2"]
````

This is why when we want to send a literal "|" we need to do
`encodeURIComponent` and `decodeURIComponent` manually on each item,
and THEN we join.

For example:
Sender:
````javascript
const arr = ["foo|1", "bar|2"];
const uri = new URI("test.html").setData(arr.map(encodeURIComponent).join("|"));
````

Receiver:
````javascript
const arr = new URI().getData('hashes').split('|').map(decodeURIComponent);
// arr is now ["foo|1", "bar|2"]
````

We don't need to with hashes as they are HEX, so no risk of any weird
characters in there.
2021-07-16 12:53:47 +08:00
Vladimir Golovnev (glassez)
960b9b855f CI: Use Qt-5.15.2 on AppVeyor 2021-07-15 10:56:50 +03:00
FranciscoPombal
1e1d55b26d CI: Use Qt 5.15.2 from third-party PPA on Linux 2021-07-15 10:56:50 +03:00
Vladimir Golovnev (glassez)
925bf7715c Disable functions deprecated in Qt 5.15.2 and earlier 2021-07-15 10:56:49 +03:00
Vladimir Golovnev (Glassez)
399d3ad85a Replace QStringRef with QStringView 2021-07-15 10:56:49 +03:00
Chocobo1
d923c03d52 Merge pull request #15186 from Piccirello/webui-table-keyboard-nav
Support navigating Web UI tables with arrow keys
2021-07-13 11:26:50 +08:00
Vladimir Golovnev
699b91ab8d Properly create "clean path" for watched folder (#15179) 2021-07-12 11:44:52 +03:00
AbeniMatteo
abd6eb2ff3 Add context menu to toggle content tab columns (#15164) 2021-07-12 13:57:17 +08:00
Thomas Piccirello
32f29e72c6 Support expanding/collapsing Web UI folders with arrow keys 2021-07-11 03:01:31 -07:00
Thomas Piccirello
e76bac4131 Support navigating Web UI tables with arrow keys
This allows navigating rows via up/down arrow keys.
2021-07-11 03:01:31 -07:00
Thomas Piccirello
8b94642ab1 Always set Web UI row id as a string
This helps ensure consistent behavior when performing rowId comparisons against strings.
2021-07-10 11:50:48 -07:00
Chocobo1
d3497148c5 Merge pull request #15176 from Chocobo1/tooltip
Add tooltip for more widgets
2021-07-09 16:48:58 +08:00
Vladimir Golovnev (glassez)
27baa55443 Raise minimum Qt version to 5.15.2 2021-07-09 07:41:13 +03:00
Chocobo1
fd3d4d479a Suppress type narrowing warning on MSVC
Fix up 45e31a153c.
2021-07-08 14:25:39 +08:00
Chocobo1
4b0a2d050a Display tooltip for all columns in torrent content widget
It is primary useful for showing long file names.
2021-07-08 14:23:30 +08:00
Chocobo1
d85c14864b Add tooltip for "client ID" column
Sometimes the client ID could be quite long and this patch helps showing
it.
2021-07-08 14:22:59 +08:00
Chocobo1
ee696e6f36 Merge pull request #15170 from Chocobo1/tooltip
Add tooltip for various columns
2021-07-08 13:01:59 +08:00
Chocobo1
6ccbd8472c Merge pull request #15161 from Chocobo1/helper
Use `underlying_type` member directly
2021-07-08 13:01:46 +08:00
Chocobo1
8ec26e9ea9 Don't use old style casts
Ref: https://github.com/qbittorrent/qBittorrent/runs/2996702005?check_suite_focus=true#step:8:298
2021-07-07 14:44:39 +08:00
Chocobo1
45e31a153c Reserve space for vector 2021-07-07 14:20:27 +08:00
Chocobo1
7c23d800e6 Use underlying_type member directly
`LTUnderlyingType` served as a intermediate type for libtorrent 1.1 and
1.2 and is obsoleted now.
Also add helper to convert to underlying type.
2021-07-07 14:19:17 +08:00
Chocobo1
4dbf6af733 Simplify initialization statement 2021-07-07 13:20:13 +08:00
Chocobo1
bdc03b1c75 Add tooltip for various columns
Those strings sometimes are quite long and having a tooltip would
save the action of resizing the column width to see the full message.
The WebUI already has it done for all columns.
2021-07-07 13:19:29 +08:00
AbeniMatteo
9bfc74a1bc Filter torrent info endpoint by tag (#15152) 2021-07-05 13:55:49 +08:00
Vladimir Golovnev
5d03917877 Use torrent info with hashes for creating .torrent file (#15138) 2021-07-04 09:29:34 +03:00
Vladimir Golovnev (Glassez)
d2f975a0f3 Don't forget to start "watch timer" 2021-07-02 08:34:31 +03:00
Chocobo1
eedd47860a Merge pull request #15142 from Chocobo1/warning
Use proper signed number type
2021-07-01 11:35:04 +08:00
sledgehammer999
6e59248ea6 Merge pull request #15093 from FranciscoPombal/bump_libtorrent
Raise minimum libtorrent version to 1.2.14 (2.0.4)
2021-06-30 22:39:53 +03:00
Chocobo1
365554d064 Use proper signed number type
This also suppress the compiler warning:
src/base/bittorrent/torrentimpl.cpp:228:36: warning: comparison of integer expressions of different signedness: ‘int’ and ‘const size_t’ {aka ‘const long unsigned int’} [-Wsign-compare]
2021-06-29 18:04:33 +08:00
Chocobo1
70d1cb86fd Disable move constructor where it is sensible 2021-06-29 14:49:45 +08:00
FranciscoPombal
ccb7c0d579 Raise minimum libtorrent version to 1.2.14 (2.0.4)
- Also update vcpkg to latest commit: includes libtorrent 1.2.14,
Qt 5.15.2, and Qt 6.1.1
2021-06-28 23:04:47 +01:00
sledgehammer999
fd9941e2d8 Merge pull request #15131 from FranciscoPombal/goodbye_travis
Remove TravisCI config
2021-06-28 21:48:30 +03:00
FranciscoPombal
2f89563fca Remove TravisCI config 2021-06-28 10:41:16 +01:00
sledgehammer999
261f601bd5 Merge pull request #15129 from adem4ik/patch-5
Remove excess space in torrentfileswatcher.cpp
2021-06-27 15:32:50 +03:00
Andrei Stepanov
5157e4965a Remove excess space 2021-06-27 13:01:03 +04:00
279 changed files with 34610 additions and 36759 deletions

View File

@@ -43,7 +43,7 @@ install:
before_build:
# setup env
- CALL "C:\Program Files (x86)\Microsoft Visual Studio\2019\Community\VC\Auxiliary\Build\vcvars64.bat"
- SET PATH=%PATH%;c:\qbt\qt5_64\bin;%CACHE_DIR%\jom;
- SET PATH=%PATH%;C:\Qt\5.15.2\msvc2019_64\bin;%CACHE_DIR%\jom
# setup project
- COPY /Y "%CACHE_DIR%\conf.pri" "%REPO_DIR%"
# workarounds

View File

@@ -7,10 +7,10 @@ name: GitHub Actions CI
on: [pull_request, push]
env:
VCPKG_COMMIT: 8f03e2264da6b95fa5b01dd89cdd5b499458d428
VCPKG_COMMIT: 8dddc6c899ce6fdbeab38b525a31e7f23cb2d5bb
VCPKG_DEST_MACOS: /Users/runner/qbt_tools/vcpkg
VCPKG_DEST_WIN: C:\qbt_tools\vcpkg
LIBTORRENT_VERSION_TAG: v1.2.13
LIBTORRENT_VERSION_TAG: v1.2.14
jobs:
@@ -42,12 +42,12 @@ jobs:
libboost-dev libboost-chrono-dev libboost-random-dev libboost-system-dev
# sudo apt install libqt5svg5-dev qtbase5-dev qttools5-dev # the Qt version in the standard repositories is too old...
# this will be installed under /opt/qt514. CMake will still find it automatically without additional hints
# to speed up the process, only the required components are installed rather than the full qt514-meta-full metapackage
- name: install Qt 5.14.2 from an external PPA
# this will be installed under /opt/qt515. CMake will still find it automatically without additional hints
# to speed up the process, only the required components are installed rather than the full qt515-meta-full metapackage
- name: install Qt 5.15.2 from an external PPA
run: |
sudo add-apt-repository ppa:beineri/opt-qt-5.14.2-focal
sudo apt install qt514base qt514svg qt514tools
sudo add-apt-repository ppa:beineri/opt-qt-5.15.2-focal
sudo apt install qt515base qt515svg qt515tools
- name: install libtorrent from source
run: |

View File

@@ -1,194 +0,0 @@
language: cpp
os:
- linux
- osx
dist: focal
osx_image: xcode12.2
env:
matrix:
- libt_branch=RC_1_2 gui=true build_system=qmake
- libt_branch=RC_1_2 gui=false build_system=qmake
- libt_branch=RC_1_2 gui=true build_system=cmake
- libt_branch=RC_1_2 gui=false build_system=cmake
global:
- secure: "OI9CUjj4lTb0HwwIZU5PbECU3hLlAL6KC8KsbwohG8/O3j5fLcnmDsK4Ad9us5cC39sS11Jcd1kDP2qRcCuST/glVNhLkcjKkiQerOfd5nQ/qL4JYfz/1mfP5mdpz9jHKzpLUIG+TXkbSTjP6VVmsb5KPT+3pKEdRFZB+Pu9+J8="
- coverity_branch: coverity_scan
jobs:
include:
- env: libt_branch=RC_2_0 gui=true build_system=qmake
os: linux
notifications:
email:
on_success: change
on_failure: change
cache:
ccache: true
directories:
- $HOME/travis/deb
- $HOME/travis/brew
addons:
coverity_scan:
project:
name: "qbittorrent/qBittorrent"
description: "Build submitted via Travis CI"
build_command_prepend: "./bootstrap.sh && ./configure $qmake_conf"
build_command: "make -j2"
branch_pattern: $coverity_branch
notification_email: sledgehammer999@qbittorrent.org
apt:
sources:
# sources list: https://github.com/travis-ci/apt-source-safelist/blob/master/ubuntu.json
- sourceline: 'deb https://apt.kitware.com/ubuntu/ focal main'
key_url: 'https://apt.kitware.com/keys/kitware-archive-latest.asc'
- sourceline: 'ppa:beineri/opt-qt-5.14.2-focal'
packages:
# packages list: https://github.com/travis-ci/apt-package-safelist/blob/master/ubuntu-trusty
- [autoconf, automake, cmake, colormake]
- [libboost-dev, libboost-system-dev]
- libssl-dev
- [qt514base, qt514svg, qt514tools]
- zlib1g-dev
before_install:
# only allow specific build for coverity scan, others will stop
- if [ "$TRAVIS_BRANCH" = "$coverity_branch" ] && ! [ "$TRAVIS_OS_NAME" = "linux" -a "$libt_branch" = "RC_1_2" -a "$gui" = "true" -a "$build_system" = "qmake" ]; then exit ; fi
- shopt -s expand_aliases
- alias make="colormake -j2" # Using nprocs/2 sometimes may fail (gcc is killed by system)
- qbt_path="$HOME/qbt_install"
- qmake_conf="$qmake_conf --prefix=$qbt_path"
- cmake_conf="$cmake_conf -DCMAKE_INSTALL_PREFIX=$qbt_path"
# options for specific branches
- |
if [ "$TRAVIS_OS_NAME" = "linux" ]; then
# setup virtual display for after_success target
if [ "$gui" = "true" ]; then export "DISPLAY=:99.0" && /sbin/start-stop-daemon --start --quiet --pidfile /tmp/custom_xvfb_99.pid --make-pidfile --background --exec /usr/bin/Xvfb -- :99 -ac -screen 0 1280x1024x16 ; fi ;
# CMake from Kitware is installed in /usr/bin
# TravisCI installs its own cmake to another location which ovverides other installations
# if they don't call the new binary directly
alias cmake="/usr/bin/cmake"
# Qt 5.14.2
PATH="/opt/qt514/bin:$PATH"
qmake_conf="$qmake_conf PKG_CONFIG_PATH=/opt/qt514/lib/pkgconfig:$PKG_CONFIG_PATH"
cmake_conf="$cmake_conf PKG_CONFIG_PATH=/opt/qt514/lib/pkgconfig:$PKG_CONFIG_PATH"
export LD_LIBRARY_PATH="$LD_LIBRARY_PATH:/usr/local/lib"
fi
- |
if [ "$TRAVIS_OS_NAME" = "osx" ]; then
CXXFLAGS="$CXXFLAGS -Wno-unused-local-typedefs"
openssl_root_path="/usr/local/opt/openssl"
qmake_conf="$qmake_conf PKG_CONFIG_PATH=$openssl_root_path/lib/pkgconfig:$PKG_CONFIG_PATH"
cmake_conf="$cmake_conf -DOPENSSL_ROOT_DIR=$openssl_root_path"
fi
- |
if [ "$gui" = "false" ]; then
qmake_conf="$qmake_conf --disable-gui"
cmake_conf="$cmake_conf -DGUI=OFF"
fi
# print settings
- echo $libt_branch
- echo $gui
- echo $build_system
- echo $qmake_conf
- echo $cmake_conf
install:
- |
if [ "$TRAVIS_OS_NAME" = "osx" ]; then
# dependencies
PATH="/usr/local/opt/ccache/libexec:$PATH"
brew update > /dev/null
brew upgrade cmake
brew install ccache colormake boost openssl qt@5 zlib
brew link --force qt@5 zlib
if [ "$build_system" = "cmake" ]; then
sudo ln -s /usr/local/opt/qt/mkspecs /usr/local/mkspecs
sudo ln -s /usr/local/opt/qt/plugins /usr/local/plugins
fi
fi
- |
if [ "$TRAVIS_BRANCH" != "$coverity_branch" ]; then
export use_ccache=true
ccache -M 512M
ccache -V && ccache --show-stats && ccache --zero-stats
fi
- |
if [ "$libt_branch" = "RC_1_2" ]; then
pushd "$HOME"
git clone --single-branch --branch RC_1_2 https://github.com/arvidn/libtorrent.git
cd libtorrent
git checkout tags/v1.2.13
cmake \
-DCMAKE_BUILD_TYPE=Release \
-DCMAKE_CXX_STANDARD=17 \
-Ddeprecated-functions=OFF \
-DOPENSSL_ROOT_DIR="$openssl_root_path" \
./
make
sudo make install
popd
elif [ "$libt_branch" = "RC_2_0" ]; then
pushd "$HOME"
git clone --single-branch --branch RC_2_0 https://github.com/arvidn/libtorrent.git
cd libtorrent
git checkout tags/v2.0.3
git submodule update --init --recursive
cmake \
-DCMAKE_BUILD_TYPE=Release \
-DCMAKE_CXX_STANDARD=17 \
-Ddeprecated-functions=OFF \
-DOPENSSL_ROOT_DIR="$openssl_root_path" \
./
make
sudo make install
popd
fi
script:
- if [ "$TRAVIS_BRANCH" = "$coverity_branch" ]; then exit ; fi # skip usual build when running coverity scan
- |
cd "$TRAVIS_BUILD_DIR"
if [ "$build_system" = "qmake" ]; then
# scan only as lupdate is prone to hang
lupdate -extensions c,cpp,h,hpp,ui ./
./bootstrap.sh
./configure $qmake_conf CXXFLAGS="$CXXFLAGS"
else
mkdir build && cd build
cmake $cmake_conf ../
fi
- make
- make install
after_success:
- if [ "$gui" = "true" ]; then qbt_exe="qbittorrent" ; else qbt_exe="qbittorrent-nox" ; fi
- if [ "$TRAVIS_OS_NAME" = "linux" ]; then cd "$qbt_path/bin" ; fi
- |
if [ "$TRAVIS_OS_NAME" = "osx" ]; then
if [ "$build_system" = "qmake" ]; then
macdeployqt "$TRAVIS_BUILD_DIR/src/$qbt_exe.app"
cd "$TRAVIS_BUILD_DIR/src/$qbt_exe.app/Contents/MacOS"
else
cd "$qbt_path/$qbt_exe.app/Contents/MacOS"
fi
fi
- ./$qbt_exe --version
after_script:
- if [ "$use_ccache" = true ]; then ccache --show-stats ; fi

View File

@@ -12,9 +12,9 @@ project(qBittorrent
set(CMAKE_FIND_PACKAGE_PREFER_CONFIG ON)
# version requirements - older vesions may work, but you are on your own
set(minBoostVersion 1.65)
set(minQtVersion 5.14)
set(minQtVersion 5.15.2)
set(minOpenSSLVersion 1.1.1)
set(minLibtorrentVersion 1.2.13)
set(minLibtorrentVersion 1.2.14)
set(minZlibVersion 1.2.11)
# features (some are platform-specific)

View File

@@ -5,13 +5,13 @@ qBittorrent - A BitTorrent client in C++ / Qt
- Boost >= 1.65
- libtorrent-rasterbar >= 1.2.13 (by Arvid Norberg)
- libtorrent-rasterbar >= 1.2.14 (by Arvid Norberg)
* https://www.libtorrent.org/
* Be careful: another library (the one used by rTorrent) uses a similar name
- OpenSSL >= 1.1.1
- Qt >= 5.14
- Qt >= 5.15.2
- zlib >= 1.2.11

View File

@@ -1,7 +1,6 @@
qBittorrent - A BitTorrent client in Qt
------------------------------------------
[![TravisCI Status](https://travis-ci.org/qbittorrent/qBittorrent.svg?branch=master)](https://travis-ci.org/qbittorrent/qBittorrent)
[![AppVeyor Status](https://ci.appveyor.com/api/projects/status/github/qbittorrent/qBittorrent?branch=master&svg=true)](https://ci.appveyor.com/project/qbittorrent/qBittorrent)
[![GitHub Actions CI Status](https://github.com/qbittorrent/qBittorrent/workflows/GitHub%20Actions%20CI/badge.svg)](https://github.com/qbittorrent/qBittorrent/actions)
[![Coverity Status](https://scan.coverity.com/projects/5494/badge.svg)](https://scan.coverity.com/projects/5494)

View File

@@ -17,7 +17,7 @@ macro(qbt_common_config)
)
target_compile_definitions(qbt_common_cfg INTERFACE
QT_DISABLE_DEPRECATED_BEFORE=0x050e00
QT_DISABLE_DEPRECATED_BEFORE=0x050f02
QT_NO_CAST_TO_ASCII
QT_NO_CAST_FROM_BYTEARRAY
QT_USE_QSTRINGBUILDER

61
configure vendored
View File

@@ -1450,7 +1450,7 @@ Some influential environment variables:
directories to add to pkg-config's search path
PKG_CONFIG_LIBDIR
path overriding pkg-config's built-in search path
QT_QMAKE value of host_bins for Qt5Core >= 5.14, overriding pkg-config
QT_QMAKE value of host_bins for Qt5Core >= 5.15.2, overriding pkg-config
Qt5Svg_CFLAGS
C compiler flags for Qt5Svg, overriding pkg-config
Qt5Svg_LIBS linker flags for Qt5Svg, overriding pkg-config
@@ -5456,8 +5456,8 @@ printf "%s\n" "$enable_webui" >&6; }
esac
if test -n "$PKG_CONFIG" && \
{ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: \$PKG_CONFIG --exists --print-errors \"Qt5Core >= 5.14\""; } >&5
($PKG_CONFIG --exists --print-errors "Qt5Core >= 5.14") 2>&5
{ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: \$PKG_CONFIG --exists --print-errors \"Qt5Core >= 5.15.2\""; } >&5
($PKG_CONFIG --exists --print-errors "Qt5Core >= 5.15.2") 2>&5
ac_status=$?
printf "%s\n" "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
test $ac_status = 0; }; then
@@ -5466,12 +5466,12 @@ if test -n "$QT_QMAKE"; then
pkg_cv_QT_QMAKE="$QT_QMAKE"
elif test -n "$PKG_CONFIG"; then
if test -n "$PKG_CONFIG" && \
{ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: \$PKG_CONFIG --exists --print-errors \"Qt5Core >= 5.14\""; } >&5
($PKG_CONFIG --exists --print-errors "Qt5Core >= 5.14") 2>&5
{ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: \$PKG_CONFIG --exists --print-errors \"Qt5Core >= 5.15.2\""; } >&5
($PKG_CONFIG --exists --print-errors "Qt5Core >= 5.15.2") 2>&5
ac_status=$?
printf "%s\n" "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
test $ac_status = 0; }; then
pkg_cv_QT_QMAKE=`$PKG_CONFIG --variable="host_bins" "Qt5Core >= 5.14" 2>/dev/null`
pkg_cv_QT_QMAKE=`$PKG_CONFIG --variable="host_bins" "Qt5Core >= 5.15.2" 2>/dev/null`
test "x$?" != "x0" && pkg_failed=yes
else
pkg_failed=yes
@@ -5501,8 +5501,8 @@ fi
fi
{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for Qt5 qmake >= 5.14" >&5
printf %s "checking for Qt5 qmake >= 5.14... " >&6; }
{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for Qt5 qmake >= 5.15.2" >&5
printf %s "checking for Qt5 qmake >= 5.15.2... " >&6; }
if test "x$QT_QMAKE" != "x"
then :
{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $QT_QMAKE" >&5
@@ -5529,12 +5529,12 @@ if test -n "$Qt5Svg_CFLAGS"; then
pkg_cv_Qt5Svg_CFLAGS="$Qt5Svg_CFLAGS"
elif test -n "$PKG_CONFIG"; then
if test -n "$PKG_CONFIG" && \
{ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: \$PKG_CONFIG --exists --print-errors \"Qt5Svg >= 5.14\""; } >&5
($PKG_CONFIG --exists --print-errors "Qt5Svg >= 5.14") 2>&5
{ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: \$PKG_CONFIG --exists --print-errors \"Qt5Svg >= 5.15.2\""; } >&5
($PKG_CONFIG --exists --print-errors "Qt5Svg >= 5.15.2") 2>&5
ac_status=$?
printf "%s\n" "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
test $ac_status = 0; }; then
pkg_cv_Qt5Svg_CFLAGS=`$PKG_CONFIG --cflags "Qt5Svg >= 5.14" 2>/dev/null`
pkg_cv_Qt5Svg_CFLAGS=`$PKG_CONFIG --cflags "Qt5Svg >= 5.15.2" 2>/dev/null`
test "x$?" != "x0" && pkg_failed=yes
else
pkg_failed=yes
@@ -5546,12 +5546,12 @@ if test -n "$Qt5Svg_LIBS"; then
pkg_cv_Qt5Svg_LIBS="$Qt5Svg_LIBS"
elif test -n "$PKG_CONFIG"; then
if test -n "$PKG_CONFIG" && \
{ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: \$PKG_CONFIG --exists --print-errors \"Qt5Svg >= 5.14\""; } >&5
($PKG_CONFIG --exists --print-errors "Qt5Svg >= 5.14") 2>&5
{ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: \$PKG_CONFIG --exists --print-errors \"Qt5Svg >= 5.15.2\""; } >&5
($PKG_CONFIG --exists --print-errors "Qt5Svg >= 5.15.2") 2>&5
ac_status=$?
printf "%s\n" "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
test $ac_status = 0; }; then
pkg_cv_Qt5Svg_LIBS=`$PKG_CONFIG --libs "Qt5Svg >= 5.14" 2>/dev/null`
pkg_cv_Qt5Svg_LIBS=`$PKG_CONFIG --libs "Qt5Svg >= 5.15.2" 2>/dev/null`
test "x$?" != "x0" && pkg_failed=yes
else
pkg_failed=yes
@@ -5572,14 +5572,14 @@ else
_pkg_short_errors_supported=no
fi
if test $_pkg_short_errors_supported = yes; then
Qt5Svg_PKG_ERRORS=`$PKG_CONFIG --short-errors --print-errors --cflags --libs "Qt5Svg >= 5.14" 2>&1`
Qt5Svg_PKG_ERRORS=`$PKG_CONFIG --short-errors --print-errors --cflags --libs "Qt5Svg >= 5.15.2" 2>&1`
else
Qt5Svg_PKG_ERRORS=`$PKG_CONFIG --print-errors --cflags --libs "Qt5Svg >= 5.14" 2>&1`
Qt5Svg_PKG_ERRORS=`$PKG_CONFIG --print-errors --cflags --libs "Qt5Svg >= 5.15.2" 2>&1`
fi
# Put the nasty error message in config.log where it belongs
echo "$Qt5Svg_PKG_ERRORS" >&5
as_fn_error $? "Package requirements (Qt5Svg >= 5.14) were not met:
as_fn_error $? "Package requirements (Qt5Svg >= 5.15.2) were not met:
$Qt5Svg_PKG_ERRORS
@@ -5619,11 +5619,11 @@ case "x$enable_qt_dbus" in #(
"xyes") :
{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes" >&5
printf "%s\n" "yes" >&6; }
{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for Qt5DBus >= 5.14" >&5
printf %s "checking for Qt5DBus >= 5.14... " >&6; }
{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for Qt5DBus >= 5.15.2" >&5
printf %s "checking for Qt5DBus >= 5.15.2... " >&6; }
if test -n "$PKG_CONFIG" && \
{ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: \$PKG_CONFIG --exists --print-errors \"Qt5DBus >= 5.14\""; } >&5
($PKG_CONFIG --exists --print-errors "Qt5DBus >= 5.14") 2>&5
{ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: \$PKG_CONFIG --exists --print-errors \"Qt5DBus >= 5.15.2\""; } >&5
($PKG_CONFIG --exists --print-errors "Qt5DBus >= 5.15.2") 2>&5
ac_status=$?
printf "%s\n" "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
test $ac_status = 0; }; then
@@ -6039,12 +6039,12 @@ if test -n "$libtorrent_CFLAGS"; then
pkg_cv_libtorrent_CFLAGS="$libtorrent_CFLAGS"
elif test -n "$PKG_CONFIG"; then
if test -n "$PKG_CONFIG" && \
{ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: \$PKG_CONFIG --exists --print-errors \"libtorrent-rasterbar >= 1.2.13\""; } >&5
($PKG_CONFIG --exists --print-errors "libtorrent-rasterbar >= 1.2.13") 2>&5
{ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: \$PKG_CONFIG --exists --print-errors \"libtorrent-rasterbar >= 1.2.14\""; } >&5
($PKG_CONFIG --exists --print-errors "libtorrent-rasterbar >= 1.2.14") 2>&5
ac_status=$?
printf "%s\n" "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
test $ac_status = 0; }; then
pkg_cv_libtorrent_CFLAGS=`$PKG_CONFIG --cflags "libtorrent-rasterbar >= 1.2.13" 2>/dev/null`
pkg_cv_libtorrent_CFLAGS=`$PKG_CONFIG --cflags "libtorrent-rasterbar >= 1.2.14" 2>/dev/null`
test "x$?" != "x0" && pkg_failed=yes
else
pkg_failed=yes
@@ -6056,12 +6056,12 @@ if test -n "$libtorrent_LIBS"; then
pkg_cv_libtorrent_LIBS="$libtorrent_LIBS"
elif test -n "$PKG_CONFIG"; then
if test -n "$PKG_CONFIG" && \
{ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: \$PKG_CONFIG --exists --print-errors \"libtorrent-rasterbar >= 1.2.13\""; } >&5
($PKG_CONFIG --exists --print-errors "libtorrent-rasterbar >= 1.2.13") 2>&5
{ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: \$PKG_CONFIG --exists --print-errors \"libtorrent-rasterbar >= 1.2.14\""; } >&5
($PKG_CONFIG --exists --print-errors "libtorrent-rasterbar >= 1.2.14") 2>&5
ac_status=$?
printf "%s\n" "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
test $ac_status = 0; }; then
pkg_cv_libtorrent_LIBS=`$PKG_CONFIG --libs "libtorrent-rasterbar >= 1.2.13" 2>/dev/null`
pkg_cv_libtorrent_LIBS=`$PKG_CONFIG --libs "libtorrent-rasterbar >= 1.2.14" 2>/dev/null`
test "x$?" != "x0" && pkg_failed=yes
else
pkg_failed=yes
@@ -6082,14 +6082,14 @@ else
_pkg_short_errors_supported=no
fi
if test $_pkg_short_errors_supported = yes; then
libtorrent_PKG_ERRORS=`$PKG_CONFIG --short-errors --print-errors --cflags --libs "libtorrent-rasterbar >= 1.2.13" 2>&1`
libtorrent_PKG_ERRORS=`$PKG_CONFIG --short-errors --print-errors --cflags --libs "libtorrent-rasterbar >= 1.2.14" 2>&1`
else
libtorrent_PKG_ERRORS=`$PKG_CONFIG --print-errors --cflags --libs "libtorrent-rasterbar >= 1.2.13" 2>&1`
libtorrent_PKG_ERRORS=`$PKG_CONFIG --print-errors --cflags --libs "libtorrent-rasterbar >= 1.2.14" 2>&1`
fi
# Put the nasty error message in config.log where it belongs
echo "$libtorrent_PKG_ERRORS" >&5
as_fn_error $? "Package requirements (libtorrent-rasterbar >= 1.2.13) were not met:
as_fn_error $? "Package requirements (libtorrent-rasterbar >= 1.2.14) were not met:
$libtorrent_PKG_ERRORS
@@ -7845,4 +7845,3 @@ fi
{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: Good, the configure finished." >&5
printf "%s\n" "$as_me: Good, the configure finished." >&6;}
printf "%s\n"

View File

@@ -1,3 +1,4 @@
AC_INIT([qbittorrent], [v4.4.0alpha], [bugs.qbittorrent.org], [], [https://www.qbittorrent.org/])
AC_CONFIG_AUX_DIR([build-aux])
AC_CONFIG_MACRO_DIR([m4])
@@ -141,7 +142,7 @@ AS_IF([test "x$QT_QMAKE" = "x"],
[AC_MSG_ERROR([Could not find qmake])
])
AS_IF([test "x$enable_gui" = "xyes"],
[PKG_CHECK_MODULES(Qt5Svg, [Qt5Svg >= 5.14])
[PKG_CHECK_MODULES(Qt5Svg, [Qt5Svg >= 5.15.2])
])
AC_MSG_CHECKING([whether QtDBus should be enabled])
AS_CASE(["x$enable_qt_dbus"],
@@ -176,7 +177,7 @@ AC_COMPILE_IFELSE([DETECT_BOOST_VERSION_PROGRAM(106000)], [],
[QBT_ADD_DEFINES="$QBT_ADD_DEFINES BOOST_NO_CXX11_RVALUE_REFERENCES"])
PKG_CHECK_MODULES(libtorrent,
[libtorrent-rasterbar >= 1.2.13],
[libtorrent-rasterbar >= 1.2.14],
[CXXFLAGS="$libtorrent_CFLAGS $CXXFLAGS"
LIBS="$libtorrent_LIBS $LIBS"])

View File

@@ -177,8 +177,8 @@ Name[ur]=قیو بٹ ٹورنٹ
Comment[uk]=Завантажуйте та поширюйте файли через BitTorrent
GenericName[uk]=BitTorrent-клієнт
Name[uk]=qBittorrent
Comment[vi]=Tải xuống và chia sẻ tệp qua BitTorrent
GenericName[vi]=Client BitTorrent
Comment[vi]=Tải về và chia sẻ tệp qua BitTorrent
GenericName[vi]=Máy khách BitTorrent
Name[vi]=qBittorrent
Comment[az@latin]=Faylları BitTorrent vasitəsilə göndərin və paylaşın
GenericName[az@latin]=BitTorrent client

View File

@@ -7,7 +7,7 @@ LangString inst_dekstop ${LANG_DANISH} "Opret skrivebordsgenvej"
;LangString inst_startmenu ${LANG_ENGLISH} "Create Start Menu Shortcut"
LangString inst_startmenu ${LANG_DANISH} "Opret genvej i menuen Start"
;LangString inst_startup ${LANG_ENGLISH} "Start qBittorrent on Windows start up"
LangString inst_startup ${LANG_DANISH} "Start qBittorrent i Windows opstart"
LangString inst_startup ${LANG_DANISH} "Start qBittorrent når Windows starter"
;LangString inst_torrent ${LANG_ENGLISH} "Open .torrent files with qBittorrent"
LangString inst_torrent ${LANG_DANISH} "Åbn .torrent-filer med qBittorrent"
;LangString inst_magnet ${LANG_ENGLISH} "Open magnet links with qBittorrent"
@@ -15,7 +15,7 @@ LangString inst_magnet ${LANG_DANISH} "Åbn magnet-links med qBittorrent"
;LangString inst_firewall ${LANG_ENGLISH} "Add Windows Firewall rule"
LangString inst_firewall ${LANG_DANISH} "Tilføj Windows Firewall-regel"
;LangString inst_pathlimit ${LANG_ENGLISH} "Disable Windows path length limit (260 character MAX_PATH limitation, requires Windows 10 1607 or later)"
LangString inst_pathlimit ${LANG_DANISH} "Disable Windows path length limit (260 character MAX_PATH limitation, requires Windows 10 1607 or later)"
LangString inst_pathlimit ${LANG_DANISH} "Deaktivér grænse for for lang Windows-stien kan være (MAX_PATH-begrænsning på 260 tegn, kræver Windows 10 1607 eller senere)"
;LangString inst_firewallinfo ${LANG_ENGLISH} "Adding Windows Firewall rule"
LangString inst_firewallinfo ${LANG_DANISH} "Tilføjer Windows Firewall-regel"
;LangString inst_warning ${LANG_ENGLISH} "qBittorrent is running. Please close the application before installing."
@@ -27,11 +27,11 @@ LangString inst_unist ${LANG_DANISH} "Afinstallerer tidligere version."
;LangString launch_qbt ${LANG_ENGLISH} "Launch qBittorrent."
LangString launch_qbt ${LANG_DANISH} "Start qBittorrent."
;LangString inst_requires_64bit ${LANG_ENGLISH} "This installer works only in 64-bit Windows versions."
LangString inst_requires_64bit ${LANG_DANISH} "Dette installationsprogram virker kun i 64-bit Windows versioner."
LangString inst_requires_64bit ${LANG_DANISH} "Installationsprogrammet virker kun i Windows-versioner som er 64-bit."
;LangString inst_requires_win7 ${LANG_ENGLISH} "This qBittorrent version requires at least Windows 7."
LangString inst_requires_win7 ${LANG_DANISH} "This qBittorrent version requires at least Windows 7."
LangString inst_requires_win7 ${LANG_DANISH} "qBittorrent-versionen kræver mindst Windows 7."
;LangString inst_uninstall_link_description ${LANG_ENGLISH} "Uninstall qBittorrent"
LangString inst_uninstall_link_description ${LANG_DANISH} "Uninstall qBittorrent"
LangString inst_uninstall_link_description ${LANG_DANISH} "Afinstaller qBittorrent"
;------------------------------------
;Uninstaller strings

View File

@@ -5,9 +5,9 @@
# Sets the QT_QMAKE variable to the path of Qt5 qmake if found.
# --------------------------------------
AC_DEFUN([FIND_QT5],
[PKG_CHECK_EXISTS([Qt5Core >= 5.14],
[PKG_CHECK_EXISTS([Qt5Core >= 5.15.2],
[PKG_CHECK_VAR(QT_QMAKE,
[Qt5Core >= 5.14],
[Qt5Core >= 5.15.2],
[host_bins])
])
@@ -18,7 +18,7 @@ AS_IF([test -f "$QT_QMAKE/qmake"],
[QT_QMAKE=""])
])
AC_MSG_CHECKING([for Qt5 qmake >= 5.14])
AC_MSG_CHECKING([for Qt5 qmake >= 5.15.2])
AS_IF([test "x$QT_QMAKE" != "x"],
[AC_MSG_RESULT([$QT_QMAKE])],
[AC_MSG_RESULT([not found])]
@@ -29,8 +29,8 @@ AS_IF([test "x$QT_QMAKE" != "x"],
# Sets the HAVE_QTDBUS variable to true or false.
# --------------------------------------
AC_DEFUN([FIND_QTDBUS],
[AC_MSG_CHECKING([for Qt5DBus >= 5.14])
PKG_CHECK_EXISTS([Qt5DBus >= 5.14],
[AC_MSG_CHECKING([for Qt5DBus >= 5.15.2])
PKG_CHECK_EXISTS([Qt5DBus >= 5.15.2],
[AC_MSG_RESULT([found])
HAVE_QTDBUS=[true]],
[AC_MSG_RESULT([not found])

View File

@@ -435,16 +435,12 @@ void Application::runExternalProgram(const BitTorrent::Torrent *torrent) const
// enable command injection via torrent name and other arguments
// (especially when some automated download mechanism has been setup).
// See: https://github.com/qbittorrent/qBittorrent/issues/10925
#if (QT_VERSION >= QT_VERSION_CHECK(5, 15, 0))
QStringList args = QProcess::splitCommand(program);
if (args.isEmpty())
return;
const QString command = args.takeFirst();
QProcess::startDetached(command, args);
#else
QProcess::startDetached(program);
#endif
#endif
}
@@ -565,7 +561,7 @@ void Application::processParams(const QStringList &params)
if (param.startsWith(QLatin1String("@addPaused=")))
{
torrentParams.addPaused = (param.midRef(11).toInt() != 0);
torrentParams.addPaused = (QStringView(param).mid(11).toInt() != 0);
continue;
}
@@ -595,7 +591,7 @@ void Application::processParams(const QStringList &params)
if (param.startsWith(QLatin1String("@skipDialog=")))
{
skipTorrentDialog = (param.midRef(12).toInt() != 0);
skipTorrentDialog = (QStringView(param).mid(12).toInt() != 0);
continue;
}

View File

@@ -71,7 +71,7 @@ namespace RSS
class Application final : public BaseApplication
{
Q_OBJECT
Q_DISABLE_COPY(Application)
Q_DISABLE_COPY_MOVE(Application)
public:
Application(int &argc, char **argv);

View File

@@ -35,7 +35,7 @@ class QtLocalPeer;
class ApplicationInstanceManager : public QObject
{
Q_OBJECT
Q_DISABLE_COPY(ApplicationInstanceManager)
Q_DISABLE_COPY_MOVE(ApplicationInstanceManager)
public:
explicit ApplicationInstanceManager(const QString &appId, QObject *parent = nullptr);

View File

@@ -40,7 +40,7 @@ namespace Log
class FileLogger : public QObject
{
Q_OBJECT
Q_DISABLE_COPY(FileLogger)
Q_DISABLE_COPY_MOVE(FileLogger)
public:
enum FileLogAgeType

View File

@@ -39,7 +39,7 @@ namespace Ui
class StacktraceDialog : public QDialog
{
Q_OBJECT
Q_DISABLE_COPY(StacktraceDialog)
Q_DISABLE_COPY_MOVE(StacktraceDialog)
public:
explicit StacktraceDialog(QWidget *parent = nullptr);

View File

@@ -102,12 +102,28 @@ namespace
settingsStorage->storeValue(newKey, Utils::String::fromEnum(torrentContentLayout));
settingsStorage->removeValue(oldKey);
}
void upgradeListenPortSettings()
{
const auto oldKey = QString::fromLatin1("BitTorrent/Session/UseRandomPort");
const auto newKey = QString::fromLatin1("Preferences/Connection/PortRangeMin");
auto *settingsStorage = SettingsStorage::instance();
if (settingsStorage->hasKey(oldKey))
{
if (settingsStorage->loadValue<bool>(oldKey))
settingsStorage->storeValue(newKey, 0);
settingsStorage->removeValue(oldKey);
}
}
}
bool upgrade(const bool /*ask*/)
{
exportWebUIHttpsFiles();
upgradeTorrentContentLayout();
upgradeListenPortSettings();
return true;
}

View File

@@ -43,7 +43,7 @@ public:
class AsyncFileStorage : public QObject
{
Q_OBJECT
Q_DISABLE_COPY(AsyncFileStorage)
Q_DISABLE_COPY_MOVE(AsyncFileStorage)
public:
explicit AsyncFileStorage(const QString &storageFolderPath, QObject *parent = nullptr);

View File

@@ -35,7 +35,7 @@
class BandwidthScheduler : public QObject
{
Q_OBJECT
Q_DISABLE_COPY(BandwidthScheduler)
Q_DISABLE_COPY_MOVE(BandwidthScheduler)
public:
explicit BandwidthScheduler(QObject *parent = nullptr);

View File

@@ -30,9 +30,9 @@
#include <libtorrent/bdecode.hpp>
#include <libtorrent/bencode.hpp>
#include <libtorrent/create_torrent.hpp>
#include <libtorrent/entry.hpp>
#include <libtorrent/read_resume_data.hpp>
#include <libtorrent/torrent_info.hpp>
#include <libtorrent/write_resume_data.hpp>
#include <QByteArray>
@@ -51,13 +51,12 @@
#include "base/utils/string.h"
#include "infohash.h"
#include "loadtorrentparams.h"
#include "torrentinfo.h"
namespace BitTorrent
{
class BencodeResumeDataStorage::Worker final : public QObject
{
Q_DISABLE_COPY(Worker)
Q_DISABLE_COPY_MOVE(Worker)
public:
explicit Worker(const QDir &resumeDataDir);
@@ -151,25 +150,36 @@ std::optional<BitTorrent::LoadTorrentParams> BitTorrent::BencodeResumeDataStorag
const QString fastresumePath = m_resumeDataDir.absoluteFilePath(QString::fromLatin1("%1.fastresume").arg(idString));
const QString torrentFilePath = m_resumeDataDir.absoluteFilePath(QString::fromLatin1("%1.torrent").arg(idString));
QFile file {fastresumePath};
if (!file.open(QIODevice::ReadOnly))
QFile resumeDataFile {fastresumePath};
if (!resumeDataFile.open(QIODevice::ReadOnly))
{
LogMsg(tr("Cannot read file %1: %2").arg(fastresumePath, file.errorString()), Log::WARNING);
LogMsg(tr("Cannot read file %1: %2").arg(fastresumePath, resumeDataFile.errorString()), Log::WARNING);
return std::nullopt;
}
const QByteArray data = file.readAll();
const TorrentInfo metadata = TorrentInfo::loadFromFile(torrentFilePath);
QFile metadataFile {torrentFilePath};
if (metadataFile.exists() && !metadataFile.open(QIODevice::ReadOnly))
{
LogMsg(tr("Cannot read file %1: %2").arg(torrentFilePath, metadataFile.errorString()), Log::WARNING);
return std::nullopt;
}
const QByteArray data = resumeDataFile.readAll();
const QByteArray metadata = (metadataFile.isOpen() ? metadataFile.readAll() : "");
return loadTorrentResumeData(data, metadata);
}
std::optional<BitTorrent::LoadTorrentParams> BitTorrent::BencodeResumeDataStorage::loadTorrentResumeData(
const QByteArray &data, const TorrentInfo &metadata) const
const QByteArray &data, const QByteArray &metadata) const
{
const QByteArray allData = ((metadata.isEmpty() || data.isEmpty())
? data : (data.chopped(1) + metadata.mid(1)));
lt::error_code ec;
const lt::bdecode_node root = lt::bdecode(data, ec);
if (ec || (root.type() != lt::bdecode_node::dict_t)) return std::nullopt;
const lt::bdecode_node root = lt::bdecode(allData, ec);
if (ec || (root.type() != lt::bdecode_node::dict_t))
return std::nullopt;
LoadTorrentParams torrentParams;
torrentParams.restored = true;
@@ -220,8 +230,6 @@ std::optional<BitTorrent::LoadTorrentParams> BitTorrent::BencodeResumeDataStorag
p = lt::read_resume_data(root, ec);
p.save_path = Profile::instance()->fromPortablePath(fromLTString(p.save_path)).toStdString();
if (metadata.isValid())
p.ti = metadata.nativeInfo();
if (p.flags & lt::torrent_flags::stop_when_ready)
{
@@ -333,15 +341,22 @@ void BitTorrent::BencodeResumeDataStorage::Worker::store(const TorrentID &id, co
}
}
lt::entry data = lt::write_resume_data(p);
// metadata is stored in separate .torrent file
const std::shared_ptr<lt::torrent_info> torrentInfo = std::move(p.ti);
if (torrentInfo)
if (p.ti)
{
lt::entry::dictionary_type &dataDict = data.dict();
lt::entry metadata {lt::entry::dictionary_t};
lt::entry::dictionary_type &metadataDict = metadata.dict();
metadataDict.insert(dataDict.extract("info"));
metadataDict.insert(dataDict.extract("creation date"));
metadataDict.insert(dataDict.extract("created by"));
metadataDict.insert(dataDict.extract("comment"));
const QString torrentFilepath = m_resumeDataDir.absoluteFilePath(QString::fromLatin1("%1.torrent").arg(id.toString()));
try
{
const auto torrentCreator = lt::create_torrent(*torrentInfo);
const lt::entry metadata = torrentCreator.generate();
writeEntryToFile(torrentFilepath, metadata);
}
catch (const RuntimeError &err)
@@ -350,16 +365,8 @@ void BitTorrent::BencodeResumeDataStorage::Worker::store(const TorrentID &id, co
.arg(torrentFilepath, err.message()), Log::CRITICAL);
return;
}
catch (const std::exception &err)
{
LogMsg(tr("Couldn't save torrent metadata to '%1'. Error: %2.")
.arg(torrentFilepath, QString::fromLocal8Bit(err.what())), Log::CRITICAL);
return;
}
}
lt::entry data = lt::write_resume_data(p);
data["qBt-savePath"] = Profile::instance()->toPortablePath(resumeData.savePath).toStdString();
data["qBt-ratioLimit"] = static_cast<int>(resumeData.ratioLimit * 1000);
data["qBt-seedingTimeLimit"] = resumeData.seedingTimeLimit;

View File

@@ -38,12 +38,10 @@ class QThread;
namespace BitTorrent
{
class TorrentInfo;
class BencodeResumeDataStorage final : public ResumeDataStorage
{
Q_OBJECT
Q_DISABLE_COPY(BencodeResumeDataStorage)
Q_DISABLE_COPY_MOVE(BencodeResumeDataStorage)
public:
explicit BencodeResumeDataStorage(const QString &path, QObject *parent = nullptr);
@@ -57,7 +55,7 @@ namespace BitTorrent
private:
void loadQueue(const QString &queueFilename);
std::optional<LoadTorrentParams> loadTorrentResumeData(const QByteArray &data, const TorrentInfo &metadata) const;
std::optional<LoadTorrentParams> loadTorrentResumeData(const QByteArray &data, const QByteArray &metadata) const;
const QDir m_resumeDataDir;
QVector<TorrentID> m_registeredTorrents;

View File

@@ -30,9 +30,9 @@
#include <libtorrent/bdecode.hpp>
#include <libtorrent/bencode.hpp>
#include <libtorrent/create_torrent.hpp>
#include <libtorrent/entry.hpp>
#include <libtorrent/read_resume_data.hpp>
#include <libtorrent/torrent_info.hpp>
#include <libtorrent/write_resume_data.hpp>
#include <QByteArray>
@@ -52,7 +52,6 @@
#include "base/utils/string.h"
#include "infohash.h"
#include "loadtorrentparams.h"
#include "torrentinfo.h"
namespace
{
@@ -158,7 +157,7 @@ namespace BitTorrent
{
class DBResumeDataStorage::Worker final : public QObject
{
Q_DISABLE_COPY(Worker)
Q_DISABLE_COPY_MOVE(Worker)
public:
Worker(const QString &dbPath, const QString &dbConnectionName);
@@ -290,20 +289,19 @@ std::optional<BitTorrent::LoadTorrentParams> BitTorrent::DBResumeDataStorage::lo
resumeData.stopped = query.value(DB_COLUMN_STOPPED.name).toBool();
const QByteArray bencodedResumeData = query.value(DB_COLUMN_RESUMEDATA.name).toByteArray();
const QByteArray bencodedMetadata = query.value(DB_COLUMN_METADATA.name).toByteArray();
const QByteArray allData = ((bencodedMetadata.isEmpty() || bencodedResumeData.isEmpty())
? bencodedResumeData
: (bencodedResumeData.chopped(1) + bencodedMetadata.mid(1)));
lt::error_code ec;
const lt::bdecode_node root = lt::bdecode(bencodedResumeData, ec);
const lt::bdecode_node root = lt::bdecode(allData, ec);
lt::add_torrent_params &p = resumeData.ltAddTorrentParams;
p = lt::read_resume_data(root, ec);
p.save_path = Profile::instance()->fromPortablePath(fromLTString(p.save_path)).toStdString();
const QByteArray bencodedMetadata = query.value(DB_COLUMN_METADATA.name).toByteArray();
auto metadata = TorrentInfo::load(bencodedMetadata);
if (metadata.isValid())
p.ti = metadata.nativeInfo();
return resumeData;
}
@@ -453,16 +451,23 @@ void BitTorrent::DBResumeDataStorage::Worker::store(const TorrentID &id, const L
DB_COLUMN_RESUMEDATA
};
lt::entry data = lt::write_resume_data(p);
// metadata is stored in separate column
QByteArray bencodedMetadata;
bencodedMetadata.reserve(512 * 1024);
const std::shared_ptr<lt::torrent_info> torrentInfo = std::move(p.ti);
if (torrentInfo)
if (p.ti)
{
lt::entry::dictionary_type &dataDict = data.dict();
lt::entry metadata {lt::entry::dictionary_t};
lt::entry::dictionary_type &metadataDict = metadata.dict();
metadataDict.insert(dataDict.extract("info"));
metadataDict.insert(dataDict.extract("creation date"));
metadataDict.insert(dataDict.extract("created by"));
metadataDict.insert(dataDict.extract("comment"));
try
{
const auto torrentCreator = lt::create_torrent(*torrentInfo);
const lt::entry metadata = torrentCreator.generate();
bencodedMetadata.reserve(512 * 1024);
lt::bencode(std::back_inserter(bencodedMetadata), metadata);
}
catch (const std::exception &err)
@@ -477,7 +482,7 @@ void BitTorrent::DBResumeDataStorage::Worker::store(const TorrentID &id, const L
QByteArray bencodedResumeData;
bencodedResumeData.reserve(256 * 1024);
lt::bencode(std::back_inserter(bencodedResumeData), lt::write_resume_data(p));
lt::bencode(std::back_inserter(bencodedResumeData), data);
const QString insertTorrentStatement = makeInsertStatement(DB_TABLE_TORRENTS, columns)
+ makeOnConflictUpdateStatement(DB_COLUMN_TORRENT_ID, columns);
@@ -503,7 +508,7 @@ void BitTorrent::DBResumeDataStorage::Worker::store(const TorrentID &id, const L
query.bindValue(DB_COLUMN_OPERATING_MODE.placeholder, Utils::String::fromEnum(resumeData.operatingMode));
query.bindValue(DB_COLUMN_STOPPED.placeholder, resumeData.stopped);
query.bindValue(DB_COLUMN_RESUMEDATA.placeholder, bencodedResumeData);
if (torrentInfo)
if (!bencodedMetadata.isEmpty())
query.bindValue(DB_COLUMN_METADATA.placeholder, bencodedMetadata);
if (!query.exec())

View File

@@ -37,7 +37,7 @@ namespace BitTorrent
class DBResumeDataStorage final : public ResumeDataStorage
{
Q_OBJECT
Q_DISABLE_COPY(DBResumeDataStorage)
Q_DISABLE_COPY_MOVE(DBResumeDataStorage)
public:
explicit DBResumeDataStorage(const QString &dbPath, QObject *parent = nullptr);

View File

@@ -38,7 +38,7 @@ namespace BitTorrent
class FileSearcher final : public QObject
{
Q_OBJECT
Q_DISABLE_COPY(FileSearcher)
Q_DISABLE_COPY_MOVE(FileSearcher)
public:
FileSearcher() = default;

View File

@@ -28,31 +28,8 @@
#pragma once
#include <type_traits>
template <typename T, typename = void>
struct HasUnderlyingType
: std::false_type
{
};
template <typename T>
struct HasUnderlyingType<T, std::void_t<typename T::underlying_type>>
: std::true_type
typename T::underlying_type toLTUnderlyingType(const T &t)
{
};
template <typename T, typename = void>
struct LTUnderlying
{
using type = T;
};
template <typename T>
struct LTUnderlying<T, typename std::enable_if_t<HasUnderlyingType<T>::value>>
{
using type = typename T::underlying_type;
};
template <typename T>
using LTUnderlyingType = typename LTUnderlying<T>::type;
return static_cast<typename T::underlying_type>(t);
}

View File

@@ -39,21 +39,34 @@
namespace
{
bool isSHA1Hash(const QString &string)
// BEP9 Extension for Peers to Send Metadata Files
bool isV1Hash(const QString &string)
{
// There are 2 representations for BitTorrent info hash:
// There are 2 representations for BitTorrent v1 info hash:
// 1. 40 chars hex-encoded string
// == 20 (SHA-1 length in bytes) * 2 (each byte maps to 2 hex characters)
// 2. 32 chars Base32 encoded string
// == 20 (SHA-1 length in bytes) * 1.6 (the efficiency of Base32 encoding)
const int SHA1_HEX_SIZE = SHA1Hash::length() * 2;
const int SHA1_BASE32_SIZE = SHA1Hash::length() * 1.6;
const int V1_HEX_SIZE = SHA1Hash::length() * 2;
const int V1_BASE32_SIZE = SHA1Hash::length() * 1.6;
return ((((string.size() == SHA1_HEX_SIZE))
return ((((string.size() == V1_HEX_SIZE))
&& !string.contains(QRegularExpression(QLatin1String("[^0-9A-Fa-f]"))))
|| ((string.size() == SHA1_BASE32_SIZE)
|| ((string.size() == V1_BASE32_SIZE)
&& !string.contains(QRegularExpression(QLatin1String("[^2-7A-Za-z]")))));
}
bool isV2Hash(const QString &string)
{
// There are 1 representation for BitTorrent v2 info hash:
// 1. 64 chars hex-encoded string
// == 32 (SHA-2 256 length in bytes) * 2 (each byte maps to 2 hex characters)
const int V2_HEX_SIZE = SHA256Hash::length() * 2;
return (string.size() == V2_HEX_SIZE)
&& !string.contains(QRegularExpression(QLatin1String("[^0-9A-Fa-f]")));
}
}
using namespace BitTorrent;
@@ -66,8 +79,10 @@ MagnetUri::MagnetUri(const QString &source)
{
if (source.isEmpty()) return;
if (isSHA1Hash(source))
m_url = QLatin1String("magnet:?xt=urn:btih:") + source;
if (isV2Hash(source))
m_url = QString::fromLatin1("magnet:?xt=urn:btmh:") + source;
else if (isV1Hash(source))
m_url = QString::fromLatin1("magnet:?xt=urn:btih:") + source;
lt::error_code ec;
lt::parse_magnet_uri(m_url.toStdString(), m_addTorrentParams, ec);

View File

@@ -32,18 +32,18 @@
using namespace BitTorrent;
PeerAddress PeerAddress::parse(const QString &address)
PeerAddress PeerAddress::parse(const QStringView address)
{
QVector<QStringRef> ipPort;
QList<QStringView> ipPort;
if (address.startsWith('[') && address.contains("]:"))
if (address.startsWith(u'[') && address.contains(QLatin1String("]:")))
{ // IPv6
ipPort = address.splitRef("]:");
ipPort = address.split(QString::fromLatin1("]:"));
ipPort[0] = ipPort[0].mid(1); // chop '['
}
else if (address.contains(':'))
else if (address.contains(u':'))
{ // IPv4
ipPort = address.splitRef(':');
ipPort = address.split(u':');
}
else
{

View File

@@ -39,7 +39,7 @@ namespace BitTorrent
QHostAddress ip;
ushort port = 0;
static PeerAddress parse(const QString &address);
static PeerAddress parse(QStringView address);
QString toString() const;
};

View File

@@ -40,7 +40,7 @@
class PortForwarderImpl final : public Net::PortForwarder
{
Q_OBJECT
Q_DISABLE_COPY(PortForwarderImpl)
Q_DISABLE_COPY_MOVE(PortForwarderImpl)
public:
explicit PortForwarderImpl(lt::session *provider, QObject *parent = nullptr);

View File

@@ -41,7 +41,7 @@ namespace BitTorrent
class ResumeDataStorage : public QObject
{
Q_OBJECT
Q_DISABLE_COPY(ResumeDataStorage)
Q_DISABLE_COPY_MOVE(ResumeDataStorage)
public:
using QObject::QObject;

View File

@@ -89,6 +89,7 @@
#include "common.h"
#include "customstorage.h"
#include "dbresumedatastorage.h"
#include "downloadpriority.h"
#include "filesearcher.h"
#include "filterparserthread.h"
#include "loadtorrentparams.h"
@@ -407,7 +408,6 @@ Session::Session(QObject *parent)
, m_isBandwidthSchedulerEnabled(BITTORRENT_SESSION_KEY("BandwidthSchedulerEnabled"), false)
, m_saveResumeDataInterval(BITTORRENT_SESSION_KEY("SaveResumeDataInterval"), 60)
, m_port(BITTORRENT_SESSION_KEY("Port"), -1)
, m_useRandomPort(BITTORRENT_SESSION_KEY("UseRandomPort"), false)
, m_networkInterface(BITTORRENT_SESSION_KEY("Interface"))
, m_networkInterfaceName(BITTORRENT_SESSION_KEY("InterfaceName"))
, m_networkInterfaceAddress(BITTORRENT_SESSION_KEY("InterfaceAddress"))
@@ -1421,13 +1421,12 @@ void Session::configureNetworkInterfaces(lt::settings_pack &settingsPack)
if (m_listenInterfaceConfigured)
return;
const int port = useRandomPort() ? 0 : this->port();
if (port > 0) // user specified port
if (port() > 0) // user has specified port number
settingsPack.set_int(lt::settings_pack::max_retry_port_bind, 0);
QStringList endpoints;
QStringList outgoingInterfaces;
const QString portString = ':' + QString::number(port);
const QString portString = ':' + QString::number(port());
for (const QString &ip : asConst(getListeningIPs()))
{
@@ -1489,7 +1488,7 @@ void Session::configurePeerClasses()
// Proactively do the same for 0.0.0.0 and address_v4::any()
f.add_rule(lt::address_v4::any()
, lt::address_v4::broadcast()
, 1 << static_cast<LTUnderlyingType<lt::peer_class_t>>(lt::session::global_peer_class_id));
, 1 << toLTUnderlyingType(lt::session::global_peer_class_id));
// IPv6 may not be available on OS and the parsing
// would result in an exception -> abnormal program termination
@@ -1498,7 +1497,7 @@ void Session::configurePeerClasses()
{
f.add_rule(lt::address_v6::any()
, lt::make_address("ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff")
, 1 << static_cast<LTUnderlyingType<lt::peer_class_t>>(lt::session::global_peer_class_id));
, 1 << toLTUnderlyingType(lt::session::global_peer_class_id));
}
catch (const std::exception &) {}
@@ -1507,21 +1506,21 @@ void Session::configurePeerClasses()
// local networks
f.add_rule(lt::make_address("10.0.0.0")
, lt::make_address("10.255.255.255")
, 1 << static_cast<LTUnderlyingType<lt::peer_class_t>>(lt::session::local_peer_class_id));
, 1 << toLTUnderlyingType(lt::session::local_peer_class_id));
f.add_rule(lt::make_address("172.16.0.0")
, lt::make_address("172.31.255.255")
, 1 << static_cast<LTUnderlyingType<lt::peer_class_t>>(lt::session::local_peer_class_id));
, 1 << toLTUnderlyingType(lt::session::local_peer_class_id));
f.add_rule(lt::make_address("192.168.0.0")
, lt::make_address("192.168.255.255")
, 1 << static_cast<LTUnderlyingType<lt::peer_class_t>>(lt::session::local_peer_class_id));
, 1 << toLTUnderlyingType(lt::session::local_peer_class_id));
// link local
f.add_rule(lt::make_address("169.254.0.0")
, lt::make_address("169.254.255.255")
, 1 << static_cast<LTUnderlyingType<lt::peer_class_t>>(lt::session::local_peer_class_id));
, 1 << toLTUnderlyingType(lt::session::local_peer_class_id));
// loopback
f.add_rule(lt::make_address("127.0.0.0")
, lt::make_address("127.255.255.255")
, 1 << static_cast<LTUnderlyingType<lt::peer_class_t>>(lt::session::local_peer_class_id));
, 1 << toLTUnderlyingType(lt::session::local_peer_class_id));
// IPv6 may not be available on OS and the parsing
// would result in an exception -> abnormal program termination
@@ -1531,15 +1530,15 @@ void Session::configurePeerClasses()
// link local
f.add_rule(lt::make_address("fe80::")
, lt::make_address("febf:ffff:ffff:ffff:ffff:ffff:ffff:ffff")
, 1 << static_cast<LTUnderlyingType<lt::peer_class_t>>(lt::session::local_peer_class_id));
, 1 << toLTUnderlyingType(lt::session::local_peer_class_id));
// unique local addresses
f.add_rule(lt::make_address("fc00::")
, lt::make_address("fdff:ffff:ffff:ffff:ffff:ffff:ffff:ffff")
, 1 << static_cast<LTUnderlyingType<lt::peer_class_t>>(lt::session::local_peer_class_id));
, 1 << toLTUnderlyingType(lt::session::local_peer_class_id));
// loopback
f.add_rule(lt::address_v6::loopback()
, lt::address_v6::loopback()
, 1 << static_cast<LTUnderlyingType<lt::peer_class_t>>(lt::session::local_peer_class_id));
, 1 << toLTUnderlyingType(lt::session::local_peer_class_id));
}
catch (const std::exception &) {}
}
@@ -1590,7 +1589,7 @@ void Session::populateAdditionalTrackers()
m_additionalTrackerList.clear();
const QString trackers = additionalTrackers();
for (QStringRef tracker : asConst(trackers.splitRef('\n')))
for (QStringView tracker : asConst(QStringView(trackers).split(u'\n')))
{
tracker = tracker.trimmed();
if (!tracker.isEmpty())
@@ -2146,12 +2145,21 @@ bool Session::addTorrent_impl(const std::variant<MagnetUri, TorrentInfo> &source
}
Q_ASSERT(p.file_priorities.empty());
std::transform(addTorrentParams.filePriorities.cbegin(), addTorrentParams.filePriorities.cend()
, std::back_inserter(p.file_priorities), [](const DownloadPriority priority)
if (addTorrentParams.filePriorities.empty())
{
return static_cast<lt::download_priority_t>(
// Use qBittorrent default priority rather than libtorrent's (4)
p.file_priorities = std::vector(metadata.filesCount(), static_cast<lt::download_priority_t>(
static_cast<lt::download_priority_t::underlying_type>(DownloadPriority::Normal)));
}
else
{
std::transform(addTorrentParams.filePriorities.cbegin(), addTorrentParams.filePriorities.cend()
, std::back_inserter(p.file_priorities), [](const DownloadPriority priority)
{
return static_cast<lt::download_priority_t>(
static_cast<lt::download_priority_t::underlying_type>(priority));
});
});
}
p.ti = metadata.nativeInfo();
}
@@ -2296,28 +2304,25 @@ bool Session::downloadMetadata(const MagnetUri &magnetUri)
return true;
}
void Session::exportTorrentFile(const Torrent *torrent, TorrentExportFolder folder)
void Session::exportTorrentFile(const TorrentInfo &torrentInfo, const QString &folderPath, const QString &baseName)
{
Q_ASSERT(((folder == TorrentExportFolder::Regular) && !torrentExportDirectory().isEmpty()) ||
((folder == TorrentExportFolder::Finished) && !finishedTorrentExportDirectory().isEmpty()));
const QString validName = Utils::Fs::toValidFileSystemName(torrent->name());
const QString validName = Utils::Fs::toValidFileSystemName(baseName);
QString torrentExportFilename = QString::fromLatin1("%1.torrent").arg(validName);
const QDir exportPath(folder == TorrentExportFolder::Regular ? torrentExportDirectory() : finishedTorrentExportDirectory());
if (exportPath.exists() || exportPath.mkpath(exportPath.absolutePath()))
const QDir exportDir {folderPath};
if (exportDir.exists() || exportDir.mkpath(exportDir.absolutePath()))
{
QString newTorrentPath = exportPath.absoluteFilePath(torrentExportFilename);
QString newTorrentPath = exportDir.absoluteFilePath(torrentExportFilename);
int counter = 0;
while (QFile::exists(newTorrentPath))
{
// Append number to torrent name to make it unique
torrentExportFilename = QString::fromLatin1("%1 %2.torrent").arg(validName).arg(++counter);
newTorrentPath = exportPath.absoluteFilePath(torrentExportFilename);
newTorrentPath = exportDir.absoluteFilePath(torrentExportFilename);
}
try
{
torrent->info().saveToFile(newTorrentPath);
torrentInfo.saveToFile(newTorrentPath);
}
catch (const RuntimeError &err)
{
@@ -2380,7 +2385,7 @@ void Session::saveTorrentsQueue() const
for (const TorrentImpl *torrent : asConst(m_torrents))
{
// 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 = toLTUnderlyingType(torrent->nativeHandle().queue_position());
if (queuePos >= 0)
{
if (queuePos >= queue.size())
@@ -2754,16 +2759,6 @@ void Session::setPort(const int port)
}
}
bool Session::useRandomPort() const
{
return m_useRandomPort;
}
void Session::setUseRandomPort(const bool value)
{
m_useRandomPort = value;
}
QString Session::networkInterface() const
{
return m_networkInterface;
@@ -3893,7 +3888,14 @@ void Session::handleTorrentMetadataReceived(TorrentImpl *const torrent)
{
// Copy the torrent file to the export folder
if (!torrentExportDirectory().isEmpty())
exportTorrentFile(torrent);
{
#if (LIBTORRENT_VERSION_NUM >= 20000)
const TorrentInfo torrentInfo {torrent->nativeHandle().torrent_file_with_hashes()};
#else
const TorrentInfo torrentInfo {torrent->nativeHandle().torrent_file()};
#endif
exportTorrentFile(torrentInfo, torrentExportDirectory(), torrent->name());
}
emit torrentMetadataReceived(torrent);
}
@@ -3944,7 +3946,14 @@ void Session::handleTorrentFinished(TorrentImpl *const torrent)
// Move .torrent file to another folder
if (!finishedTorrentExportDirectory().isEmpty())
exportTorrentFile(torrent, TorrentExportFolder::Finished);
{
#if (LIBTORRENT_VERSION_NUM >= 20000)
const TorrentInfo torrentInfo {torrent->nativeHandle().torrent_file_with_hashes()};
#else
const TorrentInfo torrentInfo {torrent->nativeHandle().torrent_file()};
#endif
exportTorrentFile(torrentInfo, finishedTorrentExportDirectory(), torrent->name());
}
if (!hasUnfinishedTorrents())
emit allTorrentsFinished();
@@ -4452,7 +4461,10 @@ void Session::createTorrent(const lt::torrent_handle &nativeHandle)
{
// Copy the torrent file to the export folder
if (!torrentExportDirectory().isEmpty())
exportTorrentFile(torrent);
{
const TorrentInfo torrentInfo {params.ltAddTorrentParams.ti};
exportTorrentFile(torrentInfo, torrentExportDirectory(), torrent->name());
}
}
if (isAddTrackersEnabled() && !torrent->isPrivate())
@@ -4579,7 +4591,7 @@ void Session::handleMetadataReceivedAlert(const lt::metadata_received_alert *p)
if (downloadedMetadataIter != m_downloadedMetadata.end())
{
TorrentInfo metadata {p->handle.torrent_file()};
const TorrentInfo metadata {p->handle.torrent_file()};
m_downloadedMetadata.erase(downloadedMetadataIter);
--m_extraLimit;

View File

@@ -82,12 +82,6 @@ enum DeleteOption
DeleteTorrentAndFiles
};
enum TorrentExportFolder
{
Regular,
Finished
};
namespace Net
{
struct DownloadResult;
@@ -211,7 +205,7 @@ namespace BitTorrent
class Session : public QObject
{
Q_OBJECT
Q_DISABLE_COPY(Session)
Q_DISABLE_COPY_MOVE(Session)
public:
static void initInstance();
@@ -312,8 +306,6 @@ namespace BitTorrent
void setSaveResumeDataInterval(int value);
int port() const;
void setPort(int port);
bool useRandomPort() const;
void setUseRandomPort(bool value);
QString networkInterface() const;
void setNetworkInterface(const QString &iface);
QString networkInterfaceName() const;
@@ -613,7 +605,7 @@ namespace BitTorrent
bool addTorrent_impl(const std::variant<MagnetUri, TorrentInfo> &source, const AddTorrentParams &addTorrentParams);
void updateSeedingLimitTimer();
void exportTorrentFile(const Torrent *torrent, TorrentExportFolder folder = TorrentExportFolder::Regular);
void exportTorrentFile(const TorrentInfo &torrentInfo, const QString &folderPath, const QString &baseName);
void handleAlert(const lt::alert *a);
void dispatchTorrentAlert(const lt::alert *a);
@@ -728,7 +720,6 @@ namespace BitTorrent
CachedSettingValue<bool> m_isBandwidthSchedulerEnabled;
CachedSettingValue<int> m_saveResumeDataInterval;
CachedSettingValue<int> m_port;
CachedSettingValue<bool> m_useRandomPort;
CachedSettingValue<QString> m_networkInterface;
CachedSettingValue<QString> m_networkInterfaceName;
CachedSettingValue<QString> m_networkInterfaceAddress;

View File

@@ -39,7 +39,7 @@ namespace BitTorrent
class Statistics : public QObject
{
Q_OBJECT
Q_DISABLE_COPY(Statistics)
Q_DISABLE_COPY_MOVE(Statistics)
public:
explicit Statistics(BitTorrent::Session *session);

View File

@@ -72,6 +72,7 @@ namespace BitTorrent
ForcedDownloading,
Downloading,
ForcedDownloadingMetadata,
DownloadingMetadata,
StalledDownloading,

View File

@@ -188,7 +188,7 @@ void TorrentCreatorThread::run()
, [this, &newTorrent](const lt::piece_index_t n)
{
checkInterruptionRequested();
sendProgressSignal(static_cast<LTUnderlyingType<lt::piece_index_t>>(n), newTorrent.num_pieces());
sendProgressSignal(toLTUnderlyingType(n), newTorrent.num_pieces());
});
// Set qBittorrent as creator and add user comment to

View File

@@ -84,7 +84,7 @@ namespace
, std::back_inserter(out), [](const DownloadPriority priority)
{
return static_cast<lt::download_priority_t>(
static_cast<LTUnderlyingType<lt::download_priority_t>>(priority));
static_cast<lt::download_priority_t::underlying_type>(priority));
});
return out;
}
@@ -112,7 +112,7 @@ namespace
QString firstTrackerMessage;
QString firstErrorMessage;
#if (LIBTORRENT_VERSION_NUM >= 20000)
const size_t numEndpoints = nativeEntry.endpoints.size() * ((hashes.has_v1() && hashes.has_v2()) ? 2 : 1);
const auto numEndpoints = static_cast<qsizetype>(nativeEntry.endpoints.size() * ((hashes.has_v1() && hashes.has_v2()) ? 2 : 1));
trackerEntry.endpoints.reserve(static_cast<decltype(trackerEntry.endpoints)::size_type>(numEndpoints));
for (const lt::announce_endpoint &endpoint : nativeEntry.endpoints)
{
@@ -167,8 +167,8 @@ namespace
}
}
#else
const int numEndpoints = nativeEntry.endpoints.size();
trackerEntry.endpoints.reserve(numEndpoints);
const auto numEndpoints = static_cast<qsizetype>(nativeEntry.endpoints.size());
trackerEntry.endpoints.reserve(static_cast<decltype(trackerEntry.endpoints)::size_type>(numEndpoints));
for (const lt::announce_endpoint &endpoint : nativeEntry.endpoints)
{
TrackerEntry::EndpointStats trackerEndpoint;
@@ -797,9 +797,10 @@ QVector<DownloadPriority> TorrentImpl::filePriorities() const
const std::vector<lt::download_priority_t> fp = m_nativeHandle.get_file_priorities();
QVector<DownloadPriority> ret;
std::transform(fp.cbegin(), fp.cend(), std::back_inserter(ret), [](lt::download_priority_t priority)
ret.reserve(static_cast<decltype(ret)::size_type>(fp.size()));
std::transform(fp.cbegin(), fp.cend(), std::back_inserter(ret), [](const lt::download_priority_t priority)
{
return static_cast<DownloadPriority>(static_cast<LTUnderlyingType<lt::download_priority_t>>(priority));
return static_cast<DownloadPriority>(toLTUnderlyingType(priority));
});
return ret;
}
@@ -832,6 +833,7 @@ bool TorrentImpl::isDownloading() const
{
return m_state == TorrentState::Downloading
|| m_state == TorrentState::DownloadingMetadata
|| m_state == TorrentState::ForcedDownloadingMetadata
|| m_state == TorrentState::StalledDownloading
|| m_state == TorrentState::CheckingDownloading
|| m_state == TorrentState::PausedDownloading
@@ -864,6 +866,7 @@ bool TorrentImpl::isActive() const
return (uploadPayloadRate() > 0);
return m_state == TorrentState::DownloadingMetadata
|| m_state == TorrentState::ForcedDownloadingMetadata
|| m_state == TorrentState::Downloading
|| m_state == TorrentState::ForcedDownloading
|| m_state == TorrentState::Uploading
@@ -933,7 +936,7 @@ void TorrentImpl::updateState()
else if (m_session->isQueueingSystemEnabled() && isQueued())
m_state = TorrentState::QueuedDownloading;
else
m_state = TorrentState::DownloadingMetadata;
m_state = isForced() ? TorrentState::ForcedDownloadingMetadata : TorrentState::DownloadingMetadata;
}
else if ((m_nativeStatus.state == lt::torrent_status::checking_files)
&& (!isPaused() || (m_nativeStatus.flags & lt::torrent_flags::auto_managed)
@@ -1250,7 +1253,7 @@ QBitArray TorrentImpl::downloadingPieces() const
m_nativeHandle.get_download_queue(queue);
for (const lt::partial_piece_info &info : queue)
result.setBit(static_cast<LTUnderlyingType<lt::piece_index_t>>(info.piece_index));
result.setBit(toLTUnderlyingType(info.piece_index));
return result;
}
@@ -1509,6 +1512,10 @@ void TorrentImpl::endReceivedMetadataHandling(const QString &savePath, const QSt
p.renamed_files[lt::file_index_t {i}] = fileNames[i].toStdString();
p.save_path = Utils::Fs::toNativePath(savePath).toStdString();
// Use qBittorrent default priority rather than libtorrent's (4)
p.file_priorities = std::vector(fileNames.size(), static_cast<lt::download_priority_t>(
static_cast<lt::download_priority_t::underlying_type>(DownloadPriority::Normal)));
reload();
// If first/last piece priority was specified when adding this torrent,
@@ -1865,9 +1872,9 @@ void TorrentImpl::handleFileRenamedAlert(const lt::file_renamed_alert *p)
if (m_oldPath[p->index].isEmpty())
m_oldPath.remove(p->index);
QVector<QStringRef> oldPathParts = oldFilePath.splitRef('/', Qt::SkipEmptyParts);
QList<QStringView> oldPathParts = QStringView(oldFilePath).split('/', Qt::SkipEmptyParts);
oldPathParts.removeLast(); // drop file name part
QVector<QStringRef> newPathParts = newFilePath.splitRef('/', Qt::SkipEmptyParts);
QList<QStringView> newPathParts = QStringView(newFilePath).split('/', Qt::SkipEmptyParts);
newPathParts.removeLast(); // drop file name part
#if defined(Q_OS_WIN)
@@ -1886,7 +1893,7 @@ void TorrentImpl::handleFileRenamedAlert(const lt::file_renamed_alert *p)
for (int i = (oldPathParts.size() - 1); i >= pathIdx; --i)
{
QDir().rmdir(savePath() + Utils::String::join(oldPathParts, QLatin1String("/")));
QDir().rmdir(savePath() + Utils::String::join(oldPathParts, QString::fromLatin1("/")));
oldPathParts.removeLast();
}
@@ -1900,7 +1907,7 @@ void TorrentImpl::handleFileRenamedAlert(const lt::file_renamed_alert *p)
void TorrentImpl::handleFileRenameFailedAlert(const lt::file_rename_failed_alert *p)
{
LogMsg(tr("File rename failed. Torrent: \"%1\", file: \"%2\", reason: \"%3\"")
.arg(name(), filePath(static_cast<LTUnderlyingType<lt::file_index_t>>(p->index))
.arg(name(), filePath(toLTUnderlyingType(p->index))
, QString::fromLocal8Bit(p->error.message().c_str())), Log::WARNING);
m_oldPath[p->index].removeFirst();
@@ -1919,13 +1926,13 @@ void TorrentImpl::handleFileCompletedAlert(const lt::file_completed_alert *p)
qDebug("A file completed download in torrent \"%s\"", qUtf8Printable(name()));
if (m_session->isAppendExtensionEnabled())
{
QString name = filePath(static_cast<LTUnderlyingType<lt::file_index_t>>(p->index));
QString name = filePath(toLTUnderlyingType(p->index));
if (name.endsWith(QB_EXT))
{
const QString oldName = name;
name.chop(QB_EXT.size());
qDebug("Renaming %s to %s", qUtf8Printable(oldName), qUtf8Printable(name));
renameFile(static_cast<LTUnderlyingType<lt::file_index_t>>(p->index), name);
renameFile(toLTUnderlyingType(p->index), name);
}
}
}

View File

@@ -51,16 +51,6 @@
#include "torrent.h"
#include "torrentinfo.h"
#if (LIBTORRENT_VERSION_NUM == 20003)
// file_prio_alert is missing to be forward declared in "libtorrent/fwd.hpp"
namespace libtorrent
{
TORRENT_VERSION_NAMESPACE_3
struct file_prio_alert;
TORRENT_VERSION_NAMESPACE_3_END
}
#endif
namespace BitTorrent
{
class Session;
@@ -86,7 +76,7 @@ namespace BitTorrent
class TorrentImpl final : public QObject, public Torrent
{
Q_DISABLE_COPY(TorrentImpl)
Q_DISABLE_COPY_MOVE(TorrentImpl)
Q_DECLARE_TR_FUNCTIONS(BitTorrent::TorrentImpl)
public:

View File

@@ -61,7 +61,7 @@ namespace
{
if (QDir::isAbsolutePath(filePath)) continue;
const auto filePathElements = filePath.splitRef('/');
const auto filePathElements = QStringView(filePath).split(u'/');
// if at least one file has no root folder, no common root folder exists
if (filePathElements.count() <= 1) return {};

View File

@@ -72,7 +72,7 @@ namespace BitTorrent
class Tracker final : public QObject, public Http::IRequestHandler, private Http::ResponseBuilder
{
Q_OBJECT
Q_DISABLE_COPY(Tracker)
Q_DISABLE_COPY_MOVE(Tracker)
struct TrackerAnnounceRequest;

View File

@@ -137,9 +137,9 @@ bool Connection::acceptsGzipEncoding(QString codings)
{
// [rfc7231] 5.3.4. Accept-Encoding
const auto isCodingAvailable = [](const QVector<QStringRef> &list, const QString &encoding) -> bool
const auto isCodingAvailable = [](const QList<QStringView> &list, const QStringView encoding) -> bool
{
for (const QStringRef &str : list)
for (const QStringView &str : list)
{
if (!str.startsWith(encoding))
continue;
@@ -149,7 +149,7 @@ bool Connection::acceptsGzipEncoding(QString codings)
return true;
// [rfc7231] 5.3.1. Quality Values
const QStringRef substr = str.mid(encoding.size() + 3); // ex. skip over "gzip;q="
const QStringView substr = str.mid(encoding.size() + 3); // ex. skip over "gzip;q="
bool ok = false;
const double qvalue = substr.toDouble(&ok);
@@ -161,15 +161,15 @@ bool Connection::acceptsGzipEncoding(QString codings)
return false;
};
const QVector<QStringRef> list = codings.remove(' ').remove('\t').splitRef(',', Qt::SkipEmptyParts);
const QList<QStringView> list = QStringView(codings.remove(' ').remove('\t')).split(u',', Qt::SkipEmptyParts);
if (list.isEmpty())
return false;
const bool canGzip = isCodingAvailable(list, QLatin1String("gzip"));
const bool canGzip = isCodingAvailable(list, QString::fromLatin1("gzip"));
if (canGzip)
return true;
const bool canAny = isCodingAvailable(list, QLatin1String("*"));
const bool canAny = isCodingAvailable(list, QString::fromLatin1("*"));
if (canAny)
return true;

View File

@@ -43,7 +43,7 @@ namespace Http
class Connection : public QObject
{
Q_OBJECT
Q_DISABLE_COPY(Connection)
Q_DISABLE_COPY_MOVE(Connection)
public:
Connection(QTcpSocket *socket, IRequestHandler *requestHandler, QObject *parent = nullptr);

View File

@@ -57,7 +57,7 @@ namespace
return in;
}
bool parseHeaderLine(const QString &line, HeaderMap &out)
bool parseHeaderLine(const QStringView line, HeaderMap &out)
{
// [rfc7230] 3.2. Header Fields
const int i = line.indexOf(':');
@@ -67,8 +67,8 @@ namespace
return false;
}
const QString name = line.leftRef(i).trimmed().toString().toLower();
const QString value = line.midRef(i + 1).trimmed().toString();
const QString name = line.left(i).trimmed().toString().toLower();
const QString value = line.mid(i + 1).trimmed().toString();
out[name] = value;
return true;
@@ -145,10 +145,10 @@ RequestParser::ParseResult RequestParser::doParse(const QByteArray &data)
return {ParseStatus::BadRequest, Request(), 0}; // TODO: SHOULD respond "501 Not Implemented"
}
bool RequestParser::parseStartLines(const QString &data)
bool RequestParser::parseStartLines(const QStringView data)
{
// we don't handle malformed request which uses `LF` for newline
const QVector<QStringRef> lines = data.splitRef(CRLF, Qt::SkipEmptyParts);
const QList<QStringView> lines = data.split(QString::fromLatin1(CRLF), Qt::SkipEmptyParts);
// [rfc7230] 3.2.2. Field Order
QStringList requestLines;
@@ -267,7 +267,7 @@ bool RequestParser::parsePostMessage(const QByteArray &data)
return false;
}
const QByteArray delimiter = Utils::String::unquote(contentType.midRef(idx + boundaryFieldName.size())).toLatin1();
const QByteArray delimiter = Utils::String::unquote(QStringView(contentType).mid(idx + boundaryFieldName.size())).toLatin1();
if (delimiter.isEmpty())
{
qWarning() << Q_FUNC_INFO << "boundary delimiter field empty!";
@@ -311,13 +311,13 @@ bool RequestParser::parseFormData(const QByteArray &data)
const QByteArray payload = viewWithoutEndingWith(list[1], CRLF);
HeaderMap headersMap;
const QVector<QStringRef> headerLines = headers.splitRef(CRLF, Qt::SkipEmptyParts);
const QList<QStringView> headerLines = QStringView(headers).split(QString::fromLatin1(CRLF), Qt::SkipEmptyParts);
for (const auto &line : headerLines)
{
if (line.trimmed().startsWith(HEADER_CONTENT_DISPOSITION, Qt::CaseInsensitive))
if (line.trimmed().startsWith(QString::fromLatin1(HEADER_CONTENT_DISPOSITION), Qt::CaseInsensitive))
{
// extract out filename & name
const QVector<QStringRef> directives = line.split(';', Qt::SkipEmptyParts);
const QList<QStringView> directives = line.split(u';', Qt::SkipEmptyParts);
for (const auto &directive : directives)
{

View File

@@ -60,7 +60,7 @@ namespace Http
RequestParser();
ParseResult doParse(const QByteArray &data);
bool parseStartLines(const QString &data);
bool parseStartLines(QStringView data);
bool parseRequestLine(const QString &line);
bool parsePostMessage(const QByteArray &data);

View File

@@ -43,7 +43,7 @@ namespace Http
class Server final : public QTcpServer
{
Q_OBJECT
Q_DISABLE_COPY(Server)
Q_DISABLE_COPY_MOVE(Server)
public:
explicit Server(IRequestHandler *requestHandler, QObject *parent = nullptr);

View File

@@ -35,7 +35,7 @@ class QString;
class IconProvider : public QObject
{
Q_DISABLE_COPY(IconProvider)
Q_DISABLE_COPY_MOVE(IconProvider)
public:
static void initInstance();

View File

@@ -72,7 +72,7 @@ Q_DECLARE_OPERATORS_FOR_FLAGS(Log::MsgTypes)
class Logger : public QObject
{
Q_OBJECT
Q_DISABLE_COPY(Logger)
Q_DISABLE_COPY_MOVE(Logger)
public:
static void initInstance();

View File

@@ -39,7 +39,7 @@ class QUrl;
class DownloadHandlerImpl final : public Net::DownloadHandler
{
Q_OBJECT
Q_DISABLE_COPY(DownloadHandlerImpl)
Q_DISABLE_COPY_MOVE(DownloadHandlerImpl)
public:
DownloadHandlerImpl(Net::DownloadManager *manager, const Net::DownloadRequest &downloadRequest);

View File

@@ -98,7 +98,7 @@ namespace Net
class DownloadHandler : public QObject
{
Q_OBJECT
Q_DISABLE_COPY(DownloadHandler)
Q_DISABLE_COPY_MOVE(DownloadHandler)
public:
using QObject::QObject;
@@ -112,7 +112,7 @@ namespace Net
class DownloadManager : public QObject
{
Q_OBJECT
Q_DISABLE_COPY(DownloadManager)
Q_DISABLE_COPY_MOVE(DownloadManager)
public:
static void initInstance();

View File

@@ -43,7 +43,7 @@ namespace Net
class GeoIPManager : public QObject
{
Q_OBJECT
Q_DISABLE_COPY(GeoIPManager)
Q_DISABLE_COPY_MOVE(GeoIPManager)
public:
static void initInstance();

View File

@@ -34,7 +34,7 @@ namespace Net
{
class PortForwarder : public QObject
{
Q_DISABLE_COPY(PortForwarder)
Q_DISABLE_COPY_MOVE(PortForwarder)
public:
explicit PortForwarder(QObject *parent = nullptr);

View File

@@ -56,7 +56,7 @@ namespace Net
class ProxyConfigurationManager : public QObject
{
Q_OBJECT
Q_DISABLE_COPY(ProxyConfigurationManager)
Q_DISABLE_COPY_MOVE(ProxyConfigurationManager)
explicit ProxyConfigurationManager(QObject *parent = nullptr);
~ProxyConfigurationManager() = default;

View File

@@ -40,7 +40,7 @@ namespace Net
class ReverseResolution : public QObject
{
Q_OBJECT
Q_DISABLE_COPY(ReverseResolution)
Q_DISABLE_COPY_MOVE(ReverseResolution)
public:
explicit ReverseResolution(QObject *parent = nullptr);

View File

@@ -122,12 +122,7 @@ Smtp::Smtp(QObject *parent)
connect(m_socket, &QIODevice::readyRead, this, &Smtp::readyRead);
connect(m_socket, &QAbstractSocket::disconnected, this, &QObject::deleteLater);
#if (QT_VERSION >= QT_VERSION_CHECK(5, 15, 0))
connect(m_socket, &QAbstractSocket::errorOccurred, this, &Smtp::error);
#else
connect(m_socket, qOverload<QAbstractSocket::SocketError>(&QAbstractSocket::error)
, this, &Smtp::error);
#endif
// Test hmacMD5 function (http://www.faqs.org/rfcs/rfc2202.html)
Q_ASSERT(hmacMD5("Jefe", "what do ya want for nothing?").toHex()

View File

@@ -76,7 +76,7 @@ namespace DNS
class Preferences : public QObject
{
Q_OBJECT
Q_DISABLE_COPY(Preferences)
Q_DISABLE_COPY_MOVE(Preferences)
Preferences();

View File

@@ -42,7 +42,7 @@ namespace RSS
class Article : public QObject
{
Q_OBJECT
Q_DISABLE_COPY(Article)
Q_DISABLE_COPY_MOVE(Article)
friend class Feed;

View File

@@ -62,7 +62,7 @@ namespace RSS
class AutoDownloader final : public QObject
{
Q_OBJECT
Q_DISABLE_COPY(AutoDownloader)
Q_DISABLE_COPY_MOVE(AutoDownloader)
friend class ::Application;

View File

@@ -325,7 +325,7 @@ bool AutoDownloadRule::matchesEpisodeFilterExpression(const QString &articleTitl
if (episode.endsWith('-'))
{ // Infinite range
const int episodeOurs {episode.leftRef(episode.size() - 1).toInt()};
const int episodeOurs {QStringView(episode).left(episode.size() - 1).toInt()};
if (((seasonTheirs == seasonOurs) && (episodeTheirs >= episodeOurs)) || (seasonTheirs > seasonOurs))
return true;
}

View File

@@ -59,7 +59,7 @@ namespace RSS
class Feed final : public Item
{
Q_OBJECT
Q_DISABLE_COPY(Feed)
Q_DISABLE_COPY_MOVE(Feed)
friend class Session;

View File

@@ -40,7 +40,7 @@ namespace RSS
class Folder final : public Item
{
Q_OBJECT
Q_DISABLE_COPY(Folder)
Q_DISABLE_COPY_MOVE(Folder)
friend class Session;

View File

@@ -42,7 +42,7 @@ namespace RSS
class Item : public QObject
{
Q_OBJECT
Q_DISABLE_COPY(Item)
Q_DISABLE_COPY_MOVE(Item)
friend class Folder;
friend class Session;

View File

@@ -87,7 +87,7 @@ namespace RSS
class Session : public QObject
{
Q_OBJECT
Q_DISABLE_COPY(Session)
Q_DISABLE_COPY_MOVE(Session)
friend class ::Application;

View File

@@ -59,7 +59,7 @@ void SearchDownloadHandler::downloadProcessFinished(int exitcode)
if ((exitcode == 0) && (m_downloadProcess->exitStatus() == QProcess::NormalExit))
{
const QString line = QString::fromUtf8(m_downloadProcess->readAllStandardOutput()).trimmed();
const QVector<QStringRef> parts = line.splitRef(' ');
const QList<QStringView> parts = QStringView(line).split(u' ');
if (parts.size() == 2)
path = parts[0].toString();
}

View File

@@ -37,7 +37,7 @@ class SearchPluginManager;
class SearchDownloadHandler : public QObject
{
Q_OBJECT
Q_DISABLE_COPY(SearchDownloadHandler)
Q_DISABLE_COPY_MOVE(SearchDownloadHandler)
friend class SearchPluginManager;

View File

@@ -163,9 +163,9 @@ void SearchHandler::processFailed()
// Parse one line of search results list
// Line is in the following form:
// file url | file name | file size | nb seeds | nb leechers | Search engine url
bool SearchHandler::parseSearchResult(const QString &line, SearchResult &searchResult)
bool SearchHandler::parseSearchResult(const QStringView line, SearchResult &searchResult)
{
const QVector<QStringRef> parts = line.splitRef('|');
const QList<QStringView> parts = line.split(u'|');
const int nbFields = parts.size();
if (nbFields < (NB_PLUGIN_COLUMNS - 1)) return false; // -1 because desc_link is optional

View File

@@ -54,7 +54,7 @@ class SearchPluginManager;
class SearchHandler : public QObject
{
Q_OBJECT
Q_DISABLE_COPY(SearchHandler)
Q_DISABLE_COPY_MOVE(SearchHandler)
friend class SearchPluginManager;
@@ -78,7 +78,7 @@ private:
void readSearchOutput();
void processFailed();
void processFinished(int exitcode);
bool parseSearchResult(const QString &line, SearchResult &searchResult);
bool parseSearchResult(QStringView line, SearchResult &searchResult);
const QString m_pattern;
const QString m_category;

View File

@@ -60,7 +60,7 @@ class SearchHandler;
class SearchPluginManager : public QObject
{
Q_OBJECT
Q_DISABLE_COPY(SearchPluginManager)
Q_DISABLE_COPY_MOVE(SearchPluginManager)
public:
SearchPluginManager();

View File

@@ -234,6 +234,13 @@ void SettingsStorage::removeValue(const QString &key)
}
}
bool SettingsStorage::hasKey(const QString &key) const
{
const QString realKey = mapKey(key);
const QReadLocker locker {&m_lock};
return m_data.contains(realKey);
}
QVariantHash TransactionalSettings::read() const
{
QVariantHash res;

View File

@@ -79,6 +79,7 @@ public:
}
void removeValue(const QString &key);
bool hasKey(const QString &key) const;
public slots:
bool save();

View File

@@ -192,7 +192,7 @@ namespace
class TorrentFilesWatcher::Worker final : public QObject
{
Q_OBJECT
Q_DISABLE_COPY(Worker)
Q_DISABLE_COPY_MOVE(Worker)
public:
Worker();
@@ -268,11 +268,10 @@ QString TorrentFilesWatcher::makeCleanPath(const QString &path)
if (path.isEmpty())
throw InvalidArgument(tr("Watched folder path cannot be empty."));
const QDir dir {path};
if (dir.isRelative())
if (QDir::isRelativePath(path))
throw InvalidArgument(tr("Watched folder path cannot be relative."));
return dir.canonicalPath();
return QDir::cleanPath(path);
}
void TorrentFilesWatcher::load()
@@ -295,7 +294,7 @@ void TorrentFilesWatcher::load()
const QJsonDocument jsonDoc = QJsonDocument::fromJson(confFile.readAll(), &jsonError);
if (jsonError.error != QJsonParseError::NoError)
{
LogMsg(tr("Couldn't parse Watched Folders configuration from %1. Error: %2")
LogMsg(tr("Couldn't parse Watched Folders configuration from %1. Error: %2")
.arg(confFile.fileName(), jsonError.errorString()), Log::WARNING);
return;
}
@@ -601,13 +600,10 @@ void TorrentFilesWatcher::Worker::addWatchedFolder(const QString &path, const To
{
#if !defined Q_OS_HAIKU
// Check if the path points to a network file system or not
if (Utils::Fs::isNetworkFileSystem(path))
{
m_watchedByTimeoutFolders.insert(path);
}
else
#endif
if (Utils::Fs::isNetworkFileSystem(path) || options.recursive)
#else
if (options.recursive)
#endif
{
m_watchedByTimeoutFolders.insert(path);
if (!m_watchTimer->isActive())

View File

@@ -48,7 +48,7 @@ namespace BitTorrent
class TorrentFilesWatcher final : public QObject
{
Q_OBJECT
Q_DISABLE_COPY(TorrentFilesWatcher)
Q_DISABLE_COPY_MOVE(TorrentFilesWatcher)
public:
struct WatchedFolderOptions

View File

@@ -45,6 +45,7 @@ const TorrentFilter TorrentFilter::InactiveTorrent(TorrentFilter::Inactive);
const TorrentFilter TorrentFilter::StalledTorrent(TorrentFilter::Stalled);
const TorrentFilter TorrentFilter::StalledUploadingTorrent(TorrentFilter::StalledUploading);
const TorrentFilter TorrentFilter::StalledDownloadingTorrent(TorrentFilter::StalledDownloading);
const TorrentFilter TorrentFilter::CheckingTorrent(TorrentFilter::Checking);
const TorrentFilter TorrentFilter::ErroredTorrent(TorrentFilter::Errored);
using BitTorrent::Torrent;
@@ -101,6 +102,8 @@ bool TorrentFilter::setTypeByName(const QString &filter)
type = StalledUploading;
else if (filter == "stalled_downloading")
type = StalledDownloading;
else if (filter == "checking")
type = Checking;
else if (filter == "errored")
type = Errored;
@@ -180,6 +183,10 @@ bool TorrentFilter::matchState(const BitTorrent::Torrent *const torrent) const
return torrent->state() == BitTorrent::TorrentState::StalledUploading;
case StalledDownloading:
return torrent->state() == BitTorrent::TorrentState::StalledDownloading;
case Checking:
return (torrent->state() == BitTorrent::TorrentState::CheckingUploading)
|| (torrent->state() == BitTorrent::TorrentState::CheckingDownloading)
|| (torrent->state() == BitTorrent::TorrentState::CheckingResumeData);
case Errored:
return torrent->isErrored();
default: // All

View File

@@ -56,6 +56,7 @@ public:
Stalled,
StalledUploading,
StalledDownloading,
Checking,
Errored
};
@@ -74,6 +75,7 @@ public:
static const TorrentFilter StalledTorrent;
static const TorrentFilter StalledUploadingTorrent;
static const TorrentFilter StalledDownloadingTorrent;
static const TorrentFilter CheckingTorrent;
static const TorrentFilter ErroredTorrent;
TorrentFilter() = default;

View File

@@ -28,14 +28,14 @@
#pragma once
#include <QString>
#include <Qt>
#include <QtContainerFwd>
class QByteArray;
namespace Utils::ByteArray
{
// Mimic QString::splitRef(sep, behavior)
// Mimic QStringView(in).split(sep, behavior)
QVector<QByteArray> splitToViews(const QByteArray &in, const QByteArray &sep, const Qt::SplitBehavior behavior = Qt::KeepEmptyParts);
// Mimic QByteArray::mid(pos, len) but instead of returning a full-copy,

View File

@@ -60,16 +60,16 @@ int Utils::Compare::naturalCompare(const QString &left, const QString &right, co
{
// Both are digits, compare the numbers
const auto numberView = [](const QString &str, int &pos) -> QStringRef
const auto numberView = [](const QStringView str, int &pos) -> QStringView
{
const int start = pos;
while ((pos < str.size()) && str[pos].isDigit())
++pos;
return str.midRef(start, (pos - start));
return str.mid(start, (pos - start));
};
const QStringRef numViewL = numberView(left, posL);
const QStringRef numViewR = numberView(right, posR);
const QStringView numViewL = numberView(left, posL);
const QStringView numViewR = numberView(right, posR);
if (numViewL.length() != numViewR.length())
return (numViewL.length() - numViewR.length());

View File

@@ -498,7 +498,7 @@ QString Utils::Misc::opensslVersionString()
#else
static const auto version {QString::fromLatin1(SSLeay_version(SSLEAY_VERSION))};
#endif
return version.splitRef(' ', Qt::SkipEmptyParts)[1].toString();
return QStringView(version).split(u' ', Qt::SkipEmptyParts)[1].toString();
}
QString Utils::Misc::zlibVersionString()

View File

@@ -43,7 +43,7 @@
// to send numbers instead of strings with suffixes
QString Utils::String::fromDouble(const double n, const int precision)
{
/* HACK because QString rounds up. Eg QString::number(0.999*100.0, 'f' ,1) == 99.9
/* HACK because QString rounds up. Eg QString::number(0.999*100.0, 'f', 1) == 99.9
** but QString::number(0.9999*100.0, 'f' ,1) == 100.0 The problem manifests when
** the number has more digits after the decimal than we want AND the digit after
** our 'wanted' is >= 5. In this case our last digit gets rounded up. So for each
@@ -99,7 +99,7 @@ std::optional<double> Utils::String::parseDouble(const QString &string)
return std::nullopt;
}
QString Utils::String::join(const QVector<QStringRef> &strings, const QString &separator)
QString Utils::String::join(const QList<QStringView> &strings, const QStringView separator)
{
if (strings.empty())
return {};

View File

@@ -37,8 +37,6 @@
#include <Qt>
#include <QtContainerFwd>
class QStringRef;
namespace Utils::String
{
QString wildcardToRegexPattern(const QString &pattern);
@@ -61,7 +59,7 @@ namespace Utils::String
std::optional<int> parseInt(const QString &string);
std::optional<double> parseDouble(const QString &string);
QString join(const QVector<QStringRef> &strings, const QString &separator);
QString join(const QList<QStringView> &strings, QStringView separator);
QString fromDouble(double n, int precision);

View File

@@ -32,7 +32,7 @@
#define QBT_VERSION_MINOR 4
#define QBT_VERSION_BUGFIX 0
#define QBT_VERSION_BUILD 0
#define QBT_VERSION_STATUS "beta1" // Should be empty for stable releases!
#define QBT_VERSION_STATUS "beta2" // Should be empty for stable releases!
#define QBT__STRINGIFY(x) #x
#define QBT_STRINGIFY(x) QBT__STRINGIFY(x)

View File

@@ -40,7 +40,7 @@ namespace Ui
class AboutDialog final : public QDialog
{
Q_OBJECT
Q_DISABLE_COPY(AboutDialog)
Q_DISABLE_COPY_MOVE(AboutDialog)
public:
explicit AboutDialog(QWidget *parent);

View File

@@ -460,7 +460,7 @@ void AddNewTorrentDialog::saveTorrentFile()
Q_ASSERT(m_hasMetadata);
const QString torrentFileExtension {C_TORRENT_FILE_EXTENSION};
const QString filter {QString{"Torrent file (*%1)"}.arg(torrentFileExtension)};
const QString filter {tr("Torrent file (*%1)").arg(torrentFileExtension)};
QString path = QFileDialog::getSaveFileName(
this, tr("Save as torrent file")
@@ -679,6 +679,13 @@ void AddNewTorrentDialog::updateMetadata(const BitTorrent::TorrentInfo &metadata
// Update UI
setupTreeview();
setMetadataProgressIndicator(false, tr("Metadata retrieval complete"));
m_ui->buttonSave->setVisible(true);
if (m_torrentInfo.infoHash().v2().isValid())
{
m_ui->buttonSave->setEnabled(false);
m_ui->buttonSave->setToolTip(tr("Cannot create v2 torrent until its data is fully downloaded."));
}
}
void AddNewTorrentDialog::setMetadataProgressIndicator(bool visibleIndicator, const QString &labelText)
@@ -687,7 +694,6 @@ void AddNewTorrentDialog::setMetadataProgressIndicator(bool visibleIndicator, co
m_ui->lblMetaLoading->setVisible(true);
m_ui->lblMetaLoading->setText(labelText);
m_ui->progMetaLoading->setVisible(visibleIndicator);
m_ui->buttonSave->setVisible(!visibleIndicator);
}
void AddNewTorrentDialog::setupTreeview()

View File

@@ -59,7 +59,7 @@ class TorrentFileGuard;
class AddNewTorrentDialog final : public QDialog
{
Q_OBJECT
Q_DISABLE_COPY(AddNewTorrentDialog)
Q_DISABLE_COPY_MOVE(AddNewTorrentDialog)
public:
static const int minPathHistoryLength = 0;

View File

@@ -355,7 +355,7 @@
<item row="3" column="0">
<widget class="QLabel" name="labelInfohash2">
<property name="text">
<string>Info hash v2</string>
<string>Info hash v2:</string>
</property>
</widget>
</item>

View File

@@ -43,7 +43,7 @@ namespace Ui
class BanListOptionsDialog final : public QDialog
{
Q_OBJECT
Q_DISABLE_COPY(BanListOptionsDialog)
Q_DISABLE_COPY_MOVE(BanListOptionsDialog)
public:
explicit BanListOptionsDialog(QWidget *parent = nullptr);

View File

@@ -33,7 +33,7 @@
class CategoryFilterWidget final : public QTreeView
{
Q_OBJECT
Q_DISABLE_COPY(CategoryFilterWidget)
Q_DISABLE_COPY_MOVE(CategoryFilterWidget)
public:
explicit CategoryFilterWidget(QWidget *parent = nullptr);

View File

@@ -49,8 +49,12 @@ namespace
|| str.startsWith("https://", Qt::CaseInsensitive)
|| str.startsWith("ftp://", Qt::CaseInsensitive)
|| str.startsWith("magnet:", Qt::CaseInsensitive)
|| ((str.size() == 40) && !str.contains(QRegularExpression("[^0-9A-Fa-f]")))
|| ((str.size() == 32) && !str.contains(QRegularExpression("[^2-7A-Za-z]"))));
|| ((str.size() == 40) && !str.contains(QRegularExpression("[^0-9A-Fa-f]"))) // v1 hex-encoded SHA-1 info-hash
#if (LIBTORRENT_VERSION_NUM >= 20000)
|| ((str.size() == 64) && !str.contains(QRegularExpression("[^0-9A-Fa-f]"))) // v2 hex-encoded SHA-256 info-hash
#endif
|| ((str.size() == 32) && !str.contains(QRegularExpression("[^2-7A-Za-z]")))); // v1 Base32 encoded SHA-1 info-hash
}
}
@@ -71,10 +75,10 @@ DownloadFromURLDialog::DownloadFromURLDialog(QWidget *parent)
// Paste clipboard if there is an URL in it
const QString clipboardText = qApp->clipboard()->text();
const QVector<QStringRef> clipboardList = clipboardText.splitRef('\n');
const QList<QStringView> clipboardList = QStringView(clipboardText).split(u'\n');
QSet<QString> uniqueURLs;
for (QStringRef strRef : clipboardList)
for (QStringView strRef : clipboardList)
{
strRef = strRef.trimmed();
if (strRef.isEmpty()) continue;
@@ -103,10 +107,10 @@ DownloadFromURLDialog::~DownloadFromURLDialog()
void DownloadFromURLDialog::downloadButtonClicked()
{
const QString plainText = m_ui->textUrls->toPlainText();
const QVector<QStringRef> urls = plainText.splitRef('\n');
const QList<QStringView> urls = QStringView(plainText).split(u'\n');
QSet<QString> uniqueURLs;
for (QStringRef url : urls)
for (QStringView url : urls)
{
url = url.trimmed();
if (url.isEmpty()) continue;

View File

@@ -40,7 +40,7 @@ namespace Ui
class DownloadFromURLDialog final : public QDialog
{
Q_OBJECT
Q_DISABLE_COPY(DownloadFromURLDialog)
Q_DISABLE_COPY_MOVE(DownloadFromURLDialog)
public:
explicit DownloadFromURLDialog(QWidget *parent);

View File

@@ -68,7 +68,7 @@ namespace
class FileSystemPathEdit::FileSystemPathEditPrivate
{
Q_DECLARE_PUBLIC(FileSystemPathEdit)
Q_DISABLE_COPY(FileSystemPathEditPrivate)
Q_DISABLE_COPY_MOVE(FileSystemPathEditPrivate)
FileSystemPathEditPrivate(FileSystemPathEdit *q, Private::FileEditorWithCompletion *editor);

View File

@@ -100,7 +100,7 @@ private:
virtual void setEditWidgetText(const QString &text) = 0;
QWidget *editWidgetImpl() const;
Q_DISABLE_COPY(FileSystemPathEdit)
Q_DISABLE_COPY_MOVE(FileSystemPathEdit)
class FileSystemPathEditPrivate;
Q_DECLARE_PRIVATE(FileSystemPathEdit)
FileSystemPathEditPrivate *d_ptr;

View File

@@ -107,30 +107,32 @@ QValidator::State Private::FileSystemPathValidator::validate(QString &input, int
// we test path components from beginning to the one with cursor location in strict mode
// and the one with cursor and beyond in non-strict mode
QVector<QStringRef> components = input.splitRef(QDir::separator(), Qt::KeepEmptyParts);
QList<QStringView> components = QStringView(input).split(QDir::separator(), Qt::KeepEmptyParts);
// find index of the component that contains pos
int componentWithCursorIndex = 0;
int componentWithCursorPosition = 0;
int pathLength = 0;
// components.size() - 1 because when path ends with QDir::separator(), we will not see the last
// character in the components array, yet everything past the one before the last delimiter
// belongs to the last component
for (; (componentWithCursorIndex < components.size() - 1) && (pathLength < pos); ++componentWithCursorIndex)
for (; (componentWithCursorIndex < (components.size() - 1)) && (pathLength < pos); ++componentWithCursorIndex)
{
pathLength = components[componentWithCursorIndex].position() + components[componentWithCursorIndex].size();
pathLength = componentWithCursorPosition + components[componentWithCursorIndex].size();
componentWithCursorPosition += components[componentWithCursorIndex].size() + 1;
}
Q_ASSERT(componentWithCursorIndex < components.size());
m_lastValidationState = QValidator::Acceptable;
if (componentWithCursorIndex > 0)
m_lastValidationState = validate(input, components, m_strictMode, 0, componentWithCursorIndex - 1);
m_lastValidationState = validate(components, m_strictMode, 0, componentWithCursorIndex - 1);
if ((m_lastValidationState == QValidator::Acceptable) && (componentWithCursorIndex < components.size()))
m_lastValidationState = validate(input, components, false, componentWithCursorIndex, components.size() - 1);
m_lastValidationState = validate(components, false, componentWithCursorIndex, components.size() - 1);
return m_lastValidationState;
}
QValidator::State Private::FileSystemPathValidator::validate(const QString &path, const QVector<QStringRef> &pathComponents, bool strict,
QValidator::State Private::FileSystemPathValidator::validate(const QList<QStringView> &pathComponents, bool strict,
int firstComponentToTest, int lastComponentToTest) const
{
Q_ASSERT(firstComponentToTest >= 0);
@@ -141,12 +143,13 @@ QValidator::State Private::FileSystemPathValidator::validate(const QString &path
if (pathComponents.empty())
return strict ? QValidator::Invalid : QValidator::Intermediate;
for (int i = firstComponentToTest; i < lastComponentToTest; ++i)
for (int i = firstComponentToTest; i <= lastComponentToTest; ++i)
{
if (pathComponents[i].isEmpty()) continue;
const bool isFinalPath = (i == (pathComponents.size() - 1));
const QStringView componentPath = pathComponents[i];
if (componentPath.isEmpty()) continue;
QStringRef componentPath(&path, 0, pathComponents[i].position() + pathComponents[i].size());
m_lastTestResult = testPath(componentPath, false);
m_lastTestResult = testPath(pathComponents[i], isFinalPath);
if (m_lastTestResult != TestResult::OK)
{
m_lastTestedPath = componentPath.toString();
@@ -154,20 +157,11 @@ QValidator::State Private::FileSystemPathValidator::validate(const QString &path
}
}
const bool finalPath = (lastComponentToTest == (pathComponents.size() - 1));
QStringRef componentPath(&path, 0, pathComponents[lastComponentToTest].position()
+ pathComponents[lastComponentToTest].size());
m_lastTestResult = testPath(componentPath, finalPath);
if (m_lastTestResult != TestResult::OK)
{
m_lastTestedPath = componentPath.toString();
return strict ? QValidator::Invalid : QValidator::Intermediate;
}
return QValidator::Acceptable;
}
Private::FileSystemPathValidator::TestResult
Private::FileSystemPathValidator::testPath(const QStringRef &path, bool pathIsComplete) const
Private::FileSystemPathValidator::testPath(const QStringView path, bool pathIsComplete) const
{
QFileInfo fi(path.toString());
if (m_existingOnly && !fi.exists())

View File

@@ -39,7 +39,6 @@ class QCompleter;
class QContextMenuEvent;
class QFileSystemModel;
class QKeyEvent;
class QStringRef;
namespace Private
{
@@ -82,10 +81,10 @@ namespace Private
QString lastTestedPath() const;
private:
QValidator::State validate(const QString &path, const QVector<QStringRef> &pathComponents, bool strict,
QValidator::State validate(const QList<QStringView> &pathComponents, bool strict,
int firstComponentToTest, int lastComponentToTest) const;
TestResult testPath(const QStringRef &path, bool pathIsComplete) const;
TestResult testPath(QStringView path, bool pathIsComplete) const;
bool m_strictMode;
bool m_existingOnly;
@@ -112,7 +111,7 @@ namespace Private
class FileLineEdit final : public QLineEdit, public FileEditorWithCompletion
{
Q_OBJECT
Q_DISABLE_COPY(FileLineEdit)
Q_DISABLE_COPY_MOVE(FileLineEdit)
public:
FileLineEdit(QWidget *parent = nullptr);

View File

@@ -43,7 +43,7 @@ namespace Ui
class IPSubnetWhitelistOptionsDialog final : public QDialog
{
Q_OBJECT
Q_DISABLE_COPY(IPSubnetWhitelistOptionsDialog)
Q_DISABLE_COPY_MOVE(IPSubnetWhitelistOptionsDialog)
public:
explicit IPSubnetWhitelistOptionsDialog(QWidget *parent = nullptr);

View File

@@ -35,7 +35,7 @@
class LogFilterModel final : public QSortFilterProxyModel
{
Q_OBJECT
Q_DISABLE_COPY(LogFilterModel)
Q_DISABLE_COPY_MOVE(LogFilterModel)
public:
explicit LogFilterModel(Log::MsgTypes types = Log::ALL, QObject *parent = nullptr);

View File

@@ -34,7 +34,7 @@
class LogListView final : public QListView
{
Q_OBJECT
Q_DISABLE_COPY(LogListView)
Q_DISABLE_COPY_MOVE(LogListView)
public:
explicit LogListView(QWidget *parent = nullptr);

View File

@@ -39,7 +39,7 @@
class BaseLogModel : public QAbstractListModel
{
Q_DISABLE_COPY(BaseLogModel)
Q_DISABLE_COPY_MOVE(BaseLogModel)
public:
enum MessageTypeRole
@@ -86,7 +86,7 @@ private:
class LogMessageModel : public BaseLogModel
{
Q_OBJECT
Q_DISABLE_COPY(LogMessageModel)
Q_DISABLE_COPY_MOVE(LogMessageModel)
public:
explicit LogMessageModel(QObject *parent = nullptr);
@@ -101,7 +101,7 @@ private:
class LogPeerModel : public BaseLogModel
{
Q_OBJECT
Q_DISABLE_COPY(LogPeerModel)
Q_DISABLE_COPY_MOVE(LogPeerModel)
public:
explicit LogPeerModel(QObject *parent = nullptr);

View File

@@ -68,14 +68,14 @@ namespace MacUtils
if (class_getInstanceMethod(delClass, shouldHandle))
{
if (class_replaceMethod(delClass, shouldHandle, (IMP)dockClickHandler, "B@:"))
if (class_replaceMethod(delClass, shouldHandle, reinterpret_cast<IMP>(dockClickHandler), "B@:"))
qDebug("Registered dock click handler (replaced original method)");
else
qWarning("Failed to replace method for dock click handler");
}
else
{
if (class_addMethod(delClass, shouldHandle, (IMP)dockClickHandler, "B@:"))
if (class_addMethod(delClass, shouldHandle, reinterpret_cast<IMP>(dockClickHandler), "B@:"))
qDebug("Registered dock click handler");
else
qWarning("Failed to register dock click handler");

View File

@@ -2184,8 +2184,9 @@ void MainWindow::pythonDownloadFinished(const Net::DownloadResult &result)
QProcess installer;
qDebug("Launching Python installer in passive mode...");
QFile::rename(result.filePath, result.filePath + ".exe");
installer.start('"' + Utils::Fs::toNativePath(result.filePath) + ".exe\" /passive");
const QString exePath = result.filePath + QLatin1String(".exe");
QFile::rename(result.filePath, exePath);
installer.start(Utils::Fs::toNativePath(exePath), {"/passive"});
// Wait for setup to complete
installer.waitForFinished(10 * 60 * 1000);
@@ -2195,7 +2196,7 @@ void MainWindow::pythonDownloadFinished(const Net::DownloadResult &result)
qDebug("Setup should be complete!");
// Delete temp file
Utils::Fs::forceRemove(result.filePath + ".exe");
Utils::Fs::forceRemove(exePath);
// Reload search engine
if (Utils::ForeignApps::pythonInfo().isSupportedVersion())

View File

@@ -180,6 +180,7 @@ OptionsDialog::OptionsDialog(QWidget *parent)
, m_ui {new Ui::OptionsDialog}
, m_storeDialogSize {SETTINGS_KEY("Size")}
, m_storeHSplitterSize {SETTINGS_KEY("HorizontalSplitterSizes")}
, m_storeLastViewedPage {SETTINGS_KEY("LastViewedPage")}
{
qDebug("-> Constructing Options");
m_ui->setupUi(this);
@@ -300,7 +301,6 @@ OptionsDialog::OptionsDialog(QWidget *parent)
void (QSpinBox::*qSpinBoxValueChanged)(int) = &QSpinBox::valueChanged;
connect(m_ui->comboProxyType, qComboBoxCurrentIndexChanged, this, &ThisType::enableProxy);
connect(m_ui->checkRandomPort, &QAbstractButton::toggled, m_ui->spinPort, &ThisType::setDisabled);
// Apply button is activated when a value is changed
// Behavior tab
@@ -408,7 +408,6 @@ OptionsDialog::OptionsDialog(QWidget *parent)
// Connection tab
connect(m_ui->comboProtocol, qComboBoxCurrentIndexChanged, this, &ThisType::enableApplyButton);
connect(m_ui->spinPort, qSpinBoxValueChanged, this, &ThisType::enableApplyButton);
connect(m_ui->checkRandomPort, &QAbstractButton::toggled, this, &ThisType::enableApplyButton);
connect(m_ui->checkUPnP, &QAbstractButton::toggled, this, &ThisType::enableApplyButton);
connect(m_ui->spinUploadLimit, qSpinBoxValueChanged, this, &ThisType::enableApplyButton);
connect(m_ui->spinDownloadLimit, qSpinBoxValueChanged, this, &ThisType::enableApplyButton);
@@ -570,6 +569,8 @@ OptionsDialog::OptionsDialog(QWidget *parent)
for (QSpinBox *widget : asConst(findChildren<QSpinBox *>()))
widget->installEventFilter(wheelEventEater);
m_ui->tabSelection->setCurrentRow(m_storeLastViewedPage);
Utils::Gui::resize(this, m_storeDialogSize);
show();
// Have to be called after show(), because splitter width needed
@@ -619,6 +620,8 @@ OptionsDialog::~OptionsDialog()
hSplitterSizes.append(QString::number(size));
m_storeHSplitterSize = hSplitterSizes;
m_storeLastViewedPage = m_ui->tabSelection->currentRow();
delete m_ui;
}
@@ -770,7 +773,6 @@ void OptionsDialog::saveOptions()
// Connection preferences
session->setBTProtocol(static_cast<BitTorrent::BTProtocol>(m_ui->comboProtocol->currentIndex()));
session->setPort(getPort());
session->setUseRandomPort(m_ui->checkRandomPort->isChecked());
Net::PortForwarder::instance()->setEnabled(isUPnPEnabled());
session->setGlobalDownloadSpeedLimit(m_ui->spinDownloadLimit->value() * 1024);
session->setGlobalUploadSpeedLimit(m_ui->spinUploadLimit->value() * 1024);
@@ -1067,10 +1069,8 @@ void OptionsDialog::loadOptions()
// Connection preferences
m_ui->comboProtocol->setCurrentIndex(static_cast<int>(session->btProtocol()));
m_ui->checkUPnP->setChecked(Net::PortForwarder::instance()->isEnabled());
m_ui->checkRandomPort->setChecked(session->useRandomPort());
m_ui->spinPort->setValue(session->port());
m_ui->spinPort->setDisabled(m_ui->checkRandomPort->isChecked());
m_ui->checkUPnP->setChecked(Net::PortForwarder::instance()->isEnabled());
intValue = session->maxConnections();
if (intValue > 0)

View File

@@ -59,7 +59,7 @@ namespace Ui
class OptionsDialog final : public QDialog
{
Q_OBJECT
Q_DISABLE_COPY(OptionsDialog)
Q_DISABLE_COPY_MOVE(OptionsDialog)
using ThisType = OptionsDialog;
@@ -181,6 +181,7 @@ private:
Ui::OptionsDialog *m_ui;
SettingValue<QSize> m_storeDialogSize;
SettingValue<QStringList> m_storeHSplitterSize;
SettingValue<int> m_storeLastViewedPage;
QPushButton *m_applyButton;

View File

@@ -1457,15 +1457,12 @@ Manual: Various torrent properties (e.g. save path) must be assigned manually</s
</item>
<item>
<widget class="QSpinBox" name="spinPort">
<property name="minimum">
<number>1</number>
<property name="specialValueText">
<string>Any</string>
</property>
<property name="maximum">
<number>65535</number>
</property>
<property name="value">
<number>8999</number>
</property>
</widget>
</item>
<item>
@@ -1500,13 +1497,6 @@ Manual: Various torrent properties (e.g. save path) must be assigned manually</s
</property>
</widget>
</item>
<item>
<widget class="QCheckBox" name="checkRandomPort">
<property name="text">
<string>Use different port on each startup</string>
</property>
</widget>
</item>
</layout>
</widget>
</item>
@@ -2673,14 +2663,7 @@ Disable encryption: Only connect to peers without protocol encryption</string>
</property>
<layout class="QGridLayout" name="gridLayout_16">
<item row="0" column="0">
<widget class="QPlainTextEdit" name="textTrackers">
<property name="enabled">
<bool>true</bool>
</property>
<property name="focusPolicy">
<enum>Qt::StrongFocus</enum>
</property>
</widget>
<widget class="QPlainTextEdit" name="textTrackers"/>
</item>
</layout>
</widget>
@@ -3288,7 +3271,7 @@ Use ';' to split multiple entries. Can use wildcard '*'.</string>
</layout>
</widget>
</item>
<item>
<item>
<widget class="QGroupBox" name="groupEnableReverseProxySupport">
<property name="title">
<string>Enable reverse proxy support</string>
@@ -3527,7 +3510,6 @@ Use ';' to split multiple entries. Can use wildcard '*'.</string>
<tabstop>lineEditAutoRun</tabstop>
<tabstop>scrollArea_3</tabstop>
<tabstop>randomButton</tabstop>
<tabstop>checkRandomPort</tabstop>
<tabstop>checkMaxConnecs</tabstop>
<tabstop>spinMaxConnec</tabstop>
<tabstop>checkMaxConnecsPerTorrent</tabstop>

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