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