mirror of
https://github.com/qbittorrent/qBittorrent
synced 2025-08-21 05:43:32 -07:00
Merge pull request #15150 from glassez/backports
Backport changes to v4.3.x branch
This commit is contained in:
commit
ede42910da
21 changed files with 116 additions and 288 deletions
|
@ -3,7 +3,7 @@ version: '{branch}-{build}'
|
||||||
# Do not build on tags (GitHub only)
|
# Do not build on tags (GitHub only)
|
||||||
skip_tags: true
|
skip_tags: true
|
||||||
|
|
||||||
image: Visual Studio 2017
|
image: Visual Studio 2019
|
||||||
|
|
||||||
branches:
|
branches:
|
||||||
except: # blacklist
|
except: # blacklist
|
||||||
|
@ -42,7 +42,7 @@ install:
|
||||||
|
|
||||||
before_build:
|
before_build:
|
||||||
# setup env
|
# setup env
|
||||||
- CALL "C:\Program Files (x86)\Microsoft Visual Studio\2017\Community\VC\Auxiliary\Build\vcvars32.bat"
|
- CALL "C:\Program Files (x86)\Microsoft Visual Studio\2019\Community\VC\Auxiliary\Build\vcvars32.bat"
|
||||||
- SET PATH=%PATH%;c:\qbt\qt5_32\bin;%CACHE_DIR%\jom;
|
- SET PATH=%PATH%;c:\qbt\qt5_32\bin;%CACHE_DIR%\jom;
|
||||||
# setup project
|
# setup project
|
||||||
- COPY /Y "%CACHE_DIR%\conf.pri" "%REPO_DIR%"
|
- COPY /Y "%CACHE_DIR%\conf.pri" "%REPO_DIR%"
|
||||||
|
|
188
.travis.yml
188
.travis.yml
|
@ -1,188 +0,0 @@
|
||||||
language: cpp
|
|
||||||
|
|
||||||
os:
|
|
||||||
- linux
|
|
||||||
- osx
|
|
||||||
|
|
||||||
dist: focal
|
|
||||||
osx_image: xcode12.2
|
|
||||||
|
|
||||||
env:
|
|
||||||
matrix:
|
|
||||||
- libt_branch=RC_1_2 gui=true build_system=qmake
|
|
||||||
- libt_branch=RC_1_2 gui=false build_system=qmake
|
|
||||||
- libt_branch=RC_1_2 gui=true build_system=cmake
|
|
||||||
- libt_branch=RC_1_2 gui=false build_system=cmake
|
|
||||||
global:
|
|
||||||
- secure: "OI9CUjj4lTb0HwwIZU5PbECU3hLlAL6KC8KsbwohG8/O3j5fLcnmDsK4Ad9us5cC39sS11Jcd1kDP2qRcCuST/glVNhLkcjKkiQerOfd5nQ/qL4JYfz/1mfP5mdpz9jHKzpLUIG+TXkbSTjP6VVmsb5KPT+3pKEdRFZB+Pu9+J8="
|
|
||||||
- coverity_branch: coverity_scan
|
|
||||||
|
|
||||||
jobs:
|
|
||||||
include:
|
|
||||||
- env: libt_branch=RC_2_0 gui=true build_system=qmake
|
|
||||||
os: linux
|
|
||||||
|
|
||||||
notifications:
|
|
||||||
email:
|
|
||||||
on_success: change
|
|
||||||
on_failure: change
|
|
||||||
|
|
||||||
cache:
|
|
||||||
ccache: true
|
|
||||||
directories:
|
|
||||||
- $HOME/travis/deb
|
|
||||||
- $HOME/travis/brew
|
|
||||||
|
|
||||||
addons:
|
|
||||||
coverity_scan:
|
|
||||||
project:
|
|
||||||
name: "qbittorrent/qBittorrent"
|
|
||||||
description: "Build submitted via Travis CI"
|
|
||||||
build_command_prepend: "./bootstrap.sh && ./configure $qmake_conf"
|
|
||||||
build_command: "make -j2"
|
|
||||||
branch_pattern: $coverity_branch
|
|
||||||
notification_email: sledgehammer999@qbittorrent.org
|
|
||||||
apt:
|
|
||||||
sources:
|
|
||||||
# sources list: https://github.com/travis-ci/apt-source-safelist/blob/master/ubuntu.json
|
|
||||||
- sourceline: 'deb https://apt.kitware.com/ubuntu/ focal main'
|
|
||||||
key_url: 'https://apt.kitware.com/keys/kitware-archive-latest.asc'
|
|
||||||
packages:
|
|
||||||
# packages list: https://github.com/travis-ci/apt-package-safelist/blob/master/ubuntu-trusty
|
|
||||||
- [autoconf, automake, cmake, colormake]
|
|
||||||
- [libboost-dev, libboost-system-dev]
|
|
||||||
- libssl-dev
|
|
||||||
- [qtbase5-dev, libqt5svg5-dev, qttools5-dev]
|
|
||||||
- zlib1g-dev
|
|
||||||
|
|
||||||
before_install:
|
|
||||||
# only allow specific build for coverity scan, others will stop
|
|
||||||
- if [ "$TRAVIS_BRANCH" = "$coverity_branch" ] && ! [ "$TRAVIS_OS_NAME" = "linux" -a "$libt_branch" = "RC_1_2" -a "$gui" = "true" -a "$build_system" = "qmake" ]; then exit ; fi
|
|
||||||
|
|
||||||
- shopt -s expand_aliases
|
|
||||||
- alias make="colormake -j2" # Using nprocs/2 sometimes may fail (gcc is killed by system)
|
|
||||||
- qbt_path="$HOME/qbt_install"
|
|
||||||
- qmake_conf="$qmake_conf --prefix=$qbt_path"
|
|
||||||
- cmake_conf="$cmake_conf -DCMAKE_INSTALL_PREFIX=$qbt_path"
|
|
||||||
|
|
||||||
# options for specific branches
|
|
||||||
- |
|
|
||||||
if [ "$TRAVIS_OS_NAME" = "linux" ]; then
|
|
||||||
# setup virtual display for after_success target
|
|
||||||
if [ "$gui" = "true" ]; then export "DISPLAY=:99.0" && /sbin/start-stop-daemon --start --quiet --pidfile /tmp/custom_xvfb_99.pid --make-pidfile --background --exec /usr/bin/Xvfb -- :99 -ac -screen 0 1280x1024x16 ; fi ;
|
|
||||||
# CMake from Kitware is installed in /usr/bin
|
|
||||||
# TravisCI installs its own cmake to another location which ovverides other installations
|
|
||||||
# if they don't call the new binary directly
|
|
||||||
alias cmake="/usr/bin/cmake"
|
|
||||||
|
|
||||||
export LD_LIBRARY_PATH="$LD_LIBRARY_PATH:/usr/local/lib"
|
|
||||||
fi
|
|
||||||
- |
|
|
||||||
if [ "$TRAVIS_OS_NAME" = "osx" ]; then
|
|
||||||
CXXFLAGS="$CXXFLAGS -Wno-unused-local-typedefs"
|
|
||||||
|
|
||||||
openssl_root_path="/usr/local/opt/openssl"
|
|
||||||
qmake_conf="$qmake_conf PKG_CONFIG_PATH=$openssl_root_path/lib/pkgconfig:$PKG_CONFIG_PATH"
|
|
||||||
cmake_conf="$cmake_conf -DOPENSSL_ROOT_DIR=$openssl_root_path"
|
|
||||||
fi
|
|
||||||
- |
|
|
||||||
if [ "$gui" = "false" ]; then
|
|
||||||
qmake_conf="$qmake_conf --disable-gui"
|
|
||||||
cmake_conf="$cmake_conf -DGUI=OFF"
|
|
||||||
fi
|
|
||||||
|
|
||||||
# print settings
|
|
||||||
- echo $libt_branch
|
|
||||||
- echo $gui
|
|
||||||
- echo $build_system
|
|
||||||
- echo $qmake_conf
|
|
||||||
- echo $cmake_conf
|
|
||||||
|
|
||||||
install:
|
|
||||||
- |
|
|
||||||
if [ "$TRAVIS_OS_NAME" = "osx" ]; then
|
|
||||||
# dependencies
|
|
||||||
PATH="/usr/local/opt/ccache/libexec:$PATH"
|
|
||||||
|
|
||||||
brew update > /dev/null
|
|
||||||
brew upgrade cmake
|
|
||||||
brew install ccache colormake boost openssl qt@5 zlib
|
|
||||||
brew link --force qt@5 zlib
|
|
||||||
|
|
||||||
if [ "$build_system" = "cmake" ]; then
|
|
||||||
sudo ln -s /usr/local/opt/qt/mkspecs /usr/local/mkspecs
|
|
||||||
sudo ln -s /usr/local/opt/qt/plugins /usr/local/plugins
|
|
||||||
fi
|
|
||||||
fi
|
|
||||||
- |
|
|
||||||
if [ "$TRAVIS_BRANCH" != "$coverity_branch" ]; then
|
|
||||||
export use_ccache=true
|
|
||||||
ccache -M 512M
|
|
||||||
ccache -V && ccache --show-stats && ccache --zero-stats
|
|
||||||
fi
|
|
||||||
- |
|
|
||||||
if [ "$libt_branch" = "RC_1_2" ]; then
|
|
||||||
pushd "$HOME"
|
|
||||||
git clone --single-branch --branch RC_1_2 https://github.com/arvidn/libtorrent.git
|
|
||||||
cd libtorrent
|
|
||||||
git checkout tags/v1.2.12
|
|
||||||
|
|
||||||
cmake \
|
|
||||||
-DCMAKE_BUILD_TYPE=Release \
|
|
||||||
-DCMAKE_CXX_STANDARD=17 \
|
|
||||||
-Ddeprecated-functions=OFF \
|
|
||||||
-DOPENSSL_ROOT_DIR="$openssl_root_path" \
|
|
||||||
./
|
|
||||||
make
|
|
||||||
sudo make install
|
|
||||||
popd
|
|
||||||
elif [ "$libt_branch" = "RC_2_0" ]; then
|
|
||||||
pushd "$HOME"
|
|
||||||
git clone --single-branch --branch RC_2_0 https://github.com/arvidn/libtorrent.git
|
|
||||||
cd libtorrent
|
|
||||||
git checkout tags/v2.0.2
|
|
||||||
git submodule update --init --recursive
|
|
||||||
|
|
||||||
cmake \
|
|
||||||
-DCMAKE_BUILD_TYPE=Release \
|
|
||||||
-DCMAKE_CXX_STANDARD=17 \
|
|
||||||
-Ddeprecated-functions=OFF \
|
|
||||||
-DOPENSSL_ROOT_DIR="$openssl_root_path" \
|
|
||||||
./
|
|
||||||
make
|
|
||||||
sudo make install
|
|
||||||
popd
|
|
||||||
fi
|
|
||||||
|
|
||||||
script:
|
|
||||||
- if [ "$TRAVIS_BRANCH" = "$coverity_branch" ]; then exit ; fi # skip usual build when running coverity scan
|
|
||||||
- |
|
|
||||||
cd "$TRAVIS_BUILD_DIR"
|
|
||||||
if [ "$build_system" = "qmake" ]; then
|
|
||||||
# scan only as lupdate is prone to hang
|
|
||||||
lupdate -extensions c,cpp,h,hpp,ui ./
|
|
||||||
./bootstrap.sh
|
|
||||||
./configure $qmake_conf CXXFLAGS="$CXXFLAGS"
|
|
||||||
else
|
|
||||||
mkdir build && cd build
|
|
||||||
cmake $cmake_conf ../
|
|
||||||
fi
|
|
||||||
- make
|
|
||||||
- make install
|
|
||||||
|
|
||||||
after_success:
|
|
||||||
- if [ "$gui" = "true" ]; then qbt_exe="qbittorrent" ; else qbt_exe="qbittorrent-nox" ; fi
|
|
||||||
- if [ "$TRAVIS_OS_NAME" = "linux" ]; then cd "$qbt_path/bin" ; fi
|
|
||||||
- |
|
|
||||||
if [ "$TRAVIS_OS_NAME" = "osx" ]; then
|
|
||||||
if [ "$build_system" = "qmake" ]; then
|
|
||||||
macdeployqt "$TRAVIS_BUILD_DIR/src/$qbt_exe.app"
|
|
||||||
cd "$TRAVIS_BUILD_DIR/src/$qbt_exe.app/Contents/MacOS"
|
|
||||||
else
|
|
||||||
cd "$qbt_path/$qbt_exe.app/Contents/MacOS"
|
|
||||||
fi
|
|
||||||
fi
|
|
||||||
- ./$qbt_exe --version
|
|
||||||
|
|
||||||
after_script:
|
|
||||||
- if [ "$use_ccache" = true ]; then ccache --show-stats ; fi
|
|
|
@ -1,7 +1,6 @@
|
||||||
qBittorrent - A BitTorrent client in Qt
|
qBittorrent - A BitTorrent client in Qt
|
||||||
------------------------------------------
|
------------------------------------------
|
||||||
|
|
||||||
[](https://travis-ci.org/qbittorrent/qBittorrent)
|
|
||||||
[](https://ci.appveyor.com/project/qbittorrent/qBittorrent)
|
[](https://ci.appveyor.com/project/qbittorrent/qBittorrent)
|
||||||
[](https://github.com/qbittorrent/qBittorrent/actions)
|
[](https://github.com/qbittorrent/qBittorrent/actions)
|
||||||
[](https://scan.coverity.com/projects/5494)
|
[](https://scan.coverity.com/projects/5494)
|
||||||
|
|
|
@ -83,13 +83,13 @@ MagnetUri::MagnetUri(const QString &source)
|
||||||
|
|
||||||
m_name = QString::fromStdString(m_addTorrentParams.name);
|
m_name = QString::fromStdString(m_addTorrentParams.name);
|
||||||
|
|
||||||
m_trackers.reserve(m_addTorrentParams.trackers.size());
|
m_trackers.reserve(static_cast<decltype(m_trackers)::size_type>(m_addTorrentParams.trackers.size()));
|
||||||
for (const std::string &tracker : m_addTorrentParams.trackers)
|
for (const std::string &tracker : m_addTorrentParams.trackers)
|
||||||
m_trackers.append({QString::fromStdString(tracker)});
|
m_trackers.append({QString::fromStdString(tracker)});
|
||||||
|
|
||||||
m_urlSeeds.reserve(m_addTorrentParams.url_seeds.size());
|
m_urlSeeds.reserve(static_cast<decltype(m_urlSeeds)::size_type>(m_addTorrentParams.url_seeds.size()));
|
||||||
for (const std::string &urlSeed : m_addTorrentParams.url_seeds)
|
for (const std::string &urlSeed : m_addTorrentParams.url_seeds)
|
||||||
m_urlSeeds.append(QUrl(QString::fromStdString(urlSeed)));
|
m_urlSeeds.append(QString::fromStdString(urlSeed));
|
||||||
}
|
}
|
||||||
|
|
||||||
bool MagnetUri::isValid() const
|
bool MagnetUri::isValid() const
|
||||||
|
|
|
@ -359,7 +359,7 @@ Session::Session(QObject *parent)
|
||||||
, m_announceToAllTiers(BITTORRENT_SESSION_KEY("AnnounceToAllTiers"), true)
|
, m_announceToAllTiers(BITTORRENT_SESSION_KEY("AnnounceToAllTiers"), true)
|
||||||
, m_asyncIOThreads(BITTORRENT_SESSION_KEY("AsyncIOThreadsCount"), 10)
|
, m_asyncIOThreads(BITTORRENT_SESSION_KEY("AsyncIOThreadsCount"), 10)
|
||||||
, m_hashingThreads(BITTORRENT_SESSION_KEY("HashingThreadsCount"), 2)
|
, m_hashingThreads(BITTORRENT_SESSION_KEY("HashingThreadsCount"), 2)
|
||||||
, m_filePoolSize(BITTORRENT_SESSION_KEY("FilePoolSize"), 40)
|
, m_filePoolSize(BITTORRENT_SESSION_KEY("FilePoolSize"), 5000)
|
||||||
, m_checkingMemUsage(BITTORRENT_SESSION_KEY("CheckingMemUsageSize"), 32)
|
, m_checkingMemUsage(BITTORRENT_SESSION_KEY("CheckingMemUsageSize"), 32)
|
||||||
, m_diskCacheSize(BITTORRENT_SESSION_KEY("DiskCacheSize"), -1)
|
, m_diskCacheSize(BITTORRENT_SESSION_KEY("DiskCacheSize"), -1)
|
||||||
, m_diskCacheTTL(BITTORRENT_SESSION_KEY("DiskCacheTTL"), 60)
|
, m_diskCacheTTL(BITTORRENT_SESSION_KEY("DiskCacheTTL"), 60)
|
||||||
|
@ -4984,7 +4984,7 @@ void Session::handleStorageMovedFailedAlert(const lt::storage_moved_failed_alert
|
||||||
void Session::handleStateUpdateAlert(const lt::state_update_alert *p)
|
void Session::handleStateUpdateAlert(const lt::state_update_alert *p)
|
||||||
{
|
{
|
||||||
QVector<Torrent *> updatedTorrents;
|
QVector<Torrent *> updatedTorrents;
|
||||||
updatedTorrents.reserve(p->status.size());
|
updatedTorrents.reserve(static_cast<decltype(updatedTorrents)::size_type>(p->status.size()));
|
||||||
|
|
||||||
for (const lt::torrent_status &status : p->status)
|
for (const lt::torrent_status &status : p->status)
|
||||||
{
|
{
|
||||||
|
|
|
@ -94,12 +94,6 @@ namespace BitTorrent
|
||||||
Error
|
Error
|
||||||
};
|
};
|
||||||
|
|
||||||
struct TrackerInfo
|
|
||||||
{
|
|
||||||
QString lastMessage;
|
|
||||||
int numPeers = 0;
|
|
||||||
};
|
|
||||||
|
|
||||||
uint qHash(TorrentState key, uint seed);
|
uint qHash(TorrentState key, uint seed);
|
||||||
|
|
||||||
class Torrent : public AbstractFileStorage
|
class Torrent : public AbstractFileStorage
|
||||||
|
@ -221,7 +215,6 @@ namespace BitTorrent
|
||||||
virtual bool hasFilteredPieces() const = 0;
|
virtual bool hasFilteredPieces() const = 0;
|
||||||
virtual int queuePosition() const = 0;
|
virtual int queuePosition() const = 0;
|
||||||
virtual QVector<TrackerEntry> trackers() const = 0;
|
virtual QVector<TrackerEntry> trackers() const = 0;
|
||||||
virtual QHash<QString, TrackerInfo> trackerInfos() const = 0;
|
|
||||||
virtual QVector<QUrl> urlSeeds() const = 0;
|
virtual QVector<QUrl> urlSeeds() const = 0;
|
||||||
virtual QString error() const = 0;
|
virtual QString error() const = 0;
|
||||||
virtual qlonglong totalDownload() const = 0;
|
virtual qlonglong totalDownload() const = 0;
|
||||||
|
|
|
@ -96,9 +96,11 @@ namespace
|
||||||
}
|
}
|
||||||
|
|
||||||
#if (LIBTORRENT_VERSION_NUM >= 20000)
|
#if (LIBTORRENT_VERSION_NUM >= 20000)
|
||||||
TrackerEntry fromNativeAnnouncerEntry(const lt::announce_entry &nativeEntry, const lt::info_hash_t &hashes)
|
TrackerEntry fromNativeAnnouncerEntry(const lt::announce_entry &nativeEntry
|
||||||
|
, const lt::info_hash_t &hashes, const QMap<lt::tcp::endpoint, int> &trackerPeerCounts)
|
||||||
#else
|
#else
|
||||||
TrackerEntry fromNativeAnnouncerEntry(const lt::announce_entry &nativeEntry)
|
TrackerEntry fromNativeAnnouncerEntry(const lt::announce_entry &nativeEntry
|
||||||
|
, const QMap<lt::tcp::endpoint, int> &trackerPeerCounts)
|
||||||
#endif
|
#endif
|
||||||
{
|
{
|
||||||
TrackerEntry trackerEntry {QString::fromStdString(nativeEntry.url), nativeEntry.tier};
|
TrackerEntry trackerEntry {QString::fromStdString(nativeEntry.url), nativeEntry.tier};
|
||||||
|
@ -106,9 +108,11 @@ namespace
|
||||||
int numUpdating = 0;
|
int numUpdating = 0;
|
||||||
int numWorking = 0;
|
int numWorking = 0;
|
||||||
int numNotWorking = 0;
|
int numNotWorking = 0;
|
||||||
|
QString firstTrackerMessage;
|
||||||
|
QString firstErrorMessage;
|
||||||
#if (LIBTORRENT_VERSION_NUM >= 20000)
|
#if (LIBTORRENT_VERSION_NUM >= 20000)
|
||||||
const int numEndpoints = nativeEntry.endpoints.size() * ((hashes.has_v1() && hashes.has_v2()) ? 2 : 1);
|
const size_t numEndpoints = nativeEntry.endpoints.size() * ((hashes.has_v1() && hashes.has_v2()) ? 2 : 1);
|
||||||
trackerEntry.endpoints.reserve(numEndpoints);
|
trackerEntry.endpoints.reserve(static_cast<decltype(trackerEntry.endpoints)::size_type>(numEndpoints));
|
||||||
for (const lt::announce_endpoint &endpoint : nativeEntry.endpoints)
|
for (const lt::announce_endpoint &endpoint : nativeEntry.endpoints)
|
||||||
{
|
{
|
||||||
for (const auto protocolVersion : {lt::protocol_version::V1, lt::protocol_version::V2})
|
for (const auto protocolVersion : {lt::protocol_version::V1, lt::protocol_version::V2})
|
||||||
|
@ -119,9 +123,11 @@ namespace
|
||||||
|
|
||||||
TrackerEntry::EndpointStats trackerEndpoint;
|
TrackerEntry::EndpointStats trackerEndpoint;
|
||||||
trackerEndpoint.protocolVersion = (protocolVersion == lt::protocol_version::V1) ? 1 : 2;
|
trackerEndpoint.protocolVersion = (protocolVersion == lt::protocol_version::V1) ? 1 : 2;
|
||||||
|
trackerEndpoint.numPeers = trackerPeerCounts.value(endpoint.local_endpoint, -1);
|
||||||
trackerEndpoint.numSeeds = infoHash.scrape_complete;
|
trackerEndpoint.numSeeds = infoHash.scrape_complete;
|
||||||
trackerEndpoint.numLeeches = infoHash.scrape_incomplete;
|
trackerEndpoint.numLeeches = infoHash.scrape_incomplete;
|
||||||
trackerEndpoint.numDownloaded = infoHash.scrape_downloaded;
|
trackerEndpoint.numDownloaded = infoHash.scrape_downloaded;
|
||||||
|
|
||||||
if (infoHash.updating)
|
if (infoHash.updating)
|
||||||
{
|
{
|
||||||
trackerEndpoint.status = TrackerEntry::Updating;
|
trackerEndpoint.status = TrackerEntry::Updating;
|
||||||
|
@ -141,11 +147,21 @@ namespace
|
||||||
{
|
{
|
||||||
trackerEndpoint.status = TrackerEntry::NotContacted;
|
trackerEndpoint.status = TrackerEntry::NotContacted;
|
||||||
}
|
}
|
||||||
trackerEntry.endpoints.append(trackerEndpoint);
|
|
||||||
|
|
||||||
trackerEntry.numSeeds = std::max(trackerEntry.numSeeds, infoHash.scrape_complete);
|
const QString trackerMessage = QString::fromStdString(infoHash.message);
|
||||||
trackerEntry.numLeeches = std::max(trackerEntry.numLeeches, infoHash.scrape_incomplete);
|
const QString errorMessage = QString::fromLocal8Bit(infoHash.last_error.message().c_str());
|
||||||
trackerEntry.numDownloaded = std::max(trackerEntry.numDownloaded, infoHash.scrape_downloaded);
|
trackerEndpoint.message = (!trackerMessage.isEmpty() ? trackerMessage : errorMessage);
|
||||||
|
|
||||||
|
trackerEntry.endpoints.append(trackerEndpoint);
|
||||||
|
trackerEntry.numPeers = std::max(trackerEntry.numPeers, trackerEndpoint.numPeers);
|
||||||
|
trackerEntry.numSeeds = std::max(trackerEntry.numSeeds, trackerEndpoint.numSeeds);
|
||||||
|
trackerEntry.numLeeches = std::max(trackerEntry.numLeeches, trackerEndpoint.numLeeches);
|
||||||
|
trackerEntry.numDownloaded = std::max(trackerEntry.numDownloaded, trackerEndpoint.numDownloaded);
|
||||||
|
|
||||||
|
if (firstTrackerMessage.isEmpty())
|
||||||
|
firstTrackerMessage = trackerMessage;
|
||||||
|
if (firstErrorMessage.isEmpty())
|
||||||
|
firstErrorMessage = errorMessage;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -155,9 +171,11 @@ namespace
|
||||||
for (const lt::announce_endpoint &endpoint : nativeEntry.endpoints)
|
for (const lt::announce_endpoint &endpoint : nativeEntry.endpoints)
|
||||||
{
|
{
|
||||||
TrackerEntry::EndpointStats trackerEndpoint;
|
TrackerEntry::EndpointStats trackerEndpoint;
|
||||||
|
trackerEndpoint.numPeers = trackerPeerCounts.value(endpoint.local_endpoint, -1);
|
||||||
trackerEndpoint.numSeeds = endpoint.scrape_complete;
|
trackerEndpoint.numSeeds = endpoint.scrape_complete;
|
||||||
trackerEndpoint.numLeeches = endpoint.scrape_incomplete;
|
trackerEndpoint.numLeeches = endpoint.scrape_incomplete;
|
||||||
trackerEndpoint.numDownloaded = endpoint.scrape_downloaded;
|
trackerEndpoint.numDownloaded = endpoint.scrape_downloaded;
|
||||||
|
|
||||||
if (endpoint.updating)
|
if (endpoint.updating)
|
||||||
{
|
{
|
||||||
trackerEndpoint.status = TrackerEntry::Updating;
|
trackerEndpoint.status = TrackerEntry::Updating;
|
||||||
|
@ -177,22 +195,40 @@ namespace
|
||||||
{
|
{
|
||||||
trackerEndpoint.status = TrackerEntry::NotContacted;
|
trackerEndpoint.status = TrackerEntry::NotContacted;
|
||||||
}
|
}
|
||||||
trackerEntry.endpoints.append(trackerEndpoint);
|
|
||||||
|
|
||||||
trackerEntry.numSeeds = std::max(trackerEntry.numSeeds, endpoint.scrape_complete);
|
const QString trackerMessage = QString::fromStdString(endpoint.message);
|
||||||
trackerEntry.numLeeches = std::max(trackerEntry.numLeeches, endpoint.scrape_incomplete);
|
const QString errorMessage = QString::fromLocal8Bit(endpoint.last_error.message().c_str());
|
||||||
trackerEntry.numDownloaded = std::max(trackerEntry.numDownloaded, endpoint.scrape_downloaded);
|
trackerEndpoint.message = (!trackerMessage.isEmpty() ? trackerMessage : errorMessage);
|
||||||
|
|
||||||
|
trackerEntry.endpoints.append(trackerEndpoint);
|
||||||
|
trackerEntry.numPeers = std::max(trackerEntry.numPeers, trackerEndpoint.numPeers);
|
||||||
|
trackerEntry.numSeeds = std::max(trackerEntry.numSeeds, trackerEndpoint.numSeeds);
|
||||||
|
trackerEntry.numLeeches = std::max(trackerEntry.numLeeches, trackerEndpoint.numLeeches);
|
||||||
|
trackerEntry.numDownloaded = std::max(trackerEntry.numDownloaded, trackerEndpoint.numDownloaded);
|
||||||
|
|
||||||
|
if (firstTrackerMessage.isEmpty())
|
||||||
|
firstTrackerMessage = trackerMessage;
|
||||||
|
if (firstErrorMessage.isEmpty())
|
||||||
|
firstErrorMessage = errorMessage;
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
if (numEndpoints > 0)
|
if (numEndpoints > 0)
|
||||||
{
|
{
|
||||||
if (numUpdating > 0)
|
if (numUpdating > 0)
|
||||||
|
{
|
||||||
trackerEntry.status = TrackerEntry::Updating;
|
trackerEntry.status = TrackerEntry::Updating;
|
||||||
|
}
|
||||||
else if (numWorking > 0)
|
else if (numWorking > 0)
|
||||||
|
{
|
||||||
trackerEntry.status = TrackerEntry::Working;
|
trackerEntry.status = TrackerEntry::Working;
|
||||||
|
trackerEntry.message = firstTrackerMessage;
|
||||||
|
}
|
||||||
else if (numNotWorking == numEndpoints)
|
else if (numNotWorking == numEndpoints)
|
||||||
|
{
|
||||||
trackerEntry.status = TrackerEntry::NotWorking;
|
trackerEntry.status = TrackerEntry::NotWorking;
|
||||||
|
trackerEntry.message = (!firstTrackerMessage.isEmpty() ? firstTrackerMessage : firstErrorMessage);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return trackerEntry;
|
return trackerEntry;
|
||||||
|
@ -436,23 +472,21 @@ QVector<TrackerEntry> TorrentImpl::trackers() const
|
||||||
const std::vector<lt::announce_entry> nativeTrackers = m_nativeHandle.trackers();
|
const std::vector<lt::announce_entry> nativeTrackers = m_nativeHandle.trackers();
|
||||||
|
|
||||||
QVector<TrackerEntry> entries;
|
QVector<TrackerEntry> entries;
|
||||||
entries.reserve(nativeTrackers.size());
|
entries.reserve(static_cast<decltype(entries)::size_type>(nativeTrackers.size()));
|
||||||
|
|
||||||
for (const lt::announce_entry &tracker : nativeTrackers)
|
for (const lt::announce_entry &tracker : nativeTrackers)
|
||||||
|
{
|
||||||
|
const QString trackerURL = QString::fromStdString(tracker.url);
|
||||||
#if (LIBTORRENT_VERSION_NUM >= 20000)
|
#if (LIBTORRENT_VERSION_NUM >= 20000)
|
||||||
entries << fromNativeAnnouncerEntry(tracker, m_nativeHandle.info_hashes());
|
entries << fromNativeAnnouncerEntry(tracker, m_nativeHandle.info_hashes(), m_trackerPeerCounts[trackerURL]);
|
||||||
#else
|
#else
|
||||||
entries << fromNativeAnnouncerEntry(tracker);
|
entries << fromNativeAnnouncerEntry(tracker, m_trackerPeerCounts[trackerURL]);
|
||||||
#endif
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
return entries;
|
return entries;
|
||||||
}
|
}
|
||||||
|
|
||||||
QHash<QString, TrackerInfo> TorrentImpl::trackerInfos() const
|
|
||||||
{
|
|
||||||
return m_trackerInfos;
|
|
||||||
}
|
|
||||||
|
|
||||||
void TorrentImpl::addTrackers(const QVector<TrackerEntry> &trackers)
|
void TorrentImpl::addTrackers(const QVector<TrackerEntry> &trackers)
|
||||||
{
|
{
|
||||||
QSet<TrackerEntry> currentTrackers;
|
QSet<TrackerEntry> currentTrackers;
|
||||||
|
@ -525,10 +559,10 @@ QVector<QUrl> TorrentImpl::urlSeeds() const
|
||||||
const std::set<std::string> currentSeeds = m_nativeHandle.url_seeds();
|
const std::set<std::string> currentSeeds = m_nativeHandle.url_seeds();
|
||||||
|
|
||||||
QVector<QUrl> urlSeeds;
|
QVector<QUrl> urlSeeds;
|
||||||
urlSeeds.reserve(currentSeeds.size());
|
urlSeeds.reserve(static_cast<decltype(urlSeeds)::size_type>(currentSeeds.size()));
|
||||||
|
|
||||||
for (const std::string &urlSeed : currentSeeds)
|
for (const std::string &urlSeed : currentSeeds)
|
||||||
urlSeeds.append(QUrl(urlSeed.c_str()));
|
urlSeeds.append(QString::fromStdString(urlSeed));
|
||||||
|
|
||||||
return urlSeeds;
|
return urlSeeds;
|
||||||
}
|
}
|
||||||
|
@ -1188,9 +1222,11 @@ QVector<PeerInfo> TorrentImpl::peers() const
|
||||||
m_nativeHandle.get_peer_info(nativePeers);
|
m_nativeHandle.get_peer_info(nativePeers);
|
||||||
|
|
||||||
QVector<PeerInfo> peers;
|
QVector<PeerInfo> peers;
|
||||||
peers.reserve(nativePeers.size());
|
peers.reserve(static_cast<decltype(peers)::size_type>(nativePeers.size()));
|
||||||
|
|
||||||
for (const lt::peer_info &peer : nativePeers)
|
for (const lt::peer_info &peer : nativePeers)
|
||||||
peers << PeerInfo(this, peer);
|
peers << PeerInfo(this, peer);
|
||||||
|
|
||||||
return peers;
|
return peers;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1627,10 +1663,8 @@ void TorrentImpl::handleMoveStorageJobFinished(const bool hasOutstandingJob)
|
||||||
|
|
||||||
void TorrentImpl::handleTrackerReplyAlert(const lt::tracker_reply_alert *p)
|
void TorrentImpl::handleTrackerReplyAlert(const lt::tracker_reply_alert *p)
|
||||||
{
|
{
|
||||||
const QString trackerUrl(p->tracker_url());
|
const QString trackerUrl = p->tracker_url();
|
||||||
qDebug("Received a tracker reply from %s (Num_peers = %d)", qUtf8Printable(trackerUrl), p->num_peers);
|
m_trackerPeerCounts[trackerUrl][p->local_endpoint] = p->num_peers;
|
||||||
// Connection was successful now. Remove possible old errors
|
|
||||||
m_trackerInfos[trackerUrl] = {{}, p->num_peers};
|
|
||||||
|
|
||||||
m_session->handleTorrentTrackerReply(this, trackerUrl);
|
m_session->handleTorrentTrackerReply(this, trackerUrl);
|
||||||
}
|
}
|
||||||
|
@ -1638,20 +1672,12 @@ void TorrentImpl::handleTrackerReplyAlert(const lt::tracker_reply_alert *p)
|
||||||
void TorrentImpl::handleTrackerWarningAlert(const lt::tracker_warning_alert *p)
|
void TorrentImpl::handleTrackerWarningAlert(const lt::tracker_warning_alert *p)
|
||||||
{
|
{
|
||||||
const QString trackerUrl = p->tracker_url();
|
const QString trackerUrl = p->tracker_url();
|
||||||
const QString message = p->warning_message();
|
|
||||||
|
|
||||||
// Connection was successful now but there is a warning message
|
|
||||||
m_trackerInfos[trackerUrl].lastMessage = message; // Store warning message
|
|
||||||
|
|
||||||
m_session->handleTorrentTrackerWarning(this, trackerUrl);
|
m_session->handleTorrentTrackerWarning(this, trackerUrl);
|
||||||
}
|
}
|
||||||
|
|
||||||
void TorrentImpl::handleTrackerErrorAlert(const lt::tracker_error_alert *p)
|
void TorrentImpl::handleTrackerErrorAlert(const lt::tracker_error_alert *p)
|
||||||
{
|
{
|
||||||
const QString trackerUrl = p->tracker_url();
|
const QString trackerUrl = p->tracker_url();
|
||||||
const QString message = p->error_message();
|
|
||||||
|
|
||||||
m_trackerInfos[trackerUrl].lastMessage = message;
|
|
||||||
|
|
||||||
// Starting with libtorrent 1.2.x each tracker has multiple local endpoints from which
|
// Starting with libtorrent 1.2.x each tracker has multiple local endpoints from which
|
||||||
// an announce is attempted. Some endpoints might succeed while others might fail.
|
// an announce is attempted. Some endpoints might succeed while others might fail.
|
||||||
|
|
|
@ -33,11 +33,13 @@
|
||||||
|
|
||||||
#include <libtorrent/add_torrent_params.hpp>
|
#include <libtorrent/add_torrent_params.hpp>
|
||||||
#include <libtorrent/fwd.hpp>
|
#include <libtorrent/fwd.hpp>
|
||||||
|
#include <libtorrent/socket.hpp>
|
||||||
#include <libtorrent/torrent_handle.hpp>
|
#include <libtorrent/torrent_handle.hpp>
|
||||||
#include <libtorrent/torrent_status.hpp>
|
#include <libtorrent/torrent_status.hpp>
|
||||||
|
|
||||||
#include <QDateTime>
|
#include <QDateTime>
|
||||||
#include <QHash>
|
#include <QHash>
|
||||||
|
#include <QMap>
|
||||||
#include <QObject>
|
#include <QObject>
|
||||||
#include <QQueue>
|
#include <QQueue>
|
||||||
#include <QSet>
|
#include <QSet>
|
||||||
|
@ -170,7 +172,6 @@ namespace BitTorrent
|
||||||
bool hasFilteredPieces() const override;
|
bool hasFilteredPieces() const override;
|
||||||
int queuePosition() const override;
|
int queuePosition() const override;
|
||||||
QVector<TrackerEntry> trackers() const override;
|
QVector<TrackerEntry> trackers() const override;
|
||||||
QHash<QString, TrackerInfo> trackerInfos() const override;
|
|
||||||
QVector<QUrl> urlSeeds() const override;
|
QVector<QUrl> urlSeeds() const override;
|
||||||
QString error() const override;
|
QString error() const override;
|
||||||
qlonglong totalDownload() const override;
|
qlonglong totalDownload() const override;
|
||||||
|
@ -321,8 +322,8 @@ namespace BitTorrent
|
||||||
// we will rely on this workaround to remove empty leftover folders
|
// we will rely on this workaround to remove empty leftover folders
|
||||||
QHash<lt::file_index_t, QVector<QString>> m_oldPath;
|
QHash<lt::file_index_t, QVector<QString>> m_oldPath;
|
||||||
|
|
||||||
QHash<QString, TrackerInfo> m_trackerInfos;
|
|
||||||
FileErrorInfo m_lastFileError;
|
FileErrorInfo m_lastFileError;
|
||||||
|
QHash<QString, QMap<lt::tcp::endpoint, int>> m_trackerPeerCounts;
|
||||||
|
|
||||||
// Persistent data
|
// Persistent data
|
||||||
QString m_name;
|
QString m_name;
|
||||||
|
|
|
@ -306,10 +306,11 @@ QVector<TrackerEntry> TorrentInfo::trackers() const
|
||||||
const std::vector<lt::announce_entry> trackers = m_nativeInfo->trackers();
|
const std::vector<lt::announce_entry> trackers = m_nativeInfo->trackers();
|
||||||
|
|
||||||
QVector<TrackerEntry> ret;
|
QVector<TrackerEntry> ret;
|
||||||
ret.reserve(trackers.size());
|
ret.reserve(static_cast<decltype(ret)::size_type>(trackers.size()));
|
||||||
|
|
||||||
for (const lt::announce_entry &tracker : trackers)
|
for (const lt::announce_entry &tracker : trackers)
|
||||||
ret.append({QString::fromStdString(tracker.url)});
|
ret.append({QString::fromStdString(tracker.url)});
|
||||||
|
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -320,7 +321,7 @@ QVector<QUrl> TorrentInfo::urlSeeds() const
|
||||||
const std::vector<lt::web_seed_entry> &nativeWebSeeds = m_nativeInfo->web_seeds();
|
const std::vector<lt::web_seed_entry> &nativeWebSeeds = m_nativeInfo->web_seeds();
|
||||||
|
|
||||||
QVector<QUrl> urlSeeds;
|
QVector<QUrl> urlSeeds;
|
||||||
urlSeeds.reserve(nativeWebSeeds.size());
|
urlSeeds.reserve(static_cast<decltype(urlSeeds)::size_type>(nativeWebSeeds.size()));
|
||||||
|
|
||||||
for (const lt::web_seed_entry &webSeed : nativeWebSeeds)
|
for (const lt::web_seed_entry &webSeed : nativeWebSeeds)
|
||||||
{
|
{
|
||||||
|
@ -360,11 +361,10 @@ QVector<int> TorrentInfo::fileIndicesForPiece(const int pieceIndex) const
|
||||||
if (!isValid() || (pieceIndex < 0) || (pieceIndex >= piecesCount()))
|
if (!isValid() || (pieceIndex < 0) || (pieceIndex >= piecesCount()))
|
||||||
return {};
|
return {};
|
||||||
|
|
||||||
const std::vector<lt::file_slice> files(
|
const std::vector<lt::file_slice> files = nativeInfo()->map_block(
|
||||||
nativeInfo()->map_block(lt::piece_index_t {pieceIndex}, 0
|
lt::piece_index_t {pieceIndex}, 0, nativeInfo()->piece_size(lt::piece_index_t {pieceIndex}));
|
||||||
, nativeInfo()->piece_size(lt::piece_index_t {pieceIndex})));
|
|
||||||
QVector<int> res;
|
QVector<int> res;
|
||||||
res.reserve(int(files.size()));
|
res.reserve(static_cast<decltype(res)::size_type>(files.size()));
|
||||||
std::transform(files.begin(), files.end(), std::back_inserter(res),
|
std::transform(files.begin(), files.end(), std::back_inserter(res),
|
||||||
[](const lt::file_slice &s) { return static_cast<int>(s.file_index); });
|
[](const lt::file_slice &s) { return static_cast<int>(s.file_index); });
|
||||||
|
|
||||||
|
|
|
@ -49,9 +49,11 @@ namespace BitTorrent
|
||||||
int protocolVersion = 1;
|
int protocolVersion = 1;
|
||||||
|
|
||||||
Status status = NotContacted;
|
Status status = NotContacted;
|
||||||
|
int numPeers = -1;
|
||||||
int numSeeds = -1;
|
int numSeeds = -1;
|
||||||
int numLeeches = -1;
|
int numLeeches = -1;
|
||||||
int numDownloaded = -1;
|
int numDownloaded = -1;
|
||||||
|
QString message;
|
||||||
};
|
};
|
||||||
|
|
||||||
QString url;
|
QString url;
|
||||||
|
@ -61,9 +63,11 @@ namespace BitTorrent
|
||||||
|
|
||||||
// Deprecated fields
|
// Deprecated fields
|
||||||
Status status = NotContacted;
|
Status status = NotContacted;
|
||||||
|
int numPeers = -1;
|
||||||
int numSeeds = -1;
|
int numSeeds = -1;
|
||||||
int numLeeches = -1;
|
int numLeeches = -1;
|
||||||
int numDownloaded = -1;
|
int numDownloaded = -1;
|
||||||
|
QString message;
|
||||||
};
|
};
|
||||||
|
|
||||||
bool operator==(const TrackerEntry &left, const TrackerEntry &right);
|
bool operator==(const TrackerEntry &left, const TrackerEntry &right);
|
||||||
|
|
|
@ -39,7 +39,7 @@ namespace
|
||||||
QVector<T> loadFromBuffer(const boost::circular_buffer_space_optimized<T> &src, const int offset = 0)
|
QVector<T> loadFromBuffer(const boost::circular_buffer_space_optimized<T> &src, const int offset = 0)
|
||||||
{
|
{
|
||||||
QVector<T> ret;
|
QVector<T> ret;
|
||||||
ret.reserve(src.size() - offset);
|
ret.reserve(static_cast<typename decltype(ret)::size_type>(src.size()) - offset);
|
||||||
std::copy((src.begin() + offset), src.end(), std::back_inserter(ret));
|
std::copy((src.begin() + offset), src.end(), std::back_inserter(ret));
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
@ -95,7 +95,7 @@ QVector<Log::Msg> Logger::getMessages(const int lastKnownId) const
|
||||||
const QReadLocker locker(&m_lock);
|
const QReadLocker locker(&m_lock);
|
||||||
|
|
||||||
const int diff = m_msgCounter - lastKnownId - 1;
|
const int diff = m_msgCounter - lastKnownId - 1;
|
||||||
const int size = m_messages.size();
|
const int size = static_cast<int>(m_messages.size());
|
||||||
|
|
||||||
if ((lastKnownId == -1) || (diff >= size))
|
if ((lastKnownId == -1) || (diff >= size))
|
||||||
return loadFromBuffer(m_messages);
|
return loadFromBuffer(m_messages);
|
||||||
|
@ -111,7 +111,7 @@ QVector<Log::Peer> Logger::getPeers(const int lastKnownId) const
|
||||||
const QReadLocker locker(&m_lock);
|
const QReadLocker locker(&m_lock);
|
||||||
|
|
||||||
const int diff = m_peerCounter - lastKnownId - 1;
|
const int diff = m_peerCounter - lastKnownId - 1;
|
||||||
const int size = m_peers.size();
|
const int size = static_cast<int>(m_peers.size());
|
||||||
|
|
||||||
if ((lastKnownId == -1) || (diff >= size))
|
if ((lastKnownId == -1) || (diff >= size))
|
||||||
return loadFromBuffer(m_peers);
|
return loadFromBuffer(m_peers);
|
||||||
|
|
|
@ -600,13 +600,10 @@ void TorrentFilesWatcher::Worker::addWatchedFolder(const QString &path, const To
|
||||||
{
|
{
|
||||||
#if !defined Q_OS_HAIKU
|
#if !defined Q_OS_HAIKU
|
||||||
// Check if the path points to a network file system or not
|
// Check if the path points to a network file system or not
|
||||||
if (Utils::Fs::isNetworkFileSystem(path))
|
if (Utils::Fs::isNetworkFileSystem(path) || options.recursive)
|
||||||
{
|
#else
|
||||||
m_watchedByTimeoutFolders.insert(path);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
#endif
|
|
||||||
if (options.recursive)
|
if (options.recursive)
|
||||||
|
#endif
|
||||||
{
|
{
|
||||||
m_watchedByTimeoutFolders.insert(path);
|
m_watchedByTimeoutFolders.insert(path);
|
||||||
if (!m_watchTimer->isActive())
|
if (!m_watchTimer->isActive())
|
||||||
|
|
|
@ -79,7 +79,7 @@ BaseLogModel::BaseLogModel(QObject *parent)
|
||||||
|
|
||||||
int BaseLogModel::rowCount(const QModelIndex &) const
|
int BaseLogModel::rowCount(const QModelIndex &) const
|
||||||
{
|
{
|
||||||
return m_messages.size();
|
return static_cast<int>(m_messages.size());
|
||||||
}
|
}
|
||||||
|
|
||||||
int BaseLogModel::columnCount(const QModelIndex &) const
|
int BaseLogModel::columnCount(const QModelIndex &) const
|
||||||
|
@ -120,7 +120,7 @@ void BaseLogModel::addNewMessage(const BaseLogModel::Message &message)
|
||||||
// but because of calling of beginInsertRows function we'll have ghost rows.
|
// but because of calling of beginInsertRows function we'll have ghost rows.
|
||||||
if (m_messages.size() == MAX_VISIBLE_MESSAGES)
|
if (m_messages.size() == MAX_VISIBLE_MESSAGES)
|
||||||
{
|
{
|
||||||
const int lastMessage = m_messages.size() - 1;
|
const int lastMessage = static_cast<int>(m_messages.size()) - 1;
|
||||||
beginRemoveRows(QModelIndex(), lastMessage, lastMessage);
|
beginRemoveRows(QModelIndex(), lastMessage, lastMessage);
|
||||||
m_messages.pop_back();
|
m_messages.pop_back();
|
||||||
endRemoveRows();
|
endRemoveRows();
|
||||||
|
|
|
@ -33,7 +33,6 @@
|
||||||
#include <QClipboard>
|
#include <QClipboard>
|
||||||
#include <QColor>
|
#include <QColor>
|
||||||
#include <QDebug>
|
#include <QDebug>
|
||||||
#include <QHash>
|
|
||||||
#include <QHeaderView>
|
#include <QHeaderView>
|
||||||
#include <QMenu>
|
#include <QMenu>
|
||||||
#include <QMessageBox>
|
#include <QMessageBox>
|
||||||
|
@ -363,7 +362,6 @@ void TrackerListWidget::loadTrackers()
|
||||||
loadStickyItems(torrent);
|
loadStickyItems(torrent);
|
||||||
|
|
||||||
// Load actual trackers information
|
// Load actual trackers information
|
||||||
const QHash<QString, BitTorrent::TrackerInfo> trackerData = torrent->trackerInfos();
|
|
||||||
QStringList oldTrackerURLs = m_trackerItems.keys();
|
QStringList oldTrackerURLs = m_trackerItems.keys();
|
||||||
|
|
||||||
for (const BitTorrent::TrackerEntry &entry : asConst(torrent->trackers()))
|
for (const BitTorrent::TrackerEntry &entry : asConst(torrent->trackers()))
|
||||||
|
@ -385,29 +383,26 @@ void TrackerListWidget::loadTrackers()
|
||||||
|
|
||||||
item->setText(COL_TIER, QString::number(entry.tier));
|
item->setText(COL_TIER, QString::number(entry.tier));
|
||||||
|
|
||||||
const BitTorrent::TrackerInfo data = trackerData.value(trackerURL);
|
|
||||||
|
|
||||||
switch (entry.status)
|
switch (entry.status)
|
||||||
{
|
{
|
||||||
case BitTorrent::TrackerEntry::Working:
|
case BitTorrent::TrackerEntry::Working:
|
||||||
item->setText(COL_STATUS, tr("Working"));
|
item->setText(COL_STATUS, tr("Working"));
|
||||||
item->setText(COL_MSG, "");
|
|
||||||
break;
|
break;
|
||||||
case BitTorrent::TrackerEntry::Updating:
|
case BitTorrent::TrackerEntry::Updating:
|
||||||
item->setText(COL_STATUS, tr("Updating..."));
|
item->setText(COL_STATUS, tr("Updating..."));
|
||||||
item->setText(COL_MSG, "");
|
|
||||||
break;
|
break;
|
||||||
case BitTorrent::TrackerEntry::NotWorking:
|
case BitTorrent::TrackerEntry::NotWorking:
|
||||||
item->setText(COL_STATUS, tr("Not working"));
|
item->setText(COL_STATUS, tr("Not working"));
|
||||||
item->setText(COL_MSG, data.lastMessage.trimmed());
|
|
||||||
break;
|
break;
|
||||||
case BitTorrent::TrackerEntry::NotContacted:
|
case BitTorrent::TrackerEntry::NotContacted:
|
||||||
item->setText(COL_STATUS, tr("Not contacted yet"));
|
item->setText(COL_STATUS, tr("Not contacted yet"));
|
||||||
item->setText(COL_MSG, "");
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
item->setText(COL_PEERS, QString::number(data.numPeers));
|
item->setText(COL_MSG, entry.message);
|
||||||
|
item->setText(COL_PEERS, ((entry.numPeers > -1)
|
||||||
|
? QString::number(entry.numPeers)
|
||||||
|
: tr("N/A")));
|
||||||
item->setText(COL_SEEDS, ((entry.numSeeds > -1)
|
item->setText(COL_SEEDS, ((entry.numSeeds > -1)
|
||||||
? QString::number(entry.numSeeds)
|
? QString::number(entry.numSeeds)
|
||||||
: tr("N/A")));
|
: tr("N/A")));
|
||||||
|
|
|
@ -318,7 +318,7 @@ TagModelItem *TagFilterModel::findItem(const QString &tag)
|
||||||
QVector<TagModelItem *> TagFilterModel::findItems(const QSet<QString> &tags)
|
QVector<TagModelItem *> TagFilterModel::findItems(const QSet<QString> &tags)
|
||||||
{
|
{
|
||||||
QVector<TagModelItem *> items;
|
QVector<TagModelItem *> items;
|
||||||
items.reserve(tags.size());
|
items.reserve(tags.count());
|
||||||
for (const QString &tag : tags)
|
for (const QString &tag : tags)
|
||||||
{
|
{
|
||||||
TagModelItem *item = findItem(tag);
|
TagModelItem *item = findItem(tag);
|
||||||
|
|
|
@ -1008,14 +1008,14 @@ void TransferListWidget::displayListMenu(const QPoint &)
|
||||||
for (const QString &tag : asConst(tags))
|
for (const QString &tag : asConst(tags))
|
||||||
{
|
{
|
||||||
auto *action = new TriStateAction(tag, tagsMenu);
|
auto *action = new TriStateAction(tag, tagsMenu);
|
||||||
action->setCloseOnTriggered(false);
|
action->setCloseOnInteraction(false);
|
||||||
|
|
||||||
const Qt::CheckState initialState = tagsInAll.contains(tag) ? Qt::Checked
|
const Qt::CheckState initialState = tagsInAll.contains(tag) ? Qt::Checked
|
||||||
: tagsInAny.contains(tag) ? Qt::PartiallyChecked
|
: tagsInAny.contains(tag) ? Qt::PartiallyChecked
|
||||||
: Qt::Unchecked;
|
: Qt::Unchecked;
|
||||||
action->setCheckState(initialState);
|
action->setCheckState(initialState);
|
||||||
|
|
||||||
connect(action, &QAction::triggered, this, [this, tag](const bool checked)
|
connect(action, &QAction::toggled, this, [this, tag](const bool checked)
|
||||||
{
|
{
|
||||||
if (checked)
|
if (checked)
|
||||||
addSelectionTag(tag);
|
addSelectionTag(tag);
|
||||||
|
|
|
@ -45,8 +45,7 @@ TriStateAction::TriStateAction(const QString &text, QWidget *parent)
|
||||||
m_triStateWidget->setCheckState(checked ? Qt::Checked : Qt::Unchecked);
|
m_triStateWidget->setCheckState(checked ? Qt::Checked : Qt::Unchecked);
|
||||||
});
|
});
|
||||||
|
|
||||||
connect(m_triStateWidget, &TriStateWidget::triggered, this, &QAction::setChecked);
|
connect(m_triStateWidget, &TriStateWidget::triggered, this, &QAction::toggled);
|
||||||
connect(m_triStateWidget, &TriStateWidget::triggered, this, &QAction::triggered);
|
|
||||||
setDefaultWidget(m_triStateWidget);
|
setDefaultWidget(m_triStateWidget);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -56,7 +55,7 @@ void TriStateAction::setCheckState(const Qt::CheckState checkState)
|
||||||
m_triStateWidget->setCheckState(checkState);
|
m_triStateWidget->setCheckState(checkState);
|
||||||
}
|
}
|
||||||
|
|
||||||
void TriStateAction::setCloseOnTriggered(const bool enabled)
|
void TriStateAction::setCloseOnInteraction(const bool enabled)
|
||||||
{
|
{
|
||||||
m_triStateWidget->setCloseOnTriggered(enabled);
|
m_triStateWidget->setCloseOnInteraction(enabled);
|
||||||
}
|
}
|
||||||
|
|
|
@ -37,7 +37,7 @@ class TriStateWidget;
|
||||||
|
|
||||||
// TriStateWidget is responsible for checkbox state (tri-state) and paint events while
|
// TriStateWidget is responsible for checkbox state (tri-state) and paint events while
|
||||||
// TriStateAction will keep in sync with it. This allows connecting with the usual
|
// TriStateAction will keep in sync with it. This allows connecting with the usual
|
||||||
// QAction::triggered slot.
|
// QAction::triggered or QAction::toggled slots.
|
||||||
class TriStateAction : public QWidgetAction
|
class TriStateAction : public QWidgetAction
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
|
@ -46,7 +46,12 @@ public:
|
||||||
// should use this function instead of QAction::setChecked(bool)
|
// should use this function instead of QAction::setChecked(bool)
|
||||||
void setCheckState(Qt::CheckState checkState);
|
void setCheckState(Qt::CheckState checkState);
|
||||||
|
|
||||||
void setCloseOnTriggered(bool enabled);
|
// When set to 'true' toggling the checkbox will emit a signal on
|
||||||
|
// QAction::triggered. When placed in a QMenu, this causes the menu to close.
|
||||||
|
// When set to 'false' emits a signal on QAction::toggled instead, leaving the
|
||||||
|
// menu open.
|
||||||
|
// Default value: 'true'.
|
||||||
|
void setCloseOnInteraction(bool enabled);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
TriStateWidget *m_triStateWidget;
|
TriStateWidget *m_triStateWidget;
|
||||||
|
|
|
@ -38,7 +38,7 @@
|
||||||
|
|
||||||
TriStateWidget::TriStateWidget(const QString &text, QWidget *parent)
|
TriStateWidget::TriStateWidget(const QString &text, QWidget *parent)
|
||||||
: QWidget {parent}
|
: QWidget {parent}
|
||||||
, m_closeOnTriggered {true}
|
, m_closeOnInteraction {true}
|
||||||
, m_checkState {Qt::Unchecked}
|
, m_checkState {Qt::Unchecked}
|
||||||
, m_text {text}
|
, m_text {text}
|
||||||
{
|
{
|
||||||
|
@ -51,9 +51,9 @@ void TriStateWidget::setCheckState(const Qt::CheckState checkState)
|
||||||
m_checkState = checkState;
|
m_checkState = checkState;
|
||||||
}
|
}
|
||||||
|
|
||||||
void TriStateWidget::setCloseOnTriggered(const bool enabled)
|
void TriStateWidget::setCloseOnInteraction(const bool enabled)
|
||||||
{
|
{
|
||||||
m_closeOnTriggered = enabled;
|
m_closeOnInteraction = enabled;
|
||||||
}
|
}
|
||||||
|
|
||||||
QSize TriStateWidget::minimumSizeHint() const
|
QSize TriStateWidget::minimumSizeHint() const
|
||||||
|
@ -104,7 +104,7 @@ void TriStateWidget::mouseReleaseEvent(QMouseEvent *event)
|
||||||
{
|
{
|
||||||
toggleCheckState();
|
toggleCheckState();
|
||||||
|
|
||||||
if (m_closeOnTriggered)
|
if (m_closeOnInteraction)
|
||||||
{
|
{
|
||||||
// parent `triggered` signal will be emitted
|
// parent `triggered` signal will be emitted
|
||||||
QWidget::mouseReleaseEvent(event);
|
QWidget::mouseReleaseEvent(event);
|
||||||
|
@ -112,7 +112,7 @@ void TriStateWidget::mouseReleaseEvent(QMouseEvent *event)
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
update();
|
update();
|
||||||
// need to emit parent `triggered` signal manually
|
// need to emit `triggered` signal manually
|
||||||
emit triggered(m_checkState == Qt::Checked);
|
emit triggered(m_checkState == Qt::Checked);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -124,7 +124,7 @@ void TriStateWidget::keyPressEvent(QKeyEvent *event)
|
||||||
{
|
{
|
||||||
toggleCheckState();
|
toggleCheckState();
|
||||||
|
|
||||||
if (!m_closeOnTriggered)
|
if (!m_closeOnInteraction)
|
||||||
{
|
{
|
||||||
update();
|
update();
|
||||||
// need to emit parent `triggered` signal manually
|
// need to emit parent `triggered` signal manually
|
||||||
|
|
|
@ -41,7 +41,7 @@ public:
|
||||||
TriStateWidget(const QString &text, QWidget *parent);
|
TriStateWidget(const QString &text, QWidget *parent);
|
||||||
|
|
||||||
void setCheckState(Qt::CheckState checkState);
|
void setCheckState(Qt::CheckState checkState);
|
||||||
void setCloseOnTriggered(bool enabled);
|
void setCloseOnInteraction(bool enabled);
|
||||||
|
|
||||||
signals:
|
signals:
|
||||||
void triggered(bool checked) const;
|
void triggered(bool checked) const;
|
||||||
|
@ -55,7 +55,7 @@ private:
|
||||||
|
|
||||||
void toggleCheckState();
|
void toggleCheckState();
|
||||||
|
|
||||||
bool m_closeOnTriggered;
|
bool m_closeOnInteraction;
|
||||||
Qt::CheckState m_checkState;
|
Qt::CheckState m_checkState;
|
||||||
const QString m_text;
|
const QString m_text;
|
||||||
};
|
};
|
||||||
|
|
|
@ -453,18 +453,15 @@ void TorrentsController::trackersAction()
|
||||||
|
|
||||||
QJsonArray trackerList = getStickyTrackers(torrent);
|
QJsonArray trackerList = getStickyTrackers(torrent);
|
||||||
|
|
||||||
QHash<QString, BitTorrent::TrackerInfo> trackersData = torrent->trackerInfos();
|
|
||||||
for (const BitTorrent::TrackerEntry &tracker : asConst(torrent->trackers()))
|
for (const BitTorrent::TrackerEntry &tracker : asConst(torrent->trackers()))
|
||||||
{
|
{
|
||||||
const BitTorrent::TrackerInfo data = trackersData.value(tracker.url);
|
|
||||||
|
|
||||||
trackerList << QJsonObject
|
trackerList << QJsonObject
|
||||||
{
|
{
|
||||||
{KEY_TRACKER_URL, tracker.url},
|
{KEY_TRACKER_URL, tracker.url},
|
||||||
{KEY_TRACKER_TIER, tracker.tier},
|
{KEY_TRACKER_TIER, tracker.tier},
|
||||||
{KEY_TRACKER_STATUS, static_cast<int>(tracker.status)},
|
{KEY_TRACKER_STATUS, static_cast<int>(tracker.status)},
|
||||||
{KEY_TRACKER_PEERS_COUNT, data.numPeers},
|
{KEY_TRACKER_MSG, tracker.message},
|
||||||
{KEY_TRACKER_MSG, data.lastMessage.trimmed()},
|
{KEY_TRACKER_PEERS_COUNT, tracker.numPeers},
|
||||||
{KEY_TRACKER_SEEDS_COUNT, tracker.numSeeds},
|
{KEY_TRACKER_SEEDS_COUNT, tracker.numSeeds},
|
||||||
{KEY_TRACKER_LEECHES_COUNT, tracker.numLeeches},
|
{KEY_TRACKER_LEECHES_COUNT, tracker.numLeeches},
|
||||||
{KEY_TRACKER_DOWNLOADED_COUNT, tracker.numDownloaded}
|
{KEY_TRACKER_DOWNLOADED_COUNT, tracker.numDownloaded}
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue