mirror of
https://github.com/qbittorrent/qBittorrent.git
synced 2025-12-22 16:37:21 -06:00
Compare commits
73 Commits
release-5.
...
release-4.
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
ea5a29018f | ||
|
|
c8d0a715e8 | ||
|
|
2cfc6514ab | ||
|
|
1d78bc7206 | ||
|
|
e5577e43f8 | ||
|
|
17c0463906 | ||
|
|
4168772904 | ||
|
|
44f2186749 | ||
|
|
0c918bcc3a | ||
|
|
0a8925dc75 | ||
|
|
a446597597 | ||
|
|
54354a2732 | ||
|
|
d94b8f08ab | ||
|
|
0d8189efeb | ||
|
|
00c886e426 | ||
|
|
551fc35439 | ||
|
|
9ff17c8d9d | ||
|
|
ec37732e99 | ||
|
|
8a414f32a8 | ||
|
|
bac06acb49 | ||
|
|
ae1e3c2a81 | ||
|
|
67940eb0f9 | ||
|
|
007aa8480e | ||
|
|
dedec10c58 | ||
|
|
75219e21be | ||
|
|
10f5964f8e | ||
|
|
a4a64d51c0 | ||
|
|
1014313d88 | ||
|
|
e486bb4c29 | ||
|
|
5c3d9ffb46 | ||
|
|
2e474fd8db | ||
|
|
b2b110ae1f | ||
|
|
68a34e0738 | ||
|
|
38fa575958 | ||
|
|
6cfeefe054 | ||
|
|
8007971a53 | ||
|
|
d66bd30fae | ||
|
|
3fa59b1b12 | ||
|
|
20e7aff393 | ||
|
|
4b7ce87f57 | ||
|
|
2075533468 | ||
|
|
a4ad5c8d11 | ||
|
|
35f2f56757 | ||
|
|
e6f4aa6a2f | ||
|
|
92fc62bb0d | ||
|
|
44b57a59f5 | ||
|
|
97b8e02bf5 | ||
|
|
5df42420cb | ||
|
|
0ede11a1b7 | ||
|
|
7d9c282db9 | ||
|
|
bc0e0813a4 | ||
|
|
f3aebb3001 | ||
|
|
800f966df9 | ||
|
|
e33df4dd8c | ||
|
|
96d9d810fd | ||
|
|
8707a1bc86 | ||
|
|
0c988a5fd4 | ||
|
|
b396ca771d | ||
|
|
a37dfcf961 | ||
|
|
31989740cd | ||
|
|
501191289b | ||
|
|
8971e92d78 | ||
|
|
0c96e79d0d | ||
|
|
0704c0f5e6 | ||
|
|
9cb190ebe7 | ||
|
|
667f84995c | ||
|
|
7a93fae6e4 | ||
|
|
0d6deca15c | ||
|
|
f54d7d46f2 | ||
|
|
8cf00ba5e1 | ||
|
|
ecc9c6bbd9 | ||
|
|
e11199f988 | ||
|
|
e9ed621178 |
@@ -1,6 +1,8 @@
|
|||||||
cmake_minimum_required(VERSION 3.5)
|
cmake_minimum_required(VERSION 3.5)
|
||||||
cmake_policy(VERSION 3.5)
|
cmake_policy(VERSION 3.5)
|
||||||
|
|
||||||
|
message(WARNING "No official support for cmake build system. If it is broken, please submit patches!")
|
||||||
|
|
||||||
list(APPEND CMAKE_MODULE_PATH ${CMAKE_CURRENT_SOURCE_DIR}/cmake/Modules)
|
list(APPEND CMAKE_MODULE_PATH ${CMAKE_CURRENT_SOURCE_DIR}/cmake/Modules)
|
||||||
include(FunctionReadVersion)
|
include(FunctionReadVersion)
|
||||||
|
|
||||||
|
|||||||
@@ -239,11 +239,11 @@ The headers should be placed in the following group order:
|
|||||||
4. Boost library headers
|
4. Boost library headers
|
||||||
5. Libtorrent headers
|
5. Libtorrent headers
|
||||||
6. Qt headers
|
6. Qt headers
|
||||||
7. qBittorrent own headers, starting from *base* headers.
|
7. qBittorrent's own headers, starting from the *base* headers.
|
||||||
|
|
||||||
The headers should be ordered alphabetically within each group.
|
The headers should be ordered alphabetically within each group.
|
||||||
If there are conditionals for the same header group, then put them at the bottom of the respective group.
|
If there are conditionals for the same header group, then put them at the bottom of the respective group.
|
||||||
If there are conditionals for the different header groups, then put them above of the "qBittorrent own headers" group.
|
If there are conditionals that contain headers from several different header groups, then put them above the "qBittorrent's own headers" group.
|
||||||
|
|
||||||
One exception is the header containing the library version (for example, QtGlobal), this particular header isn't constrained by the aforementioned order.
|
One exception is the header containing the library version (for example, QtGlobal), this particular header isn't constrained by the aforementioned order.
|
||||||
|
|
||||||
@@ -285,13 +285,13 @@ Example:
|
|||||||
#include <QFont>
|
#include <QFont>
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
// conditional for the different header groups
|
// conditional that contains headers from several different header groups
|
||||||
#if LIBTORRENT_VERSION_NUM >= 10100
|
#if LIBTORRENT_VERSION_NUM >= 10100
|
||||||
#include <memory>
|
#include <memory>
|
||||||
#include <QElapsedTimer>
|
#include <QElapsedTimer>
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
// qBittorrent own headers
|
// qBittorrent's own headers
|
||||||
#include "base/bittorrent/infohash.h"
|
#include "base/bittorrent/infohash.h"
|
||||||
#include "anothermodule.h"
|
#include "anothermodule.h"
|
||||||
#include "ui_examplewidget.h"
|
#include "ui_examplewidget.h"
|
||||||
|
|||||||
36
Changelog
36
Changelog
@@ -1,3 +1,39 @@
|
|||||||
|
* Sun May 27 2018 - sledgehammer999 <sledgehammer999@qbittorrent.org> - v4.1.1
|
||||||
|
- FEATURE: Add 'Moving' state for torrents being relocated/moved (sledgehammer999)
|
||||||
|
- FEATURE: Show rechecking progress (sledgehammer999)
|
||||||
|
- FEATURE: Add option to remember last used save path (glassez)
|
||||||
|
- FEATURE: Torrent name is also renamed if the content was renamed in the "Add New Torrent" dialog (glassez)
|
||||||
|
- FEATURE: Relax behavior of "Download first and last piece first". It applies to all files and not only to the previewable. (Chocobo1)
|
||||||
|
- BUGFIX: Fix issues with translatable strings (Chocobo1)
|
||||||
|
- BUGFIX: Fix displayed tracker messages (Chocobo1)
|
||||||
|
- BUGFIX: Make settings file recovery more robust (Chocobo1)
|
||||||
|
- BUGFIX: Retry saving settings when operation failed (Chocobo1)
|
||||||
|
- BUGFIX: Log successful torrent move (sledgehammer999)
|
||||||
|
- BUGFIX: Fix deletion of old logs (sledgehammer999)
|
||||||
|
- BUGFIX: Delete non-commited fastresume files (sledgehammer999)
|
||||||
|
- BUGFIX: Don't migrate torrents that have newer fastresumes (sledgehammer999)
|
||||||
|
- BUGFIX: Fix adding multiple torrents at once from WebUI (glassez)
|
||||||
|
- BUGFIX: Improve "Run External Program" behavior. On Windows, a backslash isn't appended to paths from path variables (Chocobo1)
|
||||||
|
- BUGFIX: Suppress multiple I/O errors for the same torrent (sledgehammer999)
|
||||||
|
- BUGFIX: Replace raster qbt logo with vector version (Chocobo1)
|
||||||
|
- WEBUI: Fix wrong API method names (glassez)
|
||||||
|
- WEBUI: Filter torrent info endpoint by hashes (Marcel Petersen)
|
||||||
|
- WEBUI: Fix invalid API calls in WebUI (glassez)
|
||||||
|
- WEBUI: Improve legacy API params handling (glassez)
|
||||||
|
- WEBUI: Fix params handling for some legacy API methods (glassez)
|
||||||
|
- WEBUI: Apply locale changes immediately in WebUI (Chocobo1)
|
||||||
|
- WEBUI: Use 32px icons for favicon (Chocobo1)
|
||||||
|
- WEBUI/RSS: Properly set RSS settings via API (glassez)
|
||||||
|
- RSS: Fix auto-downloading rule when Smart filter with regular Episode filter are used (glassez)
|
||||||
|
- RSS: Make "Ignoring days" to behave like other filters (glassez)
|
||||||
|
- RSS: Place "Use Smart Episode Filter" more correctly (glassez)
|
||||||
|
- RSS: Use RSS feed update time as a fallback (glassez)
|
||||||
|
- COSMETIC: Fix Stats dialog size (sledgehammer999)
|
||||||
|
- MACOS: Fix GUI scaling factor on macOS (Chocobo1)
|
||||||
|
- WINDOWS: Update icons (adem4ik)
|
||||||
|
- LINUX: Fix open destination folder with Nautilus > 3.28 (Evgeny Lensky)
|
||||||
|
- OTHER: Code improvements and refactoring (thalieht, Nick Korotysh, Chocobo1)
|
||||||
|
|
||||||
* Sat May 05 2018 - sledgehammer999 <sledgehammer999@qbittorrent.org> - v4.1.0
|
* Sat May 05 2018 - sledgehammer999 <sledgehammer999@qbittorrent.org> - v4.1.0
|
||||||
- FEATURE: Add "Coalesce reads & writes" checkbox in advanced options (Chocobo1)
|
- FEATURE: Add "Coalesce reads & writes" checkbox in advanced options (Chocobo1)
|
||||||
- FEATURE: Smart Filter for RSS (Stephen Dawkins)
|
- FEATURE: Smart Filter for RSS (Stephen Dawkins)
|
||||||
|
|||||||
@@ -11,18 +11,17 @@ macro(qbt_set_compiler_options)
|
|||||||
#-Wshadow -Wconversion ?
|
#-Wshadow -Wconversion ?
|
||||||
set(_GCC_COMMON_C_AND_CXX_FLAGS "-Wall -Wextra"
|
set(_GCC_COMMON_C_AND_CXX_FLAGS "-Wall -Wextra"
|
||||||
"-Wfloat-equal -Wcast-qual -Wcast-align"
|
"-Wfloat-equal -Wcast-qual -Wcast-align"
|
||||||
"-Wsign-conversion -Winvalid-pch -Werror=return-type -Wno-long-long"
|
"-Wsign-conversion -Winvalid-pch -Wno-long-long"
|
||||||
# -fstack-protector-all
|
#"-fstack-protector-all"
|
||||||
"-Werror -Wno-error=deprecated-declarations"
|
#"-Werror -Wno-error=deprecated-declarations"
|
||||||
)
|
)
|
||||||
set(_GCC_COMMON_CXX_FLAGS "-fexceptions -frtti"
|
set(_GCC_COMMON_CXX_FLAGS "-fexceptions -frtti"
|
||||||
"-Woverloaded-virtual -Wold-style-cast"
|
"-Woverloaded-virtual -Wold-style-cast"
|
||||||
"-Wnon-virtual-dtor -Wfloat-equal -Wcast-qual -Wcast-align"
|
"-Wnon-virtual-dtor -Wfloat-equal -Wcast-qual -Wcast-align"
|
||||||
"-Werror=overloaded-virtual"
|
|
||||||
#"-Weffc++"
|
#"-Weffc++"
|
||||||
"-Werror -Wno-error=cpp"
|
#"-Werror -Wno-error=cpp"
|
||||||
# we should modify code to make these ones obsolete
|
# we should modify code to make these ones obsolete
|
||||||
"-Wno-error=sign-conversion -Wno-error=float-equal"
|
#"-Wno-error=sign-conversion -Wno-error=float-equal"
|
||||||
)
|
)
|
||||||
|
|
||||||
if ("${CMAKE_CXX_COMPILER_ID}" STREQUAL "GNU" AND CMAKE_CXX_COMPILER_VERSION VERSION_LESS 4.9)
|
if ("${CMAKE_CXX_COMPILER_ID}" STREQUAL "GNU" AND CMAKE_CXX_COMPILER_VERSION VERSION_LESS 4.9)
|
||||||
|
|||||||
@@ -58,4 +58,4 @@ DEFINES += BOOST_USE_WINAPI_VERSION=0x0501
|
|||||||
#DEFINES += TORRENT_LINKING_SHARED
|
#DEFINES += TORRENT_LINKING_SHARED
|
||||||
|
|
||||||
# Enable stack trace support
|
# Enable stack trace support
|
||||||
CONFIG += strace_win
|
CONFIG += stacktrace
|
||||||
|
|||||||
24
configure
vendored
24
configure
vendored
@@ -1,6 +1,6 @@
|
|||||||
#! /bin/sh
|
#! /bin/sh
|
||||||
# Guess values for system-dependent variables and create Makefiles.
|
# Guess values for system-dependent variables and create Makefiles.
|
||||||
# Generated by GNU Autoconf 2.69 for qbittorrent v4.1.0alpha.
|
# Generated by GNU Autoconf 2.69 for qbittorrent v4.1.1.
|
||||||
#
|
#
|
||||||
# Report bugs to <bugs.qbittorrent.org>.
|
# Report bugs to <bugs.qbittorrent.org>.
|
||||||
#
|
#
|
||||||
@@ -580,8 +580,8 @@ MAKEFLAGS=
|
|||||||
# Identity of this package.
|
# Identity of this package.
|
||||||
PACKAGE_NAME='qbittorrent'
|
PACKAGE_NAME='qbittorrent'
|
||||||
PACKAGE_TARNAME='qbittorrent'
|
PACKAGE_TARNAME='qbittorrent'
|
||||||
PACKAGE_VERSION='v4.1.0alpha'
|
PACKAGE_VERSION='v4.1.1'
|
||||||
PACKAGE_STRING='qbittorrent v4.1.0alpha'
|
PACKAGE_STRING='qbittorrent v4.1.1'
|
||||||
PACKAGE_BUGREPORT='bugs.qbittorrent.org'
|
PACKAGE_BUGREPORT='bugs.qbittorrent.org'
|
||||||
PACKAGE_URL='https://www.qbittorrent.org/'
|
PACKAGE_URL='https://www.qbittorrent.org/'
|
||||||
|
|
||||||
@@ -1297,7 +1297,7 @@ if test "$ac_init_help" = "long"; then
|
|||||||
# Omit some internal or obsolete options to make the list less imposing.
|
# Omit some internal or obsolete options to make the list less imposing.
|
||||||
# This message is too long to be a string in the A/UX 3.1 sh.
|
# This message is too long to be a string in the A/UX 3.1 sh.
|
||||||
cat <<_ACEOF
|
cat <<_ACEOF
|
||||||
\`configure' configures qbittorrent v4.1.0alpha to adapt to many kinds of systems.
|
\`configure' configures qbittorrent v4.1.1 to adapt to many kinds of systems.
|
||||||
|
|
||||||
Usage: $0 [OPTION]... [VAR=VALUE]...
|
Usage: $0 [OPTION]... [VAR=VALUE]...
|
||||||
|
|
||||||
@@ -1368,7 +1368,7 @@ fi
|
|||||||
|
|
||||||
if test -n "$ac_init_help"; then
|
if test -n "$ac_init_help"; then
|
||||||
case $ac_init_help in
|
case $ac_init_help in
|
||||||
short | recursive ) echo "Configuration of qbittorrent v4.1.0alpha:";;
|
short | recursive ) echo "Configuration of qbittorrent v4.1.1:";;
|
||||||
esac
|
esac
|
||||||
cat <<\_ACEOF
|
cat <<\_ACEOF
|
||||||
|
|
||||||
@@ -1503,7 +1503,7 @@ fi
|
|||||||
test -n "$ac_init_help" && exit $ac_status
|
test -n "$ac_init_help" && exit $ac_status
|
||||||
if $ac_init_version; then
|
if $ac_init_version; then
|
||||||
cat <<\_ACEOF
|
cat <<\_ACEOF
|
||||||
qbittorrent configure v4.1.0alpha
|
qbittorrent configure v4.1.1
|
||||||
generated by GNU Autoconf 2.69
|
generated by GNU Autoconf 2.69
|
||||||
|
|
||||||
Copyright (C) 2012 Free Software Foundation, Inc.
|
Copyright (C) 2012 Free Software Foundation, Inc.
|
||||||
@@ -1642,7 +1642,7 @@ cat >config.log <<_ACEOF
|
|||||||
This file contains any messages produced by compilers while
|
This file contains any messages produced by compilers while
|
||||||
running configure, to aid debugging if configure makes a mistake.
|
running configure, to aid debugging if configure makes a mistake.
|
||||||
|
|
||||||
It was created by qbittorrent $as_me v4.1.0alpha, which was
|
It was created by qbittorrent $as_me v4.1.1, which was
|
||||||
generated by GNU Autoconf 2.69. Invocation command line was
|
generated by GNU Autoconf 2.69. Invocation command line was
|
||||||
|
|
||||||
$ $0 $@
|
$ $0 $@
|
||||||
@@ -3820,7 +3820,7 @@ fi
|
|||||||
|
|
||||||
# Define the identity of the package.
|
# Define the identity of the package.
|
||||||
PACKAGE='qbittorrent'
|
PACKAGE='qbittorrent'
|
||||||
VERSION='v4.1.0alpha'
|
VERSION='v4.1.1'
|
||||||
|
|
||||||
|
|
||||||
cat >>confdefs.h <<_ACEOF
|
cat >>confdefs.h <<_ACEOF
|
||||||
@@ -6140,7 +6140,7 @@ cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1
|
|||||||
# report actual input values of CONFIG_FILES etc. instead of their
|
# report actual input values of CONFIG_FILES etc. instead of their
|
||||||
# values after options handling.
|
# values after options handling.
|
||||||
ac_log="
|
ac_log="
|
||||||
This file was extended by qbittorrent $as_me v4.1.0alpha, which was
|
This file was extended by qbittorrent $as_me v4.1.1, which was
|
||||||
generated by GNU Autoconf 2.69. Invocation command line was
|
generated by GNU Autoconf 2.69. Invocation command line was
|
||||||
|
|
||||||
CONFIG_FILES = $CONFIG_FILES
|
CONFIG_FILES = $CONFIG_FILES
|
||||||
@@ -6198,7 +6198,7 @@ _ACEOF
|
|||||||
cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1
|
cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1
|
||||||
ac_cs_config="`$as_echo "$ac_configure_args" | sed 's/^ //; s/[\\""\`\$]/\\\\&/g'`"
|
ac_cs_config="`$as_echo "$ac_configure_args" | sed 's/^ //; s/[\\""\`\$]/\\\\&/g'`"
|
||||||
ac_cs_version="\\
|
ac_cs_version="\\
|
||||||
qbittorrent config.status v4.1.0alpha
|
qbittorrent config.status v4.1.1
|
||||||
configured by $0, generated by GNU Autoconf 2.69,
|
configured by $0, generated by GNU Autoconf 2.69,
|
||||||
with options \\"\$ac_cs_config\\"
|
with options \\"\$ac_cs_config\\"
|
||||||
|
|
||||||
@@ -7455,7 +7455,7 @@ cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1
|
|||||||
# report actual input values of CONFIG_FILES etc. instead of their
|
# report actual input values of CONFIG_FILES etc. instead of their
|
||||||
# values after options handling.
|
# values after options handling.
|
||||||
ac_log="
|
ac_log="
|
||||||
This file was extended by qbittorrent $as_me v4.1.0alpha, which was
|
This file was extended by qbittorrent $as_me v4.1.1, which was
|
||||||
generated by GNU Autoconf 2.69. Invocation command line was
|
generated by GNU Autoconf 2.69. Invocation command line was
|
||||||
|
|
||||||
CONFIG_FILES = $CONFIG_FILES
|
CONFIG_FILES = $CONFIG_FILES
|
||||||
@@ -7513,7 +7513,7 @@ _ACEOF
|
|||||||
cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1
|
cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1
|
||||||
ac_cs_config="`$as_echo "$ac_configure_args" | sed 's/^ //; s/[\\""\`\$]/\\\\&/g'`"
|
ac_cs_config="`$as_echo "$ac_configure_args" | sed 's/^ //; s/[\\""\`\$]/\\\\&/g'`"
|
||||||
ac_cs_version="\\
|
ac_cs_version="\\
|
||||||
qbittorrent config.status v4.1.0alpha
|
qbittorrent config.status v4.1.1
|
||||||
configured by $0, generated by GNU Autoconf 2.69,
|
configured by $0, generated by GNU Autoconf 2.69,
|
||||||
with options \\"\$ac_cs_config\\"
|
with options \\"\$ac_cs_config\\"
|
||||||
|
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
AC_INIT([qbittorrent], [v4.1.0alpha], [bugs.qbittorrent.org], [], [https://www.qbittorrent.org/])
|
AC_INIT([qbittorrent], [v4.1.1], [bugs.qbittorrent.org], [], [https://www.qbittorrent.org/])
|
||||||
AC_CONFIG_AUX_DIR([build-aux])
|
AC_CONFIG_AUX_DIR([build-aux])
|
||||||
AC_CONFIG_MACRO_DIR([m4])
|
AC_CONFIG_MACRO_DIR([m4])
|
||||||
AC_PROG_CC
|
AC_PROG_CC
|
||||||
|
|||||||
2
dist/mac/Info.plist
vendored
2
dist/mac/Info.plist
vendored
@@ -45,7 +45,7 @@
|
|||||||
<key>CFBundlePackageType</key>
|
<key>CFBundlePackageType</key>
|
||||||
<string>APPL</string>
|
<string>APPL</string>
|
||||||
<key>CFBundleShortVersionString</key>
|
<key>CFBundleShortVersionString</key>
|
||||||
<string>4.1.0</string>
|
<string>4.1.1</string>
|
||||||
<key>CFBundleSignature</key>
|
<key>CFBundleSignature</key>
|
||||||
<string>qBit</string>
|
<string>qBit</string>
|
||||||
<key>CFBundleExecutable</key>
|
<key>CFBundleExecutable</key>
|
||||||
|
|||||||
2
dist/windows/options.nsi
vendored
2
dist/windows/options.nsi
vendored
@@ -27,7 +27,7 @@ XPStyle on
|
|||||||
!define CSIDL_LOCALAPPDATA '0x1C' ;Local Application Data path
|
!define CSIDL_LOCALAPPDATA '0x1C' ;Local Application Data path
|
||||||
|
|
||||||
; Program specific
|
; Program specific
|
||||||
!define PROG_VERSION "4.1.0"
|
!define PROG_VERSION "4.1.1"
|
||||||
|
|
||||||
!define MUI_FINISHPAGE_RUN
|
!define MUI_FINISHPAGE_RUN
|
||||||
!define MUI_FINISHPAGE_RUN_FUNCTION PageFinishRun
|
!define MUI_FINISHPAGE_RUN_FUNCTION PageFinishRun
|
||||||
|
|||||||
@@ -93,7 +93,7 @@ namespace
|
|||||||
#define SETTINGS_KEY(name) "Application/" name
|
#define SETTINGS_KEY(name) "Application/" name
|
||||||
|
|
||||||
// FileLogger properties keys
|
// FileLogger properties keys
|
||||||
#define FILELOGGER_SETTINGS_KEY(name) SETTINGS_KEY("FileLogger/") name
|
#define FILELOGGER_SETTINGS_KEY(name) QStringLiteral(SETTINGS_KEY("FileLogger/") name)
|
||||||
const QString KEY_FILELOGGER_ENABLED = FILELOGGER_SETTINGS_KEY("Enabled");
|
const QString KEY_FILELOGGER_ENABLED = FILELOGGER_SETTINGS_KEY("Enabled");
|
||||||
const QString KEY_FILELOGGER_PATH = FILELOGGER_SETTINGS_KEY("Path");
|
const QString KEY_FILELOGGER_PATH = FILELOGGER_SETTINGS_KEY("Path");
|
||||||
const QString KEY_FILELOGGER_BACKUP = FILELOGGER_SETTINGS_KEY("Backup");
|
const QString KEY_FILELOGGER_BACKUP = FILELOGGER_SETTINGS_KEY("Backup");
|
||||||
@@ -151,11 +151,11 @@ Application::Application(const QString &id, int &argc, char **argv)
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
#if defined(Q_OS_WIN) && !defined(DISABLE_GUI)
|
#if defined(Q_OS_WIN) && !defined(DISABLE_GUI)
|
||||||
connect(this, SIGNAL(commitDataRequest(QSessionManager &)), this, SLOT(shutdownCleanup(QSessionManager &)), Qt::DirectConnection);
|
connect(this, &QGuiApplication::commitDataRequest, this, &Application::shutdownCleanup, Qt::DirectConnection);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
connect(this, SIGNAL(messageReceived(const QString &)), SLOT(processMessage(const QString &)));
|
connect(this, &Application::messageReceived, this, &Application::processMessage);
|
||||||
connect(this, SIGNAL(aboutToQuit()), SLOT(cleanup()));
|
connect(this, &QCoreApplication::aboutToQuit, this, &Application::cleanup);
|
||||||
|
|
||||||
if (isFileLoggerEnabled())
|
if (isFileLoggerEnabled())
|
||||||
m_fileLogger = new FileLogger(fileLoggerPath(), isFileLoggerBackup(), fileLoggerMaxSize(), isFileLoggerDeleteOld(), fileLoggerAge(), static_cast<FileLogger::FileLogAgeType>(fileLoggerAgeType()));
|
m_fileLogger = new FileLogger(fileLoggerPath(), isFileLoggerBackup(), fileLoggerMaxSize(), isFileLoggerDeleteOld(), fileLoggerAge(), static_cast<FileLogger::FileLogAgeType>(fileLoggerAgeType()));
|
||||||
@@ -290,9 +290,21 @@ void Application::runExternalProgram(const BitTorrent::TorrentHandle *torrent) c
|
|||||||
std::sort(tags.begin(), tags.end(), Utils::String::naturalLessThan<Qt::CaseInsensitive>);
|
std::sort(tags.begin(), tags.end(), Utils::String::naturalLessThan<Qt::CaseInsensitive>);
|
||||||
program.replace("%G", tags.join(','));
|
program.replace("%G", tags.join(','));
|
||||||
|
|
||||||
|
#if defined(Q_OS_WIN)
|
||||||
|
const auto chopPathSep = [](const QString &str) -> QString
|
||||||
|
{
|
||||||
|
if (str.endsWith('\\'))
|
||||||
|
return str.mid(0, (str.length() -1));
|
||||||
|
return str;
|
||||||
|
};
|
||||||
|
program.replace("%F", chopPathSep(Utils::Fs::toNativePath(torrent->contentPath())));
|
||||||
|
program.replace("%R", chopPathSep(Utils::Fs::toNativePath(torrent->rootPath())));
|
||||||
|
program.replace("%D", chopPathSep(Utils::Fs::toNativePath(torrent->savePath())));
|
||||||
|
#else
|
||||||
program.replace("%F", Utils::Fs::toNativePath(torrent->contentPath()));
|
program.replace("%F", Utils::Fs::toNativePath(torrent->contentPath()));
|
||||||
program.replace("%R", Utils::Fs::toNativePath(torrent->rootPath()));
|
program.replace("%R", Utils::Fs::toNativePath(torrent->rootPath()));
|
||||||
program.replace("%D", Utils::Fs::toNativePath(torrent->savePath()));
|
program.replace("%D", Utils::Fs::toNativePath(torrent->savePath()));
|
||||||
|
#endif
|
||||||
program.replace("%C", QString::number(torrent->filesCount()));
|
program.replace("%C", QString::number(torrent->filesCount()));
|
||||||
program.replace("%Z", QString::number(torrent->totalSize()));
|
program.replace("%Z", QString::number(torrent->totalSize()));
|
||||||
program.replace("%T", torrent->currentTracker());
|
program.replace("%T", torrent->currentTracker());
|
||||||
@@ -301,9 +313,7 @@ void Application::runExternalProgram(const BitTorrent::TorrentHandle *torrent) c
|
|||||||
Logger *logger = Logger::instance();
|
Logger *logger = Logger::instance();
|
||||||
logger->addMessage(tr("Torrent: %1, running external program, command: %2").arg(torrent->name(), program));
|
logger->addMessage(tr("Torrent: %1, running external program, command: %2").arg(torrent->name(), program));
|
||||||
|
|
||||||
#if defined(Q_OS_UNIX)
|
#if defined(Q_OS_WIN)
|
||||||
QProcess::startDetached(QLatin1String("/bin/sh"), {QLatin1String("-c"), program});
|
|
||||||
#else
|
|
||||||
std::unique_ptr<wchar_t[]> programWchar(new wchar_t[program.length() + 1] {});
|
std::unique_ptr<wchar_t[]> programWchar(new wchar_t[program.length() + 1] {});
|
||||||
program.toWCharArray(programWchar.get());
|
program.toWCharArray(programWchar.get());
|
||||||
|
|
||||||
@@ -320,6 +330,8 @@ void Application::runExternalProgram(const BitTorrent::TorrentHandle *torrent) c
|
|||||||
QProcess::startDetached(QString::fromWCharArray(args[0]), argList);
|
QProcess::startDetached(QString::fromWCharArray(args[0]), argList);
|
||||||
|
|
||||||
::LocalFree(args);
|
::LocalFree(args);
|
||||||
|
#else
|
||||||
|
QProcess::startDetached(QLatin1String("/bin/sh"), {QLatin1String("-c"), program});
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -489,8 +501,8 @@ int Application::exec(const QStringList ¶ms)
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
BitTorrent::Session::initInstance();
|
BitTorrent::Session::initInstance();
|
||||||
connect(BitTorrent::Session::instance(), SIGNAL(torrentFinished(BitTorrent::TorrentHandle *const)), SLOT(torrentFinished(BitTorrent::TorrentHandle *const)));
|
connect(BitTorrent::Session::instance(), &BitTorrent::Session::torrentFinished, this, &Application::torrentFinished);
|
||||||
connect(BitTorrent::Session::instance(), SIGNAL(allTorrentsFinished()), SLOT(allTorrentsFinished()), Qt::QueuedConnection);
|
connect(BitTorrent::Session::instance(), &BitTorrent::Session::allTorrentsFinished, this, &Application::allTorrentsFinished, Qt::QueuedConnection);
|
||||||
|
|
||||||
#ifndef DISABLE_COUNTRIES_RESOLUTION
|
#ifndef DISABLE_COUNTRIES_RESOLUTION
|
||||||
Net::GeoIPManager::initInstance();
|
Net::GeoIPManager::initInstance();
|
||||||
@@ -660,7 +672,7 @@ void Application::shutdownCleanup(QSessionManager &manager)
|
|||||||
// According to the qt docs we shouldn't call quit() inside a slot.
|
// According to the qt docs we shouldn't call quit() inside a slot.
|
||||||
// aboutToQuit() is never emitted if the user hits "Cancel" in
|
// aboutToQuit() is never emitted if the user hits "Cancel" in
|
||||||
// the above dialog.
|
// the above dialog.
|
||||||
QTimer::singleShot(0, qApp, SLOT(quit()));
|
QTimer::singleShot(0, qApp, &QCoreApplication::quit);
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|||||||
@@ -110,7 +110,7 @@ public:
|
|||||||
protected:
|
protected:
|
||||||
#ifndef DISABLE_GUI
|
#ifndef DISABLE_GUI
|
||||||
#ifdef Q_OS_MAC
|
#ifdef Q_OS_MAC
|
||||||
bool event(QEvent *);
|
bool event(QEvent *) override;
|
||||||
#endif
|
#endif
|
||||||
bool notify(QObject* receiver, QEvent* event) override;
|
bool notify(QObject* receiver, QEvent* event) override;
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
@@ -41,7 +41,7 @@ FileLogger::FileLogger(const QString &path, const bool backup, const int maxSize
|
|||||||
{
|
{
|
||||||
m_flusher.setInterval(0);
|
m_flusher.setInterval(0);
|
||||||
m_flusher.setSingleShot(true);
|
m_flusher.setSingleShot(true);
|
||||||
connect(&m_flusher, SIGNAL(timeout()), SLOT(flushLog()));
|
connect(&m_flusher, &QTimer::timeout, this, &FileLogger::flushLog);
|
||||||
|
|
||||||
changePath(path);
|
changePath(path);
|
||||||
if (deleteOld)
|
if (deleteOld)
|
||||||
@@ -51,7 +51,7 @@ FileLogger::FileLogger(const QString &path, const bool backup, const int maxSize
|
|||||||
foreach (const Log::Msg& msg, logger->getMessages())
|
foreach (const Log::Msg& msg, logger->getMessages())
|
||||||
addLogMessage(msg);
|
addLogMessage(msg);
|
||||||
|
|
||||||
connect(logger, SIGNAL(newLogMessage(const Log::Msg &)), SLOT(addLogMessage(const Log::Msg &)));
|
connect(logger, &Logger::newLogMessage, this, &FileLogger::addLogMessage);
|
||||||
}
|
}
|
||||||
|
|
||||||
FileLogger::~FileLogger()
|
FileLogger::~FileLogger()
|
||||||
@@ -83,21 +83,21 @@ void FileLogger::changePath(const QString& newPath)
|
|||||||
void FileLogger::deleteOld(const int age, const FileLogAgeType ageType)
|
void FileLogger::deleteOld(const int age, const FileLogAgeType ageType)
|
||||||
{
|
{
|
||||||
QDateTime date = QDateTime::currentDateTime();
|
QDateTime date = QDateTime::currentDateTime();
|
||||||
QDir dir(m_path);
|
QDir dir(Utils::Fs::branchPath(m_path));
|
||||||
|
|
||||||
switch (ageType) {
|
|
||||||
case DAYS:
|
|
||||||
date = date.addDays(age);
|
|
||||||
break;
|
|
||||||
case MONTHS:
|
|
||||||
date = date.addMonths(age);
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
date = date.addYears(age);
|
|
||||||
}
|
|
||||||
|
|
||||||
foreach (const QFileInfo file, dir.entryInfoList(QStringList("qbittorrent.log.bak*"), QDir::Files | QDir::Writable, QDir::Time | QDir::Reversed)) {
|
foreach (const QFileInfo file, dir.entryInfoList(QStringList("qbittorrent.log.bak*"), QDir::Files | QDir::Writable, QDir::Time | QDir::Reversed)) {
|
||||||
if (file.lastModified() < date)
|
QDateTime modificationDate = file.lastModified();
|
||||||
|
switch (ageType) {
|
||||||
|
case DAYS:
|
||||||
|
modificationDate = modificationDate.addDays(age);
|
||||||
|
break;
|
||||||
|
case MONTHS:
|
||||||
|
modificationDate = modificationDate.addMonths(age);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
modificationDate = modificationDate.addYears(age);
|
||||||
|
}
|
||||||
|
if (modificationDate > date)
|
||||||
break;
|
break;
|
||||||
Utils::Fs::forceRemove(file.absoluteFilePath());
|
Utils::Fs::forceRemove(file.absoluteFilePath());
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -329,7 +329,7 @@ void showSplashScreen()
|
|||||||
painter.drawText(224 - painter.fontMetrics().width(version), 270, version);
|
painter.drawText(224 - painter.fontMetrics().width(version), 270, version);
|
||||||
QSplashScreen *splash = new QSplashScreen(splash_img);
|
QSplashScreen *splash = new QSplashScreen(splash_img);
|
||||||
splash->show();
|
splash->show();
|
||||||
QTimer::singleShot(1500, splash, SLOT(deleteLater()));
|
QTimer::singleShot(1500, splash, &QObject::deleteLater);
|
||||||
qApp->processEvents();
|
qApp->processEvents();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -138,7 +138,7 @@ bool straceWin::makeRelativePath(const QString& dir, QString& file)
|
|||||||
|
|
||||||
QString straceWin::getSourcePathAndLineNumber(HANDLE hProcess, DWORD64 addr)
|
QString straceWin::getSourcePathAndLineNumber(HANDLE hProcess, DWORD64 addr)
|
||||||
{
|
{
|
||||||
IMAGEHLP_LINE64 line = {0};
|
IMAGEHLP_LINE64 line {};
|
||||||
line.SizeOfStruct = sizeof(IMAGEHLP_LINE64);
|
line.SizeOfStruct = sizeof(IMAGEHLP_LINE64);
|
||||||
DWORD dwDisplacement = 0;
|
DWORD dwDisplacement = 0;
|
||||||
|
|
||||||
|
|||||||
@@ -114,12 +114,27 @@ bool upgradeResumeFile(const QString &filepath, const QVariantHash &oldTorrent =
|
|||||||
bool v3_3 = false;
|
bool v3_3 = false;
|
||||||
int queuePosition = 0;
|
int queuePosition = 0;
|
||||||
QString outFilePath = filepath;
|
QString outFilePath = filepath;
|
||||||
QRegExp rx(QLatin1String("([A-Fa-f0-9]{40})\\.fastresume\\.(\\d+)$"));
|
QRegExp rx(QLatin1String("([A-Fa-f0-9]{40})\\.fastresume\\.(.+)$"));
|
||||||
if (rx.indexIn(filepath) != -1) {
|
if (rx.indexIn(filepath) != -1) {
|
||||||
// old v3.3.x format
|
// Old v3.3.x format had a number at the end indicating the queue position.
|
||||||
|
// The naming scheme was '<infohash>.fastresume.<queueposition>'.
|
||||||
|
// However, QSaveFile, which uses QTemporaryFile internally, might leave
|
||||||
|
// non-commited files behind eg after a crash. These files have the
|
||||||
|
// naming scheme '<infohash>.fastresume.XXXXXX' where each X is a random
|
||||||
|
// character. So we detect if the last part is present. Then check if it
|
||||||
|
// is 6 chars long. If all the 6 chars are digits we assume it is an old
|
||||||
|
// v3.3.x format. Otherwise it is considered a non-commited fastresume
|
||||||
|
// and is deleted, because it may be a corrupted/incomplete fastresume.
|
||||||
|
// NOTE: When the upgrade code is removed, we must continue to perform
|
||||||
|
// cleanup of non-commited QSaveFile/QTemporaryFile fastresumes
|
||||||
queuePosition = rx.cap(2).toInt();
|
queuePosition = rx.cap(2).toInt();
|
||||||
|
if ((rx.cap(2).size() == 6) && (queuePosition <= 99999)) {
|
||||||
|
Utils::Fs::forceRemove(filepath);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
v3_3 = true;
|
v3_3 = true;
|
||||||
outFilePath.replace(QRegExp("\\.\\d+$"), "");
|
outFilePath.replace(QRegExp("\\.fastresume\\..+$"), ".fastresume");
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
queuePosition = fastOld.dict_find_int_value("qBt-queuePosition", 0);
|
queuePosition = fastOld.dict_find_int_value("qBt-queuePosition", 0);
|
||||||
@@ -130,6 +145,15 @@ bool upgradeResumeFile(const QString &filepath, const QVariantHash &oldTorrent =
|
|||||||
// in versions < 3.3 we have -1 for seeding torrents, so we convert it to 0
|
// in versions < 3.3 we have -1 for seeding torrents, so we convert it to 0
|
||||||
fastNew["qBt-queuePosition"] = (queuePosition >= 0 ? queuePosition : 0);
|
fastNew["qBt-queuePosition"] = (queuePosition >= 0 ? queuePosition : 0);
|
||||||
|
|
||||||
|
if (v3_3) {
|
||||||
|
QFileInfo oldFile(filepath);
|
||||||
|
QFileInfo newFile(outFilePath);
|
||||||
|
if (newFile.exists()
|
||||||
|
&& (oldFile.lastModified() < newFile.lastModified())) {
|
||||||
|
Utils::Fs::forceRemove(filepath);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
QFile file2(outFilePath);
|
QFile file2(outFilePath);
|
||||||
QVector<char> out;
|
QVector<char> out;
|
||||||
libtorrent::bencode(std::back_inserter(out), fastNew);
|
libtorrent::bencode(std::back_inserter(out), fastNew);
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
* Bittorrent Client using Qt and libt.
|
* Bittorrent Client using Qt and libtorrent.
|
||||||
* Copyright (C) 2006 Christophe Dumez <chris@qbittorrent.org>
|
* Copyright (C) 2006 Christophe Dumez <chris@qbittorrent.org>
|
||||||
*
|
*
|
||||||
* This program is free software; you can redistribute it and/or
|
* This program is free software; you can redistribute it and/or
|
||||||
@@ -147,13 +147,13 @@ int FilterParserThread::parseDATFilterFile()
|
|||||||
if (bytesRead < 0)
|
if (bytesRead < 0)
|
||||||
break;
|
break;
|
||||||
int dataSize = bytesRead + offset;
|
int dataSize = bytesRead + offset;
|
||||||
if (bytesRead == 0 && dataSize == 0)
|
if ((bytesRead == 0) && (dataSize == 0))
|
||||||
break;
|
break;
|
||||||
|
|
||||||
for (start = 0; start < dataSize; ++start) {
|
for (start = 0; start < dataSize; ++start) {
|
||||||
endOfLine = -1;
|
endOfLine = -1;
|
||||||
// The file might have ended without the last line having a newline
|
// The file might have ended without the last line having a newline
|
||||||
if (!(bytesRead == 0 && dataSize > 0)) {
|
if (!((bytesRead == 0) && (dataSize > 0))) {
|
||||||
for (int i = start; i < dataSize; ++i) {
|
for (int i = start; i < dataSize; ++i) {
|
||||||
if (buffer[i] == '\n') {
|
if (buffer[i] == '\n') {
|
||||||
endOfLine = i;
|
endOfLine = i;
|
||||||
@@ -295,13 +295,13 @@ int FilterParserThread::parseP2PFilterFile()
|
|||||||
if (bytesRead < 0)
|
if (bytesRead < 0)
|
||||||
break;
|
break;
|
||||||
int dataSize = bytesRead + offset;
|
int dataSize = bytesRead + offset;
|
||||||
if (bytesRead == 0 && dataSize == 0)
|
if ((bytesRead == 0) && (dataSize == 0))
|
||||||
break;
|
break;
|
||||||
|
|
||||||
for (start = 0; start < dataSize; ++start) {
|
for (start = 0; start < dataSize; ++start) {
|
||||||
endOfLine = -1;
|
endOfLine = -1;
|
||||||
// The file might have ended without the last line having a newline
|
// The file might have ended without the last line having a newline
|
||||||
if (!(bytesRead == 0 && dataSize > 0)) {
|
if (!((bytesRead == 0) && (dataSize > 0))) {
|
||||||
for (int i = start; i < dataSize; ++i) {
|
for (int i = start; i < dataSize; ++i) {
|
||||||
if (buffer[i] == '\n') {
|
if (buffer[i] == '\n') {
|
||||||
endOfLine = i;
|
endOfLine = i;
|
||||||
|
|||||||
@@ -22,7 +22,7 @@ Statistics::Statistics(Session *session)
|
|||||||
, m_dirty(false)
|
, m_dirty(false)
|
||||||
{
|
{
|
||||||
load();
|
load();
|
||||||
connect(&m_timer, SIGNAL(timeout()), this, SLOT(gather()));
|
connect(&m_timer, &QTimer::timeout, this, &Statistics::gather);
|
||||||
m_timer.start(60 * 1000);
|
m_timer.start(60 * 1000);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -9,7 +9,7 @@ namespace BitTorrent
|
|||||||
class Session;
|
class Session;
|
||||||
}
|
}
|
||||||
|
|
||||||
class Statistics : QObject
|
class Statistics : public QObject
|
||||||
{
|
{
|
||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
Q_DISABLE_COPY(Statistics)
|
Q_DISABLE_COPY(Statistics)
|
||||||
|
|||||||
@@ -49,9 +49,6 @@
|
|||||||
#include <QUuid>
|
#include <QUuid>
|
||||||
|
|
||||||
#include <libtorrent/alert_types.hpp>
|
#include <libtorrent/alert_types.hpp>
|
||||||
#if LIBTORRENT_VERSION_NUM >= 10100
|
|
||||||
#include <libtorrent/bdecode.hpp>
|
|
||||||
#endif
|
|
||||||
#include <libtorrent/bencode.hpp>
|
#include <libtorrent/bencode.hpp>
|
||||||
#include <libtorrent/disk_io_thread.hpp>
|
#include <libtorrent/disk_io_thread.hpp>
|
||||||
#include <libtorrent/error_code.hpp>
|
#include <libtorrent/error_code.hpp>
|
||||||
@@ -60,17 +57,18 @@
|
|||||||
#include <libtorrent/extensions/smart_ban.hpp>
|
#include <libtorrent/extensions/smart_ban.hpp>
|
||||||
#include <libtorrent/identify_client.hpp>
|
#include <libtorrent/identify_client.hpp>
|
||||||
#include <libtorrent/ip_filter.hpp>
|
#include <libtorrent/ip_filter.hpp>
|
||||||
#if LIBTORRENT_VERSION_NUM < 10100
|
|
||||||
#include <libtorrent/lazy_entry.hpp>
|
|
||||||
#endif
|
|
||||||
#include <libtorrent/magnet_uri.hpp>
|
#include <libtorrent/magnet_uri.hpp>
|
||||||
#include <libtorrent/session.hpp>
|
#include <libtorrent/session.hpp>
|
||||||
#if LIBTORRENT_VERSION_NUM >= 10100
|
|
||||||
#include <libtorrent/session_stats.hpp>
|
|
||||||
#endif
|
|
||||||
#include <libtorrent/session_status.hpp>
|
#include <libtorrent/session_status.hpp>
|
||||||
#include <libtorrent/torrent_info.hpp>
|
#include <libtorrent/torrent_info.hpp>
|
||||||
|
|
||||||
|
#if LIBTORRENT_VERSION_NUM < 10100
|
||||||
|
#include <libtorrent/lazy_entry.hpp>
|
||||||
|
#else
|
||||||
|
#include <libtorrent/bdecode.hpp>
|
||||||
|
#include <libtorrent/session_stats.hpp>
|
||||||
|
#endif
|
||||||
|
|
||||||
#include "base/algorithm.h"
|
#include "base/algorithm.h"
|
||||||
#include "base/logger.h"
|
#include "base/logger.h"
|
||||||
#include "base/net/downloadhandler.h"
|
#include "base/net/downloadhandler.h"
|
||||||
@@ -96,6 +94,7 @@
|
|||||||
#include "trackerentry.h"
|
#include "trackerentry.h"
|
||||||
|
|
||||||
#ifdef Q_OS_WIN
|
#ifdef Q_OS_WIN
|
||||||
|
#include <wincrypt.h>
|
||||||
#include <iphlpapi.h>
|
#include <iphlpapi.h>
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
@@ -371,11 +370,16 @@ Session::Session(QObject *parent)
|
|||||||
, m_numResumeData(0)
|
, m_numResumeData(0)
|
||||||
, m_extraLimit(0)
|
, m_extraLimit(0)
|
||||||
, m_useProxy(false)
|
, m_useProxy(false)
|
||||||
|
, m_recentErroredTorrentsTimer(new QTimer(this))
|
||||||
{
|
{
|
||||||
Logger *const logger = Logger::instance();
|
Logger *const logger = Logger::instance();
|
||||||
|
|
||||||
initResumeFolder();
|
initResumeFolder();
|
||||||
|
|
||||||
|
m_recentErroredTorrentsTimer->setSingleShot(true);
|
||||||
|
m_recentErroredTorrentsTimer->setInterval(1000);
|
||||||
|
connect(m_recentErroredTorrentsTimer, &QTimer::timeout, this, [this]() { m_recentErroredTorrents.clear(); });
|
||||||
|
|
||||||
m_seedingLimitTimer = new QTimer(this);
|
m_seedingLimitTimer = new QTimer(this);
|
||||||
m_seedingLimitTimer->setInterval(10000);
|
m_seedingLimitTimer->setInterval(10000);
|
||||||
connect(m_seedingLimitTimer, &QTimer::timeout, this, &Session::processShareLimits);
|
connect(m_seedingLimitTimer, &QTimer::timeout, this, &Session::processShareLimits);
|
||||||
@@ -519,13 +523,14 @@ Session::Session(QObject *parent)
|
|||||||
|
|
||||||
enableTracker(isTrackerEnabled());
|
enableTracker(isTrackerEnabled());
|
||||||
|
|
||||||
connect(Net::ProxyConfigurationManager::instance(), SIGNAL(proxyConfigurationChanged()), SLOT(configureDeferred()));
|
connect(Net::ProxyConfigurationManager::instance(), &Net::ProxyConfigurationManager::proxyConfigurationChanged
|
||||||
|
, this, &Session::configureDeferred);
|
||||||
|
|
||||||
// Network configuration monitor
|
// Network configuration monitor
|
||||||
connect(&m_networkManager, SIGNAL(onlineStateChanged(bool)), SLOT(networkOnlineStateChanged(bool)));
|
connect(&m_networkManager, &QNetworkConfigurationManager::onlineStateChanged, this, &Session::networkOnlineStateChanged);
|
||||||
connect(&m_networkManager, SIGNAL(configurationAdded(const QNetworkConfiguration&)), SLOT(networkConfigurationChange(const QNetworkConfiguration&)));
|
connect(&m_networkManager, &QNetworkConfigurationManager::configurationAdded, this, &Session::networkConfigurationChange);
|
||||||
connect(&m_networkManager, SIGNAL(configurationRemoved(const QNetworkConfiguration&)), SLOT(networkConfigurationChange(const QNetworkConfiguration&)));
|
connect(&m_networkManager, &QNetworkConfigurationManager::configurationRemoved, this, &Session::networkConfigurationChange);
|
||||||
connect(&m_networkManager, SIGNAL(configurationChanged(const QNetworkConfiguration&)), SLOT(networkConfigurationChange(const QNetworkConfiguration&)));
|
connect(&m_networkManager, &QNetworkConfigurationManager::configurationChanged, this, &Session::networkConfigurationChange);
|
||||||
|
|
||||||
m_ioThread = new QThread(this);
|
m_ioThread = new QThread(this);
|
||||||
m_resumeDataSavingManager = new ResumeDataSavingManager(m_resumeFolderPath);
|
m_resumeDataSavingManager = new ResumeDataSavingManager(m_resumeFolderPath);
|
||||||
@@ -941,7 +946,7 @@ qreal Session::globalMaxRatio() const
|
|||||||
return m_globalMaxRatio;
|
return m_globalMaxRatio;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Torrents will a ratio superior to the given value will
|
// Torrents with a ratio superior to the given value will
|
||||||
// be automatically deleted
|
// be automatically deleted
|
||||||
void Session::setGlobalMaxRatio(qreal ratio)
|
void Session::setGlobalMaxRatio(qreal ratio)
|
||||||
{
|
{
|
||||||
@@ -1005,7 +1010,7 @@ void Session::freeInstance()
|
|||||||
{
|
{
|
||||||
if (m_instance) {
|
if (m_instance) {
|
||||||
delete m_instance;
|
delete m_instance;
|
||||||
m_instance = 0;
|
m_instance = nullptr;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1303,7 +1308,7 @@ void Session::configure(libtorrent::settings_pack &settingsPack)
|
|||||||
settingsPack.set_bool(libt::settings_pack::announce_to_all_trackers, announceToAllTrackers());
|
settingsPack.set_bool(libt::settings_pack::announce_to_all_trackers, announceToAllTrackers());
|
||||||
settingsPack.set_bool(libt::settings_pack::announce_to_all_tiers, announceToAllTiers());
|
settingsPack.set_bool(libt::settings_pack::announce_to_all_tiers, announceToAllTiers());
|
||||||
|
|
||||||
const int cacheSize = (diskCacheSize() > -1) ? diskCacheSize() * 64 : -1;
|
const int cacheSize = (diskCacheSize() > -1) ? (diskCacheSize() * 64) : -1;
|
||||||
settingsPack.set_int(libt::settings_pack::cache_size, cacheSize);
|
settingsPack.set_int(libt::settings_pack::cache_size, cacheSize);
|
||||||
settingsPack.set_int(libt::settings_pack::cache_expiry, diskCacheTTL());
|
settingsPack.set_int(libt::settings_pack::cache_expiry, diskCacheTTL());
|
||||||
qDebug() << "Using a disk cache size of" << cacheSize << "MiB";
|
qDebug() << "Using a disk cache size of" << cacheSize << "MiB";
|
||||||
@@ -1515,8 +1520,8 @@ void Session::adjustLimits(libt::session_settings &sessionSettings)
|
|||||||
int maxDownloads = maxActiveDownloads();
|
int maxDownloads = maxActiveDownloads();
|
||||||
int maxActive = maxActiveTorrents();
|
int maxActive = maxActiveTorrents();
|
||||||
|
|
||||||
sessionSettings.active_downloads = maxDownloads > -1 ? maxDownloads + m_extraLimit : maxDownloads;
|
sessionSettings.active_downloads = (maxDownloads > -1) ? (maxDownloads + m_extraLimit) : maxDownloads;
|
||||||
sessionSettings.active_limit = maxActive > -1 ? maxActive + m_extraLimit : maxActive;
|
sessionSettings.active_limit = (maxActive > -1) ? (maxActive + m_extraLimit) : maxActive;
|
||||||
}
|
}
|
||||||
|
|
||||||
void Session::applyBandwidthLimits(libt::session_settings &sessionSettings)
|
void Session::applyBandwidthLimits(libt::session_settings &sessionSettings)
|
||||||
@@ -1590,7 +1595,7 @@ void Session::configure(libtorrent::session_settings &sessionSettings)
|
|||||||
|
|
||||||
sessionSettings.announce_to_all_trackers = announceToAllTrackers();
|
sessionSettings.announce_to_all_trackers = announceToAllTrackers();
|
||||||
sessionSettings.announce_to_all_tiers = announceToAllTiers();
|
sessionSettings.announce_to_all_tiers = announceToAllTiers();
|
||||||
const int cacheSize = (diskCacheSize() > -1) ? diskCacheSize() * 64 : -1;
|
const int cacheSize = (diskCacheSize() > -1) ? (diskCacheSize() * 64) : -1;
|
||||||
sessionSettings.cache_size = cacheSize;
|
sessionSettings.cache_size = cacheSize;
|
||||||
sessionSettings.cache_expiry = diskCacheTTL();
|
sessionSettings.cache_expiry = diskCacheTTL();
|
||||||
qDebug() << "Using a disk cache size of" << cacheSize << "MiB";
|
qDebug() << "Using a disk cache size of" << cacheSize << "MiB";
|
||||||
@@ -1763,7 +1768,7 @@ void Session::enableBandwidthScheduler()
|
|||||||
void Session::populateAdditionalTrackers()
|
void Session::populateAdditionalTrackers()
|
||||||
{
|
{
|
||||||
m_additionalTrackerList.clear();
|
m_additionalTrackerList.clear();
|
||||||
foreach (QString tracker, additionalTrackers().split("\n")) {
|
foreach (QString tracker, additionalTrackers().split('\n')) {
|
||||||
tracker = tracker.trimmed();
|
tracker = tracker.trimmed();
|
||||||
if (!tracker.isEmpty())
|
if (!tracker.isEmpty())
|
||||||
m_additionalTrackerList << tracker;
|
m_additionalTrackerList << tracker;
|
||||||
@@ -2075,9 +2080,10 @@ bool Session::addTorrent(QString source, const AddTorrentParams ¶ms)
|
|||||||
Logger::instance()->addMessage(tr("Downloading '%1', please wait...", "e.g: Downloading 'xxx.torrent', please wait...").arg(source));
|
Logger::instance()->addMessage(tr("Downloading '%1', please wait...", "e.g: Downloading 'xxx.torrent', please wait...").arg(source));
|
||||||
// Launch downloader
|
// Launch downloader
|
||||||
Net::DownloadHandler *handler = Net::DownloadManager::instance()->downloadUrl(source, true, 10485760 /* 10MB */, true);
|
Net::DownloadHandler *handler = Net::DownloadManager::instance()->downloadUrl(source, true, 10485760 /* 10MB */, true);
|
||||||
connect(handler, SIGNAL(downloadFinished(QString, QString)), this, SLOT(handleDownloadFinished(QString, QString)));
|
connect(handler, static_cast<void (Net::DownloadHandler::*)(const QString &, const QString &)>(&Net::DownloadHandler::downloadFinished)
|
||||||
connect(handler, SIGNAL(downloadFailed(QString, QString)), this, SLOT(handleDownloadFailed(QString, QString)));
|
, this, &Session::handleDownloadFinished);
|
||||||
connect(handler, SIGNAL(redirectedToMagnet(QString, QString)), this, SLOT(handleRedirectedToMagnet(QString, QString)));
|
connect(handler, &Net::DownloadHandler::downloadFailed, this, &Session::handleDownloadFailed);
|
||||||
|
connect(handler, &Net::DownloadHandler::redirectedToMagnet, this, &Session::handleRedirectedToMagnet);
|
||||||
m_downloadedTorrents[handler->url()] = params;
|
m_downloadedTorrents[handler->url()] = params;
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
@@ -2148,12 +2154,26 @@ bool Session::addTorrent_impl(AddTorrentData addData, const MagnetUri &magnetUri
|
|||||||
p = magnetUri.addTorrentParams();
|
p = magnetUri.addTorrentParams();
|
||||||
}
|
}
|
||||||
else if (torrentInfo.isValid()) {
|
else if (torrentInfo.isValid()) {
|
||||||
if (!addData.resumed && !addData.hasRootFolder)
|
if (!addData.resumed) {
|
||||||
|
if (!addData.hasRootFolder)
|
||||||
torrentInfo.stripRootFolder();
|
torrentInfo.stripRootFolder();
|
||||||
|
|
||||||
// Metadata
|
// Metadata
|
||||||
if (!addData.resumed && !addData.hasSeedStatus)
|
if (!addData.hasSeedStatus)
|
||||||
findIncompleteFiles(torrentInfo, savePath);
|
findIncompleteFiles(torrentInfo, savePath);
|
||||||
|
|
||||||
|
// if torrent name wasn't explicitly set we handle the case of
|
||||||
|
// initial renaming of torrent content and rename torrent accordingly
|
||||||
|
if (addData.name.isEmpty()) {
|
||||||
|
QString contentName = torrentInfo.rootFolder();
|
||||||
|
if (contentName.isEmpty() && (torrentInfo.filesCount() == 1))
|
||||||
|
contentName = torrentInfo.fileName(0);
|
||||||
|
|
||||||
|
if (!contentName.isEmpty() && (contentName != torrentInfo.name()))
|
||||||
|
addData.name = contentName;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
p.ti = torrentInfo.nativeInfo();
|
p.ti = torrentInfo.nativeInfo();
|
||||||
hash = torrentInfo.hash();
|
hash = torrentInfo.hash();
|
||||||
}
|
}
|
||||||
@@ -2259,7 +2279,7 @@ bool Session::loadMetadata(const MagnetUri &magnetUri)
|
|||||||
InfoHash hash = magnetUri.hash();
|
InfoHash hash = magnetUri.hash();
|
||||||
QString name = magnetUri.name();
|
QString name = magnetUri.name();
|
||||||
|
|
||||||
// We should not add torrent if it already
|
// We should not add torrent if it's already
|
||||||
// processed or adding to session
|
// processed or adding to session
|
||||||
if (m_torrents.contains(hash)) return false;
|
if (m_torrents.contains(hash)) return false;
|
||||||
if (m_addingTorrents.contains(hash)) return false;
|
if (m_addingTorrents.contains(hash)) return false;
|
||||||
@@ -2473,12 +2493,12 @@ const QStringList Session::getListeningIPs()
|
|||||||
ip = entry.ip();
|
ip = entry.ip();
|
||||||
ipString = ip.toString();
|
ipString = ip.toString();
|
||||||
protocol = ip.protocol();
|
protocol = ip.protocol();
|
||||||
Q_ASSERT(protocol == QAbstractSocket::IPv4Protocol || protocol == QAbstractSocket::IPv6Protocol);
|
Q_ASSERT((protocol == QAbstractSocket::IPv4Protocol) || (protocol == QAbstractSocket::IPv6Protocol));
|
||||||
if ((!listenIPv6 && (protocol == QAbstractSocket::IPv6Protocol))
|
if ((!listenIPv6 && (protocol == QAbstractSocket::IPv6Protocol))
|
||||||
|| (listenIPv6 && (protocol == QAbstractSocket::IPv4Protocol)))
|
|| (listenIPv6 && (protocol == QAbstractSocket::IPv4Protocol)))
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
//If an iface address has been defined only allow ip's that match it to go through
|
// If an iface address has been defined to only allow ip's that match it to go through
|
||||||
if (!ifaceAddr.isEmpty()) {
|
if (!ifaceAddr.isEmpty()) {
|
||||||
if (ifaceAddr == ipString) {
|
if (ifaceAddr == ipString) {
|
||||||
IPs.append(ipString);
|
IPs.append(ipString);
|
||||||
@@ -2945,7 +2965,7 @@ void Session::setMaxConnectionsPerTorrent(int max)
|
|||||||
try {
|
try {
|
||||||
handle.set_max_connections(max);
|
handle.set_max_connections(max);
|
||||||
}
|
}
|
||||||
catch (std::exception) {}
|
catch (const std::exception &) {}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -2967,7 +2987,7 @@ void Session::setMaxUploadsPerTorrent(int max)
|
|||||||
try {
|
try {
|
||||||
handle.set_max_uploads(max);
|
handle.set_max_uploads(max);
|
||||||
}
|
}
|
||||||
catch (std::exception) {}
|
catch (const std::exception &) {}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -3714,8 +3734,8 @@ void Session::enableIPFilter()
|
|||||||
// set between clearing the old one and setting the new one.
|
// set between clearing the old one and setting the new one.
|
||||||
if (!m_filterParser) {
|
if (!m_filterParser) {
|
||||||
m_filterParser = new FilterParserThread(this);
|
m_filterParser = new FilterParserThread(this);
|
||||||
connect(m_filterParser.data(), SIGNAL(IPFilterParsed(int)), SLOT(handleIPFilterParsed(int)));
|
connect(m_filterParser.data(), &FilterParserThread::IPFilterParsed, this, &Session::handleIPFilterParsed);
|
||||||
connect(m_filterParser.data(), SIGNAL(IPFilterError()), SLOT(handleIPFilterError()));
|
connect(m_filterParser.data(), &FilterParserThread::IPFilterError, this, &Session::handleIPFilterError);
|
||||||
}
|
}
|
||||||
m_filterParser->processFilterFile(IPFilterFile());
|
m_filterParser->processFilterFile(IPFilterFile());
|
||||||
}
|
}
|
||||||
@@ -3798,7 +3818,7 @@ void Session::startUpTorrents()
|
|||||||
.arg(params.hash), Log::CRITICAL);
|
.arg(params.hash), Log::CRITICAL);
|
||||||
|
|
||||||
// process add torrent messages before message queue overflow
|
// process add torrent messages before message queue overflow
|
||||||
if (resumedTorrentsCount % 100 == 0) readAlerts();
|
if ((resumedTorrentsCount % 100) == 0) readAlerts();
|
||||||
|
|
||||||
++resumedTorrentsCount;
|
++resumedTorrentsCount;
|
||||||
};
|
};
|
||||||
@@ -4169,11 +4189,16 @@ void Session::handleFileErrorAlert(libt::file_error_alert *p)
|
|||||||
// NOTE: Check this function!
|
// NOTE: Check this function!
|
||||||
TorrentHandle *const torrent = m_torrents.value(p->handle.info_hash());
|
TorrentHandle *const torrent = m_torrents.value(p->handle.info_hash());
|
||||||
if (torrent) {
|
if (torrent) {
|
||||||
QString msg = QString::fromStdString(p->message());
|
const InfoHash hash = torrent->hash();
|
||||||
Logger::instance()->addMessage(tr("An I/O error occurred, '%1' paused. %2")
|
if (!m_recentErroredTorrents.contains(hash)) {
|
||||||
.arg(torrent->name(), msg));
|
m_recentErroredTorrents.insert(hash);
|
||||||
|
const QString msg = QString::fromStdString(p->message());
|
||||||
|
LogMsg(tr("An I/O error occurred, '%1' paused. %2").arg(torrent->name(), msg));
|
||||||
emit fullDiskError(torrent, msg);
|
emit fullDiskError(torrent, msg);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
m_recentErroredTorrentsTimer->start();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void Session::handlePortmapWarningAlert(libt::portmap_error_alert *p)
|
void Session::handlePortmapWarningAlert(libt::portmap_error_alert *p)
|
||||||
|
|||||||
@@ -30,18 +30,14 @@
|
|||||||
#ifndef BITTORRENT_SESSION_H
|
#ifndef BITTORRENT_SESSION_H
|
||||||
#define BITTORRENT_SESSION_H
|
#define BITTORRENT_SESSION_H
|
||||||
|
|
||||||
#include <vector>
|
|
||||||
#include <libtorrent/version.hpp>
|
#include <libtorrent/version.hpp>
|
||||||
|
|
||||||
#if LIBTORRENT_VERSION_NUM >= 10100
|
#include <vector>
|
||||||
#include <QElapsedTimer>
|
|
||||||
#endif
|
|
||||||
#include <QFile>
|
#include <QFile>
|
||||||
#include <QHash>
|
#include <QHash>
|
||||||
|
#include <QList>
|
||||||
#include <QMap>
|
#include <QMap>
|
||||||
#if LIBTORRENT_VERSION_NUM < 10100
|
|
||||||
#include <QMutex>
|
|
||||||
#endif
|
|
||||||
#include <QNetworkConfigurationManager>
|
#include <QNetworkConfigurationManager>
|
||||||
#include <QPointer>
|
#include <QPointer>
|
||||||
#include <QSet>
|
#include <QSet>
|
||||||
@@ -49,6 +45,12 @@
|
|||||||
#include <QVector>
|
#include <QVector>
|
||||||
#include <QWaitCondition>
|
#include <QWaitCondition>
|
||||||
|
|
||||||
|
#if LIBTORRENT_VERSION_NUM < 10100
|
||||||
|
#include <QMutex>
|
||||||
|
#else
|
||||||
|
#include <QElapsedTimer>
|
||||||
|
#endif
|
||||||
|
|
||||||
#include "base/settingvalue.h"
|
#include "base/settingvalue.h"
|
||||||
#include "base/tristatebool.h"
|
#include "base/tristatebool.h"
|
||||||
#include "base/types.h"
|
#include "base/types.h"
|
||||||
@@ -111,7 +113,6 @@ class QTimer;
|
|||||||
class QStringList;
|
class QStringList;
|
||||||
class QString;
|
class QString;
|
||||||
class QUrl;
|
class QUrl;
|
||||||
template<typename T> class QList;
|
|
||||||
|
|
||||||
class FilterParserThread;
|
class FilterParserThread;
|
||||||
class BandwidthScheduler;
|
class BandwidthScheduler;
|
||||||
@@ -562,7 +563,7 @@ namespace BitTorrent
|
|||||||
bool requestedFileDeletion;
|
bool requestedFileDeletion;
|
||||||
};
|
};
|
||||||
|
|
||||||
explicit Session(QObject *parent = 0);
|
explicit Session(QObject *parent = nullptr);
|
||||||
~Session();
|
~Session();
|
||||||
|
|
||||||
bool hasPerTorrentRatioLimit() const;
|
bool hasPerTorrentRatioLimit() const;
|
||||||
@@ -760,6 +761,10 @@ namespace BitTorrent
|
|||||||
QStringMap m_categories;
|
QStringMap m_categories;
|
||||||
QSet<QString> m_tags;
|
QSet<QString> m_tags;
|
||||||
|
|
||||||
|
// I/O errored torrents
|
||||||
|
QSet<InfoHash> m_recentErroredTorrents;
|
||||||
|
QTimer *m_recentErroredTorrentsTimer;
|
||||||
|
|
||||||
#if LIBTORRENT_VERSION_NUM < 10100
|
#if LIBTORRENT_VERSION_NUM < 10100
|
||||||
QMutex m_alertsMutex;
|
QMutex m_alertsMutex;
|
||||||
QWaitCondition m_alertsWaitCondition;
|
QWaitCondition m_alertsWaitCondition;
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
/*
|
/*
|
||||||
* Bittorrent Client using Qt and libtorrent.
|
* Bittorrent Client using Qt and libtorrent.
|
||||||
* Copyright (C) 2010 Christophe Dumez
|
* Copyright (C) 2010 Christophe Dumez <chris@qbittorrent.org>
|
||||||
*
|
*
|
||||||
* This program is free software; you can redistribute it and/or
|
* This program is free software; you can redistribute it and/or
|
||||||
* modify it under the terms of the GNU General Public License
|
* modify it under the terms of the GNU General Public License
|
||||||
@@ -24,8 +24,6 @@
|
|||||||
* modify file(s), you may extend this exception to your version of the file(s),
|
* modify file(s), you may extend this exception to your version of the file(s),
|
||||||
* but you are not obligated to do so. If you do not wish to do so, delete this
|
* but you are not obligated to do so. If you do not wish to do so, delete this
|
||||||
* exception statement from your version.
|
* exception statement from your version.
|
||||||
*
|
|
||||||
* Contact : chris@qbittorrent.org
|
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include "torrentcreatorthread.h"
|
#include "torrentcreatorthread.h"
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
/*
|
/*
|
||||||
* Bittorrent Client using Qt and libtorrent.
|
* Bittorrent Client using Qt and libtorrent.
|
||||||
* Copyright (C) 2010 Christophe Dumez
|
* Copyright (C) 2010 Christophe Dumez <chris@qbittorrent.org>
|
||||||
*
|
*
|
||||||
* This program is free software; you can redistribute it and/or
|
* This program is free software; you can redistribute it and/or
|
||||||
* modify it under the terms of the GNU General Public License
|
* modify it under the terms of the GNU General Public License
|
||||||
@@ -24,8 +24,6 @@
|
|||||||
* modify file(s), you may extend this exception to your version of the file(s),
|
* modify file(s), you may extend this exception to your version of the file(s),
|
||||||
* but you are not obligated to do so. If you do not wish to do so, delete this
|
* but you are not obligated to do so. If you do not wish to do so, delete this
|
||||||
* exception statement from your version.
|
* exception statement from your version.
|
||||||
*
|
|
||||||
* Contact : chris@qbittorrent.org
|
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#ifndef BITTORRENT_TORRENTCREATORTHREAD_H
|
#ifndef BITTORRENT_TORRENTCREATORTHREAD_H
|
||||||
|
|||||||
@@ -65,7 +65,7 @@
|
|||||||
#include "session.h"
|
#include "session.h"
|
||||||
#include "trackerentry.h"
|
#include "trackerentry.h"
|
||||||
|
|
||||||
const QString QB_EXT {".!qB"};
|
const QString QB_EXT {QStringLiteral(".!qB")};
|
||||||
|
|
||||||
namespace libt = libtorrent;
|
namespace libt = libtorrent;
|
||||||
using namespace BitTorrent;
|
using namespace BitTorrent;
|
||||||
@@ -156,8 +156,6 @@ const int TorrentHandle::MAX_SEEDING_TIME = 525600;
|
|||||||
// The following can be removed after one or two libtorrent releases on each branch.
|
// The following can be removed after one or two libtorrent releases on each branch.
|
||||||
namespace
|
namespace
|
||||||
{
|
{
|
||||||
const char i18nContext[] = "TorrentHandle";
|
|
||||||
|
|
||||||
// new constructor is available
|
// new constructor is available
|
||||||
template<typename T, typename std::enable_if<std::is_constructible<T, libt::torrent_info, bool>::value, int>::type = 0>
|
template<typename T, typename std::enable_if<std::is_constructible<T, libt::torrent_info, bool>::value, int>::type = 0>
|
||||||
T makeTorrentCreator(const libtorrent::torrent_info & ti)
|
T makeTorrentCreator(const libtorrent::torrent_info & ti)
|
||||||
@@ -521,17 +519,21 @@ int TorrentHandle::piecesHave() const
|
|||||||
|
|
||||||
qreal TorrentHandle::progress() const
|
qreal TorrentHandle::progress() const
|
||||||
{
|
{
|
||||||
|
if (!isChecking()) {
|
||||||
if (!m_nativeStatus.total_wanted)
|
if (!m_nativeStatus.total_wanted)
|
||||||
return 0.;
|
return 0.;
|
||||||
|
|
||||||
if (m_nativeStatus.total_wanted_done == m_nativeStatus.total_wanted)
|
if (m_nativeStatus.total_wanted_done == m_nativeStatus.total_wanted)
|
||||||
return 1.;
|
return 1.;
|
||||||
|
|
||||||
float progress = static_cast<float>(m_nativeStatus.total_wanted_done) / m_nativeStatus.total_wanted;
|
qreal progress = static_cast<qreal>(m_nativeStatus.total_wanted_done) / m_nativeStatus.total_wanted;
|
||||||
Q_ASSERT((progress >= 0.f) && (progress <= 1.f));
|
Q_ASSERT((progress >= 0.f) && (progress <= 1.f));
|
||||||
return progress;
|
return progress;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return m_nativeStatus.progress;
|
||||||
|
}
|
||||||
|
|
||||||
QString TorrentHandle::category() const
|
QString TorrentHandle::category() const
|
||||||
{
|
{
|
||||||
return m_category;
|
return m_category;
|
||||||
@@ -736,7 +738,8 @@ bool TorrentHandle::isActive() const
|
|||||||
|| m_state == TorrentState::Downloading
|
|| m_state == TorrentState::Downloading
|
||||||
|| m_state == TorrentState::ForcedDownloading
|
|| m_state == TorrentState::ForcedDownloading
|
||||||
|| m_state == TorrentState::Uploading
|
|| m_state == TorrentState::Uploading
|
||||||
|| m_state == TorrentState::ForcedUploading;
|
|| m_state == TorrentState::ForcedUploading
|
||||||
|
|| m_state == TorrentState::Moving;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool TorrentHandle::isInactive() const
|
bool TorrentHandle::isInactive() const
|
||||||
@@ -778,28 +781,18 @@ bool TorrentHandle::hasFirstLastPiecePriority() const
|
|||||||
if (!hasMetadata())
|
if (!hasMetadata())
|
||||||
return m_needsToSetFirstLastPiecePriority;
|
return m_needsToSetFirstLastPiecePriority;
|
||||||
|
|
||||||
// Get int first media file
|
const std::vector<int> filePriorities = nativeHandle().file_priorities();
|
||||||
std::vector<int> fp;
|
for (int i = 0; i < static_cast<int>(filePriorities.size()); ++i) {
|
||||||
fp = m_nativeHandle.file_priorities();
|
if (filePriorities[i] <= 0)
|
||||||
|
continue;
|
||||||
|
|
||||||
TorrentInfo::PieceRange extremities;
|
const TorrentInfo::PieceRange extremities = info().filePieces(i);
|
||||||
bool found = false;
|
const int firstPiecePrio = nativeHandle().piece_priority(extremities.first());
|
||||||
int count = static_cast<int>(fp.size());
|
const int lastPiecePrio = nativeHandle().piece_priority(extremities.last());
|
||||||
for (int i = 0; i < count; ++i) {
|
return ((firstPiecePrio == 7) && (lastPiecePrio == 7));
|
||||||
const QString ext = Utils::Fs::fileExtension(filePath(i));
|
|
||||||
if (Utils::Misc::isPreviewable(ext) && (fp[i] > 0)) {
|
|
||||||
extremities = info().filePieces(i);
|
|
||||||
found = true;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!found) return false; // No media file
|
return false;
|
||||||
|
|
||||||
int first = m_nativeHandle.piece_priority(extremities.first());
|
|
||||||
int last = m_nativeHandle.piece_priority(extremities.last());
|
|
||||||
|
|
||||||
return ((first == 7) && (last == 7));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
TorrentState TorrentHandle::state() const
|
TorrentState TorrentHandle::state() const
|
||||||
@@ -809,7 +802,10 @@ TorrentState TorrentHandle::state() const
|
|||||||
|
|
||||||
void TorrentHandle::updateState()
|
void TorrentHandle::updateState()
|
||||||
{
|
{
|
||||||
if (isPaused()) {
|
if (isMoveInProgress()) {
|
||||||
|
m_state = TorrentState::Moving;
|
||||||
|
}
|
||||||
|
else if (isPaused()) {
|
||||||
if (hasMissingFiles())
|
if (hasMissingFiles())
|
||||||
m_state = TorrentState::MissingFiles;
|
m_state = TorrentState::MissingFiles;
|
||||||
else if (hasError())
|
else if (hasError())
|
||||||
@@ -1296,39 +1292,37 @@ void TorrentHandle::toggleSequentialDownload()
|
|||||||
setSequentialDownload(!isSequentialDownload());
|
setSequentialDownload(!isSequentialDownload());
|
||||||
}
|
}
|
||||||
|
|
||||||
void TorrentHandle::setFirstLastPiecePriority(bool b)
|
void TorrentHandle::setFirstLastPiecePriority(const bool enabled)
|
||||||
{
|
{
|
||||||
if (!hasMetadata()) {
|
if (!hasMetadata()) {
|
||||||
m_needsToSetFirstLastPiecePriority = b;
|
m_needsToSetFirstLastPiecePriority = enabled;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::vector<int> fp = m_nativeHandle.file_priorities();
|
// Download first and last pieces first for every file in the torrent
|
||||||
std::vector<int> pp = m_nativeHandle.piece_priorities();
|
const std::vector<int> filePriorities = nativeHandle().file_priorities();
|
||||||
|
std::vector<int> piecePriorities = nativeHandle().piece_priorities();
|
||||||
// Download first and last pieces first for all media files in the torrent
|
for (int index = 0; index < static_cast<int>(filePriorities.size()); ++index) {
|
||||||
int nbfiles = static_cast<int>(fp.size());
|
const int filePrio = filePriorities[index];
|
||||||
for (int index = 0; index < nbfiles; ++index) {
|
if (filePrio <= 0)
|
||||||
const QString path = filePath(index);
|
continue;
|
||||||
const QString ext = Utils::Fs::fileExtension(path);
|
|
||||||
if (Utils::Misc::isPreviewable(ext) && (fp[index] > 0)) {
|
|
||||||
qDebug() << "File" << path << "is previewable, toggle downloading of first/last pieces first";
|
|
||||||
|
|
||||||
// Determine the priority to set
|
// Determine the priority to set
|
||||||
int prio = b ? 7 : fp[index];
|
const int newPrio = enabled ? 7 : filePrio;
|
||||||
|
const TorrentInfo::PieceRange extremities = info().filePieces(index);
|
||||||
TorrentInfo::PieceRange extremities = info().filePieces(index);
|
|
||||||
|
|
||||||
// worst case: AVI index = 1% of total file size (at the end of the file)
|
// worst case: AVI index = 1% of total file size (at the end of the file)
|
||||||
int nNumPieces = ceil(fileSize(index) * 0.01 / pieceLength());
|
const int nNumPieces = std::ceil(fileSize(index) * 0.01 / pieceLength());
|
||||||
for (int i = 0; i < nNumPieces; ++i) {
|
for (int i = 0; i < nNumPieces; ++i) {
|
||||||
pp[extremities.first() + i] = prio;
|
piecePriorities[extremities.first() + i] = newPrio;
|
||||||
pp[extremities.last() - i] = prio;
|
piecePriorities[extremities.last() - i] = newPrio;
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
m_nativeHandle.prioritize_pieces(pp);
|
m_nativeHandle.prioritize_pieces(piecePriorities);
|
||||||
|
|
||||||
|
LogMsg(tr("Download first and last piece first: %1, torrent: '%2'")
|
||||||
|
.arg((enabled ? tr("On") : tr("Off")), name()));
|
||||||
}
|
}
|
||||||
|
|
||||||
void TorrentHandle::toggleFirstLastPiecePriority()
|
void TorrentHandle::toggleFirstLastPiecePriority()
|
||||||
@@ -1376,6 +1370,7 @@ void TorrentHandle::moveStorage(const QString &newPath, bool overwrite)
|
|||||||
, (overwrite ? libt::always_replace_files : libt::dont_replace));
|
, (overwrite ? libt::always_replace_files : libt::dont_replace));
|
||||||
m_moveStorageInfo.oldPath = oldPath;
|
m_moveStorageInfo.oldPath = oldPath;
|
||||||
m_moveStorageInfo.newPath = newPath;
|
m_moveStorageInfo.newPath = newPath;
|
||||||
|
updateState();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1425,7 +1420,7 @@ void TorrentHandle::handleStateUpdate(const libt::torrent_status &nativeStatus)
|
|||||||
updateStatus(nativeStatus);
|
updateStatus(nativeStatus);
|
||||||
}
|
}
|
||||||
|
|
||||||
void TorrentHandle::handleStorageMovedAlert(libtorrent::storage_moved_alert *p)
|
void TorrentHandle::handleStorageMovedAlert(const libtorrent::storage_moved_alert *p)
|
||||||
{
|
{
|
||||||
if (!isMoveInProgress()) {
|
if (!isMoveInProgress()) {
|
||||||
qWarning() << "Unexpected " << Q_FUNC_INFO << " call.";
|
qWarning() << "Unexpected " << Q_FUNC_INFO << " call.";
|
||||||
@@ -1442,8 +1437,8 @@ void TorrentHandle::handleStorageMovedAlert(libtorrent::storage_moved_alert *p)
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
qDebug("Torrent is successfully moved from %s to %s"
|
LogMsg(tr("Successfully moved torrent: %1. New path: %2").arg(name(), m_moveStorageInfo.newPath));
|
||||||
, qUtf8Printable(m_moveStorageInfo.oldPath), qUtf8Printable(m_moveStorageInfo.newPath));
|
|
||||||
const QDir oldDir {m_moveStorageInfo.oldPath};
|
const QDir oldDir {m_moveStorageInfo.oldPath};
|
||||||
if ((oldDir == QDir(m_session->torrentTempPath(info())))
|
if ((oldDir == QDir(m_session->torrentTempPath(info())))
|
||||||
&& (oldDir != QDir(m_session->tempPath()))) {
|
&& (oldDir != QDir(m_session->tempPath()))) {
|
||||||
@@ -1452,9 +1447,10 @@ void TorrentHandle::handleStorageMovedAlert(libtorrent::storage_moved_alert *p)
|
|||||||
qDebug() << "Removing torrent temp folder:" << m_moveStorageInfo.oldPath;
|
qDebug() << "Removing torrent temp folder:" << m_moveStorageInfo.oldPath;
|
||||||
Utils::Fs::smartRemoveEmptyFolderTree(m_moveStorageInfo.oldPath);
|
Utils::Fs::smartRemoveEmptyFolderTree(m_moveStorageInfo.oldPath);
|
||||||
}
|
}
|
||||||
updateStatus();
|
|
||||||
|
|
||||||
m_moveStorageInfo.newPath.clear();
|
m_moveStorageInfo.newPath.clear();
|
||||||
|
updateStatus();
|
||||||
|
|
||||||
if (!m_moveStorageInfo.queuedPath.isEmpty()) {
|
if (!m_moveStorageInfo.queuedPath.isEmpty()) {
|
||||||
moveStorage(m_moveStorageInfo.queuedPath, m_moveStorageInfo.queuedOverwrite);
|
moveStorage(m_moveStorageInfo.queuedPath, m_moveStorageInfo.queuedOverwrite);
|
||||||
m_moveStorageInfo.queuedPath.clear();
|
m_moveStorageInfo.queuedPath.clear();
|
||||||
@@ -1469,17 +1465,19 @@ void TorrentHandle::handleStorageMovedAlert(libtorrent::storage_moved_alert *p)
|
|||||||
m_moveFinishedTriggers.takeFirst()();
|
m_moveFinishedTriggers.takeFirst()();
|
||||||
}
|
}
|
||||||
|
|
||||||
void TorrentHandle::handleStorageMovedFailedAlert(libtorrent::storage_moved_failed_alert *p)
|
void TorrentHandle::handleStorageMovedFailedAlert(const libtorrent::storage_moved_failed_alert *p)
|
||||||
{
|
{
|
||||||
if (!isMoveInProgress()) {
|
if (!isMoveInProgress()) {
|
||||||
qWarning() << "Unexpected " << Q_FUNC_INFO << " call.";
|
qWarning() << "Unexpected " << Q_FUNC_INFO << " call.";
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
LogMsg(QCoreApplication::translate(i18nContext, "Could not move torrent: '%1'. Reason: %2")
|
LogMsg(tr("Could not move torrent: '%1'. Reason: %2")
|
||||||
.arg(name(), QString::fromStdString(p->message())), Log::CRITICAL);
|
.arg(name(), QString::fromStdString(p->message())), Log::CRITICAL);
|
||||||
|
|
||||||
m_moveStorageInfo.newPath.clear();
|
m_moveStorageInfo.newPath.clear();
|
||||||
|
updateStatus();
|
||||||
|
|
||||||
if (!m_moveStorageInfo.queuedPath.isEmpty()) {
|
if (!m_moveStorageInfo.queuedPath.isEmpty()) {
|
||||||
moveStorage(m_moveStorageInfo.queuedPath, m_moveStorageInfo.queuedOverwrite);
|
moveStorage(m_moveStorageInfo.queuedPath, m_moveStorageInfo.queuedOverwrite);
|
||||||
m_moveStorageInfo.queuedPath.clear();
|
m_moveStorageInfo.queuedPath.clear();
|
||||||
@@ -1489,7 +1487,7 @@ void TorrentHandle::handleStorageMovedFailedAlert(libtorrent::storage_moved_fail
|
|||||||
m_moveFinishedTriggers.takeFirst()();
|
m_moveFinishedTriggers.takeFirst()();
|
||||||
}
|
}
|
||||||
|
|
||||||
void TorrentHandle::handleTrackerReplyAlert(libtorrent::tracker_reply_alert *p)
|
void TorrentHandle::handleTrackerReplyAlert(const libtorrent::tracker_reply_alert *p)
|
||||||
{
|
{
|
||||||
#if LIBTORRENT_VERSION_NUM < 10100
|
#if LIBTORRENT_VERSION_NUM < 10100
|
||||||
QString trackerUrl = QString::fromStdString(p->url);
|
QString trackerUrl = QString::fromStdString(p->url);
|
||||||
@@ -1504,32 +1502,32 @@ void TorrentHandle::handleTrackerReplyAlert(libtorrent::tracker_reply_alert *p)
|
|||||||
m_session->handleTorrentTrackerReply(this, trackerUrl);
|
m_session->handleTorrentTrackerReply(this, trackerUrl);
|
||||||
}
|
}
|
||||||
|
|
||||||
void TorrentHandle::handleTrackerWarningAlert(libtorrent::tracker_warning_alert *p)
|
void TorrentHandle::handleTrackerWarningAlert(const libtorrent::tracker_warning_alert *p)
|
||||||
{
|
{
|
||||||
#if LIBTORRENT_VERSION_NUM < 10100
|
#if LIBTORRENT_VERSION_NUM < 10100
|
||||||
QString trackerUrl = QString::fromStdString(p->url);
|
const QString trackerUrl = QString::fromStdString(p->url);
|
||||||
QString message = QString::fromStdString(p->msg);
|
const QString message = QString::fromStdString(p->msg);
|
||||||
#else
|
#else
|
||||||
QString trackerUrl(p->tracker_url());
|
const QString trackerUrl = p->tracker_url();
|
||||||
QString message = QString::fromStdString(p->message());
|
const QString message = p->warning_message();
|
||||||
#endif
|
#endif
|
||||||
qDebug("Received a tracker warning for %s: %s", qUtf8Printable(trackerUrl), qUtf8Printable(message));
|
|
||||||
// Connection was successful now but there is a warning message
|
// Connection was successful now but there is a warning message
|
||||||
m_trackerInfos[trackerUrl].lastMessage = message; // Store warning message
|
m_trackerInfos[trackerUrl].lastMessage = message; // Store warning message
|
||||||
|
|
||||||
m_session->handleTorrentTrackerWarning(this, trackerUrl);
|
m_session->handleTorrentTrackerWarning(this, trackerUrl);
|
||||||
}
|
}
|
||||||
|
|
||||||
void TorrentHandle::handleTrackerErrorAlert(libtorrent::tracker_error_alert *p)
|
void TorrentHandle::handleTrackerErrorAlert(const libtorrent::tracker_error_alert *p)
|
||||||
{
|
{
|
||||||
#if LIBTORRENT_VERSION_NUM < 10100
|
#if LIBTORRENT_VERSION_NUM < 10100
|
||||||
QString trackerUrl = QString::fromStdString(p->url);
|
const QString trackerUrl = QString::fromStdString(p->url);
|
||||||
QString message = QString::fromStdString(p->msg);
|
const QString message = QString::fromStdString(p->msg);
|
||||||
#else
|
#else
|
||||||
QString trackerUrl(p->tracker_url());
|
const QString trackerUrl = p->tracker_url();
|
||||||
QString message = QString::fromStdString(p->message());
|
const QString message = p->error_message();
|
||||||
#endif
|
#endif
|
||||||
qDebug("Received a tracker error for %s: %s", qUtf8Printable(trackerUrl), qUtf8Printable(message));
|
|
||||||
m_trackerInfos[trackerUrl].lastMessage = message;
|
m_trackerInfos[trackerUrl].lastMessage = message;
|
||||||
|
|
||||||
if (p->status_code == 401)
|
if (p->status_code == 401)
|
||||||
@@ -1538,7 +1536,7 @@ void TorrentHandle::handleTrackerErrorAlert(libtorrent::tracker_error_alert *p)
|
|||||||
m_session->handleTorrentTrackerError(this, trackerUrl);
|
m_session->handleTorrentTrackerError(this, trackerUrl);
|
||||||
}
|
}
|
||||||
|
|
||||||
void TorrentHandle::handleTorrentCheckedAlert(libtorrent::torrent_checked_alert *p)
|
void TorrentHandle::handleTorrentCheckedAlert(const libtorrent::torrent_checked_alert *p)
|
||||||
{
|
{
|
||||||
Q_UNUSED(p);
|
Q_UNUSED(p);
|
||||||
qDebug("%s have just finished checking", qUtf8Printable(hash()));
|
qDebug("%s have just finished checking", qUtf8Printable(hash()));
|
||||||
@@ -1561,7 +1559,7 @@ void TorrentHandle::handleTorrentCheckedAlert(libtorrent::torrent_checked_alert
|
|||||||
m_session->handleTorrentChecked(this);
|
m_session->handleTorrentChecked(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
void TorrentHandle::handleTorrentFinishedAlert(libtorrent::torrent_finished_alert *p)
|
void TorrentHandle::handleTorrentFinishedAlert(const libtorrent::torrent_finished_alert *p)
|
||||||
{
|
{
|
||||||
Q_UNUSED(p);
|
Q_UNUSED(p);
|
||||||
qDebug("Got a torrent finished alert for %s", qUtf8Printable(name()));
|
qDebug("Got a torrent finished alert for %s", qUtf8Printable(name()));
|
||||||
@@ -1588,7 +1586,7 @@ void TorrentHandle::handleTorrentFinishedAlert(libtorrent::torrent_finished_aler
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void TorrentHandle::handleTorrentPausedAlert(libtorrent::torrent_paused_alert *p)
|
void TorrentHandle::handleTorrentPausedAlert(const libtorrent::torrent_paused_alert *p)
|
||||||
{
|
{
|
||||||
Q_UNUSED(p);
|
Q_UNUSED(p);
|
||||||
updateStatus();
|
updateStatus();
|
||||||
@@ -1596,13 +1594,13 @@ void TorrentHandle::handleTorrentPausedAlert(libtorrent::torrent_paused_alert *p
|
|||||||
m_session->handleTorrentPaused(this);
|
m_session->handleTorrentPaused(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
void TorrentHandle::handleTorrentResumedAlert(libtorrent::torrent_resumed_alert *p)
|
void TorrentHandle::handleTorrentResumedAlert(const libtorrent::torrent_resumed_alert *p)
|
||||||
{
|
{
|
||||||
Q_UNUSED(p);
|
Q_UNUSED(p);
|
||||||
m_session->handleTorrentResumed(this);
|
m_session->handleTorrentResumed(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
void TorrentHandle::handleSaveResumeDataAlert(libtorrent::save_resume_data_alert *p)
|
void TorrentHandle::handleSaveResumeDataAlert(const libtorrent::save_resume_data_alert *p)
|
||||||
{
|
{
|
||||||
const bool useDummyResumeData = !(p && p->resume_data);
|
const bool useDummyResumeData = !(p && p->resume_data);
|
||||||
libtorrent::entry dummyEntry;
|
libtorrent::entry dummyEntry;
|
||||||
@@ -1636,36 +1634,35 @@ void TorrentHandle::handleSaveResumeDataAlert(libtorrent::save_resume_data_alert
|
|||||||
m_session->handleTorrentResumeDataReady(this, resumeData);
|
m_session->handleTorrentResumeDataReady(this, resumeData);
|
||||||
}
|
}
|
||||||
|
|
||||||
void TorrentHandle::handleSaveResumeDataFailedAlert(libtorrent::save_resume_data_failed_alert *p)
|
void TorrentHandle::handleSaveResumeDataFailedAlert(const libtorrent::save_resume_data_failed_alert *p)
|
||||||
{
|
{
|
||||||
// if torrent has no metadata we should save dummy fastresume data
|
// if torrent has no metadata we should save dummy fastresume data
|
||||||
// containing Magnet URI and qBittorrent own resume data only
|
// containing Magnet URI and qBittorrent own resume data only
|
||||||
if (p->error.value() == libt::errors::no_metadata)
|
if (p->error.value() == libt::errors::no_metadata)
|
||||||
handleSaveResumeDataAlert(0);
|
handleSaveResumeDataAlert(nullptr);
|
||||||
else
|
else
|
||||||
m_session->handleTorrentResumeDataFailed(this);
|
m_session->handleTorrentResumeDataFailed(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
void TorrentHandle::handleFastResumeRejectedAlert(libtorrent::fastresume_rejected_alert *p)
|
void TorrentHandle::handleFastResumeRejectedAlert(const libtorrent::fastresume_rejected_alert *p)
|
||||||
{
|
{
|
||||||
qDebug("/!\\ Fast resume failed for %s, reason: %s", qUtf8Printable(name()), p->message().c_str());
|
qDebug("/!\\ Fast resume failed for %s, reason: %s", qUtf8Printable(name()), p->message().c_str());
|
||||||
Logger *const logger = Logger::instance();
|
|
||||||
|
|
||||||
updateStatus();
|
updateStatus();
|
||||||
if (p->error.value() == libt::errors::mismatching_file_size) {
|
if (p->error.value() == libt::errors::mismatching_file_size) {
|
||||||
// Mismatching file size (files were probably moved)
|
// Mismatching file size (files were probably moved)
|
||||||
logger->addMessage(QCoreApplication::translate(i18nContext, "File sizes mismatch for torrent '%1', pausing it.").arg(name()), Log::CRITICAL);
|
LogMsg(tr("File sizes mismatch for torrent '%1', pausing it.").arg(name()), Log::CRITICAL);
|
||||||
m_hasMissingFiles = true;
|
m_hasMissingFiles = true;
|
||||||
if (!isPaused())
|
if (!isPaused())
|
||||||
pause();
|
pause();
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
logger->addMessage(QCoreApplication::translate(i18nContext, "Fast resume data was rejected for torrent '%1'. Reason: %2. Checking again...")
|
LogMsg(tr("Fast resume data was rejected for torrent '%1'. Reason: %2. Checking again...")
|
||||||
.arg(name(), QString::fromStdString(p->message())), Log::CRITICAL);
|
.arg(name(), QString::fromStdString(p->message())), Log::CRITICAL);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void TorrentHandle::handleFileRenamedAlert(libtorrent::file_renamed_alert *p)
|
void TorrentHandle::handleFileRenamedAlert(const libtorrent::file_renamed_alert *p)
|
||||||
{
|
{
|
||||||
#if LIBTORRENT_VERSION_NUM < 10100
|
#if LIBTORRENT_VERSION_NUM < 10100
|
||||||
QString newName = Utils::Fs::fromNativePath(QString::fromStdString(p->name));
|
QString newName = Utils::Fs::fromNativePath(QString::fromStdString(p->name));
|
||||||
@@ -1697,7 +1694,7 @@ void TorrentHandle::handleFileRenamedAlert(libtorrent::file_renamed_alert *p)
|
|||||||
m_moveFinishedTriggers.takeFirst()();
|
m_moveFinishedTriggers.takeFirst()();
|
||||||
}
|
}
|
||||||
|
|
||||||
void TorrentHandle::handleFileRenameFailedAlert(libtorrent::file_rename_failed_alert *p)
|
void TorrentHandle::handleFileRenameFailedAlert(const libtorrent::file_rename_failed_alert *p)
|
||||||
{
|
{
|
||||||
Q_UNUSED(p);
|
Q_UNUSED(p);
|
||||||
|
|
||||||
@@ -1706,7 +1703,7 @@ void TorrentHandle::handleFileRenameFailedAlert(libtorrent::file_rename_failed_a
|
|||||||
m_moveFinishedTriggers.takeFirst()();
|
m_moveFinishedTriggers.takeFirst()();
|
||||||
}
|
}
|
||||||
|
|
||||||
void TorrentHandle::handleFileCompletedAlert(libtorrent::file_completed_alert *p)
|
void TorrentHandle::handleFileCompletedAlert(const libtorrent::file_completed_alert *p)
|
||||||
{
|
{
|
||||||
updateStatus();
|
updateStatus();
|
||||||
|
|
||||||
@@ -1722,7 +1719,7 @@ void TorrentHandle::handleFileCompletedAlert(libtorrent::file_completed_alert *p
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void TorrentHandle::handleStatsAlert(libtorrent::stats_alert *p)
|
void TorrentHandle::handleStatsAlert(const libtorrent::stats_alert *p)
|
||||||
{
|
{
|
||||||
Q_ASSERT(p->interval >= 1000);
|
Q_ASSERT(p->interval >= 1000);
|
||||||
SpeedSample transferred(p->transferred[libt::stats_alert::download_payload] * 1000LL / p->interval,
|
SpeedSample transferred(p->transferred[libt::stats_alert::download_payload] * 1000LL / p->interval,
|
||||||
@@ -1730,7 +1727,7 @@ void TorrentHandle::handleStatsAlert(libtorrent::stats_alert *p)
|
|||||||
m_speedMonitor.addSample(transferred);
|
m_speedMonitor.addSample(transferred);
|
||||||
}
|
}
|
||||||
|
|
||||||
void TorrentHandle::handleMetadataReceivedAlert(libt::metadata_received_alert *p)
|
void TorrentHandle::handleMetadataReceivedAlert(const libt::metadata_received_alert *p)
|
||||||
{
|
{
|
||||||
Q_UNUSED(p);
|
Q_UNUSED(p);
|
||||||
qDebug("Metadata received for torrent %s.", qUtf8Printable(name()));
|
qDebug("Metadata received for torrent %s.", qUtf8Printable(name()));
|
||||||
|
|||||||
@@ -149,6 +149,8 @@ namespace BitTorrent
|
|||||||
PausedDownloading,
|
PausedDownloading,
|
||||||
PausedUploading,
|
PausedUploading,
|
||||||
|
|
||||||
|
Moving,
|
||||||
|
|
||||||
MissingFiles,
|
MissingFiles,
|
||||||
Error
|
Error
|
||||||
};
|
};
|
||||||
@@ -331,7 +333,7 @@ namespace BitTorrent
|
|||||||
void setName(const QString &name);
|
void setName(const QString &name);
|
||||||
void setSequentialDownload(bool b);
|
void setSequentialDownload(bool b);
|
||||||
void toggleSequentialDownload();
|
void toggleSequentialDownload();
|
||||||
void setFirstLastPiecePriority(bool b);
|
void setFirstLastPiecePriority(bool enabled);
|
||||||
void toggleFirstLastPiecePriority();
|
void toggleFirstLastPiecePriority();
|
||||||
void pause();
|
void pause();
|
||||||
void resume(bool forced = false);
|
void resume(bool forced = false);
|
||||||
@@ -388,23 +390,23 @@ namespace BitTorrent
|
|||||||
void updateState();
|
void updateState();
|
||||||
void updateTorrentInfo();
|
void updateTorrentInfo();
|
||||||
|
|
||||||
void handleStorageMovedAlert(libtorrent::storage_moved_alert *p);
|
void handleStorageMovedAlert(const libtorrent::storage_moved_alert *p);
|
||||||
void handleStorageMovedFailedAlert(libtorrent::storage_moved_failed_alert *p);
|
void handleStorageMovedFailedAlert(const libtorrent::storage_moved_failed_alert *p);
|
||||||
void handleTrackerReplyAlert(libtorrent::tracker_reply_alert *p);
|
void handleTrackerReplyAlert(const libtorrent::tracker_reply_alert *p);
|
||||||
void handleTrackerWarningAlert(libtorrent::tracker_warning_alert *p);
|
void handleTrackerWarningAlert(const libtorrent::tracker_warning_alert *p);
|
||||||
void handleTrackerErrorAlert(libtorrent::tracker_error_alert *p);
|
void handleTrackerErrorAlert(const libtorrent::tracker_error_alert *p);
|
||||||
void handleTorrentCheckedAlert(libtorrent::torrent_checked_alert *p);
|
void handleTorrentCheckedAlert(const libtorrent::torrent_checked_alert *p);
|
||||||
void handleTorrentFinishedAlert(libtorrent::torrent_finished_alert *p);
|
void handleTorrentFinishedAlert(const libtorrent::torrent_finished_alert *p);
|
||||||
void handleTorrentPausedAlert(libtorrent::torrent_paused_alert *p);
|
void handleTorrentPausedAlert(const libtorrent::torrent_paused_alert *p);
|
||||||
void handleTorrentResumedAlert(libtorrent::torrent_resumed_alert *p);
|
void handleTorrentResumedAlert(const libtorrent::torrent_resumed_alert *p);
|
||||||
void handleSaveResumeDataAlert(libtorrent::save_resume_data_alert *p);
|
void handleSaveResumeDataAlert(const libtorrent::save_resume_data_alert *p);
|
||||||
void handleSaveResumeDataFailedAlert(libtorrent::save_resume_data_failed_alert *p);
|
void handleSaveResumeDataFailedAlert(const libtorrent::save_resume_data_failed_alert *p);
|
||||||
void handleFastResumeRejectedAlert(libtorrent::fastresume_rejected_alert *p);
|
void handleFastResumeRejectedAlert(const libtorrent::fastresume_rejected_alert *p);
|
||||||
void handleFileRenamedAlert(libtorrent::file_renamed_alert *p);
|
void handleFileRenamedAlert(const libtorrent::file_renamed_alert *p);
|
||||||
void handleFileRenameFailedAlert(libtorrent::file_rename_failed_alert *p);
|
void handleFileRenameFailedAlert(const libtorrent::file_rename_failed_alert *p);
|
||||||
void handleFileCompletedAlert(libtorrent::file_completed_alert *p);
|
void handleFileCompletedAlert(const libtorrent::file_completed_alert *p);
|
||||||
void handleMetadataReceivedAlert(libtorrent::metadata_received_alert *p);
|
void handleMetadataReceivedAlert(const libtorrent::metadata_received_alert *p);
|
||||||
void handleStatsAlert(libtorrent::stats_alert *p);
|
void handleStatsAlert(const libtorrent::stats_alert *p);
|
||||||
|
|
||||||
void resume_impl(bool forced, bool uploadMode);
|
void resume_impl(bool forced, bool uploadMode);
|
||||||
bool isMoveInProgress() const;
|
bool isMoveInProgress() const;
|
||||||
|
|||||||
@@ -26,20 +26,20 @@
|
|||||||
* exception statement from your version.
|
* exception statement from your version.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include <QDebug>
|
#include "torrentinfo.h"
|
||||||
#include <QString>
|
|
||||||
#include <QList>
|
|
||||||
#include <QUrl>
|
|
||||||
#include <QDateTime>
|
|
||||||
|
|
||||||
#include <libtorrent/error_code.hpp>
|
#include <libtorrent/error_code.hpp>
|
||||||
|
|
||||||
#include "base/utils/misc.h"
|
#include <QDateTime>
|
||||||
|
#include <QDebug>
|
||||||
|
#include <QString>
|
||||||
|
#include <QUrl>
|
||||||
|
|
||||||
#include "base/utils/fs.h"
|
#include "base/utils/fs.h"
|
||||||
|
#include "base/utils/misc.h"
|
||||||
#include "base/utils/string.h"
|
#include "base/utils/string.h"
|
||||||
#include "infohash.h"
|
#include "infohash.h"
|
||||||
#include "trackerentry.h"
|
#include "trackerentry.h"
|
||||||
#include "torrentinfo.h"
|
|
||||||
|
|
||||||
namespace libt = libtorrent;
|
namespace libt = libtorrent;
|
||||||
using namespace BitTorrent;
|
using namespace BitTorrent;
|
||||||
@@ -353,8 +353,8 @@ void TorrentInfo::renameFile(uint index, const QString &newPath)
|
|||||||
|
|
||||||
int BitTorrent::TorrentInfo::fileIndex(const QString& fileName) const
|
int BitTorrent::TorrentInfo::fileIndex(const QString& fileName) const
|
||||||
{
|
{
|
||||||
// the check whether the object valid is not needed here
|
// the check whether the object is valid is not needed here
|
||||||
// because filesCount() returns -1 in that case and the loop exits immediately
|
// because if filesCount() returns -1 the loop exits immediately
|
||||||
for (int i = 0; i < filesCount(); ++i)
|
for (int i = 0; i < filesCount(); ++i)
|
||||||
if (fileName == filePath(i))
|
if (fileName == filePath(i))
|
||||||
return i;
|
return i;
|
||||||
@@ -362,24 +362,29 @@ int BitTorrent::TorrentInfo::fileIndex(const QString& fileName) const
|
|||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool TorrentInfo::hasRootFolder() const
|
QString TorrentInfo::rootFolder() const
|
||||||
{
|
{
|
||||||
QString testRootFolder;
|
QString rootFolder;
|
||||||
for (int i = 0; i < filesCount(); ++i) {
|
for (int i = 0; i < filesCount(); ++i) {
|
||||||
const QString filePath = this->filePath(i);
|
const QString filePath = this->filePath(i);
|
||||||
if (QDir::isAbsolutePath(filePath)) continue;
|
if (QDir::isAbsolutePath(filePath)) continue;
|
||||||
|
|
||||||
const auto filePathElements = filePath.splitRef('/');
|
const auto filePathElements = filePath.splitRef('/');
|
||||||
// if at least one file has no root folder, no common root folder exists
|
// if at least one file has no root folder, no common root folder exists
|
||||||
if (filePathElements.count() <= 1) return false;
|
if (filePathElements.count() <= 1) return "";
|
||||||
|
|
||||||
if (testRootFolder.isEmpty())
|
if (rootFolder.isEmpty())
|
||||||
testRootFolder = filePathElements.at(0).toString();
|
rootFolder = filePathElements.at(0).toString();
|
||||||
else if (testRootFolder != filePathElements.at(0))
|
else if (rootFolder != filePathElements.at(0))
|
||||||
return false;
|
return "";
|
||||||
}
|
}
|
||||||
|
|
||||||
return true;
|
return rootFolder;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool TorrentInfo::hasRootFolder() const
|
||||||
|
{
|
||||||
|
return !rootFolder().isEmpty();
|
||||||
}
|
}
|
||||||
|
|
||||||
void TorrentInfo::stripRootFolder()
|
void TorrentInfo::stripRootFolder()
|
||||||
|
|||||||
@@ -29,21 +29,21 @@
|
|||||||
#ifndef BITTORRENT_TORRENTINFO_H
|
#ifndef BITTORRENT_TORRENTINFO_H
|
||||||
#define BITTORRENT_TORRENTINFO_H
|
#define BITTORRENT_TORRENTINFO_H
|
||||||
|
|
||||||
#include <QCoreApplication>
|
|
||||||
#include <QtGlobal>
|
|
||||||
|
|
||||||
#include <libtorrent/torrent_info.hpp>
|
#include <libtorrent/torrent_info.hpp>
|
||||||
#include <libtorrent/version.hpp>
|
#include <libtorrent/version.hpp>
|
||||||
|
|
||||||
|
#include <QCoreApplication>
|
||||||
|
#include <QList>
|
||||||
|
#include <QtGlobal>
|
||||||
|
#include <QVector>
|
||||||
|
|
||||||
#include "base/indexrange.h"
|
#include "base/indexrange.h"
|
||||||
|
|
||||||
class QString;
|
|
||||||
class QUrl;
|
|
||||||
class QDateTime;
|
|
||||||
class QStringList;
|
|
||||||
class QByteArray;
|
class QByteArray;
|
||||||
template<typename T> class QList;
|
class QDateTime;
|
||||||
template<typename T> class QVector;
|
class QString;
|
||||||
|
class QStringList;
|
||||||
|
class QUrl;
|
||||||
|
|
||||||
namespace BitTorrent
|
namespace BitTorrent
|
||||||
{
|
{
|
||||||
@@ -52,7 +52,7 @@ namespace BitTorrent
|
|||||||
|
|
||||||
class TorrentInfo
|
class TorrentInfo
|
||||||
{
|
{
|
||||||
Q_DECLARE_TR_FUNCTIONS("TorrentInfo")
|
Q_DECLARE_TR_FUNCTIONS(TorrentInfo)
|
||||||
|
|
||||||
public:
|
public:
|
||||||
#if LIBTORRENT_VERSION_NUM < 10100
|
#if LIBTORRENT_VERSION_NUM < 10100
|
||||||
@@ -104,6 +104,7 @@ namespace BitTorrent
|
|||||||
|
|
||||||
void renameFile(uint index, const QString &newPath);
|
void renameFile(uint index, const QString &newPath);
|
||||||
|
|
||||||
|
QString rootFolder() const;
|
||||||
bool hasRootFolder() const;
|
bool hasRootFolder() const;
|
||||||
void stripRootFolder();
|
void stripRootFolder();
|
||||||
|
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
* Bittorrent Client using Qt4 and libtorrent.
|
* Bittorrent Client using Qt and libtorrent.
|
||||||
* Copyright (C) 2015 Vladimir Golovnev <glassez@yandex.ru>
|
* Copyright (C) 2015 Vladimir Golovnev <glassez@yandex.ru>
|
||||||
* Copyright (C) 2006 Christophe Dumez <chris@qbittorrent.org>
|
* Copyright (C) 2006 Christophe Dumez <chris@qbittorrent.org>
|
||||||
*
|
*
|
||||||
@@ -27,6 +27,8 @@
|
|||||||
* exception statement from your version.
|
* exception statement from your version.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
#include "tracker.h"
|
||||||
|
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
|
||||||
#include <libtorrent/bencode.hpp>
|
#include <libtorrent/bencode.hpp>
|
||||||
@@ -37,7 +39,6 @@
|
|||||||
#include "base/preferences.h"
|
#include "base/preferences.h"
|
||||||
#include "base/utils/bytearray.h"
|
#include "base/utils/bytearray.h"
|
||||||
#include "base/utils/string.h"
|
#include "base/utils/string.h"
|
||||||
#include "tracker.h"
|
|
||||||
|
|
||||||
// static limits
|
// static limits
|
||||||
static const int MAX_TORRENTS = 100;
|
static const int MAX_TORRENTS = 100;
|
||||||
@@ -277,5 +278,3 @@ void Tracker::replyWithPeerList(const TrackerAnnounceRequest &annonceReq)
|
|||||||
// HTTP reply
|
// HTTP reply
|
||||||
print(reply, Http::CONTENT_TYPE_TXT);
|
print(reply, Http::CONTENT_TYPE_TXT);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -28,14 +28,14 @@
|
|||||||
|
|
||||||
#include "filesystemwatcher.h"
|
#include "filesystemwatcher.h"
|
||||||
|
|
||||||
|
#include <QtGlobal>
|
||||||
|
|
||||||
#if defined(Q_OS_MAC) || defined(Q_OS_FREEBSD)
|
#if defined(Q_OS_MAC) || defined(Q_OS_FREEBSD)
|
||||||
#include <cstring>
|
#include <cstring>
|
||||||
#include <sys/mount.h>
|
#include <sys/mount.h>
|
||||||
#include <sys/param.h>
|
#include <sys/param.h>
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#include <QtGlobal>
|
|
||||||
|
|
||||||
#include "base/algorithm.h"
|
#include "base/algorithm.h"
|
||||||
#include "base/bittorrent/magneturi.h"
|
#include "base/bittorrent/magneturi.h"
|
||||||
#include "base/bittorrent/torrentinfo.h"
|
#include "base/bittorrent/torrentinfo.h"
|
||||||
|
|||||||
@@ -2,7 +2,7 @@
|
|||||||
* Bittorrent Client using Qt and libtorrent.
|
* Bittorrent Client using Qt and libtorrent.
|
||||||
* Copyright (C) 2018 Mike Tzou (Chocobo1)
|
* Copyright (C) 2018 Mike Tzou (Chocobo1)
|
||||||
* Copyright (C) 2014 Vladimir Golovnev <glassez@yandex.ru>
|
* Copyright (C) 2014 Vladimir Golovnev <glassez@yandex.ru>
|
||||||
* Copyright (C) 2006 Ishan Arora and Christophe Dumez
|
* Copyright (C) 2006 Ishan Arora and Christophe Dumez <chris@qbittorrent.org>
|
||||||
*
|
*
|
||||||
* This program is free software; you can redistribute it and/or
|
* This program is free software; you can redistribute it and/or
|
||||||
* modify it under the terms of the GNU General Public License
|
* modify it under the terms of the GNU General Public License
|
||||||
@@ -26,8 +26,6 @@
|
|||||||
* modify file(s), you may extend this exception to your version of the file(s),
|
* modify file(s), you may extend this exception to your version of the file(s),
|
||||||
* but you are not obligated to do so. If you do not wish to do so, delete this
|
* but you are not obligated to do so. If you do not wish to do so, delete this
|
||||||
* exception statement from your version.
|
* exception statement from your version.
|
||||||
*
|
|
||||||
* Contact : chris@qbittorrent.org
|
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include "connection.h"
|
#include "connection.h"
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
/*
|
/*
|
||||||
* Bittorrent Client using Qt and libtorrent.
|
* Bittorrent Client using Qt and libtorrent.
|
||||||
* Copyright (C) 2014 Vladimir Golovnev <glassez@yandex.ru>
|
* Copyright (C) 2014 Vladimir Golovnev <glassez@yandex.ru>
|
||||||
* Copyright (C) 2006 Ishan Arora and Christophe Dumez
|
* Copyright (C) 2006 Ishan Arora and Christophe Dumez <chris@qbittorrent.org>
|
||||||
*
|
*
|
||||||
* This program is free software; you can redistribute it and/or
|
* This program is free software; you can redistribute it and/or
|
||||||
* modify it under the terms of the GNU General Public License
|
* modify it under the terms of the GNU General Public License
|
||||||
@@ -25,8 +25,6 @@
|
|||||||
* modify file(s), you may extend this exception to your version of the file(s),
|
* modify file(s), you may extend this exception to your version of the file(s),
|
||||||
* but you are not obligated to do so. If you do not wish to do so, delete this
|
* but you are not obligated to do so. If you do not wish to do so, delete this
|
||||||
* exception statement from your version.
|
* exception statement from your version.
|
||||||
*
|
|
||||||
* Contact : chris@qbittorrent.org
|
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
|
||||||
@@ -50,7 +48,7 @@ namespace Http
|
|||||||
Q_DISABLE_COPY(Connection)
|
Q_DISABLE_COPY(Connection)
|
||||||
|
|
||||||
public:
|
public:
|
||||||
Connection(QTcpSocket *socket, IRequestHandler *requestHandler, QObject *parent = 0);
|
Connection(QTcpSocket *socket, IRequestHandler *requestHandler, QObject *parent = nullptr);
|
||||||
~Connection();
|
~Connection();
|
||||||
|
|
||||||
bool hasExpired(qint64 timeout) const;
|
bool hasExpired(qint64 timeout) const;
|
||||||
|
|||||||
@@ -291,7 +291,7 @@ bool RequestParser::parseFormData(const QByteArray &data)
|
|||||||
const QLatin1String name("name");
|
const QLatin1String name("name");
|
||||||
|
|
||||||
if (headersMap.contains(filename)) {
|
if (headersMap.contains(filename)) {
|
||||||
m_request.files.append({filename, headersMap[HEADER_CONTENT_TYPE], payload});
|
m_request.files.append({headersMap[filename], headersMap[HEADER_CONTENT_TYPE], payload});
|
||||||
}
|
}
|
||||||
else if (headersMap.contains(name)) {
|
else if (headersMap.contains(name)) {
|
||||||
m_request.posts[headersMap[name]] = payload;
|
m_request.posts[headersMap[name]] = payload;
|
||||||
|
|||||||
@@ -47,7 +47,7 @@ void IconProvider::freeInstance()
|
|||||||
{
|
{
|
||||||
if (m_instance) {
|
if (m_instance) {
|
||||||
delete m_instance;
|
delete m_instance;
|
||||||
m_instance = 0;
|
m_instance = nullptr;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -61,4 +61,4 @@ QString IconProvider::getIconPath(const QString &iconId)
|
|||||||
return ":/icons/qbt-theme/" + iconId + ".png";
|
return ":/icons/qbt-theme/" + iconId + ".png";
|
||||||
}
|
}
|
||||||
|
|
||||||
IconProvider *IconProvider::m_instance = 0;
|
IconProvider *IconProvider::m_instance = nullptr;
|
||||||
|
|||||||
@@ -46,7 +46,7 @@ public:
|
|||||||
virtual QString getIconPath(const QString &iconId);
|
virtual QString getIconPath(const QString &iconId);
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
explicit IconProvider(QObject *parent = 0);
|
explicit IconProvider(QObject *parent = nullptr);
|
||||||
~IconProvider();
|
~IconProvider();
|
||||||
|
|
||||||
static IconProvider *m_instance;
|
static IconProvider *m_instance;
|
||||||
|
|||||||
@@ -3,12 +3,12 @@
|
|||||||
#include <QDateTime>
|
#include <QDateTime>
|
||||||
#include "base/utils/string.h"
|
#include "base/utils/string.h"
|
||||||
|
|
||||||
Logger* Logger::m_instance = 0;
|
Logger *Logger::m_instance = nullptr;
|
||||||
|
|
||||||
Logger::Logger()
|
Logger::Logger()
|
||||||
: lock(QReadWriteLock::Recursive)
|
: m_lock(QReadWriteLock::Recursive)
|
||||||
, msgCounter(0)
|
, m_msgCounter(0)
|
||||||
, peerCounter(0)
|
, m_peerCounter(0)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -29,15 +29,15 @@ void Logger::freeInstance()
|
|||||||
{
|
{
|
||||||
if (m_instance) {
|
if (m_instance) {
|
||||||
delete m_instance;
|
delete m_instance;
|
||||||
m_instance = 0;
|
m_instance = nullptr;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void Logger::addMessage(const QString &message, const Log::MsgType &type)
|
void Logger::addMessage(const QString &message, const Log::MsgType &type)
|
||||||
{
|
{
|
||||||
QWriteLocker locker(&lock);
|
QWriteLocker locker(&m_lock);
|
||||||
|
|
||||||
Log::Msg temp = { msgCounter++, QDateTime::currentMSecsSinceEpoch(), type, message.toHtmlEscaped() };
|
Log::Msg temp = {m_msgCounter++, QDateTime::currentMSecsSinceEpoch(), type, message.toHtmlEscaped()};
|
||||||
m_messages.push_back(temp);
|
m_messages.push_back(temp);
|
||||||
|
|
||||||
if (m_messages.size() >= MAX_LOG_MESSAGES)
|
if (m_messages.size() >= MAX_LOG_MESSAGES)
|
||||||
@@ -48,9 +48,9 @@ void Logger::addMessage(const QString &message, const Log::MsgType &type)
|
|||||||
|
|
||||||
void Logger::addPeer(const QString &ip, bool blocked, const QString &reason)
|
void Logger::addPeer(const QString &ip, bool blocked, const QString &reason)
|
||||||
{
|
{
|
||||||
QWriteLocker locker(&lock);
|
QWriteLocker locker(&m_lock);
|
||||||
|
|
||||||
Log::Peer temp = { peerCounter++, QDateTime::currentMSecsSinceEpoch(), ip.toHtmlEscaped(), blocked, reason.toHtmlEscaped() };
|
Log::Peer temp = {m_peerCounter++, QDateTime::currentMSecsSinceEpoch(), ip.toHtmlEscaped(), blocked, reason.toHtmlEscaped()};
|
||||||
m_peers.push_back(temp);
|
m_peers.push_back(temp);
|
||||||
|
|
||||||
if (m_peers.size() >= MAX_LOG_MESSAGES)
|
if (m_peers.size() >= MAX_LOG_MESSAGES)
|
||||||
@@ -61,9 +61,9 @@ void Logger::addPeer(const QString &ip, bool blocked, const QString &reason)
|
|||||||
|
|
||||||
QVector<Log::Msg> Logger::getMessages(int lastKnownId) const
|
QVector<Log::Msg> Logger::getMessages(int lastKnownId) const
|
||||||
{
|
{
|
||||||
QReadLocker locker(&lock);
|
QReadLocker locker(&m_lock);
|
||||||
|
|
||||||
int diff = msgCounter - lastKnownId - 1;
|
int diff = m_msgCounter - lastKnownId - 1;
|
||||||
int size = m_messages.size();
|
int size = m_messages.size();
|
||||||
|
|
||||||
if ((lastKnownId == -1) || (diff >= size))
|
if ((lastKnownId == -1) || (diff >= size))
|
||||||
@@ -77,9 +77,9 @@ QVector<Log::Msg> Logger::getMessages(int lastKnownId) const
|
|||||||
|
|
||||||
QVector<Log::Peer> Logger::getPeers(int lastKnownId) const
|
QVector<Log::Peer> Logger::getPeers(int lastKnownId) const
|
||||||
{
|
{
|
||||||
QReadLocker locker(&lock);
|
QReadLocker locker(&m_lock);
|
||||||
|
|
||||||
int diff = peerCounter - lastKnownId - 1;
|
int diff = m_peerCounter - lastKnownId - 1;
|
||||||
int size = m_peers.size();
|
int size = m_peers.size();
|
||||||
|
|
||||||
if ((lastKnownId == -1) || (diff >= size))
|
if ((lastKnownId == -1) || (diff >= size))
|
||||||
|
|||||||
@@ -1,10 +1,10 @@
|
|||||||
#ifndef LOGGER_H
|
#ifndef LOGGER_H
|
||||||
#define LOGGER_H
|
#define LOGGER_H
|
||||||
|
|
||||||
|
#include <QObject>
|
||||||
|
#include <QReadWriteLock>
|
||||||
#include <QString>
|
#include <QString>
|
||||||
#include <QVector>
|
#include <QVector>
|
||||||
#include <QReadWriteLock>
|
|
||||||
#include <QObject>
|
|
||||||
|
|
||||||
const int MAX_LOG_MESSAGES = 20000;
|
const int MAX_LOG_MESSAGES = 20000;
|
||||||
|
|
||||||
@@ -66,9 +66,9 @@ private:
|
|||||||
static Logger *m_instance;
|
static Logger *m_instance;
|
||||||
QVector<Log::Msg> m_messages;
|
QVector<Log::Msg> m_messages;
|
||||||
QVector<Log::Peer> m_peers;
|
QVector<Log::Peer> m_peers;
|
||||||
mutable QReadWriteLock lock;
|
mutable QReadWriteLock m_lock;
|
||||||
int msgCounter;
|
int m_msgCounter;
|
||||||
int peerCounter;
|
int m_peerCounter;
|
||||||
};
|
};
|
||||||
|
|
||||||
// Helper function
|
// Helper function
|
||||||
|
|||||||
@@ -52,7 +52,7 @@ DNSUpdater::DNSUpdater(QObject *parent)
|
|||||||
|
|
||||||
// Start IP checking timer
|
// Start IP checking timer
|
||||||
m_ipCheckTimer.setInterval(IP_CHECK_INTERVAL_MS);
|
m_ipCheckTimer.setInterval(IP_CHECK_INTERVAL_MS);
|
||||||
connect(&m_ipCheckTimer, SIGNAL(timeout()), SLOT(checkPublicIP()));
|
connect(&m_ipCheckTimer, &QTimer::timeout, this, &DNSUpdater::checkPublicIP);
|
||||||
m_ipCheckTimer.start();
|
m_ipCheckTimer.start();
|
||||||
|
|
||||||
// Check lastUpdate to avoid flooding
|
// Check lastUpdate to avoid flooding
|
||||||
@@ -77,8 +77,9 @@ void DNSUpdater::checkPublicIP()
|
|||||||
DownloadHandler *handler = DownloadManager::instance()->downloadUrl(
|
DownloadHandler *handler = DownloadManager::instance()->downloadUrl(
|
||||||
"http://checkip.dyndns.org", false, 0, false,
|
"http://checkip.dyndns.org", false, 0, false,
|
||||||
"qBittorrent/" QBT_VERSION_2);
|
"qBittorrent/" QBT_VERSION_2);
|
||||||
connect(handler, SIGNAL(downloadFinished(QString, QByteArray)), SLOT(ipRequestFinished(QString, QByteArray)));
|
connect(handler, static_cast<void (Net::DownloadHandler::*)(const QString &, const QByteArray &)>(&Net::DownloadHandler::downloadFinished)
|
||||||
connect(handler, SIGNAL(downloadFailed(QString, QString)), SLOT(ipRequestFailed(QString, QString)));
|
, this, &DNSUpdater::ipRequestFinished);
|
||||||
|
connect(handler, &Net::DownloadHandler::downloadFailed, this, &DNSUpdater::ipRequestFailed);
|
||||||
|
|
||||||
m_lastIPCheckTime = QDateTime::currentDateTime();
|
m_lastIPCheckTime = QDateTime::currentDateTime();
|
||||||
}
|
}
|
||||||
@@ -124,8 +125,9 @@ void DNSUpdater::updateDNSService()
|
|||||||
DownloadHandler *handler = DownloadManager::instance()->downloadUrl(
|
DownloadHandler *handler = DownloadManager::instance()->downloadUrl(
|
||||||
getUpdateUrl(), false, 0, false,
|
getUpdateUrl(), false, 0, false,
|
||||||
"qBittorrent/" QBT_VERSION_2);
|
"qBittorrent/" QBT_VERSION_2);
|
||||||
connect(handler, SIGNAL(downloadFinished(QString, QByteArray)), SLOT(ipUpdateFinished(QString, QByteArray)));
|
connect(handler, static_cast<void (Net::DownloadHandler::*)(const QString &, const QByteArray &)>(&Net::DownloadHandler::downloadFinished)
|
||||||
connect(handler, SIGNAL(downloadFailed(QString, QString)), SLOT(ipUpdateFailed(QString, QString)));
|
, this, &DNSUpdater::ipUpdateFinished);
|
||||||
|
connect(handler, &Net::DownloadHandler::downloadFailed, this, &DNSUpdater::ipUpdateFailed);
|
||||||
}
|
}
|
||||||
|
|
||||||
QString DNSUpdater::getUpdateUrl() const
|
QString DNSUpdater::getUpdateUrl() const
|
||||||
|
|||||||
@@ -124,7 +124,7 @@ void DownloadHandler::checkDownloadSize(qint64 bytesReceived, qint64 bytesTotal)
|
|||||||
emit downloadFailed(m_url, msg.arg(Utils::Misc::friendlyUnit(bytesTotal), Utils::Misc::friendlyUnit(m_sizeLimit)));
|
emit downloadFailed(m_url, msg.arg(Utils::Misc::friendlyUnit(bytesTotal), Utils::Misc::friendlyUnit(m_sizeLimit)));
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
disconnect(m_reply, SIGNAL(downloadProgress(qint64, qint64)), this, SLOT(checkDownloadSize(qint64, qint64)));
|
disconnect(m_reply, &QNetworkReply::downloadProgress, this, &Net::DownloadHandler::checkDownloadSize);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else if (bytesReceived > m_sizeLimit) {
|
else if (bytesReceived > m_sizeLimit) {
|
||||||
@@ -137,8 +137,8 @@ void DownloadHandler::init()
|
|||||||
{
|
{
|
||||||
m_reply->setParent(this);
|
m_reply->setParent(this);
|
||||||
if (m_sizeLimit > 0)
|
if (m_sizeLimit > 0)
|
||||||
connect(m_reply, SIGNAL(downloadProgress(qint64, qint64)), this, SLOT(checkDownloadSize(qint64, qint64)));
|
connect(m_reply, &QNetworkReply::downloadProgress, this, &Net::DownloadHandler::checkDownloadSize);
|
||||||
connect(m_reply, SIGNAL(finished()), this, SLOT(processFinishedDownload()));
|
connect(m_reply, &QNetworkReply::finished, this, &Net::DownloadHandler::processFinishedDownload);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool DownloadHandler::saveToFile(const QByteArray &replyData, QString &filePath)
|
bool DownloadHandler::saveToFile(const QByteArray &replyData, QString &filePath)
|
||||||
|
|||||||
@@ -51,7 +51,7 @@ namespace
|
|||||||
class NetworkCookieJar : public QNetworkCookieJar
|
class NetworkCookieJar : public QNetworkCookieJar
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
explicit NetworkCookieJar(QObject *parent = 0)
|
explicit NetworkCookieJar(QObject *parent = nullptr)
|
||||||
: QNetworkCookieJar(parent)
|
: QNetworkCookieJar(parent)
|
||||||
{
|
{
|
||||||
QDateTime now = QDateTime::currentDateTime();
|
QDateTime now = QDateTime::currentDateTime();
|
||||||
@@ -107,13 +107,13 @@ namespace
|
|||||||
|
|
||||||
using namespace Net;
|
using namespace Net;
|
||||||
|
|
||||||
DownloadManager *DownloadManager::m_instance = 0;
|
DownloadManager *DownloadManager::m_instance = nullptr;
|
||||||
|
|
||||||
DownloadManager::DownloadManager(QObject *parent)
|
DownloadManager::DownloadManager(QObject *parent)
|
||||||
: QObject(parent)
|
: QObject(parent)
|
||||||
{
|
{
|
||||||
#ifndef QT_NO_OPENSSL
|
#ifndef QT_NO_OPENSSL
|
||||||
connect(&m_networkManager, SIGNAL(sslErrors(QNetworkReply *, QList<QSslError>)), this, SLOT(ignoreSslErrors(QNetworkReply *, QList<QSslError>)));
|
connect(&m_networkManager, &QNetworkAccessManager::sslErrors, this, &Net::DownloadManager::ignoreSslErrors);
|
||||||
#endif
|
#endif
|
||||||
m_networkManager.setCookieJar(new NetworkCookieJar(this));
|
m_networkManager.setCookieJar(new NetworkCookieJar(this));
|
||||||
}
|
}
|
||||||
@@ -128,7 +128,7 @@ void DownloadManager::freeInstance()
|
|||||||
{
|
{
|
||||||
if (m_instance) {
|
if (m_instance) {
|
||||||
delete m_instance;
|
delete m_instance;
|
||||||
m_instance = 0;
|
m_instance = nullptr;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -64,7 +64,7 @@ namespace Net
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
private:
|
private:
|
||||||
explicit DownloadManager(QObject *parent = 0);
|
explicit DownloadManager(QObject *parent = nullptr);
|
||||||
|
|
||||||
void applyProxySettings();
|
void applyProxySettings();
|
||||||
|
|
||||||
|
|||||||
@@ -60,7 +60,7 @@ GeoIPManager::GeoIPManager()
|
|||||||
, m_geoIPDatabase(nullptr)
|
, m_geoIPDatabase(nullptr)
|
||||||
{
|
{
|
||||||
configure();
|
configure();
|
||||||
connect(Preferences::instance(), SIGNAL(changed()), SLOT(configure()));
|
connect(Preferences::instance(), &Preferences::changed, this, &GeoIPManager::configure);
|
||||||
}
|
}
|
||||||
|
|
||||||
GeoIPManager::~GeoIPManager()
|
GeoIPManager::~GeoIPManager()
|
||||||
@@ -119,8 +119,9 @@ void GeoIPManager::manageDatabaseUpdate()
|
|||||||
void GeoIPManager::downloadDatabaseFile()
|
void GeoIPManager::downloadDatabaseFile()
|
||||||
{
|
{
|
||||||
DownloadHandler *handler = DownloadManager::instance()->downloadUrl(DATABASE_URL);
|
DownloadHandler *handler = DownloadManager::instance()->downloadUrl(DATABASE_URL);
|
||||||
connect(handler, SIGNAL(downloadFinished(QString, QByteArray)), SLOT(downloadFinished(QString, QByteArray)));
|
connect(handler, static_cast<void (Net::DownloadHandler::*)(const QString &, const QByteArray &)>(&Net::DownloadHandler::downloadFinished)
|
||||||
connect(handler, SIGNAL(downloadFailed(QString, QString)), SLOT(downloadFailed(QString, QString)));
|
, this, &GeoIPManager::downloadFinished);
|
||||||
|
connect(handler, &Net::DownloadHandler::downloadFailed, this, &GeoIPManager::downloadFailed);
|
||||||
}
|
}
|
||||||
|
|
||||||
QString GeoIPManager::lookup(const QHostAddress &hostAddr) const
|
QString GeoIPManager::lookup(const QHostAddress &hostAddr) const
|
||||||
|
|||||||
@@ -36,7 +36,7 @@
|
|||||||
#include "base/logger.h"
|
#include "base/logger.h"
|
||||||
#include "base/settingsstorage.h"
|
#include "base/settingsstorage.h"
|
||||||
|
|
||||||
static const QString KEY_ENABLED = QLatin1String("Network/PortForwardingEnabled");
|
static const QString KEY_ENABLED = QStringLiteral("Network/PortForwardingEnabled");
|
||||||
|
|
||||||
namespace libt = libtorrent;
|
namespace libt = libtorrent;
|
||||||
using namespace Net;
|
using namespace Net;
|
||||||
|
|||||||
@@ -26,20 +26,18 @@
|
|||||||
* exception statement from your version.
|
* exception statement from your version.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
#include <QDateTime>
|
||||||
#include <QDebug>
|
#include <QDebug>
|
||||||
#include <QVariant>
|
#include <QFile>
|
||||||
#include <QHash>
|
#include <QHash>
|
||||||
#include <QHostAddress>
|
#include <QHostAddress>
|
||||||
#include <QDateTime>
|
#include <QVariant>
|
||||||
#include <QFile>
|
|
||||||
|
|
||||||
#include "base/types.h"
|
#include "base/types.h"
|
||||||
#include "geoipdatabase.h"
|
#include "geoipdatabase.h"
|
||||||
|
|
||||||
namespace
|
namespace
|
||||||
{
|
{
|
||||||
const quint32 __ENDIAN_TEST__ = 0x00000001;
|
|
||||||
const bool __IS_LITTLE_ENDIAN__ = (reinterpret_cast<const uchar *>(&__ENDIAN_TEST__)[0] == 0x01);
|
|
||||||
const qint32 MAX_FILE_SIZE = 67108864; // 64MB
|
const qint32 MAX_FILE_SIZE = 67108864; // 64MB
|
||||||
const char DB_TYPE[] = "GeoLite2-Country";
|
const char DB_TYPE[] = "GeoLite2-Country";
|
||||||
const quint32 MAX_METADATA_SIZE = 131072; // 128KB
|
const quint32 MAX_METADATA_SIZE = 131072; // 128KB
|
||||||
@@ -91,7 +89,7 @@ GeoIPDatabase::GeoIPDatabase(quint32 size)
|
|||||||
|
|
||||||
GeoIPDatabase *GeoIPDatabase::load(const QString &filename, QString &error)
|
GeoIPDatabase *GeoIPDatabase::load(const QString &filename, QString &error)
|
||||||
{
|
{
|
||||||
GeoIPDatabase *db = 0;
|
GeoIPDatabase *db = nullptr;
|
||||||
QFile file(filename);
|
QFile file(filename);
|
||||||
if (file.size() > MAX_FILE_SIZE) {
|
if (file.size() > MAX_FILE_SIZE) {
|
||||||
error = tr("Unsupported database file size.");
|
error = tr("Unsupported database file size.");
|
||||||
@@ -122,7 +120,7 @@ GeoIPDatabase *GeoIPDatabase::load(const QString &filename, QString &error)
|
|||||||
|
|
||||||
GeoIPDatabase *GeoIPDatabase::load(const QByteArray &data, QString &error)
|
GeoIPDatabase *GeoIPDatabase::load(const QByteArray &data, QString &error)
|
||||||
{
|
{
|
||||||
GeoIPDatabase *db = 0;
|
GeoIPDatabase *db = nullptr;
|
||||||
if (data.size() > MAX_FILE_SIZE) {
|
if (data.size() > MAX_FILE_SIZE) {
|
||||||
error = tr("Unsupported database file size.");
|
error = tr("Unsupported database file size.");
|
||||||
return 0;
|
return 0;
|
||||||
@@ -448,8 +446,12 @@ bool GeoIPDatabase::readDataFieldDescriptor(quint32 &offset, DataFieldDescriptor
|
|||||||
|
|
||||||
void GeoIPDatabase::fromBigEndian(uchar *buf, quint32 len) const
|
void GeoIPDatabase::fromBigEndian(uchar *buf, quint32 len) const
|
||||||
{
|
{
|
||||||
if (__IS_LITTLE_ENDIAN__)
|
#if (Q_BYTE_ORDER == Q_LITTLE_ENDIAN)
|
||||||
std::reverse(buf, buf + len);
|
std::reverse(buf, buf + len);
|
||||||
|
#else
|
||||||
|
Q_UNUSED(buf);
|
||||||
|
Q_UNUSED(len);
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
QVariant GeoIPDatabase::readMapValue(quint32 &offset, quint32 count) const
|
QVariant GeoIPDatabase::readMapValue(quint32 &offset, quint32 count) const
|
||||||
|
|||||||
@@ -29,13 +29,13 @@
|
|||||||
#ifndef GEOIPDATABASE_H
|
#ifndef GEOIPDATABASE_H
|
||||||
#define GEOIPDATABASE_H
|
#define GEOIPDATABASE_H
|
||||||
|
|
||||||
#include <QtGlobal>
|
|
||||||
#include <QCoreApplication>
|
#include <QCoreApplication>
|
||||||
|
#include <QtGlobal>
|
||||||
|
|
||||||
class QHostAddress;
|
|
||||||
class QString;
|
|
||||||
class QByteArray;
|
class QByteArray;
|
||||||
class QDateTime;
|
class QDateTime;
|
||||||
|
class QHostAddress;
|
||||||
|
class QString;
|
||||||
|
|
||||||
struct DataFieldDescriptor;
|
struct DataFieldDescriptor;
|
||||||
|
|
||||||
|
|||||||
@@ -27,9 +27,10 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
#include "proxyconfigurationmanager.h"
|
#include "proxyconfigurationmanager.h"
|
||||||
|
|
||||||
#include "base/settingsstorage.h"
|
#include "base/settingsstorage.h"
|
||||||
|
|
||||||
#define SETTINGS_KEY(name) "Network/Proxy/" name
|
#define SETTINGS_KEY(name) QStringLiteral("Network/Proxy/" name)
|
||||||
const QString KEY_ONLY_FOR_TORRENTS = SETTINGS_KEY("OnlyForTorrents");
|
const QString KEY_ONLY_FOR_TORRENTS = SETTINGS_KEY("OnlyForTorrents");
|
||||||
const QString KEY_TYPE = SETTINGS_KEY("Type");
|
const QString KEY_TYPE = SETTINGS_KEY("Type");
|
||||||
const QString KEY_IP = SETTINGS_KEY("IP");
|
const QString KEY_IP = SETTINGS_KEY("IP");
|
||||||
@@ -80,7 +81,7 @@ void ProxyConfigurationManager::freeInstance()
|
|||||||
{
|
{
|
||||||
if (m_instance) {
|
if (m_instance) {
|
||||||
delete m_instance;
|
delete m_instance;
|
||||||
m_instance = 0;
|
m_instance = nullptr;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
/*
|
/*
|
||||||
* Bittorrent Client using Qt and libtorrent.
|
* Bittorrent Client using Qt and libtorrent.
|
||||||
* Copyright (C) 2006 Christophe Dumez
|
* Copyright (C) 2006 Christophe Dumez <chris@qbittorrent.org>
|
||||||
*
|
*
|
||||||
* This program is free software; you can redistribute it and/or
|
* This program is free software; you can redistribute it and/or
|
||||||
* modify it under the terms of the GNU General Public License
|
* modify it under the terms of the GNU General Public License
|
||||||
@@ -24,26 +24,24 @@
|
|||||||
* modify file(s), you may extend this exception to your version of the file(s),
|
* modify file(s), you may extend this exception to your version of the file(s),
|
||||||
* but you are not obligated to do so. If you do not wish to do so, delete this
|
* but you are not obligated to do so. If you do not wish to do so, delete this
|
||||||
* exception statement from your version.
|
* exception statement from your version.
|
||||||
*
|
|
||||||
* Contact : chris@qbittorrent.org
|
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
#include "reverseresolution.h"
|
||||||
|
|
||||||
|
#include <boost/asio/ip/tcp.hpp>
|
||||||
|
#include <boost/version.hpp>
|
||||||
|
|
||||||
#include <QDebug>
|
#include <QDebug>
|
||||||
#include <QHostInfo>
|
#include <QHostInfo>
|
||||||
#include <QString>
|
#include <QString>
|
||||||
|
|
||||||
#include <boost/version.hpp>
|
|
||||||
#include <boost/asio/ip/tcp.hpp>
|
|
||||||
|
|
||||||
#include "reverseresolution.h"
|
|
||||||
|
|
||||||
const int CACHE_SIZE = 500;
|
const int CACHE_SIZE = 500;
|
||||||
|
|
||||||
using namespace Net;
|
using namespace Net;
|
||||||
|
|
||||||
static inline bool isUsefulHostName(const QString &hostname, const QString &ip)
|
static inline bool isUsefulHostName(const QString &hostname, const QString &ip)
|
||||||
{
|
{
|
||||||
return (!hostname.isEmpty() && hostname != ip);
|
return (!hostname.isEmpty() && (hostname != ip));
|
||||||
}
|
}
|
||||||
|
|
||||||
ReverseResolution::ReverseResolution(QObject *parent)
|
ReverseResolution::ReverseResolution(QObject *parent)
|
||||||
@@ -67,7 +65,11 @@ void ReverseResolution::resolve(const QString &ip)
|
|||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
// Actually resolve the ip
|
// Actually resolve the ip
|
||||||
|
#if (QT_VERSION >= QT_VERSION_CHECK(5, 9, 0))
|
||||||
|
m_lookups.insert(QHostInfo::lookupHost(ip, this, &ReverseResolution::hostResolved), ip);
|
||||||
|
#else
|
||||||
m_lookups.insert(QHostInfo::lookupHost(ip, this, SLOT(hostResolved(QHostInfo))), ip);
|
m_lookups.insert(QHostInfo::lookupHost(ip, this, SLOT(hostResolved(QHostInfo))), ip);
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
/*
|
/*
|
||||||
* Bittorrent Client using Qt and libtorrent.
|
* Bittorrent Client using Qt and libtorrent.
|
||||||
* Copyright (C) 2006 Christophe Dumez
|
* Copyright (C) 2006 Christophe Dumez <chris@qbittorrent.org>
|
||||||
*
|
*
|
||||||
* This program is free software; you can redistribute it and/or
|
* This program is free software; you can redistribute it and/or
|
||||||
* modify it under the terms of the GNU General Public License
|
* modify it under the terms of the GNU General Public License
|
||||||
@@ -24,8 +24,6 @@
|
|||||||
* modify file(s), you may extend this exception to your version of the file(s),
|
* modify file(s), you may extend this exception to your version of the file(s),
|
||||||
* but you are not obligated to do so. If you do not wish to do so, delete this
|
* but you are not obligated to do so. If you do not wish to do so, delete this
|
||||||
* exception statement from your version.
|
* exception statement from your version.
|
||||||
*
|
|
||||||
* Contact : chris@qbittorrent.org
|
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#ifndef NET_REVERSERESOLUTION_H
|
#ifndef NET_REVERSERESOLUTION_H
|
||||||
@@ -34,10 +32,8 @@
|
|||||||
#include <QCache>
|
#include <QCache>
|
||||||
#include <QObject>
|
#include <QObject>
|
||||||
|
|
||||||
QT_BEGIN_NAMESPACE
|
|
||||||
class QHostInfo;
|
class QHostInfo;
|
||||||
class QString;
|
class QString;
|
||||||
QT_END_NAMESPACE
|
|
||||||
|
|
||||||
namespace Net
|
namespace Net
|
||||||
{
|
{
|
||||||
@@ -47,7 +43,7 @@ namespace Net
|
|||||||
Q_DISABLE_COPY(ReverseResolution)
|
Q_DISABLE_COPY(ReverseResolution)
|
||||||
|
|
||||||
public:
|
public:
|
||||||
explicit ReverseResolution(QObject *parent = 0);
|
explicit ReverseResolution(QObject *parent = nullptr);
|
||||||
~ReverseResolution();
|
~ReverseResolution();
|
||||||
|
|
||||||
void resolve(const QString &ip);
|
void resolve(const QString &ip);
|
||||||
|
|||||||
@@ -111,9 +111,10 @@ Smtp::Smtp(QObject *parent)
|
|||||||
m_socket = new QTcpSocket(this);
|
m_socket = new QTcpSocket(this);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
connect(m_socket, SIGNAL(readyRead()), SLOT(readyRead()));
|
connect(m_socket, &QIODevice::readyRead, this, &Smtp::readyRead);
|
||||||
connect(m_socket, SIGNAL(disconnected()), SLOT(deleteLater()));
|
connect(m_socket, &QAbstractSocket::disconnected, this, &QObject::deleteLater);
|
||||||
connect(m_socket, SIGNAL(error(QAbstractSocket::SocketError)), SLOT(error(QAbstractSocket::SocketError)));
|
connect(m_socket, static_cast<void (QAbstractSocket::*)(QAbstractSocket::SocketError)>(&QAbstractSocket::error)
|
||||||
|
, this, &Smtp::error);
|
||||||
|
|
||||||
// Test hmacMD5 function (http://www.faqs.org/rfcs/rfc2202.html)
|
// Test hmacMD5 function (http://www.faqs.org/rfcs/rfc2202.html)
|
||||||
Q_ASSERT(hmacMD5("Jefe", "what do ya want for nothing?").toHex()
|
Q_ASSERT(hmacMD5("Jefe", "what do ya want for nothing?").toHex()
|
||||||
@@ -140,8 +141,8 @@ void Smtp::sendMail(const QString &from, const QString &to, const QString &subje
|
|||||||
+ "Content-Transfer-Encoding: base64\r\n"
|
+ "Content-Transfer-Encoding: base64\r\n"
|
||||||
+ "\r\n";
|
+ "\r\n";
|
||||||
// Encode the body in base64
|
// Encode the body in base64
|
||||||
QString crlf_body = body;
|
QString crlfBody = body;
|
||||||
QByteArray b = crlf_body.replace("\n", "\r\n").toUtf8().toBase64();
|
QByteArray b = crlfBody.replace("\n", "\r\n").toUtf8().toBase64();
|
||||||
int ct = b.length();
|
int ct = b.length();
|
||||||
for (int i = 0; i < ct; i += 78)
|
for (int i = 0; i < ct; i += 78)
|
||||||
m_message += b.mid(i, 78);
|
m_message += b.mid(i, 78);
|
||||||
@@ -183,7 +184,7 @@ void Smtp::readyRead()
|
|||||||
QByteArray code = line.left(3);
|
QByteArray code = line.left(3);
|
||||||
|
|
||||||
switch (m_state) {
|
switch (m_state) {
|
||||||
case Init: {
|
case Init:
|
||||||
if (code[0] == '2') {
|
if (code[0] == '2') {
|
||||||
// The server may send a multiline greeting/INIT/220 response.
|
// The server may send a multiline greeting/INIT/220 response.
|
||||||
// We wait until it finishes.
|
// We wait until it finishes.
|
||||||
@@ -197,7 +198,6 @@ void Smtp::readyRead()
|
|||||||
m_state = Close;
|
m_state = Close;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
}
|
|
||||||
case EhloSent:
|
case EhloSent:
|
||||||
case HeloSent:
|
case HeloSent:
|
||||||
case EhloGreetReceived:
|
case EhloGreetReceived:
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
/*
|
/*
|
||||||
* Bittorrent Client using Qt4 and libtorrent.
|
* Bittorrent Client using Qt and libtorrent.
|
||||||
* Copyright (C) 2006 Christophe Dumez
|
* Copyright (C) 2014 sledgehammer999 <sledgehammer999@qbittorrent.org>
|
||||||
* Copyright (C) 2014 sledgehammer999
|
* Copyright (C) 2006 Christophe Dumez <chris@qbittorrent.org>
|
||||||
*
|
*
|
||||||
* This program is free software; you can redistribute it and/or
|
* This program is free software; you can redistribute it and/or
|
||||||
* modify it under the terms of the GNU General Public License
|
* modify it under the terms of the GNU General Public License
|
||||||
@@ -25,9 +25,6 @@
|
|||||||
* modify file(s), you may extend this exception to your version of the file(s),
|
* modify file(s), you may extend this exception to your version of the file(s),
|
||||||
* but you are not obligated to do so. If you do not wish to do so, delete this
|
* but you are not obligated to do so. If you do not wish to do so, delete this
|
||||||
* exception statement from your version.
|
* exception statement from your version.
|
||||||
*
|
|
||||||
* Contact : chris@qbittorrent.org
|
|
||||||
* Contact : hammered999@gmail.com
|
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include "preferences.h"
|
#include "preferences.h"
|
||||||
@@ -59,7 +56,7 @@
|
|||||||
#include "utils/fs.h"
|
#include "utils/fs.h"
|
||||||
#include "utils/misc.h"
|
#include "utils/misc.h"
|
||||||
|
|
||||||
Preferences *Preferences::m_instance = 0;
|
Preferences *Preferences::m_instance = nullptr;
|
||||||
|
|
||||||
Preferences::Preferences() = default;
|
Preferences::Preferences() = default;
|
||||||
|
|
||||||
@@ -78,7 +75,7 @@ void Preferences::freeInstance()
|
|||||||
{
|
{
|
||||||
if (m_instance) {
|
if (m_instance) {
|
||||||
delete m_instance;
|
delete m_instance;
|
||||||
m_instance = 0;
|
m_instance = nullptr;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -420,12 +417,12 @@ void Preferences::setSchedulerEndTime(const QTime &time)
|
|||||||
setValue("Preferences/Scheduler/end_time", time);
|
setValue("Preferences/Scheduler/end_time", time);
|
||||||
}
|
}
|
||||||
|
|
||||||
scheduler_days Preferences::getSchedulerDays() const
|
SchedulerDays Preferences::getSchedulerDays() const
|
||||||
{
|
{
|
||||||
return static_cast<scheduler_days>(value("Preferences/Scheduler/days", EVERY_DAY).toInt());
|
return static_cast<SchedulerDays>(value("Preferences/Scheduler/days", EVERY_DAY).toInt());
|
||||||
}
|
}
|
||||||
|
|
||||||
void Preferences::setSchedulerDays(scheduler_days days)
|
void Preferences::setSchedulerDays(SchedulerDays days)
|
||||||
{
|
{
|
||||||
setValue("Preferences/Scheduler/days", static_cast<int>(days));
|
setValue("Preferences/Scheduler/days", static_cast<int>(days));
|
||||||
}
|
}
|
||||||
@@ -690,12 +687,12 @@ QString Preferences::getUILockPasswordMD5() const
|
|||||||
return value("Locking/password").toString();
|
return value("Locking/password").toString();
|
||||||
}
|
}
|
||||||
|
|
||||||
void Preferences::setUILockPassword(const QString &clear_password)
|
void Preferences::setUILockPassword(const QString &clearPassword)
|
||||||
{
|
{
|
||||||
QCryptographicHash md5(QCryptographicHash::Md5);
|
QCryptographicHash md5(QCryptographicHash::Md5);
|
||||||
md5.addData(clear_password.toLocal8Bit());
|
md5.addData(clearPassword.toLocal8Bit());
|
||||||
QString md5_password = md5.result().toHex();
|
QString md5Password = md5.result().toHex();
|
||||||
setValue("Locking/password", md5_password);
|
setValue("Locking/password", md5Password);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool Preferences::isUILocked() const
|
bool Preferences::isUILocked() const
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
/*
|
/*
|
||||||
* Bittorrent Client using Qt4 and libtorrent.
|
* Bittorrent Client using Qt and libtorrent.
|
||||||
* Copyright (C) 2006 Christophe Dumez
|
* Copyright (C) 2014 sledgehammer999 <sledgehammer999@qbittorrent.org>
|
||||||
* Copyright (C) 2014 sledgehammer999
|
* Copyright (C) 2006 Christophe Dumez <chris@qbittorrent.org>
|
||||||
*
|
*
|
||||||
* This program is free software; you can redistribute it and/or
|
* This program is free software; you can redistribute it and/or
|
||||||
* modify it under the terms of the GNU General Public License
|
* modify it under the terms of the GNU General Public License
|
||||||
@@ -25,9 +25,6 @@
|
|||||||
* modify file(s), you may extend this exception to your version of the file(s),
|
* modify file(s), you may extend this exception to your version of the file(s),
|
||||||
* but you are not obligated to do so. If you do not wish to do so, delete this
|
* but you are not obligated to do so. If you do not wish to do so, delete this
|
||||||
* exception statement from your version.
|
* exception statement from your version.
|
||||||
*
|
|
||||||
* Contact : chris@qbittorrent.org
|
|
||||||
* Contact : hammered999@gmail.com
|
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#ifndef PREFERENCES_H
|
#ifndef PREFERENCES_H
|
||||||
@@ -47,7 +44,7 @@
|
|||||||
#include "base/utils/net.h"
|
#include "base/utils/net.h"
|
||||||
#include "types.h"
|
#include "types.h"
|
||||||
|
|
||||||
enum scheduler_days
|
enum SchedulerDays
|
||||||
{
|
{
|
||||||
EVERY_DAY,
|
EVERY_DAY,
|
||||||
WEEK_DAYS,
|
WEEK_DAYS,
|
||||||
@@ -166,8 +163,8 @@ public:
|
|||||||
void setSchedulerStartTime(const QTime &time);
|
void setSchedulerStartTime(const QTime &time);
|
||||||
QTime getSchedulerEndTime() const;
|
QTime getSchedulerEndTime() const;
|
||||||
void setSchedulerEndTime(const QTime &time);
|
void setSchedulerEndTime(const QTime &time);
|
||||||
scheduler_days getSchedulerDays() const;
|
SchedulerDays getSchedulerDays() const;
|
||||||
void setSchedulerDays(scheduler_days days);
|
void setSchedulerDays(SchedulerDays days);
|
||||||
|
|
||||||
// Search
|
// Search
|
||||||
bool isSearchEnabled() const;
|
bool isSearchEnabled() const;
|
||||||
@@ -222,7 +219,7 @@ public:
|
|||||||
void setDynDNSPassword(const QString &password);
|
void setDynDNSPassword(const QString &password);
|
||||||
|
|
||||||
// Advanced settings
|
// Advanced settings
|
||||||
void setUILockPassword(const QString &clear_password);
|
void setUILockPassword(const QString &clearPassword);
|
||||||
void clearUILockPassword();
|
void clearUILockPassword();
|
||||||
QString getUILockPasswordMD5() const;
|
QString getUILockPasswordMD5() const;
|
||||||
bool isUILocked() const;
|
bool isUILocked() const;
|
||||||
|
|||||||
@@ -25,7 +25,6 @@
|
|||||||
* modify file(s), you may extend this exception to your version of the file(s),
|
* modify file(s), you may extend this exception to your version of the file(s),
|
||||||
* but you are not obligated to do so. If you do not wish to do so, delete this
|
* but you are not obligated to do so. If you do not wish to do so, delete this
|
||||||
* exception statement from your version.
|
* exception statement from your version.
|
||||||
*
|
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#ifndef QBT_PROFILE_P_H
|
#ifndef QBT_PROFILE_P_H
|
||||||
@@ -33,6 +32,7 @@
|
|||||||
|
|
||||||
#include <QDir>
|
#include <QDir>
|
||||||
#include <QStandardPaths>
|
#include <QStandardPaths>
|
||||||
|
|
||||||
#include "base/profile.h"
|
#include "base/profile.h"
|
||||||
|
|
||||||
namespace Private
|
namespace Private
|
||||||
@@ -132,4 +132,5 @@ namespace Private
|
|||||||
QDir m_baseDir;
|
QDir m_baseDir;
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif // QBT_PROFILE_P_H
|
#endif // QBT_PROFILE_P_H
|
||||||
|
|||||||
@@ -25,7 +25,6 @@
|
|||||||
* modify file(s), you may extend this exception to your version of the file(s),
|
* modify file(s), you may extend this exception to your version of the file(s),
|
||||||
* but you are not obligated to do so. If you do not wish to do so, delete this
|
* but you are not obligated to do so. If you do not wish to do so, delete this
|
||||||
* exception statement from your version.
|
* exception statement from your version.
|
||||||
*
|
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include "profile.h"
|
#include "profile.h"
|
||||||
|
|||||||
@@ -33,9 +33,9 @@
|
|||||||
|
|
||||||
#include <memory>
|
#include <memory>
|
||||||
|
|
||||||
#include <QString>
|
|
||||||
#include <QScopedPointer>
|
#include <QScopedPointer>
|
||||||
#include <QSettings>
|
#include <QSettings>
|
||||||
|
#include <QString>
|
||||||
|
|
||||||
class Application;
|
class Application;
|
||||||
|
|
||||||
|
|||||||
@@ -29,8 +29,8 @@
|
|||||||
|
|
||||||
#include "rss_parser.h"
|
#include "rss_parser.h"
|
||||||
|
|
||||||
#include <QDebug>
|
|
||||||
#include <QDateTime>
|
#include <QDateTime>
|
||||||
|
#include <QDebug>
|
||||||
#include <QGlobalStatic>
|
#include <QGlobalStatic>
|
||||||
#include <QHash>
|
#include <QHash>
|
||||||
#include <QMetaObject>
|
#include <QMetaObject>
|
||||||
|
|||||||
@@ -38,6 +38,19 @@
|
|||||||
|
|
||||||
using namespace RSS;
|
using namespace RSS;
|
||||||
|
|
||||||
|
namespace
|
||||||
|
{
|
||||||
|
QVariantHash articleDataFromJSON(const QJsonObject &jsonObj)
|
||||||
|
{
|
||||||
|
auto varHash = jsonObj.toVariantHash();
|
||||||
|
// JSON object store DateTime as string so we need to convert it
|
||||||
|
varHash[Article::KeyDate] =
|
||||||
|
QDateTime::fromString(jsonObj.value(Article::KeyDate).toString(), Qt::RFC2822Date);
|
||||||
|
|
||||||
|
return varHash;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
const QString Article::KeyId(QStringLiteral("id"));
|
const QString Article::KeyId(QStringLiteral("id"));
|
||||||
const QString Article::KeyDate(QStringLiteral("date"));
|
const QString Article::KeyDate(QStringLiteral("date"));
|
||||||
const QString Article::KeyTitle(QStringLiteral("title"));
|
const QString Article::KeyTitle(QStringLiteral("title"));
|
||||||
@@ -60,6 +73,9 @@ Article::Article(Feed *feed, const QVariantHash &varHash)
|
|||||||
, m_isRead(varHash.value(KeyIsRead, false).toBool())
|
, m_isRead(varHash.value(KeyIsRead, false).toBool())
|
||||||
, m_data(varHash)
|
, m_data(varHash)
|
||||||
{
|
{
|
||||||
|
if (!m_date.isValid())
|
||||||
|
throw std::runtime_error("Bad RSS Article data");
|
||||||
|
|
||||||
// If item does not have a guid, fall back to some other identifier
|
// If item does not have a guid, fall back to some other identifier
|
||||||
if (m_guid.isEmpty())
|
if (m_guid.isEmpty())
|
||||||
m_guid = varHash.value(KeyTorrentURL).toString();
|
m_guid = varHash.value(KeyTorrentURL).toString();
|
||||||
@@ -77,11 +93,8 @@ Article::Article(Feed *feed, const QVariantHash &varHash)
|
|||||||
}
|
}
|
||||||
|
|
||||||
Article::Article(Feed *feed, const QJsonObject &jsonObj)
|
Article::Article(Feed *feed, const QJsonObject &jsonObj)
|
||||||
: Article(feed, jsonObj.toVariantHash())
|
: Article(feed, articleDataFromJSON(jsonObj))
|
||||||
{
|
{
|
||||||
// JSON object store DateTime as string so we need to convert it
|
|
||||||
m_date = QDateTime::fromString(jsonObj.value(KeyDate).toString(), Qt::RFC2822Date);
|
|
||||||
m_data[KeyDate] = m_date;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
QString Article::guid() const
|
QString Article::guid() const
|
||||||
|
|||||||
@@ -365,19 +365,7 @@ void AutoDownloader::processJob(const QSharedPointer<ProcessingJob> &job)
|
|||||||
for (AutoDownloadRule &rule: m_rules) {
|
for (AutoDownloadRule &rule: m_rules) {
|
||||||
if (!rule.isEnabled()) continue;
|
if (!rule.isEnabled()) continue;
|
||||||
if (!rule.feedURLs().contains(job->feedURL)) continue;
|
if (!rule.feedURLs().contains(job->feedURL)) continue;
|
||||||
if (!rule.matches(job->articleData.value(Article::KeyTitle).toString())) continue;
|
if (!rule.accepts(job->articleData)) continue;
|
||||||
|
|
||||||
auto articleDate = job->articleData.value(Article::KeyDate).toDateTime();
|
|
||||||
// if rule is in ignoring state do nothing with matched torrent
|
|
||||||
if (rule.ignoreDays() > 0) {
|
|
||||||
if (rule.lastMatch().isValid()) {
|
|
||||||
if (articleDate < rule.lastMatch().addDays(rule.ignoreDays()))
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
rule.setLastMatch(articleDate);
|
|
||||||
rule.appendLastComputedEpisode();
|
|
||||||
|
|
||||||
m_dirty = true;
|
m_dirty = true;
|
||||||
storeDeferred();
|
storeDeferred();
|
||||||
|
|||||||
@@ -39,13 +39,14 @@
|
|||||||
#include <QString>
|
#include <QString>
|
||||||
#include <QStringList>
|
#include <QStringList>
|
||||||
|
|
||||||
|
#include "../global.h"
|
||||||
#include "../preferences.h"
|
#include "../preferences.h"
|
||||||
#include "../tristatebool.h"
|
#include "../tristatebool.h"
|
||||||
#include "../utils/fs.h"
|
#include "../utils/fs.h"
|
||||||
#include "../utils/string.h"
|
#include "../utils/string.h"
|
||||||
#include "rss_feed.h"
|
|
||||||
#include "rss_article.h"
|
#include "rss_article.h"
|
||||||
#include "rss_autodownloader.h"
|
#include "rss_autodownloader.h"
|
||||||
|
#include "rss_feed.h"
|
||||||
|
|
||||||
namespace
|
namespace
|
||||||
{
|
{
|
||||||
@@ -192,197 +193,198 @@ QRegularExpression AutoDownloadRule::cachedRegex(const QString &expression, bool
|
|||||||
// The cache is cleared whenever the regex/wildcard, must or must not contain fields or
|
// The cache is cleared whenever the regex/wildcard, must or must not contain fields or
|
||||||
// episode filter are modified.
|
// episode filter are modified.
|
||||||
Q_ASSERT(!expression.isEmpty());
|
Q_ASSERT(!expression.isEmpty());
|
||||||
QRegularExpression regex(m_dataPtr->cachedRegexes[expression]);
|
|
||||||
|
|
||||||
if (!regex.pattern().isEmpty())
|
QRegularExpression ®ex = m_dataPtr->cachedRegexes[expression];
|
||||||
return regex;
|
if (regex.pattern().isEmpty()) {
|
||||||
|
regex = QRegularExpression {
|
||||||
return m_dataPtr->cachedRegexes[expression] = QRegularExpression(isRegex ? expression : Utils::String::wildcardToRegex(expression), QRegularExpression::CaseInsensitiveOption);
|
(isRegex ? expression : Utils::String::wildcardToRegex(expression))
|
||||||
|
, QRegularExpression::CaseInsensitiveOption};
|
||||||
}
|
}
|
||||||
|
|
||||||
bool AutoDownloadRule::matches(const QString &articleTitle, const QString &expression) const
|
return regex;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool AutoDownloadRule::matchesExpression(const QString &articleTitle, const QString &expression) const
|
||||||
{
|
{
|
||||||
static QRegularExpression whitespace("\\s+");
|
const QRegularExpression whitespace {"\\s+"};
|
||||||
|
|
||||||
if (expression.isEmpty()) {
|
if (expression.isEmpty()) {
|
||||||
// A regex of the form "expr|" will always match, so do the same for wildcards
|
// A regex of the form "expr|" will always match, so do the same for wildcards
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
else if (m_dataPtr->useRegex) {
|
|
||||||
|
if (m_dataPtr->useRegex) {
|
||||||
QRegularExpression reg(cachedRegex(expression));
|
QRegularExpression reg(cachedRegex(expression));
|
||||||
return reg.match(articleTitle).hasMatch();
|
return reg.match(articleTitle).hasMatch();
|
||||||
}
|
}
|
||||||
else {
|
|
||||||
// Only match if every wildcard token (separated by spaces) is present in the article name.
|
// Only match if every wildcard token (separated by spaces) is present in the article name.
|
||||||
// Order of wildcard tokens is unimportant (if order is important, they should have used *).
|
// Order of wildcard tokens is unimportant (if order is important, they should have used *).
|
||||||
foreach (const QString &wildcard, expression.split(whitespace, QString::SplitBehavior::SkipEmptyParts)) {
|
const QStringList wildcards {expression.split(whitespace, QString::SplitBehavior::SkipEmptyParts)};
|
||||||
QRegularExpression reg(cachedRegex(wildcard, false));
|
for (const QString &wildcard : wildcards) {
|
||||||
|
const QRegularExpression reg {cachedRegex(wildcard, false)};
|
||||||
if (!reg.match(articleTitle).hasMatch())
|
if (!reg.match(articleTitle).hasMatch())
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool AutoDownloadRule::matches(const QString &articleTitle) const
|
bool AutoDownloadRule::matchesMustContainExpression(const QString &articleTitle) const
|
||||||
|
{
|
||||||
|
if (m_dataPtr->mustContain.empty())
|
||||||
|
return true;
|
||||||
|
|
||||||
|
// Each expression is either a regex, or a set of wildcards separated by whitespace.
|
||||||
|
// Accept if any complete expression matches.
|
||||||
|
for (const QString &expression : qAsConst(m_dataPtr->mustContain)) {
|
||||||
|
// A regex of the form "expr|" will always match, so do the same for wildcards
|
||||||
|
if (matchesExpression(articleTitle, expression))
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool AutoDownloadRule::matchesMustNotContainExpression(const QString& articleTitle) const
|
||||||
|
{
|
||||||
|
if (m_dataPtr->mustNotContain.empty())
|
||||||
|
return true;
|
||||||
|
|
||||||
|
// Each expression is either a regex, or a set of wildcards separated by whitespace.
|
||||||
|
// Reject if any complete expression matches.
|
||||||
|
for (const QString &expression : qAsConst(m_dataPtr->mustNotContain)) {
|
||||||
|
// A regex of the form "expr|" will always match, so do the same for wildcards
|
||||||
|
if (matchesExpression(articleTitle, expression))
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool AutoDownloadRule::matchesEpisodeFilterExpression(const QString& articleTitle) const
|
||||||
{
|
{
|
||||||
// Reset the lastComputedEpisode, we don't want to leak it between matches
|
// Reset the lastComputedEpisode, we don't want to leak it between matches
|
||||||
m_dataPtr->lastComputedEpisode.clear();
|
m_dataPtr->lastComputedEpisode.clear();
|
||||||
|
|
||||||
if (!m_dataPtr->mustContain.empty()) {
|
if (m_dataPtr->episodeFilter.isEmpty())
|
||||||
bool logged = false;
|
return true;
|
||||||
bool foundMustContain = false;
|
|
||||||
|
|
||||||
// Each expression is either a regex, or a set of wildcards separated by whitespace.
|
const QRegularExpression filterRegex {cachedRegex("(^\\d{1,4})x(.*;$)")};
|
||||||
// Accept if any complete expression matches.
|
const QRegularExpressionMatch matcher {filterRegex.match(m_dataPtr->episodeFilter)};
|
||||||
foreach (const QString &expression, m_dataPtr->mustContain) {
|
if (!matcher.hasMatch())
|
||||||
if (!logged) {
|
|
||||||
// qDebug() << "Checking matching" << (m_dataPtr->useRegex ? "regex:" : "wildcard expressions:") << m_dataPtr->mustContain.join("|");
|
|
||||||
logged = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
// A regex of the form "expr|" will always match, so do the same for wildcards
|
|
||||||
foundMustContain = matches(articleTitle, expression);
|
|
||||||
|
|
||||||
if (foundMustContain) {
|
|
||||||
// qDebug() << "Found matching" << (m_dataPtr->useRegex ? "regex:" : "wildcard expression:") << expression;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!foundMustContain)
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!m_dataPtr->mustNotContain.empty()) {
|
|
||||||
bool logged = false;
|
|
||||||
|
|
||||||
// Each expression is either a regex, or a set of wildcards separated by whitespace.
|
|
||||||
// Reject if any complete expression matches.
|
|
||||||
foreach (const QString &expression, m_dataPtr->mustNotContain) {
|
|
||||||
if (!logged) {
|
|
||||||
// qDebug() << "Checking not matching" << (m_dataPtr->useRegex ? "regex:" : "wildcard expressions:") << m_dataPtr->mustNotContain.join("|");
|
|
||||||
logged = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
// A regex of the form "expr|" will always match, so do the same for wildcards
|
|
||||||
if (matches(articleTitle, expression)) {
|
|
||||||
// qDebug() << "Found not matching" << (m_dataPtr->useRegex ? "regex:" : "wildcard expression:") << expression;
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!m_dataPtr->episodeFilter.isEmpty()) {
|
|
||||||
// qDebug() << "Checking episode filter:" << m_dataPtr->episodeFilter;
|
|
||||||
QRegularExpression f(cachedRegex("(^\\d{1,4})x(.*;$)"));
|
|
||||||
QRegularExpressionMatch matcher = f.match(m_dataPtr->episodeFilter);
|
|
||||||
bool matched = matcher.hasMatch();
|
|
||||||
|
|
||||||
if (!matched)
|
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
QString s = matcher.captured(1);
|
const QString season {matcher.captured(1)};
|
||||||
QStringList eps = matcher.captured(2).split(";");
|
const QStringList episodes {matcher.captured(2).split(';')};
|
||||||
int sOurs = s.toInt();
|
const int seasonOurs {season.toInt()};
|
||||||
|
|
||||||
foreach (QString ep, eps) {
|
for (QString episode : episodes) {
|
||||||
if (ep.isEmpty())
|
if (episode.isEmpty())
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
// We need to trim leading zeroes, but if it's all zeros then we want episode zero.
|
// We need to trim leading zeroes, but if it's all zeros then we want episode zero.
|
||||||
while (ep.size() > 1 && ep.startsWith("0"))
|
while ((episode.size() > 1) && episode.startsWith('0'))
|
||||||
ep = ep.right(ep.size() - 1);
|
episode = episode.right(episode.size() - 1);
|
||||||
|
|
||||||
if (ep.indexOf('-') != -1) { // Range detected
|
if (episode.indexOf('-') != -1) { // Range detected
|
||||||
QString partialPattern1 = "\\bs0?(\\d{1,4})[ -_\\.]?e(0?\\d{1,4})(?:\\D|\\b)";
|
const QString partialPattern1 {"\\bs0?(\\d{1,4})[ -_\\.]?e(0?\\d{1,4})(?:\\D|\\b)"};
|
||||||
QString partialPattern2 = "\\b(\\d{1,4})x(0?\\d{1,4})(?:\\D|\\b)";
|
const QString partialPattern2 {"\\b(\\d{1,4})x(0?\\d{1,4})(?:\\D|\\b)"};
|
||||||
QRegularExpression reg(cachedRegex(partialPattern1));
|
|
||||||
|
|
||||||
if (ep.endsWith('-')) { // Infinite range
|
|
||||||
int epOurs = ep.leftRef(ep.size() - 1).toInt();
|
|
||||||
|
|
||||||
// Extract partial match from article and compare as digits
|
// Extract partial match from article and compare as digits
|
||||||
matcher = reg.match(articleTitle);
|
QRegularExpressionMatch matcher = cachedRegex(partialPattern1).match(articleTitle);
|
||||||
matched = matcher.hasMatch();
|
bool matched = matcher.hasMatch();
|
||||||
|
|
||||||
if (!matched) {
|
if (!matched) {
|
||||||
reg = QRegularExpression(cachedRegex(partialPattern2));
|
matcher = cachedRegex(partialPattern2).match(articleTitle);
|
||||||
matcher = reg.match(articleTitle);
|
|
||||||
matched = matcher.hasMatch();
|
matched = matcher.hasMatch();
|
||||||
}
|
}
|
||||||
|
|
||||||
if (matched) {
|
if (matched) {
|
||||||
int sTheirs = matcher.captured(1).toInt();
|
const int seasonTheirs {matcher.captured(1).toInt()};
|
||||||
int epTheirs = matcher.captured(2).toInt();
|
const int episodeTheirs {matcher.captured(2).toInt()};
|
||||||
if (((sTheirs == sOurs) && (epTheirs >= epOurs)) || (sTheirs > sOurs)) {
|
|
||||||
// qDebug() << "Matched episode:" << ep;
|
if (episode.endsWith('-')) { // Infinite range
|
||||||
// qDebug() << "Matched article:" << articleTitle;
|
const int episodeOurs {episode.leftRef(episode.size() - 1).toInt()};
|
||||||
|
if (((seasonTheirs == seasonOurs) && (episodeTheirs >= episodeOurs)) || (seasonTheirs > seasonOurs))
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
}
|
|
||||||
}
|
|
||||||
else { // Normal range
|
else { // Normal range
|
||||||
QStringList range = ep.split('-');
|
const QStringList range {episode.split('-')};
|
||||||
Q_ASSERT(range.size() == 2);
|
Q_ASSERT(range.size() == 2);
|
||||||
if (range.first().toInt() > range.last().toInt())
|
if (range.first().toInt() > range.last().toInt())
|
||||||
continue; // Ignore this subrule completely
|
continue; // Ignore this subrule completely
|
||||||
|
|
||||||
int epOursFirst = range.first().toInt();
|
const int episodeOursFirst {range.first().toInt()};
|
||||||
int epOursLast = range.last().toInt();
|
const int episodeOursLast {range.last().toInt()};
|
||||||
|
if ((seasonTheirs == seasonOurs) && ((episodeOursFirst <= episodeTheirs) && (episodeOursLast >= episodeTheirs)))
|
||||||
// Extract partial match from article and compare as digits
|
|
||||||
matcher = reg.match(articleTitle);
|
|
||||||
matched = matcher.hasMatch();
|
|
||||||
|
|
||||||
if (!matched) {
|
|
||||||
reg = QRegularExpression(cachedRegex(partialPattern2));
|
|
||||||
matcher = reg.match(articleTitle);
|
|
||||||
matched = matcher.hasMatch();
|
|
||||||
}
|
|
||||||
|
|
||||||
if (matched) {
|
|
||||||
int sTheirs = matcher.captured(1).toInt();
|
|
||||||
int epTheirs = matcher.captured(2).toInt();
|
|
||||||
if ((sTheirs == sOurs) && ((epOursFirst <= epTheirs) && (epOursLast >= epTheirs))) {
|
|
||||||
// qDebug() << "Matched episode:" << ep;
|
|
||||||
// qDebug() << "Matched article:" << articleTitle;
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
else { // Single number
|
else { // Single number
|
||||||
QString expStr("\\b(?:s0?" + s + "[ -_\\.]?" + "e0?" + ep + "|" + s + "x" + "0?" + ep + ")(?:\\D|\\b)");
|
const QString expStr {QString("\\b(?:s0?%1[ -_\\.]?e0?%2|%1x0?%2)(?:\\D|\\b)").arg(season, episode)};
|
||||||
QRegularExpression reg(cachedRegex(expStr));
|
if (cachedRegex(expStr).match(articleTitle).hasMatch())
|
||||||
if (reg.match(articleTitle).hasMatch()) {
|
|
||||||
// qDebug() << "Matched episode:" << ep;
|
|
||||||
// qDebug() << "Matched article:" << articleTitle;
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (useSmartFilter()) {
|
bool AutoDownloadRule::matchesSmartEpisodeFilter(const QString& articleTitle) const
|
||||||
// now see if this episode has been downloaded before
|
{
|
||||||
const QString episodeStr = computeEpisodeName(articleTitle);
|
if (!useSmartFilter())
|
||||||
|
return true;
|
||||||
|
|
||||||
if (!episodeStr.isEmpty()) {
|
const QString episodeStr = computeEpisodeName(articleTitle);
|
||||||
bool previouslyMatched = m_dataPtr->previouslyMatchedEpisodes.contains(episodeStr);
|
if (episodeStr.isEmpty())
|
||||||
bool isRepack = articleTitle.contains("REPACK", Qt::CaseInsensitive) || articleTitle.contains("PROPER", Qt::CaseInsensitive);
|
return true;
|
||||||
|
|
||||||
|
// See if this episode has been downloaded before
|
||||||
|
const bool previouslyMatched = m_dataPtr->previouslyMatchedEpisodes.contains(episodeStr);
|
||||||
|
const bool isRepack = articleTitle.contains("REPACK", Qt::CaseInsensitive) || articleTitle.contains("PROPER", Qt::CaseInsensitive);
|
||||||
if (previouslyMatched && !isRepack)
|
if (previouslyMatched && !isRepack)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
m_dataPtr->lastComputedEpisode = episodeStr;
|
m_dataPtr->lastComputedEpisode = episodeStr;
|
||||||
}
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool AutoDownloadRule::matches(const QVariantHash &articleData) const
|
||||||
|
{
|
||||||
|
const QDateTime articleDate {articleData[Article::KeyDate].toDateTime()};
|
||||||
|
if (ignoreDays() > 0) {
|
||||||
|
if (lastMatch().isValid() && (articleDate < lastMatch().addDays(ignoreDays())))
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
const QString articleTitle {articleData[Article::KeyTitle].toString()};
|
||||||
|
if (!matchesMustContainExpression(articleTitle))
|
||||||
|
return false;
|
||||||
|
if (!matchesMustNotContainExpression(articleTitle))
|
||||||
|
return false;
|
||||||
|
if (!matchesEpisodeFilterExpression(articleTitle))
|
||||||
|
return false;
|
||||||
|
if (!matchesSmartEpisodeFilter(articleTitle))
|
||||||
|
return false;
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool AutoDownloadRule::accepts(const QVariantHash &articleData)
|
||||||
|
{
|
||||||
|
if (!matches(articleData))
|
||||||
|
return false;
|
||||||
|
|
||||||
|
setLastMatch(articleData[Article::KeyDate].toDateTime());
|
||||||
|
|
||||||
|
if (!m_dataPtr->lastComputedEpisode.isEmpty()) {
|
||||||
|
// TODO: probably need to add a marker for PROPER/REPACK to avoid duplicate downloads
|
||||||
|
m_dataPtr->previouslyMatchedEpisodes.append(m_dataPtr->lastComputedEpisode);
|
||||||
|
m_dataPtr->lastComputedEpisode.clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
// qDebug() << "Matched article:" << articleTitle;
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -642,15 +644,6 @@ void AutoDownloadRule::setPreviouslyMatchedEpisodes(const QStringList &previousl
|
|||||||
m_dataPtr->previouslyMatchedEpisodes = previouslyMatchedEpisodes;
|
m_dataPtr->previouslyMatchedEpisodes = previouslyMatchedEpisodes;
|
||||||
}
|
}
|
||||||
|
|
||||||
void AutoDownloadRule::appendLastComputedEpisode()
|
|
||||||
{
|
|
||||||
if (!m_dataPtr->lastComputedEpisode.isEmpty()) {
|
|
||||||
// TODO: probably need to add a marker for PROPER/REPACK to avoid duplicate downloads
|
|
||||||
m_dataPtr->previouslyMatchedEpisodes.append(m_dataPtr->lastComputedEpisode);
|
|
||||||
m_dataPtr->lastComputedEpisode.clear();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
QString AutoDownloadRule::episodeFilter() const
|
QString AutoDownloadRule::episodeFilter() const
|
||||||
{
|
{
|
||||||
return m_dataPtr->episodeFilter;
|
return m_dataPtr->episodeFilter;
|
||||||
|
|||||||
@@ -71,7 +71,6 @@ namespace RSS
|
|||||||
QString episodeFilter() const;
|
QString episodeFilter() const;
|
||||||
void setEpisodeFilter(const QString &e);
|
void setEpisodeFilter(const QString &e);
|
||||||
|
|
||||||
void appendLastComputedEpisode();
|
|
||||||
QStringList previouslyMatchedEpisodes() const;
|
QStringList previouslyMatchedEpisodes() const;
|
||||||
void setPreviouslyMatchedEpisodes(const QStringList &previouslyMatchedEpisodes);
|
void setPreviouslyMatchedEpisodes(const QStringList &previouslyMatchedEpisodes);
|
||||||
|
|
||||||
@@ -82,7 +81,8 @@ namespace RSS
|
|||||||
QString assignedCategory() const;
|
QString assignedCategory() const;
|
||||||
void setCategory(const QString &category);
|
void setCategory(const QString &category);
|
||||||
|
|
||||||
bool matches(const QString &articleTitle) const;
|
bool matches(const QVariantHash &articleData) const;
|
||||||
|
bool accepts(const QVariantHash &articleData);
|
||||||
|
|
||||||
AutoDownloadRule &operator=(const AutoDownloadRule &other);
|
AutoDownloadRule &operator=(const AutoDownloadRule &other);
|
||||||
bool operator==(const AutoDownloadRule &other) const;
|
bool operator==(const AutoDownloadRule &other) const;
|
||||||
@@ -95,7 +95,11 @@ namespace RSS
|
|||||||
static AutoDownloadRule fromLegacyDict(const QVariantHash &dict);
|
static AutoDownloadRule fromLegacyDict(const QVariantHash &dict);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
bool matches(const QString &articleTitle, const QString &expression) const;
|
bool matchesMustContainExpression(const QString &articleTitle) const;
|
||||||
|
bool matchesMustNotContainExpression(const QString &articleTitle) const;
|
||||||
|
bool matchesEpisodeFilterExpression(const QString &articleTitle) const;
|
||||||
|
bool matchesSmartEpisodeFilter(const QString &articleTitle) const;
|
||||||
|
bool matchesExpression(const QString &articleTitle, const QString &expression) const;
|
||||||
QRegularExpression cachedRegex(const QString &expression, bool isRegex = true) const;
|
QRegularExpression cachedRegex(const QString &expression, bool isRegex = true) const;
|
||||||
|
|
||||||
QSharedDataPointer<AutoDownloadRuleData> m_dataPtr;
|
QSharedDataPointer<AutoDownloadRuleData> m_dataPtr;
|
||||||
|
|||||||
@@ -212,7 +212,13 @@ void Feed::handleParsingFinished(const RSS::Private::ParsingResult &result)
|
|||||||
m_lastBuildDate = result.lastBuildDate;
|
m_lastBuildDate = result.lastBuildDate;
|
||||||
|
|
||||||
int newArticlesCount = 0;
|
int newArticlesCount = 0;
|
||||||
for (const QVariantHash &varHash : result.articles) {
|
const QDateTime now {QDateTime::currentDateTime()};
|
||||||
|
for (QVariantHash varHash : result.articles) {
|
||||||
|
// if article has no publication date we use feed update time as a fallback
|
||||||
|
QVariant &articleDate = varHash[Article::KeyDate];
|
||||||
|
if (!articleDate.toDateTime().isValid())
|
||||||
|
articleDate = now;
|
||||||
|
|
||||||
try {
|
try {
|
||||||
auto article = new Article(this, varHash);
|
auto article = new Article(this, varHash);
|
||||||
if (addArticle(article))
|
if (addArticle(article))
|
||||||
|
|||||||
@@ -36,7 +36,7 @@
|
|||||||
|
|
||||||
using namespace RSS;
|
using namespace RSS;
|
||||||
|
|
||||||
const QString Item::PathSeparator("\\");
|
const QChar Item::PathSeparator('\\');
|
||||||
|
|
||||||
Item::Item(const QString &path)
|
Item::Item(const QString &path)
|
||||||
: m_path(path)
|
: m_path(path)
|
||||||
|
|||||||
@@ -58,7 +58,7 @@ namespace RSS
|
|||||||
|
|
||||||
virtual QJsonValue toJsonValue(bool withData = false) const = 0;
|
virtual QJsonValue toJsonValue(bool withData = false) const = 0;
|
||||||
|
|
||||||
static const QString PathSeparator;
|
static const QChar PathSeparator;
|
||||||
|
|
||||||
static bool isValidPath(const QString &path);
|
static bool isValidPath(const QString &path);
|
||||||
static QString joinPath(const QString &path1, const QString &path2);
|
static QString joinPath(const QString &path1, const QString &path2);
|
||||||
|
|||||||
@@ -47,8 +47,8 @@
|
|||||||
#include "../utils/fs.h"
|
#include "../utils/fs.h"
|
||||||
#include "rss_article.h"
|
#include "rss_article.h"
|
||||||
#include "rss_feed.h"
|
#include "rss_feed.h"
|
||||||
#include "rss_item.h"
|
|
||||||
#include "rss_folder.h"
|
#include "rss_folder.h"
|
||||||
|
#include "rss_item.h"
|
||||||
|
|
||||||
const int MsecsPerMin = 60000;
|
const int MsecsPerMin = 60000;
|
||||||
const QString ConfFolderName(QStringLiteral("rss"));
|
const QString ConfFolderName(QStringLiteral("rss"));
|
||||||
|
|||||||
@@ -69,9 +69,9 @@ class AsyncFileStorage;
|
|||||||
|
|
||||||
namespace RSS
|
namespace RSS
|
||||||
{
|
{
|
||||||
class Item;
|
|
||||||
class Feed;
|
class Feed;
|
||||||
class Folder;
|
class Folder;
|
||||||
|
class Item;
|
||||||
|
|
||||||
class Session : public QObject
|
class Session : public QObject
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
/*
|
/*
|
||||||
* Bittorrent Client using Qt and libtorrent.
|
* Bittorrent Client using Qt and libtorrent.
|
||||||
* Copyright (C) 2010 Christian Kandeler, Christophe Dumez
|
* Copyright (C) 2010 Christian Kandeler, Christophe Dumez <chris@qbittorrent.org>
|
||||||
*
|
*
|
||||||
* This program is free software; you can redistribute it and/or
|
* This program is free software; you can redistribute it and/or
|
||||||
* modify it under the terms of the GNU General Public License
|
* modify it under the terms of the GNU General Public License
|
||||||
@@ -24,8 +24,6 @@
|
|||||||
* modify file(s), you may extend this exception to your version of the file(s),
|
* modify file(s), you may extend this exception to your version of the file(s),
|
||||||
* but you are not obligated to do so. If you do not wish to do so, delete this
|
* but you are not obligated to do so. If you do not wish to do so, delete this
|
||||||
* exception statement from your version.
|
* exception statement from your version.
|
||||||
*
|
|
||||||
* Contact : chris@qbittorrent.org
|
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include "scanfoldersmodel.h"
|
#include "scanfoldersmodel.h"
|
||||||
@@ -56,7 +54,7 @@ struct ScanFoldersModel::PathData
|
|||||||
QString downloadPath; // valid for CUSTOM_LOCATION
|
QString downloadPath; // valid for CUSTOM_LOCATION
|
||||||
};
|
};
|
||||||
|
|
||||||
ScanFoldersModel *ScanFoldersModel::m_instance = 0;
|
ScanFoldersModel *ScanFoldersModel::m_instance = nullptr;
|
||||||
|
|
||||||
bool ScanFoldersModel::initInstance(QObject *parent)
|
bool ScanFoldersModel::initInstance(QObject *parent)
|
||||||
{
|
{
|
||||||
@@ -72,7 +70,7 @@ void ScanFoldersModel::freeInstance()
|
|||||||
{
|
{
|
||||||
if (m_instance) {
|
if (m_instance) {
|
||||||
delete m_instance;
|
delete m_instance;
|
||||||
m_instance = 0;
|
m_instance = nullptr;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -83,10 +81,10 @@ ScanFoldersModel *ScanFoldersModel::instance()
|
|||||||
|
|
||||||
ScanFoldersModel::ScanFoldersModel(QObject *parent)
|
ScanFoldersModel::ScanFoldersModel(QObject *parent)
|
||||||
: QAbstractListModel(parent)
|
: QAbstractListModel(parent)
|
||||||
, m_fsWatcher(0)
|
, m_fsWatcher(nullptr)
|
||||||
{
|
{
|
||||||
configure();
|
configure();
|
||||||
connect(Preferences::instance(), SIGNAL(changed()), SLOT(configure()));
|
connect(Preferences::instance(), &Preferences::changed, this, &ScanFoldersModel::configure);
|
||||||
}
|
}
|
||||||
|
|
||||||
ScanFoldersModel::~ScanFoldersModel()
|
ScanFoldersModel::~ScanFoldersModel()
|
||||||
@@ -222,7 +220,7 @@ ScanFoldersModel::PathStatus ScanFoldersModel::addPath(const QString &watchPath,
|
|||||||
|
|
||||||
if (!m_fsWatcher) {
|
if (!m_fsWatcher) {
|
||||||
m_fsWatcher = new FileSystemWatcher(this);
|
m_fsWatcher = new FileSystemWatcher(this);
|
||||||
connect(m_fsWatcher, SIGNAL(torrentsAdded(const QStringList &)), this, SLOT(addTorrentsToSession(const QStringList &)));
|
connect(m_fsWatcher, &FileSystemWatcher::torrentsAdded, this, &ScanFoldersModel::addTorrentsToSession);
|
||||||
}
|
}
|
||||||
|
|
||||||
beginInsertRows(QModelIndex(), rowCount(), rowCount());
|
beginInsertRows(QModelIndex(), rowCount(), rowCount());
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
/*
|
/*
|
||||||
* Bittorrent Client using Qt and libtorrent.
|
* Bittorrent Client using Qt and libtorrent.
|
||||||
* Copyright (C) 2010 Christian Kandeler, Christophe Dumez
|
* Copyright (C) 2010 Christian Kandeler, Christophe Dumez <chris@qbittorrent.org>
|
||||||
*
|
*
|
||||||
* This program is free software; you can redistribute it and/or
|
* This program is free software; you can redistribute it and/or
|
||||||
* modify it under the terms of the GNU General Public License
|
* modify it under the terms of the GNU General Public License
|
||||||
@@ -24,8 +24,6 @@
|
|||||||
* modify file(s), you may extend this exception to your version of the file(s),
|
* modify file(s), you may extend this exception to your version of the file(s),
|
||||||
* but you are not obligated to do so. If you do not wish to do so, delete this
|
* but you are not obligated to do so. If you do not wish to do so, delete this
|
||||||
* exception statement from your version.
|
* exception statement from your version.
|
||||||
*
|
|
||||||
* Contact : chris@qbittorrent.org
|
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#ifndef SCANFOLDERSMODEL_H
|
#ifndef SCANFOLDERSMODEL_H
|
||||||
@@ -66,7 +64,7 @@ public:
|
|||||||
CUSTOM_LOCATION
|
CUSTOM_LOCATION
|
||||||
};
|
};
|
||||||
|
|
||||||
static bool initInstance(QObject *parent = 0);
|
static bool initInstance(QObject *parent = nullptr);
|
||||||
static void freeInstance();
|
static void freeInstance();
|
||||||
static ScanFoldersModel *instance();
|
static ScanFoldersModel *instance();
|
||||||
|
|
||||||
@@ -97,7 +95,7 @@ private slots:
|
|||||||
void addTorrentsToSession(const QStringList &pathList);
|
void addTorrentsToSession(const QStringList &pathList);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
explicit ScanFoldersModel(QObject *parent = 0);
|
explicit ScanFoldersModel(QObject *parent = nullptr);
|
||||||
~ScanFoldersModel();
|
~ScanFoldersModel();
|
||||||
|
|
||||||
virtual bool setData(const QModelIndex &index, const QVariant &value, int role = Qt::EditRole);
|
virtual bool setData(const QModelIndex &index, const QVariant &value, int role = Qt::EditRole);
|
||||||
|
|||||||
@@ -42,8 +42,8 @@
|
|||||||
|
|
||||||
#include "base/global.h"
|
#include "base/global.h"
|
||||||
#include "base/logger.h"
|
#include "base/logger.h"
|
||||||
#include "base/net/downloadmanager.h"
|
|
||||||
#include "base/net/downloadhandler.h"
|
#include "base/net/downloadhandler.h"
|
||||||
|
#include "base/net/downloadmanager.h"
|
||||||
#include "base/preferences.h"
|
#include "base/preferences.h"
|
||||||
#include "base/profile.h"
|
#include "base/profile.h"
|
||||||
#include "base/utils/fs.h"
|
#include "base/utils/fs.h"
|
||||||
@@ -62,18 +62,6 @@ namespace
|
|||||||
|
|
||||||
QPointer<SearchPluginManager> SearchPluginManager::m_instance = nullptr;
|
QPointer<SearchPluginManager> SearchPluginManager::m_instance = nullptr;
|
||||||
|
|
||||||
const QHash<QString, QString> SearchPluginManager::m_categoryNames {
|
|
||||||
{"all", QT_TRANSLATE_NOOP("SearchEngine", "All categories")},
|
|
||||||
{"movies", QT_TRANSLATE_NOOP("SearchEngine", "Movies")},
|
|
||||||
{"tv", QT_TRANSLATE_NOOP("SearchEngine", "TV shows")},
|
|
||||||
{"music", QT_TRANSLATE_NOOP("SearchEngine", "Music")},
|
|
||||||
{"games", QT_TRANSLATE_NOOP("SearchEngine", "Games")},
|
|
||||||
{"anime", QT_TRANSLATE_NOOP("SearchEngine", "Anime")},
|
|
||||||
{"software", QT_TRANSLATE_NOOP("SearchEngine", "Software")},
|
|
||||||
{"pictures", QT_TRANSLATE_NOOP("SearchEngine", "Pictures")},
|
|
||||||
{"books", QT_TRANSLATE_NOOP("SearchEngine", "Books")}
|
|
||||||
};
|
|
||||||
|
|
||||||
SearchPluginManager::SearchPluginManager()
|
SearchPluginManager::SearchPluginManager()
|
||||||
: m_updateUrl(QString("http://searchplugins.qbittorrent.org/%1/engines/").arg(Utils::Misc::pythonVersion() >= 3 ? "nova3" : "nova"))
|
: m_updateUrl(QString("http://searchplugins.qbittorrent.org/%1/engines/").arg(Utils::Misc::pythonVersion() >= 3 ? "nova3" : "nova"))
|
||||||
{
|
{
|
||||||
@@ -307,7 +295,18 @@ SearchHandler *SearchPluginManager::startSearch(const QString &pattern, const QS
|
|||||||
|
|
||||||
QString SearchPluginManager::categoryFullName(const QString &categoryName)
|
QString SearchPluginManager::categoryFullName(const QString &categoryName)
|
||||||
{
|
{
|
||||||
return tr(m_categoryNames.value(categoryName).toUtf8().constData());
|
static const QHash<QString, QString> categoryTable {
|
||||||
|
{"all", tr("All categories")},
|
||||||
|
{"movies", tr("Movies")},
|
||||||
|
{"tv", tr("TV shows")},
|
||||||
|
{"music", tr("Music")},
|
||||||
|
{"games", tr("Games")},
|
||||||
|
{"anime", tr("Anime")},
|
||||||
|
{"software", tr("Software")},
|
||||||
|
{"pictures", tr("Pictures")},
|
||||||
|
{"books", tr("Books")}
|
||||||
|
};
|
||||||
|
return categoryTable.value(categoryName);
|
||||||
}
|
}
|
||||||
|
|
||||||
QString SearchPluginManager::pluginFullName(const QString &pluginName)
|
QString SearchPluginManager::pluginFullName(const QString &pluginName)
|
||||||
|
|||||||
@@ -111,7 +111,6 @@ private:
|
|||||||
static QString pluginPath(const QString &name);
|
static QString pluginPath(const QString &name);
|
||||||
|
|
||||||
static QPointer<SearchPluginManager> m_instance;
|
static QPointer<SearchPluginManager> m_instance;
|
||||||
static const QHash<QString, QString> m_categoryNames;
|
|
||||||
|
|
||||||
const QString m_updateUrl;
|
const QString m_updateUrl;
|
||||||
|
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
/*
|
/*
|
||||||
* Bittorrent Client using Qt and libtorrent.
|
* Bittorrent Client using Qt and libtorrent.
|
||||||
* Copyright (C) 2016 Vladimir Golovnev <glassez@yandex.ru>
|
* Copyright (C) 2016 Vladimir Golovnev <glassez@yandex.ru>
|
||||||
* Copyright (C) 2014 sledgehammer999 <hammered999@gmail.com>
|
* Copyright (C) 2014 sledgehammer999 <sledgehammer999@qbittorrent.org>
|
||||||
*
|
*
|
||||||
* This program is free software; you can redistribute it and/or
|
* This program is free software; you can redistribute it and/or
|
||||||
* modify it under the terms of the GNU General Public License
|
* modify it under the terms of the GNU General Public License
|
||||||
@@ -62,15 +62,12 @@ namespace
|
|||||||
QString deserialize(const QString &name, QVariantHash &data);
|
QString deserialize(const QString &name, QVariantHash &data);
|
||||||
QString serialize(const QString &name, const QVariantHash &data);
|
QString serialize(const QString &name, const QVariantHash &data);
|
||||||
|
|
||||||
QString m_name;
|
const QString m_name;
|
||||||
};
|
};
|
||||||
|
|
||||||
typedef QHash<QString, QString> MappingTable;
|
|
||||||
|
|
||||||
QString mapKey(const QString &key)
|
QString mapKey(const QString &key)
|
||||||
{
|
{
|
||||||
static const MappingTable keyMapping = {
|
static const QHash<QString, QString> keyMapping = {
|
||||||
|
|
||||||
{"BitTorrent/Session/MaxRatioAction", "Preferences/Bittorrent/MaxRatioAction"},
|
{"BitTorrent/Session/MaxRatioAction", "Preferences/Bittorrent/MaxRatioAction"},
|
||||||
{"BitTorrent/Session/DefaultSavePath", "Preferences/Downloads/SavePath"},
|
{"BitTorrent/Session/DefaultSavePath", "Preferences/Downloads/SavePath"},
|
||||||
{"BitTorrent/Session/TempPath", "Preferences/Downloads/TempPath"},
|
{"BitTorrent/Session/TempPath", "Preferences/Downloads/TempPath"},
|
||||||
@@ -147,7 +144,6 @@ namespace
|
|||||||
{"AddNewTorrentDialog/TopLevel", "Preferences/Downloads/NewAdditionDialogFront"},
|
{"AddNewTorrentDialog/TopLevel", "Preferences/Downloads/NewAdditionDialogFront"},
|
||||||
|
|
||||||
{"State/BannedIPs", "Preferences/IPFilter/BannedIPs"}
|
{"State/BannedIPs", "Preferences/IPFilter/BannedIPs"}
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
return keyMapping.value(key, key);
|
return keyMapping.value(key, key);
|
||||||
@@ -163,7 +159,7 @@ SettingsStorage::SettingsStorage()
|
|||||||
{
|
{
|
||||||
m_timer.setSingleShot(true);
|
m_timer.setSingleShot(true);
|
||||||
m_timer.setInterval(5 * 1000);
|
m_timer.setInterval(5 * 1000);
|
||||||
connect(&m_timer, SIGNAL(timeout()), SLOT(save()));
|
connect(&m_timer, &QTimer::timeout, this, &SettingsStorage::save);
|
||||||
}
|
}
|
||||||
|
|
||||||
SettingsStorage::~SettingsStorage()
|
SettingsStorage::~SettingsStorage()
|
||||||
@@ -200,6 +196,7 @@ bool SettingsStorage::save()
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
m_timer.start();
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -211,7 +208,7 @@ QVariant SettingsStorage::loadValue(const QString &key, const QVariant &defaultV
|
|||||||
|
|
||||||
void SettingsStorage::storeValue(const QString &key, const QVariant &value)
|
void SettingsStorage::storeValue(const QString &key, const QVariant &value)
|
||||||
{
|
{
|
||||||
QString realKey = mapKey(key);
|
const QString realKey = mapKey(key);
|
||||||
QWriteLocker locker(&m_lock);
|
QWriteLocker locker(&m_lock);
|
||||||
if (m_data.value(realKey) != value) {
|
if (m_data.value(realKey) != value) {
|
||||||
m_dirty = true;
|
m_dirty = true;
|
||||||
@@ -222,7 +219,7 @@ void SettingsStorage::storeValue(const QString &key, const QVariant &value)
|
|||||||
|
|
||||||
void SettingsStorage::removeValue(const QString &key)
|
void SettingsStorage::removeValue(const QString &key)
|
||||||
{
|
{
|
||||||
QString realKey = mapKey(key);
|
const QString realKey = mapKey(key);
|
||||||
QWriteLocker locker(&m_lock);
|
QWriteLocker locker(&m_lock);
|
||||||
if (m_data.contains(realKey)) {
|
if (m_data.contains(realKey)) {
|
||||||
m_dirty = true;
|
m_dirty = true;
|
||||||
@@ -234,36 +231,39 @@ void SettingsStorage::removeValue(const QString &key)
|
|||||||
QVariantHash TransactionalSettings::read()
|
QVariantHash TransactionalSettings::read()
|
||||||
{
|
{
|
||||||
QVariantHash res;
|
QVariantHash res;
|
||||||
bool writeBackNeeded = false;
|
|
||||||
QString newPath = deserialize(m_name + QLatin1String("_new"), res);
|
const QString newPath = deserialize(m_name + QLatin1String("_new"), res);
|
||||||
if (!newPath.isEmpty()) { // "_new" file is NOT empty
|
if (!newPath.isEmpty()) { // "_new" file is NOT empty
|
||||||
// This means that the PC closed either due to power outage
|
// This means that the PC closed either due to power outage
|
||||||
// or because the disk was full. In any case the settings weren't transferred
|
// or because the disk was full. In any case the settings weren't transferred
|
||||||
// in their final position. So assume that qbittorrent_new.ini/qbittorrent_new.conf
|
// in their final position. So assume that qbittorrent_new.ini/qbittorrent_new.conf
|
||||||
// contains the most recent settings.
|
// contains the most recent settings.
|
||||||
Logger::instance()->addMessage(QObject::tr("Detected unclean program exit. Using fallback file to restore settings."), Log::WARNING);
|
Logger::instance()->addMessage(QObject::tr("Detected unclean program exit. Using fallback file to restore settings: %1")
|
||||||
writeBackNeeded = true;
|
.arg(Utils::Fs::toNativePath(newPath))
|
||||||
|
, Log::WARNING);
|
||||||
|
|
||||||
|
QString finalPath = newPath;
|
||||||
|
int index = finalPath.lastIndexOf("_new", -1, Qt::CaseInsensitive);
|
||||||
|
finalPath.remove(index, 4);
|
||||||
|
|
||||||
|
Utils::Fs::forceRemove(finalPath);
|
||||||
|
QFile::rename(newPath, finalPath);
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
deserialize(m_name, res);
|
deserialize(m_name, res);
|
||||||
}
|
}
|
||||||
|
|
||||||
Utils::Fs::forceRemove(newPath);
|
|
||||||
|
|
||||||
if (writeBackNeeded)
|
|
||||||
write(res);
|
|
||||||
|
|
||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool TransactionalSettings::write(const QVariantHash &data)
|
bool TransactionalSettings::write(const QVariantHash &data)
|
||||||
{
|
{
|
||||||
// QSettings delete the file before writing it out. This can result in problems
|
// QSettings deletes the file before writing it out. This can result in problems
|
||||||
// if the disk is full or a power outage occurs. Those events might occur
|
// if the disk is full or a power outage occurs. Those events might occur
|
||||||
// between deleting the file and recreating it. This is a safety measure.
|
// between deleting the file and recreating it. This is a safety measure.
|
||||||
// Write everything to qBittorrent_new.ini/qBittorrent_new.conf and if it succeeds
|
// Write everything to qBittorrent_new.ini/qBittorrent_new.conf and if it succeeds
|
||||||
// replace qBittorrent.ini/qBittorrent.conf with it.
|
// replace qBittorrent.ini/qBittorrent.conf with it.
|
||||||
QString newPath = serialize(m_name + QLatin1String("_new"), data);
|
const QString newPath = serialize(m_name + QLatin1String("_new"), data);
|
||||||
if (newPath.isEmpty()) {
|
if (newPath.isEmpty()) {
|
||||||
Utils::Fs::forceRemove(newPath);
|
Utils::Fs::forceRemove(newPath);
|
||||||
return false;
|
return false;
|
||||||
@@ -272,10 +272,9 @@ bool TransactionalSettings::write(const QVariantHash &data)
|
|||||||
QString finalPath = newPath;
|
QString finalPath = newPath;
|
||||||
int index = finalPath.lastIndexOf("_new", -1, Qt::CaseInsensitive);
|
int index = finalPath.lastIndexOf("_new", -1, Qt::CaseInsensitive);
|
||||||
finalPath.remove(index, 4);
|
finalPath.remove(index, 4);
|
||||||
Utils::Fs::forceRemove(finalPath);
|
|
||||||
QFile::rename(newPath, finalPath);
|
|
||||||
|
|
||||||
return true;
|
Utils::Fs::forceRemove(finalPath);
|
||||||
|
return QFile::rename(newPath, finalPath);
|
||||||
}
|
}
|
||||||
|
|
||||||
QString TransactionalSettings::deserialize(const QString &name, QVariantHash &data)
|
QString TransactionalSettings::deserialize(const QString &name, QVariantHash &data)
|
||||||
@@ -301,13 +300,19 @@ QString TransactionalSettings::serialize(const QString &name, const QVariantHash
|
|||||||
settings->setValue(i.key(), i.value());
|
settings->setValue(i.key(), i.value());
|
||||||
|
|
||||||
settings->sync(); // Important to get error status
|
settings->sync(); // Important to get error status
|
||||||
QSettings::Status status = settings->status();
|
|
||||||
if (status != QSettings::NoError) {
|
switch (settings->status()) {
|
||||||
if (status == QSettings::AccessError)
|
case QSettings::NoError:
|
||||||
|
return settings->fileName();
|
||||||
|
case QSettings::AccessError:
|
||||||
Logger::instance()->addMessage(QObject::tr("An access error occurred while trying to write the configuration file."), Log::CRITICAL);
|
Logger::instance()->addMessage(QObject::tr("An access error occurred while trying to write the configuration file."), Log::CRITICAL);
|
||||||
else
|
break;
|
||||||
|
case QSettings::FormatError:
|
||||||
Logger::instance()->addMessage(QObject::tr("A format error occurred while trying to write the configuration file."), Log::CRITICAL);
|
Logger::instance()->addMessage(QObject::tr("A format error occurred while trying to write the configuration file."), Log::CRITICAL);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
Logger::instance()->addMessage(QObject::tr("An unknown error occurred while trying to write the configuration file."), Log::CRITICAL);
|
||||||
|
break;
|
||||||
|
}
|
||||||
return QString();
|
return QString();
|
||||||
}
|
}
|
||||||
return settings->fileName();
|
|
||||||
}
|
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
/*
|
/*
|
||||||
* Bittorrent Client using Qt and libtorrent.
|
* Bittorrent Client using Qt and libtorrent.
|
||||||
* Copyright (C) 2016 Vladimir Golovnev <glassez@yandex.ru>
|
* Copyright (C) 2016 Vladimir Golovnev <glassez@yandex.ru>
|
||||||
* Copyright (C) 2014 sledgehammer999 <hammered999@gmail.com>
|
* Copyright (C) 2014 sledgehammer999 <sledgehammer999@qbittorrent.org>
|
||||||
*
|
*
|
||||||
* This program is free software; you can redistribute it and/or
|
* This program is free software; you can redistribute it and/or
|
||||||
* modify it under the terms of the GNU General Public License
|
* modify it under the terms of the GNU General Public License
|
||||||
@@ -31,9 +31,9 @@
|
|||||||
#define SETTINGSSTORAGE_H
|
#define SETTINGSSTORAGE_H
|
||||||
|
|
||||||
#include <QObject>
|
#include <QObject>
|
||||||
#include <QVariantHash>
|
|
||||||
#include <QTimer>
|
|
||||||
#include <QReadWriteLock>
|
#include <QReadWriteLock>
|
||||||
|
#include <QTimer>
|
||||||
|
#include <QVariantHash>
|
||||||
|
|
||||||
class SettingsStorage : public QObject
|
class SettingsStorage : public QObject
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -31,6 +31,7 @@
|
|||||||
|
|
||||||
#include <functional>
|
#include <functional>
|
||||||
#include <type_traits>
|
#include <type_traits>
|
||||||
|
|
||||||
#include <QMetaEnum>
|
#include <QMetaEnum>
|
||||||
#include <QString>
|
#include <QString>
|
||||||
#include <QVariant>
|
#include <QVariant>
|
||||||
|
|||||||
@@ -29,8 +29,8 @@
|
|||||||
#ifndef TORRENTFILTER_H
|
#ifndef TORRENTFILTER_H
|
||||||
#define TORRENTFILTER_H
|
#define TORRENTFILTER_H
|
||||||
|
|
||||||
#include <QString>
|
|
||||||
#include <QSet>
|
#include <QSet>
|
||||||
|
#include <QString>
|
||||||
|
|
||||||
typedef QSet<QString> QStringSet;
|
typedef QSet<QString> QStringSet;
|
||||||
|
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
/*
|
/*
|
||||||
* Bittorrent Client using Qt and libtorrent.
|
* Bittorrent Client using Qt and libtorrent.
|
||||||
* Copyright (C) 2012 Christophe Dumez
|
* Copyright (C) 2012 Christophe Dumez <chris@qbittorrent.org>
|
||||||
*
|
*
|
||||||
* This program is free software; you can redistribute it and/or
|
* This program is free software; you can redistribute it and/or
|
||||||
* modify it under the terms of the GNU General Public License
|
* modify it under the terms of the GNU General Public License
|
||||||
@@ -24,20 +24,18 @@
|
|||||||
* modify file(s), you may extend this exception to your version of the file(s),
|
* modify file(s), you may extend this exception to your version of the file(s),
|
||||||
* but you are not obligated to do so. If you do not wish to do so, delete this
|
* but you are not obligated to do so. If you do not wish to do so, delete this
|
||||||
* exception statement from your version.
|
* exception statement from your version.
|
||||||
*
|
|
||||||
* Contact : chris@qbittorrent.org
|
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include "fs.h"
|
#include "fs.h"
|
||||||
|
|
||||||
#include <cstring>
|
#include <cstring>
|
||||||
|
|
||||||
|
#include <QCoreApplication>
|
||||||
#include <QDebug>
|
#include <QDebug>
|
||||||
#include <QDir>
|
#include <QDir>
|
||||||
|
#include <QDirIterator>
|
||||||
#include <QFile>
|
#include <QFile>
|
||||||
#include <QFileInfo>
|
#include <QFileInfo>
|
||||||
#include <QDirIterator>
|
|
||||||
#include <QCoreApplication>
|
|
||||||
#include <QStorageInfo>
|
#include <QStorageInfo>
|
||||||
|
|
||||||
#include <sys/stat.h>
|
#include <sys/stat.h>
|
||||||
@@ -152,7 +150,7 @@ bool Utils::Fs::smartRemoveEmptyFolderTree(const QString &path)
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Removes the file with the given file_path.
|
* Removes the file with the given filePath.
|
||||||
*
|
*
|
||||||
* This function will try to fix the file permissions before removing it.
|
* This function will try to fix the file permissions before removing it.
|
||||||
*/
|
*/
|
||||||
@@ -169,7 +167,6 @@ bool Utils::Fs::forceRemove(const QString &filePath)
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Removes directory and its content recursively.
|
* Removes directory and its content recursively.
|
||||||
*
|
|
||||||
*/
|
*/
|
||||||
void Utils::Fs::removeDirRecursive(const QString &path)
|
void Utils::Fs::removeDirRecursive(const QString &path)
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
/*
|
/*
|
||||||
* Bittorrent Client using Qt and libtorrent.
|
* Bittorrent Client using Qt and libtorrent.
|
||||||
* Copyright (C) 2012 Christophe Dumez
|
* Copyright (C) 2012 Christophe Dumez <chris@qbittorrent.org>
|
||||||
*
|
*
|
||||||
* This program is free software; you can redistribute it and/or
|
* This program is free software; you can redistribute it and/or
|
||||||
* modify it under the terms of the GNU General Public License
|
* modify it under the terms of the GNU General Public License
|
||||||
@@ -24,8 +24,6 @@
|
|||||||
* modify file(s), you may extend this exception to your version of the file(s),
|
* modify file(s), you may extend this exception to your version of the file(s),
|
||||||
* but you are not obligated to do so. If you do not wish to do so, delete this
|
* but you are not obligated to do so. If you do not wish to do so, delete this
|
||||||
* exception statement from your version.
|
* exception statement from your version.
|
||||||
*
|
|
||||||
* Contact : chris@qbittorrent.org
|
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#ifndef UTILS_FS_H
|
#ifndef UTILS_FS_H
|
||||||
@@ -52,7 +50,7 @@ namespace Utils
|
|||||||
, const QString &pad = QLatin1String(" "));
|
, const QString &pad = QLatin1String(" "));
|
||||||
bool isValidFileSystemName(const QString &name, bool allowSeparators = false);
|
bool isValidFileSystemName(const QString &name, bool allowSeparators = false);
|
||||||
qint64 freeDiskSpaceOnPath(const QString &path);
|
qint64 freeDiskSpaceOnPath(const QString &path);
|
||||||
QString branchPath(const QString &filePath, QString *removed = 0);
|
QString branchPath(const QString &filePath, QString *removed = nullptr);
|
||||||
bool sameFileNames(const QString &first, const QString &second);
|
bool sameFileNames(const QString &first, const QString &second);
|
||||||
QString expandPath(const QString &path);
|
QString expandPath(const QString &path);
|
||||||
QString expandPathAbs(const QString &path);
|
QString expandPathAbs(const QString &path);
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
/*
|
/*
|
||||||
* Bittorrent Client using Qt and libtorrent.
|
* Bittorrent Client using Qt and libtorrent.
|
||||||
* Copyright (C) 2006 Christophe Dumez
|
* Copyright (C) 2006 Christophe Dumez <chris@qbittorrent.org>
|
||||||
*
|
*
|
||||||
* This program is free software; you can redistribute it and/or
|
* This program is free software; you can redistribute it and/or
|
||||||
* modify it under the terms of the GNU General Public License
|
* modify it under the terms of the GNU General Public License
|
||||||
@@ -24,8 +24,6 @@
|
|||||||
* modify file(s), you may extend this exception to your version of the file(s),
|
* modify file(s), you may extend this exception to your version of the file(s),
|
||||||
* but you are not obligated to do so. If you do not wish to do so, delete this
|
* but you are not obligated to do so. If you do not wish to do so, delete this
|
||||||
* exception statement from your version.
|
* exception statement from your version.
|
||||||
*
|
|
||||||
* Contact : chris@qbittorrent.org
|
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include "misc.h"
|
#include "misc.h"
|
||||||
@@ -52,6 +50,7 @@
|
|||||||
#include <QDir>
|
#include <QDir>
|
||||||
#include <QFileInfo>
|
#include <QFileInfo>
|
||||||
#include <QProcess>
|
#include <QProcess>
|
||||||
|
#include <QRegExp>
|
||||||
#include <QRegularExpression>
|
#include <QRegularExpression>
|
||||||
#include <QSysInfo>
|
#include <QSysInfo>
|
||||||
#include <QUrl>
|
#include <QUrl>
|
||||||
@@ -62,17 +61,19 @@
|
|||||||
#include <QApplication>
|
#include <QApplication>
|
||||||
#include <QDesktopServices>
|
#include <QDesktopServices>
|
||||||
#include <QDesktopWidget>
|
#include <QDesktopWidget>
|
||||||
#include <QProcess>
|
|
||||||
#include <QStyle>
|
#include <QStyle>
|
||||||
#if (defined(Q_OS_UNIX) && !defined(Q_OS_MAC)) && defined(QT_DBUS_LIB)
|
#if (defined(Q_OS_UNIX) && !defined(Q_OS_MAC)) && defined(QT_DBUS_LIB)
|
||||||
#include <QDBusInterface>
|
#include <QDBusInterface>
|
||||||
#include <QDBusMessage>
|
#include <QDBusMessage>
|
||||||
#endif
|
#endif
|
||||||
|
#if defined(Q_OS_UNIX) && !defined(Q_OS_MAC)
|
||||||
|
#include "base/utils/version.h"
|
||||||
|
#endif
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#include "base/utils/string.h"
|
|
||||||
#include "base/unicodestrings.h"
|
|
||||||
#include "base/logger.h"
|
#include "base/logger.h"
|
||||||
|
#include "base/unicodestrings.h"
|
||||||
|
#include "base/utils/string.h"
|
||||||
#include "fs.h"
|
#include "fs.h"
|
||||||
|
|
||||||
namespace
|
namespace
|
||||||
@@ -271,12 +272,12 @@ QString Utils::Misc::pythonExecutable()
|
|||||||
* On Unix-Like Systems python2 and python3 should always exist
|
* On Unix-Like Systems python2 and python3 should always exist
|
||||||
* http://legacy.python.org/dev/peps/pep-0394/
|
* http://legacy.python.org/dev/peps/pep-0394/
|
||||||
*/
|
*/
|
||||||
pythonProc.start("python3", QStringList() << "--version", QIODevice::ReadOnly);
|
pythonProc.start("python3", {"--version"}, QIODevice::ReadOnly);
|
||||||
if (pythonProc.waitForFinished() && (pythonProc.exitCode() == 0)) {
|
if (pythonProc.waitForFinished() && (pythonProc.exitCode() == 0)) {
|
||||||
executable = "python3";
|
executable = "python3";
|
||||||
return executable;
|
return executable;
|
||||||
}
|
}
|
||||||
pythonProc.start("python2", QStringList() << "--version", QIODevice::ReadOnly);
|
pythonProc.start("python2", {"--version"}, QIODevice::ReadOnly);
|
||||||
if (pythonProc.waitForFinished() && (pythonProc.exitCode() == 0)) {
|
if (pythonProc.waitForFinished() && (pythonProc.exitCode() == 0)) {
|
||||||
executable = "python2";
|
executable = "python2";
|
||||||
return executable;
|
return executable;
|
||||||
@@ -284,7 +285,7 @@ QString Utils::Misc::pythonExecutable()
|
|||||||
#endif
|
#endif
|
||||||
// Look for "python" in Windows and in UNIX if "python2" and "python3" are
|
// Look for "python" in Windows and in UNIX if "python2" and "python3" are
|
||||||
// not detected.
|
// not detected.
|
||||||
pythonProc.start("python", QStringList() << "--version", QIODevice::ReadOnly);
|
pythonProc.start("python", {"--version"}, QIODevice::ReadOnly);
|
||||||
if (pythonProc.waitForFinished() && (pythonProc.exitCode() == 0))
|
if (pythonProc.waitForFinished() && (pythonProc.exitCode() == 0))
|
||||||
executable = "python";
|
executable = "python";
|
||||||
else
|
else
|
||||||
@@ -305,7 +306,7 @@ QString Utils::Misc::pythonVersionComplete()
|
|||||||
if (pythonExecutable().isEmpty())
|
if (pythonExecutable().isEmpty())
|
||||||
return version;
|
return version;
|
||||||
QProcess pythonProc;
|
QProcess pythonProc;
|
||||||
pythonProc.start(pythonExecutable(), QStringList() << "--version", QIODevice::ReadOnly);
|
pythonProc.start(pythonExecutable(), {"--version"}, QIODevice::ReadOnly);
|
||||||
if (pythonProc.waitForFinished() && (pythonProc.exitCode() == 0)) {
|
if (pythonProc.waitForFinished() && (pythonProc.exitCode() == 0)) {
|
||||||
QByteArray output = pythonProc.readAllStandardOutput();
|
QByteArray output = pythonProc.readAllStandardOutput();
|
||||||
if (output.isEmpty())
|
if (output.isEmpty())
|
||||||
@@ -525,9 +526,9 @@ bool Utils::Misc::isUrl(const QString &s)
|
|||||||
return reURLScheme.match(QUrl(s).scheme()).hasMatch();
|
return reURLScheme.match(QUrl(s).scheme()).hasMatch();
|
||||||
}
|
}
|
||||||
|
|
||||||
QString Utils::Misc::parseHtmlLinks(const QString &raw_text)
|
QString Utils::Misc::parseHtmlLinks(const QString &rawText)
|
||||||
{
|
{
|
||||||
QString result = raw_text;
|
QString result = rawText;
|
||||||
static QRegExp reURL(
|
static QRegExp reURL(
|
||||||
"(\\s|^)" // start with whitespace or beginning of line
|
"(\\s|^)" // start with whitespace or beginning of line
|
||||||
"("
|
"("
|
||||||
@@ -621,21 +622,33 @@ void Utils::Misc::openFolderSelect(const QString &absolutePath)
|
|||||||
::CoUninitialize();
|
::CoUninitialize();
|
||||||
#elif defined(Q_OS_UNIX) && !defined(Q_OS_MAC)
|
#elif defined(Q_OS_UNIX) && !defined(Q_OS_MAC)
|
||||||
QProcess proc;
|
QProcess proc;
|
||||||
proc.start("xdg-mime", QStringList() << "query" << "default" << "inode/directory");
|
proc.start("xdg-mime", {"query", "default", "inode/directory"});
|
||||||
proc.waitForFinished();
|
proc.waitForFinished();
|
||||||
QString output = proc.readLine().simplified();
|
QString output = proc.readLine().simplified();
|
||||||
if ((output == "dolphin.desktop") || (output == "org.kde.dolphin.desktop"))
|
if ((output == "dolphin.desktop") || (output == "org.kde.dolphin.desktop")) {
|
||||||
proc.startDetached("dolphin", QStringList() << "--select" << Utils::Fs::toNativePath(path));
|
proc.startDetached("dolphin", {"--select", Utils::Fs::toNativePath(path)});
|
||||||
|
}
|
||||||
else if ((output == "nautilus.desktop") || (output == "org.gnome.Nautilus.desktop")
|
else if ((output == "nautilus.desktop") || (output == "org.gnome.Nautilus.desktop")
|
||||||
|| (output == "nautilus-folder-handler.desktop"))
|
|| (output == "nautilus-folder-handler.desktop")) {
|
||||||
proc.startDetached("nautilus", QStringList() << "--no-desktop" << Utils::Fs::toNativePath(path));
|
proc.start("nautilus", {"--version"});
|
||||||
else if (output == "nemo.desktop")
|
proc.waitForFinished();
|
||||||
proc.startDetached("nemo", QStringList() << "--no-desktop" << Utils::Fs::toNativePath(path));
|
const QString nautilusVerStr = QString(proc.readLine()).remove(QRegExp("[^0-9.]"));
|
||||||
else if ((output == "konqueror.desktop") || (output == "kfmclient_dir.desktop"))
|
using NautilusVersion = Utils::Version<int, 3>;
|
||||||
proc.startDetached("konqueror", QStringList() << "--select" << Utils::Fs::toNativePath(path));
|
if (NautilusVersion::tryParse(nautilusVerStr, {1, 0, 0}) > NautilusVersion {3, 28})
|
||||||
|
proc.startDetached("nautilus", {Utils::Fs::toNativePath(path)});
|
||||||
else
|
else
|
||||||
|
proc.startDetached("nautilus", {"--no-desktop", Utils::Fs::toNativePath(path)});
|
||||||
|
}
|
||||||
|
else if (output == "nemo.desktop") {
|
||||||
|
proc.startDetached("nemo", {"--no-desktop", Utils::Fs::toNativePath(path)});
|
||||||
|
}
|
||||||
|
else if ((output == "konqueror.desktop") || (output == "kfmclient_dir.desktop")) {
|
||||||
|
proc.startDetached("konqueror", {"--select", Utils::Fs::toNativePath(path)});
|
||||||
|
}
|
||||||
|
else {
|
||||||
// "caja" manager can't pinpoint the file, see: https://github.com/qbittorrent/qBittorrent/issues/5003
|
// "caja" manager can't pinpoint the file, see: https://github.com/qbittorrent/qBittorrent/issues/5003
|
||||||
openPath(path.left(path.lastIndexOf("/")));
|
openPath(path.left(path.lastIndexOf("/")));
|
||||||
|
}
|
||||||
#else
|
#else
|
||||||
openPath(path.left(path.lastIndexOf("/")));
|
openPath(path.left(path.lastIndexOf("/")));
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
/*
|
/*
|
||||||
* Bittorrent Client using Qt and libtorrent.
|
* Bittorrent Client using Qt and libtorrent.
|
||||||
* Copyright (C) 2006 Christophe Dumez
|
* Copyright (C) 2006 Christophe Dumez <chris@qbittorrent.org>
|
||||||
*
|
*
|
||||||
* This program is free software; you can redistribute it and/or
|
* This program is free software; you can redistribute it and/or
|
||||||
* modify it under the terms of the GNU General Public License
|
* modify it under the terms of the GNU General Public License
|
||||||
@@ -24,8 +24,6 @@
|
|||||||
* modify file(s), you may extend this exception to your version of the file(s),
|
* modify file(s), you may extend this exception to your version of the file(s),
|
||||||
* but you are not obligated to do so. If you do not wish to do so, delete this
|
* but you are not obligated to do so. If you do not wish to do so, delete this
|
||||||
* exception statement from your version.
|
* exception statement from your version.
|
||||||
*
|
|
||||||
* Contact : chris@qbittorrent.org
|
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#ifndef UTILS_MISC_H
|
#ifndef UTILS_MISC_H
|
||||||
@@ -73,7 +71,7 @@ namespace Utils
|
|||||||
// YobiByte, // 1024^8
|
// YobiByte, // 1024^8
|
||||||
};
|
};
|
||||||
|
|
||||||
QString parseHtmlLinks(const QString &raw_text);
|
QString parseHtmlLinks(const QString &rawText);
|
||||||
bool isUrl(const QString &s);
|
bool isUrl(const QString &s);
|
||||||
|
|
||||||
void shutdownComputer(const ShutdownDialogAction &action);
|
void shutdownComputer(const ShutdownDialogAction &action);
|
||||||
@@ -88,7 +86,7 @@ namespace Utils
|
|||||||
|
|
||||||
QString unitString(SizeUnit unit);
|
QString unitString(SizeUnit unit);
|
||||||
|
|
||||||
// return best user friendly storage unit (B, KiB, MiB, GiB, TiB)
|
// return the best user friendly storage unit (B, KiB, MiB, GiB, TiB)
|
||||||
// value must be given in bytes
|
// value must be given in bytes
|
||||||
bool friendlyUnit(qint64 sizeInBytes, qreal &val, SizeUnit &unit);
|
bool friendlyUnit(qint64 sizeInBytes, qreal &val, SizeUnit &unit);
|
||||||
QString friendlyUnit(qint64 bytesValue, bool isSpeed = false);
|
QString friendlyUnit(qint64 bytesValue, bool isSpeed = false);
|
||||||
@@ -97,7 +95,7 @@ namespace Utils
|
|||||||
|
|
||||||
bool isPreviewable(const QString &extension);
|
bool isPreviewable(const QString &extension);
|
||||||
|
|
||||||
// Take a number of seconds and return an user-friendly
|
// Take a number of seconds and return a user-friendly
|
||||||
// time duration like "1d 2h 10m".
|
// time duration like "1d 2h 10m".
|
||||||
QString userFriendlyDuration(qlonglong seconds);
|
QString userFriendlyDuration(qlonglong seconds);
|
||||||
QString getUserIDString();
|
QString getUserIDString();
|
||||||
@@ -136,4 +134,4 @@ namespace Utils
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif
|
#endif // UTILS_MISC_H
|
||||||
|
|||||||
@@ -27,6 +27,7 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
#include "net.h"
|
#include "net.h"
|
||||||
|
|
||||||
#include <QHostAddress>
|
#include <QHostAddress>
|
||||||
#include <QString>
|
#include <QString>
|
||||||
#include <QStringList>
|
#include <QStringList>
|
||||||
|
|||||||
@@ -24,7 +24,6 @@
|
|||||||
* modify file(s), you may extend this exception to your version of the file(s),
|
* modify file(s), you may extend this exception to your version of the file(s),
|
||||||
* but you are not obligated to do so. If you do not wish to do so, delete this
|
* but you are not obligated to do so. If you do not wish to do so, delete this
|
||||||
* exception statement from your version.
|
* exception statement from your version.
|
||||||
*
|
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include "random.h"
|
#include "random.h"
|
||||||
|
|||||||
@@ -24,7 +24,6 @@
|
|||||||
* modify file(s), you may extend this exception to your version of the file(s),
|
* modify file(s), you may extend this exception to your version of the file(s),
|
||||||
* but you are not obligated to do so. If you do not wish to do so, delete this
|
* but you are not obligated to do so. If you do not wish to do so, delete this
|
||||||
* exception statement from your version.
|
* exception statement from your version.
|
||||||
*
|
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#ifndef UTILS_RANDOM_H
|
#ifndef UTILS_RANDOM_H
|
||||||
|
|||||||
@@ -117,7 +117,7 @@ namespace Utils
|
|||||||
{
|
{
|
||||||
// find the last one non-zero component
|
// find the last one non-zero component
|
||||||
std::size_t lastSignificantIndex = N - 1;
|
std::size_t lastSignificantIndex = N - 1;
|
||||||
while (lastSignificantIndex > 0 && (*this)[lastSignificantIndex] == 0)
|
while ((lastSignificantIndex > 0) && ((*this)[lastSignificantIndex] == 0))
|
||||||
--lastSignificantIndex;
|
--lastSignificantIndex;
|
||||||
|
|
||||||
if (lastSignificantIndex + 1 < Mandatory) // lastSignificantIndex >= 0
|
if (lastSignificantIndex + 1 < Mandatory) // lastSignificantIndex >= 0
|
||||||
|
|||||||
@@ -55,7 +55,7 @@ public:
|
|||||||
lb_name->setText("<b><h2>qBittorrent " QBT_VERSION " (32-bit)</h2></b>");
|
lb_name->setText("<b><h2>qBittorrent " QBT_VERSION " (32-bit)</h2></b>");
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
logo->setPixmap(Utils::Gui::scaledPixmap(":/icons/skin/qbittorrent32.png", this));
|
logo->setPixmap(Utils::Gui::scaledPixmapSvg(":/icons/skin/qbittorrent-tray.svg", this, 32));
|
||||||
|
|
||||||
// About
|
// About
|
||||||
QString aboutText = QString(
|
QString aboutText = QString(
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
/*
|
/*
|
||||||
* Bittorrent Client using Qt and libtorrent.
|
* Bittorrent Client using Qt and libtorrent.
|
||||||
* Copyright (C) 2012 Christophe Dumez
|
* Copyright (C) 2012 Christophe Dumez <chris@qbittorrent.org>
|
||||||
*
|
*
|
||||||
* This program is free software; you can redistribute it and/or
|
* This program is free software; you can redistribute it and/or
|
||||||
* modify it under the terms of the GNU General Public License
|
* modify it under the terms of the GNU General Public License
|
||||||
@@ -24,8 +24,6 @@
|
|||||||
* modify file(s), you may extend this exception to your version of the file(s),
|
* modify file(s), you may extend this exception to your version of the file(s),
|
||||||
* but you are not obligated to do so. If you do not wish to do so, delete this
|
* but you are not obligated to do so. If you do not wish to do so, delete this
|
||||||
* exception statement from your version.
|
* exception statement from your version.
|
||||||
*
|
|
||||||
* Contact : chris@qbittorrent.org
|
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include "addnewtorrentdialog.h"
|
#include "addnewtorrentdialog.h"
|
||||||
@@ -37,22 +35,23 @@
|
|||||||
#include <QPushButton>
|
#include <QPushButton>
|
||||||
#include <QString>
|
#include <QString>
|
||||||
#include <QUrl>
|
#include <QUrl>
|
||||||
|
#include <QVector>
|
||||||
|
|
||||||
#include "autoexpandabledialog.h"
|
|
||||||
#include "base/bittorrent/magneturi.h"
|
#include "base/bittorrent/magneturi.h"
|
||||||
#include "base/bittorrent/session.h"
|
#include "base/bittorrent/session.h"
|
||||||
#include "base/bittorrent/torrenthandle.h"
|
#include "base/bittorrent/torrenthandle.h"
|
||||||
#include "base/bittorrent/torrentinfo.h"
|
#include "base/bittorrent/torrentinfo.h"
|
||||||
|
#include "base/global.h"
|
||||||
#include "base/net/downloadhandler.h"
|
#include "base/net/downloadhandler.h"
|
||||||
#include "base/net/downloadmanager.h"
|
#include "base/net/downloadmanager.h"
|
||||||
#include "base/preferences.h"
|
#include "base/preferences.h"
|
||||||
#include "base/settingsstorage.h"
|
#include "base/settingsstorage.h"
|
||||||
#include "base/settingvalue.h"
|
|
||||||
#include "base/torrentfileguard.h"
|
#include "base/torrentfileguard.h"
|
||||||
#include "base/unicodestrings.h"
|
#include "base/unicodestrings.h"
|
||||||
#include "base/utils/fs.h"
|
#include "base/utils/fs.h"
|
||||||
#include "base/utils/misc.h"
|
#include "base/utils/misc.h"
|
||||||
#include "base/utils/string.h"
|
#include "base/utils/string.h"
|
||||||
|
#include "autoexpandabledialog.h"
|
||||||
#include "guiiconprovider.h"
|
#include "guiiconprovider.h"
|
||||||
#include "messageboxraised.h"
|
#include "messageboxraised.h"
|
||||||
#include "proplistdelegate.h"
|
#include "proplistdelegate.h"
|
||||||
@@ -63,7 +62,7 @@
|
|||||||
|
|
||||||
namespace
|
namespace
|
||||||
{
|
{
|
||||||
#define SETTINGS_KEY(name) "AddNewTorrentDialog/" name
|
#define SETTINGS_KEY(name) QStringLiteral("AddNewTorrentDialog/" name)
|
||||||
const QString KEY_ENABLED = SETTINGS_KEY("Enabled");
|
const QString KEY_ENABLED = SETTINGS_KEY("Enabled");
|
||||||
const QString KEY_DEFAULTCATEGORY = SETTINGS_KEY("DefaultCategory");
|
const QString KEY_DEFAULTCATEGORY = SETTINGS_KEY("DefaultCategory");
|
||||||
const QString KEY_TREEHEADERSTATE = SETTINGS_KEY("TreeHeaderState");
|
const QString KEY_TREEHEADERSTATE = SETTINGS_KEY("TreeHeaderState");
|
||||||
@@ -71,7 +70,8 @@ namespace
|
|||||||
const QString KEY_EXPANDED = SETTINGS_KEY("Expanded");
|
const QString KEY_EXPANDED = SETTINGS_KEY("Expanded");
|
||||||
const QString KEY_TOPLEVEL = SETTINGS_KEY("TopLevel");
|
const QString KEY_TOPLEVEL = SETTINGS_KEY("TopLevel");
|
||||||
const QString KEY_SAVEPATHHISTORY = SETTINGS_KEY("SavePathHistory");
|
const QString KEY_SAVEPATHHISTORY = SETTINGS_KEY("SavePathHistory");
|
||||||
const char KEY_SAVEPATHHISTORYLENGTH[] = SETTINGS_KEY("SavePathHistoryLength");
|
const QString KEY_SAVEPATHHISTORYLENGTH = SETTINGS_KEY("SavePathHistoryLength");
|
||||||
|
const QString KEY_REMEMBERLASTSAVEPATH = SETTINGS_KEY("RememberLastSavePath");
|
||||||
|
|
||||||
// just a shortcut
|
// just a shortcut
|
||||||
inline SettingsStorage *settings()
|
inline SettingsStorage *settings()
|
||||||
@@ -80,12 +80,12 @@ namespace
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
constexpr int AddNewTorrentDialog::minPathHistoryLength;
|
const int AddNewTorrentDialog::minPathHistoryLength;
|
||||||
constexpr int AddNewTorrentDialog::maxPathHistoryLength;
|
const int AddNewTorrentDialog::maxPathHistoryLength;
|
||||||
|
|
||||||
AddNewTorrentDialog::AddNewTorrentDialog(const BitTorrent::AddTorrentParams &inParams, QWidget *parent)
|
AddNewTorrentDialog::AddNewTorrentDialog(const BitTorrent::AddTorrentParams &inParams, QWidget *parent)
|
||||||
: QDialog(parent)
|
: QDialog(parent)
|
||||||
, ui(new Ui::AddNewTorrentDialog)
|
, m_ui(new Ui::AddNewTorrentDialog)
|
||||||
, m_contentModel(nullptr)
|
, m_contentModel(nullptr)
|
||||||
, m_contentDelegate(nullptr)
|
, m_contentDelegate(nullptr)
|
||||||
, m_hasMetadata(false)
|
, m_hasMetadata(false)
|
||||||
@@ -93,40 +93,42 @@ AddNewTorrentDialog::AddNewTorrentDialog(const BitTorrent::AddTorrentParams &inP
|
|||||||
, m_torrentParams(inParams)
|
, m_torrentParams(inParams)
|
||||||
{
|
{
|
||||||
// TODO: set dialog file properties using m_torrentParams.filePriorities
|
// TODO: set dialog file properties using m_torrentParams.filePriorities
|
||||||
ui->setupUi(this);
|
m_ui->setupUi(this);
|
||||||
setAttribute(Qt::WA_DeleteOnClose);
|
setAttribute(Qt::WA_DeleteOnClose);
|
||||||
ui->lblMetaLoading->setVisible(false);
|
m_ui->lblMetaLoading->setVisible(false);
|
||||||
ui->progMetaLoading->setVisible(false);
|
m_ui->progMetaLoading->setVisible(false);
|
||||||
|
|
||||||
ui->savePath->setMode(FileSystemPathEdit::Mode::DirectorySave);
|
m_ui->savePath->setMode(FileSystemPathEdit::Mode::DirectorySave);
|
||||||
ui->savePath->setDialogCaption(tr("Choose save path"));
|
m_ui->savePath->setDialogCaption(tr("Choose save path"));
|
||||||
ui->savePath->setMaxVisibleItems(20);
|
m_ui->savePath->setMaxVisibleItems(20);
|
||||||
|
|
||||||
auto session = BitTorrent::Session::instance();
|
auto session = BitTorrent::Session::instance();
|
||||||
|
|
||||||
if (m_torrentParams.addPaused == TriStateBool::True)
|
if (m_torrentParams.addPaused == TriStateBool::True)
|
||||||
ui->startTorrentCheckBox->setChecked(false);
|
m_ui->startTorrentCheckBox->setChecked(false);
|
||||||
else if (m_torrentParams.addPaused == TriStateBool::False)
|
else if (m_torrentParams.addPaused == TriStateBool::False)
|
||||||
ui->startTorrentCheckBox->setChecked(true);
|
m_ui->startTorrentCheckBox->setChecked(true);
|
||||||
else
|
else
|
||||||
ui->startTorrentCheckBox->setChecked(!session->isAddTorrentPaused());
|
m_ui->startTorrentCheckBox->setChecked(!session->isAddTorrentPaused());
|
||||||
|
|
||||||
ui->comboTTM->blockSignals(true); // the TreeView size isn't correct if the slot does it job at this point
|
m_ui->comboTTM->blockSignals(true); // the TreeView size isn't correct if the slot does it job at this point
|
||||||
ui->comboTTM->setCurrentIndex(!session->isAutoTMMDisabledByDefault());
|
m_ui->comboTTM->setCurrentIndex(!session->isAutoTMMDisabledByDefault());
|
||||||
ui->comboTTM->blockSignals(false);
|
m_ui->comboTTM->blockSignals(false);
|
||||||
populateSavePathComboBox();
|
populateSavePathComboBox();
|
||||||
connect(ui->savePath, &FileSystemPathEdit::selectedPathChanged, this, &AddNewTorrentDialog::onSavePathChanged);
|
connect(m_ui->savePath, &FileSystemPathEdit::selectedPathChanged, this, &AddNewTorrentDialog::onSavePathChanged);
|
||||||
ui->defaultSavePathCheckBox->setVisible(false); // Default path is selected by default
|
|
||||||
|
const bool rememberLastSavePath = settings()->loadValue(KEY_REMEMBERLASTSAVEPATH, false).toBool();
|
||||||
|
m_ui->checkBoxRememberLastSavePath->setChecked(rememberLastSavePath);
|
||||||
|
|
||||||
if (m_torrentParams.createSubfolder == TriStateBool::True)
|
if (m_torrentParams.createSubfolder == TriStateBool::True)
|
||||||
ui->createSubfolderCheckBox->setChecked(true);
|
m_ui->createSubfolderCheckBox->setChecked(true);
|
||||||
else if (m_torrentParams.createSubfolder == TriStateBool::False)
|
else if (m_torrentParams.createSubfolder == TriStateBool::False)
|
||||||
ui->createSubfolderCheckBox->setChecked(false);
|
m_ui->createSubfolderCheckBox->setChecked(false);
|
||||||
else
|
else
|
||||||
ui->createSubfolderCheckBox->setChecked(session->isCreateTorrentSubfolder());
|
m_ui->createSubfolderCheckBox->setChecked(session->isCreateTorrentSubfolder());
|
||||||
|
|
||||||
ui->skipCheckingCheckBox->setChecked(m_torrentParams.skipChecking);
|
m_ui->skipCheckingCheckBox->setChecked(m_torrentParams.skipChecking);
|
||||||
ui->doNotDeleteTorrentCheckBox->setVisible(TorrentFileGuard::autoDeleteMode() != TorrentFileGuard::Never);
|
m_ui->doNotDeleteTorrentCheckBox->setVisible(TorrentFileGuard::autoDeleteMode() != TorrentFileGuard::Never);
|
||||||
|
|
||||||
// Load categories
|
// Load categories
|
||||||
QStringList categories = session->categories().keys();
|
QStringList categories = session->categories().keys();
|
||||||
@@ -134,25 +136,25 @@ AddNewTorrentDialog::AddNewTorrentDialog(const BitTorrent::AddTorrentParams &inP
|
|||||||
QString defaultCategory = settings()->loadValue(KEY_DEFAULTCATEGORY).toString();
|
QString defaultCategory = settings()->loadValue(KEY_DEFAULTCATEGORY).toString();
|
||||||
|
|
||||||
if (!m_torrentParams.category.isEmpty())
|
if (!m_torrentParams.category.isEmpty())
|
||||||
ui->categoryComboBox->addItem(m_torrentParams.category);
|
m_ui->categoryComboBox->addItem(m_torrentParams.category);
|
||||||
if (!defaultCategory.isEmpty())
|
if (!defaultCategory.isEmpty())
|
||||||
ui->categoryComboBox->addItem(defaultCategory);
|
m_ui->categoryComboBox->addItem(defaultCategory);
|
||||||
ui->categoryComboBox->addItem("");
|
m_ui->categoryComboBox->addItem("");
|
||||||
|
|
||||||
foreach (const QString &category, categories)
|
foreach (const QString &category, categories)
|
||||||
if (category != defaultCategory && category != m_torrentParams.category)
|
if (category != defaultCategory && category != m_torrentParams.category)
|
||||||
ui->categoryComboBox->addItem(category);
|
m_ui->categoryComboBox->addItem(category);
|
||||||
|
|
||||||
ui->contentTreeView->header()->setSortIndicator(0, Qt::AscendingOrder);
|
m_ui->contentTreeView->header()->setSortIndicator(0, Qt::AscendingOrder);
|
||||||
loadState();
|
loadState();
|
||||||
// Signal / slots
|
// Signal / slots
|
||||||
connect(ui->adv_button, SIGNAL(clicked(bool)), SLOT(showAdvancedSettings(bool)));
|
connect(m_ui->adv_button, &QToolButton::clicked, this, &AddNewTorrentDialog::showAdvancedSettings);
|
||||||
connect(ui->doNotDeleteTorrentCheckBox, SIGNAL(clicked(bool)), SLOT(doNotDeleteTorrentClicked(bool)));
|
connect(m_ui->doNotDeleteTorrentCheckBox, &QCheckBox::clicked, this, &AddNewTorrentDialog::doNotDeleteTorrentClicked);
|
||||||
QShortcut *editHotkey = new QShortcut(Qt::Key_F2, ui->contentTreeView, 0, 0, Qt::WidgetShortcut);
|
QShortcut *editHotkey = new QShortcut(Qt::Key_F2, m_ui->contentTreeView, nullptr, nullptr, Qt::WidgetShortcut);
|
||||||
connect(editHotkey, SIGNAL(activated()), SLOT(renameSelectedFile()));
|
connect(editHotkey, &QShortcut::activated, this, &AddNewTorrentDialog::renameSelectedFile);
|
||||||
connect(ui->contentTreeView, SIGNAL(doubleClicked(QModelIndex)), SLOT(renameSelectedFile()));
|
connect(m_ui->contentTreeView, &QAbstractItemView::doubleClicked, this, &AddNewTorrentDialog::renameSelectedFile);
|
||||||
|
|
||||||
ui->buttonBox->button(QDialogButtonBox::Ok)->setFocus();
|
m_ui->buttonBox->button(QDialogButtonBox::Ok)->setFocus();
|
||||||
}
|
}
|
||||||
|
|
||||||
AddNewTorrentDialog::~AddNewTorrentDialog()
|
AddNewTorrentDialog::~AddNewTorrentDialog()
|
||||||
@@ -160,7 +162,7 @@ AddNewTorrentDialog::~AddNewTorrentDialog()
|
|||||||
saveState();
|
saveState();
|
||||||
|
|
||||||
delete m_contentDelegate;
|
delete m_contentDelegate;
|
||||||
delete ui;
|
delete m_ui;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool AddNewTorrentDialog::isEnabled()
|
bool AddNewTorrentDialog::isEnabled()
|
||||||
@@ -185,30 +187,21 @@ void AddNewTorrentDialog::setTopLevel(bool value)
|
|||||||
|
|
||||||
int AddNewTorrentDialog::savePathHistoryLength()
|
int AddNewTorrentDialog::savePathHistoryLength()
|
||||||
{
|
{
|
||||||
return savePathHistoryLengthSetting();
|
const int defaultHistoryLength = 8;
|
||||||
|
const int value = settings()->loadValue(KEY_SAVEPATHHISTORYLENGTH, defaultHistoryLength).toInt();
|
||||||
|
return qBound(minPathHistoryLength, value, maxPathHistoryLength);
|
||||||
}
|
}
|
||||||
|
|
||||||
void AddNewTorrentDialog::setSavePathHistoryLength(int value)
|
void AddNewTorrentDialog::setSavePathHistoryLength(int value)
|
||||||
{
|
{
|
||||||
Q_ASSERT(value >= minPathHistoryLength);
|
const int clampedValue = qBound(minPathHistoryLength, value, maxPathHistoryLength);
|
||||||
Q_ASSERT(value <= maxPathHistoryLength);
|
|
||||||
const int oldValue = savePathHistoryLength();
|
const int oldValue = savePathHistoryLength();
|
||||||
if (oldValue != value) {
|
if (clampedValue == oldValue)
|
||||||
savePathHistoryLengthSetting() = value;
|
return;
|
||||||
settings()->storeValue(KEY_SAVEPATHHISTORY,
|
|
||||||
QStringList(settings()->loadValue(KEY_SAVEPATHHISTORY).toStringList().mid(0, value)));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
CachedSettingValue<int> &AddNewTorrentDialog::savePathHistoryLengthSetting()
|
settings()->storeValue(KEY_SAVEPATHHISTORYLENGTH, clampedValue);
|
||||||
{
|
settings()->storeValue(KEY_SAVEPATHHISTORY
|
||||||
const int defaultHistoryLength = 8;
|
, QStringList(settings()->loadValue(KEY_SAVEPATHHISTORY).toStringList().mid(0, clampedValue)));
|
||||||
static CachedSettingValue<int> setting(KEY_SAVEPATHHISTORYLENGTH, defaultHistoryLength,
|
|
||||||
[](int v)
|
|
||||||
{
|
|
||||||
return std::max(minPathHistoryLength, std::min(maxPathHistoryLength, v));
|
|
||||||
});
|
|
||||||
return setting;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void AddNewTorrentDialog::loadState()
|
void AddNewTorrentDialog::loadState()
|
||||||
@@ -220,15 +213,15 @@ void AddNewTorrentDialog::loadState()
|
|||||||
const int height = newSize.height();
|
const int height = newSize.height();
|
||||||
resize(width, height);
|
resize(width, height);
|
||||||
|
|
||||||
ui->adv_button->setChecked(settings()->loadValue(KEY_EXPANDED).toBool());
|
m_ui->adv_button->setChecked(settings()->loadValue(KEY_EXPANDED).toBool());
|
||||||
}
|
}
|
||||||
|
|
||||||
void AddNewTorrentDialog::saveState()
|
void AddNewTorrentDialog::saveState()
|
||||||
{
|
{
|
||||||
if (m_contentModel)
|
if (m_contentModel)
|
||||||
settings()->storeValue(KEY_TREEHEADERSTATE, ui->contentTreeView->header()->saveState());
|
settings()->storeValue(KEY_TREEHEADERSTATE, m_ui->contentTreeView->header()->saveState());
|
||||||
settings()->storeValue(KEY_WIDTH, width());
|
settings()->storeValue(KEY_WIDTH, width());
|
||||||
settings()->storeValue(KEY_EXPANDED, ui->adv_button->isChecked());
|
settings()->storeValue(KEY_EXPANDED, m_ui->adv_button->isChecked());
|
||||||
}
|
}
|
||||||
|
|
||||||
void AddNewTorrentDialog::show(QString source, const BitTorrent::AddTorrentParams &inParams, QWidget *parent)
|
void AddNewTorrentDialog::show(QString source, const BitTorrent::AddTorrentParams &inParams, QWidget *parent)
|
||||||
@@ -238,9 +231,10 @@ void AddNewTorrentDialog::show(QString source, const BitTorrent::AddTorrentParam
|
|||||||
if (Utils::Misc::isUrl(source)) {
|
if (Utils::Misc::isUrl(source)) {
|
||||||
// Launch downloader
|
// Launch downloader
|
||||||
Net::DownloadHandler *handler = Net::DownloadManager::instance()->downloadUrl(source, true, 10485760 /* 10MB */, true);
|
Net::DownloadHandler *handler = Net::DownloadManager::instance()->downloadUrl(source, true, 10485760 /* 10MB */, true);
|
||||||
connect(handler, SIGNAL(downloadFinished(QString,QString)), dlg, SLOT(handleDownloadFinished(QString,QString)));
|
connect(handler, static_cast<void (Net::DownloadHandler::*)(const QString &, const QString &)>(&Net::DownloadHandler::downloadFinished)
|
||||||
connect(handler, SIGNAL(downloadFailed(QString,QString)), dlg, SLOT(handleDownloadFailed(QString,QString)));
|
, dlg, &AddNewTorrentDialog::handleDownloadFinished);
|
||||||
connect(handler, SIGNAL(redirectedToMagnet(QString,QString)), dlg, SLOT(handleRedirectedToMagnet(QString,QString)));
|
connect(handler, &Net::DownloadHandler::downloadFailed, dlg, &AddNewTorrentDialog::handleDownloadFailed);
|
||||||
|
connect(handler, &Net::DownloadHandler::redirectedToMagnet, dlg, &AddNewTorrentDialog::handleRedirectedToMagnet);
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
bool ok = false;
|
bool ok = false;
|
||||||
@@ -315,9 +309,9 @@ bool AddNewTorrentDialog::loadTorrent(const QString &torrentPath)
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
ui->lblhash->setText(m_hash);
|
m_ui->lblhash->setText(m_hash);
|
||||||
setupTreeview();
|
setupTreeview();
|
||||||
TMMChanged(ui->comboTTM->currentIndex());
|
TMMChanged(m_ui->comboTTM->currentIndex());
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -349,18 +343,18 @@ bool AddNewTorrentDialog::loadMagnet(const BitTorrent::MagnetUri &magnetUri)
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
connect(BitTorrent::Session::instance(), SIGNAL(metadataLoaded(BitTorrent::TorrentInfo)), SLOT(updateMetadata(BitTorrent::TorrentInfo)));
|
connect(BitTorrent::Session::instance(), &BitTorrent::Session::metadataLoaded, this, &AddNewTorrentDialog::updateMetadata);
|
||||||
|
|
||||||
// Set dialog title
|
// Set dialog title
|
||||||
QString torrent_name = magnetUri.name();
|
QString torrentName = magnetUri.name();
|
||||||
setWindowTitle(torrent_name.isEmpty() ? tr("Magnet link") : torrent_name);
|
setWindowTitle(torrentName.isEmpty() ? tr("Magnet link") : torrentName);
|
||||||
|
|
||||||
setupTreeview();
|
setupTreeview();
|
||||||
TMMChanged(ui->comboTTM->currentIndex());
|
TMMChanged(m_ui->comboTTM->currentIndex());
|
||||||
|
|
||||||
BitTorrent::Session::instance()->loadMetadata(magnetUri);
|
BitTorrent::Session::instance()->loadMetadata(magnetUri);
|
||||||
setMetadataProgressIndicator(true, tr("Retrieving metadata..."));
|
setMetadataProgressIndicator(true, tr("Retrieving metadata..."));
|
||||||
ui->lblhash->setText(m_hash);
|
m_ui->lblhash->setText(m_hash);
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
@@ -379,17 +373,17 @@ void AddNewTorrentDialog::showAdvancedSettings(bool show)
|
|||||||
const int minimumW = minimumWidth();
|
const int minimumW = minimumWidth();
|
||||||
setMinimumWidth(width()); // to remain the same width
|
setMinimumWidth(width()); // to remain the same width
|
||||||
if (show) {
|
if (show) {
|
||||||
ui->adv_button->setText(QString::fromUtf8(C_UP));
|
m_ui->adv_button->setText(QString::fromUtf8(C_UP));
|
||||||
ui->settings_group->setVisible(true);
|
m_ui->settings_group->setVisible(true);
|
||||||
ui->infoGroup->setVisible(true);
|
m_ui->infoGroup->setVisible(true);
|
||||||
ui->contentTreeView->setVisible(m_hasMetadata);
|
m_ui->contentTreeView->setVisible(m_hasMetadata);
|
||||||
static_cast<QVBoxLayout *>(layout())->insertWidget(layout()->indexOf(ui->never_show_cb) + 1, ui->adv_button);
|
static_cast<QVBoxLayout *>(layout())->insertWidget(layout()->indexOf(m_ui->never_show_cb) + 1, m_ui->adv_button);
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
ui->adv_button->setText(QString::fromUtf8(C_DOWN));
|
m_ui->adv_button->setText(QString::fromUtf8(C_DOWN));
|
||||||
ui->settings_group->setVisible(false);
|
m_ui->settings_group->setVisible(false);
|
||||||
ui->infoGroup->setVisible(false);
|
m_ui->infoGroup->setVisible(false);
|
||||||
ui->buttonsHLayout->insertWidget(0, layout()->takeAt(layout()->indexOf(ui->never_show_cb) + 1)->widget());
|
m_ui->buttonsHLayout->insertWidget(0, layout()->takeAt(layout()->indexOf(m_ui->never_show_cb) + 1)->widget());
|
||||||
}
|
}
|
||||||
adjustSize();
|
adjustSize();
|
||||||
setMinimumWidth(minimumW);
|
setMinimumWidth(minimumW);
|
||||||
@@ -397,31 +391,30 @@ void AddNewTorrentDialog::showAdvancedSettings(bool show)
|
|||||||
|
|
||||||
void AddNewTorrentDialog::saveSavePathHistory() const
|
void AddNewTorrentDialog::saveSavePathHistory() const
|
||||||
{
|
{
|
||||||
QDir selectedSavePath(ui->savePath->selectedPath());
|
|
||||||
// Get current history
|
// Get current history
|
||||||
QStringList history = settings()->loadValue(KEY_SAVEPATHHISTORY).toStringList();
|
QStringList history = settings()->loadValue(KEY_SAVEPATHHISTORY).toStringList();
|
||||||
if (history.size() > savePathHistoryLength())
|
QVector<QDir> historyDirs;
|
||||||
history = history.mid(0, savePathHistoryLength());
|
for (const QString &path : qAsConst(history))
|
||||||
QList<QDir> historyDirs;
|
historyDirs << QDir {path};
|
||||||
foreach (const QString dir, history)
|
|
||||||
historyDirs << QDir(dir);
|
const QDir selectedSavePath {m_ui->savePath->selectedPath()};
|
||||||
if (!historyDirs.contains(selectedSavePath)) {
|
const int selectedSavePathIndex = historyDirs.indexOf(selectedSavePath);
|
||||||
// Add save path to history
|
if (selectedSavePathIndex > 0)
|
||||||
|
history.removeAt(selectedSavePathIndex);
|
||||||
|
if (selectedSavePathIndex != 0)
|
||||||
|
// Add last used save path to the front of history
|
||||||
history.push_front(selectedSavePath.absolutePath());
|
history.push_front(selectedSavePath.absolutePath());
|
||||||
// Limit list size
|
|
||||||
if (history.size() > savePathHistoryLength())
|
|
||||||
history.pop_back();
|
|
||||||
// Save history
|
// Save history
|
||||||
settings()->storeValue(KEY_SAVEPATHHISTORY, history);
|
settings()->storeValue(KEY_SAVEPATHHISTORY, QStringList {history.mid(0, savePathHistoryLength())});
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// save_path is a folder, not an absolute file path
|
// savePath is a folder, not an absolute file path
|
||||||
int AddNewTorrentDialog::indexOfSavePath(const QString &save_path)
|
int AddNewTorrentDialog::indexOfSavePath(const QString &savePath)
|
||||||
{
|
{
|
||||||
QDir saveDir(save_path);
|
QDir saveDir(savePath);
|
||||||
for (int i = 0; i < ui->savePath->count(); ++i)
|
for (int i = 0; i < m_ui->savePath->count(); ++i)
|
||||||
if (QDir(ui->savePath->item(i)) == saveDir)
|
if (QDir(m_ui->savePath->item(i)) == saveDir)
|
||||||
return i;
|
return i;
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
@@ -429,7 +422,7 @@ int AddNewTorrentDialog::indexOfSavePath(const QString &save_path)
|
|||||||
void AddNewTorrentDialog::updateDiskSpaceLabel()
|
void AddNewTorrentDialog::updateDiskSpaceLabel()
|
||||||
{
|
{
|
||||||
// Determine torrent size
|
// Determine torrent size
|
||||||
qulonglong torrent_size = 0;
|
qulonglong torrentSize = 0;
|
||||||
|
|
||||||
if (m_hasMetadata) {
|
if (m_hasMetadata) {
|
||||||
if (m_contentModel) {
|
if (m_contentModel) {
|
||||||
@@ -437,28 +430,26 @@ void AddNewTorrentDialog::updateDiskSpaceLabel()
|
|||||||
Q_ASSERT(priorities.size() == m_torrentInfo.filesCount());
|
Q_ASSERT(priorities.size() == m_torrentInfo.filesCount());
|
||||||
for (int i = 0; i < priorities.size(); ++i)
|
for (int i = 0; i < priorities.size(); ++i)
|
||||||
if (priorities[i] > 0)
|
if (priorities[i] > 0)
|
||||||
torrent_size += m_torrentInfo.fileSize(i);
|
torrentSize += m_torrentInfo.fileSize(i);
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
torrent_size = m_torrentInfo.totalSize();
|
torrentSize = m_torrentInfo.totalSize();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
QString size_string = torrent_size ? Utils::Misc::friendlyUnit(torrent_size) : QString(tr("Not Available", "This size is unavailable."));
|
QString sizeString = torrentSize ? Utils::Misc::friendlyUnit(torrentSize) : QString(tr("Not Available", "This size is unavailable."));
|
||||||
size_string += " (";
|
sizeString += " (";
|
||||||
size_string += tr("Free space on disk: %1").arg(Utils::Misc::friendlyUnit(Utils::Fs::freeDiskSpaceOnPath(
|
sizeString += tr("Free space on disk: %1").arg(Utils::Misc::friendlyUnit(Utils::Fs::freeDiskSpaceOnPath(
|
||||||
ui->savePath->selectedPath())));
|
m_ui->savePath->selectedPath())));
|
||||||
size_string += ")";
|
sizeString += ")";
|
||||||
ui->size_lbl->setText(size_string);
|
m_ui->size_lbl->setText(sizeString);
|
||||||
}
|
}
|
||||||
|
|
||||||
void AddNewTorrentDialog::onSavePathChanged(const QString &newPath)
|
void AddNewTorrentDialog::onSavePathChanged(const QString &newPath)
|
||||||
{
|
{
|
||||||
// Toggle default save path setting checkbox visibility
|
Q_UNUSED(newPath);
|
||||||
ui->defaultSavePathCheckBox->setChecked(false);
|
|
||||||
ui->defaultSavePathCheckBox->setVisible(QDir(newPath) != QDir(BitTorrent::Session::instance()->defaultSavePath()));
|
|
||||||
// Remember index
|
// Remember index
|
||||||
m_oldIndex = ui->savePath->currentIndex();
|
m_oldIndex = m_ui->savePath->currentIndex();
|
||||||
updateDiskSpaceLabel();
|
updateDiskSpaceLabel();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -466,9 +457,9 @@ void AddNewTorrentDialog::categoryChanged(int index)
|
|||||||
{
|
{
|
||||||
Q_UNUSED(index);
|
Q_UNUSED(index);
|
||||||
|
|
||||||
if (ui->comboTTM->currentIndex() == 1) {
|
if (m_ui->comboTTM->currentIndex() == 1) {
|
||||||
QString savePath = BitTorrent::Session::instance()->categorySavePath(ui->categoryComboBox->currentText());
|
QString savePath = BitTorrent::Session::instance()->categorySavePath(m_ui->categoryComboBox->currentText());
|
||||||
ui->savePath->setSelectedPath(Utils::Fs::toNativePath(savePath));
|
m_ui->savePath->setSelectedPath(Utils::Fs::toNativePath(savePath));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -477,16 +468,16 @@ void AddNewTorrentDialog::setSavePath(const QString &newPath)
|
|||||||
int existingIndex = indexOfSavePath(newPath);
|
int existingIndex = indexOfSavePath(newPath);
|
||||||
if (existingIndex < 0) {
|
if (existingIndex < 0) {
|
||||||
// New path, prepend to combo box
|
// New path, prepend to combo box
|
||||||
ui->savePath->insertItem(0, newPath);
|
m_ui->savePath->insertItem(0, newPath);
|
||||||
existingIndex = 0;
|
existingIndex = 0;
|
||||||
}
|
}
|
||||||
ui->savePath->setCurrentIndex(existingIndex);
|
m_ui->savePath->setCurrentIndex(existingIndex);
|
||||||
onSavePathChanged(newPath);
|
onSavePathChanged(newPath);
|
||||||
}
|
}
|
||||||
|
|
||||||
void AddNewTorrentDialog::renameSelectedFile()
|
void AddNewTorrentDialog::renameSelectedFile()
|
||||||
{
|
{
|
||||||
const QModelIndexList selectedIndexes = ui->contentTreeView->selectionModel()->selectedRows(0);
|
const QModelIndexList selectedIndexes = m_ui->contentTreeView->selectionModel()->selectedRows(0);
|
||||||
if (selectedIndexes.size() != 1) return;
|
if (selectedIndexes.size() != 1) return;
|
||||||
|
|
||||||
const QModelIndex modelIndex = selectedIndexes.first();
|
const QModelIndex modelIndex = selectedIndexes.first();
|
||||||
@@ -587,35 +578,38 @@ void AddNewTorrentDialog::renameSelectedFile()
|
|||||||
|
|
||||||
void AddNewTorrentDialog::populateSavePathComboBox()
|
void AddNewTorrentDialog::populateSavePathComboBox()
|
||||||
{
|
{
|
||||||
QString defSavePath = BitTorrent::Session::instance()->defaultSavePath();
|
m_ui->savePath->clear();
|
||||||
|
|
||||||
ui->savePath->clear();
|
|
||||||
ui->savePath->addItem(defSavePath);
|
|
||||||
QDir defaultSaveDir(defSavePath);
|
|
||||||
// Load save path history
|
// Load save path history
|
||||||
foreach (const QString &savePath, settings()->loadValue(KEY_SAVEPATHHISTORY).toStringList())
|
const QStringList savePathHistory {settings()->loadValue(KEY_SAVEPATHHISTORY).toStringList()};
|
||||||
if (QDir(savePath) != defaultSaveDir)
|
for (const QString &savePath : savePathHistory)
|
||||||
ui->savePath->addItem(savePath);
|
m_ui->savePath->addItem(savePath);
|
||||||
|
|
||||||
|
const bool rememberLastSavePath {settings()->loadValue(KEY_REMEMBERLASTSAVEPATH, false).toBool()};
|
||||||
|
const QString defSavePath {BitTorrent::Session::instance()->defaultSavePath()};
|
||||||
|
|
||||||
if (!m_torrentParams.savePath.isEmpty())
|
if (!m_torrentParams.savePath.isEmpty())
|
||||||
setSavePath(m_torrentParams.savePath);
|
setSavePath(m_torrentParams.savePath);
|
||||||
|
else if (!rememberLastSavePath)
|
||||||
|
setSavePath(defSavePath);
|
||||||
|
// else last used save path will be selected since it is the first in the list
|
||||||
}
|
}
|
||||||
|
|
||||||
void AddNewTorrentDialog::displayContentTreeMenu(const QPoint &)
|
void AddNewTorrentDialog::displayContentTreeMenu(const QPoint &)
|
||||||
{
|
{
|
||||||
QMenu myFilesLlistMenu;
|
QMenu myFilesLlistMenu;
|
||||||
const QModelIndexList selectedRows = ui->contentTreeView->selectionModel()->selectedRows(0);
|
const QModelIndexList selectedRows = m_ui->contentTreeView->selectionModel()->selectedRows(0);
|
||||||
QAction *actRename = 0;
|
QAction *actRename = nullptr;
|
||||||
if (selectedRows.size() == 1) {
|
if (selectedRows.size() == 1) {
|
||||||
actRename = myFilesLlistMenu.addAction(GuiIconProvider::instance()->getIcon("edit-rename"), tr("Rename..."));
|
actRename = myFilesLlistMenu.addAction(GuiIconProvider::instance()->getIcon("edit-rename"), tr("Rename..."));
|
||||||
myFilesLlistMenu.addSeparator();
|
myFilesLlistMenu.addSeparator();
|
||||||
}
|
}
|
||||||
QMenu subMenu;
|
QMenu subMenu;
|
||||||
subMenu.setTitle(tr("Priority"));
|
subMenu.setTitle(tr("Priority"));
|
||||||
subMenu.addAction(ui->actionNot_downloaded);
|
subMenu.addAction(m_ui->actionNot_downloaded);
|
||||||
subMenu.addAction(ui->actionNormal);
|
subMenu.addAction(m_ui->actionNormal);
|
||||||
subMenu.addAction(ui->actionHigh);
|
subMenu.addAction(m_ui->actionHigh);
|
||||||
subMenu.addAction(ui->actionMaximum);
|
subMenu.addAction(m_ui->actionMaximum);
|
||||||
myFilesLlistMenu.addMenu(&subMenu);
|
myFilesLlistMenu.addMenu(&subMenu);
|
||||||
// Call menu
|
// Call menu
|
||||||
QAction *act = myFilesLlistMenu.exec(QCursor::pos());
|
QAction *act = myFilesLlistMenu.exec(QCursor::pos());
|
||||||
@@ -625,11 +619,11 @@ void AddNewTorrentDialog::displayContentTreeMenu(const QPoint &)
|
|||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
int prio = prio::NORMAL;
|
int prio = prio::NORMAL;
|
||||||
if (act == ui->actionHigh)
|
if (act == m_ui->actionHigh)
|
||||||
prio = prio::HIGH;
|
prio = prio::HIGH;
|
||||||
else if (act == ui->actionMaximum)
|
else if (act == m_ui->actionMaximum)
|
||||||
prio = prio::MAXIMUM;
|
prio = prio::MAXIMUM;
|
||||||
else if (act == ui->actionNot_downloaded)
|
else if (act == m_ui->actionNot_downloaded)
|
||||||
prio = prio::IGNORED;
|
prio = prio::IGNORED;
|
||||||
|
|
||||||
qDebug("Setting files priority");
|
qDebug("Setting files priority");
|
||||||
@@ -647,34 +641,33 @@ void AddNewTorrentDialog::accept()
|
|||||||
disconnect(this, SLOT(updateMetadata(const BitTorrent::TorrentInfo&)));
|
disconnect(this, SLOT(updateMetadata(const BitTorrent::TorrentInfo&)));
|
||||||
|
|
||||||
// TODO: Check if destination actually exists
|
// TODO: Check if destination actually exists
|
||||||
m_torrentParams.skipChecking = ui->skipCheckingCheckBox->isChecked();
|
m_torrentParams.skipChecking = m_ui->skipCheckingCheckBox->isChecked();
|
||||||
|
|
||||||
// Category
|
// Category
|
||||||
m_torrentParams.category = ui->categoryComboBox->currentText();
|
m_torrentParams.category = m_ui->categoryComboBox->currentText();
|
||||||
|
if (m_ui->defaultCategoryCheckbox->isChecked())
|
||||||
if (ui->defaultCategoryCheckbox->isChecked())
|
|
||||||
settings()->storeValue(KEY_DEFAULTCATEGORY, m_torrentParams.category);
|
settings()->storeValue(KEY_DEFAULTCATEGORY, m_torrentParams.category);
|
||||||
|
|
||||||
|
settings()->storeValue(KEY_REMEMBERLASTSAVEPATH, m_ui->checkBoxRememberLastSavePath->isChecked());
|
||||||
|
|
||||||
// Save file priorities
|
// Save file priorities
|
||||||
if (m_contentModel)
|
if (m_contentModel)
|
||||||
m_torrentParams.filePriorities = m_contentModel->model()->getFilePriorities();
|
m_torrentParams.filePriorities = m_contentModel->model()->getFilePriorities();
|
||||||
|
|
||||||
m_torrentParams.addPaused = TriStateBool(!ui->startTorrentCheckBox->isChecked());
|
m_torrentParams.addPaused = TriStateBool(!m_ui->startTorrentCheckBox->isChecked());
|
||||||
m_torrentParams.createSubfolder = TriStateBool(ui->createSubfolderCheckBox->isChecked());
|
m_torrentParams.createSubfolder = TriStateBool(m_ui->createSubfolderCheckBox->isChecked());
|
||||||
|
|
||||||
QString savePath = ui->savePath->selectedPath();
|
QString savePath = m_ui->savePath->selectedPath();
|
||||||
if (ui->comboTTM->currentIndex() != 1) { // 0 is Manual mode and 1 is Automatic mode. Handle all non 1 values as manual mode.
|
if (m_ui->comboTTM->currentIndex() != 1) { // 0 is Manual mode and 1 is Automatic mode. Handle all non 1 values as manual mode.
|
||||||
m_torrentParams.useAutoTMM = TriStateBool::False;
|
m_torrentParams.useAutoTMM = TriStateBool::False;
|
||||||
m_torrentParams.savePath = savePath;
|
m_torrentParams.savePath = savePath;
|
||||||
saveSavePathHistory();
|
saveSavePathHistory();
|
||||||
if (ui->defaultSavePathCheckBox->isChecked())
|
|
||||||
BitTorrent::Session::instance()->setDefaultSavePath(savePath);
|
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
m_torrentParams.useAutoTMM = TriStateBool::True;
|
m_torrentParams.useAutoTMM = TriStateBool::True;
|
||||||
}
|
}
|
||||||
|
|
||||||
setEnabled(!ui->never_show_cb->isChecked());
|
setEnabled(!m_ui->never_show_cb->isChecked());
|
||||||
|
|
||||||
// Add torrent
|
// Add torrent
|
||||||
if (!m_hasMetadata)
|
if (!m_hasMetadata)
|
||||||
@@ -721,16 +714,16 @@ void AddNewTorrentDialog::updateMetadata(const BitTorrent::TorrentInfo &info)
|
|||||||
void AddNewTorrentDialog::setMetadataProgressIndicator(bool visibleIndicator, const QString &labelText)
|
void AddNewTorrentDialog::setMetadataProgressIndicator(bool visibleIndicator, const QString &labelText)
|
||||||
{
|
{
|
||||||
// Always show info label when waiting for metadata
|
// Always show info label when waiting for metadata
|
||||||
ui->lblMetaLoading->setVisible(true);
|
m_ui->lblMetaLoading->setVisible(true);
|
||||||
ui->lblMetaLoading->setText(labelText);
|
m_ui->lblMetaLoading->setText(labelText);
|
||||||
ui->progMetaLoading->setVisible(visibleIndicator);
|
m_ui->progMetaLoading->setVisible(visibleIndicator);
|
||||||
}
|
}
|
||||||
|
|
||||||
void AddNewTorrentDialog::setupTreeview()
|
void AddNewTorrentDialog::setupTreeview()
|
||||||
{
|
{
|
||||||
if (!m_hasMetadata) {
|
if (!m_hasMetadata) {
|
||||||
setCommentText(tr("Not Available", "This comment is unavailable"));
|
setCommentText(tr("Not Available", "This comment is unavailable"));
|
||||||
ui->date_lbl->setText(tr("Not Available", "This date is unavailable"));
|
m_ui->date_lbl->setText(tr("Not Available", "This date is unavailable"));
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
// Set dialog title
|
// Set dialog title
|
||||||
@@ -738,29 +731,30 @@ void AddNewTorrentDialog::setupTreeview()
|
|||||||
|
|
||||||
// Set torrent information
|
// Set torrent information
|
||||||
setCommentText(Utils::Misc::parseHtmlLinks(m_torrentInfo.comment()));
|
setCommentText(Utils::Misc::parseHtmlLinks(m_torrentInfo.comment()));
|
||||||
ui->date_lbl->setText(!m_torrentInfo.creationDate().isNull() ? m_torrentInfo.creationDate().toString(Qt::DefaultLocaleShortDate) : tr("Not available"));
|
m_ui->date_lbl->setText(!m_torrentInfo.creationDate().isNull() ? m_torrentInfo.creationDate().toString(Qt::DefaultLocaleShortDate) : tr("Not available"));
|
||||||
|
|
||||||
// Prepare content tree
|
// Prepare content tree
|
||||||
m_contentModel = new TorrentContentFilterModel(this);
|
m_contentModel = new TorrentContentFilterModel(this);
|
||||||
connect(m_contentModel->model(), SIGNAL(filteredFilesChanged()), SLOT(updateDiskSpaceLabel()));
|
connect(m_contentModel->model(), &TorrentContentModel::filteredFilesChanged, this, &AddNewTorrentDialog::updateDiskSpaceLabel);
|
||||||
ui->contentTreeView->setModel(m_contentModel);
|
m_ui->contentTreeView->setModel(m_contentModel);
|
||||||
m_contentDelegate = new PropListDelegate(nullptr);
|
m_contentDelegate = new PropListDelegate(nullptr);
|
||||||
ui->contentTreeView->setItemDelegate(m_contentDelegate);
|
m_ui->contentTreeView->setItemDelegate(m_contentDelegate);
|
||||||
connect(ui->contentTreeView, SIGNAL(clicked(const QModelIndex&)), ui->contentTreeView, SLOT(edit(const QModelIndex&)));
|
connect(m_ui->contentTreeView, &QAbstractItemView::clicked, m_ui->contentTreeView
|
||||||
connect(ui->contentTreeView, SIGNAL(customContextMenuRequested(const QPoint&)), this, SLOT(displayContentTreeMenu(const QPoint&)));
|
, static_cast<void (QAbstractItemView::*)(const QModelIndex &)>(&QAbstractItemView::edit));
|
||||||
|
connect(m_ui->contentTreeView, &QWidget::customContextMenuRequested, this, &AddNewTorrentDialog::displayContentTreeMenu);
|
||||||
|
|
||||||
// List files in torrent
|
// List files in torrent
|
||||||
m_contentModel->model()->setupModelData(m_torrentInfo);
|
m_contentModel->model()->setupModelData(m_torrentInfo);
|
||||||
if (!m_headerState.isEmpty())
|
if (!m_headerState.isEmpty())
|
||||||
ui->contentTreeView->header()->restoreState(m_headerState);
|
m_ui->contentTreeView->header()->restoreState(m_headerState);
|
||||||
|
|
||||||
// Hide useless columns after loading the header state
|
// Hide useless columns after loading the header state
|
||||||
ui->contentTreeView->hideColumn(PROGRESS);
|
m_ui->contentTreeView->hideColumn(PROGRESS);
|
||||||
ui->contentTreeView->hideColumn(REMAINING);
|
m_ui->contentTreeView->hideColumn(REMAINING);
|
||||||
ui->contentTreeView->hideColumn(AVAILABILITY);
|
m_ui->contentTreeView->hideColumn(AVAILABILITY);
|
||||||
|
|
||||||
// Expand root folder
|
// Expand root folder
|
||||||
ui->contentTreeView->setExpanded(m_contentModel->index(0, 0), true);
|
m_ui->contentTreeView->setExpanded(m_contentModel->index(0, 0), true);
|
||||||
}
|
}
|
||||||
|
|
||||||
updateDiskSpaceLabel();
|
updateDiskSpaceLabel();
|
||||||
@@ -796,33 +790,32 @@ void AddNewTorrentDialog::TMMChanged(int index)
|
|||||||
{
|
{
|
||||||
if (index != 1) { // 0 is Manual mode and 1 is Automatic mode. Handle all non 1 values as manual mode.
|
if (index != 1) { // 0 is Manual mode and 1 is Automatic mode. Handle all non 1 values as manual mode.
|
||||||
populateSavePathComboBox();
|
populateSavePathComboBox();
|
||||||
ui->groupBoxSavePath->setEnabled(true);
|
m_ui->groupBoxSavePath->setEnabled(true);
|
||||||
ui->savePath->blockSignals(false);
|
m_ui->savePath->blockSignals(false);
|
||||||
ui->savePath->setCurrentIndex(m_oldIndex < ui->savePath->count() ? m_oldIndex : ui->savePath->count() - 1);
|
m_ui->savePath->setCurrentIndex(m_oldIndex < m_ui->savePath->count() ? m_oldIndex : m_ui->savePath->count() - 1);
|
||||||
ui->adv_button->setEnabled(true);
|
m_ui->adv_button->setEnabled(true);
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
ui->groupBoxSavePath->setEnabled(false);
|
m_ui->groupBoxSavePath->setEnabled(false);
|
||||||
ui->savePath->blockSignals(true);
|
m_ui->savePath->blockSignals(true);
|
||||||
ui->savePath->clear();
|
m_ui->savePath->clear();
|
||||||
QString savePath = BitTorrent::Session::instance()->categorySavePath(ui->categoryComboBox->currentText());
|
QString savePath = BitTorrent::Session::instance()->categorySavePath(m_ui->categoryComboBox->currentText());
|
||||||
ui->savePath->addItem(savePath);
|
m_ui->savePath->addItem(savePath);
|
||||||
ui->defaultSavePathCheckBox->setVisible(false);
|
m_ui->adv_button->setChecked(true);
|
||||||
ui->adv_button->setChecked(true);
|
m_ui->adv_button->setEnabled(false);
|
||||||
ui->adv_button->setEnabled(false);
|
|
||||||
showAdvancedSettings(true);
|
showAdvancedSettings(true);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void AddNewTorrentDialog::setCommentText(const QString &str) const
|
void AddNewTorrentDialog::setCommentText(const QString &str) const
|
||||||
{
|
{
|
||||||
ui->commentLabel->setText(str);
|
m_ui->commentLabel->setText(str);
|
||||||
|
|
||||||
// workaround for the additional space introduced by QScrollArea
|
// workaround for the additional space introduced by QScrollArea
|
||||||
int lineHeight = ui->commentLabel->fontMetrics().lineSpacing();
|
int lineHeight = m_ui->commentLabel->fontMetrics().lineSpacing();
|
||||||
int lines = 1 + str.count("\n");
|
int lines = 1 + str.count("\n");
|
||||||
int height = lineHeight * lines;
|
int height = lineHeight * lines;
|
||||||
ui->scrollArea->setMaximumHeight(height);
|
m_ui->scrollArea->setMaximumHeight(height);
|
||||||
}
|
}
|
||||||
|
|
||||||
void AddNewTorrentDialog::doNotDeleteTorrentClicked(bool checked)
|
void AddNewTorrentDialog::doNotDeleteTorrentClicked(bool checked)
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
/*
|
/*
|
||||||
* Bittorrent Client using Qt4 and libtorrent.
|
* Bittorrent Client using Qt and libtorrent.
|
||||||
* Copyright (C) 2012 Christophe Dumez
|
* Copyright (C) 2012 Christophe Dumez <chris@qbittorrent.org>
|
||||||
*
|
*
|
||||||
* This program is free software; you can redistribute it and/or
|
* This program is free software; you can redistribute it and/or
|
||||||
* modify it under the terms of the GNU General Public License
|
* modify it under the terms of the GNU General Public License
|
||||||
@@ -24,8 +24,6 @@
|
|||||||
* modify file(s), you may extend this exception to your version of the file(s),
|
* modify file(s), you may extend this exception to your version of the file(s),
|
||||||
* but you are not obligated to do so. If you do not wish to do so, delete this
|
* but you are not obligated to do so. If you do not wish to do so, delete this
|
||||||
* exception statement from your version.
|
* exception statement from your version.
|
||||||
*
|
|
||||||
* Contact : chris@qbittorrent.org
|
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#ifndef ADDNEWTORRENTDIALOG_H
|
#ifndef ADDNEWTORRENTDIALOG_H
|
||||||
@@ -36,9 +34,9 @@
|
|||||||
#include <QShortcut>
|
#include <QShortcut>
|
||||||
#include <QUrl>
|
#include <QUrl>
|
||||||
|
|
||||||
|
#include "base/bittorrent/addtorrentparams.h"
|
||||||
#include "base/bittorrent/infohash.h"
|
#include "base/bittorrent/infohash.h"
|
||||||
#include "base/bittorrent/torrentinfo.h"
|
#include "base/bittorrent/torrentinfo.h"
|
||||||
#include "base/bittorrent/addtorrentparams.h"
|
|
||||||
|
|
||||||
namespace BitTorrent
|
namespace BitTorrent
|
||||||
{
|
{
|
||||||
@@ -50,18 +48,17 @@ namespace Ui
|
|||||||
class AddNewTorrentDialog;
|
class AddNewTorrentDialog;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
class PropListDelegate;
|
||||||
class TorrentContentFilterModel;
|
class TorrentContentFilterModel;
|
||||||
class TorrentFileGuard;
|
class TorrentFileGuard;
|
||||||
class PropListDelegate;
|
|
||||||
template <typename T> class CachedSettingValue;
|
|
||||||
|
|
||||||
class AddNewTorrentDialog : public QDialog
|
class AddNewTorrentDialog : public QDialog
|
||||||
{
|
{
|
||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
|
|
||||||
public:
|
public:
|
||||||
static constexpr int minPathHistoryLength = 0;
|
static const int minPathHistoryLength = 0;
|
||||||
static constexpr int maxPathHistoryLength = 99;
|
static const int maxPathHistoryLength = 99;
|
||||||
|
|
||||||
~AddNewTorrentDialog();
|
~AddNewTorrentDialog();
|
||||||
|
|
||||||
@@ -98,18 +95,17 @@ private:
|
|||||||
bool loadMagnet(const BitTorrent::MagnetUri &magnetUri);
|
bool loadMagnet(const BitTorrent::MagnetUri &magnetUri);
|
||||||
void populateSavePathComboBox();
|
void populateSavePathComboBox();
|
||||||
void saveSavePathHistory() const;
|
void saveSavePathHistory() const;
|
||||||
int indexOfSavePath(const QString &save_path);
|
int indexOfSavePath(const QString &savePath);
|
||||||
void loadState();
|
void loadState();
|
||||||
void saveState();
|
void saveState();
|
||||||
void setMetadataProgressIndicator(bool visibleIndicator, const QString &labelText = QString());
|
void setMetadataProgressIndicator(bool visibleIndicator, const QString &labelText = QString());
|
||||||
void setupTreeview();
|
void setupTreeview();
|
||||||
void setCommentText(const QString &str) const;
|
void setCommentText(const QString &str) const;
|
||||||
void setSavePath(const QString &newPath);
|
void setSavePath(const QString &newPath);
|
||||||
static CachedSettingValue<int> &savePathHistoryLengthSetting();
|
|
||||||
|
|
||||||
void showEvent(QShowEvent *event) override;
|
void showEvent(QShowEvent *event) override;
|
||||||
|
|
||||||
Ui::AddNewTorrentDialog *ui;
|
Ui::AddNewTorrentDialog *m_ui;
|
||||||
TorrentContentFilterModel *m_contentModel;
|
TorrentContentFilterModel *m_contentModel;
|
||||||
PropListDelegate *m_contentDelegate;
|
PropListDelegate *m_contentDelegate;
|
||||||
bool m_hasMetadata;
|
bool m_hasMetadata;
|
||||||
|
|||||||
@@ -62,9 +62,9 @@
|
|||||||
<widget class="FileSystemPathComboEdit" name="savePath" native="true"/>
|
<widget class="FileSystemPathComboEdit" name="savePath" native="true"/>
|
||||||
</item>
|
</item>
|
||||||
<item>
|
<item>
|
||||||
<widget class="QCheckBox" name="defaultSavePathCheckBox">
|
<widget class="QCheckBox" name="checkBoxRememberLastSavePath">
|
||||||
<property name="text">
|
<property name="text">
|
||||||
<string>Set as default save path</string>
|
<string>Remember last used save path</string>
|
||||||
</property>
|
</property>
|
||||||
</widget>
|
</widget>
|
||||||
</item>
|
</item>
|
||||||
@@ -393,7 +393,7 @@
|
|||||||
</customwidgets>
|
</customwidgets>
|
||||||
<tabstops>
|
<tabstops>
|
||||||
<tabstop>savePath</tabstop>
|
<tabstop>savePath</tabstop>
|
||||||
<tabstop>defaultSavePathCheckBox</tabstop>
|
<tabstop>checkBoxRememberLastSavePath</tabstop>
|
||||||
<tabstop>never_show_cb</tabstop>
|
<tabstop>never_show_cb</tabstop>
|
||||||
<tabstop>adv_button</tabstop>
|
<tabstop>adv_button</tabstop>
|
||||||
<tabstop>startTorrentCheckBox</tabstop>
|
<tabstop>startTorrentCheckBox</tabstop>
|
||||||
|
|||||||
@@ -125,8 +125,10 @@ AdvancedSettings::AdvancedSettings(QWidget *parent)
|
|||||||
setSelectionMode(QAbstractItemView::NoSelection);
|
setSelectionMode(QAbstractItemView::NoSelection);
|
||||||
setEditTriggers(QAbstractItemView::NoEditTriggers);
|
setEditTriggers(QAbstractItemView::NoEditTriggers);
|
||||||
// Signals
|
// Signals
|
||||||
connect(&spin_cache, SIGNAL(valueChanged(int)), SLOT(updateCacheSpinSuffix(int)));
|
connect(&spin_cache, static_cast<void (QSpinBox::*)(int)>(&QSpinBox::valueChanged)
|
||||||
connect(&combo_iface, SIGNAL(currentIndexChanged(int)), SLOT(updateInterfaceAddressCombo()));
|
, this, &AdvancedSettings::updateCacheSpinSuffix);
|
||||||
|
connect(&combo_iface, static_cast<void (QComboBox::*)(int)>(&QComboBox::currentIndexChanged)
|
||||||
|
, this, &AdvancedSettings::updateInterfaceAddressCombo);
|
||||||
// Load settings
|
// Load settings
|
||||||
loadAdvancedSettings();
|
loadAdvancedSettings();
|
||||||
resizeColumnToContents(0);
|
resizeColumnToContents(0);
|
||||||
@@ -360,7 +362,7 @@ void AdvancedSettings::loadAdvancedSettings()
|
|||||||
outgoing_ports_max.setValue(session->outgoingPortsMax());
|
outgoing_ports_max.setValue(session->outgoingPortsMax());
|
||||||
addRow(OUTGOING_PORT_MAX, tr("Outgoing ports (Max) [0: Disabled]"), &outgoing_ports_max);
|
addRow(OUTGOING_PORT_MAX, tr("Outgoing ports (Max) [0: Disabled]"), &outgoing_ports_max);
|
||||||
// uTP-TCP mixed mode
|
// uTP-TCP mixed mode
|
||||||
comboUtpMixedMode.addItems({"Prefer TCP", "Peer proportional (throttles TCP)"});
|
comboUtpMixedMode.addItems({tr("Prefer TCP"), tr("Peer proportional (throttles TCP)")});
|
||||||
comboUtpMixedMode.setCurrentIndex(static_cast<int>(session->utpMixedMode()));
|
comboUtpMixedMode.setCurrentIndex(static_cast<int>(session->utpMixedMode()));
|
||||||
addRow(UTP_MIX_MODE, tr("%1-TCP mixed mode algorithm", "uTP-TCP mixed mode algorithm").arg(C_UTP), &comboUtpMixedMode);
|
addRow(UTP_MIX_MODE, tr("%1-TCP mixed mode algorithm", "uTP-TCP mixed mode algorithm").arg(C_UTP), &comboUtpMixedMode);
|
||||||
// multiple connections per IP
|
// multiple connections per IP
|
||||||
@@ -447,11 +449,11 @@ void AdvancedSettings::loadAdvancedSettings()
|
|||||||
spin_tracker_port.setValue(pref->getTrackerPort());
|
spin_tracker_port.setValue(pref->getTrackerPort());
|
||||||
addRow(TRACKER_PORT, tr("Embedded tracker port"), &spin_tracker_port);
|
addRow(TRACKER_PORT, tr("Embedded tracker port"), &spin_tracker_port);
|
||||||
// Choking algorithm
|
// Choking algorithm
|
||||||
comboChokingAlgorithm.addItems({"Fixed slots", "Upload rate based"});
|
comboChokingAlgorithm.addItems({tr("Fixed slots"), tr("Upload rate based")});
|
||||||
comboChokingAlgorithm.setCurrentIndex(static_cast<int>(session->chokingAlgorithm()));
|
comboChokingAlgorithm.setCurrentIndex(static_cast<int>(session->chokingAlgorithm()));
|
||||||
addRow(CHOKING_ALGORITHM, tr("Upload slots behavior"), &comboChokingAlgorithm);
|
addRow(CHOKING_ALGORITHM, tr("Upload slots behavior"), &comboChokingAlgorithm);
|
||||||
// Seed choking algorithm
|
// Seed choking algorithm
|
||||||
comboSeedChokingAlgorithm.addItems({"Round-robin", "Fastest upload", "Anti-leech"});
|
comboSeedChokingAlgorithm.addItems({tr("Round-robin"), tr("Fastest upload"), tr("Anti-leech")});
|
||||||
comboSeedChokingAlgorithm.setCurrentIndex(static_cast<int>(session->seedChokingAlgorithm()));
|
comboSeedChokingAlgorithm.setCurrentIndex(static_cast<int>(session->seedChokingAlgorithm()));
|
||||||
addRow(SEED_CHOKING_ALGORITHM, tr("Upload choking algorithm"), &comboSeedChokingAlgorithm);
|
addRow(SEED_CHOKING_ALGORITHM, tr("Upload choking algorithm"), &comboSeedChokingAlgorithm);
|
||||||
|
|
||||||
|
|||||||
@@ -48,7 +48,7 @@ public:
|
|||||||
|
|
||||||
static QString getText(QWidget *parent, const QString &title, const QString &label,
|
static QString getText(QWidget *parent, const QString &title, const QString &label,
|
||||||
QLineEdit::EchoMode mode = QLineEdit::Normal, const QString &text = QString(),
|
QLineEdit::EchoMode mode = QLineEdit::Normal, const QString &text = QString(),
|
||||||
bool *ok = 0, Qt::InputMethodHints inputMethodHints = Qt::ImhNone);
|
bool *ok = nullptr, Qt::InputMethodHints inputMethodHints = Qt::ImhNone);
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
void showEvent(QShowEvent *e);
|
void showEvent(QShowEvent *e);
|
||||||
|
|||||||
@@ -174,17 +174,15 @@ CategoryFilterModel::CategoryFilterModel(QObject *parent)
|
|||||||
: QAbstractItemModel(parent)
|
: QAbstractItemModel(parent)
|
||||||
, m_rootItem(new CategoryModelItem)
|
, m_rootItem(new CategoryModelItem)
|
||||||
{
|
{
|
||||||
auto session = BitTorrent::Session::instance();
|
using namespace BitTorrent;
|
||||||
|
auto session = Session::instance();
|
||||||
|
|
||||||
connect(session, SIGNAL(categoryAdded(QString)), SLOT(categoryAdded(QString)));
|
connect(session, &Session::categoryAdded, this, &CategoryFilterModel::categoryAdded);
|
||||||
connect(session, SIGNAL(categoryRemoved(QString)), SLOT(categoryRemoved(QString)));
|
connect(session, &Session::categoryRemoved, this, &CategoryFilterModel::categoryRemoved);
|
||||||
connect(session, SIGNAL(torrentCategoryChanged(BitTorrent::TorrentHandle *const, QString))
|
connect(session, &Session::torrentCategoryChanged, this, &CategoryFilterModel::torrentCategoryChanged);
|
||||||
, SLOT(torrentCategoryChanged(BitTorrent::TorrentHandle *const, QString)));
|
connect(session, &Session::subcategoriesSupportChanged, this, &CategoryFilterModel::subcategoriesSupportChanged);
|
||||||
connect(session, SIGNAL(subcategoriesSupportChanged()), SLOT(subcategoriesSupportChanged()));
|
connect(session, &Session::torrentAdded, this, &CategoryFilterModel::torrentAdded);
|
||||||
connect(session, SIGNAL(torrentAdded(BitTorrent::TorrentHandle *const))
|
connect(session, &Session::torrentAboutToBeRemoved, this, &CategoryFilterModel::torrentAboutToBeRemoved);
|
||||||
, SLOT(torrentAdded(BitTorrent::TorrentHandle *const)));
|
|
||||||
connect(session, SIGNAL(torrentAboutToBeRemoved(BitTorrent::TorrentHandle *const))
|
|
||||||
, SLOT(torrentAboutToBeRemoved(BitTorrent::TorrentHandle *const)));
|
|
||||||
|
|
||||||
populate();
|
populate();
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -37,7 +37,7 @@
|
|||||||
#include "ui_cookiesdialog.h"
|
#include "ui_cookiesdialog.h"
|
||||||
#include "utils.h"
|
#include "utils.h"
|
||||||
|
|
||||||
#define SETTINGS_KEY(name) "CookiesDialog/" name
|
#define SETTINGS_KEY(name) QStringLiteral("CookiesDialog/" name)
|
||||||
const QString KEY_SIZE = SETTINGS_KEY("Size");
|
const QString KEY_SIZE = SETTINGS_KEY("Size");
|
||||||
const QString KEY_COOKIESVIEWSTATE = SETTINGS_KEY("CookiesViewState");
|
const QString KEY_COOKIESVIEWSTATE = SETTINGS_KEY("CookiesViewState");
|
||||||
|
|
||||||
|
|||||||
@@ -59,7 +59,7 @@ class DeletionConfirmationDlg : public QDialog, private Ui::confirmDeletionDlg {
|
|||||||
rememberBtn->setIconSize(Utils::Gui::mediumIconSize());
|
rememberBtn->setIconSize(Utils::Gui::mediumIconSize());
|
||||||
|
|
||||||
checkPermDelete->setChecked(defaultDeleteFiles || Preferences::instance()->deleteTorrentFilesAsDefault());
|
checkPermDelete->setChecked(defaultDeleteFiles || Preferences::instance()->deleteTorrentFilesAsDefault());
|
||||||
connect(checkPermDelete, SIGNAL(clicked()), this, SLOT(updateRememberButtonState()));
|
connect(checkPermDelete, &QCheckBox::clicked, this, &DeletionConfirmationDlg::updateRememberButtonState);
|
||||||
buttonBox->button(QDialogButtonBox::Cancel)->setFocus();
|
buttonBox->button(QDialogButtonBox::Cancel)->setFocus();
|
||||||
|
|
||||||
Utils::Gui::resize(this);
|
Utils::Gui::resize(this);
|
||||||
|
|||||||
@@ -59,8 +59,8 @@ ExecutionLog::ExecutionLog(QWidget *parent, const Log::MsgTypes &types)
|
|||||||
addLogMessage(msg);
|
addLogMessage(msg);
|
||||||
foreach (const Log::Peer& peer, logger->getPeers())
|
foreach (const Log::Peer& peer, logger->getPeers())
|
||||||
addPeerMessage(peer);
|
addPeerMessage(peer);
|
||||||
connect(logger, SIGNAL(newLogMessage(const Log::Msg &)), SLOT(addLogMessage(const Log::Msg &)));
|
connect(logger, &Logger::newLogMessage, this, &ExecutionLog::addLogMessage);
|
||||||
connect(logger, SIGNAL(newLogPeer(const Log::Peer &)), SLOT(addPeerMessage(const Log::Peer &)));
|
connect(logger, &Logger::newLogPeer, this, &ExecutionLog::addPeerMessage);
|
||||||
}
|
}
|
||||||
|
|
||||||
ExecutionLog::~ExecutionLog()
|
ExecutionLog::~ExecutionLog()
|
||||||
|
|||||||
@@ -41,7 +41,6 @@
|
|||||||
|
|
||||||
namespace
|
namespace
|
||||||
{
|
{
|
||||||
const char i18nContext[] = "FileSystemPathEdit";
|
|
||||||
struct TrStringWithComment
|
struct TrStringWithComment
|
||||||
{
|
{
|
||||||
const char *source;
|
const char *source;
|
||||||
@@ -49,18 +48,18 @@ namespace
|
|||||||
|
|
||||||
QString tr() const
|
QString tr() const
|
||||||
{
|
{
|
||||||
return QCoreApplication::translate(i18nContext, source, comment);
|
return QCoreApplication::translate("FileSystemPathEdit", source, comment);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
constexpr TrStringWithComment browseButtonBriefText =
|
constexpr TrStringWithComment browseButtonBriefText =
|
||||||
QT_TRANSLATE_NOOP3(i18nContext, "...", "Launch file dialog button text (brief)");
|
QT_TRANSLATE_NOOP3("FileSystemPathEdit", "...", "Launch file dialog button text (brief)");
|
||||||
constexpr TrStringWithComment browseButtonFullText =
|
constexpr TrStringWithComment browseButtonFullText =
|
||||||
QT_TRANSLATE_NOOP3(i18nContext, "&Browse...", "Launch file dialog button text (full)");
|
QT_TRANSLATE_NOOP3("FileSystemPathEdit", "&Browse...", "Launch file dialog button text (full)");
|
||||||
constexpr TrStringWithComment defaultDialogCaptionForFile =
|
constexpr TrStringWithComment defaultDialogCaptionForFile =
|
||||||
QT_TRANSLATE_NOOP3(i18nContext, "Choose a file", "Caption for file open/save dialog");
|
QT_TRANSLATE_NOOP3("FileSystemPathEdit", "Choose a file", "Caption for file open/save dialog");
|
||||||
constexpr TrStringWithComment defaultDialogCaptionForDirectory =
|
constexpr TrStringWithComment defaultDialogCaptionForDirectory =
|
||||||
QT_TRANSLATE_NOOP3(i18nContext, "Choose a folder", "Caption for directory open dialog");
|
QT_TRANSLATE_NOOP3("FileSystemPathEdit", "Choose a folder", "Caption for directory open dialog");
|
||||||
}
|
}
|
||||||
|
|
||||||
class FileSystemPathEdit::FileSystemPathEditPrivate
|
class FileSystemPathEdit::FileSystemPathEditPrivate
|
||||||
|
|||||||
@@ -40,7 +40,7 @@ GuiIconProvider::GuiIconProvider(QObject *parent)
|
|||||||
: IconProvider(parent)
|
: IconProvider(parent)
|
||||||
{
|
{
|
||||||
configure();
|
configure();
|
||||||
connect(Preferences::instance(), SIGNAL(changed()), SLOT(configure()));
|
connect(Preferences::instance(), &Preferences::changed, this, &GuiIconProvider::configure);
|
||||||
}
|
}
|
||||||
|
|
||||||
GuiIconProvider::~GuiIconProvider() = default;
|
GuiIconProvider::~GuiIconProvider() = default;
|
||||||
|
|||||||
@@ -52,7 +52,7 @@ private slots:
|
|||||||
void configure();
|
void configure();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
explicit GuiIconProvider(QObject *parent = 0);
|
explicit GuiIconProvider(QObject *parent = nullptr);
|
||||||
~GuiIconProvider();
|
~GuiIconProvider();
|
||||||
#if (defined(Q_OS_UNIX) && !defined(Q_OS_MAC))
|
#if (defined(Q_OS_UNIX) && !defined(Q_OS_MAC))
|
||||||
QIcon generateDifferentSizes(const QIcon &icon);
|
QIcon generateDifferentSizes(const QIcon &icon);
|
||||||
|
|||||||
@@ -41,7 +41,7 @@
|
|||||||
class HidableTabWidget : public QTabWidget
|
class HidableTabWidget : public QTabWidget
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
explicit HidableTabWidget(QWidget *parent = 0)
|
explicit HidableTabWidget(QWidget *parent = nullptr)
|
||||||
: QTabWidget(parent)
|
: QTabWidget(parent)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -47,8 +47,8 @@ LogListWidget::LogListWidget(int maxLines, const Log::MsgTypes &types, QWidget *
|
|||||||
// Context menu
|
// Context menu
|
||||||
QAction *copyAct = new QAction(GuiIconProvider::instance()->getIcon("edit-copy"), tr("Copy"), this);
|
QAction *copyAct = new QAction(GuiIconProvider::instance()->getIcon("edit-copy"), tr("Copy"), this);
|
||||||
QAction *clearAct = new QAction(GuiIconProvider::instance()->getIcon("edit-clear"), tr("Clear"), this);
|
QAction *clearAct = new QAction(GuiIconProvider::instance()->getIcon("edit-clear"), tr("Clear"), this);
|
||||||
connect(copyAct, SIGNAL(triggered()), SLOT(copySelection()));
|
connect(copyAct, &QAction::triggered, this, &LogListWidget::copySelection);
|
||||||
connect(clearAct, SIGNAL(triggered()), SLOT(clear()));
|
connect(clearAct, &QAction::triggered, this, &LogListWidget::clear);
|
||||||
addAction(copyAct);
|
addAction(copyAct);
|
||||||
addAction(clearAct);
|
addAction(clearAct);
|
||||||
setContextMenuPolicy(Qt::ActionsContextMenu);
|
setContextMenuPolicy(Qt::ActionsContextMenu);
|
||||||
|
|||||||
@@ -43,7 +43,7 @@ class LogListWidget: public QListWidget
|
|||||||
|
|
||||||
public:
|
public:
|
||||||
// -1 is the portable way to have all the bits set
|
// -1 is the portable way to have all the bits set
|
||||||
explicit LogListWidget(int maxLines, const Log::MsgTypes &types = Log::ALL, QWidget *parent = 0);
|
explicit LogListWidget(int maxLines, const Log::MsgTypes &types = Log::ALL, QWidget *parent = nullptr);
|
||||||
void showMsgTypes(const Log::MsgTypes &types);
|
void showMsgTypes(const Log::MsgTypes &types);
|
||||||
|
|
||||||
public slots:
|
public slots:
|
||||||
|
|||||||
@@ -121,12 +121,12 @@ namespace
|
|||||||
#define SETTINGS_KEY(name) "GUI/" name
|
#define SETTINGS_KEY(name) "GUI/" name
|
||||||
|
|
||||||
// ExecutionLog properties keys
|
// ExecutionLog properties keys
|
||||||
#define EXECUTIONLOG_SETTINGS_KEY(name) SETTINGS_KEY("Log/") name
|
#define EXECUTIONLOG_SETTINGS_KEY(name) QStringLiteral(SETTINGS_KEY("Log/") name)
|
||||||
const QString KEY_EXECUTIONLOG_ENABLED = EXECUTIONLOG_SETTINGS_KEY("Enabled");
|
const QString KEY_EXECUTIONLOG_ENABLED = EXECUTIONLOG_SETTINGS_KEY("Enabled");
|
||||||
const QString KEY_EXECUTIONLOG_TYPES = EXECUTIONLOG_SETTINGS_KEY("Types");
|
const QString KEY_EXECUTIONLOG_TYPES = EXECUTIONLOG_SETTINGS_KEY("Types");
|
||||||
|
|
||||||
// Notifications properties keys
|
// Notifications properties keys
|
||||||
#define NOTIFICATIONS_SETTINGS_KEY(name) SETTINGS_KEY("Notifications/") name
|
#define NOTIFICATIONS_SETTINGS_KEY(name) QStringLiteral(SETTINGS_KEY("Notifications/") name)
|
||||||
const QString KEY_NOTIFICATIONS_ENABLED = NOTIFICATIONS_SETTINGS_KEY("Enabled");
|
const QString KEY_NOTIFICATIONS_ENABLED = NOTIFICATIONS_SETTINGS_KEY("Enabled");
|
||||||
const QString KEY_NOTIFICATIONS_TORRENTADDED = NOTIFICATIONS_SETTINGS_KEY("TorrentAdded");
|
const QString KEY_NOTIFICATIONS_TORRENTADDED = NOTIFICATIONS_SETTINGS_KEY("TorrentAdded");
|
||||||
|
|
||||||
@@ -160,11 +160,13 @@ MainWindow::MainWindow(QWidget *parent)
|
|||||||
// Setting icons
|
// Setting icons
|
||||||
#ifndef Q_OS_MAC
|
#ifndef Q_OS_MAC
|
||||||
#ifdef Q_OS_UNIX
|
#ifdef Q_OS_UNIX
|
||||||
if (Preferences::instance()->useSystemIconTheme())
|
const QIcon appLogo = Preferences::instance()->useSystemIconTheme()
|
||||||
setWindowIcon(QIcon::fromTheme("qbittorrent", QIcon(":/icons/skin/qbittorrent32.png")));
|
? QIcon::fromTheme("qbittorrent", QIcon(":/icons/skin/qbittorrent-tray.svg"))
|
||||||
else
|
: QIcon(":/icons/skin/qbittorrent-tray.svg");
|
||||||
|
#else
|
||||||
|
const QIcon appLogo(":/icons/skin/qbittorrent-tray.svg");
|
||||||
#endif // Q_OS_UNIX
|
#endif // Q_OS_UNIX
|
||||||
setWindowIcon(QIcon(":/icons/skin/qbittorrent32.png"));
|
setWindowIcon(appLogo);
|
||||||
#endif // Q_OS_MAC
|
#endif // Q_OS_MAC
|
||||||
|
|
||||||
#if (defined(Q_OS_UNIX))
|
#if (defined(Q_OS_UNIX))
|
||||||
@@ -375,7 +377,7 @@ MainWindow::MainWindow(QWidget *parent)
|
|||||||
on_actionWarningMessages_triggered(m_ui->actionWarningMessages->isChecked());
|
on_actionWarningMessages_triggered(m_ui->actionWarningMessages->isChecked());
|
||||||
on_actionCriticalMessages_triggered(m_ui->actionCriticalMessages->isChecked());
|
on_actionCriticalMessages_triggered(m_ui->actionCriticalMessages->isChecked());
|
||||||
if (m_ui->actionSearchWidget->isChecked())
|
if (m_ui->actionSearchWidget->isChecked())
|
||||||
QTimer::singleShot(0, this, SLOT(on_actionSearchWidget_triggered()));
|
QTimer::singleShot(0, this, &MainWindow::on_actionSearchWidget_triggered);
|
||||||
|
|
||||||
// Auto shutdown actions
|
// Auto shutdown actions
|
||||||
QActionGroup *autoShutdownGroup = new QActionGroup(this);
|
QActionGroup *autoShutdownGroup = new QActionGroup(this);
|
||||||
@@ -1047,7 +1049,7 @@ void MainWindow::notifyOfUpdate(QString)
|
|||||||
, Log::CRITICAL);
|
, Log::CRITICAL);
|
||||||
// Delete the executable watcher
|
// Delete the executable watcher
|
||||||
delete m_executableWatcher;
|
delete m_executableWatcher;
|
||||||
m_executableWatcher = 0;
|
m_executableWatcher = nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifndef Q_OS_MAC
|
#ifndef Q_OS_MAC
|
||||||
@@ -1213,7 +1215,7 @@ bool MainWindow::event(QEvent *e)
|
|||||||
if (!hasModalWindow) {
|
if (!hasModalWindow) {
|
||||||
qDebug("Minimize to Tray enabled, hiding!");
|
qDebug("Minimize to Tray enabled, hiding!");
|
||||||
e->ignore();
|
e->ignore();
|
||||||
QTimer::singleShot(0, this, SLOT(hide()));
|
QTimer::singleShot(0, this, &QWidget::hide);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -75,7 +75,7 @@ class MainWindow: public QMainWindow
|
|||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
|
|
||||||
public:
|
public:
|
||||||
explicit MainWindow(QWidget *parent = 0);
|
explicit MainWindow(QWidget *parent = nullptr);
|
||||||
~MainWindow() override;
|
~MainWindow() override;
|
||||||
|
|
||||||
QWidget *currentTabWidget() const;
|
QWidget *currentTabWidget() const;
|
||||||
|
|||||||
@@ -38,7 +38,7 @@ class MessageBoxRaised : public QMessageBox
|
|||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
|
|
||||||
private:
|
private:
|
||||||
MessageBoxRaised(QMessageBox::Icon icon, const QString &title, const QString &text, QMessageBox::StandardButtons buttons = NoButton, QWidget *parent = 0, Qt::WindowFlags f = Qt::Dialog|Qt::MSWindowsFixedSizeDialogHint);
|
MessageBoxRaised(QMessageBox::Icon icon, const QString &title, const QString &text, QMessageBox::StandardButtons buttons = NoButton, QWidget *parent = nullptr, Qt::WindowFlags f = Qt::Dialog|Qt::MSWindowsFixedSizeDialogHint);
|
||||||
MessageBoxRaised();
|
MessageBoxRaised();
|
||||||
MessageBoxRaised(MessageBoxRaised const&);
|
MessageBoxRaised(MessageBoxRaised const&);
|
||||||
void operator=(MessageBoxRaised const&);
|
void operator=(MessageBoxRaised const&);
|
||||||
|
|||||||
@@ -626,7 +626,7 @@ void OptionsDialog::saveOptions()
|
|||||||
session->setAltGlobalUploadSpeedLimit(alt_down_up_limit.second);
|
session->setAltGlobalUploadSpeedLimit(alt_down_up_limit.second);
|
||||||
pref->setSchedulerStartTime(m_ui->schedule_from->time());
|
pref->setSchedulerStartTime(m_ui->schedule_from->time());
|
||||||
pref->setSchedulerEndTime(m_ui->schedule_to->time());
|
pref->setSchedulerEndTime(m_ui->schedule_to->time());
|
||||||
pref->setSchedulerDays(static_cast<scheduler_days>(m_ui->schedule_days->currentIndex()));
|
pref->setSchedulerDays(static_cast<SchedulerDays>(m_ui->schedule_days->currentIndex()));
|
||||||
session->setBandwidthSchedulerEnabled(m_ui->check_schedule->isChecked());
|
session->setBandwidthSchedulerEnabled(m_ui->check_schedule->isChecked());
|
||||||
|
|
||||||
auto proxyConfigManager = Net::ProxyConfigurationManager::instance();
|
auto proxyConfigManager = Net::ProxyConfigurationManager::instance();
|
||||||
|
|||||||
@@ -77,7 +77,7 @@ private:
|
|||||||
|
|
||||||
public:
|
public:
|
||||||
// Constructor / Destructor
|
// Constructor / Destructor
|
||||||
OptionsDialog(QWidget *parent = 0);
|
OptionsDialog(QWidget *parent = nullptr);
|
||||||
~OptionsDialog();
|
~OptionsDialog();
|
||||||
|
|
||||||
public slots:
|
public slots:
|
||||||
|
|||||||
@@ -48,7 +48,7 @@ class PowerManagement : public QObject
|
|||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
|
|
||||||
public:
|
public:
|
||||||
PowerManagement(QObject *parent = 0);
|
PowerManagement(QObject *parent = nullptr);
|
||||||
virtual ~PowerManagement();
|
virtual ~PowerManagement();
|
||||||
|
|
||||||
void setActivityState(bool busy);
|
void setActivityState(bool busy);
|
||||||
|
|||||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user