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_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)
include(FunctionReadVersion)

View File

@@ -239,11 +239,11 @@ The headers should be placed in the following group order:
4. Boost library headers
5. Libtorrent 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.
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.
@@ -285,13 +285,13 @@ Example:
#include <QFont>
#endif
// conditional for the different header groups
// conditional that contains headers from several different header groups
#if LIBTORRENT_VERSION_NUM >= 10100
#include <memory>
#include <QElapsedTimer>
#endif
// qBittorrent own headers
// qBittorrent's own headers
#include "base/bittorrent/infohash.h"
#include "anothermodule.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
- FEATURE: Add "Coalesce reads & writes" checkbox in advanced options (Chocobo1)
- FEATURE: Smart Filter for RSS (Stephen Dawkins)

View File

@@ -11,18 +11,17 @@ macro(qbt_set_compiler_options)
#-Wshadow -Wconversion ?
set(_GCC_COMMON_C_AND_CXX_FLAGS "-Wall -Wextra"
"-Wfloat-equal -Wcast-qual -Wcast-align"
"-Wsign-conversion -Winvalid-pch -Werror=return-type -Wno-long-long"
# -fstack-protector-all
"-Werror -Wno-error=deprecated-declarations"
"-Wsign-conversion -Winvalid-pch -Wno-long-long"
#"-fstack-protector-all"
#"-Werror -Wno-error=deprecated-declarations"
)
set (_GCC_COMMON_CXX_FLAGS "-fexceptions -frtti"
set(_GCC_COMMON_CXX_FLAGS "-fexceptions -frtti"
"-Woverloaded-virtual -Wold-style-cast"
"-Wnon-virtual-dtor -Wfloat-equal -Wcast-qual -Wcast-align"
"-Werror=overloaded-virtual"
# "-Weffc++"
"-Werror -Wno-error=cpp"
#"-Weffc++"
#"-Werror -Wno-error=cpp"
# 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)

View File

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

24
configure vendored
View File

@@ -1,6 +1,6 @@
#! /bin/sh
# 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>.
#
@@ -580,8 +580,8 @@ MAKEFLAGS=
# Identity of this package.
PACKAGE_NAME='qbittorrent'
PACKAGE_TARNAME='qbittorrent'
PACKAGE_VERSION='v4.1.0alpha'
PACKAGE_STRING='qbittorrent v4.1.0alpha'
PACKAGE_VERSION='v4.1.1'
PACKAGE_STRING='qbittorrent v4.1.1'
PACKAGE_BUGREPORT='bugs.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.
# This message is too long to be a string in the A/UX 3.1 sh.
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]...
@@ -1368,7 +1368,7 @@ fi
if test -n "$ac_init_help"; then
case $ac_init_help in
short | recursive ) echo "Configuration of qbittorrent v4.1.0alpha:";;
short | recursive ) echo "Configuration of qbittorrent v4.1.1:";;
esac
cat <<\_ACEOF
@@ -1503,7 +1503,7 @@ fi
test -n "$ac_init_help" && exit $ac_status
if $ac_init_version; then
cat <<\_ACEOF
qbittorrent configure v4.1.0alpha
qbittorrent configure v4.1.1
generated by GNU Autoconf 2.69
Copyright (C) 2012 Free Software Foundation, Inc.
@@ -1642,7 +1642,7 @@ cat >config.log <<_ACEOF
This file contains any messages produced by compilers while
running configure, to aid debugging if configure makes a mistake.
It was created by qbittorrent $as_me v4.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
$ $0 $@
@@ -3820,7 +3820,7 @@ fi
# Define the identity of the package.
PACKAGE='qbittorrent'
VERSION='v4.1.0alpha'
VERSION='v4.1.1'
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
# values after options handling.
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
CONFIG_FILES = $CONFIG_FILES
@@ -6198,7 +6198,7 @@ _ACEOF
cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1
ac_cs_config="`$as_echo "$ac_configure_args" | sed 's/^ //; s/[\\""\`\$]/\\\\&/g'`"
ac_cs_version="\\
qbittorrent config.status v4.1.0alpha
qbittorrent config.status v4.1.1
configured by $0, generated by GNU Autoconf 2.69,
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
# values after options handling.
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
CONFIG_FILES = $CONFIG_FILES
@@ -7513,7 +7513,7 @@ _ACEOF
cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1
ac_cs_config="`$as_echo "$ac_configure_args" | sed 's/^ //; s/[\\""\`\$]/\\\\&/g'`"
ac_cs_version="\\
qbittorrent config.status v4.1.0alpha
qbittorrent config.status v4.1.1
configured by $0, generated by GNU Autoconf 2.69,
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_MACRO_DIR([m4])
AC_PROG_CC

2
dist/mac/Info.plist vendored
View File

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

View File

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

View File

@@ -93,7 +93,7 @@ namespace
#define SETTINGS_KEY(name) "Application/" name
// 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_PATH = FILELOGGER_SETTINGS_KEY("Path");
const QString KEY_FILELOGGER_BACKUP = FILELOGGER_SETTINGS_KEY("Backup");
@@ -151,11 +151,11 @@ Application::Application(const QString &id, int &argc, char **argv)
#endif
#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
connect(this, SIGNAL(messageReceived(const QString &)), SLOT(processMessage(const QString &)));
connect(this, SIGNAL(aboutToQuit()), SLOT(cleanup()));
connect(this, &Application::messageReceived, this, &Application::processMessage);
connect(this, &QCoreApplication::aboutToQuit, this, &Application::cleanup);
if (isFileLoggerEnabled())
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>);
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("%R", Utils::Fs::toNativePath(torrent->rootPath()));
program.replace("%D", Utils::Fs::toNativePath(torrent->savePath()));
#endif
program.replace("%C", QString::number(torrent->filesCount()));
program.replace("%Z", QString::number(torrent->totalSize()));
program.replace("%T", torrent->currentTracker());
@@ -301,9 +313,7 @@ void Application::runExternalProgram(const BitTorrent::TorrentHandle *torrent) c
Logger *logger = Logger::instance();
logger->addMessage(tr("Torrent: %1, running external program, command: %2").arg(torrent->name(), program));
#if defined(Q_OS_UNIX)
QProcess::startDetached(QLatin1String("/bin/sh"), {QLatin1String("-c"), program});
#else
#if defined(Q_OS_WIN)
std::unique_ptr<wchar_t[]> programWchar(new wchar_t[program.length() + 1] {});
program.toWCharArray(programWchar.get());
@@ -320,6 +330,8 @@ void Application::runExternalProgram(const BitTorrent::TorrentHandle *torrent) c
QProcess::startDetached(QString::fromWCharArray(args[0]), argList);
::LocalFree(args);
#else
QProcess::startDetached(QLatin1String("/bin/sh"), {QLatin1String("-c"), program});
#endif
}
@@ -489,8 +501,8 @@ int Application::exec(const QStringList &params)
#endif
BitTorrent::Session::initInstance();
connect(BitTorrent::Session::instance(), SIGNAL(torrentFinished(BitTorrent::TorrentHandle *const)), SLOT(torrentFinished(BitTorrent::TorrentHandle *const)));
connect(BitTorrent::Session::instance(), SIGNAL(allTorrentsFinished()), SLOT(allTorrentsFinished()), Qt::QueuedConnection);
connect(BitTorrent::Session::instance(), &BitTorrent::Session::torrentFinished, this, &Application::torrentFinished);
connect(BitTorrent::Session::instance(), &BitTorrent::Session::allTorrentsFinished, this, &Application::allTorrentsFinished, Qt::QueuedConnection);
#ifndef DISABLE_COUNTRIES_RESOLUTION
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.
// aboutToQuit() is never emitted if the user hits "Cancel" in
// the above dialog.
QTimer::singleShot(0, qApp, SLOT(quit()));
QTimer::singleShot(0, qApp, &QCoreApplication::quit);
}
#endif

View File

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

View File

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

View File

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

View File

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

View File

@@ -114,12 +114,27 @@ bool upgradeResumeFile(const QString &filepath, const QVariantHash &oldTorrent =
bool v3_3 = false;
int queuePosition = 0;
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) {
// 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();
if ((rx.cap(2).size() == 6) && (queuePosition <= 99999)) {
Utils::Fs::forceRemove(filepath);
return true;
}
v3_3 = true;
outFilePath.replace(QRegExp("\\.\\d+$"), "");
outFilePath.replace(QRegExp("\\.fastresume\\..+$"), ".fastresume");
}
else {
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
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);
QVector<char> out;
libtorrent::bencode(std::back_inserter(out), fastNew);

View File

