mirror of
https://github.com/qbittorrent/qBittorrent.git
synced 2026-01-02 05:38:06 -06:00
Compare commits
140 Commits
release-3.
...
release-3.
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
dbfaf35db4 | ||
|
|
f3b4c4acfc | ||
|
|
b37c395118 | ||
|
|
d6ab0d6f02 | ||
|
|
1b8c61c390 | ||
|
|
cbfdc8f721 | ||
|
|
cfae8c6399 | ||
|
|
246a19d685 | ||
|
|
8b6e06cfff | ||
|
|
7e8f2ecc76 | ||
|
|
0f061aa40d | ||
|
|
256211c16a | ||
|
|
bd684df315 | ||
|
|
8eb9117033 | ||
|
|
83ae15550d | ||
|
|
3783541c30 | ||
|
|
cc388fe772 | ||
|
|
78f2afa239 | ||
|
|
245e8e09bb | ||
|
|
986cff9e66 | ||
|
|
73f477072f | ||
|
|
7e9ece2701 | ||
|
|
ba8641f1ac | ||
|
|
76c6041031 | ||
|
|
2ae8472a78 | ||
|
|
dc9df6d681 | ||
|
|
aed9e8f1b7 | ||
|
|
a94d14acaf | ||
|
|
317689bd5d | ||
|
|
1ad66ba791 | ||
|
|
b4fb193d4a | ||
|
|
ab47559bf2 | ||
|
|
ac87728150 | ||
|
|
1559205114 | ||
|
|
54e8b6944e | ||
|
|
164e8156db | ||
|
|
c83bb22e80 | ||
|
|
166c2a72ac | ||
|
|
6b659804c7 | ||
|
|
0831320f17 | ||
|
|
8d2fb06f65 | ||
|
|
bf6f103142 | ||
|
|
c4b12b854e | ||
|
|
de514e29c2 | ||
|
|
03d020f0f2 | ||
|
|
15e7726233 | ||
|
|
9258a9ae78 | ||
|
|
7c2437e5f2 | ||
|
|
dc315c080b | ||
|
|
971c340b53 | ||
|
|
76b9b02177 | ||
|
|
375c2dfd0b | ||
|
|
6a3e7a12d8 | ||
|
|
d92ef3fa4d | ||
|
|
89d4cb257f | ||
|
|
47ebb0df58 | ||
|
|
71169abaa6 | ||
|
|
83dd0ae86e | ||
|
|
c9500d933b | ||
|
|
b8787460a4 | ||
|
|
d031264d62 | ||
|
|
63b408c743 | ||
|
|
1ac4458d13 | ||
|
|
6b91510d71 | ||
|
|
f1a7e8921a | ||
|
|
78c34b948e | ||
|
|
690db070c7 | ||
|
|
0979936266 | ||
|
|
ba23b41616 | ||
|
|
412584e9c3 | ||
|
|
13aa3c3088 | ||
|
|
067c406c94 | ||
|
|
8536e79f2a | ||
|
|
70b98d903e | ||
|
|
1997a29769 | ||
|
|
f6e4f48386 | ||
|
|
10002984e6 | ||
|
|
2fa2d36c3b | ||
|
|
ceed9b468e | ||
|
|
f19854c054 | ||
|
|
989cbda29c | ||
|
|
881f79b76d | ||
|
|
51986f3ac8 | ||
|
|
943a837570 | ||
|
|
a6cf386073 | ||
|
|
b6e1b6e501 | ||
|
|
cee308a517 | ||
|
|
390d22bc66 | ||
|
|
e4a5b8d352 | ||
|
|
2ba3104337 | ||
|
|
d1dfdd1306 | ||
|
|
8a02a69924 | ||
|
|
8ffc72b626 | ||
|
|
e85479dfd7 | ||
|
|
104bed7cc8 | ||
|
|
75f3dd6d1d | ||
|
|
751f64c98b | ||
|
|
6353c2ca3c | ||
|
|
f51e467ce3 | ||
|
|
358d182c82 | ||
|
|
7d2802cf2c | ||
|
|
a739d86e3d | ||
|
|
6ff614ebea | ||
|
|
d9f4141221 | ||
|
|
415a805818 | ||
|
|
b8fff68230 | ||
|
|
44f81a2d2b | ||
|
|
b98ef9905e | ||
|
|
e4f472e0f8 | ||
|
|
91a38193f5 | ||
|
|
66b92f3bb4 | ||
|
|
a911dc57f3 | ||
|
|
c43c473105 | ||
|
|
d079b71f63 | ||
|
|
8b0b398a5f | ||
|
|
9400aac003 | ||
|
|
7856863b3e | ||
|
|
b1f598a1d3 | ||
|
|
9c7ed80292 | ||
|
|
1835ec6086 | ||
|
|
3d4cead200 | ||
|
|
112a24f9b6 | ||
|
|
cdcafecb44 | ||
|
|
4e173d34d3 | ||
|
|
df5d31b52b | ||
|
|
be745551e6 | ||
|
|
a3e4bcd1dd | ||
|
|
36cc6909f8 | ||
|
|
3987e677d5 | ||
|
|
13f27c6d3b | ||
|
|
68f88f7907 | ||
|
|
6c2c08c6dd | ||
|
|
b8eee9e1b8 | ||
|
|
ef08b4269d | ||
|
|
b5a67aefdb | ||
|
|
a302c995f8 | ||
|
|
f2877cbec4 | ||
|
|
4a95291fcc | ||
|
|
6717e3d30c | ||
|
|
778209ae49 |
@@ -3,7 +3,7 @@ version: '{branch}-{build}'
|
||||
# Do not build on tags (GitHub only)
|
||||
skip_tags: true
|
||||
|
||||
os: Visual Studio 2015
|
||||
image: Visual Studio 2017
|
||||
|
||||
environment:
|
||||
REPO_DIR: &REPO_DIR c:\qbittorrent
|
||||
@@ -36,7 +36,7 @@ install:
|
||||
|
||||
before_build:
|
||||
# setup env
|
||||
- CALL "c:\Program Files (x86)\Microsoft Visual Studio 14.0\VC\bin\vcvars32.bat"
|
||||
- CALL "C:\Program Files (x86)\Microsoft Visual Studio\2017\Community\VC\Auxiliary\Build\vcvars32.bat"
|
||||
- SET PATH=%PATH%;c:\qbt\qt5_32\bin;%CACHE_DIR%\jom;
|
||||
# setup project
|
||||
- COPY /Y "%CACHE_DIR%\winconf.pri" "%REPO_DIR%"
|
||||
|
||||
1
.gitignore
vendored
1
.gitignore
vendored
@@ -17,6 +17,7 @@ Makefile*
|
||||
|
||||
# Generated MOC, resource and UI files
|
||||
moc_*.cpp
|
||||
moc_*.h
|
||||
qrc_*.cpp
|
||||
ui_*.h
|
||||
*.moc
|
||||
|
||||
100
.travis.yml
100
.travis.yml
@@ -34,16 +34,15 @@ notifications:
|
||||
on_success: change
|
||||
on_failure: change
|
||||
|
||||
# container-based builds
|
||||
#sudo: false
|
||||
cache:
|
||||
ccache: true
|
||||
directories:
|
||||
- $HOME/hombebrew_cache
|
||||
|
||||
# opt-in Ubuntu Trusty
|
||||
sudo: required
|
||||
dist: trusty
|
||||
# container-based builds
|
||||
sudo: false
|
||||
|
||||
addons:
|
||||
coverity_scan:
|
||||
@@ -55,20 +54,27 @@ addons:
|
||||
branch_pattern: $coverity_branch
|
||||
notification_email: sledgehammer999@qbittorrent.org
|
||||
apt:
|
||||
#sources:
|
||||
# sources list: https://github.com/travis-ci/apt-source-whitelist/blob/master/ubuntu.json
|
||||
#- ubuntu-toolchain-r-test
|
||||
#- boost-latest
|
||||
sources:
|
||||
# sources list: https://github.com/travis-ci/apt-source-whitelist/blob/master/ubuntu.json
|
||||
#- ubuntu-toolchain-r-test
|
||||
#- boost-latest
|
||||
- sourceline: 'ppa:qbittorrent-team/qbittorrent-stable'
|
||||
- sourceline: 'ppa:beineri/opt-qt551-trusty'
|
||||
packages:
|
||||
# packages list: https://github.com/travis-ci/apt-package-whitelist/blob/master/ubuntu-precise
|
||||
- autoconf
|
||||
- automake
|
||||
- colormake
|
||||
- libssl-dev
|
||||
- libboost-dev
|
||||
- libboost-system-dev
|
||||
# uncomment when Travis upgraded "Ubuntu 12.04 LTS" to a newer version whose repo will have a more up-to-date libtorrent package
|
||||
#- libtorrent-rasterbar6
|
||||
# packages list: https://github.com/travis-ci/apt-package-whitelist/blob/master/ubuntu-precise
|
||||
- autoconf
|
||||
- automake
|
||||
- colormake
|
||||
- libssl-dev
|
||||
- libboost-dev
|
||||
- libboost-system-dev
|
||||
- libtorrent-rasterbar-dev
|
||||
# Qt 5.5.1
|
||||
- qt55base
|
||||
- qt55tools
|
||||
# Qt 4.8
|
||||
- qt4-default
|
||||
- libqt4-dev
|
||||
|
||||
before_install:
|
||||
# only allow specific build for coverity scan, others will stop
|
||||
@@ -79,7 +85,7 @@ before_install:
|
||||
#- libt_path="$HOME/libt_install"
|
||||
#- ltconf="$ltconf --prefix="$libt_path" --disable-geoip"
|
||||
- qbt_path="$HOME/qbt_install"
|
||||
- qbtconf="$qbtconf --prefix="$qbt_path" PKG_CONFIG_PATH="$libt_path/lib/pkgconfig":$PKG_CONFIG_PATH"
|
||||
- qbtconf="$qbtconf --prefix="$qbt_path" PKG_CONFIG_PATH="$libt_path/lib/pkgconfig":/opt/qt55/lib/pkgconfig:$PKG_CONFIG_PATH"
|
||||
|
||||
# options for specific branches
|
||||
- if [ "$qt" = 4 ]; then qbtconf="$qbtconf --with-qt4" ; fi
|
||||
@@ -88,6 +94,9 @@ before_install:
|
||||
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 ;
|
||||
|
||||
# Qt 5
|
||||
PATH=/opt/qt55/bin:${PATH}
|
||||
fi
|
||||
|
||||
# print settings
|
||||
@@ -97,31 +106,23 @@ before_install:
|
||||
- echo $qbtconf
|
||||
|
||||
install:
|
||||
- |
|
||||
if [ "$TRAVIS_OS_NAME" = "linux" ]; then
|
||||
# libtorrent
|
||||
sudo add-apt-repository --yes ppa:qbittorrent-team/qbittorrent-stable ;
|
||||
sudo apt-get update -qq ;
|
||||
sudo apt-get install -qq libtorrent-rasterbar-dev ;
|
||||
|
||||
#- |
|
||||
#if [ "$TRAVIS_OS_NAME" = "linux" ]; then
|
||||
# build libtorrent from source
|
||||
#if [ "$lt_branch" != "dist" ]; then
|
||||
#cd "$HOME" && pwd && git clone --depth 1 https://github.com/arvidn/libtorrent.git --branch $lt_branch ;
|
||||
#cd libtorrent && ./autotool.sh && ./configure $ltconf && make install ;
|
||||
#fi ;
|
||||
|
||||
# Qt
|
||||
if [ "$qt" = 4 ]; then sudo apt-get -qq install qt4-default libqt4-dev ; fi ;
|
||||
if [ "$qt" = 5 ]; then sudo apt-get -qq install qt5-default qtbase5-dev qttools5-dev-tools ; fi ;
|
||||
|
||||
# ccache
|
||||
if [ "$TRAVIS_BRANCH" != "$coverity_branch" ]; then
|
||||
dpkg-query -L ccache && export use_ccache=true ;
|
||||
ccache -V && ccache --show-stats && ccache --zero-stats ;
|
||||
fi ;
|
||||
fi
|
||||
#fi
|
||||
- |
|
||||
if [ "$TRAVIS_OS_NAME" = "osx" ]; then
|
||||
# dependencies
|
||||
brew update > /dev/null
|
||||
brew install colormake ccache zlib
|
||||
PATH="/usr/local/opt/ccache/libexec:$PATH"
|
||||
brew link --force zlib
|
||||
brew outdated "pkg-config" || brew upgrade "pkg-config"
|
||||
|
||||
wget https://builds.shiki.hu/homebrew/version ;
|
||||
if ! cmp --quiet "version" "$HOME/hombebrew_cache/version" ; then
|
||||
echo "Cached files are different from server. Downloading new ones." ;
|
||||
@@ -131,19 +132,15 @@ install:
|
||||
cp "version" $HOME/hombebrew_cache ;
|
||||
cd "$HOME/hombebrew_cache" ;
|
||||
wget https://builds.shiki.hu/homebrew/libtorrent-rasterbar.rb ;
|
||||
wget https://builds.shiki.hu/homebrew/libtorrent-rasterbar-1.0.10.el_capitan.bottle.tar.gz ;
|
||||
wget https://builds.shiki.hu/homebrew/qt5.rb ;
|
||||
wget https://builds.shiki.hu/homebrew/qt5-5.7.1_1.el_capitan.bottle.tar.gz ;
|
||||
wget https://builds.shiki.hu/homebrew/libtorrent-rasterbar-1.0.11+git20172003.8736a59adc.el_capitan.bottle.tar.gz
|
||||
wget https://builds.shiki.hu/homebrew/qt.rb
|
||||
wget https://builds.shiki.hu/homebrew/qt-5.9.1.el_capitan.bottle.tar.gz
|
||||
fi
|
||||
|
||||
# dependencies
|
||||
brew update > /dev/null ;
|
||||
brew install colormake ccache ;
|
||||
brew outdated "pkg-config" || brew upgrade "pkg-config" ;
|
||||
# Copy custom libtorrent bottle to homebrew's cache so it can find and install it
|
||||
# Also install our custom libtorrent formula by passing the local path to it
|
||||
# These 2 files are restored from Travis' cache.
|
||||
cp "$HOME/hombebrew_cache/libtorrent-rasterbar-1.0.10.el_capitan.bottle.tar.gz" "$(brew --cache)" ;
|
||||
cp "$HOME/hombebrew_cache/libtorrent-rasterbar-1.0.11+git20172003.8736a59adc.el_capitan.bottle.tar.gz" "$(brew --cache)"
|
||||
brew install "$HOME/hombebrew_cache/libtorrent-rasterbar.rb" ;
|
||||
|
||||
# Qt
|
||||
@@ -152,16 +149,15 @@ install:
|
||||
# Copy custom qt5 bottle to homebrew's cache so it can find and install it
|
||||
# Also install our custom qt5 formula by passing the local path to it
|
||||
# These 2 files are restored from Travis' cache.
|
||||
cp "$HOME/hombebrew_cache/qt5-5.7.1_1.el_capitan.bottle.tar.gz" "$(brew --cache)" ;
|
||||
brew install "$HOME/hombebrew_cache/qt5.rb" ;
|
||||
brew link --force qt5 ;
|
||||
cp "$HOME/hombebrew_cache/qt-5.9.1.el_capitan.bottle.tar.gz" "$(brew --cache)"
|
||||
brew install "$HOME/hombebrew_cache/qt.rb"
|
||||
brew link --force qt
|
||||
fi
|
||||
|
||||
# ccache
|
||||
if [ "$TRAVIS_BRANCH" != "$coverity_branch" ]; then
|
||||
export PATH="/usr/local/opt/ccache/libexec:$PATH" && export use_ccache=true ;
|
||||
ccache -V && ccache --show-stats && ccache --zero-stats ;
|
||||
fi ;
|
||||
fi
|
||||
- |
|
||||
if [ "$TRAVIS_BRANCH" != "$coverity_branch" ]; then
|
||||
export use_ccache=true
|
||||
ccache -V && ccache --show-stats && ccache --zero-stats
|
||||
fi
|
||||
|
||||
script:
|
||||
|
||||
@@ -30,7 +30,6 @@ add_definitions(-DQBT_VERSION="v${PROJECT_VERSION}")
|
||||
add_definitions(-DQBT_VERSION_2="${PROJECT_VERSION}")
|
||||
# }
|
||||
|
||||
# set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Og")
|
||||
if (UNIX AND NOT APPLE)
|
||||
include(GNUInstallDirs)
|
||||
endif (UNIX AND NOT APPLE)
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
# Filing an issue
|
||||
# Filing an issue
|
||||
|
||||
### Must read
|
||||
* If you aren't sure, you can ask on the [**forum**](http://forum.qbittorrent.org) or read our [**wiki**](http://wiki.qbittorrent.org) first.
|
||||
@@ -6,12 +6,11 @@
|
||||
* Write in **English**!
|
||||
* Provide **version** information: (You can find version numbers at menu `Help -> About -> Libraries`)
|
||||
```
|
||||
qBittorrent:
|
||||
Qt:
|
||||
libtorrent:
|
||||
boost:
|
||||
OS version:
|
||||
|
||||
qBittorrent:
|
||||
Qt:
|
||||
libtorrent:
|
||||
boost:
|
||||
OS version:
|
||||
```
|
||||
* Provide **steps** to reproduce the problem, it will be easier to pinpoint the fault.
|
||||
* **Screenshots**! A screenshot is worth a thousand words. just upload it. [(How?)](https://help.github.com/articles/file-attachments-on-issues-and-pull-requests)
|
||||
|
||||
72
Changelog
72
Changelog
@@ -1,3 +1,75 @@
|
||||
* Thu Sep 07 2017 - sledgehammer999 <sledgehammer999@qbittorrent.org> - v3.3.16
|
||||
- BUGFIX: Better memory footprint when using libtorrent 1.1.x. The cache is turned off by default(`0 (disabled)` value in the settings). The value `-1 (auto)` makes it use 1/8 of your RAM. (sledgehammer999)
|
||||
- BUGFIX: Skip user input events when adding torrent. Closes #7327. (glassez)
|
||||
- BUGFIX: Avoid memory leak in the speed graph. (Chocobo1)
|
||||
- WEBUI: Fix validating wrong header field. X-Forwarded-Host is a foreign proxy setting, it isn't the same as qbt's local setting and thus it makes no sense to verify it. Closes #7311. (Chocobo1)
|
||||
- WINDOWS: Fix connection problems when a specific interface/ip is configured. (sledgehammer999)
|
||||
- WINDOWS: Disable skipping of loopback interfaces. This fixes the absence of VPN tunnel interfaces under Windows and works around the QTBUG-32349. Fixes #7291. (Evengard)
|
||||
- WINDOWS: The installer detects the 64bit running process too. (vlakoff)
|
||||
|
||||
* Thu Aug 03 2017 - sledgehammer999 <sledgehammer999@qbittorrent.org> - v3.3.15
|
||||
- BUGFIX: Temporary subfolder wasn't being deleted. (glassez)
|
||||
|
||||
* Tue Jul 18 2017 - sledgehammer999 <sledgehammer999@qbittorrent.org> - v3.3.14
|
||||
- BUGFIX: Set interface for outgoing traffic(libtorrent 1.1.x series). (evsh)
|
||||
- WEBUI: Fix KEEP_ALIVE_DURATION value (Chocobo1)
|
||||
- WEBUI: Relax CSRF defense. Closes #6882. Allow HTTP request which has neither Origin nor Referer header included. (Chocobo1)
|
||||
- WEBUI: Skip username/password check for active sessions (closes #6860) (Thomas Piccirello)
|
||||
- WEBUI: Fix javascript errors and follow best practices (Thomas Piccirello)
|
||||
- WEBUI: Fix value comparison. Closes #7081. (Chocobo1)
|
||||
- WEBUI: Avoid modifying request headers (Chocobo1)
|
||||
- WEBUI: Implement HTTP host header filtering. This filtering is required to defend against DNS rebinding attack. Fixes security issues reported by @beardog108 privately. (Chocobo1)
|
||||
- WEBUI: Add Status column to webui (addresses #6815) (#7032) (Tom Piccirello)
|
||||
- WEBUI: Bump API_VERSION and API_VERSION_MIN to 15.
|
||||
- SEARCH: Pad shorter python versions. Closes #6877. (sledgehammer999)
|
||||
- WINDOWS: Updated Arabic, Turkish, Greek, Russian, Danish languages of the installer. (KingLucius, BouRock, thalieht, Andrei Stepanov, scootergrisen)
|
||||
- WINDOWS: Raise total stack size on Windows to 8 MB. Closes #7021. (Chocobo1)
|
||||
- LINUX: Systemd service with user switch and other fixes/optimizations. (anton.latukha)
|
||||
|
||||
* Thu Jun 01 2017 - sledgehammer999 <sledgehammer999@qbittorrent.org> - v3.3.13
|
||||
- BUGFIX: Fixed UI glitch about torrent numbers in the sidepanel. Fixes #6454. (evsh)
|
||||
- BUGFIX: Fix downloaded/uploaded columns were not highlighted properly when selected. (Chocobo1)
|
||||
- BUGFIX: Always draw background in files list and search result list (Chocobo1)
|
||||
- BUGFIX: Remove torrent temp folder if it becomes unneeded (glassez)
|
||||
- BUGFIX: Remove torrent temp folder when torrent is deleted (glassez)
|
||||
- BUGFIX: Setup DPI at startup (Chocobo1)
|
||||
- BUGFIX: Do not attempt to show detailed tooltips without torrent metadata. Closes #6768. (evsh)
|
||||
- BUGFIX: Better detection of already present files when adding a torrent. (fbriere)
|
||||
- BUGFIX: Fix double click on system tray icon causing program to open and minimize immediately. Closes #5826. (Chocobo1)
|
||||
- BUGIFX: Fix categories sorting in AddNewTorrentDialog. Partially fixes #6708. (fbriere)
|
||||
- BUGFIX: Set "category" column as case-insensitive in transfer list. (fbriere)
|
||||
- BUGFIX: Properly sort categories case-insensitively in filter widget. Closes #6708. (fbriere)
|
||||
- BUGFIX: Fix renaming files is not case sensitive on Windows platform. Closes #5128. (Chocobo1)
|
||||
- BUGFIX: Fix crash in download piece bar (evsh)
|
||||
- BUGFIX: Fix focusing on the previously opened dialog didn't work (Chocobo1)
|
||||
- WEBUI: Bugfix: `RequestParser::splitMultipartData` drop extra trailing newline. (OpenGG)
|
||||
- WEBUI: Add `skip_checking` and `paused` to `/command/download` and `/command/upload` (OpenGG)
|
||||
- WEBUI: Fix checkbox hidden. Closes #6642. (Chocobo1)
|
||||
- WEBUI: Implement http persistence connection. Max simultaneous connection limit set to 500. This also release allocated memory of Connection instances at runtime instead of at program shutdown. (Chocobo1)
|
||||
- WEBUI: Always send Content-Length header. (Chocobo1)
|
||||
- WEBUI: Send Date http header (Chocobo1)
|
||||
- WEBUI: Fix "Content-Encoding" header is always created. (Chocobo1)
|
||||
- WEBUI: Implement robust checking for gzip encoding and revise gzip compressing/decompressing code. (Chocobo1)
|
||||
- WEBUI: Make the context obligatory for translatable strings. Also delete duplicate strings from extra translations. (sledgehammer999)
|
||||
- WEBUI: Use translatable strings in Statistics dialog. (sledgehammer999)
|
||||
- WEBUI: Add missing unit sizes in misc.js (sledgehammer999)
|
||||
- WEBUI: Use the same layout in the Speed tab in preferences as the GUI. (sledgehammer999)
|
||||
- WEBUI: Return status indicating if at least one torrent was successfully added (Thomas Piccirello)
|
||||
- WEBUI: Increase the number of digits after the decimal point (thalieht)
|
||||
- WEBUI: Use less permissive Content Security Policy (Thomas Piccirello)
|
||||
- WEBUI: Fix connection status icon too large. Closes #6804. (Chocobo1)
|
||||
- WEBUI: Cosmetic fixes for WebUI upload and download windows (naikel)
|
||||
- WEBUI: Fix slow filtering in WebUI. (naikel)
|
||||
- WEBUI: Make cookie parsing robust (Chocobo1)
|
||||
- WEBUI: New API for getting torrent piece info (Chocobo1)
|
||||
- WEBUI: Implement Cross-Site Request Forgery defense. Due to this the HTTP referer header is now expected in (almost) all HTTP requests. qBittorrent will drop the request sent without the referer header. That's why we bump the API_VERSION_MIN too. (reported by OpenGG, fixed by Chocobo1)
|
||||
- SEARCH: Update demonoid, legittorrents plugins (ngosang)
|
||||
- SEARCH: Remove mininova, ExtraTorrent plugins (ngosang, KingLucius)
|
||||
- SEARCH: Add btdb plugin (ngosang)
|
||||
- WINDOWS: Updated Spanish, Ukrainian, German, Chinese languages of the installer. (ngosang, evsh, schnurlos, wevsty)
|
||||
- LINUX: Rename .desktop and appdata files to match executable name. Fixes #6625. (evsh)
|
||||
- MACOS: Fix UI responsiveness after AddNewTorrentDialog received metadata. (Brian Kendall)
|
||||
|
||||
* Thu Apr 06 2017 - sledgehammer999 <sledgehammer999@qbittorrent.org> - v3.3.12
|
||||
- FEATURE: Indicate bitness in stackstrace and about dialog. Closes #6172. (sledgehammer999)
|
||||
- BUGFIX: Fix incomplete type compile error with Qt4 (Chocobo1)
|
||||
|
||||
@@ -93,13 +93,12 @@ foreach(_boost_cmpnt IN LISTS _boost_components)
|
||||
list(APPEND LibtorrentRasterbar_LIBRARIES "Boost::${_boost_cmpnt}")
|
||||
endforeach(_boost_cmpnt)
|
||||
|
||||
set(LibtorrentRasterbar_INCLUDE_DIRS ${LibtorrentRasterbar_INCLUDE_DIRS} ${Boost_INCLUDE_DIRS})
|
||||
set(LibtorrentRasterbar_INCLUDE_DIRS ${LibtorrentRasterbar_INCLUDE_DIRS})
|
||||
|
||||
list(FIND LibtorrentRasterbar_DEFINITIONS -DTORRENT_USE_OPENSSL LibtorrentRasterbar_ENCRYPTION_INDEX)
|
||||
if(LibtorrentRasterbar_ENCRYPTION_INDEX GREATER -1)
|
||||
find_package(OpenSSL REQUIRED)
|
||||
set(LibtorrentRasterbar_LIBRARIES ${LibtorrentRasterbar_LIBRARIES} ${OPENSSL_LIBRARIES})
|
||||
set(LibtorrentRasterbar_INCLUDE_DIRS ${LibtorrentRasterbar_INCLUDE_DIRS} ${OPENSSL_INCLUDE_DIRS})
|
||||
set(LibtorrentRasterbar_LIBRARIES ${LibtorrentRasterbar_LIBRARIES} OpenSSL::SSL OpenSSL::Crypto)
|
||||
set(LibtorrentRasterbar_OPENSSL_ENABLED ON)
|
||||
endif()
|
||||
|
||||
|
||||
@@ -3,6 +3,9 @@
|
||||
# sets variables
|
||||
# SYSTEMD_FOUND
|
||||
# SYSTEMD_SERVICES_INSTALL_DIR
|
||||
|
||||
find_package(PkgConfig QUIET REQUIRED)
|
||||
|
||||
if (NOT SYSTEMD_FOUND)
|
||||
pkg_check_modules(SYSTEMD "systemd")
|
||||
endif(NOT SYSTEMD_FOUND)
|
||||
|
||||
49
cmake/Modules/MacroGlibcDetect.cmake
Normal file
49
cmake/Modules/MacroGlibcDetect.cmake
Normal file
@@ -0,0 +1,49 @@
|
||||
###############################################################
|
||||
#
|
||||
# Copyright 2011 Red Hat, Inc.
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License"); you
|
||||
# may not use this file except in compliance with the License. You may
|
||||
# obtain a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
#
|
||||
###############################################################
|
||||
|
||||
MACRO (GLIBC_DETECT _VERSION)
|
||||
|
||||
# there are multiple ways to detect glibc, but given nmi's
|
||||
# cons'd up paths I will trust only gcc. I guess I could also use
|
||||
# ldd --version to detect.
|
||||
|
||||
set(_GLIB_SOURCE_DETECT "
|
||||
#include <limits.h>
|
||||
#include <stdio.h>
|
||||
int main()
|
||||
{
|
||||
printf(\"%d%d\",__GLIBC__, __GLIBC_MINOR__);
|
||||
return 0;
|
||||
}
|
||||
")
|
||||
|
||||
file (WRITE ${CMAKE_CURRENT_BINARY_DIR}/build/cmake/glibc.cpp "${_GLIB_SOURCE_DETECT}\n")
|
||||
|
||||
try_run(POST26_GLIBC_DETECTED
|
||||
POST26_GLIBC_COMPILE
|
||||
${CMAKE_CURRENT_BINARY_DIR}/build/cmake
|
||||
${CMAKE_CURRENT_BINARY_DIR}/build/cmake/glibc.cpp
|
||||
RUN_OUTPUT_VARIABLE GLIBC_VERSION )
|
||||
|
||||
if (GLIBC_VERSION AND POST26_GLIBC_COMPILE )
|
||||
set(${_VERSION} ${GLIBC_VERSION})
|
||||
else()
|
||||
message(STATUS "NOTE: Could not detect GLIBC_VERSION from compiler")
|
||||
endif()
|
||||
|
||||
ENDMACRO (GLIBC_DETECT)
|
||||
89
cmake/Modules/MacroQbtCompilerSettings.cmake
Normal file
89
cmake/Modules/MacroQbtCompilerSettings.cmake
Normal file
@@ -0,0 +1,89 @@
|
||||
# Sets cache variable QBT_ADDITONAL_FLAGS and QBT_ADDITONAL_CXX_FLAGS to list of additional
|
||||
# compiler flags for C and C++ (QBT_ADDITONAL_FLAGS) and for C++ only (QBT_ADDITONAL_CXX_FLAGS)
|
||||
# and appends them to CMAKE_XXX_FLAGS variables.
|
||||
|
||||
# It could use add_compile_options(), but then it is needed to use generator expressions,
|
||||
# and most interesting of them are not compatible with Visual Studio :(
|
||||
|
||||
macro(qbt_set_compiler_options)
|
||||
# if (NOT QBT_ADDITONAL_FLAGS)
|
||||
if("${CMAKE_CXX_COMPILER_ID}" STREQUAL "GNU" OR "${CMAKE_CXX_COMPILER_ID}" STREQUAL "Clang")
|
||||
#-Wshadow -Wconversion ?
|
||||
set(_GCC_COMMON_C_AND_CXX_FLAGS "-Wall -Wextra"
|
||||
"-Wfloat-equal -Wcast-qual -Wcast-align"
|
||||
"-Wsign-conversion -Winvalid-pch -Werror=return-type -Wno-long-long"
|
||||
# -fstack-protector-all
|
||||
"-Werror -Wno-error=deprecated-declarations"
|
||||
)
|
||||
set (_GCC_COMMON_CXX_FLAGS "-fexceptions -frtti"
|
||||
"-Woverloaded-virtual -Wold-style-cast -Wstrict-null-sentinel"
|
||||
"-Wnon-virtual-dtor -Wfloat-equal -Wcast-qual -Wcast-align"
|
||||
"-Werror=overloaded-virtual"
|
||||
# "-Weffc++"
|
||||
"-Werror -Wno-error=cpp"
|
||||
# we should modify code to make these ones obsolete
|
||||
"-Wno-error=old-style-cast -Wno-error=sign-conversion -Wno-error=float-equal"
|
||||
)
|
||||
|
||||
if ("${CMAKE_CXX_COMPILER_ID}" STREQUAL "GNU" AND CMAKE_CXX_COMPILER_VERSION VERSION_LESS 4.9)
|
||||
# GCC 4.8 has problems with std::array and its initialization
|
||||
list(APPEND _GCC_COMMON_CXX_FLAGS "-Wno-error=missing-field-initializers")
|
||||
endif()
|
||||
|
||||
include(CheckCXXCompilerFlag)
|
||||
# check for -pedantic
|
||||
check_cxx_compiler_flag(-pedantic _PEDANTIC_IS_SUPPORTED)
|
||||
if (_PEDANTIC_IS_SUPPORTED)
|
||||
list(APPEND _GCC_COMMON_CXX_FLAGS "-pedantic -pedantic-errors")
|
||||
else (_PEDANTIC_IS_SUPPORTED)
|
||||
list(APPEND _GCC_COMMON_CXX_FLAGS "-Wpedantic")
|
||||
endif (_PEDANTIC_IS_SUPPORTED)
|
||||
|
||||
if (CMAKE_SYSTEM_NAME MATCHES Linux)
|
||||
# if Glibc version is 2.20 or higher, set -D_DEFAULT_SOURCE
|
||||
include(MacroGlibcDetect)
|
||||
message(STATUS "Detecting Glibc version...")
|
||||
glibc_detect(GLIBC_VERSION)
|
||||
if(${GLIBC_VERSION})
|
||||
if(GLIBC_VERSION LESS "220")
|
||||
message(STATUS "Glibc version is ${GLIBC_VERSION}")
|
||||
else(GLIBC_VERSION LESS "220")
|
||||
message(STATUS "Glibc version is ${GLIBC_VERSION}, adding -D_DEFAULT_SOURCE")
|
||||
add_definitions(-D_DEFAULT_SOURCE)
|
||||
endif(GLIBC_VERSION LESS "220")
|
||||
endif(${GLIBC_VERSION})
|
||||
endif (CMAKE_SYSTEM_NAME MATCHES Linux)
|
||||
|
||||
string(REPLACE ";" " " _GCC_COMMON_C_AND_CXX_FLAGS_STRING "${_GCC_COMMON_C_AND_CXX_FLAGS}")
|
||||
string(REPLACE ";" " " _GCC_COMMON_CXX_FLAGS_STRING "${_GCC_COMMON_CXX_FLAGS}")
|
||||
|
||||
string(APPEND CMAKE_C_FLAGS " ${_GCC_COMMON_C_AND_CXX_FLAGS_STRING}")
|
||||
string(APPEND CMAKE_CXX_FLAGS " ${_GCC_COMMON_C_AND_CXX_FLAGS_STRING} ${_GCC_COMMON_CXX_FLAGS_STRING}")
|
||||
|
||||
set(QBT_ADDITONAL_FLAGS "${_GCC_COMMON_C_AND_CXX_FLAGS_STRING}" CACHE STRING
|
||||
"Additional qBittorent compile flags" FORCE)
|
||||
set(QBT_ADDITONAL_CXX_FLAGS "${_GCC_COMMON_CXX_FLAGS_STRING}" CACHE STRING
|
||||
"Additional qBittorent C++ compile flags" FORCE)
|
||||
|
||||
# check whether we can enable -Og optimization for debug build
|
||||
# also let's enable -march=native for debug builds
|
||||
check_cxx_compiler_flag(-Og _DEBUG_OPTIMIZATION_LEVEL_IS_SUPPORTED)
|
||||
|
||||
if (_DEBUG_OPTIMIZATION_LEVEL_IS_SUPPORTED)
|
||||
string(APPEND CMAKE_C_FLAGS_DEBUG " -Og -g3 -march=native -pipe" )
|
||||
string(APPEND CMAKE_CXX_FLAGS_DEBUG " -Og -g3 -march=native -pipe" )
|
||||
else(_DEBUG_OPTIMIZATION_LEVEL_IS_SUPPORTED)
|
||||
string(APPEND CMAKE_C_FLAGS_DEBUG " -O0 -g3 -march=native -pipe" )
|
||||
string(APPEND CMAKE_CXX_FLAGS_DEBUG " -O0 -g3 -march=native -pipe" )
|
||||
endif (_DEBUG_OPTIMIZATION_LEVEL_IS_SUPPORTED)
|
||||
endif ("${CMAKE_CXX_COMPILER_ID}" STREQUAL "GNU" OR "${CMAKE_CXX_COMPILER_ID}" STREQUAL "Clang")
|
||||
|
||||
if ("${CMAKE_CXX_COMPILER_ID}" STREQUAL "MSVC")
|
||||
set(QBT_ADDITONAL_FLAGS "-wd4290 -wd4275 -wd4251 /W4" CACHE STRING "Additional qBittorent compile flags")
|
||||
string(APPEND CMAKE_C_FLAGS " ${QBT_ADDITONAL_FLAGS}")
|
||||
string(APPEND CMAKE_CXX_FLAGS " ${QBT_ADDITONAL_FLAGS}")
|
||||
endif ()
|
||||
|
||||
# endif (NOT QBT_ADDITONAL_FLAGS)
|
||||
endmacro(qbt_set_compiler_options)
|
||||
|
||||
@@ -1,5 +1,7 @@
|
||||
# Settings for compiling qBittorrent on Windows
|
||||
|
||||
list(APPEND CMAKE_LIBRARY_PATH "$ENV{LIB}")
|
||||
|
||||
# We want to link with static version of
|
||||
# libtorrent
|
||||
set(LibtorrentRasterbar_USE_STATIC_LIBS True)
|
||||
|
||||
22
configure
vendored
22
configure
vendored
@@ -5461,12 +5461,12 @@ if test -n "$zlib_CFLAGS"; then
|
||||
pkg_cv_zlib_CFLAGS="$zlib_CFLAGS"
|
||||
elif test -n "$PKG_CONFIG"; then
|
||||
if test -n "$PKG_CONFIG" && \
|
||||
{ { $as_echo "$as_me:${as_lineno-$LINENO}: \$PKG_CONFIG --exists --print-errors \"zlib\""; } >&5
|
||||
($PKG_CONFIG --exists --print-errors "zlib") 2>&5
|
||||
{ { $as_echo "$as_me:${as_lineno-$LINENO}: \$PKG_CONFIG --exists --print-errors \"zlib >= 1.2.5.2\""; } >&5
|
||||
($PKG_CONFIG --exists --print-errors "zlib >= 1.2.5.2") 2>&5
|
||||
ac_status=$?
|
||||
$as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
|
||||
test $ac_status = 0; }; then
|
||||
pkg_cv_zlib_CFLAGS=`$PKG_CONFIG --cflags "zlib" 2>/dev/null`
|
||||
pkg_cv_zlib_CFLAGS=`$PKG_CONFIG --cflags "zlib >= 1.2.5.2" 2>/dev/null`
|
||||
test "x$?" != "x0" && pkg_failed=yes
|
||||
else
|
||||
pkg_failed=yes
|
||||
@@ -5478,12 +5478,12 @@ if test -n "$zlib_LIBS"; then
|
||||
pkg_cv_zlib_LIBS="$zlib_LIBS"
|
||||
elif test -n "$PKG_CONFIG"; then
|
||||
if test -n "$PKG_CONFIG" && \
|
||||
{ { $as_echo "$as_me:${as_lineno-$LINENO}: \$PKG_CONFIG --exists --print-errors \"zlib\""; } >&5
|
||||
($PKG_CONFIG --exists --print-errors "zlib") 2>&5
|
||||
{ { $as_echo "$as_me:${as_lineno-$LINENO}: \$PKG_CONFIG --exists --print-errors \"zlib >= 1.2.5.2\""; } >&5
|
||||
($PKG_CONFIG --exists --print-errors "zlib >= 1.2.5.2") 2>&5
|
||||
ac_status=$?
|
||||
$as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
|
||||
test $ac_status = 0; }; then
|
||||
pkg_cv_zlib_LIBS=`$PKG_CONFIG --libs "zlib" 2>/dev/null`
|
||||
pkg_cv_zlib_LIBS=`$PKG_CONFIG --libs "zlib >= 1.2.5.2" 2>/dev/null`
|
||||
test "x$?" != "x0" && pkg_failed=yes
|
||||
else
|
||||
pkg_failed=yes
|
||||
@@ -5504,14 +5504,14 @@ else
|
||||
_pkg_short_errors_supported=no
|
||||
fi
|
||||
if test $_pkg_short_errors_supported = yes; then
|
||||
zlib_PKG_ERRORS=`$PKG_CONFIG --short-errors --print-errors --cflags --libs "zlib" 2>&1`
|
||||
zlib_PKG_ERRORS=`$PKG_CONFIG --short-errors --print-errors --cflags --libs "zlib >= 1.2.5.2" 2>&1`
|
||||
else
|
||||
zlib_PKG_ERRORS=`$PKG_CONFIG --print-errors --cflags --libs "zlib" 2>&1`
|
||||
zlib_PKG_ERRORS=`$PKG_CONFIG --print-errors --cflags --libs "zlib >= 1.2.5.2" 2>&1`
|
||||
fi
|
||||
# Put the nasty error message in config.log where it belongs
|
||||
echo "$zlib_PKG_ERRORS" >&5
|
||||
|
||||
as_fn_error $? "Package requirements (zlib) were not met:
|
||||
as_fn_error $? "Package requirements (zlib >= 1.2.5.2) were not met:
|
||||
|
||||
$zlib_PKG_ERRORS
|
||||
|
||||
@@ -6962,7 +6962,7 @@ $as_echo "$as_me: WARNING: unrecognized options: $ac_unrecognized_opts" >&2;}
|
||||
fi
|
||||
|
||||
if test "x$enable_systemd" = "xyes"; then :
|
||||
ac_config_files="$ac_config_files dist/unix/systemd/qbittorrent-nox.service"
|
||||
ac_config_files="$ac_config_files dist/unix/systemd/qbittorrent-nox@.service"
|
||||
|
||||
cat >confcache <<\_ACEOF
|
||||
# This file is a shell script that caches the results of configure
|
||||
@@ -7716,7 +7716,7 @@ do
|
||||
case $ac_config_target in
|
||||
"depfiles") CONFIG_COMMANDS="$CONFIG_COMMANDS depfiles" ;;
|
||||
"conf.pri") CONFIG_FILES="$CONFIG_FILES conf.pri" ;;
|
||||
"dist/unix/systemd/qbittorrent-nox.service") CONFIG_FILES="$CONFIG_FILES dist/unix/systemd/qbittorrent-nox.service" ;;
|
||||
"dist/unix/systemd/qbittorrent-nox@.service") CONFIG_FILES="$CONFIG_FILES dist/unix/systemd/qbittorrent-nox@.service" ;;
|
||||
|
||||
*) as_fn_error $? "invalid argument: \`$ac_config_target'" "$LINENO" 5;;
|
||||
esac
|
||||
|
||||
@@ -208,7 +208,7 @@ PKG_CHECK_MODULES(libtorrent,
|
||||
LIBS="$libtorrent_LIBS $LIBS"])
|
||||
|
||||
PKG_CHECK_MODULES(zlib,
|
||||
[zlib],
|
||||
[zlib >= 1.2.5.2],
|
||||
[CPPFLAGS="$zlib_CFLAGS $CPPFLAGS"
|
||||
LIBS="$zlib_LIBS $LIBS"])
|
||||
|
||||
@@ -260,7 +260,7 @@ AC_SUBST(QBT_REMOVE_DEFINES)
|
||||
|
||||
AC_OUTPUT(conf.pri)
|
||||
AS_IF([test "x$enable_systemd" = "xyes"],
|
||||
[AC_OUTPUT(dist/unix/systemd/qbittorrent-nox.service)])
|
||||
[AC_OUTPUT(dist/unix/systemd/qbittorrent-nox@.service)])
|
||||
|
||||
|
||||
|
||||
|
||||
2
dist/mac/Info.plist
vendored
2
dist/mac/Info.plist
vendored
@@ -45,7 +45,7 @@
|
||||
<key>CFBundlePackageType</key>
|
||||
<string>APPL</string>
|
||||
<key>CFBundleShortVersionString</key>
|
||||
<string>3.3.12</string>
|
||||
<string>3.3.16</string>
|
||||
<key>CFBundleSignature</key>
|
||||
<string>qBit</string>
|
||||
<key>CFBundleExecutable</key>
|
||||
|
||||
30
dist/unix/CMakeLists.txt
vendored
30
dist/unix/CMakeLists.txt
vendored
@@ -2,8 +2,8 @@ if (SYSTEMD)
|
||||
find_package(Systemd)
|
||||
if (SYSTEMD_FOUND)
|
||||
set(EXPAND_BINDIR ${CMAKE_INSTALL_FULL_BINDIR})
|
||||
configure_file(systemd/qbittorrent-nox.service.in ${CMAKE_CURRENT_BINARY_DIR}/qbittorrent-nox.service @ONLY)
|
||||
install(FILES ${CMAKE_CURRENT_BINARY_DIR}/qbittorrent-nox.service
|
||||
configure_file(systemd/qbittorrent-nox@.service.in ${CMAKE_CURRENT_BINARY_DIR}/qbittorrent-nox@.service @ONLY)
|
||||
install(FILES ${CMAKE_CURRENT_BINARY_DIR}/qbittorrent-nox@.service
|
||||
DESTINATION ${SYSTEMD_SERVICES_INSTALL_DIR}
|
||||
COMPONENT data)
|
||||
endif(SYSTEMD_FOUND)
|
||||
@@ -20,18 +20,20 @@ install(FILES ${MAN_FILES}
|
||||
DESTINATION ${CMAKE_INSTALL_MANDIR}/man1
|
||||
COMPONENT doc)
|
||||
|
||||
install(DIRECTORY menuicons/
|
||||
DESTINATION ${CMAKE_INSTALL_DATAROOTDIR}/icons/hicolor
|
||||
FILES_MATCHING PATTERN "*.png")
|
||||
if (GUI)
|
||||
install(DIRECTORY menuicons/
|
||||
DESTINATION ${CMAKE_INSTALL_DATAROOTDIR}/icons/hicolor
|
||||
FILES_MATCHING PATTERN "*.png")
|
||||
|
||||
install(FILES ${qBittorrent_SOURCE_DIR}/src/icons/qbittorrent.png
|
||||
DESTINATION ${CMAKE_INSTALL_DATAROOTDIR}/pixmaps/
|
||||
COMPONENT data)
|
||||
install(FILES ${qBittorrent_SOURCE_DIR}/src/icons/qbittorrent.png
|
||||
DESTINATION ${CMAKE_INSTALL_DATAROOTDIR}/pixmaps/
|
||||
COMPONENT data)
|
||||
|
||||
install(FILES ${qBittorrent_SOURCE_DIR}/src/icons/qBittorrent.desktop
|
||||
DESTINATION ${CMAKE_INSTALL_DATAROOTDIR}/applications/
|
||||
COMPONENT data)
|
||||
install(FILES ${qBittorrent_SOURCE_DIR}/src/icons/qbittorrent.desktop
|
||||
DESTINATION ${CMAKE_INSTALL_DATAROOTDIR}/applications/
|
||||
COMPONENT data)
|
||||
|
||||
install(FILES qBittorrent.appdata.xml
|
||||
DESTINATION ${CMAKE_INSTALL_DATAROOTDIR}/appdata/
|
||||
COMPONENT data)
|
||||
install(FILES qbittorrent.appdata.xml
|
||||
DESTINATION ${CMAKE_INSTALL_DATAROOTDIR}/appdata/
|
||||
COMPONENT data)
|
||||
endif()
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!-- Copyright 2014 sledgehammer999 <sledgehammer999@qbittorrent.org> -->
|
||||
<component type="desktop">
|
||||
<id>qBittorrent.desktop</id>
|
||||
<id>qbittorrent.desktop</id>
|
||||
<metadata_license>CC0-1.0</metadata_license>
|
||||
<project_license>GPL-2.0 and OpenSSL</project_license>
|
||||
<name>qBittorrent</name>
|
||||
11
dist/unix/systemd/qbittorrent-nox.service.in
vendored
11
dist/unix/systemd/qbittorrent-nox.service.in
vendored
@@ -1,11 +0,0 @@
|
||||
[Unit]
|
||||
Description=qBittorrent Daemon Service
|
||||
After=network.target
|
||||
|
||||
[Service]
|
||||
Type=forking
|
||||
User=1000
|
||||
ExecStart=@EXPAND_BINDIR@/qbittorrent-nox -d
|
||||
|
||||
[Install]
|
||||
WantedBy=multi-user.target
|
||||
14
dist/unix/systemd/qbittorrent-nox@.service.in
vendored
Normal file
14
dist/unix/systemd/qbittorrent-nox@.service.in
vendored
Normal file
@@ -0,0 +1,14 @@
|
||||
[Unit]
|
||||
Description=qBittorrenti-nox service for user %I
|
||||
|
||||
Documentation=man:qbittorrent-nox(1)
|
||||
After=network.target
|
||||
|
||||
[Service]
|
||||
Type=simple
|
||||
PrivateTmp=false
|
||||
User=%i
|
||||
ExecStart=@EXPAND_BINDIR@/qbittorrent-nox
|
||||
|
||||
[Install]
|
||||
WantedBy=multi-user.target
|
||||
@@ -17,13 +17,13 @@ LangString inst_firewallinfo ${LANG_ARABIC} "جاري اضافة القاعدة
|
||||
;LangString inst_warning ${LANG_ENGLISH} "qBittorrent is running. Please close the application before installing."
|
||||
LangString inst_warning ${LANG_ARABIC} "البرنامج يعمل. يرجى اغلاقه قبل البدء في التنصيب"
|
||||
;LangString inst_uninstall_question ${LANG_ENGLISH} "A previous installation was detected. It will be uninstalled without deleting user settings."
|
||||
LangString inst_uninstall_question ${LANG_ARABIC} "A previous installation was detected. It will be uninstalled without deleting user settings."
|
||||
LangString inst_uninstall_question ${LANG_ARABIC} "يوجد نسخة سابقة من البرنامج. سيتم إزالتها دون حذف إعدادات المستخدم"
|
||||
;LangString inst_unist ${LANG_ENGLISH} "Uninstalling previous version."
|
||||
LangString inst_unist ${LANG_ARABIC} "جاري ازالة النسخة السابقة من البرنامج"
|
||||
;LangString launch_qbt ${LANG_ENGLISH} "Launch qBittorrent."
|
||||
LangString launch_qbt ${LANG_ARABIC} "تشغيل البرنامج"
|
||||
;LangString inst_requires_64bit ${LANG_ENGLISH} "This installer works only in 64-bit Windows versions."
|
||||
LangString inst_requires_64bit ${LANG_ARABIC} "This installer works only in 64-bit Windows versions."
|
||||
LangString inst_requires_64bit ${LANG_ARABIC} "هذا المثبت يعمل فقط في نسخ ويندوز 64 بت"
|
||||
|
||||
|
||||
;------------------------------------
|
||||
|
||||
46
dist/windows/installer-translations/danish.nsi
vendored
46
dist/windows/installer-translations/danish.nsi
vendored
@@ -1,53 +1,53 @@
|
||||
;Installer strings
|
||||
|
||||
;LangString inst_qbt_req ${LANG_ENGLISH} "qBittorrent (required)"
|
||||
LangString inst_qbt_req ${LANG_DANISH} "qBittorrent (required)"
|
||||
LangString inst_qbt_req ${LANG_DANISH} "qBittorrent (påkrævet)"
|
||||
;LangString inst_dekstop ${LANG_ENGLISH} "Create Desktop Shortcut"
|
||||
LangString inst_dekstop ${LANG_DANISH} "Create Desktop Shortcut"
|
||||
LangString inst_dekstop ${LANG_DANISH} "Opret skrivebordsgenvej"
|
||||
;LangString inst_startmenu ${LANG_ENGLISH} "Create Start Menu Shortcut"
|
||||
LangString inst_startmenu ${LANG_DANISH} "Create Start Menu Shortcut"
|
||||
LangString inst_startmenu ${LANG_DANISH} "Opret genvej i menuen Start"
|
||||
;LangString inst_torrent ${LANG_ENGLISH} "Open .torrent files with qBittorrent"
|
||||
LangString inst_torrent ${LANG_DANISH} "Open .torrent files with qBittorrent"
|
||||
LangString inst_torrent ${LANG_DANISH} "Åbn .torrent-filer med qBittorrent"
|
||||
;LangString inst_magnet ${LANG_ENGLISH} "Open magnet links with qBittorrent"
|
||||
LangString inst_magnet ${LANG_DANISH} "Open magnet links with qBittorrent"
|
||||
LangString inst_magnet ${LANG_DANISH} "Åbn magnet-links med qBittorrent"
|
||||
;LangString inst_firewall ${LANG_ENGLISH} "Add Windows Firewall rule"
|
||||
LangString inst_firewall ${LANG_DANISH} "Add Windows Firewall rule"
|
||||
LangString inst_firewall ${LANG_DANISH} "Tilføj Windows Firewall-regel"
|
||||
;LangString inst_firewallinfo ${LANG_ENGLISH} "Adding Windows Firewall rule"
|
||||
LangString inst_firewallinfo ${LANG_DANISH} "Adding Windows Firewall rule"
|
||||
LangString inst_firewallinfo ${LANG_DANISH} "Tilføjer Windows Firewall-regel"
|
||||
;LangString inst_warning ${LANG_ENGLISH} "qBittorrent is running. Please close the application before installing."
|
||||
LangString inst_warning ${LANG_DANISH} "qBittorrent is running. Please close the application before installing."
|
||||
LangString inst_warning ${LANG_DANISH} "qBittorrent kører. Luk venligst programmet inden installation."
|
||||
;LangString inst_uninstall_question ${LANG_ENGLISH} "A previous installation was detected. It will be uninstalled without deleting user settings."
|
||||
LangString inst_uninstall_question ${LANG_DANISH} "A previous installation was detected. It will be uninstalled without deleting user settings."
|
||||
LangString inst_uninstall_question ${LANG_DANISH} "En tidligere installation blev registreret. Den vil blive afinstalleret uden at brugerindstillingerne slettes."
|
||||
;LangString inst_unist ${LANG_ENGLISH} "Uninstalling previous version."
|
||||
LangString inst_unist ${LANG_DANISH} "Uninstalling previous version."
|
||||
LangString inst_unist ${LANG_DANISH} "Afinstallerer tidligere version."
|
||||
;LangString launch_qbt ${LANG_ENGLISH} "Launch qBittorrent."
|
||||
LangString launch_qbt ${LANG_DANISH} "Launch qBittorrent."
|
||||
LangString launch_qbt ${LANG_DANISH} "Start qBittorrent."
|
||||
;LangString inst_requires_64bit ${LANG_ENGLISH} "This installer works only in 64-bit Windows versions."
|
||||
LangString inst_requires_64bit ${LANG_DANISH} "This installer works only in 64-bit Windows versions."
|
||||
LangString inst_requires_64bit ${LANG_DANISH} "Dette installationsprogram virker kun i 64-bit Windows versioner."
|
||||
|
||||
|
||||
;------------------------------------
|
||||
;Uninstaller strings
|
||||
|
||||
;LangString remove_files ${LANG_ENGLISH} "Remove files"
|
||||
LangString remove_files ${LANG_DANISH} "Remove files"
|
||||
LangString remove_files ${LANG_DANISH} "Fjern filer"
|
||||
;LangString remove_shortcuts ${LANG_ENGLISH} "Remove shortcuts"
|
||||
LangString remove_shortcuts ${LANG_DANISH} "Remove shortcuts"
|
||||
LangString remove_shortcuts ${LANG_DANISH} "Fjern genveje"
|
||||
;LangString remove_associations ${LANG_ENGLISH} "Remove file associations"
|
||||
LangString remove_associations ${LANG_DANISH} "Remove file associations"
|
||||
LangString remove_associations ${LANG_DANISH} "Fjern filtilknytninger"
|
||||
;LangString remove_registry ${LANG_ENGLISH} "Remove registry keys"
|
||||
LangString remove_registry ${LANG_DANISH} "Remove registry keys"
|
||||
LangString remove_registry ${LANG_DANISH} "Fjern registreringsnøgler"
|
||||
;LangString remove_conf ${LANG_ENGLISH} "Remove configuration files"
|
||||
LangString remove_conf ${LANG_DANISH} "Remove configuration files"
|
||||
LangString remove_conf ${LANG_DANISH} "Fjern konfigurationsfiler"
|
||||
;LangString remove_firewall ${LANG_ENGLISH} "Remove Windows Firewall rule"
|
||||
LangString remove_firewall ${LANG_DANISH} "Remove Windows Firewall rule"
|
||||
LangString remove_firewall ${LANG_DANISH} "Fjern Windows Firewall-regel"
|
||||
;LangString remove_firewallinfo ${LANG_ENGLISH} "Removing Windows Firewall rule"
|
||||
LangString remove_firewallinfo ${LANG_DANISH} "Removing Windows Firewall rule"
|
||||
LangString remove_firewallinfo ${LANG_DANISH} "Fjerner Windows Firewall-regel"
|
||||
;LangString remove_cache ${LANG_ENGLISH} "Remove torrents and cached data"
|
||||
LangString remove_cache ${LANG_DANISH} "Remove torrents and cached data"
|
||||
LangString remove_cache ${LANG_DANISH} "Fjern torrents og mellemlagret data"
|
||||
;LangString uninst_warning ${LANG_ENGLISH} "qBittorrent is running. Please close the application before uninstalling."
|
||||
LangString uninst_warning ${LANG_DANISH} "qBittorrent is running. Please close the application before uninstalling."
|
||||
LangString uninst_warning ${LANG_DANISH} "qBittorrent kører. Luk venligst programmet inden afinstallation."
|
||||
;LangString uninst_tor_warn ${LANG_ENGLISH} "Not removing .torrent association. It is associated with:"
|
||||
LangString uninst_tor_warn ${LANG_DANISH} "Not removing .torrent association. It is associated with:"
|
||||
LangString uninst_tor_warn ${LANG_DANISH} "Fjerner ikke .torrent-tilknytning. Det er tilknyttet:"
|
||||
;LangString uninst_mag_warn ${LANG_ENGLISH} "Not removing magnet association. It is associated with:"
|
||||
LangString uninst_mag_warn ${LANG_DANISH} "Not removing magnet association. It is associated with:"
|
||||
LangString uninst_mag_warn ${LANG_DANISH} "Fjerner ikke magnet-tilknytning. Det er tilknyttet:"
|
||||
|
||||
@@ -23,7 +23,7 @@ LangString inst_unist ${LANG_GERMAN} "Vorherige Version wird deinstalliert."
|
||||
;LangString launch_qbt ${LANG_ENGLISH} "Launch qBittorrent."
|
||||
LangString launch_qbt ${LANG_GERMAN} "Starte qBittorrent."
|
||||
;LangString inst_requires_64bit ${LANG_ENGLISH} "This installer works only in 64-bit Windows versions."
|
||||
LangString inst_requires_64bit ${LANG_GERMAN} "This installer works only in 64-bit Windows versions."
|
||||
LangString inst_requires_64bit ${LANG_GERMAN} "Diese Installation funktioniert nur mit einer 64-bit Version von Windows."
|
||||
|
||||
|
||||
;------------------------------------
|
||||
|
||||
46
dist/windows/installer-translations/greek.nsi
vendored
46
dist/windows/installer-translations/greek.nsi
vendored
@@ -1,53 +1,53 @@
|
||||
;Installer strings
|
||||
|
||||
;LangString inst_qbt_req ${LANG_ENGLISH} "qBittorrent (required)"
|
||||
LangString inst_qbt_req ${LANG_GREEK} "qBittorrent (required)"
|
||||
LangString inst_qbt_req ${LANG_GREEK} "qBittorrent (απαιτείται)"
|
||||
;LangString inst_dekstop ${LANG_ENGLISH} "Create Desktop Shortcut"
|
||||
LangString inst_dekstop ${LANG_GREEK} "Create Desktop Shortcut"
|
||||
LangString inst_dekstop ${LANG_GREEK} "Δημιουργία συντόμευσης στην Επιφάνεια Εργασίας"
|
||||
;LangString inst_startmenu ${LANG_ENGLISH} "Create Start Menu Shortcut"
|
||||
LangString inst_startmenu ${LANG_GREEK} "Create Start Menu Shortcut"
|
||||
LangString inst_startmenu ${LANG_GREEK} "Δημιουργία συντόμευσης στο Μενού Έναρξης"
|
||||
;LangString inst_torrent ${LANG_ENGLISH} "Open .torrent files with qBittorrent"
|
||||
LangString inst_torrent ${LANG_GREEK} "Open .torrent files with qBittorrent"
|
||||
LangString inst_torrent ${LANG_GREEK} "Άνοιγμα των αρχείων .torrent με το qBittorrent"
|
||||
;LangString inst_magnet ${LANG_ENGLISH} "Open magnet links with qBittorrent"
|
||||
LangString inst_magnet ${LANG_GREEK} "Open magnet links with qBittorrent"
|
||||
LangString inst_magnet ${LANG_GREEK} "Άνοιγμα των μαγνητικών συνδέσμων με το qBittorrent"
|
||||
;LangString inst_firewall ${LANG_ENGLISH} "Add Windows Firewall rule"
|
||||
LangString inst_firewall ${LANG_GREEK} "Add Windows Firewall rule"
|
||||
LangString inst_firewall ${LANG_GREEK} "Προσθήκη κανόνα εξαίρεσης στο Τείχος Προστασίας των Windows"
|
||||
;LangString inst_firewallinfo ${LANG_ENGLISH} "Adding Windows Firewall rule"
|
||||
LangString inst_firewallinfo ${LANG_GREEK} "Adding Windows Firewall rule"
|
||||
LangString inst_firewallinfo ${LANG_GREEK} "Προστίθεται κανόνας εξαίρεσης στο Τείχος Προστασίας των Windows"
|
||||
;LangString inst_warning ${LANG_ENGLISH} "qBittorrent is running. Please close the application before installing."
|
||||
LangString inst_warning ${LANG_GREEK} "qBittorrent is running. Please close the application before installing."
|
||||
LangString inst_warning ${LANG_GREEK} "Το qBittorrent βρίσκεται σε εκτέλεση. Παρακαλούμε κλείστε την εφαρμογή πριν την εγκατάσταση."
|
||||
;LangString inst_uninstall_question ${LANG_ENGLISH} "A previous installation was detected. It will be uninstalled without deleting user settings."
|
||||
LangString inst_uninstall_question ${LANG_GREEK} "A previous installation was detected. It will be uninstalled without deleting user settings."
|
||||
LangString inst_uninstall_question ${LANG_GREEK} "Ανιχνεύθηκε προηγούμενη εγκατάσταση. Θα απεγκατασταθεί χωρίς να διαγραφούν οι ρυθμίσεις του χρήστη."
|
||||
;LangString inst_unist ${LANG_ENGLISH} "Uninstalling previous version."
|
||||
LangString inst_unist ${LANG_GREEK} "Uninstalling previous version."
|
||||
LangString inst_unist ${LANG_GREEK} "Γίνεται απεγκατάσταση της προηγούμενης έκδοσης."
|
||||
;LangString launch_qbt ${LANG_ENGLISH} "Launch qBittorrent."
|
||||
LangString launch_qbt ${LANG_GREEK} "Launch qBittorrent."
|
||||
LangString launch_qbt ${LANG_GREEK} "Εκκίνηση του qBittorrent."
|
||||
;LangString inst_requires_64bit ${LANG_ENGLISH} "This installer works only in 64-bit Windows versions."
|
||||
LangString inst_requires_64bit ${LANG_GREEK} "This installer works only in 64-bit Windows versions."
|
||||
LangString inst_requires_64bit ${LANG_GREEK} "Αυτό το αρχείο εγκατάστασης λειτουργεί μόνο σε 64-bit εκδόσεις των Windows."
|
||||
|
||||
|
||||
;------------------------------------
|
||||
;Uninstaller strings
|
||||
|
||||
;LangString remove_files ${LANG_ENGLISH} "Remove files"
|
||||
LangString remove_files ${LANG_GREEK} "Remove files"
|
||||
LangString remove_files ${LANG_GREEK} "Να διαγραφούν τα αρχεία"
|
||||
;LangString remove_shortcuts ${LANG_ENGLISH} "Remove shortcuts"
|
||||
LangString remove_shortcuts ${LANG_GREEK} "Remove shortcuts"
|
||||
LangString remove_shortcuts ${LANG_GREEK} "Να διαγραφούν οι συντομεύσεις"
|
||||
;LangString remove_associations ${LANG_ENGLISH} "Remove file associations"
|
||||
LangString remove_associations ${LANG_GREEK} "Remove file associations"
|
||||
LangString remove_associations ${LANG_GREEK} "Να καταργηθούν οι συσχετίσεις αρχείων"
|
||||
;LangString remove_registry ${LANG_ENGLISH} "Remove registry keys"
|
||||
LangString remove_registry ${LANG_GREEK} "Remove registry keys"
|
||||
LangString remove_registry ${LANG_GREEK} "Να διαγραφούν τα κλειδιά μητρώου"
|
||||
;LangString remove_conf ${LANG_ENGLISH} "Remove configuration files"
|
||||
LangString remove_conf ${LANG_GREEK} "Remove configuration files"
|
||||
LangString remove_conf ${LANG_GREEK} "Να διαγραφούν τα αρχεία ρυθμίσεων"
|
||||
;LangString remove_firewall ${LANG_ENGLISH} "Remove Windows Firewall rule"
|
||||
LangString remove_firewall ${LANG_GREEK} "Remove Windows Firewall rule"
|
||||
LangString remove_firewall ${LANG_GREEK} "Να διαγραφεί ο κανόνας εξαίρεσης στο Τείχος Προστασίας των Windows"
|
||||
;LangString remove_firewallinfo ${LANG_ENGLISH} "Removing Windows Firewall rule"
|
||||
LangString remove_firewallinfo ${LANG_GREEK} "Removing Windows Firewall rule"
|
||||
LangString remove_firewallinfo ${LANG_GREEK} "Γίνεται διαγραφή του κανόνα εξαίρεσης στο Τείχος Προστασίας των Windows"
|
||||
;LangString remove_cache ${LANG_ENGLISH} "Remove torrents and cached data"
|
||||
LangString remove_cache ${LANG_GREEK} "Remove torrents and cached data"
|
||||
LangString remove_cache ${LANG_GREEK} "Να διαγραφούν τα torrents και τα δεδομένα προσωρινής αποθήκευσης"
|
||||
;LangString uninst_warning ${LANG_ENGLISH} "qBittorrent is running. Please close the application before uninstalling."
|
||||
LangString uninst_warning ${LANG_GREEK} "qBittorrent is running. Please close the application before uninstalling."
|
||||
LangString uninst_warning ${LANG_GREEK} "Το qBittorrent βρίσκεται σε εκτέλεση. Παρακαλούμε κλείστε την εφαρμογή πριν την απεγκατάσταση."
|
||||
;LangString uninst_tor_warn ${LANG_ENGLISH} "Not removing .torrent association. It is associated with:"
|
||||
LangString uninst_tor_warn ${LANG_GREEK} "Not removing .torrent association. It is associated with:"
|
||||
LangString uninst_tor_warn ${LANG_GREEK} "Δεν θα καταργηθεί η συσχέτιση με τα αρχεία .torrent. Είναι συσχετισμένα με το:"
|
||||
;LangString uninst_mag_warn ${LANG_ENGLISH} "Not removing magnet association. It is associated with:"
|
||||
LangString uninst_mag_warn ${LANG_GREEK} "Not removing magnet association. It is associated with:"
|
||||
LangString uninst_mag_warn ${LANG_GREEK} "Δεν θα καταργηθεί η συσχέτιση με τους μαγνητικούς συνδέσμους. Είναι συσχετισμένοι με το:"
|
||||
|
||||
12
dist/windows/installer-translations/russian.nsi
vendored
12
dist/windows/installer-translations/russian.nsi
vendored
@@ -7,9 +7,9 @@ LangString inst_dekstop ${LANG_RUSSIAN} "Создать ярлык на рабо
|
||||
;LangString inst_startmenu ${LANG_ENGLISH} "Create Start Menu Shortcut"
|
||||
LangString inst_startmenu ${LANG_RUSSIAN} "Создать ярлык в меню Пуск"
|
||||
;LangString inst_torrent ${LANG_ENGLISH} "Open .torrent files with qBittorrent"
|
||||
LangString inst_torrent ${LANG_RUSSIAN} "Открывать торрент файлы с помощью qBittorrent"
|
||||
LangString inst_torrent ${LANG_RUSSIAN} "Открывать торрент-файлы с помощью qBittorrent"
|
||||
;LangString inst_magnet ${LANG_ENGLISH} "Open magnet links with qBittorrent"
|
||||
LangString inst_magnet ${LANG_RUSSIAN} "Открывать magnet ссылки с помощью qBittorrent"
|
||||
LangString inst_magnet ${LANG_RUSSIAN} "Открывать magnet-ссылки с помощью qBittorrent"
|
||||
;LangString inst_firewall ${LANG_ENGLISH} "Add Windows Firewall rule"
|
||||
LangString inst_firewall ${LANG_RUSSIAN} "Добавить в список исключений брандмауера"
|
||||
;LangString inst_firewallinfo ${LANG_ENGLISH} "Adding Windows Firewall rule"
|
||||
@@ -23,7 +23,7 @@ LangString inst_unist ${LANG_RUSSIAN} "Деинсталлируем старую
|
||||
;LangString launch_qbt ${LANG_ENGLISH} "Launch qBittorrent."
|
||||
LangString launch_qbt ${LANG_RUSSIAN} "Запустить qBittorrent."
|
||||
;LangString inst_requires_64bit ${LANG_ENGLISH} "This installer works only in 64-bit Windows versions."
|
||||
LangString inst_requires_64bit ${LANG_RUSSIAN} "This installer works only in 64-bit Windows versions."
|
||||
LangString inst_requires_64bit ${LANG_RUSSIAN} "Этот установщик работает только на 64-битных версиях Windows."
|
||||
|
||||
|
||||
;------------------------------------
|
||||
@@ -44,10 +44,10 @@ LangString remove_firewall ${LANG_RUSSIAN} "Удалить из списка и
|
||||
;LangString remove_firewallinfo ${LANG_ENGLISH} "Removing Windows Firewall rule"
|
||||
LangString remove_firewallinfo ${LANG_RUSSIAN} "Удаление из списка исключений брандмауера"
|
||||
;LangString remove_cache ${LANG_ENGLISH} "Remove torrents and cached data"
|
||||
LangString remove_cache ${LANG_RUSSIAN} "Удалить сохраненные торрент файлы"
|
||||
LangString remove_cache ${LANG_RUSSIAN} "Удалить сохранённые торрент-файлы"
|
||||
;LangString uninst_warning ${LANG_ENGLISH} "qBittorrent is running. Please close the application before uninstalling."
|
||||
LangString uninst_warning ${LANG_RUSSIAN} "qBittorrent запущен. Пожалуйста, закройте qBittorrent и перезапустите программу удаления."
|
||||
;LangString uninst_tor_warn ${LANG_ENGLISH} "Not removing .torrent association. It is associated with:"
|
||||
LangString uninst_tor_warn ${LANG_RUSSIAN} "Ассоциации торрент файлов не сброшены. Уже ассоциированы с:"
|
||||
LangString uninst_tor_warn ${LANG_RUSSIAN} "Ассоциации торрент-файлов не сброшены. Уже ассоциированы с:"
|
||||
;LangString uninst_mag_warn ${LANG_ENGLISH} "Not removing magnet association. It is associated with:"
|
||||
LangString uninst_mag_warn ${LANG_RUSSIAN} "Ассоциации magnet ссылок не сброшены. Уже ассоциированы с:"
|
||||
LangString uninst_mag_warn ${LANG_RUSSIAN} "Ассоциации magnet-ссылок не сброшены. Уже ассоциированы с:"
|
||||
|
||||
@@ -1,53 +1,53 @@
|
||||
;Installer strings
|
||||
|
||||
;LangString inst_qbt_req ${LANG_ENGLISH} "qBittorrent (required)"
|
||||
LangString inst_qbt_req ${LANG_SIMPCHINESE} "qBittorrent (required)"
|
||||
LangString inst_qbt_req ${LANG_SIMPCHINESE} "qBittorrent (必要)"
|
||||
;LangString inst_dekstop ${LANG_ENGLISH} "Create Desktop Shortcut"
|
||||
LangString inst_dekstop ${LANG_SIMPCHINESE} "Create Desktop Shortcut"
|
||||
LangString inst_dekstop ${LANG_SIMPCHINESE} "创建桌面快捷方式"
|
||||
;LangString inst_startmenu ${LANG_ENGLISH} "Create Start Menu Shortcut"
|
||||
LangString inst_startmenu ${LANG_SIMPCHINESE} "Create Start Menu Shortcut"
|
||||
LangString inst_startmenu ${LANG_SIMPCHINESE} "创建开始菜单快捷方式"
|
||||
;LangString inst_torrent ${LANG_ENGLISH} "Open .torrent files with qBittorrent"
|
||||
LangString inst_torrent ${LANG_SIMPCHINESE} "Open .torrent files with qBittorrent"
|
||||
LangString inst_torrent ${LANG_SIMPCHINESE} "用 qBittorrent 打开.torrent文件"
|
||||
;LangString inst_magnet ${LANG_ENGLISH} "Open magnet links with qBittorrent"
|
||||
LangString inst_magnet ${LANG_SIMPCHINESE} "Open magnet links with qBittorrent"
|
||||
LangString inst_magnet ${LANG_SIMPCHINESE} "用 qBittorrent 打开磁力链接"
|
||||
;LangString inst_firewall ${LANG_ENGLISH} "Add Windows Firewall rule"
|
||||
LangString inst_firewall ${LANG_SIMPCHINESE} "Add Windows Firewall rule"
|
||||
LangString inst_firewall ${LANG_SIMPCHINESE} "添加Windows防火墙规则"
|
||||
;LangString inst_firewallinfo ${LANG_ENGLISH} "Adding Windows Firewall rule"
|
||||
LangString inst_firewallinfo ${LANG_SIMPCHINESE} "Adding Windows Firewall rule"
|
||||
LangString inst_firewallinfo ${LANG_SIMPCHINESE} "正在添加Windows防火墙规则"
|
||||
;LangString inst_warning ${LANG_ENGLISH} "qBittorrent is running. Please close the application before installing."
|
||||
LangString inst_warning ${LANG_SIMPCHINESE} "qBittorrent is running. Please close the application before installing."
|
||||
LangString inst_warning ${LANG_SIMPCHINESE} "qBittorrent 正在运行。 安装前请关闭应用程序。"
|
||||
;LangString inst_uninstall_question ${LANG_ENGLISH} "A previous installation was detected. It will be uninstalled without deleting user settings."
|
||||
LangString inst_uninstall_question ${LANG_SIMPCHINESE} "A previous installation was detected. It will be uninstalled without deleting user settings."
|
||||
LangString inst_uninstall_question ${LANG_SIMPCHINESE} "检测到以前的安装。 它将被卸载但不删除用户设置。"
|
||||
;LangString inst_unist ${LANG_ENGLISH} "Uninstalling previous version."
|
||||
LangString inst_unist ${LANG_SIMPCHINESE} "Uninstalling previous version."
|
||||
LangString inst_unist ${LANG_SIMPCHINESE} "卸载以前的版本。"
|
||||
;LangString launch_qbt ${LANG_ENGLISH} "Launch qBittorrent."
|
||||
LangString launch_qbt ${LANG_SIMPCHINESE} "Launch qBittorrent."
|
||||
LangString launch_qbt ${LANG_SIMPCHINESE} "启动 qBittorrent."
|
||||
;LangString inst_requires_64bit ${LANG_ENGLISH} "This installer works only in 64-bit Windows versions."
|
||||
LangString inst_requires_64bit ${LANG_SIMPCHINESE} "This installer works only in 64-bit Windows versions."
|
||||
LangString inst_requires_64bit ${LANG_SIMPCHINESE} "此安装程序只能在64位的Windows上工作。"
|
||||
|
||||
|
||||
;------------------------------------
|
||||
;Uninstaller strings
|
||||
|
||||
;LangString remove_files ${LANG_ENGLISH} "Remove files"
|
||||
LangString remove_files ${LANG_SIMPCHINESE} "Remove files"
|
||||
LangString remove_files ${LANG_SIMPCHINESE} "删除文件"
|
||||
;LangString remove_shortcuts ${LANG_ENGLISH} "Remove shortcuts"
|
||||
LangString remove_shortcuts ${LANG_SIMPCHINESE} "Remove shortcuts"
|
||||
LangString remove_shortcuts ${LANG_SIMPCHINESE} "删除快捷方式"
|
||||
;LangString remove_associations ${LANG_ENGLISH} "Remove file associations"
|
||||
LangString remove_associations ${LANG_SIMPCHINESE} "Remove file associations"
|
||||
LangString remove_associations ${LANG_SIMPCHINESE} "删除文件关联"
|
||||
;LangString remove_registry ${LANG_ENGLISH} "Remove registry keys"
|
||||
LangString remove_registry ${LANG_SIMPCHINESE} "Remove registry keys"
|
||||
LangString remove_registry ${LANG_SIMPCHINESE} "删除注册表键"
|
||||
;LangString remove_conf ${LANG_ENGLISH} "Remove configuration files"
|
||||
LangString remove_conf ${LANG_SIMPCHINESE} "Remove configuration files"
|
||||
LangString remove_conf ${LANG_SIMPCHINESE} "删除配置文件"
|
||||
;LangString remove_firewall ${LANG_ENGLISH} "Remove Windows Firewall rule"
|
||||
LangString remove_firewall ${LANG_SIMPCHINESE} "Remove Windows Firewall rule"
|
||||
LangString remove_firewall ${LANG_SIMPCHINESE} "删除Windows防火墙规则"
|
||||
;LangString remove_firewallinfo ${LANG_ENGLISH} "Removing Windows Firewall rule"
|
||||
LangString remove_firewallinfo ${LANG_SIMPCHINESE} "Removing Windows Firewall rule"
|
||||
LangString remove_firewallinfo ${LANG_SIMPCHINESE} "正在删除Windows防火墙规则"
|
||||
;LangString remove_cache ${LANG_ENGLISH} "Remove torrents and cached data"
|
||||
LangString remove_cache ${LANG_SIMPCHINESE} "Remove torrents and cached data"
|
||||
LangString remove_cache ${LANG_SIMPCHINESE} "删除种子和缓存数据"
|
||||
;LangString uninst_warning ${LANG_ENGLISH} "qBittorrent is running. Please close the application before uninstalling."
|
||||
LangString uninst_warning ${LANG_SIMPCHINESE} "qBittorrent is running. Please close the application before uninstalling."
|
||||
LangString uninst_warning ${LANG_SIMPCHINESE} "qBittorrent 正在运行。 卸载前请关闭程序。"
|
||||
;LangString uninst_tor_warn ${LANG_ENGLISH} "Not removing .torrent association. It is associated with:"
|
||||
LangString uninst_tor_warn ${LANG_SIMPCHINESE} "Not removing .torrent association. It is associated with:"
|
||||
LangString uninst_tor_warn ${LANG_SIMPCHINESE} "不删除 .torrent 关联。 关联的是:"
|
||||
;LangString uninst_mag_warn ${LANG_ENGLISH} "Not removing magnet association. It is associated with:"
|
||||
LangString uninst_mag_warn ${LANG_SIMPCHINESE} "Not removing magnet association. It is associated with:"
|
||||
LangString uninst_mag_warn ${LANG_SIMPCHINESE} "不删除磁力关联。 关联的是:"
|
||||
|
||||
@@ -23,7 +23,7 @@ LangString inst_unist ${LANG_SPANISH} "Desinstalando la versión anterior."
|
||||
;LangString launch_qbt ${LANG_ENGLISH} "Launch qBittorrent."
|
||||
LangString launch_qbt ${LANG_SPANISH} "Iniciar qBittorrent."
|
||||
;LangString inst_requires_64bit ${LANG_ENGLISH} "This installer works only in 64-bit Windows versions."
|
||||
LangString inst_requires_64bit ${LANG_SPANISH} "This installer works only in 64-bit Windows versions."
|
||||
LangString inst_requires_64bit ${LANG_SPANISH} "Este instalador solo funciona en versiones de 64-bit de Windows."
|
||||
|
||||
|
||||
;------------------------------------
|
||||
|
||||
@@ -23,7 +23,7 @@ LangString inst_unist ${LANG_SPANISHINTERNATIONAL} "Desinstalando la versión an
|
||||
;LangString launch_qbt ${LANG_ENGLISH} "Launch qBittorrent."
|
||||
LangString launch_qbt ${LANG_SPANISHINTERNATIONAL} "Iniciar qBittorrent."
|
||||
;LangString inst_requires_64bit ${LANG_ENGLISH} "This installer works only in 64-bit Windows versions."
|
||||
LangString inst_requires_64bit ${LANG_SPANISHINTERNATIONAL} "This installer works only in 64-bit Windows versions."
|
||||
LangString inst_requires_64bit ${LANG_SPANISHINTERNATIONAL} "Este instalador solo funciona en versiones de 64-bit de Windows."
|
||||
|
||||
|
||||
;------------------------------------
|
||||
|
||||
@@ -23,7 +23,7 @@ LangString inst_unist ${LANG_TURKISH} "Önceki sürüm kaldırılıyor."
|
||||
;LangString launch_qbt ${LANG_ENGLISH} "Launch qBittorrent."
|
||||
LangString launch_qbt ${LANG_TURKISH} "qBittorrent'i çalıştır."
|
||||
;LangString inst_requires_64bit ${LANG_ENGLISH} "This installer works only in 64-bit Windows versions."
|
||||
LangString inst_requires_64bit ${LANG_TURKISH} "This installer works only in 64-bit Windows versions."
|
||||
LangString inst_requires_64bit ${LANG_TURKISH} "Bu yükleyici sadece 64-bit Windows sürümlerinde çalışır."
|
||||
|
||||
|
||||
;------------------------------------
|
||||
|
||||
@@ -1,53 +1,53 @@
|
||||
;Installer strings
|
||||
|
||||
;LangString inst_qbt_req ${LANG_ENGLISH} "qBittorrent (required)"
|
||||
LangString inst_qbt_req ${LANG_UKRAINIAN} "qBittorrent (required)"
|
||||
LangString inst_qbt_req ${LANG_UKRAINIAN} "qBittorrent (необхідний)"
|
||||
;LangString inst_dekstop ${LANG_ENGLISH} "Create Desktop Shortcut"
|
||||
LangString inst_dekstop ${LANG_UKRAINIAN} "Create Desktop Shortcut"
|
||||
LangString inst_dekstop ${LANG_UKRAINIAN} "Створити ярлик на стільниці"
|
||||
;LangString inst_startmenu ${LANG_ENGLISH} "Create Start Menu Shortcut"
|
||||
LangString inst_startmenu ${LANG_UKRAINIAN} "Create Start Menu Shortcut"
|
||||
LangString inst_startmenu ${LANG_UKRAINIAN} "Створити ярлик в меню Пуск"
|
||||
;LangString inst_torrent ${LANG_ENGLISH} "Open .torrent files with qBittorrent"
|
||||
LangString inst_torrent ${LANG_UKRAINIAN} "Open .torrent files with qBittorrent"
|
||||
LangString inst_torrent ${LANG_UKRAINIAN} "Відкривати .torrent файли за допомогою qBittorrent"
|
||||
;LangString inst_magnet ${LANG_ENGLISH} "Open magnet links with qBittorrent"
|
||||
LangString inst_magnet ${LANG_UKRAINIAN} "Open magnet links with qBittorrent"
|
||||
LangString inst_magnet ${LANG_UKRAINIAN} "Відкривати посилання magnet за допомогою qBittorrent"
|
||||
;LangString inst_firewall ${LANG_ENGLISH} "Add Windows Firewall rule"
|
||||
LangString inst_firewall ${LANG_UKRAINIAN} "Add Windows Firewall rule"
|
||||
LangString inst_firewall ${LANG_UKRAINIAN} "Додати правило в Windows брандмауер"
|
||||
;LangString inst_firewallinfo ${LANG_ENGLISH} "Adding Windows Firewall rule"
|
||||
LangString inst_firewallinfo ${LANG_UKRAINIAN} "Adding Windows Firewall rule"
|
||||
LangString inst_firewallinfo ${LANG_UKRAINIAN} "Додаємо правило до брандмауера"
|
||||
;LangString inst_warning ${LANG_ENGLISH} "qBittorrent is running. Please close the application before installing."
|
||||
LangString inst_warning ${LANG_UKRAINIAN} "qBittorrent is running. Please close the application before installing."
|
||||
LangString inst_warning ${LANG_UKRAINIAN} "qBittorrent вже виконується. Будь ласка, закрийте застосунок перед запуском інсталятору."
|
||||
;LangString inst_uninstall_question ${LANG_ENGLISH} "A previous installation was detected. It will be uninstalled without deleting user settings."
|
||||
LangString inst_uninstall_question ${LANG_UKRAINIAN} "A previous installation was detected. It will be uninstalled without deleting user settings."
|
||||
LangString inst_uninstall_question ${LANG_UKRAINIAN} "Виявлено попередню інсталяцію. Її буде видалено за виключенням користувацьких налаштувань."
|
||||
;LangString inst_unist ${LANG_ENGLISH} "Uninstalling previous version."
|
||||
LangString inst_unist ${LANG_UKRAINIAN} "Uninstalling previous version."
|
||||
LangString inst_unist ${LANG_UKRAINIAN} "Видалення попередньої версії."
|
||||
;LangString launch_qbt ${LANG_ENGLISH} "Launch qBittorrent."
|
||||
LangString launch_qbt ${LANG_UKRAINIAN} "Launch qBittorrent."
|
||||
LangString launch_qbt ${LANG_UKRAINIAN} "Запустити qBittorrent."
|
||||
;LangString inst_requires_64bit ${LANG_ENGLISH} "This installer works only in 64-bit Windows versions."
|
||||
LangString inst_requires_64bit ${LANG_UKRAINIAN} "This installer works only in 64-bit Windows versions."
|
||||
LangString inst_requires_64bit ${LANG_UKRAINIAN} "Ця програма установки працює тільки в 64-розрядних версіях Windows."
|
||||
|
||||
|
||||
;------------------------------------
|
||||
;Uninstaller strings
|
||||
|
||||
;LangString remove_files ${LANG_ENGLISH} "Remove files"
|
||||
LangString remove_files ${LANG_UKRAINIAN} "Remove files"
|
||||
LangString remove_files ${LANG_UKRAINIAN} "Видалити файли"
|
||||
;LangString remove_shortcuts ${LANG_ENGLISH} "Remove shortcuts"
|
||||
LangString remove_shortcuts ${LANG_UKRAINIAN} "Remove shortcuts"
|
||||
LangString remove_shortcuts ${LANG_UKRAINIAN} "Видалити ярлики"
|
||||
;LangString remove_associations ${LANG_ENGLISH} "Remove file associations"
|
||||
LangString remove_associations ${LANG_UKRAINIAN} "Remove file associations"
|
||||
LangString remove_associations ${LANG_UKRAINIAN} "Видалити файлові асоціації"
|
||||
;LangString remove_registry ${LANG_ENGLISH} "Remove registry keys"
|
||||
LangString remove_registry ${LANG_UKRAINIAN} "Remove registry keys"
|
||||
LangString remove_registry ${LANG_UKRAINIAN} "Видалити ключі реєстру"
|
||||
;LangString remove_conf ${LANG_ENGLISH} "Remove configuration files"
|
||||
LangString remove_conf ${LANG_UKRAINIAN} "Remove configuration files"
|
||||
LangString remove_conf ${LANG_UKRAINIAN} "Видалити користувацькі налаштування"
|
||||
;LangString remove_firewall ${LANG_ENGLISH} "Remove Windows Firewall rule"
|
||||
LangString remove_firewall ${LANG_UKRAINIAN} "Remove Windows Firewall rule"
|
||||
LangString remove_firewall ${LANG_UKRAINIAN} "Видалити правило брандмауера Windows"
|
||||
;LangString remove_firewallinfo ${LANG_ENGLISH} "Removing Windows Firewall rule"
|
||||
LangString remove_firewallinfo ${LANG_UKRAINIAN} "Removing Windows Firewall rule"
|
||||
LangString remove_firewallinfo ${LANG_UKRAINIAN} "Видаляємо правило брандмауера Windows"
|
||||
;LangString remove_cache ${LANG_ENGLISH} "Remove torrents and cached data"
|
||||
LangString remove_cache ${LANG_UKRAINIAN} "Remove torrents and cached data"
|
||||
LangString remove_cache ${LANG_UKRAINIAN} "Видалити торренти та кешовані дані"
|
||||
;LangString uninst_warning ${LANG_ENGLISH} "qBittorrent is running. Please close the application before uninstalling."
|
||||
LangString uninst_warning ${LANG_UKRAINIAN} "qBittorrent is running. Please close the application before uninstalling."
|
||||
LangString uninst_warning ${LANG_UKRAINIAN} "qBittorrent виконується. Будь ласка, закрийте застосунок перед деінсталляцією."
|
||||
;LangString uninst_tor_warn ${LANG_ENGLISH} "Not removing .torrent association. It is associated with:"
|
||||
LangString uninst_tor_warn ${LANG_UKRAINIAN} "Not removing .torrent association. It is associated with:"
|
||||
LangString uninst_tor_warn ${LANG_UKRAINIAN} "Не видаляємо асоціацію .torrent файлів. Вони асоційовані з:"
|
||||
;LangString uninst_mag_warn ${LANG_ENGLISH} "Not removing magnet association. It is associated with:"
|
||||
LangString uninst_mag_warn ${LANG_UKRAINIAN} "Not removing magnet association. It is associated with:"
|
||||
LangString uninst_mag_warn ${LANG_UKRAINIAN} "Не видаляємо асоціацію magnet-посилань. Вони асоційовані з:"
|
||||
|
||||
Binary file not shown.
Binary file not shown.
BIN
dist/windows/nsis plugins/FindProcDLL_mod_by_hnedka.7z
vendored
Normal file
BIN
dist/windows/nsis plugins/FindProcDLL_mod_by_hnedka.7z
vendored
Normal file
Binary file not shown.
2
dist/windows/options.nsi
vendored
2
dist/windows/options.nsi
vendored
@@ -27,7 +27,7 @@ XPStyle on
|
||||
!define CSIDL_LOCALAPPDATA '0x1C' ;Local Application Data path
|
||||
|
||||
; Program specific
|
||||
!define PROG_VERSION "3.3.12"
|
||||
!define PROG_VERSION "3.3.16"
|
||||
|
||||
!define MUI_FINISHPAGE_RUN
|
||||
!define MUI_FINISHPAGE_RUN_FUNCTION PageFinishRun
|
||||
|
||||
@@ -2,6 +2,9 @@ set(CMAKE_CXX_STANDARD_REQUIRED True)
|
||||
set(CMAKE_CXX_STANDARD "11")
|
||||
add_definitions(-DBOOST_NO_CXX11_RVALUE_REFERENCES)
|
||||
|
||||
include(MacroQbtCompilerSettings)
|
||||
qbt_set_compiler_options()
|
||||
|
||||
include(MacroLinkQtComponents)
|
||||
include(QbtTargetSources)
|
||||
|
||||
@@ -28,6 +31,7 @@ else (QT5)
|
||||
endif (DBUS)
|
||||
find_package(Qt4 4.8.0 COMPONENTS ${QBT_QT_COMPONENTS} REQUIRED)
|
||||
include(${QT_USE_FILE})
|
||||
add_definitions(-DQStringLiteral=QLatin1String)
|
||||
endif (QT5)
|
||||
|
||||
set(CMAKE_AUTOMOC True)
|
||||
|
||||
@@ -38,6 +38,7 @@ endforeach()
|
||||
|
||||
set(QBT_APP_RESOURCES
|
||||
../icons.qrc
|
||||
../searchengine.qrc
|
||||
"${_lang_qrc_dst}"
|
||||
)
|
||||
|
||||
@@ -55,7 +56,7 @@ if (WIN32)
|
||||
else (MINGW)
|
||||
list (APPEND QBT_APP_SOURCES ../qbittorrent.rc)
|
||||
endif (MINGW)
|
||||
list(APPEND QBT_APP_SOURCES ../qbittorent.exe.manifest)
|
||||
list(APPEND QBT_APP_SOURCES ../qbittorrent.exe.manifest)
|
||||
endif (WIN32)
|
||||
|
||||
if (UNIX)
|
||||
|
||||
@@ -111,17 +111,20 @@ Application::Application(const QString &id, int &argc, char **argv)
|
||||
QFont::insertSubstitution(".Lucida Grande UI", "Lucida Grande");
|
||||
}
|
||||
#endif
|
||||
|
||||
setApplicationName("qBittorrent");
|
||||
initializeTranslation();
|
||||
#ifndef DISABLE_GUI
|
||||
|
||||
#if !defined(DISABLE_GUI)
|
||||
#ifdef QBT_USES_QT5
|
||||
setAttribute(Qt::AA_UseHighDpiPixmaps, true); // opt-in to the high DPI pixmap support
|
||||
#endif // QBT_USES_QT5
|
||||
setQuitOnLastWindowClosed(false);
|
||||
#ifdef Q_OS_WIN
|
||||
#endif
|
||||
|
||||
#if defined(Q_OS_WIN) && !defined(DISABLE_GUI)
|
||||
connect(this, SIGNAL(commitDataRequest(QSessionManager &)), this, SLOT(shutdownCleanup(QSessionManager &)), Qt::DirectConnection);
|
||||
#endif // Q_OS_WIN
|
||||
#endif // DISABLE_GUI
|
||||
#endif
|
||||
|
||||
connect(this, SIGNAL(messageReceived(const QString &)), SLOT(processMessage(const QString &)));
|
||||
connect(this, SIGNAL(aboutToQuit()), SLOT(cleanup()));
|
||||
@@ -441,6 +444,9 @@ int Application::exec(const QStringList ¶ms)
|
||||
m_paramsQueue.clear();
|
||||
}
|
||||
|
||||
// Now UI is ready to process signals from Session
|
||||
BitTorrent::Session::instance()->startUpTorrents();
|
||||
|
||||
return BaseApplication::exec();
|
||||
}
|
||||
|
||||
|
||||
@@ -40,6 +40,7 @@
|
||||
#include <QPen>
|
||||
#include <QPushButton>
|
||||
#include <QSplashScreen>
|
||||
|
||||
#ifdef QBT_STATIC_QT
|
||||
#include <QtPlugin>
|
||||
#ifdef QBT_USES_QT5
|
||||
@@ -120,15 +121,24 @@ struct QBtCommandLineParameters
|
||||
}
|
||||
};
|
||||
|
||||
#ifndef DISABLE_GUI
|
||||
void showSplashScreen();
|
||||
#if !defined Q_OS_WIN && !defined Q_OS_HAIKU
|
||||
void reportToUser(const char* str);
|
||||
#endif
|
||||
|
||||
void displayVersion();
|
||||
void displayUsage(const QString &prg_name);
|
||||
bool userAgreesWithLegalNotice();
|
||||
void displayBadArgMessage(const QString &message);
|
||||
QBtCommandLineParameters parseCommandLine();
|
||||
|
||||
#if !defined(DISABLE_GUI)
|
||||
void showSplashScreen();
|
||||
|
||||
#if defined(Q_OS_UNIX)
|
||||
void setupDpi();
|
||||
#endif // Q_OS_UNIX
|
||||
#endif // DISABLE_GUI
|
||||
|
||||
// Main
|
||||
int main(int argc, char *argv[])
|
||||
{
|
||||
@@ -141,6 +151,11 @@ int main(int argc, char *argv[])
|
||||
macMigratePlists();
|
||||
#endif
|
||||
|
||||
#if !defined(DISABLE_GUI) && defined(Q_OS_UNIX)
|
||||
setupDpi();
|
||||
#endif
|
||||
|
||||
|
||||
#ifndef DISABLE_GUI
|
||||
migrateRSS();
|
||||
#endif
|
||||
@@ -342,6 +357,17 @@ QBtCommandLineParameters parseCommandLine()
|
||||
return result;
|
||||
}
|
||||
|
||||
#if !defined Q_OS_WIN && !defined Q_OS_HAIKU
|
||||
void reportToUser(const char* str)
|
||||
{
|
||||
const size_t strLen = strlen(str);
|
||||
if (write(STDERR_FILENO, str, strLen) < static_cast<ssize_t>(strLen)) {
|
||||
auto dummy = write(STDOUT_FILENO, str, strLen);
|
||||
Q_UNUSED(dummy);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
#if defined(Q_OS_UNIX) || defined(STACKTRACE_WIN)
|
||||
void sigNormalHandler(int signum)
|
||||
{
|
||||
@@ -349,9 +375,9 @@ void sigNormalHandler(int signum)
|
||||
const char str1[] = "Catching signal: ";
|
||||
const char *sigName = sysSigName[signum];
|
||||
const char str2[] = "\nExiting cleanly\n";
|
||||
write(STDERR_FILENO, str1, strlen(str1));
|
||||
write(STDERR_FILENO, sigName, strlen(sigName));
|
||||
write(STDERR_FILENO, str2, strlen(str2));
|
||||
reportToUser(str1);
|
||||
reportToUser(sigName);
|
||||
reportToUser(str2);
|
||||
#endif // !defined Q_OS_WIN && !defined Q_OS_HAIKU
|
||||
signal(signum, SIG_DFL);
|
||||
qApp->exit(); // unsafe, but exit anyway
|
||||
@@ -364,9 +390,9 @@ void sigAbnormalHandler(int signum)
|
||||
const char *sigName = sysSigName[signum];
|
||||
const char str2[] = "\nPlease file a bug report at http://bug.qbittorrent.org and provide the following information:\n\n"
|
||||
"qBittorrent version: " QBT_VERSION "\n";
|
||||
write(STDERR_FILENO, str1, strlen(str1));
|
||||
write(STDERR_FILENO, sigName, strlen(sigName));
|
||||
write(STDERR_FILENO, str2, strlen(str2));
|
||||
reportToUser(str1);
|
||||
reportToUser(sigName);
|
||||
reportToUser(str2);
|
||||
print_stacktrace(); // unsafe
|
||||
#endif // !defined Q_OS_WIN && !defined Q_OS_HAIKU
|
||||
#ifdef STACKTRACE_WIN
|
||||
@@ -379,7 +405,7 @@ void sigAbnormalHandler(int signum)
|
||||
}
|
||||
#endif // defined(Q_OS_UNIX) || defined(STACKTRACE_WIN)
|
||||
|
||||
#ifndef DISABLE_GUI
|
||||
#if !defined(DISABLE_GUI)
|
||||
void showSplashScreen()
|
||||
{
|
||||
QPixmap splash_img(":/icons/skin/splash.png");
|
||||
@@ -393,7 +419,15 @@ void showSplashScreen()
|
||||
QTimer::singleShot(1500, splash, SLOT(deleteLater()));
|
||||
qApp->processEvents();
|
||||
}
|
||||
#endif
|
||||
|
||||
#if defined(Q_OS_UNIX)
|
||||
void setupDpi()
|
||||
{
|
||||
if (qgetenv("QT_AUTO_SCREEN_SCALE_FACTOR").isEmpty())
|
||||
qputenv("QT_AUTO_SCREEN_SCALE_FACTOR", "1");
|
||||
}
|
||||
#endif // Q_OS_UNIX
|
||||
#endif // DISABLE_GUI
|
||||
|
||||
void displayVersion()
|
||||
{
|
||||
|
||||
@@ -9,16 +9,18 @@
|
||||
#include <execinfo.h>
|
||||
#include <cxxabi.h>
|
||||
|
||||
#include <vector>
|
||||
|
||||
/** Print a demangled stack backtrace of the caller function to FILE* out. */
|
||||
static inline void print_stacktrace(FILE *out = stderr, unsigned int max_frames = 63)
|
||||
{
|
||||
fprintf(out, "stack trace:\n");
|
||||
|
||||
// storage array for stack trace address data
|
||||
void *addrlist[max_frames + 1];
|
||||
std::vector<void *> addrlist(max_frames + 1);
|
||||
|
||||
// retrieve current stack addresses
|
||||
int addrlen = backtrace(addrlist, sizeof(addrlist) / sizeof(void *));
|
||||
int addrlen = backtrace(addrlist.data(), addrlist.size());
|
||||
|
||||
if (addrlen == 0) {
|
||||
fprintf(out, " <empty, possibly corrupt>\n");
|
||||
@@ -27,7 +29,7 @@ static inline void print_stacktrace(FILE *out = stderr, unsigned int max_frames
|
||||
|
||||
// resolve addresses into strings containing "filename(function+address)",
|
||||
// this array must be free()-ed
|
||||
char * *symbollist = backtrace_symbols(addrlist, addrlen);
|
||||
char * *symbollist = backtrace_symbols(addrlist.data(), addrlen);
|
||||
|
||||
// allocate string which will be filled with the demangled function name
|
||||
size_t funcnamesize = 256;
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
find_package(ZLIB REQUIRED)
|
||||
find_package(ZLIB 1.2.5.2 REQUIRED)
|
||||
|
||||
set(QBT_BASE_HEADERS
|
||||
bittorrent/cachestatus.h
|
||||
|
||||
@@ -34,7 +34,6 @@
|
||||
#include <QDateTime>
|
||||
#include <QDebug>
|
||||
#include <QDir>
|
||||
#include <QDirIterator>
|
||||
#include <QHostAddress>
|
||||
#include <QNetworkAddressEntry>
|
||||
#include <QNetworkInterface>
|
||||
@@ -43,6 +42,7 @@
|
||||
#include <QString>
|
||||
#include <QThread>
|
||||
#include <QTimer>
|
||||
#include <QUuid>
|
||||
|
||||
#include <cstdlib>
|
||||
#include <queue>
|
||||
@@ -89,6 +89,14 @@
|
||||
#include "tracker.h"
|
||||
#include "trackerentry.h"
|
||||
|
||||
#ifdef Q_OS_WIN
|
||||
#include <iphlpapi.h>
|
||||
#endif
|
||||
|
||||
#if defined(Q_OS_WIN) && (_WIN32_WINNT < 0x0600)
|
||||
using NETIO_STATUS = LONG;
|
||||
#endif
|
||||
|
||||
static const char PEER_ID[] = "qB";
|
||||
static const char RESUME_FOLDER[] = "BT_backup";
|
||||
static const char USER_AGENT[] = "qBittorrent/" QBT_VERSION_2;
|
||||
@@ -106,6 +114,10 @@ namespace
|
||||
void torrentQueuePositionTop(const libt::torrent_handle &handle);
|
||||
void torrentQueuePositionBottom(const libt::torrent_handle &handle);
|
||||
|
||||
#ifdef Q_OS_WIN
|
||||
QString convertIfaceNameToGuid(const QString &name);
|
||||
#endif
|
||||
|
||||
inline SettingsStorage *settings() { return SettingsStorage::instance(); }
|
||||
|
||||
QStringMap map_cast(const QVariantMap &map)
|
||||
@@ -155,16 +167,6 @@ namespace
|
||||
return expanded;
|
||||
}
|
||||
|
||||
QStringList findAllFiles(const QString &dirPath)
|
||||
{
|
||||
QStringList files;
|
||||
QDirIterator it(dirPath, QDir::Files, QDirIterator::Subdirectories);
|
||||
while (it.hasNext())
|
||||
files << it.next();
|
||||
|
||||
return files;
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
struct LowerLimited
|
||||
{
|
||||
@@ -324,6 +326,10 @@ Session::Session(QObject *parent)
|
||||
sessionSettings.connection_speed = 20; // default is 10
|
||||
sessionSettings.no_connect_privileged_ports = false;
|
||||
sessionSettings.seed_choking_algorithm = libt::session_settings::fastest_upload;
|
||||
// Disk cache pool is rarely tested in libtorrent and doesn't free buffers
|
||||
// Soon to be deprecated there
|
||||
// More info: https://github.com/arvidn/libtorrent/issues/2251
|
||||
sessionSettings.use_disk_cache_pool = false;
|
||||
configure(sessionSettings);
|
||||
m_nativeSession->set_settings(sessionSettings);
|
||||
configureListeningInterface();
|
||||
@@ -351,6 +357,10 @@ Session::Session(QObject *parent)
|
||||
pack.set_int(libt::settings_pack::connection_speed, 20); // default is 10
|
||||
pack.set_bool(libt::settings_pack::no_connect_privileged_ports, false);
|
||||
pack.set_int(libt::settings_pack::seed_choking_algorithm, libt::settings_pack::fastest_upload);
|
||||
// Disk cache pool is rarely tested in libtorrent and doesn't free buffers
|
||||
// Soon to be deprecated there
|
||||
// More info: https://github.com/arvidn/libtorrent/issues/2251
|
||||
pack.set_bool(libt::settings_pack::use_disk_cache_pool, false);
|
||||
configure(pack);
|
||||
|
||||
m_nativeSession = new libt::session(pack, 0);
|
||||
@@ -425,7 +435,6 @@ Session::Session(QObject *parent)
|
||||
Net::PortForwarder::initInstance(m_nativeSession);
|
||||
|
||||
qDebug("* BitTorrent Session constructed");
|
||||
startUpTorrents();
|
||||
}
|
||||
|
||||
bool Session::isDHTEnabled() const
|
||||
@@ -858,9 +867,6 @@ void Session::adjustLimits()
|
||||
void Session::configure()
|
||||
{
|
||||
qDebug("Configuring session");
|
||||
if (!m_deferredConfigureScheduled) return; // Obtaining the lock is expensive, let's check early
|
||||
QWriteLocker locker(&m_lock);
|
||||
if (!m_deferredConfigureScheduled) return; // something might have changed while we were getting the lock
|
||||
#if LIBTORRENT_VERSION_NUM < 10100
|
||||
libt::session_settings sessionSettings = m_nativeSession->settings();
|
||||
configure(sessionSettings);
|
||||
@@ -915,6 +921,10 @@ void Session::configure(libtorrent::settings_pack &settingsPack)
|
||||
{
|
||||
Logger* const logger = Logger::instance();
|
||||
|
||||
#ifdef Q_OS_WIN
|
||||
QString chosenIP;
|
||||
#endif
|
||||
|
||||
if (m_listenInterfaceChanged) {
|
||||
const ushort port = this->port();
|
||||
std::pair<int, int> ports(port, port);
|
||||
@@ -944,10 +954,31 @@ void Session::configure(libtorrent::settings_pack &settingsPack)
|
||||
.arg(ip).arg(port)
|
||||
, Log::INFO);
|
||||
settingsPack.set_str(libt::settings_pack::listen_interfaces, interfacesStr);
|
||||
#ifdef Q_OS_WIN
|
||||
chosenIP = ip;
|
||||
#endif
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
#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.
|
||||
if (!networkInterface().isEmpty()) {
|
||||
QString guid = convertIfaceNameToGuid(networkInterface());
|
||||
if (!guid.isEmpty()) {
|
||||
settingsPack.set_str(libt::settings_pack::outgoing_interfaces, guid.toStdString());
|
||||
}
|
||||
else {
|
||||
settingsPack.set_str(libt::settings_pack::outgoing_interfaces, chosenIP.toStdString());
|
||||
LogMsg(tr("Could not get GUID of configured network interface. Binding to IP %1").arg(chosenIP)
|
||||
, Log::WARNING);
|
||||
}
|
||||
}
|
||||
#else
|
||||
settingsPack.set_str(libt::settings_pack::outgoing_interfaces, networkInterface().toStdString());
|
||||
#endif
|
||||
m_listenInterfaceChanged = false;
|
||||
}
|
||||
|
||||
@@ -1013,8 +1044,8 @@ void Session::configure(libtorrent::settings_pack &settingsPack)
|
||||
settingsPack.set_bool(libt::settings_pack::announce_to_all_trackers, announceToAll);
|
||||
settingsPack.set_bool(libt::settings_pack::announce_to_all_tiers, announceToAll);
|
||||
|
||||
const int cacheSize = diskCacheSize();
|
||||
settingsPack.set_int(libt::settings_pack::cache_size, (cacheSize > 0) ? cacheSize * 64 : -1);
|
||||
const int cacheSize = (diskCacheSize() > -1) ? diskCacheSize() * 64 : -1;
|
||||
settingsPack.set_int(libt::settings_pack::cache_size, cacheSize);
|
||||
settingsPack.set_int(libt::settings_pack::cache_expiry, diskCacheTTL());
|
||||
qDebug() << "Using a disk cache size of" << cacheSize << "MiB";
|
||||
|
||||
@@ -1160,8 +1191,8 @@ void Session::configure(libtorrent::session_settings &sessionSettings)
|
||||
bool announceToAll = announceToAllTrackers();
|
||||
sessionSettings.announce_to_all_trackers = announceToAll;
|
||||
sessionSettings.announce_to_all_tiers = announceToAll;
|
||||
int cacheSize = diskCacheSize();
|
||||
sessionSettings.cache_size = (cacheSize > 0) ? cacheSize * 64 : -1;
|
||||
const int cacheSize = (diskCacheSize() > -1) ? diskCacheSize() * 64 : -1;
|
||||
sessionSettings.cache_size = cacheSize;
|
||||
sessionSettings.cache_expiry = diskCacheTTL();
|
||||
qDebug() << "Using a disk cache size of" << cacheSize << "MiB";
|
||||
libt::session_settings::io_buffer_mode_t mode = useOSCache() ? libt::session_settings::enable_os_cache
|
||||
@@ -1392,7 +1423,14 @@ bool Session::deleteTorrent(const QString &hash, bool deleteLocalFiles)
|
||||
|
||||
// Remove it from session
|
||||
if (deleteLocalFiles) {
|
||||
m_savePathsToRemove[torrent->hash()] = torrent->rootPath(true);
|
||||
if (torrent->savePath(true) == torrentTempPath(torrent->hash())) {
|
||||
m_savePathsToRemove[torrent->hash()] = torrent->savePath(true);
|
||||
}
|
||||
else {
|
||||
QString rootPath = torrent->rootPath(true);
|
||||
if (!rootPath.isEmpty())
|
||||
m_savePathsToRemove[torrent->hash()] = rootPath;
|
||||
}
|
||||
m_nativeSession->remove_torrent(torrent->nativeHandle(), libt::session::delete_files);
|
||||
}
|
||||
else {
|
||||
@@ -1711,35 +1749,19 @@ bool Session::findIncompleteFiles(TorrentInfo &torrentInfo, QString &savePath) c
|
||||
{
|
||||
auto findInDir = [](const QString &dirPath, TorrentInfo &torrentInfo) -> bool
|
||||
{
|
||||
const QDir dir(dirPath);
|
||||
bool found = false;
|
||||
if (torrentInfo.filesCount() == 1) {
|
||||
const QString filePath = dirPath + torrentInfo.filePath(0);
|
||||
if (QFile(filePath).exists()) {
|
||||
for (int i = 0; i < torrentInfo.filesCount(); ++i) {
|
||||
const QString filePath = torrentInfo.filePath(i);
|
||||
if (dir.exists(filePath)) {
|
||||
found = true;
|
||||
}
|
||||
else if (QFile(filePath + QB_EXT).exists()) {
|
||||
else if (dir.exists(filePath + QB_EXT)) {
|
||||
found = true;
|
||||
torrentInfo.renameFile(0, torrentInfo.filePath(0) + QB_EXT);
|
||||
}
|
||||
}
|
||||
else {
|
||||
QSet<QString> allFiles;
|
||||
int dirPathSize = dirPath.size();
|
||||
foreach (const QString &file, findAllFiles(dirPath + torrentInfo.name()))
|
||||
allFiles << file.mid(dirPathSize);
|
||||
for (int i = 0; i < torrentInfo.filesCount(); ++i) {
|
||||
QString filePath = torrentInfo.filePath(i);
|
||||
if (allFiles.contains(filePath)) {
|
||||
found = true;
|
||||
}
|
||||
else {
|
||||
filePath += QB_EXT;
|
||||
if (allFiles.contains(filePath)) {
|
||||
found = true;
|
||||
torrentInfo.renameFile(i, filePath);
|
||||
}
|
||||
}
|
||||
torrentInfo.renameFile(i, filePath + QB_EXT);
|
||||
}
|
||||
if ((i % 100) == 0)
|
||||
qApp->processEvents(QEventLoop::ExcludeUserInputEvents);
|
||||
}
|
||||
|
||||
return found;
|
||||
@@ -2240,10 +2262,10 @@ QString Session::networkInterface() const
|
||||
return m_networkInterface;
|
||||
}
|
||||
|
||||
void Session::setNetworkInterface(const QString &interface)
|
||||
void Session::setNetworkInterface(const QString &iface)
|
||||
{
|
||||
if (interface != networkInterface()) {
|
||||
m_networkInterface = interface;
|
||||
if (iface != networkInterface()) {
|
||||
m_networkInterface = iface;
|
||||
configureListeningInterface();
|
||||
}
|
||||
}
|
||||
@@ -2436,27 +2458,27 @@ void Session::setAnnounceToAllTrackers(bool val)
|
||||
}
|
||||
}
|
||||
|
||||
uint Session::diskCacheSize() const
|
||||
int Session::diskCacheSize() const
|
||||
{
|
||||
uint size = m_diskCacheSize;
|
||||
int size = m_diskCacheSize;
|
||||
// These macros may not be available on compilers other than MSVC and GCC
|
||||
#if defined(__x86_64__) || defined(_M_X64)
|
||||
size = qMin(size, 4096u); // 4GiB
|
||||
size = qMin(size, 4096); // 4GiB
|
||||
#else
|
||||
// When build as 32bit binary, set the maximum at less than 2GB to prevent crashes
|
||||
// allocate 1536MiB and leave 512MiB to the rest of program data in RAM
|
||||
size = qMin(size, 1536u);
|
||||
size = qMin(size, 1536);
|
||||
#endif
|
||||
return size;
|
||||
}
|
||||
|
||||
void Session::setDiskCacheSize(uint size)
|
||||
void Session::setDiskCacheSize(int size)
|
||||
{
|
||||
#if defined(__x86_64__) || defined(_M_X64)
|
||||
size = qMin(size, 4096u); // 4GiB
|
||||
size = qMin(size, 4096); // 4GiB
|
||||
#else
|
||||
// allocate 1536MiB and leave 512MiB to the rest of program data in RAM
|
||||
size = qMin(size, 1536u);
|
||||
size = qMin(size, 1536);
|
||||
#endif
|
||||
if (size != m_diskCacheSize) {
|
||||
m_diskCacheSize = size;
|
||||
@@ -2967,12 +2989,10 @@ void Session::initResumeFolder()
|
||||
|
||||
void Session::configureDeferred()
|
||||
{
|
||||
if (m_deferredConfigureScheduled) return; // Obtaining the lock is expensive, let's check early
|
||||
QWriteLocker locker(&m_lock);
|
||||
if (m_deferredConfigureScheduled) return; // something might have changed while we were getting the lock
|
||||
|
||||
QMetaObject::invokeMethod(this, "configure", Qt::QueuedConnection);
|
||||
m_deferredConfigureScheduled = true;
|
||||
if (!m_deferredConfigureScheduled) {
|
||||
QMetaObject::invokeMethod(this, "configure", Qt::QueuedConnection);
|
||||
m_deferredConfigureScheduled = true;
|
||||
}
|
||||
}
|
||||
|
||||
// Enable IP Filtering
|
||||
@@ -3364,17 +3384,16 @@ void Session::handleTorrentRemovedAlert(libt::torrent_removed_alert *p)
|
||||
|
||||
void Session::handleTorrentDeletedAlert(libt::torrent_deleted_alert *p)
|
||||
{
|
||||
m_savePathsToRemove.remove(p->info_hash);
|
||||
const QString path = m_savePathsToRemove.take(p->info_hash);
|
||||
if (path == torrentTempPath(p->info_hash))
|
||||
Utils::Fs::smartRemoveEmptyFolderTree(path);
|
||||
}
|
||||
|
||||
void Session::handleTorrentDeleteFailedAlert(libt::torrent_delete_failed_alert *p)
|
||||
{
|
||||
// libtorrent won't delete the directory if it contains files not listed in the torrent,
|
||||
// so we remove the directory ourselves
|
||||
if (m_savePathsToRemove.contains(p->info_hash)) {
|
||||
QString path = m_savePathsToRemove.take(p->info_hash);
|
||||
Utils::Fs::smartRemoveEmptyFolderTree(path);
|
||||
}
|
||||
Utils::Fs::smartRemoveEmptyFolderTree(m_savePathsToRemove.take(p->info_hash));
|
||||
}
|
||||
|
||||
void Session::handleMetadataReceivedAlert(libt::metadata_received_alert *p)
|
||||
@@ -3628,4 +3647,32 @@ namespace
|
||||
qDebug() << Q_FUNC_INFO << " fails: " << exc.what();
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef Q_OS_WIN
|
||||
QString convertIfaceNameToGuid(const QString &name)
|
||||
{
|
||||
// Under Windows XP or on Qt version <= 5.5 'name' will be a GUID already.
|
||||
QUuid uuid(name);
|
||||
if (!uuid.isNull())
|
||||
return uuid.toString().toUpper(); // Libtorrent expects the GUID in uppercase
|
||||
|
||||
using PCONVERTIFACENAMETOLUID = NETIO_STATUS (WINAPI *)(const WCHAR *, PNET_LUID);
|
||||
PCONVERTIFACENAMETOLUID ConvertIfaceNameToLuid = reinterpret_cast<PCONVERTIFACENAMETOLUID>(::GetProcAddress(::GetModuleHandleW(L"Iphlpapi.dll"), "ConvertInterfaceNameToLuidW"));
|
||||
if (!ConvertIfaceNameToLuid) return QString();
|
||||
|
||||
using PCONVERTIFACELUIDTOGUID = NETIO_STATUS (WINAPI *)(const NET_LUID *, GUID *);
|
||||
PCONVERTIFACELUIDTOGUID ConvertIfaceLuidToGuid = reinterpret_cast<PCONVERTIFACELUIDTOGUID>(::GetProcAddress(::GetModuleHandleW(L"Iphlpapi.dll"), "ConvertInterfaceLuidToGuid"));
|
||||
if (!ConvertIfaceLuidToGuid) return QString();
|
||||
|
||||
NET_LUID luid;
|
||||
LONG res = ConvertIfaceNameToLuid(name.toStdWString().c_str(), &luid);
|
||||
if (res == 0) {
|
||||
GUID guid;
|
||||
if (ConvertIfaceLuidToGuid(&luid, &guid) == 0)
|
||||
return QUuid(guid).toString().toUpper();
|
||||
}
|
||||
|
||||
return QString();
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
@@ -41,7 +41,6 @@
|
||||
#endif
|
||||
#include <QNetworkConfigurationManager>
|
||||
#include <QPointer>
|
||||
#include <QReadWriteLock>
|
||||
#include <QStringList>
|
||||
#include <QVector>
|
||||
#include <QWaitCondition>
|
||||
@@ -280,8 +279,8 @@ namespace BitTorrent
|
||||
void setIPFilterFile(QString path);
|
||||
bool announceToAllTrackers() const;
|
||||
void setAnnounceToAllTrackers(bool val);
|
||||
uint diskCacheSize() const;
|
||||
void setDiskCacheSize(uint size);
|
||||
int diskCacheSize() const;
|
||||
void setDiskCacheSize(int size);
|
||||
uint diskCacheTTL() const;
|
||||
void setDiskCacheTTL(uint ttl);
|
||||
bool useOSCache() const;
|
||||
@@ -327,6 +326,7 @@ namespace BitTorrent
|
||||
bool isTrackerFilteringEnabled() const;
|
||||
void setTrackerFilteringEnabled(bool enabled);
|
||||
|
||||
void startUpTorrents();
|
||||
TorrentHandle *findTorrent(const InfoHash &hash) const;
|
||||
QHash<InfoHash, TorrentHandle *> torrents() const;
|
||||
TorrentStatusReport torrentStatusReport() const;
|
||||
@@ -457,7 +457,6 @@ namespace BitTorrent
|
||||
void enableIPFilter();
|
||||
void disableIPFilter();
|
||||
|
||||
void startUpTorrents();
|
||||
bool addTorrent_impl(AddTorrentData addData, const MagnetUri &magnetUri,
|
||||
TorrentInfo torrentInfo = TorrentInfo(),
|
||||
const QByteArray &fastresumeData = QByteArray());
|
||||
@@ -509,7 +508,7 @@ namespace BitTorrent
|
||||
CachedSettingValue<bool> m_isTrackerFilteringEnabled;
|
||||
CachedSettingValue<QString> m_IPFilterFile;
|
||||
CachedSettingValue<bool> m_announceToAllTrackers;
|
||||
CachedSettingValue<uint> m_diskCacheSize;
|
||||
CachedSettingValue<int> m_diskCacheSize;
|
||||
CachedSettingValue<uint> m_diskCacheTTL;
|
||||
CachedSettingValue<bool> m_useOSCache;
|
||||
CachedSettingValue<bool> m_isAnonymousModeEnabled;
|
||||
@@ -610,8 +609,6 @@ namespace BitTorrent
|
||||
|
||||
QNetworkConfigurationManager m_networkManager;
|
||||
|
||||
mutable QReadWriteLock m_lock;
|
||||
|
||||
static Session *m_instance;
|
||||
};
|
||||
}
|
||||
|
||||
@@ -1330,6 +1330,10 @@ void TorrentHandle::handleStorageMovedAlert(libtorrent::storage_moved_alert *p)
|
||||
}
|
||||
|
||||
qDebug("Torrent is successfully moved from %s to %s", qPrintable(m_oldPath), qPrintable(m_newPath));
|
||||
if (QDir(m_oldPath) == QDir(m_session->torrentTempPath(hash()))) {
|
||||
qDebug() << "Removing torrent temp folder:" << m_oldPath;
|
||||
Utils::Fs::smartRemoveEmptyFolderTree(m_oldPath);
|
||||
}
|
||||
updateStatus();
|
||||
|
||||
m_newPath.clear();
|
||||
|
||||
@@ -246,6 +246,21 @@ QVector<int> TorrentInfo::fileIndicesForPiece(int pieceIndex) const
|
||||
return res;
|
||||
}
|
||||
|
||||
QVector<QByteArray> TorrentInfo::pieceHashes() const
|
||||
{
|
||||
if (!isValid())
|
||||
return {};
|
||||
|
||||
const int count = piecesCount();
|
||||
QVector<QByteArray> hashes;
|
||||
hashes.reserve(count);
|
||||
|
||||
for (int i = 0; i < count; ++i)
|
||||
hashes += { m_nativeInfo->hash_for_piece_ptr(i), libtorrent::sha1_hash::size };
|
||||
|
||||
return hashes;
|
||||
}
|
||||
|
||||
TorrentInfo::PieceRange TorrentInfo::filePieces(const QString& file) const
|
||||
{
|
||||
if (!isValid()) // if we do not check here the debug message will be printed, which would be not correct
|
||||
|
||||
@@ -91,6 +91,7 @@ namespace BitTorrent
|
||||
QByteArray metadata() const;
|
||||
QStringList filesForPiece(int pieceIndex) const;
|
||||
QVector<int> fileIndicesForPiece(int pieceIndex) const;
|
||||
QVector<QByteArray> pieceHashes() const;
|
||||
|
||||
using PieceRange = IndexRange<int>;
|
||||
// returns pair of the first and the last pieces into which
|
||||
|
||||
@@ -29,14 +29,17 @@
|
||||
* Contact : chris@qbittorrent.org
|
||||
*/
|
||||
|
||||
#include <QTcpSocket>
|
||||
#include <QDebug>
|
||||
#include "connection.h"
|
||||
|
||||
#include <QRegExp>
|
||||
#include "types.h"
|
||||
#ifndef QBT_USES_QT5
|
||||
#include <QStringList>
|
||||
#endif
|
||||
#include <QTcpSocket>
|
||||
|
||||
#include "irequesthandler.h"
|
||||
#include "requestparser.h"
|
||||
#include "responsegenerator.h"
|
||||
#include "irequesthandler.h"
|
||||
#include "connection.h"
|
||||
|
||||
using namespace Http;
|
||||
|
||||
@@ -46,53 +49,103 @@ Connection::Connection(QTcpSocket *socket, IRequestHandler *requestHandler, QObj
|
||||
, m_requestHandler(requestHandler)
|
||||
{
|
||||
m_socket->setParent(this);
|
||||
m_idleTimer.start();
|
||||
connect(m_socket, SIGNAL(readyRead()), SLOT(read()));
|
||||
connect(m_socket, SIGNAL(disconnected()), SLOT(deleteLater()));
|
||||
}
|
||||
|
||||
Connection::~Connection()
|
||||
{
|
||||
m_socket->close();
|
||||
}
|
||||
|
||||
void Connection::read()
|
||||
{
|
||||
m_receivedData.append(m_socket->readAll());
|
||||
m_idleTimer.restart();
|
||||
|
||||
m_receivedData.append(m_socket->readAll());
|
||||
Request request;
|
||||
RequestParser::ErrorCode err = RequestParser::parse(m_receivedData, request);
|
||||
RequestParser::ErrorCode err = RequestParser::parse(m_receivedData, request); // TODO: transform request headers to lowercase
|
||||
|
||||
switch (err) {
|
||||
case RequestParser::IncompleteRequest:
|
||||
// Partial request waiting for the rest
|
||||
break;
|
||||
|
||||
case RequestParser::BadRequest:
|
||||
sendResponse(Response(400, "Bad Request"));
|
||||
m_receivedData.clear();
|
||||
break;
|
||||
|
||||
case RequestParser::NoError:
|
||||
Environment env;
|
||||
env.clientAddress = m_socket->peerAddress();
|
||||
const Environment env {m_socket->localAddress(), m_socket->localPort(), m_socket->peerAddress(), m_socket->peerPort()};
|
||||
|
||||
Response response = m_requestHandler->processRequest(request, env);
|
||||
if (acceptsGzipEncoding(request.headers["accept-encoding"]))
|
||||
response.headers[HEADER_CONTENT_ENCODING] = "gzip";
|
||||
sendResponse(response);
|
||||
m_receivedData.clear();
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void Connection::sendResponse(const Response &response)
|
||||
{
|
||||
m_socket->write(ResponseGenerator::generate(response));
|
||||
m_socket->disconnectFromHost();
|
||||
m_socket->write(toByteArray(response));
|
||||
m_socket->close(); // TODO: remove when HTTP pipelining is supported
|
||||
}
|
||||
|
||||
bool Connection::acceptsGzipEncoding(const QString &encoding)
|
||||
bool Connection::hasExpired(const qint64 timeout) const
|
||||
{
|
||||
QRegExp rx("(gzip)(;q=([^,]+))?");
|
||||
if (rx.indexIn(encoding) >= 0) {
|
||||
if (rx.cap(2).size() > 0)
|
||||
// check if quality factor > 0
|
||||
return (rx.cap(3).toDouble() > 0);
|
||||
// if quality factor is not specified, then it's 1
|
||||
return m_idleTimer.hasExpired(timeout);
|
||||
}
|
||||
|
||||
bool Connection::isClosed() const
|
||||
{
|
||||
return (m_socket->state() == QAbstractSocket::UnconnectedState);
|
||||
}
|
||||
|
||||
bool Connection::acceptsGzipEncoding(QString codings)
|
||||
{
|
||||
// [rfc7231] 5.3.4. Accept-Encoding
|
||||
|
||||
const auto isCodingAvailable = [](const QStringList &list, const QString &encoding) -> bool
|
||||
{
|
||||
for (const QString &str: list) {
|
||||
if (!str.startsWith(encoding))
|
||||
continue;
|
||||
|
||||
// without quality values
|
||||
if (str == encoding)
|
||||
return true;
|
||||
|
||||
// [rfc7231] 5.3.1. Quality Values
|
||||
#ifdef QBT_USES_QT5
|
||||
const QStringRef substr = str.midRef(encoding.size() + 3); // ex. skip over "gzip;q="
|
||||
#else
|
||||
const QString substr = str.mid(encoding.size() + 3); // ex. skip over "gzip;q="
|
||||
#endif
|
||||
|
||||
bool ok = false;
|
||||
const double qvalue = substr.toDouble(&ok);
|
||||
if (!ok || (qvalue <= 0.0))
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
};
|
||||
|
||||
const QStringList list = codings.remove(' ').remove('\t').split(',', QString::SkipEmptyParts);
|
||||
if (list.isEmpty())
|
||||
return false;
|
||||
|
||||
const bool canGzip = isCodingAvailable(list, QLatin1String("gzip"));
|
||||
if (canGzip)
|
||||
return true;
|
||||
}
|
||||
|
||||
const bool canAny = isCodingAvailable(list, QLatin1String("*"));
|
||||
if (canAny)
|
||||
return true;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -33,12 +33,12 @@
|
||||
#ifndef HTTP_CONNECTION_H
|
||||
#define HTTP_CONNECTION_H
|
||||
|
||||
#include <QElapsedTimer>
|
||||
#include <QObject>
|
||||
|
||||
#include "types.h"
|
||||
|
||||
QT_BEGIN_NAMESPACE
|
||||
class QTcpSocket;
|
||||
QT_END_NAMESPACE
|
||||
|
||||
namespace Http
|
||||
{
|
||||
@@ -53,16 +53,20 @@ namespace Http
|
||||
Connection(QTcpSocket *socket, IRequestHandler *requestHandler, QObject *parent = 0);
|
||||
~Connection();
|
||||
|
||||
bool hasExpired(qint64 timeout) const;
|
||||
bool isClosed() const;
|
||||
|
||||
private slots:
|
||||
void read();
|
||||
|
||||
private:
|
||||
static bool acceptsGzipEncoding(const QString &encoding);
|
||||
static bool acceptsGzipEncoding(QString codings);
|
||||
void sendResponse(const Response &response);
|
||||
|
||||
QTcpSocket *m_socket;
|
||||
IRequestHandler *m_requestHandler;
|
||||
QByteArray m_receivedData;
|
||||
QElapsedTimer m_idleTimer;
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
@@ -198,14 +198,14 @@ QList<QByteArray> RequestParser::splitMultipartData(const QByteArray& data, cons
|
||||
start = end + sepLength; // skip first boundary
|
||||
|
||||
while ((end = data.indexOf(sep, start)) >= 0) {
|
||||
ret << data.mid(start, end - start);
|
||||
ret << data.mid(start, end - EOL.length() - start);
|
||||
start = end + sepLength;
|
||||
}
|
||||
|
||||
// last or single part
|
||||
sep = boundary + "--" + EOL;
|
||||
if ((end = data.indexOf(sep, start)) >= 0)
|
||||
ret << data.mid(start, end - start);
|
||||
ret << data.mid(start, end - EOL.length() - start);
|
||||
}
|
||||
|
||||
return ret;
|
||||
|
||||
@@ -29,39 +29,82 @@
|
||||
* Contact : chris@qbittorrent.org
|
||||
*/
|
||||
|
||||
#include "base/utils/gzip.h"
|
||||
#include "responsegenerator.h"
|
||||
|
||||
using namespace Http;
|
||||
#include <QDateTime>
|
||||
#ifndef QBT_USES_QT5
|
||||
#include <QLocale>
|
||||
#endif
|
||||
|
||||
QByteArray ResponseGenerator::generate(Response response)
|
||||
#include "base/utils/gzip.h"
|
||||
|
||||
QByteArray Http::toByteArray(Response response)
|
||||
{
|
||||
if (response.headers[HEADER_CONTENT_ENCODING] == "gzip") {
|
||||
// A gzip seems to have 23 bytes overhead.
|
||||
// Also "Content-Encoding: gzip\r\n" is 26 bytes long
|
||||
// So we only benefit from gzip if the message is bigger than 23+26 = 49
|
||||
// If the message is smaller than 49 bytes we actually send MORE data if we gzip
|
||||
QByteArray dest_buf;
|
||||
if ((response.content.size() > 49) && (Utils::Gzip::compress(response.content, dest_buf)))
|
||||
response.content = dest_buf;
|
||||
else
|
||||
response.headers.remove(HEADER_CONTENT_ENCODING);
|
||||
}
|
||||
compressContent(response);
|
||||
|
||||
if (response.content.length() > 0)
|
||||
response.headers[HEADER_CONTENT_LENGTH] = QString::number(response.content.length());
|
||||
response.headers[HEADER_CONTENT_LENGTH] = QString::number(response.content.length());
|
||||
response.headers[HEADER_DATE] = httpDate();
|
||||
|
||||
QString ret(QLatin1String("HTTP/1.1 %1 %2\r\n%3\r\n"));
|
||||
QByteArray buf;
|
||||
buf.reserve(10 * 1024);
|
||||
|
||||
QString header;
|
||||
foreach (const QString& key, response.headers.keys())
|
||||
header += QString("%1: %2\r\n").arg(key).arg(response.headers[key]);
|
||||
// Status Line
|
||||
buf += QString("HTTP/%1 %2 %3")
|
||||
.arg("1.1", // TODO: depends on request
|
||||
QString::number(response.status.code),
|
||||
response.status.text)
|
||||
.toLatin1()
|
||||
.append(CRLF);
|
||||
|
||||
ret = ret.arg(response.status.code).arg(response.status.text).arg(header);
|
||||
// Header Fields
|
||||
for (auto i = response.headers.constBegin(); i != response.headers.constEnd(); ++i)
|
||||
buf += QString("%1: %2").arg(i.key(), i.value()).toLatin1().append(CRLF);
|
||||
|
||||
// qDebug() << Q_FUNC_INFO;
|
||||
// qDebug() << "HTTP Response header:";
|
||||
// qDebug() << ret;
|
||||
// the first empty line
|
||||
buf += CRLF;
|
||||
|
||||
return ret.toUtf8() + response.content;
|
||||
// message body // TODO: support HEAD request
|
||||
buf += response.content;
|
||||
|
||||
return buf;
|
||||
}
|
||||
|
||||
QString Http::httpDate()
|
||||
{
|
||||
// [RFC 7231] 7.1.1.1. Date/Time Formats
|
||||
// example: "Sun, 06 Nov 1994 08:49:37 GMT"
|
||||
|
||||
return QLocale::c().toString(QDateTime::currentDateTimeUtc(), QLatin1String("ddd, dd MMM yyyy HH:mm:ss"))
|
||||
.append(QLatin1String(" GMT"));
|
||||
}
|
||||
|
||||
void Http::compressContent(Response &response)
|
||||
{
|
||||
if (response.headers.value(HEADER_CONTENT_ENCODING) != QLatin1String("gzip"))
|
||||
return;
|
||||
|
||||
response.headers.remove(HEADER_CONTENT_ENCODING);
|
||||
|
||||
// for very small files, compressing them only wastes cpu cycles
|
||||
const int contentSize = response.content.size();
|
||||
if (contentSize <= 1024) // 1 kb
|
||||
return;
|
||||
|
||||
// filter out known hard-to-compress types
|
||||
const QString contentType = response.headers[HEADER_CONTENT_TYPE];
|
||||
if ((contentType == CONTENT_TYPE_GIF) || (contentType == CONTENT_TYPE_PNG))
|
||||
return;
|
||||
|
||||
// try compressing
|
||||
bool ok = false;
|
||||
const QByteArray compressedData = Utils::Gzip::compress(response.content, 6, &ok);
|
||||
if (!ok)
|
||||
return;
|
||||
|
||||
// "Content-Encoding: gzip\r\n" is 24 bytes long
|
||||
if ((compressedData.size() + 24) >= contentSize)
|
||||
return;
|
||||
|
||||
response.content = compressedData;
|
||||
response.headers[HEADER_CONTENT_ENCODING] = QLatin1String("gzip");
|
||||
}
|
||||
|
||||
@@ -37,11 +37,9 @@
|
||||
|
||||
namespace Http
|
||||
{
|
||||
class ResponseGenerator
|
||||
{
|
||||
public:
|
||||
static QByteArray generate(Response response);
|
||||
};
|
||||
QByteArray toByteArray(Response response);
|
||||
QString httpDate();
|
||||
void compressContent(Response &response);
|
||||
}
|
||||
|
||||
#endif // HTTP_RESPONSEGENERATOR_H
|
||||
|
||||
@@ -30,8 +30,10 @@
|
||||
|
||||
#include "server.h"
|
||||
|
||||
#include <QMutableListIterator>
|
||||
#include <QNetworkProxy>
|
||||
#include <QStringList>
|
||||
#include <QTimer>
|
||||
|
||||
#ifndef QT_NO_OPENSSL
|
||||
#include <QSslSocket>
|
||||
@@ -41,6 +43,10 @@
|
||||
|
||||
#include "connection.h"
|
||||
|
||||
static const int KEEP_ALIVE_DURATION = 7 * 1000; // milliseconds
|
||||
static const int CONNECTIONS_LIMIT = 500;
|
||||
static const int CONNECTIONS_SCAN_INTERVAL = 2; // seconds
|
||||
|
||||
using namespace Http;
|
||||
|
||||
Server::Server(IRequestHandler *requestHandler, QObject *parent)
|
||||
@@ -54,34 +60,24 @@ Server::Server(IRequestHandler *requestHandler, QObject *parent)
|
||||
#ifndef QT_NO_OPENSSL
|
||||
QSslSocket::setDefaultCiphers(safeCipherList());
|
||||
#endif
|
||||
|
||||
QTimer *dropConnectionTimer = new QTimer(this);
|
||||
connect(dropConnectionTimer, SIGNAL(timeout()), SLOT(dropTimedOutConnection()));
|
||||
dropConnectionTimer->start(CONNECTIONS_SCAN_INTERVAL * 1000);
|
||||
}
|
||||
|
||||
Server::~Server()
|
||||
{
|
||||
}
|
||||
|
||||
#ifndef QT_NO_OPENSSL
|
||||
void Server::enableHttps(const QList<QSslCertificate> &certificates, const QSslKey &key)
|
||||
{
|
||||
m_certificates = certificates;
|
||||
m_key = key;
|
||||
m_https = true;
|
||||
}
|
||||
|
||||
void Server::disableHttps()
|
||||
{
|
||||
m_https = false;
|
||||
m_certificates.clear();
|
||||
m_key.clear();
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef QBT_USES_QT5
|
||||
void Server::incomingConnection(qintptr socketDescriptor)
|
||||
#else
|
||||
void Server::incomingConnection(int socketDescriptor)
|
||||
#endif
|
||||
{
|
||||
if (m_connections.size() >= CONNECTIONS_LIMIT) return;
|
||||
|
||||
QTcpSocket *serverSocket;
|
||||
#ifndef QT_NO_OPENSSL
|
||||
if (m_https)
|
||||
@@ -90,28 +86,79 @@ void Server::incomingConnection(int socketDescriptor)
|
||||
#endif
|
||||
serverSocket = new QTcpSocket(this);
|
||||
|
||||
if (serverSocket->setSocketDescriptor(socketDescriptor)) {
|
||||
#ifndef QT_NO_OPENSSL
|
||||
if (m_https) {
|
||||
static_cast<QSslSocket *>(serverSocket)->setProtocol(QSsl::SecureProtocols);
|
||||
static_cast<QSslSocket *>(serverSocket)->setPrivateKey(m_key);
|
||||
#ifdef QBT_USES_QT5
|
||||
static_cast<QSslSocket *>(serverSocket)->setLocalCertificateChain(m_certificates);
|
||||
#else
|
||||
static_cast<QSslSocket *>(serverSocket)->setLocalCertificate(m_certificates.first());
|
||||
#endif
|
||||
static_cast<QSslSocket *>(serverSocket)->setPeerVerifyMode(QSslSocket::VerifyNone);
|
||||
static_cast<QSslSocket *>(serverSocket)->startServerEncryption();
|
||||
}
|
||||
#endif
|
||||
new Connection(serverSocket, m_requestHandler, this);
|
||||
if (!serverSocket->setSocketDescriptor(socketDescriptor)) {
|
||||
delete serverSocket;
|
||||
return;
|
||||
}
|
||||
else {
|
||||
serverSocket->deleteLater();
|
||||
|
||||
#ifndef QT_NO_OPENSSL
|
||||
if (m_https) {
|
||||
static_cast<QSslSocket *>(serverSocket)->setProtocol(QSsl::SecureProtocols);
|
||||
static_cast<QSslSocket *>(serverSocket)->setPrivateKey(m_key);
|
||||
#ifdef QBT_USES_QT5
|
||||
static_cast<QSslSocket *>(serverSocket)->setLocalCertificateChain(m_certificates);
|
||||
#else
|
||||
static_cast<QSslSocket *>(serverSocket)->setLocalCertificate(m_certificates.first());
|
||||
#endif
|
||||
static_cast<QSslSocket *>(serverSocket)->setPeerVerifyMode(QSslSocket::VerifyNone);
|
||||
static_cast<QSslSocket *>(serverSocket)->startServerEncryption();
|
||||
}
|
||||
#endif
|
||||
|
||||
Connection *c = new Connection(serverSocket, m_requestHandler, this);
|
||||
m_connections.append(c);
|
||||
}
|
||||
|
||||
void Server::dropTimedOutConnection()
|
||||
{
|
||||
QMutableListIterator<Connection *> i(m_connections);
|
||||
while (i.hasNext()) {
|
||||
auto connection = i.next();
|
||||
if (connection->isClosed() || connection->hasExpired(KEEP_ALIVE_DURATION)) {
|
||||
delete connection;
|
||||
i.remove();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#ifndef QT_NO_OPENSSL
|
||||
bool Server::setupHttps(const QByteArray &certificates, const QByteArray &key)
|
||||
{
|
||||
QSslKey sslKey(key, QSsl::Rsa);
|
||||
if (sslKey.isNull())
|
||||
#if QT_VERSION >= QT_VERSION_CHECK(5, 5, 0)
|
||||
sslKey = QSslKey(key, QSsl::Ec);
|
||||
#else
|
||||
{
|
||||
disableHttps();
|
||||
return false;
|
||||
}
|
||||
#endif
|
||||
|
||||
const QList<QSslCertificate> certs = QSslCertificate::fromData(certificates);
|
||||
const bool areCertsValid = !certs.empty() && std::all_of(certs.begin(), certs.end(), [](const QSslCertificate &c) { return !c.isNull(); });
|
||||
|
||||
if (!sslKey.isNull() && areCertsValid)
|
||||
{
|
||||
m_key = sslKey;
|
||||
m_certificates = certs;
|
||||
m_https = true;
|
||||
return true;
|
||||
}
|
||||
else
|
||||
{
|
||||
disableHttps();
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
void Server::disableHttps()
|
||||
{
|
||||
m_https = false;
|
||||
m_certificates.clear();
|
||||
m_key.clear();
|
||||
}
|
||||
|
||||
QList<QSslCipher> Server::safeCipherList() const
|
||||
{
|
||||
const QStringList badCiphers = {"idea", "rc4"};
|
||||
|
||||
@@ -34,6 +34,7 @@
|
||||
#define HTTP_SERVER_H
|
||||
|
||||
#include <QTcpServer>
|
||||
|
||||
#ifndef QT_NO_OPENSSL
|
||||
#include <QSslCertificate>
|
||||
#include <QSslCipher>
|
||||
@@ -55,19 +56,23 @@ namespace Http
|
||||
~Server();
|
||||
|
||||
#ifndef QT_NO_OPENSSL
|
||||
void enableHttps(const QList<QSslCertificate> &certificates, const QSslKey &key);
|
||||
bool setupHttps(const QByteArray &certificates, const QByteArray &key);
|
||||
void disableHttps();
|
||||
#endif
|
||||
|
||||
private:
|
||||
IRequestHandler *m_requestHandler;
|
||||
private slots:
|
||||
void dropTimedOutConnection();
|
||||
|
||||
private:
|
||||
#ifdef QBT_USES_QT5
|
||||
void incomingConnection(qintptr socketDescriptor);
|
||||
#else
|
||||
void incomingConnection(int socketDescriptor);
|
||||
#endif
|
||||
|
||||
IRequestHandler *m_requestHandler;
|
||||
QList<Connection *> m_connections; // for tracking persistence connections
|
||||
|
||||
#ifndef QT_NO_OPENSSL
|
||||
QList<QSslCipher> safeCipherList() const;
|
||||
|
||||
|
||||
@@ -29,36 +29,47 @@
|
||||
#ifndef HTTP_TYPES_H
|
||||
#define HTTP_TYPES_H
|
||||
|
||||
#include <QString>
|
||||
#include <QMap>
|
||||
#include <QHostAddress>
|
||||
#include <QString>
|
||||
#include <QVector>
|
||||
|
||||
#include "base/types.h"
|
||||
|
||||
namespace Http
|
||||
{
|
||||
const QString HEADER_SET_COOKIE = "Set-Cookie";
|
||||
const QString HEADER_CONTENT_TYPE = "Content-Type";
|
||||
const QString HEADER_CONTENT_ENCODING = "Content-Encoding";
|
||||
const QString HEADER_CONTENT_LENGTH = "Content-Length";
|
||||
const QString HEADER_CACHE_CONTROL = "Cache-Control";
|
||||
const QString HEADER_X_FRAME_OPTIONS = "X-Frame-Options";
|
||||
const QString HEADER_X_XSS_PROTECTION = "X-XSS-Protection";
|
||||
const QString HEADER_X_CONTENT_TYPE_OPTIONS = "X-Content-Type-Options";
|
||||
const QString HEADER_CONTENT_SECURITY_POLICY = "Content-Security-Policy";
|
||||
const char HEADER_CACHE_CONTROL[] = "cache-control";
|
||||
const char HEADER_CONTENT_ENCODING[] = "content-encoding";
|
||||
const char HEADER_CONTENT_LENGTH[] = "content-length";
|
||||
const char HEADER_CONTENT_SECURITY_POLICY[] = "content-security-policy";
|
||||
const char HEADER_CONTENT_TYPE[] = "content-type";
|
||||
const char HEADER_DATE[] = "date";
|
||||
const char HEADER_HOST[] = "host";
|
||||
const char HEADER_ORIGIN[] = "origin";
|
||||
const char HEADER_REFERER[] = "referer";
|
||||
const char HEADER_SET_COOKIE[] = "set-cookie";
|
||||
const char HEADER_X_CONTENT_TYPE_OPTIONS[] = "x-content-type-options";
|
||||
const char HEADER_X_FORWARDED_HOST[] = "x-forwarded-host";
|
||||
const char HEADER_X_FRAME_OPTIONS[] = "x-frame-options";
|
||||
const char HEADER_X_XSS_PROTECTION[] = "x-xss-protection";
|
||||
|
||||
const QString CONTENT_TYPE_CSS = "text/css; charset=UTF-8";
|
||||
const QString CONTENT_TYPE_GIF = "image/gif";
|
||||
const QString CONTENT_TYPE_HTML = "text/html; charset=UTF-8";
|
||||
const QString CONTENT_TYPE_JS = "application/javascript; charset=UTF-8";
|
||||
const QString CONTENT_TYPE_JSON = "application/json";
|
||||
const QString CONTENT_TYPE_PNG = "image/png";
|
||||
const QString CONTENT_TYPE_TXT = "text/plain; charset=UTF-8";
|
||||
const char CONTENT_TYPE_CSS[] = "text/css; charset=UTF-8";
|
||||
const char CONTENT_TYPE_GIF[] = "image/gif";
|
||||
const char CONTENT_TYPE_HTML[] = "text/html; charset=UTF-8";
|
||||
const char CONTENT_TYPE_JS[] = "application/javascript; charset=UTF-8";
|
||||
const char CONTENT_TYPE_JSON[] = "application/json";
|
||||
const char CONTENT_TYPE_PNG[] = "image/png";
|
||||
const char CONTENT_TYPE_TXT[] = "text/plain; charset=UTF-8";
|
||||
|
||||
// portability: "\r\n" doesn't guarantee mapping to the correct value
|
||||
const char CRLF[] = {0x0D, 0x0A, '\0'};
|
||||
|
||||
struct Environment
|
||||
{
|
||||
QHostAddress localAddress;
|
||||
quint16 localPort;
|
||||
|
||||
QHostAddress clientAddress;
|
||||
quint16 clientPort;
|
||||
};
|
||||
|
||||
struct UploadedFile
|
||||
|
||||
@@ -92,8 +92,8 @@ void DownloadHandler::processFinishedDownload()
|
||||
// Success
|
||||
QByteArray replyData = m_reply->readAll();
|
||||
if (m_reply->rawHeader("Content-Encoding") == "gzip") {
|
||||
// uncompress gzip reply
|
||||
Utils::Gzip::uncompress(replyData, replyData);
|
||||
// decompress gzip reply
|
||||
replyData = Utils::Gzip::decompress(replyData);
|
||||
}
|
||||
|
||||
if (m_saveToFile) {
|
||||
|
||||
@@ -415,8 +415,10 @@ void GeoIPManager::downloadFinished(const QString &url, QByteArray data)
|
||||
{
|
||||
Q_UNUSED(url);
|
||||
|
||||
if (!Utils::Gzip::uncompress(data, data)) {
|
||||
Logger::instance()->addMessage(tr("Could not uncompress GeoIP database file."), Log::WARNING);
|
||||
bool ok = false;
|
||||
data = Utils::Gzip::decompress(data, &ok);
|
||||
if (!ok) {
|
||||
Logger::instance()->addMessage(tr("Could not decompress GeoIP database file."), Log::WARNING);
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
@@ -96,7 +96,7 @@ private:
|
||||
// Search data
|
||||
mutable QHash<quint32, QString> m_countries;
|
||||
quint32 m_size;
|
||||
const uchar *m_data;
|
||||
uchar *m_data;
|
||||
};
|
||||
|
||||
#endif // GEOIPDATABASE_H
|
||||
|
||||
@@ -528,7 +528,8 @@ QString Smtp::getCurrentDateTime() const
|
||||
int timeOffsetHour = nowDateTime.secsTo(tmp) / 3600;
|
||||
int timeOffsetMin = nowDateTime.secsTo(tmp) / 60 - (60 * timeOffsetHour);
|
||||
int timeOffset = timeOffsetHour * 100 + timeOffsetMin;
|
||||
char buf[6] = {0};
|
||||
// buf size = 11 to avoid format truncation warnings from snprintf
|
||||
char buf[11] = {0};
|
||||
std::snprintf(buf, sizeof(buf), "%+05d", timeOffset);
|
||||
QString timeOffsetStr = buf;
|
||||
|
||||
|
||||
@@ -439,6 +439,16 @@ void Preferences::setWebUiLocalAuthEnabled(bool enabled)
|
||||
setValue("Preferences/WebUI/LocalHostAuth", enabled);
|
||||
}
|
||||
|
||||
QString Preferences::getServerDomains() const
|
||||
{
|
||||
return value("Preferences/WebUI/ServerDomains", "*").toString();
|
||||
}
|
||||
|
||||
void Preferences::setServerDomains(const QString &str)
|
||||
{
|
||||
setValue("Preferences/WebUI/ServerDomains", str);
|
||||
}
|
||||
|
||||
quint16 Preferences::getWebUiPort() const
|
||||
{
|
||||
return value("Preferences/WebUI/Port", 8080).toInt();
|
||||
|
||||
@@ -175,6 +175,8 @@ public:
|
||||
void setWebUiEnabled(bool enabled);
|
||||
bool isWebUiLocalAuthEnabled() const;
|
||||
void setWebUiLocalAuthEnabled(bool enabled);
|
||||
QString getServerDomains() const;
|
||||
void setServerDomains(const QString &str);
|
||||
quint16 getWebUiPort() const;
|
||||
void setWebUiPort(quint16 port);
|
||||
bool useUPnPForWebUIPort() const;
|
||||
|
||||
@@ -40,8 +40,15 @@ class CachedSettingValue
|
||||
using ProxyFunc = std::function<T (const T&)>;
|
||||
|
||||
public:
|
||||
explicit CachedSettingValue(const char *keyName, const T &defaultValue = T()
|
||||
, ProxyFunc proxyFunc = [](const T &value) { return value; })
|
||||
explicit CachedSettingValue(const char *keyName, const T &defaultValue = T())
|
||||
: m_keyName(QLatin1String(keyName))
|
||||
, m_value(SettingsStorage::instance()->loadValue(
|
||||
m_keyName, defaultValue).template value<T>())
|
||||
{
|
||||
}
|
||||
|
||||
explicit CachedSettingValue(const char *keyName, const T &defaultValue
|
||||
, const ProxyFunc &proxyFunc)
|
||||
: m_keyName(QLatin1String(keyName))
|
||||
, m_value(proxyFunc(SettingsStorage::instance()->loadValue(
|
||||
m_keyName, defaultValue).template value<T>()))
|
||||
@@ -53,6 +60,11 @@ public:
|
||||
return m_value;
|
||||
}
|
||||
|
||||
operator T() const
|
||||
{
|
||||
return value();
|
||||
}
|
||||
|
||||
CachedSettingValue<T> &operator=(const T &newValue)
|
||||
{
|
||||
m_value = newValue;
|
||||
@@ -60,11 +72,6 @@ public:
|
||||
return *this;
|
||||
}
|
||||
|
||||
operator T() const
|
||||
{
|
||||
return value();
|
||||
}
|
||||
|
||||
private:
|
||||
const QString m_keyName;
|
||||
T m_value;
|
||||
|
||||
@@ -119,7 +119,7 @@ QString Utils::Fs::folderName(const QString& file_path)
|
||||
*/
|
||||
bool Utils::Fs::smartRemoveEmptyFolderTree(const QString& path)
|
||||
{
|
||||
if (!QDir(path).exists())
|
||||
if (path.isEmpty() || !QDir(path).exists())
|
||||
return false;
|
||||
|
||||
static const QStringList deleteFilesList = {
|
||||
@@ -180,12 +180,14 @@ bool Utils::Fs::forceRemove(const QString& file_path)
|
||||
* Removes directory and its content recursively.
|
||||
*
|
||||
*/
|
||||
void Utils::Fs::removeDirRecursive(const QString& dirName)
|
||||
void Utils::Fs::removeDirRecursive(const QString &path)
|
||||
{
|
||||
if (path.isEmpty())
|
||||
return;
|
||||
#ifdef QBT_USES_QT5
|
||||
QDir(dirName).removeRecursively();
|
||||
QDir(path).removeRecursively();
|
||||
#else
|
||||
QDir dir(dirName);
|
||||
QDir dir(path);
|
||||
|
||||
if (!dir.exists()) return;
|
||||
|
||||
@@ -198,7 +200,7 @@ void Utils::Fs::removeDirRecursive(const QString& dirName)
|
||||
else forceRemove(info.absoluteFilePath());
|
||||
}
|
||||
|
||||
dir.rmdir(dirName);
|
||||
dir.rmdir(path);
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
@@ -58,7 +58,7 @@ namespace Utils
|
||||
|
||||
bool smartRemoveEmptyFolderTree(const QString& path);
|
||||
bool forceRemove(const QString& file_path);
|
||||
void removeDirRecursive(const QString& dirName);
|
||||
void removeDirRecursive(const QString& path);
|
||||
|
||||
/* Ported from Qt4 to drop dependency on QtGui */
|
||||
QString QDesktopServicesDataLocation();
|
||||
|
||||
@@ -27,116 +27,125 @@
|
||||
* exception statement from your version.
|
||||
*/
|
||||
|
||||
#include <QByteArray>
|
||||
#include <zlib.h>
|
||||
|
||||
#include "gzip.h"
|
||||
|
||||
bool Utils::Gzip::compress(QByteArray src, QByteArray &dest)
|
||||
{
|
||||
static const int BUFSIZE = 128 * 1024;
|
||||
char tmpBuf[BUFSIZE];
|
||||
int ret;
|
||||
#include <vector>
|
||||
|
||||
dest.clear();
|
||||
#include <QByteArray>
|
||||
|
||||
#ifndef ZLIB_CONST
|
||||
#define ZLIB_CONST // make z_stream.next_in const
|
||||
#endif
|
||||
#include <zlib.h>
|
||||
|
||||
QByteArray Utils::Gzip::compress(const QByteArray &data, const int level, bool *ok)
|
||||
{
|
||||
if (ok) *ok = false;
|
||||
|
||||
if (data.isEmpty())
|
||||
return {};
|
||||
|
||||
const int BUFSIZE = 128 * 1024;
|
||||
std::vector<char> tmpBuf(BUFSIZE);
|
||||
|
||||
z_stream strm;
|
||||
strm.zalloc = Z_NULL;
|
||||
strm.zfree = Z_NULL;
|
||||
strm.opaque = Z_NULL;
|
||||
strm.next_in = reinterpret_cast<uchar *>(src.data());
|
||||
strm.avail_in = src.length();
|
||||
strm.next_out = reinterpret_cast<uchar *>(tmpBuf);
|
||||
strm.next_in = reinterpret_cast<const Bytef *>(data.constData());
|
||||
strm.avail_in = uInt(data.size());
|
||||
strm.next_out = reinterpret_cast<Bytef *>(tmpBuf.data());
|
||||
strm.avail_out = BUFSIZE;
|
||||
|
||||
// windowBits = 15 + 16 to enable gzip
|
||||
// From the zlib manual: windowBits can also be greater than 15 for optional gzip encoding. Add 16 to windowBits
|
||||
// to write a simple gzip header and trailer around the compressed data instead of a zlib wrapper.
|
||||
ret = deflateInit2(&strm, Z_BEST_COMPRESSION, Z_DEFLATED, 15 + 16, 8, Z_DEFAULT_STRATEGY);
|
||||
int result = deflateInit2(&strm, level, Z_DEFLATED, (15 + 16), 9, Z_DEFAULT_STRATEGY);
|
||||
if (result != Z_OK)
|
||||
return {};
|
||||
|
||||
if (ret != Z_OK)
|
||||
return false;
|
||||
QByteArray output;
|
||||
output.reserve(deflateBound(&strm, data.size()));
|
||||
|
||||
while (strm.avail_in != 0) {
|
||||
ret = deflate(&strm, Z_NO_FLUSH);
|
||||
if (ret != Z_OK)
|
||||
return false;
|
||||
// feed to deflate
|
||||
while (strm.avail_in > 0) {
|
||||
result = deflate(&strm, Z_NO_FLUSH);
|
||||
|
||||
if (strm.avail_out == 0) {
|
||||
dest.append(tmpBuf, BUFSIZE);
|
||||
strm.next_out = reinterpret_cast<uchar *>(tmpBuf);
|
||||
strm.avail_out = BUFSIZE;
|
||||
}
|
||||
}
|
||||
|
||||
int deflateRes = Z_OK;
|
||||
while (deflateRes == Z_OK) {
|
||||
if (strm.avail_out == 0) {
|
||||
dest.append(tmpBuf, BUFSIZE);
|
||||
strm.next_out = reinterpret_cast<uchar *>(tmpBuf);
|
||||
strm.avail_out = BUFSIZE;
|
||||
if (result != Z_OK) {
|
||||
deflateEnd(&strm);
|
||||
return {};
|
||||
}
|
||||
|
||||
deflateRes = deflate(&strm, Z_FINISH);
|
||||
output.append(tmpBuf.data(), (BUFSIZE - strm.avail_out));
|
||||
strm.next_out = reinterpret_cast<Bytef *>(tmpBuf.data());
|
||||
strm.avail_out = BUFSIZE;
|
||||
}
|
||||
|
||||
if (deflateRes != Z_STREAM_END)
|
||||
return false;
|
||||
// flush the rest from deflate
|
||||
while (result != Z_STREAM_END) {
|
||||
result = deflate(&strm, Z_FINISH);
|
||||
|
||||
output.append(tmpBuf.data(), (BUFSIZE - strm.avail_out));
|
||||
strm.next_out = reinterpret_cast<Bytef *>(tmpBuf.data());
|
||||
strm.avail_out = BUFSIZE;
|
||||
}
|
||||
|
||||
dest.append(tmpBuf, BUFSIZE - strm.avail_out);
|
||||
deflateEnd(&strm);
|
||||
|
||||
return true;
|
||||
if (ok) *ok = true;
|
||||
return output;
|
||||
}
|
||||
|
||||
bool Utils::Gzip::uncompress(QByteArray src, QByteArray &dest)
|
||||
QByteArray Utils::Gzip::decompress(const QByteArray &data, bool *ok)
|
||||
{
|
||||
dest.clear();
|
||||
if (ok) *ok = false;
|
||||
|
||||
if (src.size() <= 4) {
|
||||
qWarning("uncompress: Input data is truncated");
|
||||
return false;
|
||||
}
|
||||
if (data.isEmpty())
|
||||
return {};
|
||||
|
||||
const int BUFSIZE = 1024 * 1024;
|
||||
std::vector<char> tmpBuf(BUFSIZE);
|
||||
|
||||
z_stream strm;
|
||||
static const int CHUNK_SIZE = 1024;
|
||||
char out[CHUNK_SIZE];
|
||||
|
||||
/* allocate inflate state */
|
||||
strm.zalloc = Z_NULL;
|
||||
strm.zfree = Z_NULL;
|
||||
strm.opaque = Z_NULL;
|
||||
strm.avail_in = static_cast<uint>(src.size());
|
||||
strm.next_in = reinterpret_cast<uchar *>(src.data());
|
||||
strm.next_in = reinterpret_cast<const Bytef *>(data.constData());
|
||||
strm.avail_in = uInt(data.size());
|
||||
strm.next_out = reinterpret_cast<Bytef *>(tmpBuf.data());
|
||||
strm.avail_out = BUFSIZE;
|
||||
|
||||
const int windowBits = 15;
|
||||
const int ENABLE_ZLIB_GZIP = 32;
|
||||
// windowBits must be greater than or equal to the windowBits value provided to deflateInit2() while compressing
|
||||
// Add 32 to windowBits to enable zlib and gzip decoding with automatic header detection
|
||||
int result = inflateInit2(&strm, (15 + 32));
|
||||
if (result != Z_OK)
|
||||
return {};
|
||||
|
||||
int ret = inflateInit2(&strm, windowBits | ENABLE_ZLIB_GZIP); // gzip decoding
|
||||
if (ret != Z_OK)
|
||||
return false;
|
||||
QByteArray output;
|
||||
// from lzbench, level 9 average compression ratio is: 31.92%, which decompression ratio is: 1 / 0.3192 = 3.13
|
||||
output.reserve(data.size() * 3);
|
||||
|
||||
// run inflate()
|
||||
do {
|
||||
strm.avail_out = CHUNK_SIZE;
|
||||
strm.next_out = reinterpret_cast<uchar *>(out);
|
||||
// run inflate
|
||||
while (true) {
|
||||
result = inflate(&strm, Z_NO_FLUSH);
|
||||
|
||||
ret = inflate(&strm, Z_NO_FLUSH);
|
||||
Q_ASSERT(ret != Z_STREAM_ERROR); // state not clobbered
|
||||
|
||||
switch (ret) {
|
||||
case Z_NEED_DICT:
|
||||
case Z_DATA_ERROR:
|
||||
case Z_MEM_ERROR:
|
||||
inflateEnd(&strm);
|
||||
return false;
|
||||
if (result == Z_STREAM_END) {
|
||||
output.append(tmpBuf.data(), (BUFSIZE - strm.avail_out));
|
||||
break;
|
||||
}
|
||||
|
||||
dest.append(out, CHUNK_SIZE - strm.avail_out);
|
||||
}
|
||||
while (!strm.avail_out);
|
||||
if (result != Z_OK) {
|
||||
inflateEnd(&strm);
|
||||
return {};
|
||||
}
|
||||
|
||||
output.append(tmpBuf.data(), (BUFSIZE - strm.avail_out));
|
||||
strm.next_out = reinterpret_cast<Bytef *>(tmpBuf.data());
|
||||
strm.avail_out = BUFSIZE;
|
||||
}
|
||||
|
||||
// clean up and return
|
||||
inflateEnd(&strm);
|
||||
return true;
|
||||
|
||||
if (ok) *ok = true;
|
||||
return output;
|
||||
}
|
||||
|
||||
@@ -36,8 +36,8 @@ namespace Utils
|
||||
{
|
||||
namespace Gzip
|
||||
{
|
||||
bool compress(QByteArray src, QByteArray &dest);
|
||||
bool uncompress(QByteArray src, QByteArray &dest);
|
||||
QByteArray compress(const QByteArray &data, int level = 6, bool *ok = nullptr);
|
||||
QByteArray decompress(const QByteArray &data, bool *ok = nullptr);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -313,11 +313,24 @@ QString Utils::Misc::pythonVersionComplete()
|
||||
// Software 'Anaconda' installs its own python interpreter
|
||||
// and `python --version` returns a string like this:
|
||||
// `Python 3.4.3 :: Anaconda 2.3.0 (64-bit)`
|
||||
const QList<QByteArray> verSplit = output.split(' ');
|
||||
if (verSplit.size() > 1) {
|
||||
version = verSplit.at(1).trimmed();
|
||||
const QList<QByteArray> outSplit = output.split(' ');
|
||||
if (outSplit.size() > 1) {
|
||||
version = outSplit.at(1).trimmed();
|
||||
Logger::instance()->addMessage(QCoreApplication::translate("misc", "Python version: %1").arg(version), Log::INFO);
|
||||
}
|
||||
|
||||
// If python doesn't report a 3-piece version e.g. 3.6.1
|
||||
// then fill the missing pieces with zero
|
||||
const QStringList verSplit = version.split('.', QString::SkipEmptyParts);
|
||||
if (verSplit.size() < 3) {
|
||||
for (int i = verSplit.size(); i < 3; ++i) {
|
||||
if (version.endsWith('.'))
|
||||
version.append('0');
|
||||
else
|
||||
version.append(".0");
|
||||
}
|
||||
Logger::instance()->addMessage(QCoreApplication::translate("misc", "Normalized Python version: %1").arg(version), Log::INFO);
|
||||
}
|
||||
}
|
||||
}
|
||||
return version;
|
||||
|
||||
@@ -30,10 +30,10 @@
|
||||
#ifndef UTILS_STRING_H
|
||||
#define UTILS_STRING_H
|
||||
|
||||
#include <string>
|
||||
#include <QString>
|
||||
|
||||
class QByteArray;
|
||||
class QString;
|
||||
class QLatin1String;
|
||||
|
||||
namespace Utils
|
||||
{
|
||||
@@ -51,6 +51,19 @@ namespace Utils
|
||||
|
||||
bool naturalCompareCaseSensitive(const QString &left, const QString &right);
|
||||
bool naturalCompareCaseInsensitive(const QString &left, const QString &right);
|
||||
|
||||
template <typename T>
|
||||
T unquote(const T &str, const QString "es = QLatin1String("\""))
|
||||
{
|
||||
if (str.length() < 2) return str;
|
||||
|
||||
for (auto const quote : quotes) {
|
||||
if (str.startsWith(quote) && str.endsWith(quote))
|
||||
return str.mid(1, str.length() - 2);
|
||||
}
|
||||
|
||||
return str;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -33,6 +33,7 @@ advancedsettings.h
|
||||
advancedsettings.h
|
||||
autoexpandabledialog.h
|
||||
categoryfiltermodel.h
|
||||
categoryfilterproxymodel.h
|
||||
categoryfilterwidget.h
|
||||
cookiesdialog.h
|
||||
cookiesmodel.h
|
||||
@@ -74,6 +75,7 @@ addnewtorrentdialog.cpp
|
||||
advancedsettings.cpp
|
||||
autoexpandabledialog.cpp
|
||||
categoryfiltermodel.cpp
|
||||
categoryfilterproxymodel.cpp
|
||||
categoryfilterwidget.cpp
|
||||
cookiesdialog.cpp
|
||||
cookiesmodel.cpp
|
||||
@@ -132,7 +134,7 @@ shutdownconfirmdlg.ui
|
||||
|
||||
qbt_target_sources(about.qrc)
|
||||
|
||||
add_library(qbt_gui STATIC ${QBT_GUI_HEADERS} ${QBT_GUI_SOURCES})
|
||||
add_library(qbt_gui STATIC ${QBT_GUI_HEADERS} ${QBT_GUI_SOURCES} ${QBT_GUI_FORMS})
|
||||
target_link_libraries(qbt_gui qbt_lineedit qbt_powermanagement qbt_rss qbt_properties qbt_searchengine
|
||||
${QBT_GUI_OPTIONAL_LINK_LIBRARIES} qbt_base
|
||||
QtSingleApplication::QtSingleApplication
|
||||
|
||||
@@ -68,8 +68,11 @@ const QString KEY_SAVEPATHHISTORY = SETTINGS_KEY("SavePathHistory");
|
||||
|
||||
namespace
|
||||
{
|
||||
//just a shortcut
|
||||
inline SettingsStorage *settings() { return SettingsStorage::instance(); }
|
||||
// just a shortcut
|
||||
inline SettingsStorage *settings()
|
||||
{
|
||||
return SettingsStorage::instance();
|
||||
}
|
||||
}
|
||||
|
||||
AddNewTorrentDialog::AddNewTorrentDialog(QWidget *parent)
|
||||
@@ -88,7 +91,7 @@ AddNewTorrentDialog::AddNewTorrentDialog(QWidget *parent)
|
||||
auto session = BitTorrent::Session::instance();
|
||||
|
||||
ui->startTorrentCheckBox->setChecked(!session->isAddTorrentPaused());
|
||||
ui->comboTTM->blockSignals(true); //the TreeView size isn't correct if the slot does it job at this point
|
||||
ui->comboTTM->blockSignals(true); // the TreeView size isn't correct if the slot does it job at this point
|
||||
ui->comboTTM->setCurrentIndex(!session->isAutoTMMDisabledByDefault());
|
||||
ui->comboTTM->blockSignals(false);
|
||||
populateSavePathComboBox();
|
||||
@@ -111,7 +114,6 @@ AddNewTorrentDialog::AddNewTorrentDialog(QWidget *parent)
|
||||
if (category != defaultCategory)
|
||||
ui->categoryComboBox->addItem(category);
|
||||
|
||||
ui->categoryComboBox->model()->sort(0);
|
||||
ui->contentTreeView->header()->setSortIndicator(0, Qt::AscendingOrder);
|
||||
loadState();
|
||||
// Signal / slots
|
||||
@@ -181,9 +183,9 @@ void AddNewTorrentDialog::show(QString source, QWidget *parent)
|
||||
if (Utils::Misc::isUrl(source)) {
|
||||
// Launch downloader
|
||||
Net::DownloadHandler *handler = Net::DownloadManager::instance()->downloadUrl(source, true, 10485760 /* 10MB */, true);
|
||||
connect(handler, SIGNAL(downloadFinished(QString, QString)), dlg, SLOT(handleDownloadFinished(QString, QString)));
|
||||
connect(handler, SIGNAL(downloadFailed(QString, QString)), dlg, SLOT(handleDownloadFailed(QString, QString)));
|
||||
connect(handler, SIGNAL(redirectedToMagnet(QString, QString)), dlg, SLOT(handleRedirectedToMagnet(QString, QString)));
|
||||
connect(handler, SIGNAL(downloadFinished(QString,QString)), dlg, SLOT(handleDownloadFinished(QString,QString)));
|
||||
connect(handler, SIGNAL(downloadFailed(QString,QString)), dlg, SLOT(handleDownloadFailed(QString,QString)));
|
||||
connect(handler, SIGNAL(redirectedToMagnet(QString,QString)), dlg, SLOT(handleRedirectedToMagnet(QString,QString)));
|
||||
}
|
||||
else {
|
||||
bool ok = false;
|
||||
@@ -309,7 +311,6 @@ void AddNewTorrentDialog::showEvent(QShowEvent *event)
|
||||
raise();
|
||||
}
|
||||
|
||||
|
||||
void AddNewTorrentDialog::showAdvancedSettings(bool show)
|
||||
{
|
||||
const int minimumW = minimumWidth();
|
||||
@@ -319,7 +320,7 @@ void AddNewTorrentDialog::showAdvancedSettings(bool show)
|
||||
ui->settings_group->setVisible(true);
|
||||
ui->infoGroup->setVisible(true);
|
||||
ui->contentTreeView->setVisible(m_hasMetadata);
|
||||
static_cast<QVBoxLayout*>(layout())->insertWidget(layout()->indexOf(ui->never_show_cb) + 1, ui->adv_button);
|
||||
static_cast<QVBoxLayout *>(layout())->insertWidget(layout()->indexOf(ui->never_show_cb) + 1, ui->adv_button);
|
||||
}
|
||||
else {
|
||||
ui->adv_button->setText(QString::fromUtf8(C_DOWN));
|
||||
@@ -337,7 +338,7 @@ void AddNewTorrentDialog::saveSavePathHistory() const
|
||||
// Get current history
|
||||
QStringList history = settings()->loadValue(KEY_SAVEPATHHISTORY).toStringList();
|
||||
QList<QDir> historyDirs;
|
||||
foreach(const QString dir, history)
|
||||
foreach (const QString dir, history)
|
||||
historyDirs << QDir(dir);
|
||||
if (!historyDirs.contains(selectedSavePath)) {
|
||||
// Add save path to history
|
||||
@@ -381,8 +382,8 @@ void AddNewTorrentDialog::updateDiskSpaceLabel()
|
||||
QString size_string = torrent_size ? Utils::Misc::friendlyUnit(torrent_size) : QString(tr("Not Available", "This size is unavailable."));
|
||||
size_string += " (";
|
||||
size_string += tr("Free space on disk: %1").arg(Utils::Misc::friendlyUnit(Utils::Fs::freeDiskSpaceOnPath(
|
||||
ui->savePathComboBox->itemData(
|
||||
ui->savePathComboBox->currentIndex()).toString())));
|
||||
ui->savePathComboBox->itemData(
|
||||
ui->savePathComboBox->currentIndex()).toString())));
|
||||
size_string += ")";
|
||||
ui->size_lbl->setText(size_string);
|
||||
}
|
||||
@@ -392,8 +393,8 @@ void AddNewTorrentDialog::onSavePathChanged(int index)
|
||||
// Toggle default save path setting checkbox visibility
|
||||
ui->defaultSavePathCheckBox->setChecked(false);
|
||||
ui->defaultSavePathCheckBox->setVisible(
|
||||
QDir(ui->savePathComboBox->itemData(ui->savePathComboBox->currentIndex()).toString())
|
||||
!= QDir(BitTorrent::Session::instance()->defaultSavePath()));
|
||||
QDir(ui->savePathComboBox->itemData(ui->savePathComboBox->currentIndex()).toString())
|
||||
!= QDir(BitTorrent::Session::instance()->defaultSavePath()));
|
||||
|
||||
// Remember index
|
||||
m_oldIndex = index;
|
||||
@@ -502,7 +503,7 @@ void AddNewTorrentDialog::renameSelectedFile()
|
||||
QStringList path_items;
|
||||
path_items << index.data().toString();
|
||||
QModelIndex parent = m_contentModel->parent(index);
|
||||
while(parent.isValid()) {
|
||||
while (parent.isValid()) {
|
||||
path_items.prepend(parent.data().toString());
|
||||
parent = m_contentModel->parent(parent);
|
||||
}
|
||||
@@ -549,6 +550,10 @@ void AddNewTorrentDialog::renameSelectedFile()
|
||||
|
||||
void AddNewTorrentDialog::setdialogPosition()
|
||||
{
|
||||
// In macOS, AddNewTorrentDialog is a sheet, not a window. Moving it
|
||||
// causes very bad things to happen, especially if AddNewTorrentDialog is
|
||||
// on a secondary monitor.
|
||||
#ifndef Q_OS_MAC
|
||||
qApp->processEvents();
|
||||
QPoint center(Utils::Misc::screenCenter(this));
|
||||
// Adjust y
|
||||
@@ -562,6 +567,7 @@ void AddNewTorrentDialog::setdialogPosition()
|
||||
center.setY(0);
|
||||
}
|
||||
move(center);
|
||||
#endif
|
||||
}
|
||||
|
||||
void AddNewTorrentDialog::populateSavePathComboBox()
|
||||
@@ -577,7 +583,7 @@ void AddNewTorrentDialog::populateSavePathComboBox()
|
||||
ui->savePathComboBox->addItem(Utils::Fs::toNativePath(savePath), savePath);
|
||||
}
|
||||
|
||||
void AddNewTorrentDialog::displayContentTreeMenu(const QPoint&)
|
||||
void AddNewTorrentDialog::displayContentTreeMenu(const QPoint &)
|
||||
{
|
||||
QMenu myFilesLlistMenu;
|
||||
const QModelIndexList selectedRows = ui->contentTreeView->selectionModel()->selectedRows(0);
|
||||
@@ -620,7 +626,7 @@ void AddNewTorrentDialog::displayContentTreeMenu(const QPoint&)
|
||||
void AddNewTorrentDialog::accept()
|
||||
{
|
||||
if (!m_hasMetadata)
|
||||
disconnect(this, SLOT(updateMetadata(const BitTorrent::TorrentInfo &)));
|
||||
disconnect(this, SLOT(updateMetadata(const BitTorrent::TorrentInfo&)));
|
||||
|
||||
BitTorrent::AddTorrentParams params;
|
||||
|
||||
@@ -718,10 +724,10 @@ void AddNewTorrentDialog::setupTreeview()
|
||||
m_contentModel = new TorrentContentFilterModel(this);
|
||||
connect(m_contentModel->model(), SIGNAL(filteredFilesChanged()), SLOT(updateDiskSpaceLabel()));
|
||||
ui->contentTreeView->setModel(m_contentModel);
|
||||
m_contentDelegate = new PropListDelegate();
|
||||
m_contentDelegate = new PropListDelegate(nullptr);
|
||||
ui->contentTreeView->setItemDelegate(m_contentDelegate);
|
||||
connect(ui->contentTreeView, SIGNAL(clicked(const QModelIndex &)), ui->contentTreeView, SLOT(edit(const QModelIndex &)));
|
||||
connect(ui->contentTreeView, SIGNAL(customContextMenuRequested(const QPoint &)), this, SLOT(displayContentTreeMenu(const QPoint &)));
|
||||
connect(ui->contentTreeView, SIGNAL(clicked(const QModelIndex&)), ui->contentTreeView, SLOT(edit(const QModelIndex&)));
|
||||
connect(ui->contentTreeView, SIGNAL(customContextMenuRequested(const QPoint&)), this, SLOT(displayContentTreeMenu(const QPoint&)));
|
||||
|
||||
// List files in torrent
|
||||
m_contentModel->model()->setupModelData(m_torrentInfo);
|
||||
|
||||
@@ -190,7 +190,9 @@ void AdvancedSettings::saveAdvancedSettings()
|
||||
|
||||
void AdvancedSettings::updateCacheSpinSuffix(int value)
|
||||
{
|
||||
if (value <= 0)
|
||||
if (value == 0)
|
||||
spin_cache.setSuffix(tr(" (disabled)"));
|
||||
else if (value < 0)
|
||||
spin_cache.setSuffix(tr(" (auto)"));
|
||||
else
|
||||
spin_cache.setSuffix(tr(" MiB"));
|
||||
@@ -251,7 +253,7 @@ void AdvancedSettings::loadAdvancedSettings()
|
||||
labelLibtorrentLink.setText(QString("<a href=\"%1\">%2</a>").arg("http://www.libtorrent.org/reference.html").arg(tr("Open documentation")));
|
||||
labelLibtorrentLink.setOpenExternalLinks(true);
|
||||
// Disk write cache
|
||||
spin_cache.setMinimum(0);
|
||||
spin_cache.setMinimum(-1);
|
||||
// When build as 32bit binary, set the maximum at less than 2GB to prevent crashes.
|
||||
// These macros may not be available on compilers other than MSVC and GCC
|
||||
#if defined(__x86_64__) || defined(_M_X64)
|
||||
@@ -323,7 +325,6 @@ void AdvancedSettings::loadAdvancedSettings()
|
||||
// https://github.com/qbittorrent/qBittorrent/pull/5135
|
||||
if (iface.addressEntries().isEmpty()) continue;
|
||||
|
||||
if (iface.flags() & QNetworkInterface::IsLoopBack) continue;
|
||||
combo_iface.addItem(iface.humanReadableName(), iface.name());
|
||||
if (!current_iface.isEmpty() && (iface.name() == current_iface)) {
|
||||
combo_iface.setCurrentIndex(i);
|
||||
|
||||
@@ -139,8 +139,7 @@ public:
|
||||
|
||||
item->m_parent = this;
|
||||
m_children[uid] = item;
|
||||
auto pos = std::lower_bound(m_childUids.begin(), m_childUids.end(), uid);
|
||||
m_childUids.insert(pos, uid);
|
||||
m_childUids.append(uid);
|
||||
m_torrentsCount += item->torrentsCount();
|
||||
}
|
||||
|
||||
@@ -195,6 +194,13 @@ CategoryFilterModel::~CategoryFilterModel()
|
||||
delete m_rootItem;
|
||||
}
|
||||
|
||||
bool CategoryFilterModel::isSpecialItem(const QModelIndex &index)
|
||||
{
|
||||
// the first two items at first level are special items:
|
||||
// 'All' and 'Uncategorized'
|
||||
return (!index.parent().isValid() && (index.row() <= 1));
|
||||
}
|
||||
|
||||
int CategoryFilterModel::columnCount(const QModelIndex &) const
|
||||
{
|
||||
return 1;
|
||||
@@ -307,11 +313,10 @@ void CategoryFilterModel::categoryAdded(const QString &categoryName)
|
||||
parent = findItem(expanded[expanded.count() - 2]);
|
||||
}
|
||||
|
||||
auto item = new CategoryModelItem(
|
||||
parent, m_isSubcategoriesEnabled ? shortName(categoryName) : categoryName);
|
||||
|
||||
QModelIndex i = index(item);
|
||||
beginInsertRows(i.parent(), i.row(), i.row());
|
||||
int row = parent->childCount();
|
||||
beginInsertRows(index(parent), row, row);
|
||||
new CategoryModelItem(
|
||||
parent, m_isSubcategoriesEnabled ? shortName(categoryName) : categoryName);
|
||||
endInsertRows();
|
||||
}
|
||||
|
||||
|
||||
@@ -48,6 +48,8 @@ public:
|
||||
explicit CategoryFilterModel(QObject *parent = nullptr);
|
||||
~CategoryFilterModel();
|
||||
|
||||
static bool isSpecialItem(const QModelIndex &index);
|
||||
|
||||
int columnCount(const QModelIndex &parent = QModelIndex()) const override;
|
||||
QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const override;
|
||||
Qt::ItemFlags flags(const QModelIndex &index) const override;
|
||||
|
||||
57
src/gui/categoryfilterproxymodel.cpp
Normal file
57
src/gui/categoryfilterproxymodel.cpp
Normal file
@@ -0,0 +1,57 @@
|
||||
/*
|
||||
* Bittorrent Client using Qt and libtorrent.
|
||||
* Copyright (C) 2017 Frédéric Brière <fbriere@fbriere.net>
|
||||
*
|
||||
* 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 "categoryfilterproxymodel.h"
|
||||
|
||||
#include "base/utils/string.h"
|
||||
#include "categoryfiltermodel.h"
|
||||
|
||||
CategoryFilterProxyModel::CategoryFilterProxyModel(QObject *parent)
|
||||
: QSortFilterProxyModel(parent)
|
||||
{
|
||||
}
|
||||
|
||||
QModelIndex CategoryFilterProxyModel::index(const QString &categoryName) const
|
||||
{
|
||||
return mapFromSource(static_cast<CategoryFilterModel *>(sourceModel())->index(categoryName));
|
||||
}
|
||||
|
||||
QString CategoryFilterProxyModel::categoryName(const QModelIndex &index) const
|
||||
{
|
||||
return static_cast<CategoryFilterModel *>(sourceModel())->categoryName(mapToSource(index));
|
||||
}
|
||||
|
||||
bool CategoryFilterProxyModel::lessThan(const QModelIndex &left, const QModelIndex &right) const
|
||||
{
|
||||
// "All" and "Uncategorized" must be left in place
|
||||
if (CategoryFilterModel::isSpecialItem(left) || CategoryFilterModel::isSpecialItem(right))
|
||||
return left.row() < right.row();
|
||||
else
|
||||
return Utils::String::naturalCompareCaseInsensitive(
|
||||
left.data().toString(), right.data().toString());
|
||||
}
|
||||
52
src/gui/categoryfilterproxymodel.h
Normal file
52
src/gui/categoryfilterproxymodel.h
Normal file
@@ -0,0 +1,52 @@
|
||||
/*
|
||||
* Bittorrent Client using Qt and libtorrent.
|
||||
* Copyright (C) 2017 Frédéric Brière <fbriere@fbriere.net>
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#ifndef CATEGORYFILTERPROXYMODEL_H
|
||||
#define CATEGORYFILTERPROXYMODEL_H
|
||||
|
||||
#include <QSortFilterProxyModel>
|
||||
#include <QString>
|
||||
|
||||
class CategoryFilterProxyModel: public QSortFilterProxyModel
|
||||
{
|
||||
public:
|
||||
explicit CategoryFilterProxyModel(QObject *parent = nullptr);
|
||||
|
||||
// CategoryFilterModel methods which we need to relay
|
||||
QModelIndex index(const QString &categoryName) const;
|
||||
QString categoryName(const QModelIndex &index) const;
|
||||
|
||||
protected:
|
||||
bool lessThan(const QModelIndex &left, const QModelIndex &right) const override;
|
||||
|
||||
private:
|
||||
// we added another overload of index(), hence this using directive:
|
||||
using QSortFilterProxyModel::index;
|
||||
};
|
||||
|
||||
#endif // CATEGORYFILTERPROXYMODEL_H
|
||||
@@ -38,11 +38,12 @@
|
||||
#include "base/utils/misc.h"
|
||||
#include "autoexpandabledialog.h"
|
||||
#include "categoryfiltermodel.h"
|
||||
#include "categoryfilterproxymodel.h"
|
||||
#include "guiiconprovider.h"
|
||||
|
||||
namespace
|
||||
{
|
||||
QString getCategoryFilter(const CategoryFilterModel *const model, const QModelIndex &index)
|
||||
QString getCategoryFilter(const CategoryFilterProxyModel *const model, const QModelIndex &index)
|
||||
{
|
||||
QString categoryFilter; // Defaults to All
|
||||
if (index.isValid()) {
|
||||
@@ -54,19 +55,15 @@ namespace
|
||||
|
||||
return categoryFilter;
|
||||
}
|
||||
|
||||
bool isSpecialItem(const QModelIndex &index)
|
||||
{
|
||||
// the first two items at first level are special items:
|
||||
// 'All' and 'Uncategorized'
|
||||
return (!index.parent().isValid() && (index.row() <= 1));
|
||||
}
|
||||
}
|
||||
|
||||
CategoryFilterWidget::CategoryFilterWidget(QWidget *parent)
|
||||
: QTreeView(parent)
|
||||
{
|
||||
setModel(new CategoryFilterModel(this));
|
||||
CategoryFilterProxyModel *proxyModel = new CategoryFilterProxyModel(this);
|
||||
proxyModel->setSortCaseSensitivity(Qt::CaseInsensitive);
|
||||
proxyModel->setSourceModel(new CategoryFilterModel(this));
|
||||
setModel(proxyModel);
|
||||
setFrameShape(QFrame::NoFrame);
|
||||
setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
|
||||
setVerticalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
|
||||
@@ -78,6 +75,7 @@ CategoryFilterWidget::CategoryFilterWidget(QWidget *parent)
|
||||
setAttribute(Qt::WA_MacShowFocusRect, false);
|
||||
#endif
|
||||
setContextMenuPolicy(Qt::CustomContextMenu);
|
||||
sortByColumn(0, Qt::AscendingOrder);
|
||||
setCurrentIndex(model()->index(0, 0));
|
||||
|
||||
connect(this, SIGNAL(collapsed(QModelIndex)), SLOT(callUpdateGeometry()));
|
||||
@@ -95,14 +93,14 @@ QString CategoryFilterWidget::currentCategory() const
|
||||
if (!selectedRows.isEmpty())
|
||||
current = selectedRows.first();
|
||||
|
||||
return getCategoryFilter(static_cast<CategoryFilterModel *>(model()), current);
|
||||
return getCategoryFilter(static_cast<CategoryFilterProxyModel *>(model()), current);
|
||||
}
|
||||
|
||||
void CategoryFilterWidget::onCurrentRowChanged(const QModelIndex ¤t, const QModelIndex &previous)
|
||||
{
|
||||
Q_UNUSED(previous);
|
||||
|
||||
emit categoryChanged(getCategoryFilter(static_cast<CategoryFilterModel *>(model()), current));
|
||||
emit categoryChanged(getCategoryFilter(static_cast<CategoryFilterProxyModel *>(model()), current));
|
||||
}
|
||||
|
||||
void CategoryFilterWidget::showMenu(QPoint)
|
||||
@@ -115,7 +113,7 @@ void CategoryFilterWidget::showMenu(QPoint)
|
||||
connect(addAct, SIGNAL(triggered()), SLOT(addCategory()));
|
||||
|
||||
auto selectedRows = selectionModel()->selectedRows();
|
||||
if (!selectedRows.empty() && !isSpecialItem(selectedRows.first())) {
|
||||
if (!selectedRows.empty() && !CategoryFilterModel::isSpecialItem(selectedRows.first())) {
|
||||
if (BitTorrent::Session::instance()->isSubcategoriesEnabled()) {
|
||||
QAction *addSubAct = menu.addAction(
|
||||
GuiIconProvider::instance()->getIcon("list-add")
|
||||
@@ -253,9 +251,9 @@ void CategoryFilterWidget::addSubcategory()
|
||||
void CategoryFilterWidget::removeCategory()
|
||||
{
|
||||
auto selectedRows = selectionModel()->selectedRows();
|
||||
if (!selectedRows.empty() && !isSpecialItem(selectedRows.first())) {
|
||||
if (!selectedRows.empty() && !CategoryFilterModel::isSpecialItem(selectedRows.first())) {
|
||||
BitTorrent::Session::instance()->removeCategory(
|
||||
static_cast<CategoryFilterModel *>(model())->categoryName(selectedRows.first()));
|
||||
static_cast<CategoryFilterProxyModel *>(model())->categoryName(selectedRows.first()));
|
||||
updateGeometry();
|
||||
}
|
||||
}
|
||||
@@ -264,7 +262,7 @@ void CategoryFilterWidget::removeUnusedCategories()
|
||||
{
|
||||
auto session = BitTorrent::Session::instance();
|
||||
foreach (const QString &category, session->categories())
|
||||
if (model()->data(static_cast<CategoryFilterModel *>(model())->index(category), Qt::UserRole) == 0)
|
||||
if (model()->data(static_cast<CategoryFilterProxyModel *>(model())->index(category), Qt::UserRole) == 0)
|
||||
session->removeCategory(category);
|
||||
updateGeometry();
|
||||
}
|
||||
|
||||
@@ -17,7 +17,7 @@
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="windowTitle">
|
||||
<string>Deletion confirmation - qBittorrent</string>
|
||||
<string>Deletion confirmation</string>
|
||||
</property>
|
||||
<layout class="QVBoxLayout" name="verticalLayout">
|
||||
<item>
|
||||
|
||||
@@ -11,7 +11,7 @@
|
||||
</rect>
|
||||
</property>
|
||||
<property name="windowTitle">
|
||||
<string>Download from urls</string>
|
||||
<string>Download from URLs</string>
|
||||
</property>
|
||||
<layout class="QVBoxLayout">
|
||||
<item>
|
||||
@@ -33,12 +33,12 @@
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QTextEdit" name="textUrls">
|
||||
<property name="acceptRichText">
|
||||
<bool>false</bool>
|
||||
</property>
|
||||
<property name="tabChangesFocus">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
<property name="acceptRichText">
|
||||
<bool>false</bool>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
|
||||
@@ -51,6 +51,7 @@ HEADERS += \
|
||||
$$PWD/cookiesmodel.h \
|
||||
$$PWD/cookiesdialog.h \
|
||||
$$PWD/categoryfiltermodel.h \
|
||||
$$PWD/categoryfilterproxymodel.h \
|
||||
$$PWD/categoryfilterwidget.h
|
||||
|
||||
SOURCES += \
|
||||
@@ -93,6 +94,7 @@ SOURCES += \
|
||||
$$PWD/cookiesmodel.cpp \
|
||||
$$PWD/cookiesdialog.cpp \
|
||||
$$PWD/categoryfiltermodel.cpp \
|
||||
$$PWD/categoryfilterproxymodel.cpp \
|
||||
$$PWD/categoryfilterwidget.cpp
|
||||
|
||||
win32|macx {
|
||||
|
||||
@@ -28,6 +28,8 @@
|
||||
* Contact : chris@qbittorrent.org
|
||||
*/
|
||||
|
||||
#include "mainwindow.h"
|
||||
|
||||
#include <QtGlobal>
|
||||
#if (defined(Q_OS_UNIX) && !defined(Q_OS_MAC)) && defined(QT_DBUS_LIB)
|
||||
#include <QDBusConnection>
|
||||
@@ -44,6 +46,7 @@
|
||||
#include <QCloseEvent>
|
||||
#include <QShortcut>
|
||||
#include <QScrollBar>
|
||||
#include <QSplitter>
|
||||
#include <QSysInfo>
|
||||
#include <QMimeData>
|
||||
#include <QCryptographicHash>
|
||||
@@ -91,7 +94,6 @@
|
||||
#include "executionlog.h"
|
||||
#include "hidabletabwidget.h"
|
||||
#include "ui_mainwindow.h"
|
||||
#include "mainwindow.h"
|
||||
|
||||
#ifdef Q_OS_MAC
|
||||
void qt_mac_set_dock_menu(QMenu *menu);
|
||||
@@ -941,17 +943,17 @@ void MainWindow::notifyOfUpdate(QString)
|
||||
}
|
||||
|
||||
// Toggle Main window visibility
|
||||
void MainWindow::toggleVisibility(QSystemTrayIcon::ActivationReason e)
|
||||
void MainWindow::toggleVisibility(const QSystemTrayIcon::ActivationReason reason)
|
||||
{
|
||||
if ((e == QSystemTrayIcon::Trigger) || (e == QSystemTrayIcon::DoubleClick)) {
|
||||
switch (reason) {
|
||||
case QSystemTrayIcon::Trigger: {
|
||||
if (isHidden()) {
|
||||
if (m_uiLocked) {
|
||||
// Ask for UI lock password
|
||||
if (!unlockUI())
|
||||
return;
|
||||
}
|
||||
if (m_uiLocked && !unlockUI()) // Ask for UI lock password
|
||||
return;
|
||||
|
||||
// Make sure the window is not minimized
|
||||
setWindowState((windowState() & ~Qt::WindowMinimized) | Qt::WindowActive);
|
||||
|
||||
// Then show it
|
||||
show();
|
||||
raise();
|
||||
@@ -960,6 +962,12 @@ void MainWindow::toggleVisibility(QSystemTrayIcon::ActivationReason e)
|
||||
else {
|
||||
hide();
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -968,7 +976,7 @@ void MainWindow::on_actionAbout_triggered()
|
||||
{
|
||||
// About dialog
|
||||
if (m_aboutDlg)
|
||||
m_aboutDlg->setFocus();
|
||||
m_aboutDlg->activateWindow();
|
||||
else
|
||||
m_aboutDlg = new about(this);
|
||||
}
|
||||
@@ -976,7 +984,7 @@ void MainWindow::on_actionAbout_triggered()
|
||||
void MainWindow::on_actionStatistics_triggered()
|
||||
{
|
||||
if (m_statsDlg)
|
||||
m_statsDlg->setFocus();
|
||||
m_statsDlg->activateWindow();
|
||||
else
|
||||
m_statsDlg = new StatsDialog(this);
|
||||
}
|
||||
@@ -1013,7 +1021,8 @@ void MainWindow::closeEvent(QCloseEvent *e)
|
||||
if (!isVisible())
|
||||
show();
|
||||
QMessageBox confirmBox(QMessageBox::Question, tr("Exiting qBittorrent"),
|
||||
tr("Some files are currently transferring.\nAre you sure you want to quit qBittorrent?"),
|
||||
// Split it because the last sentence is used in the Web UI
|
||||
tr("Some files are currently transferring.") + "\n" + tr("Are you sure you want to quit qBittorrent?"),
|
||||
QMessageBox::NoButton, this);
|
||||
QPushButton *noBtn = confirmBox.addButton(tr("&No"), QMessageBox::NoRole);
|
||||
confirmBox.addButton(tr("&Yes"), QMessageBox::YesRole);
|
||||
@@ -1049,7 +1058,7 @@ void MainWindow::closeEvent(QCloseEvent *e)
|
||||
void MainWindow::on_actionCreateTorrent_triggered()
|
||||
{
|
||||
if (m_createTorrentDlg)
|
||||
m_createTorrentDlg->setFocus();
|
||||
m_createTorrentDlg->activateWindow();
|
||||
else
|
||||
m_createTorrentDlg = new TorrentCreatorDlg(this);
|
||||
}
|
||||
@@ -1476,7 +1485,7 @@ void MainWindow::createTrayIcon()
|
||||
void MainWindow::on_actionOptions_triggered()
|
||||
{
|
||||
if (m_options)
|
||||
m_options->setFocus();
|
||||
m_options->activateWindow();
|
||||
else
|
||||
m_options = new OptionsDialog(this);
|
||||
}
|
||||
|
||||
@@ -103,7 +103,7 @@ public:
|
||||
void showNotificationBaloon(QString title, QString msg) const;
|
||||
|
||||
private slots:
|
||||
void toggleVisibility(QSystemTrayIcon::ActivationReason e = QSystemTrayIcon::Trigger);
|
||||
void toggleVisibility(const QSystemTrayIcon::ActivationReason reason = QSystemTrayIcon::Trigger);
|
||||
|
||||
void balloonClicked();
|
||||
void writeSettings();
|
||||
|
||||
@@ -319,6 +319,7 @@ OptionsDialog::OptionsDialog(QWidget *parent)
|
||||
connect(m_ui->textTrackers, SIGNAL(textChanged()), this, SLOT(enableApplyButton()));
|
||||
#ifndef DISABLE_WEBUI
|
||||
// Web UI tab
|
||||
connect(m_ui->textServerDomains, SIGNAL(textChanged(QString)), this, SLOT(enableApplyButton()));
|
||||
connect(m_ui->checkWebUi, SIGNAL(toggled(bool)), this, SLOT(enableApplyButton()));
|
||||
connect(m_ui->spinWebUiPort, SIGNAL(valueChanged(int)), this, SLOT(enableApplyButton()));
|
||||
connect(m_ui->checkWebUIUPnP, SIGNAL(toggled(bool)), SLOT(enableApplyButton()));
|
||||
@@ -603,6 +604,7 @@ void OptionsDialog::saveOptions()
|
||||
// Web UI
|
||||
pref->setWebUiEnabled(isWebUiEnabled());
|
||||
if (isWebUiEnabled()) {
|
||||
pref->setServerDomains(m_ui->textServerDomains->text());
|
||||
pref->setWebUiPort(webUiPort());
|
||||
pref->setUPnPForWebUIPort(m_ui->checkWebUIUPnP->isChecked());
|
||||
pref->setWebUiHttpsEnabled(m_ui->checkWebUiHttps->isChecked());
|
||||
@@ -975,6 +977,7 @@ void OptionsDialog::loadOptions()
|
||||
// End Bittorrent preferences
|
||||
|
||||
// Web UI preferences
|
||||
m_ui->textServerDomains->setText(pref->getServerDomains());
|
||||
m_ui->checkWebUi->setChecked(pref->isWebUiEnabled());
|
||||
m_ui->spinWebUiPort->setValue(pref->getWebUiPort());
|
||||
m_ui->checkWebUIUPnP->setChecked(pref->useUPnPForWebUIPort());
|
||||
|
||||
@@ -2605,15 +2605,15 @@
|
||||
<rect>
|
||||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>438</width>
|
||||
<height>543</height>
|
||||
<width>518</width>
|
||||
<height>602</height>
|
||||
</rect>
|
||||
</property>
|
||||
<layout class="QVBoxLayout" name="verticalLayout_23">
|
||||
<item>
|
||||
<widget class="QGroupBox" name="checkWebUi">
|
||||
<property name="title">
|
||||
<string>Enable Web User Interface (Remote control)</string>
|
||||
<string>Web User Interface (Remote control)</string>
|
||||
</property>
|
||||
<property name="checkable">
|
||||
<bool>true</bool>
|
||||
@@ -2622,6 +2622,28 @@
|
||||
<bool>false</bool>
|
||||
</property>
|
||||
<layout class="QVBoxLayout" name="verticalLayout_2">
|
||||
<item>
|
||||
<layout class="QHBoxLayout" name="horizontalLayout_1">
|
||||
<item>
|
||||
<widget class="QLabel" name="labelServerDomains">
|
||||
<property name="text">
|
||||
<string>Server domains:</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QLineEdit" name="textServerDomains">
|
||||
<property name="toolTip">
|
||||
<string>Whitelist for filtering HTTP Host header values.
|
||||
In order to defend against DNS rebinding attack,
|
||||
you should put in domain names used by WebUI server.
|
||||
|
||||
Use ';' to split multiple entries. Can use wildcard '*'.</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
<item>
|
||||
<layout class="QHBoxLayout" name="horizontalLayout_2">
|
||||
<item>
|
||||
|
||||
@@ -42,7 +42,7 @@ speedwidget.cpp
|
||||
speedplotview.cpp
|
||||
)
|
||||
|
||||
add_library(qbt_properties STATIC ${QBT_PROPERTIES_HEADERS} ${QBT_PROPERTIES_SOURCES})
|
||||
add_library(qbt_properties STATIC ${QBT_PROPERTIES_HEADERS} ${QBT_PROPERTIES_SOURCES} ${QBT_PROPERTIES_FORMS})
|
||||
target_link_libraries(qbt_properties qbt_base)
|
||||
if (NOT QT4_FOUND)
|
||||
target_link_libraries(qbt_properties Qt5::Widgets Qt5::Concurrent)
|
||||
|
||||
@@ -38,7 +38,8 @@
|
||||
#include "base/utils/misc.h"
|
||||
#include "base/utils/string.h"
|
||||
|
||||
class PeerListDelegate: public QItemDelegate {
|
||||
class PeerListDelegate: public QItemDelegate
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
@@ -67,14 +68,16 @@ public:
|
||||
|
||||
~PeerListDelegate() {}
|
||||
|
||||
void paint(QPainter * painter, const QStyleOptionViewItem & option, const QModelIndex & index) const
|
||||
void paint(QPainter *painter, const QStyleOptionViewItem &option, const QModelIndex &index) const override
|
||||
{
|
||||
painter->save();
|
||||
|
||||
const bool hideValues = Preferences::instance()->getHideZeroValues();
|
||||
QStyleOptionViewItem opt = QItemDelegate::setOptions(index, option);
|
||||
switch(index.column()) {
|
||||
QItemDelegate::drawBackground(painter, opt, index);
|
||||
|
||||
switch (index.column()) {
|
||||
case PORT: {
|
||||
QItemDelegate::drawBackground(painter, opt, index);
|
||||
opt.displayAlignment = Qt::AlignRight | Qt::AlignVCenter;
|
||||
QItemDelegate::drawDisplay(painter, opt, option.rect, index.data().toString());
|
||||
}
|
||||
@@ -84,40 +87,38 @@ public:
|
||||
qlonglong size = index.data().toLongLong();
|
||||
if (hideValues && (size <= 0))
|
||||
break;
|
||||
QItemDelegate::drawBackground(painter, opt, index);
|
||||
opt.displayAlignment = Qt::AlignRight | Qt::AlignVCenter;
|
||||
QItemDelegate::drawDisplay(painter, opt, option.rect, Utils::Misc::friendlyUnit(size));
|
||||
}
|
||||
break;
|
||||
case DOWN_SPEED:
|
||||
case UP_SPEED:{
|
||||
QItemDelegate::drawBackground(painter, opt, index);
|
||||
case UP_SPEED: {
|
||||
qreal speed = index.data().toDouble();
|
||||
if (speed <= 0.0)
|
||||
break;
|
||||
opt.displayAlignment = Qt::AlignRight | Qt::AlignVCenter;
|
||||
if (speed > 0.0)
|
||||
QItemDelegate::drawDisplay(painter, opt, opt.rect, Utils::Misc::friendlyUnit(speed, true));
|
||||
QItemDelegate::drawDisplay(painter, opt, opt.rect, Utils::Misc::friendlyUnit(speed, true));
|
||||
}
|
||||
break;
|
||||
case PROGRESS:
|
||||
case RELEVANCE: {
|
||||
QItemDelegate::drawBackground(painter, opt, index);
|
||||
qreal progress = index.data().toDouble();
|
||||
opt.displayAlignment = Qt::AlignRight | Qt::AlignVCenter;
|
||||
QItemDelegate::drawDisplay(painter, opt, opt.rect, Utils::String::fromDouble(progress*100.0, 1)+"%");
|
||||
QItemDelegate::drawDisplay(painter, opt, opt.rect, Utils::String::fromDouble(progress * 100.0, 1) + "%");
|
||||
}
|
||||
break;
|
||||
default:
|
||||
QItemDelegate::paint(painter, option, index);
|
||||
}
|
||||
|
||||
painter->restore();
|
||||
}
|
||||
|
||||
QWidget* createEditor(QWidget*, const QStyleOptionViewItem &, const QModelIndex &) const
|
||||
QWidget *createEditor(QWidget *, const QStyleOptionViewItem &, const QModelIndex &) const override
|
||||
{
|
||||
// No editor here
|
||||
return 0;
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
#endif // PEERLISTDELEGATE_H
|
||||
|
||||
@@ -28,6 +28,9 @@
|
||||
* Contact : chris@qbittorrent.org
|
||||
*/
|
||||
|
||||
#include "peerlistwidget.h"
|
||||
|
||||
#include <QApplication>
|
||||
#include <QStandardItemModel>
|
||||
#include <QSortFilterProxyModel>
|
||||
#include <QSet>
|
||||
@@ -53,7 +56,6 @@
|
||||
#include "guiiconprovider.h"
|
||||
#include "peerlistdelegate.h"
|
||||
#include "peerlistsortmodel.h"
|
||||
#include "peerlistwidget.h"
|
||||
|
||||
PeerListWidget::PeerListWidget(PropertiesWidget *parent)
|
||||
: QTreeView(parent)
|
||||
@@ -69,7 +71,7 @@ PeerListWidget::PeerListWidget(PropertiesWidget *parent)
|
||||
setSelectionMode(QAbstractItemView::ExtendedSelection);
|
||||
header()->setStretchLastSection(false);
|
||||
// List Model
|
||||
m_listModel = new QStandardItemModel(0, PeerListDelegate::COL_COUNT);
|
||||
m_listModel = new QStandardItemModel(0, PeerListDelegate::COL_COUNT, this);
|
||||
m_listModel->setHeaderData(PeerListDelegate::COUNTRY, Qt::Horizontal, tr("Country")); // Country flag column
|
||||
m_listModel->setHeaderData(PeerListDelegate::IP, Qt::Horizontal, tr("IP"));
|
||||
m_listModel->setHeaderData(PeerListDelegate::PORT, Qt::Horizontal, tr("Port"));
|
||||
@@ -92,7 +94,7 @@ PeerListWidget::PeerListWidget(PropertiesWidget *parent)
|
||||
m_listModel->setHeaderData(PeerListDelegate::TOT_UP, Qt::Horizontal, QVariant(Qt::AlignRight | Qt::AlignVCenter), Qt::TextAlignmentRole);
|
||||
m_listModel->setHeaderData(PeerListDelegate::RELEVANCE, Qt::Horizontal, QVariant(Qt::AlignRight | Qt::AlignVCenter), Qt::TextAlignmentRole);
|
||||
// Proxy model to support sorting without actually altering the underlying model
|
||||
m_proxyModel = new PeerListSortModel();
|
||||
m_proxyModel = new PeerListSortModel(this);
|
||||
m_proxyModel->setDynamicSortFilter(true);
|
||||
m_proxyModel->setSourceModel(m_listModel);
|
||||
m_proxyModel->setSortCaseSensitivity(Qt::CaseInsensitive);
|
||||
@@ -102,7 +104,7 @@ PeerListWidget::PeerListWidget(PropertiesWidget *parent)
|
||||
m_resolveCountries = Preferences::instance()->resolvePeerCountries();
|
||||
if (!m_resolveCountries)
|
||||
hideColumn(PeerListDelegate::COUNTRY);
|
||||
//Ensure that at least one column is visible at all times
|
||||
// Ensure that at least one column is visible at all times
|
||||
bool atLeastOne = false;
|
||||
for (unsigned int i = 0; i < PeerListDelegate::IP_HIDDEN; i++) {
|
||||
if (!isColumnHidden(i)) {
|
||||
@@ -112,9 +114,9 @@ PeerListWidget::PeerListWidget(PropertiesWidget *parent)
|
||||
}
|
||||
if (!atLeastOne)
|
||||
setColumnHidden(PeerListDelegate::IP, false);
|
||||
//To also mitigate the above issue, we have to resize each column when
|
||||
//its size is 0, because explicitly 'showing' the column isn't enough
|
||||
//in the above scenario.
|
||||
// To also mitigate the above issue, we have to resize each column when
|
||||
// its size is 0, because explicitly 'showing' the column isn't enough
|
||||
// in the above scenario.
|
||||
for (unsigned int i = 0; i < PeerListDelegate::IP_HIDDEN; i++)
|
||||
if ((columnWidth(i) <= 0) && !isColumnHidden(i))
|
||||
resizeColumnToContents(i);
|
||||
@@ -130,7 +132,7 @@ PeerListWidget::PeerListWidget(PropertiesWidget *parent)
|
||||
updatePeerHostNameResolutionState();
|
||||
// SIGNAL/SLOT
|
||||
header()->setContextMenuPolicy(Qt::CustomContextMenu);
|
||||
connect(header(), SIGNAL(customContextMenuRequested(const QPoint &)), this, SLOT(displayToggleColumnsMenu(const QPoint &)));
|
||||
connect(header(), SIGNAL(customContextMenuRequested(const QPoint&)), this, SLOT(displayToggleColumnsMenu(const QPoint&)));
|
||||
connect(header(), SIGNAL(sectionClicked(int)), SLOT(handleSortColumnChanged(int)));
|
||||
handleSortColumnChanged(header()->sortIndicatorSection());
|
||||
m_copyHotkey = new QShortcut(QKeySequence::Copy, this, SLOT(copySelectedPeers()), 0, Qt::WidgetShortcut);
|
||||
@@ -148,19 +150,15 @@ PeerListWidget::PeerListWidget(PropertiesWidget *parent)
|
||||
PeerListWidget::~PeerListWidget()
|
||||
{
|
||||
saveSettings();
|
||||
delete m_proxyModel;
|
||||
delete m_listModel;
|
||||
delete m_listDelegate;
|
||||
if (m_resolver)
|
||||
delete m_resolver;
|
||||
delete m_copyHotkey;
|
||||
}
|
||||
|
||||
void PeerListWidget::displayToggleColumnsMenu(const QPoint&)
|
||||
void PeerListWidget::displayToggleColumnsMenu(const QPoint &)
|
||||
{
|
||||
QMenu hideshowColumn(this);
|
||||
hideshowColumn.setTitle(tr("Column visibility"));
|
||||
QList<QAction*> actions;
|
||||
QList<QAction *> actions;
|
||||
for (int i = 0; i < PeerListDelegate::IP_HIDDEN; ++i) {
|
||||
if ((i == PeerListDelegate::COUNTRY) && !Preferences::instance()->resolvePeerCountries()) {
|
||||
actions.append(nullptr); // keep the index in sync
|
||||
@@ -201,7 +199,7 @@ void PeerListWidget::updatePeerHostNameResolutionState()
|
||||
if (Preferences::instance()->resolvePeerHostNames()) {
|
||||
if (!m_resolver) {
|
||||
m_resolver = new Net::ReverseResolution(this);
|
||||
connect(m_resolver, SIGNAL(ipResolved(QString, QString)), SLOT(handleResolved(QString, QString)));
|
||||
connect(m_resolver, SIGNAL(ipResolved(QString,QString)), SLOT(handleResolved(QString,QString)));
|
||||
loadPeers(m_properties->getCurrentTorrent(), true);
|
||||
}
|
||||
}
|
||||
@@ -226,7 +224,7 @@ void PeerListWidget::updatePeerCountryResolutionState()
|
||||
}
|
||||
}
|
||||
|
||||
void PeerListWidget::showPeerListMenu(const QPoint&)
|
||||
void PeerListWidget::showPeerListMenu(const QPoint &)
|
||||
{
|
||||
QMenu menu;
|
||||
bool emptyMenu = true;
|
||||
@@ -370,7 +368,7 @@ void PeerListWidget::loadPeers(BitTorrent::TorrentHandle *const torrent, bool fo
|
||||
// Delete peers that are gone
|
||||
QSetIterator<QString> it(oldeersSet);
|
||||
while (it.hasNext()) {
|
||||
const QString& ip = it.next();
|
||||
const QString &ip = it.next();
|
||||
m_missingFlags.remove(ip);
|
||||
m_peerAddresses.remove(ip);
|
||||
QStandardItem *item = m_peerItems.take(ip);
|
||||
@@ -378,7 +376,7 @@ void PeerListWidget::loadPeers(BitTorrent::TorrentHandle *const torrent, bool fo
|
||||
}
|
||||
}
|
||||
|
||||
QStandardItem* PeerListWidget::addPeer(const QString& ip, BitTorrent::TorrentHandle *const torrent, const BitTorrent::PeerInfo &peer)
|
||||
QStandardItem *PeerListWidget::addPeer(const QString &ip, BitTorrent::TorrentHandle *const torrent, const BitTorrent::PeerInfo &peer)
|
||||
{
|
||||
int row = m_listModel->rowCount();
|
||||
// Adding Peer to peer list
|
||||
@@ -468,7 +466,7 @@ void PeerListWidget::wheelEvent(QWheelEvent *event)
|
||||
{
|
||||
event->accept();
|
||||
|
||||
if(event->modifiers() & Qt::ShiftModifier) {
|
||||
if (event->modifiers() & Qt::ShiftModifier) {
|
||||
// Shift + scroll = horizontal scroll
|
||||
QWheelEvent scrollHEvent(event->pos(), event->globalPos(), event->delta(), event->buttons(), event->modifiers(), Qt::Horizontal);
|
||||
QTreeView::wheelEvent(&scrollHEvent);
|
||||
|
||||
@@ -77,8 +77,8 @@ public:
|
||||
private slots:
|
||||
void loadSettings();
|
||||
void saveSettings() const;
|
||||
void displayToggleColumnsMenu(const QPoint&);
|
||||
void showPeerListMenu(const QPoint&);
|
||||
void displayToggleColumnsMenu(const QPoint &);
|
||||
void showPeerListMenu(const QPoint &);
|
||||
void banSelectedPeers();
|
||||
void copySelectedPeers();
|
||||
void handleSortColumnChanged(int col);
|
||||
@@ -90,7 +90,7 @@ private:
|
||||
QStandardItemModel *m_listModel;
|
||||
PeerListDelegate *m_listDelegate;
|
||||
PeerListSortModel *m_proxyModel;
|
||||
QHash<QString, QStandardItem*> m_peerItems;
|
||||
QHash<QString, QStandardItem *> m_peerItems;
|
||||
QHash<QString, BitTorrent::PeerAddress> m_peerAddresses;
|
||||
QSet<QString> m_missingFlags;
|
||||
QPointer<Net::ReverseResolution> m_resolver;
|
||||
|
||||
@@ -28,23 +28,31 @@
|
||||
* Contact : chris@qbittorrent.org
|
||||
*/
|
||||
|
||||
#include "peersadditiondlg.h"
|
||||
|
||||
#include <QMessageBox>
|
||||
#include <QHostAddress>
|
||||
|
||||
#include "peersadditiondlg.h"
|
||||
#include "ui_peersadditiondlg.h"
|
||||
|
||||
PeersAdditionDlg::PeersAdditionDlg(QWidget *parent)
|
||||
: QDialog(parent)
|
||||
, m_ui(new Ui::addPeersDialog())
|
||||
{
|
||||
setupUi(this);
|
||||
connect(buttonBox, SIGNAL(accepted()), this, SLOT(validateInput()));
|
||||
m_ui->setupUi(this);
|
||||
connect(m_ui->buttonBox, SIGNAL(accepted()), this, SLOT(validateInput()));
|
||||
|
||||
#ifdef QBT_USES_QT5
|
||||
label_format->hide();
|
||||
peers_txt->setPlaceholderText("Format: IPv4:port / [IPv6]:port");
|
||||
m_ui->label_format->hide();
|
||||
m_ui->peers_txt->setPlaceholderText("Format: IPv4:port / [IPv6]:port");
|
||||
#endif
|
||||
}
|
||||
|
||||
PeersAdditionDlg::~PeersAdditionDlg()
|
||||
{
|
||||
delete m_ui;
|
||||
}
|
||||
|
||||
QList<BitTorrent::PeerAddress> PeersAdditionDlg::askForPeers()
|
||||
{
|
||||
PeersAdditionDlg dlg;
|
||||
@@ -54,13 +62,13 @@ QList<BitTorrent::PeerAddress> PeersAdditionDlg::askForPeers()
|
||||
|
||||
void PeersAdditionDlg::validateInput()
|
||||
{
|
||||
if (peers_txt->toPlainText().trimmed().isEmpty()) {
|
||||
if (m_ui->peers_txt->toPlainText().trimmed().isEmpty()) {
|
||||
QMessageBox::warning(this, tr("No peer entered"),
|
||||
tr("Please type at least one peer."),
|
||||
QMessageBox::Ok);
|
||||
return;
|
||||
}
|
||||
foreach (const QString &peer, peers_txt->toPlainText().trimmed().split("\n")) {
|
||||
foreach (const QString &peer, m_ui->peers_txt->toPlainText().trimmed().split("\n")) {
|
||||
BitTorrent::PeerAddress addr = parsePeer(peer);
|
||||
if (!addr.ip.isNull()) {
|
||||
m_peersList.append(addr);
|
||||
|
||||
@@ -34,14 +34,21 @@
|
||||
#include <QDialog>
|
||||
|
||||
#include "base/bittorrent/peerinfo.h"
|
||||
#include "ui_peersadditiondlg.h"
|
||||
|
||||
class PeersAdditionDlg: public QDialog, private Ui::addPeersDialog
|
||||
template <class T> class QList;
|
||||
|
||||
namespace Ui
|
||||
{
|
||||
class addPeersDialog;
|
||||
}
|
||||
|
||||
class PeersAdditionDlg: public QDialog
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
PeersAdditionDlg(QWidget *parent = 0);
|
||||
~PeersAdditionDlg();
|
||||
|
||||
static QList<BitTorrent::PeerAddress> askForPeers();
|
||||
|
||||
@@ -50,6 +57,8 @@ protected slots:
|
||||
|
||||
private:
|
||||
BitTorrent::PeerAddress parsePeer(QString peer);
|
||||
|
||||
Ui::addPeersDialog *m_ui;
|
||||
QList<BitTorrent::PeerAddress> m_peersList;
|
||||
|
||||
};
|
||||
|
||||
@@ -50,7 +50,8 @@ namespace
|
||||
{
|
||||
public:
|
||||
PieceIndexToImagePos(const BitTorrent::TorrentInfo &torrentInfo, const QImage &image)
|
||||
: m_bytesPerPixel {image.width() > 0 ? torrentInfo.totalSize() / image.width() : -1}
|
||||
: m_bytesPerPixel {(image.width() > 0 && torrentInfo.totalSize() >= image.width())
|
||||
? torrentInfo.totalSize() / image.width() : -1}
|
||||
, m_torrentInfo {torrentInfo}
|
||||
{
|
||||
if ((m_bytesPerPixel > 0) && (m_bytesPerPixel < 10))
|
||||
@@ -251,8 +252,8 @@ void PiecesBar::showToolTip(const QHelpEvent *e)
|
||||
|
||||
QString toolTipText;
|
||||
QTextStream stream(&toolTipText, QIODevice::WriteOnly);
|
||||
bool showDetailedInformation = QApplication::keyboardModifiers().testFlag(Qt::ShiftModifier);
|
||||
if (showDetailedInformation) {
|
||||
const bool showDetailedInformation = QApplication::keyboardModifiers().testFlag(Qt::ShiftModifier);
|
||||
if (showDetailedInformation && m_torrent->hasMetadata()) {
|
||||
const int imagePos = e->pos().x() - borderWidth;
|
||||
if ((imagePos >=0) && (imagePos < m_image.width())) {
|
||||
stream << "<html><body>";
|
||||
@@ -286,7 +287,10 @@ void PiecesBar::showToolTip(const QHelpEvent *e)
|
||||
}
|
||||
else {
|
||||
stream << simpleToolTipText();
|
||||
stream << '\n' << tr("Hold Shift key for detailed information");
|
||||
if (showDetailedInformation) // metadata are not available at this point
|
||||
stream << '\n' << tr("Wait until metadata become available to see detailed information");
|
||||
else
|
||||
stream << '\n' << tr("Hold Shift key for detailed information");
|
||||
}
|
||||
|
||||
stream.flush();
|
||||
@@ -296,7 +300,7 @@ void PiecesBar::showToolTip(const QHelpEvent *e)
|
||||
|
||||
void PiecesBar::highlightFile(int imagePos)
|
||||
{
|
||||
if (!m_torrent || (imagePos < 0) || (imagePos >= m_image.width()))
|
||||
if (!m_torrent || !m_torrent->hasMetadata() || (imagePos < 0) || (imagePos >= m_image.width()))
|
||||
return;
|
||||
|
||||
PieceIndexToImagePos transform {m_torrent->info(), m_image};
|
||||
|
||||
@@ -39,6 +39,7 @@
|
||||
#include <QHeaderView>
|
||||
#include <QAction>
|
||||
#include <QMenu>
|
||||
#include <QModelIndex>
|
||||
#include <QFileDialog>
|
||||
#include <QBitArray>
|
||||
|
||||
@@ -64,43 +65,49 @@
|
||||
#include "transferlistwidget.h"
|
||||
#include "autoexpandabledialog.h"
|
||||
|
||||
#include "ui_propertieswidget.h"
|
||||
|
||||
PropertiesWidget::PropertiesWidget(QWidget *parent, MainWindow *main_window, TransferListWidget *transferList)
|
||||
: QWidget(parent), transferList(transferList), main_window(main_window), m_torrent(0)
|
||||
: QWidget(parent)
|
||||
, m_ui(new Ui::PropertiesWidget())
|
||||
, transferList(transferList)
|
||||
, main_window(main_window)
|
||||
, m_torrent(0)
|
||||
{
|
||||
setupUi(this);
|
||||
m_ui->setupUi(this);
|
||||
setAutoFillBackground(true);
|
||||
|
||||
state = VISIBLE;
|
||||
|
||||
// Set Properties list model
|
||||
PropListModel = new TorrentContentFilterModel();
|
||||
filesList->setModel(PropListModel);
|
||||
m_ui->filesList->setModel(PropListModel);
|
||||
PropDelegate = new PropListDelegate(this);
|
||||
filesList->setItemDelegate(PropDelegate);
|
||||
filesList->setSortingEnabled(true);
|
||||
m_ui->filesList->setItemDelegate(PropDelegate);
|
||||
m_ui->filesList->setSortingEnabled(true);
|
||||
// Torrent content filtering
|
||||
m_contentFilterLine = new LineEdit(this);
|
||||
m_contentFilterLine->setPlaceholderText(tr("Filter files..."));
|
||||
m_contentFilterLine->setMaximumSize(300, m_contentFilterLine->size().height());
|
||||
connect(m_contentFilterLine, SIGNAL(textChanged(QString)), this, SLOT(filterText(QString)));
|
||||
contentFilterLayout->insertWidget(3, m_contentFilterLine);
|
||||
m_ui->contentFilterLayout->insertWidget(3, m_contentFilterLine);
|
||||
|
||||
// SIGNAL/SLOTS
|
||||
connect(filesList, SIGNAL(clicked(const QModelIndex&)), filesList, SLOT(edit(const QModelIndex&)));
|
||||
connect(selectAllButton, SIGNAL(clicked()), PropListModel, SLOT(selectAll()));
|
||||
connect(selectNoneButton, SIGNAL(clicked()), PropListModel, SLOT(selectNone()));
|
||||
connect(filesList, SIGNAL(customContextMenuRequested(const QPoint&)), this, SLOT(displayFilesListMenu(const QPoint&)));
|
||||
connect(filesList, SIGNAL(doubleClicked(const QModelIndex&)), this, SLOT(openDoubleClickedFile(const QModelIndex&)));
|
||||
connect(m_ui->filesList, SIGNAL(clicked(const QModelIndex&)), m_ui->filesList, SLOT(edit(const QModelIndex&)));
|
||||
connect(m_ui->selectAllButton, SIGNAL(clicked()), PropListModel, SLOT(selectAll()));
|
||||
connect(m_ui->selectNoneButton, SIGNAL(clicked()), PropListModel, SLOT(selectNone()));
|
||||
connect(m_ui->filesList, SIGNAL(customContextMenuRequested(const QPoint&)), this, SLOT(displayFilesListMenu(const QPoint&)));
|
||||
connect(m_ui->filesList, SIGNAL(doubleClicked(const QModelIndex&)), this, SLOT(openDoubleClickedFile(const QModelIndex&)));
|
||||
connect(PropListModel, SIGNAL(filteredFilesChanged()), this, SLOT(filteredFilesChanged()));
|
||||
connect(listWebSeeds, SIGNAL(customContextMenuRequested(const QPoint&)), this, SLOT(displayWebSeedListMenu(const QPoint&)));
|
||||
connect(m_ui->listWebSeeds, SIGNAL(customContextMenuRequested(const QPoint&)), this, SLOT(displayWebSeedListMenu(const QPoint&)));
|
||||
connect(transferList, SIGNAL(currentTorrentChanged(BitTorrent::TorrentHandle * const)), this, SLOT(loadTorrentInfos(BitTorrent::TorrentHandle * const)));
|
||||
connect(PropDelegate, SIGNAL(filteredFilesChanged()), this, SLOT(filteredFilesChanged()));
|
||||
connect(stackedProperties, SIGNAL(currentChanged(int)), this, SLOT(loadDynamicData()));
|
||||
connect(m_ui->stackedProperties, SIGNAL(currentChanged(int)), this, SLOT(loadDynamicData()));
|
||||
connect(BitTorrent::Session::instance(), SIGNAL(torrentSavePathChanged(BitTorrent::TorrentHandle * const)), this, SLOT(updateSavePath(BitTorrent::TorrentHandle * const)));
|
||||
connect(BitTorrent::Session::instance(), SIGNAL(torrentMetadataLoaded(BitTorrent::TorrentHandle * const)), this, SLOT(updateTorrentInfos(BitTorrent::TorrentHandle * const)));
|
||||
connect(filesList->header(), SIGNAL(sectionMoved(int,int,int)), this, SLOT(saveSettings()));
|
||||
connect(filesList->header(), SIGNAL(sectionResized(int,int,int)), this, SLOT(saveSettings()));
|
||||
connect(filesList->header(), SIGNAL(sortIndicatorChanged(int,Qt::SortOrder)), this, SLOT(saveSettings()));
|
||||
connect(m_ui->filesList->header(), SIGNAL(sectionMoved(int,int,int)), this, SLOT(saveSettings()));
|
||||
connect(m_ui->filesList->header(), SIGNAL(sectionResized(int,int,int)), this, SLOT(saveSettings()));
|
||||
connect(m_ui->filesList->header(), SIGNAL(sortIndicatorChanged(int,Qt::SortOrder)), this, SLOT(saveSettings()));
|
||||
|
||||
#ifdef QBT_USES_QT5
|
||||
// set bar height relative to screen dpi
|
||||
@@ -113,45 +120,45 @@ PropertiesWidget::PropertiesWidget(QWidget *parent, MainWindow *main_window, Tra
|
||||
#endif
|
||||
|
||||
// Downloaded pieces progress bar
|
||||
tempProgressBarArea->setVisible(false);
|
||||
m_ui->tempProgressBarArea->setVisible(false);
|
||||
downloaded_pieces = new DownloadedPiecesBar(this);
|
||||
groupBarLayout->addWidget(downloaded_pieces, 0, 1);
|
||||
m_ui->groupBarLayout->addWidget(downloaded_pieces, 0, 1);
|
||||
downloaded_pieces->setFixedHeight(barHeight);
|
||||
downloaded_pieces->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Fixed);
|
||||
|
||||
// Pieces availability bar
|
||||
tempAvailabilityBarArea->setVisible(false);
|
||||
m_ui->tempAvailabilityBarArea->setVisible(false);
|
||||
pieces_availability = new PieceAvailabilityBar(this);
|
||||
groupBarLayout->addWidget(pieces_availability, 1, 1);
|
||||
m_ui->groupBarLayout->addWidget(pieces_availability, 1, 1);
|
||||
pieces_availability->setFixedHeight(barHeight);
|
||||
pieces_availability->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Fixed);
|
||||
|
||||
// Tracker list
|
||||
trackerList = new TrackerList(this);
|
||||
trackerUpButton->setIcon(GuiIconProvider::instance()->getIcon("go-up"));
|
||||
trackerUpButton->setIconSize(Utils::Misc::smallIconSize());
|
||||
trackerDownButton->setIcon(GuiIconProvider::instance()->getIcon("go-down"));
|
||||
trackerDownButton->setIconSize(Utils::Misc::smallIconSize());
|
||||
connect(trackerUpButton, SIGNAL(clicked()), trackerList, SLOT(moveSelectionUp()));
|
||||
connect(trackerDownButton, SIGNAL(clicked()), trackerList, SLOT(moveSelectionDown()));
|
||||
horizontalLayout_trackers->insertWidget(0, trackerList);
|
||||
m_ui->trackerUpButton->setIcon(GuiIconProvider::instance()->getIcon("go-up"));
|
||||
m_ui->trackerUpButton->setIconSize(Utils::Misc::smallIconSize());
|
||||
m_ui->trackerDownButton->setIcon(GuiIconProvider::instance()->getIcon("go-down"));
|
||||
m_ui->trackerDownButton->setIconSize(Utils::Misc::smallIconSize());
|
||||
connect(m_ui->trackerUpButton, SIGNAL(clicked()), trackerList, SLOT(moveSelectionUp()));
|
||||
connect(m_ui->trackerDownButton, SIGNAL(clicked()), trackerList, SLOT(moveSelectionDown()));
|
||||
m_ui->horizontalLayout_trackers->insertWidget(0, trackerList);
|
||||
connect(trackerList->header(), SIGNAL(sectionMoved(int,int,int)), trackerList, SLOT(saveSettings()));
|
||||
connect(trackerList->header(), SIGNAL(sectionResized(int,int,int)), trackerList, SLOT(saveSettings()));
|
||||
connect(trackerList->header(), SIGNAL(sortIndicatorChanged(int,Qt::SortOrder)), trackerList, SLOT(saveSettings()));
|
||||
// Peers list
|
||||
peersList = new PeerListWidget(this);
|
||||
peerpage_layout->addWidget(peersList);
|
||||
m_ui->peerpage_layout->addWidget(peersList);
|
||||
connect(peersList->header(), SIGNAL(sectionMoved(int,int,int)), peersList, SLOT(saveSettings()));
|
||||
connect(peersList->header(), SIGNAL(sectionResized(int,int,int)), peersList, SLOT(saveSettings()));
|
||||
connect(peersList->header(), SIGNAL(sortIndicatorChanged(int,Qt::SortOrder)), peersList, SLOT(saveSettings()));
|
||||
// Speed widget
|
||||
speedWidget = new SpeedWidget(this);
|
||||
speed_layout->addWidget(speedWidget);
|
||||
m_ui->speed_layout->addWidget(speedWidget);
|
||||
// Tab bar
|
||||
m_tabBar = new PropTabBar();
|
||||
m_tabBar->setContentsMargins(0, 5, 0, 0);
|
||||
verticalLayout->addLayout(m_tabBar);
|
||||
connect(m_tabBar, SIGNAL(tabChanged(int)), stackedProperties, SLOT(setCurrentIndex(int)));
|
||||
m_ui->verticalLayout->addLayout(m_tabBar);
|
||||
connect(m_tabBar, SIGNAL(tabChanged(int)), m_ui->stackedProperties, SLOT(setCurrentIndex(int)));
|
||||
connect(m_tabBar, SIGNAL(tabChanged(int)), this, SLOT(saveSettings()));
|
||||
connect(m_tabBar, SIGNAL(visibilityToggled(bool)), SLOT(setVisibility(bool)));
|
||||
connect(m_tabBar, SIGNAL(visibilityToggled(bool)), this, SLOT(saveSettings()));
|
||||
@@ -159,14 +166,14 @@ PropertiesWidget::PropertiesWidget(QWidget *parent, MainWindow *main_window, Tra
|
||||
refreshTimer = new QTimer(this);
|
||||
connect(refreshTimer, SIGNAL(timeout()), this, SLOT(loadDynamicData()));
|
||||
refreshTimer->start(3000); // 3sec
|
||||
editHotkeyFile = new QShortcut(Qt::Key_F2, filesList, 0, 0, Qt::WidgetShortcut);
|
||||
editHotkeyFile = new QShortcut(Qt::Key_F2, m_ui->filesList, 0, 0, Qt::WidgetShortcut);
|
||||
connect(editHotkeyFile, SIGNAL(activated()), SLOT(renameSelectedFile()));
|
||||
editHotkeyWeb = new QShortcut(Qt::Key_F2, listWebSeeds, 0, 0, Qt::WidgetShortcut);
|
||||
editHotkeyWeb = new QShortcut(Qt::Key_F2, m_ui->listWebSeeds, 0, 0, Qt::WidgetShortcut);
|
||||
connect(editHotkeyWeb, SIGNAL(activated()), SLOT(editWebSeed()));
|
||||
connect(listWebSeeds, SIGNAL(doubleClicked(QModelIndex)), SLOT(editWebSeed()));
|
||||
deleteHotkeyWeb = new QShortcut(QKeySequence::Delete, listWebSeeds, 0, 0, Qt::WidgetShortcut);
|
||||
connect(m_ui->listWebSeeds, SIGNAL(doubleClicked(QModelIndex)), SLOT(editWebSeed()));
|
||||
deleteHotkeyWeb = new QShortcut(QKeySequence::Delete, m_ui->listWebSeeds, 0, 0, Qt::WidgetShortcut);
|
||||
connect(deleteHotkeyWeb, SIGNAL(activated()), SLOT(deleteSelectedUrlSeeds()));
|
||||
openHotkeyFile = new QShortcut(Qt::Key_Return, filesList, 0, 0, Qt::WidgetShortcut);
|
||||
openHotkeyFile = new QShortcut(Qt::Key_Return, m_ui->filesList, 0, 0, Qt::WidgetShortcut);
|
||||
connect(openHotkeyFile, SIGNAL(activated()), SLOT(openSelectedFile()));
|
||||
}
|
||||
|
||||
@@ -186,32 +193,33 @@ PropertiesWidget::~PropertiesWidget()
|
||||
delete editHotkeyWeb;
|
||||
delete deleteHotkeyWeb;
|
||||
delete openHotkeyFile;
|
||||
delete m_ui;
|
||||
qDebug() << Q_FUNC_INFO << "EXIT";
|
||||
}
|
||||
|
||||
void PropertiesWidget::showPiecesAvailability(bool show)
|
||||
{
|
||||
avail_pieces_lbl->setVisible(show);
|
||||
m_ui->avail_pieces_lbl->setVisible(show);
|
||||
pieces_availability->setVisible(show);
|
||||
avail_average_lbl->setVisible(show);
|
||||
m_ui->avail_average_lbl->setVisible(show);
|
||||
if (show || !downloaded_pieces->isVisible())
|
||||
line_2->setVisible(show);
|
||||
m_ui->line_2->setVisible(show);
|
||||
}
|
||||
|
||||
void PropertiesWidget::showPiecesDownloaded(bool show)
|
||||
{
|
||||
downloaded_pieces_lbl->setVisible(show);
|
||||
m_ui->downloaded_pieces_lbl->setVisible(show);
|
||||
downloaded_pieces->setVisible(show);
|
||||
progress_lbl->setVisible(show);
|
||||
m_ui->progress_lbl->setVisible(show);
|
||||
if (show || !pieces_availability->isVisible())
|
||||
line_2->setVisible(show);
|
||||
m_ui->line_2->setVisible(show);
|
||||
}
|
||||
|
||||
void PropertiesWidget::setVisibility(bool visible)
|
||||
{
|
||||
if (!visible && ( state == VISIBLE) ) {
|
||||
QSplitter *hSplitter = static_cast<QSplitter *>(parentWidget());
|
||||
stackedProperties->setVisible(false);
|
||||
m_ui->stackedProperties->setVisible(false);
|
||||
slideSizes = hSplitter->sizes();
|
||||
hSplitter->handle(1)->setVisible(false);
|
||||
hSplitter->handle(1)->setDisabled(true);
|
||||
@@ -222,7 +230,7 @@ void PropertiesWidget::setVisibility(bool visible)
|
||||
}
|
||||
|
||||
if (visible && ( state == REDUCED) ) {
|
||||
stackedProperties->setVisible(true);
|
||||
m_ui->stackedProperties->setVisible(true);
|
||||
QSplitter *hSplitter = static_cast<QSplitter *>(parentWidget());
|
||||
hSplitter->handle(1)->setDisabled(false);
|
||||
hSplitter->handle(1)->setVisible(true);
|
||||
@@ -236,39 +244,39 @@ void PropertiesWidget::setVisibility(bool visible)
|
||||
void PropertiesWidget::clear()
|
||||
{
|
||||
qDebug("Clearing torrent properties");
|
||||
save_path->clear();
|
||||
lbl_creationDate->clear();
|
||||
label_total_pieces_val->clear();
|
||||
hash_lbl->clear();
|
||||
comment_text->clear();
|
||||
progress_lbl->clear();
|
||||
m_ui->save_path->clear();
|
||||
m_ui->lbl_creationDate->clear();
|
||||
m_ui->label_total_pieces_val->clear();
|
||||
m_ui->hash_lbl->clear();
|
||||
m_ui->comment_text->clear();
|
||||
m_ui->progress_lbl->clear();
|
||||
trackerList->clear();
|
||||
downloaded_pieces->clear();
|
||||
pieces_availability->clear();
|
||||
avail_average_lbl->clear();
|
||||
wasted->clear();
|
||||
upTotal->clear();
|
||||
dlTotal->clear();
|
||||
m_ui->avail_average_lbl->clear();
|
||||
m_ui->wasted->clear();
|
||||
m_ui->upTotal->clear();
|
||||
m_ui->dlTotal->clear();
|
||||
peersList->clear();
|
||||
lbl_uplimit->clear();
|
||||
lbl_dllimit->clear();
|
||||
lbl_elapsed->clear();
|
||||
lbl_connections->clear();
|
||||
reannounce_lbl->clear();
|
||||
shareRatio->clear();
|
||||
listWebSeeds->clear();
|
||||
m_ui->lbl_uplimit->clear();
|
||||
m_ui->lbl_dllimit->clear();
|
||||
m_ui->lbl_elapsed->clear();
|
||||
m_ui->lbl_connections->clear();
|
||||
m_ui->reannounce_lbl->clear();
|
||||
m_ui->shareRatio->clear();
|
||||
m_ui->listWebSeeds->clear();
|
||||
m_contentFilterLine->clear();
|
||||
PropListModel->model()->clear();
|
||||
label_eta_val->clear();
|
||||
label_seeds_val->clear();
|
||||
label_peers_val->clear();
|
||||
label_dl_speed_val->clear();
|
||||
label_upload_speed_val->clear();
|
||||
label_total_size_val->clear();
|
||||
label_completed_on_val->clear();
|
||||
label_last_complete_val->clear();
|
||||
label_created_by_val->clear();
|
||||
label_added_on_val->clear();
|
||||
m_ui->label_eta_val->clear();
|
||||
m_ui->label_seeds_val->clear();
|
||||
m_ui->label_peers_val->clear();
|
||||
m_ui->label_dl_speed_val->clear();
|
||||
m_ui->label_upload_speed_val->clear();
|
||||
m_ui->label_total_size_val->clear();
|
||||
m_ui->label_completed_on_val->clear();
|
||||
m_ui->label_last_complete_val->clear();
|
||||
m_ui->label_created_by_val->clear();
|
||||
m_ui->label_added_on_val->clear();
|
||||
}
|
||||
|
||||
BitTorrent::TorrentHandle *PropertiesWidget::getCurrentTorrent() const
|
||||
@@ -276,10 +284,15 @@ BitTorrent::TorrentHandle *PropertiesWidget::getCurrentTorrent() const
|
||||
return m_torrent;
|
||||
}
|
||||
|
||||
QTreeView *PropertiesWidget::getFilesList() const
|
||||
{
|
||||
return m_ui->filesList;
|
||||
}
|
||||
|
||||
void PropertiesWidget::updateSavePath(BitTorrent::TorrentHandle *const torrent)
|
||||
{
|
||||
if (m_torrent == torrent)
|
||||
save_path->setText(Utils::Fs::toNativePath(m_torrent->savePath()));
|
||||
m_ui->save_path->setText(Utils::Fs::toNativePath(m_torrent->savePath()));
|
||||
}
|
||||
|
||||
void PropertiesWidget::loadTrackers(BitTorrent::TorrentHandle *const torrent)
|
||||
@@ -305,25 +318,25 @@ void PropertiesWidget::loadTorrentInfos(BitTorrent::TorrentHandle *const torrent
|
||||
// Save path
|
||||
updateSavePath(m_torrent);
|
||||
// Hash
|
||||
hash_lbl->setText(m_torrent->hash());
|
||||
m_ui->hash_lbl->setText(m_torrent->hash());
|
||||
PropListModel->model()->clear();
|
||||
if (m_torrent->hasMetadata()) {
|
||||
// Creation date
|
||||
lbl_creationDate->setText(m_torrent->creationDate().toString(Qt::DefaultLocaleShortDate));
|
||||
m_ui->lbl_creationDate->setText(m_torrent->creationDate().toString(Qt::DefaultLocaleShortDate));
|
||||
|
||||
label_total_size_val->setText(Utils::Misc::friendlyUnit(m_torrent->totalSize()));
|
||||
m_ui->label_total_size_val->setText(Utils::Misc::friendlyUnit(m_torrent->totalSize()));
|
||||
|
||||
// Comment
|
||||
comment_text->setText(Utils::Misc::parseHtmlLinks(Utils::String::toHtmlEscaped(m_torrent->comment())));
|
||||
m_ui->comment_text->setText(Utils::Misc::parseHtmlLinks(Utils::String::toHtmlEscaped(m_torrent->comment())));
|
||||
|
||||
// URL seeds
|
||||
loadUrlSeeds();
|
||||
|
||||
label_created_by_val->setText(Utils::String::toHtmlEscaped(m_torrent->creator()));
|
||||
m_ui->label_created_by_val->setText(Utils::String::toHtmlEscaped(m_torrent->creator()));
|
||||
|
||||
// List files in torrent
|
||||
PropListModel->model()->setupModelData(m_torrent->info());
|
||||
filesList->setExpanded(PropListModel->index(0, 0), true);
|
||||
m_ui->filesList->setExpanded(PropListModel->index(0, 0), true);
|
||||
|
||||
// Load file priorities
|
||||
PropListModel->model()->updateFilesPriorities(m_torrent->filePriorities());
|
||||
@@ -346,8 +359,8 @@ void PropertiesWidget::readSettings()
|
||||
const int current_tab = pref->getPropCurTab();
|
||||
const bool visible = pref->getPropVisible();
|
||||
// the following will call saveSettings but shouldn't change any state
|
||||
if (!filesList->header()->restoreState(pref->getPropFileListState()))
|
||||
filesList->header()->resizeSection(0, 400); // Default
|
||||
if (!m_ui->filesList->header()->restoreState(pref->getPropFileListState()))
|
||||
m_ui->filesList->header()->resizeSection(0, 400); // Default
|
||||
m_tabBar->setCurrentIndex(current_tab);
|
||||
if (!visible)
|
||||
setVisibility(false);
|
||||
@@ -367,7 +380,7 @@ void PropertiesWidget::saveSettings()
|
||||
qDebug("Sizes: %d", sizes.size());
|
||||
if (sizes.size() == 2)
|
||||
pref->setPropSplitterSizes(QString::number(sizes.first()) + ',' + QString::number(sizes.last()));
|
||||
pref->setPropFileListState(filesList->header()->saveState());
|
||||
pref->setPropFileListState(m_ui->filesList->header()->saveState());
|
||||
// Remember current tab
|
||||
pref->setPropCurTab(m_tabBar->currentIndex());
|
||||
}
|
||||
@@ -385,19 +398,19 @@ void PropertiesWidget::loadDynamicData()
|
||||
if (!m_torrent || (main_window->currentTabWidget() != transferList) || (state != VISIBLE)) return;
|
||||
|
||||
// Transfer infos
|
||||
switch (stackedProperties->currentIndex()) {
|
||||
switch (m_ui->stackedProperties->currentIndex()) {
|
||||
case PropTabBar::MAIN_TAB: {
|
||||
wasted->setText(Utils::Misc::friendlyUnit(m_torrent->wastedSize()));
|
||||
m_ui->wasted->setText(Utils::Misc::friendlyUnit(m_torrent->wastedSize()));
|
||||
|
||||
upTotal->setText(tr("%1 (%2 this session)").arg(Utils::Misc::friendlyUnit(m_torrent->totalUpload()))
|
||||
m_ui->upTotal->setText(tr("%1 (%2 this session)").arg(Utils::Misc::friendlyUnit(m_torrent->totalUpload()))
|
||||
.arg(Utils::Misc::friendlyUnit(m_torrent->totalPayloadUpload())));
|
||||
|
||||
dlTotal->setText(tr("%1 (%2 this session)").arg(Utils::Misc::friendlyUnit(m_torrent->totalDownload()))
|
||||
m_ui->dlTotal->setText(tr("%1 (%2 this session)").arg(Utils::Misc::friendlyUnit(m_torrent->totalDownload()))
|
||||
.arg(Utils::Misc::friendlyUnit(m_torrent->totalPayloadDownload())));
|
||||
|
||||
lbl_uplimit->setText(m_torrent->uploadLimit() <= 0 ? QString::fromUtf8(C_INFINITY) : Utils::Misc::friendlyUnit(m_torrent->uploadLimit(), true));
|
||||
m_ui->lbl_uplimit->setText(m_torrent->uploadLimit() <= 0 ? QString::fromUtf8(C_INFINITY) : Utils::Misc::friendlyUnit(m_torrent->uploadLimit(), true));
|
||||
|
||||
lbl_dllimit->setText(m_torrent->downloadLimit() <= 0 ? QString::fromUtf8(C_INFINITY) : Utils::Misc::friendlyUnit(m_torrent->downloadLimit(), true));
|
||||
m_ui->lbl_dllimit->setText(m_torrent->downloadLimit() <= 0 ? QString::fromUtf8(C_INFINITY) : Utils::Misc::friendlyUnit(m_torrent->downloadLimit(), true));
|
||||
|
||||
QString elapsed_txt;
|
||||
if (m_torrent->isSeed())
|
||||
@@ -406,51 +419,51 @@ void PropertiesWidget::loadDynamicData()
|
||||
.arg(Utils::Misc::userFriendlyDuration(m_torrent->seedingTime()));
|
||||
else
|
||||
elapsed_txt = Utils::Misc::userFriendlyDuration(m_torrent->activeTime());
|
||||
lbl_elapsed->setText(elapsed_txt);
|
||||
m_ui->lbl_elapsed->setText(elapsed_txt);
|
||||
|
||||
lbl_connections->setText(tr("%1 (%2 max)", "%1 and %2 are numbers, e.g. 3 (10 max)")
|
||||
m_ui->lbl_connections->setText(tr("%1 (%2 max)", "%1 and %2 are numbers, e.g. 3 (10 max)")
|
||||
.arg(m_torrent->connectionsCount())
|
||||
.arg(m_torrent->connectionsLimit() < 0 ? QString::fromUtf8(C_INFINITY) : QString::number(m_torrent->connectionsLimit())));
|
||||
|
||||
label_eta_val->setText(Utils::Misc::userFriendlyDuration(m_torrent->eta()));
|
||||
m_ui->label_eta_val->setText(Utils::Misc::userFriendlyDuration(m_torrent->eta()));
|
||||
|
||||
// Update next announce time
|
||||
reannounce_lbl->setText(Utils::Misc::userFriendlyDuration(m_torrent->nextAnnounce()));
|
||||
m_ui->reannounce_lbl->setText(Utils::Misc::userFriendlyDuration(m_torrent->nextAnnounce()));
|
||||
|
||||
// Update ratio info
|
||||
const qreal ratio = m_torrent->realRatio();
|
||||
shareRatio->setText(ratio > BitTorrent::TorrentHandle::MAX_RATIO ? QString::fromUtf8(C_INFINITY) : Utils::String::fromDouble(ratio, 2));
|
||||
m_ui->shareRatio->setText(ratio > BitTorrent::TorrentHandle::MAX_RATIO ? QString::fromUtf8(C_INFINITY) : Utils::String::fromDouble(ratio, 2));
|
||||
|
||||
label_seeds_val->setText(tr("%1 (%2 total)", "%1 and %2 are numbers, e.g. 3 (10 total)")
|
||||
m_ui->label_seeds_val->setText(tr("%1 (%2 total)", "%1 and %2 are numbers, e.g. 3 (10 total)")
|
||||
.arg(QString::number(m_torrent->seedsCount()))
|
||||
.arg(QString::number(m_torrent->totalSeedsCount())));
|
||||
|
||||
label_peers_val->setText(tr("%1 (%2 total)", "%1 and %2 are numbers, e.g. 3 (10 total)")
|
||||
m_ui->label_peers_val->setText(tr("%1 (%2 total)", "%1 and %2 are numbers, e.g. 3 (10 total)")
|
||||
.arg(QString::number(m_torrent->leechsCount()))
|
||||
.arg(QString::number(m_torrent->totalLeechersCount())));
|
||||
|
||||
label_dl_speed_val->setText(tr("%1 (%2 avg.)", "%1 and %2 are speed rates, e.g. 200KiB/s (100KiB/s avg.)")
|
||||
m_ui->label_dl_speed_val->setText(tr("%1 (%2 avg.)", "%1 and %2 are speed rates, e.g. 200KiB/s (100KiB/s avg.)")
|
||||
.arg(Utils::Misc::friendlyUnit(m_torrent->downloadPayloadRate(), true))
|
||||
.arg(Utils::Misc::friendlyUnit(m_torrent->totalDownload() / (1 + m_torrent->activeTime() - m_torrent->finishedTime()), true)));
|
||||
|
||||
label_upload_speed_val->setText(tr("%1 (%2 avg.)", "%1 and %2 are speed rates, e.g. 200KiB/s (100KiB/s avg.)")
|
||||
m_ui->label_upload_speed_val->setText(tr("%1 (%2 avg.)", "%1 and %2 are speed rates, e.g. 200KiB/s (100KiB/s avg.)")
|
||||
.arg(Utils::Misc::friendlyUnit(m_torrent->uploadPayloadRate(), true))
|
||||
.arg(Utils::Misc::friendlyUnit(m_torrent->totalUpload() / (1 + m_torrent->activeTime()), true)));
|
||||
|
||||
label_last_complete_val->setText(m_torrent->lastSeenComplete().isValid() ? m_torrent->lastSeenComplete().toString(Qt::DefaultLocaleShortDate) : tr("Never"));
|
||||
m_ui->label_last_complete_val->setText(m_torrent->lastSeenComplete().isValid() ? m_torrent->lastSeenComplete().toString(Qt::DefaultLocaleShortDate) : tr("Never"));
|
||||
|
||||
label_completed_on_val->setText(m_torrent->completedTime().isValid() ? m_torrent->completedTime().toString(Qt::DefaultLocaleShortDate) : "");
|
||||
m_ui->label_completed_on_val->setText(m_torrent->completedTime().isValid() ? m_torrent->completedTime().toString(Qt::DefaultLocaleShortDate) : "");
|
||||
|
||||
label_added_on_val->setText(m_torrent->addedTime().toString(Qt::DefaultLocaleShortDate));
|
||||
m_ui->label_added_on_val->setText(m_torrent->addedTime().toString(Qt::DefaultLocaleShortDate));
|
||||
|
||||
if (m_torrent->hasMetadata()) {
|
||||
label_total_pieces_val->setText(tr("%1 x %2 (have %3)", "(torrent pieces) eg 152 x 4MB (have 25)").arg(m_torrent->piecesCount()).arg(Utils::Misc::friendlyUnit(m_torrent->pieceLength())).arg(m_torrent->piecesHave()));
|
||||
m_ui->label_total_pieces_val->setText(tr("%1 x %2 (have %3)", "(torrent pieces) eg 152 x 4MB (have 25)").arg(m_torrent->piecesCount()).arg(Utils::Misc::friendlyUnit(m_torrent->pieceLength())).arg(m_torrent->piecesHave()));
|
||||
|
||||
if (!m_torrent->isSeed() && !m_torrent->isPaused() && !m_torrent->isQueued() && !m_torrent->isChecking()) {
|
||||
// Pieces availability
|
||||
showPiecesAvailability(true);
|
||||
pieces_availability->setAvailability(m_torrent->pieceAvailability());
|
||||
avail_average_lbl->setText(Utils::String::fromDouble(m_torrent->distributedCopies(), 3));
|
||||
m_ui->avail_average_lbl->setText(Utils::String::fromDouble(m_torrent->distributedCopies(), 3));
|
||||
}
|
||||
else {
|
||||
showPiecesAvailability(false);
|
||||
@@ -458,7 +471,7 @@ void PropertiesWidget::loadDynamicData()
|
||||
|
||||
// Progress
|
||||
qreal progress = m_torrent->progress() * 100.;
|
||||
progress_lbl->setText(Utils::String::fromDouble(progress, 1) + "%");
|
||||
m_ui->progress_lbl->setText(Utils::String::fromDouble(progress, 1) + "%");
|
||||
downloaded_pieces->setProgress(m_torrent->pieces(), m_torrent->downloadingPieces());
|
||||
}
|
||||
else {
|
||||
@@ -484,13 +497,13 @@ void PropertiesWidget::loadDynamicData()
|
||||
// Files progress
|
||||
if (m_torrent->hasMetadata()) {
|
||||
qDebug("Updating priorities in files tab");
|
||||
filesList->setUpdatesEnabled(false);
|
||||
m_ui->filesList->setUpdatesEnabled(false);
|
||||
PropListModel->model()->updateFilesProgress(m_torrent->filesProgress());
|
||||
// XXX: We don't update file priorities regularly for performance
|
||||
// reasons. This means that priorities will not be updated if
|
||||
// set from the Web UI.
|
||||
// PropListModel->model()->updateFilesPriorities(h.file_priorities());
|
||||
filesList->setUpdatesEnabled(true);
|
||||
m_ui->filesList->setUpdatesEnabled(true);
|
||||
}
|
||||
break;
|
||||
}
|
||||
@@ -501,13 +514,13 @@ void PropertiesWidget::loadDynamicData()
|
||||
|
||||
void PropertiesWidget::loadUrlSeeds()
|
||||
{
|
||||
listWebSeeds->clear();
|
||||
m_ui->listWebSeeds->clear();
|
||||
qDebug("Loading URL seeds");
|
||||
const QList<QUrl> hc_seeds = m_torrent->urlSeeds();
|
||||
// Add url seeds
|
||||
foreach (const QUrl &hc_seed, hc_seeds) {
|
||||
qDebug("Loading URL seed: %s", qPrintable(hc_seed.toString()));
|
||||
new QListWidgetItem(hc_seed.toString(), listWebSeeds);
|
||||
new QListWidgetItem(hc_seed.toString(), m_ui->listWebSeeds);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -571,7 +584,7 @@ void PropertiesWidget::displayFilesListMenu(const QPoint &)
|
||||
{
|
||||
if (!m_torrent) return;
|
||||
|
||||
QModelIndexList selectedRows = filesList->selectionModel()->selectedRows(0);
|
||||
QModelIndexList selectedRows = m_ui->filesList->selectionModel()->selectedRows(0);
|
||||
if (selectedRows.empty())
|
||||
return;
|
||||
QMenu myFilesLlistMenu;
|
||||
@@ -587,10 +600,10 @@ void PropertiesWidget::displayFilesListMenu(const QPoint &)
|
||||
QMenu subMenu;
|
||||
if (!m_torrent->isSeed()) {
|
||||
subMenu.setTitle(tr("Priority"));
|
||||
subMenu.addAction(actionNot_downloaded);
|
||||
subMenu.addAction(actionNormal);
|
||||
subMenu.addAction(actionHigh);
|
||||
subMenu.addAction(actionMaximum);
|
||||
subMenu.addAction(m_ui->actionNot_downloaded);
|
||||
subMenu.addAction(m_ui->actionNormal);
|
||||
subMenu.addAction(m_ui->actionHigh);
|
||||
subMenu.addAction(m_ui->actionMaximum);
|
||||
myFilesLlistMenu.addMenu(&subMenu);
|
||||
}
|
||||
// Call menu
|
||||
@@ -612,11 +625,11 @@ void PropertiesWidget::displayFilesListMenu(const QPoint &)
|
||||
}
|
||||
else {
|
||||
int prio = prio::NORMAL;
|
||||
if (act == actionHigh)
|
||||
if (act == m_ui->actionHigh)
|
||||
prio = prio::HIGH;
|
||||
else if (act == actionMaximum)
|
||||
else if (act == m_ui->actionMaximum)
|
||||
prio = prio::MAXIMUM;
|
||||
else if (act == actionNot_downloaded)
|
||||
else if (act == m_ui->actionNot_downloaded)
|
||||
prio = prio::IGNORED;
|
||||
|
||||
qDebug("Setting files priority");
|
||||
@@ -635,7 +648,7 @@ void PropertiesWidget::displayWebSeedListMenu(const QPoint &)
|
||||
if (!m_torrent) return;
|
||||
|
||||
QMenu seedMenu;
|
||||
QModelIndexList rows = listWebSeeds->selectionModel()->selectedRows();
|
||||
QModelIndexList rows = m_ui->listWebSeeds->selectionModel()->selectedRows();
|
||||
QAction *actAdd = seedMenu.addAction(GuiIconProvider::instance()->getIcon("list-add"), tr("New Web seed"));
|
||||
QAction *actDel = 0;
|
||||
QAction *actCpy = 0;
|
||||
@@ -663,7 +676,7 @@ void PropertiesWidget::displayWebSeedListMenu(const QPoint &)
|
||||
|
||||
void PropertiesWidget::renameSelectedFile()
|
||||
{
|
||||
const QModelIndexList selectedIndexes = filesList->selectionModel()->selectedRows(0);
|
||||
const QModelIndexList selectedIndexes = m_ui->filesList->selectionModel()->selectedRows(0);
|
||||
if (selectedIndexes.size() != 1)
|
||||
return;
|
||||
const QModelIndex index = selectedIndexes.first();
|
||||
@@ -692,7 +705,7 @@ void PropertiesWidget::renameSelectedFile()
|
||||
path_items.removeLast();
|
||||
path_items << new_name_last;
|
||||
QString new_name = path_items.join("/");
|
||||
if (Utils::Fs::sameFileNames(old_name, new_name)) {
|
||||
if (old_name == new_name) {
|
||||
qDebug("Name did not change");
|
||||
return;
|
||||
}
|
||||
@@ -783,7 +796,7 @@ void PropertiesWidget::renameSelectedFile()
|
||||
|
||||
void PropertiesWidget::openSelectedFile()
|
||||
{
|
||||
const QModelIndexList selectedIndexes = filesList->selectionModel()->selectedRows(0);
|
||||
const QModelIndexList selectedIndexes = m_ui->filesList->selectionModel()->selectedRows(0);
|
||||
if (selectedIndexes.size() != 1)
|
||||
return;
|
||||
openDoubleClickedFile(selectedIndexes.first());
|
||||
@@ -798,7 +811,7 @@ void PropertiesWidget::askWebSeed()
|
||||
QString::fromUtf8("http://www."), &ok);
|
||||
if (!ok) return;
|
||||
qDebug("Adding %s web seed", qPrintable(url_seed));
|
||||
if (!listWebSeeds->findItems(url_seed, Qt::MatchFixedString).empty()) {
|
||||
if (!m_ui->listWebSeeds->findItems(url_seed, Qt::MatchFixedString).empty()) {
|
||||
QMessageBox::warning(this, "qBittorrent",
|
||||
tr("This URL seed is already in the list."),
|
||||
QMessageBox::Ok);
|
||||
@@ -812,7 +825,7 @@ void PropertiesWidget::askWebSeed()
|
||||
|
||||
void PropertiesWidget::deleteSelectedUrlSeeds()
|
||||
{
|
||||
const QList<QListWidgetItem *> selectedItems = listWebSeeds->selectedItems();
|
||||
const QList<QListWidgetItem *> selectedItems = m_ui->listWebSeeds->selectedItems();
|
||||
if (selectedItems.isEmpty()) return;
|
||||
|
||||
QList<QUrl> urlSeeds;
|
||||
@@ -826,7 +839,7 @@ void PropertiesWidget::deleteSelectedUrlSeeds()
|
||||
|
||||
void PropertiesWidget::copySelectedWebSeedsToClipboard() const
|
||||
{
|
||||
const QList<QListWidgetItem *> selected_items = listWebSeeds->selectedItems();
|
||||
const QList<QListWidgetItem *> selected_items = m_ui->listWebSeeds->selectedItems();
|
||||
if (selected_items.isEmpty())
|
||||
return;
|
||||
|
||||
@@ -839,7 +852,7 @@ void PropertiesWidget::copySelectedWebSeedsToClipboard() const
|
||||
|
||||
void PropertiesWidget::editWebSeed()
|
||||
{
|
||||
const QList<QListWidgetItem *> selected_items = listWebSeeds->selectedItems();
|
||||
const QList<QListWidgetItem *> selected_items = m_ui->listWebSeeds->selectedItems();
|
||||
if (selected_items.size() != 1)
|
||||
return;
|
||||
|
||||
@@ -852,7 +865,7 @@ void PropertiesWidget::editWebSeed()
|
||||
if (!result)
|
||||
return;
|
||||
|
||||
if (!listWebSeeds->findItems(new_seed, Qt::MatchFixedString).empty()) {
|
||||
if (!m_ui->listWebSeeds->findItems(new_seed, Qt::MatchFixedString).empty()) {
|
||||
QMessageBox::warning(this, tr("qBittorrent"),
|
||||
tr("This URL seed is already in the list."),
|
||||
QMessageBox::Ok);
|
||||
@@ -884,10 +897,10 @@ void PropertiesWidget::filterText(const QString &filter)
|
||||
{
|
||||
PropListModel->setFilterRegExp(QRegExp(filter, Qt::CaseInsensitive, QRegExp::WildcardUnix));
|
||||
if (filter.isEmpty()) {
|
||||
filesList->collapseAll();
|
||||
filesList->expand(PropListModel->index(0, 0));
|
||||
m_ui->filesList->collapseAll();
|
||||
m_ui->filesList->expand(PropListModel->index(0, 0));
|
||||
}
|
||||
else {
|
||||
filesList->expandAll();
|
||||
m_ui->filesList->expandAll();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -33,7 +33,6 @@
|
||||
|
||||
#include <QShortcut>
|
||||
#include <QWidget>
|
||||
#include "ui_propertieswidget.h"
|
||||
#include "base/bittorrent/torrenthandle.h"
|
||||
|
||||
|
||||
@@ -52,10 +51,18 @@ class LineEdit;
|
||||
|
||||
QT_BEGIN_NAMESPACE
|
||||
class QAction;
|
||||
class QModelIndex;
|
||||
class QPushButton;
|
||||
class QTimer;
|
||||
class QTreeView;
|
||||
QT_END_NAMESPACE
|
||||
|
||||
class PropertiesWidget: public QWidget, private Ui::PropertiesWidget
|
||||
namespace Ui
|
||||
{
|
||||
class PropertiesWidget;
|
||||
}
|
||||
|
||||
class PropertiesWidget: public QWidget
|
||||
{
|
||||
Q_OBJECT
|
||||
Q_DISABLE_COPY(PropertiesWidget)
|
||||
@@ -69,7 +76,7 @@ public:
|
||||
BitTorrent::TorrentHandle *getCurrentTorrent() const;
|
||||
TrackerList *getTrackerList() const { return trackerList; }
|
||||
PeerListWidget *getPeerList() const { return peersList; }
|
||||
QTreeView *getFilesList() const { return filesList; }
|
||||
QTreeView *getFilesList() const;
|
||||
SpeedWidget *getSpeedWidget() const { return speedWidget; }
|
||||
|
||||
protected:
|
||||
@@ -107,6 +114,7 @@ private:
|
||||
void openFolder(const QModelIndex &index, bool containing_folder);
|
||||
|
||||
private:
|
||||
Ui::PropertiesWidget *m_ui;
|
||||
TransferListWidget *transferList;
|
||||
MainWindow *main_window;
|
||||
BitTorrent::TorrentHandle *m_torrent;
|
||||
|
||||
@@ -28,6 +28,9 @@
|
||||
* Contact : chris@qbittorrent.org
|
||||
*/
|
||||
|
||||
#include "proplistdelegate.h"
|
||||
|
||||
#include <QApplication>
|
||||
#include <QComboBox>
|
||||
#include <QModelIndex>
|
||||
#include <QPainter>
|
||||
@@ -46,28 +49,27 @@
|
||||
#include "base/utils/misc.h"
|
||||
#include "base/utils/string.h"
|
||||
#include "propertieswidget.h"
|
||||
#include "proplistdelegate.h"
|
||||
#include "torrentcontentmodelitem.h"
|
||||
|
||||
namespace {
|
||||
namespace
|
||||
{
|
||||
|
||||
QPalette progressBarDisabledPalette()
|
||||
{
|
||||
auto getPalette = []()
|
||||
{
|
||||
QProgressBar bar;
|
||||
bar.setEnabled(false);
|
||||
QStyleOptionProgressBar opt;
|
||||
opt.initFrom(&bar);
|
||||
return opt.palette;
|
||||
};
|
||||
auto getPalette = []() {
|
||||
QProgressBar bar;
|
||||
bar.setEnabled(false);
|
||||
QStyleOptionProgressBar opt;
|
||||
opt.initFrom(&bar);
|
||||
return opt.palette;
|
||||
};
|
||||
static QPalette palette = getPalette();
|
||||
return palette;
|
||||
}
|
||||
}
|
||||
|
||||
PropListDelegate::PropListDelegate(PropertiesWidget *properties, QObject *parent)
|
||||
: QItemDelegate(parent)
|
||||
PropListDelegate::PropListDelegate(PropertiesWidget *properties)
|
||||
: QItemDelegate(properties)
|
||||
, m_properties(properties)
|
||||
{
|
||||
}
|
||||
@@ -76,36 +78,37 @@ void PropListDelegate::paint(QPainter *painter, const QStyleOptionViewItem &opti
|
||||
{
|
||||
painter->save();
|
||||
QStyleOptionViewItem opt = QItemDelegate::setOptions(index, option);
|
||||
QItemDelegate::drawBackground(painter, opt, index);
|
||||
|
||||
switch(index.column()) {
|
||||
switch (index.column()) {
|
||||
case PCSIZE:
|
||||
QItemDelegate::drawBackground(painter, opt, index);
|
||||
QItemDelegate::drawDisplay(painter, opt, option.rect, Utils::Misc::friendlyUnit(index.data().toLongLong()));
|
||||
break;
|
||||
case REMAINING:
|
||||
QItemDelegate::drawBackground(painter, opt, index);
|
||||
QItemDelegate::drawDisplay(painter, opt, option.rect, Utils::Misc::friendlyUnit(index.data().toLongLong()));
|
||||
break;
|
||||
case PROGRESS:
|
||||
if (index.data().toDouble() >= 0) {
|
||||
QStyleOptionProgressBar newopt;
|
||||
qreal progress = index.data().toDouble() * 100.;
|
||||
newopt.rect = opt.rect;
|
||||
newopt.text = ((progress == 100.0) ? QString("100%") : Utils::String::fromDouble(progress, 1) + "%");
|
||||
newopt.progress = (int)progress;
|
||||
newopt.maximum = 100;
|
||||
newopt.minimum = 0;
|
||||
newopt.textVisible = true;
|
||||
if (index.sibling(index.row(), PRIORITY).data().toInt() == prio::IGNORED) {
|
||||
newopt.state &= ~QStyle::State_Enabled;
|
||||
newopt.palette = progressBarDisabledPalette();
|
||||
}
|
||||
else
|
||||
newopt.state |= QStyle::State_Enabled;
|
||||
case PROGRESS: {
|
||||
if (index.data().toDouble() < 0)
|
||||
break;
|
||||
|
||||
QStyleOptionProgressBar newopt;
|
||||
qreal progress = index.data().toDouble() * 100.;
|
||||
newopt.rect = opt.rect;
|
||||
newopt.text = ((progress == 100.0) ? QString("100%") : Utils::String::fromDouble(progress, 1) + "%");
|
||||
newopt.progress = int(progress);
|
||||
newopt.maximum = 100;
|
||||
newopt.minimum = 0;
|
||||
newopt.textVisible = true;
|
||||
if (index.sibling(index.row(), PRIORITY).data().toInt() == prio::IGNORED) {
|
||||
newopt.state &= ~QStyle::State_Enabled;
|
||||
newopt.palette = progressBarDisabledPalette();
|
||||
}
|
||||
else {
|
||||
newopt.state |= QStyle::State_Enabled;
|
||||
}
|
||||
|
||||
#ifndef Q_OS_WIN
|
||||
QApplication::style()->drawControl(QStyle::CE_ProgressBar, &newopt, painter);
|
||||
QApplication::style()->drawControl(QStyle::CE_ProgressBar, &newopt, painter);
|
||||
#else
|
||||
// XXX: To avoid having the progress text on the right of the bar
|
||||
// XXX: To avoid having the progress text on the right of the bar
|
||||
#ifndef QBT_USES_QT5
|
||||
QPlastiqueStyle st;
|
||||
#else
|
||||
@@ -113,33 +116,28 @@ void PropListDelegate::paint(QPainter *painter, const QStyleOptionViewItem &opti
|
||||
#endif
|
||||
st.drawControl(QStyle::CE_ProgressBar, &newopt, painter, 0);
|
||||
#endif
|
||||
}
|
||||
else {
|
||||
// Do not display anything if the file is disabled (progress == 0)
|
||||
QItemDelegate::drawBackground(painter, opt, index);
|
||||
}
|
||||
break;
|
||||
}
|
||||
break;
|
||||
case PRIORITY: {
|
||||
QItemDelegate::drawBackground(painter, opt, index);
|
||||
QString text = "";
|
||||
switch (index.data().toInt()) {
|
||||
case prio::MIXED:
|
||||
text = tr("Mixed", "Mixed (priorities");
|
||||
break;
|
||||
case prio::IGNORED:
|
||||
text = tr("Not downloaded");
|
||||
break;
|
||||
case prio::HIGH:
|
||||
text = tr("High", "High (priority)");
|
||||
break;
|
||||
case prio::MAXIMUM:
|
||||
text = tr("Maximum", "Maximum (priority)");
|
||||
break;
|
||||
default:
|
||||
text = tr("Normal", "Normal (priority)");
|
||||
break;
|
||||
}
|
||||
QItemDelegate::drawDisplay(painter, opt, option.rect, text);
|
||||
QString text = "";
|
||||
switch (index.data().toInt()) {
|
||||
case prio::MIXED:
|
||||
text = tr("Mixed", "Mixed (priorities");
|
||||
break;
|
||||
case prio::IGNORED:
|
||||
text = tr("Not downloaded");
|
||||
break;
|
||||
case prio::HIGH:
|
||||
text = tr("High", "High (priority)");
|
||||
break;
|
||||
case prio::MAXIMUM:
|
||||
text = tr("Maximum", "Maximum (priority)");
|
||||
break;
|
||||
default:
|
||||
text = tr("Normal", "Normal (priority)");
|
||||
break;
|
||||
}
|
||||
QItemDelegate::drawDisplay(painter, opt, option.rect, text);
|
||||
}
|
||||
break;
|
||||
default:
|
||||
@@ -151,9 +149,9 @@ void PropListDelegate::paint(QPainter *painter, const QStyleOptionViewItem &opti
|
||||
|
||||
void PropListDelegate::setEditorData(QWidget *editor, const QModelIndex &index) const
|
||||
{
|
||||
QComboBox *combobox = static_cast<QComboBox*>(editor);
|
||||
QComboBox *combobox = static_cast<QComboBox *>(editor);
|
||||
// Set combobox index
|
||||
switch(index.data().toInt()) {
|
||||
switch (index.data().toInt()) {
|
||||
case prio::IGNORED:
|
||||
combobox->setCurrentIndex(0);
|
||||
break;
|
||||
@@ -182,7 +180,7 @@ QWidget *PropListDelegate::createEditor(QWidget *parent, const QStyleOptionViewI
|
||||
if (index.data().toInt() == prio::MIXED)
|
||||
return 0;
|
||||
|
||||
QComboBox* editor = new QComboBox(parent);
|
||||
QComboBox *editor = new QComboBox(parent);
|
||||
editor->setFocusPolicy(Qt::StrongFocus);
|
||||
editor->addItem(tr("Do not download", "Do not download (priority)"));
|
||||
editor->addItem(tr("Normal", "Normal (priority)"));
|
||||
@@ -193,11 +191,11 @@ QWidget *PropListDelegate::createEditor(QWidget *parent, const QStyleOptionViewI
|
||||
|
||||
void PropListDelegate::setModelData(QWidget *editor, QAbstractItemModel *model, const QModelIndex &index) const
|
||||
{
|
||||
QComboBox *combobox = static_cast<QComboBox*>(editor);
|
||||
QComboBox *combobox = static_cast<QComboBox *>(editor);
|
||||
int value = combobox->currentIndex();
|
||||
qDebug("PropListDelegate: setModelData(%d)", value);
|
||||
|
||||
switch(value) {
|
||||
switch (value) {
|
||||
case 0:
|
||||
model->setData(index, prio::IGNORED); // IGNORED
|
||||
break;
|
||||
|
||||
@@ -49,20 +49,20 @@ enum PropColumn
|
||||
REMAINING
|
||||
};
|
||||
|
||||
class PropListDelegate : public QItemDelegate
|
||||
class PropListDelegate: public QItemDelegate
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
PropListDelegate(PropertiesWidget *properties = 0, QObject *parent = 0);
|
||||
PropListDelegate(PropertiesWidget *properties);
|
||||
|
||||
void paint(QPainter *painter, const QStyleOptionViewItem &option, const QModelIndex &index) const;
|
||||
void setEditorData(QWidget *editor, const QModelIndex &index) const;
|
||||
QWidget *createEditor(QWidget *parent, const QStyleOptionViewItem &/* option */, const QModelIndex &index) const;
|
||||
void paint(QPainter *painter, const QStyleOptionViewItem &option, const QModelIndex &index) const override;
|
||||
void setEditorData(QWidget *editor, const QModelIndex &index) const override;
|
||||
QWidget *createEditor(QWidget *parent, const QStyleOptionViewItem & /* option */, const QModelIndex &index) const override;
|
||||
|
||||
public slots:
|
||||
void setModelData(QWidget *editor, QAbstractItemModel *model, const QModelIndex &index) const;
|
||||
void updateEditorGeometry(QWidget *editor, const QStyleOptionViewItem &option, const QModelIndex &/* index */) const;
|
||||
void setModelData(QWidget *editor, QAbstractItemModel *model, const QModelIndex &index) const override;
|
||||
void updateEditorGeometry(QWidget *editor, const QStyleOptionViewItem &option, const QModelIndex & /* index */) const override;
|
||||
|
||||
signals:
|
||||
void filteredFilesChanged() const;
|
||||
|
||||
@@ -86,7 +86,7 @@ SpeedWidget::SpeedWidget(PropertiesWidget *parent)
|
||||
m_graphsMenu->addAction(tr("Tracker Download"));
|
||||
|
||||
m_graphsMenuActions = m_graphsMenu->actions();
|
||||
m_graphsSignalMapper = new QSignalMapper();
|
||||
m_graphsSignalMapper = new QSignalMapper(this);
|
||||
|
||||
for (int id = SpeedPlotView::UP; id < SpeedPlotView::NB_GRAPHS; ++id) {
|
||||
QAction *action = m_graphsMenuActions.at(id);
|
||||
|
||||
@@ -28,6 +28,9 @@
|
||||
* Contact : chris@qbittorrent.org
|
||||
*/
|
||||
|
||||
#include "trackerlist.h"
|
||||
|
||||
#include <QApplication>
|
||||
#include <QTreeWidgetItem>
|
||||
#include <QStringList>
|
||||
#include <QMenu>
|
||||
@@ -35,11 +38,11 @@
|
||||
#include <QAction>
|
||||
#include <QColor>
|
||||
#include <QDebug>
|
||||
#include <QHeaderView>
|
||||
#include <QUrl>
|
||||
#include <QMessageBox>
|
||||
#ifdef QBT_USES_QT5
|
||||
#include <QTableView>
|
||||
#include <QHeaderView>
|
||||
#endif
|
||||
|
||||
#include "base/bittorrent/session.h"
|
||||
@@ -52,7 +55,6 @@
|
||||
#include "trackersadditiondlg.h"
|
||||
#include "guiiconprovider.h"
|
||||
#include "autoexpandabledialog.h"
|
||||
#include "trackerlist.h"
|
||||
|
||||
TrackerList::TrackerList(PropertiesWidget *properties): QTreeWidget(), properties(properties) {
|
||||
// Graphical settings
|
||||
|
||||
@@ -27,6 +27,7 @@
|
||||
*
|
||||
* Contact : chris@qbittorrent.org
|
||||
*/
|
||||
#include "trackersadditiondlg.h"
|
||||
|
||||
#include <QStringList>
|
||||
#include <QMessageBox>
|
||||
@@ -40,21 +41,27 @@
|
||||
#include "base/bittorrent/trackerentry.h"
|
||||
#include "base/bittorrent/torrenthandle.h"
|
||||
#include "guiiconprovider.h"
|
||||
#include "trackersadditiondlg.h"
|
||||
#include "ui_trackersadditiondlg.h"
|
||||
|
||||
TrackersAdditionDlg::TrackersAdditionDlg(BitTorrent::TorrentHandle *const torrent, QWidget *parent)
|
||||
: QDialog(parent)
|
||||
, m_ui(new Ui::TrackersAdditionDlg())
|
||||
, m_torrent(torrent)
|
||||
{
|
||||
setupUi(this);
|
||||
m_ui->setupUi(this);
|
||||
// Icons
|
||||
uTorrentListButton->setIcon(GuiIconProvider::instance()->getIcon("download"));
|
||||
m_ui->uTorrentListButton->setIcon(GuiIconProvider::instance()->getIcon("download"));
|
||||
}
|
||||
|
||||
TrackersAdditionDlg::~TrackersAdditionDlg()
|
||||
{
|
||||
delete m_ui;
|
||||
}
|
||||
|
||||
QStringList TrackersAdditionDlg::newTrackers() const
|
||||
{
|
||||
QStringList cleanTrackers;
|
||||
foreach (QString url, trackers_list->toPlainText().split("\n")) {
|
||||
foreach (QString url, m_ui->trackers_list->toPlainText().split("\n")) {
|
||||
url = url.trimmed();
|
||||
if (!url.isEmpty())
|
||||
cleanTrackers << url;
|
||||
@@ -64,8 +71,8 @@ QStringList TrackersAdditionDlg::newTrackers() const
|
||||
|
||||
void TrackersAdditionDlg::on_uTorrentListButton_clicked()
|
||||
{
|
||||
uTorrentListButton->setEnabled(false);
|
||||
Net::DownloadHandler *handler = Net::DownloadManager::instance()->downloadUrl(list_url->text(), true);
|
||||
m_ui->uTorrentListButton->setEnabled(false);
|
||||
Net::DownloadHandler *handler = Net::DownloadManager::instance()->downloadUrl(m_ui->list_url->text(), true);
|
||||
connect(handler, SIGNAL(downloadFinished(QString, QString)), this, SLOT(parseUTorrentList(QString, QString)));
|
||||
connect(handler, SIGNAL(downloadFailed(QString, QString)), this, SLOT(getTrackerError(QString, QString)));
|
||||
//Just to show that it takes times
|
||||
@@ -78,7 +85,7 @@ void TrackersAdditionDlg::parseUTorrentList(const QString &, const QString &path
|
||||
if (!list_file.open(QFile::ReadOnly)) {
|
||||
QMessageBox::warning(this, tr("I/O Error"), tr("Error while trying to open the downloaded file."), QMessageBox::Ok);
|
||||
setCursor(Qt::ArrowCursor);
|
||||
uTorrentListButton->setEnabled(true);
|
||||
m_ui->uTorrentListButton->setEnabled(true);
|
||||
Utils::Fs::forceRemove(path);
|
||||
return;
|
||||
}
|
||||
@@ -86,7 +93,7 @@ void TrackersAdditionDlg::parseUTorrentList(const QString &, const QString &path
|
||||
// Load from torrent handle
|
||||
QList<BitTorrent::TrackerEntry> existingTrackers = m_torrent->trackers();
|
||||
// Load from current user list
|
||||
QStringList tmp = trackers_list->toPlainText().split("\n");
|
||||
QStringList tmp = m_ui->trackers_list->toPlainText().split("\n");
|
||||
foreach (const QString &user_url, tmp) {
|
||||
BitTorrent::TrackerEntry userTracker(user_url);
|
||||
if (!existingTrackers.contains(userTracker))
|
||||
@@ -94,15 +101,15 @@ void TrackersAdditionDlg::parseUTorrentList(const QString &, const QString &path
|
||||
}
|
||||
|
||||
// Add new trackers to the list
|
||||
if (!trackers_list->toPlainText().isEmpty() && !trackers_list->toPlainText().endsWith("\n"))
|
||||
trackers_list->insertPlainText("\n");
|
||||
if (!m_ui->trackers_list->toPlainText().isEmpty() && !m_ui->trackers_list->toPlainText().endsWith("\n"))
|
||||
m_ui->trackers_list->insertPlainText("\n");
|
||||
int nb = 0;
|
||||
while (!list_file.atEnd()) {
|
||||
const QByteArray line = list_file.readLine().trimmed();
|
||||
if (line.isEmpty()) continue;
|
||||
BitTorrent::TrackerEntry newTracker(line);
|
||||
if (!existingTrackers.contains(newTracker)) {
|
||||
trackers_list->insertPlainText(line + "\n");
|
||||
m_ui->trackers_list->insertPlainText(line + "\n");
|
||||
++nb;
|
||||
}
|
||||
}
|
||||
@@ -111,7 +118,7 @@ void TrackersAdditionDlg::parseUTorrentList(const QString &, const QString &path
|
||||
Utils::Fs::forceRemove(path);
|
||||
//To restore the cursor ...
|
||||
setCursor(Qt::ArrowCursor);
|
||||
uTorrentListButton->setEnabled(true);
|
||||
m_ui->uTorrentListButton->setEnabled(true);
|
||||
// Display information message if necessary
|
||||
if (nb == 0)
|
||||
QMessageBox::information(this, tr("No change"), tr("No additional trackers were found."), QMessageBox::Ok);
|
||||
@@ -121,7 +128,7 @@ void TrackersAdditionDlg::getTrackerError(const QString &, const QString &error)
|
||||
{
|
||||
//To restore the cursor ...
|
||||
setCursor(Qt::ArrowCursor);
|
||||
uTorrentListButton->setEnabled(true);
|
||||
m_ui->uTorrentListButton->setEnabled(true);
|
||||
QMessageBox::warning(this, tr("Download error"), tr("The trackers list could not be downloaded, reason: %1").arg(error), QMessageBox::Ok);
|
||||
}
|
||||
|
||||
|
||||
@@ -32,7 +32,6 @@
|
||||
#define TRACKERSADDITION_H
|
||||
|
||||
#include <QDialog>
|
||||
#include "ui_trackersadditiondlg.h"
|
||||
|
||||
class QString;
|
||||
class QStringList;
|
||||
@@ -42,12 +41,18 @@ namespace BitTorrent
|
||||
class TorrentHandle;
|
||||
}
|
||||
|
||||
class TrackersAdditionDlg : public QDialog, private Ui::TrackersAdditionDlg
|
||||
namespace Ui
|
||||
{
|
||||
class TrackersAdditionDlg;
|
||||
}
|
||||
|
||||
class TrackersAdditionDlg : public QDialog
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
TrackersAdditionDlg(BitTorrent::TorrentHandle *const torrent, QWidget *parent = 0);
|
||||
~TrackersAdditionDlg();
|
||||
|
||||
QStringList newTrackers() const;
|
||||
static QStringList askForTrackers(BitTorrent::TorrentHandle *const torrent);
|
||||
@@ -58,6 +63,7 @@ public slots:
|
||||
void getTrackerError(const QString &, const QString &error);
|
||||
|
||||
private:
|
||||
Ui::TrackersAdditionDlg *m_ui;
|
||||
BitTorrent::TorrentHandle *const m_torrent;
|
||||
};
|
||||
|
||||
|
||||
@@ -28,6 +28,8 @@
|
||||
* Contact : chris@qbittorrent.org arnaud@qbittorrent.org
|
||||
*/
|
||||
|
||||
#include "rss_imp.h"
|
||||
|
||||
#include <QDesktopServices>
|
||||
#include <QMenu>
|
||||
#include <QStandardItemModel>
|
||||
@@ -37,7 +39,6 @@
|
||||
#include <QDragMoveEvent>
|
||||
#include <QDebug>
|
||||
|
||||
#include "rss_imp.h"
|
||||
#include "feedlistwidget.h"
|
||||
#include "base/bittorrent/session.h"
|
||||
#include "base/net/downloadmanager.h"
|
||||
@@ -52,6 +53,8 @@
|
||||
#include "autoexpandabledialog.h"
|
||||
#include "addnewtorrentdialog.h"
|
||||
|
||||
#include "ui_rss.h"
|
||||
|
||||
namespace Article
|
||||
{
|
||||
enum ArticleRoles
|
||||
@@ -73,33 +76,33 @@ void RSSImp::displayRSSListMenu(const QPoint &pos)
|
||||
QMenu myRSSListMenu(this);
|
||||
QList<QTreeWidgetItem * > selectedItems = m_feedList->selectedItems();
|
||||
if (selectedItems.size() > 0) {
|
||||
myRSSListMenu.addAction(actionUpdate);
|
||||
myRSSListMenu.addAction(actionMark_items_read);
|
||||
myRSSListMenu.addAction(m_ui->actionUpdate);
|
||||
myRSSListMenu.addAction(m_ui->actionMark_items_read);
|
||||
myRSSListMenu.addSeparator();
|
||||
if (selectedItems.size() == 1) {
|
||||
if (m_feedList->getRSSItem(selectedItems.first()) != m_rssManager->rootFolder()) {
|
||||
myRSSListMenu.addAction(actionRename);
|
||||
myRSSListMenu.addAction(actionDelete);
|
||||
myRSSListMenu.addAction(m_ui->actionRename);
|
||||
myRSSListMenu.addAction(m_ui->actionDelete);
|
||||
myRSSListMenu.addSeparator();
|
||||
if (m_feedList->isFolder(selectedItems.first()))
|
||||
myRSSListMenu.addAction(actionNew_folder);
|
||||
myRSSListMenu.addAction(m_ui->actionNew_folder);
|
||||
}
|
||||
}
|
||||
else {
|
||||
myRSSListMenu.addAction(actionDelete);
|
||||
myRSSListMenu.addAction(m_ui->actionDelete);
|
||||
myRSSListMenu.addSeparator();
|
||||
}
|
||||
myRSSListMenu.addAction(actionNew_subscription);
|
||||
myRSSListMenu.addAction(m_ui->actionNew_subscription);
|
||||
if (m_feedList->isFeed(selectedItems.first())) {
|
||||
myRSSListMenu.addSeparator();
|
||||
myRSSListMenu.addAction(actionCopy_feed_URL);
|
||||
myRSSListMenu.addAction(m_ui->actionCopy_feed_URL);
|
||||
}
|
||||
}
|
||||
else {
|
||||
myRSSListMenu.addAction(actionNew_subscription);
|
||||
myRSSListMenu.addAction(actionNew_folder);
|
||||
myRSSListMenu.addAction(m_ui->actionNew_subscription);
|
||||
myRSSListMenu.addAction(m_ui->actionNew_folder);
|
||||
myRSSListMenu.addSeparator();
|
||||
myRSSListMenu.addAction(actionUpdate_all_feeds);
|
||||
myRSSListMenu.addAction(m_ui->actionUpdate_all_feeds);
|
||||
}
|
||||
myRSSListMenu.exec(QCursor::pos());
|
||||
}
|
||||
@@ -107,7 +110,7 @@ void RSSImp::displayRSSListMenu(const QPoint &pos)
|
||||
void RSSImp::displayItemsListMenu(const QPoint &)
|
||||
{
|
||||
QMenu myItemListMenu(this);
|
||||
QList<QListWidgetItem * > selectedItems = listArticles->selectedItems();
|
||||
QList<QListWidgetItem * > selectedItems = m_ui->listArticles->selectedItems();
|
||||
if (selectedItems.size() <= 0)
|
||||
return;
|
||||
|
||||
@@ -128,9 +131,9 @@ void RSSImp::displayItemsListMenu(const QPoint &)
|
||||
break;
|
||||
}
|
||||
if (hasTorrent)
|
||||
myItemListMenu.addAction(actionDownload_torrent);
|
||||
myItemListMenu.addAction(m_ui->actionDownload_torrent);
|
||||
if (hasLink)
|
||||
myItemListMenu.addAction(actionOpen_news_URL);
|
||||
myItemListMenu.addAction(m_ui->actionOpen_news_URL);
|
||||
if (hasTorrent || hasLink)
|
||||
myItemListMenu.exec(QCursor::pos());
|
||||
}
|
||||
@@ -323,7 +326,7 @@ void RSSImp::refreshAllFeeds()
|
||||
|
||||
void RSSImp::downloadSelectedTorrents()
|
||||
{
|
||||
QList<QListWidgetItem * > selected_items = listArticles->selectedItems();
|
||||
QList<QListWidgetItem * > selected_items = m_ui->listArticles->selectedItems();
|
||||
if (selected_items.size() <= 0)
|
||||
return;
|
||||
foreach (QListWidgetItem *item, selected_items) {
|
||||
@@ -353,7 +356,7 @@ void RSSImp::downloadSelectedTorrents()
|
||||
// open the url of the selected RSS articles in the Web browser
|
||||
void RSSImp::openSelectedArticlesUrls()
|
||||
{
|
||||
QList<QListWidgetItem * > selected_items = listArticles->selectedItems();
|
||||
QList<QListWidgetItem * > selected_items = m_ui->listArticles->selectedItems();
|
||||
if (selected_items.size() <= 0)
|
||||
return;
|
||||
foreach (QListWidgetItem *item, selected_items) {
|
||||
@@ -519,7 +522,7 @@ QListWidgetItem *RSSImp::createArticleListItem(const Rss::ArticlePtr &article)
|
||||
void RSSImp::populateArticleList(QTreeWidgetItem *item)
|
||||
{
|
||||
if (!item) {
|
||||
listArticles->clear();
|
||||
m_ui->listArticles->clear();
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -528,9 +531,9 @@ void RSSImp::populateArticleList(QTreeWidgetItem *item)
|
||||
return;
|
||||
|
||||
// Clear the list first
|
||||
textBrowser->clear();
|
||||
m_ui->textBrowser->clear();
|
||||
m_currentArticle = 0;
|
||||
listArticles->clear();
|
||||
m_ui->listArticles->clear();
|
||||
|
||||
qDebug("Getting the list of news");
|
||||
Rss::ArticleList articles;
|
||||
@@ -542,7 +545,7 @@ void RSSImp::populateArticleList(QTreeWidgetItem *item)
|
||||
qDebug("Got the list of news");
|
||||
foreach (const Rss::ArticlePtr &article, articles) {
|
||||
QListWidgetItem *articleItem = createArticleListItem(article);
|
||||
listArticles->addItem(articleItem);
|
||||
m_ui->listArticles->addItem(articleItem);
|
||||
}
|
||||
qDebug("Added all news to the GUI");
|
||||
}
|
||||
@@ -550,7 +553,7 @@ void RSSImp::populateArticleList(QTreeWidgetItem *item)
|
||||
// display a news
|
||||
void RSSImp::refreshTextBrowser()
|
||||
{
|
||||
QList<QListWidgetItem * > selection = listArticles->selectedItems();
|
||||
QList<QListWidgetItem * > selection = m_ui->listArticles->selectedItems();
|
||||
if (selection.empty()) return;
|
||||
QListWidgetItem *item = selection.first();
|
||||
Q_ASSERT(item);
|
||||
@@ -601,7 +604,7 @@ void RSSImp::refreshTextBrowser()
|
||||
html += "<pre>" + description + "</pre>";
|
||||
}
|
||||
html += "</div>";
|
||||
textBrowser->setHtml(html);
|
||||
m_ui->textBrowser->setHtml(html);
|
||||
article->markAsRead();
|
||||
item->setData(Article::ColorRole, QVariant(QColor("grey")));
|
||||
item->setData(Article::IconRole, QVariant(QIcon(":/icons/sphere.png")));
|
||||
@@ -614,8 +617,8 @@ void RSSImp::saveSlidersPosition()
|
||||
{
|
||||
// Remember sliders positions
|
||||
Preferences *const pref = Preferences::instance();
|
||||
pref->setRssSideSplitterState(splitterSide->saveState());
|
||||
pref->setRssMainSplitterState(splitterMain->saveState());
|
||||
pref->setRssSideSplitterState(m_ui->splitterSide->saveState());
|
||||
pref->setRssMainSplitterState(m_ui->splitterMain->saveState());
|
||||
qDebug("Splitters position saved");
|
||||
}
|
||||
|
||||
@@ -624,10 +627,10 @@ void RSSImp::restoreSlidersPosition()
|
||||
const Preferences *const pref = Preferences::instance();
|
||||
const QByteArray stateSide = pref->getRssSideSplitterState();
|
||||
if (!stateSide.isEmpty())
|
||||
splitterSide->restoreState(stateSide);
|
||||
m_ui->splitterSide->restoreState(stateSide);
|
||||
const QByteArray stateMain = pref->getRssMainSplitterState();
|
||||
if (!stateMain.isEmpty())
|
||||
splitterMain->restoreState(stateMain);
|
||||
m_ui->splitterMain->restoreState(stateMain);
|
||||
}
|
||||
|
||||
void RSSImp::updateItemsInfos(const QList<QTreeWidgetItem *> &items)
|
||||
@@ -701,29 +704,30 @@ void RSSImp::updateRefreshInterval(uint val)
|
||||
}
|
||||
|
||||
RSSImp::RSSImp(QWidget *parent)
|
||||
: QWidget(parent),
|
||||
m_rssManager(new Rss::Manager)
|
||||
: QWidget(parent)
|
||||
, m_ui(new Ui::RSS())
|
||||
, m_rssManager(new Rss::Manager)
|
||||
{
|
||||
setupUi(this);
|
||||
m_ui->setupUi(this);
|
||||
// Icons
|
||||
actionCopy_feed_URL->setIcon(GuiIconProvider::instance()->getIcon("edit-copy"));
|
||||
actionDelete->setIcon(GuiIconProvider::instance()->getIcon("edit-delete"));
|
||||
actionDownload_torrent->setIcon(GuiIconProvider::instance()->getIcon("download"));
|
||||
actionMark_items_read->setIcon(GuiIconProvider::instance()->getIcon("mail-mark-read"));
|
||||
actionNew_folder->setIcon(GuiIconProvider::instance()->getIcon("folder-new"));
|
||||
actionNew_subscription->setIcon(GuiIconProvider::instance()->getIcon("list-add"));
|
||||
actionOpen_news_URL->setIcon(GuiIconProvider::instance()->getIcon("application-x-mswinurl"));
|
||||
actionRename->setIcon(GuiIconProvider::instance()->getIcon("edit-rename"));
|
||||
actionUpdate->setIcon(GuiIconProvider::instance()->getIcon("view-refresh"));
|
||||
actionUpdate_all_feeds->setIcon(GuiIconProvider::instance()->getIcon("view-refresh"));
|
||||
newFeedButton->setIcon(GuiIconProvider::instance()->getIcon("list-add"));
|
||||
markReadButton->setIcon(GuiIconProvider::instance()->getIcon("mail-mark-read"));
|
||||
updateAllButton->setIcon(GuiIconProvider::instance()->getIcon("view-refresh"));
|
||||
rssDownloaderBtn->setIcon(GuiIconProvider::instance()->getIcon("download"));
|
||||
settingsButton->setIcon(GuiIconProvider::instance()->getIcon("preferences-system"));
|
||||
m_ui->actionCopy_feed_URL->setIcon(GuiIconProvider::instance()->getIcon("edit-copy"));
|
||||
m_ui->actionDelete->setIcon(GuiIconProvider::instance()->getIcon("edit-delete"));
|
||||
m_ui->actionDownload_torrent->setIcon(GuiIconProvider::instance()->getIcon("download"));
|
||||
m_ui->actionMark_items_read->setIcon(GuiIconProvider::instance()->getIcon("mail-mark-read"));
|
||||
m_ui->actionNew_folder->setIcon(GuiIconProvider::instance()->getIcon("folder-new"));
|
||||
m_ui->actionNew_subscription->setIcon(GuiIconProvider::instance()->getIcon("list-add"));
|
||||
m_ui->actionOpen_news_URL->setIcon(GuiIconProvider::instance()->getIcon("application-x-mswinurl"));
|
||||
m_ui->actionRename->setIcon(GuiIconProvider::instance()->getIcon("edit-rename"));
|
||||
m_ui->actionUpdate->setIcon(GuiIconProvider::instance()->getIcon("view-refresh"));
|
||||
m_ui->actionUpdate_all_feeds->setIcon(GuiIconProvider::instance()->getIcon("view-refresh"));
|
||||
m_ui->newFeedButton->setIcon(GuiIconProvider::instance()->getIcon("list-add"));
|
||||
m_ui->markReadButton->setIcon(GuiIconProvider::instance()->getIcon("mail-mark-read"));
|
||||
m_ui->updateAllButton->setIcon(GuiIconProvider::instance()->getIcon("view-refresh"));
|
||||
m_ui->rssDownloaderBtn->setIcon(GuiIconProvider::instance()->getIcon("download"));
|
||||
m_ui->settingsButton->setIcon(GuiIconProvider::instance()->getIcon("preferences-system"));
|
||||
|
||||
m_feedList = new FeedListWidget(splitterSide, m_rssManager);
|
||||
splitterSide->insertWidget(0, m_feedList);
|
||||
m_feedList = new FeedListWidget(m_ui->splitterSide, m_rssManager);
|
||||
m_ui->splitterSide->insertWidget(0, m_feedList);
|
||||
editHotkey = new QShortcut(Qt::Key_F2, m_feedList, 0, 0, Qt::WidgetShortcut);
|
||||
connect(editHotkey, SIGNAL(activated()), SLOT(renameSelectedRssFile()));
|
||||
connect(m_feedList, SIGNAL(doubleClicked(QModelIndex)), SLOT(renameSelectedRssFile()));
|
||||
@@ -742,33 +746,33 @@ RSSImp::RSSImp(QWidget *parent)
|
||||
connect(m_rssManager.data(), SIGNAL(feedIconChanged(QString,QString)), SLOT(updateFeedIcon(QString,QString)));
|
||||
|
||||
connect(m_feedList, SIGNAL(customContextMenuRequested(const QPoint&)), SLOT(displayRSSListMenu(const QPoint&)));
|
||||
connect(listArticles, SIGNAL(customContextMenuRequested(const QPoint&)), SLOT(displayItemsListMenu(const QPoint&)));
|
||||
connect(m_ui->listArticles, SIGNAL(customContextMenuRequested(const QPoint&)), SLOT(displayItemsListMenu(const QPoint&)));
|
||||
|
||||
// Feeds list actions
|
||||
connect(actionDelete, SIGNAL(triggered()), this, SLOT(deleteSelectedItems()));
|
||||
connect(actionRename, SIGNAL(triggered()), this, SLOT(renameSelectedRssFile()));
|
||||
connect(actionUpdate, SIGNAL(triggered()), this, SLOT(refreshSelectedItems()));
|
||||
connect(actionNew_folder, SIGNAL(triggered()), this, SLOT(askNewFolder()));
|
||||
connect(actionNew_subscription, SIGNAL(triggered()), this, SLOT(on_newFeedButton_clicked()));
|
||||
connect(actionUpdate_all_feeds, SIGNAL(triggered()), this, SLOT(refreshAllFeeds()));
|
||||
connect(updateAllButton, SIGNAL(clicked()), SLOT(refreshAllFeeds()));
|
||||
connect(actionCopy_feed_URL, SIGNAL(triggered()), this, SLOT(copySelectedFeedsURL()));
|
||||
connect(actionMark_items_read, SIGNAL(triggered()), this, SLOT(on_markReadButton_clicked()));
|
||||
connect(m_ui->actionDelete, SIGNAL(triggered()), this, SLOT(deleteSelectedItems()));
|
||||
connect(m_ui->actionRename, SIGNAL(triggered()), this, SLOT(renameSelectedRssFile()));
|
||||
connect(m_ui->actionUpdate, SIGNAL(triggered()), this, SLOT(refreshSelectedItems()));
|
||||
connect(m_ui->actionNew_folder, SIGNAL(triggered()), this, SLOT(askNewFolder()));
|
||||
connect(m_ui->actionNew_subscription, SIGNAL(triggered()), this, SLOT(on_newFeedButton_clicked()));
|
||||
connect(m_ui->actionUpdate_all_feeds, SIGNAL(triggered()), this, SLOT(refreshAllFeeds()));
|
||||
connect(m_ui->updateAllButton, SIGNAL(clicked()), SLOT(refreshAllFeeds()));
|
||||
connect(m_ui->actionCopy_feed_URL, SIGNAL(triggered()), this, SLOT(copySelectedFeedsURL()));
|
||||
connect(m_ui->actionMark_items_read, SIGNAL(triggered()), this, SLOT(on_markReadButton_clicked()));
|
||||
// News list actions
|
||||
connect(actionOpen_news_URL, SIGNAL(triggered()), this, SLOT(openSelectedArticlesUrls()));
|
||||
connect(actionDownload_torrent, SIGNAL(triggered()), this, SLOT(downloadSelectedTorrents()));
|
||||
connect(m_ui->actionOpen_news_URL, SIGNAL(triggered()), this, SLOT(openSelectedArticlesUrls()));
|
||||
connect(m_ui->actionDownload_torrent, SIGNAL(triggered()), this, SLOT(downloadSelectedTorrents()));
|
||||
|
||||
connect(m_feedList, SIGNAL(currentItemChanged(QTreeWidgetItem *,QTreeWidgetItem *)), this, SLOT(populateArticleList(QTreeWidgetItem *)));
|
||||
connect(m_feedList, SIGNAL(foldersAltered(QList<QTreeWidgetItem * >)), this, SLOT(updateItemsInfos(QList<QTreeWidgetItem * >)));
|
||||
|
||||
connect(listArticles, SIGNAL(itemSelectionChanged()), this, SLOT(refreshTextBrowser()));
|
||||
connect(listArticles, SIGNAL(itemDoubleClicked(QListWidgetItem *)), this, SLOT(downloadSelectedTorrents()));
|
||||
connect(m_ui->listArticles, SIGNAL(itemSelectionChanged()), this, SLOT(refreshTextBrowser()));
|
||||
connect(m_ui->listArticles, SIGNAL(itemDoubleClicked(QListWidgetItem *)), this, SLOT(downloadSelectedTorrents()));
|
||||
|
||||
// Restore sliders position
|
||||
restoreSlidersPosition();
|
||||
// Bind saveSliders slots
|
||||
connect(splitterMain, SIGNAL(splitterMoved(int,int)), this, SLOT(saveSlidersPosition()));
|
||||
connect(splitterSide, SIGNAL(splitterMoved(int,int)), this, SLOT(saveSlidersPosition()));
|
||||
connect(m_ui->splitterMain, SIGNAL(splitterMoved(int,int)), this, SLOT(saveSlidersPosition()));
|
||||
connect(m_ui->splitterSide, SIGNAL(splitterMoved(int,int)), this, SLOT(saveSlidersPosition()));
|
||||
|
||||
qDebug("RSSImp constructed");
|
||||
}
|
||||
@@ -780,6 +784,7 @@ RSSImp::~RSSImp()
|
||||
delete editHotkey;
|
||||
delete deleteHotkey;
|
||||
delete m_feedList;
|
||||
delete m_ui;
|
||||
qDebug("RSSImp deleted");
|
||||
}
|
||||
|
||||
|
||||
@@ -37,15 +37,20 @@
|
||||
|
||||
#include "base/rss/rssfolder.h"
|
||||
#include "base/rss/rssmanager.h"
|
||||
#include "ui_rss.h"
|
||||
|
||||
class FeedListWidget;
|
||||
|
||||
QT_BEGIN_NAMESPACE
|
||||
class QListWidgetItem;
|
||||
class QTreeWidgetItem;
|
||||
QT_END_NAMESPACE
|
||||
|
||||
class RSSImp: public QWidget, public Ui::RSS
|
||||
namespace Ui
|
||||
{
|
||||
class RSS;
|
||||
}
|
||||
|
||||
class RSSImp: public QWidget
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
@@ -92,6 +97,7 @@ private:
|
||||
static QTreeWidgetItem *createFolderListItem(const Rss::FilePtr &rssFile);
|
||||
|
||||
private:
|
||||
Ui::RSS *m_ui;
|
||||
Rss::ManagerPtr m_rssManager;
|
||||
FeedListWidget *m_feedList;
|
||||
QListWidgetItem *m_currentArticle;
|
||||
|
||||
@@ -29,6 +29,8 @@
|
||||
* Contact : chris@qbittorrent.org
|
||||
*/
|
||||
|
||||
#include "pluginselectdlg.h"
|
||||
|
||||
#include <QHeaderView>
|
||||
#include <QMenu>
|
||||
#include <QMessageBox>
|
||||
@@ -50,7 +52,7 @@
|
||||
#include "pluginsourcedlg.h"
|
||||
#include "guiiconprovider.h"
|
||||
#include "autoexpandabledialog.h"
|
||||
#include "pluginselectdlg.h"
|
||||
#include "ui_pluginselectdlg.h"
|
||||
|
||||
enum PluginColumns
|
||||
{
|
||||
@@ -63,31 +65,32 @@ enum PluginColumns
|
||||
|
||||
PluginSelectDlg::PluginSelectDlg(SearchEngine *pluginManager, QWidget *parent)
|
||||
: QDialog(parent)
|
||||
, m_ui(new Ui::PluginSelectDlg())
|
||||
, m_pluginManager(pluginManager)
|
||||
, m_asyncOps(0)
|
||||
{
|
||||
setupUi(this);
|
||||
m_ui->setupUi(this);
|
||||
setAttribute(Qt::WA_DeleteOnClose);
|
||||
|
||||
#ifdef QBT_USES_QT5
|
||||
// This hack fixes reordering of first column with Qt5.
|
||||
// https://github.com/qtproject/qtbase/commit/e0fc088c0c8bc61dbcaf5928b24986cd61a22777
|
||||
QTableView unused;
|
||||
unused.setVerticalHeader(pluginsTree->header());
|
||||
pluginsTree->header()->setParent(pluginsTree);
|
||||
unused.setVerticalHeader(m_ui->pluginsTree->header());
|
||||
m_ui->pluginsTree->header()->setParent(m_ui->pluginsTree);
|
||||
unused.setVerticalHeader(new QHeaderView(Qt::Horizontal));
|
||||
#endif
|
||||
pluginsTree->setRootIsDecorated(false);
|
||||
pluginsTree->header()->resizeSection(0, 160);
|
||||
pluginsTree->header()->resizeSection(1, 80);
|
||||
pluginsTree->header()->resizeSection(2, 200);
|
||||
pluginsTree->hideColumn(PLUGIN_ID);
|
||||
m_ui->pluginsTree->setRootIsDecorated(false);
|
||||
m_ui->pluginsTree->header()->resizeSection(0, 160);
|
||||
m_ui->pluginsTree->header()->resizeSection(1, 80);
|
||||
m_ui->pluginsTree->header()->resizeSection(2, 200);
|
||||
m_ui->pluginsTree->hideColumn(PLUGIN_ID);
|
||||
|
||||
actionUninstall->setIcon(GuiIconProvider::instance()->getIcon("list-remove"));
|
||||
m_ui->actionUninstall->setIcon(GuiIconProvider::instance()->getIcon("list-remove"));
|
||||
|
||||
connect(actionEnable, SIGNAL(toggled(bool)), this, SLOT(enableSelection(bool)));
|
||||
connect(pluginsTree, SIGNAL(customContextMenuRequested(const QPoint&)), this, SLOT(displayContextMenu(const QPoint&)));
|
||||
connect(pluginsTree, SIGNAL(itemDoubleClicked(QTreeWidgetItem*, int)), this, SLOT(togglePluginState(QTreeWidgetItem*, int)));
|
||||
connect(m_ui->actionEnable, SIGNAL(toggled(bool)), this, SLOT(enableSelection(bool)));
|
||||
connect(m_ui->pluginsTree, SIGNAL(customContextMenuRequested(const QPoint&)), this, SLOT(displayContextMenu(const QPoint&)));
|
||||
connect(m_ui->pluginsTree, SIGNAL(itemDoubleClicked(QTreeWidgetItem*, int)), this, SLOT(togglePluginState(QTreeWidgetItem*, int)));
|
||||
|
||||
loadSupportedSearchPlugins();
|
||||
|
||||
@@ -104,6 +107,7 @@ PluginSelectDlg::PluginSelectDlg(SearchEngine *pluginManager, QWidget *parent)
|
||||
PluginSelectDlg::~PluginSelectDlg()
|
||||
{
|
||||
emit pluginsChanged();
|
||||
delete m_ui;
|
||||
}
|
||||
|
||||
void PluginSelectDlg::dropEvent(QDropEvent *event)
|
||||
@@ -159,11 +163,11 @@ void PluginSelectDlg::togglePluginState(QTreeWidgetItem *item, int)
|
||||
m_pluginManager->enablePlugin(plugin->name, !plugin->enabled);
|
||||
if (plugin->enabled) {
|
||||
item->setText(PLUGIN_STATE, tr("Yes"));
|
||||
setRowColor(pluginsTree->indexOfTopLevelItem(item), "green");
|
||||
setRowColor(m_ui->pluginsTree->indexOfTopLevelItem(item), "green");
|
||||
}
|
||||
else {
|
||||
item->setText(PLUGIN_STATE, tr("No"));
|
||||
setRowColor(pluginsTree->indexOfTopLevelItem(item), "red");
|
||||
setRowColor(m_ui->pluginsTree->indexOfTopLevelItem(item), "red");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -171,14 +175,14 @@ void PluginSelectDlg::displayContextMenu(const QPoint&)
|
||||
{
|
||||
QMenu myContextMenu(this);
|
||||
// Enable/disable pause/start action given the DL state
|
||||
QList<QTreeWidgetItem *> items = pluginsTree->selectedItems();
|
||||
QList<QTreeWidgetItem *> items = m_ui->pluginsTree->selectedItems();
|
||||
if (items.isEmpty()) return;
|
||||
|
||||
QString first_id = items.first()->text(PLUGIN_ID);
|
||||
actionEnable->setChecked(m_pluginManager->pluginInfo(first_id)->enabled);
|
||||
myContextMenu.addAction(actionEnable);
|
||||
m_ui->actionEnable->setChecked(m_pluginManager->pluginInfo(first_id)->enabled);
|
||||
myContextMenu.addAction(m_ui->actionEnable);
|
||||
myContextMenu.addSeparator();
|
||||
myContextMenu.addAction(actionUninstall);
|
||||
myContextMenu.addAction(m_ui->actionUninstall);
|
||||
myContextMenu.exec(QCursor::pos());
|
||||
}
|
||||
|
||||
@@ -190,8 +194,8 @@ void PluginSelectDlg::on_closeButton_clicked()
|
||||
void PluginSelectDlg::on_actionUninstall_triggered()
|
||||
{
|
||||
bool error = false;
|
||||
foreach (QTreeWidgetItem *item, pluginsTree->selectedItems()) {
|
||||
int index = pluginsTree->indexOfTopLevelItem(item);
|
||||
foreach (QTreeWidgetItem *item, m_ui->pluginsTree->selectedItems()) {
|
||||
int index = m_ui->pluginsTree->indexOfTopLevelItem(item);
|
||||
Q_ASSERT(index != -1);
|
||||
QString id = item->text(PLUGIN_ID);
|
||||
if (m_pluginManager->uninstallPlugin(id)) {
|
||||
@@ -214,8 +218,8 @@ void PluginSelectDlg::on_actionUninstall_triggered()
|
||||
|
||||
void PluginSelectDlg::enableSelection(bool enable)
|
||||
{
|
||||
foreach (QTreeWidgetItem *item, pluginsTree->selectedItems()) {
|
||||
int index = pluginsTree->indexOfTopLevelItem(item);
|
||||
foreach (QTreeWidgetItem *item, m_ui->pluginsTree->selectedItems()) {
|
||||
int index = m_ui->pluginsTree->indexOfTopLevelItem(item);
|
||||
Q_ASSERT(index != -1);
|
||||
QString id = item->text(PLUGIN_ID);
|
||||
m_pluginManager->enablePlugin(id, enable);
|
||||
@@ -233,8 +237,8 @@ void PluginSelectDlg::enableSelection(bool enable)
|
||||
// Set the color of a row in data model
|
||||
void PluginSelectDlg::setRowColor(int row, QString color)
|
||||
{
|
||||
QTreeWidgetItem *item = pluginsTree->topLevelItem(row);
|
||||
for (int i = 0; i < pluginsTree->columnCount(); ++i) {
|
||||
QTreeWidgetItem *item = m_ui->pluginsTree->topLevelItem(row);
|
||||
for (int i = 0; i < m_ui->pluginsTree->columnCount(); ++i) {
|
||||
item->setData(i, Qt::ForegroundRole, QVariant(QColor(color)));
|
||||
}
|
||||
}
|
||||
@@ -243,8 +247,8 @@ QList<QTreeWidgetItem*> PluginSelectDlg::findItemsWithUrl(QString url)
|
||||
{
|
||||
QList<QTreeWidgetItem*> res;
|
||||
|
||||
for (int i = 0; i < pluginsTree->topLevelItemCount(); ++i) {
|
||||
QTreeWidgetItem *item = pluginsTree->topLevelItem(i);
|
||||
for (int i = 0; i < m_ui->pluginsTree->topLevelItemCount(); ++i) {
|
||||
QTreeWidgetItem *item = m_ui->pluginsTree->topLevelItem(i);
|
||||
if (url.startsWith(item->text(PLUGIN_URL), Qt::CaseInsensitive))
|
||||
res << item;
|
||||
}
|
||||
@@ -254,8 +258,8 @@ QList<QTreeWidgetItem*> PluginSelectDlg::findItemsWithUrl(QString url)
|
||||
|
||||
QTreeWidgetItem* PluginSelectDlg::findItemWithID(QString id)
|
||||
{
|
||||
for (int i = 0; i < pluginsTree->topLevelItemCount(); ++i) {
|
||||
QTreeWidgetItem *item = pluginsTree->topLevelItem(i);
|
||||
for (int i = 0; i < m_ui->pluginsTree->topLevelItemCount(); ++i) {
|
||||
QTreeWidgetItem *item = m_ui->pluginsTree->topLevelItem(i);
|
||||
if (id == item->text(PLUGIN_ID))
|
||||
return item;
|
||||
}
|
||||
@@ -266,25 +270,25 @@ QTreeWidgetItem* PluginSelectDlg::findItemWithID(QString id)
|
||||
void PluginSelectDlg::loadSupportedSearchPlugins()
|
||||
{
|
||||
// Some clean up first
|
||||
pluginsTree->clear();
|
||||
m_ui->pluginsTree->clear();
|
||||
foreach (QString name, m_pluginManager->allPlugins())
|
||||
addNewPlugin(name);
|
||||
}
|
||||
|
||||
void PluginSelectDlg::addNewPlugin(QString pluginName)
|
||||
{
|
||||
QTreeWidgetItem *item = new QTreeWidgetItem(pluginsTree);
|
||||
QTreeWidgetItem *item = new QTreeWidgetItem(m_ui->pluginsTree);
|
||||
PluginInfo *plugin = m_pluginManager->pluginInfo(pluginName);
|
||||
item->setText(PLUGIN_NAME, plugin->fullName);
|
||||
item->setText(PLUGIN_URL, plugin->url);
|
||||
item->setText(PLUGIN_ID, plugin->name);
|
||||
if (plugin->enabled) {
|
||||
item->setText(PLUGIN_STATE, tr("Yes"));
|
||||
setRowColor(pluginsTree->indexOfTopLevelItem(item), "green");
|
||||
setRowColor(m_ui->pluginsTree->indexOfTopLevelItem(item), "green");
|
||||
}
|
||||
else {
|
||||
item->setText(PLUGIN_STATE, tr("No"));
|
||||
setRowColor(pluginsTree->indexOfTopLevelItem(item), "red");
|
||||
setRowColor(m_ui->pluginsTree->indexOfTopLevelItem(item), "red");
|
||||
}
|
||||
// Handle icon
|
||||
if (QFile::exists(plugin->iconPath)) {
|
||||
|
||||
@@ -32,12 +32,19 @@
|
||||
#ifndef PLUGINSELECTDLG_H
|
||||
#define PLUGINSELECTDLG_H
|
||||
|
||||
#include "ui_pluginselectdlg.h"
|
||||
#include <QDialog>
|
||||
|
||||
class QDropEvent;
|
||||
class QTreeWidgetItem;
|
||||
|
||||
class SearchEngine;
|
||||
|
||||
class PluginSelectDlg: public QDialog, private Ui::PluginSelectDlg
|
||||
namespace Ui
|
||||
{
|
||||
class PluginSelectDlg;
|
||||
}
|
||||
|
||||
class PluginSelectDlg: public QDialog
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
@@ -82,6 +89,7 @@ private:
|
||||
void startAsyncOp();
|
||||
void finishAsyncOp();
|
||||
|
||||
Ui::PluginSelectDlg *m_ui;
|
||||
SearchEngine *m_pluginManager;
|
||||
int m_asyncOps;
|
||||
};
|
||||
|
||||
@@ -30,14 +30,22 @@
|
||||
|
||||
#include "pluginsourcedlg.h"
|
||||
|
||||
#include "ui_pluginsourcedlg.h"
|
||||
|
||||
PluginSourceDlg::PluginSourceDlg(QWidget *parent)
|
||||
: QDialog(parent)
|
||||
, m_ui(new Ui::PluginSourceDlg())
|
||||
{
|
||||
setupUi(this);
|
||||
m_ui->setupUi(this);
|
||||
setAttribute(Qt::WA_DeleteOnClose);
|
||||
show();
|
||||
}
|
||||
|
||||
PluginSourceDlg::~PluginSourceDlg()
|
||||
{
|
||||
delete m_ui;
|
||||
}
|
||||
|
||||
void PluginSourceDlg::on_localButton_clicked()
|
||||
{
|
||||
emit askForLocalFile();
|
||||
|
||||
@@ -32,14 +32,19 @@
|
||||
#define PLUGINSOURCEDLG_H
|
||||
|
||||
#include <QDialog>
|
||||
#include "ui_pluginsourcedlg.h"
|
||||
|
||||
class PluginSourceDlg: public QDialog, private Ui::PluginSourceDlg
|
||||
namespace Ui
|
||||
{
|
||||
class PluginSourceDlg;
|
||||
}
|
||||
|
||||
class PluginSourceDlg: public QDialog
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
explicit PluginSourceDlg(QWidget *parent = 0);
|
||||
~PluginSourceDlg();
|
||||
|
||||
signals:
|
||||
void askForUrl();
|
||||
@@ -48,6 +53,9 @@ signals:
|
||||
private slots:
|
||||
void on_localButton_clicked();
|
||||
void on_urlButton_clicked();
|
||||
|
||||
private:
|
||||
Ui::PluginSourceDlg *m_ui;
|
||||
};
|
||||
|
||||
#endif // PLUGINSOURCEDLG_H
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user