Compare commits

...

73 Commits

Author SHA1 Message Date
sledgehammer999
ea5a29018f Bump to 4.1.1 2018-05-27 21:35:07 +03:00
sledgehammer999
c8d0a715e8 Update Changelog 2018-05-27 21:30:13 +03:00
sledgehammer999
2cfc6514ab Sync translations from Transifex and run lupdate 2018-05-27 21:03:53 +03:00
sledgehammer999
1d78bc7206 Bump Web API version 2018-05-27 21:03:53 +03:00
Chocobo1
e5577e43f8 Replace raster qbt logo with vector version
Add helper function for svg icons.
2018-05-27 18:31:51 +03:00
Chocobo1
17c0463906 Fix GUI scaling factor on macOS
macOS seems have an unique way to handle widget size, that is, it doesn't require
application to resize widgets manually, Qt will handle the resize job
automatically.

Closes #8841.
2018-05-27 18:31:51 +03:00
Chocobo1
4168772904 Use 32px icons for favicon
One less resource to manage and 16px size can be downsampled from 32px
on-the-fly anyway.
2018-05-27 18:31:51 +03:00
sledgehammer999
44f2186749 Fix compilation without D-Bus support
Closes #8977
2018-05-27 18:31:51 +03:00
Chocobo1
0c918bcc3a Initialize variables properly
The warnings are emitted when compiling on msys2, mingw

The warning was:
gui/torrentcontentmodel.cpp:135:33: warning: missing initializer for
member '_SHFILEINFOW::iIcon' [-Wmissing-field-initializers]

..\..\qBittorrent\src\app\stacktrace_win.h:141:30: warning: missing
initializer for member '_IMAGEHLP_LINE64::Key'
[-Wmissing-field-initializers]
2018-05-27 18:31:51 +03:00
sledgehammer999
0a8925dc75 Suppress multiple I/O errors for the same torrent
When a file error happens libtorrent spews a ton of `file_error_alert`
which result in log floods and notification balloon floods. The later
might render the program inaccessible because the constant
notifications prevent the user from interacting with the tray icon.

Closes #8934
2018-05-27 18:31:51 +03:00
airium
a446597597 Update strace_win to stacktrace in conf.pri.windows
It is advised to update the stack trace statement since #8701, otherwise people may forget to change it, which results in that no pdb file is generated for Windows distribution package.
2018-05-27 18:31:51 +03:00
Vladimir Golovnev (Glassez)
54354a2732 Add missing 'return' statement 2018-05-27 18:31:51 +03:00
Vladimir Golovnev (Glassez)
d94b8f08ab Use RSS feed update time as a fallback
Some sites omit publication date in its RSS feed articles
that prevents "Ignore Subsequent Matches" to work properly.
Closes #8959.
2018-05-27 18:31:51 +03:00
Chocobo1
0d8189efeb Relax behavior of "Download first and last piece first"
Now it applies the setting to all files in torrent, no matter whether
the file is previewable or not.

Torrent client shouldn't be smart by deciding which file this
option will be applied to, i.e. it should just follow the user's decision.
2018-05-27 18:31:51 +03:00
Chocobo1
00c886e426 Refactor code
Add const to variables.
Add Logger message.
Simplify code logic.
2018-05-27 18:31:51 +03:00
Chocobo1
551fc35439 Simplify the saving & loading of a setting
Remove excessive usage of constexpr.
2018-05-27 18:31:51 +03:00
Chocobo1
9ff17c8d9d Make use of QStringLiteral
Only changed instances that are initialized at program start.
2018-05-27 18:31:51 +03:00
Chocobo1
ec37732e99 Use smaller type 2018-05-27 18:31:51 +03:00
adem
8a414f32a8 Update Windows icons 2018-05-27 18:31:51 +03:00
sledgehammer999
bac06acb49 Fix Stats dialog size
Partially reverts e31ec20ec4.
Closes #8870.
2018-05-27 18:31:51 +03:00
Vladimir Golovnev (Glassez)
ae1e3c2a81 Rename torrent if content was initially renamed
Closes #8910.
2018-05-27 18:31:51 +03:00
Vladimir Golovnev (Glassez)
67940eb0f9 Place "Use Smart Episode Filter" more correctly 2018-05-27 18:31:51 +03:00
Vladimir Golovnev (Glassez)
007aa8480e Make "Ignoring days" to behave like other filters
This prevents confusing in GUI when it shows matched RSS
articles which be really ignored by the rule.
2018-05-27 18:31:51 +03:00
Vladimir Golovnev (Glassez)
dedec10c58 Improve code of RSS auto-downloading rule
Closes #8933.
2018-05-27 18:31:51 +03:00
Vladimir Golovnev (Glassez)
75219e21be Add last used save path to the front of history 2018-05-27 18:31:51 +03:00
Evgeny Lensky
10f5964f8e Fix open destination folder with Nautilus > 3.28
Closes #8923.
2018-05-27 18:31:51 +03:00
Chocobo1
a4a64d51c0 Improve "Run External Program" behavior
This follows utorrent behavior: they don't append backslash character at
the end of path variables.
Closes #8836.
2018-05-27 18:31:51 +03:00
Vladimir Golovnev (Glassez)
1014313d88 Rename RSS properties to follow other names 2018-05-27 18:31:51 +03:00
Vladimir Golovnev (Glassez)
e486bb4c29 Properly set RSS settings via API
Closes #8925.
2018-05-27 18:31:51 +03:00
Vladimir Golovnev (Glassez)
5c3d9ffb46 Properly fill UploadedFile::filename field
Closes #8928.
2018-05-27 18:31:51 +03:00
Chocobo1
2e474fd8db Detect endianness at compile time 2018-05-27 18:31:51 +03:00
Vladimir Golovnev (Glassez)
b2b110ae1f Add option to remember last used save path
Replace in "Add new torrent" dialog confusing "Set as default save path" option
with "Remember last used save path" option that affects only selected value in
"Save path" combo box.
Closes #7323.
2018-05-27 18:31:51 +03:00
Chocobo1
68a34e0738 Refactor code
Add const to variables.
No functionality change.
2018-05-27 18:31:51 +03:00
Chocobo1
38fa575958 Apply locale changes immediately in WebUI 2018-05-27 18:31:51 +03:00
Chocobo1
6cfeefe054 Rename variables
Variable name should not start with underscore as C++ standard stated it
is reserved.
2018-05-27 18:31:51 +03:00
Chocobo1
8007971a53 Fix i18n in WebUI
Closes #8844.
2018-05-27 18:31:51 +03:00
Chocobo1
d66bd30fae Make strings translatable
Closes #8866.
2018-05-27 18:31:51 +03:00
sledgehammer999
3fa59b1b12 Don't migrate torrents that have newer fastresumes 2018-05-27 18:31:51 +03:00
sledgehammer999
20e7aff393 Delete non-commited fastresume files
Old v3.3.x format had a number at the end indicating the queue position.
The naming scheme was '<infohash>.fastresume.<queueposition>'.
However, QSaveFile, which uses QTemporaryFile internally, might leave
non-commited files behind eg after a crash. These files have the
naming scheme '<infohash>.fastresume.XXXXXX' where each X is a random
character. We try to detect the latter and remove it without "migrating"
the fastresume to the new saving system.
2018-05-27 18:31:51 +03:00
Vladimir Golovnev (Glassez)
4b7ce87f57 Fix params handling for some legacy API methods
Closes #8880.
2018-05-27 18:31:51 +03:00
Vladimir Golovnev (Glassez)
2075533468 Improve legacy API params handling 2018-05-27 18:31:51 +03:00
Vladimir Golovnev (Glassez)
a4ad5c8d11 Fix invalid API calls in WebUI
Closes #8899.
2018-05-27 18:31:51 +03:00
sledgehammer999
35f2f56757 Fix deletion of old logs 2018-05-27 18:31:51 +03:00
Marcel Petersen
e6f4aa6a2f Filter torrent info endpoint by hashes
Added hashes parameter to info action.
Allows filtering seralized torrents by passing it into the TorrentFilter.
2018-05-27 18:31:51 +03:00
sledgehammer999
92fc62bb0d Show rechecking progress
When having big torrents, the rechecking might take a while to
complete. Users need some sort of feedback that progress is being made.
Also, I changed the float to qreal since that's the return type.
2018-05-27 18:31:51 +03:00
sledgehammer999
44b57a59f5 Log successful torrent move 2018-05-27 18:31:51 +03:00
sledgehammer999
97b8e02bf5 Add 'Moving' state for torrents being relocated/moved
This is another indication to the user that something is happening
behind the scenes.
Uses the same icon/color as "Checking" status.
Torrents in the `Moving` state are considered as "Active". This should
prevent accidental program exit from the user and inhibit system sleep.
2018-05-27 18:31:51 +03:00
Chocobo1
5df42420cb Retry saving settings when operation failed 2018-05-27 18:31:51 +03:00
Chocobo1
0ede11a1b7 Make settings file recovery more robust
We should not blindly remove the leftover settings file, as the following write()
operation could fail and the user would lost all settings.
We should try renaming it instead.
2018-05-27 18:31:51 +03:00
Chocobo1
7d9c282db9 Refactor SettingsStorage class
Make use of (i.e. returning) QFile::rename operation status
Make log message more verbose
Add const
Remove empty lines
Inline typedef
2018-05-27 18:31:51 +03:00
Chocobo1
bc0e0813a4 Enable more compiler warnings on linux 2018-05-27 18:31:51 +03:00
Vladimir Golovnev (Glassez)
f3aebb3001 Fix compilation with MinGW 2018-05-27 18:31:51 +03:00
thalieht
800f966df9 Use qt5 syntax for a few remaining SLOT() 2018-05-27 18:31:51 +03:00
thalieht
e33df4dd8c Clarify guidelines and fix some typos 2018-05-27 18:31:51 +03:00
thalieht
96d9d810fd Fix coding style 2018-05-27 18:31:51 +03:00
thalieht
8707a1bc86 Move some connect() from propertieswidget to their corresponding widget 2018-05-27 18:31:51 +03:00
thalieht
0c988a5fd4 Use qt5 connect() syntax 2018-05-27 18:31:51 +03:00
Chocobo1
b396ca771d Fix displayed tracker messages
Before this change, we were displaying debug messages constructed by
libtorrent, now we show messages returned by trackers.

Closes #8739.
2018-05-27 18:31:51 +03:00
Chocobo1
a37dfcf961 Refactor functions
Add const to variables
Remove debug messages
2018-05-27 18:31:51 +03:00
Chocobo1
31989740cd Comment out Werror flag in cmake script
Werror flag should be only enabled on developer's machine, not for
users using the product.
Also fix formatting.
2018-05-27 18:31:51 +03:00
Chocobo1
501191289b Print warning about cmake support status 2018-05-27 18:31:51 +03:00
Chocobo1
8971e92d78 Remove debug messages 2018-05-27 18:31:51 +03:00
Chocobo1
0c96e79d0d Refactor code
Remove forward declarations of Qt types.
Fix header include order.
2018-05-27 18:31:51 +03:00
Nick Korotysh
0704c0f5e6 Add missing "override" 2018-05-27 18:31:51 +03:00
thalieht
9cb190ebe7 Replace the zeroing of pointers with nullptr 2018-05-27 18:31:51 +03:00
Vladimir Golovnev (Glassez)
667f84995c Fix wrong API method names
Closes #8828.
2018-05-27 18:31:51 +03:00
Chocobo1
7a93fae6e4 Fix compile warnings on gcc 8
The warning was:
warning: catching polymorphic type ‘class std::exception’ by value
[-Wcatch-value=]
2018-05-27 18:31:51 +03:00
Chocobo1
0d6deca15c Revert commit
Apparently the translations were working in previous state, but affected by
lupdate issue:
https://github.com/qbittorrent/qBittorrent/issues/8220#issuecomment-385712673

The reverts commit fb698896c9.
Closes #8831.
2018-05-27 18:31:51 +03:00
Chocobo1
f54d7d46f2 Really fix translation in fspathedit
QT_TRANSLATE_NOOP3 is a macro, so we cannot use a runtime string for the context
argument.
Fix up 1d778676cd.
2018-05-27 18:31:51 +03:00
Chocobo1
8cf00ba5e1 Fix translation strings not found
The translation context doesn't exist, so the translations were not found, fixed
now.
Closes #8829.
2018-05-27 18:31:51 +03:00
Chocobo1
ecc9c6bbd9 Work around false-positive warning from lupdate
In short, lupdate will get confused when seeing `template <class T>`,
see: QTBUG-55478
2018-05-27 18:31:51 +03:00
Chocobo1
e11199f988 Fix usage of Q_DECLARE_TR_FUNCTIONS()
The context parameter shouldn't be enclosed in double quotes.
2018-05-27 18:31:51 +03:00
sledgehammer999
e9ed621178 Bump to 4.1.0 2018-05-05 00:55:42 +03:00
220 changed files with 52641 additions and 45112 deletions

View File

@@ -1,6 +1,8 @@
cmake_minimum_required(VERSION 3.5) cmake_minimum_required(VERSION 3.5)
cmake_policy(VERSION 3.5) cmake_policy(VERSION 3.5)
message(WARNING "No official support for cmake build system. If it is broken, please submit patches!")
list(APPEND CMAKE_MODULE_PATH ${CMAKE_CURRENT_SOURCE_DIR}/cmake/Modules) list(APPEND CMAKE_MODULE_PATH ${CMAKE_CURRENT_SOURCE_DIR}/cmake/Modules)
include(FunctionReadVersion) include(FunctionReadVersion)

View File

@@ -239,11 +239,11 @@ The headers should be placed in the following group order:
4. Boost library headers 4. Boost library headers
5. Libtorrent headers 5. Libtorrent headers
6. Qt headers 6. Qt headers
7. qBittorrent own headers, starting from *base* headers. 7. qBittorrent's own headers, starting from the *base* headers.
The headers should be ordered alphabetically within each group. The headers should be ordered alphabetically within each group.
If there are conditionals for the same header group, then put them at the bottom of the respective group. If there are conditionals for the same header group, then put them at the bottom of the respective group.
If there are conditionals for the different header groups, then put them above of the "qBittorrent own headers" group. If there are conditionals that contain headers from several different header groups, then put them above the "qBittorrent's own headers" group.
One exception is the header containing the library version (for example, QtGlobal), this particular header isn't constrained by the aforementioned order. One exception is the header containing the library version (for example, QtGlobal), this particular header isn't constrained by the aforementioned order.
@@ -285,13 +285,13 @@ Example:
#include <QFont> #include <QFont>
#endif #endif
// conditional for the different header groups // conditional that contains headers from several different header groups
#if LIBTORRENT_VERSION_NUM >= 10100 #if LIBTORRENT_VERSION_NUM >= 10100
#include <memory> #include <memory>
#include <QElapsedTimer> #include <QElapsedTimer>
#endif #endif
// qBittorrent own headers // qBittorrent's own headers
#include "base/bittorrent/infohash.h" #include "base/bittorrent/infohash.h"
#include "anothermodule.h" #include "anothermodule.h"
#include "ui_examplewidget.h" #include "ui_examplewidget.h"

View File

@@ -1,3 +1,39 @@
* Sun May 27 2018 - sledgehammer999 <sledgehammer999@qbittorrent.org> - v4.1.1
- FEATURE: Add 'Moving' state for torrents being relocated/moved (sledgehammer999)
- FEATURE: Show rechecking progress (sledgehammer999)
- FEATURE: Add option to remember last used save path (glassez)
- FEATURE: Torrent name is also renamed if the content was renamed in the "Add New Torrent" dialog (glassez)
- FEATURE: Relax behavior of "Download first and last piece first". It applies to all files and not only to the previewable. (Chocobo1)
- BUGFIX: Fix issues with translatable strings (Chocobo1)
- BUGFIX: Fix displayed tracker messages (Chocobo1)
- BUGFIX: Make settings file recovery more robust (Chocobo1)
- BUGFIX: Retry saving settings when operation failed (Chocobo1)
- BUGFIX: Log successful torrent move (sledgehammer999)
- BUGFIX: Fix deletion of old logs (sledgehammer999)
- BUGFIX: Delete non-commited fastresume files (sledgehammer999)
- BUGFIX: Don't migrate torrents that have newer fastresumes (sledgehammer999)
- BUGFIX: Fix adding multiple torrents at once from WebUI (glassez)
- BUGFIX: Improve "Run External Program" behavior. On Windows, a backslash isn't appended to paths from path variables (Chocobo1)
- BUGFIX: Suppress multiple I/O errors for the same torrent (sledgehammer999)
- BUGFIX: Replace raster qbt logo with vector version (Chocobo1)
- WEBUI: Fix wrong API method names (glassez)
- WEBUI: Filter torrent info endpoint by hashes (Marcel Petersen)
- WEBUI: Fix invalid API calls in WebUI (glassez)
- WEBUI: Improve legacy API params handling (glassez)
- WEBUI: Fix params handling for some legacy API methods (glassez)
- WEBUI: Apply locale changes immediately in WebUI (Chocobo1)
- WEBUI: Use 32px icons for favicon (Chocobo1)
- WEBUI/RSS: Properly set RSS settings via API (glassez)
- RSS: Fix auto-downloading rule when Smart filter with regular Episode filter are used (glassez)
- RSS: Make "Ignoring days" to behave like other filters (glassez)
- RSS: Place "Use Smart Episode Filter" more correctly (glassez)
- RSS: Use RSS feed update time as a fallback (glassez)
- COSMETIC: Fix Stats dialog size (sledgehammer999)
- MACOS: Fix GUI scaling factor on macOS (Chocobo1)
- WINDOWS: Update icons (adem4ik)
- LINUX: Fix open destination folder with Nautilus > 3.28 (Evgeny Lensky)
- OTHER: Code improvements and refactoring (thalieht, Nick Korotysh, Chocobo1)
* Sat May 05 2018 - sledgehammer999 <sledgehammer999@qbittorrent.org> - v4.1.0 * Sat May 05 2018 - sledgehammer999 <sledgehammer999@qbittorrent.org> - v4.1.0
- FEATURE: Add "Coalesce reads & writes" checkbox in advanced options (Chocobo1) - FEATURE: Add "Coalesce reads & writes" checkbox in advanced options (Chocobo1)
- FEATURE: Smart Filter for RSS (Stephen Dawkins) - FEATURE: Smart Filter for RSS (Stephen Dawkins)

View File

@@ -11,18 +11,17 @@ macro(qbt_set_compiler_options)
#-Wshadow -Wconversion ? #-Wshadow -Wconversion ?
set(_GCC_COMMON_C_AND_CXX_FLAGS "-Wall -Wextra" set(_GCC_COMMON_C_AND_CXX_FLAGS "-Wall -Wextra"
"-Wfloat-equal -Wcast-qual -Wcast-align" "-Wfloat-equal -Wcast-qual -Wcast-align"
"-Wsign-conversion -Winvalid-pch -Werror=return-type -Wno-long-long" "-Wsign-conversion -Winvalid-pch -Wno-long-long"
# -fstack-protector-all #"-fstack-protector-all"
"-Werror -Wno-error=deprecated-declarations" #"-Werror -Wno-error=deprecated-declarations"
) )
set(_GCC_COMMON_CXX_FLAGS "-fexceptions -frtti" set(_GCC_COMMON_CXX_FLAGS "-fexceptions -frtti"
"-Woverloaded-virtual -Wold-style-cast" "-Woverloaded-virtual -Wold-style-cast"
"-Wnon-virtual-dtor -Wfloat-equal -Wcast-qual -Wcast-align" "-Wnon-virtual-dtor -Wfloat-equal -Wcast-qual -Wcast-align"
"-Werror=overloaded-virtual"
#"-Weffc++" #"-Weffc++"
"-Werror -Wno-error=cpp" #"-Werror -Wno-error=cpp"
# we should modify code to make these ones obsolete # we should modify code to make these ones obsolete
"-Wno-error=sign-conversion -Wno-error=float-equal" #"-Wno-error=sign-conversion -Wno-error=float-equal"
) )
if ("${CMAKE_CXX_COMPILER_ID}" STREQUAL "GNU" AND CMAKE_CXX_COMPILER_VERSION VERSION_LESS 4.9) if ("${CMAKE_CXX_COMPILER_ID}" STREQUAL "GNU" AND CMAKE_CXX_COMPILER_VERSION VERSION_LESS 4.9)

View File

@@ -58,4 +58,4 @@ DEFINES += BOOST_USE_WINAPI_VERSION=0x0501
#DEFINES += TORRENT_LINKING_SHARED #DEFINES += TORRENT_LINKING_SHARED
# Enable stack trace support # Enable stack trace support
CONFIG += strace_win CONFIG += stacktrace

24
configure vendored
View File

