mirror of
https://github.com/qbittorrent/qBittorrent.git
synced 2025-12-23 08:48:07 -06:00
Compare commits
42 Commits
release-4.
...
release-4.
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
50f676c305 | ||
|
|
7103ae73cd | ||
|
|
7d4b8b010f | ||
|
|
09bf033226 | ||
|
|
4e62608802 | ||
|
|
37b29bf91a | ||
|
|
d67037136b | ||
|
|
73292137b7 | ||
|
|
56f7a4e803 | ||
|
|
1cea6a25af | ||
|
|
ebc704ef14 | ||
|
|
a2a1a78f44 | ||
|
|
3a54d574b0 | ||
|
|
d0be71c225 | ||
|
|
7c04b4acd8 | ||
|
|
eda3747c08 | ||
|
|
7d23ea1f80 | ||
|
|
698ee94d0b | ||
|
|
65d1b588d9 | ||
|
|
eea693979a | ||
|
|
654bf85a71 | ||
|
|
8706a7c973 | ||
|
|
439a2ef597 | ||
|
|
c5a7aa7668 | ||
|
|
e5bf83a594 | ||
|
|
2a3e64933b | ||
|
|
35f8af32a3 | ||
|
|
37354a9e29 | ||
|
|
7cb14e2a5b | ||
|
|
4aae7266a5 | ||
|
|
075245c915 | ||
|
|
476707cc80 | ||
|
|
7b0b5e3d7f | ||
|
|
4142722303 | ||
|
|
8ebb11f981 | ||
|
|
80016db781 | ||
|
|
a9f43bd5d2 | ||
|
|
2f0c3f047a | ||
|
|
f40a36ecb3 | ||
|
|
a1ee1c0448 | ||
|
|
939f83bdd5 | ||
|
|
e98a887286 |
16
.travis.yml
16
.travis.yml
@@ -55,14 +55,13 @@ addons:
|
||||
apt:
|
||||
sources:
|
||||
# sources list: https://github.com/travis-ci/apt-source-safelist/blob/master/ubuntu.json
|
||||
- sourceline: 'ppa:qbittorrent-team/qbittorrent-stable'
|
||||
- sourceline: 'ppa:qbittorrent-team/qbt-libtorrent-travisci'
|
||||
- sourceline: 'ppa:beineri/opt-qt59-xenial'
|
||||
packages:
|
||||
# packages list: https://github.com/travis-ci/apt-package-safelist/blob/master/ubuntu-trusty
|
||||
- [autoconf, automake, colormake]
|
||||
- [libboost-dev, libboost-system-dev]
|
||||
- libssl-dev
|
||||
- libtorrent-rasterbar-dev
|
||||
- [qt59base, qt59svg, qt59tools]
|
||||
- zlib1g-dev
|
||||
# required for Qt 5.9 from 'beineri' PPA
|
||||
@@ -132,7 +131,7 @@ install:
|
||||
ccache -V && ccache --show-stats && ccache --zero-stats
|
||||
fi
|
||||
- |
|
||||
if [ "$libt_branch" = "RC_1_2" ] && [ "$TRAVIS_OS_NAME" = "linux" ]; then
|
||||
if [ "$libt_branch" = "RC_1_1" ] && [ "$TRAVIS_OS_NAME" = "linux" ]; then
|
||||
wget https://builds.shiki.hu/travis/deb/version
|
||||
if ! cmp --quiet "version" "$HOME/travis/deb/version" ; then
|
||||
echo "Cached files are different from server. Downloading new ones."
|
||||
@@ -141,11 +140,16 @@ install:
|
||||
mkdir "$HOME/travis/deb"
|
||||
cp "version" $HOME/travis/deb
|
||||
cd "$HOME/travis/deb"
|
||||
wget https://builds.shiki.hu/travis/deb/libtorrent-rasterbar-dev_1.2.x_amd64.deb
|
||||
wget https://builds.shiki.hu/travis/deb/libtorrent-rasterbar10_1.2.x_amd64.deb
|
||||
wget https://builds.shiki.hu/travis/deb/libtorrent-rasterbar-dev_1.1.x_amd64.deb
|
||||
wget https://builds.shiki.hu/travis/deb/libtorrent-rasterbar9_1.1.x_amd64.deb
|
||||
fi
|
||||
|
||||
sudo dpkg -i "$HOME/travis/deb/libtorrent-rasterbar-dev_1.2.x_amd64.deb" "$HOME/travis/deb/libtorrent-rasterbar10_1.2.x_amd64.deb"
|
||||
sudo dpkg -i "$HOME/travis/deb/libtorrent-rasterbar-dev_1.1.x_amd64.deb" "$HOME/travis/deb/libtorrent-rasterbar9_1.1.x_amd64.deb"
|
||||
fi
|
||||
- |
|
||||
if [ "$libt_branch" = "RC_1_2" ] && [ "$TRAVIS_OS_NAME" = "linux" ]; then
|
||||
# Will install latest 1.2.x daily build from the PPA
|
||||
sudo apt-get -y install libtorrent-rasterbar-dev
|
||||
fi
|
||||
- |
|
||||
if [ "$libt_branch" = "RC_1_1" ] && [ "$TRAVIS_OS_NAME" = "osx" ]; then
|
||||
|
||||
20
Changelog
20
Changelog
@@ -1,3 +1,23 @@
|
||||
Wed Apr 22 2020 - sledgehammer999 <sledgehammer999@qbittorrent.org> - v4.2.4
|
||||
- BUGFIX: Fix sub-sorting of Transfer list (glassez)
|
||||
- BUGFIX: Fix wrong logic that disables "prevent sleeping" timer (Chocobo1)
|
||||
- BUGFIX: Set disk cache size for older libtorrent versions (NotTsunami)
|
||||
- BUGFIX: Sort locale language list (Chocobo1)
|
||||
- BUGFIX: Remove white outline around mascot.png (adem)
|
||||
- BUGFIX: Various fixes in configuring the chosen network interface and not leaking the IP (Raif Atef, an0n666)
|
||||
- BUGFIX: Save "resume data" when torrent storage is moved (glassez)
|
||||
- BUGFIX: Avoid holding encoded resume data in memory (Chocobo1)
|
||||
- BUGFIX: Fix date format for "Last seen complete" (Chocobo1)
|
||||
- BUGFIX: Remove deprecated strict super seeding mode from advanced settings (an0n666)
|
||||
- BUGFIX: Change default stop_tracker_timeout settings (an0n666)
|
||||
- BUGFIX: Convert the Log widget to use custom View/Model (jagannatharjun)
|
||||
- BUGFIX: Change default upload slot choking limits (an0n666)
|
||||
- BUGFIX: Don't uncheck Authentication checkbox when changing proxy type (thalieht)
|
||||
- BUGFIX: Reduce ambiguity for selecting tray icons (Chocobo1)
|
||||
- WEBUI: Fix unable to add multiple peers in WebUI (Sepro)
|
||||
- WEBUI: Fix UPnP lease duration get/set (NotTsunami)
|
||||
- SEARCH: Detect python3 executable on Windows (József Sallai)
|
||||
|
||||
Wed Apr 01 2020 - sledgehammer999 <sledgehammer999@qbittorrent.org> - v4.2.3
|
||||
- FEATURE: Add logging for SOCKS5 proxy errors (Chocobo1)
|
||||
- FEATURE: Add UPnP lease duration advanced option (NotTsunami)
|
||||
|
||||
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.2.3.
|
||||
# Generated by GNU Autoconf 2.69 for qbittorrent v4.2.4.
|
||||
#
|
||||
# Report bugs to <bugs.qbittorrent.org>.
|
||||
#
|
||||
@@ -580,8 +580,8 @@ MAKEFLAGS=
|
||||
# Identity of this package.
|
||||
PACKAGE_NAME='qbittorrent'
|
||||
PACKAGE_TARNAME='qbittorrent'
|
||||
PACKAGE_VERSION='v4.2.3'
|
||||
PACKAGE_STRING='qbittorrent v4.2.3'
|
||||
PACKAGE_VERSION='v4.2.4'
|
||||
PACKAGE_STRING='qbittorrent v4.2.4'
|
||||
PACKAGE_BUGREPORT='bugs.qbittorrent.org'
|
||||
PACKAGE_URL='https://www.qbittorrent.org/'
|
||||
|
||||
@@ -1302,7 +1302,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.2.3 to adapt to many kinds of systems.
|
||||
\`configure' configures qbittorrent v4.2.4 to adapt to many kinds of systems.
|
||||
|
||||
Usage: $0 [OPTION]... [VAR=VALUE]...
|
||||
|
||||
@@ -1373,7 +1373,7 @@ fi
|
||||
|
||||
if test -n "$ac_init_help"; then
|
||||
case $ac_init_help in
|
||||
short | recursive ) echo "Configuration of qbittorrent v4.2.3:";;
|
||||
short | recursive ) echo "Configuration of qbittorrent v4.2.4:";;
|
||||
esac
|
||||
cat <<\_ACEOF
|
||||
|
||||
@@ -1509,7 +1509,7 @@ fi
|
||||
test -n "$ac_init_help" && exit $ac_status
|
||||
if $ac_init_version; then
|
||||
cat <<\_ACEOF
|
||||
qbittorrent configure v4.2.3
|
||||
qbittorrent configure v4.2.4
|
||||
generated by GNU Autoconf 2.69
|
||||
|
||||
Copyright (C) 2012 Free Software Foundation, Inc.
|
||||
@@ -1648,7 +1648,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.2.3, which was
|
||||
It was created by qbittorrent $as_me v4.2.4, which was
|
||||
generated by GNU Autoconf 2.69. Invocation command line was
|
||||
|
||||
$ $0 $@
|
||||
@@ -3826,7 +3826,7 @@ fi
|
||||
|
||||
# Define the identity of the package.
|
||||
PACKAGE='qbittorrent'
|
||||
VERSION='v4.2.3'
|
||||
VERSION='v4.2.4'
|
||||
|
||||
|
||||
cat >>confdefs.h <<_ACEOF
|
||||
@@ -6343,7 +6343,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.2.3, which was
|
||||
This file was extended by qbittorrent $as_me v4.2.4, which was
|
||||
generated by GNU Autoconf 2.69. Invocation command line was
|
||||
|
||||
CONFIG_FILES = $CONFIG_FILES
|
||||
@@ -6401,7 +6401,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.2.3
|
||||
qbittorrent config.status v4.2.4
|
||||
configured by $0, generated by GNU Autoconf 2.69,
|
||||
with options \\"\$ac_cs_config\\"
|
||||
|
||||
@@ -7659,7 +7659,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.2.3, which was
|
||||
This file was extended by qbittorrent $as_me v4.2.4, which was
|
||||
generated by GNU Autoconf 2.69. Invocation command line was
|
||||
|
||||
CONFIG_FILES = $CONFIG_FILES
|
||||
@@ -7717,7 +7717,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.2.3
|
||||
qbittorrent config.status v4.2.4
|
||||
configured by $0, generated by GNU Autoconf 2.69,
|
||||
with options \\"\$ac_cs_config\\"
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
AC_INIT([qbittorrent], [v4.2.3], [bugs.qbittorrent.org], [], [https://www.qbittorrent.org/])
|
||||
AC_INIT([qbittorrent], [v4.2.4], [bugs.qbittorrent.org], [], [https://www.qbittorrent.org/])
|
||||
AC_CONFIG_AUX_DIR([build-aux])
|
||||
AC_CONFIG_MACRO_DIR([m4])
|
||||
AC_PROG_CC
|
||||
|
||||
10
dist/mac/Info.plist
vendored
10
dist/mac/Info.plist
vendored
@@ -55,7 +55,7 @@
|
||||
<key>CFBundlePackageType</key>
|
||||
<string>APPL</string>
|
||||
<key>CFBundleShortVersionString</key>
|
||||
<string>4.2.3</string>
|
||||
<string>4.2.4</string>
|
||||
<key>CFBundleExecutable</key>
|
||||
<string>@EXECUTABLE@</string>
|
||||
<key>CFBundleIdentifier</key>
|
||||
@@ -88,13 +88,17 @@
|
||||
<key>UTTypeTagSpecification</key>
|
||||
<dict>
|
||||
<key>com.apple.ostype</key>
|
||||
<string>TORR</string>
|
||||
<array>
|
||||
<string>TORR</string>
|
||||
</array>
|
||||
<key>public.filename-extension</key>
|
||||
<array>
|
||||
<string>torrent</string>
|
||||
</array>
|
||||
<key>public.mime-type</key>
|
||||
<string>application/x-bittorrent</string>
|
||||
<array>
|
||||
<string>application/x-bittorrent</string>
|
||||
</array>
|
||||
</dict>
|
||||
</dict>
|
||||
</array>
|
||||
|
||||
@@ -74,6 +74,6 @@
|
||||
<url type="translate">https://github.com/qbittorrent/qBittorrent/wiki/How-to-translate-qBittorrent</url>
|
||||
<content_rating type="oars-1.1"/>
|
||||
<releases>
|
||||
<release version="4.2.3" date="2020-04-01"/>
|
||||
<release version="4.2.4" date="2020-04-20"/>
|
||||
</releases>
|
||||
</component>
|
||||
|
||||
2
dist/windows/options.nsi
vendored
2
dist/windows/options.nsi
vendored
@@ -28,7 +28,7 @@ XPStyle on
|
||||
!define CSIDL_LOCALAPPDATA '0x1C' ;Local Application Data path
|
||||
|
||||
; Program specific
|
||||
!define PROG_VERSION "4.2.3"
|
||||
!define PROG_VERSION "4.2.4"
|
||||
|
||||
!define MUI_FINISHPAGE_RUN
|
||||
!define MUI_FINISHPAGE_RUN_FUNCTION PageFinishRun
|
||||
|
||||
@@ -61,6 +61,7 @@
|
||||
#endif // Q_OS_MACOS
|
||||
#endif
|
||||
|
||||
#include "base/bittorrent/infohash.h"
|
||||
#include "base/bittorrent/session.h"
|
||||
#include "base/bittorrent/torrenthandle.h"
|
||||
#include "base/exceptions.h"
|
||||
@@ -133,6 +134,7 @@ Application::Application(int &argc, char **argv)
|
||||
, m_commandLineArgs(parseCommandLine(this->arguments()))
|
||||
{
|
||||
qRegisterMetaType<Log::Msg>("Log::Msg");
|
||||
qRegisterMetaType<Log::Peer>("Log::Peer");
|
||||
|
||||
setApplicationName("qBittorrent");
|
||||
setOrganizationDomain("qbittorrent.org");
|
||||
|
||||
@@ -68,7 +68,7 @@ namespace RSS
|
||||
class AutoDownloader;
|
||||
}
|
||||
|
||||
class Application : public BaseApplication
|
||||
class Application final : public BaseApplication
|
||||
{
|
||||
Q_OBJECT
|
||||
Q_DISABLE_COPY(Application)
|
||||
|
||||
@@ -77,7 +77,7 @@
|
||||
|
||||
namespace QtLP_Private
|
||||
{
|
||||
class QtLockedFile : public QFile
|
||||
class QtLockedFile final : public QFile
|
||||
{
|
||||
public:
|
||||
enum LockMode
|
||||
|
||||
@@ -22,6 +22,7 @@ bittorrent/session.h
|
||||
bittorrent/sessionstatus.h
|
||||
bittorrent/torrentcreatorthread.h
|
||||
bittorrent/torrenthandle.h
|
||||
bittorrent/torrenthandleimpl.h
|
||||
bittorrent/torrentinfo.h
|
||||
bittorrent/tracker.h
|
||||
bittorrent/trackerentry.h
|
||||
@@ -58,6 +59,7 @@ utils/bytearray.h
|
||||
utils/foreignapps.h
|
||||
utils/fs.h
|
||||
utils/gzip.h
|
||||
utils/io.h
|
||||
utils/misc.h
|
||||
utils/net.h
|
||||
utils/password.h
|
||||
@@ -99,6 +101,7 @@ bittorrent/private/statistics.cpp
|
||||
bittorrent/session.cpp
|
||||
bittorrent/torrentcreatorthread.cpp
|
||||
bittorrent/torrenthandle.cpp
|
||||
bittorrent/torrenthandleimpl.cpp
|
||||
bittorrent/torrentinfo.cpp
|
||||
bittorrent/tracker.cpp
|
||||
bittorrent/trackerentry.cpp
|
||||
@@ -133,6 +136,7 @@ utils/bytearray.cpp
|
||||
utils/foreignapps.cpp
|
||||
utils/fs.cpp
|
||||
utils/gzip.cpp
|
||||
utils/io.cpp
|
||||
utils/misc.cpp
|
||||
utils/net.cpp
|
||||
utils/password.cpp
|
||||
|
||||
@@ -21,6 +21,7 @@ HEADERS += \
|
||||
$$PWD/bittorrent/sessionstatus.h \
|
||||
$$PWD/bittorrent/torrentcreatorthread.h \
|
||||
$$PWD/bittorrent/torrenthandle.h \
|
||||
$$PWD/bittorrent/torrenthandleimpl.h \
|
||||
$$PWD/bittorrent/torrentinfo.h \
|
||||
$$PWD/bittorrent/tracker.h \
|
||||
$$PWD/bittorrent/trackerentry.h \
|
||||
@@ -73,6 +74,7 @@ HEADERS += \
|
||||
$$PWD/utils/foreignapps.h \
|
||||
$$PWD/utils/fs.h \
|
||||
$$PWD/utils/gzip.h \
|
||||
$$PWD/utils/io.h \
|
||||
$$PWD/utils/misc.h \
|
||||
$$PWD/utils/net.h \
|
||||
$$PWD/utils/password.h \
|
||||
@@ -98,6 +100,7 @@ SOURCES += \
|
||||
$$PWD/bittorrent/session.cpp \
|
||||
$$PWD/bittorrent/torrentcreatorthread.cpp \
|
||||
$$PWD/bittorrent/torrenthandle.cpp \
|
||||
$$PWD/bittorrent/torrenthandleimpl.cpp \
|
||||
$$PWD/bittorrent/torrentinfo.cpp \
|
||||
$$PWD/bittorrent/tracker.cpp \
|
||||
$$PWD/bittorrent/trackerentry.cpp \
|
||||
@@ -143,6 +146,7 @@ SOURCES += \
|
||||
$$PWD/utils/foreignapps.cpp \
|
||||
$$PWD/utils/fs.cpp \
|
||||
$$PWD/utils/gzip.cpp \
|
||||
$$PWD/utils/io.cpp \
|
||||
$$PWD/utils/misc.cpp \
|
||||
$$PWD/utils/net.cpp \
|
||||
$$PWD/utils/password.cpp \
|
||||
|
||||
@@ -28,6 +28,8 @@
|
||||
|
||||
#include "peerinfo.h"
|
||||
|
||||
#include <libtorrent/version.hpp>
|
||||
|
||||
#include <QBitArray>
|
||||
|
||||
#include "base/bittorrent/torrenthandle.h"
|
||||
|
||||
@@ -35,7 +35,7 @@
|
||||
|
||||
class QDataStream;
|
||||
|
||||
class FilterParserThread : public QThread
|
||||
class FilterParserThread final : public QThread
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
|
||||
@@ -31,7 +31,7 @@
|
||||
#include <libtorrent/extensions.hpp>
|
||||
#include <libtorrent/version.hpp>
|
||||
|
||||
class NativeSessionExtension : public lt::plugin
|
||||
class NativeSessionExtension final : public lt::plugin
|
||||
{
|
||||
#if (LIBTORRENT_VERSION_NUM >= 10200)
|
||||
lt::feature_flags_t implemented_features() override;
|
||||
|
||||
@@ -47,7 +47,7 @@ namespace
|
||||
#if (LIBTORRENT_VERSION_NUM < 10200)
|
||||
return torrentStatus.auto_managed;
|
||||
#else
|
||||
return bool {torrentStatus.flags & lt::torrent_flags::auto_managed};
|
||||
return static_cast<bool>(torrentStatus.flags & lt::torrent_flags::auto_managed);
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
@@ -32,7 +32,7 @@
|
||||
#include <libtorrent/torrent_handle.hpp>
|
||||
#include <libtorrent/version.hpp>
|
||||
|
||||
class NativeTorrentExtension : public lt::torrent_plugin
|
||||
class NativeTorrentExtension final : public lt::torrent_plugin
|
||||
{
|
||||
public:
|
||||
explicit NativeTorrentExtension(const lt::torrent_handle &torrentHandle);
|
||||
|
||||
@@ -44,7 +44,7 @@ using LTPortMapping = int;
|
||||
using LTPortMapping = lt::port_mapping_t;
|
||||
#endif
|
||||
|
||||
class PortForwarderImpl : public Net::PortForwarder
|
||||
class PortForwarderImpl final : public Net::PortForwarder
|
||||
{
|
||||
Q_OBJECT
|
||||
Q_DISABLE_COPY(PortForwarderImpl)
|
||||
|
||||
@@ -28,11 +28,15 @@
|
||||
|
||||
#include "resumedatasavingmanager.h"
|
||||
|
||||
#include <libtorrent/bencode.hpp>
|
||||
#include <libtorrent/entry.hpp>
|
||||
|
||||
#include <QByteArray>
|
||||
#include <QSaveFile>
|
||||
|
||||
#include "base/logger.h"
|
||||
#include "base/utils/fs.h"
|
||||
#include "base/utils/io.h"
|
||||
|
||||
ResumeDataSavingManager::ResumeDataSavingManager(const QString &resumeFolderPath)
|
||||
: m_resumeDataDir(resumeFolderPath)
|
||||
@@ -44,12 +48,27 @@ void ResumeDataSavingManager::save(const QString &filename, const QByteArray &da
|
||||
const QString filepath = m_resumeDataDir.absoluteFilePath(filename);
|
||||
|
||||
QSaveFile file {filepath};
|
||||
if (file.open(QIODevice::WriteOnly)) {
|
||||
file.write(data);
|
||||
if (!file.commit()) {
|
||||
Logger::instance()->addMessage(QString("Couldn't save data in '%1'. Error: %2")
|
||||
.arg(filepath, file.errorString()), Log::WARNING);
|
||||
}
|
||||
if (!file.open(QIODevice::WriteOnly) || (file.write(data) != data.size()) || !file.commit()) {
|
||||
LogMsg(tr("Couldn't save data to '%1'. Error: %2")
|
||||
.arg(filepath, file.errorString()), Log::CRITICAL);
|
||||
}
|
||||
}
|
||||
|
||||
void ResumeDataSavingManager::save(const QString &filename, const std::shared_ptr<lt::entry> &data) const
|
||||
{
|
||||
const QString filepath = m_resumeDataDir.absoluteFilePath(filename);
|
||||
|
||||
QSaveFile file {filepath};
|
||||
if (!file.open(QIODevice::WriteOnly)) {
|
||||
LogMsg(tr("Couldn't save data to '%1'. Error: %2")
|
||||
.arg(filepath, file.errorString()), Log::CRITICAL);
|
||||
return;
|
||||
}
|
||||
|
||||
lt::bencode(Utils::IO::FileDeviceOutputIterator {file}, *data);
|
||||
if ((file.error() != QFileDevice::NoError) || !file.commit()) {
|
||||
LogMsg(tr("Couldn't save data to '%1'. Error: %2")
|
||||
.arg(filepath, file.errorString()), Log::CRITICAL);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -28,6 +28,10 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <memory>
|
||||
|
||||
#include <libtorrent/fwd.hpp>
|
||||
|
||||
#include <QDir>
|
||||
#include <QObject>
|
||||
|
||||
@@ -43,8 +47,9 @@ public:
|
||||
|
||||
public slots:
|
||||
void save(const QString &filename, const QByteArray &data) const;
|
||||
void save(const QString &filename, const std::shared_ptr<lt::entry> &data) const;
|
||||
void remove(const QString &filename) const;
|
||||
|
||||
private:
|
||||
QDir m_resumeDataDir;
|
||||
const QDir m_resumeDataDir;
|
||||
};
|
||||
|
||||
@@ -40,25 +40,6 @@
|
||||
#include <iphlpapi.h>
|
||||
#endif
|
||||
|
||||
#include <QDebug>
|
||||
#include <QDir>
|
||||
#include <QFile>
|
||||
#include <QHostAddress>
|
||||
#include <QNetworkAddressEntry>
|
||||
#include <QNetworkConfigurationManager>
|
||||
#include <QNetworkInterface>
|
||||
#include <QRegularExpression>
|
||||
#include <QString>
|
||||
#include <QThread>
|
||||
#include <QTimer>
|
||||
#include <QUuid>
|
||||
|
||||
#ifdef Q_OS_WIN
|
||||
// TODO: Remove together with fixBrokenSavePath()
|
||||
#define NEED_TO_FIX_BROKEN_PATH
|
||||
#include <QSaveFile>
|
||||
#endif
|
||||
|
||||
#include <libtorrent/alert_types.hpp>
|
||||
#include <libtorrent/bdecode.hpp>
|
||||
#include <libtorrent/bencode.hpp>
|
||||
@@ -78,6 +59,25 @@
|
||||
#include <libtorrent/read_resume_data.hpp>
|
||||
#endif
|
||||
|
||||
#include <QDebug>
|
||||
#include <QDir>
|
||||
#include <QFile>
|
||||
#include <QHostAddress>
|
||||
#include <QNetworkAddressEntry>
|
||||
#include <QNetworkConfigurationManager>
|
||||
#include <QNetworkInterface>
|
||||
#include <QRegularExpression>
|
||||
#include <QString>
|
||||
#include <QThread>
|
||||
#include <QTimer>
|
||||
#include <QUuid>
|
||||
|
||||
#ifdef Q_OS_WIN
|
||||
// TODO: Remove together with fixBrokenSavePath()
|
||||
#define NEED_TO_FIX_BROKEN_PATH
|
||||
#include <QSaveFile>
|
||||
#endif
|
||||
|
||||
#include "base/algorithm.h"
|
||||
#include "base/exceptions.h"
|
||||
#include "base/global.h"
|
||||
@@ -101,7 +101,7 @@
|
||||
#include "private/portforwarderimpl.h"
|
||||
#include "private/resumedatasavingmanager.h"
|
||||
#include "private/statistics.h"
|
||||
#include "torrenthandle.h"
|
||||
#include "torrenthandleimpl.h"
|
||||
#include "tracker.h"
|
||||
#include "trackerentry.h"
|
||||
|
||||
@@ -438,7 +438,11 @@ Session::Session(QObject *parent)
|
||||
, m_asyncIOThreads(BITTORRENT_SESSION_KEY("AsyncIOThreadsCount"), 4)
|
||||
, m_filePoolSize(BITTORRENT_SESSION_KEY("FilePoolSize"), 40)
|
||||
, m_checkingMemUsage(BITTORRENT_SESSION_KEY("CheckingMemUsageSize"), 32)
|
||||
#if (LIBTORRENT_VERSION_NUM >= 10206)
|
||||
, m_diskCacheSize(BITTORRENT_SESSION_KEY("DiskCacheSize"), -1)
|
||||
#else
|
||||
, m_diskCacheSize(BITTORRENT_SESSION_KEY("DiskCacheSize"), 64)
|
||||
#endif
|
||||
, m_diskCacheTTL(BITTORRENT_SESSION_KEY("DiskCacheTTL"), 60)
|
||||
, m_useOSCache(BITTORRENT_SESSION_KEY("UseOSCache"), true)
|
||||
#ifdef Q_OS_WIN
|
||||
@@ -467,12 +471,15 @@ Session::Session(QObject *parent)
|
||||
, m_ignoreLimitsOnLAN(BITTORRENT_SESSION_KEY("IgnoreLimitsOnLAN"), false)
|
||||
, m_includeOverheadInLimits(BITTORRENT_SESSION_KEY("IncludeOverheadInLimits"), false)
|
||||
, m_announceIP(BITTORRENT_SESSION_KEY("AnnounceIP"))
|
||||
#if (LIBTORRENT_VERSION_NUM >= 10206)
|
||||
, m_stopTrackerTimeout(BITTORRENT_SESSION_KEY("StopTrackerTimeout"), 5)
|
||||
#else
|
||||
, m_stopTrackerTimeout(BITTORRENT_SESSION_KEY("StopTrackerTimeout"), 1)
|
||||
, m_isSuperSeedingEnabled(BITTORRENT_SESSION_KEY("SuperSeedingEnabled"), false)
|
||||
#endif
|
||||
, m_maxConnections(BITTORRENT_SESSION_KEY("MaxConnections"), 500, lowerLimited(0, -1))
|
||||
, m_maxUploads(BITTORRENT_SESSION_KEY("MaxUploads"), -1, lowerLimited(0, -1))
|
||||
, m_maxUploads(BITTORRENT_SESSION_KEY("MaxUploads"), 20, lowerLimited(0, -1))
|
||||
, m_maxConnectionsPerTorrent(BITTORRENT_SESSION_KEY("MaxConnectionsPerTorrent"), 100, lowerLimited(0, -1))
|
||||
, m_maxUploadsPerTorrent(BITTORRENT_SESSION_KEY("MaxUploadsPerTorrent"), -1, lowerLimited(0, -1))
|
||||
, m_maxUploadsPerTorrent(BITTORRENT_SESSION_KEY("MaxUploadsPerTorrent"), 4, lowerLimited(0, -1))
|
||||
, m_btProtocol(BITTORRENT_SESSION_KEY("BTProtocol"), BTProtocol::Both
|
||||
, clampValue(BTProtocol::Both, BTProtocol::UTP))
|
||||
, m_isUTPRateLimited(BITTORRENT_SESSION_KEY("uTPRateLimited"), true)
|
||||
@@ -657,7 +664,7 @@ void Session::setTempPathEnabled(const bool enabled)
|
||||
{
|
||||
if (enabled != isTempPathEnabled()) {
|
||||
m_isTempPathEnabled = enabled;
|
||||
for (TorrentHandle *const torrent : asConst(m_torrents))
|
||||
for (TorrentHandleImpl *const torrent : asConst(m_torrents))
|
||||
torrent->handleTempPathChanged();
|
||||
}
|
||||
}
|
||||
@@ -671,7 +678,7 @@ void Session::setAppendExtensionEnabled(const bool enabled)
|
||||
{
|
||||
if (isAppendExtensionEnabled() != enabled) {
|
||||
// append or remove .!qB extension for incomplete files
|
||||
for (TorrentHandle *const torrent : asConst(m_torrents))
|
||||
for (TorrentHandleImpl *const torrent : asConst(m_torrents))
|
||||
torrent->handleAppendExtensionToggled();
|
||||
|
||||
m_isAppendExtensionEnabled = enabled;
|
||||
@@ -822,12 +829,12 @@ bool Session::editCategory(const QString &name, const QString &savePath)
|
||||
m_categories[name] = savePath;
|
||||
m_storedCategories = map_cast(m_categories);
|
||||
if (isDisableAutoTMMWhenCategorySavePathChanged()) {
|
||||
for (TorrentHandle *const torrent : asConst(torrents()))
|
||||
for (TorrentHandleImpl *const torrent : asConst(m_torrents))
|
||||
if (torrent->category() == name)
|
||||
torrent->setAutoTMMEnabled(false);
|
||||
}
|
||||
else {
|
||||
for (TorrentHandle *const torrent : asConst(torrents()))
|
||||
for (TorrentHandleImpl *const torrent : asConst(m_torrents))
|
||||
if (torrent->category() == name)
|
||||
torrent->handleCategorySavePathChanged();
|
||||
}
|
||||
@@ -837,7 +844,7 @@ bool Session::editCategory(const QString &name, const QString &savePath)
|
||||
|
||||
bool Session::removeCategory(const QString &name)
|
||||
{
|
||||
for (TorrentHandle *const torrent : asConst(torrents()))
|
||||
for (TorrentHandleImpl *const torrent : asConst(m_torrents))
|
||||
if (torrent->belongsToCategory(name))
|
||||
torrent->setCategory("");
|
||||
|
||||
@@ -924,7 +931,7 @@ bool Session::addTag(const QString &tag)
|
||||
bool Session::removeTag(const QString &tag)
|
||||
{
|
||||
if (m_tags.remove(tag)) {
|
||||
for (TorrentHandle *const torrent : asConst(torrents()))
|
||||
for (TorrentHandleImpl *const torrent : asConst(m_torrents))
|
||||
torrent->removeTag(tag);
|
||||
m_storedTags = m_tags.values();
|
||||
emit tagRemoved(tag);
|
||||
@@ -1439,8 +1446,6 @@ void Session::loadLTSettings(lt::settings_pack &settingsPack)
|
||||
settingsPack.set_str(lt::settings_pack::announce_ip, announceIP().toStdString());
|
||||
// Stop tracker timeout
|
||||
settingsPack.set_int(lt::settings_pack::stop_tracker_timeout, stopTrackerTimeout());
|
||||
// Super seeding
|
||||
settingsPack.set_bool(lt::settings_pack::strict_super_seeding, isSuperSeedingEnabled());
|
||||
// * Max connections limit
|
||||
settingsPack.set_int(lt::settings_pack::connections_limit, maxConnections());
|
||||
// * Global max upload slots
|
||||
@@ -1529,10 +1534,13 @@ void Session::configureNetworkInterfaces(lt::settings_pack &settingsPack)
|
||||
for (const QString &ip : asConst(getListeningIPs())) {
|
||||
const QHostAddress addr {ip};
|
||||
if (!addr.isNull()) {
|
||||
endpoints << ((addr.protocol() == QAbstractSocket::IPv6Protocol)
|
||||
const QString ip = ((addr.protocol() == QAbstractSocket::IPv6Protocol)
|
||||
? ('[' + Utils::Net::canonicalIPv6Addr(addr).toString() + ']')
|
||||
: addr.toString())
|
||||
+ portString;
|
||||
: addr.toString());
|
||||
endpoints << (ip + portString);
|
||||
|
||||
if ((ip != "0.0.0.0") && (ip != "[::]"))
|
||||
outgoingInterfaces << ip;
|
||||
}
|
||||
else {
|
||||
// ip holds an interface name
|
||||
@@ -1547,6 +1555,10 @@ void Session::configureNetworkInterfaces(lt::settings_pack &settingsPack)
|
||||
}
|
||||
else {
|
||||
LogMsg(tr("Could not get GUID of network interface: %1").arg(ip) , Log::WARNING);
|
||||
// Since we can't get the GUID, we'll pass the interface name instead.
|
||||
// Otherwise an empty string will be passed to outgoing_interface which will cause IP leak.
|
||||
endpoints << (ip + portString);
|
||||
outgoingInterfaces << ip;
|
||||
}
|
||||
#else
|
||||
endpoints << (ip + portString);
|
||||
@@ -1555,24 +1567,6 @@ void Session::configureNetworkInterfaces(lt::settings_pack &settingsPack)
|
||||
}
|
||||
}
|
||||
|
||||
if (outgoingInterfaces.isEmpty()) {
|
||||
#ifdef Q_OS_WIN
|
||||
// On Vista+ versions and after Qt 5.5 QNetworkInterface::name() returns
|
||||
// the interface's LUID and not the GUID.
|
||||
// Libtorrent expects GUIDs for the 'outgoing_interfaces' setting.
|
||||
const QString netInterface = networkInterface();
|
||||
if (!netInterface.isEmpty()) {
|
||||
const QString guid = convertIfaceNameToGuid(netInterface);
|
||||
if (!guid.isEmpty())
|
||||
outgoingInterfaces << guid;
|
||||
else
|
||||
LogMsg(tr("Could not get GUID of network interface: %1").arg(netInterface) , Log::WARNING);
|
||||
}
|
||||
#else
|
||||
outgoingInterfaces << networkInterface();
|
||||
#endif // Q_OS_WIN
|
||||
}
|
||||
|
||||
const QString finalEndpoints = endpoints.join(',');
|
||||
settingsPack.set_str(lt::settings_pack::listen_interfaces, finalEndpoints.toStdString());
|
||||
LogMsg(tr("Trying to listen on: %1", "e.g: Trying to listen on: 192.168.0.1:6881")
|
||||
@@ -1699,7 +1693,7 @@ void Session::processShareLimits()
|
||||
{
|
||||
qDebug("Processing share limits...");
|
||||
|
||||
for (TorrentHandle *const torrent : asConst(torrents())) {
|
||||
for (TorrentHandleImpl *const torrent : asConst(m_torrents)) {
|
||||
if (torrent->isSeed() && !torrent->isForced()) {
|
||||
if (torrent->ratioLimit() != TorrentHandle::NO_RATIO_LIMIT) {
|
||||
const qreal ratio = torrent->realRatio();
|
||||
@@ -1791,7 +1785,7 @@ TorrentHandle *Session::findTorrent(const InfoHash &hash) const
|
||||
|
||||
bool Session::hasActiveTorrents() const
|
||||
{
|
||||
return std::any_of(m_torrents.begin(), m_torrents.end(), [](TorrentHandle *torrent)
|
||||
return std::any_of(m_torrents.begin(), m_torrents.end(), [](TorrentHandleImpl *torrent)
|
||||
{
|
||||
return TorrentFilter::ActiveTorrent.match(torrent);
|
||||
});
|
||||
@@ -1799,7 +1793,7 @@ bool Session::hasActiveTorrents() const
|
||||
|
||||
bool Session::hasUnfinishedTorrents() const
|
||||
{
|
||||
return std::any_of(m_torrents.begin(), m_torrents.end(), [](const TorrentHandle *torrent)
|
||||
return std::any_of(m_torrents.begin(), m_torrents.end(), [](const TorrentHandleImpl *torrent)
|
||||
{
|
||||
return (!torrent->isSeed() && !torrent->isPaused());
|
||||
});
|
||||
@@ -1807,7 +1801,7 @@ bool Session::hasUnfinishedTorrents() const
|
||||
|
||||
bool Session::hasRunningSeed() const
|
||||
{
|
||||
return std::any_of(m_torrents.begin(), m_torrents.end(), [](const TorrentHandle *torrent)
|
||||
return std::any_of(m_torrents.begin(), m_torrents.end(), [](const TorrentHandleImpl *torrent)
|
||||
{
|
||||
return (torrent->isSeed() && !torrent->isPaused());
|
||||
});
|
||||
@@ -1835,7 +1829,7 @@ void Session::banIP(const QString &ip)
|
||||
// and from the disk, if the corresponding deleteOption is chosen
|
||||
bool Session::deleteTorrent(const InfoHash &hash, const DeleteOption deleteOption)
|
||||
{
|
||||
TorrentHandle *const torrent = m_torrents.take(hash);
|
||||
TorrentHandleImpl *const torrent = m_torrents.take(hash);
|
||||
if (!torrent) return false;
|
||||
|
||||
qDebug("Deleting torrent with hash: %s", qUtf8Printable(torrent->hash()));
|
||||
@@ -1920,21 +1914,21 @@ bool Session::cancelLoadMetadata(const InfoHash &hash)
|
||||
|
||||
void Session::increaseTorrentsQueuePos(const QVector<InfoHash> &hashes)
|
||||
{
|
||||
using ElementType = std::pair<int, TorrentHandle *>;
|
||||
using ElementType = std::pair<int, TorrentHandleImpl *>;
|
||||
std::priority_queue<ElementType
|
||||
, std::vector<ElementType>
|
||||
, std::greater<ElementType>> torrentQueue;
|
||||
|
||||
// Sort torrents by queue position
|
||||
for (const InfoHash &infoHash : hashes) {
|
||||
TorrentHandle *const torrent = m_torrents.value(infoHash);
|
||||
TorrentHandleImpl *const torrent = m_torrents.value(infoHash);
|
||||
if (torrent && !torrent->isSeed())
|
||||
torrentQueue.emplace(torrent->queuePosition(), torrent);
|
||||
}
|
||||
|
||||
// Increase torrents queue position (starting with the one in the highest queue position)
|
||||
while (!torrentQueue.empty()) {
|
||||
const TorrentHandle *torrent = torrentQueue.top().second;
|
||||
const TorrentHandleImpl *torrent = torrentQueue.top().second;
|
||||
torrentQueuePositionUp(torrent->nativeHandle());
|
||||
torrentQueue.pop();
|
||||
}
|
||||
@@ -1944,19 +1938,19 @@ void Session::increaseTorrentsQueuePos(const QVector<InfoHash> &hashes)
|
||||
|
||||
void Session::decreaseTorrentsQueuePos(const QVector<InfoHash> &hashes)
|
||||
{
|
||||
using ElementType = std::pair<int, TorrentHandle *>;
|
||||
using ElementType = std::pair<int, TorrentHandleImpl *>;
|
||||
std::priority_queue<ElementType> torrentQueue;
|
||||
|
||||
// Sort torrents by queue position
|
||||
for (const InfoHash &infoHash : hashes) {
|
||||
TorrentHandle *const torrent = m_torrents.value(infoHash);
|
||||
TorrentHandleImpl *const torrent = m_torrents.value(infoHash);
|
||||
if (torrent && !torrent->isSeed())
|
||||
torrentQueue.emplace(torrent->queuePosition(), torrent);
|
||||
}
|
||||
|
||||
// Decrease torrents queue position (starting with the one in the lowest queue position)
|
||||
while (!torrentQueue.empty()) {
|
||||
const TorrentHandle *torrent = torrentQueue.top().second;
|
||||
const TorrentHandleImpl *torrent = torrentQueue.top().second;
|
||||
torrentQueuePositionDown(torrent->nativeHandle());
|
||||
torrentQueue.pop();
|
||||
}
|
||||
@@ -1969,19 +1963,19 @@ void Session::decreaseTorrentsQueuePos(const QVector<InfoHash> &hashes)
|
||||
|
||||
void Session::topTorrentsQueuePos(const QVector<InfoHash> &hashes)
|
||||
{
|
||||
using ElementType = std::pair<int, TorrentHandle *>;
|
||||
using ElementType = std::pair<int, TorrentHandleImpl *>;
|
||||
std::priority_queue<ElementType> torrentQueue;
|
||||
|
||||
// Sort torrents by queue position
|
||||
for (const InfoHash &infoHash : hashes) {
|
||||
TorrentHandle *const torrent = m_torrents.value(infoHash);
|
||||
TorrentHandleImpl *const torrent = m_torrents.value(infoHash);
|
||||
if (torrent && !torrent->isSeed())
|
||||
torrentQueue.emplace(torrent->queuePosition(), torrent);
|
||||
}
|
||||
|
||||
// Top torrents queue position (starting with the one in the lowest queue position)
|
||||
while (!torrentQueue.empty()) {
|
||||
const TorrentHandle *torrent = torrentQueue.top().second;
|
||||
const TorrentHandleImpl *torrent = torrentQueue.top().second;
|
||||
torrentQueuePositionTop(torrent->nativeHandle());
|
||||
torrentQueue.pop();
|
||||
}
|
||||
@@ -1991,21 +1985,21 @@ void Session::topTorrentsQueuePos(const QVector<InfoHash> &hashes)
|
||||
|
||||
void Session::bottomTorrentsQueuePos(const QVector<InfoHash> &hashes)
|
||||
{
|
||||
using ElementType = std::pair<int, TorrentHandle *>;
|
||||
using ElementType = std::pair<int, TorrentHandleImpl *>;
|
||||
std::priority_queue<ElementType
|
||||
, std::vector<ElementType>
|
||||
, std::greater<ElementType>> torrentQueue;
|
||||
|
||||
// Sort torrents by queue position
|
||||
for (const InfoHash &infoHash : hashes) {
|
||||
TorrentHandle *const torrent = m_torrents.value(infoHash);
|
||||
TorrentHandleImpl *const torrent = m_torrents.value(infoHash);
|
||||
if (torrent && !torrent->isSeed())
|
||||
torrentQueue.emplace(torrent->queuePosition(), torrent);
|
||||
}
|
||||
|
||||
// Bottom torrents queue position (starting with the one in the highest queue position)
|
||||
while (!torrentQueue.empty()) {
|
||||
const TorrentHandle *torrent = torrentQueue.top().second;
|
||||
const TorrentHandleImpl *torrent = torrentQueue.top().second;
|
||||
torrentQueuePositionBottom(torrent->nativeHandle());
|
||||
torrentQueue.pop();
|
||||
}
|
||||
@@ -2016,15 +2010,20 @@ void Session::bottomTorrentsQueuePos(const QVector<InfoHash> &hashes)
|
||||
saveTorrentsQueue();
|
||||
}
|
||||
|
||||
void Session::handleTorrentSaveResumeDataRequested(const TorrentHandle *torrent)
|
||||
void Session::handleTorrentSaveResumeDataRequested(const TorrentHandleImpl *torrent)
|
||||
{
|
||||
qDebug("Saving resume data is requested for torrent '%s'...", qUtf8Printable(torrent->name()));
|
||||
++m_numResumeData;
|
||||
}
|
||||
|
||||
QHash<InfoHash, TorrentHandle *> Session::torrents() const
|
||||
QVector<TorrentHandle *> Session::torrents() const
|
||||
{
|
||||
return m_torrents;
|
||||
QVector<TorrentHandle *> result;
|
||||
result.reserve(m_torrents.size());
|
||||
for (TorrentHandleImpl *torrent : asConst(m_torrents))
|
||||
result << torrent;
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
bool Session::addTorrent(const QString &source, const AddTorrentParams ¶ms)
|
||||
@@ -2325,7 +2324,7 @@ bool Session::addTorrent_impl(CreateTorrentParams params, const MagnetUri &magne
|
||||
if (m_addingTorrents.contains(hash) || m_loadedMetadata.contains(hash))
|
||||
return false;
|
||||
|
||||
TorrentHandle *const torrent = m_torrents.value(hash);
|
||||
TorrentHandleImpl *const torrent = m_torrents.value(hash);
|
||||
if (torrent) { // a duplicate torrent is added
|
||||
if (torrent->isPrivate() || (!fromMagnetUri && torrentInfo.isPrivate()))
|
||||
return false;
|
||||
@@ -2511,7 +2510,7 @@ bool Session::loadMetadata(const MagnetUri &magnetUri)
|
||||
return true;
|
||||
}
|
||||
|
||||
void Session::exportTorrentFile(TorrentHandle *const torrent, TorrentExportFolder folder)
|
||||
void Session::exportTorrentFile(const TorrentHandle *torrent, TorrentExportFolder folder)
|
||||
{
|
||||
Q_ASSERT(((folder == TorrentExportFolder::Regular) && !torrentExportDirectory().isEmpty()) ||
|
||||
((folder == TorrentExportFolder::Finished) && !finishedTorrentExportDirectory().isEmpty()));
|
||||
@@ -2537,7 +2536,7 @@ void Session::exportTorrentFile(TorrentHandle *const torrent, TorrentExportFolde
|
||||
|
||||
void Session::generateResumeData(const bool final)
|
||||
{
|
||||
for (TorrentHandle *const torrent : asConst(m_torrents)) {
|
||||
for (TorrentHandleImpl *const torrent : asConst(m_torrents)) {
|
||||
if (!torrent->isValid()) continue;
|
||||
|
||||
if (!final && !torrent->needSaveResumeData()) continue;
|
||||
@@ -2582,15 +2581,17 @@ void Session::saveResumeData()
|
||||
|
||||
void Session::saveTorrentsQueue()
|
||||
{
|
||||
// store hash in textual representation
|
||||
QMap<int, QString> queue; // Use QMap since it should be ordered by key
|
||||
for (const TorrentHandle *torrent : asConst(torrents())) {
|
||||
for (const TorrentHandleImpl *torrent : asConst(m_torrents)) {
|
||||
// We require actual (non-cached) queue position here!
|
||||
const int queuePos = LTUnderlyingType<LTQueuePosition> {torrent->nativeHandle().queue_position()};
|
||||
const int queuePos = static_cast<LTUnderlyingType<LTQueuePosition>>(torrent->nativeHandle().queue_position());
|
||||
if (queuePos >= 0)
|
||||
queue[queuePos] = torrent->hash();
|
||||
}
|
||||
|
||||
QByteArray data;
|
||||
data.reserve(((InfoHash::length() * 2) + 1) * queue.size());
|
||||
for (const QString &hash : asConst(queue))
|
||||
data += (hash.toLatin1() + '\n');
|
||||
|
||||
@@ -2623,10 +2624,10 @@ void Session::setDefaultSavePath(QString path)
|
||||
m_defaultSavePath = path;
|
||||
|
||||
if (isDisableAutoTMMWhenDefaultSavePathChanged())
|
||||
for (TorrentHandle *const torrent : asConst(torrents()))
|
||||
for (TorrentHandleImpl *const torrent : asConst(m_torrents))
|
||||
torrent->setAutoTMMEnabled(false);
|
||||
else
|
||||
for (TorrentHandle *const torrent : asConst(torrents()))
|
||||
for (TorrentHandleImpl *const torrent : asConst(m_torrents))
|
||||
torrent->handleCategorySavePathChanged();
|
||||
}
|
||||
|
||||
@@ -2637,7 +2638,7 @@ void Session::setTempPath(QString path)
|
||||
|
||||
m_tempPath = path;
|
||||
|
||||
for (TorrentHandle *const torrent : asConst(m_torrents))
|
||||
for (TorrentHandleImpl *const torrent : asConst(m_torrents))
|
||||
torrent->handleTempPathChanged();
|
||||
}
|
||||
|
||||
@@ -2673,7 +2674,11 @@ QStringList Session::getListeningIPs() const
|
||||
|
||||
if (!ifaceAddr.isEmpty() && !allIPv4 && !allIPv6 && configuredAddr.isNull()) {
|
||||
LogMsg(tr("Configured network interface address %1 isn't valid.", "Configured network interface address 124.5.158.1 isn't valid.").arg(ifaceAddr), Log::CRITICAL);
|
||||
IPs.append("127.0.0.1"); // Force listening to localhost and avoid accidental connection that will expose user data.
|
||||
// Pass the invalid user configured interface name/address to libtorrent
|
||||
// in hopes that it will come online later.
|
||||
// This will not cause IP leak but allow user to reconnect the interface
|
||||
// and re-establish connection without restarting the client.
|
||||
IPs.append(ifaceAddr);
|
||||
return IPs;
|
||||
}
|
||||
|
||||
@@ -2709,7 +2714,7 @@ QStringList Session::getListeningIPs() const
|
||||
LogMsg(tr("Can't find the configured address '%1' to listen on"
|
||||
, "Can't find the configured address '192.168.1.3' to listen on")
|
||||
.arg(ifaceAddr), Log::CRITICAL);
|
||||
IPs.append("127.0.0.1"); // Force listening to localhost and avoid accidental connection that will expose user data.
|
||||
IPs.append(ifaceAddr);
|
||||
}
|
||||
|
||||
return IPs;
|
||||
@@ -2720,7 +2725,7 @@ QStringList Session::getListeningIPs() const
|
||||
if (!networkIFace.isValid()) {
|
||||
qDebug("Invalid network interface: %s", qUtf8Printable(ifaceName));
|
||||
LogMsg(tr("The network interface defined is invalid: %1").arg(ifaceName), Log::CRITICAL);
|
||||
IPs.append("127.0.0.1"); // Force listening to localhost and avoid accidental connection that will expose user data.
|
||||
IPs.append(ifaceName);
|
||||
return IPs;
|
||||
}
|
||||
|
||||
@@ -2741,7 +2746,7 @@ QStringList Session::getListeningIPs() const
|
||||
LogMsg(tr("Can't find the configured address '%1' to listen on"
|
||||
, "Can't find the configured address '192.168.1.3' to listen on")
|
||||
.arg(ifaceAddr), Log::CRITICAL);
|
||||
IPs.append("127.0.0.1"); // Force listening to localhost and avoid accidental connection that will expose user data.
|
||||
IPs.append(ifaceAddr);
|
||||
}
|
||||
|
||||
return IPs;
|
||||
@@ -3680,19 +3685,6 @@ void Session::setStopTrackerTimeout(const int value)
|
||||
configureDeferred();
|
||||
}
|
||||
|
||||
bool Session::isSuperSeedingEnabled() const
|
||||
{
|
||||
return m_isSuperSeedingEnabled;
|
||||
}
|
||||
|
||||
void Session::setSuperSeedingEnabled(const bool enabled)
|
||||
{
|
||||
if (enabled != m_isSuperSeedingEnabled) {
|
||||
m_isSuperSeedingEnabled = enabled;
|
||||
configureDeferred();
|
||||
}
|
||||
}
|
||||
|
||||
int Session::maxConnections() const
|
||||
{
|
||||
return m_maxConnections;
|
||||
@@ -3825,48 +3817,48 @@ void Session::updateSeedingLimitTimer()
|
||||
}
|
||||
}
|
||||
|
||||
void Session::handleTorrentShareLimitChanged(TorrentHandle *const torrent)
|
||||
void Session::handleTorrentShareLimitChanged(TorrentHandleImpl *const torrent)
|
||||
{
|
||||
torrent->saveResumeData();
|
||||
updateSeedingLimitTimer();
|
||||
}
|
||||
|
||||
void Session::handleTorrentNameChanged(TorrentHandle *const torrent)
|
||||
void Session::handleTorrentNameChanged(TorrentHandleImpl *const torrent)
|
||||
{
|
||||
torrent->saveResumeData();
|
||||
}
|
||||
|
||||
void Session::handleTorrentSavePathChanged(TorrentHandle *const torrent)
|
||||
void Session::handleTorrentSavePathChanged(TorrentHandleImpl *const torrent)
|
||||
{
|
||||
torrent->saveResumeData();
|
||||
emit torrentSavePathChanged(torrent);
|
||||
}
|
||||
|
||||
void Session::handleTorrentCategoryChanged(TorrentHandle *const torrent, const QString &oldCategory)
|
||||
void Session::handleTorrentCategoryChanged(TorrentHandleImpl *const torrent, const QString &oldCategory)
|
||||
{
|
||||
torrent->saveResumeData();
|
||||
emit torrentCategoryChanged(torrent, oldCategory);
|
||||
}
|
||||
|
||||
void Session::handleTorrentTagAdded(TorrentHandle *const torrent, const QString &tag)
|
||||
void Session::handleTorrentTagAdded(TorrentHandleImpl *const torrent, const QString &tag)
|
||||
{
|
||||
torrent->saveResumeData();
|
||||
emit torrentTagAdded(torrent, tag);
|
||||
}
|
||||
|
||||
void Session::handleTorrentTagRemoved(TorrentHandle *const torrent, const QString &tag)
|
||||
void Session::handleTorrentTagRemoved(TorrentHandleImpl *const torrent, const QString &tag)
|
||||
{
|
||||
torrent->saveResumeData();
|
||||
emit torrentTagRemoved(torrent, tag);
|
||||
}
|
||||
|
||||
void Session::handleTorrentSavingModeChanged(TorrentHandle *const torrent)
|
||||
void Session::handleTorrentSavingModeChanged(TorrentHandleImpl *const torrent)
|
||||
{
|
||||
torrent->saveResumeData();
|
||||
emit torrentSavingModeChanged(torrent);
|
||||
}
|
||||
|
||||
void Session::handleTorrentTrackersAdded(TorrentHandle *const torrent, const QVector<TrackerEntry> &newTrackers)
|
||||
void Session::handleTorrentTrackersAdded(TorrentHandleImpl *const torrent, const QVector<TrackerEntry> &newTrackers)
|
||||
{
|
||||
torrent->saveResumeData();
|
||||
|
||||
@@ -3878,7 +3870,7 @@ void Session::handleTorrentTrackersAdded(TorrentHandle *const torrent, const QVe
|
||||
emit trackersChanged(torrent);
|
||||
}
|
||||
|
||||
void Session::handleTorrentTrackersRemoved(TorrentHandle *const torrent, const QVector<TrackerEntry> &deletedTrackers)
|
||||
void Session::handleTorrentTrackersRemoved(TorrentHandleImpl *const torrent, const QVector<TrackerEntry> &deletedTrackers)
|
||||
{
|
||||
torrent->saveResumeData();
|
||||
|
||||
@@ -3890,27 +3882,27 @@ void Session::handleTorrentTrackersRemoved(TorrentHandle *const torrent, const Q
|
||||
emit trackersChanged(torrent);
|
||||
}
|
||||
|
||||
void Session::handleTorrentTrackersChanged(TorrentHandle *const torrent)
|
||||
void Session::handleTorrentTrackersChanged(TorrentHandleImpl *const torrent)
|
||||
{
|
||||
torrent->saveResumeData();
|
||||
emit trackersChanged(torrent);
|
||||
}
|
||||
|
||||
void Session::handleTorrentUrlSeedsAdded(TorrentHandle *const torrent, const QVector<QUrl> &newUrlSeeds)
|
||||
void Session::handleTorrentUrlSeedsAdded(TorrentHandleImpl *const torrent, const QVector<QUrl> &newUrlSeeds)
|
||||
{
|
||||
torrent->saveResumeData();
|
||||
for (const QUrl &newUrlSeed : newUrlSeeds)
|
||||
LogMsg(tr("URL seed '%1' was added to torrent '%2'").arg(newUrlSeed.toString(), torrent->name()));
|
||||
}
|
||||
|
||||
void Session::handleTorrentUrlSeedsRemoved(TorrentHandle *const torrent, const QVector<QUrl> &urlSeeds)
|
||||
void Session::handleTorrentUrlSeedsRemoved(TorrentHandleImpl *const torrent, const QVector<QUrl> &urlSeeds)
|
||||
{
|
||||
torrent->saveResumeData();
|
||||
for (const QUrl &urlSeed : urlSeeds)
|
||||
LogMsg(tr("URL seed '%1' was removed from torrent '%2'").arg(urlSeed.toString(), torrent->name()));
|
||||
}
|
||||
|
||||
void Session::handleTorrentMetadataReceived(TorrentHandle *const torrent)
|
||||
void Session::handleTorrentMetadataReceived(TorrentHandleImpl *const torrent)
|
||||
{
|
||||
torrent->saveResumeData();
|
||||
|
||||
@@ -3931,25 +3923,25 @@ void Session::handleTorrentMetadataReceived(TorrentHandle *const torrent)
|
||||
emit torrentMetadataLoaded(torrent);
|
||||
}
|
||||
|
||||
void Session::handleTorrentPaused(TorrentHandle *const torrent)
|
||||
void Session::handleTorrentPaused(TorrentHandleImpl *const torrent)
|
||||
{
|
||||
if (!torrent->hasError() && !torrent->hasMissingFiles())
|
||||
torrent->saveResumeData();
|
||||
emit torrentPaused(torrent);
|
||||
}
|
||||
|
||||
void Session::handleTorrentResumed(TorrentHandle *const torrent)
|
||||
void Session::handleTorrentResumed(TorrentHandleImpl *const torrent)
|
||||
{
|
||||
torrent->saveResumeData();
|
||||
emit torrentResumed(torrent);
|
||||
}
|
||||
|
||||
void Session::handleTorrentChecked(TorrentHandle *const torrent)
|
||||
void Session::handleTorrentChecked(TorrentHandleImpl *const torrent)
|
||||
{
|
||||
emit torrentFinishedChecking(torrent);
|
||||
}
|
||||
|
||||
void Session::handleTorrentFinished(TorrentHandle *const torrent)
|
||||
void Session::handleTorrentFinished(TorrentHandleImpl *const torrent)
|
||||
{
|
||||
if (!torrent->hasError() && !torrent->hasMissingFiles())
|
||||
torrent->saveResumeData();
|
||||
@@ -3984,45 +3976,40 @@ void Session::handleTorrentFinished(TorrentHandle *const torrent)
|
||||
emit allTorrentsFinished();
|
||||
}
|
||||
|
||||
void Session::handleTorrentResumeDataReady(TorrentHandle *const torrent, const lt::entry &data)
|
||||
void Session::handleTorrentResumeDataReady(TorrentHandleImpl *const torrent, const std::shared_ptr<lt::entry> &data)
|
||||
{
|
||||
--m_numResumeData;
|
||||
|
||||
// Separated thread is used for the blocking IO which results in slow processing of many torrents.
|
||||
// Encoding data in parallel while doing IO saves time. Copying lt::entry objects around
|
||||
// isn't cheap too.
|
||||
|
||||
QByteArray out;
|
||||
out.reserve(1024 * 1024); // most fastresume file sizes are under 1 MB
|
||||
lt::bencode(std::back_inserter(out), data);
|
||||
// Copying lt::entry objects around isn't cheap.
|
||||
|
||||
const QString filename = QString::fromLatin1("%1.fastresume").arg(torrent->hash());
|
||||
#if (QT_VERSION >= QT_VERSION_CHECK(5, 10, 0))
|
||||
QMetaObject::invokeMethod(m_resumeDataSavingManager
|
||||
, [this, filename, out]() { m_resumeDataSavingManager->save(filename, out); });
|
||||
, [this, filename, data]() { m_resumeDataSavingManager->save(filename, data); });
|
||||
#else
|
||||
QMetaObject::invokeMethod(m_resumeDataSavingManager, "save",
|
||||
Q_ARG(QString, filename), Q_ARG(QByteArray, out));
|
||||
QMetaObject::invokeMethod(m_resumeDataSavingManager, "save"
|
||||
, Q_ARG(QString, filename), Q_ARG(std::shared_ptr<lt::entry>, data));
|
||||
#endif
|
||||
}
|
||||
|
||||
void Session::handleTorrentResumeDataFailed(TorrentHandle *const torrent)
|
||||
void Session::handleTorrentResumeDataFailed(TorrentHandleImpl *const torrent)
|
||||
{
|
||||
Q_UNUSED(torrent)
|
||||
--m_numResumeData;
|
||||
}
|
||||
|
||||
void Session::handleTorrentTrackerReply(TorrentHandle *const torrent, const QString &trackerUrl)
|
||||
void Session::handleTorrentTrackerReply(TorrentHandleImpl *const torrent, const QString &trackerUrl)
|
||||
{
|
||||
emit trackerSuccess(torrent, trackerUrl);
|
||||
}
|
||||
|
||||
void Session::handleTorrentTrackerError(TorrentHandle *const torrent, const QString &trackerUrl)
|
||||
void Session::handleTorrentTrackerError(TorrentHandleImpl *const torrent, const QString &trackerUrl)
|
||||
{
|
||||
emit trackerError(torrent, trackerUrl);
|
||||
}
|
||||
|
||||
bool Session::addMoveTorrentStorageJob(TorrentHandle *torrent, const QString &newPath, const MoveStorageMode mode)
|
||||
bool Session::addMoveTorrentStorageJob(TorrentHandleImpl *torrent, const QString &newPath, const MoveStorageMode mode)
|
||||
{
|
||||
Q_ASSERT(torrent);
|
||||
|
||||
@@ -4095,14 +4082,14 @@ void Session::handleMoveTorrentStorageJobFinished(const QString &errorMessage)
|
||||
}
|
||||
}
|
||||
|
||||
void Session::handleTorrentTrackerWarning(TorrentHandle *const torrent, const QString &trackerUrl)
|
||||
void Session::handleTorrentTrackerWarning(TorrentHandleImpl *const torrent, const QString &trackerUrl)
|
||||
{
|
||||
emit trackerWarning(torrent, trackerUrl);
|
||||
}
|
||||
|
||||
bool Session::hasPerTorrentRatioLimit() const
|
||||
{
|
||||
return std::any_of(m_torrents.cbegin(), m_torrents.cend(), [](const TorrentHandle *torrent)
|
||||
return std::any_of(m_torrents.cbegin(), m_torrents.cend(), [](const TorrentHandleImpl *torrent)
|
||||
{
|
||||
return (torrent->ratioLimit() >= 0);
|
||||
});
|
||||
@@ -4110,7 +4097,7 @@ bool Session::hasPerTorrentRatioLimit() const
|
||||
|
||||
bool Session::hasPerTorrentSeedingTimeLimit() const
|
||||
{
|
||||
return std::any_of(m_torrents.cbegin(), m_torrents.cend(), [](const TorrentHandle *torrent)
|
||||
return std::any_of(m_torrents.cbegin(), m_torrents.cend(), [](const TorrentHandleImpl *torrent)
|
||||
{
|
||||
return (torrent->seedingTimeLimit() >= 0);
|
||||
});
|
||||
@@ -4184,7 +4171,7 @@ void Session::disableIPFilter()
|
||||
|
||||
void Session::recursiveTorrentDownload(const InfoHash &hash)
|
||||
{
|
||||
TorrentHandle *const torrent = m_torrents.value(hash);
|
||||
TorrentHandleImpl *const torrent = m_torrents.value(hash);
|
||||
if (!torrent) return;
|
||||
|
||||
for (int i = 0; i < torrent->filesCount(); ++i) {
|
||||
@@ -4494,7 +4481,7 @@ void Session::handleAlert(const lt::alert *a)
|
||||
|
||||
void Session::dispatchTorrentAlert(const lt::alert *a)
|
||||
{
|
||||
TorrentHandle *const torrent = m_torrents.value(static_cast<const lt::torrent_alert*>(a)->handle.info_hash());
|
||||
TorrentHandleImpl *const torrent = m_torrents.value(static_cast<const lt::torrent_alert*>(a)->handle.info_hash());
|
||||
if (torrent) {
|
||||
torrent->handleAlert(a);
|
||||
return;
|
||||
@@ -4514,7 +4501,7 @@ void Session::createTorrentHandle(const lt::torrent_handle &nativeHandle)
|
||||
|
||||
const CreateTorrentParams params = m_addingTorrents.take(nativeHandle.info_hash());
|
||||
|
||||
TorrentHandle *const torrent = new TorrentHandle(this, nativeHandle, params);
|
||||
TorrentHandleImpl *const torrent = new TorrentHandleImpl(this, nativeHandle, params);
|
||||
m_torrents.insert(torrent->hash(), torrent);
|
||||
|
||||
const bool fromMagnetUri = !torrent->hasMetadata();
|
||||
@@ -4658,7 +4645,7 @@ void Session::handleMetadataReceivedAlert(const lt::metadata_received_alert *p)
|
||||
|
||||
void Session::handleFileErrorAlert(const lt::file_error_alert *p)
|
||||
{
|
||||
TorrentHandle *const torrent = m_torrents.value(p->handle.info_hash());
|
||||
TorrentHandleImpl *const torrent = m_torrents.value(p->handle.info_hash());
|
||||
if (!torrent)
|
||||
return;
|
||||
|
||||
@@ -4752,7 +4739,7 @@ void Session::handlePeerBanAlert(const lt::peer_ban_alert *p)
|
||||
|
||||
void Session::handleUrlSeedAlert(const lt::url_seed_alert *p)
|
||||
{
|
||||
const TorrentHandle *torrent = m_torrents.value(p->handle.info_hash());
|
||||
const TorrentHandleImpl *torrent = m_torrents.value(p->handle.info_hash());
|
||||
if (!torrent)
|
||||
return;
|
||||
|
||||
@@ -4983,7 +4970,7 @@ void Session::handleStorageMovedAlert(const lt::storage_moved_alert *p)
|
||||
{
|
||||
if (m_moveStorageQueue.isEmpty()) return;
|
||||
|
||||
const TorrentHandle *torrent = m_torrents.value(p->handle.info_hash());
|
||||
const TorrentHandleImpl *torrent = m_torrents.value(p->handle.info_hash());
|
||||
const MoveStorageJob ¤tJob = m_moveStorageQueue.first();
|
||||
if (currentJob.torrent != torrent) return;
|
||||
|
||||
@@ -4995,7 +4982,7 @@ void Session::handleStorageMovedFailedAlert(const lt::storage_moved_failed_alert
|
||||
{
|
||||
if (m_moveStorageQueue.isEmpty()) return;
|
||||
|
||||
const TorrentHandle *torrent = m_torrents.value(p->handle.info_hash());
|
||||
const TorrentHandleImpl *torrent = m_torrents.value(p->handle.info_hash());
|
||||
const MoveStorageJob ¤tJob = m_moveStorageQueue.first();
|
||||
if (currentJob.torrent != torrent) return;
|
||||
|
||||
@@ -5008,7 +4995,7 @@ void Session::handleStateUpdateAlert(const lt::state_update_alert *p)
|
||||
updatedTorrents.reserve(p->status.size());
|
||||
|
||||
for (const lt::torrent_status &status : p->status) {
|
||||
TorrentHandle *const torrent = m_torrents.value(status.info_hash);
|
||||
TorrentHandleImpl *const torrent = m_torrents.value(status.info_hash);
|
||||
|
||||
if (!torrent)
|
||||
continue;
|
||||
|
||||
@@ -30,6 +30,7 @@
|
||||
#ifndef BITTORRENT_SESSION_H
|
||||
#define BITTORRENT_SESSION_H
|
||||
|
||||
#include <memory>
|
||||
#include <vector>
|
||||
|
||||
#include <libtorrent/fwd.hpp>
|
||||
@@ -92,6 +93,7 @@ namespace BitTorrent
|
||||
class InfoHash;
|
||||
class MagnetUri;
|
||||
class TorrentHandle;
|
||||
class TorrentHandleImpl;
|
||||
class Tracker;
|
||||
class TrackerEntry;
|
||||
struct CreateTorrentParams;
|
||||
@@ -377,8 +379,6 @@ namespace BitTorrent
|
||||
void setAnnounceIP(const QString &ip);
|
||||
int stopTrackerTimeout() const;
|
||||
void setStopTrackerTimeout(int value);
|
||||
bool isSuperSeedingEnabled() const;
|
||||
void setSuperSeedingEnabled(bool enabled);
|
||||
int maxConnections() const;
|
||||
void setMaxConnections(int max);
|
||||
int maxConnectionsPerTorrent() const;
|
||||
@@ -412,7 +412,7 @@ namespace BitTorrent
|
||||
|
||||
void startUpTorrents();
|
||||
TorrentHandle *findTorrent(const InfoHash &hash) const;
|
||||
QHash<InfoHash, TorrentHandle *> torrents() const;
|
||||
QVector<TorrentHandle *> torrents() const;
|
||||
bool hasActiveTorrents() const;
|
||||
bool hasUnfinishedTorrents() const;
|
||||
bool hasRunningSeed() const;
|
||||
@@ -441,31 +441,31 @@ namespace BitTorrent
|
||||
void bottomTorrentsQueuePos(const QVector<InfoHash> &hashes);
|
||||
|
||||
// TorrentHandle interface
|
||||
void handleTorrentSaveResumeDataRequested(const TorrentHandle *torrent);
|
||||
void handleTorrentShareLimitChanged(TorrentHandle *const torrent);
|
||||
void handleTorrentNameChanged(TorrentHandle *const torrent);
|
||||
void handleTorrentSavePathChanged(TorrentHandle *const torrent);
|
||||
void handleTorrentCategoryChanged(TorrentHandle *const torrent, const QString &oldCategory);
|
||||
void handleTorrentTagAdded(TorrentHandle *const torrent, const QString &tag);
|
||||
void handleTorrentTagRemoved(TorrentHandle *const torrent, const QString &tag);
|
||||
void handleTorrentSavingModeChanged(TorrentHandle *const torrent);
|
||||
void handleTorrentMetadataReceived(TorrentHandle *const torrent);
|
||||
void handleTorrentPaused(TorrentHandle *const torrent);
|
||||
void handleTorrentResumed(TorrentHandle *const torrent);
|
||||
void handleTorrentChecked(TorrentHandle *const torrent);
|
||||
void handleTorrentFinished(TorrentHandle *const torrent);
|
||||
void handleTorrentTrackersAdded(TorrentHandle *const torrent, const QVector<TrackerEntry> &newTrackers);
|
||||
void handleTorrentTrackersRemoved(TorrentHandle *const torrent, const QVector<TrackerEntry> &deletedTrackers);
|
||||
void handleTorrentTrackersChanged(TorrentHandle *const torrent);
|
||||
void handleTorrentUrlSeedsAdded(TorrentHandle *const torrent, const QVector<QUrl> &newUrlSeeds);
|
||||
void handleTorrentUrlSeedsRemoved(TorrentHandle *const torrent, const QVector<QUrl> &urlSeeds);
|
||||
void handleTorrentResumeDataReady(TorrentHandle *const torrent, const lt::entry &data);
|
||||
void handleTorrentResumeDataFailed(TorrentHandle *const torrent);
|
||||
void handleTorrentTrackerReply(TorrentHandle *const torrent, const QString &trackerUrl);
|
||||
void handleTorrentTrackerWarning(TorrentHandle *const torrent, const QString &trackerUrl);
|
||||
void handleTorrentTrackerError(TorrentHandle *const torrent, const QString &trackerUrl);
|
||||
void handleTorrentSaveResumeDataRequested(const TorrentHandleImpl *torrent);
|
||||
void handleTorrentShareLimitChanged(TorrentHandleImpl *const torrent);
|
||||
void handleTorrentNameChanged(TorrentHandleImpl *const torrent);
|
||||
void handleTorrentSavePathChanged(TorrentHandleImpl *const torrent);
|
||||
void handleTorrentCategoryChanged(TorrentHandleImpl *const torrent, const QString &oldCategory);
|
||||
void handleTorrentTagAdded(TorrentHandleImpl *const torrent, const QString &tag);
|
||||
void handleTorrentTagRemoved(TorrentHandleImpl *const torrent, const QString &tag);
|
||||
void handleTorrentSavingModeChanged(TorrentHandleImpl *const torrent);
|
||||
void handleTorrentMetadataReceived(TorrentHandleImpl *const torrent);
|
||||
void handleTorrentPaused(TorrentHandleImpl *const torrent);
|
||||
void handleTorrentResumed(TorrentHandleImpl *const torrent);
|
||||
void handleTorrentChecked(TorrentHandleImpl *const torrent);
|
||||
void handleTorrentFinished(TorrentHandleImpl *const torrent);
|
||||
void handleTorrentTrackersAdded(TorrentHandleImpl *const torrent, const QVector<TrackerEntry> &newTrackers);
|
||||
void handleTorrentTrackersRemoved(TorrentHandleImpl *const torrent, const QVector<TrackerEntry> &deletedTrackers);
|
||||
void handleTorrentTrackersChanged(TorrentHandleImpl *const torrent);
|
||||
void handleTorrentUrlSeedsAdded(TorrentHandleImpl *const torrent, const QVector<QUrl> &newUrlSeeds);
|
||||
void handleTorrentUrlSeedsRemoved(TorrentHandleImpl *const torrent, const QVector<QUrl> &urlSeeds);
|
||||
void handleTorrentResumeDataReady(TorrentHandleImpl *const torrent, const std::shared_ptr<lt::entry> &data);
|
||||
void handleTorrentResumeDataFailed(TorrentHandleImpl *const torrent);
|
||||
void handleTorrentTrackerReply(TorrentHandleImpl *const torrent, const QString &trackerUrl);
|
||||
void handleTorrentTrackerWarning(TorrentHandleImpl *const torrent, const QString &trackerUrl);
|
||||
void handleTorrentTrackerError(TorrentHandleImpl *const torrent, const QString &trackerUrl);
|
||||
|
||||
bool addMoveTorrentStorageJob(TorrentHandle *torrent, const QString &newPath, MoveStorageMode mode);
|
||||
bool addMoveTorrentStorageJob(TorrentHandleImpl *torrent, const QString &newPath, MoveStorageMode mode);
|
||||
|
||||
signals:
|
||||
void addTorrentFailed(const QString &error);
|
||||
@@ -522,7 +522,7 @@ namespace BitTorrent
|
||||
private:
|
||||
struct MoveStorageJob
|
||||
{
|
||||
TorrentHandle *torrent;
|
||||
TorrentHandleImpl *torrent;
|
||||
QString path;
|
||||
MoveStorageMode mode;
|
||||
};
|
||||
@@ -572,7 +572,7 @@ namespace BitTorrent
|
||||
bool findIncompleteFiles(TorrentInfo &torrentInfo, QString &savePath) const;
|
||||
|
||||
void updateSeedingLimitTimer();
|
||||
void exportTorrentFile(TorrentHandle *const torrent, TorrentExportFolder folder = TorrentExportFolder::Regular);
|
||||
void exportTorrentFile(const TorrentHandle *torrent, TorrentExportFolder folder = TorrentExportFolder::Regular);
|
||||
|
||||
void handleAlert(const lt::alert *a);
|
||||
void dispatchTorrentAlert(const lt::alert *a);
|
||||
@@ -657,7 +657,6 @@ namespace BitTorrent
|
||||
CachedSettingValue<bool> m_includeOverheadInLimits;
|
||||
CachedSettingValue<QString> m_announceIP;
|
||||
CachedSettingValue<int> m_stopTrackerTimeout;
|
||||
CachedSettingValue<bool> m_isSuperSeedingEnabled;
|
||||
CachedSettingValue<int> m_maxConnections;
|
||||
CachedSettingValue<int> m_maxUploads;
|
||||
CachedSettingValue<int> m_maxConnectionsPerTorrent;
|
||||
@@ -735,7 +734,7 @@ namespace BitTorrent
|
||||
ResumeDataSavingManager *m_resumeDataSavingManager = nullptr;
|
||||
|
||||
QHash<InfoHash, TorrentInfo> m_loadedMetadata;
|
||||
QHash<InfoHash, TorrentHandle *> m_torrents;
|
||||
QHash<InfoHash, TorrentHandleImpl *> m_torrents;
|
||||
QHash<InfoHash, CreateTorrentParams> m_addingTorrents;
|
||||
QHash<QString, AddTorrentParams> m_downloadedTorrents;
|
||||
QHash<InfoHash, RemovingTorrentData> m_removingTorrents;
|
||||
|
||||
@@ -41,8 +41,10 @@
|
||||
#include <QFileInfo>
|
||||
#include <QHash>
|
||||
|
||||
#include "base/exceptions.h"
|
||||
#include "base/global.h"
|
||||
#include "base/utils/fs.h"
|
||||
#include "base/utils/io.h"
|
||||
#include "base/utils/string.h"
|
||||
#include "private/ltunderlyingtype.h"
|
||||
|
||||
@@ -162,7 +164,7 @@ void TorrentCreatorThread::run()
|
||||
lt::set_piece_hashes(newTorrent, Utils::Fs::toNativePath(parentPath).toStdString()
|
||||
, [this, &newTorrent](const LTPieceIndex n)
|
||||
{
|
||||
sendProgressSignal(LTUnderlyingType<LTPieceIndex> {n}, newTorrent.num_pieces());
|
||||
sendProgressSignal(static_cast<LTUnderlyingType<LTPieceIndex>>(n), newTorrent.num_pieces());
|
||||
});
|
||||
// Set qBittorrent as creator and add user comment to
|
||||
// torrent_info structure
|
||||
@@ -182,19 +184,19 @@ void TorrentCreatorThread::run()
|
||||
if (isInterruptionRequested()) return;
|
||||
|
||||
// create the torrent
|
||||
std::ofstream outfile(
|
||||
#ifdef _MSC_VER
|
||||
Utils::Fs::toNativePath(m_params.savePath).toStdWString().c_str()
|
||||
#else
|
||||
Utils::Fs::toNativePath(m_params.savePath).toUtf8().constData()
|
||||
#endif
|
||||
, (std::ios_base::out | std::ios_base::binary | std::ios_base::trunc));
|
||||
if (outfile.fail())
|
||||
throw std::runtime_error(tr("create new torrent file failed").toStdString());
|
||||
QFile outfile {m_params.savePath};
|
||||
if (!outfile.open(QIODevice::WriteOnly)) {
|
||||
throw RuntimeError {tr("Create new torrent file failed. Reason: %1")
|
||||
.arg(outfile.errorString())};
|
||||
}
|
||||
|
||||
if (isInterruptionRequested()) return;
|
||||
|
||||
lt::bencode(std::ostream_iterator<char>(outfile), entry);
|
||||
lt::bencode(Utils::IO::FileDeviceOutputIterator {outfile}, entry);
|
||||
if (outfile.error() != QFileDevice::NoError) {
|
||||
throw RuntimeError {tr("Create new torrent file failed. Reason: %1")
|
||||
.arg(outfile.errorString())};
|
||||
}
|
||||
outfile.close();
|
||||
|
||||
emit updateProgress(100);
|
||||
|
||||
@@ -48,7 +48,7 @@ namespace BitTorrent
|
||||
QStringList urlSeeds;
|
||||
};
|
||||
|
||||
class TorrentCreatorThread : public QThread
|
||||
class TorrentCreatorThread final : public QThread
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -27,84 +27,30 @@
|
||||
* exception statement from your version.
|
||||
*/
|
||||
|
||||
#ifndef BITTORRENT_TORRENTHANDLE_H
|
||||
#define BITTORRENT_TORRENTHANDLE_H
|
||||
#pragma once
|
||||
|
||||
#include <functional>
|
||||
|
||||
#include <libtorrent/fwd.hpp>
|
||||
#include <libtorrent/torrent_handle.hpp>
|
||||
#include <libtorrent/torrent_status.hpp>
|
||||
|
||||
#include <QDateTime>
|
||||
#include <QHash>
|
||||
#include <QObject>
|
||||
#include <QQueue>
|
||||
#include <QMetaType>
|
||||
#include <QSet>
|
||||
#include <QString>
|
||||
#include <QVector>
|
||||
|
||||
#include "private/speedmonitor.h"
|
||||
#include "infohash.h"
|
||||
#include "torrentinfo.h"
|
||||
|
||||
extern const QString QB_EXT;
|
||||
|
||||
class QBitArray;
|
||||
class QDateTime;
|
||||
class QStringList;
|
||||
class QUrl;
|
||||
|
||||
extern const QString QB_EXT;
|
||||
|
||||
namespace BitTorrent
|
||||
{
|
||||
enum class DownloadPriority;
|
||||
class InfoHash;
|
||||
class PeerInfo;
|
||||
class Session;
|
||||
class TorrentInfo;
|
||||
class TrackerEntry;
|
||||
struct AddTorrentParams;
|
||||
struct PeerAddress;
|
||||
|
||||
struct CreateTorrentParams
|
||||
{
|
||||
bool restored; // is existing torrent job?
|
||||
// for both new and restored torrents
|
||||
QString name;
|
||||
QString category;
|
||||
QSet<QString> tags;
|
||||
QString savePath;
|
||||
bool disableTempPath;
|
||||
bool sequential;
|
||||
bool firstLastPiecePriority;
|
||||
bool hasSeedStatus;
|
||||
bool skipChecking;
|
||||
bool hasRootFolder;
|
||||
bool forced;
|
||||
bool paused;
|
||||
int uploadLimit;
|
||||
int downloadLimit;
|
||||
// for new torrents
|
||||
QVector<DownloadPriority> filePriorities;
|
||||
QDateTime addedTime;
|
||||
// for restored torrents
|
||||
qreal ratioLimit;
|
||||
int seedingTimeLimit;
|
||||
|
||||
CreateTorrentParams();
|
||||
explicit CreateTorrentParams(const AddTorrentParams ¶ms);
|
||||
};
|
||||
|
||||
struct TrackerInfo
|
||||
{
|
||||
QString lastMessage;
|
||||
int numPeers = 0;
|
||||
};
|
||||
|
||||
enum class MoveStorageMode
|
||||
{
|
||||
KeepExistingFiles,
|
||||
Overwrite
|
||||
};
|
||||
|
||||
enum class TorrentState
|
||||
{
|
||||
Unknown = -1,
|
||||
@@ -135,13 +81,16 @@ namespace BitTorrent
|
||||
Error
|
||||
};
|
||||
|
||||
struct TrackerInfo
|
||||
{
|
||||
QString lastMessage;
|
||||
int numPeers = 0;
|
||||
};
|
||||
|
||||
uint qHash(TorrentState key, uint seed);
|
||||
|
||||
class TorrentHandle : public QObject
|
||||
class TorrentHandle
|
||||
{
|
||||
Q_DISABLE_COPY(TorrentHandle)
|
||||
Q_DECLARE_TR_FUNCTIONS(BitTorrent::TorrentHandle)
|
||||
|
||||
public:
|
||||
static const qreal USE_GLOBAL_RATIO;
|
||||
static const qreal NO_RATIO_LIMIT;
|
||||
@@ -152,24 +101,21 @@ namespace BitTorrent
|
||||
static const qreal MAX_RATIO;
|
||||
static const int MAX_SEEDING_TIME;
|
||||
|
||||
TorrentHandle(Session *session, const lt::torrent_handle &nativeHandle,
|
||||
const CreateTorrentParams ¶ms);
|
||||
~TorrentHandle();
|
||||
virtual ~TorrentHandle() = default;
|
||||
|
||||
bool isValid() const;
|
||||
InfoHash hash() const;
|
||||
QString name() const;
|
||||
QDateTime creationDate() const;
|
||||
QString creator() const;
|
||||
QString comment() const;
|
||||
bool isPrivate() const;
|
||||
qlonglong totalSize() const;
|
||||
qlonglong wantedSize() const;
|
||||
qlonglong completedSize() const;
|
||||
qlonglong incompletedSize() const;
|
||||
qlonglong pieceLength() const;
|
||||
qlonglong wastedSize() const;
|
||||
QString currentTracker() const;
|
||||
virtual InfoHash hash() const = 0;
|
||||
virtual QString name() const = 0;
|
||||
virtual QDateTime creationDate() const = 0;
|
||||
virtual QString creator() const = 0;
|
||||
virtual QString comment() const = 0;
|
||||
virtual bool isPrivate() const = 0;
|
||||
virtual qlonglong totalSize() const = 0;
|
||||
virtual qlonglong wantedSize() const = 0;
|
||||
virtual qlonglong completedSize() const = 0;
|
||||
virtual qlonglong incompletedSize() const = 0;
|
||||
virtual qlonglong pieceLength() const = 0;
|
||||
virtual qlonglong wastedSize() const = 0;
|
||||
virtual QString currentTracker() const = 0;
|
||||
|
||||
// 1. savePath() - the path where all the files and subfolders of torrent are stored (as always).
|
||||
// 2. rootPath() - absolute path of torrent file tree (save path + first item from 1st torrent file path).
|
||||
@@ -214,237 +160,140 @@ namespace BitTorrent
|
||||
// | B | /home/user/torrents/torrentB | /home/user/torrents/torrentB/subdir1/file1 |
|
||||
// | C | /home/user/torrents/file1 | /home/user/torrents/file1 |
|
||||
|
||||
QString savePath(bool actual = false) const;
|
||||
QString rootPath(bool actual = false) const;
|
||||
QString contentPath(bool actual = false) const;
|
||||
virtual QString savePath(bool actual = false) const = 0;
|
||||
virtual QString rootPath(bool actual = false) const = 0;
|
||||
virtual QString contentPath(bool actual = false) const = 0;
|
||||
|
||||
bool useTempPath() const;
|
||||
virtual bool useTempPath() const = 0;
|
||||
|
||||
bool isAutoTMMEnabled() const;
|
||||
void setAutoTMMEnabled(bool enabled);
|
||||
QString category() const;
|
||||
bool belongsToCategory(const QString &category) const;
|
||||
bool setCategory(const QString &category);
|
||||
virtual bool isAutoTMMEnabled() const = 0;
|
||||
virtual void setAutoTMMEnabled(bool enabled) = 0;
|
||||
virtual QString category() const = 0;
|
||||
virtual bool belongsToCategory(const QString &category) const = 0;
|
||||
virtual bool setCategory(const QString &category) = 0;
|
||||
|
||||
QSet<QString> tags() const;
|
||||
bool hasTag(const QString &tag) const;
|
||||
bool addTag(const QString &tag);
|
||||
bool removeTag(const QString &tag);
|
||||
void removeAllTags();
|
||||
virtual QSet<QString> tags() const = 0;
|
||||
virtual bool hasTag(const QString &tag) const = 0;
|
||||
virtual bool addTag(const QString &tag) = 0;
|
||||
virtual bool removeTag(const QString &tag) = 0;
|
||||
virtual void removeAllTags() = 0;
|
||||
|
||||
bool hasRootFolder() const;
|
||||
virtual bool hasRootFolder() const = 0;
|
||||
|
||||
int filesCount() const;
|
||||
int piecesCount() const;
|
||||
int piecesHave() const;
|
||||
qreal progress() const;
|
||||
QDateTime addedTime() const;
|
||||
qreal ratioLimit() const;
|
||||
int seedingTimeLimit() const;
|
||||
virtual int filesCount() const = 0;
|
||||
virtual int piecesCount() const = 0;
|
||||
virtual int piecesHave() const = 0;
|
||||
virtual qreal progress() const = 0;
|
||||
virtual QDateTime addedTime() const = 0;
|
||||
virtual qreal ratioLimit() const = 0;
|
||||
virtual int seedingTimeLimit() const = 0;
|
||||
|
||||
QString filePath(int index) const;
|
||||
QString fileName(int index) const;
|
||||
qlonglong fileSize(int index) const;
|
||||
QStringList absoluteFilePaths() const;
|
||||
QStringList absoluteFilePathsUnwanted() const;
|
||||
QVector<DownloadPriority> filePriorities() const;
|
||||
|
||||
TorrentInfo info() const;
|
||||
bool isSeed() const;
|
||||
bool isPaused() const;
|
||||
bool isResumed() const;
|
||||
bool isQueued() const;
|
||||
bool isForced() const;
|
||||
bool isChecking() const;
|
||||
bool isDownloading() const;
|
||||
bool isUploading() const;
|
||||
bool isCompleted() const;
|
||||
bool isActive() const;
|
||||
bool isInactive() const;
|
||||
bool isErrored() const;
|
||||
bool isSequentialDownload() const;
|
||||
bool hasFirstLastPiecePriority() const;
|
||||
TorrentState state() const;
|
||||
bool hasMetadata() const;
|
||||
bool hasMissingFiles() const;
|
||||
bool hasError() const;
|
||||
bool hasFilteredPieces() const;
|
||||
int queuePosition() const;
|
||||
QVector<TrackerEntry> trackers() const;
|
||||
QHash<QString, TrackerInfo> trackerInfos() const;
|
||||
QVector<QUrl> urlSeeds() const;
|
||||
QString error() const;
|
||||
qlonglong totalDownload() const;
|
||||
qlonglong totalUpload() const;
|
||||
qlonglong activeTime() const;
|
||||
qlonglong finishedTime() const;
|
||||
qlonglong seedingTime() const;
|
||||
qlonglong eta() const;
|
||||
QVector<qreal> filesProgress() const;
|
||||
int seedsCount() const;
|
||||
int peersCount() const;
|
||||
int leechsCount() const;
|
||||
int totalSeedsCount() const;
|
||||
int totalPeersCount() const;
|
||||
int totalLeechersCount() const;
|
||||
int completeCount() const;
|
||||
int incompleteCount() const;
|
||||
QDateTime lastSeenComplete() const;
|
||||
QDateTime completedTime() const;
|
||||
qlonglong timeSinceUpload() const;
|
||||
qlonglong timeSinceDownload() const;
|
||||
qlonglong timeSinceActivity() const;
|
||||
int downloadLimit() const;
|
||||
int uploadLimit() const;
|
||||
bool superSeeding() const;
|
||||
QVector<PeerInfo> peers() const;
|
||||
QBitArray pieces() const;
|
||||
QBitArray downloadingPieces() const;
|
||||
QVector<int> pieceAvailability() const;
|
||||
qreal distributedCopies() const;
|
||||
qreal maxRatio() const;
|
||||
int maxSeedingTime() const;
|
||||
qreal realRatio() const;
|
||||
int uploadPayloadRate() const;
|
||||
int downloadPayloadRate() const;
|
||||
qlonglong totalPayloadUpload() const;
|
||||
qlonglong totalPayloadDownload() const;
|
||||
int connectionsCount() const;
|
||||
int connectionsLimit() const;
|
||||
qlonglong nextAnnounce() const;
|
||||
|
||||
void setName(const QString &name);
|
||||
void setSequentialDownload(bool enable);
|
||||
void toggleSequentialDownload();
|
||||
void setFirstLastPiecePriority(bool enabled);
|
||||
void toggleFirstLastPiecePriority();
|
||||
void pause();
|
||||
void resume(bool forced = false);
|
||||
void move(QString path);
|
||||
void forceReannounce(int index = -1);
|
||||
void forceDHTAnnounce();
|
||||
void forceRecheck();
|
||||
void renameFile(int index, const QString &name);
|
||||
void prioritizeFiles(const QVector<DownloadPriority> &priorities);
|
||||
void setRatioLimit(qreal limit);
|
||||
void setSeedingTimeLimit(int limit);
|
||||
void setUploadLimit(int limit);
|
||||
void setDownloadLimit(int limit);
|
||||
void setSuperSeeding(bool enable);
|
||||
void flushCache() const;
|
||||
void addTrackers(const QVector<TrackerEntry> &trackers);
|
||||
void replaceTrackers(const QVector<TrackerEntry> &trackers);
|
||||
void addUrlSeeds(const QVector<QUrl> &urlSeeds);
|
||||
void removeUrlSeeds(const QVector<QUrl> &urlSeeds);
|
||||
bool connectPeer(const PeerAddress &peerAddress);
|
||||
|
||||
QString toMagnetUri() const;
|
||||
|
||||
bool needSaveResumeData() const;
|
||||
|
||||
// Session interface
|
||||
lt::torrent_handle nativeHandle() const;
|
||||
|
||||
void handleAlert(const lt::alert *a);
|
||||
void handleStateUpdate(const lt::torrent_status &nativeStatus);
|
||||
void handleTempPathChanged();
|
||||
void handleCategorySavePathChanged();
|
||||
void handleAppendExtensionToggled();
|
||||
void saveResumeData();
|
||||
void handleStorageMoved(const QString &newPath, const QString &errorMessage);
|
||||
virtual QString filePath(int index) const = 0;
|
||||
virtual QString fileName(int index) const = 0;
|
||||
virtual qlonglong fileSize(int index) const = 0;
|
||||
virtual QStringList absoluteFilePaths() const = 0;
|
||||
virtual QStringList absoluteFilePathsUnwanted() const = 0;
|
||||
virtual QVector<DownloadPriority> filePriorities() const = 0;
|
||||
|
||||
virtual TorrentInfo info() const = 0;
|
||||
virtual bool isSeed() const = 0;
|
||||
virtual bool isPaused() const = 0;
|
||||
virtual bool isResumed() const = 0;
|
||||
virtual bool isQueued() const = 0;
|
||||
virtual bool isForced() const = 0;
|
||||
virtual bool isChecking() const = 0;
|
||||
virtual bool isDownloading() const = 0;
|
||||
virtual bool isUploading() const = 0;
|
||||
virtual bool isCompleted() const = 0;
|
||||
virtual bool isActive() const = 0;
|
||||
virtual bool isInactive() const = 0;
|
||||
virtual bool isErrored() const = 0;
|
||||
virtual bool isSequentialDownload() const = 0;
|
||||
virtual bool hasFirstLastPiecePriority() const = 0;
|
||||
virtual TorrentState state() const = 0;
|
||||
virtual bool hasMetadata() const = 0;
|
||||
virtual bool hasMissingFiles() const = 0;
|
||||
virtual bool hasError() const = 0;
|
||||
virtual bool hasFilteredPieces() const = 0;
|
||||
virtual int queuePosition() const = 0;
|
||||
virtual QVector<TrackerEntry> trackers() const = 0;
|
||||
virtual QHash<QString, TrackerInfo> trackerInfos() const = 0;
|
||||
virtual QVector<QUrl> urlSeeds() const = 0;
|
||||
virtual QString error() const = 0;
|
||||
virtual qlonglong totalDownload() const = 0;
|
||||
virtual qlonglong totalUpload() const = 0;
|
||||
virtual qlonglong activeTime() const = 0;
|
||||
virtual qlonglong finishedTime() const = 0;
|
||||
virtual qlonglong seedingTime() const = 0;
|
||||
virtual qlonglong eta() const = 0;
|
||||
virtual QVector<qreal> filesProgress() const = 0;
|
||||
virtual int seedsCount() const = 0;
|
||||
virtual int peersCount() const = 0;
|
||||
virtual int leechsCount() const = 0;
|
||||
virtual int totalSeedsCount() const = 0;
|
||||
virtual int totalPeersCount() const = 0;
|
||||
virtual int totalLeechersCount() const = 0;
|
||||
virtual int completeCount() const = 0;
|
||||
virtual int incompleteCount() const = 0;
|
||||
virtual QDateTime lastSeenComplete() const = 0;
|
||||
virtual QDateTime completedTime() const = 0;
|
||||
virtual qlonglong timeSinceUpload() const = 0;
|
||||
virtual qlonglong timeSinceDownload() const = 0;
|
||||
virtual qlonglong timeSinceActivity() const = 0;
|
||||
virtual int downloadLimit() const = 0;
|
||||
virtual int uploadLimit() const = 0;
|
||||
virtual bool superSeeding() const = 0;
|
||||
virtual QVector<PeerInfo> peers() const = 0;
|
||||
virtual QBitArray pieces() const = 0;
|
||||
virtual QBitArray downloadingPieces() const = 0;
|
||||
virtual QVector<int> pieceAvailability() const = 0;
|
||||
virtual qreal distributedCopies() const = 0;
|
||||
virtual qreal maxRatio() const = 0;
|
||||
virtual int maxSeedingTime() const = 0;
|
||||
virtual qreal realRatio() const = 0;
|
||||
virtual int uploadPayloadRate() const = 0;
|
||||
virtual int downloadPayloadRate() const = 0;
|
||||
virtual qlonglong totalPayloadUpload() const = 0;
|
||||
virtual qlonglong totalPayloadDownload() const = 0;
|
||||
virtual int connectionsCount() const = 0;
|
||||
virtual int connectionsLimit() const = 0;
|
||||
virtual qlonglong nextAnnounce() const = 0;
|
||||
/**
|
||||
* @brief fraction of file pieces that are available at least from one peer
|
||||
*
|
||||
* This is not the same as torrrent availability, it is just a fraction of pieces
|
||||
* that can be downloaded right now. It varies between 0 to 1.
|
||||
*/
|
||||
QVector<qreal> availableFileFractions() const;
|
||||
virtual QVector<qreal> availableFileFractions() const = 0;
|
||||
|
||||
private:
|
||||
typedef std::function<void ()> EventTrigger;
|
||||
virtual void setName(const QString &name) = 0;
|
||||
virtual void setSequentialDownload(bool enable) = 0;
|
||||
virtual void setFirstLastPiecePriority(bool enabled) = 0;
|
||||
virtual void pause() = 0;
|
||||
virtual void resume(bool forced = false) = 0;
|
||||
virtual void move(QString path) = 0;
|
||||
virtual void forceReannounce(int index = -1) = 0;
|
||||
virtual void forceDHTAnnounce() = 0;
|
||||
virtual void forceRecheck() = 0;
|
||||
virtual void renameFile(int index, const QString &name) = 0;
|
||||
virtual void prioritizeFiles(const QVector<DownloadPriority> &priorities) = 0;
|
||||
virtual void setRatioLimit(qreal limit) = 0;
|
||||
virtual void setSeedingTimeLimit(int limit) = 0;
|
||||
virtual void setUploadLimit(int limit) = 0;
|
||||
virtual void setDownloadLimit(int limit) = 0;
|
||||
virtual void setSuperSeeding(bool enable) = 0;
|
||||
virtual void flushCache() const = 0;
|
||||
virtual void addTrackers(const QVector<TrackerEntry> &trackers) = 0;
|
||||
virtual void replaceTrackers(const QVector<TrackerEntry> &trackers) = 0;
|
||||
virtual void addUrlSeeds(const QVector<QUrl> &urlSeeds) = 0;
|
||||
virtual void removeUrlSeeds(const QVector<QUrl> &urlSeeds) = 0;
|
||||
virtual bool connectPeer(const PeerAddress &peerAddress) = 0;
|
||||
|
||||
#if (LIBTORRENT_VERSION_NUM < 10200)
|
||||
using LTFileIndex = int;
|
||||
#else
|
||||
using LTFileIndex = lt::file_index_t;
|
||||
#endif
|
||||
virtual QString createMagnetURI() const = 0;
|
||||
|
||||
void updateStatus();
|
||||
void updateStatus(const lt::torrent_status &nativeStatus);
|
||||
void updateState();
|
||||
void updateTorrentInfo();
|
||||
|
||||
void handleFastResumeRejectedAlert(const lt::fastresume_rejected_alert *p);
|
||||
void handleFileCompletedAlert(const lt::file_completed_alert *p);
|
||||
void handleFileRenamedAlert(const lt::file_renamed_alert *p);
|
||||
void handleFileRenameFailedAlert(const lt::file_rename_failed_alert *p);
|
||||
void handleMetadataReceivedAlert(const lt::metadata_received_alert *p);
|
||||
void handlePerformanceAlert(const lt::performance_alert *p) const;
|
||||
void handleSaveResumeDataAlert(const lt::save_resume_data_alert *p);
|
||||
void handleSaveResumeDataFailedAlert(const lt::save_resume_data_failed_alert *p);
|
||||
void handleTorrentCheckedAlert(const lt::torrent_checked_alert *p);
|
||||
void handleTorrentFinishedAlert(const lt::torrent_finished_alert *p);
|
||||
void handleTorrentPausedAlert(const lt::torrent_paused_alert *p);
|
||||
void handleTorrentResumedAlert(const lt::torrent_resumed_alert *p);
|
||||
void handleTrackerErrorAlert(const lt::tracker_error_alert *p);
|
||||
void handleTrackerReplyAlert(const lt::tracker_reply_alert *p);
|
||||
void handleTrackerWarningAlert(const lt::tracker_warning_alert *p);
|
||||
|
||||
void resume_impl(bool forced);
|
||||
bool isMoveInProgress() const;
|
||||
QString actualStorageLocation() const;
|
||||
bool isAutoManaged() const;
|
||||
void setAutoManaged(bool enable);
|
||||
|
||||
void adjustActualSavePath();
|
||||
void adjustActualSavePath_impl();
|
||||
void move_impl(QString path, MoveStorageMode mode);
|
||||
void moveStorage(const QString &newPath, MoveStorageMode mode);
|
||||
void manageIncompleteFiles();
|
||||
void setFirstLastPiecePriorityImpl(bool enabled, const QVector<DownloadPriority> &updatedFilePrio = {});
|
||||
|
||||
Session *const m_session;
|
||||
lt::torrent_handle m_nativeHandle;
|
||||
lt::torrent_status m_nativeStatus;
|
||||
TorrentState m_state;
|
||||
TorrentInfo m_torrentInfo;
|
||||
SpeedMonitor m_speedMonitor;
|
||||
|
||||
InfoHash m_hash;
|
||||
|
||||
bool m_storageIsMoving = false;
|
||||
// m_moveFinishedTriggers is activated only when the following conditions are met:
|
||||
// all file rename jobs complete, all file move jobs complete
|
||||
QQueue<EventTrigger> m_moveFinishedTriggers;
|
||||
int m_renameCount;
|
||||
|
||||
// Until libtorrent provide an "old_name" field in `file_renamed_alert`
|
||||
// we will rely on this workaround to remove empty leftover folders
|
||||
QHash<LTFileIndex, QVector<QString>> m_oldPath;
|
||||
|
||||
bool m_useAutoTMM;
|
||||
|
||||
// Persistent data
|
||||
QString m_name;
|
||||
QString m_savePath;
|
||||
QString m_category;
|
||||
QSet<QString> m_tags;
|
||||
bool m_hasSeedStatus;
|
||||
qreal m_ratioLimit;
|
||||
int m_seedingTimeLimit;
|
||||
bool m_tempPathDisabled;
|
||||
bool m_fastresumeDataRejected;
|
||||
bool m_hasMissingFiles;
|
||||
bool m_hasRootFolder;
|
||||
bool m_needsToSetFirstLastPiecePriority;
|
||||
|
||||
QHash<QString, TrackerInfo> m_trackerInfos;
|
||||
|
||||
bool m_unchecked = false;
|
||||
void toggleSequentialDownload();
|
||||
void toggleFirstLastPiecePriority();
|
||||
};
|
||||
}
|
||||
|
||||
Q_DECLARE_METATYPE(BitTorrent::TorrentState)
|
||||
|
||||
#endif // BITTORRENT_TORRENTHANDLE_H
|
||||
|
||||
2142
src/base/bittorrent/torrenthandleimpl.cpp
Normal file
2142
src/base/bittorrent/torrenthandleimpl.cpp
Normal file
File diff suppressed because it is too large
Load Diff
338
src/base/bittorrent/torrenthandleimpl.h
Normal file
338
src/base/bittorrent/torrenthandleimpl.h
Normal file
@@ -0,0 +1,338 @@
|
||||
/*
|
||||
* Bittorrent Client using Qt and libtorrent.
|
||||
* Copyright (C) 2015 Vladimir Golovnev <glassez@yandex.ru>
|
||||
* 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
|
||||
* as published by the Free Software Foundation; either version 2
|
||||
* of the License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
*
|
||||
* In addition, as a special exception, the copyright holders give permission to
|
||||
* link this program with the OpenSSL project's "OpenSSL" library (or with
|
||||
* modified versions of it that use the same license as the "OpenSSL" library),
|
||||
* and distribute the linked executables. You must obey the GNU General Public
|
||||
* License in all respects for all of the code used other than "OpenSSL". If you
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <functional>
|
||||
|
||||
#include <libtorrent/fwd.hpp>
|
||||
#include <libtorrent/torrent_handle.hpp>
|
||||
#include <libtorrent/torrent_status.hpp>
|
||||
|
||||
#include <QDateTime>
|
||||
#include <QHash>
|
||||
#include <QObject>
|
||||
#include <QQueue>
|
||||
#include <QSet>
|
||||
#include <QString>
|
||||
#include <QVector>
|
||||
|
||||
#include "private/speedmonitor.h"
|
||||
#include "infohash.h"
|
||||
#include "torrenthandle.h"
|
||||
#include "torrentinfo.h"
|
||||
|
||||
namespace BitTorrent
|
||||
{
|
||||
class Session;
|
||||
struct AddTorrentParams;
|
||||
|
||||
struct CreateTorrentParams
|
||||
{
|
||||
CreateTorrentParams() = default;
|
||||
explicit CreateTorrentParams(const AddTorrentParams ¶ms);
|
||||
|
||||
// for both new and restored torrents
|
||||
QString name;
|
||||
QString category;
|
||||
QSet<QString> tags;
|
||||
QString savePath;
|
||||
int uploadLimit = -1;
|
||||
int downloadLimit = -1;
|
||||
bool disableTempPath = false;
|
||||
bool sequential = false;
|
||||
bool firstLastPiecePriority = false;
|
||||
bool hasSeedStatus = false;
|
||||
bool skipChecking = false;
|
||||
bool hasRootFolder = true;
|
||||
bool forced = false;
|
||||
bool paused = false;
|
||||
bool restored = false; // is existing torrent job?
|
||||
|
||||
// for new torrents
|
||||
QVector<DownloadPriority> filePriorities;
|
||||
QDateTime addedTime;
|
||||
|
||||
// for restored torrents
|
||||
qreal ratioLimit = TorrentHandle::USE_GLOBAL_RATIO;
|
||||
int seedingTimeLimit = TorrentHandle::USE_GLOBAL_SEEDING_TIME;
|
||||
};
|
||||
|
||||
enum class MoveStorageMode
|
||||
{
|
||||
KeepExistingFiles,
|
||||
Overwrite
|
||||
};
|
||||
|
||||
class TorrentHandleImpl final : public QObject, public TorrentHandle
|
||||
{
|
||||
Q_DISABLE_COPY(TorrentHandleImpl)
|
||||
Q_DECLARE_TR_FUNCTIONS(BitTorrent::TorrentHandleImpl)
|
||||
|
||||
public:
|
||||
TorrentHandleImpl(Session *session, const lt::torrent_handle &nativeHandle,
|
||||
const CreateTorrentParams ¶ms);
|
||||
~TorrentHandleImpl() override;
|
||||
|
||||
bool isValid() const;
|
||||
|
||||
InfoHash hash() const override;
|
||||
QString name() const override;
|
||||
QDateTime creationDate() const override;
|
||||
QString creator() const override;
|
||||
QString comment() const override;
|
||||
bool isPrivate() const override;
|
||||
qlonglong totalSize() const override;
|
||||
qlonglong wantedSize() const override;
|
||||
qlonglong completedSize() const override;
|
||||
qlonglong incompletedSize() const override;
|
||||
qlonglong pieceLength() const override;
|
||||
qlonglong wastedSize() const override;
|
||||
QString currentTracker() const override;
|
||||
|
||||
QString savePath(bool actual = false) const override;
|
||||
QString rootPath(bool actual = false) const override;
|
||||
QString contentPath(bool actual = false) const override;
|
||||
|
||||
bool useTempPath() const override;
|
||||
|
||||
bool isAutoTMMEnabled() const override;
|
||||
void setAutoTMMEnabled(bool enabled) override;
|
||||
QString category() const override;
|
||||
bool belongsToCategory(const QString &category) const override;
|
||||
bool setCategory(const QString &category) override;
|
||||
|
||||
QSet<QString> tags() const override;
|
||||
bool hasTag(const QString &tag) const override;
|
||||
bool addTag(const QString &tag) override;
|
||||
bool removeTag(const QString &tag) override;
|
||||
void removeAllTags() override;
|
||||
|
||||
bool hasRootFolder() const override;
|
||||
|
||||
int filesCount() const override;
|
||||
int piecesCount() const override;
|
||||
int piecesHave() const override;
|
||||
qreal progress() const override;
|
||||
QDateTime addedTime() const override;
|
||||
qreal ratioLimit() const override;
|
||||
int seedingTimeLimit() const override;
|
||||
|
||||
QString filePath(int index) const override;
|
||||
QString fileName(int index) const override;
|
||||
qlonglong fileSize(int index) const override;
|
||||
QStringList absoluteFilePaths() const override;
|
||||
QStringList absoluteFilePathsUnwanted() const override;
|
||||
QVector<DownloadPriority> filePriorities() const override;
|
||||
|
||||
TorrentInfo info() const override;
|
||||
bool isSeed() const override;
|
||||
bool isPaused() const override;
|
||||
bool isResumed() const override;
|
||||
bool isQueued() const override;
|
||||
bool isForced() const override;
|
||||
bool isChecking() const override;
|
||||
bool isDownloading() const override;
|
||||
bool isUploading() const override;
|
||||
bool isCompleted() const override;
|
||||
bool isActive() const override;
|
||||
bool isInactive() const override;
|
||||
bool isErrored() const override;
|
||||
bool isSequentialDownload() const override;
|
||||
bool hasFirstLastPiecePriority() const override;
|
||||
TorrentState state() const override;
|
||||
bool hasMetadata() const override;
|
||||
bool hasMissingFiles() const override;
|
||||
bool hasError() const override;
|
||||
bool hasFilteredPieces() const override;
|
||||
int queuePosition() const override;
|
||||
QVector<TrackerEntry> trackers() const override;
|
||||
QHash<QString, TrackerInfo> trackerInfos() const override;
|
||||
QVector<QUrl> urlSeeds() const override;
|
||||
QString error() const override;
|
||||
qlonglong totalDownload() const override;
|
||||
qlonglong totalUpload() const override;
|
||||
qlonglong activeTime() const override;
|
||||
qlonglong finishedTime() const override;
|
||||
qlonglong seedingTime() const override;
|
||||
qlonglong eta() const override;
|
||||
QVector<qreal> filesProgress() const override;
|
||||
int seedsCount() const override;
|
||||
int peersCount() const override;
|
||||
int leechsCount() const override;
|
||||
int totalSeedsCount() const override;
|
||||
int totalPeersCount() const override;
|
||||
int totalLeechersCount() const override;
|
||||
int completeCount() const override;
|
||||
int incompleteCount() const override;
|
||||
QDateTime lastSeenComplete() const override;
|
||||
QDateTime completedTime() const override;
|
||||
qlonglong timeSinceUpload() const override;
|
||||
qlonglong timeSinceDownload() const override;
|
||||
qlonglong timeSinceActivity() const override;
|
||||
int downloadLimit() const override;
|
||||
int uploadLimit() const override;
|
||||
bool superSeeding() const override;
|
||||
QVector<PeerInfo> peers() const override;
|
||||
QBitArray pieces() const override;
|
||||
QBitArray downloadingPieces() const override;
|
||||
QVector<int> pieceAvailability() const override;
|
||||
qreal distributedCopies() const override;
|
||||
qreal maxRatio() const override;
|
||||
int maxSeedingTime() const override;
|
||||
qreal realRatio() const override;
|
||||
int uploadPayloadRate() const override;
|
||||
int downloadPayloadRate() const override;
|
||||
qlonglong totalPayloadUpload() const override;
|
||||
qlonglong totalPayloadDownload() const override;
|
||||
int connectionsCount() const override;
|
||||
int connectionsLimit() const override;
|
||||
qlonglong nextAnnounce() const override;
|
||||
QVector<qreal> availableFileFractions() const override;
|
||||
|
||||
void setName(const QString &name) override;
|
||||
void setSequentialDownload(bool enable) override;
|
||||
void setFirstLastPiecePriority(bool enabled) override;
|
||||
void pause() override;
|
||||
void resume(bool forced = false) override;
|
||||
void move(QString path) override;
|
||||
void forceReannounce(int index = -1) override;
|
||||
void forceDHTAnnounce() override;
|
||||
void forceRecheck() override;
|
||||
void renameFile(int index, const QString &name) override;
|
||||
void prioritizeFiles(const QVector<DownloadPriority> &priorities) override;
|
||||
void setRatioLimit(qreal limit) override;
|
||||
void setSeedingTimeLimit(int limit) override;
|
||||
void setUploadLimit(int limit) override;
|
||||
void setDownloadLimit(int limit) override;
|
||||
void setSuperSeeding(bool enable) override;
|
||||
void flushCache() const override;
|
||||
void addTrackers(const QVector<TrackerEntry> &trackers) override;
|
||||
void replaceTrackers(const QVector<TrackerEntry> &trackers) override;
|
||||
void addUrlSeeds(const QVector<QUrl> &urlSeeds) override;
|
||||
void removeUrlSeeds(const QVector<QUrl> &urlSeeds) override;
|
||||
bool connectPeer(const PeerAddress &peerAddress) override;
|
||||
|
||||
QString createMagnetURI() const override;
|
||||
|
||||
bool needSaveResumeData() const;
|
||||
|
||||
// Session interface
|
||||
lt::torrent_handle nativeHandle() const;
|
||||
|
||||
void handleAlert(const lt::alert *a);
|
||||
void handleStateUpdate(const lt::torrent_status &nativeStatus);
|
||||
void handleTempPathChanged();
|
||||
void handleCategorySavePathChanged();
|
||||
void handleAppendExtensionToggled();
|
||||
void saveResumeData();
|
||||
void handleStorageMoved(const QString &newPath, const QString &errorMessage);
|
||||
|
||||
private:
|
||||
typedef std::function<void ()> EventTrigger;
|
||||
|
||||
#if (LIBTORRENT_VERSION_NUM < 10200)
|
||||
using LTFileIndex = int;
|
||||
#else
|
||||
using LTFileIndex = lt::file_index_t;
|
||||
#endif
|
||||
|
||||
void updateStatus();
|
||||
void updateStatus(const lt::torrent_status &nativeStatus);
|
||||
void updateState();
|
||||
void updateTorrentInfo();
|
||||
|
||||
void handleFastResumeRejectedAlert(const lt::fastresume_rejected_alert *p);
|
||||
void handleFileCompletedAlert(const lt::file_completed_alert *p);
|
||||
void handleFileRenamedAlert(const lt::file_renamed_alert *p);
|
||||
void handleFileRenameFailedAlert(const lt::file_rename_failed_alert *p);
|
||||
void handleMetadataReceivedAlert(const lt::metadata_received_alert *p);
|
||||
void handlePerformanceAlert(const lt::performance_alert *p) const;
|
||||
void handleSaveResumeDataAlert(const lt::save_resume_data_alert *p);
|
||||
void handleSaveResumeDataFailedAlert(const lt::save_resume_data_failed_alert *p);
|
||||
void handleTorrentCheckedAlert(const lt::torrent_checked_alert *p);
|
||||
void handleTorrentFinishedAlert(const lt::torrent_finished_alert *p);
|
||||
void handleTorrentPausedAlert(const lt::torrent_paused_alert *p);
|
||||
void handleTorrentResumedAlert(const lt::torrent_resumed_alert *p);
|
||||
void handleTrackerErrorAlert(const lt::tracker_error_alert *p);
|
||||
void handleTrackerReplyAlert(const lt::tracker_reply_alert *p);
|
||||
void handleTrackerWarningAlert(const lt::tracker_warning_alert *p);
|
||||
|
||||
void resume_impl(bool forced);
|
||||
bool isMoveInProgress() const;
|
||||
QString actualStorageLocation() const;
|
||||
bool isAutoManaged() const;
|
||||
void setAutoManaged(bool enable);
|
||||
|
||||
void adjustActualSavePath();
|
||||
void adjustActualSavePath_impl();
|
||||
void move_impl(QString path, MoveStorageMode mode);
|
||||
void moveStorage(const QString &newPath, MoveStorageMode mode);
|
||||
void manageIncompleteFiles();
|
||||
void setFirstLastPiecePriorityImpl(bool enabled, const QVector<DownloadPriority> &updatedFilePrio = {});
|
||||
|
||||
Session *const m_session;
|
||||
lt::torrent_handle m_nativeHandle;
|
||||
lt::torrent_status m_nativeStatus;
|
||||
TorrentState m_state = TorrentState::Unknown;
|
||||
TorrentInfo m_torrentInfo;
|
||||
SpeedMonitor m_speedMonitor;
|
||||
|
||||
InfoHash m_hash;
|
||||
|
||||
// m_moveFinishedTriggers is activated only when the following conditions are met:
|
||||
// all file rename jobs complete, all file move jobs complete
|
||||
QQueue<EventTrigger> m_moveFinishedTriggers;
|
||||
int m_renameCount = 0;
|
||||
bool m_storageIsMoving = false;
|
||||
|
||||
// Until libtorrent provide an "old_name" field in `file_renamed_alert`
|
||||
// we will rely on this workaround to remove empty leftover folders
|
||||
QHash<LTFileIndex, QVector<QString>> m_oldPath;
|
||||
|
||||
QHash<QString, TrackerInfo> m_trackerInfos;
|
||||
|
||||
// Persistent data
|
||||
QString m_name;
|
||||
QString m_savePath;
|
||||
QString m_category;
|
||||
QSet<QString> m_tags;
|
||||
qreal m_ratioLimit;
|
||||
int m_seedingTimeLimit;
|
||||
bool m_hasSeedStatus;
|
||||
bool m_tempPathDisabled;
|
||||
bool m_fastresumeDataRejected = false;
|
||||
bool m_hasMissingFiles = false;
|
||||
bool m_hasRootFolder;
|
||||
bool m_needsToSetFirstLastPiecePriority = false;
|
||||
bool m_useAutoTMM;
|
||||
|
||||
bool m_unchecked = false;
|
||||
};
|
||||
}
|
||||
@@ -47,6 +47,7 @@
|
||||
#include "base/exceptions.h"
|
||||
#include "base/global.h"
|
||||
#include "base/utils/fs.h"
|
||||
#include "base/utils/io.h"
|
||||
#include "base/utils/misc.h"
|
||||
#include "infohash.h"
|
||||
#include "trackerentry.h"
|
||||
@@ -166,12 +167,12 @@ void TorrentInfo::saveToFile(const QString &path) const
|
||||
#endif
|
||||
const lt::entry torrentEntry = torrentCreator.generate();
|
||||
|
||||
QByteArray out;
|
||||
out.reserve(1024 * 1024); // most torrent file sizes are under 1 MB
|
||||
lt::bencode(std::back_inserter(out), torrentEntry);
|
||||
QFile torrentFile {path};
|
||||
if (!torrentFile.open(QIODevice::WriteOnly))
|
||||
throw RuntimeError {torrentFile.errorString()};
|
||||
|
||||
QFile torrentFile{path};
|
||||
if (!torrentFile.open(QIODevice::WriteOnly) || (torrentFile.write(out) != out.size()))
|
||||
lt::bencode(Utils::IO::FileDeviceOutputIterator {torrentFile}, torrentEntry);
|
||||
if (torrentFile.error() != QFileDevice::NoError)
|
||||
throw RuntimeError {torrentFile.errorString()};
|
||||
}
|
||||
|
||||
|
||||
@@ -70,7 +70,7 @@ namespace BitTorrent
|
||||
// *Basic* Bittorrent tracker implementation
|
||||
// [BEP-3] The BitTorrent Protocol Specification
|
||||
// also see: https://wiki.theory.org/index.php/BitTorrentSpecification#Tracker_HTTP.2FHTTPS_Protocol
|
||||
class Tracker : public QObject, public Http::IRequestHandler, private Http::ResponseBuilder
|
||||
class Tracker final : public QObject, public Http::IRequestHandler, private Http::ResponseBuilder
|
||||
{
|
||||
Q_OBJECT
|
||||
Q_DISABLE_COPY(Tracker)
|
||||
|
||||
@@ -41,7 +41,7 @@ namespace Http
|
||||
class IRequestHandler;
|
||||
class Connection;
|
||||
|
||||
class Server : public QTcpServer
|
||||
class Server final : public QTcpServer
|
||||
{
|
||||
Q_OBJECT
|
||||
Q_DISABLE_COPY(Server)
|
||||
|
||||
@@ -72,7 +72,7 @@ void Logger::freeInstance()
|
||||
void Logger::addMessage(const QString &message, const Log::MsgType &type)
|
||||
{
|
||||
QWriteLocker locker(&m_lock);
|
||||
const Log::Msg msg = {m_msgCounter++, QDateTime::currentMSecsSinceEpoch(), type, message.toHtmlEscaped()};
|
||||
const Log::Msg msg = {m_msgCounter++, type, QDateTime::currentMSecsSinceEpoch(), message};
|
||||
m_messages.push_back(msg);
|
||||
locker.unlock();
|
||||
|
||||
@@ -82,7 +82,7 @@ void Logger::addMessage(const QString &message, const Log::MsgType &type)
|
||||
void Logger::addPeer(const QString &ip, const bool blocked, const QString &reason)
|
||||
{
|
||||
QWriteLocker locker(&m_lock);
|
||||
const Log::Peer msg = {m_peerCounter++, QDateTime::currentMSecsSinceEpoch(), ip.toHtmlEscaped(), blocked, reason.toHtmlEscaped()};
|
||||
const Log::Peer msg = {m_peerCounter++, blocked, QDateTime::currentMSecsSinceEpoch(), ip, reason};
|
||||
m_peers.push_back(msg);
|
||||
locker.unlock();
|
||||
|
||||
|
||||
@@ -53,17 +53,17 @@ namespace Log
|
||||
struct Msg
|
||||
{
|
||||
int id;
|
||||
qint64 timestamp;
|
||||
MsgType type;
|
||||
qint64 timestamp;
|
||||
QString message;
|
||||
};
|
||||
|
||||
struct Peer
|
||||
{
|
||||
int id;
|
||||
bool blocked;
|
||||
qint64 timestamp;
|
||||
QString ip;
|
||||
bool blocked;
|
||||
QString reason;
|
||||
};
|
||||
}
|
||||
|
||||
@@ -52,7 +52,7 @@ namespace
|
||||
// Disguise as Firefox to avoid web server banning
|
||||
const char DEFAULT_USER_AGENT[] = "Mozilla/5.0 (X11; Linux x86_64; rv:68.0) Gecko/20100101 Firefox/68.0";
|
||||
|
||||
class NetworkCookieJar : public QNetworkCookieJar
|
||||
class NetworkCookieJar final : public QNetworkCookieJar
|
||||
{
|
||||
public:
|
||||
explicit NetworkCookieJar(QObject *parent = nullptr)
|
||||
|
||||
@@ -36,7 +36,7 @@
|
||||
class QObject;
|
||||
class QUrl;
|
||||
|
||||
class DownloadHandlerImpl : public Net::DownloadHandler
|
||||
class DownloadHandlerImpl final : public Net::DownloadHandler
|
||||
{
|
||||
Q_OBJECT
|
||||
Q_DISABLE_COPY(DownloadHandlerImpl)
|
||||
|
||||
@@ -63,7 +63,7 @@ namespace Private
|
||||
};
|
||||
|
||||
/// Default implementation. Takes paths from system
|
||||
class DefaultProfile : public Profile
|
||||
class DefaultProfile final : public Profile
|
||||
{
|
||||
public:
|
||||
explicit 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 final : 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 final : public PathConverter
|
||||
{
|
||||
public:
|
||||
QString toPortablePath(const QString &path) const override;
|
||||
QString fromPortablePath(const QString &portablePath) const override;
|
||||
};
|
||||
|
||||
class Converter : public PathConverter
|
||||
class Converter final : public PathConverter
|
||||
{
|
||||
public:
|
||||
explicit Converter(const QString &basePath);
|
||||
|
||||
@@ -44,7 +44,7 @@
|
||||
|
||||
namespace
|
||||
{
|
||||
class XmlStreamEntityResolver : public QXmlStreamEntityResolver
|
||||
class XmlStreamEntityResolver final : public QXmlStreamEntityResolver
|
||||
{
|
||||
public:
|
||||
QString resolveUndeclaredEntity(const QString &name) override
|
||||
|
||||
@@ -36,7 +36,7 @@ class QStringList;
|
||||
|
||||
class FileSystemWatcher;
|
||||
|
||||
class ScanFoldersModel : public QAbstractListModel
|
||||
class ScanFoldersModel final : public QAbstractListModel
|
||||
{
|
||||
Q_OBJECT
|
||||
Q_DISABLE_COPY(ScanFoldersModel)
|
||||
|
||||
@@ -28,6 +28,7 @@
|
||||
|
||||
#include "torrentfilter.h"
|
||||
|
||||
#include "bittorrent/infohash.h"
|
||||
#include "bittorrent/torrenthandle.h"
|
||||
|
||||
const QString TorrentFilter::AnyCategory;
|
||||
|
||||
@@ -36,58 +36,60 @@
|
||||
// Because of the poor handling of UTF-8 characters in MSVC (emits warning C4819),
|
||||
// we put all problematic UTF-8 chars/strings in this file.
|
||||
// See issue #3059 for more details (https://github.com/qbittorrent/qBittorrent/issues/3059).
|
||||
const char C_INFINITY[] = "∞";
|
||||
const char C_NON_BREAKING_SPACE[] = " ";
|
||||
|
||||
const char C_COPYRIGHT[] = "©";
|
||||
const char C_INFINITY[] = "∞";
|
||||
const char C_NON_BREAKING_SPACE[] = " ";
|
||||
const char C_THIN_SPACE[] = " ";
|
||||
const char C_UTP[] = "μTP";
|
||||
|
||||
const char C_LOCALE_ARABIC[] = "عربي";
|
||||
const char C_LOCALE_ARMENIAN[] = "Հայերեն";
|
||||
const char C_LOCALE_BASQUE[] = "Euskara";
|
||||
const char C_LOCALE_BULGARIAN[] = "Български";
|
||||
const char C_LOCALE_BYELORUSSIAN[] = "Беларуская";
|
||||
const char C_LOCALE_CATALAN[] = "Català";
|
||||
const char C_LOCALE_CHINESE_SIMPLIFIED[] = "简体中文";
|
||||
const char C_LOCALE_CHINESE_TRADITIONAL_HK[] = "香港正體字";
|
||||
const char C_LOCALE_CHINESE_TRADITIONAL_TW[] = "正體中文";
|
||||
const char C_LOCALE_CROATIAN[] = "Hrvatski";
|
||||
const char C_LOCALE_CZECH[] = "Čeština";
|
||||
const char C_LOCALE_DANISH[] = "Dansk";
|
||||
const char C_LOCALE_DUTCH[] = "Nederlands";
|
||||
const char C_LOCALE_ENGLISH[] = "English";
|
||||
const char C_LOCALE_ENGLISH_AUSTRALIA[] = "English(Australia)";
|
||||
const char C_LOCALE_ENGLISH_UNITEDKINGDOM[] = "English(United Kingdom)";
|
||||
const char C_LOCALE_ESPERANTO[] = "Esperanto";
|
||||
const char C_LOCALE_FINNISH[] = "Suomi";
|
||||
const char C_LOCALE_FRENCH[] = "Français";
|
||||
const char C_LOCALE_GALICIAN[] = "Galego";
|
||||
const char C_LOCALE_GEORGIAN[] = "ქართული";
|
||||
const char C_LOCALE_GERMAN[] = "Deutsch";
|
||||
const char C_LOCALE_GREEK[] = "Ελληνικά";
|
||||
const char C_LOCALE_HEBREW[] = "עברית";
|
||||
const char C_LOCALE_HINDI[] = "हिन्दी, हिंदी";
|
||||
const char C_LOCALE_HUNGARIAN[] = "Magyar";
|
||||
const char C_LOCALE_ICELANDIC[] = "Íslenska";
|
||||
const char C_LOCALE_INDONESIAN[] = "Bahasa Indonesia";
|
||||
const char C_LOCALE_ITALIAN[] = "Italiano";
|
||||
const char C_LOCALE_DUTCH[] = "Nederlands";
|
||||
const char C_LOCALE_SPANISH[] = "Español";
|
||||
const char C_LOCALE_CATALAN[] = "Català";
|
||||
const char C_LOCALE_GALICIAN[] = "Galego";
|
||||
const char C_LOCALE_OCCITAN[] = "lenga d'òc";
|
||||
const char C_LOCALE_PORTUGUESE[] = "Português";
|
||||
const char C_LOCALE_PORTUGUESE_BRAZIL[] = "Português brasileiro";
|
||||
const char C_LOCALE_POLISH[] = "Polski";
|
||||
const char C_LOCALE_JAPANESE[] = "日本語";
|
||||
const char C_LOCALE_KOREAN[] = "한글";
|
||||
const char C_LOCALE_LATVIAN[] = "latviešu valoda";
|
||||
const char C_LOCALE_LITHUANIAN[] = "Lietuvių";
|
||||
const char C_LOCALE_MALAY[] = "بهاس ملايو";
|
||||
const char C_LOCALE_CZECH[] = "Čeština";
|
||||
const char C_LOCALE_NORWEGIAN[] = "Norsk";
|
||||
const char C_LOCALE_OCCITAN[] = "lenga d'òc";
|
||||
const char C_LOCALE_POLISH[] = "Polski";
|
||||
const char C_LOCALE_PORTUGUESE[] = "Português";
|
||||
const char C_LOCALE_PORTUGUESE_BRAZIL[] = "Português brasileiro";
|
||||
const char C_LOCALE_ROMANIAN[] = "Română";
|
||||
const char C_LOCALE_RUSSIAN[] = "Русский";
|
||||
const char C_LOCALE_SERBIAN[] = "Српски";
|
||||
const char C_LOCALE_SLOVAK[] = "Slovenčina";
|
||||
const char C_LOCALE_SLOVENIAN[] = "Slovenščina";
|
||||
const char C_LOCALE_SERBIAN[] = "Српски";
|
||||
const char C_LOCALE_CROATIAN[] = "Hrvatski";
|
||||
const char C_LOCALE_ARMENIAN[] = "Հայերեն";
|
||||
const char C_LOCALE_ROMANIAN[] = "Română";
|
||||
const char C_LOCALE_TURKISH[] = "Türkçe";
|
||||
const char C_LOCALE_GREEK[] = "Ελληνικά";
|
||||
const char C_LOCALE_SPANISH[] = "Español";
|
||||
const char C_LOCALE_SWEDISH[] = "Svenska";
|
||||
const char C_LOCALE_FINNISH[] = "Suomi";
|
||||
const char C_LOCALE_NORWEGIAN[] = "Norsk";
|
||||
const char C_LOCALE_DANISH[] = "Dansk";
|
||||
const char C_LOCALE_BULGARIAN[] = "Български";
|
||||
const char C_LOCALE_TURKISH[] = "Türkçe";
|
||||
const char C_LOCALE_UKRAINIAN[] = "Українська";
|
||||
const char C_LOCALE_UZBEK[] = "أۇزبېك";
|
||||
const char C_LOCALE_RUSSIAN[] = "Русский";
|
||||
const char C_LOCALE_JAPANESE[] = "日本語";
|
||||
const char C_LOCALE_HEBREW[] = "עברית";
|
||||
const char C_LOCALE_HINDI[] = "हिन्दी, हिंदी";
|
||||
const char C_LOCALE_ARABIC[] = "عربي";
|
||||
const char C_LOCALE_GEORGIAN[] = "ქართული";
|
||||
const char C_LOCALE_BYELORUSSIAN[] = "Беларуская";
|
||||
const char C_LOCALE_BASQUE[] = "Euskara";
|
||||
const char C_LOCALE_VIETNAMESE[] = "tiếng Việt";
|
||||
const char C_LOCALE_CHINESE_TRADITIONAL_TW[] = "正體中文";
|
||||
const char C_LOCALE_CHINESE_TRADITIONAL_HK[] = "香港正體字";
|
||||
const char C_LOCALE_CHINESE_SIMPLIFIED[] = "简体中文";
|
||||
const char C_LOCALE_KOREAN[] = "한글";
|
||||
|
||||
@@ -190,9 +190,17 @@ namespace
|
||||
path = getRegValue(hkInstallPath);
|
||||
::RegCloseKey(hkInstallPath);
|
||||
|
||||
if (!path.isEmpty() && QDir(path).exists("python.exe")) {
|
||||
found = true;
|
||||
path = QDir(path).filePath("python.exe");
|
||||
if (!path.isEmpty()) {
|
||||
const QDir baseDir {path};
|
||||
|
||||
if (baseDir.exists("python3.exe")) {
|
||||
found = true;
|
||||
path = baseDir.filePath("python3.exe");
|
||||
}
|
||||
else if (baseDir.exists("python.exe")) {
|
||||
found = true;
|
||||
path = baseDir.filePath("python.exe");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -223,9 +231,13 @@ namespace
|
||||
// Fallback: Detect python from default locations
|
||||
const QFileInfoList dirs = QDir("C:/").entryInfoList({"Python*"}, QDir::Dirs, (QDir::Name | QDir::Reversed));
|
||||
for (const QFileInfo &info : dirs) {
|
||||
const QString path {info.absolutePath() + "/python.exe"};
|
||||
if (QFile::exists(path))
|
||||
return path;
|
||||
const QString py3Path {info.absolutePath() + "/python3.exe"};
|
||||
if (QFile::exists(py3Path))
|
||||
return py3Path;
|
||||
|
||||
const QString pyPath {info.absolutePath() + "/python.exe"};
|
||||
if (QFile::exists(pyPath))
|
||||
return pyPath;
|
||||
}
|
||||
|
||||
return {};
|
||||
@@ -247,14 +259,9 @@ PythonInfo Utils::ForeignApps::pythonInfo()
|
||||
{
|
||||
static PythonInfo pyInfo;
|
||||
if (!pyInfo.isValid()) {
|
||||
#if defined(Q_OS_UNIX)
|
||||
// On Unix-Like systems python3 should always exist
|
||||
// https://www.python.org/dev/peps/pep-0394/
|
||||
if (testPythonInstallation("python3", pyInfo))
|
||||
return pyInfo;
|
||||
#endif
|
||||
// Look for "python" in Windows and in UNIX if "python3" is
|
||||
// not detected.
|
||||
|
||||
if (testPythonInstallation("python", pyInfo))
|
||||
return pyInfo;
|
||||
|
||||
|
||||
@@ -28,6 +28,7 @@
|
||||
|
||||
#include "fs.h"
|
||||
|
||||
#include <cerrno>
|
||||
#include <cstring>
|
||||
|
||||
#if defined(Q_OS_WIN)
|
||||
|
||||
75
src/base/utils/io.cpp
Normal file
75
src/base/utils/io.cpp
Normal file
@@ -0,0 +1,75 @@
|
||||
/*
|
||||
* Bittorrent Client using Qt and libtorrent.
|
||||
* Copyright (C) 2020 Mike Tzou (Chocobo1)
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation; either version 2
|
||||
* of the License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
*
|
||||
* In addition, as a special exception, the copyright holders give permission to
|
||||
* link this program with the OpenSSL project's "OpenSSL" library (or with
|
||||
* modified versions of it that use the same license as the "OpenSSL" library),
|
||||
* and distribute the linked executables. You must obey the GNU General Public
|
||||
* License in all respects for all of the code used other than "OpenSSL". If you
|
||||
* 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 "io.h"
|
||||
|
||||
#include <QByteArray>
|
||||
#include <QFileDevice>
|
||||
|
||||
Utils::IO::FileDeviceOutputIterator::FileDeviceOutputIterator(QFileDevice &device, const int bufferSize)
|
||||
: m_device {&device}
|
||||
, m_buffer {std::make_shared<QByteArray>()}
|
||||
, m_bufferSize {bufferSize}
|
||||
{
|
||||
m_buffer->reserve(bufferSize);
|
||||
}
|
||||
|
||||
Utils::IO::FileDeviceOutputIterator::~FileDeviceOutputIterator()
|
||||
{
|
||||
if (m_buffer.use_count() == 1) {
|
||||
if (m_device->error() == QFileDevice::NoError)
|
||||
m_device->write(*m_buffer);
|
||||
m_buffer->clear();
|
||||
}
|
||||
}
|
||||
|
||||
Utils::IO::FileDeviceOutputIterator &Utils::IO::FileDeviceOutputIterator::operator=(const char c)
|
||||
{
|
||||
m_buffer->append(c);
|
||||
if (m_buffer->size() >= m_bufferSize) {
|
||||
if (m_device->error() == QFileDevice::NoError)
|
||||
m_device->write(*m_buffer);
|
||||
m_buffer->clear();
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
|
||||
Utils::IO::FileDeviceOutputIterator &Utils::IO::FileDeviceOutputIterator::operator*()
|
||||
{
|
||||
return *this;
|
||||
}
|
||||
|
||||
Utils::IO::FileDeviceOutputIterator &Utils::IO::FileDeviceOutputIterator::operator++()
|
||||
{
|
||||
return *this;
|
||||
}
|
||||
|
||||
Utils::IO::FileDeviceOutputIterator &Utils::IO::FileDeviceOutputIterator::operator++(int)
|
||||
{
|
||||
return *this;
|
||||
}
|
||||
63
src/base/utils/io.h
Normal file
63
src/base/utils/io.h
Normal file
@@ -0,0 +1,63 @@
|
||||
/*
|
||||
* Bittorrent Client using Qt and libtorrent.
|
||||
* Copyright (C) 2020 Mike Tzou (Chocobo1)
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation; either version 2
|
||||
* of the License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
*
|
||||
* In addition, as a special exception, the copyright holders give permission to
|
||||
* link this program with the OpenSSL project's "OpenSSL" library (or with
|
||||
* modified versions of it that use the same license as the "OpenSSL" library),
|
||||
* and distribute the linked executables. You must obey the GNU General Public
|
||||
* License in all respects for all of the code used other than "OpenSSL". If you
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <iterator>
|
||||
#include <memory>
|
||||
|
||||
class QByteArray;
|
||||
class QFileDevice;
|
||||
|
||||
namespace Utils
|
||||
{
|
||||
namespace IO
|
||||
{
|
||||
// A wrapper class that satisfy LegacyOutputIterator requirement
|
||||
class FileDeviceOutputIterator
|
||||
: public std::iterator<std::output_iterator_tag, void, void, void, void>
|
||||
{
|
||||
public:
|
||||
explicit FileDeviceOutputIterator(QFileDevice &device, const int bufferSize = (4 * 1024));
|
||||
FileDeviceOutputIterator(const FileDeviceOutputIterator &other) = default;
|
||||
~FileDeviceOutputIterator();
|
||||
|
||||
// mimic std::ostream_iterator behavior
|
||||
FileDeviceOutputIterator &operator=(char c);
|
||||
// TODO: make these `constexpr` in C++17
|
||||
FileDeviceOutputIterator &operator*();
|
||||
FileDeviceOutputIterator &operator++();
|
||||
FileDeviceOutputIterator &operator++(int);
|
||||
|
||||
private:
|
||||
QFileDevice *m_device;
|
||||
std::shared_ptr<QByteArray> m_buffer;
|
||||
int m_bufferSize;
|
||||
};
|
||||
}
|
||||
}
|
||||
@@ -28,7 +28,9 @@ fspathedit.h
|
||||
hidabletabwidget.h
|
||||
ipsubnetwhitelistoptionsdialog.h
|
||||
lineedit.h
|
||||
loglistwidget.h
|
||||
log/logfiltermodel.h
|
||||
log/loglistview.h
|
||||
log/logmodel.h
|
||||
mainwindow.h
|
||||
optionsdialog.h
|
||||
previewlistdelegate.h
|
||||
@@ -81,7 +83,9 @@ fspathedit.cpp
|
||||
hidabletabwidget.cpp
|
||||
ipsubnetwhitelistoptionsdialog.cpp
|
||||
lineedit.cpp
|
||||
loglistwidget.cpp
|
||||
log/logfiltermodel.cpp
|
||||
log/loglistview.cpp
|
||||
log/logmodel.cpp
|
||||
mainwindow.cpp
|
||||
optionsdialog.cpp
|
||||
previewlistdelegate.cpp
|
||||
|
||||
@@ -57,7 +57,7 @@ class PropListDelegate;
|
||||
class TorrentContentFilterModel;
|
||||
class TorrentFileGuard;
|
||||
|
||||
class AddNewTorrentDialog : public QDialog
|
||||
class AddNewTorrentDialog final : public QDialog
|
||||
{
|
||||
Q_OBJECT
|
||||
Q_DISABLE_COPY(AddNewTorrentDialog)
|
||||
|
||||
@@ -114,7 +114,6 @@ enum AdvSettingsRows
|
||||
// seeding
|
||||
CHOKING_ALGORITHM,
|
||||
SEED_CHOKING_ALGORITHM,
|
||||
SUPER_SEEDING,
|
||||
// tracker
|
||||
ANNOUNCE_ALL_TRACKERS,
|
||||
ANNOUNCE_ALL_TIERS,
|
||||
@@ -223,8 +222,6 @@ void AdvancedSettings::saveAdvancedSettings()
|
||||
// Peer resolution
|
||||
pref->resolvePeerCountries(m_checkBoxResolveCountries.isChecked());
|
||||
pref->resolvePeerHostNames(m_checkBoxResolveHosts.isChecked());
|
||||
// Super seeding
|
||||
session->setSuperSeedingEnabled(m_checkBoxSuperSeeding.isChecked());
|
||||
// Network interface
|
||||
if (m_comboBoxInterface.currentIndex() == 0) {
|
||||
// All interfaces (default)
|
||||
@@ -516,10 +513,6 @@ void AdvancedSettings::loadAdvancedSettings()
|
||||
// Resolve peer hosts
|
||||
m_checkBoxResolveHosts.setChecked(pref->resolvePeerHostNames());
|
||||
addRow(RESOLVE_HOSTS, tr("Resolve peer host names"), &m_checkBoxResolveHosts);
|
||||
// Super seeding
|
||||
m_checkBoxSuperSeeding.setChecked(session->isSuperSeedingEnabled());
|
||||
addRow(SUPER_SEEDING, (tr("Strict super seeding") + ' ' + makeLink("https://www.libtorrent.org/reference-Settings.html#strict_super_seeding", "(?)"))
|
||||
, &m_checkBoxSuperSeeding);
|
||||
// Network interface
|
||||
m_comboBoxInterface.addItem(tr("Any interface", "i.e. Any network interface"));
|
||||
const QString currentInterface = session->networkInterface();
|
||||
|
||||
@@ -61,7 +61,7 @@ private:
|
||||
m_spinBoxSaveResumeDataInterval, m_spinBoxOutgoingPortsMin, m_spinBoxOutgoingPortsMax, m_spinBoxUPnPLeaseDuration,
|
||||
m_spinBoxListRefresh, m_spinBoxTrackerPort, m_spinBoxCacheTTL, m_spinBoxSendBufferWatermark, m_spinBoxSendBufferLowWatermark,
|
||||
m_spinBoxSendBufferWatermarkFactor, m_spinBoxSocketBacklogSize, m_spinBoxStopTrackerTimeout, m_spinBoxSavePathHistoryLength;
|
||||
QCheckBox m_checkBoxOsCache, m_checkBoxRecheckCompleted, m_checkBoxResolveCountries, m_checkBoxResolveHosts, m_checkBoxSuperSeeding,
|
||||
QCheckBox m_checkBoxOsCache, m_checkBoxRecheckCompleted, m_checkBoxResolveCountries, m_checkBoxResolveHosts,
|
||||
m_checkBoxProgramNotifications, m_checkBoxTorrentAddedNotifications, m_checkBoxTrackerFavicon, m_checkBoxTrackerStatus,
|
||||
m_checkBoxConfirmTorrentRecheck, m_checkBoxConfirmRemoveAllTags, m_checkBoxAnnounceAllTrackers, m_checkBoxAnnounceAllTiers,
|
||||
m_checkBoxMultiConnectionsPerIp, m_checkBoxPieceExtentAffinity, m_checkBoxSuggestMode, m_checkBoxCoalesceRW, m_checkBoxSpeedWidgetEnabled;
|
||||
|
||||
@@ -39,7 +39,7 @@ namespace Ui
|
||||
class AutoExpandableDialog;
|
||||
}
|
||||
|
||||
class AutoExpandableDialog : public QDialog
|
||||
class AutoExpandableDialog final : public QDialog
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
|
||||
@@ -40,7 +40,7 @@ namespace BitTorrent
|
||||
class TorrentHandle;
|
||||
}
|
||||
|
||||
class CategoryFilterModel : public QAbstractItemModel
|
||||
class CategoryFilterModel final : public QAbstractItemModel
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
|
||||
@@ -33,7 +33,7 @@
|
||||
|
||||
class QString;
|
||||
|
||||
class CategoryFilterProxyModel : public QSortFilterProxyModel
|
||||
class CategoryFilterProxyModel final : public QSortFilterProxyModel
|
||||
{
|
||||
public:
|
||||
explicit CategoryFilterProxyModel(QObject *parent = nullptr);
|
||||
|
||||
@@ -30,7 +30,7 @@
|
||||
|
||||
#include <QTreeView>
|
||||
|
||||
class CategoryFilterWidget : public QTreeView
|
||||
class CategoryFilterWidget final : public QTreeView
|
||||
{
|
||||
Q_OBJECT
|
||||
Q_DISABLE_COPY(CategoryFilterWidget)
|
||||
|
||||
@@ -38,7 +38,7 @@ namespace Ui
|
||||
class CookiesDialog;
|
||||
}
|
||||
|
||||
class CookiesDialog : public QDialog
|
||||
class CookiesDialog final : public QDialog
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
|
||||
@@ -33,7 +33,7 @@
|
||||
#include <QList>
|
||||
#include <QNetworkCookie>
|
||||
|
||||
class CookiesModel : public QAbstractItemModel
|
||||
class CookiesModel final : public QAbstractItemModel
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
|
||||
@@ -29,35 +29,48 @@
|
||||
#include "executionlogwidget.h"
|
||||
|
||||
#include <QDateTime>
|
||||
#include <QMenu>
|
||||
#include <QPalette>
|
||||
|
||||
#include "base/global.h"
|
||||
#include "loglistwidget.h"
|
||||
#include "log/logfiltermodel.h"
|
||||
#include "log/loglistview.h"
|
||||
#include "log/logmodel.h"
|
||||
#include "ui_executionlogwidget.h"
|
||||
#include "uithememanager.h"
|
||||
|
||||
ExecutionLogWidget::ExecutionLogWidget(QWidget *parent, const Log::MsgTypes &types)
|
||||
ExecutionLogWidget::ExecutionLogWidget(const Log::MsgTypes types, QWidget *parent)
|
||||
: QWidget(parent)
|
||||
, m_ui(new Ui::ExecutionLogWidget)
|
||||
, m_msgList(new LogListWidget(MAX_LOG_MESSAGES, types, this))
|
||||
, m_peerList(new LogListWidget(MAX_LOG_MESSAGES, Log::ALL, this))
|
||||
, m_messageFilterModel(new LogFilterModel(types, this))
|
||||
{
|
||||
m_ui->setupUi(this);
|
||||
|
||||
LogMessageModel *messageModel = new LogMessageModel(this);
|
||||
m_messageFilterModel->setSourceModel(messageModel);
|
||||
LogListView *messageView = new LogListView(this);
|
||||
messageView->setModel(m_messageFilterModel);
|
||||
messageView->setContextMenuPolicy(Qt::CustomContextMenu);
|
||||
connect(messageView, &LogListView::customContextMenuRequested, this, [this, messageView, messageModel](const QPoint &pos)
|
||||
{
|
||||
displayContextMenu(pos, messageView, messageModel);
|
||||
});
|
||||
|
||||
LogPeerModel *peerModel = new LogPeerModel(this);
|
||||
LogListView *peerView = new LogListView(this);
|
||||
peerView->setModel(peerModel);
|
||||
peerView->setContextMenuPolicy(Qt::CustomContextMenu);
|
||||
connect(peerView, &LogListView::customContextMenuRequested, this, [this, peerView, peerModel](const QPoint &pos)
|
||||
{
|
||||
displayContextMenu(pos, peerView, peerModel);
|
||||
});
|
||||
|
||||
m_ui->tabGeneral->layout()->addWidget(messageView);
|
||||
m_ui->tabBan->layout()->addWidget(peerView);
|
||||
|
||||
#ifndef Q_OS_MACOS
|
||||
m_ui->tabConsole->setTabIcon(0, UIThemeManager::instance()->getIcon("view-calendar-journal"));
|
||||
m_ui->tabConsole->setTabIcon(1, UIThemeManager::instance()->getIcon("view-filter"));
|
||||
#endif
|
||||
m_ui->tabGeneral->layout()->addWidget(m_msgList);
|
||||
m_ui->tabBan->layout()->addWidget(m_peerList);
|
||||
|
||||
const Logger *const logger = Logger::instance();
|
||||
for (const Log::Msg &msg : asConst(logger->getMessages()))
|
||||
addLogMessage(msg);
|
||||
for (const Log::Peer &peer : asConst(logger->getPeers()))
|
||||
addPeerMessage(peer);
|
||||
connect(logger, &Logger::newLogMessage, this, &ExecutionLogWidget::addLogMessage);
|
||||
connect(logger, &Logger::newLogPeer, this, &ExecutionLogWidget::addPeerMessage);
|
||||
}
|
||||
|
||||
ExecutionLogWidget::~ExecutionLogWidget()
|
||||
@@ -65,42 +78,24 @@ ExecutionLogWidget::~ExecutionLogWidget()
|
||||
delete m_ui;
|
||||
}
|
||||
|
||||
void ExecutionLogWidget::showMsgTypes(const Log::MsgTypes &types)
|
||||
void ExecutionLogWidget::setMessageTypes(const Log::MsgTypes types)
|
||||
{
|
||||
m_msgList->showMsgTypes(types);
|
||||
m_messageFilterModel->setMessageTypes(types);
|
||||
}
|
||||
|
||||
void ExecutionLogWidget::addLogMessage(const Log::Msg &msg)
|
||||
void ExecutionLogWidget::displayContextMenu(const QPoint &pos, const LogListView *view, const BaseLogModel *model) const
|
||||
{
|
||||
QString colorName;
|
||||
switch (msg.type) {
|
||||
case Log::INFO:
|
||||
colorName = QLatin1String("blue");
|
||||
break;
|
||||
case Log::WARNING:
|
||||
colorName = QLatin1String("orange");
|
||||
break;
|
||||
case Log::CRITICAL:
|
||||
colorName = QLatin1String("red");
|
||||
break;
|
||||
default:
|
||||
colorName = QApplication::palette().color(QPalette::WindowText).name();
|
||||
QMenu *menu = new QMenu;
|
||||
menu->setAttribute(Qt::WA_DeleteOnClose);
|
||||
|
||||
// only show copy action if any of the row is selected
|
||||
if (view->currentIndex().isValid()) {
|
||||
const QAction *copyAct = menu->addAction(UIThemeManager::instance()->getIcon("edit-copy"), tr("Copy"));
|
||||
connect(copyAct, &QAction::triggered, view, &LogListView::copySelection);
|
||||
}
|
||||
|
||||
const QDateTime time = QDateTime::fromMSecsSinceEpoch(msg.timestamp);
|
||||
const QString text = QString::fromLatin1("<font color='grey'>%1</font> - <font color='%2'>%3</font>")
|
||||
.arg(time.toString(Qt::SystemLocaleShortDate), colorName, msg.message);
|
||||
m_msgList->appendLine(text, msg.type);
|
||||
}
|
||||
const QAction *clearAct = menu->addAction(UIThemeManager::instance()->getIcon("edit-clear"), tr("Clear"));
|
||||
connect(clearAct, &QAction::triggered, model, &BaseLogModel::reset);
|
||||
|
||||
void ExecutionLogWidget::addPeerMessage(const Log::Peer &peer)
|
||||
{
|
||||
const QDateTime time = QDateTime::fromMSecsSinceEpoch(peer.timestamp);
|
||||
const QString msg = QString::fromLatin1("<font color='grey'>%1</font> - <font color='red'>%2</font>")
|
||||
.arg(time.toString(Qt::SystemLocaleShortDate), peer.ip);
|
||||
|
||||
const QString text = peer.blocked
|
||||
? tr("%1 was blocked %2", "0.0.0.0 was blocked due to reason").arg(msg, peer.reason)
|
||||
: tr("%1 was banned", "0.0.0.0 was banned").arg(msg);
|
||||
m_peerList->appendLine(text, Log::NORMAL);
|
||||
menu->popup(view->mapToGlobal(pos));
|
||||
}
|
||||
|
||||
@@ -30,33 +30,33 @@
|
||||
#define EXECUTIONLOGWIDGET_H
|
||||
|
||||
#include <QWidget>
|
||||
#include "base/logger.h"
|
||||
|
||||
class LogListWidget;
|
||||
#include "base/logger.h"
|
||||
|
||||
namespace Ui
|
||||
{
|
||||
class ExecutionLogWidget;
|
||||
}
|
||||
|
||||
class BaseLogModel;
|
||||
class LogFilterModel;
|
||||
class LogListView;
|
||||
|
||||
class ExecutionLogWidget : public QWidget
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
ExecutionLogWidget(QWidget *parent, const Log::MsgTypes &types);
|
||||
void showMsgTypes(const Log::MsgTypes &types);
|
||||
ExecutionLogWidget(Log::MsgTypes types, QWidget *parent);
|
||||
~ExecutionLogWidget();
|
||||
|
||||
private slots:
|
||||
void addLogMessage(const Log::Msg &msg);
|
||||
void addPeerMessage(const Log::Peer &peer);
|
||||
|
||||
void setMessageTypes(Log::MsgTypes types);
|
||||
|
||||
private:
|
||||
Ui::ExecutionLogWidget *m_ui;
|
||||
void displayContextMenu(const QPoint &pos, const LogListView *view, const BaseLogModel *model) const;
|
||||
|
||||
LogListWidget *m_msgList;
|
||||
LogListWidget *m_peerList;
|
||||
Ui::ExecutionLogWidget *m_ui;
|
||||
LogFilterModel *m_messageFilterModel;
|
||||
};
|
||||
|
||||
#endif // EXECUTIONLOGWIDGET_H
|
||||
|
||||
@@ -108,7 +108,7 @@ private:
|
||||
};
|
||||
|
||||
/// Widget which uses QLineEdit for path editing
|
||||
class FileSystemPathLineEdit : public FileSystemPathEdit
|
||||
class FileSystemPathLineEdit final : public FileSystemPathEdit
|
||||
{
|
||||
using base = FileSystemPathEdit;
|
||||
using WidgetType = Private::FileLineEdit;
|
||||
@@ -124,7 +124,7 @@ private:
|
||||
};
|
||||
|
||||
/// Widget which uses QComboBox for path editing
|
||||
class FileSystemPathComboEdit : public FileSystemPathEdit
|
||||
class FileSystemPathComboEdit final : public FileSystemPathEdit
|
||||
{
|
||||
using base = FileSystemPathEdit;
|
||||
using WidgetType = Private::FileComboEdit;
|
||||
|
||||
@@ -22,7 +22,9 @@ HEADERS += \
|
||||
$$PWD/hidabletabwidget.h \
|
||||
$$PWD/ipsubnetwhitelistoptionsdialog.h \
|
||||
$$PWD/lineedit.h \
|
||||
$$PWD/loglistwidget.h \
|
||||
$$PWD/log/logfiltermodel.h \
|
||||
$$PWD/log/loglistview.h \
|
||||
$$PWD/log/logmodel.h \
|
||||
$$PWD/mainwindow.h \
|
||||
$$PWD/optionsdialog.h \
|
||||
$$PWD/previewlistdelegate.h \
|
||||
@@ -86,7 +88,9 @@ SOURCES += \
|
||||
$$PWD/hidabletabwidget.cpp \
|
||||
$$PWD/ipsubnetwhitelistoptionsdialog.cpp \
|
||||
$$PWD/lineedit.cpp \
|
||||
$$PWD/loglistwidget.cpp \
|
||||
$$PWD/log/logfiltermodel.cpp \
|
||||
$$PWD/log/loglistview.cpp \
|
||||
$$PWD/log/logmodel.cpp \
|
||||
$$PWD/mainwindow.cpp \
|
||||
$$PWD/optionsdialog.cpp \
|
||||
$$PWD/previewlistdelegate.cpp \
|
||||
|
||||
@@ -35,7 +35,7 @@
|
||||
class QPaintEvent;
|
||||
#endif
|
||||
|
||||
class HidableTabWidget : public QTabWidget
|
||||
class HidableTabWidget final : public QTabWidget
|
||||
{
|
||||
public:
|
||||
explicit HidableTabWidget(QWidget *parent = nullptr);
|
||||
|
||||
@@ -14,7 +14,7 @@
|
||||
|
||||
class QToolButton;
|
||||
|
||||
class LineEdit : public QLineEdit
|
||||
class LineEdit final : public QLineEdit
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
|
||||
52
src/gui/log/logfiltermodel.cpp
Normal file
52
src/gui/log/logfiltermodel.cpp
Normal file
@@ -0,0 +1,52 @@
|
||||
/*
|
||||
* Bittorrent Client using Qt and libtorrent.
|
||||
* Copyright (C) 2019 sledgehammer999 <hammered999@gmail.com>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation; either version 2
|
||||
* of the License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
*
|
||||
* In addition, as a special exception, the copyright holders give permission to
|
||||
* link this program with the OpenSSL project's "OpenSSL" library (or with
|
||||
* modified versions of it that use the same license as the "OpenSSL" library),
|
||||
* and distribute the linked executables. You must obey the GNU General Public
|
||||
* License in all respects for all of the code used other than "OpenSSL". If you
|
||||
* 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 "logfiltermodel.h"
|
||||
|
||||
#include "logmodel.h"
|
||||
|
||||
LogFilterModel::LogFilterModel(const Log::MsgTypes types, QObject *parent)
|
||||
: QSortFilterProxyModel(parent)
|
||||
, m_types(types)
|
||||
{
|
||||
}
|
||||
|
||||
void LogFilterModel::setMessageTypes(const Log::MsgTypes types)
|
||||
{
|
||||
m_types = types;
|
||||
invalidateFilter();
|
||||
}
|
||||
|
||||
bool LogFilterModel::filterAcceptsRow(const int sourceRow, const QModelIndex &sourceParent) const
|
||||
{
|
||||
const QAbstractItemModel *const sourceModel = this->sourceModel();
|
||||
const QModelIndex index = sourceModel->index(sourceRow, 0, sourceParent);
|
||||
const Log::MsgType type = static_cast<Log::MsgType>(sourceModel->data(index, BaseLogModel::TypeRole).toInt());
|
||||
|
||||
return m_types.testFlag(type);
|
||||
}
|
||||
48
src/gui/log/logfiltermodel.h
Normal file
48
src/gui/log/logfiltermodel.h
Normal file
@@ -0,0 +1,48 @@
|
||||
/*
|
||||
* Bittorrent Client using Qt and libtorrent.
|
||||
* Copyright (C) 2019 sledgehammer999 <hammered999@gmail.com>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation; either version 2
|
||||
* of the License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
*
|
||||
* In addition, as a special exception, the copyright holders give permission to
|
||||
* link this program with the OpenSSL project's "OpenSSL" library (or with
|
||||
* modified versions of it that use the same license as the "OpenSSL" library),
|
||||
* and distribute the linked executables. You must obey the GNU General Public
|
||||
* License in all respects for all of the code used other than "OpenSSL". If you
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <QSortFilterProxyModel>
|
||||
|
||||
#include "base/logger.h"
|
||||
|
||||
class LogFilterModel final : public QSortFilterProxyModel
|
||||
{
|
||||
Q_OBJECT
|
||||
Q_DISABLE_COPY(LogFilterModel)
|
||||
|
||||
public:
|
||||
explicit LogFilterModel(Log::MsgTypes types = Log::ALL, QObject *parent = nullptr);
|
||||
void setMessageTypes(Log::MsgTypes types);
|
||||
|
||||
private:
|
||||
bool filterAcceptsRow(int sourceRow, const QModelIndex &sourceParent) const override;
|
||||
|
||||
Log::MsgTypes m_types;
|
||||
};
|
||||
140
src/gui/log/loglistview.cpp
Normal file
140
src/gui/log/loglistview.cpp
Normal file
@@ -0,0 +1,140 @@
|
||||
/*
|
||||
* Bittorrent Client using Qt and libtorrent.
|
||||
* Copyright (C) 2020 Prince Gupta <jagannatharjun11@gmail.com>
|
||||
* Copyright (C) 2019 sledgehammer999 <hammered999@gmail.com>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation; either version 2
|
||||
* of the License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
*
|
||||
* In addition, as a special exception, the copyright holders give permission to
|
||||
* link this program with the OpenSSL project's "OpenSSL" library (or with
|
||||
* modified versions of it that use the same license as the "OpenSSL" library),
|
||||
* and distribute the linked executables. You must obey the GNU General Public
|
||||
* License in all respects for all of the code used other than "OpenSSL". If you
|
||||
* 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 "loglistview.h"
|
||||
|
||||
#include <QApplication>
|
||||
#include <QClipboard>
|
||||
#include <QFontMetrics>
|
||||
#include <QKeyEvent>
|
||||
#include <QPainter>
|
||||
#include <QStyle>
|
||||
#include <QStyledItemDelegate>
|
||||
|
||||
#include "logmodel.h"
|
||||
#include "uithememanager.h"
|
||||
|
||||
namespace
|
||||
{
|
||||
const QString SEPARATOR = QStringLiteral(" - ");
|
||||
|
||||
int horizontalAdvance(const QFontMetrics &fontMetrics, const QString &text)
|
||||
{
|
||||
#if (QT_VERSION >= QT_VERSION_CHECK(5, 11, 0))
|
||||
return fontMetrics.horizontalAdvance(text);
|
||||
#else
|
||||
return fontMetrics.width(text);
|
||||
#endif
|
||||
}
|
||||
|
||||
QString logText(const QModelIndex &index)
|
||||
{
|
||||
return QString::fromLatin1("%1%2%3").arg(index.data(BaseLogModel::TimeRole).toString(), SEPARATOR
|
||||
, index.data(BaseLogModel::MessageRole).toString());
|
||||
}
|
||||
|
||||
class LogItemDelegate final : public QStyledItemDelegate
|
||||
{
|
||||
public:
|
||||
using QStyledItemDelegate::QStyledItemDelegate;
|
||||
|
||||
private:
|
||||
void paint(QPainter *painter, const QStyleOptionViewItem &option, const QModelIndex &index) const override
|
||||
{
|
||||
painter->save();
|
||||
QStyledItemDelegate::paint(painter, option, index); // paints background, focus rect and selection rect
|
||||
|
||||
const QStyle *style = option.widget ? option.widget->style() : QApplication::style();;
|
||||
const QRect textRect = style->subElementRect(QStyle::SE_ItemViewItemText, &option, option.widget)
|
||||
.adjusted(1, 0, 0, 0); // shift 1 to avoid text being too close to focus rect
|
||||
|
||||
QFont font = option.font;
|
||||
if (option.font.pointSize() > 0)
|
||||
font.setPointSize(option.font.pointSize()); // somehow this needs to be set directly otherwise painter will use default font
|
||||
painter->setFont(font);
|
||||
|
||||
const QPen originalPen = painter->pen();
|
||||
QPen coloredPen = originalPen;
|
||||
coloredPen.setColor(Qt::darkGray);
|
||||
painter->setPen(coloredPen);
|
||||
const QString time = index.data(BaseLogModel::TimeRole).toString();
|
||||
style->drawItemText(painter, textRect, option.displayAlignment, option.palette, (option.state & QStyle::State_Enabled), time);
|
||||
|
||||
painter->setPen(originalPen);
|
||||
const QFontMetrics fontMetrics = painter->fontMetrics(); // option.fontMetrics adds extra padding to QFontMetrics::width
|
||||
const int separatorCoordinateX = horizontalAdvance(fontMetrics, time);
|
||||
style->drawItemText(painter, textRect.adjusted(separatorCoordinateX, 0, 0, 0), option.displayAlignment, option.palette
|
||||
, (option.state & QStyle::State_Enabled), SEPARATOR);
|
||||
|
||||
coloredPen.setColor(index.data(BaseLogModel::ForegroundRole).value<QColor>());
|
||||
painter->setPen(coloredPen);
|
||||
const int messageCoordinateX = separatorCoordinateX + horizontalAdvance(fontMetrics, SEPARATOR);
|
||||
style->drawItemText(painter, textRect.adjusted(messageCoordinateX, 0, 0, 0), option.displayAlignment, option.palette
|
||||
, (option.state & QStyle::State_Enabled), index.data(BaseLogModel::MessageRole).toString());
|
||||
painter->restore();
|
||||
}
|
||||
|
||||
QSize sizeHint(const QStyleOptionViewItem &option, const QModelIndex &index) const override
|
||||
{
|
||||
const QSize minimumFontPadding(4, 4);
|
||||
const QSize fontSize = option.fontMetrics.size(0, logText(index)) + minimumFontPadding;
|
||||
const QSize defaultSize = QStyledItemDelegate::sizeHint(option, index);
|
||||
const QSize margins = (defaultSize - fontSize).expandedTo({0, 0});
|
||||
return fontSize + margins;
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
LogListView::LogListView(QWidget *parent)
|
||||
: QListView(parent)
|
||||
{
|
||||
setSelectionMode(QAbstractItemView::ExtendedSelection);
|
||||
setItemDelegate(new LogItemDelegate(this));
|
||||
|
||||
#if defined(Q_OS_MAC)
|
||||
setAttribute(Qt::WA_MacShowFocusRect, false);
|
||||
#endif
|
||||
}
|
||||
|
||||
void LogListView::keyPressEvent(QKeyEvent *event)
|
||||
{
|
||||
if (event->matches(QKeySequence::Copy))
|
||||
copySelection();
|
||||
else
|
||||
QListView::keyPressEvent(event);
|
||||
}
|
||||
|
||||
void LogListView::copySelection() const
|
||||
{
|
||||
QStringList list;
|
||||
const QModelIndexList selectedIndexes = selectionModel()->selectedRows();
|
||||
for (const QModelIndex &index : selectedIndexes)
|
||||
list.append(logText(index));
|
||||
QApplication::clipboard()->setText(list.join('\n'));
|
||||
}
|
||||
@@ -1,6 +1,7 @@
|
||||
/*
|
||||
* Bittorrent Client using Qt and libtorrent.
|
||||
* Copyright (C) 2011 Christophe Dumez <chris@qbittorrent.org>
|
||||
* Copyright (C) 2020 Prince Gupta <jagannatharjun11@gmail.com>
|
||||
* Copyright (C) 2019 sledgehammer999 <hammered999@gmail.com>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
@@ -26,35 +27,21 @@
|
||||
* exception statement from your version.
|
||||
*/
|
||||
|
||||
#ifndef LOGLISTWIDGET_H
|
||||
#define LOGLISTWIDGET_H
|
||||
#pragma once
|
||||
|
||||
#include <QListWidget>
|
||||
#include "base/logger.h"
|
||||
#include <QListView>
|
||||
|
||||
class QKeyEvent;
|
||||
|
||||
class LogListWidget : public QListWidget
|
||||
class LogListView final : public QListView
|
||||
{
|
||||
Q_OBJECT
|
||||
Q_DISABLE_COPY(LogListView)
|
||||
|
||||
public:
|
||||
// -1 is the portable way to have all the bits set
|
||||
explicit LogListWidget(int maxLines, const Log::MsgTypes &types = Log::ALL, QWidget *parent = nullptr);
|
||||
void showMsgTypes(const Log::MsgTypes &types);
|
||||
explicit LogListView(QWidget *parent = nullptr);
|
||||
|
||||
public slots:
|
||||
void appendLine(const QString &line, const Log::MsgType &type);
|
||||
|
||||
protected slots:
|
||||
void copySelection();
|
||||
|
||||
protected:
|
||||
void keyPressEvent(QKeyEvent *event) override;
|
||||
void copySelection() const;
|
||||
|
||||
private:
|
||||
const int m_maxLines;
|
||||
Log::MsgTypes m_types;
|
||||
void keyPressEvent(QKeyEvent *event) override;
|
||||
};
|
||||
|
||||
#endif // LOGLISTWIDGET_H
|
||||
188
src/gui/log/logmodel.cpp
Normal file
188
src/gui/log/logmodel.cpp
Normal file
@@ -0,0 +1,188 @@
|
||||
/*
|
||||
* Bittorrent Client using Qt and libtorrent.
|
||||
* Copyright (C) 2020 Prince Gupta <jagannatharjun11@gmail.com>
|
||||
* Copyright (C) 2019 sledgehammer999 <hammered999@gmail.com>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation; either version 2
|
||||
* of the License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
*
|
||||
* In addition, as a special exception, the copyright holders give permission to
|
||||
* link this program with the OpenSSL project's "OpenSSL" library (or with
|
||||
* modified versions of it that use the same license as the "OpenSSL" library),
|
||||
* and distribute the linked executables. You must obey the GNU General Public
|
||||
* License in all respects for all of the code used other than "OpenSSL". If you
|
||||
* 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 "logmodel.h"
|
||||
|
||||
#include <QApplication>
|
||||
#include <QDateTime>
|
||||
#include <QColor>
|
||||
#include <QPalette>
|
||||
|
||||
#include "base/global.h"
|
||||
|
||||
namespace
|
||||
{
|
||||
const int MAX_VISIBLE_MESSAGES = 20000;
|
||||
}
|
||||
|
||||
BaseLogModel::Message::Message(const QString &time, const QString &message, const QColor &foreground, const Log::MsgType type)
|
||||
: m_time(time)
|
||||
, m_message(message)
|
||||
, m_foreground(foreground)
|
||||
, m_type(type)
|
||||
{
|
||||
}
|
||||
|
||||
QVariant BaseLogModel::Message::time() const
|
||||
{
|
||||
return m_time;
|
||||
}
|
||||
|
||||
QVariant BaseLogModel::Message::message() const
|
||||
{
|
||||
return m_message;
|
||||
}
|
||||
|
||||
QVariant BaseLogModel::Message::foreground() const
|
||||
{
|
||||
return m_foreground;
|
||||
}
|
||||
|
||||
QVariant BaseLogModel::Message::type() const
|
||||
{
|
||||
return m_type;
|
||||
}
|
||||
|
||||
BaseLogModel::BaseLogModel(QObject *parent)
|
||||
: QAbstractListModel(parent)
|
||||
, m_messages(MAX_VISIBLE_MESSAGES)
|
||||
{
|
||||
}
|
||||
|
||||
int BaseLogModel::rowCount(const QModelIndex &) const
|
||||
{
|
||||
return m_messages.size();
|
||||
}
|
||||
|
||||
int BaseLogModel::columnCount(const QModelIndex &) const
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
|
||||
QVariant BaseLogModel::data(const QModelIndex &index, const int role) const
|
||||
{
|
||||
if (!index.isValid())
|
||||
return {};
|
||||
|
||||
const int messageIndex = index.row();
|
||||
if ((messageIndex < 0) || (messageIndex >= static_cast<int>(m_messages.size())))
|
||||
return {};
|
||||
|
||||
const Message &message = m_messages[messageIndex];
|
||||
switch (role) {
|
||||
case TimeRole:
|
||||
return message.time();
|
||||
case MessageRole:
|
||||
return message.message();
|
||||
case ForegroundRole:
|
||||
return message.foreground();
|
||||
case TypeRole:
|
||||
return message.type();
|
||||
default:
|
||||
return {};
|
||||
}
|
||||
}
|
||||
|
||||
void BaseLogModel::addNewMessage(const BaseLogModel::Message &message)
|
||||
{
|
||||
// if row is inserted on filled up buffer, the size will not change
|
||||
// but because of calling of beginInsertRows function we'll have ghost rows.
|
||||
if (m_messages.size() == MAX_VISIBLE_MESSAGES) {
|
||||
const int lastMessage = m_messages.size() - 1;
|
||||
beginRemoveRows(QModelIndex(), lastMessage, lastMessage);
|
||||
m_messages.pop_back();
|
||||
endRemoveRows();
|
||||
}
|
||||
|
||||
beginInsertRows(QModelIndex(), 0, 0);
|
||||
m_messages.push_front(message);
|
||||
endInsertRows();
|
||||
}
|
||||
|
||||
void BaseLogModel::reset()
|
||||
{
|
||||
beginResetModel();
|
||||
m_messages.clear();
|
||||
endResetModel();
|
||||
}
|
||||
|
||||
LogMessageModel::LogMessageModel(QObject *parent)
|
||||
: BaseLogModel(parent)
|
||||
{
|
||||
for (const Log::Msg &msg : asConst(Logger::instance()->getMessages()))
|
||||
handleNewMessage(msg);
|
||||
connect(Logger::instance(), &Logger::newLogMessage, this, &LogMessageModel::handleNewMessage);
|
||||
}
|
||||
|
||||
void LogMessageModel::handleNewMessage(const Log::Msg &message)
|
||||
{
|
||||
const QString time = QDateTime::fromMSecsSinceEpoch(message.timestamp).toString(Qt::SystemLocaleShortDate);
|
||||
const QString messageText = message.message;
|
||||
|
||||
QColor foreground;
|
||||
switch (message.type) {
|
||||
// The RGB QColor constructor is used for performance
|
||||
case Log::NORMAL:
|
||||
foreground = QApplication::palette().color(QPalette::WindowText);
|
||||
break;
|
||||
case Log::INFO:
|
||||
foreground = QColor(0, 0, 255); // blue
|
||||
break;
|
||||
case Log::WARNING:
|
||||
foreground = QColor(255, 165, 0); // orange
|
||||
break;
|
||||
case Log::CRITICAL:
|
||||
foreground = QColor(255, 0, 0); // red
|
||||
break;
|
||||
default:
|
||||
Q_ASSERT(false);
|
||||
break;
|
||||
}
|
||||
|
||||
addNewMessage({time, messageText, foreground, message.type});
|
||||
}
|
||||
|
||||
LogPeerModel::LogPeerModel(QObject *parent)
|
||||
: BaseLogModel(parent)
|
||||
{
|
||||
for (const Log::Peer &peer : asConst(Logger::instance()->getPeers()))
|
||||
handleNewMessage(peer);
|
||||
connect(Logger::instance(), &Logger::newLogPeer, this, &LogPeerModel::handleNewMessage);
|
||||
}
|
||||
|
||||
void LogPeerModel::handleNewMessage(const Log::Peer &peer)
|
||||
{
|
||||
const QString time = QDateTime::fromMSecsSinceEpoch(peer.timestamp).toString(Qt::SystemLocaleShortDate);
|
||||
const QString message = peer.blocked
|
||||
? tr("%1 was blocked due to %2", "0.0.0.0 was blocked due to reason").arg(peer.ip, peer.reason)
|
||||
: tr("%1 was banned", "0.0.0.0 was banned").arg(peer.ip);
|
||||
const QColor foreground = Qt::red;
|
||||
|
||||
addNewMessage({time, message, foreground, Log::NORMAL});
|
||||
}
|
||||
104
src/gui/log/logmodel.h
Normal file
104
src/gui/log/logmodel.h
Normal file
@@ -0,0 +1,104 @@
|
||||
/*
|
||||
* Bittorrent Client using Qt and libtorrent.
|
||||
* Copyright (C) 2020 Prince Gupta <jagannatharjun11@gmail.com>
|
||||
* Copyright (C) 2019 sledgehammer999 <hammered999@gmail.com>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation; either version 2
|
||||
* of the License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
*
|
||||
* In addition, as a special exception, the copyright holders give permission to
|
||||
* link this program with the OpenSSL project's "OpenSSL" library (or with
|
||||
* modified versions of it that use the same license as the "OpenSSL" library),
|
||||
* and distribute the linked executables. You must obey the GNU General Public
|
||||
* License in all respects for all of the code used other than "OpenSSL". If you
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <boost/circular_buffer.hpp>
|
||||
|
||||
#include <QAbstractListModel>
|
||||
|
||||
#include "base/logger.h"
|
||||
|
||||
class BaseLogModel : public QAbstractListModel
|
||||
{
|
||||
Q_DISABLE_COPY(BaseLogModel)
|
||||
|
||||
public:
|
||||
enum MessageTypeRole
|
||||
{
|
||||
TimeRole = Qt::UserRole,
|
||||
MessageRole,
|
||||
ForegroundRole,
|
||||
TypeRole
|
||||
};
|
||||
|
||||
explicit BaseLogModel(QObject *parent = nullptr);
|
||||
|
||||
int rowCount(const QModelIndex &parent = {}) const override;
|
||||
int columnCount(const QModelIndex &parent = {}) const override;
|
||||
QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const override;
|
||||
void reset();
|
||||
|
||||
protected:
|
||||
class Message
|
||||
{
|
||||
public:
|
||||
Message(const QString &time, const QString &message, const QColor &foreground, Log::MsgType type);
|
||||
|
||||
QVariant time() const;
|
||||
QVariant message() const;
|
||||
QVariant foreground() const;
|
||||
QVariant type() const;
|
||||
|
||||
private:
|
||||
QVariant m_time;
|
||||
QVariant m_message;
|
||||
QVariant m_foreground;
|
||||
QVariant m_type;
|
||||
};
|
||||
|
||||
void addNewMessage(const Message &message);
|
||||
|
||||
private:
|
||||
boost::circular_buffer_space_optimized<Message> m_messages;
|
||||
};
|
||||
|
||||
class LogMessageModel : public BaseLogModel
|
||||
{
|
||||
Q_OBJECT
|
||||
Q_DISABLE_COPY(LogMessageModel)
|
||||
|
||||
public:
|
||||
explicit LogMessageModel(QObject *parent = nullptr);
|
||||
|
||||
private slots:
|
||||
void handleNewMessage(const Log::Msg &message);
|
||||
};
|
||||
|
||||
class LogPeerModel : public BaseLogModel
|
||||
{
|
||||
Q_OBJECT
|
||||
Q_DISABLE_COPY(LogPeerModel)
|
||||
|
||||
public:
|
||||
explicit LogPeerModel(QObject *parent = nullptr);
|
||||
|
||||
private slots:
|
||||
void handleNewMessage(const Log::Peer &peer);
|
||||
};
|
||||
@@ -1,108 +0,0 @@
|
||||
/*
|
||||
* Bittorrent Client using Qt and libtorrent.
|
||||
* Copyright (C) 2011 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
|
||||
* as published by the Free Software Foundation; either version 2
|
||||
* of the License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
*
|
||||
* In addition, as a special exception, the copyright holders give permission to
|
||||
* link this program with the OpenSSL project's "OpenSSL" library (or with
|
||||
* modified versions of it that use the same license as the "OpenSSL" library),
|
||||
* and distribute the linked executables. You must obey the GNU General Public
|
||||
* License in all respects for all of the code used other than "OpenSSL". If you
|
||||
* 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 "loglistwidget.h"
|
||||
|
||||
#include <QAction>
|
||||
#include <QApplication>
|
||||
#include <QClipboard>
|
||||
#include <QKeyEvent>
|
||||
#include <QLabel>
|
||||
#include <QListWidgetItem>
|
||||
#include <QRegularExpression>
|
||||
|
||||
#include "base/global.h"
|
||||
#include "uithememanager.h"
|
||||
|
||||
LogListWidget::LogListWidget(const int maxLines, const Log::MsgTypes &types, QWidget *parent)
|
||||
: QListWidget(parent)
|
||||
, m_maxLines(maxLines)
|
||||
, m_types(types)
|
||||
{
|
||||
// Allow multiple selections
|
||||
setSelectionMode(QAbstractItemView::ExtendedSelection);
|
||||
// Context menu
|
||||
auto *copyAct = new QAction(UIThemeManager::instance()->getIcon("edit-copy"), tr("Copy"), this);
|
||||
auto *clearAct = new QAction(UIThemeManager::instance()->getIcon("edit-clear"), tr("Clear"), this);
|
||||
connect(copyAct, &QAction::triggered, this, &LogListWidget::copySelection);
|
||||
connect(clearAct, &QAction::triggered, this, &LogListWidget::clear);
|
||||
addAction(copyAct);
|
||||
addAction(clearAct);
|
||||
setContextMenuPolicy(Qt::ActionsContextMenu);
|
||||
}
|
||||
|
||||
void LogListWidget::showMsgTypes(const Log::MsgTypes &types)
|
||||
{
|
||||
m_types = types;
|
||||
for (int i = 0; i < count(); ++i) {
|
||||
QListWidgetItem *tempItem = item(i);
|
||||
if (!tempItem) continue;
|
||||
|
||||
Log::MsgType itemType = static_cast<Log::MsgType>(tempItem->data(Qt::UserRole).toInt());
|
||||
setRowHidden(i, !(m_types & itemType));
|
||||
}
|
||||
}
|
||||
|
||||
void LogListWidget::keyPressEvent(QKeyEvent *event)
|
||||
{
|
||||
if (event->matches(QKeySequence::Copy))
|
||||
copySelection();
|
||||
else
|
||||
QListWidget::keyPressEvent(event);
|
||||
}
|
||||
|
||||
void LogListWidget::appendLine(const QString &line, const Log::MsgType &type)
|
||||
{
|
||||
// We need to use QLabel here to support rich text
|
||||
auto *lbl = new QLabel(line);
|
||||
lbl->setTextFormat(Qt::RichText);
|
||||
lbl->setContentsMargins(4, 2, 4, 2);
|
||||
|
||||
auto *item = new QListWidgetItem;
|
||||
item->setSizeHint(lbl->sizeHint());
|
||||
item->setData(Qt::UserRole, type);
|
||||
insertItem(0, item);
|
||||
setItemWidget(item, lbl);
|
||||
setRowHidden(0, !(m_types & type));
|
||||
|
||||
const int nbLines = count();
|
||||
// Limit log size
|
||||
if (nbLines > m_maxLines)
|
||||
delete takeItem(nbLines - 1);
|
||||
}
|
||||
|
||||
void LogListWidget::copySelection()
|
||||
{
|
||||
const QRegularExpression htmlTag("<[^>]+>");
|
||||
|
||||
QStringList strings;
|
||||
for (QListWidgetItem *it : asConst(selectedItems()))
|
||||
strings << static_cast<QLabel*>(itemWidget(it))->text().remove(htmlTag);
|
||||
|
||||
QApplication::clipboard()->setText(strings.join('\n'));
|
||||
}
|
||||
@@ -28,6 +28,8 @@
|
||||
|
||||
#include "mainwindow.h"
|
||||
|
||||
#include <chrono>
|
||||
|
||||
#include <QCloseEvent>
|
||||
#include <QDebug>
|
||||
#include <QDesktopServices>
|
||||
@@ -99,9 +101,6 @@
|
||||
#include "programupdater.h"
|
||||
#endif
|
||||
|
||||
#define TIME_TRAY_BALLOON 5000
|
||||
#define PREVENT_SUSPEND_INTERVAL 60000
|
||||
|
||||
namespace
|
||||
{
|
||||
#define SETTINGS_KEY(name) "GUI/" name
|
||||
@@ -119,6 +118,11 @@ namespace
|
||||
// Misc
|
||||
const QString KEY_DOWNLOAD_TRACKER_FAVICON = QStringLiteral(SETTINGS_KEY("DownloadTrackerFavicon"));
|
||||
|
||||
const std::chrono::seconds PREVENT_SUSPEND_INTERVAL {60};
|
||||
#if !defined(Q_OS_MACOS)
|
||||
const int TIME_TRAY_BALLOON = 5000;
|
||||
#endif
|
||||
|
||||
// just a shortcut
|
||||
inline SettingsStorage *settings()
|
||||
{
|
||||
@@ -487,7 +491,7 @@ int MainWindow::executionLogMsgTypes() const
|
||||
|
||||
void MainWindow::setExecutionLogMsgTypes(const int value)
|
||||
{
|
||||
m_executionLog->showMsgTypes(static_cast<Log::MsgTypes>(value));
|
||||
m_executionLog->setMessageTypes(static_cast<Log::MsgTypes>(value));
|
||||
settings()->storeValue(KEY_EXECUTIONLOG_TYPES, value);
|
||||
}
|
||||
|
||||
@@ -776,8 +780,9 @@ void MainWindow::cleanup()
|
||||
if (m_systrayCreator)
|
||||
m_systrayCreator->stop();
|
||||
#endif
|
||||
if (m_preventTimer)
|
||||
m_preventTimer->stop();
|
||||
|
||||
m_preventTimer->stop();
|
||||
|
||||
#if (defined(Q_OS_WIN) || defined(Q_OS_MACOS))
|
||||
m_programUpdateTimer->stop();
|
||||
#endif
|
||||
@@ -1401,7 +1406,7 @@ void MainWindow::showStatusBar(bool show)
|
||||
}
|
||||
}
|
||||
|
||||
void MainWindow::loadPreferences(bool configureSession)
|
||||
void MainWindow::loadPreferences(const bool configureSession)
|
||||
{
|
||||
Logger::instance()->addMessage(tr("Options were saved successfully."));
|
||||
const Preferences *const pref = Preferences::instance();
|
||||
@@ -1451,8 +1456,11 @@ void MainWindow::loadPreferences(bool configureSession)
|
||||
|
||||
showStatusBar(pref->isStatusbarDisplayed());
|
||||
|
||||
if ((pref->preventFromSuspendWhenDownloading() || pref->preventFromSuspendWhenSeeding()) && !m_preventTimer->isActive()) {
|
||||
m_preventTimer->start(PREVENT_SUSPEND_INTERVAL);
|
||||
if (pref->preventFromSuspendWhenDownloading() || pref->preventFromSuspendWhenSeeding()) {
|
||||
if (!m_preventTimer->isActive()) {
|
||||
updatePowerManagementState();
|
||||
m_preventTimer->start(PREVENT_SUSPEND_INTERVAL);
|
||||
}
|
||||
}
|
||||
else {
|
||||
m_preventTimer->stop();
|
||||
@@ -1866,7 +1874,7 @@ void MainWindow::on_actionExecutionLogs_triggered(bool checked)
|
||||
{
|
||||
if (checked) {
|
||||
Q_ASSERT(!m_executionLog);
|
||||
m_executionLog = new ExecutionLogWidget(m_tabs, static_cast<Log::MsgType>(executionLogMsgTypes()));
|
||||
m_executionLog = new ExecutionLogWidget(static_cast<Log::MsgType>(executionLogMsgTypes()), m_tabs);
|
||||
#ifdef Q_OS_MACOS
|
||||
m_tabs->addTab(m_executionLog, tr("Execution Log"));
|
||||
#else
|
||||
|
||||
@@ -72,7 +72,7 @@ namespace Ui
|
||||
class MainWindow;
|
||||
}
|
||||
|
||||
class MainWindow : public QMainWindow
|
||||
class MainWindow final : public QMainWindow
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
|
||||
@@ -81,9 +81,76 @@ namespace
|
||||
ret.append(locale.toString(date.addDays(i), "dddd"));
|
||||
return ret;
|
||||
}
|
||||
|
||||
QString languageToLocalizedString(const QLocale &locale)
|
||||
{
|
||||
switch (locale.language()) {
|
||||
case QLocale::Arabic: return QString::fromUtf8(C_LOCALE_ARABIC);
|
||||
case QLocale::Armenian: return QString::fromUtf8(C_LOCALE_ARMENIAN);
|
||||
case QLocale::Basque: return QString::fromUtf8(C_LOCALE_BASQUE);
|
||||
case QLocale::Bulgarian: return QString::fromUtf8(C_LOCALE_BULGARIAN);
|
||||
case QLocale::Byelorussian: return QString::fromUtf8(C_LOCALE_BYELORUSSIAN);
|
||||
case QLocale::Catalan: return QString::fromUtf8(C_LOCALE_CATALAN);
|
||||
case QLocale::Chinese:
|
||||
switch (locale.country()) {
|
||||
case QLocale::China: return QString::fromUtf8(C_LOCALE_CHINESE_SIMPLIFIED);
|
||||
case QLocale::HongKong: return QString::fromUtf8(C_LOCALE_CHINESE_TRADITIONAL_HK);
|
||||
default: return QString::fromUtf8(C_LOCALE_CHINESE_TRADITIONAL_TW);
|
||||
}
|
||||
case QLocale::Croatian: return QString::fromUtf8(C_LOCALE_CROATIAN);
|
||||
case QLocale::Czech: return QString::fromUtf8(C_LOCALE_CZECH);
|
||||
case QLocale::Danish: return QString::fromUtf8(C_LOCALE_DANISH);
|
||||
case QLocale::Dutch: return QString::fromUtf8(C_LOCALE_DUTCH);
|
||||
case QLocale::English:
|
||||
switch (locale.country()) {
|
||||
case QLocale::Australia: return QString::fromUtf8(C_LOCALE_ENGLISH_AUSTRALIA);
|
||||
case QLocale::UnitedKingdom: return QString::fromUtf8(C_LOCALE_ENGLISH_UNITEDKINGDOM);
|
||||
default: return QString::fromUtf8(C_LOCALE_ENGLISH);
|
||||
}
|
||||
case QLocale::Finnish: return QString::fromUtf8(C_LOCALE_FINNISH);
|
||||
case QLocale::French: return QString::fromUtf8(C_LOCALE_FRENCH);
|
||||
case QLocale::Galician: return QString::fromUtf8(C_LOCALE_GALICIAN);
|
||||
case QLocale::Georgian: return QString::fromUtf8(C_LOCALE_GEORGIAN);
|
||||
case QLocale::German: return QString::fromUtf8(C_LOCALE_GERMAN);
|
||||
case QLocale::Greek: return QString::fromUtf8(C_LOCALE_GREEK);
|
||||
case QLocale::Hebrew: return QString::fromUtf8(C_LOCALE_HEBREW);
|
||||
case QLocale::Hindi: return QString::fromUtf8(C_LOCALE_HINDI);
|
||||
case QLocale::Hungarian: return QString::fromUtf8(C_LOCALE_HUNGARIAN);
|
||||
case QLocale::Icelandic: return QString::fromUtf8(C_LOCALE_ICELANDIC);
|
||||
case QLocale::Indonesian: return QString::fromUtf8(C_LOCALE_INDONESIAN);
|
||||
case QLocale::Italian: return QString::fromUtf8(C_LOCALE_ITALIAN);
|
||||
case QLocale::Japanese: return QString::fromUtf8(C_LOCALE_JAPANESE);
|
||||
case QLocale::Korean: return QString::fromUtf8(C_LOCALE_KOREAN);
|
||||
case QLocale::Latvian: return QString::fromUtf8(C_LOCALE_LATVIAN);
|
||||
case QLocale::Lithuanian: return QString::fromUtf8(C_LOCALE_LITHUANIAN);
|
||||
case QLocale::Malay: return QString::fromUtf8(C_LOCALE_MALAY);
|
||||
case QLocale::Norwegian: return QString::fromUtf8(C_LOCALE_NORWEGIAN);
|
||||
case QLocale::Occitan: return QString::fromUtf8(C_LOCALE_OCCITAN);
|
||||
case QLocale::Polish: return QString::fromUtf8(C_LOCALE_POLISH);
|
||||
case QLocale::Portuguese:
|
||||
if (locale.country() == QLocale::Brazil)
|
||||
return QString::fromUtf8(C_LOCALE_PORTUGUESE_BRAZIL);
|
||||
return QString::fromUtf8(C_LOCALE_PORTUGUESE);
|
||||
case QLocale::Romanian: return QString::fromUtf8(C_LOCALE_ROMANIAN);
|
||||
case QLocale::Russian: return QString::fromUtf8(C_LOCALE_RUSSIAN);
|
||||
case QLocale::Serbian: return QString::fromUtf8(C_LOCALE_SERBIAN);
|
||||
case QLocale::Slovak: return QString::fromUtf8(C_LOCALE_SLOVAK);
|
||||
case QLocale::Slovenian: return QString::fromUtf8(C_LOCALE_SLOVENIAN);
|
||||
case QLocale::Spanish: return QString::fromUtf8(C_LOCALE_SPANISH);
|
||||
case QLocale::Swedish: return QString::fromUtf8(C_LOCALE_SWEDISH);
|
||||
case QLocale::Turkish: return QString::fromUtf8(C_LOCALE_TURKISH);
|
||||
case QLocale::Ukrainian: return QString::fromUtf8(C_LOCALE_UKRAINIAN);
|
||||
case QLocale::Uzbek: return QString::fromUtf8(C_LOCALE_UZBEK);
|
||||
case QLocale::Vietnamese: return QString::fromUtf8(C_LOCALE_VIETNAMESE);
|
||||
default:
|
||||
const QString lang = QLocale::languageToString(locale.language());
|
||||
qWarning() << "Unrecognized language name: " << lang;
|
||||
return lang;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
class WheelEventEater : public QObject
|
||||
class WheelEventEater final : public QObject
|
||||
{
|
||||
public:
|
||||
using QObject::QObject;
|
||||
@@ -815,7 +882,6 @@ Net::ProxyType OptionsDialog::getProxyType() const
|
||||
switch (m_ui->comboProxyType->currentIndex()) {
|
||||
case 1:
|
||||
return Net::ProxyType::SOCKS4;
|
||||
break;
|
||||
case 2:
|
||||
if (isProxyAuthEnabled())
|
||||
return Net::ProxyType::SOCKS5_PW;
|
||||
@@ -1376,28 +1442,27 @@ void OptionsDialog::toggleComboRatioLimitAct()
|
||||
m_ui->comboRatioLimitAct->setEnabled(m_ui->checkMaxRatio->isChecked() || m_ui->checkMaxSeedingMinutes->isChecked());
|
||||
}
|
||||
|
||||
void OptionsDialog::enableProxy(int index)
|
||||
void OptionsDialog::enableProxy(const int index)
|
||||
{
|
||||
if (index) {
|
||||
if (index >= 1) { // Any proxy type is used
|
||||
//enable
|
||||
m_ui->lblProxyIP->setEnabled(true);
|
||||
m_ui->textProxyIP->setEnabled(true);
|
||||
m_ui->lblProxyPort->setEnabled(true);
|
||||
m_ui->spinProxyPort->setEnabled(true);
|
||||
m_ui->checkProxyPeerConnecs->setEnabled(true);
|
||||
if (index > 1) {
|
||||
if (index >= 2) { // SOCKS5 or HTTP
|
||||
m_ui->checkProxyAuth->setEnabled(true);
|
||||
m_ui->isProxyOnlyForTorrents->setEnabled(true);
|
||||
}
|
||||
else {
|
||||
m_ui->checkProxyAuth->setEnabled(false);
|
||||
m_ui->checkProxyAuth->setChecked(false);
|
||||
m_ui->isProxyOnlyForTorrents->setEnabled(false);
|
||||
m_ui->isProxyOnlyForTorrents->setChecked(true);
|
||||
}
|
||||
}
|
||||
else {
|
||||
//disable
|
||||
else { // No proxy
|
||||
// disable
|
||||
m_ui->lblProxyIP->setEnabled(false);
|
||||
m_ui->textProxyIP->setEnabled(false);
|
||||
m_ui->lblProxyPort->setEnabled(false);
|
||||
@@ -1405,7 +1470,6 @@ void OptionsDialog::enableProxy(int index)
|
||||
m_ui->checkProxyPeerConnecs->setEnabled(false);
|
||||
m_ui->isProxyOnlyForTorrents->setEnabled(false);
|
||||
m_ui->checkProxyAuth->setEnabled(false);
|
||||
m_ui->checkProxyAuth->setChecked(false);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1698,81 +1762,6 @@ void OptionsDialog::handleIPFilterParsed(bool error, int ruleCount)
|
||||
disconnect(BitTorrent::Session::instance(), &BitTorrent::Session::IPFilterParsed, this, &OptionsDialog::handleIPFilterParsed);
|
||||
}
|
||||
|
||||
QString OptionsDialog::languageToLocalizedString(const QLocale &locale)
|
||||
{
|
||||
switch (locale.language()) {
|
||||
case QLocale::English: {
|
||||
if (locale.country() == QLocale::Australia)
|
||||
return QString::fromUtf8(C_LOCALE_ENGLISH_AUSTRALIA);
|
||||
if (locale.country() == QLocale::UnitedKingdom)
|
||||
return QString::fromUtf8(C_LOCALE_ENGLISH_UNITEDKINGDOM);
|
||||
return QString::fromUtf8(C_LOCALE_ENGLISH);
|
||||
}
|
||||
case QLocale::French: return QString::fromUtf8(C_LOCALE_FRENCH);
|
||||
case QLocale::German: return QString::fromUtf8(C_LOCALE_GERMAN);
|
||||
case QLocale::Hungarian: return QString::fromUtf8(C_LOCALE_HUNGARIAN);
|
||||
case QLocale::Icelandic: return QString::fromUtf8(C_LOCALE_ICELANDIC);
|
||||
case QLocale::Indonesian: return QString::fromUtf8(C_LOCALE_INDONESIAN);
|
||||
case QLocale::Italian: return QString::fromUtf8(C_LOCALE_ITALIAN);
|
||||
case QLocale::Dutch: return QString::fromUtf8(C_LOCALE_DUTCH);
|
||||
case QLocale::Spanish: return QString::fromUtf8(C_LOCALE_SPANISH);
|
||||
case QLocale::Catalan: return QString::fromUtf8(C_LOCALE_CATALAN);
|
||||
case QLocale::Galician: return QString::fromUtf8(C_LOCALE_GALICIAN);
|
||||
case QLocale::Occitan: return QString::fromUtf8(C_LOCALE_OCCITAN);
|
||||
case QLocale::Portuguese: {
|
||||
if (locale.country() == QLocale::Brazil)
|
||||
return QString::fromUtf8(C_LOCALE_PORTUGUESE_BRAZIL);
|
||||
return QString::fromUtf8(C_LOCALE_PORTUGUESE);
|
||||
}
|
||||
case QLocale::Polish: return QString::fromUtf8(C_LOCALE_POLISH);
|
||||
case QLocale::Latvian: return QString::fromUtf8(C_LOCALE_LATVIAN);
|
||||
case QLocale::Lithuanian: return QString::fromUtf8(C_LOCALE_LITHUANIAN);
|
||||
case QLocale::Malay: return QString::fromUtf8(C_LOCALE_MALAY);
|
||||
case QLocale::Czech: return QString::fromUtf8(C_LOCALE_CZECH);
|
||||
case QLocale::Slovak: return QString::fromUtf8(C_LOCALE_SLOVAK);
|
||||
case QLocale::Slovenian: return QString::fromUtf8(C_LOCALE_SLOVENIAN);
|
||||
case QLocale::Serbian: return QString::fromUtf8(C_LOCALE_SERBIAN);
|
||||
case QLocale::Croatian: return QString::fromUtf8(C_LOCALE_CROATIAN);
|
||||
case QLocale::Armenian: return QString::fromUtf8(C_LOCALE_ARMENIAN);
|
||||
case QLocale::Romanian: return QString::fromUtf8(C_LOCALE_ROMANIAN);
|
||||
case QLocale::Turkish: return QString::fromUtf8(C_LOCALE_TURKISH);
|
||||
case QLocale::Greek: return QString::fromUtf8(C_LOCALE_GREEK);
|
||||
case QLocale::Swedish: return QString::fromUtf8(C_LOCALE_SWEDISH);
|
||||
case QLocale::Finnish: return QString::fromUtf8(C_LOCALE_FINNISH);
|
||||
case QLocale::Norwegian: return QString::fromUtf8(C_LOCALE_NORWEGIAN);
|
||||
case QLocale::Danish: return QString::fromUtf8(C_LOCALE_DANISH);
|
||||
case QLocale::Bulgarian: return QString::fromUtf8(C_LOCALE_BULGARIAN);
|
||||
case QLocale::Ukrainian: return QString::fromUtf8(C_LOCALE_UKRAINIAN);
|
||||
case QLocale::Uzbek: return QString::fromUtf8(C_LOCALE_UZBEK);
|
||||
case QLocale::Russian: return QString::fromUtf8(C_LOCALE_RUSSIAN);
|
||||
case QLocale::Japanese: return QString::fromUtf8(C_LOCALE_JAPANESE);
|
||||
case QLocale::Hebrew: return QString::fromUtf8(C_LOCALE_HEBREW);
|
||||
case QLocale::Hindi: return QString::fromUtf8(C_LOCALE_HINDI);
|
||||
case QLocale::Arabic: return QString::fromUtf8(C_LOCALE_ARABIC);
|
||||
case QLocale::Georgian: return QString::fromUtf8(C_LOCALE_GEORGIAN);
|
||||
case QLocale::Byelorussian: return QString::fromUtf8(C_LOCALE_BYELORUSSIAN);
|
||||
case QLocale::Basque: return QString::fromUtf8(C_LOCALE_BASQUE);
|
||||
case QLocale::Vietnamese: return QString::fromUtf8(C_LOCALE_VIETNAMESE);
|
||||
case QLocale::Chinese: {
|
||||
switch (locale.country()) {
|
||||
case QLocale::China:
|
||||
return QString::fromUtf8(C_LOCALE_CHINESE_SIMPLIFIED);
|
||||
case QLocale::HongKong:
|
||||
return QString::fromUtf8(C_LOCALE_CHINESE_TRADITIONAL_HK);
|
||||
default:
|
||||
return QString::fromUtf8(C_LOCALE_CHINESE_TRADITIONAL_TW);
|
||||
}
|
||||
}
|
||||
case QLocale::Korean: return QString::fromUtf8(C_LOCALE_KOREAN);
|
||||
default: {
|
||||
// Fallback to English
|
||||
const QString engLang = QLocale::languageToString(locale.language());
|
||||
qWarning() << "Unrecognized language name: " << engLang;
|
||||
return engLang;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool OptionsDialog::schedTimesOk()
|
||||
{
|
||||
if (m_ui->timeEditScheduleFrom->time() == m_ui->timeEditScheduleTo->time()) {
|
||||
|
||||
@@ -56,7 +56,7 @@ namespace Ui
|
||||
class OptionsDialog;
|
||||
}
|
||||
|
||||
class OptionsDialog : public QDialog
|
||||
class OptionsDialog final : public QDialog
|
||||
{
|
||||
Q_OBJECT
|
||||
using ThisType = OptionsDialog;
|
||||
@@ -82,7 +82,7 @@ class OptionsDialog : public QDialog
|
||||
public:
|
||||
// Constructor / Destructor
|
||||
OptionsDialog(QWidget *parent = nullptr);
|
||||
~OptionsDialog();
|
||||
~OptionsDialog() override;
|
||||
|
||||
public slots:
|
||||
void showConnectionTab();
|
||||
@@ -117,7 +117,6 @@ private:
|
||||
void saveOptions();
|
||||
void loadOptions();
|
||||
void initializeLanguageCombo();
|
||||
static QString languageToLocalizedString(const QLocale &locale);
|
||||
// General options
|
||||
QString getLocale() const;
|
||||
#ifndef Q_OS_MACOS
|
||||
|
||||
@@ -446,7 +446,7 @@
|
||||
<item>
|
||||
<widget class="QCheckBox" name="checkCloseToSystray">
|
||||
<property name="toolTip">
|
||||
<string>The systray icon will still be visible when closing the main window</string>
|
||||
<string>The systray icon will still be visible when closing the main window</string>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string extracomment="The systray icon will still be visible when closing the main window">Close qBittorrent to notification area</string>
|
||||
@@ -471,12 +471,12 @@
|
||||
</item>
|
||||
<item>
|
||||
<property name="text">
|
||||
<string>Monochrome (Dark theme)</string>
|
||||
<string>Monochrome (for dark theme)</string>
|
||||
</property>
|
||||
</item>
|
||||
<item>
|
||||
<property name="text">
|
||||
<string>Monochrome (Light theme)</string>
|
||||
<string>Monochrome (for light theme)</string>
|
||||
</property>
|
||||
</item>
|
||||
</widget>
|
||||
|
||||
@@ -30,10 +30,6 @@
|
||||
|
||||
#include <QtGlobal>
|
||||
|
||||
#if (defined(Q_OS_UNIX) && !defined(Q_OS_MACOS)) && defined(QT_DBUS_LIB)
|
||||
#include "powermanagement_x11.h"
|
||||
#endif
|
||||
|
||||
#ifdef Q_OS_MACOS
|
||||
#include <IOKit/pwr_mgt/IOPMLib.h>
|
||||
#endif
|
||||
@@ -42,9 +38,12 @@
|
||||
#include <windows.h>
|
||||
#endif
|
||||
|
||||
#if (defined(Q_OS_UNIX) && !defined(Q_OS_MACOS)) && defined(QT_DBUS_LIB)
|
||||
#include "powermanagement_x11.h"
|
||||
#endif
|
||||
|
||||
PowerManagement::PowerManagement(QObject *parent)
|
||||
: QObject(parent)
|
||||
, m_busy(false)
|
||||
{
|
||||
#if (defined(Q_OS_UNIX) && !defined(Q_OS_MACOS)) && defined(QT_DBUS_LIB)
|
||||
m_inhibitor = new PowerManagementInhibitor(this);
|
||||
@@ -55,7 +54,7 @@ PowerManagement::~PowerManagement()
|
||||
{
|
||||
}
|
||||
|
||||
void PowerManagement::setActivityState(bool busy)
|
||||
void PowerManagement::setActivityState(const bool busy)
|
||||
{
|
||||
if (busy)
|
||||
setBusy();
|
||||
|
||||
@@ -52,11 +52,11 @@ public:
|
||||
void setActivityState(bool busy);
|
||||
|
||||
private:
|
||||
bool m_busy;
|
||||
|
||||
void setBusy();
|
||||
void setIdle();
|
||||
|
||||
bool m_busy = false;
|
||||
|
||||
#if (defined(Q_OS_UNIX) && !defined(Q_OS_MACOS)) && defined(QT_DBUS_LIB)
|
||||
PowerManagementInhibitor *m_inhibitor;
|
||||
#endif
|
||||
|
||||
@@ -31,7 +31,7 @@
|
||||
|
||||
#include <QItemDelegate>
|
||||
|
||||
class PreviewListDelegate : public QItemDelegate
|
||||
class PreviewListDelegate final : public QItemDelegate
|
||||
{
|
||||
Q_OBJECT
|
||||
Q_DISABLE_COPY(PreviewListDelegate)
|
||||
|
||||
@@ -45,7 +45,7 @@ namespace Ui
|
||||
}
|
||||
class PreviewListDelegate;
|
||||
|
||||
class PreviewSelectDialog : public QDialog
|
||||
class PreviewSelectDialog final : public QDialog
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
|
||||
@@ -45,7 +45,7 @@ class QStringRef;
|
||||
|
||||
namespace Private
|
||||
{
|
||||
class FileSystemPathValidator : public QValidator
|
||||
class FileSystemPathValidator final : public QValidator
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
@@ -111,7 +111,7 @@ namespace Private
|
||||
virtual QWidget *widget() = 0;
|
||||
};
|
||||
|
||||
class FileLineEdit : public QLineEdit, public FileEditorWithCompletion
|
||||
class FileLineEdit final : public QLineEdit, public FileEditorWithCompletion
|
||||
{
|
||||
Q_OBJECT
|
||||
Q_DISABLE_COPY(FileLineEdit)
|
||||
@@ -141,7 +141,7 @@ namespace Private
|
||||
QAction *m_warningAction;
|
||||
};
|
||||
|
||||
class FileComboEdit : public QComboBox, public FileEditorWithCompletion
|
||||
class FileComboEdit final : public QComboBox, public FileEditorWithCompletion
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
|
||||
@@ -32,7 +32,7 @@
|
||||
|
||||
class QString;
|
||||
|
||||
class TriStateWidget : public QWidget
|
||||
class TriStateWidget final : public QWidget
|
||||
{
|
||||
Q_OBJECT
|
||||
Q_DISABLE_COPY(TriStateWidget)
|
||||
|
||||
@@ -36,7 +36,7 @@
|
||||
|
||||
class QWidget;
|
||||
|
||||
class DownloadedPiecesBar : public PiecesBar
|
||||
class DownloadedPiecesBar final : public PiecesBar
|
||||
{
|
||||
using base = PiecesBar;
|
||||
Q_OBJECT
|
||||
|
||||
@@ -31,7 +31,7 @@
|
||||
|
||||
#include <QSortFilterProxyModel>
|
||||
|
||||
class PeerListSortModel : public QSortFilterProxyModel
|
||||
class PeerListSortModel final : public QSortFilterProxyModel
|
||||
{
|
||||
Q_OBJECT
|
||||
Q_DISABLE_COPY(PeerListSortModel)
|
||||
|
||||
@@ -53,7 +53,7 @@ namespace Net
|
||||
class ReverseResolution;
|
||||
}
|
||||
|
||||
class PeerListWidget : public QTreeView
|
||||
class PeerListWidget final : public QTreeView
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
|
||||
@@ -31,7 +31,7 @@
|
||||
|
||||
#include "piecesbar.h"
|
||||
|
||||
class PieceAvailabilityBar : public PiecesBar
|
||||
class PieceAvailabilityBar final : public PiecesBar
|
||||
{
|
||||
using base = PiecesBar;
|
||||
Q_OBJECT
|
||||
|
||||
@@ -37,7 +37,9 @@
|
||||
#include <QTextStream>
|
||||
#include <QToolTip>
|
||||
|
||||
#include "base/indexrange.h"
|
||||
#include "base/bittorrent/torrenthandle.h"
|
||||
#include "base/bittorrent/torrentinfo.h"
|
||||
#include "base/utils/misc.h"
|
||||
|
||||
namespace
|
||||
|
||||
@@ -43,6 +43,7 @@
|
||||
#include <QUrl>
|
||||
|
||||
#include "base/bittorrent/downloadpriority.h"
|
||||
#include "base/bittorrent/infohash.h"
|
||||
#include "base/bittorrent/session.h"
|
||||
#include "base/bittorrent/torrenthandle.h"
|
||||
#include "base/preferences.h"
|
||||
|
||||
@@ -49,7 +49,7 @@ enum PropColumn
|
||||
AVAILABILITY
|
||||
};
|
||||
|
||||
class PropListDelegate : public QItemDelegate
|
||||
class PropListDelegate final : public QItemDelegate
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
|
||||
@@ -38,7 +38,7 @@
|
||||
|
||||
class QPen;
|
||||
|
||||
class SpeedPlotView : public QGraphicsView
|
||||
class SpeedPlotView final : public QGraphicsView
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
|
||||
@@ -40,7 +40,7 @@ class QVBoxLayout;
|
||||
class PropertiesWidget;
|
||||
class SpeedPlotView;
|
||||
|
||||
class ComboBoxMenuButton : public QComboBox
|
||||
class ComboBoxMenuButton final : public QComboBox
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
|
||||
@@ -31,7 +31,7 @@
|
||||
|
||||
#include <QMessageBox>
|
||||
|
||||
class RaisedMessageBox : public QMessageBox
|
||||
class RaisedMessageBox final : public QMessageBox
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
|
||||
@@ -41,7 +41,7 @@ namespace RSS
|
||||
class Item;
|
||||
}
|
||||
|
||||
class FeedListWidget : public QTreeWidget
|
||||
class FeedListWidget final : public QTreeWidget
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
|
||||
@@ -36,7 +36,7 @@ class QNetworkAccessManager;
|
||||
class QNetworkDiskCache;
|
||||
class QNetworkReply;
|
||||
|
||||
class HtmlBrowser : public QTextBrowser
|
||||
class HtmlBrowser final : public QTextBrowser
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
@@ -44,7 +44,7 @@ public:
|
||||
explicit HtmlBrowser(QWidget* parent = nullptr);
|
||||
~HtmlBrowser();
|
||||
|
||||
virtual QVariant loadResource(int type, const QUrl &name) override;
|
||||
QVariant loadResource(int type, const QUrl &name) override;
|
||||
|
||||
protected:
|
||||
QNetworkAccessManager *m_netManager;
|
||||
|
||||
@@ -39,7 +39,7 @@ class QTreeView;
|
||||
|
||||
class PropertiesWidget;
|
||||
|
||||
class ScanFoldersDelegate : public QItemDelegate
|
||||
class ScanFoldersDelegate final : public QItemDelegate
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
|
||||
@@ -48,7 +48,7 @@ namespace Ui
|
||||
class PluginSelectDialog;
|
||||
}
|
||||
|
||||
class PluginSelectDialog : public QDialog
|
||||
class PluginSelectDialog final : public QDialog
|
||||
{
|
||||
Q_OBJECT
|
||||
Q_DISABLE_COPY(PluginSelectDialog)
|
||||
|
||||
@@ -51,7 +51,7 @@ namespace Ui
|
||||
class SearchJobWidget;
|
||||
}
|
||||
|
||||
class SearchJobWidget : public QWidget
|
||||
class SearchJobWidget final : public QWidget
|
||||
{
|
||||
Q_OBJECT
|
||||
Q_DISABLE_COPY(SearchJobWidget)
|
||||
|
||||
@@ -31,7 +31,7 @@
|
||||
|
||||
#include <QItemDelegate>
|
||||
|
||||
class SearchListDelegate : public QItemDelegate
|
||||
class SearchListDelegate final : public QItemDelegate
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
|
||||
@@ -32,7 +32,7 @@
|
||||
#include <QSortFilterProxyModel>
|
||||
#include <QStringList>
|
||||
|
||||
class SearchSortModel : public QSortFilterProxyModel
|
||||
class SearchSortModel final : public QSortFilterProxyModel
|
||||
{
|
||||
using base = QSortFilterProxyModel;
|
||||
|
||||
|
||||
@@ -39,7 +39,7 @@ namespace Ui
|
||||
class ShutdownConfirmDialog;
|
||||
}
|
||||
|
||||
class ShutdownConfirmDialog : public QDialog
|
||||
class ShutdownConfirmDialog final : public QDialog
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
|
||||
@@ -42,7 +42,7 @@ namespace BitTorrent
|
||||
class TorrentHandle;
|
||||
}
|
||||
|
||||
class TagFilterModel : public QAbstractListModel
|
||||
class TagFilterModel final : public QAbstractListModel
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
|
||||
@@ -33,7 +33,7 @@
|
||||
|
||||
class QString;
|
||||
|
||||
class TagFilterProxyModel : public QSortFilterProxyModel
|
||||
class TagFilterProxyModel final : public QSortFilterProxyModel
|
||||
{
|
||||
public:
|
||||
explicit TagFilterProxyModel(QObject *parent = nullptr);
|
||||
|
||||
@@ -31,7 +31,7 @@
|
||||
|
||||
#include <QTreeView>
|
||||
|
||||
class TagFilterWidget : public QTreeView
|
||||
class TagFilterWidget final : public QTreeView
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
|
||||
@@ -35,7 +35,7 @@
|
||||
|
||||
class TorrentContentModel;
|
||||
|
||||
class TorrentContentFilterModel : public QSortFilterProxyModel
|
||||
class TorrentContentFilterModel final : public QSortFilterProxyModel
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user