Compare commits
244 Commits
release-3.
...
release-3.
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
cb5174bfa2 | ||
|
|
9138156968 | ||
|
|
8a0b1fe0be | ||
|
|
3bbe304856 | ||
|
|
0356172a1d | ||
|
|
80f3b19356 | ||
|
|
39a569b438 | ||
|
|
edaa7e85a7 | ||
|
|
f9f7a8cbf2 | ||
|
|
7aef9828c9 | ||
|
|
18ad972936 | ||
|
|
8b5c275934 | ||
|
|
59765954b8 | ||
|
|
f5fff855bb | ||
|
|
26c713851e | ||
|
|
f9b64c4e73 | ||
|
|
edf6c30cd8 | ||
|
|
83860afa60 | ||
|
|
4b7362aa6b | ||
|
|
dd0537d8d2 | ||
|
|
3c50cc1d2c | ||
|
|
78fdb68457 | ||
|
|
bb1bd34ec0 | ||
|
|
1841834c89 | ||
|
|
30b70a99f1 | ||
|
|
f0f2e93e4d | ||
|
|
5852c5e318 | ||
|
|
b38827bb8e | ||
|
|
240046f720 | ||
|
|
78b1194da1 | ||
|
|
c1a66dad51 | ||
|
|
4a10d246c2 | ||
|
|
125ab378a4 | ||
|
|
4cd8a36b40 | ||
|
|
364df2e18c | ||
|
|
f8f2476aa5 | ||
|
|
d685c9739b | ||
|
|
6fdfcf38f1 | ||
|
|
7c85866881 | ||
|
|
37673cd86f | ||
|
|
a4a38d633c | ||
|
|
93bdc81e3c | ||
|
|
827d5a22fb | ||
|
|
34e56eade8 | ||
|
|
4a23e7da37 | ||
|
|
f577a26fe2 | ||
|
|
3f176d8265 | ||
|
|
cbc001e059 | ||
|
|
a66ed05ecd | ||
|
|
ec347d8dbe | ||
|
|
f0acafb853 | ||
|
|
1a12e891ec | ||
|
|
88ba8e2ceb | ||
|
|
2e403277f3 | ||
|
|
89349f60b0 | ||
|
|
0604d3729a | ||
|
|
cf16e3b8a1 | ||
|
|
dcb3496651 | ||
|
|
9d10da3ed2 | ||
|
|
0524deb496 | ||
|
|
787ae43d54 | ||
|
|
67bb2cc150 | ||
|
|
51995c80d1 | ||
|
|
5f43741b09 | ||
|
|
3328d8efd2 | ||
|
|
a54a9e5487 | ||
|
|
0181ca70f4 | ||
|
|
ff665af3f7 | ||
|
|
9275cdc5bf | ||
|
|
b7c3bdd443 | ||
|
|
5fd08f8664 | ||
|
|
84a4d323c7 | ||
|
|
8efb13bfaf | ||
|
|
0187b55610 | ||
|
|
2f606b2728 | ||
|
|
025f75beca | ||
|
|
4711cafd20 | ||
|
|
8d12ca9477 | ||
|
|
67b90bfb51 | ||
|
|
ab05c0c326 | ||
|
|
c5ea453438 | ||
|
|
4f041c16e1 | ||
|
|
28cfee7bd3 | ||
|
|
6272287fbb | ||
|
|
e7a1542902 | ||
|
|
5e371d8195 | ||
|
|
6bb189ea13 | ||
|
|
8496f31e39 | ||
|
|
08f634f748 | ||
|
|
2b5dc5c4a6 | ||
|
|
0a2f0aefb3 | ||
|
|
66e137b8ee | ||
|
|
f9be39545b | ||
|
|
789b8046a2 | ||
|
|
129bf497c8 | ||
|
|
a6d7693d62 | ||
|
|
4e9fbc4da5 | ||
|
|
23f6ff4673 | ||
|
|
3c0dfa6444 | ||
|
|
694311b2bd | ||
|
|
b77626897f | ||
|
|
b8081feac1 | ||
|
|
8b805f4518 | ||
|
|
8bb4f021f1 | ||
|
|
97c79050dc | ||
|
|
ac62a708de | ||
|
|
8d9789f51b | ||
|
|
559d0228fd | ||
|
|
1296e7b891 | ||
|
|
0333e23710 | ||
|
|
7320a80caa | ||
|
|
0579bfc069 | ||
|
|
d20d04299e | ||
|
|
50b2009e9c | ||
|
|
721d29edda | ||
|
|
bc9cae199b | ||
|
|
c38b250667 | ||
|
|
101b2f3ad2 | ||
|
|
9c4f798d93 | ||
|
|
249ff21738 | ||
|
|
f1149097b6 | ||
|
|
111b0df307 | ||
|
|
8041af72cd | ||
|
|
4be6d0b30f | ||
|
|
8c757969f2 | ||
|
|
ae6a82f814 | ||
|
|
eed3f0559a | ||
|
|
c7884e7621 | ||
|
|
2946ab7e7a | ||
|
|
ddb8e4d21a | ||
|
|
00d4f6141f | ||
|
|
7971a25c2a | ||
|
|
ab2411930a | ||
|
|
93f972bfca | ||
|
|
db638844d0 | ||
|
|
ba99eddc91 | ||
|
|
92428cee5d | ||
|
|
2c7d836925 | ||
|
|
7703dcf626 | ||
|
|
157520c4fc | ||
|
|
5bc728fa33 | ||
|
|
35fdc43b3f | ||
|
|
ae6ea29f2f | ||
|
|
4eac2cab31 | ||
|
|
87f4f57f8e | ||
|
|
a6e250fa43 | ||
|
|
b118079379 | ||
|
|
cb2d39f2a7 | ||
|
|
4cf549ff25 | ||
|
|
b5c6342dca | ||
|
|
46ec556921 | ||
|
|
33ae1a7bee | ||
|
|
87a3a67668 | ||
|
|
055b1e0163 | ||
|
|
2bd5ea2c68 | ||
|
|
1479a74198 | ||
|
|
9a0d25284c | ||
|
|
284e836992 | ||
|
|
43f5b31843 | ||
|
|
cada6cfc88 | ||
|
|
99f157927f | ||
|
|
664664394c | ||
|
|
a790901691 | ||
|
|
fdc70eaa62 | ||
|
|
b05a23e1ab | ||
|
|
9f6a0882e2 | ||
|
|
b351b21e55 | ||
|
|
ef22f06e92 | ||
|
|
8ea7426bc1 | ||
|
|
79e7e1727f | ||
|
|
98c33dd77c | ||
|
|
9c6504f6dd | ||
|
|
76c350bdcb | ||
|
|
106dcfd00e | ||
|
|
668c8cb0e2 | ||
|
|
3159bdf4dd | ||
|
|
97d2c0d187 | ||
|
|
0041ee3636 | ||
|
|
1ed523bec3 | ||
|
|
b131a6e9df | ||
|
|
56d9d370e9 | ||
|
|
a6efc4d92d | ||
|
|
a77db6e822 | ||
|
|
95a558941e | ||
|
|
867d69d0f2 | ||
|
|
a6d381da38 | ||
|
|
f0eb708b07 | ||
|
|
1d70698bd0 | ||
|
|
79871c8e21 | ||
|
|
25d5524213 | ||
|
|
8d21b73434 | ||
|
|
2ef01a314c | ||
|
|
a8b4aca5e6 | ||
|
|
67e7315eae | ||
|
|
a25a15d1c6 | ||
|
|
086588eeed | ||
|
|
44fa308681 | ||
|
|
6188287094 | ||
|
|
17d10afd65 | ||
|
|
89bd0e4397 | ||
|
|
1c1917f885 | ||
|
|
642377bd65 | ||
|
|
bb4668c071 | ||
|
|
689316db09 | ||
|
|
ad0c008a3e | ||
|
|
09e3698b37 | ||
|
|
6450ebfc6c | ||
|
|
e9f38ebcfd | ||
|
|
4dba31f534 | ||
|
|
04c1aad0dd | ||
|
|
6763f3ac33 | ||
|
|
afca704db0 | ||
|
|
eaec8fcddd | ||
|
|
f86fd52d6f | ||
|
|
f3f175570c | ||
|
|
729c80f910 | ||
|
|
fcaca558a0 | ||
|
|
983df9113e | ||
|
|
acf9874252 | ||
|
|
d7cf6bb11b | ||
|
|
558ea53cc2 | ||
|
|
87a6478430 | ||
|
|
cea673b267 | ||
|
|
4a5ab93c62 | ||
|
|
4c86fc8973 | ||
|
|
1c485ffb07 | ||
|
|
f283734f13 | ||
|
|
dca4ff0649 | ||
|
|
1975f2269e | ||
|
|
6fac9b42da | ||
|
|
dabae4c914 | ||
|
|
b1e9b4493d | ||
|
|
2fa207e728 | ||
|
|
7adcd909e7 | ||
|
|
50805fc2b5 | ||
|
|
3a1b7b6159 | ||
|
|
498b7c2436 | ||
|
|
4f17364305 | ||
|
|
9ebc115719 | ||
|
|
a6fa8c3a8e | ||
|
|
8187366c89 | ||
|
|
366ad01120 | ||
|
|
4da05e5914 | ||
|
|
3fb19b6a28 |
@@ -9,8 +9,8 @@ environment:
|
||||
REPO_DIR: &REPO_DIR c:\qbittorrent
|
||||
CACHE_DIR: &CACHE_DIR c:\qbt_cache
|
||||
|
||||
QBT_VER_URL: http://builds.shiki.hu/appveyor/version
|
||||
QBT_LIB_URL: http://builds.shiki.hu/appveyor/qbt_libraries.7z
|
||||
QBT_VER_URL: https://builds.shiki.hu/appveyor/version
|
||||
QBT_LIB_URL: https://builds.shiki.hu/appveyor/qbt_libraries.7z
|
||||
|
||||
# project directory
|
||||
clone_folder: *REPO_DIR
|
||||
14
.github/ISSUE_TEMPLATE.md
vendored
Normal file
@@ -0,0 +1,14 @@
|
||||
**Please provide the following information**
|
||||
|
||||
### qBittorrent version and Operating System:
|
||||
|
||||
### If on linux, libtorrent and Qt version:
|
||||
|
||||
### What is the problem:
|
||||
|
||||
### What is the expected behavior:
|
||||
|
||||
### Steps to reproduce:
|
||||
|
||||
### Extra info(if any):
|
||||
|
||||
43
.travis.yml
@@ -3,7 +3,7 @@ language: cpp
|
||||
os:
|
||||
- linux
|
||||
- osx
|
||||
osx_image: xcode7
|
||||
osx_image: xcode7.3
|
||||
|
||||
env:
|
||||
matrix:
|
||||
@@ -17,6 +17,12 @@ env:
|
||||
global:
|
||||
- secure: "OI9CUjj4lTb0HwwIZU5PbECU3hLlAL6KC8KsbwohG8/O3j5fLcnmDsK4Ad9us5cC39sS11Jcd1kDP2qRcCuST/glVNhLkcjKkiQerOfd5nQ/qL4JYfz/1mfP5mdpz9jHKzpLUIG+TXkbSTjP6VVmsb5KPT+3pKEdRFZB+Pu9+J8="
|
||||
- coverity_branch: coverity_scan
|
||||
matrix:
|
||||
allow_failures:
|
||||
- os: osx
|
||||
env: lt_branch=RC_1_0 qt=4 gui=true
|
||||
- os: osx
|
||||
env: lt_branch=RC_1_0 qt=4 gui=false
|
||||
|
||||
branches:
|
||||
except:
|
||||
@@ -30,7 +36,10 @@ notifications:
|
||||
|
||||
# container-based builds
|
||||
#sudo: false
|
||||
cache: ccache
|
||||
cache:
|
||||
ccache: true
|
||||
directories:
|
||||
- $HOME/hombebrew_cache
|
||||
|
||||
# opt-in Ubuntu Trusty
|
||||
sudo: required
|
||||
@@ -117,16 +126,40 @@ install:
|
||||
fi
|
||||
- |
|
||||
if [ "$TRAVIS_OS_NAME" = "osx" ]; then
|
||||
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." ;
|
||||
# First delete old files
|
||||
rm -r "$HOME/hombebrew_cache" ;
|
||||
mkdir "$HOME/hombebrew_cache";
|
||||
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 ;
|
||||
fi
|
||||
|
||||
# dependencies
|
||||
brew update > /dev/null ;
|
||||
brew install colormake ccache ;
|
||||
brew outdated "pkg-config" || brew upgrade "pkg-config" ;
|
||||
# libtorrent-rasterbar 1.0.9
|
||||
brew install https://raw.githubusercontent.com/Homebrew/homebrew-core/477d5060fa093883204d70323965375353e03084/Formula/libtorrent-rasterbar.rb ;
|
||||
# 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)" ;
|
||||
brew install "$HOME/hombebrew_cache/libtorrent-rasterbar.rb" ;
|
||||
|
||||
# Qt
|
||||
if [ "$qt" = 4 ]; then brew install qt && ln -s /usr/local/Cellar/qt/4.8.7_2/plugins /usr/local ; fi ;
|
||||
if [ "$qt" = 5 ]; then brew install qt5 && brew link --force qt5 && ln -s /usr/local/Cellar/qt5/5.6.0/plugins /usr/local ; fi ;
|
||||
if [ "$qt" = 5 ]; then
|
||||
# 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 ;
|
||||
fi
|
||||
|
||||
# ccache
|
||||
if [ "$TRAVIS_BRANCH" != "$coverity_branch" ]; then
|
||||
|
||||
87
5B7CC9A2.asc
@@ -26,28 +26,67 @@ HiShCTSSDBJqFmhfjrCo0nISKnzyxgO/rY9vFlwXsKkTyL7s53ONkjwK34WmGnya
|
||||
tXdjBWShzAiTfF5hephfBSszmoBG2C8Jcu6P5n4buBY4RCsEa+6jE0R1vCtmpVwx
|
||||
WrXOeN2kGYMpAkPK1L69Le0FofgUDKlaFMv7KRl4R367xNRukYrsKwVlontJ+Y72
|
||||
X5t1BeRn8VSp0IzhssNXM8a4bTE8lvs889DOS2vgWEHIi0iyIesJYWPs4AKUw4rG
|
||||
EDwWxtTS0a7Rfx3DxLkCDQRXDSCMARAAqMIVJizEJp205c546IN75xeYiFszNXcs
|
||||
3768IY8bOoWj+rTwt2wIwtL/3O5K2dG79CSt2H5o6BPKmq43tOO60YW3Yk3m9BB/
|
||||
gnAVqk0QOPr5O8+yeBzdElU8CZh6y6zZMWugSkNmTDm6jZzPhgNjcjrit/dl9+0D
|
||||
GqJQcqoD8WzEWNcWrMHVz9cDewnLSVkwR758mZMaIiL7R10MZ++tNrC0j69UINqx
|
||||
+9z1r1J07+NNnxqSTxVRcbjPYtM9E+tUiVFS2HPWN9ShVDkBAEdoWh90qzRaMiFl
|
||||
2NGNGOD1iHx/xr06RMeGEEXt2vhSlhfMW2YQW+UD2jzlFbARf53v39MUKKscGuIp
|
||||
BhxGw3JCq4l6qLW/bDkgnoXlOhZDmhQm6OpsjAyk9IEdd3ponSc7yYD3mUkJKR9e
|
||||
TaALD5t6TQGyNHakb4UfoXtE2RR78cbPlLIwag7eQ8GsNA+dfjowmOZdojx3ROsH
|
||||
ZdGQwb0YFLjuKAusA3TY+lCfbS6kzE2iI2DuaW+3dICcLrYuibbVb0CBNHyD+8KE
|
||||
tczdur/wm0lhqyVJkGyZKZT8C2cPxywKgy1Rn6F8Yfmj0Lna3nvtaZu0ZUS4/8Li
|
||||
t5PcOso1lSmYBuD6yq+GEAMCnUmn1Pm8eZRMlxxQuTPvyJKQrRDhbtAAr472MSno
|
||||
JKlS4SfaUF0AEQEAAYkCHwQYAQgACQUCVw0gjAIbDAAKCRBuSi0CW3zJomZDD/9I
|
||||
Jmzd5hiEzntlp84pyIJcfyIRe4KImvldAy6T02OSIbF1HzCNnwmqIPob6MOdMZ+K
|
||||
NwMK0htRkrRr/zM034+lBiWKZt+tVYHu49ioTYXEjAc5qDJE09Sq7HceQnhgE48f
|
||||
1n54XGT5G2w5gw+/a8Qn1SceE44VwXafL3E1gKaOrrsb1UH/AJhp+W4VMu+7bLXu
|
||||
7h1tN6v2PhvCYvBt3zyy8Q8xfJ2x7/D1lbF8ATJAiZ/km9x5bRm7OGRliVYaUe1n
|
||||
yR42fZOj3CBmAR0+lZLgjriqdMXrs+qlBbrmAhkn0XPQXAeaPifKoKIGDAUWIsqD
|
||||
HqM7imMGT+MR9APfSw8M4enOJWL+HnKpVBEARCEDpaFpJ3u7QRucFybpEhvIymoN
|
||||
ftyw+urId2Eg2K33NypeZo3M1K2LC65f2Ta7f/sZcIDUTbgW+m334fgVl1KptDA5
|
||||
DX3U9lTci7mi4uPuAFtbWrB1di4jYrxXYuzFm5g4xTb0Hw3kYIB6WXF+I7i0JaGO
|
||||
THxPC5X5lIAZrYrkxh+1n1Y1CY+TC8JcTzwORJIbFFm9tD/BHXa4849k4DVvFYCZ
|
||||
khq+/56FKZfoVByhB+x+2GaMlsBm1uPniO4lAakFPpIi0kaap4UVayQ/7ak+Bhsc
|
||||
AIHZUy6NtgZkuvW3xdpwp07LYo2ilhMI8RnzmtoRmg==
|
||||
=tDGM
|
||||
EDwWxtTS0a7Rfx3DxLRWc2xlZGdlaGFtbWVyOTk5IChVc2VkIGZvciBzaWduaW5n
|
||||
IGdpdCBjb21taXRzL3RhZ3MvZXRjLikgPGhhbW1lcmVkOTk5QHFiaXR0b3JyZW50
|
||||
Lm9yZz6JAh8EMAEIAAkFAlhie1ICHQAACgkQbkotAlt8yaILIhAAp25o1BbUG2Zk
|
||||
At3cSrTFnZSCA7nEygbSUv1Uek33JZfY0Apw5qEM8lQCMZk+mhdrSQCYUJcQlruN
|
||||
zJcJf4CH+VGE23xkI3Kf0nGp9Cjn/q6b1hLIPe5rimvw5pTAejFtebcYY/ZJIB8Z
|
||||
H1ebuzfqBZ/9k7eYTarZ/ZsgG8YptB0RXBQWOMaSEKwdeo2m7HXHgK3blQiqbuJJ
|
||||
uyPbid01Wus4AVN47/FKgDNswPs8irYZsu5yakgpi2KLycGDtSiN5XFHI4xbC0zM
|
||||
srR7Cz0/fC+klhGcuxbw0V0It7UUIitgCcTPHXkukUU8i2+AGMyKa1HjchsXDdLg
|
||||
DIs6KIurp2ve7znKOz7h1aX8cOBmB/QYeYAx9jRRkePMIRT8V1lRwfvJlJxx1+G3
|
||||
e2gJLjqTN8a08KHHjdY/S0ZFERxSlmOym2uf/y6di1ipDPxo8xvDuS5kDbdZLC0t
|
||||
XijlsH8ONK27KNuWhucG8zHzKQvnPw2qN06SZq4FjbSmAkkuYs56heLEXMzFr75k
|
||||
SE8rUoQQ+ABG9gU46GEvKlZxqSwXgGnb1X6K7h8svjMh/NlAU358p8Sra4Ru5tz4
|
||||
jUu9MoVEw5Lbjcrsnp6/4Kk1Q2ckBNt43nv8/+C7NsC3xi6BrOInuaKHZ4QsTuzJ
|
||||
m1/A4zlKRnUi6T98DXfIYnNuV9NSmAWJAjkEEwEIACMFAlhiemMCGwMHCwkIBwMC
|
||||
AQYVCAIJCgsEFgIDAQIeAQIXgAAKCRBuSi0CW3zJor6yD/9N2U0INx0nYpGkmvah
|
||||
yVG/vw2S6hhKK+03AN+RrtddNRg4aBf/gmOvRWQhAmFnXOBA7fO09wgcljaV5tVb
|
||||
MYyYZvHhK0o2/sli2p/M5N8ZxchRHypjxUSEyG9ZQ06QG5DVhh4HtM8nIN+UcwTV
|
||||
C5QjyoWZvHf+tNroyFeh7zT+w4kX1VxgynTQr5LGdYsrVA3CFyT3zsBWV3dMae23
|
||||
22CHOirsBBLwairHUsWW+BdThT3MkKYpTEV0jkH4OyAXhJYcS5IjjtKQ8UpZE9dw
|
||||
f4saJ0TnXNe7goPRZtH7UjPwfVbtYK4y8QklWUTRxgoBxNwSC5X7Flg+3xXxE/VU
|
||||
U4cehyRkH64i7MJDoFkqh5JtjkgIz+kuTTXb7xR0Wf+JXrGMybZTR8xth2TEMC20
|
||||
1FT5L5+0vH1WRzL7bhlaU3EXyCnoH8sDvMEClZbibbew+rf7fC3tFU41ohUT0HDl
|
||||
zlyfVjRvBHWMTgfpWKBV2m/qP941xTJ9VHxOlAB02XKUZYwFt07CpH+yjMOCOzA4
|
||||
cTPBD3mGRuft0V0BJ8bA5bcTly/GBciRX0Y5oIeHZGgq2czb0sywSYT6mPoQMFNM
|
||||
B+Cwr4pm90r1DMMfW518onF2itwyN/Id0FsWDhsLJHKluBJw52C3OnxCuToVutTm
|
||||
xntqpPVv62LaeVeWQqxIieTJErRQc2xlZGdlaGFtbWVyXzk5OSAoVXNlZCBmb3Ig
|
||||
c2lnbmluZyBnaXQgY29tbWl0cy90YWdzL2V0YykgPGhhbW1lcmVkOTk5QGdtYWls
|
||||
LmNvbT6JAjkEEwEIACMFAlhifeICGwMHCwkIBwMCAQYVCAIJCgsEFgIDAQIeAQIX
|
||||
gAAKCRBuSi0CW3zJolcCD/9xPBNEkFtnhTW89th0TFZnB5oykCQjyefquvQs8KWT
|
||||
C92/1VizHi4ZxDehHWP9IKVWT3ZJthj5ZXBSedyl1tHnwkyrUYBW9roQwtDWPncK
|
||||
pXl/HsE6p3q6EIus+g6YJo4UvYachJFAZATZp1WDBPIswziHGzaL0tndFWZuVM8V
|
||||
QD0tfPQsS1qCDVv6+B1JWZDnA1JzdSG/uzPhL95q/ff6JmNbfSAVedK2PyqYshnC
|
||||
KWBx6Yna/0ColBuDFho8+bDuHPQcM35xyjPosVD7moXQiY4yMAJ+VzwEBaCFleI0
|
||||
RBWw8/+qyoFqfIKwdq8G+7I9LjWpBiN2+uQBZ+OAvsMWyRShLopxt3JluPTtL6xb
|
||||
Ca6dglOdlaOS/A6FK7u05k/8kQMDS5Jq2/rpfTPRl1/weCaJZgfRIBosk1Mon/pR
|
||||
p1zd0abM4t7BcGQpwSkKAmqlKCrWf886EFQT0CJTBo8q7pzgpVraWWPVsmAOdkfU
|
||||
YcKBgz1A2uMSAxypkSzaDZkIVj6I7gwiGk7IMYx1OK7Ev46h/x4Z7kgT0y3DYYOq
|
||||
ggVEKQ+15Krn7bZ35s8vbZdfnVKPSXdCC8jkIMBmGmRX6cgZZ3OXZlrrHht5icgJ
|
||||
5Z2d1M4JUoEZVUr2xNZkkaMk01NAIpGgKvIS6yHuj6vE4GMJ+A/qEW6J60/3YHRe
|
||||
0bkCDQRXDSCMARAAqMIVJizEJp205c546IN75xeYiFszNXcs3768IY8bOoWj+rTw
|
||||
t2wIwtL/3O5K2dG79CSt2H5o6BPKmq43tOO60YW3Yk3m9BB/gnAVqk0QOPr5O8+y
|
||||
eBzdElU8CZh6y6zZMWugSkNmTDm6jZzPhgNjcjrit/dl9+0DGqJQcqoD8WzEWNcW
|
||||
rMHVz9cDewnLSVkwR758mZMaIiL7R10MZ++tNrC0j69UINqx+9z1r1J07+NNnxqS
|
||||
TxVRcbjPYtM9E+tUiVFS2HPWN9ShVDkBAEdoWh90qzRaMiFl2NGNGOD1iHx/xr06
|
||||
RMeGEEXt2vhSlhfMW2YQW+UD2jzlFbARf53v39MUKKscGuIpBhxGw3JCq4l6qLW/
|
||||
bDkgnoXlOhZDmhQm6OpsjAyk9IEdd3ponSc7yYD3mUkJKR9eTaALD5t6TQGyNHak
|
||||
b4UfoXtE2RR78cbPlLIwag7eQ8GsNA+dfjowmOZdojx3ROsHZdGQwb0YFLjuKAus
|
||||
A3TY+lCfbS6kzE2iI2DuaW+3dICcLrYuibbVb0CBNHyD+8KEtczdur/wm0lhqyVJ
|
||||
kGyZKZT8C2cPxywKgy1Rn6F8Yfmj0Lna3nvtaZu0ZUS4/8Lit5PcOso1lSmYBuD6
|
||||
yq+GEAMCnUmn1Pm8eZRMlxxQuTPvyJKQrRDhbtAAr472MSnoJKlS4SfaUF0AEQEA
|
||||
AYkCHwQYAQgACQUCVw0gjAIbDAAKCRBuSi0CW3zJomZDD/9IJmzd5hiEzntlp84p
|
||||
yIJcfyIRe4KImvldAy6T02OSIbF1HzCNnwmqIPob6MOdMZ+KNwMK0htRkrRr/zM0
|
||||
34+lBiWKZt+tVYHu49ioTYXEjAc5qDJE09Sq7HceQnhgE48f1n54XGT5G2w5gw+/
|
||||
a8Qn1SceE44VwXafL3E1gKaOrrsb1UH/AJhp+W4VMu+7bLXu7h1tN6v2PhvCYvBt
|
||||
3zyy8Q8xfJ2x7/D1lbF8ATJAiZ/km9x5bRm7OGRliVYaUe1nyR42fZOj3CBmAR0+
|
||||
lZLgjriqdMXrs+qlBbrmAhkn0XPQXAeaPifKoKIGDAUWIsqDHqM7imMGT+MR9APf
|
||||
Sw8M4enOJWL+HnKpVBEARCEDpaFpJ3u7QRucFybpEhvIymoNftyw+urId2Eg2K33
|
||||
NypeZo3M1K2LC65f2Ta7f/sZcIDUTbgW+m334fgVl1KptDA5DX3U9lTci7mi4uPu
|
||||
AFtbWrB1di4jYrxXYuzFm5g4xTb0Hw3kYIB6WXF+I7i0JaGOTHxPC5X5lIAZrYrk
|
||||
xh+1n1Y1CY+TC8JcTzwORJIbFFm9tD/BHXa4849k4DVvFYCZkhq+/56FKZfoVByh
|
||||
B+x+2GaMlsBm1uPniO4lAakFPpIi0kaap4UVayQ/7ak+BhscAIHZUy6NtgZkuvW3
|
||||
xdpwp07LYo2ilhMI8RnzmtoRmg==
|
||||
=UBeB
|
||||
-----END PGP PUBLIC KEY BLOCK-----
|
||||
|
||||
@@ -1,15 +1,14 @@
|
||||
cmake_minimum_required(VERSION 3.5)
|
||||
cmake_policy(VERSION 3.5)
|
||||
|
||||
project(qBittorrent VERSION 3.4.0.0)
|
||||
list(APPEND CMAKE_MODULE_PATH ${CMAKE_CURRENT_SOURCE_DIR}/cmake/Modules)
|
||||
include(FunctionReadVersion)
|
||||
|
||||
set(VER_MAJOR ${qBittorrent_VERSION_MAJOR})
|
||||
set(VER_MINOR ${qBittorrent_VERSION_MINOR})
|
||||
set(VER_BUGFIX ${qBittorrent_VERSION_PATCH})
|
||||
set(VER_BUILD ${qBittorrent_VERSION_TWEAK})
|
||||
set(VER_STATUS "alpha") # Should be empty for stable releases!
|
||||
read_version("${CMAKE_CURRENT_SOURCE_DIR}/version.pri" VER_MAJOR VER_MINOR VER_BUGFIX VER_BUILD VER_STATUS)
|
||||
# message(STATUS "Project version is: ${VER_MAJOR}.${VER_MINOR}.${VER_BUGFIX}.${VER_BUILD} (${VER_STATUS})")
|
||||
|
||||
project(qBittorrent VERSION ${VER_MAJOR}.${VER_MINOR}.${VER_BUGFIX}.${VER_BUILD})
|
||||
|
||||
# Don't touch the rest part
|
||||
set(PROJECT_VERSION "${VER_MAJOR}.${VER_MINOR}.${VER_BUGFIX}")
|
||||
|
||||
if (NOT VER_BUILD EQUAL 0)
|
||||
@@ -28,7 +27,6 @@ add_definitions(-DVERSION_BUILD=${VER_BUILD})
|
||||
# } else {
|
||||
add_definitions(-DVERSION="v${PROJECT_VERSION}")
|
||||
# }
|
||||
list(APPEND CMAKE_MODULE_PATH ${qBittorrent_SOURCE_DIR}/cmake/Modules)
|
||||
|
||||
# set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Og")
|
||||
if (UNIX AND NOT APPLE)
|
||||
|
||||
127
Changelog
@@ -1,3 +1,130 @@
|
||||
* Fri Mar 03 2017 - sledgehammer999 <sledgehammer999@qbittorrent.org> - v3.3.11
|
||||
- FEATURE: Always show progress and remaining bytes for unselected files. (sledgehammer999)
|
||||
- FEATURE: Allow to change priority for unselected files through the combobox like it is done via the context menu. (sledgehammer999)
|
||||
- FEATURE: Remove settings to exchange trackers. It wasn't used by non-libtorrent clients. Also it has a privacy risk and you might be DDoSing someone. (sledgehammer999)
|
||||
- FEATURE: Put temp files in .qBittorrent directory. Closes #4462. (Chocobo1)
|
||||
- FEATURE: Use the numbers from tracker scrape response. Closes #5048, #6117. (Chocobo1)
|
||||
- FEATURE: Implement category filter widget. Show categories in tree mode when subcategories are enabled. (glassez)
|
||||
- FEATURE: Allow to toggle columns in searchtab (thalieht)
|
||||
- FEATURE: PeerList: allow to hide zero values for the "uploaded" and "downloaded" columns (thalieht)
|
||||
- FEATURE: Display more information in tracker tab (ngosang)
|
||||
- FEATURE: Use Ctrl+F to search torrents. Closes #5797. (Tim Delaney)
|
||||
- FEATURE: Transferlist: add hotkeys for double click and recheck selected torrents (thalieht)
|
||||
- FEATURE: Add hotkey for execution log tab, Trackerlist, Peerlist etc (thalieht)
|
||||
- FEATURE: Seperate seeds from peers for DHT, PeX and LSD (thalieht)
|
||||
- BUGFIX: Do not remove added files unconditionally. Closes #6248 (Eugene Shalygin)
|
||||
- BUGFIX: Ignore mouse wheel events in Advanced Settings. Closes #866. (Chocobo1)
|
||||
- BUGFIX: Add queue repair code. It should fix missing torrents after restarting. (Eugene Shalygin, nxd4)
|
||||
- BUGFIX: Fetch torrent status when generating final fastresume data. It should fix missing torrents after restarting. (Eugene Shalygin)
|
||||
- BUGFIX: Fix queue overload for add torrent at session start. It should fix missing torrents after restarting. (falco)
|
||||
- BUGFIX: After files relocate, don't remove the old folder even if it is empty. (Chocobo1)
|
||||
- BUGFIX: Fix finding 'English' item in language dropdown menu when an unrecognized locale is requested. Closes #6109. (sledgehammer999)
|
||||
- BUGIFX: Speedlimitdlg: raise slider default value to 10000. Closes #6150. (Chocobo1)
|
||||
- BUGFIX: TransferListWidget: keep columns width even if they are hidden on qBittorrent startup (unless something goes wrong) (thalieht)
|
||||
- BUGFIX: fix index overflow for torrents with invalid meta data or empty progress (Falco)
|
||||
- BUGFIX: Immediately update torrent_status after manipulating super seeding mode. Partially fixes #6072. (sledgehammer999)
|
||||
- BUGFIX: Use case-insensitive comparsion for torrent content window. Closes #6327. (Chocobo1)
|
||||
- BUGFIX: Fixed sort order for datetime columns with empty values (closes #2988) (Vladimir Sinenko)
|
||||
- BUGFIX: Disable proxy in WebUI HTTP server. Closes #6349. (Eugene Shalygin)
|
||||
- COSMETIC: Use a disabled progressbar's palette for unselected files. (sledgehammer999)
|
||||
- COSMETIC: Support fallback when selecting theme icons (Eugene Shalygin)
|
||||
- COSMETIC: Do not resize SVG icons (Eugene Shalygin)
|
||||
- COSMETIC: Align text to the right in columns that handle numbers for PeerList and SearchTab (thalieht)
|
||||
- COSMETIC: Increased number of digits after the decimal point for Gibibytes and above (thalieht)
|
||||
- COSMETIC: Use non-breaking spaces between numbers and units (thalieht)
|
||||
- WEBUI: Fix proxy type bug (Oke Atime)
|
||||
- WEBUI: Use the correct value for KEY_TORRENT_NUM_COMPLETE/KEY_TORRENT_NUM_INCOMPLETE (Chocobo1)
|
||||
- WEBUI: Make torrents table scrollable horizontally (buinsky)
|
||||
- WEBUI: Make torrent peers table scrollable horizontally (buinsky)
|
||||
- WEBUI: Add tooltips to dynamic table header (buinsky)
|
||||
- WEBUI: Implement dynamic table columns resizing, reordering and hiding (buinsky)
|
||||
- WEBUI: Add some missing columns to dynamic tables (buinsky)
|
||||
- WEBUI: Make too tall menus scrollable (buinksy)
|
||||
- WEBUI: Prevent text wrapping in menus (buinsky)
|
||||
- WEBUI: Add a vertical separator between columns (buinsky)
|
||||
- WEBUI: Implement resizable progress bar in "Done" column (buinsky)
|
||||
- WEBUI: Fix scrollbar covers menu item with long text (buinsky)
|
||||
- WEBUI: Remove 300px limit of column width (buinsky)
|
||||
- WEBUI: Avoid lags in firefox on resizing progress column (buinsky)
|
||||
- WEBUI: Fix category in torrent upload. Closes #6260 (ngosang)
|
||||
- WEBUI: Turn off port forwarding of WebUI by default for GUI users (Chocobo1)
|
||||
- WEBUI: Exclude insecure ciphers. Fixes security issues reported by @beardog108 privately. (Chocobo1)
|
||||
- WEBUI: Avoid clickjacking attacks. Fixes security issues reported by @beardog108 privately. (ngosang)
|
||||
- WEBUI: Add X-XSS-Protection, X-Content-Type-Options, CSP header. Fixes security issues reported by @beardog108 privately. (Chocobo1)
|
||||
- WEBUI: Escape various values that might contain injected html. Fixes security issues reported by @beardog108 privately. (Chocobo1)
|
||||
- WEBUI: Bump API_VERSION to 12.
|
||||
- SEARCH: Update extratorrent plugin. Closes #6261 (ngosang)
|
||||
- SEARCH: SearchTab: can now save sorting column changes (thalieht)
|
||||
- SEARCH: Use case-insensitive sort for Name column in Search tab. Closes #407. (Chocobo1)
|
||||
- RSS: Fix tab order in RSS downloader. Closes #6164. (Tim Delaney)
|
||||
- RSS: Move old RSS items to separate config file. Closes #6167. (Tim Delaney)
|
||||
- RSS: Episode filter code refactoring (Tim Delaney)
|
||||
- RSS: Allow resetting rule to no category. Closes #5539. (Tim Delaney)
|
||||
- RSS: Save rule on enable/disable even if not selected. Closes #6163. (Tim Delaney)
|
||||
- RSS: Allow | in RSS must contain. Closes #6171. (Tim Delaney)
|
||||
- RSS: RSS use red text to indicate invalid filter. Closes #6165. (Tim Delaney)
|
||||
- RSS: Allow episode zero (special) and leading zeroes in RSS episode filter. (Tim Delaney)
|
||||
- RSS: RSS parse torrent episodes like 1x01 as well as S01E01. Closes #2749. (Tim Delaney)
|
||||
- RSS: RSS allow infinite range to extend beyond current season. Closes #800, #3876, #6170. (Tim Delaney)
|
||||
- RSS: Improve UI responsiveness during RSS downloading. Closes #873, #1089, #1235, #5423. (Tim Delaney)
|
||||
- RSS: Show name of feed list and sort rules in editor. Closes #3782, #6281. (Tim Delaney)
|
||||
- RSS: Fix regex matching. Closes #6337. (Tim Delaney)
|
||||
- MACOS: Fix qbittorrent-nox build (Oke Atime)
|
||||
- LINUX: fixes default indicator name (Bilal Elmoussaoui)
|
||||
- OTHER: Workaround problem with moc from Qt4 and #if (Eugene Shalygin)
|
||||
- OTHER: Print warning to the user if stacktrace contains no function names (Eugene Shalygin)
|
||||
- OTHER: Various cmake fixes (Eugene Shalygin)
|
||||
- OTHER: Fix finding qmake in configure when cross-compiling (Zach Bacon)
|
||||
|
||||
* Sat Dec 17 2016 - sledgehammer999 <sledgehammer999@qbittorrent.org> - v3.3.10
|
||||
- BUGFIX: Fix share ratio limiting. Broken by commit 259b5e51c49b744. Closes #6039 #6048. (sledgehammer999)
|
||||
- BUGFIX: Case insensitive sort for client column. Closes #6054. (Oke Atime)
|
||||
- BUGFIX: Make resume/pause menu items clickable. Closes #6040. (Oke Atime)
|
||||
- WINDOWS: Make the updater to look for the x64 installer if running x64 version. (sledgehammer999)
|
||||
|
||||
* Wed Dec 14 2016 - sledgehammer999 <sledgehammer999@qbittorrent.org> - v3.3.9
|
||||
- BUGFIX: Fix slider for per torrent speed limits when no global speed limit has been set. Closes #6046. (sledgehammer999)
|
||||
- BUGFIX: Fix GUI for proxy settings. Closes #6045. (sledgehammer999)
|
||||
- OSX: Correctly migrate settings/rss/usage stats in macOS. Closes #6041. (sledgehammer999)
|
||||
|
||||
* Wed Dec 14 2016 - sledgehammer999 <sledgehammer999@qbittorrent.org> - v3.3.8
|
||||
- FEATURE: Start using new libtorrent 1.1.x APIs (needs at least 1.1.2). Still unofficial support. (glassez, sledgehammer999)
|
||||
- FEATURE: Add a new DHT bootstrap node run by libtorrent author arvidn. (sledgehammer999)
|
||||
- FEATURE: Option to disable tracker's favicon download. (sledgehammer999)
|
||||
- FEATURE: Shift + scroll = horizontal scroll. Closes #5980. Only for TransferListWidget, PeerListWidget. (Chocobo1)
|
||||
- BUGFIX: Actually set new path as default when checkBox is enabled in Add New Torrent dialog. (erikssm)
|
||||
- BUGFIX: Properly fix the handling of default save path store/load. (sledgehammer999)
|
||||
- BUGFIX: Fix crash when restoring from tray. Closes #5854. (Chocobo1)
|
||||
- BUGFIX: Export torrents added only after the setting was enabled. (sledgehammer999)
|
||||
- BUGFIX: Delete old rss favicon before assigning new one. (sledgehammer999)
|
||||
- BUGFIX: Don't revert save path value in the Dialog when metadata are received. Closes #5482. (sledgehammer999)
|
||||
- BUGFIX: Don't ever stop seeding forced torrents. Closes #5784. (sledgehammer999)
|
||||
- BUGFIX: Fix potential crash in TransferList widget. Closes #5873. (Chocobo1)
|
||||
- BUGFIX: Sort torrent names case insensitively. (Yez Ezey)
|
||||
- BUGFIX: Fix mistake in getting values for sorting in TransferList widget. (Anton Lashkov)
|
||||
- BUGFIX: Fix memory leaks. (dzmat, Chocobo1)
|
||||
- WEBUI: Fix webui port overflow. (thalieht)
|
||||
- WEBUI: Changed meaning of the value of the 'dl_limit', 'up_limit', 'alt_dl_limit' and 'alt_up_limit' tokens. The value is expressed in bytes and not in KiB. (sledgehammer999)
|
||||
- WEBUI: Don't request client SSL certificate. Closes #3883. (borouhin)
|
||||
- WEBUI: Bump API_VERSION and API_VERSION_MIN to 11.
|
||||
- SEARCH: Fixed extratorrent search not working Closes #5736 #5753. (Yez Ezey)
|
||||
- SEARCH: Update Demonoid plugin. (ngosang)
|
||||
- SEARCH: Remove TorrentReactor plugin. (ngosang)
|
||||
- SEARCH: Fix python auto install, deletion of installer and use 3.5.x series for Vista+. Closes #5871. (sledgehammer999)
|
||||
- SEARCH: Set /usr/local/bin before default PATH on macOS. closes #5639 #5571. This enables finding newer python installs. (Yez Ezey)
|
||||
- COSMETIC: Log: set embedded Tracker [OFF] msg type as info. (thalieht)
|
||||
- COSMETIC: Remove (mostly) useless log warnings about tracker's favicon. (sledgehammer999)
|
||||
- COSMETIC: Change RSS view layout to horizontal. Closes #5920. (Chocobo1)
|
||||
- OSX: Fix crash on exit using Qt4. (Yez Ezey)
|
||||
- OSX: Change QSettings to IniFormat on macOS. Closes #5770 #5808. (Yez Ezey)
|
||||
- LINUX: Workaround a Qt5 bug which results in a flood of network interface change singals. (Eugene Shalygin)
|
||||
- OTHER: Turkish translation for installer. (Burak Yavuz)
|
||||
- OTHER: Update portugueseBR for installer. (DaRKSoM)
|
||||
- OTHER: Update portuguese for installer. (EdwardLinux)
|
||||
- OTHER: Add --disable-qt-dbus to configure if $host_os is macOS. (Yez Ezey)
|
||||
- OTHER: New translations: Icelandic, Latvian, Malay, Occitan, Uzbek.
|
||||
- OTHER: A whole lot of code refactoring by various people.
|
||||
|
||||
* Sun Sep 11 2016 - sledgehammer999 <sledgehammer999@qbittorrent.org> - v3.3.7
|
||||
- FEATURE: Delete torrent+files with Shift+Delete (pieniacy)
|
||||
- BUGFIX: Fix 6-hour speedplot point push rate. Close #5545 (Daniel Segesdi)
|
||||
|
||||
@@ -14,6 +14,11 @@
|
||||
find_package(Threads REQUIRED)
|
||||
find_package(PkgConfig QUIET)
|
||||
|
||||
macro(_detect_boost_components _outComponets librariesList)
|
||||
string(REGEX MATCHALL "boost_[a-z_]+[-a-z]*" _boost_libraries "${librariesList}")
|
||||
string(REGEX REPLACE "boost_([a-z_]+)[-a-z]*" "\\1" ${_outComponets} "${_boost_libraries}")
|
||||
endmacro()
|
||||
|
||||
if(PKG_CONFIG_FOUND)
|
||||
pkg_check_modules(PC_LIBTORRENT_RASTERBAR QUIET libtorrent-rasterbar)
|
||||
endif()
|
||||
@@ -62,13 +67,33 @@ endif()
|
||||
set(LibtorrentRasterbar_LIBRARIES ${LibtorrentRasterbar_LIBRARY} ${CMAKE_THREAD_LIBS_INIT})
|
||||
set(LibtorrentRasterbar_INCLUDE_DIRS ${LibtorrentRasterbar_INCLUDE_DIR})
|
||||
|
||||
if(NOT Boost_SYSTEM_FOUND OR NOT Boost_CHRONO_FOUND OR NOT Boost_RANDOM_FOUND)
|
||||
find_package(Boost REQUIRED COMPONENTS date_time system chrono random thread)
|
||||
set(LibtorrentRasterbar_LIBRARIES
|
||||
${LibtorrentRasterbar_LIBRARIES} ${Boost_LIBRARIES} ${CMAKE_THREAD_LIBS_INIT})
|
||||
set(LibtorrentRasterbar_INCLUDE_DIRS
|
||||
${LibtorrentRasterbar_INCLUDE_DIRS} ${Boost_INCLUDE_DIRS})
|
||||
endif()
|
||||
# Without pkg-config, we can't possibly figure out the correct boost dependencies
|
||||
if (LibtorrentRasterbar_CUSTOM_BOOST_DEPENDENCIES)
|
||||
set(_boost_components "${LibtorrentRasterbar_CUSTOM_BOOST_DEPENDENCIES}")
|
||||
else(LibtorrentRasterbar_CUSTOM_BOOST_DEPENDENCIES)
|
||||
if(PC_LIBTORRENT_RASTERBAR_FOUND)
|
||||
_detect_boost_components(_boost_components "${PC_LIBTORRENT_RASTERBAR_LIBRARIES}")
|
||||
else()
|
||||
# all possible boost dependencies
|
||||
set(_boost_components
|
||||
date_time
|
||||
system
|
||||
chrono
|
||||
random
|
||||
thread
|
||||
)
|
||||
endif()
|
||||
endif(LibtorrentRasterbar_CUSTOM_BOOST_DEPENDENCIES)
|
||||
|
||||
list(SORT _boost_components)
|
||||
message(STATUS "Libtorrent Boost dependencies: ${_boost_components}")
|
||||
find_package(Boost REQUIRED COMPONENTS ${_boost_components})
|
||||
set(LibtorrentRasterbar_LIBRARIES ${LibtorrentRasterbar_LIBRARIES} ${CMAKE_THREAD_LIBS_INIT})
|
||||
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})
|
||||
|
||||
list(FIND LibtorrentRasterbar_DEFINITIONS -DTORRENT_USE_OPENSSL LibtorrentRasterbar_ENCRYPTION_INDEX)
|
||||
if(LibtorrentRasterbar_ENCRYPTION_INDEX GREATER -1)
|
||||
@@ -83,10 +108,7 @@ include(FindPackageHandleStandardArgs)
|
||||
# if all listed variables are TRUE
|
||||
find_package_handle_standard_args(LibtorrentRasterbar DEFAULT_MSG
|
||||
LibtorrentRasterbar_LIBRARY
|
||||
LibtorrentRasterbar_INCLUDE_DIR
|
||||
Boost_SYSTEM_FOUND
|
||||
Boost_CHRONO_FOUND
|
||||
Boost_RANDOM_FOUND)
|
||||
LibtorrentRasterbar_INCLUDE_DIR)
|
||||
|
||||
mark_as_advanced(LibtorrentRasterbar_INCLUDE_DIR LibtorrentRasterbar_LIBRARY
|
||||
LibtorrentRasterbar_ORIG_CMAKE_FIND_LIBRARY_SUFFIXES
|
||||
|
||||
28
cmake/Modules/FunctionReadVersion.cmake
Normal file
@@ -0,0 +1,28 @@
|
||||
# function for parsing version variables that are set in version.pri file
|
||||
# the version identifiers there are defined as follows:
|
||||
# VER_MAJOR = 3
|
||||
# VER_MINOR = 4
|
||||
# VER_BUGFIX = 0
|
||||
# VER_BUILD = 0
|
||||
# VER_STATUS = alpha
|
||||
|
||||
function(read_version priFile outMajor outMinor outBugfix outBuild outStatus)
|
||||
file(STRINGS ${priFile} _priFileContents REGEX "^VER_.+")
|
||||
# message(STATUS "version.pri version contents: ${_priFileContents}")
|
||||
# the _priFileContents variable contains something like the following:
|
||||
# VER_MAJOR = 3;VER_MINOR = 4;VER_BUGFIX = 0;VER_BUILD = 0;VER_STATUS = alpha # Should be empty for stable releases!
|
||||
set(_regex "VER_MAJOR += +([0-9]+);VER_MINOR += +([0-9]+);VER_BUGFIX += +([0-9]+);VER_BUILD += +([0-9]+);VER_STATUS += +([0-9A-Za-z]+)?")
|
||||
# note quotes around _regex, they are needed because the variable contains semicolons
|
||||
string(REGEX MATCH "${_regex}" _tmp "${_priFileContents}")
|
||||
if (NOT _tmp)
|
||||
message(FATAL_ERROR "Could not detect project version number from ${priFile}")
|
||||
endif()
|
||||
|
||||
# message(STATUS "Matched version string: ${_tmp}")
|
||||
|
||||
set(${outMajor} ${CMAKE_MATCH_1} PARENT_SCOPE)
|
||||
set(${outMinor} ${CMAKE_MATCH_2} PARENT_SCOPE)
|
||||
set(${outBugfix} ${CMAKE_MATCH_3} PARENT_SCOPE)
|
||||
set(${outBuild} ${CMAKE_MATCH_4} PARENT_SCOPE)
|
||||
set(${outStatus} ${CMAKE_MATCH_5} PARENT_SCOPE)
|
||||
endfunction()
|
||||
@@ -5,11 +5,23 @@
|
||||
macro (target_link_qt_components target)
|
||||
if (QT4_FOUND)
|
||||
foreach(_cmp ${ARGN})
|
||||
list(APPEND _QT_CMPNTS "Qt4::Qt${_cmp}")
|
||||
if ("${_cmp}" STREQUAL "PRIVATE" OR
|
||||
"${_cmp}" STREQUAL "PUBLIC" OR
|
||||
"${_cmp}" STREQUAL "INTERFACE")
|
||||
list(APPEND _QT_CMPNTS "${_cmp}")
|
||||
else()
|
||||
list(APPEND _QT_CMPNTS "Qt4::Qt${_cmp}")
|
||||
endif()
|
||||
endforeach()
|
||||
else (QT4_FOUND)
|
||||
foreach(_cmp ${ARGN})
|
||||
list(APPEND _QT_CMPNTS "Qt5::${_cmp}")
|
||||
if ("${_cmp}" STREQUAL "PRIVATE" OR
|
||||
"${_cmp}" STREQUAL "PUBLIC" OR
|
||||
"${_cmp}" STREQUAL "INTERFACE")
|
||||
list(APPEND _QT_CMPNTS "${_cmp}")
|
||||
else()
|
||||
list(APPEND _QT_CMPNTS "Qt5::${_cmp}")
|
||||
endif()
|
||||
endforeach()
|
||||
endif (QT4_FOUND)
|
||||
target_link_libraries(${target} ${_QT_CMPNTS})
|
||||
|
||||
@@ -9,7 +9,10 @@ set(LibtorrentRasterbar_CUSTOM_DEFINITIONS
|
||||
-DBOOST_EXCEPTION_DISABLE
|
||||
-DBOOST_SYSTEM_STATIC_LINK=1
|
||||
-DTORRENT_USE_OPENSSL
|
||||
-DUNICODE
|
||||
-D__USE_W32_SOCKETS
|
||||
-D_FILE_OFFSET_BITS=64)
|
||||
|
||||
add_definitions(-DUNICODE
|
||||
-D_UNICODE
|
||||
-DWIN32
|
||||
-D_WIN32
|
||||
@@ -18,9 +21,7 @@ set(LibtorrentRasterbar_CUSTOM_DEFINITIONS
|
||||
-D_WIN32_IE=0x0500
|
||||
-D_CRT_SECURE_NO_DEPRECATE
|
||||
-D_SCL_SECURE_NO_DEPRECATE
|
||||
-D__USE_W32_SOCKETS
|
||||
-D_FILE_OFFSET_BITS=64)
|
||||
|
||||
)
|
||||
# and boost
|
||||
set(Boost_USE_STATIC_LIBS True)
|
||||
# set(Boost_USE_STATIC_RUNTIME True)
|
||||
@@ -29,16 +30,17 @@ set(Boost_USE_STATIC_LIBS True)
|
||||
# with usual unix subdirectories (bin, lib, include)
|
||||
# if so, we just need to set CMAKE_SYSTEM_PREFIX_PATH
|
||||
# If it is not the case, individual paths need to be specified manually (see below)
|
||||
set(COMMON_INSTALL_PREFIX "c:/usr")
|
||||
set(COMMON_INSTALL_PREFIX "c:/usr" CACHE PATH "Prefix used to install all the required libraries")
|
||||
list(APPEND CMAKE_SYSTEM_PREFIX_PATH "${COMMON_INSTALL_PREFIX}")
|
||||
|
||||
# If two version of Qt are installed, separate prefixes are needed most likely
|
||||
set(QT4_INSTALL_PREFIX "${COMMON_INSTALL_PREFIX}/lib/qt4")
|
||||
set(QT5_INSTALL_PREFIX "${COMMON_INSTALL_PREFIX}/lib/qt5")
|
||||
set(QT4_INSTALL_PREFIX "${COMMON_INSTALL_PREFIX}/lib/qt4" CACHE PATH "Prefix where Qt4 is installed")
|
||||
set(QT5_INSTALL_PREFIX "${COMMON_INSTALL_PREFIX}/lib/qt5" CACHE PATH "Prefix where Qt5 is installed")
|
||||
|
||||
# it is safe to set Qt dirs even if their files are directly in the prefix
|
||||
# Qt4
|
||||
if(NOT QT5)
|
||||
# for qt 4 we need qmake, Qt5 provides cmake config files
|
||||
LIST(APPEND CMAKE_PROGRAM_PATH "${QT4_INSTALL_PREFIX}/bin/")
|
||||
endif(NOT QT5)
|
||||
|
||||
|
||||
@@ -9,6 +9,8 @@ QMAKE_CXXFLAGS += @QBT_CONF_EXTRA_CFLAGS@
|
||||
|
||||
EXTERNAL_INCLUDES = @QBT_CONF_INCLUDES@
|
||||
EXTERNAL_INCLUDES -= $$QMAKE_DEFAULT_INCDIRS
|
||||
# added /usr/local/include due to Qt 5.7.0 bug on macOS
|
||||
macx: EXTERNAL_INCLUDES += "/usr/local/include"
|
||||
INCLUDEPATH += $$EXTERNAL_INCLUDES
|
||||
|
||||
EXTERNAL_LIBS = @LDFLAGS@ @LIBS@
|
||||
|
||||
98
configure
vendored
@@ -4257,6 +4257,17 @@ else
|
||||
$as_echo "no" >&6; }
|
||||
fi
|
||||
|
||||
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether OS is macOS" >&5
|
||||
$as_echo_n "checking whether OS is macOS... " >&6; }
|
||||
if expr "$host_os" : ".*darwin.*" > /dev/null; then :
|
||||
{ $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
|
||||
$as_echo "yes" >&6; }
|
||||
enable_qt_dbus=no
|
||||
else
|
||||
{ $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
|
||||
$as_echo "no" >&6; }
|
||||
fi
|
||||
|
||||
# Require 0.23 pkg-config
|
||||
|
||||
|
||||
@@ -4493,53 +4504,17 @@ fi
|
||||
|
||||
fi
|
||||
|
||||
as_ac_File=`$as_echo "ac_cv_file_$QT_QMAKE/qmake" | $as_tr_sh`
|
||||
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $QT_QMAKE/qmake" >&5
|
||||
$as_echo_n "checking for $QT_QMAKE/qmake... " >&6; }
|
||||
if eval \${$as_ac_File+:} false; then :
|
||||
$as_echo_n "(cached) " >&6
|
||||
else
|
||||
test "$cross_compiling" = yes &&
|
||||
as_fn_error $? "cannot check for file existence when cross compiling" "$LINENO" 5
|
||||
if test -r "$QT_QMAKE/qmake"; then
|
||||
eval "$as_ac_File=yes"
|
||||
else
|
||||
eval "$as_ac_File=no"
|
||||
fi
|
||||
fi
|
||||
eval ac_res=\$$as_ac_File
|
||||
{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5
|
||||
$as_echo "$ac_res" >&6; }
|
||||
if eval test \"x\$"$as_ac_File"\" = x"yes"; then :
|
||||
if test -f "$QT_QMAKE/qmake"; then :
|
||||
QT_QMAKE="$QT_QMAKE/qmake"
|
||||
else
|
||||
as_ac_File=`$as_echo "ac_cv_file_$QT_QMAKE/qmake-qt5" | $as_tr_sh`
|
||||
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $QT_QMAKE/qmake-qt5" >&5
|
||||
$as_echo_n "checking for $QT_QMAKE/qmake-qt5... " >&6; }
|
||||
if eval \${$as_ac_File+:} false; then :
|
||||
$as_echo_n "(cached) " >&6
|
||||
else
|
||||
test "$cross_compiling" = yes &&
|
||||
as_fn_error $? "cannot check for file existence when cross compiling" "$LINENO" 5
|
||||
if test -r "$QT_QMAKE/qmake-qt5"; then
|
||||
eval "$as_ac_File=yes"
|
||||
else
|
||||
eval "$as_ac_File=no"
|
||||
fi
|
||||
fi
|
||||
eval ac_res=\$$as_ac_File
|
||||
{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5
|
||||
$as_echo "$ac_res" >&6; }
|
||||
if eval test \"x\$"$as_ac_File"\" = x"yes"; then :
|
||||
if test -f "$QT_QMAKE/qmake-qt5"; then :
|
||||
QT_QMAKE="$QT_QMAKE/qmake-qt5"
|
||||
else
|
||||
QT_QMAKE=""
|
||||
fi
|
||||
|
||||
|
||||
fi
|
||||
|
||||
|
||||
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for Qt5 qmake >= 5.2.0" >&5
|
||||
$as_echo_n "checking for Qt5 qmake >= 5.2.0... " >&6; }
|
||||
if test "x$QT_QMAKE" != "x"; then :
|
||||
@@ -4610,53 +4585,17 @@ fi
|
||||
|
||||
fi
|
||||
|
||||
as_ac_File=`$as_echo "ac_cv_file_$QT_QMAKE/qmake" | $as_tr_sh`
|
||||
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $QT_QMAKE/qmake" >&5
|
||||
$as_echo_n "checking for $QT_QMAKE/qmake... " >&6; }
|
||||
if eval \${$as_ac_File+:} false; then :
|
||||
$as_echo_n "(cached) " >&6
|
||||
else
|
||||
test "$cross_compiling" = yes &&
|
||||
as_fn_error $? "cannot check for file existence when cross compiling" "$LINENO" 5
|
||||
if test -r "$QT_QMAKE/qmake"; then
|
||||
eval "$as_ac_File=yes"
|
||||
else
|
||||
eval "$as_ac_File=no"
|
||||
fi
|
||||
fi
|
||||
eval ac_res=\$$as_ac_File
|
||||
{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5
|
||||
$as_echo "$ac_res" >&6; }
|
||||
if eval test \"x\$"$as_ac_File"\" = x"yes"; then :
|
||||
if test -f "$QT_QMAKE/qmake"; then :
|
||||
QT_QMAKE="$QT_QMAKE/qmake"
|
||||
else
|
||||
as_ac_File=`$as_echo "ac_cv_file_$QT_QMAKE/qmake-qt4" | $as_tr_sh`
|
||||
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $QT_QMAKE/qmake-qt4" >&5
|
||||
$as_echo_n "checking for $QT_QMAKE/qmake-qt4... " >&6; }
|
||||
if eval \${$as_ac_File+:} false; then :
|
||||
$as_echo_n "(cached) " >&6
|
||||
else
|
||||
test "$cross_compiling" = yes &&
|
||||
as_fn_error $? "cannot check for file existence when cross compiling" "$LINENO" 5
|
||||
if test -r "$QT_QMAKE/qmake-qt4"; then
|
||||
eval "$as_ac_File=yes"
|
||||
else
|
||||
eval "$as_ac_File=no"
|
||||
fi
|
||||
fi
|
||||
eval ac_res=\$$as_ac_File
|
||||
{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5
|
||||
$as_echo "$ac_res" >&6; }
|
||||
if eval test \"x\$"$as_ac_File"\" = x"yes"; then :
|
||||
if test -f "$QT_QMAKE/qmake-qt4"; then :
|
||||
QT_QMAKE="$QT_QMAKE/qmake-qt4"
|
||||
else
|
||||
QT_QMAKE=""
|
||||
fi
|
||||
|
||||
|
||||
fi
|
||||
|
||||
|
||||
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for Qt4 qmake >= 4.8.0" >&5
|
||||
$as_echo_n "checking for Qt4 qmake >= 4.8.0... " >&6; }
|
||||
if test "x$QT_QMAKE" != "x"; then :
|
||||
@@ -5033,8 +4972,8 @@ fi
|
||||
if test "x$BOOST_CPPFLAGS" = "x"; then :
|
||||
as_fn_error $? "Could not find Boost" "$LINENO" 5
|
||||
else
|
||||
{ $as_echo "$as_me:${as_lineno-$LINENO}: Boost CPPFLGAS: $BOOST_CPPFLAGS" >&5
|
||||
$as_echo "$as_me: Boost CPPFLGAS: $BOOST_CPPFLAGS" >&6;}
|
||||
{ $as_echo "$as_me:${as_lineno-$LINENO}: Boost CPPFLAGS: $BOOST_CPPFLAGS" >&5
|
||||
$as_echo "$as_me: Boost CPPFLAGS: $BOOST_CPPFLAGS" >&6;}
|
||||
CPPFLAGS="$BOOST_CPPFLAGS $CPPFLAGS"
|
||||
LDFLAGS="$BOOST_LDFLAGS $LDFLAGS"
|
||||
fi
|
||||
@@ -5083,6 +5022,7 @@ ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ex
|
||||
ac_compiler_gnu=$ac_cv_cxx_compiler_gnu
|
||||
|
||||
CXXFLAGS_SAVE=$CXXFLAGS
|
||||
CXXFLAGS=
|
||||
|
||||
cat confdefs.h - <<_ACEOF >conftest.$ac_ext
|
||||
/* end confdefs.h. */
|
||||
@@ -5090,7 +5030,7 @@ ac_compiler_gnu=$ac_cv_cxx_compiler_gnu
|
||||
int
|
||||
main ()
|
||||
{
|
||||
boost::system::system_category
|
||||
boost::system::error_category *a = 0;
|
||||
;
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -67,6 +67,12 @@ AS_IF([expr "$host_os" : ".*freebsd.*" > /dev/null],
|
||||
LIBS="-lexecinfo $LIBS"],
|
||||
[AC_MSG_RESULT([no])])
|
||||
|
||||
AC_MSG_CHECKING([whether OS is macOS])
|
||||
AS_IF([expr "$host_os" : ".*darwin.*" > /dev/null],
|
||||
[AC_MSG_RESULT([yes])
|
||||
enable_qt_dbus=no],
|
||||
[AC_MSG_RESULT([no])])
|
||||
|
||||
# Require 0.23 pkg-config
|
||||
PKG_PROG_PKG_CONFIG([0.23])
|
||||
AS_IF([test "x$PKG_CONFIG" = "x"],
|
||||
@@ -156,7 +162,7 @@ AX_BOOST_BASE([1.35])
|
||||
# how to test for a set vs unset variable.
|
||||
AS_IF([test "x$BOOST_CPPFLAGS" = "x"],
|
||||
[AC_MSG_ERROR([Could not find Boost])],
|
||||
[AC_MSG_NOTICE([Boost CPPFLGAS: $BOOST_CPPFLAGS])
|
||||
[AC_MSG_NOTICE([Boost CPPFLAGS: $BOOST_CPPFLAGS])
|
||||
CPPFLAGS="$BOOST_CPPFLAGS $CPPFLAGS"
|
||||
LDFLAGS="$BOOST_LDFLAGS $LDFLAGS"])
|
||||
|
||||
|
||||
8
dist/mac/Info.plist
vendored
@@ -37,7 +37,7 @@
|
||||
</dict>
|
||||
</array>
|
||||
<key>CFBundleName</key>
|
||||
<string>qBittorrent</string>
|
||||
<string>@EXECUTABLE@</string>
|
||||
<key>CFBundleIconFile</key>
|
||||
<string>qbittorrent_mac.icns</string>
|
||||
<key>CFBundleInfoDictionaryVersion</key>
|
||||
@@ -45,11 +45,11 @@
|
||||
<key>CFBundlePackageType</key>
|
||||
<string>APPL</string>
|
||||
<key>CFBundleShortVersionString</key>
|
||||
<string>3.3.7</string>
|
||||
<string>3.3.11</string>
|
||||
<key>CFBundleSignature</key>
|
||||
<string>qBit</string>
|
||||
<key>CFBundleExecutable</key>
|
||||
<string>qbittorrent</string>
|
||||
<string>@EXECUTABLE@</string>
|
||||
<key>CFBundleIdentifier</key>
|
||||
<string>org.qbittorrent</string>
|
||||
<key>NSPrincipalClass</key>
|
||||
@@ -59,7 +59,7 @@
|
||||
<key>NSAppleScriptEnabled</key>
|
||||
<string>YES</string>
|
||||
<key>NSHumanReadableCopyright</key>
|
||||
<string>Copyright © 2006-2016 The qBittorrent project</string>
|
||||
<string>Copyright © 2006-2017 The qBittorrent project</string>
|
||||
<key>UTExportedTypeDeclarations</key>
|
||||
<array>
|
||||
<dict>
|
||||
|
||||
BIN
dist/unix/menuicons/128x128/status/qbittorrent-tray.png
vendored
Normal file
|
After Width: | Height: | Size: 21 KiB |
BIN
dist/unix/menuicons/16x16/status/qbittorrent-tray.png
vendored
Normal file
|
After Width: | Height: | Size: 893 B |
BIN
dist/unix/menuicons/192x192/status/qbittorrent-tray.png
vendored
Normal file
|
After Width: | Height: | Size: 36 KiB |
BIN
dist/unix/menuicons/22x22/status/qbittorrent-tray.png
vendored
Normal file
|
After Width: | Height: | Size: 1.4 KiB |
BIN
dist/unix/menuicons/24x24/status/qbittorrent-tray.png
vendored
Normal file
|
After Width: | Height: | Size: 1.6 KiB |
BIN
dist/unix/menuicons/32x32/status/qbittorrent-tray.png
vendored
Normal file
|
After Width: | Height: | Size: 2.4 KiB |
BIN
dist/unix/menuicons/36x36/status/qbittorrent-tray.png
vendored
Normal file
|
After Width: | Height: | Size: 2.9 KiB |
BIN
dist/unix/menuicons/48x48/status/qbittorrent-tray.png
vendored
Normal file
|
After Width: | Height: | Size: 4.5 KiB |
BIN
dist/unix/menuicons/64x64/status/qbittorrent-tray.png
vendored
Normal file
|
After Width: | Height: | Size: 7.3 KiB |
BIN
dist/unix/menuicons/72x72/status/qbittorrent-tray.png
vendored
Normal file
|
After Width: | Height: | Size: 8.9 KiB |
BIN
dist/unix/menuicons/96x96/status/qbittorrent-tray.png
vendored
Normal file
|
After Width: | Height: | Size: 14 KiB |
29
dist/windows/README.txt
vendored
@@ -1,12 +1,12 @@
|
||||
TRANSLATORS:
|
||||
|
||||
1. Use an editor that has NSIS syntax highlighting(eg Notepad++/Geany). This will
|
||||
1. Use an editor that has NSIS syntax highlighting(eg Notepad++/Geany). This will
|
||||
make your life easier.
|
||||
2. Open the relevant .nsi file that exists in the folder named
|
||||
2. Open the relevant .nsi file that exists in the folder named
|
||||
"installer-translations"
|
||||
3. Lines starting with ";" are considered comments. These include the
|
||||
3. Lines starting with ";" are considered comments. These include the
|
||||
english message to help you with the translation.
|
||||
4. Edit only the part inside the quotation marks(""). Unless you know
|
||||
4. Edit only the part inside the quotation marks(""). Unless you know
|
||||
what you are doing.
|
||||
5. Save the files with utf8 encoding and BOM.
|
||||
6. Submit your changes: 1) as a pull request to the official git repo or
|
||||
@@ -16,17 +16,13 @@ TRANSLATORS:
|
||||
PACKAGERS:
|
||||
|
||||
You will need NSIS and upx to make the installer. You need a unicode version of NSIS.
|
||||
I tested with NSIS 3.0a0.
|
||||
I tested with NSIS 3.0 (final).
|
||||
|
||||
1. Open the options.nsi file in an editor and change line that contains
|
||||
"!define PROG_VERSION "3.0.3"" to the version of qbittorrent you just built.
|
||||
2. Extract the plugins found in the folder "nsis plugins" into your
|
||||
"!define PROG_VERSION "3.0.3"" to the version of qbittorrent you just built.
|
||||
2. Extract the plugins found in the folder "nsis plugins" into your
|
||||
NSIS's unicode Plugin directory(usually C:\Program Files\NSIS\Plugins\x86-unicode).
|
||||
Only the *.dll files are needed. Don't use the .dll from UAC.zip, use the one from "UAC Unicode.zip".
|
||||
NOTE: To build the unicode version of UAC with MSVC2008 you need:
|
||||
a) the sources from UAC.zip
|
||||
b) apply the util.cpp.diff from "UAC Unicode.zip" to util.cpp
|
||||
c) in a msvc command prompt issue: cl.exe /O1s /GS- /GR- /EHs-c- /Zl /LD /DUNICODE RunAs.cpp uac.cpp util.cpp /link kernel32.lib user32.lib shell32.lib advapi32.lib ole32.lib /DLL /MANIFEST:NO /OUT:uac.dll
|
||||
Only the *.dll files are needed. Use the unicode version of the dlls.
|
||||
3. The script you need to compile is "qbittorrent.nsi". It includes all other necessary scripts.
|
||||
4. The script expects the following file tree:
|
||||
|
||||
@@ -53,10 +49,11 @@ qbittorrent.exe
|
||||
qbittorrent.nsi
|
||||
qt.conf
|
||||
translations.nsi
|
||||
UAC.nsh
|
||||
uninstaller.nsi
|
||||
|
||||
|
||||
5. "license.txt" is a text file that contains the text rendered
|
||||
5. "license.txt" is a text file that contains the text rendered
|
||||
from src\gui\gpl.html or the text contained in COPYING
|
||||
6. "qbittorrent.exe" is the compiled binary file.
|
||||
|
||||
@@ -64,7 +61,7 @@ SCRIPT HACKERS:
|
||||
|
||||
If you add any new LangString variable to the scripts you NEED to provide
|
||||
"translations" of it to all the .nsi files inside "installer-translations.
|
||||
You can always leave the english string but you have to use all the LANG_<lang name>
|
||||
for the given variable. Otherwise, if the user chooses a language that you
|
||||
haven't provided a LANG_<lang name> for your variable then your string will be empty.
|
||||
You can always leave the english string but you have to use all the LANG_<lang name>
|
||||
for the given variable. Otherwise, if the user chooses a language that you
|
||||
haven't provided a LANG_<lang name> for your variable then your string will be empty.
|
||||
Don't worry though, NSIS throws warnings for this when compiling the scripts.
|
||||
|
||||
2
dist/windows/UAC.nsh
vendored
@@ -228,6 +228,8 @@ pop $_LOGICLIB_TEMP
|
||||
!undef _UAC_ParseDefineFlags_orin_this
|
||||
!ifdef _UAC_ParseDefineFlags_orin_f1
|
||||
!undef _UAC_ParseDefineFlags_orin_f1
|
||||
!endif
|
||||
!ifdef _UAC_ParseDefineFlags_orin_f2
|
||||
!undef _UAC_ParseDefineFlags_orin_f2
|
||||
!endif
|
||||
!macroend
|
||||
|
||||
@@ -17,7 +17,7 @@ LangString inst_firewallinfo ${LANG_PORTUGUESE} "Adicionando regra à firewall d
|
||||
;LangString inst_warning ${LANG_ENGLISH} "qBittorrent is running. Please close the application before installing."
|
||||
LangString inst_warning ${LANG_PORTUGUESE} "O qBittorrent está a ser executado. Feche a aplicação antes de instalar esta versão."
|
||||
;LangString inst_uninstall_question ${LANG_ENGLISH} "A previous installation was detected. It will be uninstalled without deleting user settings."
|
||||
LangString inst_uninstall_question ${LANG_PORTUGUESE} "A previous installation was detected. It will be uninstalled without deleting user settings."
|
||||
LangString inst_uninstall_question ${LANG_PORTUGUESE} "Uma antiga instalação foi encontrada.Essa mesma será desinstalada sem apagar as definições do usuário."
|
||||
;LangString inst_unist ${LANG_ENGLISH} "Uninstalling previous version."
|
||||
LangString inst_unist ${LANG_PORTUGUESE} "A desinstalar versão anterior."
|
||||
;LangString launch_qbt ${LANG_ENGLISH} "Launch qBittorrent."
|
||||
|
||||
@@ -17,7 +17,7 @@ LangString inst_firewallinfo ${LANG_PORTUGUESEBR} "Adicionando regra no firewall
|
||||
;LangString inst_warning ${LANG_ENGLISH} "qBittorrent is running. Please close the application before installing."
|
||||
LangString inst_warning ${LANG_PORTUGUESEBR} "qBittorrent está rodando. Por favor feche a aplicação antes de instalar."
|
||||
;LangString inst_uninstall_question ${LANG_ENGLISH} "A previous installation was detected. It will be uninstalled without deleting user settings."
|
||||
LangString inst_uninstall_question ${LANG_PORTUGUESEBR} "A previous installation was detected. It will be uninstalled without deleting user settings."
|
||||
LangString inst_uninstall_question ${LANG_PORTUGUESEBR} "Uma instalação anterior foi detectada. Ela será desistalada sem deletar as configurações de usuário."
|
||||
;LangString inst_unist ${LANG_ENGLISH} "Uninstalling previous version."
|
||||
LangString inst_unist ${LANG_PORTUGUESEBR} "Desinstalando versão anterior."
|
||||
;LangString launch_qbt ${LANG_ENGLISH} "Launch qBittorrent."
|
||||
|
||||
44
dist/windows/installer-translations/turkish.nsi
vendored
@@ -1,51 +1,51 @@
|
||||
;Installer strings
|
||||
|
||||
;LangString inst_qbt_req ${LANG_ENGLISH} "qBittorrent (required)"
|
||||
LangString inst_qbt_req ${LANG_TURKISH} "qBittorrent (required)"
|
||||
LangString inst_qbt_req ${LANG_TURKISH} "qBittorrent (zorunlu)"
|
||||
;LangString inst_dekstop ${LANG_ENGLISH} "Create Desktop Shortcut"
|
||||
LangString inst_dekstop ${LANG_TURKISH} "Create Desktop Shortcut"
|
||||
LangString inst_dekstop ${LANG_TURKISH} "Masaüstü Kısayolu oluştur"
|
||||
;LangString inst_startmenu ${LANG_ENGLISH} "Create Start Menu Shortcut"
|
||||
LangString inst_startmenu ${LANG_TURKISH} "Create Start Menu Shortcut"
|
||||
LangString inst_startmenu ${LANG_TURKISH} "Başlangıç Menüsü Kısayolu oluştur"
|
||||
;LangString inst_torrent ${LANG_ENGLISH} "Open .torrent files with qBittorrent"
|
||||
LangString inst_torrent ${LANG_TURKISH} "Open .torrent files with qBittorrent"
|
||||
LangString inst_torrent ${LANG_TURKISH} ".torrent dosyalarını qBittorrent ile aç"
|
||||
;LangString inst_magnet ${LANG_ENGLISH} "Open magnet links with qBittorrent"
|
||||
LangString inst_magnet ${LANG_TURKISH} "Open magnet links with qBittorrent"
|
||||
LangString inst_magnet ${LANG_TURKISH} "Magnet bağlantılarını qBittorrent ile aç"
|
||||
;LangString inst_firewall ${LANG_ENGLISH} "Add Windows Firewall rule"
|
||||
LangString inst_firewall ${LANG_TURKISH} "Add Windows Firewall rule"
|
||||
LangString inst_firewall ${LANG_TURKISH} "Windows Güvenlik Duvarı kuralı ekle"
|
||||
;LangString inst_firewallinfo ${LANG_ENGLISH} "Adding Windows Firewall rule"
|
||||
LangString inst_firewallinfo ${LANG_TURKISH} "Adding Windows Firewall rule"
|
||||
LangString inst_firewallinfo ${LANG_TURKISH} "Windows Güvenlik Duvarı kuralı ekleniyor"
|
||||
;LangString inst_warning ${LANG_ENGLISH} "qBittorrent is running. Please close the application before installing."
|
||||
LangString inst_warning ${LANG_TURKISH} "qBittorrent is running. Please close the application before installing."
|
||||
LangString inst_warning ${LANG_TURKISH} "qBittorrent çalışıyor. Lütfen yüklemeden önce uygulamayı kapatın."
|
||||
;LangString inst_uninstall_question ${LANG_ENGLISH} "A previous installation was detected. It will be uninstalled without deleting user settings."
|
||||
LangString inst_uninstall_question ${LANG_TURKISH} "A previous installation was detected. It will be uninstalled without deleting user settings."
|
||||
LangString inst_uninstall_question ${LANG_TURKISH} "Önceki bir kurulum algılandı. Kullanıcı ayarları silinmeden kaldırılacaktır."
|
||||
;LangString inst_unist ${LANG_ENGLISH} "Uninstalling previous version."
|
||||
LangString inst_unist ${LANG_TURKISH} "Uninstalling previous version."
|
||||
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} "Launch qBittorrent."
|
||||
LangString launch_qbt ${LANG_TURKISH} "qBittorrent'i çalıştır."
|
||||
|
||||
|
||||
;------------------------------------
|
||||
;Uninstaller strings
|
||||
|
||||
;LangString remove_files ${LANG_ENGLISH} "Remove files"
|
||||
LangString remove_files ${LANG_TURKISH} "Remove files"
|
||||
LangString remove_files ${LANG_TURKISH} "Dosyaları kaldır"
|
||||
;LangString remove_shortcuts ${LANG_ENGLISH} "Remove shortcuts"
|
||||
LangString remove_shortcuts ${LANG_TURKISH} "Remove shortcuts"
|
||||
LangString remove_shortcuts ${LANG_TURKISH} "Kısayolları kaldır"
|
||||
;LangString remove_associations ${LANG_ENGLISH} "Remove file associations"
|
||||
LangString remove_associations ${LANG_TURKISH} "Remove file associations"
|
||||
LangString remove_associations ${LANG_TURKISH} "Dosya ilişkilendirmelerini kaldır"
|
||||
;LangString remove_registry ${LANG_ENGLISH} "Remove registry keys"
|
||||
LangString remove_registry ${LANG_TURKISH} "Remove registry keys"
|
||||
LangString remove_registry ${LANG_TURKISH} "Kayıt defteri anahtarlarını kaldır"
|
||||
;LangString remove_conf ${LANG_ENGLISH} "Remove configuration files"
|
||||
LangString remove_conf ${LANG_TURKISH} "Remove configuration files"
|
||||
LangString remove_conf ${LANG_TURKISH} "Yapılandırma dosyalarını kaldır"
|
||||
;LangString remove_firewall ${LANG_ENGLISH} "Remove Windows Firewall rule"
|
||||
LangString remove_firewall ${LANG_TURKISH} "Remove Windows Firewall rule"
|
||||
LangString remove_firewall ${LANG_TURKISH} "Windows Güvenlik Duvarı kuralını kaldır"
|
||||
;LangString remove_firewallinfo ${LANG_ENGLISH} "Removing Windows Firewall rule"
|
||||
LangString remove_firewallinfo ${LANG_TURKISH} "Removing Windows Firewall rule"
|
||||
LangString remove_firewallinfo ${LANG_TURKISH} "Windows Güvenlik Duvarı kuralı kaldırılıyor"
|
||||
;LangString remove_cache ${LANG_ENGLISH} "Remove torrents and cached data"
|
||||
LangString remove_cache ${LANG_TURKISH} "Remove torrents and cached data"
|
||||
LangString remove_cache ${LANG_TURKISH} "Torrentleri ve önbelleklenen verileri kaldır"
|
||||
;LangString uninst_warning ${LANG_ENGLISH} "qBittorrent is running. Please close the application before uninstalling."
|
||||
LangString uninst_warning ${LANG_TURKISH} "qBittorrent is running. Please close the application before uninstalling."
|
||||
LangString uninst_warning ${LANG_TURKISH} "qBittorrent çalışıyor. Lütfen kaldırmadan önce uygulamayı kapatın."
|
||||
;LangString uninst_tor_warn ${LANG_ENGLISH} "Not removing .torrent association. It is associated with:"
|
||||
LangString uninst_tor_warn ${LANG_TURKISH} "Not removing .torrent association. It is associated with:"
|
||||
LangString uninst_tor_warn ${LANG_TURKISH} ".torrent ilişkilendirmesi kaldırılmıyor. Şununla ilişkilendirildi:"
|
||||
;LangString uninst_mag_warn ${LANG_ENGLISH} "Not removing magnet association. It is associated with:"
|
||||
LangString uninst_mag_warn ${LANG_TURKISH} "Not removing magnet association. It is associated with:"
|
||||
LangString uninst_mag_warn ${LANG_TURKISH} "Magnet ilişkilendirmesi kaldırılmıyor. Şununla ilişkilendirildi:"
|
||||
|
||||
BIN
dist/windows/nsis plugins/UAC Unicode.zip
vendored
BIN
dist/windows/nsis plugins/UAC.zip
vendored
4
dist/windows/options.nsi
vendored
@@ -19,7 +19,7 @@ XPStyle on
|
||||
!define CSIDL_APPDATA '0x1A' ;Application Data path
|
||||
!define CSIDL_LOCALAPPDATA '0x1C' ;Local Application Data path
|
||||
|
||||
!define PROG_VERSION "3.3.7"
|
||||
!define PROG_VERSION "3.3.11"
|
||||
!define MUI_FINISHPAGE_RUN
|
||||
!define MUI_FINISHPAGE_RUN_FUNCTION PageFinishRun
|
||||
!define MUI_FINISHPAGE_RUN_TEXT $(launch_qbt)
|
||||
@@ -33,7 +33,7 @@ OutFile "qbittorrent_${PROG_VERSION}_setup.exe"
|
||||
;Installer Version Information
|
||||
VIAddVersionKey "ProductName" "qBittorrent"
|
||||
VIAddVersionKey "CompanyName" "The qBittorrent project"
|
||||
VIAddVersionKey "LegalCopyright" "Copyright ©2006-2016 The qBittorrent project"
|
||||
VIAddVersionKey "LegalCopyright" "Copyright ©2006-2017 The qBittorrent project"
|
||||
VIAddVersionKey "FileDescription" "qBittorrent - A Bittorrent Client"
|
||||
VIAddVersionKey "FileVersion" "${PROG_VERSION}"
|
||||
|
||||
|
||||
@@ -31,7 +31,7 @@
|
||||
# and this notice are preserved. This file is offered as-is, without any
|
||||
# warranty.
|
||||
|
||||
#serial 17
|
||||
#serial 18
|
||||
|
||||
AC_DEFUN([AX_BOOST_SYSTEM],
|
||||
[
|
||||
@@ -68,9 +68,10 @@ AC_DEFUN([AX_BOOST_SYSTEM],
|
||||
ax_cv_boost_system,
|
||||
[AC_LANG_PUSH([C++])
|
||||
CXXFLAGS_SAVE=$CXXFLAGS
|
||||
CXXFLAGS=
|
||||
|
||||
AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[@%:@include <boost/system/error_code.hpp>]],
|
||||
[[boost::system::system_category]])],
|
||||
[[boost::system::error_category *a = 0;]])],
|
||||
ax_cv_boost_system=yes, ax_cv_boost_system=no)
|
||||
CXXFLAGS=$CXXFLAGS_SAVE
|
||||
AC_LANG_POP([C++])
|
||||
|
||||
@@ -12,9 +12,9 @@ AC_DEFUN([FIND_QT4],
|
||||
[QT_QMAKE=`AS_DIRNAME(["$QT_QMAKE"])`])
|
||||
])
|
||||
|
||||
AC_CHECK_FILE([$QT_QMAKE/qmake],
|
||||
AS_IF([test -f "$QT_QMAKE/qmake"],
|
||||
[QT_QMAKE="$QT_QMAKE/qmake"],
|
||||
[AC_CHECK_FILE([$QT_QMAKE/qmake-qt4],
|
||||
[AS_IF([test -f "$QT_QMAKE/qmake-qt4"],
|
||||
[QT_QMAKE="$QT_QMAKE/qmake-qt4"],
|
||||
[QT_QMAKE=""])
|
||||
])
|
||||
@@ -36,9 +36,9 @@ AC_DEFUN([FIND_QT5],
|
||||
[host_bins])
|
||||
])
|
||||
|
||||
AC_CHECK_FILE([$QT_QMAKE/qmake],
|
||||
AS_IF([test -f "$QT_QMAKE/qmake"],
|
||||
[QT_QMAKE="$QT_QMAKE/qmake"],
|
||||
[AC_CHECK_FILE([$QT_QMAKE/qmake-qt5],
|
||||
[AS_IF([test -f "$QT_QMAKE/qmake-qt5"],
|
||||
[QT_QMAKE="$QT_QMAKE/qmake-qt5"],
|
||||
[QT_QMAKE=""])
|
||||
])
|
||||
|
||||
@@ -161,10 +161,15 @@ endif (GUI AND WIN32)
|
||||
target_link_libraries(${QBT_TARGET_NAME} ${QBT_TARGET_LIBRARIES} QtSingleApplication::QtSingleApplication)
|
||||
|
||||
if (APPLE)
|
||||
set(qbt_BUNDLE_NAME "${CMAKE_PROJECT_NAME}")
|
||||
set(qbt_BUNDLE_NAME "${QBT_TARGET_NAME}")
|
||||
|
||||
# substitute @EXECUTABLE@ in dist/mac/Info.plist
|
||||
set(EXECUTABLE ${qbt_BUNDLE_NAME})
|
||||
configure_file(${qBittorrent_SOURCE_DIR}/dist/mac/Info.plist ${qBittorrent_BINARY_DIR}/dist/mac/Info.plist @ONLY)
|
||||
|
||||
set_target_properties(${QBT_TARGET_NAME} PROPERTIES
|
||||
MACOSX_BUNDLE_BUNDLE_NAME "${qbt_BUNDLE_NAME}"
|
||||
MACOSX_BUNDLE_INFO_PLIST ${qBittorrent_SOURCE_DIR}/dist/mac/Info.plist
|
||||
MACOSX_BUNDLE_INFO_PLIST ${qBittorrent_BINARY_DIR}/dist/mac/Info.plist
|
||||
)
|
||||
endif (APPLE)
|
||||
|
||||
|
||||
@@ -70,6 +70,7 @@
|
||||
#include "base/net/smtp.h"
|
||||
#include "base/net/downloadmanager.h"
|
||||
#include "base/net/geoipmanager.h"
|
||||
#include "base/net/proxyconfigurationmanager.h"
|
||||
#include "base/bittorrent/session.h"
|
||||
#include "base/bittorrent/torrenthandle.h"
|
||||
|
||||
@@ -263,7 +264,7 @@ void Application::runExternalProgram(BitTorrent::TorrentHandle *const torrent) c
|
||||
#elif defined(Q_OS_WIN) // test cmd: `echo "%F" > "c:\ab ba.txt"`
|
||||
program.prepend(QLatin1String("\"")).append(QLatin1String("\""));
|
||||
program.prepend(Utils::Misc::windowsSystemPath() + QLatin1String("\\cmd.exe /C "));
|
||||
const uint cmdMaxLength = 32768; // max length (incl. terminate char) for `lpCommandLine` in `CreateProcessW()`
|
||||
const int cmdMaxLength = 32768; // max length (incl. terminate char) for `lpCommandLine` in `CreateProcessW()`
|
||||
if ((program.size() + 1) > cmdMaxLength) {
|
||||
logger->addMessage(tr("Torrent: %1, run external program command too long (length > %2), execution failed.").arg(torrent->name()).arg(cmdMaxLength), Log::CRITICAL);
|
||||
return;
|
||||
@@ -395,6 +396,7 @@ void Application::processParams(const QStringList ¶ms)
|
||||
|
||||
int Application::exec(const QStringList ¶ms)
|
||||
{
|
||||
Net::ProxyConfigurationManager::initInstance();
|
||||
Net::DownloadManager::initInstance();
|
||||
#ifdef DISABLE_GUI
|
||||
IconProvider::initInstance();
|
||||
@@ -509,36 +511,27 @@ void Application::initializeTranslation()
|
||||
{
|
||||
Preferences* const pref = Preferences::instance();
|
||||
// Load translation
|
||||
QString locale = pref->getLocale();
|
||||
QString localeStr = pref->getLocale();
|
||||
QLocale::setDefault(QLocale(localeStr));
|
||||
|
||||
if (locale.isEmpty()) {
|
||||
locale = QLocale::system().name();
|
||||
pref->setLocale(locale);
|
||||
}
|
||||
|
||||
if (m_qtTranslator.load(
|
||||
if (
|
||||
#ifdef QBT_USES_QT5
|
||||
QString::fromUtf8("qtbase_") + locale, QLibraryInfo::location(QLibraryInfo::TranslationsPath)) ||
|
||||
m_qtTranslator.load(
|
||||
m_qtTranslator.load(QString::fromUtf8("qtbase_") + localeStr, QLibraryInfo::location(QLibraryInfo::TranslationsPath)) ||
|
||||
#endif
|
||||
QString::fromUtf8("qt_") + locale, QLibraryInfo::location(QLibraryInfo::TranslationsPath))) {
|
||||
qDebug("Qt %s locale recognized, using translation.", qPrintable(locale));
|
||||
}
|
||||
else {
|
||||
qDebug("Qt %s locale unrecognized, using default (en).", qPrintable(locale));
|
||||
}
|
||||
m_qtTranslator.load(QString::fromUtf8("qt_") + localeStr, QLibraryInfo::location(QLibraryInfo::TranslationsPath)))
|
||||
qDebug("Qt %s locale recognized, using translation.", qPrintable(localeStr));
|
||||
else
|
||||
qDebug("Qt %s locale unrecognized, using default (en).", qPrintable(localeStr));
|
||||
installTranslator(&m_qtTranslator);
|
||||
|
||||
if (m_translator.load(QString::fromUtf8(":/lang/qbittorrent_") + locale)) {
|
||||
qDebug("%s locale recognized, using translation.", qPrintable(locale));
|
||||
}
|
||||
else {
|
||||
qDebug("%s locale unrecognized, using default (en).", qPrintable(locale));
|
||||
}
|
||||
if (m_translator.load(QString::fromUtf8(":/lang/qbittorrent_") + localeStr))
|
||||
qDebug("%s locale recognized, using translation.", qPrintable(localeStr));
|
||||
else
|
||||
qDebug("%s locale unrecognized, using default (en).", qPrintable(localeStr));
|
||||
installTranslator(&m_translator);
|
||||
|
||||
#ifndef DISABLE_GUI
|
||||
if (locale.startsWith("ar") || locale.startsWith("he")) {
|
||||
if (localeStr.startsWith("ar") || localeStr.startsWith("he")) {
|
||||
qDebug("Right to Left mode");
|
||||
setLayoutDirection(Qt::RightToLeft);
|
||||
}
|
||||
@@ -621,11 +614,13 @@ void Application::cleanup()
|
||||
Net::GeoIPManager::freeInstance();
|
||||
#endif
|
||||
Net::DownloadManager::freeInstance();
|
||||
Net::ProxyConfigurationManager::freeInstance();
|
||||
Preferences::freeInstance();
|
||||
SettingsStorage::freeInstance();
|
||||
delete m_fileLogger;
|
||||
Logger::freeInstance();
|
||||
IconProvider::freeInstance();
|
||||
Utils::Fs::removeDirRecursive(Utils::Fs::tempPath());
|
||||
|
||||
#ifndef DISABLE_GUI
|
||||
#ifdef Q_OS_WIN
|
||||
|
||||
@@ -135,6 +135,16 @@ int main(int argc, char *argv[])
|
||||
// We must save it here because QApplication constructor may change it
|
||||
bool isOneArg = (argc == 2);
|
||||
|
||||
#ifdef Q_OS_MAC
|
||||
// On macOS 10.12 Sierra, Apple changed the behaviour of CFPreferencesSetValue() https://bugreports.qt.io/browse/QTBUG-56344
|
||||
// Due to this, we have to move from native plist to IniFormat
|
||||
macMigratePlists();
|
||||
#endif
|
||||
|
||||
#ifndef DISABLE_GUI
|
||||
migrateRSS();
|
||||
#endif
|
||||
|
||||
// Create Application
|
||||
QString appId = QLatin1String("qBittorrent-") + Utils::Misc::getUserIDString();
|
||||
QScopedPointer<Application> app(new Application(appId, argc, argv));
|
||||
@@ -230,6 +240,17 @@ int main(int argc, char *argv[])
|
||||
qputenv("QT_BEARER_POLL_TIMEOUT", QByteArray::number(-1));
|
||||
#endif
|
||||
|
||||
#if defined(Q_OS_MAC)
|
||||
{
|
||||
// Since Apple made difficult for users to set PATH, we set here for convenience.
|
||||
// Users are supposed to install Homebrew Python for search function.
|
||||
// For more info see issue #5571.
|
||||
QByteArray path = "/usr/local/bin:";
|
||||
path += qgetenv("PATH");
|
||||
qputenv("PATH", path.constData());
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifndef DISABLE_GUI
|
||||
if (!upgrade()) return EXIT_FAILURE;
|
||||
#else
|
||||
|
||||
@@ -15,78 +15,86 @@ static inline void print_stacktrace(FILE *out = stderr, unsigned int max_frames
|
||||
fprintf(out, "stack trace:\n");
|
||||
|
||||
// storage array for stack trace address data
|
||||
void* addrlist[max_frames+1];
|
||||
void *addrlist[max_frames + 1];
|
||||
|
||||
// retrieve current stack addresses
|
||||
int addrlen = backtrace(addrlist, sizeof(addrlist) / sizeof(void*));
|
||||
int addrlen = backtrace(addrlist, sizeof(addrlist) / sizeof(void *));
|
||||
|
||||
if (addrlen == 0) {
|
||||
fprintf(out, " <empty, possibly corrupt>\n");
|
||||
return;
|
||||
fprintf(out, " <empty, possibly corrupt>\n");
|
||||
return;
|
||||
}
|
||||
|
||||
// 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, addrlen);
|
||||
|
||||
// allocate string which will be filled with the demangled function name
|
||||
size_t funcnamesize = 256;
|
||||
char* funcname = (char*)malloc(funcnamesize);
|
||||
char *funcname = (char *)malloc(funcnamesize);
|
||||
|
||||
int functionNamesFound = 0;
|
||||
// iterate over the returned symbol lines. skip the first, it is the
|
||||
// address of this function.
|
||||
for (int i = 2; i < addrlen; i++)
|
||||
{
|
||||
char *begin_name = 0, *begin_offset = 0, *end_offset = 0;
|
||||
for (int i = 2; i < addrlen; i++) {
|
||||
char *begin_name = 0, *begin_offset = 0, *end_offset = 0;
|
||||
|
||||
// find parentheses and +address offset surrounding the mangled name:
|
||||
// ./module(function+0x15c) [0x8048a6d]
|
||||
//fprintf(out, "%s TT\n", symbollist[i]);
|
||||
for (char *p = symbollist[i]; *p; ++p)
|
||||
{
|
||||
if (*p == '(')
|
||||
begin_name = p;
|
||||
else if (*p == '+')
|
||||
begin_offset = p;
|
||||
else if (*p == ')' && begin_offset) {
|
||||
end_offset = p;
|
||||
break;
|
||||
}
|
||||
}
|
||||
// find parentheses and +address offset surrounding the mangled name:
|
||||
// ./module(function+0x15c) [0x8048a6d]
|
||||
// fprintf(out, "%s TT\n", symbollist[i]);
|
||||
for (char *p = symbollist[i]; *p; ++p) {
|
||||
if (*p == '(') {
|
||||
begin_name = p;
|
||||
}
|
||||
else if (*p == '+') {
|
||||
begin_offset = p;
|
||||
}
|
||||
else if ((*p == ')') && begin_offset) {
|
||||
end_offset = p;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (begin_name && begin_offset && end_offset
|
||||
&& begin_name < begin_offset)
|
||||
{
|
||||
*begin_name++ = '\0';
|
||||
*begin_offset++ = '\0';
|
||||
*end_offset = '\0';
|
||||
if (begin_name && begin_offset && end_offset
|
||||
&& (begin_name < begin_offset)) {
|
||||
*begin_name++ = '\0';
|
||||
*begin_offset++ = '\0';
|
||||
*end_offset = '\0';
|
||||
|
||||
// mangled name is now in [begin_name, begin_offset) and caller
|
||||
// offset in [begin_offset, end_offset). now apply
|
||||
// __cxa_demangle():
|
||||
// mangled name is now in [begin_name, begin_offset) and caller
|
||||
// offset in [begin_offset, end_offset). now apply
|
||||
// __cxa_demangle():
|
||||
|
||||
int status;
|
||||
char* ret = abi::__cxa_demangle(begin_name,
|
||||
funcname, &funcnamesize, &status);
|
||||
if (status == 0) {
|
||||
funcname = ret; // use possibly realloc()-ed string
|
||||
fprintf(out, " %s : %s+%s %s\n",
|
||||
symbollist[i], funcname, begin_offset, ++end_offset);
|
||||
}
|
||||
else {
|
||||
// demangling failed. Output function name as a C function with
|
||||
// no arguments.
|
||||
fprintf(out, " %s : %s()+%s %s\n",
|
||||
symbollist[i], begin_name, begin_offset, ++end_offset);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// couldn't parse the line? print the whole line.
|
||||
fprintf(out, " %s\n", symbollist[i]);
|
||||
}
|
||||
int status;
|
||||
char *ret = abi::__cxa_demangle(begin_name,
|
||||
funcname, &funcnamesize, &status);
|
||||
if (status == 0) {
|
||||
funcname = ret; // use possibly realloc()-ed string
|
||||
fprintf(out, " %s : %s+%s %s\n",
|
||||
symbollist[i], funcname, begin_offset, ++end_offset);
|
||||
}
|
||||
else {
|
||||
// demangling failed. Output function name as a C function with
|
||||
// no arguments.
|
||||
fprintf(out, " %s : %s()+%s %s\n",
|
||||
symbollist[i], begin_name, begin_offset, ++end_offset);
|
||||
}
|
||||
++functionNamesFound;
|
||||
}
|
||||
else {
|
||||
// couldn't parse the line? print the whole line.
|
||||
fprintf(out, " %s\n", symbollist[i]);
|
||||
}
|
||||
}
|
||||
|
||||
if (!functionNamesFound) {
|
||||
fprintf(out, "There were no function names found in the stack trace\n."
|
||||
"Seems like debug symbols are not installed, and the stack trace is useless.\n");
|
||||
}
|
||||
if (functionNamesFound < addrlen - 2) {
|
||||
fprintf(out, "Consider installing debug symbols for packages containing files with empty"
|
||||
" function names (i.e. empty braces \"()\") to make your stack trace more useful\n");
|
||||
}
|
||||
free(funcname);
|
||||
free(symbollist);
|
||||
}
|
||||
|
||||
@@ -29,24 +29,31 @@
|
||||
#ifndef UPGRADE_H
|
||||
#define UPGRADE_H
|
||||
|
||||
#include <libtorrent/lazy_entry.hpp>
|
||||
#include <libtorrent/entry.hpp>
|
||||
#include <libtorrent/version.hpp>
|
||||
#if LIBTORRENT_VERSION_NUM >= 10100
|
||||
#include <libtorrent/bdecode.hpp>
|
||||
#endif
|
||||
#include <libtorrent/bencode.hpp>
|
||||
#include <libtorrent/entry.hpp>
|
||||
#if LIBTORRENT_VERSION_NUM < 10100
|
||||
#include <libtorrent/lazy_entry.hpp>
|
||||
#endif
|
||||
|
||||
|
||||
#include <QString>
|
||||
#include <QDir>
|
||||
#include <QFile>
|
||||
#include <QRegExp>
|
||||
#ifndef DISABLE_GUI
|
||||
#include <QMessageBox>
|
||||
#endif
|
||||
#include <QRegExp>
|
||||
#include <QString>
|
||||
|
||||
#include "base/logger.h"
|
||||
#include "base/utils/fs.h"
|
||||
#include "base/utils/misc.h"
|
||||
#include "base/utils/string.h"
|
||||
#include "base/qinisettings.h"
|
||||
#include "base/preferences.h"
|
||||
#include "base/qinisettings.h"
|
||||
|
||||
bool userAcceptsUpgrade()
|
||||
{
|
||||
@@ -86,10 +93,16 @@ bool upgradeResumeFile(const QString &filepath, const QVariantHash &oldTorrent =
|
||||
QByteArray data = file1.readAll();
|
||||
file1.close();
|
||||
|
||||
libtorrent::lazy_entry fastOld;
|
||||
libtorrent::error_code ec;
|
||||
libtorrent::lazy_bdecode(data.constData(), data.constData() + data.size(), fastOld, ec);
|
||||
if (ec || (fastOld.type() != libtorrent::lazy_entry::dict_t)) return false;
|
||||
#if LIBTORRENT_VERSION_NUM < 10100
|
||||
libtorrent::lazy_entry fastOld;
|
||||
libtorrent::lazy_bdecode(data.constData(), data.constData() + data.size(), fastOld, ec);
|
||||
if (ec || (fastOld.type() != libtorrent::lazy_entry::dict_t)) return false;
|
||||
#else
|
||||
libtorrent::bdecode_node fastOld;
|
||||
libtorrent::bdecode(data.constData(), data.constData() + data.size(), fastOld, ec);
|
||||
if (ec || (fastOld.type() != libtorrent::bdecode_node::dict_t)) return false;
|
||||
#endif
|
||||
|
||||
libtorrent::entry fastNew;
|
||||
fastNew = fastOld;
|
||||
@@ -143,7 +156,12 @@ bool upgrade(bool ask = true)
|
||||
upgradeResumeFile(backupFolderDir.absoluteFilePath(backupFile));
|
||||
// ****************************************************************************************
|
||||
|
||||
#ifdef Q_OS_MAC
|
||||
// native .plist
|
||||
QSettings *oldResumeSettings = new QSettings("qBittorrent", "qBittorrent-resume");
|
||||
#else
|
||||
QIniSettings *oldResumeSettings = new QIniSettings("qBittorrent", "qBittorrent-resume");
|
||||
#endif
|
||||
QString oldResumeFilename = oldResumeSettings->fileName();
|
||||
QVariantHash oldResumeData = oldResumeSettings->value("torrents").toHash();
|
||||
delete oldResumeSettings;
|
||||
@@ -210,4 +228,50 @@ bool upgrade(bool ask = true)
|
||||
return true;
|
||||
}
|
||||
|
||||
#ifdef Q_OS_MAC
|
||||
void migratePlistToIni(const QString &application)
|
||||
{
|
||||
QIniSettings iniFile("qBittorrent", application);
|
||||
if (!iniFile.allKeys().isEmpty()) return; // We copy the contents of plist, only if inifile does not exist(is empty).
|
||||
|
||||
QSettings *plistFile = new QSettings("qBittorrent", application);
|
||||
plistFile->setFallbacksEnabled(false);
|
||||
const QStringList plist = plistFile->allKeys();
|
||||
if (!plist.isEmpty()) {
|
||||
foreach (const QString &key, plist)
|
||||
iniFile.setValue(key, plistFile->value(key));
|
||||
plistFile->clear();
|
||||
}
|
||||
|
||||
QString plistPath = plistFile->fileName();
|
||||
delete plistFile;
|
||||
Utils::Fs::forceRemove(plistPath);
|
||||
}
|
||||
|
||||
void macMigratePlists()
|
||||
{
|
||||
migratePlistToIni("qBittorrent-data");
|
||||
migratePlistToIni("qBittorrent-rss");
|
||||
migratePlistToIni("qBittorrent");
|
||||
}
|
||||
#endif // Q_OS_MAC
|
||||
|
||||
#ifndef DISABLE_GUI
|
||||
void migrateRSS()
|
||||
{
|
||||
// Copy old feed items to new file if needed
|
||||
QIniSettings qBTRSS("qBittorrent", "qBittorrent-rss-feeds");
|
||||
if (!qBTRSS.allKeys().isEmpty()) return; // We move the contents of RSS old_items only if inifile does not exist (is empty).
|
||||
|
||||
QIniSettings qBTRSSLegacy("qBittorrent", "qBittorrent-rss");
|
||||
QHash<QString, QVariant> allOldItems = qBTRSSLegacy.value("old_items", QHash<QString, QVariant>()).toHash();
|
||||
|
||||
if (!allOldItems.empty()) {
|
||||
qDebug("Moving %d old items for feeds to qBittorrent-rss-feeds", allOldItems.size());
|
||||
qBTRSS.setValue("old_items", allOldItems);
|
||||
qBTRSSLegacy.remove("old_items");
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif // UPGRADE_H
|
||||
|
||||
@@ -30,6 +30,7 @@ net/downloadmanager.h
|
||||
net/geoipmanager.h
|
||||
net/portforwarder.h
|
||||
net/private/geoipdatabase.h
|
||||
net/proxyconfigurationmanager.h
|
||||
net/reverseresolution.h
|
||||
net/smtp.h
|
||||
rss/private/rssparser.h
|
||||
@@ -88,6 +89,7 @@ net/downloadmanager.cpp
|
||||
net/geoipmanager.cpp
|
||||
net/portforwarder.cpp
|
||||
net/private/geoipdatabase.cpp
|
||||
net/proxyconfigurationmanager.cpp
|
||||
net/reverseresolution.cpp
|
||||
net/smtp.cpp
|
||||
rss/private/rssparser.cpp
|
||||
@@ -115,24 +117,24 @@ tristatebool.cpp
|
||||
)
|
||||
|
||||
add_library(qbt_base STATIC ${QBT_BASE_HEADERS} ${QBT_BASE_SOURCES})
|
||||
target_link_libraries(qbt_base ZLIB::ZLIB LibtorrentRasterbar::LibTorrent)
|
||||
target_link_qt_components(qbt_base Core Network Xml)
|
||||
target_link_libraries(qbt_base PRIVATE ZLIB::ZLIB PUBLIC LibtorrentRasterbar::LibTorrent)
|
||||
target_link_qt_components(qbt_base PUBLIC Core Network Xml)
|
||||
if (QT4_FOUND)
|
||||
if (GUI)
|
||||
target_link_libraries(qbt_base Qt4::QtGui)
|
||||
target_link_libraries(qbt_base PUBLIC Qt4::QtGui)
|
||||
endif (GUI)
|
||||
else (QT4_FOUND)
|
||||
if (GUI)
|
||||
target_link_libraries(qbt_base Qt5::Gui Qt5::Widgets)
|
||||
target_link_libraries(qbt_base PUBLIC Qt5::Gui Qt5::Widgets)
|
||||
endif (GUI)
|
||||
endif (QT4_FOUND)
|
||||
|
||||
if (DBUS)
|
||||
target_link_qt_components(qbt_base DBus)
|
||||
target_link_qt_components(qbt_base PRIVATE DBus)
|
||||
endif ()
|
||||
|
||||
if (APPLE)
|
||||
find_library(IOKit_LIBRARY IOKit)
|
||||
find_library(Carbon_LIBRARY Carbon)
|
||||
target_link_libraries(qbt_base ${Carbon_LIBRARY} ${IOKit_LIBRARY})
|
||||
target_link_libraries(qbt_base PRIVATE ${Carbon_LIBRARY} ${IOKit_LIBRARY})
|
||||
endif (APPLE)
|
||||
|
||||
@@ -5,6 +5,7 @@ HEADERS += \
|
||||
$$PWD/qinisettings.h \
|
||||
$$PWD/logger.h \
|
||||
$$PWD/settingsstorage.h \
|
||||
$$PWD/settingvalue.h \
|
||||
$$PWD/preferences.h \
|
||||
$$PWD/indexrange.h \
|
||||
$$PWD/iconprovider.h \
|
||||
@@ -20,6 +21,7 @@ HEADERS += \
|
||||
$$PWD/net/downloadhandler.h \
|
||||
$$PWD/net/geoipmanager.h \
|
||||
$$PWD/net/portforwarder.h \
|
||||
$$PWD/net/proxyconfigurationmanager.h \
|
||||
$$PWD/net/reverseresolution.h \
|
||||
$$PWD/net/smtp.h \
|
||||
$$PWD/net/private/geoipdatabase.h \
|
||||
@@ -74,6 +76,7 @@ SOURCES += \
|
||||
$$PWD/net/downloadhandler.cpp \
|
||||
$$PWD/net/geoipmanager.cpp \
|
||||
$$PWD/net/portforwarder.cpp \
|
||||
$$PWD/net/proxyconfigurationmanager.cpp \
|
||||
$$PWD/net/reverseresolution.cpp \
|
||||
$$PWD/net/smtp.cpp \
|
||||
$$PWD/net/private/geoipdatabase.cpp \
|
||||
|
||||
@@ -31,13 +31,13 @@
|
||||
#include <QTime>
|
||||
#include <QDateTime>
|
||||
|
||||
#include "base/bittorrent/session.h"
|
||||
#include "base/preferences.h"
|
||||
#include "bandwidthscheduler.h"
|
||||
|
||||
BandwidthScheduler::BandwidthScheduler(QObject *parent)
|
||||
: QTimer(parent)
|
||||
{
|
||||
Q_ASSERT(Preferences::instance()->isSchedulerEnabled());
|
||||
// Single shot, we call start() again manually
|
||||
setSingleShot(true);
|
||||
// Connect Signals/Slots
|
||||
@@ -47,8 +47,7 @@ BandwidthScheduler::BandwidthScheduler(QObject *parent)
|
||||
void BandwidthScheduler::start()
|
||||
{
|
||||
const Preferences* const pref = Preferences::instance();
|
||||
Q_ASSERT(pref->isSchedulerEnabled());
|
||||
bool alt_bw_enabled = pref->isAltBandwidthEnabled();
|
||||
bool alt_bw_enabled = BitTorrent::Session::instance()->isAltGlobalSpeedLimitEnabled();
|
||||
|
||||
QTime start = pref->getSchedulerStartTime();
|
||||
QTime end = pref->getSchedulerEndTime();
|
||||
|
||||
@@ -55,10 +55,10 @@ FilterParserThread::~FilterParserThread()
|
||||
}
|
||||
|
||||
// Parser for eMule ip filter in DAT format
|
||||
int FilterParserThread::parseDATFilterFile(QString m_filePath, libt::ip_filter &filter)
|
||||
int FilterParserThread::parseDATFilterFile(QString filePath, libt::ip_filter &filter)
|
||||
{
|
||||
int ruleCount = 0;
|
||||
QFile file(m_filePath);
|
||||
QFile file(filePath);
|
||||
if (!file.exists()) return ruleCount;
|
||||
|
||||
if (!file.open(QIODevice::ReadOnly | QIODevice::Text)) {
|
||||
@@ -149,10 +149,10 @@ int FilterParserThread::parseDATFilterFile(QString m_filePath, libt::ip_filter &
|
||||
}
|
||||
|
||||
// Parser for PeerGuardian ip filter in p2p format
|
||||
int FilterParserThread::parseP2PFilterFile(QString m_filePath, libt::ip_filter &filter)
|
||||
int FilterParserThread::parseP2PFilterFile(QString filePath, libt::ip_filter &filter)
|
||||
{
|
||||
int ruleCount = 0;
|
||||
QFile file(m_filePath);
|
||||
QFile file(filePath);
|
||||
if (!file.exists()) return ruleCount;
|
||||
|
||||
if (!file.open(QIODevice::ReadOnly | QIODevice::Text)) {
|
||||
@@ -257,10 +257,10 @@ int FilterParserThread::getlineInStream(QDataStream &stream, std::string &name,
|
||||
}
|
||||
|
||||
// Parser for PeerGuardian ip filter in p2p format
|
||||
int FilterParserThread::parseP2BFilterFile(QString m_filePath, libt::ip_filter &filter)
|
||||
int FilterParserThread::parseP2BFilterFile(QString filePath, libt::ip_filter &filter)
|
||||
{
|
||||
int ruleCount = 0;
|
||||
QFile file(m_filePath);
|
||||
QFile file(filePath);
|
||||
if (!file.exists()) return ruleCount;
|
||||
|
||||
if (!file.open(QIODevice::ReadOnly)) {
|
||||
@@ -369,7 +369,7 @@ int FilterParserThread::parseP2BFilterFile(QString m_filePath, libt::ip_filter &
|
||||
// * eMule IP list (DAT): http://wiki.phoenixlabs.org/wiki/DAT_Format
|
||||
// * PeerGuardian Text (P2P): http://wiki.phoenixlabs.org/wiki/P2P_Format
|
||||
// * PeerGuardian Binary (P2B): http://wiki.phoenixlabs.org/wiki/P2B_Format
|
||||
void FilterParserThread::processFilterFile(QString _filePath)
|
||||
void FilterParserThread::processFilterFile(QString filePath)
|
||||
{
|
||||
if (isRunning()) {
|
||||
// Already parsing a filter, m_abort first
|
||||
@@ -378,27 +378,11 @@ void FilterParserThread::processFilterFile(QString _filePath)
|
||||
}
|
||||
|
||||
m_abort = false;
|
||||
m_filePath = _filePath;
|
||||
m_filePath = filePath;
|
||||
// Run it
|
||||
start();
|
||||
}
|
||||
|
||||
void FilterParserThread::processFilterList(libt::session *s, const QStringList &IPs)
|
||||
{
|
||||
// First, import current filter
|
||||
libt::ip_filter filter = s->get_ip_filter();
|
||||
foreach (const QString &ip, IPs) {
|
||||
qDebug("Manual ban of peer %s", ip.toLocal8Bit().constData());
|
||||
boost::system::error_code ec;
|
||||
libt::address addr = libt::address::from_string(ip.toLocal8Bit().constData(), ec);
|
||||
Q_ASSERT(!ec);
|
||||
if (!ec)
|
||||
filter.add_rule(addr, addr, libt::ip_filter::blocked);
|
||||
}
|
||||
|
||||
s->set_ip_filter(filter);
|
||||
}
|
||||
|
||||
QString FilterParserThread::cleanupIPAddress(QString _ip)
|
||||
{
|
||||
_ip = _ip.trimmed();
|
||||
|
||||
@@ -49,13 +49,7 @@ class FilterParserThread : public QThread
|
||||
public:
|
||||
FilterParserThread(libtorrent::session *s, QObject *parent = 0);
|
||||
~FilterParserThread();
|
||||
|
||||
int parseDATFilterFile(QString filePath, libtorrent::ip_filter &filter);
|
||||
int parseP2PFilterFile(QString filePath, libtorrent::ip_filter &filter);
|
||||
int getlineInStream(QDataStream &stream, std::string &name, char delim);
|
||||
int parseP2BFilterFile(QString filePath, libtorrent::ip_filter &filter);
|
||||
void processFilterFile(QString _filePath);
|
||||
static void processFilterList(libtorrent::session *s, const QStringList &IPs);
|
||||
void processFilterFile(QString filePath);
|
||||
|
||||
signals:
|
||||
void IPFilterParsed(int ruleCount);
|
||||
@@ -66,6 +60,11 @@ protected:
|
||||
void run();
|
||||
|
||||
private:
|
||||
int parseDATFilterFile(QString filePath, libtorrent::ip_filter &filter);
|
||||
int parseP2PFilterFile(QString filePath, libtorrent::ip_filter &filter);
|
||||
int getlineInStream(QDataStream &stream, std::string &name, char delim);
|
||||
int parseP2BFilterFile(QString filePath, libtorrent::ip_filter &filter);
|
||||
|
||||
libtorrent::session *m_session;
|
||||
bool m_abort;
|
||||
QString m_filePath;
|
||||
|
||||
@@ -30,17 +30,23 @@
|
||||
#ifndef BITTORRENT_SESSION_H
|
||||
#define BITTORRENT_SESSION_H
|
||||
|
||||
#include <vector>
|
||||
#include <libtorrent/version.hpp>
|
||||
|
||||
#include <QFile>
|
||||
#include <QHash>
|
||||
#include <QMap>
|
||||
#include <QPointer>
|
||||
#include <QVector>
|
||||
#if LIBTORRENT_VERSION_NUM < 10100
|
||||
#include <QMutex>
|
||||
#include <QWaitCondition>
|
||||
#endif
|
||||
#include <QNetworkConfigurationManager>
|
||||
#include <QPointer>
|
||||
#include <QReadWriteLock>
|
||||
#include <QStringList>
|
||||
#include <QVector>
|
||||
#include <QWaitCondition>
|
||||
|
||||
#include <libtorrent/version.hpp>
|
||||
|
||||
#include "base/settingvalue.h"
|
||||
#include "base/tristatebool.h"
|
||||
#include "base/types.h"
|
||||
#include "torrentinfo.h"
|
||||
@@ -52,19 +58,12 @@ namespace libtorrent
|
||||
class entry;
|
||||
struct add_torrent_params;
|
||||
struct pe_settings;
|
||||
struct session_settings;
|
||||
struct session_status;
|
||||
|
||||
#if LIBTORRENT_VERSION_NUM < 10100
|
||||
struct proxy_settings;
|
||||
struct session_settings;
|
||||
#else
|
||||
namespace aux
|
||||
{
|
||||
struct proxy_settings;
|
||||
}
|
||||
|
||||
typedef aux::proxy_settings proxy_settings;
|
||||
struct settings_pack;
|
||||
#endif
|
||||
struct session_status;
|
||||
|
||||
class alert;
|
||||
struct torrent_alert;
|
||||
@@ -111,7 +110,6 @@ class FilterParserThread;
|
||||
class BandwidthScheduler;
|
||||
class Statistics;
|
||||
class ResumeDataSavingManager;
|
||||
class SettingsStorage;
|
||||
|
||||
enum MaxRatioAction
|
||||
{
|
||||
@@ -172,13 +170,6 @@ namespace BitTorrent
|
||||
static void freeInstance();
|
||||
static Session *instance();
|
||||
|
||||
bool isDHTEnabled() const;
|
||||
bool isLSDEnabled() const;
|
||||
bool isPexEnabled() const;
|
||||
bool isQueueingEnabled() const;
|
||||
qreal globalMaxRatio() const;
|
||||
bool isAppendExtensionEnabled() const;
|
||||
|
||||
QString defaultSavePath() const;
|
||||
void setDefaultSavePath(QString path);
|
||||
QString tempPath() const;
|
||||
@@ -219,8 +210,122 @@ namespace BitTorrent
|
||||
bool isDisableAutoTMMWhenCategorySavePathChanged() const;
|
||||
void setDisableAutoTMMWhenCategorySavePathChanged(bool value);
|
||||
|
||||
qreal globalMaxRatio() const;
|
||||
void setGlobalMaxRatio(qreal ratio);
|
||||
bool isDHTEnabled() const;
|
||||
void setDHTEnabled(bool enabled);
|
||||
bool isLSDEnabled() const;
|
||||
void setLSDEnabled(bool enabled);
|
||||
bool isPeXEnabled() const;
|
||||
void setPeXEnabled(bool enabled);
|
||||
bool isAddTorrentPaused() const;
|
||||
void setAddTorrentPaused(bool value);
|
||||
bool isTrackerEnabled() const;
|
||||
void setTrackerEnabled(bool enabled);
|
||||
bool isAppendExtensionEnabled() const;
|
||||
void setAppendExtensionEnabled(bool enabled);
|
||||
uint refreshInterval() const;
|
||||
void setRefreshInterval(uint value);
|
||||
bool isPreallocationEnabled() const;
|
||||
void setPreallocationEnabled(bool enabled);
|
||||
QString torrentExportDirectory() const;
|
||||
void setTorrentExportDirectory(QString path);
|
||||
QString finishedTorrentExportDirectory() const;
|
||||
void setFinishedTorrentExportDirectory(QString path);
|
||||
|
||||
int globalDownloadSpeedLimit() const;
|
||||
void setGlobalDownloadSpeedLimit(int limit);
|
||||
int globalUploadSpeedLimit() const;
|
||||
void setGlobalUploadSpeedLimit(int limit);
|
||||
int altGlobalDownloadSpeedLimit() const;
|
||||
void setAltGlobalDownloadSpeedLimit(int limit);
|
||||
int altGlobalUploadSpeedLimit() const;
|
||||
void setAltGlobalUploadSpeedLimit(int limit);
|
||||
int downloadSpeedLimit() const;
|
||||
void setDownloadSpeedLimit(int limit);
|
||||
int uploadSpeedLimit() const;
|
||||
void setUploadSpeedLimit(int limit);
|
||||
bool isAltGlobalSpeedLimitEnabled() const;
|
||||
void setAltGlobalSpeedLimitEnabled(bool enabled);
|
||||
bool isBandwidthSchedulerEnabled() const;
|
||||
void setBandwidthSchedulerEnabled(bool enabled);
|
||||
|
||||
uint saveResumeDataInterval() const;
|
||||
void setSaveResumeDataInterval(uint value);
|
||||
int port() const;
|
||||
void setPort(int port);
|
||||
bool useRandomPort() const;
|
||||
void setUseRandomPort(bool value);
|
||||
QString networkInterface() const;
|
||||
void setNetworkInterface(const QString &interface);
|
||||
QString networkInterfaceName() const;
|
||||
void setNetworkInterfaceName(const QString &name);
|
||||
QString networkInterfaceAddress() const;
|
||||
void setNetworkInterfaceAddress(const QString &address);
|
||||
bool isIPv6Enabled() const;
|
||||
void setIPv6Enabled(bool enabled);
|
||||
int encryption() const;
|
||||
void setEncryption(int state);
|
||||
bool isForceProxyEnabled() const;
|
||||
void setForceProxyEnabled(bool enabled);
|
||||
bool isProxyPeerConnectionsEnabled() const;
|
||||
void setProxyPeerConnectionsEnabled(bool enabled);
|
||||
bool isAddTrackersEnabled() const;
|
||||
void setAddTrackersEnabled(bool enabled);
|
||||
QString additionalTrackers() const;
|
||||
void setAdditionalTrackers(const QString &trackers);
|
||||
bool isIPFilteringEnabled() const;
|
||||
void setIPFilteringEnabled(bool enabled);
|
||||
QString IPFilterFile() const;
|
||||
void setIPFilterFile(QString path);
|
||||
bool announceToAllTrackers() const;
|
||||
void setAnnounceToAllTrackers(bool val);
|
||||
uint diskCacheSize() const;
|
||||
void setDiskCacheSize(uint size);
|
||||
uint diskCacheTTL() const;
|
||||
void setDiskCacheTTL(uint ttl);
|
||||
bool useOSCache() const;
|
||||
void setUseOSCache(bool use);
|
||||
bool isAnonymousModeEnabled() const;
|
||||
void setAnonymousModeEnabled(bool enabled);
|
||||
bool isQueueingSystemEnabled() const;
|
||||
void setQueueingSystemEnabled(bool enabled);
|
||||
bool ignoreSlowTorrentsForQueueing() const;
|
||||
void setIgnoreSlowTorrentsForQueueing(bool ignore);
|
||||
uint outgoingPortsMin() const;
|
||||
void setOutgoingPortsMin(uint min);
|
||||
uint outgoingPortsMax() const;
|
||||
void setOutgoingPortsMax(uint max);
|
||||
bool ignoreLimitsOnLAN() const;
|
||||
void setIgnoreLimitsOnLAN(bool ignore);
|
||||
bool includeOverheadInLimits() const;
|
||||
void setIncludeOverheadInLimits(bool include);
|
||||
QString announceIP() const;
|
||||
void setAnnounceIP(const QString &ip);
|
||||
bool isSuperSeedingEnabled() const;
|
||||
void setSuperSeedingEnabled(bool enabled);
|
||||
int maxConnections() const;
|
||||
void setMaxConnections(int max);
|
||||
int maxHalfOpenConnections() const;
|
||||
void setMaxHalfOpenConnections(int max);
|
||||
int maxConnectionsPerTorrent() const;
|
||||
void setMaxConnectionsPerTorrent(int max);
|
||||
int maxUploads() const;
|
||||
void setMaxUploads(int max);
|
||||
int maxUploadsPerTorrent() const;
|
||||
void setMaxUploadsPerTorrent(int max);
|
||||
int maxActiveDownloads() const;
|
||||
void setMaxActiveDownloads(int max);
|
||||
int maxActiveUploads() const;
|
||||
void setMaxActiveUploads(int max);
|
||||
int maxActiveTorrents() const;
|
||||
void setMaxActiveTorrents(int max);
|
||||
bool isUTPEnabled() const;
|
||||
void setUTPEnabled(bool enabled);
|
||||
bool isUTPRateLimited() const;
|
||||
void setUTPRateLimited(bool limited);
|
||||
bool isTrackerFilteringEnabled() const;
|
||||
void setTrackerFilteringEnabled(bool enabled);
|
||||
|
||||
TorrentHandle *findTorrent(const InfoHash &hash) const;
|
||||
QHash<InfoHash, TorrentHandle *> torrents() const;
|
||||
@@ -231,19 +336,11 @@ namespace BitTorrent
|
||||
CacheStatus cacheStatus() const;
|
||||
quint64 getAlltimeDL() const;
|
||||
quint64 getAlltimeUL() const;
|
||||
int downloadRateLimit() const;
|
||||
int uploadRateLimit() const;
|
||||
bool isListening() const;
|
||||
|
||||
MaxRatioAction maxRatioAction() const;
|
||||
void setMaxRatioAction(MaxRatioAction act);
|
||||
|
||||
void changeSpeedLimitMode(bool alternative);
|
||||
void setDownloadRateLimit(int rate);
|
||||
void setUploadRateLimit(int rate);
|
||||
void setGlobalMaxRatio(qreal ratio);
|
||||
void enableIPFilter(const QString &filterPath, bool force = false);
|
||||
void disableIPFilter();
|
||||
void banIP(const QString &ip);
|
||||
|
||||
bool isKnownTorrent(const InfoHash &hash) const;
|
||||
@@ -304,7 +401,7 @@ namespace BitTorrent
|
||||
void trackerAuthenticationRequired(BitTorrent::TorrentHandle *const torrent);
|
||||
void recursiveTorrentDownloadPossible(BitTorrent::TorrentHandle *const torrent);
|
||||
void speedLimitModeChanged(bool alternative);
|
||||
void ipFilterParsed(bool error, int ruleCount);
|
||||
void IPFilterParsed(bool error, int ruleCount);
|
||||
void trackersAdded(BitTorrent::TorrentHandle *const torrent, const QList<BitTorrent::TrackerEntry> &trackers);
|
||||
void trackersRemoved(BitTorrent::TorrentHandle *const torrent, const QList<BitTorrent::TrackerEntry> &trackers);
|
||||
void trackersChanged(BitTorrent::TorrentHandle *const torrent);
|
||||
@@ -316,7 +413,7 @@ namespace BitTorrent
|
||||
void subcategoriesSupportChanged();
|
||||
|
||||
private slots:
|
||||
void configure();
|
||||
void configureDeferred();
|
||||
void readAlerts();
|
||||
void refresh();
|
||||
void processBigRatios();
|
||||
@@ -341,20 +438,24 @@ namespace BitTorrent
|
||||
void initResumeFolder();
|
||||
|
||||
// Session configuration
|
||||
void setSessionSettings();
|
||||
void setProxySettings(libtorrent::proxy_settings proxySettings);
|
||||
void adjustLimits();
|
||||
Q_INVOKABLE void configure();
|
||||
#if LIBTORRENT_VERSION_NUM < 10100
|
||||
void configure(libtorrent::session_settings &sessionSettings);
|
||||
void adjustLimits(libtorrent::session_settings &sessionSettings);
|
||||
#else
|
||||
void configure(libtorrent::settings_pack &settingsPack);
|
||||
void adjustLimits(libtorrent::settings_pack &settingsPack);
|
||||
#endif
|
||||
void adjustLimits();
|
||||
void processBannedIPs();
|
||||
const QStringList getListeningIPs();
|
||||
void setListeningPort();
|
||||
void preAllocateAllFiles(bool b);
|
||||
void setMaxConnectionsPerTorrent(int max);
|
||||
void setMaxUploadsPerTorrent(int max);
|
||||
void enableLSD(bool enable);
|
||||
void enableDHT(bool enable);
|
||||
void configureListeningInterface();
|
||||
void changeSpeedLimitMode_impl(bool alternative);
|
||||
|
||||
void setAppendExtension(bool append);
|
||||
void enableTracker(bool enable);
|
||||
void enableBandwidthScheduler();
|
||||
void populateAdditionalTrackers();
|
||||
void enableIPFilter();
|
||||
void disableIPFilter();
|
||||
|
||||
void startUpTorrents();
|
||||
bool addTorrent_impl(AddTorrentData addData, const MagnetUri &magnetUri,
|
||||
@@ -364,7 +465,7 @@ namespace BitTorrent
|
||||
|
||||
void updateRatioTimer();
|
||||
void exportTorrentFile(TorrentHandle *const torrent, TorrentExportFolder folder = TorrentExportFolder::Regular);
|
||||
void saveTorrentResumeData(TorrentHandle *const torrent);
|
||||
void saveTorrentResumeData(TorrentHandle *const torrent, bool finalSave = false);
|
||||
|
||||
void handleAlert(libtorrent::alert *a);
|
||||
void dispatchTorrentAlert(libtorrent::alert *a);
|
||||
@@ -389,35 +490,97 @@ namespace BitTorrent
|
||||
void saveResumeData();
|
||||
|
||||
#if LIBTORRENT_VERSION_NUM < 10100
|
||||
void dispatchAlerts(std::auto_ptr<libtorrent::alert> alertPtr);
|
||||
void dispatchAlerts(libtorrent::alert *alertPtr);
|
||||
#endif
|
||||
void getPendingAlerts(std::vector<libtorrent::alert *> &out, ulong time = 0);
|
||||
|
||||
SettingsStorage *m_settings;
|
||||
|
||||
// BitTorrent
|
||||
libtorrent::session *m_nativeSession;
|
||||
|
||||
bool m_LSDEnabled;
|
||||
bool m_DHTEnabled;
|
||||
bool m_PeXEnabled;
|
||||
bool m_queueingEnabled;
|
||||
bool m_torrentExportEnabled;
|
||||
bool m_finishedTorrentExportEnabled;
|
||||
bool m_preAllocateAll;
|
||||
qreal m_globalMaxRatio;
|
||||
bool m_deferredConfigureScheduled;
|
||||
bool m_IPFilteringChanged;
|
||||
#if LIBTORRENT_VERSION_NUM >= 10100
|
||||
bool m_listenInterfaceChanged; // optimization
|
||||
#endif
|
||||
CachedSettingValue<bool> m_isDHTEnabled;
|
||||
CachedSettingValue<bool> m_isLSDEnabled;
|
||||
CachedSettingValue<bool> m_isPeXEnabled;
|
||||
CachedSettingValue<bool> m_isIPFilteringEnabled;
|
||||
CachedSettingValue<bool> m_isTrackerFilteringEnabled;
|
||||
CachedSettingValue<QString> m_IPFilterFile;
|
||||
CachedSettingValue<bool> m_announceToAllTrackers;
|
||||
CachedSettingValue<uint> m_diskCacheSize;
|
||||
CachedSettingValue<uint> m_diskCacheTTL;
|
||||
CachedSettingValue<bool> m_useOSCache;
|
||||
CachedSettingValue<bool> m_isAnonymousModeEnabled;
|
||||
CachedSettingValue<bool> m_isQueueingEnabled;
|
||||
CachedSettingValue<int> m_maxActiveDownloads;
|
||||
CachedSettingValue<int> m_maxActiveUploads;
|
||||
CachedSettingValue<int> m_maxActiveTorrents;
|
||||
CachedSettingValue<bool> m_ignoreSlowTorrentsForQueueing;
|
||||
CachedSettingValue<uint> m_outgoingPortsMin;
|
||||
CachedSettingValue<uint> m_outgoingPortsMax;
|
||||
CachedSettingValue<bool> m_ignoreLimitsOnLAN;
|
||||
CachedSettingValue<bool> m_includeOverheadInLimits;
|
||||
CachedSettingValue<QString> m_announceIP;
|
||||
CachedSettingValue<bool> m_isSuperSeedingEnabled;
|
||||
CachedSettingValue<int> m_maxConnections;
|
||||
CachedSettingValue<int> m_maxHalfOpenConnections;
|
||||
CachedSettingValue<int> m_maxUploads;
|
||||
CachedSettingValue<int> m_maxConnectionsPerTorrent;
|
||||
CachedSettingValue<int> m_maxUploadsPerTorrent;
|
||||
CachedSettingValue<bool> m_isUTPEnabled;
|
||||
CachedSettingValue<bool> m_isUTPRateLimited;
|
||||
CachedSettingValue<bool> m_isAddTrackersEnabled;
|
||||
CachedSettingValue<QString> m_additionalTrackers;
|
||||
CachedSettingValue<qreal> m_globalMaxRatio;
|
||||
CachedSettingValue<bool> m_isAddTorrentPaused;
|
||||
CachedSettingValue<bool> m_isAppendExtensionEnabled;
|
||||
CachedSettingValue<uint> m_refreshInterval;
|
||||
CachedSettingValue<bool> m_isPreallocationEnabled;
|
||||
CachedSettingValue<QString> m_torrentExportDirectory;
|
||||
CachedSettingValue<QString> m_finishedTorrentExportDirectory;
|
||||
CachedSettingValue<int> m_globalDownloadSpeedLimit;
|
||||
CachedSettingValue<int> m_globalUploadSpeedLimit;
|
||||
CachedSettingValue<int> m_altGlobalDownloadSpeedLimit;
|
||||
CachedSettingValue<int> m_altGlobalUploadSpeedLimit;
|
||||
CachedSettingValue<bool> m_isAltGlobalSpeedLimitEnabled;
|
||||
CachedSettingValue<bool> m_isBandwidthSchedulerEnabled;
|
||||
CachedSettingValue<uint> m_saveResumeDataInterval;
|
||||
CachedSettingValue<int> m_port;
|
||||
CachedSettingValue<bool> m_useRandomPort;
|
||||
CachedSettingValue<QString> m_networkInterface;
|
||||
CachedSettingValue<QString> m_networkInterfaceName;
|
||||
CachedSettingValue<QString> m_networkInterfaceAddress;
|
||||
CachedSettingValue<bool> m_isIPv6Enabled;
|
||||
CachedSettingValue<int> m_encryption;
|
||||
CachedSettingValue<bool> m_isForceProxyEnabled;
|
||||
CachedSettingValue<bool> m_isProxyPeerConnectionsEnabled;
|
||||
CachedSettingValue<QVariantMap> m_storedCategories;
|
||||
CachedSettingValue<int> m_maxRatioAction;
|
||||
CachedSettingValue<QString> m_defaultSavePath;
|
||||
CachedSettingValue<QString> m_tempPath;
|
||||
CachedSettingValue<bool> m_isSubcategoriesEnabled;
|
||||
CachedSettingValue<bool> m_isTempPathEnabled;
|
||||
CachedSettingValue<bool> m_isAutoTMMDisabledByDefault;
|
||||
CachedSettingValue<bool> m_isDisableAutoTMMWhenCategoryChanged;
|
||||
CachedSettingValue<bool> m_isDisableAutoTMMWhenDefaultSavePathChanged;
|
||||
CachedSettingValue<bool> m_isDisableAutoTMMWhenCategorySavePathChanged;
|
||||
CachedSettingValue<bool> m_isTrackerEnabled;
|
||||
CachedSettingValue<QStringList> m_bannedIPs;
|
||||
|
||||
// Order is important. This needs to be declared after its CachedSettingsValue
|
||||
// counterpart, because it uses it for initialization in the constructor
|
||||
// initialization list.
|
||||
const bool m_wasPexEnabled;
|
||||
|
||||
int m_numResumeData;
|
||||
int m_extraLimit;
|
||||
bool m_appendExtension;
|
||||
uint m_refreshInterval;
|
||||
MaxRatioAction m_maxRatioAction;
|
||||
QList<BitTorrent::TrackerEntry> m_additionalTrackers;
|
||||
QString m_defaultSavePath;
|
||||
QString m_tempPath;
|
||||
QString m_filterPath;
|
||||
QList<BitTorrent::TrackerEntry> m_additionalTrackerList;
|
||||
QString m_resumeFolderPath;
|
||||
QFile m_resumeFolderLock;
|
||||
QHash<InfoHash, QString> m_savePathsToRemove;
|
||||
bool m_useProxy;
|
||||
|
||||
QTimer *m_refreshTimer;
|
||||
QTimer *m_bigRatioTimer;
|
||||
@@ -447,6 +610,8 @@ namespace BitTorrent
|
||||
|
||||
QNetworkConfigurationManager m_networkManager;
|
||||
|
||||
mutable QReadWriteLock m_lock;
|
||||
|
||||
static Session *m_instance;
|
||||
};
|
||||
}
|
||||
|
||||
@@ -27,6 +27,8 @@
|
||||
* exception statement from your version.
|
||||
*/
|
||||
|
||||
#include <type_traits>
|
||||
|
||||
#include <QDebug>
|
||||
#include <QStringList>
|
||||
#include <QFile>
|
||||
@@ -192,6 +194,31 @@ const qreal TorrentHandle::NO_RATIO_LIMIT = -1.;
|
||||
|
||||
const qreal TorrentHandle::MAX_RATIO = 9999.;
|
||||
|
||||
// The new libtorrent::create_torrent constructor appeared after 1.0.11 in RC_1_0
|
||||
// and after 1.1.1 in RC_1_1. Since it fixed an ABI incompatibility with previous versions
|
||||
// distros might choose to backport it onto 1.0.11 and 1.1.1 respectively.
|
||||
// So we need a way to detect its presence without relying solely on the LIBTORRENT_VERSION_NUM.
|
||||
// Relevant links:
|
||||
// 1. https://github.com/arvidn/libtorrent/issues/1696
|
||||
// 2. https://github.com/qbittorrent/qBittorrent/issues/6406
|
||||
// The following can be removed after one or two libtorrent releases on each branch.
|
||||
namespace
|
||||
{
|
||||
// new constructor is available
|
||||
template<typename T, typename std::enable_if<std::is_constructible<T, libt::torrent_info, bool>::value, int>::type = 0>
|
||||
T makeTorrentCreator(const libtorrent::torrent_info & ti)
|
||||
{
|
||||
return T(ti, true);
|
||||
}
|
||||
|
||||
// new constructor isn't available
|
||||
template<typename T, typename std::enable_if<!std::is_constructible<T, libt::torrent_info, bool>::value, int>::type = 0>
|
||||
T makeTorrentCreator(const libtorrent::torrent_info & ti)
|
||||
{
|
||||
return T(ti);
|
||||
}
|
||||
}
|
||||
|
||||
TorrentHandle::TorrentHandle(Session *session, const libtorrent::torrent_handle &nativeHandle,
|
||||
const AddTorrentData &data)
|
||||
: QObject(session)
|
||||
@@ -485,8 +512,11 @@ bool TorrentHandle::needSaveResumeData() const
|
||||
SAFE_RETURN(bool, need_save_resume_data, false);
|
||||
}
|
||||
|
||||
void TorrentHandle::saveResumeData()
|
||||
void TorrentHandle::saveResumeData(bool updateStatus)
|
||||
{
|
||||
if (updateStatus) // to update queue_position, see discussion in PR #6154
|
||||
this->updateStatus();
|
||||
|
||||
SAFE_CALL(save_resume_data);
|
||||
m_needSaveResumeData = false;
|
||||
}
|
||||
@@ -752,7 +782,7 @@ void TorrentHandle::updateState()
|
||||
m_state = isSeed() ? TorrentState::PausedUploading : TorrentState::PausedDownloading;
|
||||
}
|
||||
else {
|
||||
if (m_session->isQueueingEnabled() && isQueued() && !isChecking()) {
|
||||
if (m_session->isQueueingSystemEnabled() && isQueued() && !isChecking()) {
|
||||
m_state = isSeed() ? TorrentState::QueuedUploading : TorrentState::QueuedDownloading;
|
||||
}
|
||||
else {
|
||||
@@ -915,26 +945,29 @@ int TorrentHandle::leechsCount() const
|
||||
|
||||
int TorrentHandle::totalSeedsCount() const
|
||||
{
|
||||
return m_nativeStatus.list_seeds;
|
||||
return (m_nativeStatus.num_complete > 0) ? m_nativeStatus.num_complete : m_nativeStatus.list_seeds;
|
||||
}
|
||||
|
||||
int TorrentHandle::totalPeersCount() const
|
||||
{
|
||||
return m_nativeStatus.list_peers;
|
||||
int peers = m_nativeStatus.num_complete + m_nativeStatus.num_incomplete;
|
||||
return (peers > 0) ? peers : m_nativeStatus.list_peers;
|
||||
}
|
||||
|
||||
int TorrentHandle::totalLeechersCount() const
|
||||
{
|
||||
return (m_nativeStatus.list_peers - m_nativeStatus.list_seeds);
|
||||
return (m_nativeStatus.num_incomplete > 0) ? m_nativeStatus.num_incomplete : (m_nativeStatus.list_peers - m_nativeStatus.list_seeds);
|
||||
}
|
||||
|
||||
int TorrentHandle::completeCount() const
|
||||
{
|
||||
// additional info: https://github.com/qbittorrent/qBittorrent/pull/5300#issuecomment-267783646
|
||||
return m_nativeStatus.num_complete;
|
||||
}
|
||||
|
||||
int TorrentHandle::incompleteCount() const
|
||||
{
|
||||
// additional info: https://github.com/qbittorrent/qBittorrent/pull/5300#issuecomment-267783646
|
||||
return m_nativeStatus.num_incomplete;
|
||||
}
|
||||
|
||||
@@ -1280,7 +1313,7 @@ void TorrentHandle::moveStorage(const QString &newPath)
|
||||
m_queuedPath = newPath;
|
||||
}
|
||||
else {
|
||||
QString oldPath = nativeActualSavePath();
|
||||
const QString oldPath = nativeActualSavePath();
|
||||
if (QDir(oldPath) == QDir(newPath)) return;
|
||||
|
||||
qDebug("move storage: %s to %s", qPrintable(oldPath), qPrintable(newPath));
|
||||
@@ -1312,7 +1345,7 @@ bool TorrentHandle::saveTorrentFile(const QString &path)
|
||||
{
|
||||
if (!m_torrentInfo.isValid()) return false;
|
||||
|
||||
libt::create_torrent torrentCreator(*(m_torrentInfo.nativeInfo()));
|
||||
libt::create_torrent torrentCreator = makeTorrentCreator<libt::create_torrent>(*(m_torrentInfo.nativeInfo()));
|
||||
libt::entry torrentEntry = torrentCreator.generate();
|
||||
|
||||
QVector<char> out;
|
||||
@@ -1347,7 +1380,7 @@ void TorrentHandle::handleStorageMovedAlert(libtorrent::storage_moved_alert *p)
|
||||
return;
|
||||
}
|
||||
|
||||
QString newPath = Utils::String::fromStdString(p->path);
|
||||
const QString newPath = Utils::String::fromStdString(p->path);
|
||||
if (newPath != m_newPath) {
|
||||
qWarning() << Q_FUNC_INFO << ": New path doesn't match a path in a queue.";
|
||||
return;
|
||||
@@ -1367,13 +1400,6 @@ void TorrentHandle::handleStorageMovedAlert(libtorrent::storage_moved_alert *p)
|
||||
m_session->handleTorrentSavePathChanged(this);
|
||||
}
|
||||
|
||||
// Attempt to remove old folder if empty
|
||||
QDir oldSaveDir(Utils::Fs::fromNativePath(m_oldPath));
|
||||
if (oldSaveDir != QDir(m_session->defaultSavePath())) {
|
||||
qDebug("Attempting to remove %s", qPrintable(m_oldPath));
|
||||
QDir().rmpath(m_oldPath);
|
||||
}
|
||||
|
||||
while (!isMoveInProgress() && (m_renameCount == 0) && !m_moveFinishedTriggers.isEmpty())
|
||||
m_moveFinishedTriggers.takeFirst()();
|
||||
}
|
||||
@@ -1702,6 +1728,11 @@ void TorrentHandle::manageIncompleteFiles()
|
||||
{
|
||||
const bool isAppendExtensionEnabled = m_session->isAppendExtensionEnabled();
|
||||
QVector<qreal> fp = filesProgress();
|
||||
if( fp.size() != filesCount() ) {
|
||||
qDebug() << "skip manageIncompleteFiles because of invalid torrent meta-data or empty file-progress";
|
||||
return;
|
||||
}
|
||||
|
||||
for (int i = 0; i < filesCount(); ++i) {
|
||||
QString name = filePath(i);
|
||||
if (isAppendExtensionEnabled && (fileSize(i) > 0) && (fp[i] < 1)) {
|
||||
@@ -1815,6 +1846,8 @@ void TorrentHandle::setDownloadLimit(int limit)
|
||||
void TorrentHandle::setSuperSeeding(bool enable)
|
||||
{
|
||||
SAFE_CALL(super_seeding, enable)
|
||||
if (superSeeding() != enable)
|
||||
updateStatus();
|
||||
}
|
||||
|
||||
void TorrentHandle::flushCache()
|
||||
|
||||
@@ -351,7 +351,7 @@ namespace BitTorrent
|
||||
void handleTempPathChanged();
|
||||
void handleCategorySavePathChanged();
|
||||
void handleAppendExtensionToggled();
|
||||
void saveResumeData();
|
||||
void saveResumeData(bool updateStatus = false);
|
||||
|
||||
private:
|
||||
typedef boost::function<void ()> EventTrigger;
|
||||
|
||||
@@ -239,7 +239,7 @@ QVector<int> TorrentInfo::fileIndicesForPiece(int pieceIndex) const
|
||||
std::vector<libt::file_slice> files(
|
||||
nativeInfo()->map_block(pieceIndex, 0, nativeInfo()->piece_size(pieceIndex)));
|
||||
QVector<int> res;
|
||||
res.reserve(files.size());
|
||||
res.reserve(int(files.size()));
|
||||
std::transform(files.begin(), files.end(), std::back_inserter(res),
|
||||
[](const libt::file_slice &s) { return s.file_index; });
|
||||
|
||||
|
||||
@@ -35,7 +35,6 @@
|
||||
#include <QUrlQuery>
|
||||
#endif
|
||||
#include <QDir>
|
||||
#include <QTemporaryFile>
|
||||
#include <QDebug>
|
||||
#include "requestparser.h"
|
||||
|
||||
|
||||
@@ -33,6 +33,7 @@
|
||||
#else
|
||||
#include <QTcpSocket>
|
||||
#endif
|
||||
#include <QNetworkProxy>
|
||||
#include "connection.h"
|
||||
#include "server.h"
|
||||
|
||||
@@ -45,6 +46,10 @@ Server::Server(IRequestHandler *requestHandler, QObject *parent)
|
||||
, m_https(false)
|
||||
#endif
|
||||
{
|
||||
setProxy(QNetworkProxy::NoProxy);
|
||||
#ifndef QT_NO_OPENSSL
|
||||
QSslSocket::setDefaultCiphers(safeCipherList());
|
||||
#endif
|
||||
}
|
||||
|
||||
Server::~Server()
|
||||
@@ -84,14 +89,15 @@ void Server::incomingConnection(int socketDescriptor)
|
||||
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);
|
||||
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);
|
||||
static_cast<QSslSocket *>(serverSocket)->setLocalCertificateChain(m_certificates);
|
||||
#else
|
||||
static_cast<QSslSocket*>(serverSocket)->setLocalCertificate(m_certificates.first());
|
||||
static_cast<QSslSocket *>(serverSocket)->setLocalCertificate(m_certificates.first());
|
||||
#endif
|
||||
static_cast<QSslSocket*>(serverSocket)->startServerEncryption();
|
||||
static_cast<QSslSocket *>(serverSocket)->setPeerVerifyMode(QSslSocket::VerifyNone);
|
||||
static_cast<QSslSocket *>(serverSocket)->startServerEncryption();
|
||||
}
|
||||
#endif
|
||||
new Connection(serverSocket, m_requestHandler, this);
|
||||
@@ -100,3 +106,26 @@ void Server::incomingConnection(int socketDescriptor)
|
||||
serverSocket->deleteLater();
|
||||
}
|
||||
}
|
||||
|
||||
#ifndef QT_NO_OPENSSL
|
||||
QList<QSslCipher> Server::safeCipherList() const
|
||||
{
|
||||
const QStringList badCiphers = {"idea", "rc4"};
|
||||
const QList<QSslCipher> allCiphers = QSslSocket::supportedCiphers();
|
||||
QList<QSslCipher> safeCiphers;
|
||||
foreach (const QSslCipher &cipher, allCiphers) {
|
||||
bool isSafe = true;
|
||||
foreach (const QString &badCipher, badCiphers) {
|
||||
if (cipher.name().contains(badCipher, Qt::CaseInsensitive)) {
|
||||
isSafe = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (isSafe)
|
||||
safeCiphers += cipher;
|
||||
}
|
||||
|
||||
return safeCiphers;
|
||||
}
|
||||
#endif
|
||||
|
||||
@@ -36,6 +36,7 @@
|
||||
#include <QTcpServer>
|
||||
#ifndef QT_NO_OPENSSL
|
||||
#include <QSslCertificate>
|
||||
#include <QSslCipher>
|
||||
#include <QSslKey>
|
||||
#endif
|
||||
|
||||
@@ -44,7 +45,7 @@ namespace Http
|
||||
class IRequestHandler;
|
||||
class Connection;
|
||||
|
||||
class Server : public QTcpServer
|
||||
class Server: public QTcpServer
|
||||
{
|
||||
Q_OBJECT
|
||||
Q_DISABLE_COPY(Server)
|
||||
@@ -53,25 +54,27 @@ namespace Http
|
||||
Server(IRequestHandler *requestHandler, QObject *parent = 0);
|
||||
~Server();
|
||||
|
||||
#ifndef QT_NO_OPENSSL
|
||||
#ifndef QT_NO_OPENSSL
|
||||
void enableHttps(const QList<QSslCertificate> &certificates, const QSslKey &key);
|
||||
void disableHttps();
|
||||
#endif
|
||||
|
||||
private:
|
||||
#ifdef QBT_USES_QT5
|
||||
void incomingConnection(qintptr socketDescriptor);
|
||||
#else
|
||||
void incomingConnection(int socketDescriptor);
|
||||
#endif
|
||||
#endif
|
||||
|
||||
private:
|
||||
IRequestHandler *m_requestHandler;
|
||||
#ifndef QT_NO_OPENSSL
|
||||
|
||||
#ifdef QBT_USES_QT5
|
||||
void incomingConnection(qintptr socketDescriptor);
|
||||
#else
|
||||
void incomingConnection(int socketDescriptor);
|
||||
#endif
|
||||
|
||||
#ifndef QT_NO_OPENSSL
|
||||
QList<QSslCipher> safeCipherList() const;
|
||||
|
||||
bool m_https;
|
||||
QList<QSslCertificate> m_certificates;
|
||||
QSslKey m_key;
|
||||
#endif
|
||||
#endif
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
@@ -43,6 +43,10 @@ namespace Http
|
||||
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 QString CONTENT_TYPE_CSS = "text/css; charset=UTF-8";
|
||||
const QString CONTENT_TYPE_GIF = "image/gif";
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
#include "logger.h"
|
||||
|
||||
#include <QDateTime>
|
||||
#include "base/utils/string.h"
|
||||
|
||||
Logger* Logger::m_instance = 0;
|
||||
|
||||
@@ -36,7 +37,7 @@ void Logger::addMessage(const QString &message, const Log::MsgType &type)
|
||||
{
|
||||
QWriteLocker locker(&lock);
|
||||
|
||||
Log::Msg temp = { msgCounter++, QDateTime::currentMSecsSinceEpoch(), type, message };
|
||||
Log::Msg temp = { msgCounter++, QDateTime::currentMSecsSinceEpoch(), type, Utils::String::toHtmlEscaped(message) };
|
||||
m_messages.push_back(temp);
|
||||
|
||||
if (m_messages.size() >= MAX_LOG_MESSAGES)
|
||||
@@ -49,7 +50,7 @@ void Logger::addPeer(const QString &ip, bool blocked, const QString &reason)
|
||||
{
|
||||
QWriteLocker locker(&lock);
|
||||
|
||||
Log::Peer temp = { peerCounter++, QDateTime::currentMSecsSinceEpoch(), ip, blocked, reason };
|
||||
Log::Peer temp = { peerCounter++, QDateTime::currentMSecsSinceEpoch(), Utils::String::toHtmlEscaped(ip), blocked, Utils::String::toHtmlEscaped(reason) };
|
||||
m_peers.push_back(temp);
|
||||
|
||||
if (m_peers.size() >= MAX_LOG_MESSAGES)
|
||||
|
||||
@@ -142,7 +142,7 @@ void DownloadHandler::init()
|
||||
|
||||
bool DownloadHandler::saveToFile(const QByteArray &replyData, QString &filePath)
|
||||
{
|
||||
QTemporaryFile *tmpfile = new QTemporaryFile;
|
||||
QTemporaryFile *tmpfile = new QTemporaryFile(Utils::Fs::tempPath() + "XXXXXX");
|
||||
if (!tmpfile->open()) {
|
||||
delete tmpfile;
|
||||
return false;
|
||||
|
||||
@@ -27,20 +27,21 @@
|
||||
* exception statement from your version.
|
||||
*/
|
||||
|
||||
#include "downloadmanager.h"
|
||||
|
||||
#include <QDateTime>
|
||||
#include <QNetworkRequest>
|
||||
#include <QNetworkProxy>
|
||||
#include <QNetworkCookieJar>
|
||||
#include <QNetworkReply>
|
||||
#include <QDebug>
|
||||
#include <QNetworkCookie>
|
||||
#include <QNetworkCookieJar>
|
||||
#include <QNetworkProxy>
|
||||
#include <QNetworkReply>
|
||||
#include <QNetworkRequest>
|
||||
#include <QSslError>
|
||||
#include <QUrl>
|
||||
#include <QDebug>
|
||||
|
||||
#include "base/preferences.h"
|
||||
#include "downloadhandler.h"
|
||||
#include "downloadmanager.h"
|
||||
#include "proxyconfigurationmanager.h"
|
||||
|
||||
// Spoof Firefox 38 user agent to avoid web server banning
|
||||
const char DEFAULT_USER_AGENT[] = "Mozilla/5.0 (X11; Linux i686; rv:38.0) Gecko/20100101 Firefox/38.0";
|
||||
@@ -208,16 +209,16 @@ bool DownloadManager::deleteCookie(const QNetworkCookie &cookie)
|
||||
|
||||
void DownloadManager::applyProxySettings()
|
||||
{
|
||||
auto proxyManager = ProxyConfigurationManager::instance();
|
||||
ProxyConfiguration proxyConfig = proxyManager->proxyConfiguration();
|
||||
QNetworkProxy proxy;
|
||||
const Preferences* const pref = Preferences::instance();
|
||||
|
||||
if (pref->isProxyEnabled() && !pref->isProxyOnlyForTorrents()) {
|
||||
if (!proxyManager->isProxyOnlyForTorrents() && (proxyConfig.type != ProxyType::None)) {
|
||||
// Proxy enabled
|
||||
proxy.setHostName(pref->getProxyIp());
|
||||
proxy.setPort(pref->getProxyPort());
|
||||
proxy.setHostName(proxyConfig.ip);
|
||||
proxy.setPort(proxyConfig.port);
|
||||
// Default proxy type is HTTP, we must change if it is SOCKS5
|
||||
const int proxyType = pref->getProxyType();
|
||||
if ((proxyType == Proxy::SOCKS5) || (proxyType == Proxy::SOCKS5_PW)) {
|
||||
if ((proxyConfig.type == ProxyType::SOCKS5) || (proxyConfig.type == ProxyType::SOCKS5_PW)) {
|
||||
qDebug() << Q_FUNC_INFO << "using SOCKS proxy";
|
||||
proxy.setType(QNetworkProxy::Socks5Proxy);
|
||||
}
|
||||
@@ -226,10 +227,10 @@ void DownloadManager::applyProxySettings()
|
||||
proxy.setType(QNetworkProxy::HttpProxy);
|
||||
}
|
||||
// Authentication?
|
||||
if (pref->isProxyAuthEnabled()) {
|
||||
if (proxyManager->isAuthenticationRequired()) {
|
||||
qDebug("Proxy requires authentication, authenticating");
|
||||
proxy.setUser(pref->getProxyUsername());
|
||||
proxy.setPassword(pref->getProxyPassword());
|
||||
proxy.setUser(proxyConfig.username);
|
||||
proxy.setPassword(proxyConfig.password);
|
||||
}
|
||||
}
|
||||
else {
|
||||
|
||||
@@ -45,7 +45,6 @@
|
||||
static const char DATABASE_URL[] = "https://geolite.maxmind.com/download/geoip/database/GeoLite2-Country.mmdb.gz";
|
||||
static const char GEOIP_FOLDER[] = "GeoIP";
|
||||
static const char GEOIP_FILENAME[] = "GeoLite2-Country.mmdb";
|
||||
static const int CACHE_SIZE = 1000;
|
||||
static const int UPDATE_INTERVAL = 30; // Days between database updates
|
||||
|
||||
using namespace Net;
|
||||
|
||||
@@ -26,13 +26,17 @@
|
||||
* exception statement from your version.
|
||||
*/
|
||||
|
||||
#include "portforwarder.h"
|
||||
|
||||
#include <QDebug>
|
||||
|
||||
#include <libtorrent/session.hpp>
|
||||
#include <libtorrent/version.hpp>
|
||||
|
||||
#include "base/logger.h"
|
||||
#include "base/preferences.h"
|
||||
#include "portforwarder.h"
|
||||
#include "base/settingsstorage.h"
|
||||
|
||||
static const QString KEY_ENABLED = QLatin1String("Network/PortForwardingEnabled");
|
||||
|
||||
namespace libt = libtorrent;
|
||||
using namespace Net;
|
||||
@@ -42,8 +46,8 @@ PortForwarder::PortForwarder(libtorrent::session *provider, QObject *parent)
|
||||
, m_active(false)
|
||||
, m_provider(provider)
|
||||
{
|
||||
configure();
|
||||
connect(Preferences::instance(), SIGNAL(changed()), SLOT(configure()));
|
||||
if (SettingsStorage::instance()->loadValue(KEY_ENABLED, true).toBool())
|
||||
start();
|
||||
}
|
||||
|
||||
PortForwarder::~PortForwarder()
|
||||
@@ -70,7 +74,24 @@ PortForwarder *PortForwarder::instance()
|
||||
return m_instance;
|
||||
}
|
||||
|
||||
void PortForwarder::addPort(qint16 port)
|
||||
bool PortForwarder::isEnabled() const
|
||||
{
|
||||
return m_active;
|
||||
}
|
||||
|
||||
void PortForwarder::setEnabled(bool enabled)
|
||||
{
|
||||
if (m_active != enabled) {
|
||||
if (enabled)
|
||||
start();
|
||||
else
|
||||
stop();
|
||||
|
||||
SettingsStorage::instance()->storeValue(KEY_ENABLED, enabled);
|
||||
}
|
||||
}
|
||||
|
||||
void PortForwarder::addPort(quint16 port)
|
||||
{
|
||||
if (!m_mappedPorts.contains(port)) {
|
||||
m_mappedPorts.insert(port, 0);
|
||||
@@ -79,7 +100,7 @@ void PortForwarder::addPort(qint16 port)
|
||||
}
|
||||
}
|
||||
|
||||
void PortForwarder::deletePort(qint16 port)
|
||||
void PortForwarder::deletePort(quint16 port)
|
||||
{
|
||||
if (m_mappedPorts.contains(port)) {
|
||||
if (m_active)
|
||||
@@ -88,23 +109,19 @@ void PortForwarder::deletePort(qint16 port)
|
||||
}
|
||||
}
|
||||
|
||||
void PortForwarder::configure()
|
||||
{
|
||||
bool enable = Preferences::instance()->isUPnPEnabled();
|
||||
if (m_active != enable) {
|
||||
if (enable)
|
||||
start();
|
||||
else
|
||||
stop();
|
||||
}
|
||||
}
|
||||
|
||||
void PortForwarder::start()
|
||||
{
|
||||
qDebug("Enabling UPnP / NAT-PMP");
|
||||
#if LIBTORRENT_VERSION_NUM < 10100
|
||||
m_provider->start_upnp();
|
||||
m_provider->start_natpmp();
|
||||
foreach (qint16 port, m_mappedPorts.keys())
|
||||
#else
|
||||
libt::settings_pack settingsPack = m_provider->get_settings();
|
||||
settingsPack.set_bool(libt::settings_pack::enable_upnp, true);
|
||||
settingsPack.set_bool(libt::settings_pack::enable_natpmp, true);
|
||||
m_provider->apply_settings(settingsPack);
|
||||
#endif
|
||||
foreach (quint16 port, m_mappedPorts.keys())
|
||||
m_mappedPorts[port] = m_provider->add_port_mapping(libt::session::tcp, port, port);
|
||||
m_active = true;
|
||||
Logger::instance()->addMessage(tr("UPnP / NAT-PMP support [ON]"), Log::INFO);
|
||||
@@ -113,8 +130,15 @@ void PortForwarder::start()
|
||||
void PortForwarder::stop()
|
||||
{
|
||||
qDebug("Disabling UPnP / NAT-PMP");
|
||||
#if LIBTORRENT_VERSION_NUM < 10100
|
||||
m_provider->stop_upnp();
|
||||
m_provider->stop_natpmp();
|
||||
#else
|
||||
libt::settings_pack settingsPack = m_provider->get_settings();
|
||||
settingsPack.set_bool(libt::settings_pack::enable_upnp, false);
|
||||
settingsPack.set_bool(libt::settings_pack::enable_natpmp, false);
|
||||
m_provider->apply_settings(settingsPack);
|
||||
#endif
|
||||
m_active = false;
|
||||
Logger::instance()->addMessage(tr("UPnP / NAT-PMP support [OFF]"), Log::INFO);
|
||||
}
|
||||
|
||||
@@ -49,11 +49,11 @@ namespace Net
|
||||
static void freeInstance();
|
||||
static PortForwarder *instance();
|
||||
|
||||
void addPort(qint16 port);
|
||||
void deletePort(qint16 port);
|
||||
bool isEnabled() const;
|
||||
void setEnabled(bool enabled);
|
||||
|
||||
private slots:
|
||||
void configure();
|
||||
void addPort(quint16 port);
|
||||
void deletePort(quint16 port);
|
||||
|
||||
private:
|
||||
explicit PortForwarder(libtorrent::session *const provider, QObject *parent = 0);
|
||||
@@ -64,7 +64,7 @@ namespace Net
|
||||
|
||||
bool m_active;
|
||||
libtorrent::session *m_provider;
|
||||
QHash<qint16, int> m_mappedPorts;
|
||||
QHash<quint16, int> m_mappedPorts;
|
||||
|
||||
static PortForwarder *m_instance;
|
||||
};
|
||||
|
||||
163
src/base/net/proxyconfigurationmanager.cpp
Normal file
@@ -0,0 +1,163 @@
|
||||
/*
|
||||
* Bittorrent Client using Qt and libtorrent.
|
||||
* Copyright (C) 2016 Vladimir Golovnev <glassez@yandex.ru>
|
||||
*
|
||||
* 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 "proxyconfigurationmanager.h"
|
||||
#include "base/settingsstorage.h"
|
||||
|
||||
#define SETTINGS_KEY(name) "Network/Proxy/" name
|
||||
const QString KEY_ONLY_FOR_TORRENTS = SETTINGS_KEY("OnlyForTorrents");
|
||||
const QString KEY_TYPE = SETTINGS_KEY("Type");
|
||||
const QString KEY_IP = SETTINGS_KEY("IP");
|
||||
const QString KEY_PORT = SETTINGS_KEY("Port");
|
||||
const QString KEY_USERNAME = SETTINGS_KEY("Username");
|
||||
const QString KEY_PASSWORD = SETTINGS_KEY("Password");
|
||||
|
||||
namespace
|
||||
{
|
||||
inline SettingsStorage *settings() { return SettingsStorage::instance(); }
|
||||
|
||||
inline bool isSameConfig(const Net::ProxyConfiguration &conf1, const Net::ProxyConfiguration &conf2)
|
||||
{
|
||||
return conf1.type == conf2.type
|
||||
&& conf1.ip == conf2.ip
|
||||
&& conf1.port == conf2.port
|
||||
&& conf1.username == conf2.username
|
||||
&& conf1.password == conf2.password;
|
||||
}
|
||||
}
|
||||
|
||||
using namespace Net;
|
||||
|
||||
ProxyConfigurationManager *ProxyConfigurationManager::m_instance = nullptr;
|
||||
|
||||
ProxyConfigurationManager::ProxyConfigurationManager(QObject *parent)
|
||||
: QObject(parent)
|
||||
{
|
||||
m_isProxyOnlyForTorrents = settings()->loadValue(KEY_ONLY_FOR_TORRENTS, false).toBool();
|
||||
m_config.type = static_cast<ProxyType>(
|
||||
settings()->loadValue(KEY_TYPE, static_cast<int>(ProxyType::None)).toInt());
|
||||
if ((m_config.type < ProxyType::None) || (m_config.type > ProxyType::SOCKS4))
|
||||
m_config.type = ProxyType::None;
|
||||
m_config.ip = settings()->loadValue(KEY_IP, "0.0.0.0").toString();
|
||||
m_config.port = static_cast<ushort>(settings()->loadValue(KEY_PORT, 8080).toUInt());
|
||||
m_config.username = settings()->loadValue(KEY_USERNAME).toString();
|
||||
m_config.password = settings()->loadValue(KEY_PASSWORD).toString();
|
||||
configureProxy();
|
||||
}
|
||||
|
||||
void ProxyConfigurationManager::initInstance()
|
||||
{
|
||||
if (!m_instance)
|
||||
m_instance = new ProxyConfigurationManager;
|
||||
}
|
||||
|
||||
void ProxyConfigurationManager::freeInstance()
|
||||
{
|
||||
if (m_instance) {
|
||||
delete m_instance;
|
||||
m_instance = 0;
|
||||
}
|
||||
}
|
||||
|
||||
ProxyConfigurationManager *ProxyConfigurationManager::instance()
|
||||
{
|
||||
return m_instance;
|
||||
}
|
||||
|
||||
ProxyConfiguration ProxyConfigurationManager::proxyConfiguration() const
|
||||
{
|
||||
return m_config;
|
||||
}
|
||||
|
||||
void ProxyConfigurationManager::setProxyConfiguration(const ProxyConfiguration &config)
|
||||
{
|
||||
if (!isSameConfig(config, m_config)) {
|
||||
m_config = config;
|
||||
settings()->storeValue(KEY_TYPE, static_cast<int>(config.type));
|
||||
settings()->storeValue(KEY_IP, config.ip);
|
||||
settings()->storeValue(KEY_PORT, config.port);
|
||||
settings()->storeValue(KEY_USERNAME, config.username);
|
||||
settings()->storeValue(KEY_PASSWORD, config.password);
|
||||
configureProxy();
|
||||
|
||||
emit proxyConfigurationChanged();
|
||||
}
|
||||
}
|
||||
|
||||
bool ProxyConfigurationManager::isProxyOnlyForTorrents() const
|
||||
{
|
||||
return m_isProxyOnlyForTorrents || (m_config.type == ProxyType::SOCKS4);
|
||||
}
|
||||
|
||||
void ProxyConfigurationManager::setProxyOnlyForTorrents(bool onlyForTorrents)
|
||||
{
|
||||
if (m_isProxyOnlyForTorrents != onlyForTorrents) {
|
||||
settings()->storeValue(KEY_ONLY_FOR_TORRENTS, onlyForTorrents);
|
||||
m_isProxyOnlyForTorrents = onlyForTorrents;
|
||||
}
|
||||
}
|
||||
|
||||
bool ProxyConfigurationManager::isAuthenticationRequired() const
|
||||
{
|
||||
return m_config.type == ProxyType::SOCKS5_PW
|
||||
|| m_config.type == ProxyType::HTTP_PW;
|
||||
}
|
||||
|
||||
void ProxyConfigurationManager::configureProxy()
|
||||
{
|
||||
// Define environment variables for urllib in search engine plugins
|
||||
QString proxyStrHTTP, proxyStrSOCK;
|
||||
if (!m_isProxyOnlyForTorrents) {
|
||||
switch (m_config.type) {
|
||||
case ProxyType::HTTP_PW:
|
||||
proxyStrHTTP = QString("http://%1:%2@%3:%4").arg(m_config.username)
|
||||
.arg(m_config.password).arg(m_config.ip).arg(m_config.port);
|
||||
break;
|
||||
case ProxyType::HTTP:
|
||||
proxyStrHTTP = QString("http://%1:%2").arg(m_config.ip).arg(m_config.port);
|
||||
break;
|
||||
case ProxyType::SOCKS5:
|
||||
proxyStrSOCK = QString("%1:%2").arg(m_config.ip).arg(m_config.port);
|
||||
break;
|
||||
case ProxyType::SOCKS5_PW:
|
||||
proxyStrSOCK = QString("%1:%2@%3:%4").arg(m_config.username)
|
||||
.arg(m_config.password).arg(m_config.ip).arg(m_config.port);
|
||||
break;
|
||||
default:
|
||||
qDebug("Disabling HTTP communications proxy");
|
||||
}
|
||||
|
||||
qDebug("HTTP communications proxy string: %s"
|
||||
, qPrintable((m_config.type == ProxyType::SOCKS5) || (m_config.type == ProxyType::SOCKS5_PW)
|
||||
? proxyStrSOCK : proxyStrHTTP));
|
||||
}
|
||||
|
||||
qputenv("http_proxy", proxyStrHTTP.toLocal8Bit());
|
||||
qputenv("https_proxy", proxyStrHTTP.toLocal8Bit());
|
||||
qputenv("sock_proxy", proxyStrSOCK.toLocal8Bit());
|
||||
}
|
||||
87
src/base/net/proxyconfigurationmanager.h
Normal file
@@ -0,0 +1,87 @@
|
||||
/*
|
||||
* Bittorrent Client using Qt and libtorrent.
|
||||
* Copyright (C) 2016 Vladimir Golovnev <glassez@yandex.ru>
|
||||
*
|
||||
* 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 NET_PROXYCONFIGURATIONMANAGER_H
|
||||
#define NET_PROXYCONFIGURATIONMANAGER_H
|
||||
|
||||
#include <QObject>
|
||||
|
||||
namespace Net
|
||||
{
|
||||
enum class ProxyType
|
||||
{
|
||||
None = 0,
|
||||
HTTP = 1,
|
||||
SOCKS5 = 2,
|
||||
HTTP_PW = 3,
|
||||
SOCKS5_PW = 4,
|
||||
SOCKS4 = 5
|
||||
};
|
||||
|
||||
struct ProxyConfiguration
|
||||
{
|
||||
ProxyType type = ProxyType::None;
|
||||
QString ip = "0.0.0.0";
|
||||
ushort port = 8080;
|
||||
QString username;
|
||||
QString password;
|
||||
};
|
||||
|
||||
class ProxyConfigurationManager: public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
Q_DISABLE_COPY(ProxyConfigurationManager)
|
||||
|
||||
explicit ProxyConfigurationManager(QObject *parent = nullptr);
|
||||
~ProxyConfigurationManager() = default;
|
||||
|
||||
public:
|
||||
static void initInstance();
|
||||
static void freeInstance();
|
||||
static ProxyConfigurationManager *instance();
|
||||
|
||||
ProxyConfiguration proxyConfiguration() const;
|
||||
void setProxyConfiguration(const ProxyConfiguration &config);
|
||||
bool isProxyOnlyForTorrents() const;
|
||||
void setProxyOnlyForTorrents(bool onlyForTorrents);
|
||||
|
||||
bool isAuthenticationRequired() const;
|
||||
|
||||
signals:
|
||||
void proxyConfigurationChanged();
|
||||
|
||||
private:
|
||||
void configureProxy();
|
||||
|
||||
static ProxyConfigurationManager *m_instance;
|
||||
ProxyConfiguration m_config;
|
||||
bool m_isProxyOnlyForTorrents;
|
||||
};
|
||||
}
|
||||
|
||||
#endif // NET_PROXYCONFIGURATIONMANAGER_H
|
||||
@@ -53,7 +53,9 @@
|
||||
namespace
|
||||
{
|
||||
const short DEFAULT_PORT = 25;
|
||||
#ifndef QT_NO_OPENSSL
|
||||
const short DEFAULT_PORT_SSL = 465;
|
||||
#endif
|
||||
|
||||
QByteArray hmacMD5(QByteArray key, const QByteArray &msg)
|
||||
{
|
||||
@@ -98,12 +100,12 @@ Smtp::Smtp(QObject *parent)
|
||||
, m_authType(AuthPlain)
|
||||
{
|
||||
static bool needToRegisterMetaType = true;
|
||||
|
||||
|
||||
if (needToRegisterMetaType) {
|
||||
qRegisterMetaType<QAbstractSocket::SocketError>();
|
||||
needToRegisterMetaType = false;
|
||||
}
|
||||
|
||||
|
||||
#ifndef QT_NO_OPENSSL
|
||||
m_socket = new QSslSocket(this);
|
||||
#else
|
||||
|
||||
@@ -31,8 +31,9 @@
|
||||
*/
|
||||
|
||||
#include <QCryptographicHash>
|
||||
#include <QPair>
|
||||
#include <QDir>
|
||||
#include <QLocale>
|
||||
#include <QPair>
|
||||
#include <QSettings>
|
||||
|
||||
#ifndef DISABLE_GUI
|
||||
@@ -50,8 +51,6 @@
|
||||
#include <CoreServices/CoreServices.h>
|
||||
#endif
|
||||
|
||||
#include <cstdlib>
|
||||
|
||||
#include "utils/fs.h"
|
||||
#include "utils/misc.h"
|
||||
#include "settingsstorage.h"
|
||||
@@ -60,10 +59,7 @@
|
||||
|
||||
Preferences* Preferences::m_instance = 0;
|
||||
|
||||
Preferences::Preferences()
|
||||
: m_randomPort(rand() % 64512 + 1024)
|
||||
{
|
||||
}
|
||||
Preferences::Preferences() {}
|
||||
|
||||
Preferences *Preferences::instance()
|
||||
{
|
||||
@@ -97,7 +93,7 @@ void Preferences::setValue(const QString &key, const QVariant &value)
|
||||
// General options
|
||||
QString Preferences::getLocale() const
|
||||
{
|
||||
return value("Preferences/General/Locale").toString();
|
||||
return value("Preferences/General/Locale", QLocale::system().name()).toString();
|
||||
}
|
||||
|
||||
void Preferences::setLocale(const QString &locale)
|
||||
@@ -165,16 +161,6 @@ void Preferences::setHideZeroComboValues(int n)
|
||||
setValue("Preferences/General/HideZeroComboValues", n);
|
||||
}
|
||||
|
||||
bool Preferences::useRandomPort() const
|
||||
{
|
||||
return value("Preferences/General/UseRandomPort", false).toBool();
|
||||
}
|
||||
|
||||
void Preferences::setRandomPort(bool b)
|
||||
{
|
||||
setValue("Preferences/General/UseRandomPort", b);
|
||||
}
|
||||
|
||||
bool Preferences::systrayIntegration() const
|
||||
{
|
||||
return value("Preferences/General/SystrayEnabled", true).toBool();
|
||||
@@ -267,16 +253,6 @@ void Preferences::setWinStartup(bool b)
|
||||
#endif
|
||||
|
||||
// Downloads
|
||||
bool Preferences::useIncompleteFilesExtension() const
|
||||
{
|
||||
return value("Preferences/Downloads/UseIncompleteExtension", false).toBool();
|
||||
}
|
||||
|
||||
void Preferences::useIncompleteFilesExtension(bool enabled)
|
||||
{
|
||||
setValue("Preferences/Downloads/UseIncompleteExtension", enabled);
|
||||
}
|
||||
|
||||
QString Preferences::lastLocationPath() const
|
||||
{
|
||||
return Utils::Fs::fromNativePath(value("Preferences/Downloads/LastLocationPath").toString());
|
||||
@@ -287,16 +263,6 @@ void Preferences::setLastLocationPath(const QString &path)
|
||||
setValue("Preferences/Downloads/LastLocationPath", Utils::Fs::fromNativePath(path));
|
||||
}
|
||||
|
||||
bool Preferences::preAllocateAllFiles() const
|
||||
{
|
||||
return value("Preferences/Downloads/PreAllocation", false).toBool();
|
||||
}
|
||||
|
||||
void Preferences::preAllocateAllFiles(bool enabled)
|
||||
{
|
||||
return setValue("Preferences/Downloads/PreAllocation", enabled);
|
||||
}
|
||||
|
||||
QVariantHash Preferences::getScanDirs() const
|
||||
{
|
||||
return value("Preferences/Downloads/ScanDirsV2").toHash();
|
||||
@@ -318,36 +284,6 @@ void Preferences::setScanDirsLastPath(const QString &path)
|
||||
setValue("Preferences/Downloads/ScanDirsLastPath", Utils::Fs::fromNativePath(path));
|
||||
}
|
||||
|
||||
bool Preferences::isTorrentExportEnabled() const
|
||||
{
|
||||
return !value("Preferences/Downloads/TorrentExportDir").toString().isEmpty();
|
||||
}
|
||||
|
||||
QString Preferences::getTorrentExportDir() const
|
||||
{
|
||||
return Utils::Fs::fromNativePath(value("Preferences/Downloads/TorrentExportDir").toString());
|
||||
}
|
||||
|
||||
void Preferences::setTorrentExportDir(QString path)
|
||||
{
|
||||
setValue("Preferences/Downloads/TorrentExportDir", Utils::Fs::fromNativePath(path.trimmed()));
|
||||
}
|
||||
|
||||
bool Preferences::isFinishedTorrentExportEnabled() const
|
||||
{
|
||||
return !value("Preferences/Downloads/FinishedTorrentExportDir").toString().isEmpty();
|
||||
}
|
||||
|
||||
QString Preferences::getFinishedTorrentExportDir() const
|
||||
{
|
||||
return Utils::Fs::fromNativePath(value("Preferences/Downloads/FinishedTorrentExportDir").toString());
|
||||
}
|
||||
|
||||
void Preferences::setFinishedTorrentExportDir(QString path)
|
||||
{
|
||||
setValue("Preferences/Downloads/FinishedTorrentExportDir", Utils::Fs::fromNativePath(path.trimmed()));
|
||||
}
|
||||
|
||||
bool Preferences::isMailNotificationEnabled() const
|
||||
{
|
||||
return value("Preferences/MailNotification/enabled", false).toBool();
|
||||
@@ -438,97 +374,6 @@ void Preferences::setActionOnDblClOnTorrentFn(int act)
|
||||
setValue("Preferences/Downloads/DblClOnTorFn", act);
|
||||
}
|
||||
|
||||
// Connection options
|
||||
int Preferences::getSessionPort() const
|
||||
{
|
||||
if (useRandomPort())
|
||||
return m_randomPort;
|
||||
return value("Preferences/Connection/PortRangeMin", 8999).toInt();
|
||||
}
|
||||
|
||||
void Preferences::setSessionPort(int port)
|
||||
{
|
||||
setValue("Preferences/Connection/PortRangeMin", port);
|
||||
}
|
||||
|
||||
bool Preferences::isUPnPEnabled() const
|
||||
{
|
||||
return value("Preferences/Connection/UPnP", true).toBool();
|
||||
}
|
||||
|
||||
void Preferences::setUPnPEnabled(bool enabled)
|
||||
{
|
||||
setValue("Preferences/Connection/UPnP", enabled);
|
||||
}
|
||||
|
||||
int Preferences::getGlobalDownloadLimit() const
|
||||
{
|
||||
return value("Preferences/Connection/GlobalDLLimit", -1).toInt();
|
||||
}
|
||||
|
||||
void Preferences::setGlobalDownloadLimit(int limit)
|
||||
{
|
||||
if (limit <= 0)
|
||||
limit = -1;
|
||||
setValue("Preferences/Connection/GlobalDLLimit", limit);
|
||||
}
|
||||
|
||||
int Preferences::getGlobalUploadLimit() const
|
||||
{
|
||||
return value("Preferences/Connection/GlobalUPLimit", -1).toInt();
|
||||
}
|
||||
|
||||
void Preferences::setGlobalUploadLimit(int limit)
|
||||
{
|
||||
if (limit <= 0)
|
||||
limit = -1;
|
||||
setValue("Preferences/Connection/GlobalUPLimit", limit);
|
||||
}
|
||||
|
||||
int Preferences::getAltGlobalDownloadLimit() const
|
||||
{
|
||||
return value("Preferences/Connection/GlobalDLLimitAlt", 10).toInt();
|
||||
}
|
||||
|
||||
void Preferences::setAltGlobalDownloadLimit(int limit)
|
||||
{
|
||||
if (limit <= 0)
|
||||
limit = -1;
|
||||
setValue("Preferences/Connection/GlobalDLLimitAlt", limit);
|
||||
}
|
||||
|
||||
int Preferences::getAltGlobalUploadLimit() const
|
||||
{
|
||||
return value("Preferences/Connection/GlobalUPLimitAlt", 10).toInt();
|
||||
}
|
||||
|
||||
void Preferences::setAltGlobalUploadLimit(int limit)
|
||||
{
|
||||
if (limit <= 0)
|
||||
limit = -1;
|
||||
setValue("Preferences/Connection/GlobalUPLimitAlt", limit);
|
||||
}
|
||||
|
||||
bool Preferences::isAltBandwidthEnabled() const
|
||||
{
|
||||
return value("Preferences/Connection/alt_speeds_on", false).toBool();
|
||||
}
|
||||
|
||||
void Preferences::setAltBandwidthEnabled(bool enabled)
|
||||
{
|
||||
setValue("Preferences/Connection/alt_speeds_on", enabled);
|
||||
}
|
||||
|
||||
bool Preferences::isSchedulerEnabled() const
|
||||
{
|
||||
return value("Preferences/Scheduler/Enabled", false).toBool();
|
||||
}
|
||||
|
||||
void Preferences::setSchedulerEnabled(bool enabled)
|
||||
{
|
||||
setValue("Preferences/Scheduler/Enabled", enabled);
|
||||
}
|
||||
|
||||
QTime Preferences::getSchedulerStartTime() const
|
||||
{
|
||||
return value("Preferences/Scheduler/start_time", QTime(8,0)).toTime();
|
||||
@@ -559,286 +404,6 @@ void Preferences::setSchedulerDays(scheduler_days days)
|
||||
setValue("Preferences/Scheduler/days", (int)days);
|
||||
}
|
||||
|
||||
// Proxy options
|
||||
bool Preferences::isProxyEnabled() const
|
||||
{
|
||||
return getProxyType() > 0;
|
||||
}
|
||||
|
||||
bool Preferences::isProxyAuthEnabled() const
|
||||
{
|
||||
return value("Preferences/Connection/Proxy/Authentication", false).toBool();
|
||||
}
|
||||
|
||||
void Preferences::setProxyAuthEnabled(bool enabled)
|
||||
{
|
||||
setValue("Preferences/Connection/Proxy/Authentication", enabled);
|
||||
}
|
||||
|
||||
QString Preferences::getProxyIp() const
|
||||
{
|
||||
return value("Preferences/Connection/Proxy/IP", "0.0.0.0").toString();
|
||||
}
|
||||
|
||||
void Preferences::setProxyIp(const QString &ip)
|
||||
{
|
||||
setValue("Preferences/Connection/Proxy/IP", ip);
|
||||
}
|
||||
|
||||
unsigned short Preferences::getProxyPort() const
|
||||
{
|
||||
return value("Preferences/Connection/Proxy/Port", 8080).toInt();
|
||||
}
|
||||
|
||||
void Preferences::setProxyPort(unsigned short port)
|
||||
{
|
||||
setValue("Preferences/Connection/Proxy/Port", port);
|
||||
}
|
||||
|
||||
QString Preferences::getProxyUsername() const
|
||||
{
|
||||
return value("Preferences/Connection/Proxy/Username").toString();
|
||||
}
|
||||
|
||||
void Preferences::setProxyUsername(const QString &username)
|
||||
{
|
||||
setValue("Preferences/Connection/Proxy/Username", username);
|
||||
}
|
||||
|
||||
QString Preferences::getProxyPassword() const
|
||||
{
|
||||
return value("Preferences/Connection/Proxy/Password").toString();
|
||||
}
|
||||
|
||||
void Preferences::setProxyPassword(const QString &password)
|
||||
{
|
||||
setValue("Preferences/Connection/Proxy/Password", password);
|
||||
}
|
||||
|
||||
int Preferences::getProxyType() const
|
||||
{
|
||||
return value("Preferences/Connection/ProxyType", 0).toInt();
|
||||
}
|
||||
|
||||
void Preferences::setProxyType(int type)
|
||||
{
|
||||
setValue("Preferences/Connection/ProxyType", type);
|
||||
}
|
||||
|
||||
bool Preferences::proxyPeerConnections() const
|
||||
{
|
||||
return value("Preferences/Connection/ProxyPeerConnections", false).toBool();
|
||||
}
|
||||
|
||||
void Preferences::setProxyPeerConnections(bool enabled)
|
||||
{
|
||||
setValue("Preferences/Connection/ProxyPeerConnections", enabled);
|
||||
}
|
||||
|
||||
bool Preferences::getForceProxy() const
|
||||
{
|
||||
return value("Preferences/Connection/ProxyForce", true).toBool();
|
||||
}
|
||||
|
||||
void Preferences::setForceProxy(bool enabled)
|
||||
{
|
||||
setValue("Preferences/Connection/ProxyForce", enabled);
|
||||
}
|
||||
|
||||
void Preferences::setProxyOnlyForTorrents(bool enabled)
|
||||
{
|
||||
setValue("Preferences/Connection/ProxyOnlyForTorrents", enabled);
|
||||
}
|
||||
|
||||
bool Preferences::isProxyOnlyForTorrents() const
|
||||
{
|
||||
return value("Preferences/Connection/ProxyOnlyForTorrents", false).toBool();
|
||||
}
|
||||
|
||||
// Bittorrent options
|
||||
int Preferences::getMaxConnecs() const
|
||||
{
|
||||
return value("Preferences/Bittorrent/MaxConnecs", 500).toInt();
|
||||
}
|
||||
|
||||
void Preferences::setMaxConnecs(int val)
|
||||
{
|
||||
if (val <= 0)
|
||||
val = -1;
|
||||
setValue("Preferences/Bittorrent/MaxConnecs", val);
|
||||
}
|
||||
|
||||
int Preferences::getMaxConnecsPerTorrent() const
|
||||
{
|
||||
return value("Preferences/Bittorrent/MaxConnecsPerTorrent", 100).toInt();
|
||||
}
|
||||
|
||||
void Preferences::setMaxConnecsPerTorrent(int val)
|
||||
{
|
||||
if (val <= 0)
|
||||
val = -1;
|
||||
setValue("Preferences/Bittorrent/MaxConnecsPerTorrent", val);
|
||||
}
|
||||
|
||||
int Preferences::getMaxUploads() const
|
||||
{
|
||||
return value("Preferences/Bittorrent/MaxUploads", -1).toInt();
|
||||
}
|
||||
|
||||
void Preferences::setMaxUploads(int val)
|
||||
{
|
||||
if (val <= 0)
|
||||
val = -1;
|
||||
setValue("Preferences/Bittorrent/MaxUploads", val);
|
||||
}
|
||||
|
||||
int Preferences::getMaxUploadsPerTorrent() const
|
||||
{
|
||||
return value("Preferences/Bittorrent/MaxUploadsPerTorrent", -1).toInt();
|
||||
}
|
||||
|
||||
void Preferences::setMaxUploadsPerTorrent(int val)
|
||||
{
|
||||
if (val <= 0)
|
||||
val = -1;
|
||||
setValue("Preferences/Bittorrent/MaxUploadsPerTorrent", val);
|
||||
}
|
||||
|
||||
bool Preferences::isuTPEnabled() const
|
||||
{
|
||||
return value("Preferences/Bittorrent/uTP", true).toBool();
|
||||
}
|
||||
|
||||
void Preferences::setuTPEnabled(bool enabled)
|
||||
{
|
||||
setValue("Preferences/Bittorrent/uTP", enabled);
|
||||
}
|
||||
|
||||
bool Preferences::isuTPRateLimited() const
|
||||
{
|
||||
return value("Preferences/Bittorrent/uTP_rate_limited", true).toBool();
|
||||
}
|
||||
|
||||
void Preferences::setuTPRateLimited(bool enabled)
|
||||
{
|
||||
setValue("Preferences/Bittorrent/uTP_rate_limited", enabled);
|
||||
}
|
||||
|
||||
bool Preferences::isDHTEnabled() const
|
||||
{
|
||||
return value("Preferences/Bittorrent/DHT", true).toBool();
|
||||
}
|
||||
|
||||
void Preferences::setDHTEnabled(bool enabled)
|
||||
{
|
||||
setValue("Preferences/Bittorrent/DHT", enabled);
|
||||
}
|
||||
|
||||
bool Preferences::isPeXEnabled() const
|
||||
{
|
||||
return value("Preferences/Bittorrent/PeX", true).toBool();
|
||||
}
|
||||
|
||||
void Preferences::setPeXEnabled(bool enabled)
|
||||
{
|
||||
setValue("Preferences/Bittorrent/PeX", enabled);
|
||||
}
|
||||
|
||||
bool Preferences::isLSDEnabled() const
|
||||
{
|
||||
return value("Preferences/Bittorrent/LSD", true).toBool();
|
||||
}
|
||||
|
||||
void Preferences::setLSDEnabled(bool enabled)
|
||||
{
|
||||
setValue("Preferences/Bittorrent/LSD", enabled);
|
||||
}
|
||||
|
||||
int Preferences::getEncryptionSetting() const
|
||||
{
|
||||
return value("Preferences/Bittorrent/Encryption", 0).toInt();
|
||||
}
|
||||
|
||||
void Preferences::setEncryptionSetting(int val)
|
||||
{
|
||||
setValue("Preferences/Bittorrent/Encryption", val);
|
||||
}
|
||||
|
||||
bool Preferences::isAddTrackersEnabled() const
|
||||
{
|
||||
return value("Preferences/Bittorrent/AddTrackers", false).toBool();
|
||||
}
|
||||
|
||||
void Preferences::setAddTrackersEnabled(bool enabled)
|
||||
{
|
||||
setValue("Preferences/Bittorrent/AddTrackers", enabled);
|
||||
}
|
||||
|
||||
QString Preferences::getTrackersList() const
|
||||
{
|
||||
return value("Preferences/Bittorrent/TrackersList").toString();
|
||||
}
|
||||
|
||||
void Preferences::setTrackersList(const QString &val)
|
||||
{
|
||||
setValue("Preferences/Bittorrent/TrackersList", val);
|
||||
}
|
||||
|
||||
qreal Preferences::getGlobalMaxRatio() const
|
||||
{
|
||||
return value("Preferences/Bittorrent/MaxRatio", -1).toReal();
|
||||
}
|
||||
|
||||
void Preferences::setGlobalMaxRatio(qreal ratio)
|
||||
{
|
||||
setValue("Preferences/Bittorrent/MaxRatio", ratio);
|
||||
}
|
||||
|
||||
// IP Filter
|
||||
bool Preferences::isFilteringEnabled() const
|
||||
{
|
||||
return value("Preferences/IPFilter/Enabled", false).toBool();
|
||||
}
|
||||
|
||||
void Preferences::setFilteringEnabled(bool enabled)
|
||||
{
|
||||
setValue("Preferences/IPFilter/Enabled", enabled);
|
||||
}
|
||||
|
||||
bool Preferences::isFilteringTrackerEnabled() const
|
||||
{
|
||||
return value("Preferences/IPFilter/FilterTracker", false).toBool();
|
||||
}
|
||||
|
||||
void Preferences::setFilteringTrackerEnabled(bool enabled)
|
||||
{
|
||||
setValue("Preferences/IPFilter/FilterTracker", enabled);
|
||||
}
|
||||
|
||||
QString Preferences::getFilter() const
|
||||
{
|
||||
return Utils::Fs::fromNativePath(value("Preferences/IPFilter/File").toString());
|
||||
}
|
||||
|
||||
void Preferences::setFilter(const QString &path)
|
||||
{
|
||||
setValue("Preferences/IPFilter/File", Utils::Fs::fromNativePath(path));
|
||||
}
|
||||
|
||||
QStringList Preferences::bannedIPs() const
|
||||
{
|
||||
return value("Preferences/IPFilter/BannedIPs").toStringList();
|
||||
}
|
||||
|
||||
void Preferences::banIP(const QString &ip)
|
||||
{
|
||||
QStringList banned_ips = value("Preferences/IPFilter/BannedIPs").toStringList();
|
||||
if (!banned_ips.contains(ip)) {
|
||||
banned_ips << ip;
|
||||
setValue("Preferences/IPFilter/BannedIPs", banned_ips);
|
||||
}
|
||||
}
|
||||
|
||||
// Search
|
||||
bool Preferences::isSearchEnabled() const
|
||||
{
|
||||
@@ -850,63 +415,6 @@ void Preferences::setSearchEnabled(bool enabled)
|
||||
setValue("Preferences/Search/SearchEnabled", enabled);
|
||||
}
|
||||
|
||||
// Queueing system
|
||||
bool Preferences::isQueueingSystemEnabled() const
|
||||
{
|
||||
return value("Preferences/Queueing/QueueingEnabled", true).toBool();
|
||||
}
|
||||
|
||||
void Preferences::setQueueingSystemEnabled(bool enabled)
|
||||
{
|
||||
setValue("Preferences/Queueing/QueueingEnabled", enabled);
|
||||
}
|
||||
|
||||
int Preferences::getMaxActiveDownloads() const
|
||||
{
|
||||
return value("Preferences/Queueing/MaxActiveDownloads", 3).toInt();
|
||||
}
|
||||
|
||||
void Preferences::setMaxActiveDownloads(int val)
|
||||
{
|
||||
if (val < 0)
|
||||
val = -1;
|
||||
setValue("Preferences/Queueing/MaxActiveDownloads", val);
|
||||
}
|
||||
|
||||
int Preferences::getMaxActiveUploads() const
|
||||
{
|
||||
return value("Preferences/Queueing/MaxActiveUploads", 3).toInt();
|
||||
}
|
||||
|
||||
void Preferences::setMaxActiveUploads(int val)
|
||||
{
|
||||
if (val < 0)
|
||||
val = -1;
|
||||
setValue("Preferences/Queueing/MaxActiveUploads", val);
|
||||
}
|
||||
|
||||
int Preferences::getMaxActiveTorrents() const
|
||||
{
|
||||
return value("Preferences/Queueing/MaxActiveTorrents", 5).toInt();
|
||||
}
|
||||
|
||||
void Preferences::setMaxActiveTorrents(int val)
|
||||
{
|
||||
if (val < 0)
|
||||
val = -1;
|
||||
setValue("Preferences/Queueing/MaxActiveTorrents", val);
|
||||
}
|
||||
|
||||
bool Preferences::ignoreSlowTorrentsForQueueing() const
|
||||
{
|
||||
return value("Preferences/Queueing/IgnoreSlowTorrents", false).toBool();
|
||||
}
|
||||
|
||||
void Preferences::setIgnoreSlowTorrentsForQueueing(bool ignore)
|
||||
{
|
||||
setValue("Preferences/Queueing/IgnoreSlowTorrents", ignore);
|
||||
}
|
||||
|
||||
bool Preferences::isWebUiEnabled() const
|
||||
{
|
||||
#ifdef DISABLE_GUI
|
||||
@@ -943,7 +451,11 @@ void Preferences::setWebUiPort(quint16 port)
|
||||
|
||||
bool Preferences::useUPnPForWebUIPort() const
|
||||
{
|
||||
#ifdef DISABLE_GUI
|
||||
return value("Preferences/WebUI/UseUPnP", true).toBool();
|
||||
#else
|
||||
return value("Preferences/WebUI/UseUPnP", false).toBool();
|
||||
#endif
|
||||
}
|
||||
|
||||
void Preferences::setUPnPForWebUIPort(bool enabled)
|
||||
@@ -1164,111 +676,6 @@ void Preferences::setDontConfirmAutoExit(bool dontConfirmAutoExit)
|
||||
setValue("ShutdownConfirmDlg/DontConfirmAutoExit", dontConfirmAutoExit);
|
||||
}
|
||||
|
||||
uint Preferences::diskCacheSize() const
|
||||
{
|
||||
uint size = value("Preferences/Downloads/DiskWriteCacheSize", 0).toUInt();
|
||||
// These macros may not be available on compilers other than MSVC and GCC
|
||||
#if defined(__x86_64__) || defined(_M_X64)
|
||||
size = qMin(size, (uint) 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, (uint) 1536);
|
||||
#endif
|
||||
return size;
|
||||
}
|
||||
|
||||
void Preferences::setDiskCacheSize(uint size)
|
||||
{
|
||||
#if defined(__x86_64__) || defined(_M_X64)
|
||||
size = qMin(size, (uint) 4096); // 4GiB
|
||||
#else
|
||||
// allocate 1536MiB and leave 512MiB to the rest of program data in RAM
|
||||
size = qMin(size, (uint) 1536);
|
||||
#endif
|
||||
setValue("Preferences/Downloads/DiskWriteCacheSize", size);
|
||||
}
|
||||
|
||||
uint Preferences::diskCacheTTL() const
|
||||
{
|
||||
return value("Preferences/Downloads/DiskWriteCacheTTL", 60).toUInt();
|
||||
}
|
||||
|
||||
void Preferences::setDiskCacheTTL(uint ttl)
|
||||
{
|
||||
setValue("Preferences/Downloads/DiskWriteCacheTTL", ttl);
|
||||
}
|
||||
|
||||
bool Preferences::osCache() const
|
||||
{
|
||||
return value("Preferences/Advanced/osCache", true).toBool();
|
||||
}
|
||||
|
||||
void Preferences::setOsCache(bool enable)
|
||||
{
|
||||
setValue("Preferences/Advanced/osCache", enable);
|
||||
}
|
||||
|
||||
uint Preferences::saveResumeDataInterval() const
|
||||
{
|
||||
return value("Preferences/Downloads/SaveResumeDataInterval", 3).toUInt();
|
||||
}
|
||||
|
||||
void Preferences::setSaveResumeDataInterval(uint m)
|
||||
{
|
||||
setValue("Preferences/Downloads/SaveResumeDataInterval", m);
|
||||
}
|
||||
|
||||
uint Preferences::outgoingPortsMin() const
|
||||
{
|
||||
return value("Preferences/Advanced/OutgoingPortsMin", 0).toUInt();
|
||||
}
|
||||
|
||||
void Preferences::setOutgoingPortsMin(uint val)
|
||||
{
|
||||
setValue("Preferences/Advanced/OutgoingPortsMin", val);
|
||||
}
|
||||
|
||||
uint Preferences::outgoingPortsMax() const
|
||||
{
|
||||
return value("Preferences/Advanced/OutgoingPortsMax", 0).toUInt();
|
||||
}
|
||||
|
||||
void Preferences::setOutgoingPortsMax(uint val)
|
||||
{
|
||||
setValue("Preferences/Advanced/OutgoingPortsMax", val);
|
||||
}
|
||||
|
||||
bool Preferences::getIgnoreLimitsOnLAN() const
|
||||
{
|
||||
return value("Preferences/Advanced/IgnoreLimitsLAN", true).toBool();
|
||||
}
|
||||
|
||||
void Preferences::setIgnoreLimitsOnLAN(bool ignore)
|
||||
{
|
||||
setValue("Preferences/Advanced/IgnoreLimitsLAN", ignore);
|
||||
}
|
||||
|
||||
bool Preferences::includeOverheadInLimits() const
|
||||
{
|
||||
return value("Preferences/Advanced/IncludeOverhead", false).toBool();
|
||||
}
|
||||
|
||||
void Preferences::includeOverheadInLimits(bool include)
|
||||
{
|
||||
setValue("Preferences/Advanced/IncludeOverhead", include);
|
||||
}
|
||||
|
||||
bool Preferences::trackerExchangeEnabled() const
|
||||
{
|
||||
return value("Preferences/Advanced/LtTrackerExchange", false).toBool();
|
||||
}
|
||||
|
||||
void Preferences::setTrackerExchangeEnabled(bool enable)
|
||||
{
|
||||
setValue("Preferences/Advanced/LtTrackerExchange", enable);
|
||||
}
|
||||
|
||||
bool Preferences::recheckTorrentsOnCompletion() const
|
||||
{
|
||||
return value("Preferences/Advanced/RecheckOnCompletion", false).toBool();
|
||||
@@ -1279,16 +686,6 @@ void Preferences::recheckTorrentsOnCompletion(bool recheck)
|
||||
setValue("Preferences/Advanced/RecheckOnCompletion", recheck);
|
||||
}
|
||||
|
||||
unsigned int Preferences::getRefreshInterval() const
|
||||
{
|
||||
return value("Preferences/General/RefreshInterval", 1500).toUInt();
|
||||
}
|
||||
|
||||
void Preferences::setRefreshInterval(uint interval)
|
||||
{
|
||||
setValue("Preferences/General/RefreshInterval", interval);
|
||||
}
|
||||
|
||||
bool Preferences::resolvePeerCountries() const
|
||||
{
|
||||
return value("Preferences/Connection/ResolvePeerCountries", true).toBool();
|
||||
@@ -1309,101 +706,6 @@ void Preferences::resolvePeerHostNames(bool resolve)
|
||||
setValue("Preferences/Connection/ResolvePeerHostNames", resolve);
|
||||
}
|
||||
|
||||
int Preferences::getMaxHalfOpenConnections() const
|
||||
{
|
||||
const int val = value("Preferences/Connection/MaxHalfOpenConnec", 20).toInt();
|
||||
if (val <= 0)
|
||||
return -1;
|
||||
return val;
|
||||
}
|
||||
|
||||
void Preferences::setMaxHalfOpenConnections(int value)
|
||||
{
|
||||
if (value <= 0)
|
||||
value = -1;
|
||||
setValue("Preferences/Connection/MaxHalfOpenConnec", value);
|
||||
}
|
||||
|
||||
QString Preferences::getNetworkInterface() const
|
||||
{
|
||||
return value("Preferences/Connection/Interface").toString();
|
||||
}
|
||||
|
||||
void Preferences::setNetworkInterface(const QString& iface)
|
||||
{
|
||||
setValue("Preferences/Connection/Interface", iface);
|
||||
}
|
||||
|
||||
QString Preferences::getNetworkInterfaceName() const
|
||||
{
|
||||
return value("Preferences/Connection/InterfaceName").toString();
|
||||
}
|
||||
|
||||
void Preferences::setNetworkInterfaceName(const QString& iface)
|
||||
{
|
||||
setValue("Preferences/Connection/InterfaceName", iface);
|
||||
}
|
||||
|
||||
void Preferences::setNetworkInterfaceAddress(const QString& addr)
|
||||
{
|
||||
setValue("Preferences/Connection/InterfaceAddress", addr);
|
||||
}
|
||||
|
||||
QString Preferences::getNetworkInterfaceAddress() const
|
||||
{
|
||||
return value("Preferences/Connection/InterfaceAddress").toString();
|
||||
}
|
||||
|
||||
bool Preferences::getListenIPv6() const
|
||||
{
|
||||
return value("Preferences/Connection/InterfaceListenIPv6", false).toBool();
|
||||
}
|
||||
|
||||
void Preferences::setListenIPv6(bool enable)
|
||||
{
|
||||
setValue("Preferences/Connection/InterfaceListenIPv6", enable);
|
||||
}
|
||||
|
||||
QString Preferences::getNetworkAddress() const
|
||||
{
|
||||
return value("Preferences/Connection/InetAddress").toString();
|
||||
}
|
||||
|
||||
void Preferences::setNetworkAddress(const QString& addr)
|
||||
{
|
||||
setValue("Preferences/Connection/InetAddress", addr);
|
||||
}
|
||||
|
||||
bool Preferences::isAnonymousModeEnabled() const
|
||||
{
|
||||
return value("Preferences/Advanced/AnonymousMode", false).toBool();
|
||||
}
|
||||
|
||||
void Preferences::enableAnonymousMode(bool enabled)
|
||||
{
|
||||
setValue("Preferences/Advanced/AnonymousMode", enabled);
|
||||
}
|
||||
|
||||
bool Preferences::isSuperSeedingEnabled() const
|
||||
{
|
||||
return value("Preferences/Advanced/SuperSeeding", false).toBool();
|
||||
}
|
||||
|
||||
void Preferences::enableSuperSeeding(bool enabled)
|
||||
{
|
||||
setValue("Preferences/Advanced/SuperSeeding", enabled);
|
||||
}
|
||||
|
||||
bool Preferences::announceToAllTrackers() const
|
||||
{
|
||||
return value("Preferences/Advanced/AnnounceToAllTrackers", true).toBool();
|
||||
}
|
||||
|
||||
void Preferences::setAnnounceToAllTrackers(bool enabled)
|
||||
{
|
||||
setValue("Preferences/Advanced/AnnounceToAllTrackers", enabled);
|
||||
}
|
||||
|
||||
#if (defined(Q_OS_UNIX) && !defined(Q_OS_MAC))
|
||||
bool Preferences::useSystemIconTheme() const
|
||||
{
|
||||
@@ -1710,16 +1012,6 @@ void Preferences::setMagnetLinkAssoc()
|
||||
}
|
||||
#endif
|
||||
|
||||
bool Preferences::isTrackerEnabled() const
|
||||
{
|
||||
return value("Preferences/Advanced/trackerEnabled", false).toBool();
|
||||
}
|
||||
|
||||
void Preferences::setTrackerEnabled(bool enabled)
|
||||
{
|
||||
setValue("Preferences/Advanced/trackerEnabled", enabled);
|
||||
}
|
||||
|
||||
int Preferences::getTrackerPort() const
|
||||
{
|
||||
return value("Preferences/Advanced/trackerPort", 9000).toInt();
|
||||
@@ -1997,7 +1289,7 @@ void Preferences::setRssOpenFolders(const QStringList &folders)
|
||||
setValue("Rss/open_folders", folders);
|
||||
}
|
||||
|
||||
QByteArray Preferences::getRssHSplitterState() const
|
||||
QByteArray Preferences::getRssSideSplitterState() const
|
||||
{
|
||||
#ifdef QBT_USES_QT5
|
||||
return value("Rss/qt5/splitter_h").toByteArray();
|
||||
@@ -2006,7 +1298,7 @@ QByteArray Preferences::getRssHSplitterState() const
|
||||
#endif
|
||||
}
|
||||
|
||||
void Preferences::setRssHSplitterState(const QByteArray &state)
|
||||
void Preferences::setRssSideSplitterState(const QByteArray &state)
|
||||
{
|
||||
#ifdef QBT_USES_QT5
|
||||
setValue("Rss/qt5/splitter_h", state);
|
||||
@@ -2015,32 +1307,40 @@ void Preferences::setRssHSplitterState(const QByteArray &state)
|
||||
#endif
|
||||
}
|
||||
|
||||
QByteArray Preferences::getRssVSplitterState() const
|
||||
QByteArray Preferences::getRssMainSplitterState() const
|
||||
{
|
||||
#ifdef QBT_USES_QT5
|
||||
return value("Rss/qt5/splitter_v").toByteArray();
|
||||
return value("Rss/qt5/splitterMain").toByteArray();
|
||||
#else
|
||||
return value("Rss/splitter_v").toByteArray();
|
||||
return value("Rss/splitterMain").toByteArray();
|
||||
#endif
|
||||
}
|
||||
|
||||
void Preferences::setRssVSplitterState(const QByteArray &state)
|
||||
void Preferences::setRssMainSplitterState(const QByteArray &state)
|
||||
{
|
||||
#ifdef QBT_USES_QT5
|
||||
setValue("Rss/qt5/splitter_v", state);
|
||||
setValue("Rss/qt5/splitterMain", state);
|
||||
#else
|
||||
setValue("Rss/splitter_v", state);
|
||||
setValue("Rss/splitterMain", state);
|
||||
#endif
|
||||
}
|
||||
|
||||
QString Preferences::getSearchColsWidth() const
|
||||
QByteArray Preferences::getSearchTabHeaderState() const
|
||||
{
|
||||
return value("SearchResultsColsWidth").toString();
|
||||
#ifdef QBT_USES_QT5
|
||||
return value("SearchTab/qt5/HeaderState").toByteArray();
|
||||
#else
|
||||
return value("SearchTab/HeaderState").toByteArray();
|
||||
#endif
|
||||
}
|
||||
|
||||
void Preferences::setSearchColsWidth(const QString &width)
|
||||
void Preferences::setSearchTabHeaderState(const QByteArray &state)
|
||||
{
|
||||
setValue("SearchResultsColsWidth", width);
|
||||
#ifdef QBT_USES_QT5
|
||||
setValue("SearchTab/qt5/HeaderState", state);
|
||||
#else
|
||||
setValue("SearchTab/HeaderState", state);
|
||||
#endif
|
||||
}
|
||||
|
||||
QStringList Preferences::getSearchEngDisabled() const
|
||||
|
||||
@@ -57,18 +57,6 @@ enum scheduler_days
|
||||
SUN
|
||||
};
|
||||
|
||||
namespace Proxy
|
||||
{
|
||||
enum ProxyType
|
||||
{
|
||||
HTTP = 1,
|
||||
SOCKS5 = 2,
|
||||
HTTP_PW = 3,
|
||||
SOCKS5_PW = 4,
|
||||
SOCKS4 = 5
|
||||
};
|
||||
}
|
||||
|
||||
namespace TrayIcon
|
||||
{
|
||||
enum Style
|
||||
@@ -102,7 +90,6 @@ class Preferences: public QObject
|
||||
void setValue(const QString &key, const QVariant &value);
|
||||
|
||||
static Preferences* m_instance;
|
||||
int m_randomPort;
|
||||
|
||||
signals:
|
||||
void changed();
|
||||
@@ -127,8 +114,6 @@ public:
|
||||
void setHideZeroValues(bool b);
|
||||
int getHideZeroComboValues() const;
|
||||
void setHideZeroComboValues(int n);
|
||||
bool useRandomPort() const;
|
||||
void setRandomPort(bool b);
|
||||
bool systrayIntegration() const;
|
||||
void setSystrayIntegration(bool enabled);
|
||||
bool isToolbarDisplayed() const;
|
||||
@@ -149,22 +134,12 @@ public:
|
||||
#endif
|
||||
|
||||
// Downloads
|
||||
bool useIncompleteFilesExtension() const;
|
||||
void useIncompleteFilesExtension(bool enabled);
|
||||
QString lastLocationPath() const;
|
||||
void setLastLocationPath(const QString &path);
|
||||
bool preAllocateAllFiles() const;
|
||||
void preAllocateAllFiles(bool enabled);
|
||||
QVariantHash getScanDirs() const;
|
||||
void setScanDirs(const QVariantHash &dirs);
|
||||
QString getScanDirsLastPath() const;
|
||||
void setScanDirsLastPath(const QString &path);
|
||||
bool isTorrentExportEnabled() const;
|
||||
QString getTorrentExportDir() const;
|
||||
void setTorrentExportDir(QString path);
|
||||
bool isFinishedTorrentExportEnabled() const;
|
||||
QString getFinishedTorrentExportDir() const;
|
||||
void setFinishedTorrentExportDir(QString path);
|
||||
bool isMailNotificationEnabled() const;
|
||||
void setMailNotificationEnabled(bool enabled);
|
||||
QString getMailNotificationEmail() const;
|
||||
@@ -185,22 +160,6 @@ public:
|
||||
void setActionOnDblClOnTorrentFn(int act);
|
||||
|
||||
// Connection options
|
||||
int getSessionPort() const;
|
||||
void setSessionPort(int port);
|
||||
bool isUPnPEnabled() const;
|
||||
void setUPnPEnabled(bool enabled);
|
||||
int getGlobalDownloadLimit() const;
|
||||
void setGlobalDownloadLimit(int limit);
|
||||
int getGlobalUploadLimit() const;
|
||||
void setGlobalUploadLimit(int limit);
|
||||
int getAltGlobalDownloadLimit() const;
|
||||
void setAltGlobalDownloadLimit(int limit);
|
||||
int getAltGlobalUploadLimit() const;
|
||||
void setAltGlobalUploadLimit(int limit);
|
||||
bool isAltBandwidthEnabled() const;
|
||||
void setAltBandwidthEnabled(bool enabled);
|
||||
bool isSchedulerEnabled() const;
|
||||
void setSchedulerEnabled(bool enabled);
|
||||
QTime getSchedulerStartTime() const;
|
||||
void setSchedulerStartTime(const QTime &time);
|
||||
QTime getSchedulerEndTime() const;
|
||||
@@ -208,80 +167,10 @@ public:
|
||||
scheduler_days getSchedulerDays() const;
|
||||
void setSchedulerDays(scheduler_days days);
|
||||
|
||||
// Proxy options
|
||||
bool isProxyEnabled() const;
|
||||
bool isProxyAuthEnabled() const;
|
||||
void setProxyAuthEnabled(bool enabled);
|
||||
QString getProxyIp() const;
|
||||
void setProxyIp(const QString &ip);
|
||||
unsigned short getProxyPort() const;
|
||||
void setProxyPort(unsigned short port);
|
||||
QString getProxyUsername() const;
|
||||
void setProxyUsername(const QString &username);
|
||||
QString getProxyPassword() const;
|
||||
void setProxyPassword(const QString &password);
|
||||
int getProxyType() const;
|
||||
void setProxyType(int type);
|
||||
bool proxyPeerConnections() const;
|
||||
void setProxyPeerConnections(bool enabled);
|
||||
bool getForceProxy() const;
|
||||
void setForceProxy(bool enabled);
|
||||
void setProxyOnlyForTorrents(bool enabled);
|
||||
bool isProxyOnlyForTorrents() const;
|
||||
|
||||
// Bittorrent options
|
||||
int getMaxConnecs() const;
|
||||
void setMaxConnecs(int val);
|
||||
int getMaxConnecsPerTorrent() const;
|
||||
void setMaxConnecsPerTorrent(int val);
|
||||
int getMaxUploads() const;
|
||||
void setMaxUploads(int val);
|
||||
int getMaxUploadsPerTorrent() const;
|
||||
void setMaxUploadsPerTorrent(int val);
|
||||
bool isuTPEnabled() const;
|
||||
void setuTPEnabled(bool enabled);
|
||||
bool isuTPRateLimited() const;
|
||||
void setuTPRateLimited(bool enabled);
|
||||
bool isDHTEnabled() const;
|
||||
void setDHTEnabled(bool enabled);
|
||||
bool isPeXEnabled() const;
|
||||
void setPeXEnabled(bool enabled);
|
||||
bool isLSDEnabled() const;
|
||||
void setLSDEnabled(bool enabled);
|
||||
int getEncryptionSetting() const;
|
||||
void setEncryptionSetting(int val);
|
||||
bool isAddTrackersEnabled() const;
|
||||
void setAddTrackersEnabled(bool enabled);
|
||||
QString getTrackersList() const;
|
||||
void setTrackersList(const QString &val);
|
||||
qreal getGlobalMaxRatio() const;
|
||||
void setGlobalMaxRatio(qreal ratio);
|
||||
|
||||
// IP Filter
|
||||
bool isFilteringEnabled() const;
|
||||
void setFilteringEnabled(bool enabled);
|
||||
bool isFilteringTrackerEnabled() const;
|
||||
void setFilteringTrackerEnabled(bool enabled);
|
||||
QString getFilter() const;
|
||||
void setFilter(const QString &path);
|
||||
QStringList bannedIPs() const;
|
||||
void banIP(const QString &ip);
|
||||
|
||||
// Search
|
||||
bool isSearchEnabled() const;
|
||||
void setSearchEnabled(bool enabled);
|
||||
|
||||
// Queueing system
|
||||
bool isQueueingSystemEnabled() const;
|
||||
void setQueueingSystemEnabled(bool enabled);
|
||||
int getMaxActiveDownloads() const;
|
||||
void setMaxActiveDownloads(int val);
|
||||
int getMaxActiveUploads() const;
|
||||
void setMaxActiveUploads(int val);
|
||||
int getMaxActiveTorrents() const;
|
||||
void setMaxActiveTorrents(int val);
|
||||
bool ignoreSlowTorrentsForQueueing() const;
|
||||
void setIgnoreSlowTorrentsForQueueing(bool ignore);
|
||||
bool isWebUiEnabled() const;
|
||||
void setWebUiEnabled(bool enabled);
|
||||
bool isWebUiLocalAuthEnabled() const;
|
||||
@@ -331,50 +220,12 @@ public:
|
||||
void setShutdownqBTWhenDownloadsComplete(bool shutdown);
|
||||
bool dontConfirmAutoExit() const;
|
||||
void setDontConfirmAutoExit(bool dontConfirmAutoExit);
|
||||
uint diskCacheSize() const;
|
||||
void setDiskCacheSize(uint size);
|
||||
uint diskCacheTTL() const;
|
||||
void setDiskCacheTTL(uint ttl);
|
||||
bool osCache() const;
|
||||
void setOsCache(bool enable);
|
||||
uint saveResumeDataInterval() const;
|
||||
void setSaveResumeDataInterval(uint m);
|
||||
uint outgoingPortsMin() const;
|
||||
void setOutgoingPortsMin(uint val);
|
||||
uint outgoingPortsMax() const;
|
||||
void setOutgoingPortsMax(uint val);
|
||||
bool getIgnoreLimitsOnLAN() const;
|
||||
void setIgnoreLimitsOnLAN(bool ignore);
|
||||
bool includeOverheadInLimits() const;
|
||||
void includeOverheadInLimits(bool include);
|
||||
bool trackerExchangeEnabled() const;
|
||||
void setTrackerExchangeEnabled(bool enable);
|
||||
bool recheckTorrentsOnCompletion() const;
|
||||
void recheckTorrentsOnCompletion(bool recheck);
|
||||
unsigned int getRefreshInterval() const;
|
||||
void setRefreshInterval(uint interval);
|
||||
bool resolvePeerCountries() const;
|
||||
void resolvePeerCountries(bool resolve);
|
||||
bool resolvePeerHostNames() const;
|
||||
void resolvePeerHostNames(bool resolve);
|
||||
int getMaxHalfOpenConnections() const;
|
||||
void setMaxHalfOpenConnections(int value);
|
||||
QString getNetworkInterface() const;
|
||||
void setNetworkInterface(const QString& iface);
|
||||
QString getNetworkInterfaceName() const;
|
||||
void setNetworkInterfaceName(const QString& iface);
|
||||
QString getNetworkInterfaceAddress() const;
|
||||
void setNetworkInterfaceAddress(const QString& addr);
|
||||
bool getListenIPv6() const;
|
||||
void setListenIPv6(bool enable);
|
||||
QString getNetworkAddress() const;
|
||||
void setNetworkAddress(const QString& addr);
|
||||
bool isAnonymousModeEnabled() const;
|
||||
void enableAnonymousMode(bool enabled);
|
||||
bool isSuperSeedingEnabled() const;
|
||||
void enableSuperSeeding(bool enabled);
|
||||
bool announceToAllTrackers() const;
|
||||
void setAnnounceToAllTrackers(bool enabled);
|
||||
#if (defined(Q_OS_UNIX) && !defined(Q_OS_MAC))
|
||||
bool useSystemIconTheme() const;
|
||||
void useSystemIconTheme(bool enabled);
|
||||
@@ -396,8 +247,6 @@ public:
|
||||
static void setTorrentFileAssoc();
|
||||
static void setMagnetLinkAssoc();
|
||||
#endif
|
||||
bool isTrackerEnabled() const;
|
||||
void setTrackerEnabled(bool enabled);
|
||||
int getTrackerPort() const;
|
||||
void setTrackerPort(int port);
|
||||
#if defined(Q_OS_WIN) || defined(Q_OS_MAC)
|
||||
@@ -451,12 +300,12 @@ public:
|
||||
void setRssHSplitterSizes(const QByteArray &sizes);
|
||||
QStringList getRssOpenFolders() const;
|
||||
void setRssOpenFolders(const QStringList &folders);
|
||||
QByteArray getRssHSplitterState() const;
|
||||
void setRssHSplitterState(const QByteArray &state);
|
||||
QByteArray getRssVSplitterState() const;
|
||||
void setRssVSplitterState(const QByteArray &state);
|
||||
QString getSearchColsWidth() const;
|
||||
void setSearchColsWidth(const QString &width);
|
||||
QByteArray getRssSideSplitterState() const;
|
||||
void setRssSideSplitterState(const QByteArray &state);
|
||||
QByteArray getRssMainSplitterState() const;
|
||||
void setRssMainSplitterState(const QByteArray &state);
|
||||
QByteArray getSearchTabHeaderState() const;
|
||||
void setSearchTabHeaderState(const QByteArray &state);
|
||||
QStringList getSearchEngDisabled() const;
|
||||
void setSearchEngDisabled(const QStringList &engines);
|
||||
QString getCreateTorLastAddPath() const;
|
||||
|
||||
@@ -39,7 +39,7 @@ class QIniSettings : public QSettings {
|
||||
|
||||
public:
|
||||
QIniSettings(const QString &organization = "qBittorrent", const QString &application = "qBittorrent", QObject *parent = 0 ):
|
||||
#ifdef Q_OS_WIN
|
||||
#if defined(Q_OS_WIN) || defined(Q_OS_MAC)
|
||||
QSettings(QSettings::IniFormat, QSettings::UserScope, organization, application, parent)
|
||||
#else
|
||||
QSettings(organization, application, parent)
|
||||
|
||||
@@ -31,6 +31,8 @@
|
||||
#include <QRegExp>
|
||||
#include <QDebug>
|
||||
#include <QDir>
|
||||
#include <QString>
|
||||
#include <QStringList>
|
||||
|
||||
#include "base/preferences.h"
|
||||
#include "base/utils/fs.h"
|
||||
@@ -48,53 +50,122 @@ DownloadRule::DownloadRule()
|
||||
{
|
||||
}
|
||||
|
||||
bool DownloadRule::matches(const QString &articleTitle, const QString &expression) const
|
||||
{
|
||||
static QRegExp whitespace("\\s+");
|
||||
|
||||
if (expression.isEmpty()) {
|
||||
// A regex of the form "expr|" will always match, so do the same for wildcards
|
||||
return true;
|
||||
}
|
||||
else if (m_useRegex) {
|
||||
QRegExp reg(expression, Qt::CaseInsensitive, QRegExp::RegExp);
|
||||
return reg.indexIn(articleTitle) > -1;
|
||||
}
|
||||
else {
|
||||
// Only match if every wildcard token (separated by spaces) is present in the article name.
|
||||
// Order of wildcard tokens is unimportant (if order is important, they should have used *).
|
||||
foreach (const QString &wildcard, expression.split(whitespace, QString::SplitBehavior::SkipEmptyParts)) {
|
||||
QRegExp reg(wildcard, Qt::CaseInsensitive, QRegExp::Wildcard);
|
||||
|
||||
if (reg.indexIn(articleTitle) == -1)
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool DownloadRule::matches(const QString &articleTitle) const
|
||||
{
|
||||
foreach (const QString &token, m_mustContain) {
|
||||
if (!token.isEmpty()) {
|
||||
QRegExp reg(token, Qt::CaseInsensitive, m_useRegex ? QRegExp::RegExp : QRegExp::Wildcard);
|
||||
if (reg.indexIn(articleTitle) < 0)
|
||||
return false;
|
||||
}
|
||||
}
|
||||
qDebug("Checking not matching tokens");
|
||||
// Checking not matching
|
||||
foreach (const QString &token, m_mustNotContain) {
|
||||
if (!token.isEmpty()) {
|
||||
QRegExp reg(token, Qt::CaseInsensitive, m_useRegex ? QRegExp::RegExp : QRegExp::Wildcard);
|
||||
if (reg.indexIn(articleTitle) > -1)
|
||||
if (!m_mustContain.empty()) {
|
||||
bool logged = false;
|
||||
bool foundMustContain = false;
|
||||
|
||||
// Each expression is either a regex, or a set of wildcards separated by whitespace.
|
||||
// Accept if any complete expression matches.
|
||||
foreach (const QString &expression, m_mustContain) {
|
||||
if (!logged) {
|
||||
qDebug() << "Checking matching" << (m_useRegex ? "regex:" : "wildcard expressions:") << m_mustContain.join("|");
|
||||
logged = true;
|
||||
}
|
||||
|
||||
// A regex of the form "expr|" will always match, so do the same for wildcards
|
||||
foundMustContain = matches(articleTitle, expression);
|
||||
|
||||
if (foundMustContain) {
|
||||
qDebug() << "Found matching" << (m_useRegex ? "regex:" : "wildcard expression:") << expression;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (!foundMustContain)
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!m_mustNotContain.empty()) {
|
||||
bool logged = false;
|
||||
|
||||
// Each expression is either a regex, or a set of wildcards separated by whitespace.
|
||||
// Reject if any complete expression matches.
|
||||
foreach (const QString &expression, m_mustNotContain) {
|
||||
if (!logged) {
|
||||
qDebug() << "Checking not matching" << (m_useRegex ? "regex:" : "wildcard expressions:") << m_mustNotContain.join("|");
|
||||
logged = true;
|
||||
}
|
||||
|
||||
// A regex of the form "expr|" will always match, so do the same for wildcards
|
||||
if (matches(articleTitle, expression)) {
|
||||
qDebug() << "Found not matching" << (m_useRegex ? "regex:" : "wildcard expression:") << expression;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!m_episodeFilter.isEmpty()) {
|
||||
qDebug("Checking episode filter");
|
||||
qDebug() << "Checking episode filter:" << m_episodeFilter;
|
||||
QRegExp f("(^\\d{1,4})x(.*;$)");
|
||||
int pos = f.indexIn(m_episodeFilter);
|
||||
|
||||
if (pos < 0)
|
||||
return false;
|
||||
|
||||
QString s = f.cap(1);
|
||||
QStringList eps = f.cap(2).split(";");
|
||||
QString expStr;
|
||||
expStr += "s0?" + s + "[ -_\\.]?" + "e0?";
|
||||
int sOurs = s.toInt();
|
||||
|
||||
foreach (const QString &ep, eps) {
|
||||
foreach (QString ep, eps) {
|
||||
if (ep.isEmpty())
|
||||
continue;
|
||||
|
||||
// We need to trim leading zeroes, but if it's all zeros then we want episode zero.
|
||||
while (ep.size() > 1 && ep.startsWith("0"))
|
||||
ep = ep.right(ep.size() - 1);
|
||||
|
||||
if (ep.indexOf('-') != -1) { // Range detected
|
||||
QString partialPattern = "s0?" + s + "[ -_\\.]?" + "e(0?\\d{1,4})";
|
||||
QRegExp reg(partialPattern, Qt::CaseInsensitive);
|
||||
QString partialPattern1 = "\\bs0?(\\d{1,4})[ -_\\.]?e(0?\\d{1,4})(?:\\D|\\b)";
|
||||
QString partialPattern2 = "\\b(\\d{1,4})x(0?\\d{1,4})(?:\\D|\\b)";
|
||||
QRegExp reg(partialPattern1, Qt::CaseInsensitive);
|
||||
|
||||
if (ep.endsWith('-')) { // Infinite range
|
||||
int epOurs = ep.left(ep.size() - 1).toInt();
|
||||
|
||||
// Extract partial match from article and compare as digits
|
||||
pos = reg.indexIn(articleTitle);
|
||||
|
||||
if (pos == -1) {
|
||||
reg = QRegExp(partialPattern2, Qt::CaseInsensitive);
|
||||
pos = reg.indexIn(articleTitle);
|
||||
}
|
||||
|
||||
if (pos != -1) {
|
||||
int epTheirs = reg.cap(1).toInt();
|
||||
if (epTheirs >= epOurs)
|
||||
int sTheirs = reg.cap(1).toInt();
|
||||
int epTheirs = reg.cap(2).toInt();
|
||||
if (((sTheirs == sOurs) && (epTheirs >= epOurs)) || (sTheirs > sOurs)) {
|
||||
qDebug() << "Matched episode:" << ep;
|
||||
qDebug() << "Matched article:" << articleTitle;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
else { // Normal range
|
||||
@@ -108,21 +179,38 @@ bool DownloadRule::matches(const QString &articleTitle) const
|
||||
|
||||
// Extract partial match from article and compare as digits
|
||||
pos = reg.indexIn(articleTitle);
|
||||
|
||||
if (pos == -1) {
|
||||
reg = QRegExp(partialPattern2, Qt::CaseInsensitive);
|
||||
pos = reg.indexIn(articleTitle);
|
||||
}
|
||||
|
||||
if (pos != -1) {
|
||||
int epTheirs = reg.cap(1).toInt();
|
||||
if (epOursFirst <= epTheirs && epOursLast >= epTheirs)
|
||||
int sTheirs = reg.cap(1).toInt();
|
||||
int epTheirs = reg.cap(2).toInt();
|
||||
if ((sTheirs == sOurs) && ((epOursFirst <= epTheirs) && (epOursLast >= epTheirs))) {
|
||||
qDebug() << "Matched episode:" << ep;
|
||||
qDebug() << "Matched article:" << articleTitle;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
else { // Single number
|
||||
QRegExp reg(expStr + ep + "\\D", Qt::CaseInsensitive);
|
||||
if (reg.indexIn(articleTitle) != -1)
|
||||
QString expStr("\\b(?:s0?" + s + "[ -_\\.]?" + "e0?" + ep + "|" + s + "x" + "0?" + ep + ")(?:\\D|\\b)");
|
||||
QRegExp reg(expStr, Qt::CaseInsensitive);
|
||||
if (reg.indexIn(articleTitle) != -1) {
|
||||
qDebug() << "Matched episode:" << ep;
|
||||
qDebug() << "Matched article:" << articleTitle;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
qDebug() << "Matched article:" << articleTitle;
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -131,7 +219,11 @@ void DownloadRule::setMustContain(const QString &tokens)
|
||||
if (m_useRegex)
|
||||
m_mustContain = QStringList() << tokens;
|
||||
else
|
||||
m_mustContain = tokens.split(" ");
|
||||
m_mustContain = tokens.split("|");
|
||||
|
||||
// Check for single empty string - if so, no condition
|
||||
if ((m_mustContain.size() == 1) && m_mustContain[0].isEmpty())
|
||||
m_mustContain.clear();
|
||||
}
|
||||
|
||||
void DownloadRule::setMustNotContain(const QString &tokens)
|
||||
@@ -140,6 +232,10 @@ void DownloadRule::setMustNotContain(const QString &tokens)
|
||||
m_mustNotContain = QStringList() << tokens;
|
||||
else
|
||||
m_mustNotContain = tokens.split("|");
|
||||
|
||||
// Check for single empty string - if so, no condition
|
||||
if ((m_mustNotContain.size() == 1) && m_mustNotContain[0].isEmpty())
|
||||
m_mustNotContain.clear();
|
||||
}
|
||||
|
||||
QStringList DownloadRule::rssFeeds() const
|
||||
@@ -189,7 +285,7 @@ QVariantHash DownloadRule::toVariantHash() const
|
||||
{
|
||||
QVariantHash hash;
|
||||
hash["name"] = m_name;
|
||||
hash["must_contain"] = m_mustContain.join(" ");
|
||||
hash["must_contain"] = m_mustContain.join("|");
|
||||
hash["must_not_contain"] = m_mustNotContain.join("|");
|
||||
hash["save_path"] = m_savePath;
|
||||
hash["affected_feeds"] = m_rssFeeds;
|
||||
@@ -265,7 +361,7 @@ int DownloadRule::ignoreDays() const
|
||||
|
||||
QString DownloadRule::mustContain() const
|
||||
{
|
||||
return m_mustContain.join(" ");
|
||||
return m_mustContain.join("|");
|
||||
}
|
||||
|
||||
QString DownloadRule::mustNotContain() const
|
||||
@@ -300,8 +396,9 @@ QStringList DownloadRule::findMatchingArticles(const FeedPtr &feed) const
|
||||
|
||||
ArticleHash::ConstIterator artIt = feedArticles.begin();
|
||||
ArticleHash::ConstIterator artItend = feedArticles.end();
|
||||
for ( ; artIt != artItend ; ++artIt) {
|
||||
for (; artIt != artItend; ++artIt) {
|
||||
const QString title = artIt.value()->title();
|
||||
qDebug() << "Matching article:" << title;
|
||||
if (matches(title))
|
||||
ret << title;
|
||||
}
|
||||
|
||||
@@ -88,6 +88,8 @@ namespace Rss
|
||||
bool operator==(const DownloadRule &other) const;
|
||||
|
||||
private:
|
||||
bool matches(const QString &articleTitle, const QString &expression) const;
|
||||
|
||||
QString m_name;
|
||||
QStringList m_mustContain;
|
||||
QStringList m_mustNotContain;
|
||||
|
||||
@@ -46,6 +46,7 @@ DownloadRuleList::DownloadRuleList()
|
||||
DownloadRulePtr DownloadRuleList::findMatchingRule(const QString &feedUrl, const QString &articleTitle) const
|
||||
{
|
||||
Q_ASSERT(Preferences::instance()->isRssDownloadingEnabled());
|
||||
qDebug() << "Matching article:" << articleTitle;
|
||||
QStringList ruleNames = m_feedRules.value(feedUrl);
|
||||
foreach (const QString &rule_name, ruleNames) {
|
||||
DownloadRulePtr rule = m_rules[rule_name];
|
||||
|
||||
@@ -78,7 +78,7 @@ Feed::Feed(const QString &url, Manager *manager)
|
||||
|
||||
// Download the RSS Feed icon
|
||||
Net::DownloadHandler *handler = Net::DownloadManager::instance()->downloadUrl(iconUrl(), true);
|
||||
connect(handler, SIGNAL(downloadFinished(QString, QString)), this, SLOT(handleIconDownloadFinished(QString, QString)));
|
||||
connect(handler, SIGNAL(downloadFinished(QString,QString)), this, SLOT(handleIconDownloadFinished(QString,QString)));
|
||||
|
||||
// Load old RSS articles
|
||||
loadItemsFromDisk();
|
||||
@@ -99,24 +99,24 @@ void Feed::saveItemsToDisk()
|
||||
|
||||
m_dirty = false;
|
||||
|
||||
QIniSettings qBTRSS("qBittorrent", "qBittorrent-rss");
|
||||
QIniSettings qBTRSSFeeds("qBittorrent", "qBittorrent-rss-feeds");
|
||||
QVariantList oldItems;
|
||||
|
||||
ArticleHash::ConstIterator it = m_articles.begin();
|
||||
ArticleHash::ConstIterator itend = m_articles.end();
|
||||
for ( ; it != itend; ++it) {
|
||||
for (; it != itend; ++it)
|
||||
oldItems << it.value()->toHash();
|
||||
}
|
||||
qDebug("Saving %d old items for feed %s", oldItems.size(), qPrintable(displayName()));
|
||||
QHash<QString, QVariant> allOldItems = qBTRSS.value("old_items", QHash<QString, QVariant>()).toHash();
|
||||
QHash<QString, QVariant> allOldItems = qBTRSSFeeds.value("old_items", QHash<QString, QVariant>()).toHash();
|
||||
allOldItems[m_url] = oldItems;
|
||||
qBTRSS.setValue("old_items", allOldItems);
|
||||
qBTRSSFeeds.setValue("old_items", allOldItems);
|
||||
}
|
||||
|
||||
void Feed::loadItemsFromDisk()
|
||||
{
|
||||
QIniSettings qBTRSS("qBittorrent", "qBittorrent-rss");
|
||||
QHash<QString, QVariant> allOldItems = qBTRSS.value("old_items", QHash<QString, QVariant>()).toHash();
|
||||
QIniSettings qBTRSSFeeds("qBittorrent", "qBittorrent-rss-feeds");
|
||||
QHash<QString, QVariant> allOldItems = qBTRSSFeeds.value("old_items", QHash<QString, QVariant>()).toHash();
|
||||
|
||||
const QVariantList oldItems = allOldItems.value(m_url, QVariantList()).toList();
|
||||
qDebug("Loading %d old items for feed %s", oldItems.size(), qPrintable(displayName()));
|
||||
|
||||
@@ -155,20 +155,18 @@ void Feed::addArticle(const ArticlePtr &article)
|
||||
}
|
||||
|
||||
// Check if article was inserted at the end of the list and will break max_articles limit
|
||||
if (Preferences::instance()->isRssDownloadingEnabled()) {
|
||||
if (Preferences::instance()->isRssDownloadingEnabled())
|
||||
if ((lbIndex < maxArticles) && !article->isRead())
|
||||
downloadArticleTorrentIfMatching(article);
|
||||
}
|
||||
}
|
||||
else {
|
||||
// m_articles.contains(article->guid())
|
||||
// Try to download skipped articles
|
||||
if (Preferences::instance()->isRssDownloadingEnabled()) {
|
||||
ArticlePtr skipped = m_articles.value(article->guid(), ArticlePtr());
|
||||
if (skipped) {
|
||||
if (skipped)
|
||||
if (!skipped->isRead())
|
||||
downloadArticleTorrentIfMatching(skipped);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -182,8 +180,8 @@ bool Feed::refresh()
|
||||
m_loading = true;
|
||||
// Download the RSS again
|
||||
Net::DownloadHandler *handler = Net::DownloadManager::instance()->downloadUrl(m_url);
|
||||
connect(handler, SIGNAL(downloadFinished(QString, QByteArray)), this, SLOT(handleRssDownloadFinished(QString, QByteArray)));
|
||||
connect(handler, SIGNAL(downloadFailed(QString, QString)), this, SLOT(handleRssDownloadFailed(QString, QString)));
|
||||
connect(handler, SIGNAL(downloadFinished(QString,QByteArray)), this, SLOT(handleRssDownloadFinished(QString,QByteArray)));
|
||||
connect(handler, SIGNAL(downloadFailed(QString,QString)), this, SLOT(handleRssDownloadFailed(QString,QString)));
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -206,10 +204,11 @@ void Feed::removeAllSettings()
|
||||
allFeedsFilters.remove(m_url);
|
||||
qBTRSS.setValue("feed_filters", allFeedsFilters);
|
||||
}
|
||||
QVariantHash allOldItems = qBTRSS.value("old_items", QVariantHash()).toHash();
|
||||
QIniSettings qBTRSSFeeds("qBittorrent", "qBittorrent-rss-feeds");
|
||||
QVariantHash allOldItems = qBTRSSFeeds.value("old_items", QVariantHash()).toHash();
|
||||
if (allOldItems.contains(m_url)) {
|
||||
allOldItems.remove(m_url);
|
||||
qBTRSS.setValue("old_items", allOldItems);
|
||||
qBTRSSFeeds.setValue("old_items", allOldItems);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -259,8 +258,13 @@ bool Feed::hasCustomIcon() const
|
||||
|
||||
void Feed::setIconPath(const QString &path)
|
||||
{
|
||||
if (!path.isEmpty() && QFile::exists(path))
|
||||
m_icon = path;
|
||||
QString nativePath = Utils::Fs::fromNativePath(path);
|
||||
if ((nativePath == m_icon) || nativePath.isEmpty() || !QFile::exists(nativePath)) return;
|
||||
|
||||
if (!m_icon.startsWith(":/") && QFile::exists(m_icon))
|
||||
Utils::Fs::forceRemove(m_icon);
|
||||
|
||||
m_icon = nativePath;
|
||||
}
|
||||
|
||||
ArticlePtr Feed::getItem(const QString &guid) const
|
||||
@@ -277,9 +281,8 @@ void Feed::markAsRead()
|
||||
{
|
||||
ArticleHash::ConstIterator it = m_articles.begin();
|
||||
ArticleHash::ConstIterator itend = m_articles.end();
|
||||
for ( ; it != itend; ++it) {
|
||||
for (; it != itend; ++it)
|
||||
it.value()->markAsRead();
|
||||
}
|
||||
m_unreadCount = 0;
|
||||
m_manager->forwardFeedInfosChanged(m_url, displayName(), 0);
|
||||
}
|
||||
@@ -305,10 +308,9 @@ ArticleList Feed::unreadArticleListByDateDesc() const
|
||||
|
||||
ArticleList::ConstIterator it = m_articlesByDate.begin();
|
||||
ArticleList::ConstIterator itend = m_articlesByDate.end();
|
||||
for ( ; it != itend; ++it) {
|
||||
for (; it != itend; ++it)
|
||||
if (!(*it)->isRead())
|
||||
unreadNews << *it;
|
||||
}
|
||||
return unreadNews;
|
||||
}
|
||||
|
||||
@@ -322,7 +324,7 @@ QString Feed::iconUrl() const
|
||||
void Feed::handleIconDownloadFinished(const QString &url, const QString &filePath)
|
||||
{
|
||||
Q_UNUSED(url);
|
||||
m_icon = filePath;
|
||||
setIconPath(filePath);
|
||||
qDebug() << Q_FUNC_INFO << "icon path:" << m_icon;
|
||||
m_manager->forwardFeedIconChanged(m_url, m_icon);
|
||||
}
|
||||
@@ -359,6 +361,14 @@ void Feed::handleFeedTitle(const QString &title)
|
||||
void Feed::downloadArticleTorrentIfMatching(const ArticlePtr &article)
|
||||
{
|
||||
Q_ASSERT(Preferences::instance()->isRssDownloadingEnabled());
|
||||
qDebug().nospace() << Q_FUNC_INFO << " Deferring matching of " << article->title() << " from " << displayName() << " RSS feed";
|
||||
m_manager->downloadArticleTorrentIfMatching(m_url, article);
|
||||
}
|
||||
|
||||
void Feed::deferredDownloadArticleTorrentIfMatching(const ArticlePtr &article)
|
||||
{
|
||||
qDebug().nospace() << Q_FUNC_INFO << " Matching of " << article->title() << " from " << displayName() << " RSS feed";
|
||||
|
||||
DownloadRuleList *rules = m_manager->downloadRules();
|
||||
DownloadRulePtr matchingRule = rules->findMatchingRule(m_url, article->title());
|
||||
if (!matchingRule) return;
|
||||
@@ -402,10 +412,9 @@ void Feed::downloadArticleTorrentIfMatching(const ArticlePtr &article)
|
||||
void Feed::recheckRssItemsForDownload()
|
||||
{
|
||||
Q_ASSERT(Preferences::instance()->isRssDownloadingEnabled());
|
||||
foreach (const ArticlePtr &article, m_articlesByDate) {
|
||||
foreach (const ArticlePtr &article, m_articlesByDate)
|
||||
if (!article->isRead())
|
||||
downloadArticleTorrentIfMatching(article);
|
||||
}
|
||||
}
|
||||
|
||||
void Feed::handleNewArticle(const QVariantHash &articleData)
|
||||
@@ -421,7 +430,7 @@ void Feed::handleNewArticle(const QVariantHash &articleData)
|
||||
m_manager->forwardFeedInfosChanged(m_url, displayName(), m_unreadCount);
|
||||
// FIXME: We should forward the information here but this would seriously decrease
|
||||
// performance with current design.
|
||||
//m_manager->forwardFeedContentChanged(m_url);
|
||||
// m_manager->forwardFeedContentChanged(m_url);
|
||||
}
|
||||
|
||||
void Feed::handleParsingFinished(const QString &error)
|
||||
|
||||
@@ -64,7 +64,7 @@ namespace Rss
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
Feed(const QString &url, Manager *manager);
|
||||
Feed(const QString &url, Manager * manager);
|
||||
~Feed();
|
||||
|
||||
bool refresh();
|
||||
@@ -98,10 +98,13 @@ namespace Rss
|
||||
void handleArticleRead();
|
||||
|
||||
private:
|
||||
friend class Manager;
|
||||
|
||||
QString iconUrl() const;
|
||||
void loadItemsFromDisk();
|
||||
void addArticle(const ArticlePtr &article);
|
||||
void downloadArticleTorrentIfMatching(const ArticlePtr &article);
|
||||
void deferredDownloadArticleTorrentIfMatching(const ArticlePtr &article);
|
||||
|
||||
private:
|
||||
Manager *m_manager;
|
||||
|
||||
@@ -54,6 +54,10 @@ Manager::Manager(QObject *parent)
|
||||
connect(&m_refreshTimer, SIGNAL(timeout()), SLOT(refresh()));
|
||||
m_refreshInterval = Preferences::instance()->getRSSRefreshInterval();
|
||||
m_refreshTimer.start(m_refreshInterval * MSECS_PER_MIN);
|
||||
|
||||
m_deferredDownloadTimer.setInterval(1);
|
||||
m_deferredDownloadTimer.setSingleShot(true);
|
||||
connect(&m_deferredDownloadTimer, SIGNAL(timeout()), SLOT(downloadNextArticleTorrentIfMatching()));
|
||||
}
|
||||
|
||||
Manager::~Manager()
|
||||
@@ -72,7 +76,7 @@ void Manager::updateRefreshInterval(uint val)
|
||||
{
|
||||
if (m_refreshInterval != val) {
|
||||
m_refreshInterval = val;
|
||||
m_refreshTimer.start(m_refreshInterval*60000);
|
||||
m_refreshTimer.start(m_refreshInterval * 60000);
|
||||
qDebug("New RSS refresh interval is now every %dmin", m_refreshInterval);
|
||||
}
|
||||
}
|
||||
@@ -81,7 +85,7 @@ void Manager::loadStreamList()
|
||||
{
|
||||
const Preferences *const pref = Preferences::instance();
|
||||
const QStringList streamsUrl = pref->getRssFeedsUrls();
|
||||
const QStringList aliases = pref->getRssFeedsAliases();
|
||||
const QStringList aliases = pref->getRssFeedsAliases();
|
||||
if (streamsUrl.size() != aliases.size()) {
|
||||
Logger::instance()->addMessage("Corrupted RSS list, not loading it.", Log::WARNING);
|
||||
return;
|
||||
@@ -188,3 +192,27 @@ void Manager::refresh()
|
||||
{
|
||||
m_rootFolder->refresh();
|
||||
}
|
||||
|
||||
void Manager::downloadArticleTorrentIfMatching(const QString &url, const ArticlePtr &article)
|
||||
{
|
||||
m_deferredDownloads.append(qMakePair(url, article));
|
||||
m_deferredDownloadTimer.start();
|
||||
}
|
||||
|
||||
void Manager::downloadNextArticleTorrentIfMatching()
|
||||
{
|
||||
if (m_deferredDownloads.empty())
|
||||
return;
|
||||
|
||||
// Schedule to process the next article (if any)
|
||||
m_deferredDownloadTimer.start();
|
||||
|
||||
QPair<QString, ArticlePtr> urlArticle(m_deferredDownloads.takeFirst());
|
||||
FeedList streams = m_rootFolder->getAllFeeds();
|
||||
foreach (const FeedPtr &stream, streams) {
|
||||
if (stream->url() == urlArticle.first) {
|
||||
stream->deferredDownloadArticleTorrentIfMatching(urlArticle.second);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -32,19 +32,23 @@
|
||||
#ifndef RSSMANAGER_H
|
||||
#define RSSMANAGER_H
|
||||
|
||||
#include <QList>
|
||||
#include <QObject>
|
||||
#include <QPair>
|
||||
#include <QTimer>
|
||||
#include <QSharedPointer>
|
||||
#include <QThread>
|
||||
|
||||
namespace Rss
|
||||
{
|
||||
class Article;
|
||||
class DownloadRuleList;
|
||||
class File;
|
||||
class Folder;
|
||||
class Feed;
|
||||
class Manager;
|
||||
|
||||
typedef QSharedPointer<Article> ArticlePtr;
|
||||
typedef QSharedPointer<File> FilePtr;
|
||||
typedef QSharedPointer<Folder> FolderPtr;
|
||||
typedef QSharedPointer<Feed> FeedPtr;
|
||||
@@ -62,6 +66,7 @@ namespace Rss
|
||||
DownloadRuleList *downloadRules() const;
|
||||
FolderPtr rootFolder() const;
|
||||
QThread *workingThread() const;
|
||||
void downloadArticleTorrentIfMatching(const QString &url, const ArticlePtr &article);
|
||||
|
||||
public slots:
|
||||
void refresh();
|
||||
@@ -78,12 +83,17 @@ namespace Rss
|
||||
void feedInfosChanged(const QString &url, const QString &displayName, uint unreadCount);
|
||||
void feedIconChanged(const QString &url, const QString &iconPath);
|
||||
|
||||
private slots:
|
||||
void downloadNextArticleTorrentIfMatching();
|
||||
|
||||
private:
|
||||
QTimer m_refreshTimer;
|
||||
uint m_refreshInterval;
|
||||
DownloadRuleList *m_downloadRules;
|
||||
FolderPtr m_rootFolder;
|
||||
QThread *m_workingThread;
|
||||
QTimer m_deferredDownloadTimer;
|
||||
QList<QPair<QString, ArticlePtr>> m_deferredDownloads;
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
@@ -62,7 +62,7 @@ static inline void removePythonScriptIfExists(const QString &scriptPath)
|
||||
const QHash<QString, QString> SearchEngine::m_categoryNames = SearchEngine::initializeCategoryNames();
|
||||
|
||||
SearchEngine::SearchEngine()
|
||||
: m_updateUrl(QString("https://raw.github.com/qbittorrent/qBittorrent/master/src/searchengine/%1/engines/").arg(Utils::Misc::pythonVersion() >= 3 ? "nova3" : "nova"))
|
||||
: m_updateUrl(QString("http://searchplugins.qbittorrent.org/%1/engines/").arg(Utils::Misc::pythonVersion() >= 3 ? "nova3" : "nova"))
|
||||
, m_searchStopped(false)
|
||||
{
|
||||
updateNova();
|
||||
|
||||
@@ -38,10 +38,6 @@
|
||||
#include "logger.h"
|
||||
#include "utils/fs.h"
|
||||
|
||||
#ifdef Q_OS_MAC
|
||||
#define QSETTINGS_SYNC_IS_SAVE // whether QSettings::sync() is "atomic"
|
||||
#endif
|
||||
|
||||
namespace
|
||||
{
|
||||
// Encapsulates serialization of settings in "atomic" way.
|
||||
@@ -69,7 +65,7 @@ namespace
|
||||
using SettingsPtr = std::unique_ptr<QSettings>;
|
||||
SettingsPtr createSettings(const QString &name)
|
||||
{
|
||||
#ifdef Q_OS_WIN
|
||||
#if defined(Q_OS_WIN) || defined(Q_OS_MAC)
|
||||
return SettingsPtr(new QSettings(QSettings::IniFormat, QSettings::UserScope, "qBittorrent", name));
|
||||
#else
|
||||
return SettingsPtr(new QSettings("qBittorrent", name));
|
||||
@@ -98,22 +94,86 @@ namespace
|
||||
{
|
||||
static const MappingTable keyMapping = {
|
||||
|
||||
{ "BitTorrent/Session/MaxRatioAction", "Preferences/Bittorrent/MaxRatioAction" },
|
||||
{ "BitTorrent/Session/DefaultSavePath", "Preferences/Downloads/SavePath" },
|
||||
{ "BitTorrent/Session/TempPath", "Preferences/Downloads/TempPath" },
|
||||
{ "BitTorrent/Session/TempPathEnabled", "Preferences/Downloads/TempPathEnabled" },
|
||||
{ "BitTorrent/Session/AddTorrentPaused", "Preferences/Downloads/StartInPause" },
|
||||
{"BitTorrent/Session/MaxRatioAction", "Preferences/Bittorrent/MaxRatioAction"},
|
||||
{"BitTorrent/Session/DefaultSavePath", "Preferences/Downloads/SavePath"},
|
||||
{"BitTorrent/Session/TempPath", "Preferences/Downloads/TempPath"},
|
||||
{"BitTorrent/Session/TempPathEnabled", "Preferences/Downloads/TempPathEnabled"},
|
||||
{"BitTorrent/Session/AddTorrentPaused", "Preferences/Downloads/StartInPause"},
|
||||
{"BitTorrent/Session/RefreshInterval", "Preferences/General/RefreshInterval"},
|
||||
{"BitTorrent/Session/Preallocation", "Preferences/Downloads/PreAllocation"},
|
||||
{"BitTorrent/Session/AddExtensionToIncompleteFiles", "Preferences/Downloads/UseIncompleteExtension"},
|
||||
{"BitTorrent/Session/TorrentExportDirectory", "Preferences/Downloads/TorrentExportDir"},
|
||||
{"BitTorrent/Session/FinishedTorrentExportDirectory", "Preferences/Downloads/FinishedTorrentExportDir"},
|
||||
{"BitTorrent/Session/GlobalUPSpeedLimit", "Preferences/Connection/GlobalUPLimit"},
|
||||
{"BitTorrent/Session/GlobalDLSpeedLimit", "Preferences/Connection/GlobalDLLimit"},
|
||||
{"BitTorrent/Session/AlternativeGlobalUPSpeedLimit", "Preferences/Connection/GlobalUPLimitAlt"},
|
||||
{"BitTorrent/Session/AlternativeGlobalDLSpeedLimit", "Preferences/Connection/GlobalDLLimitAlt"},
|
||||
{"BitTorrent/Session/UseAlternativeGlobalSpeedLimit", "Preferences/Connection/alt_speeds_on"},
|
||||
{"BitTorrent/Session/BandwidthSchedulerEnabled", "Preferences/Scheduler/Enabled"},
|
||||
{"BitTorrent/Session/Port", "Preferences/Connection/PortRangeMin"},
|
||||
{"BitTorrent/Session/UseRandomPort", "Preferences/General/UseRandomPort"},
|
||||
{"BitTorrent/Session/IPv6Enabled", "Preferences/Connection/InterfaceListenIPv6"},
|
||||
{"BitTorrent/Session/Interface", "Preferences/Connection/Interface"},
|
||||
{"BitTorrent/Session/InterfaceName", "Preferences/Connection/InterfaceName"},
|
||||
{"BitTorrent/Session/InterfaceAddress", "Preferences/Connection/InterfaceAddress"},
|
||||
{"BitTorrent/Session/SaveResumeDataInterval", "Preferences/Downloads/SaveResumeDataInterval"},
|
||||
{"BitTorrent/Session/Encryption", "Preferences/Bittorrent/Encryption"},
|
||||
{"BitTorrent/Session/ForceProxy", "Preferences/Connection/ProxyForce"},
|
||||
{"BitTorrent/Session/ProxyPeerConnections", "Preferences/Connection/ProxyPeerConnections"},
|
||||
{"BitTorrent/Session/MaxConnections", "Preferences/Bittorrent/MaxConnecs"},
|
||||
{"BitTorrent/Session/MaxUploads", "Preferences/Bittorrent/MaxUploads"},
|
||||
{"BitTorrent/Session/MaxConnectionsPerTorrent", "Preferences/Bittorrent/MaxConnecsPerTorrent"},
|
||||
{"BitTorrent/Session/MaxUploadsPerTorrent", "Preferences/Bittorrent/MaxUploadsPerTorrent"},
|
||||
{"BitTorrent/Session/DHTEnabled", "Preferences/Bittorrent/DHT"},
|
||||
{"BitTorrent/Session/LSDEnabled", "Preferences/Bittorrent/LSD"},
|
||||
{"BitTorrent/Session/PeXEnabled", "Preferences/Bittorrent/PeX"},
|
||||
{"BitTorrent/Session/AddTrackersEnabled", "Preferences/Bittorrent/AddTrackers"},
|
||||
{"BitTorrent/Session/AdditionalTrackers", "Preferences/Bittorrent/TrackersList"},
|
||||
{"BitTorrent/Session/IPFilteringEnabled", "Preferences/IPFilter/Enabled"},
|
||||
{"BitTorrent/Session/TrackerFilteringEnabled", "Preferences/IPFilter/FilterTracker"},
|
||||
{"BitTorrent/Session/IPFilter", "Preferences/IPFilter/File"},
|
||||
{"BitTorrent/Session/GlobalMaxRatio", "Preferences/Bittorrent/MaxRatio"},
|
||||
{"BitTorrent/Session/AnnounceToAllTrackers", "Preferences/Advanced/AnnounceToAllTrackers"},
|
||||
{"BitTorrent/Session/DiskCacheSize", "Preferences/Downloads/DiskWriteCacheSize"},
|
||||
{"BitTorrent/Session/DiskCacheTTL", "Preferences/Downloads/DiskWriteCacheTTL"},
|
||||
{"BitTorrent/Session/UseOSCache", "Preferences/Advanced/osCache"},
|
||||
{"BitTorrent/Session/AnonymousModeEnabled", "Preferences/Advanced/AnonymousMode"},
|
||||
{"BitTorrent/Session/QueueingSystemEnabled", "Preferences/Queueing/QueueingEnabled"},
|
||||
{"BitTorrent/Session/MaxActiveDownloads", "Preferences/Queueing/MaxActiveDownloads"},
|
||||
{"BitTorrent/Session/MaxActiveUploads", "Preferences/Queueing/MaxActiveUploads"},
|
||||
{"BitTorrent/Session/MaxActiveTorrents", "Preferences/Queueing/MaxActiveTorrents"},
|
||||
{"BitTorrent/Session/IgnoreSlowTorrentsForQueueing", "Preferences/Queueing/IgnoreSlowTorrents"},
|
||||
{"BitTorrent/Session/OutgoingPortsMin", "Preferences/Advanced/OutgoingPortsMin"},
|
||||
{"BitTorrent/Session/OutgoingPortsMax", "Preferences/Advanced/OutgoingPortsMax"},
|
||||
{"BitTorrent/Session/IgnoreLimitsOnLAN", "Preferences/Advanced/IgnoreLimitsLAN"},
|
||||
{"BitTorrent/Session/IncludeOverheadInLimits", "Preferences/Advanced/IncludeOverhead"},
|
||||
{"BitTorrent/Session/AnnounceIP", "Preferences/Connection/InetAddress"},
|
||||
{"BitTorrent/Session/SuperSeedingEnabled", "Preferences/Advanced/SuperSeeding"},
|
||||
{"BitTorrent/Session/MaxHalfOpenConnections", "Preferences/Connection/MaxHalfOpenConnec"},
|
||||
{"BitTorrent/Session/uTPEnabled", "Preferences/Bittorrent/uTP"},
|
||||
{"BitTorrent/Session/uTPRateLimited", "Preferences/Bittorrent/uTP_rate_limited"},
|
||||
{"BitTorrent/TrackerEnabled", "Preferences/Advanced/trackerEnabled"},
|
||||
{"Network/Proxy/OnlyForTorrents", "Preferences/Connection/ProxyOnlyForTorrents"},
|
||||
{"Network/Proxy/Type", "Preferences/Connection/ProxyType"},
|
||||
{"Network/Proxy/Authentication", "Preferences/Connection/Proxy/Authentication"},
|
||||
{"Network/Proxy/Username", "Preferences/Connection/Proxy/Username"},
|
||||
{"Network/Proxy/Password", "Preferences/Connection/Proxy/Password"},
|
||||
{"Network/Proxy/IP", "Preferences/Connection/Proxy/IP"},
|
||||
{"Network/Proxy/Port", "Preferences/Connection/Proxy/Port"},
|
||||
{"Network/PortForwardingEnabled", "Preferences/Connection/UPnP"},
|
||||
#ifdef QBT_USES_QT5
|
||||
{ "AddNewTorrentDialog/TreeHeaderState", "AddNewTorrentDialog/qt5/treeHeaderState" },
|
||||
{"AddNewTorrentDialog/TreeHeaderState", "AddNewTorrentDialog/qt5/treeHeaderState"},
|
||||
#else
|
||||
{ "AddNewTorrentDialog/TreeHeaderState", "AddNewTorrentDialog/treeHeaderState" },
|
||||
{"AddNewTorrentDialog/TreeHeaderState", "AddNewTorrentDialog/treeHeaderState"},
|
||||
#endif
|
||||
{ "AddNewTorrentDialog/Width", "AddNewTorrentDialog/width" },
|
||||
{ "AddNewTorrentDialog/Position", "AddNewTorrentDialog/y" },
|
||||
{ "AddNewTorrentDialog/Expanded", "AddNewTorrentDialog/expanded" },
|
||||
{ "AddNewTorrentDialog/SavePathHistory", "TorrentAdditionDlg/save_path_history" },
|
||||
{ "AddNewTorrentDialog/Enabled", "Preferences/Downloads/NewAdditionDialog" },
|
||||
{ "AddNewTorrentDialog/TopLevel", "Preferences/Downloads/NewAdditionDialogFront" }
|
||||
{"AddNewTorrentDialog/Width", "AddNewTorrentDialog/width"},
|
||||
{"AddNewTorrentDialog/Position", "AddNewTorrentDialog/y"},
|
||||
{"AddNewTorrentDialog/Expanded", "AddNewTorrentDialog/expanded"},
|
||||
{"AddNewTorrentDialog/SavePathHistory", "TorrentAdditionDlg/save_path_history"},
|
||||
{"AddNewTorrentDialog/Enabled", "Preferences/Downloads/NewAdditionDialog"},
|
||||
{"AddNewTorrentDialog/TopLevel", "Preferences/Downloads/NewAdditionDialogFront"},
|
||||
|
||||
{"State/BannedIPs", "Preferences/IPFilter/BannedIPs"}
|
||||
|
||||
};
|
||||
|
||||
@@ -201,9 +261,6 @@ void SettingsStorage::removeValue(const QString &key)
|
||||
QVariantHash TransactionalSettings::read()
|
||||
{
|
||||
QVariantHash res;
|
||||
#ifdef QSETTINGS_SYNC_IS_SAVE
|
||||
deserialize(m_name, res);
|
||||
#else
|
||||
bool writeBackNeeded = false;
|
||||
QString newPath = deserialize(m_name + QLatin1String("_new"), res);
|
||||
if (!newPath.isEmpty()) { // "_new" file is NOT empty
|
||||
@@ -222,15 +279,12 @@ QVariantHash TransactionalSettings::read()
|
||||
|
||||
if (writeBackNeeded)
|
||||
write(res);
|
||||
#endif
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
bool TransactionalSettings::write(const QVariantHash &data)
|
||||
{
|
||||
#ifdef QSETTINGS_SYNC_IS_SAVE
|
||||
serialize(m_name, data);
|
||||
#else
|
||||
// QSettings delete the file before writing it out. This can result in problems
|
||||
// if the disk is full or a power outage occurs. Those events might occur
|
||||
// between deleting the file and recreating it. This is a safety measure.
|
||||
@@ -247,7 +301,7 @@ bool TransactionalSettings::write(const QVariantHash &data)
|
||||
finalPath.remove(index, 4);
|
||||
Utils::Fs::forceRemove(finalPath);
|
||||
QFile::rename(newPath, finalPath);
|
||||
#endif
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
73
src/base/settingvalue.h
Normal file
@@ -0,0 +1,73 @@
|
||||
/*
|
||||
* Bittorrent Client using Qt and libtorrent.
|
||||
* Copyright (C) 2016 Vladimir Golovnev <glassez@yandex.ru>
|
||||
*
|
||||
* 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 SETTINGVALUE_H
|
||||
#define SETTINGVALUE_H
|
||||
|
||||
#include <functional>
|
||||
#include <QString>
|
||||
|
||||
#include "settingsstorage.h"
|
||||
|
||||
template <typename T>
|
||||
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; })
|
||||
: m_keyName(QLatin1String(keyName))
|
||||
, m_value(proxyFunc(SettingsStorage::instance()->loadValue(
|
||||
m_keyName, defaultValue).template value<T>()))
|
||||
{
|
||||
}
|
||||
|
||||
T value() const
|
||||
{
|
||||
return m_value;
|
||||
}
|
||||
|
||||
CachedSettingValue<T> &operator=(const T &newValue)
|
||||
{
|
||||
m_value = newValue;
|
||||
SettingsStorage::instance()->storeValue(m_keyName, m_value);
|
||||
return *this;
|
||||
}
|
||||
|
||||
operator T() const
|
||||
{
|
||||
return value();
|
||||
}
|
||||
|
||||
private:
|
||||
const QString m_keyName;
|
||||
T m_value;
|
||||
};
|
||||
|
||||
#endif // SETTINGVALUE_H
|
||||
@@ -92,9 +92,11 @@ void TorrentFileGuard::setAutoDeleteMode(TorrentFileGuard::AutoDeleteMode mode)
|
||||
|
||||
QMetaEnum TorrentFileGuard::modeMetaEnum()
|
||||
{
|
||||
#if QT_VERSION >= QT_VERSION_CHECK(5, 7, 0)
|
||||
#if QT_VERSION >= QT_VERSION_CHECK(5, 5, 0)
|
||||
return QMetaEnum::fromType<AutoDeleteMode>();
|
||||
#else
|
||||
return staticMetaObject.enumerator(staticMetaObject.indexOfEnumerator("AutoDeleteMode"));
|
||||
const int enumeratorIndex = staticMetaObject.indexOfEnumerator("AutoDeleteMode");
|
||||
Q_ASSERT(enumeratorIndex >= 0);
|
||||
return staticMetaObject.enumerator(enumeratorIndex);
|
||||
#endif
|
||||
}
|
||||
|
||||
@@ -26,6 +26,9 @@
|
||||
* exception statement from your version.
|
||||
*/
|
||||
|
||||
#ifndef TOFFENTFILEGURAD_H
|
||||
#define TOFFENTFILEGURAD_H
|
||||
|
||||
#include <QString>
|
||||
#include <QMetaType>
|
||||
|
||||
@@ -50,6 +53,10 @@ private:
|
||||
class TorrentFileGuard
|
||||
{
|
||||
Q_GADGET
|
||||
// moc from Qt4 ignores Q_ENUMS when it is behind #if QT_VERSION check
|
||||
// this declaration is needed for Qt 4 only
|
||||
// TODO Qt5: remove when dropping Qt4 support
|
||||
Q_ENUMS(AutoDeleteMode)
|
||||
|
||||
public:
|
||||
TorrentFileGuard(const QString &path = QString());
|
||||
@@ -72,9 +79,7 @@ public:
|
||||
|
||||
private:
|
||||
static QMetaEnum modeMetaEnum();
|
||||
#if QT_VERSION < QT_VERSION_CHECK(5, 5, 0)
|
||||
Q_ENUMS(AutoDeleteMode)
|
||||
#else
|
||||
#if QT_VERSION >= QT_VERSION_CHECK(5, 5, 0)
|
||||
Q_ENUM(AutoDeleteMode)
|
||||
#endif
|
||||
AutoDeleteMode m_mode;
|
||||
@@ -87,9 +92,12 @@ private:
|
||||
// This problem is NOT present in Qt 5.7.0 and maybe in some older Qt 5 versions too
|
||||
// Qt 4.8.7 has it.
|
||||
// Therefore, we can't inherit FileGuard :(
|
||||
// TODO Qt5: port to private inheritance when dropping Qt 4 support
|
||||
FileGuard m_guard;
|
||||
};
|
||||
|
||||
#if QT_VERSION < QT_VERSION_CHECK(5, 5, 0)
|
||||
Q_DECLARE_METATYPE(TorrentFileGuard::AutoDeleteMode)
|
||||
#endif
|
||||
|
||||
#endif // TOFFENTFILEGURAD_H
|
||||
|
||||
@@ -35,6 +35,7 @@
|
||||
// we put all problematic UTF-8 chars/strings in this file.
|
||||
// See issue #3059 for more details (https://github.com/qbittorrent/qBittorrent/issues/3059).
|
||||
const char C_INFINITY[] = "∞";
|
||||
const char C_NON_BREAKING_SPACE[] = " ";
|
||||
const char C_UP[] = "▲";
|
||||
const char C_DOWN[] = "▼";
|
||||
const char C_COPYRIGHT[] = "©";
|
||||
@@ -46,16 +47,20 @@ const char C_LOCALE_ESPERANTO[] = "Esperanto";
|
||||
const char C_LOCALE_FRENCH[] = "Français";
|
||||
const char C_LOCALE_GERMAN[] = "Deutsch";
|
||||
const char C_LOCALE_HUNGARIAN[] = "Magyar";
|
||||
const char C_LOCALE_ICELANDIC[] = "Íslenska";
|
||||
const char C_LOCALE_INDONESIAN[] = "Bahasa Indonesia";
|
||||
const char C_LOCALE_ITALIAN[] = "Italiano";
|
||||
const char C_LOCALE_DUTCH[] = "Nederlands";
|
||||
const char C_LOCALE_SPANISH[] = "Español";
|
||||
const char C_LOCALE_CATALAN[] = "Català";
|
||||
const char C_LOCALE_GALICIAN[] = "Galego";
|
||||
const char C_LOCALE_OCCITAN[] = "lenga d'òc";
|
||||
const char C_LOCALE_PORTUGUESE[] = "Português";
|
||||
const char C_LOCALE_PORTUGUESE_BRAZIL[] = "Português brasileiro";
|
||||
const char C_LOCALE_POLISH[] = "Polski";
|
||||
const char C_LOCALE_LATVIAN[] = "latviešu valoda";
|
||||
const char C_LOCALE_LITHUANIAN[] = "Lietuvių";
|
||||
const char C_LOCALE_MALAY[] = "بهاس ملايو";
|
||||
const char C_LOCALE_CZECH[] = "Čeština";
|
||||
const char C_LOCALE_SLOVAK[] = "Slovenčina";
|
||||
const char C_LOCALE_SLOVENIAN[] = "Slovenščina";
|
||||
@@ -71,6 +76,7 @@ const char C_LOCALE_NORWEGIAN[] = "Norsk";
|
||||
const char C_LOCALE_DANISH[] = "Dansk";
|
||||
const char C_LOCALE_BULGARIAN[] = "Български";
|
||||
const char C_LOCALE_UKRAINIAN[] = "Українська";
|
||||
const char C_LOCALE_UZBEK[] = "أۇزبېك";
|
||||
const char C_LOCALE_RUSSIAN[] = "Русский";
|
||||
const char C_LOCALE_JAPANESE[] = "日本語";
|
||||
const char C_LOCALE_HEBREW[] = "עברית";
|
||||
|
||||
@@ -269,67 +269,43 @@ bool Utils::Fs::isValidFileSystemName(const QString &name, bool allowSeparators)
|
||||
return !name.contains(regex);
|
||||
}
|
||||
|
||||
qlonglong Utils::Fs::freeDiskSpaceOnPath(QString path)
|
||||
qulonglong Utils::Fs::freeDiskSpaceOnPath(const QString &path)
|
||||
{
|
||||
if (path.isEmpty()) return -1;
|
||||
QDir dir_path(path);
|
||||
if (!dir_path.exists()) {
|
||||
QStringList parts = path.split("/");
|
||||
while (parts.size() > 1 && !QDir(parts.join("/")).exists()) {
|
||||
parts.removeLast();
|
||||
}
|
||||
dir_path = QDir(parts.join("/"));
|
||||
if (!dir_path.exists()) return -1;
|
||||
}
|
||||
Q_ASSERT(dir_path.exists());
|
||||
if (path.isEmpty()) return 0;
|
||||
|
||||
#ifndef Q_OS_WIN
|
||||
unsigned long long available;
|
||||
#ifdef Q_OS_HAIKU
|
||||
const QString statfs_path = dir_path.path() + "/.";
|
||||
dev_t device = dev_for_path (qPrintable(statfs_path));
|
||||
if (device >= 0) {
|
||||
fs_info info;
|
||||
if (fs_stat_dev(device, &info) == B_OK) {
|
||||
available = ((unsigned long long)(info.free_blocks * info.block_size));
|
||||
return available;
|
||||
}
|
||||
QDir dirPath(path);
|
||||
if (!dirPath.exists()) {
|
||||
QStringList parts = path.split("/");
|
||||
while (parts.size() > 1 && !QDir(parts.join("/")).exists())
|
||||
parts.removeLast();
|
||||
|
||||
dirPath = QDir(parts.join("/"));
|
||||
if (!dirPath.exists()) return 0;
|
||||
}
|
||||
return -1;
|
||||
Q_ASSERT(dirPath.exists());
|
||||
|
||||
#if defined(Q_OS_WIN)
|
||||
ULARGE_INTEGER bytesFree;
|
||||
LPCWSTR nativePath = reinterpret_cast<LPCWSTR>((toNativePath(dirPath.path())).utf16());
|
||||
if (GetDiskFreeSpaceExW(nativePath, &bytesFree, NULL, NULL) == 0)
|
||||
return 0;
|
||||
return bytesFree.QuadPart;
|
||||
#elif defined(Q_OS_HAIKU)
|
||||
const QString statfsPath = dirPath.path() + "/.";
|
||||
dev_t device = dev_for_path(qPrintable(statfsPath));
|
||||
if (device < 0)
|
||||
return 0;
|
||||
fs_info info;
|
||||
if (fs_stat_dev(device, &info) != B_OK)
|
||||
return 0;
|
||||
return ((qulonglong) info.free_blocks * (qulonglong) info.block_size);
|
||||
#else
|
||||
struct statfs stats;
|
||||
const QString statfs_path = dir_path.path() + "/.";
|
||||
const int ret = statfs(qPrintable(statfs_path), &stats);
|
||||
if (ret == 0) {
|
||||
available = ((unsigned long long)stats.f_bavail)
|
||||
* ((unsigned long long)stats.f_bsize);
|
||||
return available;
|
||||
}
|
||||
else {
|
||||
return -1;
|
||||
}
|
||||
#endif
|
||||
#else
|
||||
typedef BOOL (WINAPI *GetDiskFreeSpaceEx_t)(LPCTSTR,
|
||||
PULARGE_INTEGER,
|
||||
PULARGE_INTEGER,
|
||||
PULARGE_INTEGER);
|
||||
GetDiskFreeSpaceEx_t pGetDiskFreeSpaceEx =
|
||||
(GetDiskFreeSpaceEx_t)::GetProcAddress(::GetModuleHandleW(L"kernel32.dll"), "GetDiskFreeSpaceExW");
|
||||
if (pGetDiskFreeSpaceEx) {
|
||||
ULARGE_INTEGER bytesFree, bytesTotal;
|
||||
unsigned long long *ret;
|
||||
if (pGetDiskFreeSpaceEx((LPCTSTR)(toNativePath(dir_path.path())).utf16(), &bytesFree, &bytesTotal, NULL)) {
|
||||
ret = (unsigned long long*)&bytesFree;
|
||||
return *ret;
|
||||
}
|
||||
else {
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
else {
|
||||
return -1;
|
||||
}
|
||||
const QString statfsPath = dirPath.path() + "/.";
|
||||
const int ret = statfs(qPrintable(statfsPath), &stats);
|
||||
if (ret != 0)
|
||||
return 0;
|
||||
return ((qulonglong) stats.f_bavail * (qulonglong) stats.f_bsize);
|
||||
#endif
|
||||
}
|
||||
|
||||
@@ -378,19 +354,17 @@ QString Utils::Fs::expandPathAbs(const QString& path)
|
||||
QString Utils::Fs::QDesktopServicesDataLocation()
|
||||
{
|
||||
QString result;
|
||||
#ifdef Q_OS_WIN
|
||||
LPWSTR path=new WCHAR[256];
|
||||
if (SHGetSpecialFolderPath(0, path, CSIDL_LOCAL_APPDATA, FALSE))
|
||||
#if defined(Q_OS_WIN)
|
||||
wchar_t path[MAX_PATH + 1] = {L'\0'};
|
||||
if (SHGetSpecialFolderPathW(0, path, CSIDL_LOCAL_APPDATA, FALSE))
|
||||
result = fromNativePath(QString::fromWCharArray(path));
|
||||
if (!QCoreApplication::applicationName().isEmpty())
|
||||
result += QLatin1String("/") + qApp->applicationName();
|
||||
#else
|
||||
#ifdef Q_OS_MAC
|
||||
#elif defined(Q_OS_MAC)
|
||||
FSRef ref;
|
||||
OSErr err = FSFindFolder(kUserDomain, kApplicationSupportFolderType, false, &ref);
|
||||
if (err)
|
||||
return QString();
|
||||
QString path;
|
||||
QByteArray ba(2048, 0);
|
||||
if (FSRefMakePath(&ref, reinterpret_cast<UInt8 *>(ba.data()), ba.size()) == noErr)
|
||||
result = QString::fromUtf8(ba).normalized(QString::NormalizationForm_C);
|
||||
@@ -402,7 +376,6 @@ QString Utils::Fs::QDesktopServicesDataLocation()
|
||||
xdgDataHome += QLatin1String("/data/")
|
||||
+ qApp->applicationName();
|
||||
result = xdgDataHome;
|
||||
#endif
|
||||
#endif
|
||||
if (!result.endsWith("/"))
|
||||
result += "/";
|
||||
@@ -518,3 +491,10 @@ QString Utils::Fs::cacheLocation()
|
||||
locationDir.mkpath(locationDir.absolutePath());
|
||||
return location;
|
||||
}
|
||||
|
||||
QString Utils::Fs::tempPath()
|
||||
{
|
||||
static const QString path = QDir::tempPath() + "/.qBittorrent/";
|
||||
QDir().mkdir(path);
|
||||
return path;
|
||||
}
|
||||
|
||||
@@ -50,7 +50,7 @@ namespace Utils
|
||||
bool sameFiles(const QString& path1, const QString& path2);
|
||||
QString toValidFileSystemName(const QString &name, bool allowSeparators = false);
|
||||
bool isValidFileSystemName(const QString& name, bool allowSeparators = false);
|
||||
qlonglong freeDiskSpaceOnPath(QString path);
|
||||
qulonglong freeDiskSpaceOnPath(const QString &path);
|
||||
QString branchPath(const QString& file_path, QString* removed = 0);
|
||||
bool sameFileNames(const QString& first, const QString& second);
|
||||
QString expandPath(const QString& path);
|
||||
@@ -67,6 +67,7 @@ namespace Utils
|
||||
/* End of Qt4 code */
|
||||
|
||||
QString cacheLocation();
|
||||
QString tempPath();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -94,7 +94,73 @@ static struct { const char *source; const char *comment; } units[] = {
|
||||
|
||||
void Utils::Misc::shutdownComputer(const ShutdownDialogAction &action)
|
||||
{
|
||||
#if (defined(Q_OS_UNIX) && !defined(Q_OS_MAC)) && defined(QT_DBUS_LIB)
|
||||
#if defined(Q_OS_WIN)
|
||||
HANDLE hToken; // handle to process token
|
||||
TOKEN_PRIVILEGES tkp; // pointer to token structure
|
||||
if (!OpenProcessToken(GetCurrentProcess(), TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY, &hToken))
|
||||
return;
|
||||
// Get the LUID for shutdown privilege.
|
||||
LookupPrivilegeValue(NULL, SE_SHUTDOWN_NAME,
|
||||
&tkp.Privileges[0].Luid);
|
||||
|
||||
tkp.PrivilegeCount = 1; // one privilege to set
|
||||
tkp.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED;
|
||||
|
||||
// Get shutdown privilege for this process.
|
||||
|
||||
AdjustTokenPrivileges(hToken, FALSE, &tkp, 0,
|
||||
(PTOKEN_PRIVILEGES) NULL, 0);
|
||||
|
||||
// Cannot test the return value of AdjustTokenPrivileges.
|
||||
|
||||
if (GetLastError() != ERROR_SUCCESS)
|
||||
return;
|
||||
|
||||
if (action == ShutdownDialogAction::Suspend)
|
||||
SetSuspendState(false, false, false);
|
||||
else if (action == ShutdownDialogAction::Hibernate)
|
||||
SetSuspendState(true, false, false);
|
||||
else
|
||||
InitiateSystemShutdownA(0, QCoreApplication::translate("misc", "qBittorrent will shutdown the computer now because all downloads are complete.").toLocal8Bit().data(), 10, true, false);
|
||||
|
||||
// Disable shutdown privilege.
|
||||
tkp.Privileges[0].Attributes = 0;
|
||||
AdjustTokenPrivileges(hToken, FALSE, &tkp, 0, (PTOKEN_PRIVILEGES) NULL, 0);
|
||||
|
||||
#elif defined(Q_OS_MAC)
|
||||
AEEventID EventToSend;
|
||||
if (action != ShutdownDialogAction::Shutdown)
|
||||
EventToSend = kAESleep;
|
||||
else
|
||||
EventToSend = kAEShutDown;
|
||||
AEAddressDesc targetDesc;
|
||||
static const ProcessSerialNumber kPSNOfSystemProcess = { 0, kSystemProcess };
|
||||
AppleEvent eventReply = {typeNull, NULL};
|
||||
AppleEvent appleEventToSend = {typeNull, NULL};
|
||||
|
||||
OSStatus error = AECreateDesc(typeProcessSerialNumber, &kPSNOfSystemProcess,
|
||||
sizeof(kPSNOfSystemProcess), &targetDesc);
|
||||
|
||||
if (error != noErr)
|
||||
return;
|
||||
|
||||
error = AECreateAppleEvent(kCoreEventClass, EventToSend, &targetDesc,
|
||||
kAutoGenerateReturnID, kAnyTransactionID, &appleEventToSend);
|
||||
|
||||
AEDisposeDesc(&targetDesc);
|
||||
if (error != noErr)
|
||||
return;
|
||||
|
||||
error = AESend(&appleEventToSend, &eventReply, kAENoReply,
|
||||
kAENormalPriority, kAEDefaultTimeout, NULL, NULL);
|
||||
|
||||
AEDisposeDesc(&appleEventToSend);
|
||||
if (error != noErr)
|
||||
return;
|
||||
|
||||
AEDisposeDesc(&eventReply);
|
||||
|
||||
#elif (defined(Q_OS_UNIX) && defined(QT_DBUS_LIB))
|
||||
// Use dbus to power off / suspend the system
|
||||
if (action != ShutdownDialogAction::Shutdown) {
|
||||
// Some recent systems use systemd's logind
|
||||
@@ -147,73 +213,9 @@ void Utils::Misc::shutdownComputer(const ShutdownDialogAction &action)
|
||||
QDBusConnection::systemBus());
|
||||
halIface.call("Shutdown");
|
||||
}
|
||||
#endif
|
||||
#ifdef Q_OS_MAC
|
||||
AEEventID EventToSend;
|
||||
if (action != ShutdownDialogAction::Shutdown)
|
||||
EventToSend = kAESleep;
|
||||
else
|
||||
EventToSend = kAEShutDown;
|
||||
AEAddressDesc targetDesc;
|
||||
static const ProcessSerialNumber kPSNOfSystemProcess = { 0, kSystemProcess };
|
||||
AppleEvent eventReply = {typeNull, NULL};
|
||||
AppleEvent appleEventToSend = {typeNull, NULL};
|
||||
|
||||
OSStatus error = AECreateDesc(typeProcessSerialNumber, &kPSNOfSystemProcess,
|
||||
sizeof(kPSNOfSystemProcess), &targetDesc);
|
||||
|
||||
if (error != noErr)
|
||||
return;
|
||||
|
||||
error = AECreateAppleEvent(kCoreEventClass, EventToSend, &targetDesc,
|
||||
kAutoGenerateReturnID, kAnyTransactionID, &appleEventToSend);
|
||||
|
||||
AEDisposeDesc(&targetDesc);
|
||||
if (error != noErr)
|
||||
return;
|
||||
|
||||
error = AESend(&appleEventToSend, &eventReply, kAENoReply,
|
||||
kAENormalPriority, kAEDefaultTimeout, NULL, NULL);
|
||||
|
||||
AEDisposeDesc(&appleEventToSend);
|
||||
if (error != noErr)
|
||||
return;
|
||||
|
||||
AEDisposeDesc(&eventReply);
|
||||
#endif
|
||||
#ifdef Q_OS_WIN
|
||||
HANDLE hToken; // handle to process token
|
||||
TOKEN_PRIVILEGES tkp; // pointer to token structure
|
||||
if (!OpenProcessToken(GetCurrentProcess(), TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY, &hToken))
|
||||
return;
|
||||
// Get the LUID for shutdown privilege.
|
||||
LookupPrivilegeValue(NULL, SE_SHUTDOWN_NAME,
|
||||
&tkp.Privileges[0].Luid);
|
||||
|
||||
tkp.PrivilegeCount = 1; // one privilege to set
|
||||
tkp.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED;
|
||||
|
||||
// Get shutdown privilege for this process.
|
||||
|
||||
AdjustTokenPrivileges(hToken, FALSE, &tkp, 0,
|
||||
(PTOKEN_PRIVILEGES) NULL, 0);
|
||||
|
||||
// Cannot test the return value of AdjustTokenPrivileges.
|
||||
|
||||
if (GetLastError() != ERROR_SUCCESS)
|
||||
return;
|
||||
|
||||
if (action == ShutdownDialogAction::Suspend)
|
||||
SetSuspendState(false, false, false);
|
||||
else if (action == ShutdownDialogAction::Hibernate)
|
||||
SetSuspendState(true, false, false);
|
||||
else
|
||||
InitiateSystemShutdownA(0, QCoreApplication::translate("misc", "qBittorrent will shutdown the computer now because all downloads are complete.").toLocal8Bit().data(), 10, true, false);
|
||||
|
||||
// Disable shutdown privilege.
|
||||
tkp.Privileges[0].Attributes = 0;
|
||||
AdjustTokenPrivileges(hToken, FALSE, &tkp, 0,
|
||||
(PTOKEN_PRIVILEGES) NULL, 0);
|
||||
#else
|
||||
Q_UNUSED(action);
|
||||
#endif
|
||||
}
|
||||
|
||||
@@ -356,14 +358,22 @@ QString Utils::Misc::friendlyUnit(qint64 bytesValue, bool isSpeed)
|
||||
return QCoreApplication::translate("misc", "Unknown", "Unknown (size)");
|
||||
QString ret;
|
||||
if (unit == SizeUnit::Byte)
|
||||
ret = QString::number(bytesValue) + " " + unitString(unit);
|
||||
ret = QString::number(bytesValue) + QString::fromUtf8(C_NON_BREAKING_SPACE) + unitString(unit);
|
||||
else
|
||||
ret = Utils::String::fromDouble(friendlyVal, 1) + " " + unitString(unit);
|
||||
ret = Utils::String::fromDouble(friendlyVal, friendlyUnitPrecision(unit)) + QString::fromUtf8(C_NON_BREAKING_SPACE) + unitString(unit);
|
||||
if (isSpeed)
|
||||
ret += QCoreApplication::translate("misc", "/s", "per second");
|
||||
return ret;
|
||||
}
|
||||
|
||||
int Utils::Misc::friendlyUnitPrecision(SizeUnit unit)
|
||||
{
|
||||
// friendlyUnit's number of digits after the decimal point
|
||||
if (unit <= SizeUnit::MebiByte) return 1;
|
||||
else if (unit == SizeUnit::GibiByte) return 2;
|
||||
else return 3;
|
||||
}
|
||||
|
||||
qlonglong Utils::Misc::sizeInBytes(qreal size, Utils::Misc::SizeUnit unit)
|
||||
{
|
||||
for (int i = 0; i < static_cast<int>(unit); ++i)
|
||||
@@ -430,21 +440,27 @@ QString Utils::Misc::userFriendlyDuration(qlonglong seconds)
|
||||
{
|
||||
if ((seconds < 0) || (seconds >= MAX_ETA))
|
||||
return QString::fromUtf8(C_INFINITY);
|
||||
|
||||
if (seconds == 0)
|
||||
return "0";
|
||||
|
||||
if (seconds < 60)
|
||||
return QCoreApplication::translate("misc", "< 1m", "< 1 minute");
|
||||
int minutes = seconds / 60;
|
||||
|
||||
qlonglong minutes = seconds / 60;
|
||||
if (minutes < 60)
|
||||
return QCoreApplication::translate("misc", "%1m", "e.g: 10minutes").arg(QString::number(minutes));
|
||||
int hours = minutes / 60;
|
||||
minutes = minutes - hours * 60;
|
||||
|
||||
qlonglong hours = minutes / 60;
|
||||
minutes -= hours * 60;
|
||||
if (hours < 24)
|
||||
return QCoreApplication::translate("misc", "%1h %2m", "e.g: 3hours 5minutes").arg(QString::number(hours)).arg(QString::number(minutes));
|
||||
int days = hours / 24;
|
||||
hours = hours - days * 24;
|
||||
|
||||
qlonglong days = hours / 24;
|
||||
hours -= days * 24;
|
||||
if (days < 100)
|
||||
return QCoreApplication::translate("misc", "%1d %2h", "e.g: 2days 10hours").arg(QString::number(days)).arg(QString::number(hours));
|
||||
|
||||
return QString::fromUtf8(C_INFINITY);
|
||||
}
|
||||
|
||||
@@ -580,7 +596,7 @@ void Utils::Misc::openFolderSelect(const QString &absolutePath)
|
||||
}
|
||||
#ifdef Q_OS_WIN
|
||||
HRESULT hresult = ::CoInitializeEx(nullptr, COINIT_MULTITHREADED);
|
||||
ITEMIDLIST *pidl = ::ILCreateFromPathW(reinterpret_cast<PCTSTR>(Utils::Fs::toNativePath(path).utf16()));
|
||||
PIDLIST_ABSOLUTE pidl = ::ILCreateFromPathW(reinterpret_cast<PCTSTR>(Utils::Fs::toNativePath(path).utf16()));
|
||||
if (pidl) {
|
||||
::SHOpenFolderAndSelectItems(pidl, 0, nullptr, 0);
|
||||
::ILFree(pidl);
|
||||
|
||||
@@ -88,6 +88,7 @@ namespace Utils
|
||||
// value must be given in bytes
|
||||
bool friendlyUnit(qint64 sizeInBytes, qreal& val, SizeUnit& unit);
|
||||
QString friendlyUnit(qint64 bytesValue, bool isSpeed = false);
|
||||
int friendlyUnitPrecision(SizeUnit unit);
|
||||
qint64 sizeInBytes(qreal size, SizeUnit unit);
|
||||
|
||||
bool isPreviewable(const QString& extension);
|
||||
|
||||
@@ -177,8 +177,12 @@ QString Utils::String::fromStdString(const std::string &str)
|
||||
|
||||
std::string Utils::String::toStdString(const QString &str)
|
||||
{
|
||||
#ifdef QBT_USES_QT5
|
||||
return str.toStdString();
|
||||
#else
|
||||
QByteArray utf8 = str.toUtf8();
|
||||
return std::string(utf8.constData(), utf8.length());
|
||||
#endif
|
||||
}
|
||||
|
||||
// to send numbers instead of strings with suffixes
|
||||
@@ -207,3 +211,12 @@ bool Utils::String::slowEquals(const QByteArray &a, const QByteArray &b)
|
||||
|
||||
return (diff == 0);
|
||||
}
|
||||
|
||||
QString Utils::String::toHtmlEscaped(const QString &str)
|
||||
{
|
||||
#ifdef QBT_USES_QT5
|
||||
return str.toHtmlEscaped();
|
||||
#else
|
||||
return Qt::escape(str);
|
||||
#endif
|
||||
}
|
||||
|
||||
@@ -47,6 +47,8 @@ namespace Utils
|
||||
// Taken from https://crackstation.net/hashing-security.htm
|
||||
bool slowEquals(const QByteArray &a, const QByteArray &b);
|
||||
|
||||
QString toHtmlEscaped(const QString &str);
|
||||
|
||||
bool naturalCompareCaseSensitive(const QString &left, const QString &right);
|
||||
bool naturalCompareCaseInsensitive(const QString &left, const QString &right);
|
||||
}
|
||||
|
||||
@@ -32,6 +32,8 @@ addnewtorrentdialog.h
|
||||
advancedsettings.h
|
||||
advancedsettings.h
|
||||
autoexpandabledialog.h
|
||||
categoryfiltermodel.h
|
||||
categoryfilterwidget.h
|
||||
cookiesdialog.h
|
||||
cookiesmodel.h
|
||||
deletionconfirmationdlg.h
|
||||
@@ -71,6 +73,8 @@ set(QBT_GUI_SOURCES
|
||||
addnewtorrentdialog.cpp
|
||||
advancedsettings.cpp
|
||||
autoexpandabledialog.cpp
|
||||
categoryfiltermodel.cpp
|
||||
categoryfilterwidget.cpp
|
||||
cookiesdialog.cpp
|
||||
cookiesmodel.cpp
|
||||
executionlog.cpp
|
||||
|
||||
@@ -61,7 +61,7 @@ public:
|
||||
"</table>"
|
||||
"</p>")
|
||||
.arg(tr("An advanced BitTorrent client programmed in C++, based on Qt toolkit and libtorrent-rasterbar."))
|
||||
.arg(tr("Copyright %1 2006-2016 The qBittorrent project").arg(QString::fromUtf8(C_COPYRIGHT)))
|
||||
.arg(tr("Copyright %1 2006-2017 The qBittorrent project").arg(QString::fromUtf8(C_COPYRIGHT)))
|
||||
.arg(tr("Home Page:"))
|
||||
.arg(tr("Forum:"))
|
||||
.arg(tr("Bug Tracker:"));
|
||||
|
||||
@@ -58,7 +58,6 @@
|
||||
|
||||
#define SETTINGS_KEY(name) "AddNewTorrentDialog/" name
|
||||
const QString KEY_ENABLED = SETTINGS_KEY("Enabled");
|
||||
const QString KEY_DEFAULTSAVEPATH = SETTINGS_KEY("DefaultSavePath");
|
||||
const QString KEY_DEFAULTCATEGORY = SETTINGS_KEY("DefaultCategory");
|
||||
const QString KEY_TREEHEADERSTATE = SETTINGS_KEY("TreeHeaderState");
|
||||
const QString KEY_WIDTH = SETTINGS_KEY("Width");
|
||||
@@ -118,7 +117,7 @@ AddNewTorrentDialog::AddNewTorrentDialog(QWidget *parent)
|
||||
// Signal / slots
|
||||
connect(ui->adv_button, SIGNAL(clicked(bool)), SLOT(showAdvancedSettings(bool)));
|
||||
connect(ui->doNotDeleteTorrentCheckBox, SIGNAL(clicked(bool)), SLOT(doNotDeleteTorrentClicked(bool)));
|
||||
editHotkey = new QShortcut(QKeySequence("F2"), ui->contentTreeView, 0, 0, Qt::WidgetShortcut);
|
||||
editHotkey = new QShortcut(Qt::Key_F2, ui->contentTreeView, 0, 0, Qt::WidgetShortcut);
|
||||
connect(editHotkey, SIGNAL(activated()), SLOT(renameSelectedFile()));
|
||||
connect(ui->contentTreeView, SIGNAL(doubleClicked(QModelIndex)), SLOT(renameSelectedFile()));
|
||||
|
||||
@@ -394,7 +393,7 @@ void AddNewTorrentDialog::onSavePathChanged(int index)
|
||||
ui->defaultSavePathCheckBox->setChecked(false);
|
||||
ui->defaultSavePathCheckBox->setVisible(
|
||||
QDir(ui->savePathComboBox->itemData(ui->savePathComboBox->currentIndex()).toString())
|
||||
!= QDir(defaultSavePath()));
|
||||
!= QDir(BitTorrent::Session::instance()->defaultSavePath()));
|
||||
|
||||
// Remember index
|
||||
m_oldIndex = index;
|
||||
@@ -567,7 +566,7 @@ void AddNewTorrentDialog::setdialogPosition()
|
||||
|
||||
void AddNewTorrentDialog::populateSavePathComboBox()
|
||||
{
|
||||
QString defSavePath = defaultSavePath();
|
||||
QString defSavePath = BitTorrent::Session::instance()->defaultSavePath();
|
||||
|
||||
ui->savePathComboBox->clear();
|
||||
ui->savePathComboBox->addItem(Utils::Fs::toNativePath(defSavePath), defSavePath);
|
||||
@@ -646,7 +645,7 @@ void AddNewTorrentDialog::accept()
|
||||
params.savePath = savePath;
|
||||
saveSavePathHistory();
|
||||
if (ui->defaultSavePathCheckBox->isChecked())
|
||||
settings()->storeValue(KEY_DEFAULTSAVEPATH, savePath);
|
||||
BitTorrent::Session::instance()->setDefaultSavePath(savePath);
|
||||
}
|
||||
|
||||
setEnabled(!ui->never_show_cb->isChecked());
|
||||
@@ -690,7 +689,6 @@ void AddNewTorrentDialog::updateMetadata(const BitTorrent::TorrentInfo &info)
|
||||
|
||||
// Update UI
|
||||
setupTreeview();
|
||||
TMMChanged(ui->comboTTM->currentIndex());
|
||||
setMetadataProgressIndicator(false, tr("Metadata retrieval complete"));
|
||||
}
|
||||
|
||||
@@ -744,13 +742,6 @@ void AddNewTorrentDialog::setupTreeview()
|
||||
setdialogPosition();
|
||||
}
|
||||
|
||||
QString AddNewTorrentDialog::defaultSavePath() const
|
||||
{
|
||||
return Utils::Fs::fromNativePath(
|
||||
settings()->loadValue(KEY_DEFAULTSAVEPATH,
|
||||
BitTorrent::Session::instance()->defaultSavePath()).toString());
|
||||
}
|
||||
|
||||
void AddNewTorrentDialog::handleDownloadFailed(const QString &url, const QString &reason)
|
||||
{
|
||||
MessageBoxRaised::critical(0, tr("Download Error"), QString("Cannot download '%1': %2").arg(url).arg(reason));
|
||||
|
||||
@@ -97,7 +97,6 @@ private:
|
||||
void saveState();
|
||||
void setMetadataProgressIndicator(bool visibleIndicator, const QString &labelText = QString());
|
||||
void setupTreeview();
|
||||
QString defaultSavePath() const;
|
||||
void setCommentText(const QString &str) const;
|
||||
|
||||
void showEvent(QShowEvent *event) override;
|
||||
|
||||
@@ -27,11 +27,14 @@
|
||||
*/
|
||||
|
||||
#include "advancedsettings.h"
|
||||
|
||||
#include <QFont>
|
||||
#include <QHeaderView>
|
||||
#include <QHostAddress>
|
||||
#include <QNetworkInterface>
|
||||
|
||||
#include "app/application.h"
|
||||
#include "base/bittorrent/session.h"
|
||||
#include "base/preferences.h"
|
||||
#include "gui/mainwindow.h"
|
||||
|
||||
@@ -63,6 +66,7 @@ enum AdvSettingsRows
|
||||
RESOLVE_COUNTRIES,
|
||||
PROGRAM_NOTIFICATIONS,
|
||||
TORRENT_ADDED_NOTIFICATIONS,
|
||||
DOWNLOAD_TRACKER_FAVICON,
|
||||
#if (defined(Q_OS_UNIX) && !defined(Q_OS_MAC))
|
||||
USE_ICON_THEME,
|
||||
#endif
|
||||
@@ -83,9 +87,8 @@ enum AdvSettingsRows
|
||||
// seeding
|
||||
SUPER_SEEDING,
|
||||
// tracker
|
||||
TRACKER_EXCHANGE,
|
||||
ANNOUNCE_ALL_TRACKERS,
|
||||
NETWORK_ADDRESS,
|
||||
ANNOUNCE_IP,
|
||||
|
||||
ROW_COUNT
|
||||
};
|
||||
@@ -116,61 +119,63 @@ AdvancedSettings::AdvancedSettings(QWidget *parent)
|
||||
void AdvancedSettings::saveAdvancedSettings()
|
||||
{
|
||||
Preferences* const pref = Preferences::instance();
|
||||
BitTorrent::Session *const session = BitTorrent::Session::instance();
|
||||
|
||||
// Disk write cache
|
||||
pref->setDiskCacheSize(spin_cache.value());
|
||||
pref->setDiskCacheTTL(spin_cache_ttl.value());
|
||||
session->setDiskCacheSize(spin_cache.value());
|
||||
session->setDiskCacheTTL(spin_cache_ttl.value());
|
||||
// Enable OS cache
|
||||
pref->setOsCache(cb_os_cache.isChecked());
|
||||
session->setUseOSCache(cb_os_cache.isChecked());
|
||||
// Save resume data interval
|
||||
pref->setSaveResumeDataInterval(spin_save_resume_data_interval.value());
|
||||
session->setSaveResumeDataInterval(spin_save_resume_data_interval.value());
|
||||
// Outgoing ports
|
||||
pref->setOutgoingPortsMin(outgoing_ports_min.value());
|
||||
pref->setOutgoingPortsMax(outgoing_ports_max.value());
|
||||
session->setOutgoingPortsMin(outgoing_ports_min.value());
|
||||
session->setOutgoingPortsMax(outgoing_ports_max.value());
|
||||
// Recheck torrents on completion
|
||||
pref->recheckTorrentsOnCompletion(cb_recheck_completed.isChecked());
|
||||
// Transfer list refresh interval
|
||||
pref->setRefreshInterval(spin_list_refresh.value());
|
||||
session->setRefreshInterval(spin_list_refresh.value());
|
||||
// Peer resolution
|
||||
pref->resolvePeerCountries(cb_resolve_countries.isChecked());
|
||||
pref->resolvePeerHostNames(cb_resolve_hosts.isChecked());
|
||||
// Max Half-Open connections
|
||||
pref->setMaxHalfOpenConnections(spin_maxhalfopen.value());
|
||||
session->setMaxHalfOpenConnections(spin_maxhalfopen.value());
|
||||
// Super seeding
|
||||
pref->enableSuperSeeding(cb_super_seeding.isChecked());
|
||||
session->setSuperSeedingEnabled(cb_super_seeding.isChecked());
|
||||
// Network interface
|
||||
if (combo_iface.currentIndex() == 0) {
|
||||
// All interfaces (default)
|
||||
pref->setNetworkInterface(QString::null);
|
||||
pref->setNetworkInterfaceName(QString::null);
|
||||
session->setNetworkInterface(QString());
|
||||
session->setNetworkInterfaceName(QString());
|
||||
}
|
||||
else {
|
||||
pref->setNetworkInterface(combo_iface.itemData(combo_iface.currentIndex()).toString());
|
||||
pref->setNetworkInterfaceName(combo_iface.currentText());
|
||||
session->setNetworkInterface(combo_iface.itemData(combo_iface.currentIndex()).toString());
|
||||
session->setNetworkInterfaceName(combo_iface.currentText());
|
||||
}
|
||||
// Listen on IPv6 address
|
||||
pref->setListenIPv6(cb_listen_ipv6.isChecked());
|
||||
|
||||
// Interface address
|
||||
if (combo_iface_address.currentIndex() == 0) {
|
||||
// All addresses (default)
|
||||
pref->setNetworkInterfaceAddress(QString::null);
|
||||
session->setNetworkInterfaceAddress(QString::null);
|
||||
}
|
||||
else {
|
||||
QHostAddress ifaceAddr(combo_iface_address.currentText().trimmed());
|
||||
ifaceAddr.isNull() ? pref->setNetworkInterfaceAddress(QString::null) : pref->setNetworkInterfaceAddress(ifaceAddr.toString());
|
||||
ifaceAddr.isNull() ? session->setNetworkInterfaceAddress(QString::null) : session->setNetworkInterfaceAddress(ifaceAddr.toString());
|
||||
}
|
||||
// Network Announce address
|
||||
QHostAddress networkAddr(txt_network_address.text().trimmed());
|
||||
if (networkAddr.isNull())
|
||||
pref->setNetworkAddress("");
|
||||
else
|
||||
pref->setNetworkAddress(networkAddr.toString());
|
||||
session->setIPv6Enabled(cb_listen_ipv6.isChecked());
|
||||
// Announce IP
|
||||
QHostAddress addr(txtAnnounceIP.text().trimmed());
|
||||
session->setAnnounceIP(addr.isNull() ? "" : addr.toString());
|
||||
|
||||
// Program notification
|
||||
MainWindow * const mainWindow = static_cast<Application*>(QCoreApplication::instance())->mainWindow();
|
||||
mainWindow->setNotificationsEnabled(cb_program_notifications.isChecked());
|
||||
mainWindow->setTorrentAddedNotificationsEnabled(cb_torrent_added_notifications.isChecked());
|
||||
// Misc GUI properties
|
||||
mainWindow->setDownloadTrackerFavicon(cb_tracker_favicon.isChecked());
|
||||
|
||||
// Tracker
|
||||
pref->setTrackerEnabled(cb_tracker_status.isChecked());
|
||||
session->setTrackerEnabled(cb_tracker_status.isChecked());
|
||||
pref->setTrackerPort(spin_tracker_port.value());
|
||||
#if defined(Q_OS_WIN) || defined(Q_OS_MAC)
|
||||
pref->setUpdateCheckEnabled(cb_update_check.isChecked());
|
||||
@@ -180,9 +185,7 @@ void AdvancedSettings::saveAdvancedSettings()
|
||||
pref->useSystemIconTheme(cb_use_icon_theme.isChecked());
|
||||
#endif
|
||||
pref->setConfirmTorrentRecheck(cb_confirm_torrent_recheck.isChecked());
|
||||
// Tracker exchange
|
||||
pref->setTrackerExchangeEnabled(cb_enable_tracker_ext.isChecked());
|
||||
pref->setAnnounceToAllTrackers(cb_announce_all_trackers.isChecked());
|
||||
session->setAnnounceToAllTrackers(cb_announce_all_trackers.isChecked());
|
||||
}
|
||||
|
||||
void AdvancedSettings::updateCacheSpinSuffix(int value)
|
||||
@@ -197,7 +200,7 @@ void AdvancedSettings::updateInterfaceAddressCombo()
|
||||
{
|
||||
// Try to get the currently selected interface name
|
||||
const QString ifaceName = combo_iface.itemData(combo_iface.currentIndex()).toString(); // Empty string for the first element
|
||||
const QString currentAddress = Preferences::instance()->getNetworkInterfaceAddress();
|
||||
const QString currentAddress = BitTorrent::Session::instance()->networkInterfaceAddress();
|
||||
|
||||
//Clear all items and reinsert them, default to all
|
||||
combo_iface_address.clear();
|
||||
@@ -233,6 +236,8 @@ void AdvancedSettings::updateInterfaceAddressCombo()
|
||||
void AdvancedSettings::loadAdvancedSettings()
|
||||
{
|
||||
const Preferences* const pref = Preferences::instance();
|
||||
const BitTorrent::Session *const session = BitTorrent::Session::instance();
|
||||
|
||||
// add section headers
|
||||
QFont boldFont;
|
||||
boldFont.setBold(true);
|
||||
@@ -255,33 +260,33 @@ void AdvancedSettings::loadAdvancedSettings()
|
||||
// allocate 1536MiB and leave 512MiB to the rest of program data in RAM
|
||||
spin_cache.setMaximum(1536);
|
||||
#endif
|
||||
spin_cache.setValue(pref->diskCacheSize());
|
||||
spin_cache.setValue(session->diskCacheSize());
|
||||
updateCacheSpinSuffix(spin_cache.value());
|
||||
addRow(DISK_CACHE, tr("Disk write cache size"), &spin_cache);
|
||||
// Disk cache expiry
|
||||
spin_cache_ttl.setMinimum(15);
|
||||
spin_cache_ttl.setMaximum(600);
|
||||
spin_cache_ttl.setValue(pref->diskCacheTTL());
|
||||
spin_cache_ttl.setValue(session->diskCacheTTL());
|
||||
spin_cache_ttl.setSuffix(tr(" s", " seconds"));
|
||||
addRow(DISK_CACHE_TTL, tr("Disk cache expiry interval"), &spin_cache_ttl);
|
||||
// Enable OS cache
|
||||
cb_os_cache.setChecked(pref->osCache());
|
||||
cb_os_cache.setChecked(session->useOSCache());
|
||||
addRow(OS_CACHE, tr("Enable OS cache"), &cb_os_cache);
|
||||
// Save resume data interval
|
||||
spin_save_resume_data_interval.setMinimum(1);
|
||||
spin_save_resume_data_interval.setMaximum(1440);
|
||||
spin_save_resume_data_interval.setValue(pref->saveResumeDataInterval());
|
||||
spin_save_resume_data_interval.setValue(session->saveResumeDataInterval());
|
||||
spin_save_resume_data_interval.setSuffix(tr(" m", " minutes"));
|
||||
addRow(SAVE_RESUME_DATA_INTERVAL, tr("Save resume data interval", "How often the fastresume file is saved."), &spin_save_resume_data_interval);
|
||||
// Outgoing port Min
|
||||
outgoing_ports_min.setMinimum(0);
|
||||
outgoing_ports_min.setMaximum(65535);
|
||||
outgoing_ports_min.setValue(pref->outgoingPortsMin());
|
||||
outgoing_ports_min.setValue(session->outgoingPortsMin());
|
||||
addRow(OUTGOING_PORT_MIN, tr("Outgoing ports (Min) [0: Disabled]"), &outgoing_ports_min);
|
||||
// Outgoing port Min
|
||||
outgoing_ports_max.setMinimum(0);
|
||||
outgoing_ports_max.setMaximum(65535);
|
||||
outgoing_ports_max.setValue(pref->outgoingPortsMax());
|
||||
outgoing_ports_max.setValue(session->outgoingPortsMax());
|
||||
addRow(OUTGOING_PORT_MAX, tr("Outgoing ports (Max) [0: Disabled]"), &outgoing_ports_max);
|
||||
// Recheck completed torrents
|
||||
cb_recheck_completed.setChecked(pref->recheckTorrentsOnCompletion());
|
||||
@@ -289,7 +294,7 @@ void AdvancedSettings::loadAdvancedSettings()
|
||||
// Transfer list refresh interval
|
||||
spin_list_refresh.setMinimum(30);
|
||||
spin_list_refresh.setMaximum(99999);
|
||||
spin_list_refresh.setValue(pref->getRefreshInterval());
|
||||
spin_list_refresh.setValue(session->refreshInterval());
|
||||
spin_list_refresh.setSuffix(tr(" ms", " milliseconds"));
|
||||
addRow(LIST_REFRESH, tr("Transfer list refresh interval"), &spin_list_refresh);
|
||||
// Resolve Peer countries
|
||||
@@ -301,14 +306,14 @@ void AdvancedSettings::loadAdvancedSettings()
|
||||
// Max Half Open connections
|
||||
spin_maxhalfopen.setMinimum(0);
|
||||
spin_maxhalfopen.setMaximum(99999);
|
||||
spin_maxhalfopen.setValue(pref->getMaxHalfOpenConnections());
|
||||
spin_maxhalfopen.setValue(session->maxHalfOpenConnections());
|
||||
addRow(MAX_HALF_OPEN, tr("Maximum number of half-open connections [0: Unlimited]"), &spin_maxhalfopen);
|
||||
// Super seeding
|
||||
cb_super_seeding.setChecked(pref->isSuperSeedingEnabled());
|
||||
cb_super_seeding.setChecked(session->isSuperSeedingEnabled());
|
||||
addRow(SUPER_SEEDING, tr("Strict super seeding"), &cb_super_seeding);
|
||||
// Network interface
|
||||
combo_iface.addItem(tr("Any interface", "i.e. Any network interface"));
|
||||
const QString current_iface = pref->getNetworkInterface();
|
||||
const QString current_iface = session->networkInterface();
|
||||
bool interface_exists = current_iface.isEmpty();
|
||||
int i = 1;
|
||||
foreach (const QNetworkInterface& iface, QNetworkInterface::allInterfaces()) {
|
||||
@@ -328,7 +333,7 @@ void AdvancedSettings::loadAdvancedSettings()
|
||||
}
|
||||
// Saved interface does not exist, show it anyway
|
||||
if (!interface_exists) {
|
||||
combo_iface.addItem(pref->getNetworkInterfaceName(), current_iface);
|
||||
combo_iface.addItem(session->networkInterfaceName(), current_iface);
|
||||
combo_iface.setCurrentIndex(i);
|
||||
}
|
||||
addRow(NETWORK_IFACE, tr("Network Interface (requires restart)"), &combo_iface);
|
||||
@@ -336,11 +341,11 @@ void AdvancedSettings::loadAdvancedSettings()
|
||||
updateInterfaceAddressCombo();
|
||||
addRow(NETWORK_IFACE_ADDRESS, tr("Optional IP Address to bind to (requires restart)"), &combo_iface_address);
|
||||
// Listen on IPv6 address
|
||||
cb_listen_ipv6.setChecked(pref->getListenIPv6());
|
||||
cb_listen_ipv6.setChecked(session->isIPv6Enabled());
|
||||
addRow(NETWORK_LISTEN_IPV6, tr("Listen on IPv6 address (requires restart)"), &cb_listen_ipv6);
|
||||
// Announce address
|
||||
txt_network_address.setText(pref->getNetworkAddress());
|
||||
addRow(NETWORK_ADDRESS, tr("IP Address to report to trackers (requires restart)"), &txt_network_address);
|
||||
// Announce IP
|
||||
txtAnnounceIP.setText(session->announceIP());
|
||||
addRow(ANNOUNCE_IP, tr("IP Address to report to trackers (requires restart)"), &txtAnnounceIP);
|
||||
|
||||
// Program notifications
|
||||
const MainWindow * const mainWindow = static_cast<Application*>(QCoreApplication::instance())->mainWindow();
|
||||
@@ -349,8 +354,12 @@ void AdvancedSettings::loadAdvancedSettings()
|
||||
// Torrent added notifications
|
||||
cb_torrent_added_notifications.setChecked(mainWindow->isTorrentAddedNotificationsEnabled());
|
||||
addRow(TORRENT_ADDED_NOTIFICATIONS, tr("Display notifications for added torrents"), &cb_torrent_added_notifications);
|
||||
// Download tracker's favicon
|
||||
cb_tracker_favicon.setChecked(mainWindow->isDownloadTrackerFavicon());
|
||||
addRow(DOWNLOAD_TRACKER_FAVICON, tr("Download tracker's favicon"), &cb_tracker_favicon);
|
||||
|
||||
// Tracker State
|
||||
cb_tracker_status.setChecked(pref->isTrackerEnabled());
|
||||
cb_tracker_status.setChecked(session->isTrackerEnabled());
|
||||
addRow(TRACKER_STATUS, tr("Enable embedded tracker"), &cb_tracker_status);
|
||||
// Tracker port
|
||||
spin_tracker_port.setMinimum(1);
|
||||
@@ -368,17 +377,18 @@ void AdvancedSettings::loadAdvancedSettings()
|
||||
// Torrent recheck confirmation
|
||||
cb_confirm_torrent_recheck.setChecked(pref->confirmTorrentRecheck());
|
||||
addRow(CONFIRM_RECHECK_TORRENT, tr("Confirm torrent recheck"), &cb_confirm_torrent_recheck);
|
||||
// Tracker exchange
|
||||
cb_enable_tracker_ext.setChecked(pref->trackerExchangeEnabled());
|
||||
addRow(TRACKER_EXCHANGE, tr("Exchange trackers with other peers"), &cb_enable_tracker_ext);
|
||||
// Announce to all trackers
|
||||
cb_announce_all_trackers.setChecked(pref->announceToAllTrackers());
|
||||
cb_announce_all_trackers.setChecked(session->announceToAllTrackers());
|
||||
addRow(ANNOUNCE_ALL_TRACKERS, tr("Always announce to all trackers"), &cb_announce_all_trackers);
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
void AdvancedSettings::addRow(int row, const QString &rowText, T* widget)
|
||||
{
|
||||
// ignore mouse wheel event
|
||||
static WheelEventEater filter;
|
||||
widget->installEventFilter(&filter);
|
||||
|
||||
setItem(row, PROPERTY, new QTableWidgetItem(rowText));
|
||||
setCellWidget(row, VALUE, widget);
|
||||
|
||||
|
||||
@@ -29,6 +29,7 @@
|
||||
#ifndef ADVANCEDSETTINGS_H
|
||||
#define ADVANCEDSETTINGS_H
|
||||
|
||||
#include <QEvent>
|
||||
#include <QLabel>
|
||||
#include <QSpinBox>
|
||||
#include <QCheckBox>
|
||||
@@ -37,6 +38,22 @@
|
||||
#include <QTableWidget>
|
||||
|
||||
|
||||
class WheelEventEater: public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
private:
|
||||
bool eventFilter(QObject *obj, QEvent *event)
|
||||
{
|
||||
switch (event->type()) {
|
||||
case QEvent::Wheel:
|
||||
return true;
|
||||
default:
|
||||
return QObject::eventFilter(obj, event);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
class AdvancedSettings: public QTableWidget
|
||||
{
|
||||
Q_OBJECT
|
||||
@@ -60,11 +77,11 @@ private:
|
||||
|
||||
QLabel labelQbtLink, labelLibtorrentLink;
|
||||
QSpinBox spin_cache, spin_save_resume_data_interval, outgoing_ports_min, outgoing_ports_max, spin_list_refresh, spin_maxhalfopen, spin_tracker_port, spin_cache_ttl;
|
||||
QCheckBox cb_os_cache, cb_recheck_completed, cb_resolve_countries, cb_resolve_hosts,
|
||||
cb_super_seeding, cb_program_notifications, cb_torrent_added_notifications, cb_tracker_status,
|
||||
cb_confirm_torrent_recheck, cb_enable_tracker_ext, cb_listen_ipv6, cb_announce_all_trackers;
|
||||
QCheckBox cb_os_cache, cb_recheck_completed, cb_resolve_countries, cb_resolve_hosts, cb_super_seeding,
|
||||
cb_program_notifications, cb_torrent_added_notifications, cb_tracker_favicon, cb_tracker_status,
|
||||
cb_confirm_torrent_recheck, cb_listen_ipv6, cb_announce_all_trackers;
|
||||
QComboBox combo_iface, combo_iface_address;
|
||||
QLineEdit txt_network_address;
|
||||
QLineEdit txtAnnounceIP;
|
||||
|
||||
// OS dependent settings
|
||||
#if defined(Q_OS_WIN) || defined(Q_OS_MAC)
|
||||
|
||||
@@ -18,15 +18,6 @@
|
||||
<layout class="QHBoxLayout" name="horizontalLayout">
|
||||
<item>
|
||||
<widget class="QSlider" name="bandwidthSlider">
|
||||
<property name="minimum">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<property name="maximum">
|
||||
<number>1000</number>
|
||||
</property>
|
||||
<property name="sliderPosition">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<property name="orientation">
|
||||
<enum>Qt::Horizontal</enum>
|
||||
</property>
|
||||
|
||||
442
src/gui/categoryfiltermodel.cpp
Normal file
@@ -0,0 +1,442 @@
|
||||
/*
|
||||
* Bittorrent Client using Qt and libtorrent.
|
||||
* Copyright (C) 2016 Vladimir Golovnev <glassez@yandex.ru>
|
||||
*
|
||||
* 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 "categoryfiltermodel.h"
|
||||
|
||||
#include <QHash>
|
||||
#include <QIcon>
|
||||
|
||||
#include "base/bittorrent/torrenthandle.h"
|
||||
#include "base/bittorrent/session.h"
|
||||
#include "guiiconprovider.h"
|
||||
|
||||
class CategoryModelItem
|
||||
{
|
||||
public:
|
||||
CategoryModelItem()
|
||||
: m_parent(nullptr)
|
||||
, m_torrentsCount(0)
|
||||
{
|
||||
}
|
||||
|
||||
CategoryModelItem(CategoryModelItem *parent, QString categoryName, int torrentsCount = 0)
|
||||
: m_parent(nullptr)
|
||||
, m_name(categoryName)
|
||||
, m_torrentsCount(torrentsCount)
|
||||
{
|
||||
if (parent)
|
||||
parent->addChild(m_name, this);
|
||||
}
|
||||
|
||||
~CategoryModelItem()
|
||||
{
|
||||
clear();
|
||||
if (m_parent) {
|
||||
m_parent->m_torrentsCount -= m_torrentsCount;
|
||||
const QString uid = m_parent->m_children.key(this);
|
||||
m_parent->m_children.remove(uid);
|
||||
m_parent->m_childUids.removeOne(uid);
|
||||
}
|
||||
}
|
||||
|
||||
QString name() const
|
||||
{
|
||||
return m_name;
|
||||
}
|
||||
|
||||
QString fullName() const
|
||||
{
|
||||
if (!m_parent || m_parent->name().isEmpty())
|
||||
return m_name;
|
||||
|
||||
return QString("%1/%2").arg(m_parent->fullName()).arg(m_name);
|
||||
}
|
||||
|
||||
CategoryModelItem *parent() const
|
||||
{
|
||||
return m_parent;
|
||||
}
|
||||
|
||||
int torrentsCount() const
|
||||
{
|
||||
return m_torrentsCount;
|
||||
}
|
||||
|
||||
void increaseTorrentsCount()
|
||||
{
|
||||
++m_torrentsCount;
|
||||
if (m_parent)
|
||||
m_parent->increaseTorrentsCount();
|
||||
}
|
||||
|
||||
void decreaseTorrentsCount()
|
||||
{
|
||||
--m_torrentsCount;
|
||||
if (m_parent)
|
||||
m_parent->decreaseTorrentsCount();
|
||||
}
|
||||
|
||||
int pos() const
|
||||
{
|
||||
if (!m_parent) return -1;
|
||||
|
||||
return m_parent->m_childUids.indexOf(m_name);
|
||||
}
|
||||
|
||||
bool hasChild(const QString &name) const
|
||||
{
|
||||
return m_children.contains(name);
|
||||
}
|
||||
|
||||
int childCount() const
|
||||
{
|
||||
return m_children.count();
|
||||
}
|
||||
|
||||
CategoryModelItem *child(const QString &uid) const
|
||||
{
|
||||
return m_children.value(uid);
|
||||
}
|
||||
|
||||
CategoryModelItem *childAt(int index) const
|
||||
{
|
||||
if ((index < 0) || (index >= m_childUids.count()))
|
||||
return nullptr;
|
||||
|
||||
return m_children[m_childUids[index]];
|
||||
}
|
||||
|
||||
void addChild(const QString &uid, CategoryModelItem *item)
|
||||
{
|
||||
Q_ASSERT(item);
|
||||
Q_ASSERT(!item->parent());
|
||||
Q_ASSERT(!m_children.contains(uid));
|
||||
|
||||
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_torrentsCount += item->torrentsCount();
|
||||
}
|
||||
|
||||
void clear()
|
||||
{
|
||||
// use copy of m_children for qDeleteAll
|
||||
// to avoid collision when child removes
|
||||
// itself from parent children
|
||||
qDeleteAll(decltype(m_children)(m_children));
|
||||
}
|
||||
|
||||
private:
|
||||
CategoryModelItem *m_parent;
|
||||
QString m_name;
|
||||
int m_torrentsCount;
|
||||
QHash<QString, CategoryModelItem *> m_children;
|
||||
QStringList m_childUids;
|
||||
};
|
||||
|
||||
namespace
|
||||
{
|
||||
QString shortName(const QString &fullName)
|
||||
{
|
||||
int pos = fullName.lastIndexOf(QLatin1Char('/'));
|
||||
if (pos >= 0)
|
||||
return fullName.mid(pos + 1);
|
||||
return fullName;
|
||||
}
|
||||
}
|
||||
|
||||
CategoryFilterModel::CategoryFilterModel(QObject *parent)
|
||||
: QAbstractItemModel(parent)
|
||||
, m_rootItem(new CategoryModelItem)
|
||||
{
|
||||
auto session = BitTorrent::Session::instance();
|
||||
|
||||
connect(session, SIGNAL(categoryAdded(QString)), SLOT(categoryAdded(QString)));
|
||||
connect(session, SIGNAL(categoryRemoved(QString)), SLOT(categoryRemoved(QString)));
|
||||
connect(session, SIGNAL(torrentCategoryChanged(BitTorrent::TorrentHandle *const, QString))
|
||||
, SLOT(torrentCategoryChanged(BitTorrent::TorrentHandle *const, QString)));
|
||||
connect(session, SIGNAL(subcategoriesSupportChanged()), SLOT(subcategoriesSupportChanged()));
|
||||
connect(session, SIGNAL(torrentAdded(BitTorrent::TorrentHandle *const))
|
||||
, SLOT(torrentAdded(BitTorrent::TorrentHandle *const)));
|
||||
connect(session, SIGNAL(torrentAboutToBeRemoved(BitTorrent::TorrentHandle *const))
|
||||
, SLOT(torrentAboutToBeRemoved(BitTorrent::TorrentHandle *const)));
|
||||
|
||||
populate();
|
||||
}
|
||||
|
||||
CategoryFilterModel::~CategoryFilterModel()
|
||||
{
|
||||
delete m_rootItem;
|
||||
}
|
||||
|
||||
int CategoryFilterModel::columnCount(const QModelIndex &) const
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
|
||||
QVariant CategoryFilterModel::data(const QModelIndex &index, int role) const
|
||||
{
|
||||
if (!index.isValid()) return QVariant();
|
||||
|
||||
auto item = static_cast<CategoryModelItem *>(index.internalPointer());
|
||||
|
||||
if ((index.column() == 0) && (role == Qt::DecorationRole)) {
|
||||
return GuiIconProvider::instance()->getIcon("inode-directory");
|
||||
}
|
||||
|
||||
if ((index.column() == 0) && (role == Qt::DisplayRole)) {
|
||||
return QString(QStringLiteral("%1 (%2)"))
|
||||
.arg(item->name()).arg(item->torrentsCount());
|
||||
}
|
||||
|
||||
if ((index.column() == 0) && (role == Qt::UserRole)) {
|
||||
return item->torrentsCount();
|
||||
}
|
||||
|
||||
return QVariant();
|
||||
}
|
||||
|
||||
Qt::ItemFlags CategoryFilterModel::flags(const QModelIndex &index) const
|
||||
{
|
||||
if (!index.isValid()) return 0;
|
||||
|
||||
return Qt::ItemIsEnabled | Qt::ItemIsSelectable;
|
||||
}
|
||||
|
||||
QVariant CategoryFilterModel::headerData(int section, Qt::Orientation orientation, int role) const
|
||||
{
|
||||
if ((orientation == Qt::Horizontal) && (role == Qt::DisplayRole))
|
||||
if (section == 0)
|
||||
return tr("Categories");
|
||||
|
||||
return QVariant();
|
||||
}
|
||||
|
||||
QModelIndex CategoryFilterModel::index(int row, int column, const QModelIndex &parent) const
|
||||
{
|
||||
if (column > 0)
|
||||
return QModelIndex();
|
||||
|
||||
if (parent.isValid() && (parent.column() != 0))
|
||||
return QModelIndex();
|
||||
|
||||
auto parentItem = parent.isValid() ? static_cast<CategoryModelItem *>(parent.internalPointer())
|
||||
: m_rootItem;
|
||||
if (row < parentItem->childCount())
|
||||
return createIndex(row, column, parentItem->childAt(row));
|
||||
|
||||
return QModelIndex();
|
||||
}
|
||||
|
||||
QModelIndex CategoryFilterModel::parent(const QModelIndex &index) const
|
||||
{
|
||||
if (!index.isValid())
|
||||
return QModelIndex();
|
||||
|
||||
auto item = static_cast<CategoryModelItem *>(index.internalPointer());
|
||||
if (!item) return QModelIndex();
|
||||
|
||||
return this->index(item->parent());
|
||||
}
|
||||
|
||||
int CategoryFilterModel::rowCount(const QModelIndex &parent) const
|
||||
{
|
||||
if (parent.column() > 0)
|
||||
return 0;
|
||||
|
||||
if (!parent.isValid())
|
||||
return m_rootItem->childCount();
|
||||
|
||||
auto item = static_cast<CategoryModelItem *>(parent.internalPointer());
|
||||
if (!item) return 0;
|
||||
|
||||
return item->childCount();
|
||||
}
|
||||
|
||||
QModelIndex CategoryFilterModel::index(const QString &categoryName) const
|
||||
{
|
||||
return index(findItem(categoryName));
|
||||
}
|
||||
|
||||
QString CategoryFilterModel::categoryName(const QModelIndex &index) const
|
||||
{
|
||||
if (!index.isValid()) return QString();
|
||||
return static_cast<CategoryModelItem *>(index.internalPointer())->fullName();
|
||||
}
|
||||
|
||||
QModelIndex CategoryFilterModel::index(CategoryModelItem *item) const
|
||||
{
|
||||
if (!item || !item->parent()) return QModelIndex();
|
||||
|
||||
return index(item->pos(), 0, index(item->parent()));
|
||||
}
|
||||
|
||||
void CategoryFilterModel::categoryAdded(const QString &categoryName)
|
||||
{
|
||||
CategoryModelItem *parent = m_rootItem;
|
||||
|
||||
if (m_isSubcategoriesEnabled) {
|
||||
QStringList expanded = BitTorrent::Session::expandCategory(categoryName);
|
||||
if (expanded.count() > 1)
|
||||
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());
|
||||
endInsertRows();
|
||||
}
|
||||
|
||||
void CategoryFilterModel::categoryRemoved(const QString &categoryName)
|
||||
{
|
||||
auto item = findItem(categoryName);
|
||||
if (item) {
|
||||
QModelIndex i = index(item);
|
||||
beginRemoveRows(i.parent(), i.row(), i.row());
|
||||
delete item;
|
||||
endRemoveRows();
|
||||
}
|
||||
}
|
||||
|
||||
void CategoryFilterModel::torrentAdded(BitTorrent::TorrentHandle *const torrent)
|
||||
{
|
||||
CategoryModelItem *item = findItem(torrent->category());
|
||||
Q_ASSERT(item);
|
||||
|
||||
item->increaseTorrentsCount();
|
||||
m_rootItem->childAt(0)->increaseTorrentsCount();
|
||||
}
|
||||
|
||||
void CategoryFilterModel::torrentAboutToBeRemoved(BitTorrent::TorrentHandle *const torrent)
|
||||
{
|
||||
CategoryModelItem *item = findItem(torrent->category());
|
||||
Q_ASSERT(item);
|
||||
|
||||
item->decreaseTorrentsCount();
|
||||
m_rootItem->childAt(0)->decreaseTorrentsCount();
|
||||
}
|
||||
|
||||
void CategoryFilterModel::torrentCategoryChanged(BitTorrent::TorrentHandle *const torrent, const QString &oldCategory)
|
||||
{
|
||||
QModelIndex i;
|
||||
|
||||
auto item = findItem(oldCategory);
|
||||
Q_ASSERT(item);
|
||||
|
||||
item->decreaseTorrentsCount();
|
||||
i = index(item);
|
||||
while (i.isValid()) {
|
||||
emit dataChanged(i, i);
|
||||
i = parent(i);
|
||||
}
|
||||
|
||||
item = findItem(torrent->category());
|
||||
Q_ASSERT(item);
|
||||
|
||||
item->increaseTorrentsCount();
|
||||
i = index(item);
|
||||
while (i.isValid()) {
|
||||
emit dataChanged(i, i);
|
||||
i = parent(i);
|
||||
}
|
||||
}
|
||||
|
||||
void CategoryFilterModel::subcategoriesSupportChanged()
|
||||
{
|
||||
beginResetModel();
|
||||
populate();
|
||||
endResetModel();
|
||||
}
|
||||
|
||||
void CategoryFilterModel::populate()
|
||||
{
|
||||
m_rootItem->clear();
|
||||
|
||||
auto session = BitTorrent::Session::instance();
|
||||
auto torrents = session->torrents();
|
||||
m_isSubcategoriesEnabled = session->isSubcategoriesEnabled();
|
||||
|
||||
const QString UID_ALL;
|
||||
const QString UID_UNCATEGORIZED(QChar(1));
|
||||
|
||||
// All torrents
|
||||
m_rootItem->addChild(UID_ALL, new CategoryModelItem(nullptr, tr("All"), torrents.count()));
|
||||
|
||||
// Uncategorized torrents
|
||||
using Torrent = BitTorrent::TorrentHandle;
|
||||
m_rootItem->addChild(
|
||||
UID_UNCATEGORIZED
|
||||
, new CategoryModelItem(
|
||||
nullptr, tr("Uncategorized")
|
||||
, std::count_if(torrents.begin(), torrents.end()
|
||||
, [](Torrent *torrent) { return torrent->category().isEmpty(); })));
|
||||
|
||||
using Torrent = BitTorrent::TorrentHandle;
|
||||
foreach (const QString &category, session->categories()) {
|
||||
if (m_isSubcategoriesEnabled) {
|
||||
CategoryModelItem *parent = m_rootItem;
|
||||
foreach (const QString &subcat, session->expandCategory(category)) {
|
||||
const QString subcatName = shortName(subcat);
|
||||
if (!parent->hasChild(subcatName)) {
|
||||
new CategoryModelItem(
|
||||
parent, subcatName
|
||||
, std::count_if(torrents.begin(), torrents.end()
|
||||
, [subcat](Torrent *torrent) { return torrent->category() == subcat; }));
|
||||
}
|
||||
parent = parent->child(subcatName);
|
||||
}
|
||||
}
|
||||
else {
|
||||
new CategoryModelItem(
|
||||
m_rootItem, category
|
||||
, std::count_if(torrents.begin(), torrents.end()
|
||||
, [category](Torrent *torrent) { return torrent->belongsToCategory(category); }));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
CategoryModelItem *CategoryFilterModel::findItem(const QString &fullName) const
|
||||
{
|
||||
if (fullName.isEmpty())
|
||||
return m_rootItem->childAt(1); // "Uncategorized" item
|
||||
|
||||
if (!m_isSubcategoriesEnabled)
|
||||
return m_rootItem->child(fullName);
|
||||
|
||||
CategoryModelItem *item = m_rootItem;
|
||||
foreach (const QString &subcat, BitTorrent::Session::expandCategory(fullName)) {
|
||||
const QString subcatName = shortName(subcat);
|
||||
if (!item->hasChild(subcatName)) return nullptr;
|
||||
item = item->child(subcatName);
|
||||
}
|
||||
|
||||
return item;
|
||||
}
|
||||
79
src/gui/categoryfiltermodel.h
Normal file
@@ -0,0 +1,79 @@
|
||||
/*
|
||||
* Bittorrent Client using Qt and libtorrent.
|
||||
* Copyright (C) 2016 Vladimir Golovnev <glassez@yandex.ru>
|
||||
*
|
||||
* 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 CATEGORYFILTERMODEL_H
|
||||
#define CATEGORYFILTERMODEL_H
|
||||
|
||||
#include <QAbstractItemModel>
|
||||
#include <QHash>
|
||||
#include <QModelIndex>
|
||||
|
||||
namespace BitTorrent
|
||||
{
|
||||
class TorrentHandle;
|
||||
}
|
||||
|
||||
class CategoryModelItem;
|
||||
|
||||
class CategoryFilterModel: public QAbstractItemModel
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
explicit CategoryFilterModel(QObject *parent = nullptr);
|
||||
~CategoryFilterModel();
|
||||
|
||||
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;
|
||||
QVariant headerData(int section, Qt::Orientation orientation, int role) const override;
|
||||
QModelIndex index(int row, int column, const QModelIndex &parent = QModelIndex()) const override;
|
||||
QModelIndex parent(const QModelIndex &index) const override;
|
||||
int rowCount(const QModelIndex &parent = QModelIndex()) const override;
|
||||
|
||||
QModelIndex index(const QString &categoryName) const;
|
||||
QString categoryName(const QModelIndex &index) const;
|
||||
|
||||
private slots:
|
||||
void categoryAdded(const QString &categoryName);
|
||||
void categoryRemoved(const QString &categoryName);
|
||||
void torrentAdded(BitTorrent::TorrentHandle *const torrent);
|
||||
void torrentAboutToBeRemoved(BitTorrent::TorrentHandle *const torrent);
|
||||
void torrentCategoryChanged(BitTorrent::TorrentHandle *const torrent, const QString &oldCategory);
|
||||
void subcategoriesSupportChanged();
|
||||
|
||||
private:
|
||||
void populate();
|
||||
QModelIndex index(CategoryModelItem *item) const;
|
||||
CategoryModelItem *findItem(const QString &fullName) const;
|
||||
|
||||
bool m_isSubcategoriesEnabled;
|
||||
CategoryModelItem *m_rootItem;
|
||||
};
|
||||
|
||||
#endif // CATEGORYFILTERMODEL_H
|
||||
270
src/gui/categoryfilterwidget.cpp
Normal file
@@ -0,0 +1,270 @@
|
||||
/*
|
||||
* Bittorrent Client using Qt and libtorrent.
|
||||
* Copyright (C) 2016 Vladimir Golovnev <glassez@yandex.ru>
|
||||
*
|
||||
* 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 "categoryfilterwidget.h"
|
||||
|
||||
#include <QAction>
|
||||
#include <QHeaderView>
|
||||
#include <QLayout>
|
||||
#include <QMenu>
|
||||
#include <QMessageBox>
|
||||
|
||||
#include "base/bittorrent/session.h"
|
||||
#include "base/utils/misc.h"
|
||||
#include "autoexpandabledialog.h"
|
||||
#include "categoryfiltermodel.h"
|
||||
#include "guiiconprovider.h"
|
||||
|
||||
namespace
|
||||
{
|
||||
QString getCategoryFilter(const CategoryFilterModel *const model, const QModelIndex &index)
|
||||
{
|
||||
QString categoryFilter; // Defaults to All
|
||||
if (index.isValid()) {
|
||||
if (!index.parent().isValid() && (index.row() == 1))
|
||||
categoryFilter = ""; // Uncategorized
|
||||
else if (index.parent().isValid() || (index.row() > 1))
|
||||
categoryFilter = model->categoryName(index);
|
||||
}
|
||||
|
||||
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));
|
||||
setFrameShape(QFrame::NoFrame);
|
||||
setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
|
||||
setVerticalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
|
||||
setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Fixed);
|
||||
setUniformRowHeights(true);
|
||||
setHeaderHidden(true);
|
||||
setIconSize(Utils::Misc::smallIconSize());
|
||||
#if defined(Q_OS_MAC)
|
||||
setAttribute(Qt::WA_MacShowFocusRect, false);
|
||||
#endif
|
||||
setContextMenuPolicy(Qt::CustomContextMenu);
|
||||
setCurrentIndex(model()->index(0, 0));
|
||||
|
||||
connect(this, SIGNAL(collapsed(QModelIndex)), SLOT(callUpdateGeometry()));
|
||||
connect(this, SIGNAL(expanded(QModelIndex)), SLOT(callUpdateGeometry()));
|
||||
connect(this, SIGNAL(customContextMenuRequested(QPoint)), SLOT(showMenu(QPoint)));
|
||||
connect(selectionModel(), SIGNAL(currentRowChanged(QModelIndex,QModelIndex))
|
||||
, SLOT(onCurrentRowChanged(QModelIndex,QModelIndex)));
|
||||
connect(model(), SIGNAL(modelReset()), SLOT(callUpdateGeometry()));
|
||||
}
|
||||
|
||||
QString CategoryFilterWidget::currentCategory() const
|
||||
{
|
||||
QModelIndex current;
|
||||
auto selectedRows = selectionModel()->selectedRows();
|
||||
if (!selectedRows.isEmpty())
|
||||
current = selectedRows.first();
|
||||
|
||||
return getCategoryFilter(static_cast<CategoryFilterModel *>(model()), current);
|
||||
}
|
||||
|
||||
void CategoryFilterWidget::onCurrentRowChanged(const QModelIndex ¤t, const QModelIndex &previous)
|
||||
{
|
||||
Q_UNUSED(previous);
|
||||
|
||||
emit categoryChanged(getCategoryFilter(static_cast<CategoryFilterModel *>(model()), current));
|
||||
}
|
||||
|
||||
void CategoryFilterWidget::showMenu(QPoint)
|
||||
{
|
||||
QMenu menu(this);
|
||||
|
||||
QAction *addAct = menu.addAction(
|
||||
GuiIconProvider::instance()->getIcon("list-add")
|
||||
, tr("Add category..."));
|
||||
connect(addAct, SIGNAL(triggered()), SLOT(addCategory()));
|
||||
|
||||
auto selectedRows = selectionModel()->selectedRows();
|
||||
if (!selectedRows.empty() && !isSpecialItem(selectedRows.first())) {
|
||||
if (BitTorrent::Session::instance()->isSubcategoriesEnabled()) {
|
||||
QAction *addSubAct = menu.addAction(
|
||||
GuiIconProvider::instance()->getIcon("list-add")
|
||||
, tr("Add subcategory..."));
|
||||
connect(addSubAct, SIGNAL(triggered()), SLOT(addSubcategory()));
|
||||
}
|
||||
|
||||
QAction *removeAct = menu.addAction(
|
||||
GuiIconProvider::instance()->getIcon("list-remove")
|
||||
, tr("Remove category"));
|
||||
connect(removeAct, SIGNAL(triggered()), SLOT(removeCategory()));
|
||||
}
|
||||
|
||||
QAction *removeUnusedAct = menu.addAction(
|
||||
GuiIconProvider::instance()->getIcon("list-remove")
|
||||
, tr("Remove unused categories"));
|
||||
connect(removeUnusedAct, SIGNAL(triggered()), SLOT(removeUnusedCategories()));
|
||||
|
||||
menu.addSeparator();
|
||||
|
||||
QAction *startAct = menu.addAction(
|
||||
GuiIconProvider::instance()->getIcon("media-playback-start")
|
||||
, tr("Resume torrents"));
|
||||
connect(startAct, SIGNAL(triggered()), SIGNAL(actionResumeTorrentsTriggered()));
|
||||
|
||||
QAction *pauseAct = menu.addAction(
|
||||
GuiIconProvider::instance()->getIcon("media-playback-pause")
|
||||
, tr("Pause torrents"));
|
||||
connect(pauseAct, SIGNAL(triggered()), SIGNAL(actionPauseTorrentsTriggered()));
|
||||
|
||||
QAction *deleteTorrentsAct = menu.addAction(
|
||||
GuiIconProvider::instance()->getIcon("edit-delete")
|
||||
, tr("Delete torrents"));
|
||||
connect(deleteTorrentsAct, SIGNAL(triggered()), SIGNAL(actionDeleteTorrentsTriggered()));
|
||||
|
||||
menu.exec(QCursor::pos());
|
||||
}
|
||||
|
||||
void CategoryFilterWidget::callUpdateGeometry()
|
||||
{
|
||||
updateGeometry();
|
||||
}
|
||||
|
||||
QSize CategoryFilterWidget::sizeHint() const
|
||||
{
|
||||
#ifdef QBT_USES_QT5
|
||||
return viewportSizeHint();
|
||||
#else
|
||||
int lastRow = model()->rowCount() - 1;
|
||||
QModelIndex last = model()->index(lastRow, 0);
|
||||
while ((lastRow >= 0) && isExpanded(last)) {
|
||||
lastRow = model()->rowCount(last) - 1;
|
||||
last = model()->index(lastRow, 0, last);
|
||||
}
|
||||
const QRect deepestRect = visualRect(last);
|
||||
|
||||
if (!deepestRect.isValid())
|
||||
return viewport()->sizeHint();
|
||||
|
||||
return QSize(header()->length(), deepestRect.bottom() + 1);
|
||||
#endif
|
||||
}
|
||||
|
||||
QSize CategoryFilterWidget::minimumSizeHint() const
|
||||
{
|
||||
QSize size = sizeHint();
|
||||
size.setWidth(6);
|
||||
return size;
|
||||
}
|
||||
|
||||
void CategoryFilterWidget::rowsInserted(const QModelIndex &parent, int start, int end)
|
||||
{
|
||||
QTreeView::rowsInserted(parent, start, end);
|
||||
|
||||
// Expand all parents if the parent(s) of the node are not expanded.
|
||||
QModelIndex p = parent;
|
||||
while (p.isValid()) {
|
||||
if (!isExpanded(p))
|
||||
expand(p);
|
||||
p = model()->parent(p);
|
||||
}
|
||||
|
||||
updateGeometry();
|
||||
}
|
||||
|
||||
QString CategoryFilterWidget::askCategoryName()
|
||||
{
|
||||
bool ok;
|
||||
QString category = "";
|
||||
bool invalid;
|
||||
do {
|
||||
invalid = false;
|
||||
category = AutoExpandableDialog::getText(
|
||||
this, tr("New Category"), tr("Category:"), QLineEdit::Normal, category, &ok);
|
||||
if (ok && !category.isEmpty()) {
|
||||
if (!BitTorrent::Session::isValidCategoryName(category)) {
|
||||
QMessageBox::warning(
|
||||
this, tr("Invalid category name")
|
||||
, tr("Category name must not contain '\\'.\n"
|
||||
"Category name must not start/end with '/'.\n"
|
||||
"Category name must not contain '//' sequence."));
|
||||
invalid = true;
|
||||
}
|
||||
}
|
||||
} while (invalid);
|
||||
|
||||
return ok ? category : QString();
|
||||
}
|
||||
|
||||
void CategoryFilterWidget::addCategory()
|
||||
{
|
||||
const QString category = askCategoryName();
|
||||
if (category.isEmpty()) return;
|
||||
|
||||
if (BitTorrent::Session::instance()->categories().contains(category))
|
||||
QMessageBox::warning(this, tr("Category exists"), tr("Category name already exists."));
|
||||
else
|
||||
BitTorrent::Session::instance()->addCategory(category);
|
||||
}
|
||||
|
||||
void CategoryFilterWidget::addSubcategory()
|
||||
{
|
||||
const QString subcat = askCategoryName();
|
||||
if (subcat.isEmpty()) return;
|
||||
|
||||
const QString category = QString(QStringLiteral("%1/%2")).arg(currentCategory()).arg(subcat);
|
||||
|
||||
if (BitTorrent::Session::instance()->categories().contains(category))
|
||||
QMessageBox::warning(this, tr("Category exists")
|
||||
, tr("Subcategory name already exists in selected category."));
|
||||
else
|
||||
BitTorrent::Session::instance()->addCategory(category);
|
||||
}
|
||||
|
||||
void CategoryFilterWidget::removeCategory()
|
||||
{
|
||||
auto selectedRows = selectionModel()->selectedRows();
|
||||
if (!selectedRows.empty() && !isSpecialItem(selectedRows.first())) {
|
||||
BitTorrent::Session::instance()->removeCategory(
|
||||
static_cast<CategoryFilterModel *>(model())->categoryName(selectedRows.first()));
|
||||
updateGeometry();
|
||||
}
|
||||
}
|
||||
|
||||
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)
|
||||
session->removeCategory(category);
|
||||
updateGeometry();
|
||||
}
|
||||
60
src/gui/categoryfilterwidget.h
Normal file
@@ -0,0 +1,60 @@
|
||||
/*
|
||||
* Bittorrent Client using Qt and libtorrent.
|
||||
* Copyright (C) 2016 Vladimir Golovnev <glassez@yandex.ru>
|
||||
*
|
||||
* 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 <QTreeView>
|
||||
|
||||
class CategoryFilterWidget: public QTreeView
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
explicit CategoryFilterWidget(QWidget *parent = nullptr);
|
||||
|
||||
QString currentCategory() const;
|
||||
|
||||
signals:
|
||||
void categoryChanged(const QString &categoryName);
|
||||
void actionResumeTorrentsTriggered();
|
||||
void actionPauseTorrentsTriggered();
|
||||
void actionDeleteTorrentsTriggered();
|
||||
|
||||
private slots:
|
||||
void onCurrentRowChanged(const QModelIndex ¤t, const QModelIndex &previous);
|
||||
void showMenu(QPoint);
|
||||
void callUpdateGeometry();
|
||||
void addCategory();
|
||||
void addSubcategory();
|
||||
void removeCategory();
|
||||
void removeUnusedCategories();
|
||||
|
||||
private:
|
||||
QSize sizeHint() const override;
|
||||
QSize minimumSizeHint() const override;
|
||||
void rowsInserted(const QModelIndex &parent, int start, int end) override;
|
||||
QString askCategoryName();
|
||||
};
|
||||
@@ -35,8 +35,9 @@
|
||||
#include <QPushButton>
|
||||
#include "ui_confirmdeletiondlg.h"
|
||||
#include "base/preferences.h"
|
||||
#include "guiiconprovider.h"
|
||||
#include "base/utils/misc.h"
|
||||
#include "base/utils/string.h"
|
||||
#include "guiiconprovider.h"
|
||||
|
||||
class DeletionConfirmationDlg : public QDialog, private Ui::confirmDeletionDlg {
|
||||
Q_OBJECT
|
||||
@@ -45,7 +46,7 @@ class DeletionConfirmationDlg : public QDialog, private Ui::confirmDeletionDlg {
|
||||
DeletionConfirmationDlg(QWidget *parent, const int &size, const QString &name, bool defaultDeleteFiles): QDialog(parent) {
|
||||
setupUi(this);
|
||||
if (size == 1)
|
||||
label->setText(tr("Are you sure you want to delete '%1' from the transfer list?", "Are you sure you want to delete 'ubuntu-linux-iso' from the transfer list?").arg(name));
|
||||
label->setText(tr("Are you sure you want to delete '%1' from the transfer list?", "Are you sure you want to delete 'ubuntu-linux-iso' from the transfer list?").arg(Utils::String::toHtmlEscaped(name)));
|
||||
else
|
||||
label->setText(tr("Are you sure you want to delete these %1 torrents from the transfer list?", "Are you sure you want to delete these 5 torrents from the transfer list?").arg(QString::number(size)));
|
||||
// Icons
|
||||
|
||||
@@ -96,9 +96,9 @@ class downloadFromURL : public QDialog, private Ui::downloadFromURL{
|
||||
QMessageBox::warning(0, tr("No URL entered"), tr("Please type at least one URL."));
|
||||
return;
|
||||
}
|
||||
close();
|
||||
emit urlsReadyToBeDownloaded(url_list_cleaned);
|
||||
qDebug("Emitted urlsReadytobedownloaded signal");
|
||||
close();
|
||||
}
|
||||
|
||||
void on_cancelButton_clicked() {
|
||||
|
||||
@@ -49,7 +49,9 @@ HEADERS += \
|
||||
$$PWD/search/searchlistdelegate.h \
|
||||
$$PWD/search/searchsortmodel.h \
|
||||
$$PWD/cookiesmodel.h \
|
||||
$$PWD/cookiesdialog.h
|
||||
$$PWD/cookiesdialog.h \
|
||||
$$PWD/categoryfiltermodel.h \
|
||||
$$PWD/categoryfilterwidget.h
|
||||
|
||||
SOURCES += \
|
||||
$$PWD/mainwindow.cpp \
|
||||
@@ -89,7 +91,9 @@ SOURCES += \
|
||||
$$PWD/search/searchlistdelegate.cpp \
|
||||
$$PWD/search/searchsortmodel.cpp \
|
||||
$$PWD/cookiesmodel.cpp \
|
||||
$$PWD/cookiesdialog.cpp
|
||||
$$PWD/cookiesdialog.cpp \
|
||||
$$PWD/categoryfiltermodel.cpp \
|
||||
$$PWD/categoryfilterwidget.cpp
|
||||
|
||||
win32|macx {
|
||||
HEADERS += $$PWD/programupdater.h
|
||||
|
||||
@@ -57,13 +57,22 @@ GuiIconProvider *GuiIconProvider::instance()
|
||||
}
|
||||
|
||||
QIcon GuiIconProvider::getIcon(const QString &iconId)
|
||||
{
|
||||
return getIcon(iconId, iconId);
|
||||
}
|
||||
|
||||
QIcon GuiIconProvider::getIcon(const QString &iconId, const QString &fallback)
|
||||
{
|
||||
#if (defined(Q_OS_UNIX) && !defined(Q_OS_MAC))
|
||||
if (m_useSystemTheme) {
|
||||
QIcon icon = QIcon::fromTheme(iconId, QIcon(IconProvider::getIconPath(iconId)));
|
||||
QIcon icon = QIcon::fromTheme(iconId);
|
||||
if (icon.name() != iconId)
|
||||
icon = QIcon::fromTheme(fallback, QIcon(IconProvider::getIconPath(iconId)));
|
||||
icon = generateDifferentSizes(icon);
|
||||
return icon;
|
||||
}
|
||||
#else
|
||||
Q_UNUSED(fallback)
|
||||
#endif
|
||||
return QIcon(IconProvider::getIconPath(iconId));
|
||||
}
|
||||
@@ -81,6 +90,13 @@ QIcon GuiIconProvider::getFlagIcon(const QString &countryIsoCode)
|
||||
#if (defined(Q_OS_UNIX) && !defined(Q_OS_MAC))
|
||||
QIcon GuiIconProvider::generateDifferentSizes(const QIcon &icon)
|
||||
{
|
||||
// if icon is loaded from SVG format, it already contains all the required sizes and we shall not resize it
|
||||
// In that case it will be available in the following sizes:
|
||||
// (QSize(16, 16), QSize(22, 22), QSize(32, 32), QSize(48, 48), QSize(64, 64), QSize(128, 128), QSize(256, 256))
|
||||
|
||||
if (icon.availableSizes(QIcon::Normal, QIcon::On).size() > 6)
|
||||
return icon;
|
||||
|
||||
QIcon newIcon;
|
||||
QList<QSize> requiredSizes;
|
||||
requiredSizes << QSize(16, 16) << QSize(24, 24) << QSize(32, 32);
|
||||
|
||||