@@ -1,6 +1,6 @@
#! /bin/sh #! /bin/sh
# Guess values for system-dependent variables and create Makefiles. # Guess values for system-dependent variables and create Makefiles.
# Generated by GNU Autoconf 2.69 for qbittorrent v4.1.0alpha. # Generated by GNU Autoconf 2.69 for qbittorrent v4.1.1.
# #
# Report bugs to <bugs.qbittorrent.org>. # Report bugs to <bugs.qbittorrent.org>.
# #
@@ -580,8 +580,8 @@ MAKEFLAGS=
# Identity of this package. # Identity of this package.
PACKAGE_NAME='qbittorrent' PACKAGE_NAME='qbittorrent'
PACKAGE_TARNAME='qbittorrent' PACKAGE_TARNAME='qbittorrent'
PACKAGE_VERSION='v4.1.0alpha' PACKAGE_VERSION='v4.1.1'
PACKAGE_STRING='qbittorrent v4.1.0alpha' PACKAGE_STRING='qbittorrent v4.1.1'
PACKAGE_BUGREPORT='bugs.qbittorrent.org' PACKAGE_BUGREPORT='bugs.qbittorrent.org'
PACKAGE_URL='https://www.qbittorrent.org/' PACKAGE_URL='https://www.qbittorrent.org/'
@@ -1297,7 +1297,7 @@ if test "$ac_init_help" = "long"; then
# Omit some internal or obsolete options to make the list less imposing. # Omit some internal or obsolete options to make the list less imposing.
# This message is too long to be a string in the A/UX 3.1 sh. # This message is too long to be a string in the A/UX 3.1 sh.
cat <<_ACEOF cat <<_ACEOF
\`configure' configures qbittorrent v4.1.0alpha to adapt to many kinds of systems. \`configure' configures qbittorrent v4.1.1 to adapt to many kinds of systems.
Usage: $0 [OPTION]... [VAR=VALUE]... Usage: $0 [OPTION]... [VAR=VALUE]...
@@ -1368,7 +1368,7 @@ fi
if test -n "$ac_init_help"; then if test -n "$ac_init_help"; then
case $ac_init_help in case $ac_init_help in
short | recursive ) echo "Configuration of qbittorrent v4.1.0alpha:";; short | recursive ) echo "Configuration of qbittorrent v4.1.1:";;
esac esac
cat <<\_ACEOF cat <<\_ACEOF
@@ -1503,7 +1503,7 @@ fi
test -n "$ac_init_help" && exit $ac_status test -n "$ac_init_help" && exit $ac_status
if $ac_init_version; then if $ac_init_version; then
cat <<\_ACEOF cat <<\_ACEOF
qbittorrent configure v4.1.0alpha qbittorrent configure v4.1.1
generated by GNU Autoconf 2.69 generated by GNU Autoconf 2.69
Copyright (C) 2012 Free Software Foundation, Inc. Copyright (C) 2012 Free Software Foundation, Inc.
@@ -1642,7 +1642,7 @@ cat >config.log <<_ACEOF
This file contains any messages produced by compilers while This file contains any messages produced by compilers while
running configure, to aid debugging if configure makes a mistake. running configure, to aid debugging if configure makes a mistake.
It was created by qbittorrent $as_me v4.1.0alpha, which was It was created by qbittorrent $as_me v4.1.1, which was
generated by GNU Autoconf 2.69. Invocation command line was generated by GNU Autoconf 2.69. Invocation command line was
$ $0 $@ $ $0 $@
@@ -3820,7 +3820,7 @@ fi
# Define the identity of the package. # Define the identity of the package.
PACKAGE='qbittorrent' PACKAGE='qbittorrent'
VERSION='v4.1.0alpha' VERSION='v4.1.1'
cat >>confdefs.h <<_ACEOF cat >>confdefs.h <<_ACEOF
@@ -6140,7 +6140,7 @@ cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1
# report actual input values of CONFIG_FILES etc. instead of their # report actual input values of CONFIG_FILES etc. instead of their
# values after options handling. # values after options handling.
ac_log=" ac_log="
This file was extended by qbittorrent $as_me v4.1.0alpha, which was This file was extended by qbittorrent $as_me v4.1.1, which was
generated by GNU Autoconf 2.69. Invocation command line was generated by GNU Autoconf 2.69. Invocation command line was
CONFIG_FILES = $CONFIG_FILES CONFIG_FILES = $CONFIG_FILES
@@ -6198,7 +6198,7 @@ _ACEOF
cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1
ac_cs_config="`$as_echo "$ac_configure_args" | sed 's/^ //; s/[\\""\`\$]/\\\\&/g'`" ac_cs_config="`$as_echo "$ac_configure_args" | sed 's/^ //; s/[\\""\`\$]/\\\\&/g'`"
ac_cs_version="\\ ac_cs_version="\\
qbittorrent config.status v4.1.0alpha qbittorrent config.status v4.1.1
configured by $0, generated by GNU Autoconf 2.69, configured by $0, generated by GNU Autoconf 2.69,
with options \\"\$ac_cs_config\\" with options \\"\$ac_cs_config\\"
@@ -7455,7 +7455,7 @@ cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1
# report actual input values of CONFIG_FILES etc. instead of their # report actual input values of CONFIG_FILES etc. instead of their
# values after options handling. # values after options handling.
ac_log=" ac_log="
This file was extended by qbittorrent $as_me v4.1.0alpha, which was This file was extended by qbittorrent $as_me v4.1.1, which was
generated by GNU Autoconf 2.69. Invocation command line was generated by GNU Autoconf 2.69. Invocation command line was
CONFIG_FILES = $CONFIG_FILES CONFIG_FILES = $CONFIG_FILES
@@ -7513,7 +7513,7 @@ _ACEOF
cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1
ac_cs_config="`$as_echo "$ac_configure_args" | sed 's/^ //; s/[\\""\`\$]/\\\\&/g'`" ac_cs_config="`$as_echo "$ac_configure_args" | sed 's/^ //; s/[\\""\`\$]/\\\\&/g'`"
ac_cs_version="\\ ac_cs_version="\\
qbittorrent config.status v4.1.0alpha qbittorrent config.status v4.1.1
configured by $0, generated by GNU Autoconf 2.69, configured by $0, generated by GNU Autoconf 2.69,
with options \\"\$ac_cs_config\\" with options \\"\$ac_cs_config\\"

View File

@@ -1,4 +1,4 @@
AC_INIT([qbittorrent], [v4.1.0alpha], [bugs.qbittorrent.org], [], [https://www.qbittorrent.org/]) AC_INIT([qbittorrent], [v4.1.1], [bugs.qbittorrent.org], [], [https://www.qbittorrent.org/])
AC_CONFIG_AUX_DIR([build-aux]) AC_CONFIG_AUX_DIR([build-aux])
AC_CONFIG_MACRO_DIR([m4]) AC_CONFIG_MACRO_DIR([m4])
AC_PROG_CC AC_PROG_CC

2
dist/mac/Info.plist vendored
View File

@@ -45,7 +45,7 @@
<key>CFBundlePackageType</key> <key>CFBundlePackageType</key>
<string>APPL</string> <string>APPL</string>
<key>CFBundleShortVersionString</key> <key>CFBundleShortVersionString</key>
<string>4.1.0</string> <string>4.1.1</string>
<key>CFBundleSignature</key> <key>CFBundleSignature</key>
<string>qBit</string> <string>qBit</string>
<key>CFBundleExecutable</key> <key>CFBundleExecutable</key>

View File

@@ -27,7 +27,7 @@ XPStyle on
!define CSIDL_LOCALAPPDATA '0x1C' ;Local Application Data path !define CSIDL_LOCALAPPDATA '0x1C' ;Local Application Data path
; Program specific ; Program specific
!define PROG_VERSION "4.1.0" !define PROG_VERSION "4.1.1"
!define MUI_FINISHPAGE_RUN !define MUI_FINISHPAGE_RUN
!define MUI_FINISHPAGE_RUN_FUNCTION PageFinishRun !define MUI_FINISHPAGE_RUN_FUNCTION PageFinishRun

View File

@@ -93,7 +93,7 @@ namespace
#define SETTINGS_KEY(name) "Application/" name #define SETTINGS_KEY(name) "Application/" name
// FileLogger properties keys // FileLogger properties keys
#define FILELOGGER_SETTINGS_KEY(name) SETTINGS_KEY("FileLogger/") name #define FILELOGGER_SETTINGS_KEY(name) QStringLiteral(SETTINGS_KEY("FileLogger/") name)
const QString KEY_FILELOGGER_ENABLED = FILELOGGER_SETTINGS_KEY("Enabled"); const QString KEY_FILELOGGER_ENABLED = FILELOGGER_SETTINGS_KEY("Enabled");
const QString KEY_FILELOGGER_PATH = FILELOGGER_SETTINGS_KEY("Path"); const QString KEY_FILELOGGER_PATH = FILELOGGER_SETTINGS_KEY("Path");
const QString KEY_FILELOGGER_BACKUP = FILELOGGER_SETTINGS_KEY("Backup"); const QString KEY_FILELOGGER_BACKUP = FILELOGGER_SETTINGS_KEY("Backup");
@@ -151,11 +151,11 @@ Application::Application(const QString &id, int &argc, char **argv)
#endif #endif
#if defined(Q_OS_WIN) && !defined(DISABLE_GUI) #if defined(Q_OS_WIN) && !defined(DISABLE_GUI)
connect(this, SIGNAL(commitDataRequest(QSessionManager &)), this, SLOT(shutdownCleanup(QSessionManager &)), Qt::DirectConnection); connect(this, &QGuiApplication::commitDataRequest, this, &Application::shutdownCleanup, Qt::DirectConnection);
#endif #endif
connect(this, SIGNAL(messageReceived(const QString &)), SLOT(processMessage(const QString &))); connect(this, &Application::messageReceived, this, &Application::processMessage);
connect(this, SIGNAL(aboutToQuit()), SLOT(cleanup())); connect(this, &QCoreApplication::aboutToQuit, this, &Application::cleanup);
if (isFileLoggerEnabled()) if (isFileLoggerEnabled())
m_fileLogger = new FileLogger(fileLoggerPath(), isFileLoggerBackup(), fileLoggerMaxSize(), isFileLoggerDeleteOld(), fileLoggerAge(), static_cast<FileLogger::FileLogAgeType>(fileLoggerAgeType())); m_fileLogger = new FileLogger(fileLoggerPath(), isFileLoggerBackup(), fileLoggerMaxSize(), isFileLoggerDeleteOld(), fileLoggerAge(), static_cast<FileLogger::FileLogAgeType>(fileLoggerAgeType()));
@@ -290,9 +290,21 @@ void Application::runExternalProgram(const BitTorrent::TorrentHandle *torrent) c
std::sort(tags.begin(), tags.end(), Utils::String::naturalLessThan<Qt::CaseInsensitive>); std::sort(tags.begin(), tags.end(), Utils::String::naturalLessThan<Qt::CaseInsensitive>);
program.replace("%G", tags.join(',')); program.replace("%G", tags.join(','));
#if defined(Q_OS_WIN)
const auto chopPathSep = [](const QString &str) -> QString
{
if (str.endsWith('\\'))
return str.mid(0, (str.length() -1));
return str;
};
program.replace("%F", chopPathSep(Utils::Fs::toNativePath(torrent->contentPath())));
program.replace("%R", chopPathSep(Utils::Fs::toNativePath(torrent->rootPath())));
program.replace("%D", chopPathSep(Utils::Fs::toNativePath(torrent->savePath())));
#else
program.replace("%F", Utils::Fs::toNativePath(torrent->contentPath())); program.replace("%F", Utils::Fs::toNativePath(torrent->contentPath()));
program.replace("%R", Utils::Fs::toNativePath(torrent->rootPath())); program.replace("%R", Utils::Fs::toNativePath(torrent->rootPath()));
program.replace("%D", Utils::Fs::toNativePath(torrent->savePath())); program.replace("%D", Utils::Fs::toNativePath(torrent->savePath()));
#endif
program.replace("%C", QString::number(torrent->filesCount())); program.replace("%C", QString::number(torrent->filesCount()));
program.replace("%Z", QString::number(torrent->totalSize())); program.replace("%Z", QString::number(torrent->totalSize()));
program.replace("%T", torrent->currentTracker()); program.replace("%T", torrent->currentTracker());
@@ -301,9 +313,7 @@ void Application::runExternalProgram(const BitTorrent::TorrentHandle *torrent) c
Logger *logger = Logger::instance(); Logger *logger = Logger::instance();
logger->addMessage(tr("Torrent: %1, running external program, command: %2").arg(torrent->name(), program)); logger->addMessage(tr("Torrent: %1, running external program, command: %2").arg(torrent->name(), program));
#if defined(Q_OS_UNIX) #if defined(Q_OS_WIN)
QProcess::startDetached(QLatin1String("/bin/sh"), {QLatin1String("-c"), program});
#else
std::unique_ptr<wchar_t[]> programWchar(new wchar_t[program.length() + 1] {}); std::unique_ptr<wchar_t[]> programWchar(new wchar_t[program.length() + 1] {});
program.toWCharArray(programWchar.get()); program.toWCharArray(programWchar.get());
@@ -320,6 +330,8 @@ void Application::runExternalProgram(const BitTorrent::TorrentHandle *torrent) c
QProcess::startDetached(QString::fromWCharArray(args[0]), argList); QProcess::startDetached(QString::fromWCharArray(args[0]), argList);
::LocalFree(args); ::LocalFree(args);
#else
QProcess::startDetached(QLatin1String("/bin/sh"), {QLatin1String("-c"), program});
#endif #endif
} }
@@ -489,8 +501,8 @@ int Application::exec(const QStringList &params)
#endif #endif
BitTorrent::Session::initInstance(); BitTorrent::Session::initInstance();
connect(BitTorrent::Session::instance(), SIGNAL(torrentFinished(BitTorrent::TorrentHandle *const)), SLOT(torrentFinished(BitTorrent::TorrentHandle *const))); connect(BitTorrent::Session::instance(), &BitTorrent::Session::torrentFinished, this, &Application::torrentFinished);
connect(BitTorrent::Session::instance(), SIGNAL(allTorrentsFinished()), SLOT(allTorrentsFinished()), Qt::QueuedConnection); connect(BitTorrent::Session::instance(), &BitTorrent::Session::allTorrentsFinished, this, &Application::allTorrentsFinished, Qt::QueuedConnection);
#ifndef DISABLE_COUNTRIES_RESOLUTION #ifndef DISABLE_COUNTRIES_RESOLUTION
Net::GeoIPManager::initInstance(); Net::GeoIPManager::initInstance();
@@ -660,7 +672,7 @@ void Application::shutdownCleanup(QSessionManager &manager)
// According to the qt docs we shouldn't call quit() inside a slot. // According to the qt docs we shouldn't call quit() inside a slot.
// aboutToQuit() is never emitted if the user hits "Cancel" in // aboutToQuit() is never emitted if the user hits "Cancel" in
// the above dialog. // the above dialog.
QTimer::singleShot(0, qApp, SLOT(quit())); QTimer::singleShot(0, qApp, &QCoreApplication::quit);
} }
#endif #endif

View File

@@ -110,7 +110,7 @@ public:
protected: protected:
#ifndef DISABLE_GUI #ifndef DISABLE_GUI
#ifdef Q_OS_MAC #ifdef Q_OS_MAC
bool event(QEvent *); bool event(QEvent *) override;
#endif #endif
bool notify(QObject* receiver, QEvent* event) override; bool notify(QObject* receiver, QEvent* event) override;
#endif #endif

View File

@@ -41,7 +41,7 @@ FileLogger::FileLogger(const QString &path, const bool backup, const int maxSize
{ {
m_flusher.setInterval(0); m_flusher.setInterval(0);
m_flusher.setSingleShot(true); m_flusher.setSingleShot(true);
connect(&m_flusher, SIGNAL(timeout()), SLOT(flushLog())); connect(&m_flusher, &QTimer::timeout, this, &FileLogger::flushLog);
changePath(path); changePath(path);
if (deleteOld) if (deleteOld)
@@ -51,7 +51,7 @@ FileLogger::FileLogger(const QString &path, const bool backup, const int maxSize
foreach (const Log::Msg& msg, logger->getMessages()) foreach (const Log::Msg& msg, logger->getMessages())
addLogMessage(msg); addLogMessage(msg);
connect(logger, SIGNAL(newLogMessage(const Log::Msg &)), SLOT(addLogMessage(const Log::Msg &))); connect(logger, &Logger::newLogMessage, this, &FileLogger::addLogMessage);
} }
FileLogger::~FileLogger() FileLogger::~FileLogger()
@@ -83,21 +83,21 @@ void FileLogger::changePath(const QString& newPath)
void FileLogger::deleteOld(const int age, const FileLogAgeType ageType) void FileLogger::deleteOld(const int age, const FileLogAgeType ageType)
{ {
QDateTime date = QDateTime::currentDateTime(); QDateTime date = QDateTime::currentDateTime();
QDir dir(m_path); QDir dir(Utils::Fs::branchPath(m_path));
switch (ageType) {
case DAYS:
date = date.addDays(age);
break;
case MONTHS:
date = date.addMonths(age);
break;
default:
date = date.addYears(age);
}
foreach (const QFileInfo file, dir.entryInfoList(QStringList("qbittorrent.log.bak*"), QDir::Files | QDir::Writable, QDir::Time | QDir::Reversed)) { foreach (const QFileInfo file, dir.entryInfoList(QStringList("qbittorrent.log.bak*"), QDir::Files | QDir::Writable, QDir::Time | QDir::Reversed)) {
if (file.lastModified() < date) QDateTime modificationDate = file.lastModified();
switch (ageType) {
case DAYS:
modificationDate = modificationDate.addDays(age);
break;
case MONTHS:
modificationDate = modificationDate.addMonths(age);
break;
default:
modificationDate = modificationDate.addYears(age);
}
if (modificationDate > date)
break; break;
Utils::Fs::forceRemove(file.absoluteFilePath()); Utils::Fs::forceRemove(file.absoluteFilePath());
} }

View File

@@ -329,7 +329,7 @@ void showSplashScreen()
painter.drawText(224 - painter.fontMetrics().width(version), 270, version); painter.drawText(224 - painter.fontMetrics().width(version), 270, version);
QSplashScreen *splash = new QSplashScreen(splash_img); QSplashScreen *splash = new QSplashScreen(splash_img);
splash->show(); splash->show();
QTimer::singleShot(1500, splash, SLOT(deleteLater())); QTimer::singleShot(1500, splash, &QObject::deleteLater);
qApp->processEvents(); qApp->processEvents();
} }

View File

@@ -138,7 +138,7 @@ bool straceWin::makeRelativePath(const QString& dir, QString& file)
QString straceWin::getSourcePathAndLineNumber(HANDLE hProcess, DWORD64 addr) QString straceWin::getSourcePathAndLineNumber(HANDLE hProcess, DWORD64 addr)
{ {
IMAGEHLP_LINE64 line = {0}; IMAGEHLP_LINE64 line {};
line.SizeOfStruct = sizeof(IMAGEHLP_LINE64); line.SizeOfStruct = sizeof(IMAGEHLP_LINE64);
DWORD dwDisplacement = 0; DWORD dwDisplacement = 0;

View File

@@ -114,12 +114,27 @@ bool upgradeResumeFile(const QString &filepath, const QVariantHash &oldTorrent =
bool v3_3 = false; bool v3_3 = false;
int queuePosition = 0; int queuePosition = 0;
QString outFilePath = filepath; QString outFilePath = filepath;
QRegExp rx(QLatin1String("([A-Fa-f0-9]{40})\\.fastresume\\.(\\d+)$")); QRegExp rx(QLatin1String("([A-Fa-f0-9]{40})\\.fastresume\\.(.+)$"));
if (rx.indexIn(filepath) != -1) { if (rx.indexIn(filepath) != -1) {
// old v3.3.x format // Old v3.3.x format had a number at the end indicating the queue position.
// The naming scheme was '<infohash>.fastresume.<queueposition>'.
// However, QSaveFile, which uses QTemporaryFile internally, might leave
// non-commited files behind eg after a crash. These files have the
// naming scheme '<infohash>.fastresume.XXXXXX' where each X is a random
// character. So we detect if the last part is present. Then check if it
// is 6 chars long. If all the 6 chars are digits we assume it is an old
// v3.3.x format. Otherwise it is considered a non-commited fastresume
// and is deleted, because it may be a corrupted/incomplete fastresume.
// NOTE: When the upgrade code is removed, we must continue to perform
// cleanup of non-commited QSaveFile/QTemporaryFile fastresumes
queuePosition = rx.cap(2).toInt(); queuePosition = rx.cap(2).toInt();
if ((rx.cap(2).size() == 6) && (queuePosition <= 99999)) {
Utils::Fs::forceRemove(filepath);
return true;
}
v3_3 = true; v3_3 = true;
outFilePath.replace(QRegExp("\\.\\d+$"), ""); outFilePath.replace(QRegExp("\\.fastresume\\..+$"), ".fastresume");
} }
else { else {
queuePosition = fastOld.dict_find_int_value("qBt-queuePosition", 0); queuePosition = fastOld.dict_find_int_value("qBt-queuePosition", 0);
@@ -130,6 +145,15 @@ bool upgradeResumeFile(const QString &filepath, const QVariantHash &oldTorrent =
// in versions < 3.3 we have -1 for seeding torrents, so we convert it to 0 // in versions < 3.3 we have -1 for seeding torrents, so we convert it to 0
fastNew["qBt-queuePosition"] = (queuePosition >= 0 ? queuePosition : 0); fastNew["qBt-queuePosition"] = (queuePosition >= 0 ? queuePosition : 0);
if (v3_3) {
QFileInfo oldFile(filepath);
QFileInfo newFile(outFilePath);
if (newFile.exists()
&& (oldFile.lastModified() < newFile.lastModified())) {
Utils::Fs::forceRemove(filepath);
return true;
}
}
QFile file2(outFilePath); QFile file2(outFilePath);
QVector<char> out; QVector<char> out;
libtorrent::bencode(std::back_inserter(out), fastNew); libtorrent::bencode(std::back_inserter(out), fastNew);

View File

@@ -1,5 +1,5 @@
/* /*
* Bittorrent Client using Qt and libt. * Bittorrent Client using Qt and libtorrent.
* Copyright (C) 2006 Christophe Dumez <chris@qbittorrent.org> * Copyright (C) 2006 Christophe Dumez <chris@qbittorrent.org>
* *
* This program is free software; you can redistribute it and/or * This program is free software; you can redistribute it and/or
@@ -147,13 +147,13 @@ int FilterParserThread::parseDATFilterFile()
if (bytesRead < 0) if (bytesRead < 0)
break; break;
int dataSize = bytesRead + offset; int dataSize = bytesRead + offset;
if (bytesRead == 0 && dataSize == 0) if ((bytesRead == 0) && (dataSize == 0))
break; break;
for (start = 0; start < dataSize; ++start) { for (start = 0; start < dataSize; ++start) {
endOfLine = -1; endOfLine = -1;
// The file might have ended without the last line having a newline // The file might have ended without the last line having a newline
if (!(bytesRead == 0 && dataSize > 0)) { if (!((bytesRead == 0) && (dataSize > 0))) {
for (int i = start; i < dataSize; ++i) { for (int i = start; i < dataSize; ++i) {
if (buffer[i] == '\n') { if (buffer[i] == '\n') {
endOfLine = i; endOfLine = i;
@@ -295,13 +295,13 @@ int FilterParserThread::parseP2PFilterFile()
if (bytesRead < 0) if (bytesRead < 0)
break; break;
int dataSize = bytesRead + offset; int dataSize = bytesRead + offset;
if (bytesRead == 0 && dataSize == 0) if ((bytesRead == 0) && (dataSize == 0))
break; break;
for (start = 0; start < dataSize; ++start) { for (start = 0; start < dataSize; ++start) {
endOfLine = -1; endOfLine = -1;
// The file might have ended without the last line having a newline // The file might have ended without the last line having a newline
if (!(bytesRead == 0 && dataSize > 0)) { if (!((bytesRead == 0) && (dataSize > 0))) {
for (int i = start; i < dataSize; ++i) { for (int i = start; i < dataSize; ++i) {
if (buffer[i] == '\n') { if (buffer[i] == '\n') {
endOfLine = i; endOfLine = i;

View File

@@ -22,7 +22,7 @@ Statistics::Statistics(Session *session)
, m_dirty(false) , m_dirty(false)
{ {
load(); load();
connect(&m_timer, SIGNAL(timeout()), this, SLOT(gather())); connect(&m_timer, &QTimer::timeout, this, &Statistics::gather);
m_timer.start(60 * 1000); m_timer.start(60 * 1000);
} }

View File

@@ -9,7 +9,7 @@ namespace BitTorrent
class Session; class Session;
} }
class Statistics : QObject class Statistics : public QObject
{ {
Q_OBJECT Q_OBJECT
Q_DISABLE_COPY(Statistics) Q_DISABLE_COPY(Statistics)

View File

@@ -49,9 +49,6 @@
#include <QUuid> #include <QUuid>
#include <libtorrent/alert_types.hpp> #include <libtorrent/alert_types.hpp>
#if LIBTORRENT_VERSION_NUM >= 10100
#include <libtorrent/bdecode.hpp>
#endif
#include <libtorrent/bencode.hpp> #include <libtorrent/bencode.hpp>
#include <libtorrent/disk_io_thread.hpp> #include <libtorrent/disk_io_thread.hpp>
#include <libtorrent/error_code.hpp> #include <libtorrent/error_code.hpp>
@@ -60,17 +57,18 @@
#include <libtorrent/extensions/smart_ban.hpp> #include <libtorrent/extensions/smart_ban.hpp>
#include <libtorrent/identify_client.hpp> #include <libtorrent/identify_client.hpp>
#include <libtorrent/ip_filter.hpp> #include <libtorrent/ip_filter.hpp>
#if LIBTORRENT_VERSION_NUM < 10100
#include <libtorrent/lazy_entry.hpp>
#endif
#include <libtorrent/magnet_uri.hpp> #include <libtorrent/magnet_uri.hpp>
#include <libtorrent/session.hpp> #include <libtorrent/session.hpp>
#if LIBTORRENT_VERSION_NUM >= 10100
#include <libtorrent/session_stats.hpp>
#endif
#include <libtorrent/session_status.hpp> #include <libtorrent/session_status.hpp>
#include <libtorrent/torrent_info.hpp> #include <libtorrent/torrent_info.hpp>
#if LIBTORRENT_VERSION_NUM < 10100
#include <libtorrent/lazy_entry.hpp>
#else
#include <libtorrent/bdecode.hpp>
#include <libtorrent/session_stats.hpp>
#endif
#include "base/algorithm.h" #include "base/algorithm.h"
#include "base/logger.h" #include "base/logger.h"
#include "base/net/downloadhandler.h" #include "base/net/downloadhandler.h"
@@ -96,6 +94,7 @@
#include "trackerentry.h" #include "trackerentry.h"
#ifdef Q_OS_WIN #ifdef Q_OS_WIN
#include <wincrypt.h>
#include <iphlpapi.h> #include <iphlpapi.h>
#endif #endif
@@ -371,11 +370,16 @@ Session::Session(QObject *parent)
, m_numResumeData(0) , m_numResumeData(0)
, m_extraLimit(0) , m_extraLimit(0)
, m_useProxy(false) , m_useProxy(false)
, m_recentErroredTorrentsTimer(new QTimer(this))
{ {
Logger *const logger = Logger::instance(); Logger *const logger = Logger::instance();
initResumeFolder(); initResumeFolder();
m_recentErroredTorrentsTimer->setSingleShot(true);
m_recentErroredTorrentsTimer->setInterval(1000);
connect(m_recentErroredTorrentsTimer, &QTimer::timeout, this, [this]() { m_recentErroredTorrents.clear(); });
m_seedingLimitTimer = new QTimer(this); m_seedingLimitTimer = new QTimer(this);
m_seedingLimitTimer->setInterval(10000); m_seedingLimitTimer->setInterval(10000);
connect(m_seedingLimitTimer, &QTimer::timeout, this, &Session::processShareLimits); connect(m_seedingLimitTimer, &QTimer::timeout, this, &Session::processShareLimits);
@@ -519,13 +523,14 @@ Session::Session(QObject *parent)
enableTracker(isTrackerEnabled()); enableTracker(isTrackerEnabled());
connect(Net::ProxyConfigurationManager::instance(), SIGNAL(proxyConfigurationChanged()), SLOT(configureDeferred())); connect(Net::ProxyConfigurationManager::instance(), &Net::ProxyConfigurationManager::proxyConfigurationChanged
, this, &Session::configureDeferred);
// Network configuration monitor // Network configuration monitor
connect(&m_networkManager, SIGNAL(onlineStateChanged(bool)), SLOT(networkOnlineStateChanged(bool))); connect(&m_networkManager, &QNetworkConfigurationManager::onlineStateChanged, this, &Session::networkOnlineStateChanged);
connect(&m_networkManager, SIGNAL(configurationAdded(const QNetworkConfiguration&)), SLOT(networkConfigurationChange(const QNetworkConfiguration&))); connect(&m_networkManager, &QNetworkConfigurationManager::configurationAdded, this, &Session::networkConfigurationChange);
connect(&m_networkManager, SIGNAL(configurationRemoved(const QNetworkConfiguration&)), SLOT(networkConfigurationChange(const QNetworkConfiguration&))); connect(&m_networkManager, &QNetworkConfigurationManager::configurationRemoved, this, &Session::networkConfigurationChange);
connect(&m_networkManager, SIGNAL(configurationChanged(const QNetworkConfiguration&)), SLOT(networkConfigurationChange(const QNetworkConfiguration&))); connect(&m_networkManager, &QNetworkConfigurationManager::configurationChanged, this, &Session::networkConfigurationChange);
m_ioThread = new QThread(this); m_ioThread = new QThread(this);
m_resumeDataSavingManager = new ResumeDataSavingManager(m_resumeFolderPath); m_resumeDataSavingManager = new ResumeDataSavingManager(m_resumeFolderPath);
@@ -941,7 +946,7 @@ qreal Session::globalMaxRatio() const
return m_globalMaxRatio; return m_globalMaxRatio;
} }
// Torrents will a ratio superior to the given value will // Torrents with a ratio superior to the given value will
// be automatically deleted // be automatically deleted
void Session::setGlobalMaxRatio(qreal ratio) void Session::setGlobalMaxRatio(qreal ratio)
{ {
@@ -1005,7 +1010,7 @@ void Session::freeInstance()
{ {
if (m_instance) { if (m_instance) {
delete m_instance; delete m_instance;
m_instance = 0; m_instance = nullptr;
} }
} }
@@ -1303,7 +1308,7 @@ void Session::configure(libtorrent::settings_pack &settingsPack)
settingsPack.set_bool(libt::settings_pack::announce_to_all_trackers, announceToAllTrackers()); settingsPack.set_bool(libt::settings_pack::announce_to_all_trackers, announceToAllTrackers());
settingsPack.set_bool(libt::settings_pack::announce_to_all_tiers, announceToAllTiers()); settingsPack.set_bool(libt::settings_pack::announce_to_all_tiers, announceToAllTiers());
const int cacheSize = (diskCacheSize() > -1) ? diskCacheSize() * 64 : -1; const int cacheSize = (diskCacheSize() > -1) ? (diskCacheSize() * 64) : -1;
settingsPack.set_int(libt::settings_pack::cache_size, cacheSize); settingsPack.set_int(libt::settings_pack::cache_size, cacheSize);
settingsPack.set_int(libt::settings_pack::cache_expiry, diskCacheTTL()); settingsPack.set_int(libt::settings_pack::cache_expiry, diskCacheTTL());
qDebug() << "Using a disk cache size of" << cacheSize << "MiB"; qDebug() << "Using a disk cache size of" << cacheSize << "MiB";
@@ -1515,8 +1520,8 @@ void Session::adjustLimits(libt::session_settings &sessionSettings)
int maxDownloads = maxActiveDownloads(); int maxDownloads = maxActiveDownloads();
int maxActive = maxActiveTorrents(); int maxActive = maxActiveTorrents();
sessionSettings.active_downloads = maxDownloads > -1 ? maxDownloads + m_extraLimit : maxDownloads; sessionSettings.active_downloads = (maxDownloads > -1) ? (maxDownloads + m_extraLimit) : maxDownloads;
sessionSettings.active_limit = maxActive > -1 ? maxActive + m_extraLimit : maxActive; sessionSettings.active_limit = (maxActive > -1) ? (maxActive + m_extraLimit) : maxActive;
} }
void Session::applyBandwidthLimits(libt::session_settings &sessionSettings) void Session::applyBandwidthLimits(libt::session_settings &sessionSettings)
@@ -1590,7 +1595,7 @@ void Session::configure(libtorrent::session_settings &sessionSettings)
sessionSettings.announce_to_all_trackers = announceToAllTrackers(); sessionSettings.announce_to_all_trackers = announceToAllTrackers();
sessionSettings.announce_to_all_tiers = announceToAllTiers(); sessionSettings.announce_to_all_tiers = announceToAllTiers();
const int cacheSize = (diskCacheSize() > -1) ? diskCacheSize() * 64 : -1; const int cacheSize = (diskCacheSize() > -1) ? (diskCacheSize() * 64) : -1;
sessionSettings.cache_size = cacheSize; sessionSettings.cache_size = cacheSize;
sessionSettings.cache_expiry = diskCacheTTL(); sessionSettings.cache_expiry = diskCacheTTL();
qDebug() << "Using a disk cache size of" << cacheSize << "MiB"; qDebug() << "Using a disk cache size of" << cacheSize << "MiB";
@@ -1763,7 +1768,7 @@ void Session::enableBandwidthScheduler()
void Session::populateAdditionalTrackers() void Session::populateAdditionalTrackers()
{ {
m_additionalTrackerList.clear(); m_additionalTrackerList.clear();
foreach (QString tracker, additionalTrackers().split("\n")) { foreach (QString tracker, additionalTrackers().split('\n')) {
tracker = tracker.trimmed(); tracker = tracker.trimmed();
if (!tracker.isEmpty()) if (!tracker.isEmpty())
m_additionalTrackerList << tracker; m_additionalTrackerList << tracker;
@@ -2075,9 +2080,10 @@ bool Session::addTorrent(QString source, const AddTorrentParams &params)
Logger::instance()->addMessage(tr("Downloading '%1', please wait...", "e.g: Downloading 'xxx.torrent', please wait...").arg(source)); Logger::instance()->addMessage(tr("Downloading '%1', please wait...", "e.g: Downloading 'xxx.torrent', please wait...").arg(source));
// Launch downloader // Launch downloader
Net::DownloadHandler *handler = Net::DownloadManager::instance()->downloadUrl(source, true, 10485760 /* 10MB */, true); Net::DownloadHandler *handler = Net::DownloadManager::instance()->downloadUrl(source, true, 10485760 /* 10MB */, true);
connect(handler, SIGNAL(downloadFinished(QString, QString)), this, SLOT(handleDownloadFinished(QString, QString))); connect(handler, static_cast<void (Net::DownloadHandler::*)(const QString &, const QString &)>(&Net::DownloadHandler::downloadFinished)
connect(handler, SIGNAL(downloadFailed(QString, QString)), this, SLOT(handleDownloadFailed(QString, QString))); , this, &Session::handleDownloadFinished);
connect(handler, SIGNAL(redirectedToMagnet(QString, QString)), this, SLOT(handleRedirectedToMagnet(QString, QString))); connect(handler, &Net::DownloadHandler::downloadFailed, this, &Session::handleDownloadFailed);
connect(handler, &Net::DownloadHandler::redirectedToMagnet, this, &Session::handleRedirectedToMagnet);
m_downloadedTorrents[handler->url()] = params; m_downloadedTorrents[handler->url()] = params;
} }
else { else {
@@ -2148,12 +2154,26 @@ bool Session::addTorrent_impl(AddTorrentData addData, const MagnetUri &magnetUri
p = magnetUri.addTorrentParams(); p = magnetUri.addTorrentParams();
} }
else if (torrentInfo.isValid()) { else if (torrentInfo.isValid()) {
if (!addData.resumed && !addData.hasRootFolder) if (!addData.resumed) {
if (!addData.hasRootFolder)
torrentInfo.stripRootFolder(); torrentInfo.stripRootFolder();
// Metadata // Metadata
if (!addData.resumed && !addData.hasSeedStatus) if (!addData.hasSeedStatus)
findIncompleteFiles(torrentInfo, savePath); findIncompleteFiles(torrentInfo, savePath);
// if torrent name wasn't explicitly set we handle the case of
// initial renaming of torrent content and rename torrent accordingly
if (addData.name.isEmpty()) {
QString contentName = torrentInfo.rootFolder();
if (contentName.isEmpty() && (torrentInfo.filesCount() == 1))
contentName = torrentInfo.fileName(0);
if (!contentName.isEmpty() && (contentName != torrentInfo.name()))
addData.name = contentName;
}
}
p.ti = torrentInfo.nativeInfo(); p.ti = torrentInfo.nativeInfo();
hash = torrentInfo.hash(); hash = torrentInfo.hash();
} }
@@ -2259,7 +2279,7 @@ bool Session::loadMetadata(const MagnetUri &magnetUri)
InfoHash hash = magnetUri.hash(); InfoHash hash = magnetUri.hash();
QString name = magnetUri.name(); QString name = magnetUri.name();
// We should not add torrent if it already // We should not add torrent if it's already
// processed or adding to session // processed or adding to session
if (m_torrents.contains(hash)) return false; if (m_torrents.contains(hash)) return false;
if (m_addingTorrents.contains(hash)) return false; if (m_addingTorrents.contains(hash)) return false;
@@ -2473,12 +2493,12 @@ const QStringList Session::getListeningIPs()
ip = entry.ip(); ip = entry.ip();
ipString = ip.toString(); ipString = ip.toString();
protocol = ip.protocol(); protocol = ip.protocol();
Q_ASSERT(protocol == QAbstractSocket::IPv4Protocol || protocol == QAbstractSocket::IPv6Protocol); Q_ASSERT((protocol == QAbstractSocket::IPv4Protocol) || (protocol == QAbstractSocket::IPv6Protocol));
if ((!listenIPv6 && (protocol == QAbstractSocket::IPv6Protocol)) if ((!listenIPv6 && (protocol == QAbstractSocket::IPv6Protocol))
|| (listenIPv6 && (protocol == QAbstractSocket::IPv4Protocol))) || (listenIPv6 && (protocol == QAbstractSocket::IPv4Protocol)))
continue; continue;
//If an iface address has been defined only allow ip's that match it to go through // If an iface address has been defined to only allow ip's that match it to go through
if (!ifaceAddr.isEmpty()) { if (!ifaceAddr.isEmpty()) {
if (ifaceAddr == ipString) { if (ifaceAddr == ipString) {
IPs.append(ipString); IPs.append(ipString);
@@ -2945,7 +2965,7 @@ void Session::setMaxConnectionsPerTorrent(int max)
try { try {
handle.set_max_connections(max); handle.set_max_connections(max);
} }
catch (std::exception) {} catch (const std::exception &) {}
} }
} }
} }
@@ -2967,7 +2987,7 @@ void Session::setMaxUploadsPerTorrent(int max)
try { try {
handle.set_max_uploads(max); handle.set_max_uploads(max);
} }
catch (std::exception) {} catch (const std::exception &) {}
} }
} }
} }
@@ -3714,8 +3734,8 @@ void Session::enableIPFilter()
// set between clearing the old one and setting the new one. // set between clearing the old one and setting the new one.
if (!m_filterParser) { if (!m_filterParser) {
m_filterParser = new FilterParserThread(this); m_filterParser = new FilterParserThread(this);
connect(m_filterParser.data(), SIGNAL(IPFilterParsed(int)), SLOT(handleIPFilterParsed(int))); connect(m_filterParser.data(), &FilterParserThread::IPFilterParsed, this, &Session::handleIPFilterParsed);
connect(m_filterParser.data(), SIGNAL(IPFilterError()), SLOT(handleIPFilterError())); connect(m_filterParser.data(), &FilterParserThread::IPFilterError, this, &Session::handleIPFilterError);
} }
m_filterParser->processFilterFile(IPFilterFile()); m_filterParser->processFilterFile(IPFilterFile());
} }
@@ -3798,7 +3818,7 @@ void Session::startUpTorrents()
.arg(params.hash), Log::CRITICAL); .arg(params.hash), Log::CRITICAL);
// process add torrent messages before message queue overflow // process add torrent messages before message queue overflow
if (resumedTorrentsCount % 100 == 0) readAlerts(); if ((resumedTorrentsCount % 100) == 0) readAlerts();
++resumedTorrentsCount; ++resumedTorrentsCount;
}; };
@@ -4169,11 +4189,16 @@ void Session::handleFileErrorAlert(libt::file_error_alert *p)
// NOTE: Check this function! // NOTE: Check this function!
TorrentHandle *const torrent = m_torrents.value(p->handle.info_hash()); TorrentHandle *const torrent = m_torrents.value(p->handle.info_hash());
if (torrent) { if (torrent) {
QString msg = QString::fromStdString(p->message()); const InfoHash hash = torrent->hash();
Logger::instance()->addMessage(tr("An I/O error occurred, '%1' paused. %2") if (!m_recentErroredTorrents.contains(hash)) {
.arg(torrent->name(), msg)); m_recentErroredTorrents.insert(hash);
const QString msg = QString::fromStdString(p->message());
LogMsg(tr("An I/O error occurred, '%1' paused. %2").arg(torrent->name(), msg));
emit fullDiskError(torrent, msg); emit fullDiskError(torrent, msg);
} }
m_recentErroredTorrentsTimer->start();
}
} }
void Session::handlePortmapWarningAlert(libt::portmap_error_alert *p) void Session::handlePortmapWarningAlert(libt::portmap_error_alert *p)

View File

@@ -30,18 +30,14 @@
#ifndef BITTORRENT_SESSION_H #ifndef BITTORRENT_SESSION_H
#define BITTORRENT_SESSION_H #define BITTORRENT_SESSION_H
#include <vector>
#include <libtorrent/version.hpp> #include <libtorrent/version.hpp>
#if LIBTORRENT_VERSION_NUM >= 10100 #include <vector>
#include <QElapsedTimer>
#endif
#include <QFile> #include <QFile>
#include <QHash> #include <QHash>
#include <QList>
#include <QMap> #include <QMap>
#if LIBTORRENT_VERSION_NUM < 10100
#include <QMutex>
#endif
#include <QNetworkConfigurationManager> #include <QNetworkConfigurationManager>
#include <QPointer> #include <QPointer>
#include <QSet> #include <QSet>
@@ -49,6 +45,12 @@
#include <QVector> #include <QVector>
#include <QWaitCondition> #include <QWaitCondition>
#if LIBTORRENT_VERSION_NUM < 10100
#include <QMutex>
#else
#include <QElapsedTimer>
#endif
#include "base/settingvalue.h" #include "base/settingvalue.h"
#include "base/tristatebool.h" #include "base/tristatebool.h"
#include "base/types.h" #include "base/types.h"
@@ -111,7 +113,6 @@ class QTimer;
class QStringList; class QStringList;
class QString; class QString;
class QUrl; class QUrl;
template<typename T> class QList;
class FilterParserThread; class FilterParserThread;
class BandwidthScheduler; class BandwidthScheduler;
@@ -562,7 +563,7 @@ namespace BitTorrent
bool requestedFileDeletion; bool requestedFileDeletion;
}; };
explicit Session(QObject *parent = 0); explicit Session(QObject *parent = nullptr);
~Session(); ~Session();
bool hasPerTorrentRatioLimit() const; bool hasPerTorrentRatioLimit() const;
@@ -760,6 +761,10 @@ namespace BitTorrent
QStringMap m_categories; QStringMap m_categories;
QSet<QString> m_tags; QSet<QString> m_tags;
// I/O errored torrents
QSet<InfoHash> m_recentErroredTorrents;
QTimer *m_recentErroredTorrentsTimer;
#if LIBTORRENT_VERSION_NUM < 10100 #if LIBTORRENT_VERSION_NUM < 10100
QMutex m_alertsMutex; QMutex m_alertsMutex;
QWaitCondition m_alertsWaitCondition; QWaitCondition m_alertsWaitCondition;

View File

@@ -1,6 +1,6 @@
/* /*
* Bittorrent Client using Qt and libtorrent. * Bittorrent Client using Qt and libtorrent.
* Copyright (C) 2010 Christophe Dumez * Copyright (C) 2010 Christophe Dumez <chris@qbittorrent.org>
* *
* This program is free software; you can redistribute it and/or * This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License * modify it under the terms of the GNU General Public License
@@ -24,8 +24,6 @@
* modify file(s), you may extend this exception to your version of the file(s), * modify file(s), you may extend this exception to your version of the file(s),
* but you are not obligated to do so. If you do not wish to do so, delete this * but you are not obligated to do so. If you do not wish to do so, delete this
* exception statement from your version. * exception statement from your version.
*
* Contact : chris@qbittorrent.org
*/ */
#include "torrentcreatorthread.h" #include "torrentcreatorthread.h"

View File

@@ -1,6 +1,6 @@
/* /*
* Bittorrent Client using Qt and libtorrent. * Bittorrent Client using Qt and libtorrent.
* Copyright (C) 2010 Christophe Dumez * Copyright (C) 2010 Christophe Dumez <chris@qbittorrent.org>
* *
* This program is free software; you can redistribute it and/or * This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License * modify it under the terms of the GNU General Public License
@@ -24,8 +24,6 @@
* modify file(s), you may extend this exception to your version of the file(s), * modify file(s), you may extend this exception to your version of the file(s),
* but you are not obligated to do so. If you do not wish to do so, delete this * but you are not obligated to do so. If you do not wish to do so, delete this
* exception statement from your version. * exception statement from your version.
*
* Contact : chris@qbittorrent.org
*/ */
#ifndef BITTORRENT_TORRENTCREATORTHREAD_H #ifndef BITTORRENT_TORRENTCREATORTHREAD_H

View File

@@ -65,7 +65,7 @@
#include "session.h" #include "session.h"
#include "trackerentry.h" #include "trackerentry.h"
const QString QB_EXT {".!qB"}; const QString QB_EXT {QStringLiteral(".!qB")};
namespace libt = libtorrent; namespace libt = libtorrent;
using namespace BitTorrent; using namespace BitTorrent;
@@ -156,8 +156,6 @@ const int TorrentHandle::MAX_SEEDING_TIME = 525600;
// The following can be removed after one or two libtorrent releases on each branch. // The following can be removed after one or two libtorrent releases on each branch.
namespace namespace
{ {
const char i18nContext[] = "TorrentHandle";
// new constructor is available // new constructor is available
template<typename T, typename std::enable_if<std::is_constructible<T, libt::torrent_info, bool>::value, int>::type = 0> template<typename T, typename std::enable_if<std::is_constructible<T, libt::torrent_info, bool>::value, int>::type = 0>
T makeTorrentCreator(const libtorrent::torrent_info & ti) T makeTorrentCreator(const libtorrent::torrent_info & ti)
@@ -521,17 +519,21 @@ int TorrentHandle::piecesHave() const
qreal TorrentHandle::progress() const qreal TorrentHandle::progress() const
{ {
if (!isChecking()) {
if (!m_nativeStatus.total_wanted) if (!m_nativeStatus.total_wanted)
return 0.; return 0.;
if (m_nativeStatus.total_wanted_done == m_nativeStatus.total_wanted) if (m_nativeStatus.total_wanted_done == m_nativeStatus.total_wanted)
return 1.; return 1.;
float progress = static_cast<float>(m_nativeStatus.total_wanted_done) / m_nativeStatus.total_wanted; qreal progress = static_cast<qreal>(m_nativeStatus.total_wanted_done) / m_nativeStatus.total_wanted;
Q_ASSERT((progress >= 0.f) && (progress <= 1.f)); Q_ASSERT((progress >= 0.f) && (progress <= 1.f));
return progress; return progress;
} }
return m_nativeStatus.progress;
}
QString TorrentHandle::category() const QString TorrentHandle::category() const
{ {
return m_category; return m_category;
@@ -736,7 +738,8 @@ bool TorrentHandle::isActive() const
|| m_state == TorrentState::Downloading || m_state == TorrentState::Downloading
|| m_state == TorrentState::ForcedDownloading || m_state == TorrentState::ForcedDownloading
|| m_state == TorrentState::Uploading || m_state == TorrentState::Uploading
|| m_state == TorrentState::ForcedUploading; || m_state == TorrentState::ForcedUploading
|| m_state == TorrentState::Moving;
} }
bool TorrentHandle::isInactive() const bool TorrentHandle::isInactive() const
@@ -778,28 +781,18 @@ bool TorrentHandle::hasFirstLastPiecePriority() const
if (!hasMetadata()) if (!hasMetadata())
return m_needsToSetFirstLastPiecePriority; return m_needsToSetFirstLastPiecePriority;
// Get int first media file const std::vector<int> filePriorities = nativeHandle().file_priorities();
std::vector<int> fp; for (int i = 0; i < static_cast<int>(filePriorities.size()); ++i) {
fp = m_nativeHandle.file_priorities(); if (filePriorities[i] <= 0)
continue;
TorrentInfo::PieceRange extremities; const TorrentInfo::PieceRange extremities = info().filePieces(i);
bool found = false; const int firstPiecePrio = nativeHandle().piece_priority(extremities.first());
int count = static_cast<int>(fp.size()); const int lastPiecePrio = nativeHandle().piece_priority(extremities.last());
for (int i = 0; i < count; ++i) { return ((firstPiecePrio == 7) && (lastPiecePrio == 7));
const QString ext = Utils::Fs::fileExtension(filePath(i));
if (Utils::Misc::isPreviewable(ext) && (fp[i] > 0)) {
extremities = info().filePieces(i);
found = true;
break;
}
} }
if (!found) return false; // No media file return false;
int first = m_nativeHandle.piece_priority(extremities.first());
int last = m_nativeHandle.piece_priority(extremities.last());
return ((first == 7) && (last == 7));
} }
TorrentState TorrentHandle::state() const TorrentState TorrentHandle::state() const
@@ -809,7 +802,10 @@ TorrentState TorrentHandle::state() const
void TorrentHandle::updateState() void TorrentHandle::updateState()
{ {
if (isPaused()) { if (isMoveInProgress()) {
m_state = TorrentState::Moving;
}
else if (isPaused()) {
if (hasMissingFiles()) if (hasMissingFiles())
m_state = TorrentState::MissingFiles; m_state = TorrentState::MissingFiles;
else if (hasError()) else if (hasError())
@@ -1296,39 +1292,37 @@ void TorrentHandle::toggleSequentialDownload()
setSequentialDownload(!isSequentialDownload()); setSequentialDownload(!isSequentialDownload());
} }
void TorrentHandle::setFirstLastPiecePriority(bool b) void TorrentHandle::setFirstLastPiecePriority(const bool enabled)
{ {
if (!hasMetadata()) { if (!hasMetadata()) {
m_needsToSetFirstLastPiecePriority = b; m_needsToSetFirstLastPiecePriority = enabled;
return; return;
} }
std::vector<int> fp = m_nativeHandle.file_priorities(); // Download first and last pieces first for every file in the torrent
std::vector<int> pp = m_nativeHandle.piece_priorities(); const std::vector<int> filePriorities = nativeHandle().file_priorities();
std::vector<int> piecePriorities = nativeHandle().piece_priorities();
// Download first and last pieces first for all media files in the torrent for (int index = 0; index < static_cast<int>(filePriorities.size()); ++index) {
int nbfiles = static_cast<int>(fp.size()); const int filePrio = filePriorities[index];
for (int index = 0; index < nbfiles; ++index) { if (filePrio <= 0)
const QString path = filePath(index); continue;
const QString ext = Utils::Fs::fileExtension(path);
if (Utils::Misc::isPreviewable(ext) && (fp[index] > 0)) {
qDebug() << "File" << path << "is previewable, toggle downloading of first/last pieces first";
// Determine the priority to set // Determine the priority to set
int prio = b ? 7 : fp[index]; const int newPrio = enabled ? 7 : filePrio;
const TorrentInfo::PieceRange extremities = info().filePieces(index);
TorrentInfo::PieceRange extremities = info().filePieces(index);
// worst case: AVI index = 1% of total file size (at the end of the file) // worst case: AVI index = 1% of total file size (at the end of the file)
int nNumPieces = ceil(fileSize(index) * 0.01 / pieceLength()); const int nNumPieces = std::ceil(fileSize(index) * 0.01 / pieceLength());
for (int i = 0; i < nNumPieces; ++i) { for (int i = 0; i < nNumPieces; ++i) {
pp[extremities.first() + i] = prio; piecePriorities[extremities.first() + i] = newPrio;
pp[extremities.last() - i] = prio; piecePriorities[extremities.last() - i] = newPrio;
}
} }
} }
m_nativeHandle.prioritize_pieces(pp); m_nativeHandle.prioritize_pieces(piecePriorities);
LogMsg(tr("Download first and last piece first: %1, torrent: '%2'")
.arg((enabled ? tr("On") : tr("Off")), name()));
} }
void TorrentHandle::toggleFirstLastPiecePriority() void TorrentHandle::toggleFirstLastPiecePriority()
@@ -1376,6 +1370,7 @@ void TorrentHandle::moveStorage(const QString &newPath, bool overwrite)
, (overwrite ? libt::always_replace_files : libt::dont_replace)); , (overwrite ? libt::always_replace_files : libt::dont_replace));
m_moveStorageInfo.oldPath = oldPath; m_moveStorageInfo.oldPath = oldPath;
m_moveStorageInfo.newPath = newPath; m_moveStorageInfo.newPath = newPath;
updateState();
} }
} }
@@ -1425,7 +1420,7 @@ void TorrentHandle::handleStateUpdate(const libt::torrent_status &nativeStatus)
updateStatus(nativeStatus); updateStatus(nativeStatus);
} }
void TorrentHandle::handleStorageMovedAlert(libtorrent::storage_moved_alert *p) void TorrentHandle::handleStorageMovedAlert(const libtorrent::storage_moved_alert *p)
{ {
if (!isMoveInProgress()) { if (!isMoveInProgress()) {
qWarning() << "Unexpected " << Q_FUNC_INFO << " call."; qWarning() << "Unexpected " << Q_FUNC_INFO << " call.";
@@ -1442,8 +1437,8 @@ void TorrentHandle::handleStorageMovedAlert(libtorrent::storage_moved_alert *p)
return; return;
} }
qDebug("Torrent is successfully moved from %s to %s" LogMsg(tr("Successfully moved torrent: %1. New path: %2").arg(name(), m_moveStorageInfo.newPath));
, qUtf8Printable(m_moveStorageInfo.oldPath), qUtf8Printable(m_moveStorageInfo.newPath));
const QDir oldDir {m_moveStorageInfo.oldPath}; const QDir oldDir {m_moveStorageInfo.oldPath};
if ((oldDir == QDir(m_session->torrentTempPath(info()))) if ((oldDir == QDir(m_session->torrentTempPath(info())))
&& (oldDir != QDir(m_session->tempPath()))) { && (oldDir != QDir(m_session->tempPath()))) {
@@ -1452,9 +1447,10 @@ void TorrentHandle::handleStorageMovedAlert(libtorrent::storage_moved_alert *p)
qDebug() << "Removing torrent temp folder:" << m_moveStorageInfo.oldPath; qDebug() << "Removing torrent temp folder:" << m_moveStorageInfo.oldPath;
Utils::Fs::smartRemoveEmptyFolderTree(m_moveStorageInfo.oldPath); Utils::Fs::smartRemoveEmptyFolderTree(m_moveStorageInfo.oldPath);
} }
updateStatus();
m_moveStorageInfo.newPath.clear(); m_moveStorageInfo.newPath.clear();
updateStatus();
if (!m_moveStorageInfo.queuedPath.isEmpty()) { if (!m_moveStorageInfo.queuedPath.isEmpty()) {
moveStorage(m_moveStorageInfo.queuedPath, m_moveStorageInfo.queuedOverwrite); moveStorage(m_moveStorageInfo.queuedPath, m_moveStorageInfo.queuedOverwrite);
m_moveStorageInfo.queuedPath.clear(); m_moveStorageInfo.queuedPath.clear();
@@ -1469,17 +1465,19 @@ void TorrentHandle::handleStorageMovedAlert(libtorrent::storage_moved_alert *p)
m_moveFinishedTriggers.takeFirst()(); m_moveFinishedTriggers.takeFirst()();
} }
void TorrentHandle::handleStorageMovedFailedAlert(libtorrent::storage_moved_failed_alert *p) void TorrentHandle::handleStorageMovedFailedAlert(const libtorrent::storage_moved_failed_alert *p)
{ {
if (!isMoveInProgress()) { if (!isMoveInProgress()) {
qWarning() << "Unexpected " << Q_FUNC_INFO << " call."; qWarning() << "Unexpected " << Q_FUNC_INFO << " call.";
return; return;
} }
LogMsg(QCoreApplication::translate(i18nContext, "Could not move torrent: '%1'. Reason: %2") LogMsg(tr("Could not move torrent: '%1'. Reason: %2")
.arg(name(), QString::fromStdString(p->message())), Log::CRITICAL); .arg(name(), QString::fromStdString(p->message())), Log::CRITICAL);
m_moveStorageInfo.newPath.clear(); m_moveStorageInfo.newPath.clear();
updateStatus();
if (!m_moveStorageInfo.queuedPath.isEmpty()) { if (!m_moveStorageInfo.queuedPath.isEmpty()) {
moveStorage(m_moveStorageInfo.queuedPath, m_moveStorageInfo.queuedOverwrite); moveStorage(m_moveStorageInfo.queuedPath, m_moveStorageInfo.queuedOverwrite);
m_moveStorageInfo.queuedPath.clear(); m_moveStorageInfo.queuedPath.clear();
@@ -1489,7 +1487,7 @@ void TorrentHandle::handleStorageMovedFailedAlert(libtorrent::storage_moved_fail
m_moveFinishedTriggers.takeFirst()(); m_moveFinishedTriggers.takeFirst()();
} }
void TorrentHandle::handleTrackerReplyAlert(libtorrent::tracker_reply_alert *p) void TorrentHandle::handleTrackerReplyAlert(const libtorrent::tracker_reply_alert *p)
{ {
#if LIBTORRENT_VERSION_NUM < 10100 #if LIBTORRENT_VERSION_NUM < 10100
QString trackerUrl = QString::fromStdString(p->url); QString trackerUrl = QString::fromStdString(p->url);
@@ -1504,32 +1502,32 @@ void TorrentHandle::handleTrackerReplyAlert(libtorrent::tracker_reply_alert *p)
m_session->handleTorrentTrackerReply(this, trackerUrl); m_session->handleTorrentTrackerReply(this, trackerUrl);
} }
void TorrentHandle::handleTrackerWarningAlert(libtorrent::tracker_warning_alert *p) void TorrentHandle::handleTrackerWarningAlert(const libtorrent::tracker_warning_alert *p)
{ {
#if LIBTORRENT_VERSION_NUM < 10100 #if LIBTORRENT_VERSION_NUM < 10100
QString trackerUrl = QString::fromStdString(p->url); const QString trackerUrl = QString::fromStdString(p->url);
QString message = QString::fromStdString(p->msg); const QString message = QString::fromStdString(p->msg);
#else #else
QString trackerUrl(p->tracker_url()); const QString trackerUrl = p->tracker_url();
QString message = QString::fromStdString(p->message()); const QString message = p->warning_message();
#endif #endif
qDebug("Received a tracker warning for %s: %s", qUtf8Printable(trackerUrl), qUtf8Printable(message));
// Connection was successful now but there is a warning message // Connection was successful now but there is a warning message
m_trackerInfos[trackerUrl].lastMessage = message; // Store warning message m_trackerInfos[trackerUrl].lastMessage = message; // Store warning message
m_session->handleTorrentTrackerWarning(this, trackerUrl); m_session->handleTorrentTrackerWarning(this, trackerUrl);
} }
void TorrentHandle::handleTrackerErrorAlert(libtorrent::tracker_error_alert *p) void TorrentHandle::handleTrackerErrorAlert(const libtorrent::tracker_error_alert *p)
{ {
#if LIBTORRENT_VERSION_NUM < 10100 #if LIBTORRENT_VERSION_NUM < 10100
QString trackerUrl = QString::fromStdString(p->url); const QString trackerUrl = QString::fromStdString(p->url);
QString message = QString::fromStdString(p->msg); const QString message = QString::fromStdString(p->msg);
#else #else
QString trackerUrl(p->tracker_url()); const QString trackerUrl = p->tracker_url();
QString message = QString::fromStdString(p->message()); const QString message = p->error_message();
#endif #endif
qDebug("Received a tracker error for %s: %s", qUtf8Printable(trackerUrl), qUtf8Printable(message));
m_trackerInfos[trackerUrl].lastMessage = message; m_trackerInfos[trackerUrl].lastMessage = message;
if (p->status_code == 401) if (p->status_code == 401)
@@ -1538,7 +1536,7 @@ void TorrentHandle::handleTrackerErrorAlert(libtorrent::tracker_error_alert *p)
m_session->handleTorrentTrackerError(this, trackerUrl); m_session->handleTorrentTrackerError(this, trackerUrl);
} }
void TorrentHandle::handleTorrentCheckedAlert(libtorrent::torrent_checked_alert *p) void TorrentHandle::handleTorrentCheckedAlert(const libtorrent::torrent_checked_alert *p)
{ {
Q_UNUSED(p); Q_UNUSED(p);
qDebug("%s have just finished checking", qUtf8Printable(hash())); qDebug("%s have just finished checking", qUtf8Printable(hash()));
@@ -1561,7 +1559,7 @@ void TorrentHandle::handleTorrentCheckedAlert(libtorrent::torrent_checked_alert
m_session->handleTorrentChecked(this); m_session->handleTorrentChecked(this);
} }
void TorrentHandle::handleTorrentFinishedAlert(libtorrent::torrent_finished_alert *p) void TorrentHandle::handleTorrentFinishedAlert(const libtorrent::torrent_finished_alert *p)
{ {
Q_UNUSED(p); Q_UNUSED(p);
qDebug("Got a torrent finished alert for %s", qUtf8Printable(name())); qDebug("Got a torrent finished alert for %s", qUtf8Printable(name()));
@@ -1588,7 +1586,7 @@ void TorrentHandle::handleTorrentFinishedAlert(libtorrent::torrent_finished_aler
} }
} }
void TorrentHandle::handleTorrentPausedAlert(libtorrent::torrent_paused_alert *p) void TorrentHandle::handleTorrentPausedAlert(const libtorrent::torrent_paused_alert *p)
{ {
Q_UNUSED(p); Q_UNUSED(p);
updateStatus(); updateStatus();
@@ -1596,13 +1594,13 @@ void TorrentHandle::handleTorrentPausedAlert(libtorrent::torrent_paused_alert *p
m_session->handleTorrentPaused(this); m_session->handleTorrentPaused(this);
} }
void TorrentHandle::handleTorrentResumedAlert(libtorrent::torrent_resumed_alert *p) void TorrentHandle::handleTorrentResumedAlert(const libtorrent::torrent_resumed_alert *p)
{ {
Q_UNUSED(p); Q_UNUSED(p);
m_session->handleTorrentResumed(this); m_session->handleTorrentResumed(this);
} }
void TorrentHandle::handleSaveResumeDataAlert(libtorrent::save_resume_data_alert *p) void TorrentHandle::handleSaveResumeDataAlert(const libtorrent::save_resume_data_alert *p)
{ {
const bool useDummyResumeData = !(p && p->resume_data); const bool useDummyResumeData = !(p && p->resume_data);
libtorrent::entry dummyEntry; libtorrent::entry dummyEntry;
@@ -1636,36 +1634,35 @@ void TorrentHandle::handleSaveResumeDataAlert(libtorrent::save_resume_data_alert
m_session->handleTorrentResumeDataReady(this, resumeData); m_session->handleTorrentResumeDataReady(this, resumeData);
} }
void TorrentHandle::handleSaveResumeDataFailedAlert(libtorrent::save_resume_data_failed_alert *p) void TorrentHandle::handleSaveResumeDataFailedAlert(const libtorrent::save_resume_data_failed_alert *p)
{ {
// if torrent has no metadata we should save dummy fastresume data // if torrent has no metadata we should save dummy fastresume data
// containing Magnet URI and qBittorrent own resume data only // containing Magnet URI and qBittorrent own resume data only
if (p->error.value() == libt::errors::no_metadata) if (p->error.value() == libt::errors::no_metadata)
handleSaveResumeDataAlert(0); handleSaveResumeDataAlert(nullptr);
else else
m_session->handleTorrentResumeDataFailed(this); m_session->handleTorrentResumeDataFailed(this);
} }
void TorrentHandle::handleFastResumeRejectedAlert(libtorrent::fastresume_rejected_alert *p) void TorrentHandle::handleFastResumeRejectedAlert(const libtorrent::fastresume_rejected_alert *p)
{ {
qDebug("/!\\ Fast resume failed for %s, reason: %s", qUtf8Printable(name()), p->message().c_str()); qDebug("/!\\ Fast resume failed for %s, reason: %s", qUtf8Printable(name()), p->message().c_str());
Logger *const logger = Logger::instance();
updateStatus(); updateStatus();
if (p->error.value() == libt::errors::mismatching_file_size) { if (p->error.value() == libt::errors::mismatching_file_size) {
// Mismatching file size (files were probably moved) // Mismatching file size (files were probably moved)
logger->addMessage(QCoreApplication::translate(i18nContext, "File sizes mismatch for torrent '%1', pausing it.").arg(name()), Log::CRITICAL); LogMsg(tr("File sizes mismatch for torrent '%1', pausing it.").arg(name()), Log::CRITICAL);
m_hasMissingFiles = true; m_hasMissingFiles = true;
if (!isPaused()) if (!isPaused())
pause(); pause();
} }
else { else {
logger->addMessage(QCoreApplication::translate(i18nContext, "Fast resume data was rejected for torrent '%1'. Reason: %2. Checking again...") LogMsg(tr("Fast resume data was rejected for torrent '%1'. Reason: %2. Checking again...")
.arg(name(), QString::fromStdString(p->message())), Log::CRITICAL); .arg(name(), QString::fromStdString(p->message())), Log::CRITICAL);
} }
} }
void TorrentHandle::handleFileRenamedAlert(libtorrent::file_renamed_alert *p) void TorrentHandle::handleFileRenamedAlert(const libtorrent::file_renamed_alert *p)
{ {
#if LIBTORRENT_VERSION_NUM < 10100 #if LIBTORRENT_VERSION_NUM < 10100
QString newName = Utils::Fs::fromNativePath(QString::fromStdString(p->name)); QString newName = Utils::Fs::fromNativePath(QString::fromStdString(p->name));
@@ -1697,7 +1694,7 @@ void TorrentHandle::handleFileRenamedAlert(libtorrent::file_renamed_alert *p)
m_moveFinishedTriggers.takeFirst()(); m_moveFinishedTriggers.takeFirst()();
} }
void TorrentHandle::handleFileRenameFailedAlert(libtorrent::file_rename_failed_alert *p) void TorrentHandle::handleFileRenameFailedAlert(const libtorrent::file_rename_failed_alert *p)
{ {
Q_UNUSED(p); Q_UNUSED(p);
@@ -1706,7 +1703,7 @@ void TorrentHandle::handleFileRenameFailedAlert(libtorrent::file_rename_failed_a
m_moveFinishedTriggers.takeFirst()(); m_moveFinishedTriggers.takeFirst()();
} }
void TorrentHandle::handleFileCompletedAlert(libtorrent::file_completed_alert *p) void TorrentHandle::handleFileCompletedAlert(const libtorrent::file_completed_alert *p)
{ {
updateStatus(); updateStatus();
@@ -1722,7 +1719,7 @@ void TorrentHandle::handleFileCompletedAlert(libtorrent::file_completed_alert *p
} }
} }
void TorrentHandle::handleStatsAlert(libtorrent::stats_alert *p) void TorrentHandle::handleStatsAlert(const libtorrent::stats_alert *p)
{ {
Q_ASSERT(p->interval >= 1000); Q_ASSERT(p->interval >= 1000);
SpeedSample transferred(p->transferred[libt::stats_alert::download_payload] * 1000LL / p->interval, SpeedSample transferred(p->transferred[libt::stats_alert::download_payload] * 1000LL / p->interval,
@@ -1730,7 +1727,7 @@ void TorrentHandle::handleStatsAlert(libtorrent::stats_alert *p)
m_speedMonitor.addSample(transferred); m_speedMonitor.addSample(transferred);
} }
void TorrentHandle::handleMetadataReceivedAlert(libt::metadata_received_alert *p) void TorrentHandle::handleMetadataReceivedAlert(const libt::metadata_received_alert *p)
{ {
Q_UNUSED(p); Q_UNUSED(p);
qDebug("Metadata received for torrent %s.", qUtf8Printable(name())); qDebug("Metadata received for torrent %s.", qUtf8Printable(name()));

View File

@@ -149,6 +149,8 @@ namespace BitTorrent
PausedDownloading, PausedDownloading,
PausedUploading, PausedUploading,
Moving,
MissingFiles, MissingFiles,
Error Error
}; };
@@ -331,7 +333,7 @@ namespace BitTorrent
void setName(const QString &name); void setName(const QString &name);
void setSequentialDownload(bool b); void setSequentialDownload(bool b);
void toggleSequentialDownload(); void toggleSequentialDownload();
void setFirstLastPiecePriority(bool b); void setFirstLastPiecePriority(bool enabled);
void toggleFirstLastPiecePriority(); void toggleFirstLastPiecePriority();
void pause(); void pause();
void resume(bool forced = false); void resume(bool forced = false);
@@ -388,23 +390,23 @@ namespace BitTorrent
void updateState(); void updateState();
void updateTorrentInfo(); void updateTorrentInfo();
void handleStorageMovedAlert(libtorrent::storage_moved_alert *p); void handleStorageMovedAlert(const libtorrent::storage_moved_alert *p);
void handleStorageMovedFailedAlert(libtorrent::storage_moved_failed_alert *p); void handleStorageMovedFailedAlert(const libtorrent::storage_moved_failed_alert *p);
void handleTrackerReplyAlert(libtorrent::tracker_reply_alert *p); void handleTrackerReplyAlert(const libtorrent::tracker_reply_alert *p);
void handleTrackerWarningAlert(libtorrent::tracker_warning_alert *p); void handleTrackerWarningAlert(const libtorrent::tracker_warning_alert *p);
void handleTrackerErrorAlert(libtorrent::tracker_error_alert *p); void handleTrackerErrorAlert(const libtorrent::tracker_error_alert *p);
void handleTorrentCheckedAlert(libtorrent::torrent_checked_alert *p); void handleTorrentCheckedAlert(const libtorrent::torrent_checked_alert *p);
void handleTorrentFinishedAlert(libtorrent::torrent_finished_alert *p); void handleTorrentFinishedAlert(const libtorrent::torrent_finished_alert *p);
void handleTorrentPausedAlert(libtorrent::torrent_paused_alert *p); void handleTorrentPausedAlert(const libtorrent::torrent_paused_alert *p);
void handleTorrentResumedAlert(libtorrent::torrent_resumed_alert *p); void handleTorrentResumedAlert(const libtorrent::torrent_resumed_alert *p);
void handleSaveResumeDataAlert(libtorrent::save_resume_data_alert *p); void handleSaveResumeDataAlert(const libtorrent::save_resume_data_alert *p);
void handleSaveResumeDataFailedAlert(libtorrent::save_resume_data_failed_alert *p); void handleSaveResumeDataFailedAlert(const libtorrent::save_resume_data_failed_alert *p);
void handleFastResumeRejectedAlert(libtorrent::fastresume_rejected_alert *p); void handleFastResumeRejectedAlert(const libtorrent::fastresume_rejected_alert *p);
void handleFileRenamedAlert(libtorrent::file_renamed_alert *p); void handleFileRenamedAlert(const libtorrent::file_renamed_alert *p);
void handleFileRenameFailedAlert(libtorrent::file_rename_failed_alert *p); void handleFileRenameFailedAlert(const libtorrent::file_rename_failed_alert *p);
void handleFileCompletedAlert(libtorrent::file_completed_alert *p); void handleFileCompletedAlert(const libtorrent::file_completed_alert *p);
void handleMetadataReceivedAlert(libtorrent::metadata_received_alert *p); void handleMetadataReceivedAlert(const libtorrent::metadata_received_alert *p);
void handleStatsAlert(libtorrent::stats_alert *p); void handleStatsAlert(const libtorrent::stats_alert *p);
void resume_impl(bool forced, bool uploadMode); void resume_impl(bool forced, bool uploadMode);
bool isMoveInProgress() const; bool isMoveInProgress() const;

View File

@@ -26,20 +26,20 @@
* exception statement from your version. * exception statement from your version.
*/ */
#include <QDebug> #include "torrentinfo.h"
#include <QString>
#include <QList>
#include <QUrl>
#include <QDateTime>
#include <libtorrent/error_code.hpp> #include <libtorrent/error_code.hpp>
#include "base/utils/misc.h" #include <QDateTime>
#include <QDebug>
#include <QString>
#include <QUrl>
#include "base/utils/fs.h" #include "base/utils/fs.h"
#include "base/utils/misc.h"
#include "base/utils/string.h" #include "base/utils/string.h"
#include "infohash.h" #include "infohash.h"
#include "trackerentry.h" #include "trackerentry.h"
#include "torrentinfo.h"
namespace libt = libtorrent; namespace libt = libtorrent;
using namespace BitTorrent; using namespace BitTorrent;
@@ -353,8 +353,8 @@ void TorrentInfo::renameFile(uint index, const QString &newPath)
int BitTorrent::TorrentInfo::fileIndex(const QString& fileName) const int BitTorrent::TorrentInfo::fileIndex(const QString& fileName) const
{ {
// the check whether the object valid is not needed here // the check whether the object is valid is not needed here
// because filesCount() returns -1 in that case and the loop exits immediately // because if filesCount() returns -1 the loop exits immediately
for (int i = 0; i < filesCount(); ++i) for (int i = 0; i < filesCount(); ++i)
if (fileName == filePath(i)) if (fileName == filePath(i))
return i; return i;
@@ -362,24 +362,29 @@ int BitTorrent::TorrentInfo::fileIndex(const QString& fileName) const
return -1; return -1;
} }
bool TorrentInfo::hasRootFolder() const QString TorrentInfo::rootFolder() const
{ {
QString testRootFolder; QString rootFolder;
for (int i = 0; i < filesCount(); ++i) { for (int i = 0; i < filesCount(); ++i) {
const QString filePath = this->filePath(i); const QString filePath = this->filePath(i);
if (QDir::isAbsolutePath(filePath)) continue; if (QDir::isAbsolutePath(filePath)) continue;
const auto filePathElements = filePath.splitRef('/'); const auto filePathElements = filePath.splitRef('/');
// if at least one file has no root folder, no common root folder exists // if at least one file has no root folder, no common root folder exists
if (filePathElements.count() <= 1) return false; if (filePathElements.count() <= 1) return "";
if (testRootFolder.isEmpty()) if (rootFolder.isEmpty())
testRootFolder = filePathElements.at(0).toString(); rootFolder = filePathElements.at(0).toString();
else if (testRootFolder != filePathElements.at(0)) else if (rootFolder != filePathElements.at(0))
return false; return "";
} }
return true; return rootFolder;
}
bool TorrentInfo::hasRootFolder() const
{
return !rootFolder().isEmpty();
} }
void TorrentInfo::stripRootFolder() void TorrentInfo::stripRootFolder()

View File

@@ -29,21 +29,21 @@
#ifndef BITTORRENT_TORRENTINFO_H #ifndef BITTORRENT_TORRENTINFO_H
#define BITTORRENT_TORRENTINFO_H #define BITTORRENT_TORRENTINFO_H
#include <QCoreApplication>
#include <QtGlobal>
#include <libtorrent/torrent_info.hpp> #include <libtorrent/torrent_info.hpp>
#include <libtorrent/version.hpp> #include <libtorrent/version.hpp>
#include <QCoreApplication>
#include <QList>
#include <QtGlobal>
#include <QVector>
#include "base/indexrange.h" #include "base/indexrange.h"
class QString;
class QUrl;
class QDateTime;
class QStringList;
class QByteArray; class QByteArray;
template<typename T> class QList; class QDateTime;
template<typename T> class QVector; class QString;
class QStringList;
class QUrl;
namespace BitTorrent namespace BitTorrent
{ {
@@ -52,7 +52,7 @@ namespace BitTorrent
class TorrentInfo class TorrentInfo
{ {
Q_DECLARE_TR_FUNCTIONS("TorrentInfo") Q_DECLARE_TR_FUNCTIONS(TorrentInfo)
public: public:
#if LIBTORRENT_VERSION_NUM < 10100 #if LIBTORRENT_VERSION_NUM < 10100
@@ -104,6 +104,7 @@ namespace BitTorrent
void renameFile(uint index, const QString &newPath); void renameFile(uint index, const QString &newPath);
QString rootFolder() const;
bool hasRootFolder() const; bool hasRootFolder() const;
void stripRootFolder(); void stripRootFolder();

View File

@@ -1,5 +1,5 @@
/* /*
* Bittorrent Client using Qt4 and libtorrent. * Bittorrent Client using Qt and libtorrent.
* Copyright (C) 2015 Vladimir Golovnev <glassez@yandex.ru> * Copyright (C) 2015 Vladimir Golovnev <glassez@yandex.ru>
* Copyright (C) 2006 Christophe Dumez <chris@qbittorrent.org> * Copyright (C) 2006 Christophe Dumez <chris@qbittorrent.org>
* *
@@ -27,6 +27,8 @@
* exception statement from your version. * exception statement from your version.
*/ */
#include "tracker.h"
#include <vector> #include <vector>
#include <libtorrent/bencode.hpp> #include <libtorrent/bencode.hpp>
@@ -37,7 +39,6 @@
#include "base/preferences.h" #include "base/preferences.h"
#include "base/utils/bytearray.h" #include "base/utils/bytearray.h"
#include "base/utils/string.h" #include "base/utils/string.h"
#include "tracker.h"
// static limits // static limits
static const int MAX_TORRENTS = 100; static const int MAX_TORRENTS = 100;
@@ -277,5 +278,3 @@ void Tracker::replyWithPeerList(const TrackerAnnounceRequest &annonceReq)
// HTTP reply // HTTP reply
print(reply, Http::CONTENT_TYPE_TXT); print(reply, Http::CONTENT_TYPE_TXT);
} }

View File

@@ -28,14 +28,14 @@
#include "filesystemwatcher.h" #include "filesystemwatcher.h"
#include <QtGlobal>
#if defined(Q_OS_MAC) || defined(Q_OS_FREEBSD) #if defined(Q_OS_MAC) || defined(Q_OS_FREEBSD)
#include <cstring> #include <cstring>
#include <sys/mount.h> #include <sys/mount.h>
#include <sys/param.h> #include <sys/param.h>
#endif #endif
#include <QtGlobal>
#include "base/algorithm.h" #include "base/algorithm.h"
#include "base/bittorrent/magneturi.h" #include "base/bittorrent/magneturi.h"
#include "base/bittorrent/torrentinfo.h" #include "base/bittorrent/torrentinfo.h"

View File

@@ -2,7 +2,7 @@
* Bittorrent Client using Qt and libtorrent. * Bittorrent Client using Qt and libtorrent.
* Copyright (C) 2018 Mike Tzou (Chocobo1) * Copyright (C) 2018 Mike Tzou (Chocobo1)
* Copyright (C) 2014 Vladimir Golovnev <glassez@yandex.ru> * Copyright (C) 2014 Vladimir Golovnev <glassez@yandex.ru>
* Copyright (C) 2006 Ishan Arora and Christophe Dumez * Copyright (C) 2006 Ishan Arora and Christophe Dumez <chris@qbittorrent.org>
* *
* This program is free software; you can redistribute it and/or * This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License * modify it under the terms of the GNU General Public License
@@ -26,8 +26,6 @@
* modify file(s), you may extend this exception to your version of the file(s), * modify file(s), you may extend this exception to your version of the file(s),
* but you are not obligated to do so. If you do not wish to do so, delete this * but you are not obligated to do so. If you do not wish to do so, delete this
* exception statement from your version. * exception statement from your version.
*
* Contact : chris@qbittorrent.org
*/ */
#include "connection.h" #include "connection.h"

View File

@@ -1,7 +1,7 @@
/* /*
* Bittorrent Client using Qt and libtorrent. * Bittorrent Client using Qt and libtorrent.
* Copyright (C) 2014 Vladimir Golovnev <glassez@yandex.ru> * Copyright (C) 2014 Vladimir Golovnev <glassez@yandex.ru>
* Copyright (C) 2006 Ishan Arora and Christophe Dumez * Copyright (C) 2006 Ishan Arora and Christophe Dumez <chris@qbittorrent.org>
* *
* This program is free software; you can redistribute it and/or * This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License * modify it under the terms of the GNU General Public License
@@ -25,8 +25,6 @@
* modify file(s), you may extend this exception to your version of the file(s), * modify file(s), you may extend this exception to your version of the file(s),
* but you are not obligated to do so. If you do not wish to do so, delete this * but you are not obligated to do so. If you do not wish to do so, delete this
* exception statement from your version. * exception statement from your version.
*
* Contact : chris@qbittorrent.org
*/ */
@@ -50,7 +48,7 @@ namespace Http
Q_DISABLE_COPY(Connection) Q_DISABLE_COPY(Connection)
public: public:
Connection(QTcpSocket *socket, IRequestHandler *requestHandler, QObject *parent = 0); Connection(QTcpSocket *socket, IRequestHandler *requestHandler, QObject *parent = nullptr);
~Connection(); ~Connection();
bool hasExpired(qint64 timeout) const; bool hasExpired(qint64 timeout) const;

View File

@@ -291,7 +291,7 @@ bool RequestParser::parseFormData(const QByteArray &data)
const QLatin1String name("name"); const QLatin1String name("name");
if (headersMap.contains(filename)) { if (headersMap.contains(filename)) {
m_request.files.append({filename, headersMap[HEADER_CONTENT_TYPE], payload}); m_request.files.append({headersMap[filename], headersMap[HEADER_CONTENT_TYPE], payload});
} }
else if (headersMap.contains(name)) { else if (headersMap.contains(name)) {
m_request.posts[headersMap[name]] = payload; m_request.posts[headersMap[name]] = payload;

View File

@@ -47,7 +47,7 @@ void IconProvider::freeInstance()
{ {
if (m_instance) { if (m_instance) {
delete m_instance; delete m_instance;
m_instance = 0; m_instance = nullptr;
} }
} }
@@ -61,4 +61,4 @@ QString IconProvider::getIconPath(const QString &iconId)
return ":/icons/qbt-theme/" + iconId + ".png"; return ":/icons/qbt-theme/" + iconId + ".png";
} }
IconProvider *IconProvider::m_instance = 0; IconProvider *IconProvider::m_instance = nullptr;

View File

@@ -46,7 +46,7 @@ public:
virtual QString getIconPath(const QString &iconId); virtual QString getIconPath(const QString &iconId);
protected: protected:
explicit IconProvider(QObject *parent = 0); explicit IconProvider(QObject *parent = nullptr);
~IconProvider(); ~IconProvider();
static IconProvider *m_instance; static IconProvider *m_instance;

View File

@@ -3,12 +3,12 @@
#include <QDateTime> #include <QDateTime>
#include "base/utils/string.h" #include "base/utils/string.h"
Logger* Logger::m_instance = 0; Logger *Logger::m_instance = nullptr;
Logger::Logger() Logger::Logger()
: lock(QReadWriteLock::Recursive) : m_lock(QReadWriteLock::Recursive)
, msgCounter(0) , m_msgCounter(0)
, peerCounter(0) , m_peerCounter(0)
{ {
} }
@@ -29,15 +29,15 @@ void Logger::freeInstance()
{ {
if (m_instance) { if (m_instance) {
delete m_instance; delete m_instance;
m_instance = 0; m_instance = nullptr;
} }
} }
void Logger::addMessage(const QString &message, const Log::MsgType &type) void Logger::addMessage(const QString &message, const Log::MsgType &type)
{ {
QWriteLocker locker(&lock); QWriteLocker locker(&m_lock);
Log::Msg temp = { msgCounter++, QDateTime::currentMSecsSinceEpoch(), type, message.toHtmlEscaped() }; Log::Msg temp = {m_msgCounter++, QDateTime::currentMSecsSinceEpoch(), type, message.toHtmlEscaped()};
m_messages.push_back(temp); m_messages.push_back(temp);
if (m_messages.size() >= MAX_LOG_MESSAGES) if (m_messages.size() >= MAX_LOG_MESSAGES)
@@ -48,9 +48,9 @@ void Logger::addMessage(const QString &message, const Log::MsgType &type)
void Logger::addPeer(const QString &ip, bool blocked, const QString &reason) void Logger::addPeer(const QString &ip, bool blocked, const QString &reason)
{ {
QWriteLocker locker(&lock); QWriteLocker locker(&m_lock);
Log::Peer temp = { peerCounter++, QDateTime::currentMSecsSinceEpoch(), ip.toHtmlEscaped(), blocked, reason.toHtmlEscaped() }; Log::Peer temp = {m_peerCounter++, QDateTime::currentMSecsSinceEpoch(), ip.toHtmlEscaped(), blocked, reason.toHtmlEscaped()};
m_peers.push_back(temp); m_peers.push_back(temp);
if (m_peers.size() >= MAX_LOG_MESSAGES) if (m_peers.size() >= MAX_LOG_MESSAGES)
@@ -61,9 +61,9 @@ void Logger::addPeer(const QString &ip, bool blocked, const QString &reason)
QVector<Log::Msg> Logger::getMessages(int lastKnownId) const QVector<Log::Msg> Logger::getMessages(int lastKnownId) const
{ {
QReadLocker locker(&lock); QReadLocker locker(&m_lock);
int diff = msgCounter - lastKnownId - 1; int diff = m_msgCounter - lastKnownId - 1;
int size = m_messages.size(); int size = m_messages.size();
if ((lastKnownId == -1) || (diff >= size)) if ((lastKnownId == -1) || (diff >= size))
@@ -77,9 +77,9 @@ QVector<Log::Msg> Logger::getMessages(int lastKnownId) const
QVector<Log::Peer> Logger::getPeers(int lastKnownId) const QVector<Log::Peer> Logger::getPeers(int lastKnownId) const
{ {
QReadLocker locker(&lock); QReadLocker locker(&m_lock);
int diff = peerCounter - lastKnownId - 1; int diff = m_peerCounter - lastKnownId - 1;
int size = m_peers.size(); int size = m_peers.size();
if ((lastKnownId == -1) || (diff >= size)) if ((lastKnownId == -1) || (diff >= size))

View File

@@ -1,10 +1,10 @@
#ifndef LOGGER_H #ifndef LOGGER_H
#define LOGGER_H #define LOGGER_H
#include <QObject>
#include <QReadWriteLock>
#include <QString> #include <QString>
#include <QVector> #include <QVector>
#include <QReadWriteLock>
#include <QObject>
const int MAX_LOG_MESSAGES = 20000; const int MAX_LOG_MESSAGES = 20000;
@@ -66,9 +66,9 @@ private:
static Logger *m_instance; static Logger *m_instance;
QVector<Log::Msg> m_messages; QVector<Log::Msg> m_messages;
QVector<Log::Peer> m_peers; QVector<Log::Peer> m_peers;
mutable QReadWriteLock lock; mutable QReadWriteLock m_lock;
int msgCounter; int m_msgCounter;
int peerCounter; int m_peerCounter;
}; };
// Helper function // Helper function

View File

@@ -52,7 +52,7 @@ DNSUpdater::DNSUpdater(QObject *parent)
// Start IP checking timer // Start IP checking timer
m_ipCheckTimer.setInterval(IP_CHECK_INTERVAL_MS); m_ipCheckTimer.setInterval(IP_CHECK_INTERVAL_MS);
connect(&m_ipCheckTimer, SIGNAL(timeout()), SLOT(checkPublicIP())); connect(&m_ipCheckTimer, &QTimer::timeout, this, &DNSUpdater::checkPublicIP);
m_ipCheckTimer.start(); m_ipCheckTimer.start();
// Check lastUpdate to avoid flooding // Check lastUpdate to avoid flooding
@@ -77,8 +77,9 @@ void DNSUpdater::checkPublicIP()
DownloadHandler *handler = DownloadManager::instance()->downloadUrl( DownloadHandler *handler = DownloadManager::instance()->downloadUrl(
"http://checkip.dyndns.org", false, 0, false, "http://checkip.dyndns.org", false, 0, false,
"qBittorrent/" QBT_VERSION_2); "qBittorrent/" QBT_VERSION_2);
connect(handler, SIGNAL(downloadFinished(QString, QByteArray)), SLOT(ipRequestFinished(QString, QByteArray))); connect(handler, static_cast<void (Net::DownloadHandler::*)(const QString &, const QByteArray &)>(&Net::DownloadHandler::downloadFinished)
connect(handler, SIGNAL(downloadFailed(QString, QString)), SLOT(ipRequestFailed(QString, QString))); , this, &DNSUpdater::ipRequestFinished);
connect(handler, &Net::DownloadHandler::downloadFailed, this, &DNSUpdater::ipRequestFailed);
m_lastIPCheckTime = QDateTime::currentDateTime(); m_lastIPCheckTime = QDateTime::currentDateTime();
} }
@@ -124,8 +125,9 @@ void DNSUpdater::updateDNSService()
DownloadHandler *handler = DownloadManager::instance()->downloadUrl( DownloadHandler *handler = DownloadManager::instance()->downloadUrl(
getUpdateUrl(), false, 0, false, getUpdateUrl(), false, 0, false,
"qBittorrent/" QBT_VERSION_2); "qBittorrent/" QBT_VERSION_2);
connect(handler, SIGNAL(downloadFinished(QString, QByteArray)), SLOT(ipUpdateFinished(QString, QByteArray))); connect(handler, static_cast<void (Net::DownloadHandler::*)(const QString &, const QByteArray &)>(&Net::DownloadHandler::downloadFinished)
connect(handler, SIGNAL(downloadFailed(QString, QString)), SLOT(ipUpdateFailed(QString, QString))); , this, &DNSUpdater::ipUpdateFinished);
connect(handler, &Net::DownloadHandler::downloadFailed, this, &DNSUpdater::ipUpdateFailed);
} }
QString DNSUpdater::getUpdateUrl() const QString DNSUpdater::getUpdateUrl() const

View File

@@ -124,7 +124,7 @@ void DownloadHandler::checkDownloadSize(qint64 bytesReceived, qint64 bytesTotal)
emit downloadFailed(m_url, msg.arg(Utils::Misc::friendlyUnit(bytesTotal), Utils::Misc::friendlyUnit(m_sizeLimit))); emit downloadFailed(m_url, msg.arg(Utils::Misc::friendlyUnit(bytesTotal), Utils::Misc::friendlyUnit(m_sizeLimit)));
} }
else { else {
disconnect(m_reply, SIGNAL(downloadProgress(qint64, qint64)), this, SLOT(checkDownloadSize(qint64, qint64))); disconnect(m_reply, &QNetworkReply::downloadProgress, this, &Net::DownloadHandler::checkDownloadSize);
} }
} }
else if (bytesReceived > m_sizeLimit) { else if (bytesReceived > m_sizeLimit) {
@@ -137,8 +137,8 @@ void DownloadHandler::init()
{ {
m_reply->setParent(this); m_reply->setParent(this);
if (m_sizeLimit > 0) if (m_sizeLimit > 0)
connect(m_reply, SIGNAL(downloadProgress(qint64, qint64)), this, SLOT(checkDownloadSize(qint64, qint64))); connect(m_reply, &QNetworkReply::downloadProgress, this, &Net::DownloadHandler::checkDownloadSize);
connect(m_reply, SIGNAL(finished()), this, SLOT(processFinishedDownload())); connect(m_reply, &QNetworkReply::finished, this, &Net::DownloadHandler::processFinishedDownload);
} }
bool DownloadHandler::saveToFile(const QByteArray &replyData, QString &filePath) bool DownloadHandler::saveToFile(const QByteArray &replyData, QString &filePath)

View File

@@ -51,7 +51,7 @@ namespace
class NetworkCookieJar : public QNetworkCookieJar class NetworkCookieJar : public QNetworkCookieJar
{ {
public: public:
explicit NetworkCookieJar(QObject *parent = 0) explicit NetworkCookieJar(QObject *parent = nullptr)
: QNetworkCookieJar(parent) : QNetworkCookieJar(parent)
{ {
QDateTime now = QDateTime::currentDateTime(); QDateTime now = QDateTime::currentDateTime();
@@ -107,13 +107,13 @@ namespace
using namespace Net; using namespace Net;
DownloadManager *DownloadManager::m_instance = 0; DownloadManager *DownloadManager::m_instance = nullptr;
DownloadManager::DownloadManager(QObject *parent) DownloadManager::DownloadManager(QObject *parent)
: QObject(parent) : QObject(parent)
{ {
#ifndef QT_NO_OPENSSL #ifndef QT_NO_OPENSSL
connect(&m_networkManager, SIGNAL(sslErrors(QNetworkReply *, QList<QSslError>)), this, SLOT(ignoreSslErrors(QNetworkReply *, QList<QSslError>))); connect(&m_networkManager, &QNetworkAccessManager::sslErrors, this, &Net::DownloadManager::ignoreSslErrors);
#endif #endif
m_networkManager.setCookieJar(new NetworkCookieJar(this)); m_networkManager.setCookieJar(new NetworkCookieJar(this));
} }
@@ -128,7 +128,7 @@ void DownloadManager::freeInstance()
{ {
if (m_instance) { if (m_instance) {
delete m_instance; delete m_instance;
m_instance = 0; m_instance = nullptr;
} }
} }

View File

@@ -64,7 +64,7 @@ namespace Net
#endif #endif
private: private:
explicit DownloadManager(QObject *parent = 0); explicit DownloadManager(QObject *parent = nullptr);
void applyProxySettings(); void applyProxySettings();

View File

@@ -60,7 +60,7 @@ GeoIPManager::GeoIPManager()
, m_geoIPDatabase(nullptr) , m_geoIPDatabase(nullptr)
{ {
configure(); configure();
connect(Preferences::instance(), SIGNAL(changed()), SLOT(configure())); connect(Preferences::instance(), &Preferences::changed, this, &GeoIPManager::configure);
} }
GeoIPManager::~GeoIPManager() GeoIPManager::~GeoIPManager()
@@ -119,8 +119,9 @@ void GeoIPManager::manageDatabaseUpdate()
void GeoIPManager::downloadDatabaseFile() void GeoIPManager::downloadDatabaseFile()
{ {
DownloadHandler *handler = DownloadManager::instance()->downloadUrl(DATABASE_URL); DownloadHandler *handler = DownloadManager::instance()->downloadUrl(DATABASE_URL);
connect(handler, SIGNAL(downloadFinished(QString, QByteArray)), SLOT(downloadFinished(QString, QByteArray))); connect(handler, static_cast<void (Net::DownloadHandler::*)(const QString &, const QByteArray &)>(&Net::DownloadHandler::downloadFinished)
connect(handler, SIGNAL(downloadFailed(QString, QString)), SLOT(downloadFailed(QString, QString))); , this, &GeoIPManager::downloadFinished);
connect(handler, &Net::DownloadHandler::downloadFailed, this, &GeoIPManager::downloadFailed);
} }
QString GeoIPManager::lookup(const QHostAddress &hostAddr) const QString GeoIPManager::lookup(const QHostAddress &hostAddr) const

View File

@@ -36,7 +36,7 @@
#include "base/logger.h" #include "base/logger.h"
#include "base/settingsstorage.h" #include "base/settingsstorage.h"
static const QString KEY_ENABLED = QLatin1String("Network/PortForwardingEnabled"); static const QString KEY_ENABLED = QStringLiteral("Network/PortForwardingEnabled");
namespace libt = libtorrent; namespace libt = libtorrent;
using namespace Net; using namespace Net;

View File

@@ -26,20 +26,18 @@
* exception statement from your version. * exception statement from your version.
*/ */
#include <QDateTime>
#include <QDebug> #include <QDebug>
#include <QVariant> #include <QFile>
#include <QHash> #include <QHash>
#include <QHostAddress> #include <QHostAddress>
#include <QDateTime> #include <QVariant>
#include <QFile>
#include "base/types.h" #include "base/types.h"
#include "geoipdatabase.h" #include "geoipdatabase.h"
namespace namespace
{ {
const quint32 __ENDIAN_TEST__ = 0x00000001;
const bool __IS_LITTLE_ENDIAN__ = (reinterpret_cast<const uchar *>(&__ENDIAN_TEST__)[0] == 0x01);
const qint32 MAX_FILE_SIZE = 67108864; // 64MB const qint32 MAX_FILE_SIZE = 67108864; // 64MB
const char DB_TYPE[] = "GeoLite2-Country"; const char DB_TYPE[] = "GeoLite2-Country";
const quint32 MAX_METADATA_SIZE = 131072; // 128KB const quint32 MAX_METADATA_SIZE = 131072; // 128KB
@@ -91,7 +89,7 @@ GeoIPDatabase::GeoIPDatabase(quint32 size)
GeoIPDatabase *GeoIPDatabase::load(const QString &filename, QString &error) GeoIPDatabase *GeoIPDatabase::load(const QString &filename, QString &error)
{ {
GeoIPDatabase *db = 0; GeoIPDatabase *db = nullptr;
QFile file(filename); QFile file(filename);
if (file.size() > MAX_FILE_SIZE) { if (file.size() > MAX_FILE_SIZE) {
error = tr("Unsupported database file size."); error = tr("Unsupported database file size.");
@@ -122,7 +120,7 @@ GeoIPDatabase *GeoIPDatabase::load(const QString &filename, QString &error)
GeoIPDatabase *GeoIPDatabase::load(const QByteArray &data, QString &error) GeoIPDatabase *GeoIPDatabase::load(const QByteArray &data, QString &error)
{ {
GeoIPDatabase *db = 0; GeoIPDatabase *db = nullptr;
if (data.size() > MAX_FILE_SIZE) { if (data.size() > MAX_FILE_SIZE) {
error = tr("Unsupported database file size."); error = tr("Unsupported database file size.");
return 0; return 0;
@@ -448,8 +446,12 @@ bool GeoIPDatabase::readDataFieldDescriptor(quint32 &offset, DataFieldDescriptor
void GeoIPDatabase::fromBigEndian(uchar *buf, quint32 len) const void GeoIPDatabase::fromBigEndian(uchar *buf, quint32 len) const
{ {
if (__IS_LITTLE_ENDIAN__) #if (Q_BYTE_ORDER == Q_LITTLE_ENDIAN)
std::reverse(buf, buf + len); std::reverse(buf, buf + len);
#else
Q_UNUSED(buf);
Q_UNUSED(len);
#endif
} }
QVariant GeoIPDatabase::readMapValue(quint32 &offset, quint32 count) const QVariant GeoIPDatabase::readMapValue(quint32 &offset, quint32 count) const

View File

@@ -29,13 +29,13 @@
#ifndef GEOIPDATABASE_H #ifndef GEOIPDATABASE_H
#define GEOIPDATABASE_H #define GEOIPDATABASE_H
#include <QtGlobal>
#include <QCoreApplication> #include <QCoreApplication>
#include <QtGlobal>
class QHostAddress;
class QString;
class QByteArray; class QByteArray;
class QDateTime; class QDateTime;
class QHostAddress;
class QString;
struct DataFieldDescriptor; struct DataFieldDescriptor;

View File

@@ -27,9 +27,10 @@
*/ */
#include "proxyconfigurationmanager.h" #include "proxyconfigurationmanager.h"
#include "base/settingsstorage.h" #include "base/settingsstorage.h"
#define SETTINGS_KEY(name) "Network/Proxy/" name #define SETTINGS_KEY(name) QStringLiteral("Network/Proxy/" name)
const QString KEY_ONLY_FOR_TORRENTS = SETTINGS_KEY("OnlyForTorrents"); const QString KEY_ONLY_FOR_TORRENTS = SETTINGS_KEY("OnlyForTorrents");
const QString KEY_TYPE = SETTINGS_KEY("Type"); const QString KEY_TYPE = SETTINGS_KEY("Type");
const QString KEY_IP = SETTINGS_KEY("IP"); const QString KEY_IP = SETTINGS_KEY("IP");
@@ -80,7 +81,7 @@ void ProxyConfigurationManager::freeInstance()
{ {
if (m_instance) { if (m_instance) {
delete m_instance; delete m_instance;
m_instance = 0; m_instance = nullptr;
} }
} }

View File

@@ -1,6 +1,6 @@
/* /*
* Bittorrent Client using Qt and libtorrent. * Bittorrent Client using Qt and libtorrent.
* Copyright (C) 2006 Christophe Dumez * Copyright (C) 2006 Christophe Dumez <chris@qbittorrent.org>
* *
* This program is free software; you can redistribute it and/or * This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License * modify it under the terms of the GNU General Public License
@@ -24,26 +24,24 @@
* modify file(s), you may extend this exception to your version of the file(s), * modify file(s), you may extend this exception to your version of the file(s),
* but you are not obligated to do so. If you do not wish to do so, delete this * but you are not obligated to do so. If you do not wish to do so, delete this
* exception statement from your version. * exception statement from your version.
*
* Contact : chris@qbittorrent.org
*/ */
#include "reverseresolution.h"
#include <boost/asio/ip/tcp.hpp>
#include <boost/version.hpp>
#include <QDebug> #include <QDebug>
#include <QHostInfo> #include <QHostInfo>
#include <QString> #include <QString>
#include <boost/version.hpp>
#include <boost/asio/ip/tcp.hpp>
#include "reverseresolution.h"
const int CACHE_SIZE = 500; const int CACHE_SIZE = 500;
using namespace Net; using namespace Net;
static inline bool isUsefulHostName(const QString &hostname, const QString &ip) static inline bool isUsefulHostName(const QString &hostname, const QString &ip)
{ {
return (!hostname.isEmpty() && hostname != ip); return (!hostname.isEmpty() && (hostname != ip));
} }
ReverseResolution::ReverseResolution(QObject *parent) ReverseResolution::ReverseResolution(QObject *parent)
@@ -67,7 +65,11 @@ void ReverseResolution::resolve(const QString &ip)
} }
else { else {
// Actually resolve the ip // Actually resolve the ip
#if (QT_VERSION >= QT_VERSION_CHECK(5, 9, 0))
m_lookups.insert(QHostInfo::lookupHost(ip, this, &ReverseResolution::hostResolved), ip);
#else
m_lookups.insert(QHostInfo::lookupHost(ip, this, SLOT(hostResolved(QHostInfo))), ip); m_lookups.insert(QHostInfo::lookupHost(ip, this, SLOT(hostResolved(QHostInfo))), ip);
#endif
} }
} }

View File

@@ -1,6 +1,6 @@
/* /*
* Bittorrent Client using Qt and libtorrent. * Bittorrent Client using Qt and libtorrent.
* Copyright (C) 2006 Christophe Dumez * Copyright (C) 2006 Christophe Dumez <chris@qbittorrent.org>
* *
* This program is free software; you can redistribute it and/or * This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License * modify it under the terms of the GNU General Public License
@@ -24,8 +24,6 @@
* modify file(s), you may extend this exception to your version of the file(s), * modify file(s), you may extend this exception to your version of the file(s),
* but you are not obligated to do so. If you do not wish to do so, delete this * but you are not obligated to do so. If you do not wish to do so, delete this
* exception statement from your version. * exception statement from your version.
*
* Contact : chris@qbittorrent.org
*/ */
#ifndef NET_REVERSERESOLUTION_H #ifndef NET_REVERSERESOLUTION_H
@@ -34,10 +32,8 @@
#include <QCache> #include <QCache>
#include <QObject> #include <QObject>
QT_BEGIN_NAMESPACE
class QHostInfo; class QHostInfo;
class QString; class QString;
QT_END_NAMESPACE
namespace Net namespace Net
{ {
@@ -47,7 +43,7 @@ namespace Net
Q_DISABLE_COPY(ReverseResolution) Q_DISABLE_COPY(ReverseResolution)
public: public:
explicit ReverseResolution(QObject *parent = 0); explicit ReverseResolution(QObject *parent = nullptr);
~ReverseResolution(); ~ReverseResolution();
void resolve(const QString &ip); void resolve(const QString &ip);

View File

@@ -111,9 +111,10 @@ Smtp::Smtp(QObject *parent)
m_socket = new QTcpSocket(this); m_socket = new QTcpSocket(this);
#endif #endif
connect(m_socket, SIGNAL(readyRead()), SLOT(readyRead())); connect(m_socket, &QIODevice::readyRead, this, &Smtp::readyRead);
connect(m_socket, SIGNAL(disconnected()), SLOT(deleteLater())); connect(m_socket, &QAbstractSocket::disconnected, this, &QObject::deleteLater);
connect(m_socket, SIGNAL(error(QAbstractSocket::SocketError)), SLOT(error(QAbstractSocket::SocketError))); connect(m_socket, static_cast<void (QAbstractSocket::*)(QAbstractSocket::SocketError)>(&QAbstractSocket::error)
, this, &Smtp::error);
// Test hmacMD5 function (http://www.faqs.org/rfcs/rfc2202.html) // Test hmacMD5 function (http://www.faqs.org/rfcs/rfc2202.html)
Q_ASSERT(hmacMD5("Jefe", "what do ya want for nothing?").toHex() Q_ASSERT(hmacMD5("Jefe", "what do ya want for nothing?").toHex()
@@ -140,8 +141,8 @@ void Smtp::sendMail(const QString &from, const QString &to, const QString &subje
+ "Content-Transfer-Encoding: base64\r\n" + "Content-Transfer-Encoding: base64\r\n"
+ "\r\n"; + "\r\n";
// Encode the body in base64 // Encode the body in base64
QString crlf_body = body; QString crlfBody = body;
QByteArray b = crlf_body.replace("\n", "\r\n").toUtf8().toBase64(); QByteArray b = crlfBody.replace("\n", "\r\n").toUtf8().toBase64();
int ct = b.length(); int ct = b.length();
for (int i = 0; i < ct; i += 78) for (int i = 0; i < ct; i += 78)
m_message += b.mid(i, 78); m_message += b.mid(i, 78);
@@ -183,7 +184,7 @@ void Smtp::readyRead()
QByteArray code = line.left(3); QByteArray code = line.left(3);
switch (m_state) { switch (m_state) {
case Init: { case Init:
if (code[0] == '2') { if (code[0] == '2') {
// The server may send a multiline greeting/INIT/220 response. // The server may send a multiline greeting/INIT/220 response.
// We wait until it finishes. // We wait until it finishes.
@@ -197,7 +198,6 @@ void Smtp::readyRead()
m_state = Close; m_state = Close;
} }
break; break;
}
case EhloSent: case EhloSent:
case HeloSent: case HeloSent:
case EhloGreetReceived: case EhloGreetReceived:

View File

@@ -1,7 +1,7 @@
/* /*
* Bittorrent Client using Qt4 and libtorrent. * Bittorrent Client using Qt and libtorrent.
* Copyright (C) 2006 Christophe Dumez * Copyright (C) 2014 sledgehammer999 <sledgehammer999@qbittorrent.org>
* Copyright (C) 2014 sledgehammer999 * Copyright (C) 2006 Christophe Dumez <chris@qbittorrent.org>
* *
* This program is free software; you can redistribute it and/or * This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License * modify it under the terms of the GNU General Public License
@@ -25,9 +25,6 @@
* modify file(s), you may extend this exception to your version of the file(s), * modify file(s), you may extend this exception to your version of the file(s),
* but you are not obligated to do so. If you do not wish to do so, delete this * but you are not obligated to do so. If you do not wish to do so, delete this
* exception statement from your version. * exception statement from your version.
*
* Contact : chris@qbittorrent.org
* Contact : hammered999@gmail.com
*/ */
#include "preferences.h" #include "preferences.h"
@@ -59,7 +56,7 @@
#include "utils/fs.h" #include "utils/fs.h"
#include "utils/misc.h" #include "utils/misc.h"
Preferences *Preferences::m_instance = 0; Preferences *Preferences::m_instance = nullptr;
Preferences::Preferences() = default; Preferences::Preferences() = default;
@@ -78,7 +75,7 @@ void Preferences::freeInstance()
{ {
if (m_instance) { if (m_instance) {
delete m_instance; delete m_instance;
m_instance = 0; m_instance = nullptr;
} }
} }
@@ -420,12 +417,12 @@ void Preferences::setSchedulerEndTime(const QTime &time)
setValue("Preferences/Scheduler/end_time", time); setValue("Preferences/Scheduler/end_time", time);
} }
scheduler_days Preferences::getSchedulerDays() const SchedulerDays Preferences::getSchedulerDays() const
{ {
return static_cast<scheduler_days>(value("Preferences/Scheduler/days", EVERY_DAY).toInt()); return static_cast<SchedulerDays>(value("Preferences/Scheduler/days", EVERY_DAY).toInt());
} }
void Preferences::setSchedulerDays(scheduler_days days) void Preferences::setSchedulerDays(SchedulerDays days)
{ {
setValue("Preferences/Scheduler/days", static_cast<int>(days)); setValue("Preferences/Scheduler/days", static_cast<int>(days));
} }
@@ -690,12 +687,12 @@ QString Preferences::getUILockPasswordMD5() const
return value("Locking/password").toString(); return value("Locking/password").toString();
} }
void Preferences::setUILockPassword(const QString &clear_password) void Preferences::setUILockPassword(const QString &clearPassword)
{ {
QCryptographicHash md5(QCryptographicHash::Md5); QCryptographicHash md5(QCryptographicHash::Md5);
md5.addData(clear_password.toLocal8Bit()); md5.addData(clearPassword.toLocal8Bit());
QString md5_password = md5.result().toHex(); QString md5Password = md5.result().toHex();
setValue("Locking/password", md5_password); setValue("Locking/password", md5Password);
} }
bool Preferences::isUILocked() const bool Preferences::isUILocked() const

View File

@@ -1,7 +1,7 @@
/* /*
* Bittorrent Client using Qt4 and libtorrent. * Bittorrent Client using Qt and libtorrent.
* Copyright (C) 2006 Christophe Dumez * Copyright (C) 2014 sledgehammer999 <sledgehammer999@qbittorrent.org>
* Copyright (C) 2014 sledgehammer999 * Copyright (C) 2006 Christophe Dumez <chris@qbittorrent.org>
* *
* This program is free software; you can redistribute it and/or * This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License * modify it under the terms of the GNU General Public License
@@ -25,9 +25,6 @@
* modify file(s), you may extend this exception to your version of the file(s), * modify file(s), you may extend this exception to your version of the file(s),
* but you are not obligated to do so. If you do not wish to do so, delete this * but you are not obligated to do so. If you do not wish to do so, delete this
* exception statement from your version. * exception statement from your version.
*
* Contact : chris@qbittorrent.org
* Contact : hammered999@gmail.com
*/ */
#ifndef PREFERENCES_H #ifndef PREFERENCES_H
@@ -47,7 +44,7 @@
#include "base/utils/net.h" #include "base/utils/net.h"
#include "types.h" #include "types.h"
enum scheduler_days enum SchedulerDays
{ {
EVERY_DAY, EVERY_DAY,
WEEK_DAYS, WEEK_DAYS,
@@ -166,8 +163,8 @@ public:
void setSchedulerStartTime(const QTime &time); void setSchedulerStartTime(const QTime &time);
QTime getSchedulerEndTime() const; QTime getSchedulerEndTime() const;
void setSchedulerEndTime(const QTime &time); void setSchedulerEndTime(const QTime &time);
scheduler_days getSchedulerDays() const; SchedulerDays getSchedulerDays() const;
void setSchedulerDays(scheduler_days days); void setSchedulerDays(SchedulerDays days);
// Search // Search
bool isSearchEnabled() const; bool isSearchEnabled() const;
@@ -222,7 +219,7 @@ public:
void setDynDNSPassword(const QString &password); void setDynDNSPassword(const QString &password);
// Advanced settings // Advanced settings
void setUILockPassword(const QString &clear_password); void setUILockPassword(const QString &clearPassword);
void clearUILockPassword(); void clearUILockPassword();
QString getUILockPasswordMD5() const; QString getUILockPasswordMD5() const;
bool isUILocked() const; bool isUILocked() const;

View File

@@ -25,7 +25,6 @@
* modify file(s), you may extend this exception to your version of the file(s), * modify file(s), you may extend this exception to your version of the file(s),
* but you are not obligated to do so. If you do not wish to do so, delete this * but you are not obligated to do so. If you do not wish to do so, delete this
* exception statement from your version. * exception statement from your version.
*
*/ */
#ifndef QBT_PROFILE_P_H #ifndef QBT_PROFILE_P_H
@@ -33,6 +32,7 @@
#include <QDir> #include <QDir>
#include <QStandardPaths> #include <QStandardPaths>
#include "base/profile.h" #include "base/profile.h"
namespace Private namespace Private
@@ -132,4 +132,5 @@ namespace Private
QDir m_baseDir; QDir m_baseDir;
}; };
} }
#endif // QBT_PROFILE_P_H #endif // QBT_PROFILE_P_H

View File

@@ -25,7 +25,6 @@
* modify file(s), you may extend this exception to your version of the file(s), * modify file(s), you may extend this exception to your version of the file(s),
* but you are not obligated to do so. If you do not wish to do so, delete this * but you are not obligated to do so. If you do not wish to do so, delete this
* exception statement from your version. * exception statement from your version.
*
*/ */
#include "profile.h" #include "profile.h"

View File

@@ -33,9 +33,9 @@
#include <memory> #include <memory>
#include <QString>
#include <QScopedPointer> #include <QScopedPointer>
#include <QSettings> #include <QSettings>
#include <QString>
class Application; class Application;

View File

@@ -29,8 +29,8 @@
#include "rss_parser.h" #include "rss_parser.h"
#include <QDebug>
#include <QDateTime> #include <QDateTime>
#include <QDebug>
#include <QGlobalStatic> #include <QGlobalStatic>
#include <QHash> #include <QHash>
#include <QMetaObject> #include <QMetaObject>

View File

@@ -38,6 +38,19 @@
using namespace RSS; using namespace RSS;
namespace
{
QVariantHash articleDataFromJSON(const QJsonObject &jsonObj)
{
auto varHash = jsonObj.toVariantHash();
// JSON object store DateTime as string so we need to convert it
varHash[Article::KeyDate] =
QDateTime::fromString(jsonObj.value(Article::KeyDate).toString(), Qt::RFC2822Date);
return varHash;
}
}
const QString Article::KeyId(QStringLiteral("id")); const QString Article::KeyId(QStringLiteral("id"));
const QString Article::KeyDate(QStringLiteral("date")); const QString Article::KeyDate(QStringLiteral("date"));
const QString Article::KeyTitle(QStringLiteral("title")); const QString Article::KeyTitle(QStringLiteral("title"));
@@ -60,6 +73,9 @@ Article::Article(Feed *feed, const QVariantHash &varHash)
, m_isRead(varHash.value(KeyIsRead, false).toBool()) , m_isRead(varHash.value(KeyIsRead, false).toBool())
, m_data(varHash) , m_data(varHash)
{ {
if (!m_date.isValid())
throw std::runtime_error("Bad RSS Article data");
// If item does not have a guid, fall back to some other identifier // If item does not have a guid, fall back to some other identifier
if (m_guid.isEmpty()) if (m_guid.isEmpty())
m_guid = varHash.value(KeyTorrentURL).toString(); m_guid = varHash.value(KeyTorrentURL).toString();
@@ -77,11 +93,8 @@ Article::Article(Feed *feed, const QVariantHash &varHash)
} }
Article::Article(Feed *feed, const QJsonObject &jsonObj) Article::Article(Feed *feed, const QJsonObject &jsonObj)
: Article(feed, jsonObj.toVariantHash()) : Article(feed, articleDataFromJSON(jsonObj))
{ {
// JSON object store DateTime as string so we need to convert it
m_date = QDateTime::fromString(jsonObj.value(KeyDate).toString(), Qt::RFC2822Date);
m_data[KeyDate] = m_date;
} }
QString Article::guid() const QString Article::guid() const

View File

@@ -365,19 +365,7 @@ void AutoDownloader::processJob(const QSharedPointer<ProcessingJob> &job)
for (AutoDownloadRule &rule: m_rules) { for (AutoDownloadRule &rule: m_rules) {
if (!rule.isEnabled()) continue; if (!rule.isEnabled()) continue;
if (!rule.feedURLs().contains(job->feedURL)) continue; if (!rule.feedURLs().contains(job->feedURL)) continue;
if (!rule.matches(job->articleData.value(Article::KeyTitle).toString())) continue; if (!rule.accepts(job->articleData)) continue;
auto articleDate = job->articleData.value(Article::KeyDate).toDateTime();
// if rule is in ignoring state do nothing with matched torrent
if (rule.ignoreDays() > 0) {
if (rule.lastMatch().isValid()) {
if (articleDate < rule.lastMatch().addDays(rule.ignoreDays()))
return;
}
}
rule.setLastMatch(articleDate);
rule.appendLastComputedEpisode();
m_dirty = true; m_dirty = true;
storeDeferred(); storeDeferred();

View File

@@ -39,13 +39,14 @@
#include <QString> #include <QString>
#include <QStringList> #include <QStringList>
#include "../global.h"
#include "../preferences.h" #include "../preferences.h"
#include "../tristatebool.h" #include "../tristatebool.h"
#include "../utils/fs.h" #include "../utils/fs.h"
#include "../utils/string.h" #include "../utils/string.h"
#include "rss_feed.h"
#include "rss_article.h" #include "rss_article.h"
#include "rss_autodownloader.h" #include "rss_autodownloader.h"
#include "rss_feed.h"
namespace namespace
{ {
@@ -192,197 +193,198 @@ QRegularExpression AutoDownloadRule::cachedRegex(const QString &expression, bool
// The cache is cleared whenever the regex/wildcard, must or must not contain fields or // The cache is cleared whenever the regex/wildcard, must or must not contain fields or
// episode filter are modified. // episode filter are modified.
Q_ASSERT(!expression.isEmpty()); Q_ASSERT(!expression.isEmpty());
QRegularExpression regex(m_dataPtr->cachedRegexes[expression]);
if (!regex.pattern().isEmpty()) QRegularExpression &regex = m_dataPtr->cachedRegexes[expression];
return regex; if (regex.pattern().isEmpty()) {
regex = QRegularExpression {
return m_dataPtr->cachedRegexes[expression] = QRegularExpression(isRegex ? expression : Utils::String::wildcardToRegex(expression), QRegularExpression::CaseInsensitiveOption); (isRegex ? expression : Utils::String::wildcardToRegex(expression))
, QRegularExpression::CaseInsensitiveOption};
} }
bool AutoDownloadRule::matches(const QString &articleTitle, const QString &expression) const return regex;
}
bool AutoDownloadRule::matchesExpression(const QString &articleTitle, const QString &expression) const
{ {
static QRegularExpression whitespace("\\s+"); const QRegularExpression whitespace {"\\s+"};
if (expression.isEmpty()) { if (expression.isEmpty()) {
// A regex of the form "expr|" will always match, so do the same for wildcards // A regex of the form "expr|" will always match, so do the same for wildcards
return true; return true;
} }
else if (m_dataPtr->useRegex) {
if (m_dataPtr->useRegex) {
QRegularExpression reg(cachedRegex(expression)); QRegularExpression reg(cachedRegex(expression));
return reg.match(articleTitle).hasMatch(); return reg.match(articleTitle).hasMatch();
} }
else {
// Only match if every wildcard token (separated by spaces) is present in the article name. // Only match if every wildcard token (separated by spaces) is present in the article name.
// Order of wildcard tokens is unimportant (if order is important, they should have used *). // Order of wildcard tokens is unimportant (if order is important, they should have used *).
foreach (const QString &wildcard, expression.split(whitespace, QString::SplitBehavior::SkipEmptyParts)) { const QStringList wildcards {expression.split(whitespace, QString::SplitBehavior::SkipEmptyParts)};
QRegularExpression reg(cachedRegex(wildcard, false)); for (const QString &wildcard : wildcards) {
const QRegularExpression reg {cachedRegex(wildcard, false)};
if (!reg.match(articleTitle).hasMatch()) if (!reg.match(articleTitle).hasMatch())
return false; return false;
} }
}
return true; return true;
} }
bool AutoDownloadRule::matches(const QString &articleTitle) const bool AutoDownloadRule::matchesMustContainExpression(const QString &articleTitle) const
{
if (m_dataPtr->mustContain.empty())
return true;
// Each expression is either a regex, or a set of wildcards separated by whitespace.
// Accept if any complete expression matches.
for (const QString &expression : qAsConst(m_dataPtr->mustContain)) {
// A regex of the form "expr|" will always match, so do the same for wildcards
if (matchesExpression(articleTitle, expression))
return true;
}
return false;
}
bool AutoDownloadRule::matchesMustNotContainExpression(const QString& articleTitle) const
{
if (m_dataPtr->mustNotContain.empty())
return true;
// Each expression is either a regex, or a set of wildcards separated by whitespace.
// Reject if any complete expression matches.
for (const QString &expression : qAsConst(m_dataPtr->mustNotContain)) {
// A regex of the form "expr|" will always match, so do the same for wildcards
if (matchesExpression(articleTitle, expression))
return false;
}
return true;
}
bool AutoDownloadRule::matchesEpisodeFilterExpression(const QString& articleTitle) const
{ {
// Reset the lastComputedEpisode, we don't want to leak it between matches // Reset the lastComputedEpisode, we don't want to leak it between matches
m_dataPtr->lastComputedEpisode.clear(); m_dataPtr->lastComputedEpisode.clear();
if (!m_dataPtr->mustContain.empty()) { if (m_dataPtr->episodeFilter.isEmpty())
bool logged = false; return true;
bool foundMustContain = false;
// Each expression is either a regex, or a set of wildcards separated by whitespace. const QRegularExpression filterRegex {cachedRegex("(^\\d{1,4})x(.*;$)")};
// Accept if any complete expression matches. const QRegularExpressionMatch matcher {filterRegex.match(m_dataPtr->episodeFilter)};
foreach (const QString &expression, m_dataPtr->mustContain) { if (!matcher.hasMatch())
if (!logged) {
// qDebug() << "Checking matching" << (m_dataPtr->useRegex ? "regex:" : "wildcard expressions:") << m_dataPtr->mustContain.join("|");
logged = true;
}
// A regex of the form "expr|" will always match, so do the same for wildcards
foundMustContain = matches(articleTitle, expression);
if (foundMustContain) {
// qDebug() << "Found matching" << (m_dataPtr->useRegex ? "regex:" : "wildcard expression:") << expression;
break;
}
}
if (!foundMustContain)
return false;
}
if (!m_dataPtr->mustNotContain.empty()) {
bool logged = false;
// Each expression is either a regex, or a set of wildcards separated by whitespace.
// Reject if any complete expression matches.
foreach (const QString &expression, m_dataPtr->mustNotContain) {
if (!logged) {
// qDebug() << "Checking not matching" << (m_dataPtr->useRegex ? "regex:" : "wildcard expressions:") << m_dataPtr->mustNotContain.join("|");
logged = true;
}
// A regex of the form "expr|" will always match, so do the same for wildcards
if (matches(articleTitle, expression)) {
// qDebug() << "Found not matching" << (m_dataPtr->useRegex ? "regex:" : "wildcard expression:") << expression;
return false;
}
}
}
if (!m_dataPtr->episodeFilter.isEmpty()) {
// qDebug() << "Checking episode filter:" << m_dataPtr->episodeFilter;
QRegularExpression f(cachedRegex("(^\\d{1,4})x(.*;$)"));
QRegularExpressionMatch matcher = f.match(m_dataPtr->episodeFilter);
bool matched = matcher.hasMatch();
if (!matched)
return false; return false;
QString s = matcher.captured(1); const QString season {matcher.captured(1)};
QStringList eps = matcher.captured(2).split(";"); const QStringList episodes {matcher.captured(2).split(';')};
int sOurs = s.toInt(); const int seasonOurs {season.toInt()};
foreach (QString ep, eps) { for (QString episode : episodes) {
if (ep.isEmpty()) if (episode.isEmpty())
continue; continue;
// We need to trim leading zeroes, but if it's all zeros then we want episode zero. // We need to trim leading zeroes, but if it's all zeros then we want episode zero.
while (ep.size() > 1 && ep.startsWith("0")) while ((episode.size() > 1) && episode.startsWith('0'))
ep = ep.right(ep.size() - 1); episode = episode.right(episode.size() - 1);
if (ep.indexOf('-') != -1) { // Range detected if (episode.indexOf('-') != -1) { // Range detected
QString partialPattern1 = "\\bs0?(\\d{1,4})[ -_\\.]?e(0?\\d{1,4})(?:\\D|\\b)"; const QString partialPattern1 {"\\bs0?(\\d{1,4})[ -_\\.]?e(0?\\d{1,4})(?:\\D|\\b)"};
QString partialPattern2 = "\\b(\\d{1,4})x(0?\\d{1,4})(?:\\D|\\b)"; const QString partialPattern2 {"\\b(\\d{1,4})x(0?\\d{1,4})(?:\\D|\\b)"};
QRegularExpression reg(cachedRegex(partialPattern1));
if (ep.endsWith('-')) { // Infinite range
int epOurs = ep.leftRef(ep.size() - 1).toInt();
// Extract partial match from article and compare as digits // Extract partial match from article and compare as digits
matcher = reg.match(articleTitle); QRegularExpressionMatch matcher = cachedRegex(partialPattern1).match(articleTitle);
matched = matcher.hasMatch(); bool matched = matcher.hasMatch();
if (!matched) { if (!matched) {
reg = QRegularExpression(cachedRegex(partialPattern2)); matcher = cachedRegex(partialPattern2).match(articleTitle);
matcher = reg.match(articleTitle);
matched = matcher.hasMatch(); matched = matcher.hasMatch();
} }
if (matched) { if (matched) {
int sTheirs = matcher.captured(1).toInt(); const int seasonTheirs {matcher.captured(1).toInt()};
int epTheirs = matcher.captured(2).toInt(); const int episodeTheirs {matcher.captured(2).toInt()};
if (((sTheirs == sOurs) && (epTheirs >= epOurs)) || (sTheirs > sOurs)) {
// qDebug() << "Matched episode:" << ep; if (episode.endsWith('-')) { // Infinite range
// qDebug() << "Matched article:" << articleTitle; const int episodeOurs {episode.leftRef(episode.size() - 1).toInt()};
if (((seasonTheirs == seasonOurs) && (episodeTheirs >= episodeOurs)) || (seasonTheirs > seasonOurs))
return true; return true;
} }
}
}
else { // Normal range else { // Normal range
QStringList range = ep.split('-'); const QStringList range {episode.split('-')};
Q_ASSERT(range.size() == 2); Q_ASSERT(range.size() == 2);
if (range.first().toInt() > range.last().toInt()) if (range.first().toInt() > range.last().toInt())
continue; // Ignore this subrule completely continue; // Ignore this subrule completely
int epOursFirst = range.first().toInt(); const int episodeOursFirst {range.first().toInt()};
int epOursLast = range.last().toInt(); const int episodeOursLast {range.last().toInt()};
if ((seasonTheirs == seasonOurs) && ((episodeOursFirst <= episodeTheirs) && (episodeOursLast >= episodeTheirs)))
// Extract partial match from article and compare as digits
matcher = reg.match(articleTitle);
matched = matcher.hasMatch();
if (!matched) {
reg = QRegularExpression(cachedRegex(partialPattern2));
matcher = reg.match(articleTitle);
matched = matcher.hasMatch();
}
if (matched) {
int sTheirs = matcher.captured(1).toInt();
int epTheirs = matcher.captured(2).toInt();
if ((sTheirs == sOurs) && ((epOursFirst <= epTheirs) && (epOursLast >= epTheirs))) {
// qDebug() << "Matched episode:" << ep;
// qDebug() << "Matched article:" << articleTitle;
return true; return true;
} }
} }
} }
}
else { // Single number else { // Single number
QString expStr("\\b(?:s0?" + s + "[ -_\\.]?" + "e0?" + ep + "|" + s + "x" + "0?" + ep + ")(?:\\D|\\b)"); const QString expStr {QString("\\b(?:s0?%1[ -_\\.]?e0?%2|%1x0?%2)(?:\\D|\\b)").arg(season, episode)};
QRegularExpression reg(cachedRegex(expStr)); if (cachedRegex(expStr).match(articleTitle).hasMatch())
if (reg.match(articleTitle).hasMatch()) {
// qDebug() << "Matched episode:" << ep;
// qDebug() << "Matched article:" << articleTitle;
return true; return true;
} }
} }
}
return false; return false;
} }
if (useSmartFilter()) { bool AutoDownloadRule::matchesSmartEpisodeFilter(const QString& articleTitle) const
// now see if this episode has been downloaded before {
const QString episodeStr = computeEpisodeName(articleTitle); if (!useSmartFilter())
return true;
if (!episodeStr.isEmpty()) { const QString episodeStr = computeEpisodeName(articleTitle);
bool previouslyMatched = m_dataPtr->previouslyMatchedEpisodes.contains(episodeStr); if (episodeStr.isEmpty())
bool isRepack = articleTitle.contains("REPACK", Qt::CaseInsensitive) || articleTitle.contains("PROPER", Qt::CaseInsensitive); return true;
// See if this episode has been downloaded before
const bool previouslyMatched = m_dataPtr->previouslyMatchedEpisodes.contains(episodeStr);
const bool isRepack = articleTitle.contains("REPACK", Qt::CaseInsensitive) || articleTitle.contains("PROPER", Qt::CaseInsensitive);
if (previouslyMatched && !isRepack) if (previouslyMatched && !isRepack)
return false; return false;
m_dataPtr->lastComputedEpisode = episodeStr; m_dataPtr->lastComputedEpisode = episodeStr;
} return true;
}
bool AutoDownloadRule::matches(const QVariantHash &articleData) const
{
const QDateTime articleDate {articleData[Article::KeyDate].toDateTime()};
if (ignoreDays() > 0) {
if (lastMatch().isValid() && (articleDate < lastMatch().addDays(ignoreDays())))
return false;
}
const QString articleTitle {articleData[Article::KeyTitle].toString()};
if (!matchesMustContainExpression(articleTitle))
return false;
if (!matchesMustNotContainExpression(articleTitle))
return false;
if (!matchesEpisodeFilterExpression(articleTitle))
return false;
if (!matchesSmartEpisodeFilter(articleTitle))
return false;
return true;
}
bool AutoDownloadRule::accepts(const QVariantHash &articleData)
{
if (!matches(articleData))
return false;
setLastMatch(articleData[Article::KeyDate].toDateTime());
if (!m_dataPtr->lastComputedEpisode.isEmpty()) {
// TODO: probably need to add a marker for PROPER/REPACK to avoid duplicate downloads
m_dataPtr->previouslyMatchedEpisodes.append(m_dataPtr->lastComputedEpisode);
m_dataPtr->lastComputedEpisode.clear();
} }
// qDebug() << "Matched article:" << articleTitle;
return true; return true;
} }
@@ -642,15 +644,6 @@ void AutoDownloadRule::setPreviouslyMatchedEpisodes(const QStringList &previousl
m_dataPtr->previouslyMatchedEpisodes = previouslyMatchedEpisodes; m_dataPtr->previouslyMatchedEpisodes = previouslyMatchedEpisodes;
} }
void AutoDownloadRule::appendLastComputedEpisode()
{
if (!m_dataPtr->lastComputedEpisode.isEmpty()) {
// TODO: probably need to add a marker for PROPER/REPACK to avoid duplicate downloads
m_dataPtr->previouslyMatchedEpisodes.append(m_dataPtr->lastComputedEpisode);
m_dataPtr->lastComputedEpisode.clear();
}
}
QString AutoDownloadRule::episodeFilter() const QString AutoDownloadRule::episodeFilter() const
{ {
return m_dataPtr->episodeFilter; return m_dataPtr->episodeFilter;

View File

@@ -71,7 +71,6 @@ namespace RSS
QString episodeFilter() const; QString episodeFilter() const;
void setEpisodeFilter(const QString &e); void setEpisodeFilter(const QString &e);
void appendLastComputedEpisode();
QStringList previouslyMatchedEpisodes() const; QStringList previouslyMatchedEpisodes() const;
void setPreviouslyMatchedEpisodes(const QStringList &previouslyMatchedEpisodes); void setPreviouslyMatchedEpisodes(const QStringList &previouslyMatchedEpisodes);
@@ -82,7 +81,8 @@ namespace RSS
QString assignedCategory() const; QString assignedCategory() const;
void setCategory(const QString &category); void setCategory(const QString &category);
bool matches(const QString &articleTitle) const; bool matches(const QVariantHash &articleData) const;
bool accepts(const QVariantHash &articleData);
AutoDownloadRule &operator=(const AutoDownloadRule &other); AutoDownloadRule &operator=(const AutoDownloadRule &other);
bool operator==(const AutoDownloadRule &other) const; bool operator==(const AutoDownloadRule &other) const;
@@ -95,7 +95,11 @@ namespace RSS
static AutoDownloadRule fromLegacyDict(const QVariantHash &dict); static AutoDownloadRule fromLegacyDict(const QVariantHash &dict);
private: private:
bool matches(const QString &articleTitle, const QString &expression) const; bool matchesMustContainExpression(const QString &articleTitle) const;
bool matchesMustNotContainExpression(const QString &articleTitle) const;
bool matchesEpisodeFilterExpression(const QString &articleTitle) const;
bool matchesSmartEpisodeFilter(const QString &articleTitle) const;
bool matchesExpression(const QString &articleTitle, const QString &expression) const;
QRegularExpression cachedRegex(const QString &expression, bool isRegex = true) const; QRegularExpression cachedRegex(const QString &expression, bool isRegex = true) const;
QSharedDataPointer<AutoDownloadRuleData> m_dataPtr; QSharedDataPointer<AutoDownloadRuleData> m_dataPtr;

View File

@@ -212,7 +212,13 @@ void Feed::handleParsingFinished(const RSS::Private::ParsingResult &result)
m_lastBuildDate = result.lastBuildDate; m_lastBuildDate = result.lastBuildDate;
int newArticlesCount = 0; int newArticlesCount = 0;
for (const QVariantHash &varHash : result.articles) { const QDateTime now {QDateTime::currentDateTime()};
for (QVariantHash varHash : result.articles) {
// if article has no publication date we use feed update time as a fallback
QVariant &articleDate = varHash[Article::KeyDate];
if (!articleDate.toDateTime().isValid())
articleDate = now;
try { try {
auto article = new Article(this, varHash); auto article = new Article(this, varHash);
if (addArticle(article)) if (addArticle(article))

View File

@@ -36,7 +36,7 @@
using namespace RSS; using namespace RSS;
const QString Item::PathSeparator("\\"); const QChar Item::PathSeparator('\\');
Item::Item(const QString &path) Item::Item(const QString &path)
: m_path(path) : m_path(path)

View File

@@ -58,7 +58,7 @@ namespace RSS
virtual QJsonValue toJsonValue(bool withData = false) const = 0; virtual QJsonValue toJsonValue(bool withData = false) const = 0;
static const QString PathSeparator; static const QChar PathSeparator;
static bool isValidPath(const QString &path); static bool isValidPath(const QString &path);
static QString joinPath(const QString &path1, const QString &path2); static QString joinPath(const QString &path1, const QString &path2);

View File

@@ -47,8 +47,8 @@
#include "../utils/fs.h" #include "../utils/fs.h"
#include "rss_article.h" #include "rss_article.h"
#include "rss_feed.h" #include "rss_feed.h"
#include "rss_item.h"
#include "rss_folder.h" #include "rss_folder.h"
#include "rss_item.h"
const int MsecsPerMin = 60000; const int MsecsPerMin = 60000;
const QString ConfFolderName(QStringLiteral("rss")); const QString ConfFolderName(QStringLiteral("rss"));

View File

@@ -69,9 +69,9 @@ class AsyncFileStorage;
namespace RSS namespace RSS
{ {
class Item;
class Feed; class Feed;
class Folder; class Folder;
class Item;
class Session : public QObject class Session : public QObject
{ {

View File

@@ -1,6 +1,6 @@
/* /*
* Bittorrent Client using Qt and libtorrent. * Bittorrent Client using Qt and libtorrent.
* Copyright (C) 2010 Christian Kandeler, Christophe Dumez * Copyright (C) 2010 Christian Kandeler, Christophe Dumez <chris@qbittorrent.org>
* *
* This program is free software; you can redistribute it and/or * This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License * modify it under the terms of the GNU General Public License
@@ -24,8 +24,6 @@
* modify file(s), you may extend this exception to your version of the file(s), * modify file(s), you may extend this exception to your version of the file(s),
* but you are not obligated to do so. If you do not wish to do so, delete this * but you are not obligated to do so. If you do not wish to do so, delete this
* exception statement from your version. * exception statement from your version.
*
* Contact : chris@qbittorrent.org
*/ */
#include "scanfoldersmodel.h" #include "scanfoldersmodel.h"
@@ -56,7 +54,7 @@ struct ScanFoldersModel::PathData
QString downloadPath; // valid for CUSTOM_LOCATION QString downloadPath; // valid for CUSTOM_LOCATION
}; };
ScanFoldersModel *ScanFoldersModel::m_instance = 0; ScanFoldersModel *ScanFoldersModel::m_instance = nullptr;
bool ScanFoldersModel::initInstance(QObject *parent) bool ScanFoldersModel::initInstance(QObject *parent)
{ {
@@ -72,7 +70,7 @@ void ScanFoldersModel::freeInstance()
{ {
if (m_instance) { if (m_instance) {
delete m_instance; delete m_instance;
m_instance = 0; m_instance = nullptr;
} }
} }
@@ -83,10 +81,10 @@ ScanFoldersModel *ScanFoldersModel::instance()
ScanFoldersModel::ScanFoldersModel(QObject *parent) ScanFoldersModel::ScanFoldersModel(QObject *parent)
: QAbstractListModel(parent) : QAbstractListModel(parent)
, m_fsWatcher(0) , m_fsWatcher(nullptr)
{ {
configure(); configure();
connect(Preferences::instance(), SIGNAL(changed()), SLOT(configure())); connect(Preferences::instance(), &Preferences::changed, this, &ScanFoldersModel::configure);
} }
ScanFoldersModel::~ScanFoldersModel() ScanFoldersModel::~ScanFoldersModel()
@@ -222,7 +220,7 @@ ScanFoldersModel::PathStatus ScanFoldersModel::addPath(const QString &watchPath,
if (!m_fsWatcher) { if (!m_fsWatcher) {
m_fsWatcher = new FileSystemWatcher(this); m_fsWatcher = new FileSystemWatcher(this);
connect(m_fsWatcher, SIGNAL(torrentsAdded(const QStringList &)), this, SLOT(addTorrentsToSession(const QStringList &))); connect(m_fsWatcher, &FileSystemWatcher::torrentsAdded, this, &ScanFoldersModel::addTorrentsToSession);
} }
beginInsertRows(QModelIndex(), rowCount(), rowCount()); beginInsertRows(QModelIndex(), rowCount(), rowCount());

View File

@@ -1,6 +1,6 @@
/* /*
* Bittorrent Client using Qt and libtorrent. * Bittorrent Client using Qt and libtorrent.
* Copyright (C) 2010 Christian Kandeler, Christophe Dumez * Copyright (C) 2010 Christian Kandeler, Christophe Dumez <chris@qbittorrent.org>
* *
* This program is free software; you can redistribute it and/or * This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License * modify it under the terms of the GNU General Public License
@@ -24,8 +24,6 @@
* modify file(s), you may extend this exception to your version of the file(s), * modify file(s), you may extend this exception to your version of the file(s),
* but you are not obligated to do so. If you do not wish to do so, delete this * but you are not obligated to do so. If you do not wish to do so, delete this
* exception statement from your version. * exception statement from your version.
*
* Contact : chris@qbittorrent.org
*/ */
#ifndef SCANFOLDERSMODEL_H #ifndef SCANFOLDERSMODEL_H
@@ -66,7 +64,7 @@ public:
CUSTOM_LOCATION CUSTOM_LOCATION
}; };
static bool initInstance(QObject *parent = 0); static bool initInstance(QObject *parent = nullptr);
static void freeInstance(); static void freeInstance();
static ScanFoldersModel *instance(); static ScanFoldersModel *instance();
@@ -97,7 +95,7 @@ private slots:
void addTorrentsToSession(const QStringList &pathList); void addTorrentsToSession(const QStringList &pathList);
private: private:
explicit ScanFoldersModel(QObject *parent = 0); explicit ScanFoldersModel(QObject *parent = nullptr);
~ScanFoldersModel(); ~ScanFoldersModel();
virtual bool setData(const QModelIndex &index, const QVariant &value, int role = Qt::EditRole); virtual bool setData(const QModelIndex &index, const QVariant &value, int role = Qt::EditRole);

View File

@@ -42,8 +42,8 @@
#include "base/global.h" #include "base/global.h"
#include "base/logger.h" #include "base/logger.h"
#include "base/net/downloadmanager.h"
#include "base/net/downloadhandler.h" #include "base/net/downloadhandler.h"
#include "base/net/downloadmanager.h"
#include "base/preferences.h" #include "base/preferences.h"
#include "base/profile.h" #include "base/profile.h"
#include "base/utils/fs.h" #include "base/utils/fs.h"
@@ -62,18 +62,6 @@ namespace
QPointer<SearchPluginManager> SearchPluginManager::m_instance = nullptr; QPointer<SearchPluginManager> SearchPluginManager::m_instance = nullptr;
const QHash<QString, QString> SearchPluginManager::m_categoryNames {
{"all", QT_TRANSLATE_NOOP("SearchEngine", "All categories")},
{"movies", QT_TRANSLATE_NOOP("SearchEngine", "Movies")},
{"tv", QT_TRANSLATE_NOOP("SearchEngine", "TV shows")},
{"music", QT_TRANSLATE_NOOP("SearchEngine", "Music")},
{"games", QT_TRANSLATE_NOOP("SearchEngine", "Games")},
{"anime", QT_TRANSLATE_NOOP("SearchEngine", "Anime")},
{"software", QT_TRANSLATE_NOOP("SearchEngine", "Software")},
{"pictures", QT_TRANSLATE_NOOP("SearchEngine", "Pictures")},
{"books", QT_TRANSLATE_NOOP("SearchEngine", "Books")}
};
SearchPluginManager::SearchPluginManager() SearchPluginManager::SearchPluginManager()
: m_updateUrl(QString("http://searchplugins.qbittorrent.org/%1/engines/").arg(Utils::Misc::pythonVersion() >= 3 ? "nova3" : "nova")) : m_updateUrl(QString("http://searchplugins.qbittorrent.org/%1/engines/").arg(Utils::Misc::pythonVersion() >= 3 ? "nova3" : "nova"))
{ {
@@ -307,7 +295,18 @@ SearchHandler *SearchPluginManager::startSearch(const QString &pattern, const QS
QString SearchPluginManager::categoryFullName(const QString &categoryName) QString SearchPluginManager::categoryFullName(const QString &categoryName)
{ {
return tr(m_categoryNames.value(categoryName).toUtf8().constData()); static const QHash<QString, QString> categoryTable {
{"all", tr("All categories")},
{"movies", tr("Movies")},
{"tv", tr("TV shows")},
{"music", tr("Music")},
{"games", tr("Games")},
{"anime", tr("Anime")},
{"software", tr("Software")},
{"pictures", tr("Pictures")},
{"books", tr("Books")}
};
return categoryTable.value(categoryName);
} }
QString SearchPluginManager::pluginFullName(const QString &pluginName) QString SearchPluginManager::pluginFullName(const QString &pluginName)

View File

@@ -111,7 +111,6 @@ private:
static QString pluginPath(const QString &name); static QString pluginPath(const QString &name);
static QPointer<SearchPluginManager> m_instance; static QPointer<SearchPluginManager> m_instance;
static const QHash<QString, QString> m_categoryNames;
const QString m_updateUrl; const QString m_updateUrl;

View File

@@ -1,7 +1,7 @@
/* /*
* Bittorrent Client using Qt and libtorrent. * Bittorrent Client using Qt and libtorrent.
* Copyright (C) 2016 Vladimir Golovnev <glassez@yandex.ru> * Copyright (C) 2016 Vladimir Golovnev <glassez@yandex.ru>
* Copyright (C) 2014 sledgehammer999 <hammered999@gmail.com> * Copyright (C) 2014 sledgehammer999 <sledgehammer999@qbittorrent.org>
* *
* This program is free software; you can redistribute it and/or * This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License * modify it under the terms of the GNU General Public License
@@ -62,15 +62,12 @@ namespace
QString deserialize(const QString &name, QVariantHash &data); QString deserialize(const QString &name, QVariantHash &data);
QString serialize(const QString &name, const QVariantHash &data); QString serialize(const QString &name, const QVariantHash &data);
QString m_name; const QString m_name;
}; };
typedef QHash<QString, QString> MappingTable;
QString mapKey(const QString &key) QString mapKey(const QString &key)
{ {
static const MappingTable keyMapping = { static const QHash<QString, QString> keyMapping = {
{"BitTorrent/Session/MaxRatioAction", "Preferences/Bittorrent/MaxRatioAction"}, {"BitTorrent/Session/MaxRatioAction", "Preferences/Bittorrent/MaxRatioAction"},
{"BitTorrent/Session/DefaultSavePath", "Preferences/Downloads/SavePath"}, {"BitTorrent/Session/DefaultSavePath", "Preferences/Downloads/SavePath"},
{"BitTorrent/Session/TempPath", "Preferences/Downloads/TempPath"}, {"BitTorrent/Session/TempPath", "Preferences/Downloads/TempPath"},
@@ -147,7 +144,6 @@ namespace
{"AddNewTorrentDialog/TopLevel", "Preferences/Downloads/NewAdditionDialogFront"}, {"AddNewTorrentDialog/TopLevel", "Preferences/Downloads/NewAdditionDialogFront"},
{"State/BannedIPs", "Preferences/IPFilter/BannedIPs"} {"State/BannedIPs", "Preferences/IPFilter/BannedIPs"}
}; };
return keyMapping.value(key, key); return keyMapping.value(key, key);
@@ -163,7 +159,7 @@ SettingsStorage::SettingsStorage()
{ {
m_timer.setSingleShot(true); m_timer.setSingleShot(true);
m_timer.setInterval(5 * 1000); m_timer.setInterval(5 * 1000);
connect(&m_timer, SIGNAL(timeout()), SLOT(save())); connect(&m_timer, &QTimer::timeout, this, &SettingsStorage::save);
} }
SettingsStorage::~SettingsStorage() SettingsStorage::~SettingsStorage()
@@ -200,6 +196,7 @@ bool SettingsStorage::save()
return true; return true;
} }
m_timer.start();
return false; return false;
} }
@@ -211,7 +208,7 @@ QVariant SettingsStorage::loadValue(const QString &key, const QVariant &defaultV
void SettingsStorage::storeValue(const QString &key, const QVariant &value) void SettingsStorage::storeValue(const QString &key, const QVariant &value)
{ {
QString realKey = mapKey(key); const QString realKey = mapKey(key);
QWriteLocker locker(&m_lock); QWriteLocker locker(&m_lock);
if (m_data.value(realKey) != value) { if (m_data.value(realKey) != value) {
m_dirty = true; m_dirty = true;
@@ -222,7 +219,7 @@ void SettingsStorage::storeValue(const QString &key, const QVariant &value)
void SettingsStorage::removeValue(const QString &key) void SettingsStorage::removeValue(const QString &key)
{ {
QString realKey = mapKey(key); const QString realKey = mapKey(key);
QWriteLocker locker(&m_lock); QWriteLocker locker(&m_lock);
if (m_data.contains(realKey)) { if (m_data.contains(realKey)) {
m_dirty = true; m_dirty = true;
@@ -234,36 +231,39 @@ void SettingsStorage::removeValue(const QString &key)
QVariantHash TransactionalSettings::read() QVariantHash TransactionalSettings::read()
{ {
QVariantHash res; QVariantHash res;
bool writeBackNeeded = false;
QString newPath = deserialize(m_name + QLatin1String("_new"), res); const QString newPath = deserialize(m_name + QLatin1String("_new"), res);
if (!newPath.isEmpty()) { // "_new" file is NOT empty if (!newPath.isEmpty()) { // "_new" file is NOT empty
// This means that the PC closed either due to power outage // This means that the PC closed either due to power outage
// or because the disk was full. In any case the settings weren't transferred // or because the disk was full. In any case the settings weren't transferred
// in their final position. So assume that qbittorrent_new.ini/qbittorrent_new.conf // in their final position. So assume that qbittorrent_new.ini/qbittorrent_new.conf
// contains the most recent settings. // contains the most recent settings.
Logger::instance()->addMessage(QObject::tr("Detected unclean program exit. Using fallback file to restore settings."), Log::WARNING); Logger::instance()->addMessage(QObject::tr("Detected unclean program exit. Using fallback file to restore settings: %1")
writeBackNeeded = true; .arg(Utils::Fs::toNativePath(newPath))
, Log::WARNING);
QString finalPath = newPath;
int index = finalPath.lastIndexOf("_new", -1, Qt::CaseInsensitive);
finalPath.remove(index, 4);
Utils::Fs::forceRemove(finalPath);
QFile::rename(newPath, finalPath);
} }
else { else {
deserialize(m_name, res); deserialize(m_name, res);
} }
Utils::Fs::forceRemove(newPath);
if (writeBackNeeded)
write(res);
return res; return res;
} }
bool TransactionalSettings::write(const QVariantHash &data) bool TransactionalSettings::write(const QVariantHash &data)
{ {
// QSettings delete the file before writing it out. This can result in problems // QSettings deletes the file before writing it out. This can result in problems
// if the disk is full or a power outage occurs. Those events might occur // if the disk is full or a power outage occurs. Those events might occur
// between deleting the file and recreating it. This is a safety measure. // between deleting the file and recreating it. This is a safety measure.
// Write everything to qBittorrent_new.ini/qBittorrent_new.conf and if it succeeds // Write everything to qBittorrent_new.ini/qBittorrent_new.conf and if it succeeds
// replace qBittorrent.ini/qBittorrent.conf with it. // replace qBittorrent.ini/qBittorrent.conf with it.
QString newPath = serialize(m_name + QLatin1String("_new"), data); const QString newPath = serialize(m_name + QLatin1String("_new"), data);
if (newPath.isEmpty()) { if (newPath.isEmpty()) {
Utils::Fs::forceRemove(newPath); Utils::Fs::forceRemove(newPath);
return false; return false;
@@ -272,10 +272,9 @@ bool TransactionalSettings::write(const QVariantHash &data)
QString finalPath = newPath; QString finalPath = newPath;
int index = finalPath.lastIndexOf("_new", -1, Qt::CaseInsensitive); int index = finalPath.lastIndexOf("_new", -1, Qt::CaseInsensitive);
finalPath.remove(index, 4); finalPath.remove(index, 4);
Utils::Fs::forceRemove(finalPath);
QFile::rename(newPath, finalPath);
return true; Utils::Fs::forceRemove(finalPath);
return QFile::rename(newPath, finalPath);
} }
QString TransactionalSettings::deserialize(const QString &name, QVariantHash &data) QString TransactionalSettings::deserialize(const QString &name, QVariantHash &data)
@@ -301,13 +300,19 @@ QString TransactionalSettings::serialize(const QString &name, const QVariantHash
settings->setValue(i.key(), i.value()); settings->setValue(i.key(), i.value());
settings->sync(); // Important to get error status settings->sync(); // Important to get error status
QSettings::Status status = settings->status();
if (status != QSettings::NoError) { switch (settings->status()) {
if (status == QSettings::AccessError) case QSettings::NoError:
return settings->fileName();
case QSettings::AccessError:
Logger::instance()->addMessage(QObject::tr("An access error occurred while trying to write the configuration file."), Log::CRITICAL); Logger::instance()->addMessage(QObject::tr("An access error occurred while trying to write the configuration file."), Log::CRITICAL);
else break;
case QSettings::FormatError:
Logger::instance()->addMessage(QObject::tr("A format error occurred while trying to write the configuration file."), Log::CRITICAL); Logger::instance()->addMessage(QObject::tr("A format error occurred while trying to write the configuration file."), Log::CRITICAL);
break;
default:
Logger::instance()->addMessage(QObject::tr("An unknown error occurred while trying to write the configuration file."), Log::CRITICAL);
break;
}
return QString(); return QString();
} }
return settings->fileName();
}

View File

@@ -1,7 +1,7 @@
/* /*
* Bittorrent Client using Qt and libtorrent. * Bittorrent Client using Qt and libtorrent.
* Copyright (C) 2016 Vladimir Golovnev <glassez@yandex.ru> * Copyright (C) 2016 Vladimir Golovnev <glassez@yandex.ru>
* Copyright (C) 2014 sledgehammer999 <hammered999@gmail.com> * Copyright (C) 2014 sledgehammer999 <sledgehammer999@qbittorrent.org>
* *
* This program is free software; you can redistribute it and/or * This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License * modify it under the terms of the GNU General Public License
@@ -31,9 +31,9 @@
#define SETTINGSSTORAGE_H #define SETTINGSSTORAGE_H
#include <QObject> #include <QObject>
#include <QVariantHash>
#include <QTimer>
#include <QReadWriteLock> #include <QReadWriteLock>
#include <QTimer>
#include <QVariantHash>
class SettingsStorage : public QObject class SettingsStorage : public QObject
{ {

View File

@@ -31,6 +31,7 @@
#include <functional> #include <functional>
#include <type_traits> #include <type_traits>
#include <QMetaEnum> #include <QMetaEnum>
#include <QString> #include <QString>
#include <QVariant> #include <QVariant>

View File

@@ -29,8 +29,8 @@
#ifndef TORRENTFILTER_H #ifndef TORRENTFILTER_H
#define TORRENTFILTER_H #define TORRENTFILTER_H
#include <QString>
#include <QSet> #include <QSet>
#include <QString>
typedef QSet<QString> QStringSet; typedef QSet<QString> QStringSet;

View File

@@ -1,6 +1,6 @@
/* /*
* Bittorrent Client using Qt and libtorrent. * Bittorrent Client using Qt and libtorrent.
* Copyright (C) 2012 Christophe Dumez * Copyright (C) 2012 Christophe Dumez <chris@qbittorrent.org>
* *
* This program is free software; you can redistribute it and/or * This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License * modify it under the terms of the GNU General Public License
@@ -24,20 +24,18 @@
* modify file(s), you may extend this exception to your version of the file(s), * modify file(s), you may extend this exception to your version of the file(s),
* but you are not obligated to do so. If you do not wish to do so, delete this * but you are not obligated to do so. If you do not wish to do so, delete this
* exception statement from your version. * exception statement from your version.
*
* Contact : chris@qbittorrent.org
*/ */
#include "fs.h" #include "fs.h"
#include <cstring> #include <cstring>
#include <QCoreApplication>
#include <QDebug> #include <QDebug>
#include <QDir> #include <QDir>
#include <QDirIterator>
#include <QFile> #include <QFile>
#include <QFileInfo> #include <QFileInfo>
#include <QDirIterator>
#include <QCoreApplication>
#include <QStorageInfo> #include <QStorageInfo>
#include <sys/stat.h> #include <sys/stat.h>
@@ -152,7 +150,7 @@ bool Utils::Fs::smartRemoveEmptyFolderTree(const QString &path)
} }
/** /**
* Removes the file with the given file_path. * Removes the file with the given filePath.
* *
* This function will try to fix the file permissions before removing it. * This function will try to fix the file permissions before removing it.
*/ */
@@ -169,7 +167,6 @@ bool Utils::Fs::forceRemove(const QString &filePath)
/** /**
* Removes directory and its content recursively. * Removes directory and its content recursively.
*
*/ */
void Utils::Fs::removeDirRecursive(const QString &path) void Utils::Fs::removeDirRecursive(const QString &path)
{ {

View File

@@ -1,6 +1,6 @@
/* /*
* Bittorrent Client using Qt and libtorrent. * Bittorrent Client using Qt and libtorrent.
* Copyright (C) 2012 Christophe Dumez * Copyright (C) 2012 Christophe Dumez <chris@qbittorrent.org>
* *
* This program is free software; you can redistribute it and/or * This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License * modify it under the terms of the GNU General Public License
@@ -24,8 +24,6 @@
* modify file(s), you may extend this exception to your version of the file(s), * modify file(s), you may extend this exception to your version of the file(s),
* but you are not obligated to do so. If you do not wish to do so, delete this * but you are not obligated to do so. If you do not wish to do so, delete this
* exception statement from your version. * exception statement from your version.
*
* Contact : chris@qbittorrent.org
*/ */
#ifndef UTILS_FS_H #ifndef UTILS_FS_H
@@ -52,7 +50,7 @@ namespace Utils
, const QString &pad = QLatin1String(" ")); , const QString &pad = QLatin1String(" "));
bool isValidFileSystemName(const QString &name, bool allowSeparators = false); bool isValidFileSystemName(const QString &name, bool allowSeparators = false);
qint64 freeDiskSpaceOnPath(const QString &path); qint64 freeDiskSpaceOnPath(const QString &path);
QString branchPath(const QString &filePath, QString *removed = 0); QString branchPath(const QString &filePath, QString *removed = nullptr);
bool sameFileNames(const QString &first, const QString &second); bool sameFileNames(const QString &first, const QString &second);
QString expandPath(const QString &path); QString expandPath(const QString &path);
QString expandPathAbs(const QString &path); QString expandPathAbs(const QString &path);

View File

@@ -1,6 +1,6 @@
/* /*
* Bittorrent Client using Qt and libtorrent. * Bittorrent Client using Qt and libtorrent.
* Copyright (C) 2006 Christophe Dumez * Copyright (C) 2006 Christophe Dumez <chris@qbittorrent.org>
* *
* This program is free software; you can redistribute it and/or * This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License * modify it under the terms of the GNU General Public License
@@ -24,8 +24,6 @@
* modify file(s), you may extend this exception to your version of the file(s), * modify file(s), you may extend this exception to your version of the file(s),
* but you are not obligated to do so. If you do not wish to do so, delete this * but you are not obligated to do so. If you do not wish to do so, delete this
* exception statement from your version. * exception statement from your version.
*
* Contact : chris@qbittorrent.org
*/ */
#include "misc.h" #include "misc.h"
@@ -52,6 +50,7 @@
#include <QDir> #include <QDir>
#include <QFileInfo> #include <QFileInfo>
#include <QProcess> #include <QProcess>
#include <QRegExp>
#include <QRegularExpression> #include <QRegularExpression>
#include <QSysInfo> #include <QSysInfo>
#include <QUrl> #include <QUrl>
@@ -62,17 +61,19 @@
#include <QApplication> #include <QApplication>
#include <QDesktopServices> #include <QDesktopServices>
#include <QDesktopWidget> #include <QDesktopWidget>
#include <QProcess>
#include <QStyle> #include <QStyle>
#if (defined(Q_OS_UNIX) && !defined(Q_OS_MAC)) && defined(QT_DBUS_LIB) #if (defined(Q_OS_UNIX) && !defined(Q_OS_MAC)) && defined(QT_DBUS_LIB)
#include <QDBusInterface> #include <QDBusInterface>
#include <QDBusMessage> #include <QDBusMessage>
#endif #endif
#if defined(Q_OS_UNIX) && !defined(Q_OS_MAC)
#include "base/utils/version.h"
#endif
#endif #endif
#include "base/utils/string.h"
#include "base/unicodestrings.h"
#include "base/logger.h" #include "base/logger.h"
#include "base/unicodestrings.h"
#include "base/utils/string.h"
#include "fs.h" #include "fs.h"
namespace namespace
@@ -271,12 +272,12 @@ QString Utils::Misc::pythonExecutable()
* On Unix-Like Systems python2 and python3 should always exist * On Unix-Like Systems python2 and python3 should always exist
* http://legacy.python.org/dev/peps/pep-0394/ * http://legacy.python.org/dev/peps/pep-0394/
*/ */
pythonProc.start("python3", QStringList() << "--version", QIODevice::ReadOnly); pythonProc.start("python3", {"--version"}, QIODevice::ReadOnly);
if (pythonProc.waitForFinished() && (pythonProc.exitCode() == 0)) { if (pythonProc.waitForFinished() && (pythonProc.exitCode() == 0)) {
executable = "python3"; executable = "python3";
return executable; return executable;
} }
pythonProc.start("python2", QStringList() << "--version", QIODevice::ReadOnly); pythonProc.start("python2", {"--version"}, QIODevice::ReadOnly);
if (pythonProc.waitForFinished() && (pythonProc.exitCode() == 0)) { if (pythonProc.waitForFinished() && (pythonProc.exitCode() == 0)) {
executable = "python2"; executable = "python2";
return executable; return executable;
@@ -284,7 +285,7 @@ QString Utils::Misc::pythonExecutable()
#endif #endif
// Look for "python" in Windows and in UNIX if "python2" and "python3" are // Look for "python" in Windows and in UNIX if "python2" and "python3" are
// not detected. // not detected.
pythonProc.start("python", QStringList() << "--version", QIODevice::ReadOnly); pythonProc.start("python", {"--version"}, QIODevice::ReadOnly);
if (pythonProc.waitForFinished() && (pythonProc.exitCode() == 0)) if (pythonProc.waitForFinished() && (pythonProc.exitCode() == 0))
executable = "python"; executable = "python";
else else
@@ -305,7 +306,7 @@ QString Utils::Misc::pythonVersionComplete()
if (pythonExecutable().isEmpty()) if (pythonExecutable().isEmpty())
return version; return version;
QProcess pythonProc; QProcess pythonProc;
pythonProc.start(pythonExecutable(), QStringList() << "--version", QIODevice::ReadOnly); pythonProc.start(pythonExecutable(), {"--version"}, QIODevice::ReadOnly);
if (pythonProc.waitForFinished() && (pythonProc.exitCode() == 0)) { if (pythonProc.waitForFinished() && (pythonProc.exitCode() == 0)) {
QByteArray output = pythonProc.readAllStandardOutput(); QByteArray output = pythonProc.readAllStandardOutput();
if (output.isEmpty()) if (output.isEmpty())
@@ -525,9 +526,9 @@ bool Utils::Misc::isUrl(const QString &s)
return reURLScheme.match(QUrl(s).scheme()).hasMatch(); return reURLScheme.match(QUrl(s).scheme()).hasMatch();
} }
QString Utils::Misc::parseHtmlLinks(const QString &raw_text) QString Utils::Misc::parseHtmlLinks(const QString &rawText)
{ {
QString result = raw_text; QString result = rawText;
static QRegExp reURL( static QRegExp reURL(
"(\\s|^)" // start with whitespace or beginning of line "(\\s|^)" // start with whitespace or beginning of line
"(" "("
@@ -621,21 +622,33 @@ void Utils::Misc::openFolderSelect(const QString &absolutePath)
::CoUninitialize(); ::CoUninitialize();
#elif defined(Q_OS_UNIX) && !defined(Q_OS_MAC) #elif defined(Q_OS_UNIX) && !defined(Q_OS_MAC)
QProcess proc; QProcess proc;
proc.start("xdg-mime", QStringList() << "query" << "default" << "inode/directory"); proc.start("xdg-mime", {"query", "default", "inode/directory"});
proc.waitForFinished(); proc.waitForFinished();
QString output = proc.readLine().simplified(); QString output = proc.readLine().simplified();
if ((output == "dolphin.desktop") || (output == "org.kde.dolphin.desktop")) if ((output == "dolphin.desktop") || (output == "org.kde.dolphin.desktop")) {
proc.startDetached("dolphin", QStringList() << "--select" << Utils::Fs::toNativePath(path)); proc.startDetached("dolphin", {"--select", Utils::Fs::toNativePath(path)});
}
else if ((output == "nautilus.desktop") || (output == "org.gnome.Nautilus.desktop") else if ((output == "nautilus.desktop") || (output == "org.gnome.Nautilus.desktop")
|| (output == "nautilus-folder-handler.desktop")) || (output == "nautilus-folder-handler.desktop")) {
proc.startDetached("nautilus", QStringList() << "--no-desktop" << Utils::Fs::toNativePath(path)); proc.start("nautilus", {"--version"});
else if (output == "nemo.desktop") proc.waitForFinished();
proc.startDetached("nemo", QStringList() << "--no-desktop" << Utils::Fs::toNativePath(path)); const QString nautilusVerStr = QString(proc.readLine()).remove(QRegExp("[^0-9.]"));
else if ((output == "konqueror.desktop") || (output == "kfmclient_dir.desktop")) using NautilusVersion = Utils::Version<int, 3>;
proc.startDetached("konqueror", QStringList() << "--select" << Utils::Fs::toNativePath(path)); if (NautilusVersion::tryParse(nautilusVerStr, {1, 0, 0}) > NautilusVersion {3, 28})
proc.startDetached("nautilus", {Utils::Fs::toNativePath(path)});
else else
proc.startDetached("nautilus", {"--no-desktop", Utils::Fs::toNativePath(path)});
}
else if (output == "nemo.desktop") {
proc.startDetached("nemo", {"--no-desktop", Utils::Fs::toNativePath(path)});
}
else if ((output == "konqueror.desktop") || (output == "kfmclient_dir.desktop")) {
proc.startDetached("konqueror", {"--select", Utils::Fs::toNativePath(path)});
}
else {
// "caja" manager can't pinpoint the file, see: https://github.com/qbittorrent/qBittorrent/issues/5003 // "caja" manager can't pinpoint the file, see: https://github.com/qbittorrent/qBittorrent/issues/5003
openPath(path.left(path.lastIndexOf("/"))); openPath(path.left(path.lastIndexOf("/")));
}
#else #else
openPath(path.left(path.lastIndexOf("/"))); openPath(path.left(path.lastIndexOf("/")));
#endif #endif

View File

@@ -1,6 +1,6 @@
/* /*
* Bittorrent Client using Qt and libtorrent. * Bittorrent Client using Qt and libtorrent.
* Copyright (C) 2006 Christophe Dumez * Copyright (C) 2006 Christophe Dumez <chris@qbittorrent.org>
* *
* This program is free software; you can redistribute it and/or * This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License * modify it under the terms of the GNU General Public License
@@ -24,8 +24,6 @@
* modify file(s), you may extend this exception to your version of the file(s), * modify file(s), you may extend this exception to your version of the file(s),
* but you are not obligated to do so. If you do not wish to do so, delete this * but you are not obligated to do so. If you do not wish to do so, delete this
* exception statement from your version. * exception statement from your version.
*
* Contact : chris@qbittorrent.org
*/ */
#ifndef UTILS_MISC_H #ifndef UTILS_MISC_H
@@ -73,7 +71,7 @@ namespace Utils
// YobiByte, // 1024^8 // YobiByte, // 1024^8
}; };
QString parseHtmlLinks(const QString &raw_text); QString parseHtmlLinks(const QString &rawText);
bool isUrl(const QString &s); bool isUrl(const QString &s);
void shutdownComputer(const ShutdownDialogAction &action); void shutdownComputer(const ShutdownDialogAction &action);
@@ -88,7 +86,7 @@ namespace Utils
QString unitString(SizeUnit unit); QString unitString(SizeUnit unit);
// return best user friendly storage unit (B, KiB, MiB, GiB, TiB) // return the best user friendly storage unit (B, KiB, MiB, GiB, TiB)
// value must be given in bytes // value must be given in bytes
bool friendlyUnit(qint64 sizeInBytes, qreal &val, SizeUnit &unit); bool friendlyUnit(qint64 sizeInBytes, qreal &val, SizeUnit &unit);
QString friendlyUnit(qint64 bytesValue, bool isSpeed = false); QString friendlyUnit(qint64 bytesValue, bool isSpeed = false);
@@ -97,7 +95,7 @@ namespace Utils
bool isPreviewable(const QString &extension); bool isPreviewable(const QString &extension);
// Take a number of seconds and return an user-friendly // Take a number of seconds and return a user-friendly
// time duration like "1d 2h 10m". // time duration like "1d 2h 10m".
QString userFriendlyDuration(qlonglong seconds); QString userFriendlyDuration(qlonglong seconds);
QString getUserIDString(); QString getUserIDString();
@@ -136,4 +134,4 @@ namespace Utils
} }
} }
#endif #endif // UTILS_MISC_H

View File

@@ -27,6 +27,7 @@
*/ */
#include "net.h" #include "net.h"
#include <QHostAddress> #include <QHostAddress>
#include <QString> #include <QString>
#include <QStringList> #include <QStringList>

View File

@@ -24,7 +24,6 @@
* modify file(s), you may extend this exception to your version of the file(s), * modify file(s), you may extend this exception to your version of the file(s),
* but you are not obligated to do so. If you do not wish to do so, delete this * but you are not obligated to do so. If you do not wish to do so, delete this
* exception statement from your version. * exception statement from your version.
*
*/ */
#include "random.h" #include "random.h"

View File

@@ -24,7 +24,6 @@
* modify file(s), you may extend this exception to your version of the file(s), * modify file(s), you may extend this exception to your version of the file(s),
* but you are not obligated to do so. If you do not wish to do so, delete this * but you are not obligated to do so. If you do not wish to do so, delete this
* exception statement from your version. * exception statement from your version.
*
*/ */
#ifndef UTILS_RANDOM_H #ifndef UTILS_RANDOM_H

View File

@@ -117,7 +117,7 @@ namespace Utils
{ {
// find the last one non-zero component // find the last one non-zero component
std::size_t lastSignificantIndex = N - 1; std::size_t lastSignificantIndex = N - 1;
while (lastSignificantIndex > 0 && (*this)[lastSignificantIndex] == 0) while ((lastSignificantIndex > 0) && ((*this)[lastSignificantIndex] == 0))
--lastSignificantIndex; --lastSignificantIndex;
if (lastSignificantIndex + 1 < Mandatory) // lastSignificantIndex >= 0 if (lastSignificantIndex + 1 < Mandatory) // lastSignificantIndex >= 0

View File

@@ -55,7 +55,7 @@ public:
lb_name->setText("<b><h2>qBittorrent " QBT_VERSION " (32-bit)</h2></b>"); lb_name->setText("<b><h2>qBittorrent " QBT_VERSION " (32-bit)</h2></b>");
#endif #endif
logo->setPixmap(Utils::Gui::scaledPixmap(":/icons/skin/qbittorrent32.png", this)); logo->setPixmap(Utils::Gui::scaledPixmapSvg(":/icons/skin/qbittorrent-tray.svg", this, 32));
// About // About
QString aboutText = QString( QString aboutText = QString(

View File

@@ -1,6 +1,6 @@
/* /*
* Bittorrent Client using Qt and libtorrent. * Bittorrent Client using Qt and libtorrent.
* Copyright (C) 2012 Christophe Dumez * Copyright (C) 2012 Christophe Dumez <chris@qbittorrent.org>
* *
* This program is free software; you can redistribute it and/or * This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License * modify it under the terms of the GNU General Public License
@@ -24,8 +24,6 @@
* modify file(s), you may extend this exception to your version of the file(s), * modify file(s), you may extend this exception to your version of the file(s),
* but you are not obligated to do so. If you do not wish to do so, delete this * but you are not obligated to do so. If you do not wish to do so, delete this
* exception statement from your version. * exception statement from your version.
*
* Contact : chris@qbittorrent.org
*/ */
#include "addnewtorrentdialog.h" #include "addnewtorrentdialog.h"
@@ -37,22 +35,23 @@
#include <QPushButton> #include <QPushButton>
#include <QString> #include <QString>
#include <QUrl> #include <QUrl>
#include <QVector>
#include "autoexpandabledialog.h"
#include "base/bittorrent/magneturi.h" #include "base/bittorrent/magneturi.h"
#include "base/bittorrent/session.h" #include "base/bittorrent/session.h"
#include "base/bittorrent/torrenthandle.h" #include "base/bittorrent/torrenthandle.h"
#include "base/bittorrent/torrentinfo.h" #include "base/bittorrent/torrentinfo.h"
#include "base/global.h"
#include "base/net/downloadhandler.h" #include "base/net/downloadhandler.h"
#include "base/net/downloadmanager.h" #include "base/net/downloadmanager.h"
#include "base/preferences.h" #include "base/preferences.h"
#include "base/settingsstorage.h" #include "base/settingsstorage.h"
#include "base/settingvalue.h"
#include "base/torrentfileguard.h" #include "base/torrentfileguard.h"
#include "base/unicodestrings.h" #include "base/unicodestrings.h"
#include "base/utils/fs.h" #include "base/utils/fs.h"
#include "base/utils/misc.h" #include "base/utils/misc.h"
#include "base/utils/string.h" #include "base/utils/string.h"
#include "autoexpandabledialog.h"
#include "guiiconprovider.h" #include "guiiconprovider.h"
#include "messageboxraised.h" #include "messageboxraised.h"
#include "proplistdelegate.h" #include "proplistdelegate.h"
@@ -63,7 +62,7 @@
namespace namespace
{ {
#define SETTINGS_KEY(name) "AddNewTorrentDialog/" name #define SETTINGS_KEY(name) QStringLiteral("AddNewTorrentDialog/" name)
const QString KEY_ENABLED = SETTINGS_KEY("Enabled"); const QString KEY_ENABLED = SETTINGS_KEY("Enabled");
const QString KEY_DEFAULTCATEGORY = SETTINGS_KEY("DefaultCategory"); const QString KEY_DEFAULTCATEGORY = SETTINGS_KEY("DefaultCategory");
const QString KEY_TREEHEADERSTATE = SETTINGS_KEY("TreeHeaderState"); const QString KEY_TREEHEADERSTATE = SETTINGS_KEY("TreeHeaderState");
@@ -71,7 +70,8 @@ namespace
const QString KEY_EXPANDED = SETTINGS_KEY("Expanded"); const QString KEY_EXPANDED = SETTINGS_KEY("Expanded");
const QString KEY_TOPLEVEL = SETTINGS_KEY("TopLevel"); const QString KEY_TOPLEVEL = SETTINGS_KEY("TopLevel");
const QString KEY_SAVEPATHHISTORY = SETTINGS_KEY("SavePathHistory"); const QString KEY_SAVEPATHHISTORY = SETTINGS_KEY("SavePathHistory");
const char KEY_SAVEPATHHISTORYLENGTH[] = SETTINGS_KEY("SavePathHistoryLength"); const QString KEY_SAVEPATHHISTORYLENGTH = SETTINGS_KEY("SavePathHistoryLength");
const QString KEY_REMEMBERLASTSAVEPATH = SETTINGS_KEY("RememberLastSavePath");
// just a shortcut // just a shortcut
inline SettingsStorage *settings() inline SettingsStorage *settings()
@@ -80,12 +80,12 @@ namespace
} }
} }
constexpr int AddNewTorrentDialog::minPathHistoryLength; const int AddNewTorrentDialog::minPathHistoryLength;
constexpr int AddNewTorrentDialog::maxPathHistoryLength; const int AddNewTorrentDialog::maxPathHistoryLength;
AddNewTorrentDialog::AddNewTorrentDialog(const BitTorrent::AddTorrentParams &inParams, QWidget *parent) AddNewTorrentDialog::AddNewTorrentDialog(const BitTorrent::AddTorrentParams &inParams, QWidget *parent)
: QDialog(parent) : QDialog(parent)
, ui(new Ui::AddNewTorrentDialog) , m_ui(new Ui::AddNewTorrentDialog)
, m_contentModel(nullptr) , m_contentModel(nullptr)
, m_contentDelegate(nullptr) , m_contentDelegate(nullptr)
, m_hasMetadata(false) , m_hasMetadata(false)
@@ -93,40 +93,42 @@ AddNewTorrentDialog::AddNewTorrentDialog(const BitTorrent::AddTorrentParams &inP
, m_torrentParams(inParams) , m_torrentParams(inParams)
{ {
// TODO: set dialog file properties using m_torrentParams.filePriorities // TODO: set dialog file properties using m_torrentParams.filePriorities
ui->setupUi(this); m_ui->setupUi(this);
setAttribute(Qt::WA_DeleteOnClose); setAttribute(Qt::WA_DeleteOnClose);
ui->lblMetaLoading->setVisible(false); m_ui->lblMetaLoading->setVisible(false);
ui->progMetaLoading->setVisible(false); m_ui->progMetaLoading->setVisible(false);
ui->savePath->setMode(FileSystemPathEdit::Mode::DirectorySave); m_ui->savePath->setMode(FileSystemPathEdit::Mode::DirectorySave);
ui->savePath->setDialogCaption(tr("Choose save path")); m_ui->savePath->setDialogCaption(tr("Choose save path"));
ui->savePath->setMaxVisibleItems(20); m_ui->savePath->setMaxVisibleItems(20);
auto session = BitTorrent::Session::instance(); auto session = BitTorrent::Session::instance();
if (m_torrentParams.addPaused == TriStateBool::True) if (m_torrentParams.addPaused == TriStateBool::True)
ui->startTorrentCheckBox->setChecked(false); m_ui->startTorrentCheckBox->setChecked(false);
else if (m_torrentParams.addPaused == TriStateBool::False) else if (m_torrentParams.addPaused == TriStateBool::False)
ui->startTorrentCheckBox->setChecked(true); m_ui->startTorrentCheckBox->setChecked(true);
else else
ui->startTorrentCheckBox->setChecked(!session->isAddTorrentPaused()); m_ui->startTorrentCheckBox->setChecked(!session->isAddTorrentPaused());
ui->comboTTM->blockSignals(true); // the TreeView size isn't correct if the slot does it job at this point m_ui->comboTTM->blockSignals(true); // the TreeView size isn't correct if the slot does it job at this point
ui->comboTTM->setCurrentIndex(!session->isAutoTMMDisabledByDefault()); m_ui->comboTTM->setCurrentIndex(!session->isAutoTMMDisabledByDefault());
ui->comboTTM->blockSignals(false); m_ui->comboTTM->blockSignals(false);
populateSavePathComboBox(); populateSavePathComboBox();
connect(ui->savePath, &FileSystemPathEdit::selectedPathChanged, this, &AddNewTorrentDialog::onSavePathChanged); connect(m_ui->savePath, &FileSystemPathEdit::selectedPathChanged, this, &AddNewTorrentDialog::onSavePathChanged);
ui->defaultSavePathCheckBox->setVisible(false); // Default path is selected by default
const bool rememberLastSavePath = settings()->loadValue(KEY_REMEMBERLASTSAVEPATH, false).toBool();
m_ui->checkBoxRememberLastSavePath->setChecked(rememberLastSavePath);
if (m_torrentParams.createSubfolder == TriStateBool::True) if (m_torrentParams.createSubfolder == TriStateBool::True)
ui->createSubfolderCheckBox->setChecked(true); m_ui->createSubfolderCheckBox->setChecked(true);
else if (m_torrentParams.createSubfolder == TriStateBool::False) else if (m_torrentParams.createSubfolder == TriStateBool::False)
ui->createSubfolderCheckBox->setChecked(false); m_ui->createSubfolderCheckBox->setChecked(false);
else else
ui->createSubfolderCheckBox->setChecked(session->isCreateTorrentSubfolder()); m_ui->createSubfolderCheckBox->setChecked(session->isCreateTorrentSubfolder());
ui->skipCheckingCheckBox->setChecked(m_torrentParams.skipChecking); m_ui->skipCheckingCheckBox->setChecked(m_torrentParams.skipChecking);
ui->doNotDeleteTorrentCheckBox->setVisible(TorrentFileGuard::autoDeleteMode() != TorrentFileGuard::Never); m_ui->doNotDeleteTorrentCheckBox->setVisible(TorrentFileGuard::autoDeleteMode() != TorrentFileGuard::Never);
// Load categories // Load categories
QStringList categories = session->categories().keys(); QStringList categories = session->categories().keys();
@@ -134,25 +136,25 @@ AddNewTorrentDialog::AddNewTorrentDialog(const BitTorrent::AddTorrentParams &inP
QString defaultCategory = settings()->loadValue(KEY_DEFAULTCATEGORY).toString(); QString defaultCategory = settings()->loadValue(KEY_DEFAULTCATEGORY).toString();
if (!m_torrentParams.category.isEmpty()) if (!m_torrentParams.category.isEmpty())
ui->categoryComboBox->addItem(m_torrentParams.category); m_ui->categoryComboBox->addItem(m_torrentParams.category);
if (!defaultCategory.isEmpty()) if (!defaultCategory.isEmpty())
ui->categoryComboBox->addItem(defaultCategory); m_ui->categoryComboBox->addItem(defaultCategory);
ui->categoryComboBox->addItem(""); m_ui->categoryComboBox->addItem("");
foreach (const QString &category, categories) foreach (const QString &category, categories)
if (category != defaultCategory && category != m_torrentParams.category) if (category != defaultCategory && category != m_torrentParams.category)
ui->categoryComboBox->addItem(category); m_ui->categoryComboBox->addItem(category);
ui->contentTreeView->header()->setSortIndicator(0, Qt::AscendingOrder); m_ui->contentTreeView->header()->setSortIndicator(0, Qt::AscendingOrder);
loadState(); loadState();
// Signal / slots // Signal / slots
connect(ui->adv_button, SIGNAL(clicked(bool)), SLOT(showAdvancedSettings(bool))); connect(m_ui->adv_button, &QToolButton::clicked, this, &AddNewTorrentDialog::showAdvancedSettings);
connect(ui->doNotDeleteTorrentCheckBox, SIGNAL(clicked(bool)), SLOT(doNotDeleteTorrentClicked(bool))); connect(m_ui->doNotDeleteTorrentCheckBox, &QCheckBox::clicked, this, &AddNewTorrentDialog::doNotDeleteTorrentClicked);
QShortcut *editHotkey = new QShortcut(Qt::Key_F2, ui->contentTreeView, 0, 0, Qt::WidgetShortcut); QShortcut *editHotkey = new QShortcut(Qt::Key_F2, m_ui->contentTreeView, nullptr, nullptr, Qt::WidgetShortcut);
connect(editHotkey, SIGNAL(activated()), SLOT(renameSelectedFile())); connect(editHotkey, &QShortcut::activated, this, &AddNewTorrentDialog::renameSelectedFile);
connect(ui->contentTreeView, SIGNAL(doubleClicked(QModelIndex)), SLOT(renameSelectedFile())); connect(m_ui->contentTreeView, &QAbstractItemView::doubleClicked, this, &AddNewTorrentDialog::renameSelectedFile);
ui->buttonBox->button(QDialogButtonBox::Ok)->setFocus(); m_ui->buttonBox->button(QDialogButtonBox::Ok)->setFocus();
} }
AddNewTorrentDialog::~AddNewTorrentDialog() AddNewTorrentDialog::~AddNewTorrentDialog()
@@ -160,7 +162,7 @@ AddNewTorrentDialog::~AddNewTorrentDialog()
saveState(); saveState();
delete m_contentDelegate; delete m_contentDelegate;
delete ui; delete m_ui;
} }
bool AddNewTorrentDialog::isEnabled() bool AddNewTorrentDialog::isEnabled()
@@ -185,30 +187,21 @@ void AddNewTorrentDialog::setTopLevel(bool value)
int AddNewTorrentDialog::savePathHistoryLength() int AddNewTorrentDialog::savePathHistoryLength()
{ {
return savePathHistoryLengthSetting(); const int defaultHistoryLength = 8;
const int value = settings()->loadValue(KEY_SAVEPATHHISTORYLENGTH, defaultHistoryLength).toInt();
return qBound(minPathHistoryLength, value, maxPathHistoryLength);
} }
void AddNewTorrentDialog::setSavePathHistoryLength(int value) void AddNewTorrentDialog::setSavePathHistoryLength(int value)
{ {
Q_ASSERT(value >= minPathHistoryLength); const int clampedValue = qBound(minPathHistoryLength, value, maxPathHistoryLength);
Q_ASSERT(value <= maxPathHistoryLength);
const int oldValue = savePathHistoryLength(); const int oldValue = savePathHistoryLength();
if (oldValue != value) { if (clampedValue == oldValue)
savePathHistoryLengthSetting() = value; return;
settings()->storeValue(KEY_SAVEPATHHISTORY,
QStringList(settings()->loadValue(KEY_SAVEPATHHISTORY).toStringList().mid(0, value)));
}
}
CachedSettingValue<int> &AddNewTorrentDialog::savePathHistoryLengthSetting() settings()->storeValue(KEY_SAVEPATHHISTORYLENGTH, clampedValue);
{ settings()->storeValue(KEY_SAVEPATHHISTORY
const int defaultHistoryLength = 8; , QStringList(settings()->loadValue(KEY_SAVEPATHHISTORY).toStringList().mid(0, clampedValue)));
static CachedSettingValue<int> setting(KEY_SAVEPATHHISTORYLENGTH, defaultHistoryLength,
[](int v)
{
return std::max(minPathHistoryLength, std::min(maxPathHistoryLength, v));
});
return setting;
} }
void AddNewTorrentDialog::loadState() void AddNewTorrentDialog::loadState()
@@ -220,15 +213,15 @@ void AddNewTorrentDialog::loadState()
const int height = newSize.height(); const int height = newSize.height();
resize(width, height); resize(width, height);
ui->adv_button->setChecked(settings()->loadValue(KEY_EXPANDED).toBool()); m_ui->adv_button->setChecked(settings()->loadValue(KEY_EXPANDED).toBool());
} }
void AddNewTorrentDialog::saveState() void AddNewTorrentDialog::saveState()
{ {
if (m_contentModel) if (m_contentModel)
settings()->storeValue(KEY_TREEHEADERSTATE, ui->contentTreeView->header()->saveState()); settings()->storeValue(KEY_TREEHEADERSTATE, m_ui->contentTreeView->header()->saveState());
settings()->storeValue(KEY_WIDTH, width()); settings()->storeValue(KEY_WIDTH, width());
settings()->storeValue(KEY_EXPANDED, ui->adv_button->isChecked()); settings()->storeValue(KEY_EXPANDED, m_ui->adv_button->isChecked());
} }
void AddNewTorrentDialog::show(QString source, const BitTorrent::AddTorrentParams &inParams, QWidget *parent) void AddNewTorrentDialog::show(QString source, const BitTorrent::AddTorrentParams &inParams, QWidget *parent)
@@ -238,9 +231,10 @@ void AddNewTorrentDialog::show(QString source, const BitTorrent::AddTorrentParam
if (Utils::Misc::isUrl(source)) { if (Utils::Misc::isUrl(source)) {
// Launch downloader // Launch downloader
Net::DownloadHandler *handler = Net::DownloadManager::instance()->downloadUrl(source, true, 10485760 /* 10MB */, true); Net::DownloadHandler *handler = Net::DownloadManager::instance()->downloadUrl(source, true, 10485760 /* 10MB */, true);
connect(handler, SIGNAL(downloadFinished(QString,QString)), dlg, SLOT(handleDownloadFinished(QString,QString))); connect(handler, static_cast<void (Net::DownloadHandler::*)(const QString &, const QString &)>(&Net::DownloadHandler::downloadFinished)
connect(handler, SIGNAL(downloadFailed(QString,QString)), dlg, SLOT(handleDownloadFailed(QString,QString))); , dlg, &AddNewTorrentDialog::handleDownloadFinished);
connect(handler, SIGNAL(redirectedToMagnet(QString,QString)), dlg, SLOT(handleRedirectedToMagnet(QString,QString))); connect(handler, &Net::DownloadHandler::downloadFailed, dlg, &AddNewTorrentDialog::handleDownloadFailed);
connect(handler, &Net::DownloadHandler::redirectedToMagnet, dlg, &AddNewTorrentDialog::handleRedirectedToMagnet);
} }
else { else {
bool ok = false; bool ok = false;
@@ -315,9 +309,9 @@ bool AddNewTorrentDialog::loadTorrent(const QString &torrentPath)
return false; return false;
} }
ui->lblhash->setText(m_hash); m_ui->lblhash->setText(m_hash);
setupTreeview(); setupTreeview();
TMMChanged(ui->comboTTM->currentIndex()); TMMChanged(m_ui->comboTTM->currentIndex());
return true; return true;
} }
@@ -349,18 +343,18 @@ bool AddNewTorrentDialog::loadMagnet(const BitTorrent::MagnetUri &magnetUri)
return false; return false;
} }
connect(BitTorrent::Session::instance(), SIGNAL(metadataLoaded(BitTorrent::TorrentInfo)), SLOT(updateMetadata(BitTorrent::TorrentInfo))); connect(BitTorrent::Session::instance(), &BitTorrent::Session::metadataLoaded, this, &AddNewTorrentDialog::updateMetadata);
// Set dialog title // Set dialog title
QString torrent_name = magnetUri.name(); QString torrentName = magnetUri.name();
setWindowTitle(torrent_name.isEmpty() ? tr("Magnet link") : torrent_name); setWindowTitle(torrentName.isEmpty() ? tr("Magnet link") : torrentName);
setupTreeview(); setupTreeview();
TMMChanged(ui->comboTTM->currentIndex()); TMMChanged(m_ui->comboTTM->currentIndex());
BitTorrent::Session::instance()->loadMetadata(magnetUri); BitTorrent::Session::instance()->loadMetadata(magnetUri);
setMetadataProgressIndicator(true, tr("Retrieving metadata...")); setMetadataProgressIndicator(true, tr("Retrieving metadata..."));
ui->lblhash->setText(m_hash); m_ui->lblhash->setText(m_hash);
return true; return true;
} }
@@ -379,17 +373,17 @@ void AddNewTorrentDialog::showAdvancedSettings(bool show)
const int minimumW = minimumWidth(); const int minimumW = minimumWidth();
setMinimumWidth(width()); // to remain the same width setMinimumWidth(width()); // to remain the same width
if (show) { if (show) {
ui->adv_button->setText(QString::fromUtf8(C_UP)); m_ui->adv_button->setText(QString::fromUtf8(C_UP));
ui->settings_group->setVisible(true); m_ui->settings_group->setVisible(true);
ui->infoGroup->setVisible(true); m_ui->infoGroup->setVisible(true);
ui->contentTreeView->setVisible(m_hasMetadata); m_ui->contentTreeView->setVisible(m_hasMetadata);
static_cast<QVBoxLayout *>(layout())->insertWidget(layout()->indexOf(ui->never_show_cb) + 1, ui->adv_button); static_cast<QVBoxLayout *>(layout())->insertWidget(layout()->indexOf(m_ui->never_show_cb) + 1, m_ui->adv_button);
} }
else { else {
ui->adv_button->setText(QString::fromUtf8(C_DOWN)); m_ui->adv_button->setText(QString::fromUtf8(C_DOWN));
ui->settings_group->setVisible(false); m_ui->settings_group->setVisible(false);
ui->infoGroup->setVisible(false); m_ui->infoGroup->setVisible(false);
ui->buttonsHLayout->insertWidget(0, layout()->takeAt(layout()->indexOf(ui->never_show_cb) + 1)->widget()); m_ui->buttonsHLayout->insertWidget(0, layout()->takeAt(layout()->indexOf(m_ui->never_show_cb) + 1)->widget());
} }
adjustSize(); adjustSize();
setMinimumWidth(minimumW); setMinimumWidth(minimumW);
@@ -397,31 +391,30 @@ void AddNewTorrentDialog::showAdvancedSettings(bool show)
void AddNewTorrentDialog::saveSavePathHistory() const void AddNewTorrentDialog::saveSavePathHistory() const
{ {
QDir selectedSavePath(ui->savePath->selectedPath());
// Get current history // Get current history
QStringList history = settings()->loadValue(KEY_SAVEPATHHISTORY).toStringList(); QStringList history = settings()->loadValue(KEY_SAVEPATHHISTORY).toStringList();
if (history.size() > savePathHistoryLength()) QVector<QDir> historyDirs;
history = history.mid(0, savePathHistoryLength()); for (const QString &path : qAsConst(history))
QList<QDir> historyDirs; historyDirs << QDir {path};
foreach (const QString dir, history)
historyDirs << QDir(dir); const QDir selectedSavePath {m_ui->savePath->selectedPath()};
if (!historyDirs.contains(selectedSavePath)) { const int selectedSavePathIndex = historyDirs.indexOf(selectedSavePath);
// Add save path to history if (selectedSavePathIndex > 0)
history.removeAt(selectedSavePathIndex);
if (selectedSavePathIndex != 0)
// Add last used save path to the front of history
history.push_front(selectedSavePath.absolutePath()); history.push_front(selectedSavePath.absolutePath());
// Limit list size
if (history.size() > savePathHistoryLength())
history.pop_back();
// Save history // Save history
settings()->storeValue(KEY_SAVEPATHHISTORY, history); settings()->storeValue(KEY_SAVEPATHHISTORY, QStringList {history.mid(0, savePathHistoryLength())});
}
} }
// save_path is a folder, not an absolute file path // savePath is a folder, not an absolute file path
int AddNewTorrentDialog::indexOfSavePath(const QString &save_path) int AddNewTorrentDialog::indexOfSavePath(const QString &savePath)
{ {
QDir saveDir(save_path); QDir saveDir(savePath);
for (int i = 0; i < ui->savePath->count(); ++i) for (int i = 0; i < m_ui->savePath->count(); ++i)
if (QDir(ui->savePath->item(i)) == saveDir) if (QDir(m_ui->savePath->item(i)) == saveDir)
return i; return i;
return -1; return -1;
} }
@@ -429,7 +422,7 @@ int AddNewTorrentDialog::indexOfSavePath(const QString &save_path)
void AddNewTorrentDialog::updateDiskSpaceLabel() void AddNewTorrentDialog::updateDiskSpaceLabel()
{ {
// Determine torrent size // Determine torrent size
qulonglong torrent_size = 0; qulonglong torrentSize = 0;
if (m_hasMetadata) { if (m_hasMetadata) {
if (m_contentModel) { if (m_contentModel) {
@@ -437,28 +430,26 @@ void AddNewTorrentDialog::updateDiskSpaceLabel()
Q_ASSERT(priorities.size() == m_torrentInfo.filesCount()); Q_ASSERT(priorities.size() == m_torrentInfo.filesCount());
for (int i = 0; i < priorities.size(); ++i) for (int i = 0; i < priorities.size(); ++i)
if (priorities[i] > 0) if (priorities[i] > 0)
torrent_size += m_torrentInfo.fileSize(i); torrentSize += m_torrentInfo.fileSize(i);
} }
else { else {
torrent_size = m_torrentInfo.totalSize(); torrentSize = m_torrentInfo.totalSize();
} }
} }
QString size_string = torrent_size ? Utils::Misc::friendlyUnit(torrent_size) : QString(tr("Not Available", "This size is unavailable.")); QString sizeString = torrentSize ? Utils::Misc::friendlyUnit(torrentSize) : QString(tr("Not Available", "This size is unavailable."));
size_string += " ("; sizeString += " (";
size_string += tr("Free space on disk: %1").arg(Utils::Misc::friendlyUnit(Utils::Fs::freeDiskSpaceOnPath( sizeString += tr("Free space on disk: %1").arg(Utils::Misc::friendlyUnit(Utils::Fs::freeDiskSpaceOnPath(
ui->savePath->selectedPath()))); m_ui->savePath->selectedPath())));
size_string += ")"; sizeString += ")";
ui->size_lbl->setText(size_string); m_ui->size_lbl->setText(sizeString);
} }
void AddNewTorrentDialog::onSavePathChanged(const QString &newPath) void AddNewTorrentDialog::onSavePathChanged(const QString &newPath)
{ {
// Toggle default save path setting checkbox visibility Q_UNUSED(newPath);
ui->defaultSavePathCheckBox->setChecked(false);
ui->defaultSavePathCheckBox->setVisible(QDir(newPath) != QDir(BitTorrent::Session::instance()->defaultSavePath()));
// Remember index // Remember index
m_oldIndex = ui->savePath->currentIndex(); m_oldIndex = m_ui->savePath->currentIndex();
updateDiskSpaceLabel(); updateDiskSpaceLabel();
} }
@@ -466,9 +457,9 @@ void AddNewTorrentDialog::categoryChanged(int index)
{ {
Q_UNUSED(index); Q_UNUSED(index);
if (ui->comboTTM->currentIndex() == 1) { if (m_ui->comboTTM->currentIndex() == 1) {
QString savePath = BitTorrent::Session::instance()->categorySavePath(ui->categoryComboBox->currentText()); QString savePath = BitTorrent::Session::instance()->categorySavePath(m_ui->categoryComboBox->currentText());
ui->savePath->setSelectedPath(Utils::Fs::toNativePath(savePath)); m_ui->savePath->setSelectedPath(Utils::Fs::toNativePath(savePath));
} }
} }
@@ -477,16 +468,16 @@ void AddNewTorrentDialog::setSavePath(const QString &newPath)
int existingIndex = indexOfSavePath(newPath); int existingIndex = indexOfSavePath(newPath);
if (existingIndex < 0) { if (existingIndex < 0) {
// New path, prepend to combo box // New path, prepend to combo box
ui->savePath->insertItem(0, newPath); m_ui->savePath->insertItem(0, newPath);
existingIndex = 0; existingIndex = 0;
} }
ui->savePath->setCurrentIndex(existingIndex); m_ui->savePath->setCurrentIndex(existingIndex);
onSavePathChanged(newPath); onSavePathChanged(newPath);
} }
void AddNewTorrentDialog::renameSelectedFile() void AddNewTorrentDialog::renameSelectedFile()
{ {
const QModelIndexList selectedIndexes = ui->contentTreeView->selectionModel()->selectedRows(0); const QModelIndexList selectedIndexes = m_ui->contentTreeView->selectionModel()->selectedRows(0);
if (selectedIndexes.size() != 1) return; if (selectedIndexes.size() != 1) return;
const QModelIndex modelIndex = selectedIndexes.first(); const QModelIndex modelIndex = selectedIndexes.first();
@@ -587,35 +578,38 @@ void AddNewTorrentDialog::renameSelectedFile()
void AddNewTorrentDialog::populateSavePathComboBox() void AddNewTorrentDialog::populateSavePathComboBox()
{ {
QString defSavePath = BitTorrent::Session::instance()->defaultSavePath(); m_ui->savePath->clear();
ui->savePath->clear();
ui->savePath->addItem(defSavePath);
QDir defaultSaveDir(defSavePath);
// Load save path history // Load save path history
foreach (const QString &savePath, settings()->loadValue(KEY_SAVEPATHHISTORY).toStringList()) const QStringList savePathHistory {settings()->loadValue(KEY_SAVEPATHHISTORY).toStringList()};
if (QDir(savePath) != defaultSaveDir) for (const QString &savePath : savePathHistory)
ui->savePath->addItem(savePath); m_ui->savePath->addItem(savePath);
const bool rememberLastSavePath {settings()->loadValue(KEY_REMEMBERLASTSAVEPATH, false).toBool()};
const QString defSavePath {BitTorrent::Session::instance()->defaultSavePath()};
if (!m_torrentParams.savePath.isEmpty()) if (!m_torrentParams.savePath.isEmpty())
setSavePath(m_torrentParams.savePath); setSavePath(m_torrentParams.savePath);
else if (!rememberLastSavePath)
setSavePath(defSavePath);
// else last used save path will be selected since it is the first in the list
} }
void AddNewTorrentDialog::displayContentTreeMenu(const QPoint &) void AddNewTorrentDialog::displayContentTreeMenu(const QPoint &)
{ {
QMenu myFilesLlistMenu; QMenu myFilesLlistMenu;
const QModelIndexList selectedRows = ui->contentTreeView->selectionModel()->selectedRows(0); const QModelIndexList selectedRows = m_ui->contentTreeView->selectionModel()->selectedRows(0);
QAction *actRename = 0; QAction *actRename = nullptr;
if (selectedRows.size() == 1) { if (selectedRows.size() == 1) {
actRename = myFilesLlistMenu.addAction(GuiIconProvider::instance()->getIcon("edit-rename"), tr("Rename...")); actRename = myFilesLlistMenu.addAction(GuiIconProvider::instance()->getIcon("edit-rename"), tr("Rename..."));
myFilesLlistMenu.addSeparator(); myFilesLlistMenu.addSeparator();
} }
QMenu subMenu; QMenu subMenu;
subMenu.setTitle(tr("Priority")); subMenu.setTitle(tr("Priority"));
subMenu.addAction(ui->actionNot_downloaded); subMenu.addAction(m_ui->actionNot_downloaded);
subMenu.addAction(ui->actionNormal); subMenu.addAction(m_ui->actionNormal);
subMenu.addAction(ui->actionHigh); subMenu.addAction(m_ui->actionHigh);
subMenu.addAction(ui->actionMaximum); subMenu.addAction(m_ui->actionMaximum);
myFilesLlistMenu.addMenu(&subMenu); myFilesLlistMenu.addMenu(&subMenu);
// Call menu // Call menu
QAction *act = myFilesLlistMenu.exec(QCursor::pos()); QAction *act = myFilesLlistMenu.exec(QCursor::pos());
@@ -625,11 +619,11 @@ void AddNewTorrentDialog::displayContentTreeMenu(const QPoint &)
} }
else { else {
int prio = prio::NORMAL; int prio = prio::NORMAL;
if (act == ui->actionHigh) if (act == m_ui->actionHigh)
prio = prio::HIGH; prio = prio::HIGH;
else if (act == ui->actionMaximum) else if (act == m_ui->actionMaximum)
prio = prio::MAXIMUM; prio = prio::MAXIMUM;
else if (act == ui->actionNot_downloaded) else if (act == m_ui->actionNot_downloaded)
prio = prio::IGNORED; prio = prio::IGNORED;
qDebug("Setting files priority"); qDebug("Setting files priority");
@@ -647,34 +641,33 @@ void AddNewTorrentDialog::accept()
disconnect(this, SLOT(updateMetadata(const BitTorrent::TorrentInfo&))); disconnect(this, SLOT(updateMetadata(const BitTorrent::TorrentInfo&)));
// TODO: Check if destination actually exists // TODO: Check if destination actually exists
m_torrentParams.skipChecking = ui->skipCheckingCheckBox->isChecked(); m_torrentParams.skipChecking = m_ui->skipCheckingCheckBox->isChecked();
// Category // Category
m_torrentParams.category = ui->categoryComboBox->currentText(); m_torrentParams.category = m_ui->categoryComboBox->currentText();
if (m_ui->defaultCategoryCheckbox->isChecked())
if (ui->defaultCategoryCheckbox->isChecked())
settings()->storeValue(KEY_DEFAULTCATEGORY, m_torrentParams.category); settings()->storeValue(KEY_DEFAULTCATEGORY, m_torrentParams.category);
settings()->storeValue(KEY_REMEMBERLASTSAVEPATH, m_ui->checkBoxRememberLastSavePath->isChecked());
// Save file priorities // Save file priorities
if (m_contentModel) if (m_contentModel)
m_torrentParams.filePriorities = m_contentModel->model()->getFilePriorities(); m_torrentParams.filePriorities = m_contentModel->model()->getFilePriorities();
m_torrentParams.addPaused = TriStateBool(!ui->startTorrentCheckBox->isChecked()); m_torrentParams.addPaused = TriStateBool(!m_ui->startTorrentCheckBox->isChecked());
m_torrentParams.createSubfolder = TriStateBool(ui->createSubfolderCheckBox->isChecked()); m_torrentParams.createSubfolder = TriStateBool(m_ui->createSubfolderCheckBox->isChecked());
QString savePath = ui->savePath->selectedPath(); QString savePath = m_ui->savePath->selectedPath();
if (ui->comboTTM->currentIndex() != 1) { // 0 is Manual mode and 1 is Automatic mode. Handle all non 1 values as manual mode. if (m_ui->comboTTM->currentIndex() != 1) { // 0 is Manual mode and 1 is Automatic mode. Handle all non 1 values as manual mode.
m_torrentParams.useAutoTMM = TriStateBool::False; m_torrentParams.useAutoTMM = TriStateBool::False;
m_torrentParams.savePath = savePath; m_torrentParams.savePath = savePath;
saveSavePathHistory(); saveSavePathHistory();
if (ui->defaultSavePathCheckBox->isChecked())
BitTorrent::Session::instance()->setDefaultSavePath(savePath);
} }
else { else {
m_torrentParams.useAutoTMM = TriStateBool::True; m_torrentParams.useAutoTMM = TriStateBool::True;
} }
setEnabled(!ui->never_show_cb->isChecked()); setEnabled(!m_ui->never_show_cb->isChecked());
// Add torrent // Add torrent
if (!m_hasMetadata) if (!m_hasMetadata)
@@ -721,16 +714,16 @@ void AddNewTorrentDialog::updateMetadata(const BitTorrent::TorrentInfo &info)
void AddNewTorrentDialog::setMetadataProgressIndicator(bool visibleIndicator, const QString &labelText) void AddNewTorrentDialog::setMetadataProgressIndicator(bool visibleIndicator, const QString &labelText)
{ {
// Always show info label when waiting for metadata // Always show info label when waiting for metadata
ui->lblMetaLoading->setVisible(true); m_ui->lblMetaLoading->setVisible(true);
ui->lblMetaLoading->setText(labelText); m_ui->lblMetaLoading->setText(labelText);
ui->progMetaLoading->setVisible(visibleIndicator); m_ui->progMetaLoading->setVisible(visibleIndicator);
} }
void AddNewTorrentDialog::setupTreeview() void AddNewTorrentDialog::setupTreeview()
{ {
if (!m_hasMetadata) { if (!m_hasMetadata) {
setCommentText(tr("Not Available", "This comment is unavailable")); setCommentText(tr("Not Available", "This comment is unavailable"));
ui->date_lbl->setText(tr("Not Available", "This date is unavailable")); m_ui->date_lbl->setText(tr("Not Available", "This date is unavailable"));
} }
else { else {
// Set dialog title // Set dialog title
@@ -738,29 +731,30 @@ void AddNewTorrentDialog::setupTreeview()
// Set torrent information // Set torrent information
setCommentText(Utils::Misc::parseHtmlLinks(m_torrentInfo.comment())); setCommentText(Utils::Misc::parseHtmlLinks(m_torrentInfo.comment()));
ui->date_lbl->setText(!m_torrentInfo.creationDate().isNull() ? m_torrentInfo.creationDate().toString(Qt::DefaultLocaleShortDate) : tr("Not available")); m_ui->date_lbl->setText(!m_torrentInfo.creationDate().isNull() ? m_torrentInfo.creationDate().toString(Qt::DefaultLocaleShortDate) : tr("Not available"));
// Prepare content tree // Prepare content tree
m_contentModel = new TorrentContentFilterModel(this); m_contentModel = new TorrentContentFilterModel(this);
connect(m_contentModel->model(), SIGNAL(filteredFilesChanged()), SLOT(updateDiskSpaceLabel())); connect(m_contentModel->model(), &TorrentContentModel::filteredFilesChanged, this, &AddNewTorrentDialog::updateDiskSpaceLabel);
ui->contentTreeView->setModel(m_contentModel); m_ui->contentTreeView->setModel(m_contentModel);
m_contentDelegate = new PropListDelegate(nullptr); m_contentDelegate = new PropListDelegate(nullptr);
ui->contentTreeView->setItemDelegate(m_contentDelegate); m_ui->contentTreeView->setItemDelegate(m_contentDelegate);
connect(ui->contentTreeView, SIGNAL(clicked(const QModelIndex&)), ui->contentTreeView, SLOT(edit(const QModelIndex&))); connect(m_ui->contentTreeView, &QAbstractItemView::clicked, m_ui->contentTreeView
connect(ui->contentTreeView, SIGNAL(customContextMenuRequested(const QPoint&)), this, SLOT(displayContentTreeMenu(const QPoint&))); , static_cast<void (QAbstractItemView::*)(const QModelIndex &)>(&QAbstractItemView::edit));
connect(m_ui->contentTreeView, &QWidget::customContextMenuRequested, this, &AddNewTorrentDialog::displayContentTreeMenu);
// List files in torrent // List files in torrent
m_contentModel->model()->setupModelData(m_torrentInfo); m_contentModel->model()->setupModelData(m_torrentInfo);
if (!m_headerState.isEmpty()) if (!m_headerState.isEmpty())
ui->contentTreeView->header()->restoreState(m_headerState); m_ui->contentTreeView->header()->restoreState(m_headerState);
// Hide useless columns after loading the header state // Hide useless columns after loading the header state
ui->contentTreeView->hideColumn(PROGRESS); m_ui->contentTreeView->hideColumn(PROGRESS);
ui->contentTreeView->hideColumn(REMAINING); m_ui->contentTreeView->hideColumn(REMAINING);
ui->contentTreeView->hideColumn(AVAILABILITY); m_ui->contentTreeView->hideColumn(AVAILABILITY);
// Expand root folder // Expand root folder
ui->contentTreeView->setExpanded(m_contentModel->index(0, 0), true); m_ui->contentTreeView->setExpanded(m_contentModel->index(0, 0), true);
} }
updateDiskSpaceLabel(); updateDiskSpaceLabel();
@@ -796,33 +790,32 @@ void AddNewTorrentDialog::TMMChanged(int index)
{ {
if (index != 1) { // 0 is Manual mode and 1 is Automatic mode. Handle all non 1 values as manual mode. if (index != 1) { // 0 is Manual mode and 1 is Automatic mode. Handle all non 1 values as manual mode.
populateSavePathComboBox(); populateSavePathComboBox();
ui->groupBoxSavePath->setEnabled(true); m_ui->groupBoxSavePath->setEnabled(true);
ui->savePath->blockSignals(false); m_ui->savePath->blockSignals(false);
ui->savePath->setCurrentIndex(m_oldIndex < ui->savePath->count() ? m_oldIndex : ui->savePath->count() - 1); m_ui->savePath->setCurrentIndex(m_oldIndex < m_ui->savePath->count() ? m_oldIndex : m_ui->savePath->count() - 1);
ui->adv_button->setEnabled(true); m_ui->adv_button->setEnabled(true);
} }
else { else {
ui->groupBoxSavePath->setEnabled(false); m_ui->groupBoxSavePath->setEnabled(false);
ui->savePath->blockSignals(true); m_ui->savePath->blockSignals(true);
ui->savePath->clear(); m_ui->savePath->clear();
QString savePath = BitTorrent::Session::instance()->categorySavePath(ui->categoryComboBox->currentText()); QString savePath = BitTorrent::Session::instance()->categorySavePath(m_ui->categoryComboBox->currentText());
ui->savePath->addItem(savePath); m_ui->savePath->addItem(savePath);
ui->defaultSavePathCheckBox->setVisible(false); m_ui->adv_button->setChecked(true);
ui->adv_button->setChecked(true); m_ui->adv_button->setEnabled(false);
ui->adv_button->setEnabled(false);
showAdvancedSettings(true); showAdvancedSettings(true);
} }
} }
void AddNewTorrentDialog::setCommentText(const QString &str) const void AddNewTorrentDialog::setCommentText(const QString &str) const
{ {
ui->commentLabel->setText(str); m_ui->commentLabel->setText(str);
// workaround for the additional space introduced by QScrollArea // workaround for the additional space introduced by QScrollArea
int lineHeight = ui->commentLabel->fontMetrics().lineSpacing(); int lineHeight = m_ui->commentLabel->fontMetrics().lineSpacing();
int lines = 1 + str.count("\n"); int lines = 1 + str.count("\n");
int height = lineHeight * lines; int height = lineHeight * lines;
ui->scrollArea->setMaximumHeight(height); m_ui->scrollArea->setMaximumHeight(height);
} }
void AddNewTorrentDialog::doNotDeleteTorrentClicked(bool checked) void AddNewTorrentDialog::doNotDeleteTorrentClicked(bool checked)

View File

@@ -1,6 +1,6 @@
/* /*
* Bittorrent Client using Qt4 and libtorrent. * Bittorrent Client using Qt and libtorrent.
* Copyright (C) 2012 Christophe Dumez * Copyright (C) 2012 Christophe Dumez <chris@qbittorrent.org>
* *
* This program is free software; you can redistribute it and/or * This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License * modify it under the terms of the GNU General Public License
@@ -24,8 +24,6 @@
* modify file(s), you may extend this exception to your version of the file(s), * modify file(s), you may extend this exception to your version of the file(s),
* but you are not obligated to do so. If you do not wish to do so, delete this * but you are not obligated to do so. If you do not wish to do so, delete this
* exception statement from your version. * exception statement from your version.
*
* Contact : chris@qbittorrent.org
*/ */
#ifndef ADDNEWTORRENTDIALOG_H #ifndef ADDNEWTORRENTDIALOG_H
@@ -36,9 +34,9 @@
#include <QShortcut> #include <QShortcut>
#include <QUrl> #include <QUrl>
#include "base/bittorrent/addtorrentparams.h"
#include "base/bittorrent/infohash.h" #include "base/bittorrent/infohash.h"
#include "base/bittorrent/torrentinfo.h" #include "base/bittorrent/torrentinfo.h"
#include "base/bittorrent/addtorrentparams.h"
namespace BitTorrent namespace BitTorrent
{ {
@@ -50,18 +48,17 @@ namespace Ui
class AddNewTorrentDialog; class AddNewTorrentDialog;
} }
class PropListDelegate;
class TorrentContentFilterModel; class TorrentContentFilterModel;
class TorrentFileGuard; class TorrentFileGuard;
class PropListDelegate;
template <typename T> class CachedSettingValue;
class AddNewTorrentDialog : public QDialog class AddNewTorrentDialog : public QDialog
{ {
Q_OBJECT Q_OBJECT
public: public:
static constexpr int minPathHistoryLength = 0; static const int minPathHistoryLength = 0;
static constexpr int maxPathHistoryLength = 99; static const int maxPathHistoryLength = 99;
~AddNewTorrentDialog(); ~AddNewTorrentDialog();
@@ -98,18 +95,17 @@ private:
bool loadMagnet(const BitTorrent::MagnetUri &magnetUri); bool loadMagnet(const BitTorrent::MagnetUri &magnetUri);
void populateSavePathComboBox(); void populateSavePathComboBox();
void saveSavePathHistory() const; void saveSavePathHistory() const;
int indexOfSavePath(const QString &save_path); int indexOfSavePath(const QString &savePath);
void loadState(); void loadState();
void saveState(); void saveState();
void setMetadataProgressIndicator(bool visibleIndicator, const QString &labelText = QString()); void setMetadataProgressIndicator(bool visibleIndicator, const QString &labelText = QString());
void setupTreeview(); void setupTreeview();
void setCommentText(const QString &str) const; void setCommentText(const QString &str) const;
void setSavePath(const QString &newPath); void setSavePath(const QString &newPath);
static CachedSettingValue<int> &savePathHistoryLengthSetting();
void showEvent(QShowEvent *event) override; void showEvent(QShowEvent *event) override;
Ui::AddNewTorrentDialog *ui; Ui::AddNewTorrentDialog *m_ui;
TorrentContentFilterModel *m_contentModel; TorrentContentFilterModel *m_contentModel;
PropListDelegate *m_contentDelegate; PropListDelegate *m_contentDelegate;
bool m_hasMetadata; bool m_hasMetadata;

View File

@@ -62,9 +62,9 @@
<widget class="FileSystemPathComboEdit" name="savePath" native="true"/> <widget class="FileSystemPathComboEdit" name="savePath" native="true"/>
</item> </item>
<item> <item>
<widget class="QCheckBox" name="defaultSavePathCheckBox"> <widget class="QCheckBox" name="checkBoxRememberLastSavePath">
<property name="text"> <property name="text">
<string>Set as default save path</string> <string>Remember last used save path</string>
</property> </property>
</widget> </widget>
</item> </item>
@@ -393,7 +393,7 @@
</customwidgets> </customwidgets>
<tabstops> <tabstops>
<tabstop>savePath</tabstop> <tabstop>savePath</tabstop>
<tabstop>defaultSavePathCheckBox</tabstop> <tabstop>checkBoxRememberLastSavePath</tabstop>
<tabstop>never_show_cb</tabstop> <tabstop>never_show_cb</tabstop>
<tabstop>adv_button</tabstop> <tabstop>adv_button</tabstop>
<tabstop>startTorrentCheckBox</tabstop> <tabstop>startTorrentCheckBox</tabstop>

View File

@@ -125,8 +125,10 @@ AdvancedSettings::AdvancedSettings(QWidget *parent)
setSelectionMode(QAbstractItemView::NoSelection); setSelectionMode(QAbstractItemView::NoSelection);
setEditTriggers(QAbstractItemView::NoEditTriggers); setEditTriggers(QAbstractItemView::NoEditTriggers);
// Signals // Signals
connect(&spin_cache, SIGNAL(valueChanged(int)), SLOT(updateCacheSpinSuffix(int))); connect(&spin_cache, static_cast<void (QSpinBox::*)(int)>(&QSpinBox::valueChanged)
connect(&combo_iface, SIGNAL(currentIndexChanged(int)), SLOT(updateInterfaceAddressCombo())); , this, &AdvancedSettings::updateCacheSpinSuffix);
connect(&combo_iface, static_cast<void (QComboBox::*)(int)>(&QComboBox::currentIndexChanged)
, this, &AdvancedSettings::updateInterfaceAddressCombo);
// Load settings // Load settings
loadAdvancedSettings(); loadAdvancedSettings();
resizeColumnToContents(0); resizeColumnToContents(0);
@@ -360,7 +362,7 @@ void AdvancedSettings::loadAdvancedSettings()
outgoing_ports_max.setValue(session->outgoingPortsMax()); outgoing_ports_max.setValue(session->outgoingPortsMax());
addRow(OUTGOING_PORT_MAX, tr("Outgoing ports (Max) [0: Disabled]"), &outgoing_ports_max); addRow(OUTGOING_PORT_MAX, tr("Outgoing ports (Max) [0: Disabled]"), &outgoing_ports_max);
// uTP-TCP mixed mode // uTP-TCP mixed mode
comboUtpMixedMode.addItems({"Prefer TCP", "Peer proportional (throttles TCP)"}); comboUtpMixedMode.addItems({tr("Prefer TCP"), tr("Peer proportional (throttles TCP)")});
comboUtpMixedMode.setCurrentIndex(static_cast<int>(session->utpMixedMode())); comboUtpMixedMode.setCurrentIndex(static_cast<int>(session->utpMixedMode()));
addRow(UTP_MIX_MODE, tr("%1-TCP mixed mode algorithm", "uTP-TCP mixed mode algorithm").arg(C_UTP), &comboUtpMixedMode); addRow(UTP_MIX_MODE, tr("%1-TCP mixed mode algorithm", "uTP-TCP mixed mode algorithm").arg(C_UTP), &comboUtpMixedMode);
// multiple connections per IP // multiple connections per IP
@@ -447,11 +449,11 @@ void AdvancedSettings::loadAdvancedSettings()
spin_tracker_port.setValue(pref->getTrackerPort()); spin_tracker_port.setValue(pref->getTrackerPort());
addRow(TRACKER_PORT, tr("Embedded tracker port"), &spin_tracker_port); addRow(TRACKER_PORT, tr("Embedded tracker port"), &spin_tracker_port);
// Choking algorithm // Choking algorithm
comboChokingAlgorithm.addItems({"Fixed slots", "Upload rate based"}); comboChokingAlgorithm.addItems({tr("Fixed slots"), tr("Upload rate based")});
comboChokingAlgorithm.setCurrentIndex(static_cast<int>(session->chokingAlgorithm())); comboChokingAlgorithm.setCurrentIndex(static_cast<int>(session->chokingAlgorithm()));
addRow(CHOKING_ALGORITHM, tr("Upload slots behavior"), &comboChokingAlgorithm); addRow(CHOKING_ALGORITHM, tr("Upload slots behavior"), &comboChokingAlgorithm);
// Seed choking algorithm // Seed choking algorithm
comboSeedChokingAlgorithm.addItems({"Round-robin", "Fastest upload", "Anti-leech"}); comboSeedChokingAlgorithm.addItems({tr("Round-robin"), tr("Fastest upload"), tr("Anti-leech")});
comboSeedChokingAlgorithm.setCurrentIndex(static_cast<int>(session->seedChokingAlgorithm())); comboSeedChokingAlgorithm.setCurrentIndex(static_cast<int>(session->seedChokingAlgorithm()));
addRow(SEED_CHOKING_ALGORITHM, tr("Upload choking algorithm"), &comboSeedChokingAlgorithm); addRow(SEED_CHOKING_ALGORITHM, tr("Upload choking algorithm"), &comboSeedChokingAlgorithm);

View File

@@ -48,7 +48,7 @@ public:
static QString getText(QWidget *parent, const QString &title, const QString &label, static QString getText(QWidget *parent, const QString &title, const QString &label,
QLineEdit::EchoMode mode = QLineEdit::Normal, const QString &text = QString(), QLineEdit::EchoMode mode = QLineEdit::Normal, const QString &text = QString(),
bool *ok = 0, Qt::InputMethodHints inputMethodHints = Qt::ImhNone); bool *ok = nullptr, Qt::InputMethodHints inputMethodHints = Qt::ImhNone);
protected: protected:
void showEvent(QShowEvent *e); void showEvent(QShowEvent *e);

View File

@@ -174,17 +174,15 @@ CategoryFilterModel::CategoryFilterModel(QObject *parent)
: QAbstractItemModel(parent) : QAbstractItemModel(parent)
, m_rootItem(new CategoryModelItem) , m_rootItem(new CategoryModelItem)
{ {
auto session = BitTorrent::Session::instance(); using namespace BitTorrent;
auto session = Session::instance();
connect(session, SIGNAL(categoryAdded(QString)), SLOT(categoryAdded(QString))); connect(session, &Session::categoryAdded, this, &CategoryFilterModel::categoryAdded);
connect(session, SIGNAL(categoryRemoved(QString)), SLOT(categoryRemoved(QString))); connect(session, &Session::categoryRemoved, this, &CategoryFilterModel::categoryRemoved);
connect(session, SIGNAL(torrentCategoryChanged(BitTorrent::TorrentHandle *const, QString)) connect(session, &Session::torrentCategoryChanged, this, &CategoryFilterModel::torrentCategoryChanged);
, SLOT(torrentCategoryChanged(BitTorrent::TorrentHandle *const, QString))); connect(session, &Session::subcategoriesSupportChanged, this, &CategoryFilterModel::subcategoriesSupportChanged);
connect(session, SIGNAL(subcategoriesSupportChanged()), SLOT(subcategoriesSupportChanged())); connect(session, &Session::torrentAdded, this, &CategoryFilterModel::torrentAdded);
connect(session, SIGNAL(torrentAdded(BitTorrent::TorrentHandle *const)) connect(session, &Session::torrentAboutToBeRemoved, this, &CategoryFilterModel::torrentAboutToBeRemoved);
, SLOT(torrentAdded(BitTorrent::TorrentHandle *const)));
connect(session, SIGNAL(torrentAboutToBeRemoved(BitTorrent::TorrentHandle *const))
, SLOT(torrentAboutToBeRemoved(BitTorrent::TorrentHandle *const)));
populate(); populate();
} }

View File

@@ -37,7 +37,7 @@
#include "ui_cookiesdialog.h" #include "ui_cookiesdialog.h"
#include "utils.h" #include "utils.h"
#define SETTINGS_KEY(name) "CookiesDialog/" name #define SETTINGS_KEY(name) QStringLiteral("CookiesDialog/" name)
const QString KEY_SIZE = SETTINGS_KEY("Size"); const QString KEY_SIZE = SETTINGS_KEY("Size");
const QString KEY_COOKIESVIEWSTATE = SETTINGS_KEY("CookiesViewState"); const QString KEY_COOKIESVIEWSTATE = SETTINGS_KEY("CookiesViewState");

View File

@@ -59,7 +59,7 @@ class DeletionConfirmationDlg : public QDialog, private Ui::confirmDeletionDlg {
rememberBtn->setIconSize(Utils::Gui::mediumIconSize()); rememberBtn->setIconSize(Utils::Gui::mediumIconSize());
checkPermDelete->setChecked(defaultDeleteFiles || Preferences::instance()->deleteTorrentFilesAsDefault()); checkPermDelete->setChecked(defaultDeleteFiles || Preferences::instance()->deleteTorrentFilesAsDefault());
connect(checkPermDelete, SIGNAL(clicked()), this, SLOT(updateRememberButtonState())); connect(checkPermDelete, &QCheckBox::clicked, this, &DeletionConfirmationDlg::updateRememberButtonState);
buttonBox->button(QDialogButtonBox::Cancel)->setFocus(); buttonBox->button(QDialogButtonBox::Cancel)->setFocus();
Utils::Gui::resize(this); Utils::Gui::resize(this);

View File

@@ -59,8 +59,8 @@ ExecutionLog::ExecutionLog(QWidget *parent, const Log::MsgTypes &types)
addLogMessage(msg); addLogMessage(msg);
foreach (const Log::Peer& peer, logger->getPeers()) foreach (const Log::Peer& peer, logger->getPeers())
addPeerMessage(peer); addPeerMessage(peer);
connect(logger, SIGNAL(newLogMessage(const Log::Msg &)), SLOT(addLogMessage(const Log::Msg &))); connect(logger, &Logger::newLogMessage, this, &ExecutionLog::addLogMessage);
connect(logger, SIGNAL(newLogPeer(const Log::Peer &)), SLOT(addPeerMessage(const Log::Peer &))); connect(logger, &Logger::newLogPeer, this, &ExecutionLog::addPeerMessage);
} }
ExecutionLog::~ExecutionLog() ExecutionLog::~ExecutionLog()

View File

@@ -41,7 +41,6 @@
namespace namespace
{ {
const char i18nContext[] = "FileSystemPathEdit";
struct TrStringWithComment struct TrStringWithComment
{ {
const char *source; const char *source;
@@ -49,18 +48,18 @@ namespace
QString tr() const QString tr() const
{ {
return QCoreApplication::translate(i18nContext, source, comment); return QCoreApplication::translate("FileSystemPathEdit", source, comment);
} }
}; };
constexpr TrStringWithComment browseButtonBriefText = constexpr TrStringWithComment browseButtonBriefText =
QT_TRANSLATE_NOOP3(i18nContext, "...", "Launch file dialog button text (brief)"); QT_TRANSLATE_NOOP3("FileSystemPathEdit", "...", "Launch file dialog button text (brief)");
constexpr TrStringWithComment browseButtonFullText = constexpr TrStringWithComment browseButtonFullText =
QT_TRANSLATE_NOOP3(i18nContext, "&Browse...", "Launch file dialog button text (full)"); QT_TRANSLATE_NOOP3("FileSystemPathEdit", "&Browse...", "Launch file dialog button text (full)");
constexpr TrStringWithComment defaultDialogCaptionForFile = constexpr TrStringWithComment defaultDialogCaptionForFile =
QT_TRANSLATE_NOOP3(i18nContext, "Choose a file", "Caption for file open/save dialog"); QT_TRANSLATE_NOOP3("FileSystemPathEdit", "Choose a file", "Caption for file open/save dialog");
constexpr TrStringWithComment defaultDialogCaptionForDirectory = constexpr TrStringWithComment defaultDialogCaptionForDirectory =
QT_TRANSLATE_NOOP3(i18nContext, "Choose a folder", "Caption for directory open dialog"); QT_TRANSLATE_NOOP3("FileSystemPathEdit", "Choose a folder", "Caption for directory open dialog");
} }
class FileSystemPathEdit::FileSystemPathEditPrivate class FileSystemPathEdit::FileSystemPathEditPrivate

View File

@@ -40,7 +40,7 @@ GuiIconProvider::GuiIconProvider(QObject *parent)
: IconProvider(parent) : IconProvider(parent)
{ {
configure(); configure();
connect(Preferences::instance(), SIGNAL(changed()), SLOT(configure())); connect(Preferences::instance(), &Preferences::changed, this, &GuiIconProvider::configure);
} }
GuiIconProvider::~GuiIconProvider() = default; GuiIconProvider::~GuiIconProvider() = default;

View File

@@ -52,7 +52,7 @@ private slots:
void configure(); void configure();
private: private:
explicit GuiIconProvider(QObject *parent = 0); explicit GuiIconProvider(QObject *parent = nullptr);
~GuiIconProvider(); ~GuiIconProvider();
#if (defined(Q_OS_UNIX) && !defined(Q_OS_MAC)) #if (defined(Q_OS_UNIX) && !defined(Q_OS_MAC))
QIcon generateDifferentSizes(const QIcon &icon); QIcon generateDifferentSizes(const QIcon &icon);

View File

@@ -41,7 +41,7 @@
class HidableTabWidget : public QTabWidget class HidableTabWidget : public QTabWidget
{ {
public: public:
explicit HidableTabWidget(QWidget *parent = 0) explicit HidableTabWidget(QWidget *parent = nullptr)
: QTabWidget(parent) : QTabWidget(parent)
{ {
} }

View File

@@ -47,8 +47,8 @@ LogListWidget::LogListWidget(int maxLines, const Log::MsgTypes &types, QWidget *
// Context menu // Context menu
QAction *copyAct = new QAction(GuiIconProvider::instance()->getIcon("edit-copy"), tr("Copy"), this); QAction *copyAct = new QAction(GuiIconProvider::instance()->getIcon("edit-copy"), tr("Copy"), this);
QAction *clearAct = new QAction(GuiIconProvider::instance()->getIcon("edit-clear"), tr("Clear"), this); QAction *clearAct = new QAction(GuiIconProvider::instance()->getIcon("edit-clear"), tr("Clear"), this);
connect(copyAct, SIGNAL(triggered()), SLOT(copySelection())); connect(copyAct, &QAction::triggered, this, &LogListWidget::copySelection);
connect(clearAct, SIGNAL(triggered()), SLOT(clear())); connect(clearAct, &QAction::triggered, this, &LogListWidget::clear);
addAction(copyAct); addAction(copyAct);
addAction(clearAct); addAction(clearAct);
setContextMenuPolicy(Qt::ActionsContextMenu); setContextMenuPolicy(Qt::ActionsContextMenu);

View File

@@ -43,7 +43,7 @@ class LogListWidget: public QListWidget
public: public:
// -1 is the portable way to have all the bits set // -1 is the portable way to have all the bits set
explicit LogListWidget(int maxLines, const Log::MsgTypes &types = Log::ALL, QWidget *parent = 0); explicit LogListWidget(int maxLines, const Log::MsgTypes &types = Log::ALL, QWidget *parent = nullptr);
void showMsgTypes(const Log::MsgTypes &types); void showMsgTypes(const Log::MsgTypes &types);
public slots: public slots:

View File

@@ -121,12 +121,12 @@ namespace
#define SETTINGS_KEY(name) "GUI/" name #define SETTINGS_KEY(name) "GUI/" name
// ExecutionLog properties keys // ExecutionLog properties keys
#define EXECUTIONLOG_SETTINGS_KEY(name) SETTINGS_KEY("Log/") name #define EXECUTIONLOG_SETTINGS_KEY(name) QStringLiteral(SETTINGS_KEY("Log/") name)
const QString KEY_EXECUTIONLOG_ENABLED = EXECUTIONLOG_SETTINGS_KEY("Enabled"); const QString KEY_EXECUTIONLOG_ENABLED = EXECUTIONLOG_SETTINGS_KEY("Enabled");
const QString KEY_EXECUTIONLOG_TYPES = EXECUTIONLOG_SETTINGS_KEY("Types"); const QString KEY_EXECUTIONLOG_TYPES = EXECUTIONLOG_SETTINGS_KEY("Types");
// Notifications properties keys // Notifications properties keys
#define NOTIFICATIONS_SETTINGS_KEY(name) SETTINGS_KEY("Notifications/") name #define NOTIFICATIONS_SETTINGS_KEY(name) QStringLiteral(SETTINGS_KEY("Notifications/") name)
const QString KEY_NOTIFICATIONS_ENABLED = NOTIFICATIONS_SETTINGS_KEY("Enabled"); const QString KEY_NOTIFICATIONS_ENABLED = NOTIFICATIONS_SETTINGS_KEY("Enabled");
const QString KEY_NOTIFICATIONS_TORRENTADDED = NOTIFICATIONS_SETTINGS_KEY("TorrentAdded"); const QString KEY_NOTIFICATIONS_TORRENTADDED = NOTIFICATIONS_SETTINGS_KEY("TorrentAdded");
@@ -160,11 +160,13 @@ MainWindow::MainWindow(QWidget *parent)
// Setting icons // Setting icons
#ifndef Q_OS_MAC #ifndef Q_OS_MAC
#ifdef Q_OS_UNIX #ifdef Q_OS_UNIX
if (Preferences::instance()->useSystemIconTheme()) const QIcon appLogo = Preferences::instance()->useSystemIconTheme()
setWindowIcon(QIcon::fromTheme("qbittorrent", QIcon(":/icons/skin/qbittorrent32.png"))); ? QIcon::fromTheme("qbittorrent", QIcon(":/icons/skin/qbittorrent-tray.svg"))
else : QIcon(":/icons/skin/qbittorrent-tray.svg");
#else
const QIcon appLogo(":/icons/skin/qbittorrent-tray.svg");
#endif // Q_OS_UNIX #endif // Q_OS_UNIX
setWindowIcon(QIcon(":/icons/skin/qbittorrent32.png")); setWindowIcon(appLogo);
#endif // Q_OS_MAC #endif // Q_OS_MAC
#if (defined(Q_OS_UNIX)) #if (defined(Q_OS_UNIX))
@@ -375,7 +377,7 @@ MainWindow::MainWindow(QWidget *parent)
on_actionWarningMessages_triggered(m_ui->actionWarningMessages->isChecked()); on_actionWarningMessages_triggered(m_ui->actionWarningMessages->isChecked());
on_actionCriticalMessages_triggered(m_ui->actionCriticalMessages->isChecked()); on_actionCriticalMessages_triggered(m_ui->actionCriticalMessages->isChecked());
if (m_ui->actionSearchWidget->isChecked()) if (m_ui->actionSearchWidget->isChecked())
QTimer::singleShot(0, this, SLOT(on_actionSearchWidget_triggered())); QTimer::singleShot(0, this, &MainWindow::on_actionSearchWidget_triggered);
// Auto shutdown actions // Auto shutdown actions
QActionGroup *autoShutdownGroup = new QActionGroup(this); QActionGroup *autoShutdownGroup = new QActionGroup(this);
@@ -1047,7 +1049,7 @@ void MainWindow::notifyOfUpdate(QString)
, Log::CRITICAL); , Log::CRITICAL);
// Delete the executable watcher // Delete the executable watcher
delete m_executableWatcher; delete m_executableWatcher;
m_executableWatcher = 0; m_executableWatcher = nullptr;
} }
#ifndef Q_OS_MAC #ifndef Q_OS_MAC
@@ -1213,7 +1215,7 @@ bool MainWindow::event(QEvent *e)
if (!hasModalWindow) { if (!hasModalWindow) {
qDebug("Minimize to Tray enabled, hiding!"); qDebug("Minimize to Tray enabled, hiding!");
e->ignore(); e->ignore();
QTimer::singleShot(0, this, SLOT(hide())); QTimer::singleShot(0, this, &QWidget::hide);
return true; return true;
} }
} }

View File

@@ -75,7 +75,7 @@ class MainWindow: public QMainWindow
Q_OBJECT Q_OBJECT
public: public:
explicit MainWindow(QWidget *parent = 0); explicit MainWindow(QWidget *parent = nullptr);
~MainWindow() override; ~MainWindow() override;
QWidget *currentTabWidget() const; QWidget *currentTabWidget() const;

View File

@@ -38,7 +38,7 @@ class MessageBoxRaised : public QMessageBox
Q_OBJECT Q_OBJECT
private: private:
MessageBoxRaised(QMessageBox::Icon icon, const QString &title, const QString &text, QMessageBox::StandardButtons buttons = NoButton, QWidget *parent = 0, Qt::WindowFlags f = Qt::Dialog|Qt::MSWindowsFixedSizeDialogHint); MessageBoxRaised(QMessageBox::Icon icon, const QString &title, const QString &text, QMessageBox::StandardButtons buttons = NoButton, QWidget *parent = nullptr, Qt::WindowFlags f = Qt::Dialog|Qt::MSWindowsFixedSizeDialogHint);
MessageBoxRaised(); MessageBoxRaised();
MessageBoxRaised(MessageBoxRaised const&); MessageBoxRaised(MessageBoxRaised const&);
void operator=(MessageBoxRaised const&); void operator=(MessageBoxRaised const&);

View File

@@ -626,7 +626,7 @@ void OptionsDialog::saveOptions()
session->setAltGlobalUploadSpeedLimit(alt_down_up_limit.second); session->setAltGlobalUploadSpeedLimit(alt_down_up_limit.second);
pref->setSchedulerStartTime(m_ui->schedule_from->time()); pref->setSchedulerStartTime(m_ui->schedule_from->time());
pref->setSchedulerEndTime(m_ui->schedule_to->time()); pref->setSchedulerEndTime(m_ui->schedule_to->time());
pref->setSchedulerDays(static_cast<scheduler_days>(m_ui->schedule_days->currentIndex())); pref->setSchedulerDays(static_cast<SchedulerDays>(m_ui->schedule_days->currentIndex()));
session->setBandwidthSchedulerEnabled(m_ui->check_schedule->isChecked()); session->setBandwidthSchedulerEnabled(m_ui->check_schedule->isChecked());
auto proxyConfigManager = Net::ProxyConfigurationManager::instance(); auto proxyConfigManager = Net::ProxyConfigurationManager::instance();

View File

@@ -77,7 +77,7 @@ private:
public: public:
// Constructor / Destructor // Constructor / Destructor
OptionsDialog(QWidget *parent = 0); OptionsDialog(QWidget *parent = nullptr);
~OptionsDialog(); ~OptionsDialog();
public slots: public slots:

View File

@@ -48,7 +48,7 @@ class PowerManagement : public QObject
Q_OBJECT Q_OBJECT
public: public:
PowerManagement(QObject *parent = 0); PowerManagement(QObject *parent = nullptr);
virtual ~PowerManagement(); virtual ~PowerManagement();
void setActivityState(bool busy); void setActivityState(bool busy);

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