diff --git a/.appveyor.yml b/.appveyor.yml index e74e56069a8..bd987d47072 100644 --- a/.appveyor.yml +++ b/.appveyor.yml @@ -3,7 +3,7 @@ version: '{branch}-{build}' # Do not build on tags (GitHub only) skip_tags: true -image: Visual Studio 2017 +image: Visual Studio 2019 branches: except: # blacklist @@ -42,7 +42,7 @@ install: before_build: # 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; # setup project - COPY /Y "%CACHE_DIR%\conf.pri" "%REPO_DIR%" diff --git a/.travis.yml b/.travis.yml deleted file mode 100644 index dbf00b2df03..00000000000 --- a/.travis.yml +++ /dev/null @@ -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 diff --git a/README.md b/README.md index ff7624a17b5..353c7559a81 100644 --- a/README.md +++ b/README.md @@ -1,7 +1,6 @@ qBittorrent - A BitTorrent client in Qt ------------------------------------------ -[![TravisCI Status](https://travis-ci.org/qbittorrent/qBittorrent.svg?branch=master)](https://travis-ci.org/qbittorrent/qBittorrent) [![AppVeyor Status](https://ci.appveyor.com/api/projects/status/github/qbittorrent/qBittorrent?branch=master&svg=true)](https://ci.appveyor.com/project/qbittorrent/qBittorrent) [![GitHub Actions CI Status](https://github.com/qbittorrent/qBittorrent/workflows/GitHub%20Actions%20CI/badge.svg)](https://github.com/qbittorrent/qBittorrent/actions) [![Coverity Status](https://scan.coverity.com/projects/5494/badge.svg)](https://scan.coverity.com/projects/5494) diff --git a/src/base/bittorrent/magneturi.cpp b/src/base/bittorrent/magneturi.cpp index cf755e1a70d..ef8f7b812cc 100644 --- a/src/base/bittorrent/magneturi.cpp +++ b/src/base/bittorrent/magneturi.cpp @@ -83,13 +83,13 @@ MagnetUri::MagnetUri(const QString &source) m_name = QString::fromStdString(m_addTorrentParams.name); - m_trackers.reserve(m_addTorrentParams.trackers.size()); + m_trackers.reserve(static_cast(m_addTorrentParams.trackers.size())); for (const std::string &tracker : m_addTorrentParams.trackers) m_trackers.append({QString::fromStdString(tracker)}); - m_urlSeeds.reserve(m_addTorrentParams.url_seeds.size()); + m_urlSeeds.reserve(static_cast(m_addTorrentParams.url_seeds.size())); 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 diff --git a/src/base/bittorrent/session.cpp b/src/base/bittorrent/session.cpp index bd804bddf4e..4cce40e92d5 100644 --- a/src/base/bittorrent/session.cpp +++ b/src/base/bittorrent/session.cpp @@ -359,7 +359,7 @@ Session::Session(QObject *parent) , m_announceToAllTiers(BITTORRENT_SESSION_KEY("AnnounceToAllTiers"), true) , m_asyncIOThreads(BITTORRENT_SESSION_KEY("AsyncIOThreadsCount"), 10) , 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_diskCacheSize(BITTORRENT_SESSION_KEY("DiskCacheSize"), -1) , 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) { QVector updatedTorrents; - updatedTorrents.reserve(p->status.size()); + updatedTorrents.reserve(static_cast(p->status.size())); for (const lt::torrent_status &status : p->status) { diff --git a/src/base/bittorrent/torrent.h b/src/base/bittorrent/torrent.h index de8cae7d359..4573617e2f8 100644 --- a/src/base/bittorrent/torrent.h +++ b/src/base/bittorrent/torrent.h @@ -94,12 +94,6 @@ namespace BitTorrent Error }; - struct TrackerInfo - { - QString lastMessage; - int numPeers = 0; - }; - uint qHash(TorrentState key, uint seed); class Torrent : public AbstractFileStorage @@ -221,7 +215,6 @@ namespace BitTorrent virtual bool hasFilteredPieces() const = 0; virtual int queuePosition() const = 0; virtual QVector trackers() const = 0; - virtual QHash trackerInfos() const = 0; virtual QVector urlSeeds() const = 0; virtual QString error() const = 0; virtual qlonglong totalDownload() const = 0; diff --git a/src/base/bittorrent/torrentimpl.cpp b/src/base/bittorrent/torrentimpl.cpp index 167e20d738c..18306cf5886 100644 --- a/src/base/bittorrent/torrentimpl.cpp +++ b/src/base/bittorrent/torrentimpl.cpp @@ -96,9 +96,11 @@ namespace } #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 &trackerPeerCounts) #else - TrackerEntry fromNativeAnnouncerEntry(const lt::announce_entry &nativeEntry) + TrackerEntry fromNativeAnnouncerEntry(const lt::announce_entry &nativeEntry + , const QMap &trackerPeerCounts) #endif { TrackerEntry trackerEntry {QString::fromStdString(nativeEntry.url), nativeEntry.tier}; @@ -106,9 +108,11 @@ namespace int numUpdating = 0; int numWorking = 0; int numNotWorking = 0; + QString firstTrackerMessage; + QString firstErrorMessage; #if (LIBTORRENT_VERSION_NUM >= 20000) - const int numEndpoints = nativeEntry.endpoints.size() * ((hashes.has_v1() && hashes.has_v2()) ? 2 : 1); - trackerEntry.endpoints.reserve(numEndpoints); + const size_t numEndpoints = nativeEntry.endpoints.size() * ((hashes.has_v1() && hashes.has_v2()) ? 2 : 1); + trackerEntry.endpoints.reserve(static_cast(numEndpoints)); for (const lt::announce_endpoint &endpoint : nativeEntry.endpoints) { for (const auto protocolVersion : {lt::protocol_version::V1, lt::protocol_version::V2}) @@ -119,9 +123,11 @@ namespace TrackerEntry::EndpointStats trackerEndpoint; trackerEndpoint.protocolVersion = (protocolVersion == lt::protocol_version::V1) ? 1 : 2; + trackerEndpoint.numPeers = trackerPeerCounts.value(endpoint.local_endpoint, -1); trackerEndpoint.numSeeds = infoHash.scrape_complete; trackerEndpoint.numLeeches = infoHash.scrape_incomplete; trackerEndpoint.numDownloaded = infoHash.scrape_downloaded; + if (infoHash.updating) { trackerEndpoint.status = TrackerEntry::Updating; @@ -141,11 +147,21 @@ namespace { trackerEndpoint.status = TrackerEntry::NotContacted; } - trackerEntry.endpoints.append(trackerEndpoint); - trackerEntry.numSeeds = std::max(trackerEntry.numSeeds, infoHash.scrape_complete); - trackerEntry.numLeeches = std::max(trackerEntry.numLeeches, infoHash.scrape_incomplete); - trackerEntry.numDownloaded = std::max(trackerEntry.numDownloaded, infoHash.scrape_downloaded); + const QString trackerMessage = QString::fromStdString(infoHash.message); + const QString errorMessage = QString::fromLocal8Bit(infoHash.last_error.message().c_str()); + 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) { TrackerEntry::EndpointStats trackerEndpoint; + trackerEndpoint.numPeers = trackerPeerCounts.value(endpoint.local_endpoint, -1); trackerEndpoint.numSeeds = endpoint.scrape_complete; trackerEndpoint.numLeeches = endpoint.scrape_incomplete; trackerEndpoint.numDownloaded = endpoint.scrape_downloaded; + if (endpoint.updating) { trackerEndpoint.status = TrackerEntry::Updating; @@ -177,22 +195,40 @@ namespace { trackerEndpoint.status = TrackerEntry::NotContacted; } - trackerEntry.endpoints.append(trackerEndpoint); - trackerEntry.numSeeds = std::max(trackerEntry.numSeeds, endpoint.scrape_complete); - trackerEntry.numLeeches = std::max(trackerEntry.numLeeches, endpoint.scrape_incomplete); - trackerEntry.numDownloaded = std::max(trackerEntry.numDownloaded, endpoint.scrape_downloaded); + const QString trackerMessage = QString::fromStdString(endpoint.message); + const QString errorMessage = QString::fromLocal8Bit(endpoint.last_error.message().c_str()); + 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 if (numEndpoints > 0) { if (numUpdating > 0) + { trackerEntry.status = TrackerEntry::Updating; + } else if (numWorking > 0) + { trackerEntry.status = TrackerEntry::Working; + trackerEntry.message = firstTrackerMessage; + } else if (numNotWorking == numEndpoints) + { trackerEntry.status = TrackerEntry::NotWorking; + trackerEntry.message = (!firstTrackerMessage.isEmpty() ? firstTrackerMessage : firstErrorMessage); + } } return trackerEntry; @@ -436,23 +472,21 @@ QVector TorrentImpl::trackers() const const std::vector nativeTrackers = m_nativeHandle.trackers(); QVector entries; - entries.reserve(nativeTrackers.size()); + entries.reserve(static_cast(nativeTrackers.size())); for (const lt::announce_entry &tracker : nativeTrackers) + { + const QString trackerURL = QString::fromStdString(tracker.url); #if (LIBTORRENT_VERSION_NUM >= 20000) - entries << fromNativeAnnouncerEntry(tracker, m_nativeHandle.info_hashes()); + entries << fromNativeAnnouncerEntry(tracker, m_nativeHandle.info_hashes(), m_trackerPeerCounts[trackerURL]); #else - entries << fromNativeAnnouncerEntry(tracker); + entries << fromNativeAnnouncerEntry(tracker, m_trackerPeerCounts[trackerURL]); #endif + } return entries; } -QHash TorrentImpl::trackerInfos() const -{ - return m_trackerInfos; -} - void TorrentImpl::addTrackers(const QVector &trackers) { QSet currentTrackers; @@ -525,10 +559,10 @@ QVector TorrentImpl::urlSeeds() const const std::set currentSeeds = m_nativeHandle.url_seeds(); QVector urlSeeds; - urlSeeds.reserve(currentSeeds.size()); + urlSeeds.reserve(static_cast(currentSeeds.size())); for (const std::string &urlSeed : currentSeeds) - urlSeeds.append(QUrl(urlSeed.c_str())); + urlSeeds.append(QString::fromStdString(urlSeed)); return urlSeeds; } @@ -1188,9 +1222,11 @@ QVector TorrentImpl::peers() const m_nativeHandle.get_peer_info(nativePeers); QVector peers; - peers.reserve(nativePeers.size()); + peers.reserve(static_cast(nativePeers.size())); + for (const lt::peer_info &peer : nativePeers) peers << PeerInfo(this, peer); + return peers; } @@ -1627,10 +1663,8 @@ void TorrentImpl::handleMoveStorageJobFinished(const bool hasOutstandingJob) void TorrentImpl::handleTrackerReplyAlert(const lt::tracker_reply_alert *p) { - const QString trackerUrl(p->tracker_url()); - qDebug("Received a tracker reply from %s (Num_peers = %d)", qUtf8Printable(trackerUrl), p->num_peers); - // Connection was successful now. Remove possible old errors - m_trackerInfos[trackerUrl] = {{}, p->num_peers}; + const QString trackerUrl = p->tracker_url(); + m_trackerPeerCounts[trackerUrl][p->local_endpoint] = p->num_peers; 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) { 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); } void TorrentImpl::handleTrackerErrorAlert(const lt::tracker_error_alert *p) { 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 // an announce is attempted. Some endpoints might succeed while others might fail. diff --git a/src/base/bittorrent/torrentimpl.h b/src/base/bittorrent/torrentimpl.h index 25902fa98a4..ff25b6d0e3c 100644 --- a/src/base/bittorrent/torrentimpl.h +++ b/src/base/bittorrent/torrentimpl.h @@ -33,11 +33,13 @@ #include #include +#include #include #include #include #include +#include #include #include #include @@ -170,7 +172,6 @@ namespace BitTorrent bool hasFilteredPieces() const override; int queuePosition() const override; QVector trackers() const override; - QHash trackerInfos() const override; QVector urlSeeds() const override; QString error() const override; qlonglong totalDownload() const override; @@ -321,8 +322,8 @@ namespace BitTorrent // we will rely on this workaround to remove empty leftover folders QHash> m_oldPath; - QHash m_trackerInfos; FileErrorInfo m_lastFileError; + QHash> m_trackerPeerCounts; // Persistent data QString m_name; diff --git a/src/base/bittorrent/torrentinfo.cpp b/src/base/bittorrent/torrentinfo.cpp index e610b821974..aaccedac953 100644 --- a/src/base/bittorrent/torrentinfo.cpp +++ b/src/base/bittorrent/torrentinfo.cpp @@ -306,10 +306,11 @@ QVector TorrentInfo::trackers() const const std::vector trackers = m_nativeInfo->trackers(); QVector ret; - ret.reserve(trackers.size()); + ret.reserve(static_cast(trackers.size())); for (const lt::announce_entry &tracker : trackers) ret.append({QString::fromStdString(tracker.url)}); + return ret; } @@ -320,7 +321,7 @@ QVector TorrentInfo::urlSeeds() const const std::vector &nativeWebSeeds = m_nativeInfo->web_seeds(); QVector urlSeeds; - urlSeeds.reserve(nativeWebSeeds.size()); + urlSeeds.reserve(static_cast(nativeWebSeeds.size())); for (const lt::web_seed_entry &webSeed : nativeWebSeeds) { @@ -360,11 +361,10 @@ QVector TorrentInfo::fileIndicesForPiece(const int pieceIndex) const if (!isValid() || (pieceIndex < 0) || (pieceIndex >= piecesCount())) return {}; - const std::vector files( - nativeInfo()->map_block(lt::piece_index_t {pieceIndex}, 0 - , nativeInfo()->piece_size(lt::piece_index_t {pieceIndex}))); + const std::vector files = nativeInfo()->map_block( + lt::piece_index_t {pieceIndex}, 0, nativeInfo()->piece_size(lt::piece_index_t {pieceIndex})); QVector res; - res.reserve(int(files.size())); + res.reserve(static_cast(files.size())); std::transform(files.begin(), files.end(), std::back_inserter(res), [](const lt::file_slice &s) { return static_cast(s.file_index); }); diff --git a/src/base/bittorrent/trackerentry.h b/src/base/bittorrent/trackerentry.h index e4bdd55388d..63f7434dbf4 100644 --- a/src/base/bittorrent/trackerentry.h +++ b/src/base/bittorrent/trackerentry.h @@ -49,9 +49,11 @@ namespace BitTorrent int protocolVersion = 1; Status status = NotContacted; + int numPeers = -1; int numSeeds = -1; int numLeeches = -1; int numDownloaded = -1; + QString message; }; QString url; @@ -61,9 +63,11 @@ namespace BitTorrent // Deprecated fields Status status = NotContacted; + int numPeers = -1; int numSeeds = -1; int numLeeches = -1; int numDownloaded = -1; + QString message; }; bool operator==(const TrackerEntry &left, const TrackerEntry &right); diff --git a/src/base/logger.cpp b/src/base/logger.cpp index fc5c358e6b6..88835cc9966 100644 --- a/src/base/logger.cpp +++ b/src/base/logger.cpp @@ -39,7 +39,7 @@ namespace QVector loadFromBuffer(const boost::circular_buffer_space_optimized &src, const int offset = 0) { QVector ret; - ret.reserve(src.size() - offset); + ret.reserve(static_cast(src.size()) - offset); std::copy((src.begin() + offset), src.end(), std::back_inserter(ret)); return ret; } @@ -95,7 +95,7 @@ QVector Logger::getMessages(const int lastKnownId) const const QReadLocker locker(&m_lock); const int diff = m_msgCounter - lastKnownId - 1; - const int size = m_messages.size(); + const int size = static_cast(m_messages.size()); if ((lastKnownId == -1) || (diff >= size)) return loadFromBuffer(m_messages); @@ -111,7 +111,7 @@ QVector Logger::getPeers(const int lastKnownId) const const QReadLocker locker(&m_lock); const int diff = m_peerCounter - lastKnownId - 1; - const int size = m_peers.size(); + const int size = static_cast(m_peers.size()); if ((lastKnownId == -1) || (diff >= size)) return loadFromBuffer(m_peers); diff --git a/src/base/torrentfileswatcher.cpp b/src/base/torrentfileswatcher.cpp index 99f9c8daeb1..ee44c5c3ee4 100644 --- a/src/base/torrentfileswatcher.cpp +++ b/src/base/torrentfileswatcher.cpp @@ -600,13 +600,10 @@ void TorrentFilesWatcher::Worker::addWatchedFolder(const QString &path, const To { #if !defined Q_OS_HAIKU // Check if the path points to a network file system or not - if (Utils::Fs::isNetworkFileSystem(path)) - { - m_watchedByTimeoutFolders.insert(path); - } - else -#endif + if (Utils::Fs::isNetworkFileSystem(path) || options.recursive) +#else if (options.recursive) +#endif { m_watchedByTimeoutFolders.insert(path); if (!m_watchTimer->isActive()) diff --git a/src/gui/log/logmodel.cpp b/src/gui/log/logmodel.cpp index 50386e3234b..8c8d4b0236f 100644 --- a/src/gui/log/logmodel.cpp +++ b/src/gui/log/logmodel.cpp @@ -79,7 +79,7 @@ BaseLogModel::BaseLogModel(QObject *parent) int BaseLogModel::rowCount(const QModelIndex &) const { - return m_messages.size(); + return static_cast(m_messages.size()); } 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. if (m_messages.size() == MAX_VISIBLE_MESSAGES) { - const int lastMessage = m_messages.size() - 1; + const int lastMessage = static_cast(m_messages.size()) - 1; beginRemoveRows(QModelIndex(), lastMessage, lastMessage); m_messages.pop_back(); endRemoveRows(); diff --git a/src/gui/properties/trackerlistwidget.cpp b/src/gui/properties/trackerlistwidget.cpp index fd323761245..a1d00af0944 100644 --- a/src/gui/properties/trackerlistwidget.cpp +++ b/src/gui/properties/trackerlistwidget.cpp @@ -33,7 +33,6 @@ #include #include #include -#include #include #include #include @@ -363,7 +362,6 @@ void TrackerListWidget::loadTrackers() loadStickyItems(torrent); // Load actual trackers information - const QHash trackerData = torrent->trackerInfos(); QStringList oldTrackerURLs = m_trackerItems.keys(); for (const BitTorrent::TrackerEntry &entry : asConst(torrent->trackers())) @@ -385,29 +383,26 @@ void TrackerListWidget::loadTrackers() item->setText(COL_TIER, QString::number(entry.tier)); - const BitTorrent::TrackerInfo data = trackerData.value(trackerURL); - switch (entry.status) { case BitTorrent::TrackerEntry::Working: item->setText(COL_STATUS, tr("Working")); - item->setText(COL_MSG, ""); break; case BitTorrent::TrackerEntry::Updating: item->setText(COL_STATUS, tr("Updating...")); - item->setText(COL_MSG, ""); break; case BitTorrent::TrackerEntry::NotWorking: item->setText(COL_STATUS, tr("Not working")); - item->setText(COL_MSG, data.lastMessage.trimmed()); break; case BitTorrent::TrackerEntry::NotContacted: item->setText(COL_STATUS, tr("Not contacted yet")); - item->setText(COL_MSG, ""); 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) ? QString::number(entry.numSeeds) : tr("N/A"))); diff --git a/src/gui/tagfiltermodel.cpp b/src/gui/tagfiltermodel.cpp index 0713ad17750..fbb384bc677 100644 --- a/src/gui/tagfiltermodel.cpp +++ b/src/gui/tagfiltermodel.cpp @@ -318,7 +318,7 @@ TagModelItem *TagFilterModel::findItem(const QString &tag) QVector TagFilterModel::findItems(const QSet &tags) { QVector items; - items.reserve(tags.size()); + items.reserve(tags.count()); for (const QString &tag : tags) { TagModelItem *item = findItem(tag); diff --git a/src/gui/transferlistwidget.cpp b/src/gui/transferlistwidget.cpp index ca1abb8f6a2..12d308a76f0 100644 --- a/src/gui/transferlistwidget.cpp +++ b/src/gui/transferlistwidget.cpp @@ -1008,14 +1008,14 @@ void TransferListWidget::displayListMenu(const QPoint &) for (const QString &tag : asConst(tags)) { auto *action = new TriStateAction(tag, tagsMenu); - action->setCloseOnTriggered(false); + action->setCloseOnInteraction(false); const Qt::CheckState initialState = tagsInAll.contains(tag) ? Qt::Checked : tagsInAny.contains(tag) ? Qt::PartiallyChecked : Qt::Unchecked; 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) addSelectionTag(tag); diff --git a/src/gui/tristateaction.cpp b/src/gui/tristateaction.cpp index 46e9abd6aec..a42c91a64eb 100644 --- a/src/gui/tristateaction.cpp +++ b/src/gui/tristateaction.cpp @@ -45,8 +45,7 @@ TriStateAction::TriStateAction(const QString &text, QWidget *parent) m_triStateWidget->setCheckState(checked ? Qt::Checked : Qt::Unchecked); }); - connect(m_triStateWidget, &TriStateWidget::triggered, this, &QAction::setChecked); - connect(m_triStateWidget, &TriStateWidget::triggered, this, &QAction::triggered); + connect(m_triStateWidget, &TriStateWidget::triggered, this, &QAction::toggled); setDefaultWidget(m_triStateWidget); } @@ -56,7 +55,7 @@ void TriStateAction::setCheckState(const Qt::CheckState 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); } diff --git a/src/gui/tristateaction.h b/src/gui/tristateaction.h index fe014cdbc92..4c4ccb5a239 100644 --- a/src/gui/tristateaction.h +++ b/src/gui/tristateaction.h @@ -37,7 +37,7 @@ class TriStateWidget; // 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 -// QAction::triggered slot. +// QAction::triggered or QAction::toggled slots. class TriStateAction : public QWidgetAction { public: @@ -46,7 +46,12 @@ class TriStateAction : public QWidgetAction // should use this function instead of QAction::setChecked(bool) 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: TriStateWidget *m_triStateWidget; diff --git a/src/gui/tristatewidget.cpp b/src/gui/tristatewidget.cpp index a4b8d7f2564..bc4cb0db95a 100644 --- a/src/gui/tristatewidget.cpp +++ b/src/gui/tristatewidget.cpp @@ -38,7 +38,7 @@ TriStateWidget::TriStateWidget(const QString &text, QWidget *parent) : QWidget {parent} - , m_closeOnTriggered {true} + , m_closeOnInteraction {true} , m_checkState {Qt::Unchecked} , m_text {text} { @@ -51,9 +51,9 @@ void TriStateWidget::setCheckState(const Qt::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 @@ -104,7 +104,7 @@ void TriStateWidget::mouseReleaseEvent(QMouseEvent *event) { toggleCheckState(); - if (m_closeOnTriggered) + if (m_closeOnInteraction) { // parent `triggered` signal will be emitted QWidget::mouseReleaseEvent(event); @@ -112,7 +112,7 @@ void TriStateWidget::mouseReleaseEvent(QMouseEvent *event) else { update(); - // need to emit parent `triggered` signal manually + // need to emit `triggered` signal manually emit triggered(m_checkState == Qt::Checked); } } @@ -124,7 +124,7 @@ void TriStateWidget::keyPressEvent(QKeyEvent *event) { toggleCheckState(); - if (!m_closeOnTriggered) + if (!m_closeOnInteraction) { update(); // need to emit parent `triggered` signal manually diff --git a/src/gui/tristatewidget.h b/src/gui/tristatewidget.h index 697561bf4af..a5139ff21f9 100644 --- a/src/gui/tristatewidget.h +++ b/src/gui/tristatewidget.h @@ -41,7 +41,7 @@ class TriStateWidget final : public QWidget TriStateWidget(const QString &text, QWidget *parent); void setCheckState(Qt::CheckState checkState); - void setCloseOnTriggered(bool enabled); + void setCloseOnInteraction(bool enabled); signals: void triggered(bool checked) const; @@ -55,7 +55,7 @@ class TriStateWidget final : public QWidget void toggleCheckState(); - bool m_closeOnTriggered; + bool m_closeOnInteraction; Qt::CheckState m_checkState; const QString m_text; }; diff --git a/src/webui/api/torrentscontroller.cpp b/src/webui/api/torrentscontroller.cpp index 98f65895c03..8596b112f56 100644 --- a/src/webui/api/torrentscontroller.cpp +++ b/src/webui/api/torrentscontroller.cpp @@ -453,18 +453,15 @@ void TorrentsController::trackersAction() QJsonArray trackerList = getStickyTrackers(torrent); - QHash trackersData = torrent->trackerInfos(); for (const BitTorrent::TrackerEntry &tracker : asConst(torrent->trackers())) { - const BitTorrent::TrackerInfo data = trackersData.value(tracker.url); - trackerList << QJsonObject { {KEY_TRACKER_URL, tracker.url}, {KEY_TRACKER_TIER, tracker.tier}, {KEY_TRACKER_STATUS, static_cast(tracker.status)}, - {KEY_TRACKER_PEERS_COUNT, data.numPeers}, - {KEY_TRACKER_MSG, data.lastMessage.trimmed()}, + {KEY_TRACKER_MSG, tracker.message}, + {KEY_TRACKER_PEERS_COUNT, tracker.numPeers}, {KEY_TRACKER_SEEDS_COUNT, tracker.numSeeds}, {KEY_TRACKER_LEECHES_COUNT, tracker.numLeeches}, {KEY_TRACKER_DOWNLOADED_COUNT, tracker.numDownloaded}