@@ -34,14 +34,14 @@
#include <QFile>
#include <QObject>
class AsyncFileStorageError: public std::runtime_error
class AsyncFileStorageError : public std::runtime_error
{
public:
explicit AsyncFileStorageError(const QString &message);
QString message() const;
};
class AsyncFileStorage: public QObject
class AsyncFileStorage : public QObject
{
Q_OBJECT

View File

@@ -55,7 +55,7 @@ void BandwidthScheduler::start()
bool BandwidthScheduler::isTimeForAlternative() const
{
const Preferences* const pref = Preferences::instance();
const Preferences *const pref = Preferences::instance();
QTime start = pref->getSchedulerStartTime();
QTime end = pref->getSchedulerEndTime();

View File

@@ -33,7 +33,7 @@
#include <QObject>
#include <QTimer>
class BandwidthScheduler: public QObject
class BandwidthScheduler : public QObject
{
Q_OBJECT
Q_DISABLE_COPY(BandwidthScheduler)

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>
*
* This program is free software; you can redistribute it and/or
@@ -147,13 +147,13 @@ int FilterParserThread::parseDATFilterFile()
if (bytesRead < 0)
break;
int dataSize = bytesRead + offset;
if (bytesRead == 0 && dataSize == 0)
if ((bytesRead == 0) && (dataSize == 0))
break;
for (start = 0; start < dataSize; ++start) {
endOfLine = -1;
// 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) {
if (buffer[i] == '\n') {
endOfLine = i;
@@ -295,13 +295,13 @@ int FilterParserThread::parseP2PFilterFile()
if (bytesRead < 0)
break;
int dataSize = bytesRead + offset;
if (bytesRead == 0 && dataSize == 0)
if ((bytesRead == 0) && (dataSize == 0))
break;
for (start = 0; start < dataSize; ++start) {
endOfLine = -1;
// 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) {
if (buffer[i] == '\n') {
endOfLine = i;
@@ -610,7 +610,7 @@ int FilterParserThread::findAndNullDelimiter(char *const data, char delimiter, i
return -1;
}
int FilterParserThread::trim(char* const data, int start, int end)
int FilterParserThread::trim(char *const data, int start, int end)
{
if (start >= end) return start;
int newStart = start;

View File

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

View File

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

View File

@@ -49,9 +49,6 @@
#include <QUuid>
#include <libtorrent/alert_types.hpp>
#if LIBTORRENT_VERSION_NUM >= 10100
#include <libtorrent/bdecode.hpp>
#endif
#include <libtorrent/bencode.hpp>
#include <libtorrent/disk_io_thread.hpp>
#include <libtorrent/error_code.hpp>
@@ -60,17 +57,18 @@
#include <libtorrent/extensions/smart_ban.hpp>
#include <libtorrent/identify_client.hpp>
#include <libtorrent/ip_filter.hpp>
#if LIBTORRENT_VERSION_NUM < 10100
#include <libtorrent/lazy_entry.hpp>
#endif
#include <libtorrent/magnet_uri.hpp>
#include <libtorrent/session.hpp>
#if LIBTORRENT_VERSION_NUM >= 10100
#include <libtorrent/session_stats.hpp>
#endif
#include <libtorrent/session_status.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/logger.h"
#include "base/net/downloadhandler.h"
@@ -96,6 +94,7 @@
#include "trackerentry.h"
#ifdef Q_OS_WIN
#include <wincrypt.h>
#include <iphlpapi.h>
#endif
@@ -371,11 +370,16 @@ Session::Session(QObject *parent)
, m_numResumeData(0)
, m_extraLimit(0)
, m_useProxy(false)
, m_recentErroredTorrentsTimer(new QTimer(this))
{
Logger* const logger = Logger::instance();
Logger *const logger = Logger::instance();
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->setInterval(10000);
connect(m_seedingLimitTimer, &QTimer::timeout, this, &Session::processShareLimits);
@@ -519,13 +523,14 @@ Session::Session(QObject *parent)
enableTracker(isTrackerEnabled());
connect(Net::ProxyConfigurationManager::instance(), SIGNAL(proxyConfigurationChanged()), SLOT(configureDeferred()));
connect(Net::ProxyConfigurationManager::instance(), &Net::ProxyConfigurationManager::proxyConfigurationChanged
, this, &Session::configureDeferred);
// Network configuration monitor
connect(&m_networkManager, SIGNAL(onlineStateChanged(bool)), SLOT(networkOnlineStateChanged(bool)));
connect(&m_networkManager, SIGNAL(configurationAdded(const QNetworkConfiguration&)), SLOT(networkConfigurationChange(const QNetworkConfiguration&)));
connect(&m_networkManager, SIGNAL(configurationRemoved(const QNetworkConfiguration&)), SLOT(networkConfigurationChange(const QNetworkConfiguration&)));
connect(&m_networkManager, SIGNAL(configurationChanged(const QNetworkConfiguration&)), SLOT(networkConfigurationChange(const QNetworkConfiguration&)));
connect(&m_networkManager, &QNetworkConfigurationManager::onlineStateChanged, this, &Session::networkOnlineStateChanged);
connect(&m_networkManager, &QNetworkConfigurationManager::configurationAdded, this, &Session::networkConfigurationChange);
connect(&m_networkManager, &QNetworkConfigurationManager::configurationRemoved, this, &Session::networkConfigurationChange);
connect(&m_networkManager, &QNetworkConfigurationManager::configurationChanged, this, &Session::networkConfigurationChange);
m_ioThread = new QThread(this);
m_resumeDataSavingManager = new ResumeDataSavingManager(m_resumeFolderPath);
@@ -941,7 +946,7 @@ qreal Session::globalMaxRatio() const
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
void Session::setGlobalMaxRatio(qreal ratio)
{
@@ -1005,7 +1010,7 @@ void Session::freeInstance()
{
if (m_instance) {
delete m_instance;
m_instance = 0;
m_instance = nullptr;
}
}
@@ -1084,7 +1089,7 @@ void Session::processBannedIPs(libt::ip_filter &filter)
#if LIBTORRENT_VERSION_NUM >= 10100
void Session::adjustLimits(libt::settings_pack &settingsPack)
{
//Internally increase the queue limits to ensure that the magnet is started
// Internally increase the queue limits to ensure that the magnet is started
int maxDownloads = maxActiveDownloads();
int maxActive = maxActiveTorrents();
@@ -1181,7 +1186,7 @@ void Session::initMetrics()
void Session::configure(libtorrent::settings_pack &settingsPack)
{
Logger* const logger = Logger::instance();
Logger *const logger = Logger::instance();
#ifdef Q_OS_WIN
QString chosenIP;
@@ -1250,7 +1255,7 @@ void Session::configure(libtorrent::settings_pack &settingsPack)
settingsPack.set_int(libt::settings_pack::allowed_enc_level, libt::settings_pack::pe_rc4);
settingsPack.set_bool(libt::settings_pack::prefer_rc4, true);
switch (encryption()) {
case 0: //Enabled
case 0: // Enabled
settingsPack.set_int(libt::settings_pack::out_enc_policy, libt::settings_pack::pe_enabled);
settingsPack.set_int(libt::settings_pack::in_enc_policy, libt::settings_pack::pe_enabled);
break;
@@ -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_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_expiry, diskCacheTTL());
qDebug() << "Using a disk cache size of" << cacheSize << "MiB";
@@ -1511,12 +1516,12 @@ void Session::configurePeerClasses()
void Session::adjustLimits(libt::session_settings &sessionSettings)
{
//Internally increase the queue limits to ensure that the magnet is started
// Internally increase the queue limits to ensure that the magnet is started
int maxDownloads = maxActiveDownloads();
int maxActive = maxActiveTorrents();
sessionSettings.active_downloads = maxDownloads > -1 ? maxDownloads + m_extraLimit : maxDownloads;
sessionSettings.active_limit = maxActive > -1 ? maxActive + m_extraLimit : maxActive;
sessionSettings.active_downloads = (maxDownloads > -1) ? (maxDownloads + m_extraLimit) : maxDownloads;
sessionSettings.active_limit = (maxActive > -1) ? (maxActive + m_extraLimit) : maxActive;
}
void Session::applyBandwidthLimits(libt::session_settings &sessionSettings)
@@ -1535,7 +1540,7 @@ void Session::configure(libtorrent::session_settings &sessionSettings)
encryptionSettings.allowed_enc_level = libt::pe_settings::rc4;
encryptionSettings.prefer_rc4 = true;
switch (encryption()) {
case 0: //Enabled
case 0: // Enabled
encryptionSettings.out_enc_policy = libt::pe_settings::enabled;
encryptionSettings.in_enc_policy = libt::pe_settings::enabled;
break;
@@ -1590,7 +1595,7 @@ void Session::configure(libtorrent::session_settings &sessionSettings)
sessionSettings.announce_to_all_trackers = announceToAllTrackers();
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_expiry = diskCacheTTL();
qDebug() << "Using a disk cache size of" << cacheSize << "MiB";
@@ -1763,7 +1768,7 @@ void Session::enableBandwidthScheduler()
void Session::populateAdditionalTrackers()
{
m_additionalTrackerList.clear();
foreach (QString tracker, additionalTrackers().split("\n")) {
foreach (QString tracker, additionalTrackers().split('\n')) {
tracker = tracker.trimmed();
if (!tracker.isEmpty())
m_additionalTrackerList << tracker;
@@ -1787,7 +1792,7 @@ void Session::processShareLimits()
qDebug("Ratio: %f (limit: %f)", ratio, ratioLimit);
if ((ratio <= TorrentHandle::MAX_RATIO) && (ratio >= ratioLimit)) {
Logger* const logger = Logger::instance();
Logger *const logger = Logger::instance();
if (m_maxRatioAction == Remove) {
logger->addMessage(tr("'%1' reached the maximum ratio you set. Removed.").arg(torrent->name()));
deleteTorrent(torrent->hash());
@@ -1812,7 +1817,7 @@ void Session::processShareLimits()
qDebug("Seeding Time: %d (limit: %d)", seedingTimeInMinutes, seedingTimeLimit);
if ((seedingTimeInMinutes <= TorrentHandle::MAX_SEEDING_TIME) && (seedingTimeInMinutes >= seedingTimeLimit)) {
Logger* const logger = Logger::instance();
Logger *const logger = Logger::instance();
if (m_maxRatioAction == Remove) {
logger->addMessage(tr("'%1' reached the maximum seeding time you set. Removed.").arg(torrent->name()));
deleteTorrent(torrent->hash());
@@ -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));
// Launch downloader
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, SIGNAL(downloadFailed(QString, QString)), this, SLOT(handleDownloadFailed(QString, QString)));
connect(handler, SIGNAL(redirectedToMagnet(QString, QString)), this, SLOT(handleRedirectedToMagnet(QString, QString)));
connect(handler, static_cast<void (Net::DownloadHandler::*)(const QString &, const QString &)>(&Net::DownloadHandler::downloadFinished)
, this, &Session::handleDownloadFinished);
connect(handler, &Net::DownloadHandler::downloadFailed, this, &Session::handleDownloadFailed);
connect(handler, &Net::DownloadHandler::redirectedToMagnet, this, &Session::handleRedirectedToMagnet);
m_downloadedTorrents[handler->url()] = params;
}
else {
@@ -2148,12 +2154,26 @@ bool Session::addTorrent_impl(AddTorrentData addData, const MagnetUri &magnetUri
p = magnetUri.addTorrentParams();
}
else if (torrentInfo.isValid()) {
if (!addData.resumed && !addData.hasRootFolder)
torrentInfo.stripRootFolder();
if (!addData.resumed) {
if (!addData.hasRootFolder)
torrentInfo.stripRootFolder();
// Metadata
if (!addData.hasSeedStatus)
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;
}
}
// Metadata
if (!addData.resumed && !addData.hasSeedStatus)
findIncompleteFiles(torrentInfo, savePath);
p.ti = torrentInfo.nativeInfo();
hash = torrentInfo.hash();
}
@@ -2259,7 +2279,7 @@ bool Session::loadMetadata(const MagnetUri &magnetUri)
InfoHash hash = magnetUri.hash();
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
if (m_torrents.contains(hash)) return false;
if (m_addingTorrents.contains(hash)) return false;
@@ -2404,7 +2424,7 @@ void Session::networkOnlineStateChanged(const bool online)
Logger::instance()->addMessage(tr("System network status changed to %1", "e.g: System network status changed to ONLINE").arg(online ? tr("ONLINE") : tr("OFFLINE")), Log::INFO);
}
void Session::networkConfigurationChange(const QNetworkConfiguration& cfg)
void Session::networkConfigurationChange(const QNetworkConfiguration &cfg)
{
const QString configuredInterfaceName = networkInterface();
// Empty means "Any Interface". In this case libtorrent has binded to 0.0.0.0 so any change to any interface will
@@ -2430,7 +2450,7 @@ void Session::networkConfigurationChange(const QNetworkConfiguration& cfg)
const QStringList Session::getListeningIPs()
{
Logger* const logger = Logger::instance();
Logger *const logger = Logger::instance();
QStringList IPs;
const QString ifaceName = networkInterface();
@@ -2473,12 +2493,12 @@ const QStringList Session::getListeningIPs()
ip = entry.ip();
ipString = ip.toString();
protocol = ip.protocol();
Q_ASSERT(protocol == QAbstractSocket::IPv4Protocol || protocol == QAbstractSocket::IPv6Protocol);
Q_ASSERT((protocol == QAbstractSocket::IPv4Protocol) || (protocol == QAbstractSocket::IPv6Protocol));
if ((!listenIPv6 && (protocol == QAbstractSocket::IPv6Protocol))
|| (listenIPv6 && (protocol == QAbstractSocket::IPv4Protocol)))
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 == ipString) {
IPs.append(ipString);
@@ -2509,7 +2529,7 @@ void Session::configureListeningInterface()
const ushort port = this->port();
qDebug() << Q_FUNC_INFO << port;
Logger* const logger = Logger::instance();
Logger *const logger = Logger::instance();
std::pair<int, int> ports(port, port);
libt::error_code ec;
@@ -2945,7 +2965,7 @@ void Session::setMaxConnectionsPerTorrent(int max)
try {
handle.set_max_connections(max);
}
catch (std::exception) {}
catch (const std::exception &) {}
}
}
}
@@ -2967,7 +2987,7 @@ void Session::setMaxUploadsPerTorrent(int max)
try {
handle.set_max_uploads(max);
}
catch (std::exception) {}
catch (const std::exception &) {}
}
}
}
@@ -3512,7 +3532,7 @@ void Session::handleTorrentTagRemoved(TorrentHandle *const torrent, const QStrin
emit torrentTagRemoved(torrent, tag);
}
void Session::handleTorrentSavingModeChanged(TorrentHandle * const torrent)
void Session::handleTorrentSavingModeChanged(TorrentHandle *const torrent)
{
emit torrentSavingModeChanged(torrent);
}
@@ -3714,8 +3734,8 @@ void Session::enableIPFilter()
// set between clearing the old one and setting the new one.
if (!m_filterParser) {
m_filterParser = new FilterParserThread(this);
connect(m_filterParser.data(), SIGNAL(IPFilterParsed(int)), SLOT(handleIPFilterParsed(int)));
connect(m_filterParser.data(), SIGNAL(IPFilterError()), SLOT(handleIPFilterError()));
connect(m_filterParser.data(), &FilterParserThread::IPFilterParsed, this, &Session::handleIPFilterParsed);
connect(m_filterParser.data(), &FilterParserThread::IPFilterError, this, &Session::handleIPFilterError);
}
m_filterParser->processFilterFile(IPFilterFile());
}
@@ -3798,7 +3818,7 @@ void Session::startUpTorrents()
.arg(params.hash), Log::CRITICAL);
// process add torrent messages before message queue overflow
if (resumedTorrentsCount % 100 == 0) readAlerts();
if ((resumedTorrentsCount % 100) == 0) readAlerts();
++resumedTorrentsCount;
};
@@ -3833,12 +3853,12 @@ void Session::startUpTorrents()
}
else {
int q = queuePosition;
for(; queuedResumeData.contains(q); ++q) {
for (; queuedResumeData.contains(q); ++q) {
}
if (q != queuePosition) {
++numOfRemappedFiles;
}
queuedResumeData[q] = { hash, magnetUri, resumeData, data };
queuedResumeData[q] = {hash, magnetUri, resumeData, data};
}
}
}
@@ -4169,10 +4189,15 @@ void Session::handleFileErrorAlert(libt::file_error_alert *p)
// NOTE: Check this function!
TorrentHandle *const torrent = m_torrents.value(p->handle.info_hash());
if (torrent) {
QString msg = QString::fromStdString(p->message());
Logger::instance()->addMessage(tr("An I/O error occurred, '%1' paused. %2")
.arg(torrent->name(), msg));
emit fullDiskError(torrent, msg);
const InfoHash hash = torrent->hash();
if (!m_recentErroredTorrents.contains(hash)) {
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);
}
m_recentErroredTorrentsTimer->start();
}
}

View File

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

View File

@@ -1,6 +1,6 @@
/*
* 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
* 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),
* but you are not obligated to do so. If you do not wish to do so, delete this
* exception statement from your version.
*
* Contact : chris@qbittorrent.org
*/
#include "torrentcreatorthread.h"

View File

@@ -1,6 +1,6 @@
/*
* 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
* 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),
* but you are not obligated to do so. If you do not wish to do so, delete this
* exception statement from your version.
*
* Contact : chris@qbittorrent.org
*/
#ifndef BITTORRENT_TORRENTCREATORTHREAD_H

View File

@@ -65,7 +65,7 @@
#include "session.h"
#include "trackerentry.h"
const QString QB_EXT {".!qB"};
const QString QB_EXT {QStringLiteral(".!qB")};
namespace libt = libtorrent;
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.
namespace
{
const char i18nContext[] = "TorrentHandle";
// new constructor is available
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)
@@ -521,15 +519,19 @@ int TorrentHandle::piecesHave() const
qreal TorrentHandle::progress() const
{
if (!m_nativeStatus.total_wanted)
return 0.;
if (!isChecking()) {
if (!m_nativeStatus.total_wanted)
return 0.;
if (m_nativeStatus.total_wanted_done == m_nativeStatus.total_wanted)
return 1.;
if (m_nativeStatus.total_wanted_done == m_nativeStatus.total_wanted)
return 1.;
float progress = static_cast<float>(m_nativeStatus.total_wanted_done) / m_nativeStatus.total_wanted;
Q_ASSERT((progress >= 0.f) && (progress <= 1.f));
return progress;
qreal progress = static_cast<qreal>(m_nativeStatus.total_wanted_done) / m_nativeStatus.total_wanted;
Q_ASSERT((progress >= 0.f) && (progress <= 1.f));
return progress;
}
return m_nativeStatus.progress;
}
QString TorrentHandle::category() const
@@ -736,7 +738,8 @@ bool TorrentHandle::isActive() const
|| m_state == TorrentState::Downloading
|| m_state == TorrentState::ForcedDownloading
|| m_state == TorrentState::Uploading
|| m_state == TorrentState::ForcedUploading;
|| m_state == TorrentState::ForcedUploading
|| m_state == TorrentState::Moving;
}
bool TorrentHandle::isInactive() const
@@ -778,28 +781,18 @@ bool TorrentHandle::hasFirstLastPiecePriority() const
if (!hasMetadata())
return m_needsToSetFirstLastPiecePriority;
// Get int first media file
std::vector<int> fp;
fp = m_nativeHandle.file_priorities();
const std::vector<int> filePriorities = nativeHandle().file_priorities();
for (int i = 0; i < static_cast<int>(filePriorities.size()); ++i) {
if (filePriorities[i] <= 0)
continue;
TorrentInfo::PieceRange extremities;
bool found = false;
int count = static_cast<int>(fp.size());
for (int i = 0; i < count; ++i) {
const QString ext = Utils::Fs::fileExtension(filePath(i));
if (Utils::Misc::isPreviewable(ext) && (fp[i] > 0)) {
extremities = info().filePieces(i);
found = true;
break;
}
const TorrentInfo::PieceRange extremities = info().filePieces(i);
const int firstPiecePrio = nativeHandle().piece_priority(extremities.first());
const int lastPiecePrio = nativeHandle().piece_priority(extremities.last());
return ((firstPiecePrio == 7) && (lastPiecePrio == 7));
}
if (!found) return false; // No media file
int first = m_nativeHandle.piece_priority(extremities.first());
int last = m_nativeHandle.piece_priority(extremities.last());
return ((first == 7) && (last == 7));
return false;
}
TorrentState TorrentHandle::state() const
@@ -809,7 +802,10 @@ TorrentState TorrentHandle::state() const
void TorrentHandle::updateState()
{
if (isPaused()) {
if (isMoveInProgress()) {
m_state = TorrentState::Moving;
}
else if (isPaused()) {
if (hasMissingFiles())
m_state = TorrentState::MissingFiles;
else if (hasError())
@@ -1296,39 +1292,37 @@ void TorrentHandle::toggleSequentialDownload()
setSequentialDownload(!isSequentialDownload());
}
void TorrentHandle::setFirstLastPiecePriority(bool b)
void TorrentHandle::setFirstLastPiecePriority(const bool enabled)
{
if (!hasMetadata()) {
m_needsToSetFirstLastPiecePriority = b;
m_needsToSetFirstLastPiecePriority = enabled;
return;
}
std::vector<int> fp = m_nativeHandle.file_priorities();
std::vector<int> pp = m_nativeHandle.piece_priorities();
// Download first and last pieces first for every file in the torrent
const std::vector<int> filePriorities = nativeHandle().file_priorities();
std::vector<int> piecePriorities = nativeHandle().piece_priorities();
for (int index = 0; index < static_cast<int>(filePriorities.size()); ++index) {
const int filePrio = filePriorities[index];
if (filePrio <= 0)
continue;
// Download first and last pieces first for all media files in the torrent
int nbfiles = static_cast<int>(fp.size());
for (int index = 0; index < nbfiles; ++index) {
const QString path = filePath(index);
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
const int newPrio = enabled ? 7 : filePrio;
const TorrentInfo::PieceRange extremities = info().filePieces(index);
// Determine the priority to set
int prio = b ? 7 : fp[index];
TorrentInfo::PieceRange extremities = info().filePieces(index);
// worst case: AVI index = 1% of total file size (at the end of the file)
int nNumPieces = ceil(fileSize(index) * 0.01 / pieceLength());
for (int i = 0; i < nNumPieces; ++i) {
pp[extremities.first() + i] = prio;
pp[extremities.last() - i] = prio;
}
// worst case: AVI index = 1% of total file size (at the end of the file)
const int nNumPieces = std::ceil(fileSize(index) * 0.01 / pieceLength());
for (int i = 0; i < nNumPieces; ++i) {
piecePriorities[extremities.first() + i] = newPrio;
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()
@@ -1376,6 +1370,7 @@ void TorrentHandle::moveStorage(const QString &newPath, bool overwrite)
, (overwrite ? libt::always_replace_files : libt::dont_replace));
m_moveStorageInfo.oldPath = oldPath;
m_moveStorageInfo.newPath = newPath;
updateState();
}
}
@@ -1425,7 +1420,7 @@ void TorrentHandle::handleStateUpdate(const libt::torrent_status &nativeStatus)
updateStatus(nativeStatus);
}
void TorrentHandle::handleStorageMovedAlert(libtorrent::storage_moved_alert *p)
void TorrentHandle::handleStorageMovedAlert(const libtorrent::storage_moved_alert *p)
{
if (!isMoveInProgress()) {
qWarning() << "Unexpected " << Q_FUNC_INFO << " call.";
@@ -1442,8 +1437,8 @@ void TorrentHandle::handleStorageMovedAlert(libtorrent::storage_moved_alert *p)
return;
}
qDebug("Torrent is successfully moved from %s to %s"
, qUtf8Printable(m_moveStorageInfo.oldPath), qUtf8Printable(m_moveStorageInfo.newPath));
LogMsg(tr("Successfully moved torrent: %1. New path: %2").arg(name(), m_moveStorageInfo.newPath));
const QDir oldDir {m_moveStorageInfo.oldPath};
if ((oldDir == QDir(m_session->torrentTempPath(info())))
&& (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;
Utils::Fs::smartRemoveEmptyFolderTree(m_moveStorageInfo.oldPath);
}
updateStatus();
m_moveStorageInfo.newPath.clear();
updateStatus();
if (!m_moveStorageInfo.queuedPath.isEmpty()) {
moveStorage(m_moveStorageInfo.queuedPath, m_moveStorageInfo.queuedOverwrite);
m_moveStorageInfo.queuedPath.clear();
@@ -1469,17 +1465,19 @@ void TorrentHandle::handleStorageMovedAlert(libtorrent::storage_moved_alert *p)
m_moveFinishedTriggers.takeFirst()();
}
void TorrentHandle::handleStorageMovedFailedAlert(libtorrent::storage_moved_failed_alert *p)
void TorrentHandle::handleStorageMovedFailedAlert(const libtorrent::storage_moved_failed_alert *p)
{
if (!isMoveInProgress()) {
qWarning() << "Unexpected " << Q_FUNC_INFO << " call.";
return;
}
LogMsg(QCoreApplication::translate(i18nContext, "Could not move torrent: '%1'. Reason: %2")
.arg(name(), QString::fromStdString(p->message())), Log::CRITICAL);
LogMsg(tr("Could not move torrent: '%1'. Reason: %2")
.arg(name(), QString::fromStdString(p->message())), Log::CRITICAL);
m_moveStorageInfo.newPath.clear();
updateStatus();
if (!m_moveStorageInfo.queuedPath.isEmpty()) {
moveStorage(m_moveStorageInfo.queuedPath, m_moveStorageInfo.queuedOverwrite);
m_moveStorageInfo.queuedPath.clear();
@@ -1489,7 +1487,7 @@ void TorrentHandle::handleStorageMovedFailedAlert(libtorrent::storage_moved_fail
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
QString trackerUrl = QString::fromStdString(p->url);
@@ -1504,32 +1502,32 @@ void TorrentHandle::handleTrackerReplyAlert(libtorrent::tracker_reply_alert *p)
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
QString trackerUrl = QString::fromStdString(p->url);
QString message = QString::fromStdString(p->msg);
const QString trackerUrl = QString::fromStdString(p->url);
const QString message = QString::fromStdString(p->msg);
#else
QString trackerUrl(p->tracker_url());
QString message = QString::fromStdString(p->message());
const QString trackerUrl = p->tracker_url();
const QString message = p->warning_message();
#endif
qDebug("Received a tracker warning for %s: %s", qUtf8Printable(trackerUrl), qUtf8Printable(message));
// Connection was successful now but there is a warning message
m_trackerInfos[trackerUrl].lastMessage = message; // Store warning message
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
QString trackerUrl = QString::fromStdString(p->url);
QString message = QString::fromStdString(p->msg);
const QString trackerUrl = QString::fromStdString(p->url);
const QString message = QString::fromStdString(p->msg);
#else
QString trackerUrl(p->tracker_url());
QString message = QString::fromStdString(p->message());
const QString trackerUrl = p->tracker_url();
const QString message = p->error_message();
#endif
qDebug("Received a tracker error for %s: %s", qUtf8Printable(trackerUrl), qUtf8Printable(message));
m_trackerInfos[trackerUrl].lastMessage = message;
if (p->status_code == 401)
@@ -1538,7 +1536,7 @@ void TorrentHandle::handleTrackerErrorAlert(libtorrent::tracker_error_alert *p)
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);
qDebug("%s have just finished checking", qUtf8Printable(hash()));
@@ -1561,7 +1559,7 @@ void TorrentHandle::handleTorrentCheckedAlert(libtorrent::torrent_checked_alert
m_session->handleTorrentChecked(this);
}
void TorrentHandle::handleTorrentFinishedAlert(libtorrent::torrent_finished_alert *p)
void TorrentHandle::handleTorrentFinishedAlert(const libtorrent::torrent_finished_alert *p)
{
Q_UNUSED(p);
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);
updateStatus();
@@ -1596,13 +1594,13 @@ void TorrentHandle::handleTorrentPausedAlert(libtorrent::torrent_paused_alert *p
m_session->handleTorrentPaused(this);
}
void TorrentHandle::handleTorrentResumedAlert(libtorrent::torrent_resumed_alert *p)
void TorrentHandle::handleTorrentResumedAlert(const libtorrent::torrent_resumed_alert *p)
{
Q_UNUSED(p);
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);
libtorrent::entry dummyEntry;
@@ -1636,36 +1634,35 @@ void TorrentHandle::handleSaveResumeDataAlert(libtorrent::save_resume_data_alert
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
// containing Magnet URI and qBittorrent own resume data only
if (p->error.value() == libt::errors::no_metadata)
handleSaveResumeDataAlert(0);
handleSaveResumeDataAlert(nullptr);
else
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());
Logger *const logger = Logger::instance();
updateStatus();
if (p->error.value() == libt::errors::mismatching_file_size) {
// 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;
if (!isPaused())
pause();
}
else {
logger->addMessage(QCoreApplication::translate(i18nContext, "Fast resume data was rejected for torrent '%1'. Reason: %2. Checking again...")
.arg(name(), QString::fromStdString(p->message())), Log::CRITICAL);
LogMsg(tr("Fast resume data was rejected for torrent '%1'. Reason: %2. Checking again...")
.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
QString newName = Utils::Fs::fromNativePath(QString::fromStdString(p->name));
@@ -1697,7 +1694,7 @@ void TorrentHandle::handleFileRenamedAlert(libtorrent::file_renamed_alert *p)
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);
@@ -1706,7 +1703,7 @@ void TorrentHandle::handleFileRenameFailedAlert(libtorrent::file_rename_failed_a
m_moveFinishedTriggers.takeFirst()();
}
void TorrentHandle::handleFileCompletedAlert(libtorrent::file_completed_alert *p)
void TorrentHandle::handleFileCompletedAlert(const libtorrent::file_completed_alert *p)
{
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);
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);
}
void TorrentHandle::handleMetadataReceivedAlert(libt::metadata_received_alert *p)
void TorrentHandle::handleMetadataReceivedAlert(const libt::metadata_received_alert *p)
{
Q_UNUSED(p);
qDebug("Metadata received for torrent %s.", qUtf8Printable(name()));

View File

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

View File

@@ -26,20 +26,20 @@
* exception statement from your version.
*/
#include <QDebug>
#include <QString>
#include <QList>
#include <QUrl>
#include <QDateTime>
#include "torrentinfo.h"
#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/misc.h"
#include "base/utils/string.h"
#include "infohash.h"
#include "trackerentry.h"
#include "torrentinfo.h"
namespace libt = libtorrent;
using namespace BitTorrent;
@@ -315,7 +315,7 @@ QVector<QByteArray> TorrentInfo::pieceHashes() const
return hashes;
}
TorrentInfo::PieceRange TorrentInfo::filePieces(const QString& file) const
TorrentInfo::PieceRange TorrentInfo::filePieces(const QString &file) const
{
if (!isValid()) // if we do not check here the debug message will be printed, which would be not correct
return {};
@@ -353,8 +353,8 @@ void TorrentInfo::renameFile(uint index, const QString &newPath)
int BitTorrent::TorrentInfo::fileIndex(const QString& fileName) const
{
// the check whether the object valid is not needed here
// because filesCount() returns -1 in that case and the loop exits immediately
// the check whether the object is valid is not needed here
// because if filesCount() returns -1 the loop exits immediately
for (int i = 0; i < filesCount(); ++i)
if (fileName == filePath(i))
return i;
@@ -362,24 +362,29 @@ int BitTorrent::TorrentInfo::fileIndex(const QString& fileName) const
return -1;
}
bool TorrentInfo::hasRootFolder() const
QString TorrentInfo::rootFolder() const
{
QString testRootFolder;
QString rootFolder;
for (int i = 0; i < filesCount(); ++i) {
const QString filePath = this->filePath(i);
if (QDir::isAbsolutePath(filePath)) continue;
const auto filePathElements = filePath.splitRef('/');
// 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())
testRootFolder = filePathElements.at(0).toString();
else if (testRootFolder != filePathElements.at(0))
return false;
if (rootFolder.isEmpty())
rootFolder = filePathElements.at(0).toString();
else if (rootFolder != filePathElements.at(0))
return "";
}
return true;
return rootFolder;
}
bool TorrentInfo::hasRootFolder() const
{
return !rootFolder().isEmpty();
}
void TorrentInfo::stripRootFolder()

View File

@@ -29,21 +29,21 @@
#ifndef BITTORRENT_TORRENTINFO_H
#define BITTORRENT_TORRENTINFO_H
#include <QCoreApplication>
#include <QtGlobal>
#include <libtorrent/torrent_info.hpp>
#include <libtorrent/version.hpp>
#include <QCoreApplication>
#include <QList>
#include <QtGlobal>
#include <QVector>
#include "base/indexrange.h"
class QString;
class QUrl;
class QDateTime;
class QStringList;
class QByteArray;
template<typename T> class QList;
template<typename T> class QVector;
class QDateTime;
class QString;
class QStringList;
class QUrl;
namespace BitTorrent
{
@@ -52,7 +52,7 @@ namespace BitTorrent
class TorrentInfo
{
Q_DECLARE_TR_FUNCTIONS("TorrentInfo")
Q_DECLARE_TR_FUNCTIONS(TorrentInfo)
public:
#if LIBTORRENT_VERSION_NUM < 10100
@@ -104,6 +104,7 @@ namespace BitTorrent
void renameFile(uint index, const QString &newPath);
QString rootFolder() const;
bool hasRootFolder() const;
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) 2006 Christophe Dumez <chris@qbittorrent.org>
*
@@ -27,6 +27,8 @@
* exception statement from your version.
*/
#include "tracker.h"
#include <vector>
#include <libtorrent/bencode.hpp>
@@ -37,7 +39,6 @@
#include "base/preferences.h"
#include "base/utils/bytearray.h"
#include "base/utils/string.h"
#include "tracker.h"
// static limits
static const int MAX_TORRENTS = 100;
@@ -277,5 +278,3 @@ void Tracker::replyWithPeerList(const TrackerAnnounceRequest &annonceReq)
// HTTP reply
print(reply, Http::CONTENT_TYPE_TXT);
}

View File

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

View File

@@ -2,7 +2,7 @@
* Bittorrent Client using Qt and libtorrent.
* Copyright (C) 2018 Mike Tzou (Chocobo1)
* 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
* 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),
* but you are not obligated to do so. If you do not wish to do so, delete this
* exception statement from your version.
*
* Contact : chris@qbittorrent.org
*/
#include "connection.h"

View File

@@ -1,7 +1,7 @@
/*
* Bittorrent Client using Qt and libtorrent.
* 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
* 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),
* but you are not obligated to do so. If you do not wish to do so, delete this
* exception statement from your version.
*
* Contact : chris@qbittorrent.org
*/
@@ -50,7 +48,7 @@ namespace Http
Q_DISABLE_COPY(Connection)
public:
Connection(QTcpSocket *socket, IRequestHandler *requestHandler, QObject *parent = 0);
Connection(QTcpSocket *socket, IRequestHandler *requestHandler, QObject *parent = nullptr);
~Connection();
bool hasExpired(qint64 timeout) const;

View File

@@ -291,7 +291,7 @@ bool RequestParser::parseFormData(const QByteArray &data)
const QLatin1String name("name");
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)) {
m_request.posts[headersMap[name]] = payload;

View File

@@ -47,7 +47,7 @@ void IconProvider::freeInstance()
{
if (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";
}
IconProvider *IconProvider::m_instance = 0;
IconProvider *IconProvider::m_instance = nullptr;

View File

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

View File

@@ -3,12 +3,12 @@
#include <QDateTime>
#include "base/utils/string.h"
Logger* Logger::m_instance = 0;
Logger *Logger::m_instance = nullptr;
Logger::Logger()
: lock(QReadWriteLock::Recursive)
, msgCounter(0)
, peerCounter(0)
: m_lock(QReadWriteLock::Recursive)
, m_msgCounter(0)
, m_peerCounter(0)
{
}
@@ -29,15 +29,15 @@ void Logger::freeInstance()
{
if (m_instance) {
delete m_instance;
m_instance = 0;
m_instance = nullptr;
}
}
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);
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)
{
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);
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
{
QReadLocker locker(&lock);
QReadLocker locker(&m_lock);
int diff = msgCounter - lastKnownId - 1;
int diff = m_msgCounter - lastKnownId - 1;
int size = m_messages.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
{
QReadLocker locker(&lock);
QReadLocker locker(&m_lock);
int diff = peerCounter - lastKnownId - 1;
int diff = m_peerCounter - lastKnownId - 1;
int size = m_peers.size();
if ((lastKnownId == -1) || (diff >= size))

View File

@@ -1,10 +1,10 @@
#ifndef LOGGER_H
#define LOGGER_H
#include <QObject>
#include <QReadWriteLock>
#include <QString>
#include <QVector>
#include <QReadWriteLock>
#include <QObject>
const int MAX_LOG_MESSAGES = 20000;
@@ -16,7 +16,7 @@ namespace Log
NORMAL = 0x1,
INFO = 0x2,
WARNING = 0x4,
CRITICAL = 0x8 //ERROR is defined by libtorrent and results in compiler error
CRITICAL = 0x8 // ERROR is defined by libtorrent and results in compiler error
};
Q_DECLARE_FLAGS(MsgTypes, MsgType)
@@ -63,12 +63,12 @@ private:
Logger();
~Logger();
static Logger* m_instance;
static Logger *m_instance;
QVector<Log::Msg> m_messages;
QVector<Log::Peer> m_peers;
mutable QReadWriteLock lock;
int msgCounter;
int peerCounter;
mutable QReadWriteLock m_lock;
int m_msgCounter;
int m_peerCounter;
};
// Helper function

View File

@@ -52,7 +52,7 @@ DNSUpdater::DNSUpdater(QObject *parent)
// Start IP checking timer
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();
// Check lastUpdate to avoid flooding
@@ -77,8 +77,9 @@ void DNSUpdater::checkPublicIP()
DownloadHandler *handler = DownloadManager::instance()->downloadUrl(
"http://checkip.dyndns.org", false, 0, false,
"qBittorrent/" QBT_VERSION_2);
connect(handler, SIGNAL(downloadFinished(QString, QByteArray)), SLOT(ipRequestFinished(QString, QByteArray)));
connect(handler, SIGNAL(downloadFailed(QString, QString)), SLOT(ipRequestFailed(QString, QString)));
connect(handler, static_cast<void (Net::DownloadHandler::*)(const QString &, const QByteArray &)>(&Net::DownloadHandler::downloadFinished)
, this, &DNSUpdater::ipRequestFinished);
connect(handler, &Net::DownloadHandler::downloadFailed, this, &DNSUpdater::ipRequestFailed);
m_lastIPCheckTime = QDateTime::currentDateTime();
}
@@ -124,8 +125,9 @@ void DNSUpdater::updateDNSService()
DownloadHandler *handler = DownloadManager::instance()->downloadUrl(
getUpdateUrl(), false, 0, false,
"qBittorrent/" QBT_VERSION_2);
connect(handler, SIGNAL(downloadFinished(QString, QByteArray)), SLOT(ipUpdateFinished(QString, QByteArray)));
connect(handler, SIGNAL(downloadFailed(QString, QString)), SLOT(ipUpdateFailed(QString, QString)));
connect(handler, static_cast<void (Net::DownloadHandler::*)(const QString &, const QByteArray &)>(&Net::DownloadHandler::downloadFinished)
, this, &DNSUpdater::ipUpdateFinished);
connect(handler, &Net::DownloadHandler::downloadFailed, this, &DNSUpdater::ipUpdateFailed);
}
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)));
}
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) {
@@ -137,8 +137,8 @@ void DownloadHandler::init()
{
m_reply->setParent(this);
if (m_sizeLimit > 0)
connect(m_reply, SIGNAL(downloadProgress(qint64, qint64)), this, SLOT(checkDownloadSize(qint64, qint64)));
connect(m_reply, SIGNAL(finished()), this, SLOT(processFinishedDownload()));
connect(m_reply, &QNetworkReply::downloadProgress, this, &Net::DownloadHandler::checkDownloadSize);
connect(m_reply, &QNetworkReply::finished, this, &Net::DownloadHandler::processFinishedDownload);
}
bool DownloadHandler::saveToFile(const QByteArray &replyData, QString &filePath)

View File

@@ -48,10 +48,10 @@ const char DEFAULT_USER_AGENT[] = "Mozilla/5.0 (X11; Linux i686; rv:38.0) Gecko/
namespace
{
class NetworkCookieJar: public QNetworkCookieJar
class NetworkCookieJar : public QNetworkCookieJar
{
public:
explicit NetworkCookieJar(QObject *parent = 0)
explicit NetworkCookieJar(QObject *parent = nullptr)
: QNetworkCookieJar(parent)
{
QDateTime now = QDateTime::currentDateTime();
@@ -107,13 +107,13 @@ namespace
using namespace Net;
DownloadManager *DownloadManager::m_instance = 0;
DownloadManager *DownloadManager::m_instance = nullptr;
DownloadManager::DownloadManager(QObject *parent)
: QObject(parent)
{
#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
m_networkManager.setCookieJar(new NetworkCookieJar(this));
}
@@ -128,7 +128,7 @@ void DownloadManager::freeInstance()
{
if (m_instance) {
delete m_instance;
m_instance = 0;
m_instance = nullptr;
}
}

View File

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

View File

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

View File

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

View File

@@ -26,25 +26,23 @@
* exception statement from your version.
*/
#include <QDateTime>
#include <QDebug>
#include <QVariant>
#include <QFile>
#include <QHash>
#include <QHostAddress>
#include <QDateTime>
#include <QFile>
#include <QVariant>
#include "base/types.h"
#include "geoipdatabase.h"
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 char DB_TYPE[] = "GeoLite2-Country";
const quint32 MAX_METADATA_SIZE = 131072; // 128KB
const char METADATA_BEGIN_MARK[] = "\xab\xcd\xefMaxMind.com";
const char DATA_SECTION_SEPARATOR[16] = { 0 };
const char DATA_SECTION_SEPARATOR[16] = {0};
enum class DataType
{
@@ -91,7 +89,7 @@ GeoIPDatabase::GeoIPDatabase(quint32 size)
GeoIPDatabase *GeoIPDatabase::load(const QString &filename, QString &error)
{
GeoIPDatabase *db = 0;
GeoIPDatabase *db = nullptr;
QFile file(filename);
if (file.size() > MAX_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 *db = 0;
GeoIPDatabase *db = nullptr;
if (data.size() > MAX_FILE_SIZE) {
error = tr("Unsupported database file size.");
return 0;
@@ -448,8 +446,12 @@ bool GeoIPDatabase::readDataFieldDescriptor(quint32 &offset, DataFieldDescriptor
void GeoIPDatabase::fromBigEndian(uchar *buf, quint32 len) const
{
if (__IS_LITTLE_ENDIAN__)
std::reverse(buf, buf + len);
#if (Q_BYTE_ORDER == Q_LITTLE_ENDIAN)
std::reverse(buf, buf + len);
#else
Q_UNUSED(buf);
Q_UNUSED(len);
#endif
}
QVariant GeoIPDatabase::readMapValue(quint32 &offset, quint32 count) const

View File

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

View File

@@ -27,9 +27,10 @@
*/
#include "proxyconfigurationmanager.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_TYPE = SETTINGS_KEY("Type");
const QString KEY_IP = SETTINGS_KEY("IP");
@@ -80,7 +81,7 @@ void ProxyConfigurationManager::freeInstance()
{
if (m_instance) {
delete m_instance;
m_instance = 0;
m_instance = nullptr;
}
}

View File

@@ -52,7 +52,7 @@ namespace Net
QString password;
};
class ProxyConfigurationManager: public QObject
class ProxyConfigurationManager : public QObject
{
Q_OBJECT
Q_DISABLE_COPY(ProxyConfigurationManager)

View File

@@ -1,6 +1,6 @@
/*
* 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
* 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),
* but you are not obligated to do so. If you do not wish to do so, delete this
* 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 <QHostInfo>
#include <QString>
#include <boost/version.hpp>
#include <boost/asio/ip/tcp.hpp>
#include "reverseresolution.h"
const int CACHE_SIZE = 500;
using namespace Net;
static inline bool isUsefulHostName(const QString &hostname, const QString &ip)
{
return (!hostname.isEmpty() && hostname != ip);
return (!hostname.isEmpty() && (hostname != ip));
}
ReverseResolution::ReverseResolution(QObject *parent)
@@ -67,7 +65,11 @@ void ReverseResolution::resolve(const QString &ip)
}
else {
// 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);
#endif
}
}

View File

@@ -1,6 +1,6 @@
/*
* 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
* 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),
* but you are not obligated to do so. If you do not wish to do so, delete this
* exception statement from your version.
*
* Contact : chris@qbittorrent.org
*/
#ifndef NET_REVERSERESOLUTION_H
@@ -34,10 +32,8 @@
#include <QCache>
#include <QObject>
QT_BEGIN_NAMESPACE
class QHostInfo;
class QString;
QT_END_NAMESPACE
namespace Net
{
@@ -47,7 +43,7 @@ namespace Net
Q_DISABLE_COPY(ReverseResolution)
public:
explicit ReverseResolution(QObject *parent = 0);
explicit ReverseResolution(QObject *parent = nullptr);
~ReverseResolution();
void resolve(const QString &ip);

View File

@@ -111,9 +111,10 @@ Smtp::Smtp(QObject *parent)
m_socket = new QTcpSocket(this);
#endif
connect(m_socket, SIGNAL(readyRead()), SLOT(readyRead()));
connect(m_socket, SIGNAL(disconnected()), SLOT(deleteLater()));
connect(m_socket, SIGNAL(error(QAbstractSocket::SocketError)), SLOT(error(QAbstractSocket::SocketError)));
connect(m_socket, &QIODevice::readyRead, this, &Smtp::readyRead);
connect(m_socket, &QAbstractSocket::disconnected, this, &QObject::deleteLater);
connect(m_socket, static_cast<void (QAbstractSocket::*)(QAbstractSocket::SocketError)>(&QAbstractSocket::error)
, this, &Smtp::error);
// Test hmacMD5 function (http://www.faqs.org/rfcs/rfc2202.html)
Q_ASSERT(hmacMD5("Jefe", "what do ya want for nothing?").toHex()
@@ -129,8 +130,8 @@ Smtp::~Smtp()
void Smtp::sendMail(const QString &from, const QString &to, const QString &subject, const QString &body)
{
const Preferences* const pref = Preferences::instance();
QTextCodec* latin1 = QTextCodec::codecForName("latin1");
const Preferences *const pref = Preferences::instance();
QTextCodec *latin1 = QTextCodec::codecForName("latin1");
m_message = "Date: " + getCurrentDateTime().toLatin1() + "\r\n"
+ encodeMimeHeader("From", from, latin1)
+ encodeMimeHeader("Subject", subject, latin1)
@@ -140,8 +141,8 @@ void Smtp::sendMail(const QString &from, const QString &to, const QString &subje
+ "Content-Transfer-Encoding: base64\r\n"
+ "\r\n";
// Encode the body in base64
QString crlf_body = body;
QByteArray b = crlf_body.replace("\n", "\r\n").toUtf8().toBase64();
QString crlfBody = body;
QByteArray b = crlfBody.replace("\n", "\r\n").toUtf8().toBase64();
int ct = b.length();
for (int i = 0; i < ct; i += 78)
m_message += b.mid(i, 78);
@@ -164,7 +165,7 @@ void Smtp::sendMail(const QString &from, const QString &to, const QString &subje
m_socket->connectToHost(pref->getMailNotificationSMTP(), DEFAULT_PORT);
m_useSsl = false;
#ifndef QT_NO_OPENSSL
}
}
#endif
}
@@ -183,7 +184,7 @@ void Smtp::readyRead()
QByteArray code = line.left(3);
switch (m_state) {
case Init: {
case Init:
if (code[0] == '2') {
// The server may send a multiline greeting/INIT/220 response.
// We wait until it finishes.
@@ -197,7 +198,6 @@ void Smtp::readyRead()
m_state = Close;
}
break;
}
case EhloSent:
case HeloSent:
case EhloGreetReceived:
@@ -447,7 +447,7 @@ void Smtp::startTLS()
#endif
}
void Smtp::authCramMD5(const QByteArray& challenge)
void Smtp::authCramMD5(const QByteArray &challenge)
{
if (m_state != AuthRequestSent) {
m_socket->write("auth cram-md5\r\n");

View File

@@ -1,7 +1,7 @@
/*
* Bittorrent Client using Qt4 and libtorrent.
* Copyright (C) 2006 Christophe Dumez
* Copyright (C) 2014 sledgehammer999
* Bittorrent Client using Qt and libtorrent.
* Copyright (C) 2014 sledgehammer999 <sledgehammer999@qbittorrent.org>
* Copyright (C) 2006 Christophe Dumez <chris@qbittorrent.org>
*
* This program is free software; you can redistribute it and/or
* 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),
* but you are not obligated to do so. If you do not wish to do so, delete this
* exception statement from your version.
*
* Contact : chris@qbittorrent.org
* Contact : hammered999@gmail.com
*/
#include "preferences.h"
@@ -59,7 +56,7 @@
#include "utils/fs.h"
#include "utils/misc.h"
Preferences *Preferences::m_instance = 0;
Preferences *Preferences::m_instance = nullptr;
Preferences::Preferences() = default;
@@ -78,7 +75,7 @@ void Preferences::freeInstance()
{
if (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);
}
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));
}
@@ -690,12 +687,12 @@ QString Preferences::getUILockPasswordMD5() const
return value("Locking/password").toString();
}
void Preferences::setUILockPassword(const QString &clear_password)
void Preferences::setUILockPassword(const QString &clearPassword)
{
QCryptographicHash md5(QCryptographicHash::Md5);
md5.addData(clear_password.toLocal8Bit());
QString md5_password = md5.result().toHex();
setValue("Locking/password", md5_password);
md5.addData(clearPassword.toLocal8Bit());
QString md5Password = md5.result().toHex();
setValue("Locking/password", md5Password);
}
bool Preferences::isUILocked() const

View File

@@ -1,7 +1,7 @@
/*
* Bittorrent Client using Qt4 and libtorrent.
* Copyright (C) 2006 Christophe Dumez
* Copyright (C) 2014 sledgehammer999
* Bittorrent Client using Qt and libtorrent.
* Copyright (C) 2014 sledgehammer999 <sledgehammer999@qbittorrent.org>
* Copyright (C) 2006 Christophe Dumez <chris@qbittorrent.org>
*
* This program is free software; you can redistribute it and/or
* 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),
* but you are not obligated to do so. If you do not wish to do so, delete this
* exception statement from your version.
*
* Contact : chris@qbittorrent.org
* Contact : hammered999@gmail.com
*/
#ifndef PREFERENCES_H
@@ -47,7 +44,7 @@
#include "base/utils/net.h"
#include "types.h"
enum scheduler_days
enum SchedulerDays
{
EVERY_DAY,
WEEK_DAYS,
@@ -83,7 +80,7 @@ namespace DNS
class SettingsStorage;
class Preferences: public QObject
class Preferences : public QObject
{
Q_OBJECT
Q_DISABLE_COPY(Preferences)
@@ -166,8 +163,8 @@ public:
void setSchedulerStartTime(const QTime &time);
QTime getSchedulerEndTime() const;
void setSchedulerEndTime(const QTime &time);
scheduler_days getSchedulerDays() const;
void setSchedulerDays(scheduler_days days);
SchedulerDays getSchedulerDays() const;
void setSchedulerDays(SchedulerDays days);
// Search
bool isSearchEnabled() const;
@@ -222,7 +219,7 @@ public:
void setDynDNSPassword(const QString &password);
// Advanced settings
void setUILockPassword(const QString &clear_password);
void setUILockPassword(const QString &clearPassword);
void clearUILockPassword();
QString getUILockPasswordMD5() 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),
* but you are not obligated to do so. If you do not wish to do so, delete this
* exception statement from your version.
*
*/
#ifndef QBT_PROFILE_P_H
@@ -33,6 +32,7 @@
#include <QDir>
#include <QStandardPaths>
#include "base/profile.h"
namespace Private
@@ -63,7 +63,7 @@ namespace Private
};
/// Default implementation. Takes paths from system
class DefaultProfile: public Profile
class DefaultProfile : public Profile
{
public:
DefaultProfile(const QString &configurationName);
@@ -86,7 +86,7 @@ namespace Private
};
/// Custom tree: creates directories under the specified root directory
class CustomProfile: public Profile
class CustomProfile : public Profile
{
public:
CustomProfile(const QString &rootPath, const QString &configurationName);
@@ -114,14 +114,14 @@ namespace Private
virtual ~PathConverter() = default;
};
class NoConvertConverter: public PathConverter
class NoConvertConverter : public PathConverter
{
public:
QString toPortablePath(const QString &path) const override;
QString fromPortablePath(const QString &portablePath) const override;
};
class Converter: public PathConverter
class Converter : public PathConverter
{
public:
Converter(const QString &basePath);
@@ -132,4 +132,5 @@ namespace Private
QDir m_baseDir;
};
}
#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),
* but you are not obligated to do so. If you do not wish to do so, delete this
* exception statement from your version.
*
*/
#include "profile.h"

View File

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

View File

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

View File

@@ -48,7 +48,7 @@ namespace RSS
QList<QVariantHash> articles;
};
class Parser: public QObject
class Parser : public QObject
{
Q_OBJECT

View File

@@ -38,6 +38,19 @@
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::KeyDate(QStringLiteral("date"));
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_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 (m_guid.isEmpty())
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(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

View File

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

View File

@@ -365,19 +365,7 @@ void AutoDownloader::processJob(const QSharedPointer<ProcessingJob> &job)
for (AutoDownloadRule &rule: m_rules) {
if (!rule.isEnabled()) continue;
if (!rule.feedURLs().contains(job->feedURL)) continue;
if (!rule.matches(job->articleData.value(Article::KeyTitle).toString())) 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();
if (!rule.accepts(job->articleData)) continue;
m_dirty = true;
storeDeferred();

View File

@@ -59,7 +59,7 @@ namespace RSS
QString message() const;
};
class AutoDownloader final: public QObject
class AutoDownloader final : public QObject
{
Q_OBJECT
Q_DISABLE_COPY(AutoDownloader)

View File

@@ -39,13 +39,14 @@
#include <QString>
#include <QStringList>
#include "../global.h"
#include "../preferences.h"
#include "../tristatebool.h"
#include "../utils/fs.h"
#include "../utils/string.h"
#include "rss_feed.h"
#include "rss_article.h"
#include "rss_autodownloader.h"
#include "rss_feed.h"
namespace
{
@@ -105,7 +106,7 @@ const QString Str_PreviouslyMatched(QStringLiteral("previouslyMatchedEpisodes"))
namespace RSS
{
struct AutoDownloadRuleData: public QSharedData
struct AutoDownloadRuleData : public QSharedData
{
QString name;
bool enabled = true;
@@ -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
// episode filter are modified.
Q_ASSERT(!expression.isEmpty());
QRegularExpression regex(m_dataPtr->cachedRegexes[expression]);
if (!regex.pattern().isEmpty())
return regex;
QRegularExpression &regex = m_dataPtr->cachedRegexes[expression];
if (regex.pattern().isEmpty()) {
regex = QRegularExpression {
(isRegex ? expression : Utils::String::wildcardToRegex(expression))
, QRegularExpression::CaseInsensitiveOption};
}
return m_dataPtr->cachedRegexes[expression] = QRegularExpression(isRegex ? expression : Utils::String::wildcardToRegex(expression), QRegularExpression::CaseInsensitiveOption);
return regex;
}
bool AutoDownloadRule::matches(const QString &articleTitle, const QString &expression) const
bool AutoDownloadRule::matchesExpression(const QString &articleTitle, const QString &expression) const
{
static QRegularExpression whitespace("\\s+");
const QRegularExpression whitespace {"\\s+"};
if (expression.isEmpty()) {
// A regex of the form "expr|" will always match, so do the same for wildcards
return true;
}
else if (m_dataPtr->useRegex) {
if (m_dataPtr->useRegex) {
QRegularExpression reg(cachedRegex(expression));
return reg.match(articleTitle).hasMatch();
}
else {
// 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 *).
foreach (const QString &wildcard, expression.split(whitespace, QString::SplitBehavior::SkipEmptyParts)) {
QRegularExpression reg(cachedRegex(wildcard, false));
if (!reg.match(articleTitle).hasMatch())
return false;
}
// 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 *).
const QStringList wildcards {expression.split(whitespace, QString::SplitBehavior::SkipEmptyParts)};
for (const QString &wildcard : wildcards) {
const QRegularExpression reg {cachedRegex(wildcard, false)};
if (!reg.match(articleTitle).hasMatch())
return false;
}
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
m_dataPtr->lastComputedEpisode.clear();
if (!m_dataPtr->mustContain.empty()) {
bool logged = false;
bool foundMustContain = false;
if (m_dataPtr->episodeFilter.isEmpty())
return true;
// Each expression is either a regex, or a set of wildcards separated by whitespace.
// Accept if any complete expression matches.
foreach (const QString &expression, m_dataPtr->mustContain) {
if (!logged) {
// qDebug() << "Checking matching" << (m_dataPtr->useRegex ? "regex:" : "wildcard expressions:") << m_dataPtr->mustContain.join("|");
logged = true;
const QRegularExpression filterRegex {cachedRegex("(^\\d{1,4})x(.*;$)")};
const QRegularExpressionMatch matcher {filterRegex.match(m_dataPtr->episodeFilter)};
if (!matcher.hasMatch())
return false;
const QString season {matcher.captured(1)};
const QStringList episodes {matcher.captured(2).split(';')};
const int seasonOurs {season.toInt()};
for (QString episode : episodes) {
if (episode.isEmpty())
continue;
// We need to trim leading zeroes, but if it's all zeros then we want episode zero.
while ((episode.size() > 1) && episode.startsWith('0'))
episode = episode.right(episode.size() - 1);
if (episode.indexOf('-') != -1) { // Range detected
const QString partialPattern1 {"\\bs0?(\\d{1,4})[ -_\\.]?e(0?\\d{1,4})(?:\\D|\\b)"};
const QString partialPattern2 {"\\b(\\d{1,4})x(0?\\d{1,4})(?:\\D|\\b)"};
// Extract partial match from article and compare as digits
QRegularExpressionMatch matcher = cachedRegex(partialPattern1).match(articleTitle);
bool matched = matcher.hasMatch();
if (!matched) {
matcher = cachedRegex(partialPattern2).match(articleTitle);
matched = matcher.hasMatch();
}
// A regex of the form "expr|" will always match, so do the same for wildcards
foundMustContain = matches(articleTitle, expression);
if (matched) {
const int seasonTheirs {matcher.captured(1).toInt()};
const int episodeTheirs {matcher.captured(2).toInt()};
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;
QString s = matcher.captured(1);
QStringList eps = matcher.captured(2).split(";");
int sOurs = s.toInt();
foreach (QString ep, eps) {
if (ep.isEmpty())
continue;
// We need to trim leading zeroes, but if it's all zeros then we want episode zero.
while (ep.size() > 1 && ep.startsWith("0"))
ep = ep.right(ep.size() - 1);
if (ep.indexOf('-') != -1) { // Range detected
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)";
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
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) && (epTheirs >= epOurs)) || (sTheirs > sOurs)) {
// qDebug() << "Matched episode:" << ep;
// qDebug() << "Matched article:" << articleTitle;
return true;
}
}
if (episode.endsWith('-')) { // Infinite range
const int episodeOurs {episode.leftRef(episode.size() - 1).toInt()};
if (((seasonTheirs == seasonOurs) && (episodeTheirs >= episodeOurs)) || (seasonTheirs > seasonOurs))
return true;
}
else { // Normal range
QStringList range = ep.split('-');
const QStringList range {episode.split('-')};
Q_ASSERT(range.size() == 2);
if (range.first().toInt() > range.last().toInt())
continue; // Ignore this subrule completely
int epOursFirst = range.first().toInt();
int epOursLast = range.last().toInt();
// 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;
}
}
}
}
else { // Single number
QString expStr("\\b(?:s0?" + s + "[ -_\\.]?" + "e0?" + ep + "|" + s + "x" + "0?" + ep + ")(?:\\D|\\b)");
QRegularExpression reg(cachedRegex(expStr));
if (reg.match(articleTitle).hasMatch()) {
// qDebug() << "Matched episode:" << ep;
// qDebug() << "Matched article:" << articleTitle;
return true;
const int episodeOursFirst {range.first().toInt()};
const int episodeOursLast {range.last().toInt()};
if ((seasonTheirs == seasonOurs) && ((episodeOursFirst <= episodeTheirs) && (episodeOursLast >= episodeTheirs)))
return true;
}
}
}
else { // Single number
const QString expStr {QString("\\b(?:s0?%1[ -_\\.]?e0?%2|%1x0?%2)(?:\\D|\\b)").arg(season, episode)};
if (cachedRegex(expStr).match(articleTitle).hasMatch())
return true;
}
}
return false;
}
bool AutoDownloadRule::matchesSmartEpisodeFilter(const QString& articleTitle) const
{
if (!useSmartFilter())
return true;
const QString episodeStr = computeEpisodeName(articleTitle);
if (episodeStr.isEmpty())
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)
return false;
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;
}
if (useSmartFilter()) {
// now see if this episode has been downloaded before
const QString episodeStr = computeEpisodeName(articleTitle);
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;
if (!episodeStr.isEmpty()) {
bool previouslyMatched = m_dataPtr->previouslyMatchedEpisodes.contains(episodeStr);
bool isRepack = articleTitle.contains("REPACK", Qt::CaseInsensitive) || articleTitle.contains("PROPER", Qt::CaseInsensitive);
if (previouslyMatched && !isRepack)
return false;
return true;
}
m_dataPtr->lastComputedEpisode = episodeStr;
}
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;
}
@@ -642,15 +644,6 @@ void AutoDownloadRule::setPreviouslyMatchedEpisodes(const QStringList &previousl
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
{
return m_dataPtr->episodeFilter;

View File

@@ -71,7 +71,6 @@ namespace RSS
QString episodeFilter() const;
void setEpisodeFilter(const QString &e);
void appendLastComputedEpisode();
QStringList previouslyMatchedEpisodes() const;
void setPreviouslyMatchedEpisodes(const QStringList &previouslyMatchedEpisodes);
@@ -82,7 +81,8 @@ namespace RSS
QString assignedCategory() const;
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);
bool operator==(const AutoDownloadRule &other) const;
@@ -95,7 +95,11 @@ namespace RSS
static AutoDownloadRule fromLegacyDict(const QVariantHash &dict);
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;
QSharedDataPointer<AutoDownloadRuleData> m_dataPtr;

View File

@@ -212,7 +212,13 @@ void Feed::handleParsingFinished(const RSS::Private::ParsingResult &result)
m_lastBuildDate = result.lastBuildDate;
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 {
auto article = new Article(this, varHash);
if (addArticle(article))

View File

@@ -49,7 +49,7 @@ namespace RSS
struct ParsingResult;
}
class Feed final: public Item
class Feed final : public Item
{
Q_OBJECT
Q_DISABLE_COPY(Feed)

View File

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

View File

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

View File

@@ -39,7 +39,7 @@ namespace RSS
class Folder;
class Session;
class Item: public QObject
class Item : public QObject
{
Q_OBJECT
Q_DISABLE_COPY(Item)
@@ -58,7 +58,7 @@ namespace RSS
virtual QJsonValue toJsonValue(bool withData = false) const = 0;
static const QString PathSeparator;
static const QChar PathSeparator;
static bool isValidPath(const QString &path);
static QString joinPath(const QString &path1, const QString &path2);

View File

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

View File

@@ -69,11 +69,11 @@ class AsyncFileStorage;
namespace RSS
{
class Item;
class Feed;
class Folder;
class Item;
class Session: public QObject
class Session : public QObject
{
Q_OBJECT
Q_DISABLE_COPY(Session)

View File

@@ -1,6 +1,6 @@
/*
* 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
* 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),
* but you are not obligated to do so. If you do not wish to do so, delete this
* exception statement from your version.
*
* Contact : chris@qbittorrent.org
*/
#include "scanfoldersmodel.h"
@@ -56,7 +54,7 @@ struct ScanFoldersModel::PathData
QString downloadPath; // valid for CUSTOM_LOCATION
};
ScanFoldersModel *ScanFoldersModel::m_instance = 0;
ScanFoldersModel *ScanFoldersModel::m_instance = nullptr;
bool ScanFoldersModel::initInstance(QObject *parent)
{
@@ -72,7 +70,7 @@ void ScanFoldersModel::freeInstance()
{
if (m_instance) {
delete m_instance;
m_instance = 0;
m_instance = nullptr;
}
}
@@ -83,10 +81,10 @@ ScanFoldersModel *ScanFoldersModel::instance()
ScanFoldersModel::ScanFoldersModel(QObject *parent)
: QAbstractListModel(parent)
, m_fsWatcher(0)
, m_fsWatcher(nullptr)
{
configure();
connect(Preferences::instance(), SIGNAL(changed()), SLOT(configure()));
connect(Preferences::instance(), &Preferences::changed, this, &ScanFoldersModel::configure);
}
ScanFoldersModel::~ScanFoldersModel()
@@ -222,7 +220,7 @@ ScanFoldersModel::PathStatus ScanFoldersModel::addPath(const QString &watchPath,
if (!m_fsWatcher) {
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());
@@ -235,7 +233,7 @@ ScanFoldersModel::PathStatus ScanFoldersModel::addPath(const QString &watchPath,
return Ok;
}
ScanFoldersModel::PathStatus ScanFoldersModel::updatePath(const QString &watchPath, const PathType& downloadType, const QString &downloadPath)
ScanFoldersModel::PathStatus ScanFoldersModel::updatePath(const QString &watchPath, const PathType &downloadType, const QString &downloadPath)
{
QDir watchDir(watchPath);
const QString &canonicalWatchPath = watchDir.canonicalPath();

View File

@@ -1,6 +1,6 @@
/*
* 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
* 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),
* but you are not obligated to do so. If you do not wish to do so, delete this
* exception statement from your version.
*
* Contact : chris@qbittorrent.org
*/
#ifndef SCANFOLDERSMODEL_H
@@ -37,7 +35,7 @@
class QStringList;
class FileSystemWatcher;
class ScanFoldersModel: public QAbstractListModel
class ScanFoldersModel : public QAbstractListModel
{
Q_OBJECT
Q_DISABLE_COPY(ScanFoldersModel)
@@ -66,9 +64,9 @@ public:
CUSTOM_LOCATION
};
static bool initInstance(QObject *parent = 0);
static bool initInstance(QObject *parent = nullptr);
static void freeInstance();
static ScanFoldersModel* instance();
static ScanFoldersModel *instance();
static QString pathTypeDisplayName(const PathType type);
@@ -97,7 +95,7 @@ private slots:
void addTorrentsToSession(const QStringList &pathList);
private:
explicit ScanFoldersModel(QObject *parent = 0);
explicit ScanFoldersModel(QObject *parent = nullptr);
~ScanFoldersModel();
virtual bool setData(const QModelIndex &index, const QVariant &value, int role = Qt::EditRole);

View File

@@ -76,7 +76,7 @@ SearchHandler::SearchHandler(const QString &pattern, const QString &category, co
#if (QT_VERSION >= QT_VERSION_CHECK(5, 6, 0))
connect(m_searchProcess, &QProcess::errorOccurred, this, &SearchHandler::processFailed);
#else
connect(m_searchProcess, static_cast<void(QProcess::*)(QProcess::ProcessError)>(&QProcess::error)
connect(m_searchProcess, static_cast<void (QProcess::*)(QProcess::ProcessError)>(&QProcess::error)
, this, &SearchHandler::processFailed);
#endif
connect(m_searchProcess, &QProcess::readyReadStandardOutput, this, &SearchHandler::readSearchOutput);

View File

@@ -42,8 +42,8 @@
#include "base/global.h"
#include "base/logger.h"
#include "base/net/downloadmanager.h"
#include "base/net/downloadhandler.h"
#include "base/net/downloadmanager.h"
#include "base/preferences.h"
#include "base/profile.h"
#include "base/utils/fs.h"
@@ -62,18 +62,6 @@ namespace
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()
: m_updateUrl(QString("http://searchplugins.qbittorrent.org/%1/engines/").arg(Utils::Misc::pythonVersion() >= 3 ? "nova3" : "nova"))
{
@@ -268,7 +256,7 @@ bool SearchPluginManager::uninstallPlugin(const QString &name)
return true;
}
void SearchPluginManager::updateIconPath(PluginInfo * const plugin)
void SearchPluginManager::updateIconPath(PluginInfo *const plugin)
{
if (!plugin) return;
QString iconPath = QString("%1/%2.png").arg(pluginsLocation(), plugin->name);
@@ -307,7 +295,18 @@ SearchHandler *SearchPluginManager::startSearch(const QString &pattern, const QS
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)

View File

@@ -73,7 +73,7 @@ public:
void updatePlugin(const QString &name);
void installPlugin(const QString &source);
bool uninstallPlugin(const QString &name);
static void updateIconPath(PluginInfo * const plugin);
static void updateIconPath(PluginInfo *const plugin);
void checkForUpdates();
SearchHandler *startSearch(const QString &pattern, const QString &category, const QStringList &usedPlugins);
@@ -111,7 +111,6 @@ private:
static QString pluginPath(const QString &name);
static QPointer<SearchPluginManager> m_instance;
static const QHash<QString, QString> m_categoryNames;
const QString m_updateUrl;

View File

@@ -1,7 +1,7 @@
/*
* Bittorrent Client using Qt and libtorrent.
* 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
* modify it under the terms of the GNU General Public License
@@ -62,15 +62,12 @@ namespace
QString deserialize(const QString &name, 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)
{
static const MappingTable keyMapping = {
static const QHash<QString, QString> keyMapping = {
{"BitTorrent/Session/MaxRatioAction", "Preferences/Bittorrent/MaxRatioAction"},
{"BitTorrent/Session/DefaultSavePath", "Preferences/Downloads/SavePath"},
{"BitTorrent/Session/TempPath", "Preferences/Downloads/TempPath"},
@@ -147,7 +144,6 @@ namespace
{"AddNewTorrentDialog/TopLevel", "Preferences/Downloads/NewAdditionDialogFront"},
{"State/BannedIPs", "Preferences/IPFilter/BannedIPs"}
};
return keyMapping.value(key, key);
@@ -163,7 +159,7 @@ SettingsStorage::SettingsStorage()
{
m_timer.setSingleShot(true);
m_timer.setInterval(5 * 1000);
connect(&m_timer, SIGNAL(timeout()), SLOT(save()));
connect(&m_timer, &QTimer::timeout, this, &SettingsStorage::save);
}
SettingsStorage::~SettingsStorage()
@@ -200,6 +196,7 @@ bool SettingsStorage::save()
return true;
}
m_timer.start();
return false;
}
@@ -211,7 +208,7 @@ QVariant SettingsStorage::loadValue(const QString &key, const QVariant &defaultV
void SettingsStorage::storeValue(const QString &key, const QVariant &value)
{
QString realKey = mapKey(key);
const QString realKey = mapKey(key);
QWriteLocker locker(&m_lock);
if (m_data.value(realKey) != value) {
m_dirty = true;
@@ -222,7 +219,7 @@ void SettingsStorage::storeValue(const QString &key, const QVariant &value)
void SettingsStorage::removeValue(const QString &key)
{
QString realKey = mapKey(key);
const QString realKey = mapKey(key);
QWriteLocker locker(&m_lock);
if (m_data.contains(realKey)) {
m_dirty = true;
@@ -234,36 +231,39 @@ void SettingsStorage::removeValue(const QString &key)
QVariantHash TransactionalSettings::read()
{
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
// 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
// in their final position. So assume that qbittorrent_new.ini/qbittorrent_new.conf
// contains the most recent settings.
Logger::instance()->addMessage(QObject::tr("Detected unclean program exit. Using fallback file to restore settings."), Log::WARNING);
writeBackNeeded = true;
Logger::instance()->addMessage(QObject::tr("Detected unclean program exit. Using fallback file to restore settings: %1")
.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 {
deserialize(m_name, res);
}
Utils::Fs::forceRemove(newPath);
if (writeBackNeeded)
write(res);
return res;
}
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
// 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
// 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()) {
Utils::Fs::forceRemove(newPath);
return false;
@@ -272,10 +272,9 @@ bool TransactionalSettings::write(const QVariantHash &data)
QString finalPath = newPath;
int index = finalPath.lastIndexOf("_new", -1, Qt::CaseInsensitive);
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)
@@ -301,13 +300,19 @@ QString TransactionalSettings::serialize(const QString &name, const QVariantHash
settings->setValue(i.key(), i.value());
settings->sync(); // Important to get error status
QSettings::Status status = settings->status();
if (status != QSettings::NoError) {
if (status == QSettings::AccessError)
Logger::instance()->addMessage(QObject::tr("An access error occurred while trying to write the configuration file."), Log::CRITICAL);
else
Logger::instance()->addMessage(QObject::tr("A format error occurred while trying to write the configuration file."), Log::CRITICAL);
return QString();
switch (settings->status()) {
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);
break;
case QSettings::FormatError:
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 settings->fileName();
return QString();
}

View File

@@ -1,7 +1,7 @@
/*
* Bittorrent Client using Qt and libtorrent.
* 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
* modify it under the terms of the GNU General Public License
@@ -31,11 +31,11 @@
#define SETTINGSSTORAGE_H
#include <QObject>
#include <QVariantHash>
#include <QTimer>
#include <QReadWriteLock>
#include <QTimer>
#include <QVariantHash>
class SettingsStorage: public QObject
class SettingsStorage : public QObject
{
Q_OBJECT
SettingsStorage();
@@ -44,7 +44,7 @@ class SettingsStorage: public QObject
public:
static void initInstance();
static void freeInstance();
static SettingsStorage* instance();
static SettingsStorage *instance();
QVariant loadValue(const QString &key, const QVariant &defaultValue = QVariant()) const;
void storeValue(const QString &key, const QVariant &value);

View File

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

View File

@@ -51,7 +51,7 @@ private:
/// Reads settings for .torrent files from preferences
/// and sets the file guard up accordingly
class TorrentFileGuard: private FileGuard
class TorrentFileGuard : private FileGuard
{
Q_GADGET

View File

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

View File

@@ -1,6 +1,6 @@
/*
* 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
* 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),
* but you are not obligated to do so. If you do not wish to do so, delete this
* exception statement from your version.
*
* Contact : chris@qbittorrent.org
*/
#include "fs.h"
#include <cstring>
#include <QCoreApplication>
#include <QDebug>
#include <QDir>
#include <QDirIterator>
#include <QFile>
#include <QFileInfo>
#include <QDirIterator>
#include <QCoreApplication>
#include <QStorageInfo>
#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.
*/
@@ -169,7 +167,6 @@ bool Utils::Fs::forceRemove(const QString &filePath)
/**
* Removes directory and its content recursively.
*
*/
void Utils::Fs::removeDirRecursive(const QString &path)
{

View File

@@ -1,6 +1,6 @@
/*
* 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
* 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),
* but you are not obligated to do so. If you do not wish to do so, delete this
* exception statement from your version.
*
* Contact : chris@qbittorrent.org
*/
#ifndef UTILS_FS_H
@@ -52,7 +50,7 @@ namespace Utils
, const QString &pad = QLatin1String(" "));
bool isValidFileSystemName(const QString &name, bool allowSeparators = false);
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);
QString expandPath(const QString &path);
QString expandPathAbs(const QString &path);

View File

@@ -1,6 +1,6 @@
/*
* 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
* 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),
* but you are not obligated to do so. If you do not wish to do so, delete this
* exception statement from your version.
*
* Contact : chris@qbittorrent.org
*/
#include "misc.h"
@@ -52,6 +50,7 @@
#include <QDir>
#include <QFileInfo>
#include <QProcess>
#include <QRegExp>
#include <QRegularExpression>
#include <QSysInfo>
#include <QUrl>
@@ -62,17 +61,19 @@
#include <QApplication>
#include <QDesktopServices>
#include <QDesktopWidget>
#include <QProcess>
#include <QStyle>
#if (defined(Q_OS_UNIX) && !defined(Q_OS_MAC)) && defined(QT_DBUS_LIB)
#include <QDBusInterface>
#include <QDBusMessage>
#endif
#if defined(Q_OS_UNIX) && !defined(Q_OS_MAC)
#include "base/utils/version.h"
#endif
#endif
#include "base/utils/string.h"
#include "base/unicodestrings.h"
#include "base/logger.h"
#include "base/unicodestrings.h"
#include "base/utils/string.h"
#include "fs.h"
namespace
@@ -141,7 +142,7 @@ void Utils::Misc::shutdownComputer(const ShutdownDialogAction &action)
else
EventToSend = kAEShutDown;
AEAddressDesc targetDesc;
static const ProcessSerialNumber kPSNOfSystemProcess = { 0, kSystemProcess };
static const ProcessSerialNumber kPSNOfSystemProcess = {0, kSystemProcess};
AppleEvent eventReply = {typeNull, NULL};
AppleEvent appleEventToSend = {typeNull, NULL};
@@ -271,12 +272,12 @@ QString Utils::Misc::pythonExecutable()
* On Unix-Like Systems python2 and python3 should always exist
* 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)) {
executable = "python3";
return executable;
}
pythonProc.start("python2", QStringList() << "--version", QIODevice::ReadOnly);
pythonProc.start("python2", {"--version"}, QIODevice::ReadOnly);
if (pythonProc.waitForFinished() && (pythonProc.exitCode() == 0)) {
executable = "python2";
return executable;
@@ -284,7 +285,7 @@ QString Utils::Misc::pythonExecutable()
#endif
// Look for "python" in Windows and in UNIX if "python2" and "python3" are
// not detected.
pythonProc.start("python", QStringList() << "--version", QIODevice::ReadOnly);
pythonProc.start("python", {"--version"}, QIODevice::ReadOnly);
if (pythonProc.waitForFinished() && (pythonProc.exitCode() == 0))
executable = "python";
else
@@ -305,7 +306,7 @@ QString Utils::Misc::pythonVersionComplete()
if (pythonExecutable().isEmpty())
return version;
QProcess pythonProc;
pythonProc.start(pythonExecutable(), QStringList() << "--version", QIODevice::ReadOnly);
pythonProc.start(pythonExecutable(), {"--version"}, QIODevice::ReadOnly);
if (pythonProc.waitForFinished() && (pythonProc.exitCode() == 0)) {
QByteArray output = pythonProc.readAllStandardOutput();
if (output.isEmpty())
@@ -525,9 +526,9 @@ bool Utils::Misc::isUrl(const QString &s)
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(
"(\\s|^)" // start with whitespace or beginning of line
"("
@@ -621,21 +622,33 @@ void Utils::Misc::openFolderSelect(const QString &absolutePath)
::CoUninitialize();
#elif defined(Q_OS_UNIX) && !defined(Q_OS_MAC)
QProcess proc;
proc.start("xdg-mime", QStringList() << "query" << "default" << "inode/directory");
proc.start("xdg-mime", {"query", "default", "inode/directory"});
proc.waitForFinished();
QString output = proc.readLine().simplified();
if ((output == "dolphin.desktop") || (output == "org.kde.dolphin.desktop"))
proc.startDetached("dolphin", QStringList() << "--select" << Utils::Fs::toNativePath(path));
if ((output == "dolphin.desktop") || (output == "org.kde.dolphin.desktop")) {
proc.startDetached("dolphin", {"--select", Utils::Fs::toNativePath(path)});
}
else if ((output == "nautilus.desktop") || (output == "org.gnome.Nautilus.desktop")
|| (output == "nautilus-folder-handler.desktop"))
proc.startDetached("nautilus", QStringList() << "--no-desktop" << Utils::Fs::toNativePath(path));
else if (output == "nemo.desktop")
proc.startDetached("nemo", QStringList() << "--no-desktop" << Utils::Fs::toNativePath(path));
else if ((output == "konqueror.desktop") || (output == "kfmclient_dir.desktop"))
proc.startDetached("konqueror", QStringList() << "--select" << Utils::Fs::toNativePath(path));
else
|| (output == "nautilus-folder-handler.desktop")) {
proc.start("nautilus", {"--version"});
proc.waitForFinished();
const QString nautilusVerStr = QString(proc.readLine()).remove(QRegExp("[^0-9.]"));
using NautilusVersion = Utils::Version<int, 3>;
if (NautilusVersion::tryParse(nautilusVerStr, {1, 0, 0}) > NautilusVersion {3, 28})
proc.startDetached("nautilus", {Utils::Fs::toNativePath(path)});
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
openPath(path.left(path.lastIndexOf("/")));
}
#else
openPath(path.left(path.lastIndexOf("/")));
#endif

View File

@@ -1,6 +1,6 @@
/*
* 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
* 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),
* but you are not obligated to do so. If you do not wish to do so, delete this
* exception statement from your version.
*
* Contact : chris@qbittorrent.org
*/
#ifndef UTILS_MISC_H
@@ -73,7 +71,7 @@ namespace Utils
// YobiByte, // 1024^8
};
QString parseHtmlLinks(const QString &raw_text);
QString parseHtmlLinks(const QString &rawText);
bool isUrl(const QString &s);
void shutdownComputer(const ShutdownDialogAction &action);
@@ -88,16 +86,16 @@ namespace Utils
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
bool friendlyUnit(qint64 sizeInBytes, qreal& val, SizeUnit& unit);
bool friendlyUnit(qint64 sizeInBytes, qreal &val, SizeUnit &unit);
QString friendlyUnit(qint64 bytesValue, bool isSpeed = false);
int friendlyUnitPrecision(SizeUnit unit);
qint64 sizeInBytes(qreal size, SizeUnit unit);
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".
QString userFriendlyDuration(qlonglong seconds);
QString getUserIDString();
@@ -108,8 +106,8 @@ namespace Utils
QList<bool> boolListfromStringList(const QStringList &l);
#ifndef DISABLE_GUI
void openPath(const QString& absolutePath);
void openFolderSelect(const QString& absolutePath);
void openPath(const QString &absolutePath);
void openFolderSelect(const QString &absolutePath);
QPoint screenCenter(const QWidget *w);
#endif
@@ -136,4 +134,4 @@ namespace Utils
}
}
#endif
#endif // UTILS_MISC_H

View File

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

View File

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

View File

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

View File

@@ -117,7 +117,7 @@ namespace Utils
{
// find the last one non-zero component
std::size_t lastSignificantIndex = N - 1;
while (lastSignificantIndex > 0 && (*this)[lastSignificantIndex] == 0)
while ((lastSignificantIndex > 0) && ((*this)[lastSignificantIndex] == 0))
--lastSignificantIndex;
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>");
#endif
logo->setPixmap(Utils::Gui::scaledPixmap(":/icons/skin/qbittorrent32.png", this));
logo->setPixmap(Utils::Gui::scaledPixmapSvg(":/icons/skin/qbittorrent-tray.svg", this, 32));
// About
QString aboutText = QString(

View File

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

View File

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

View File

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

View File

@@ -115,7 +115,7 @@ AdvancedSettings::AdvancedSettings(QWidget *parent)
{
// column
setColumnCount(COL_COUNT);
QStringList header = { tr("Setting"), tr("Value", "Value set for this setting") };
QStringList header = {tr("Setting"), tr("Value", "Value set for this setting")};
setHorizontalHeaderLabels(header);
// row
setRowCount(ROW_COUNT);
@@ -125,8 +125,10 @@ AdvancedSettings::AdvancedSettings(QWidget *parent)
setSelectionMode(QAbstractItemView::NoSelection);
setEditTriggers(QAbstractItemView::NoEditTriggers);
// Signals
connect(&spin_cache, SIGNAL(valueChanged(int)), SLOT(updateCacheSpinSuffix(int)));
connect(&combo_iface, SIGNAL(currentIndexChanged(int)), SLOT(updateInterfaceAddressCombo()));
connect(&spin_cache, static_cast<void (QSpinBox::*)(int)>(&QSpinBox::valueChanged)
, this, &AdvancedSettings::updateCacheSpinSuffix);
connect(&combo_iface, static_cast<void (QComboBox::*)(int)>(&QComboBox::currentIndexChanged)
, this, &AdvancedSettings::updateInterfaceAddressCombo);
// Load settings
loadAdvancedSettings();
resizeColumnToContents(0);
@@ -360,7 +362,7 @@ void AdvancedSettings::loadAdvancedSettings()
outgoing_ports_max.setValue(session->outgoingPortsMax());
addRow(OUTGOING_PORT_MAX, tr("Outgoing ports (Max) [0: Disabled]"), &outgoing_ports_max);
// 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()));
addRow(UTP_MIX_MODE, tr("%1-TCP mixed mode algorithm", "uTP-TCP mixed mode algorithm").arg(C_UTP), &comboUtpMixedMode);
// multiple connections per IP
@@ -447,11 +449,11 @@ void AdvancedSettings::loadAdvancedSettings()
spin_tracker_port.setValue(pref->getTrackerPort());
addRow(TRACKER_PORT, tr("Embedded tracker port"), &spin_tracker_port);
// 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()));
addRow(CHOKING_ALGORITHM, tr("Upload slots behavior"), &comboChokingAlgorithm);
// 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()));
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,
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:
void showEvent(QShowEvent *e);

View File

@@ -174,17 +174,15 @@ CategoryFilterModel::CategoryFilterModel(QObject *parent)
: QAbstractItemModel(parent)
, 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, SIGNAL(categoryRemoved(QString)), SLOT(categoryRemoved(QString)));
connect(session, SIGNAL(torrentCategoryChanged(BitTorrent::TorrentHandle *const, QString))
, SLOT(torrentCategoryChanged(BitTorrent::TorrentHandle *const, QString)));
connect(session, SIGNAL(subcategoriesSupportChanged()), SLOT(subcategoriesSupportChanged()));
connect(session, SIGNAL(torrentAdded(BitTorrent::TorrentHandle *const))
, SLOT(torrentAdded(BitTorrent::TorrentHandle *const)));
connect(session, SIGNAL(torrentAboutToBeRemoved(BitTorrent::TorrentHandle *const))
, SLOT(torrentAboutToBeRemoved(BitTorrent::TorrentHandle *const)));
connect(session, &Session::categoryAdded, this, &CategoryFilterModel::categoryAdded);
connect(session, &Session::categoryRemoved, this, &CategoryFilterModel::categoryRemoved);
connect(session, &Session::torrentCategoryChanged, this, &CategoryFilterModel::torrentCategoryChanged);
connect(session, &Session::subcategoriesSupportChanged, this, &CategoryFilterModel::subcategoriesSupportChanged);
connect(session, &Session::torrentAdded, this, &CategoryFilterModel::torrentAdded);
connect(session, &Session::torrentAboutToBeRemoved, this, &CategoryFilterModel::torrentAboutToBeRemoved);
populate();
}

View File

@@ -37,7 +37,7 @@
#include "ui_cookiesdialog.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_COOKIESVIEWSTATE = SETTINGS_KEY("CookiesViewState");

View File

@@ -59,7 +59,7 @@ class DeletionConfirmationDlg : public QDialog, private Ui::confirmDeletionDlg {
rememberBtn->setIconSize(Utils::Gui::mediumIconSize());
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();
Utils::Gui::resize(this);

View File

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

View File

@@ -41,7 +41,6 @@
namespace
{
const char i18nContext[] = "FileSystemPathEdit";
struct TrStringWithComment
{
const char *source;
@@ -49,18 +48,18 @@ namespace
QString tr() const
{
return QCoreApplication::translate(i18nContext, source, comment);
return QCoreApplication::translate("FileSystemPathEdit", source, comment);
}
};
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 =
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 =
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 =
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

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